diff --git a/.gitignore b/.gitignore index 97fd50282..c726ce016 100644 --- a/.gitignore +++ b/.gitignore @@ -19,8 +19,11 @@ clutter/stamp-* /clutter/clutter-json.h /clutter/cogl/cogl-defines-gl.h /clutter/cogl/cogl-defines-gles.h +/clutter/cogl/cogl-enum-types.h /clutter/cogl/cogl.h /clutter/cogl/*.pc +/clutter/cogl/common/cogl-enum-types.[ch] +/clutter/cogl/common/stamp-cogl-enum-types.h /clutter/cogl/gles/cogl-fixed-vertex-shader.[ch] /clutter/cogl/gles/cogl-fixed-fragment-shader.[ch] *.gir @@ -36,12 +39,12 @@ doc/reference/clutter/clutter-*.txt doc/reference/clutter/html doc/reference/clutter/tmpl doc/reference/clutter/xml -doc/reference/clutter/version.xml doc/reference/clutter/clutter.args doc/reference/clutter/clutter.hierarchy doc/reference/clutter/clutter.interfaces doc/reference/clutter/clutter.prerequisites doc/reference/clutter/clutter.signals +doc/reference/clutter/clutter-docs.xml doc/reference/clutter/*.stamp doc/reference/clutter/*.bak doc/reference/cogl/cogl-*.txt @@ -49,12 +52,12 @@ doc/reference/cogl/cogl-*.txt doc/reference/cogl/html doc/reference/cogl/tmpl doc/reference/cogl/xml -doc/reference/cogl/version.xml doc/reference/cogl/cogl.args doc/reference/cogl/cogl.hierarchy doc/reference/cogl/cogl.interfaces doc/reference/cogl/cogl.prerequisites doc/reference/cogl/cogl.signals +doc/reference/cogl/cogl-docs.xml doc/reference/cogl/*.stamp doc/reference/cogl/*.bak doltcompile @@ -193,7 +196,16 @@ stamp-h1 /tests/conform/test-list-model-filter /tests/conform/test-npot-texture /tests/conform/redhand.png -/tests/micro-bench/test-glyph-perf +/tests/conform/test-map-recursive +/tests/conform/test-realize-not-recursive +/tests/conform/test-shown-not-parented +/tests/conform/test-blend-strings +/tests/conform/test-color-from-string +/tests/conform/test-color-to-string +/tests/conform/test-units-constructors +/tests/conform/test-units-string +/tests/conform/test-conformance-result.xml +/tests/micro-bench/test-text-perf /tests/micro-bench/test-text /tests/micro-bench/test-picking /tests/tools/disable-npots.sh diff --git a/README b/README index 7c0b3af68..44c519f44 100644 --- a/README +++ b/README @@ -333,6 +333,9 @@ Release Notes for Clutter 1.0 * cogl_shader_get_parameteriv has been replaced by cogl_shader_get_type and cogl_shader_is_compiled. More getters can be added later if desired. +* cogl_enable_depth_test has been renamed to cogl_set_depth_test_enabled and + a corresponding cogl_get_depth_test_enabled function has been added. + Release Notes for Clutter 0.8 ------------------------------- diff --git a/clutter.doap b/clutter.doap index 5e55e7c0e..2269ca1af 100644 --- a/clutter.doap +++ b/clutter.doap @@ -1,29 +1,27 @@ + Clutter clutter 2006-11-18 - - Clutter is an OpenGL based interface library - + Clutter is an OpenGL based interface library - - Clutter is an open source software library for creating fast, visually - rich and animated graphical user interfaces. Clutter uses OpenGL (and - optionally OpenGL ES for use on Mobile and embedded platforms) for - rendering, but with an API which hides the underlying GL complexity - from the developer. The Clutter API is intended to be easy to use, - efficient and flexible. - + Clutter is an open source software library for creating + fast, visually rich, portable and animated graphical user interfaces. Clutter uses + OpenGL (and optionally OpenGL|ES for use on Mobile and embedded platforms) for + rendering, but with an API which hides the underlying GL complexity from the + developer. The Clutter API is intended to be easy to use, efficient and + flexible. - + C @@ -32,6 +30,7 @@ + Matthew Allum @@ -39,6 +38,13 @@ + + + Emmanuele Bassi + + + + Matthew Allum @@ -49,15 +55,36 @@ Emmanuele Bassi - + + + + + + + Neil Roberts + + + + + + + Robert Bragg + + + + + + + Øyvind Kolås + - - - - + + + + diff --git a/clutter/Makefile.am b/clutter/Makefile.am index 5b838cea5..1eef4019b 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -169,6 +169,7 @@ source_c = \ $(srcdir)/clutter-list-model.c \ $(srcdir)/clutter-main.c \ clutter-marshal.c \ + $(srcdir)/clutter-master-clock.c \ $(srcdir)/clutter-media.c \ $(srcdir)/clutter-model.c \ $(srcdir)/clutter-path.c \ @@ -195,6 +196,7 @@ source_h_priv = \ $(srcdir)/clutter-bezier.h \ $(srcdir)/clutter-debug.h \ $(srcdir)/clutter-keysyms-table.h \ + $(srcdir)/clutter-master-clock.h \ $(srcdir)/clutter-model-private.h \ $(srcdir)/clutter-private.h \ $(srcdir)/clutter-id-pool.h \ @@ -234,7 +236,6 @@ clutter_HEADERS = \ $(source_h) \ $(top_builddir)/clutter/clutter-json.h \ $(top_builddir)/clutter/clutter-enum-types.h \ - $(top_builddir)/clutter/clutter-version.h \ $(top_srcdir)/clutter/clutter.h if HAVE_INTROSPECTION @@ -248,11 +249,6 @@ endif # subdir Makefile.am, so just extract them from cogl.h instead. The doc # comments for COGL are in the headers, so we don't need the source files. Clutter-@CLUTTER_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libclutter-@CLUTTER_FLAVOUR@-@CLUTTER_API_VERSION@.la - headers=`sed -n "s/#include ]*\)>/\1/p" < $(top_srcdir)/clutter/cogl/cogl.h` ; \ - cogl_headers="" ; \ - for header in $$headers; do \ - cogl_headers="$$cogl_headers $(top_srcdir)/clutter/cogl/$$header " ; \ - done ; \ $(INTROSPECTION_SCANNER) -v --namespace Clutter --nsversion=@CLUTTER_API_VERSION@ \ $(INCLUDES) \ $(json_gir_include_path) \ @@ -260,6 +256,7 @@ Clutter-@CLUTTER_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libclutter-@CLUTTER_ --include=GObject-2.0 \ --include=Pango-1.0 \ --include=PangoCairo-1.0 \ + --include=Cogl-@CLUTTER_API_VERSION@ \ --include=ClutterJson-@CLUTTER_API_VERSION@ \ --library=clutter-@CLUTTER_FLAVOUR@-@CLUTTER_API_VERSION@ \ --libtool="$(top_builddir)/doltlibtool" \ @@ -268,8 +265,6 @@ Clutter-@CLUTTER_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libclutter-@CLUTTER_ --pkg pangocairo \ --output $@ \ $(clutter_HEADERS) \ - $$cogl_headers \ - $(top_builddir)/clutter/cogl/cogl-defines-$(CLUTTER_COGL).h \ $(source_c) BUILT_GIRSOURCES += Clutter-@CLUTTER_API_VERSION@.gir diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 675464355..3aac1c1fc 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -132,37 +132,61 @@ /** * CLUTTER_ACTOR_IS_MAPPED: - * @e: a #ClutterActor + * @a: a #ClutterActor * * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set. * + * Means "the actor will be painted if the stage is mapped." + * + * %TRUE if the actor is visible; and all parents with possible exception + * of the stage are visible; and an ancestor of the actor is a toplevel. + * + * Clutter auto-maintains the mapped flag whenever actors are + * reparented or shown/hidden. + * * Since: 0.2 */ /** * CLUTTER_ACTOR_IS_REALIZED: - * @e: a #ClutterActor + * @a: a #ClutterActor * * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set. * + * Whether GL resources such as textures are allocated; + * if an actor is mapped it must also be realized, but an actor + * can be realized and unmapped (this is so hiding an actor temporarily + * doesn't do an expensive unrealize/realize). + * + * To be realized an actor must be inside a stage, and all its parents + * must be realized. The stage is required so the actor knows the + * correct GL context and window system resources to use. + * * Since: 0.2 */ /** * CLUTTER_ACTOR_IS_VISIBLE: - * @e: a #ClutterActor + * @a: a #ClutterActor * - * Evaluates to %TRUE if the actor is both realized and mapped. + * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden. + * Equivalent to the ClutterActor::visible object property. + * + * Note that an actor is only painted onscreen if it's mapped, which + * means it's visible, and all its parents are visible, and one of the + * parents is a toplevel stage. * * Since: 0.2 */ /** * CLUTTER_ACTOR_IS_REACTIVE: - * @e: a #ClutterActor + * @a: a #ClutterActor * * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set. * + * Only reactive actors will receive event-related signals. + * * Since: 0.6 */ @@ -210,69 +234,88 @@ struct _AnchorCoord } v; }; +/* Internal enum used to control mapped state update. This is a hint + * which indicates when to do something other than just enforce + * invariants. + */ +typedef enum { + MAP_STATE_CHECK, /* just enforce invariants. */ + MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants, + * used when about to unparent. + */ + MAP_STATE_MAKE_MAPPED, /* set mapped, error if invariants not met; + * used to set mapped on toplevels. + */ + MAP_STATE_MAKE_UNMAPPED /* set unmapped, even if parent is mapped, + * used just before unmapping parent. + */ +} MapStateChange; + struct _ClutterActorPrivate { /* fixed_x, fixed_y, and the allocation box are all in parent * coordinates. */ - ClutterUnit fixed_x; - ClutterUnit fixed_y; + gfloat fixed_x; + gfloat fixed_y; /* request mode */ ClutterRequestMode request_mode; /* our cached request width is for this height */ - ClutterUnit request_width_for_height; - ClutterUnit request_min_width; - ClutterUnit request_natural_width; + gfloat request_width_for_height; + gfloat request_min_width; + gfloat request_natural_width; + /* our cached request height is for this width */ - ClutterUnit request_height_for_width; - ClutterUnit request_min_height; - ClutterUnit request_natural_height; + gfloat request_height_for_width; + gfloat request_min_height; + gfloat request_natural_height; ClutterActorBox allocation; + ClutterAllocationFlags allocation_flags; - guint position_set : 1; - guint min_width_set : 1; - guint min_height_set : 1; - guint natural_width_set : 1; - guint natural_height_set : 1; + guint position_set : 1; + guint min_width_set : 1; + guint min_height_set : 1; + guint natural_width_set : 1; + guint natural_height_set : 1; /* cached request is invalid (implies allocation is too) */ - guint needs_width_request : 1; + guint needs_width_request : 1; /* cached request is invalid (implies allocation is too) */ - guint needs_height_request : 1; + guint needs_height_request : 1; /* cached allocation is invalid (request has changed, probably) */ - guint needs_allocation : 1; + guint needs_allocation : 1; + guint queued_redraw : 1; + guint show_on_set_parent : 1; + guint has_clip : 1; + guint clip_to_allocation : 1; + guint enable_model_view_transform : 1; + guint enable_paint_unmapped : 1; - guint queued_redraw : 1; - - guint show_on_set_parent : 1; - guint has_clip : 1; - guint clip_to_allocation : 1; - - ClutterUnit clip[4]; + gfloat clip[4]; /* Rotation angles */ - gdouble rxang; - gdouble ryang; - gdouble rzang; + gdouble rxang; + gdouble ryang; + gdouble rzang; /* Rotation center: X axis */ - AnchorCoord rx_center; + AnchorCoord rx_center; /* Rotation center: Y axis */ - AnchorCoord ry_center; + AnchorCoord ry_center; /* Rotation center: Z axis */ - AnchorCoord rz_center; + AnchorCoord rz_center; /* Anchor point coordinates */ - AnchorCoord anchor; + AnchorCoord anchor; /* depth */ - ClutterUnit z; + gfloat z; - guint8 opacity; + guint8 opacity; ClutterActor *parent_actor; @@ -289,7 +332,6 @@ struct _ClutterActorPrivate PangoContext *pango_context; ClutterActor *opacity_parent; - gboolean enable_model_view_transform; }; enum @@ -301,8 +343,7 @@ enum /* X, Y, WIDTH, HEIGHT are "do what I mean" properties; * when set they force a size request, when gotten they * get the allocation if the allocation is valid, and the - * request otherwise. Also, they are in pixels, while - * all the underlying properties are in ClutterUnit. + * request otherwise */ PROP_X, PROP_Y, @@ -310,8 +351,7 @@ enum PROP_HEIGHT, /* Then the rest of these size-related properties are the "actual" - * underlying properties set or gotten by X, Y, WIDTH, HEIGHT. All - * of these are in ClutterUnit not in pixels. + * underlying properties set or gotten by X, Y, WIDTH, HEIGHT */ PROP_FIXED_X, PROP_FIXED_Y, @@ -342,7 +382,10 @@ enum PROP_CLIP_TO_ALLOCATION, PROP_OPACITY, + PROP_VISIBLE, + PROP_MAPPED, + PROP_REALIZED, PROP_REACTIVE, PROP_SCALE_X, @@ -375,8 +418,8 @@ enum HIDE, DESTROY, PARENT_SET, - FOCUS_IN, - FOCUS_OUT, + KEY_FOCUS_IN, + KEY_FOCUS_OUT, PAINT, PICK, REALIZE, @@ -392,6 +435,7 @@ enum MOTION_EVENT, ENTER_EVENT, LEAVE_EVENT, + ALLOCATION_CHANGED, LAST_SIGNAL }; @@ -413,13 +457,13 @@ static void destroy_shader_data (ClutterActor *self); * properties */ static void clutter_actor_set_min_width (ClutterActor *self, - ClutterUnit min_width); + gfloat min_width); static void clutter_actor_set_min_height (ClutterActor *self, - ClutterUnit min_height); + gfloat min_height); static void clutter_actor_set_natural_width (ClutterActor *self, - ClutterUnit natural_width); + gfloat natural_width); static void clutter_actor_set_natural_height (ClutterActor *self, - ClutterUnit natural_height); + gfloat natural_height); static void clutter_actor_set_min_width_set (ClutterActor *self, gboolean use_min_width); static void clutter_actor_set_min_height_set (ClutterActor *self, @@ -430,39 +474,35 @@ static void clutter_actor_set_natural_height_set (ClutterActor *self, gboolean use_natural_height); static void clutter_actor_set_request_mode (ClutterActor *self, ClutterRequestMode mode); +static void clutter_actor_update_map_state (ClutterActor *self, + MapStateChange change); +static void clutter_actor_unrealize_not_hiding (ClutterActor *self); /* Helper routines for managing anchor coords */ -static void clutter_anchor_coord_get_units (ClutterActor *self, +static void clutter_anchor_coord_get_units (ClutterActor *self, const AnchorCoord *coord, - ClutterUnit *x, - ClutterUnit *y, - ClutterUnit *z); -static void clutter_anchor_coord_set_units (AnchorCoord *coord, - ClutterUnit x, - ClutterUnit y, - ClutterUnit z); -static ClutterGravity clutter_anchor_coord_get_gravity (AnchorCoord *coord); -static void clutter_anchor_coord_set_gravity (AnchorCoord *coord, - ClutterGravity gravity); + gfloat *x, + gfloat *y, + gfloat *z); +static void clutter_anchor_coord_set_units (AnchorCoord *coord, + gfloat x, + gfloat y, + gfloat z); + +static ClutterGravity clutter_anchor_coord_get_gravity (AnchorCoord *coord); +static void clutter_anchor_coord_set_gravity (AnchorCoord *coord, + ClutterGravity gravity); + static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord); /* Helper macro which translates by the anchor coord, applies the given transformation and then translates back */ -#define TRANSFORM_ABOUT_ANCHOR_COORD(actor, coord, transform) \ - G_STMT_START \ - { \ - ClutterUnit __tx, __ty, __tz; \ - clutter_anchor_coord_get_units ((actor), (coord), \ - &__tx, &__ty, &__tz); \ - cogl_translate (CLUTTER_UNITS_TO_FLOAT (__tx), \ - CLUTTER_UNITS_TO_FLOAT (__ty), \ - CLUTTER_UNITS_TO_FLOAT (__tz)); \ - (transform); \ - cogl_translate (-CLUTTER_UNITS_TO_FLOAT (__tx), \ - -CLUTTER_UNITS_TO_FLOAT (__ty), \ - -CLUTTER_UNITS_TO_FLOAT (__tz)); \ - } \ - G_STMT_END +#define TRANSFORM_ABOUT_ANCHOR_COORD(actor,coord,transform) G_STMT_START { \ + gfloat _tx, _ty, _tz; \ + clutter_anchor_coord_get_units ((actor), (coord), &_tx, &_ty, &_tz); \ + cogl_translate (_tx, _ty, _tz); \ + { transform; } \ + cogl_translate (-_tx, -_ty, -_tz); } G_STMT_END G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ClutterActor, clutter_actor, @@ -471,22 +511,461 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ClutterActor, clutter_scriptable_iface_init)); +#ifdef CLUTTER_ENABLE_DEBUG +/* XXX - this is for debugging only, remove once working (or leave + * in only in some debug mode). Should leave it for a little while + * until we're confident in the new map/realize/visible handling. + */ +static inline void +clutter_actor_verify_map_state (ClutterActor *self) +{ + ClutterActorPrivate *priv = self->priv; + + if (CLUTTER_ACTOR_IS_REALIZED (self)) + { + /* all bets are off during reparent when we're potentially realized, + * but should not be according to invariants + */ + if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_REPARENT)) + { + if (priv->parent_actor == NULL) + { + if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL) + { + } + else + g_warning ("Realized non-toplevel actor should have a parent"); + } + else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent_actor)) + { + g_warning ("Realized actor %s[%p] has an unrealized parent %s[%p]", + G_OBJECT_TYPE_NAME (self), self, + G_OBJECT_TYPE_NAME (priv->parent_actor), + priv->parent_actor); + } + } + } + + if (CLUTTER_ACTOR_IS_MAPPED (self)) + { + if (!CLUTTER_ACTOR_IS_REALIZED (self)) + g_warning ("Actor is mapped but not realized"); + + /* remaining bets are off during reparent when we're potentially + * mapped, but should not be according to invariants + */ + if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_REPARENT)) + { + if (priv->parent_actor == NULL) + { + if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL) + { + if (!CLUTTER_ACTOR_IS_VISIBLE (self) && + !(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_DESTRUCTION)) + { + g_warning ("Toplevel actor is mapped but not visible"); + } + } + else + { + g_warning ("Mapped actor %s %p should have a parent", + G_OBJECT_TYPE_NAME (self), self); + } + } + else + { + ClutterActor *parent = priv->parent_actor; + + /* check for the enable_paint_unmapped flag on any of the + * parents; if the flag is enabled at any point of this + * branch of the scene graph then all the later checks + * become pointless + */ + while (parent != NULL) + { + if (parent->priv->enable_paint_unmapped) + return; + + parent = parent->priv->parent_actor; + } + + if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent_actor)) + { + g_warning ("Actor should not be mapped if parent " + "is not visible"); + } + + if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent_actor)) + { + g_warning ("Actor should not be mapped if parent " + "is not realized"); + } + + if (!(CLUTTER_PRIVATE_FLAGS (priv->parent_actor) & + CLUTTER_ACTOR_IS_TOPLEVEL)) + { + if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent_actor)) + g_warning ("Actor is mapped but its non-toplevel " + "parent is not mapped"); + } + } + } + } +} + +#endif /* CLUTTER_ENABLE_DEBUG */ + +static void +clutter_actor_set_mapped (ClutterActor *self, + gboolean mapped) +{ + if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped) + return; + + if (mapped) + { + CLUTTER_ACTOR_GET_CLASS (self)->map (self); + g_assert (CLUTTER_ACTOR_IS_MAPPED (self)); + } + else + { + CLUTTER_ACTOR_GET_CLASS (self)->unmap (self); + g_assert (!CLUTTER_ACTOR_IS_MAPPED (self)); + } +} + +/* this function updates the mapped and realized states according to + * invariants, in the appropriate order. + */ +static void +clutter_actor_update_map_state (ClutterActor *self, + MapStateChange change) +{ + gboolean was_mapped; + gboolean was_realized; + + was_mapped = CLUTTER_ACTOR_IS_MAPPED (self); + was_realized = CLUTTER_ACTOR_IS_REALIZED (self); + + if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL) + { + /* the mapped flag on top-level actors must be set by the + * per-backend implementation because it might be asynchronous. + * + * That is, the MAPPED flag on toplevels currently tracks the X + * server mapped-ness of the window, while the expected behavior + * (if used to GTK) may be to track WM_STATE!=WithdrawnState. + * This creates some weird complexity by breaking the invariant + * that if we're visible and all ancestors shown then we are + * also mapped - instead, we are mapped if all ancestors + * _possibly excepting_ the stage are mapped. The stage + * will map/unmap for example when it is minimized or + * moved to another workspace. + * + * So, the only invariant on the stage is that if visible it + * should be realized, and that it has to be visible to be + * mapped. + */ + if (CLUTTER_ACTOR_IS_VISIBLE (self)) + clutter_actor_realize (self); + + switch (change) + { + case MAP_STATE_CHECK: + break; + + case MAP_STATE_MAKE_MAPPED: + g_assert (!was_mapped); + clutter_actor_set_mapped (self, TRUE); + break; + + case MAP_STATE_MAKE_UNMAPPED: + g_assert (was_mapped); + clutter_actor_set_mapped (self, FALSE); + break; + + case MAP_STATE_MAKE_UNREALIZED: + /* we only use MAKE_UNREALIZED in unparent, + * and unparenting a stage isn't possible. + * If someone wants to just unrealize a stage + * then clutter_actor_unrealize() doesn't + * go through this codepath. + */ + g_warning ("Trying to force unrealize stage is not allowed"); + break; + } + + if (CLUTTER_ACTOR_IS_MAPPED (self) && + !CLUTTER_ACTOR_IS_VISIBLE (self) && + !(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_DESTRUCTION)) + { + g_warning ("Clutter toplevel of type '%s' is not visible, but " + "it is somehow still mapped", + G_OBJECT_TYPE_NAME (self)); + } + } + else + { + ClutterActorPrivate *priv = self->priv; + ClutterActor *parent = priv->parent_actor; + gboolean should_be_mapped; + gboolean may_be_realized; + gboolean must_be_realized; + + should_be_mapped = FALSE; + may_be_realized = TRUE; + must_be_realized = FALSE; + + if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED) + { + may_be_realized = FALSE; + } + else + { + /* Maintain invariant that if parent is mapped, and we are + * visible, then we are mapped ... unless parent is a + * stage, in which case we map regardless of parent's map + * state but do require stage to be visible and realized. + * + * If parent is realized, that does not force us to be + * realized; but if parent is unrealized, that does force + * us to be unrealized. + * + * The reason we don't force children to realize with + * parents is _clutter_actor_rerealize(); if we require that + * a realized parent means children are realized, then to + * unrealize an actor we would have to unrealize its + * parents, which would end up meaning unrealizing and + * hiding the entire stage. So we allow unrealizing a + * child (as long as that child is not mapped) while that + * child still has a realized parent. + * + * Also, if we unrealize from leaf nodes to root, and + * realize from root to leaf, the invariants are never + * violated if we allow children to be unrealized + * while parents are realized. + * + * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified + * to force us to unmap, even though parent is still + * mapped. This is because we're unmapping from leaf nodes + * up to root nodes. + */ + if (CLUTTER_ACTOR_IS_VISIBLE (self) && + change != MAP_STATE_MAKE_UNMAPPED) + { + gboolean parent_is_visible_realized_toplevel; + + parent_is_visible_realized_toplevel = + (((CLUTTER_PRIVATE_FLAGS (parent) & + CLUTTER_ACTOR_IS_TOPLEVEL) != 0) && + CLUTTER_ACTOR_IS_VISIBLE (parent) && + CLUTTER_ACTOR_IS_REALIZED (parent)); + + if (CLUTTER_ACTOR_IS_MAPPED (parent) || + parent_is_visible_realized_toplevel) + { + must_be_realized = TRUE; + should_be_mapped = TRUE; + } + } + + /* if the actor has been set to be painted even if unmapped + * then we should map it and check for realization as well; + * this is an override for the branch of the scene graph + * which begins with this node + */ + if (priv->enable_paint_unmapped) + { + if (priv->parent_actor == NULL) + g_warning ("Attempting to map an unparented actor"); + + should_be_mapped = TRUE; + must_be_realized = TRUE; + } + + if (!CLUTTER_ACTOR_IS_REALIZED (parent)) + may_be_realized = FALSE; + } + + if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped) + { + g_warning ("Attempting to map a child that does not " + "meet the necessary invariants"); + } + + /* If in reparent, we temporarily suspend unmap and unrealize. + * + * We want to go in the order "realize, map" and "unmap, unrealize" + */ + + /* Unmap */ + if (!should_be_mapped && + !(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_REPARENT)) + { + clutter_actor_set_mapped (self, FALSE); + } + + /* Realize */ + if (must_be_realized) + clutter_actor_realize (self); + + /* if we must be realized then we may be, presumably */ + g_assert (!(must_be_realized && !may_be_realized)); + + /* Unrealize */ + if (!may_be_realized && + !(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_REPARENT)) + clutter_actor_unrealize_not_hiding (self); + + /* Map */ + if (should_be_mapped) + { + if (!must_be_realized) + g_warning ("Somehow we think an actor should be mapped but " + "not realized, which isn't allowed"); + + /* realization is allowed to fail (though I don't know what + * an app is supposed to do about that - shouldn't it just + * be a g_error? anyway, we have to avoid mapping if this + * happens) + */ + if (CLUTTER_ACTOR_IS_REALIZED (self)) + clutter_actor_set_mapped (self, TRUE); + } + } + +#ifdef CLUTTER_ENABLE_DEBUG + /* check all invariants were kept */ + clutter_actor_verify_map_state (self); +#endif +} + +static void +clutter_actor_real_map (ClutterActor *self) +{ + g_assert (!CLUTTER_ACTOR_IS_MAPPED (self)); + + CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED); + /* notify on parent mapped before potentially mapping + * children, so apps see a top-down notification. + */ + g_object_notify (G_OBJECT (self), "mapped"); + + clutter_actor_queue_redraw (self); + + if (CLUTTER_IS_CONTAINER (self)) + clutter_container_foreach_with_internals (CLUTTER_CONTAINER (self), + CLUTTER_CALLBACK (clutter_actor_map), + NULL); +} + +/** + * clutter_actor_map: + * @self: A #ClutterActor + * + * Sets the #CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps + * and realizes its children if they are visible. Does nothing if the + * actor is not visible. + * + * Calling this is allowed in only one case: you are implementing the + * #ClutterActor::map virtual function in an actor and you need to map + * the children of that actor. It is not necessary to call this + * if you implement #ClutterContainer because the default implementation + * will automatically map children of containers. + * + * When overriding map, it is mandatory to chain up to the parent + * implementation. + * + * Since: 1.0 + */ +void +clutter_actor_map (ClutterActor *self) +{ + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + + if (CLUTTER_ACTOR_IS_MAPPED (self)) + return; + + if (!CLUTTER_ACTOR_IS_VISIBLE (self)) + return; + + clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED); +} + +static void +clutter_actor_real_unmap (ClutterActor *self) +{ + g_assert (CLUTTER_ACTOR_IS_MAPPED (self)); + + if (CLUTTER_IS_CONTAINER (self)) + clutter_container_foreach_with_internals (CLUTTER_CONTAINER (self), + CLUTTER_CALLBACK (clutter_actor_unmap), + NULL); + + CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED); + + /* notify on parent mapped after potentially unmapping + * children, so apps see a bottom-up notification. + */ + g_object_notify (G_OBJECT (self), "mapped"); + + /* relinquish keyboard focus if we were unmapped while owning it */ + if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL)) + { + ClutterActor *stage; + + stage = clutter_actor_get_stage (self); + + if (stage && + clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self) + { + clutter_stage_set_key_focus (CLUTTER_STAGE (stage), NULL); + } + } + + clutter_actor_queue_redraw (self); +} + +/** + * clutter_actor_unmap: + * @self: A #ClutterActor + * + * Unsets the #CLUTTER_ACTOR_MAPPED flag on the actor and possibly + * unmaps its children if they were mapped. + * + * Calling this is allowed in only one case: you are implementing the + * #ClutterActor::unmap virtual function in an actor and you need to + * unmap the children of that actor. It is not necessary to call this + * if you implement #ClutterContainer because the default implementation + * will automatically unmap children of containers. + * + * When overriding unmap, it is mandatory to chain up to the parent + * implementation. + * + * Since: 1.0 + */ +void +clutter_actor_unmap (ClutterActor *self) +{ + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + + if (!CLUTTER_ACTOR_IS_MAPPED (self)) + return; + + clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED); +} + static void clutter_actor_real_show (ClutterActor *self) { if (!CLUTTER_ACTOR_IS_VISIBLE (self)) { - if (!CLUTTER_ACTOR_IS_REALIZED (self)) - clutter_actor_realize (self); - - /* the mapped flag on the top-level actors must be set by the - * per-backend implementation because it might be asynchronous + CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE); + /* we notify on the "visible" flag in the clutter_actor_show() + * wrapper so the entire show signal emission completes first + * (?) */ - if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL)) - CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED); - - if (CLUTTER_ACTOR_IS_VISIBLE (self)) - clutter_actor_queue_redraw (self); + clutter_actor_update_map_state (self, MAP_STATE_CHECK); clutter_actor_queue_relayout (self); } @@ -512,6 +991,10 @@ clutter_actor_show (ClutterActor *self) g_return_if_fail (CLUTTER_IS_ACTOR (self)); +#ifdef CLUTTER_ENABLE_DEBUG + clutter_actor_verify_map_state (self); +#endif + priv = self->priv; g_object_freeze_notify (G_OBJECT (self)); @@ -556,11 +1039,13 @@ clutter_actor_real_hide (ClutterActor *self) { if (CLUTTER_ACTOR_IS_VISIBLE (self)) { - /* see comment in clutter_actor_real_show() on why we don't set - * the mapped flag on the top-level actors + CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE); + + /* we notify on the "visible" flag in the clutter_actor_hide() + * wrapper so the entire hide signal emission completes first + * (?) */ - if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL)) - CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED); + clutter_actor_update_map_state (self, MAP_STATE_CHECK); clutter_actor_queue_relayout (self); } @@ -586,6 +1071,10 @@ clutter_actor_hide (ClutterActor *self) g_return_if_fail (CLUTTER_IS_ACTOR (self)); +#ifdef CLUTTER_ENABLE_DEBUG + clutter_actor_verify_map_state (self); +#endif + priv = self->priv; g_object_freeze_notify (G_OBJECT (self)); @@ -596,7 +1085,7 @@ clutter_actor_hide (ClutterActor *self) g_object_notify (G_OBJECT (self), "show-on-set-parent"); } - if (CLUTTER_ACTOR_IS_MAPPED (self)) + if (CLUTTER_ACTOR_IS_VISIBLE (self)) { g_signal_emit (self, actor_signals[HIDE], 0); g_object_notify (G_OBJECT (self), "visible"); @@ -631,44 +1120,239 @@ clutter_actor_hide_all (ClutterActor *self) * * Creates any underlying graphics resources needed by the actor to be * displayed. + * + * Realization means the actor is now tied to a specific rendering context + * (that is, a specific toplevel stage). + * + * This function does nothing if the actor is already realized. + * + * Because a realized actor must have realized parent actors, calling + * clutter_actor_realize() will also realize all parents of the actor. + * + * This function does not realize child actors, except in the special + * case that realizing the stage, when the stage is visible, will + * suddenly map (and thus realize) the children of the stage. **/ void clutter_actor_realize (ClutterActor *self) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); +#ifdef CLUTTER_ENABLE_DEBUG + clutter_actor_verify_map_state (self); +#endif + if (CLUTTER_ACTOR_IS_REALIZED (self)) return; + /* To be realized, our parent actors must be realized first. + * This will only succeed if we're inside a toplevel. + */ + if (self->priv->parent_actor != NULL) + clutter_actor_realize (self->priv->parent_actor); + + if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL) + { + /* toplevels can be realized at any time */ + } + else + { + /* "Fail" the realization if parent is missing or unrealized; + * this should really be a g_warning() not some kind of runtime + * failure; how can an app possibly recover? Instead it's a bug + * in the app and the app should get an explanatory warning so + * someone can fix it. But for now it's too hard to fix this + * because e.g. ClutterTexture needs reworking. + */ + if (self->priv->parent_actor == NULL || + !CLUTTER_ACTOR_IS_REALIZED (self->priv->parent_actor)) + return; + } + + CLUTTER_NOTE (ACTOR, "Realizing actor '%s' [%p]", + self->priv->name ? self->priv->name + : G_OBJECT_TYPE_NAME (self), + self); + CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED); + g_object_notify (G_OBJECT (self), "realized"); g_signal_emit (self, actor_signals[REALIZE], 0); + + /* Stage actor is allowed to unset the realized flag again in its + * default signal handler, though that is a pathological situation. + */ + + /* If realization "failed" we'll have to update child state. */ + clutter_actor_update_map_state (self, MAP_STATE_CHECK); +} + +void +clutter_actor_real_unrealize (ClutterActor *self) +{ + /* we must be unmapped (implying our children are also unmapped) */ + g_assert (!CLUTTER_ACTOR_IS_MAPPED (self)); + + if (CLUTTER_IS_CONTAINER (self)) + clutter_container_foreach_with_internals (CLUTTER_CONTAINER (self), + CLUTTER_CALLBACK (clutter_actor_unrealize_not_hiding), + NULL); } /** * clutter_actor_unrealize: * @self: A #ClutterActor * - * Frees up any underlying graphics resources needed by the actor to be - * displayed. - **/ + * Frees up any underlying graphics resources needed by the actor to + * be displayed. + * + * Unrealization means the actor is now independent of any specific + * rendering context (is not attached to a specific toplevel stage). + * + * Because mapped actors must be realized, actors may not be + * unrealized if they are mapped. This function hides the actor to be + * sure it isn't mapped, an application-visible side effect that you + * may not be expecting. + * + * This function should not really be in the public API, because + * there isn't a good reason to call it. ClutterActor will already + * unrealize things for you when it's important to do so. + * + * If you were using clutter_actor_unrealize() in a dispose + * implementation, then don't, just chain up to ClutterActor's + * dispose. + * + * If you were using clutter_actor_unrealize() to implement + * unrealizing children of your container, then don't, ClutterActor + * will already take care of that. + * + * If you were using clutter_actor_unrealize() to re-realize to + * create your resources in a different way, then use + * _clutter_actor_rerealize() (inside Clutter) or just call your + * code that recreates your resources directly (outside Clutter). + */ void clutter_actor_unrealize (ClutterActor *self) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); + g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self)); + +#ifdef CLUTTER_ENABLE_DEBUG + clutter_actor_verify_map_state (self); +#endif + + clutter_actor_hide (self); + + clutter_actor_unrealize_not_hiding (self); +} + +/** + * clutter_actor_unrealize_not_hiding: + * @self: A #ClutterActor + * + * Frees up any underlying graphics resources needed by the actor to + * be displayed. + * + * Unrealization means the actor is now independent of any specific + * rendering context (is not attached to a specific toplevel stage). + * + * Because mapped actors must be realized, actors may not be + * unrealized if they are mapped. You must hide the actor or one of + * its parents before attempting to unrealize. + * + * This function is separate from clutter_actor_unrealize() because it + * does not automatically hide the actor. + * Actors need not be hidden to be unrealized, they just need to + * be unmapped. In fact we don't want to mess up the application's + * setting of the "visible" flag, so hiding is very undesirable. + * + * clutter_actor_unrealize() does a clutter_actor_hide() just for + * backward compatibility. + */ +static void +clutter_actor_unrealize_not_hiding (ClutterActor *self) +{ + /* All callers of clutter_actor_unrealize_not_hiding() should have + * taken care of unmapping the actor first. This means + * all our children should also be unmapped. + */ + g_assert (!CLUTTER_ACTOR_IS_MAPPED (self)); if (!CLUTTER_ACTOR_IS_REALIZED (self)) return; - /* unrealizing also means hiding a visible actor, exactly - * like showing implies realization if called on an unrealized - * actor. this keeps the flags in sync. + /* The default handler for the signal should recursively unrealize + * child actors. We want to unset the realized flag only _after_ + * child actors are unrealized, to maintain invariants. */ - clutter_actor_hide (self); + + g_signal_emit (self, actor_signals[UNREALIZE], 0); CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED); - g_signal_emit (self, actor_signals[UNREALIZE], 0); + g_object_notify (G_OBJECT (self), "realized"); +} + +/** + * _clutter_actor_rerealize: + * @self: A #ClutterActor + * @callback: Function to call while unrealized + * @data: data for callback + * + * If an actor is already unrealized, this just calls the callback. + * + * If it is realized, it unrealizes temporarily, calls the callback, + * and then re-realizes the actor. + * + * As a side effect, leaves all children of the actor unrealized if + * the actor was realized but not showing. This is because when we + * unrealize the actor temporarily we must unrealize its children + * (e.g. children of a stage can't be realized if stage window is + * gone). And we aren't clever enough to save the realization state of + * all children. In most cases this should not matter, because + * the children will automatically realize when they next become mapped. + */ +void +_clutter_actor_rerealize (ClutterActor *self, + ClutterCallback callback, + void *data) +{ + gboolean was_mapped; + gboolean was_showing; + gboolean was_realized; + + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + +#ifdef CLUTTER_ENABLE_DEBUG + clutter_actor_verify_map_state (self); +#endif + + was_realized = CLUTTER_ACTOR_IS_REALIZED (self); + was_mapped = CLUTTER_ACTOR_IS_MAPPED (self); + was_showing = CLUTTER_ACTOR_IS_VISIBLE (self); + + /* Must be unmapped to unrealize. Note we only have to hide this + * actor if it was mapped (if all parents were showing). If actor + * is merely visible (but not mapped), then that's fine, we can + * leave it visible. + */ + if (was_mapped) + clutter_actor_hide (self); + + g_assert (!CLUTTER_ACTOR_IS_MAPPED (self)); + + /* unrealize self and all children */ + clutter_actor_unrealize_not_hiding (self); + + if (callback != NULL) + { + (* callback) (self, data); + } + + if (was_showing) + clutter_actor_show (self); /* will realize only if mapping implies it */ + else if (was_realized) + clutter_actor_realize (self); /* realize self and all parents */ } static void @@ -685,8 +1369,8 @@ clutter_actor_real_pick (ClutterActor *self, clutter_actor_get_allocation_box (self, &box); - width = CLUTTER_UNITS_TO_FLOAT (box.x2 - box.x1); - height = CLUTTER_UNITS_TO_FLOAT (box.y2 - box.y1); + width = box.x2 - box.x1; + height = box.y2 - box.y1; cogl_set_source_color4ub (color->red, color->green, @@ -758,9 +1442,9 @@ clutter_actor_should_pick_paint (ClutterActor *self) static void clutter_actor_real_get_preferred_width (ClutterActor *self, - ClutterUnit for_height, - ClutterUnit *min_width_p, - ClutterUnit *natural_width_p) + gfloat for_height, + gfloat *min_width_p, + gfloat *natural_width_p) { /* Default implementation is always 0x0, usually an actor * using this default is relying on someone to set the @@ -777,9 +1461,9 @@ clutter_actor_real_get_preferred_width (ClutterActor *self, static void clutter_actor_real_get_preferred_height (ClutterActor *self, - ClutterUnit for_width, - ClutterUnit *min_height_p, - ClutterUnit *natural_height_p) + gfloat for_width, + gfloat *min_height_p, + gfloat *natural_height_p) { /* Default implementation is always 0x0, usually an actor * using this default is relying on someone to set the @@ -806,8 +1490,9 @@ clutter_actor_notify_if_geometry_changed (ClutterActor *self, const ClutterActorBox *old) { ClutterActorPrivate *priv = self->priv; + GObject *obj = G_OBJECT (self); - g_object_freeze_notify (G_OBJECT (self)); + g_object_freeze_notify (obj); /* to avoid excessive requisition or allocation cycles we * use the cached values. @@ -822,20 +1507,20 @@ clutter_actor_notify_if_geometry_changed (ClutterActor *self, */ if (priv->needs_allocation) { - g_object_notify (G_OBJECT (self), "x"); - g_object_notify (G_OBJECT (self), "y"); - g_object_notify (G_OBJECT (self), "width"); - g_object_notify (G_OBJECT (self), "height"); + g_object_notify (obj, "x"); + g_object_notify (obj, "y"); + g_object_notify (obj, "width"); + g_object_notify (obj, "height"); } else if (priv->needs_width_request || priv->needs_height_request) { - g_object_notify (G_OBJECT (self), "width"); - g_object_notify (G_OBJECT (self), "height"); + g_object_notify (obj, "width"); + g_object_notify (obj, "height"); } else { - ClutterUnit xu, yu; - ClutterUnit widthu, heightu; + gfloat xu, yu; + gfloat widthu, heightu; xu = priv->allocation.x1; yu = priv->allocation.y1; @@ -843,28 +1528,29 @@ clutter_actor_notify_if_geometry_changed (ClutterActor *self, heightu = priv->allocation.y2 - priv->allocation.y1; if (xu != old->x1) - g_object_notify (G_OBJECT (self), "x"); + g_object_notify (obj, "x"); if (yu != old->y1) - g_object_notify (G_OBJECT (self), "y"); + g_object_notify (obj, "y"); if (widthu != (old->x2 - old->x1)) - g_object_notify (G_OBJECT (self), "width"); + g_object_notify (obj, "width"); if (heightu != (old->y2 - old->y1)) - g_object_notify (G_OBJECT (self), "height"); + g_object_notify (obj, "height"); } - g_object_thaw_notify (G_OBJECT (self)); + g_object_thaw_notify (obj); } static void -clutter_actor_real_allocate (ClutterActor *self, - const ClutterActorBox *box, - gboolean absolute_origin_changed) +clutter_actor_real_allocate (ClutterActor *self, + const ClutterActorBox *box, + ClutterAllocationFlags flags) { ClutterActorPrivate *priv = self->priv; gboolean x1_changed, y1_changed, x2_changed, y2_changed; + gboolean flags_changed; ClutterActorBox old = { 0, }; clutter_actor_store_old_geometry (self, &old); @@ -874,13 +1560,25 @@ clutter_actor_real_allocate (ClutterActor *self, x2_changed = priv->allocation.x2 != box->x2; y2_changed = priv->allocation.y2 != box->y2; + flags_changed = priv->allocation_flags != flags; + priv->allocation = *box; + priv->allocation_flags = flags; priv->needs_allocation = FALSE; g_object_freeze_notify (G_OBJECT (self)); if (x1_changed || y1_changed || x2_changed || y2_changed) - g_object_notify (G_OBJECT (self), "allocation"); + { + g_object_notify (G_OBJECT (self), "allocation"); + + /* we also emit the ::allocation-changed signal for people + * that wish to track the allocation flags + */ + g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0, + box, + flags); + } clutter_actor_notify_if_geometry_changed (self, &old); @@ -892,7 +1590,7 @@ clutter_actor_queue_redraw_with_origin (ClutterActor *self, ClutterActor *origin) { /* short-circuit the trivial case */ - if (!CLUTTER_ACTOR_IS_VISIBLE(self)) + if (!CLUTTER_ACTOR_IS_MAPPED(self)) return; /* already queued since last paint() */ @@ -910,13 +1608,16 @@ clutter_actor_real_queue_redraw (ClutterActor *self, ClutterActor *parent; /* short-circuit the trivial case */ - if (!CLUTTER_ACTOR_IS_VISIBLE (self)) + if (!CLUTTER_ACTOR_IS_MAPPED (self)) return; /* already queued since last paint() */ if (self->priv->queued_redraw) return; + CLUTTER_NOTE (PAINT, "Redraw queued on '%s'", + clutter_actor_get_name (self) ? clutter_actor_get_name (self) + : G_OBJECT_TYPE_NAME (self)); self->priv->queued_redraw = TRUE; /* notify parents, if they are all visible eventually we'll @@ -943,9 +1644,9 @@ static inline void full_vertex_to_units (const full_vertex_t *f, ClutterVertex *u) { - u->x = CLUTTER_UNITS_FROM_FLOAT (f->x); - u->y = CLUTTER_UNITS_FROM_FLOAT (f->y); - u->z = CLUTTER_UNITS_FROM_FLOAT (f->z); + u->x = f->x; + u->y = f->y; + u->z = f->z; } /* Transforms a vertex using the passed matrix; vertex is @@ -993,7 +1694,7 @@ full_vertex_transform (const CoglMatrix *matrix, } /* scales a fixed @vertex using @matrix and @viewport, and - * transforms the result into ClutterUnits, filling @vertex_p + * transforms the result into a ClutterVertex, filling @vertex_p */ static inline void full_vertex_scale (const CoglMatrix *matrix, @@ -1013,9 +1714,9 @@ full_vertex_scale (const CoglMatrix *matrix, v_width = viewport[2]; v_height = viewport[3]; - tmp.x = MTX_GL_SCALE_X (tmp.x, tmp.w, v_width, v_x); + tmp.x = MTX_GL_SCALE_X (tmp.x, tmp.w, v_width, v_x); tmp.y = MTX_GL_SCALE_Y (tmp.y, tmp.w, v_height, v_y); - tmp.z = MTX_GL_SCALE_Z (tmp.z, tmp.w, v_width, v_x); + tmp.z = MTX_GL_SCALE_Z (tmp.z, tmp.w, v_width, v_x); tmp.w = 0; full_vertex_to_units (&tmp, vertex_p); @@ -1030,18 +1731,18 @@ full_vertex_scale (const CoglMatrix *matrix, static void clutter_actor_transform_point_relative (ClutterActor *actor, ClutterActor *ancestor, - ClutterUnit *x, - ClutterUnit *y, - ClutterUnit *z, - ClutterUnit *w) + gfloat *x, + gfloat *y, + gfloat *z, + gfloat *w) { full_vertex_t vertex = { 0, }; CoglMatrix matrix; - vertex.x = (x != NULL) ? CLUTTER_UNITS_TO_FLOAT (*x) : 0; - vertex.y = (y != NULL) ? CLUTTER_UNITS_TO_FLOAT (*y) : 0; - vertex.z = (z != NULL) ? CLUTTER_UNITS_TO_FLOAT (*z) : 0; - vertex.w = (w != NULL) ? CLUTTER_UNITS_TO_FLOAT (*w) : 0; + vertex.x = (x != NULL) ? *x : 0; + vertex.y = (y != NULL) ? *y : 0; + vertex.z = (z != NULL) ? *z : 0; + vertex.w = (w != NULL) ? *w : 0; cogl_push_matrix(); @@ -1053,16 +1754,16 @@ clutter_actor_transform_point_relative (ClutterActor *actor, cogl_pop_matrix(); if (x) - *x = CLUTTER_UNITS_FROM_FLOAT (vertex.x); + *x = vertex.x; if (y) - *y = CLUTTER_UNITS_FROM_FLOAT (vertex.y); + *y = vertex.y; if (z) - *z = CLUTTER_UNITS_FROM_FLOAT (vertex.z); + *z = vertex.z; if (w) - *w = CLUTTER_UNITS_FROM_FLOAT (vertex.w); + *w = vertex.w; } /* Applies the transforms associated with this actor and its ancestors, @@ -1071,18 +1772,18 @@ clutter_actor_transform_point_relative (ClutterActor *actor, */ static void clutter_actor_transform_point (ClutterActor *actor, - ClutterUnit *x, - ClutterUnit *y, - ClutterUnit *z, - ClutterUnit *w) + gfloat *x, + gfloat *y, + gfloat *z, + gfloat *w) { full_vertex_t vertex = { 0, }; CoglMatrix matrix; - vertex.x = (x != NULL) ? CLUTTER_UNITS_TO_FLOAT (*x) : 0; - vertex.y = (y != NULL) ? CLUTTER_UNITS_TO_FLOAT (*y) : 0; - vertex.z = (z != NULL) ? CLUTTER_UNITS_TO_FLOAT (*z) : 0; - vertex.w = (w != NULL) ? CLUTTER_UNITS_TO_FLOAT (*w) : 0; + vertex.x = (x != NULL) ? *x : 0; + vertex.y = (y != NULL) ? *y : 0; + vertex.z = (z != NULL) ? *z : 0; + vertex.w = (w != NULL) ? *w : 0; cogl_push_matrix(); @@ -1094,16 +1795,16 @@ clutter_actor_transform_point (ClutterActor *actor, cogl_pop_matrix(); if (x) - *x = CLUTTER_UNITS_FROM_FLOAT (vertex.x); + *x = vertex.x; if (y) - *y = CLUTTER_UNITS_FROM_FLOAT (vertex.y); + *y = vertex.y; if (z) - *z = CLUTTER_UNITS_FROM_FLOAT (vertex.z); + *z = vertex.z; if (w) - *w = CLUTTER_UNITS_FROM_FLOAT (vertex.w); + *w = vertex.w; } /** @@ -1131,7 +1832,7 @@ clutter_actor_apply_relative_transform_to_point (ClutterActor *self, const ClutterVertex *point, ClutterVertex *vertex) { - ClutterUnit x, y, z, w; + gfloat x, y, z, w; full_vertex_t tmp; gfloat v[4]; @@ -1179,7 +1880,7 @@ clutter_actor_apply_transform_to_point (ClutterActor *self, ClutterVertex *vertex) { full_vertex_t tmp = { 0, }; - ClutterUnit x, y, z, w; + gfloat x, y, z, w; CoglMatrix matrix_p; gfloat v[4]; @@ -1225,8 +1926,8 @@ clutter_actor_transform_vertices_relative (ClutterActor *self, gfloat width, height; CoglMatrix mtx; - width = CLUTTER_UNITS_TO_FLOAT (priv->allocation.x2 - priv->allocation.x1); - height = CLUTTER_UNITS_TO_FLOAT (priv->allocation.y2 - priv->allocation.y1); + width = priv->allocation.x2 - priv->allocation.x1; + height = priv->allocation.y2 - priv->allocation.y1; cogl_push_matrix(); @@ -1259,8 +1960,8 @@ clutter_actor_transform_and_project_box (ClutterActor *self, gfloat width, height; full_vertex_t vertices[4]; - width = CLUTTER_UNITS_TO_FLOAT (box->x2 - box->x1); - height = CLUTTER_UNITS_TO_FLOAT (box->y2 - box->y1); + width = box->x2 - box->x1; + height = box->y2 - box->y1; /* We essentially have to dupe some code from clutter_redraw() here * to make sure GL Matrices etc are initialised if we're called and we @@ -1272,7 +1973,7 @@ clutter_actor_transform_and_project_box (ClutterActor *self, stage = clutter_actor_get_stage (self); /* FIXME: if were not yet added to a stage, its probably unsafe to - * return default - idealy the func should fail. + * return default - ideally the func should fail */ if (stage == NULL) stage = clutter_stage_get_default (); @@ -1353,7 +2054,7 @@ clutter_actor_get_allocation_vertices (ClutterActor *self, stage = clutter_actor_get_stage (self); /* FIXME: if were not yet added to a stage, its probably unsafe to - * return default - idealy the func should fail. + * return default - idealy the func should fail */ if (stage == NULL) stage = clutter_stage_get_default (); @@ -1433,7 +2134,7 @@ clutter_actor_get_abs_allocation_vertices (ClutterActor *self, ClutterActor *stage = clutter_actor_get_stage (self); /* FIXME: if were not yet added to a stage, its probably unsafe to - * return default - idealy the func should fail. + * return default - idealy the func should fail */ if (stage == NULL) stage = clutter_stage_get_default (); @@ -1459,9 +2160,9 @@ _clutter_actor_apply_modelview_transform (ClutterActor *self) gboolean is_stage = CLUTTER_IS_STAGE (self); if (!is_stage) - cogl_translate (CLUTTER_UNITS_TO_FLOAT (priv->allocation.x1), - CLUTTER_UNITS_TO_FLOAT (priv->allocation.y1), - 0); + cogl_translate (priv->allocation.x1, + priv->allocation.y1, + 0); if (priv->z) cogl_translate (0, 0, priv->z); @@ -1473,29 +2174,33 @@ _clutter_actor_apply_modelview_transform (ClutterActor *self) * entire object will move on the screen as a result of rotating it). */ if (priv->scale_x != 1.0 || priv->scale_y != 1.0) - TRANSFORM_ABOUT_ANCHOR_COORD (self, &priv->scale_center, - cogl_scale (priv->scale_x, - priv->scale_y, - 1.0)); + { + TRANSFORM_ABOUT_ANCHOR_COORD (self, + &priv->scale_center, + cogl_scale (priv->scale_x, + priv->scale_y, + 1.0)); + } if (priv->rzang) - TRANSFORM_ABOUT_ANCHOR_COORD (self, &priv->rz_center, - cogl_rotate (priv->rzang, - 0, 0, 1.0)); + TRANSFORM_ABOUT_ANCHOR_COORD (self, + &priv->rz_center, + cogl_rotate (priv->rzang, 0, 0, 1.0)); if (priv->ryang) - TRANSFORM_ABOUT_ANCHOR_COORD (self, &priv->ry_center, - cogl_rotate (priv->ryang, - 0, 1.0, 0)); + TRANSFORM_ABOUT_ANCHOR_COORD (self, + &priv->ry_center, + cogl_rotate (priv->ryang, 0, 1.0, 0)); if (priv->rxang) - TRANSFORM_ABOUT_ANCHOR_COORD (self, &priv->rx_center, - cogl_rotate (priv->rxang, - 1.0, 0, 0)); + TRANSFORM_ABOUT_ANCHOR_COORD (self, + &priv->rx_center, + cogl_rotate (priv->rxang, 1.0, 0, 0)); if (!is_stage && !clutter_anchor_coord_is_zero (&priv->anchor)) { - ClutterUnit x, y, z; + gfloat x, y, z; + clutter_anchor_coord_get_units (self, &priv->anchor, &x, &y, &z); cogl_translate (-x, -y, -z); } @@ -1527,7 +2232,7 @@ _clutter_actor_apply_modelview_transform_recursive (ClutterActor *self, stage = clutter_actor_get_stage (self); /* FIXME: if were not yet added to a stage, its probably unsafe to - * return default - idealy the func should fail. + * return default - idealy the func should fail */ if (stage == NULL) stage = clutter_stage_get_default (); @@ -1572,17 +2277,11 @@ clutter_actor_paint (ClutterActor *self) return; } - if (!CLUTTER_ACTOR_IS_REALIZED (self)) - { - CLUTTER_NOTE (PAINT, "Attempting realize via paint()"); - clutter_actor_realize(self); - - if (!CLUTTER_ACTOR_IS_REALIZED (self)) - { - CLUTTER_NOTE (PAINT, "Attempt failed, aborting paint"); - return; - } - } + /* if we aren't paintable (not in a toplevel with all + * parents paintable) then do nothing. + */ + if (!CLUTTER_ACTOR_IS_MAPPED (self)) + return; /* mark that we are in the paint process */ CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_IN_PAINT); @@ -1594,22 +2293,20 @@ clutter_actor_paint (ClutterActor *self) if (priv->has_clip) { - cogl_clip_push (CLUTTER_UNITS_TO_FLOAT (priv->clip[0]), - CLUTTER_UNITS_TO_FLOAT (priv->clip[1]), - CLUTTER_UNITS_TO_FLOAT (priv->clip[2]), - CLUTTER_UNITS_TO_FLOAT (priv->clip[3])); + cogl_clip_push (priv->clip[0], + priv->clip[1], + priv->clip[2], + priv->clip[3]); clip_set = TRUE; } else if (priv->clip_to_allocation) { - ClutterUnit width, height; + gfloat width, height; width = priv->allocation.x2 - priv->allocation.x1; height = priv->allocation.y2 - priv->allocation.y1; - cogl_clip_push (0, 0, - CLUTTER_UNITS_TO_FLOAT (width), - CLUTTER_UNITS_TO_FLOAT (height)); + cogl_clip_push (0, 0, width, height); clip_set = TRUE; } @@ -1688,131 +2385,157 @@ clutter_actor_set_property (GObject *object, const GValue *value, GParamSpec *pspec) { - - ClutterActor *actor; - ClutterActorPrivate *priv; - - actor = CLUTTER_ACTOR(object); - priv = actor->priv; + ClutterActor *actor = CLUTTER_ACTOR (object); + ClutterActorPrivate *priv = actor->priv; switch (prop_id) { case PROP_X: - clutter_actor_set_x (actor, g_value_get_int (value)); + clutter_actor_set_x (actor, g_value_get_float (value)); break; + case PROP_Y: - clutter_actor_set_y (actor, g_value_get_int (value)); + clutter_actor_set_y (actor, g_value_get_float (value)); break; + case PROP_WIDTH: - clutter_actor_set_width (actor, g_value_get_int (value)); + clutter_actor_set_width (actor, g_value_get_float (value)); break; + case PROP_HEIGHT: - clutter_actor_set_height (actor, g_value_get_int (value)); + clutter_actor_set_height (actor, g_value_get_float (value)); break; + case PROP_FIXED_X: - clutter_actor_set_xu (actor, clutter_value_get_unit (value)); + clutter_actor_set_x (actor, g_value_get_float (value)); break; + case PROP_FIXED_Y: - clutter_actor_set_yu (actor, clutter_value_get_unit (value)); + clutter_actor_set_y (actor, g_value_get_float (value)); break; + case PROP_FIXED_POSITION_SET: clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value)); break; + case PROP_MIN_WIDTH: - clutter_actor_set_min_width (actor, clutter_value_get_unit (value)); + clutter_actor_set_min_width (actor, g_value_get_float (value)); break; + case PROP_MIN_HEIGHT: - clutter_actor_set_min_height (actor, clutter_value_get_unit (value)); + clutter_actor_set_min_height (actor, g_value_get_float (value)); break; + case PROP_NATURAL_WIDTH: - clutter_actor_set_natural_width (actor, clutter_value_get_unit (value)); + clutter_actor_set_natural_width (actor, g_value_get_float (value)); break; + case PROP_NATURAL_HEIGHT: - clutter_actor_set_natural_height (actor, clutter_value_get_unit (value)); + clutter_actor_set_natural_height (actor, g_value_get_float (value)); break; + case PROP_MIN_WIDTH_SET: clutter_actor_set_min_width_set (actor, g_value_get_boolean (value)); break; + case PROP_MIN_HEIGHT_SET: clutter_actor_set_min_height_set (actor, g_value_get_boolean (value)); break; + case PROP_NATURAL_WIDTH_SET: clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value)); break; + case PROP_NATURAL_HEIGHT_SET: clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value)); break; + case PROP_REQUEST_MODE: clutter_actor_set_request_mode (actor, g_value_get_enum (value)); break; + case PROP_DEPTH: - clutter_actor_set_depth (actor, g_value_get_int (value)); + clutter_actor_set_depth (actor, g_value_get_float (value)); break; + case PROP_OPACITY: clutter_actor_set_opacity (actor, g_value_get_uchar (value)); break; + case PROP_NAME: clutter_actor_set_name (actor, g_value_get_string (value)); break; + case PROP_VISIBLE: if (g_value_get_boolean (value) == TRUE) clutter_actor_show (actor); else clutter_actor_hide (actor); break; + case PROP_SCALE_X: clutter_actor_set_scale (actor, g_value_get_double (value), priv->scale_y); break; + case PROP_SCALE_Y: clutter_actor_set_scale (actor, priv->scale_x, g_value_get_double (value)); break; + case PROP_SCALE_CENTER_X: { - int center_x = g_value_get_int (value); - ClutterUnit center_y; + gfloat center_x = g_value_get_float (value); + gfloat center_y; clutter_anchor_coord_get_units (actor, &priv->scale_center, - NULL, ¢er_y, NULL); - clutter_actor_set_scale_fullu (actor, - priv->scale_x, - priv->scale_y, - CLUTTER_UNITS_FROM_DEVICE (center_x), - center_y); + NULL, + ¢er_y, + NULL); + clutter_actor_set_scale_full (actor, + priv->scale_x, + priv->scale_y, + center_x, + center_y); } break; + case PROP_SCALE_CENTER_Y: { - ClutterUnit center_x; - gint center_y = g_value_get_int (value); + gfloat center_y = g_value_get_float (value); + gfloat center_x; clutter_anchor_coord_get_units (actor, &priv->scale_center, - ¢er_x, NULL, NULL); - clutter_actor_set_scale_fullu (actor, - priv->scale_x, - priv->scale_y, - center_x, - CLUTTER_UNITS_FROM_DEVICE (center_y)); + ¢er_x, + NULL, + NULL); + clutter_actor_set_scale_full (actor, + priv->scale_x, + priv->scale_y, + center_x, + center_y); } break; + case PROP_SCALE_GRAVITY: clutter_actor_set_scale_with_gravity (actor, priv->scale_x, priv->scale_y, g_value_get_enum (value)); break; + case PROP_CLIP: { - ClutterGeometry *geom = g_value_get_boxed (value); + const ClutterGeometry *geom = g_value_get_boxed (value); clutter_actor_set_clip (actor, geom->x, geom->y, geom->width, geom->height); } break; + case PROP_CLIP_TO_ALLOCATION: if (priv->clip_to_allocation != g_value_get_boolean (value)) { @@ -1820,24 +2543,29 @@ clutter_actor_set_property (GObject *object, clutter_actor_queue_redraw (actor); } break; + case PROP_REACTIVE: clutter_actor_set_reactive (actor, g_value_get_boolean (value)); break; + case PROP_ROTATION_ANGLE_X: clutter_actor_set_rotation_internal (actor, CLUTTER_X_AXIS, g_value_get_double (value)); break; + case PROP_ROTATION_ANGLE_Y: clutter_actor_set_rotation_internal (actor, CLUTTER_Y_AXIS, g_value_get_double (value)); break; + case PROP_ROTATION_ANGLE_Z: clutter_actor_set_rotation_internal (actor, CLUTTER_Z_AXIS, g_value_get_double (value)); break; + case PROP_ROTATION_CENTER_X: { const ClutterVertex *center; @@ -1851,6 +2579,7 @@ clutter_actor_set_property (GObject *object, center->z); } break; + case PROP_ROTATION_CENTER_Y: { const ClutterVertex *center; @@ -1864,6 +2593,7 @@ clutter_actor_set_property (GObject *object, center->z); } break; + case PROP_ROTATION_CENTER_Z: { const ClutterVertex *center; @@ -1877,41 +2607,47 @@ clutter_actor_set_property (GObject *object, center->z); } break; + case PROP_ROTATION_CENTER_Z_GRAVITY: - clutter_actor_set_z_rotation_from_gravity - (actor, priv->rzang, g_value_get_enum (value)); + clutter_actor_set_z_rotation_from_gravity (actor, priv->rzang, + g_value_get_enum (value)); break; + case PROP_ANCHOR_X: { - int anchor_x = g_value_get_int (value); - ClutterUnit anchor_y; + gfloat anchor_x = g_value_get_float (value); + gfloat anchor_y; clutter_anchor_coord_get_units (actor, &priv->anchor, - NULL, &anchor_y, NULL); - clutter_actor_set_anchor_pointu (actor, - CLUTTER_UNITS_FROM_DEVICE (anchor_x), - anchor_y); + NULL, + &anchor_y, + NULL); + clutter_actor_set_anchor_point (actor, anchor_x, anchor_y); } break; + case PROP_ANCHOR_Y: { - ClutterUnit anchor_x; - int anchor_y = g_value_get_int (value); + gfloat anchor_y = g_value_get_float (value); + gfloat anchor_x; clutter_anchor_coord_get_units (actor, &priv->anchor, - &anchor_x, NULL, NULL); - clutter_actor_set_anchor_pointu (actor, - anchor_x, - CLUTTER_UNITS_FROM_DEVICE (anchor_y)); + &anchor_x, + NULL, + NULL); + clutter_actor_set_anchor_point (actor, anchor_x, anchor_y); } break; + case PROP_ANCHOR_GRAVITY: clutter_actor_set_anchor_point_from_gravity (actor, g_value_get_enum (value)); break; + case PROP_SHOW_ON_SET_PARENT: priv->show_on_set_parent = g_value_get_boolean (value); break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1924,186 +2660,247 @@ clutter_actor_get_property (GObject *object, GValue *value, GParamSpec *pspec) { - ClutterActor *actor; - ClutterActorPrivate *priv; - - actor = CLUTTER_ACTOR(object); - priv = actor->priv; + ClutterActor *actor = CLUTTER_ACTOR (object); + ClutterActorPrivate *priv = actor->priv; switch (prop_id) { case PROP_X: - g_value_set_int (value, clutter_actor_get_x (actor)); + g_value_set_float (value, clutter_actor_get_x (actor)); break; + case PROP_Y: - g_value_set_int (value, clutter_actor_get_y (actor)); + g_value_set_float (value, clutter_actor_get_y (actor)); break; + case PROP_WIDTH: - g_value_set_int (value, clutter_actor_get_width (actor)); + g_value_set_float (value, clutter_actor_get_width (actor)); break; + case PROP_HEIGHT: - g_value_set_int (value, clutter_actor_get_height (actor)); + g_value_set_float (value, clutter_actor_get_height (actor)); break; + case PROP_FIXED_X: - clutter_value_set_unit (value, priv->fixed_x); + g_value_set_float (value, priv->fixed_x); break; + case PROP_FIXED_Y: - clutter_value_set_unit (value, priv->fixed_y); + g_value_set_float (value, priv->fixed_y); break; + case PROP_FIXED_POSITION_SET: g_value_set_boolean (value, priv->position_set); break; + case PROP_MIN_WIDTH: - clutter_value_set_unit (value, priv->request_min_width); + g_value_set_float (value, priv->request_min_width); break; + case PROP_MIN_HEIGHT: - clutter_value_set_unit (value, priv->request_min_height); + g_value_set_float (value, priv->request_min_height); break; + case PROP_NATURAL_WIDTH: - clutter_value_set_unit (value, priv->request_natural_width); + g_value_set_float (value, priv->request_natural_width); break; + case PROP_NATURAL_HEIGHT: - clutter_value_set_unit (value, priv->request_natural_height); + g_value_set_float (value, priv->request_natural_height); break; + case PROP_MIN_WIDTH_SET: g_value_set_boolean (value, priv->min_width_set); break; + case PROP_MIN_HEIGHT_SET: g_value_set_boolean (value, priv->min_height_set); break; + case PROP_NATURAL_WIDTH_SET: g_value_set_boolean (value, priv->natural_width_set); break; + case PROP_NATURAL_HEIGHT_SET: g_value_set_boolean (value, priv->natural_height_set); break; + case PROP_REQUEST_MODE: g_value_set_enum (value, priv->request_mode); break; + case PROP_ALLOCATION: g_value_set_boxed (value, &priv->allocation); break; + case PROP_DEPTH: - g_value_set_int (value, clutter_actor_get_depth (actor)); + g_value_set_float (value, clutter_actor_get_depth (actor)); break; + case PROP_OPACITY: g_value_set_uchar (value, priv->opacity); break; + case PROP_NAME: g_value_set_string (value, priv->name); break; + case PROP_VISIBLE: - g_value_set_boolean (value, - (CLUTTER_ACTOR_IS_VISIBLE (actor) != FALSE)); + g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor)); break; + + case PROP_MAPPED: + g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor)); + break; + + case PROP_REALIZED: + g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor)); + break; + case PROP_HAS_CLIP: g_value_set_boolean (value, priv->has_clip); break; + case PROP_CLIP: { ClutterGeometry clip = { 0, }; - clip.x = CLUTTER_UNITS_TO_DEVICE (priv->clip[0]); - clip.y = CLUTTER_UNITS_TO_DEVICE (priv->clip[1]); - clip.width = CLUTTER_UNITS_TO_DEVICE (priv->clip[2]); - clip.height = CLUTTER_UNITS_TO_DEVICE (priv->clip[3]); + clip.x = priv->clip[0]; + clip.y = priv->clip[1]; + clip.width = priv->clip[2]; + clip.height = priv->clip[3]; g_value_set_boxed (value, &clip); } break; + case PROP_CLIP_TO_ALLOCATION: g_value_set_boolean (value, priv->clip_to_allocation); break; + case PROP_SCALE_X: g_value_set_double (value, priv->scale_x); break; + case PROP_SCALE_Y: g_value_set_double (value, priv->scale_y); break; + case PROP_SCALE_CENTER_X: { - gint center; + gfloat center; + clutter_actor_get_scale_center (actor, ¢er, NULL); - g_value_set_int (value, center); + + g_value_set_float (value, center); } break; + case PROP_SCALE_CENTER_Y: { - gint center; + gfloat center; + clutter_actor_get_scale_center (actor, NULL, ¢er); - g_value_set_int (value, center); + + g_value_set_float (value, center); } break; + case PROP_SCALE_GRAVITY: g_value_set_enum (value, clutter_actor_get_scale_gravity (actor)); break; + case PROP_REACTIVE: g_value_set_boolean (value, clutter_actor_get_reactive (actor)); break; + case PROP_ROTATION_ANGLE_X: g_value_set_double (value, priv->rxang); break; + case PROP_ROTATION_ANGLE_Y: g_value_set_double (value, priv->ryang); break; + case PROP_ROTATION_ANGLE_Z: g_value_set_double (value, priv->rzang); break; + case PROP_ROTATION_CENTER_X: { ClutterVertex center; - clutter_actor_get_rotationu (actor, CLUTTER_X_AXIS, - ¢er.x, ¢er.y, ¢er.z); + clutter_actor_get_rotation (actor, CLUTTER_X_AXIS, + ¢er.x, + ¢er.y, + ¢er.z); g_value_set_boxed (value, ¢er); } break; + case PROP_ROTATION_CENTER_Y: { ClutterVertex center; - clutter_actor_get_rotationu (actor, CLUTTER_Y_AXIS, - ¢er.x, ¢er.y, ¢er.z); + clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS, + ¢er.x, + ¢er.y, + ¢er.z); g_value_set_boxed (value, ¢er); } break; + case PROP_ROTATION_CENTER_Z: { ClutterVertex center; - clutter_actor_get_rotationu (actor, CLUTTER_Z_AXIS, - ¢er.x, ¢er.y, ¢er.z); + clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS, + ¢er.x, + ¢er.y, + ¢er.z); g_value_set_boxed (value, ¢er); } break; + case PROP_ROTATION_CENTER_Z_GRAVITY: g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor)); break; + case PROP_ANCHOR_X: { - ClutterUnit anchor_x; + gfloat anchor_x; + clutter_anchor_coord_get_units (actor, &priv->anchor, - &anchor_x, NULL, NULL); - g_value_set_int (value, CLUTTER_UNITS_TO_DEVICE (anchor_x)); + &anchor_x, + NULL, + NULL); + g_value_set_float (value, anchor_x); } break; + case PROP_ANCHOR_Y: { - ClutterUnit anchor_y; + gfloat anchor_y; + clutter_anchor_coord_get_units (actor, &priv->anchor, - NULL, &anchor_y, NULL); - g_value_set_int (value, CLUTTER_UNITS_TO_DEVICE (anchor_y)); + NULL, + &anchor_y, + NULL); + g_value_set_float (value, anchor_y); } break; + case PROP_ANCHOR_GRAVITY: g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor)); break; + case PROP_SHOW_ON_SET_PARENT: g_value_set_boolean (value, priv->show_on_set_parent); break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -2122,7 +2919,7 @@ clutter_actor_dispose (GObject *object) object->ref_count); /* avoid recursing when called from clutter_actor_destroy() */ - if (priv->parent_actor) + if (priv->parent_actor != NULL) { ClutterActor *parent = priv->parent_actor; @@ -2132,7 +2929,15 @@ clutter_actor_dispose (GObject *object) priv->parent_actor = NULL; } - clutter_actor_unrealize (self); + /* parent should be gone */ + g_assert (priv->parent_actor == NULL); + + if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL)) + { + /* can't be mapped or realized with no parent */ + g_assert (!CLUTTER_ACTOR_IS_MAPPED (self)); + g_assert (!CLUTTER_ACTOR_IS_REALIZED (self)); + } destroy_shader_data (self); @@ -2182,14 +2987,14 @@ clutter_actor_class_init (ClutterActorClass *klass) * position for the actor. If read, returns the fixed position if any, * otherwise the allocation if available, otherwise 0. */ - g_object_class_install_property (object_class, - PROP_X, - g_param_spec_int ("x", - "X coordinate", - "X coordinate of the actor", - -G_MAXINT, G_MAXINT, - 0, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_float ("x", + "X coordinate", + "X coordinate of the actor", + -G_MAXFLOAT, G_MAXFLOAT, + 0.0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_X, pspec); + /** * ClutterActor:y: * @@ -2197,14 +3002,14 @@ clutter_actor_class_init (ClutterActorClass *klass) * position for the actor. If read, returns the fixed position if * any, otherwise the allocation if available, otherwise 0. */ - g_object_class_install_property (object_class, - PROP_Y, - g_param_spec_int ("y", - "Y coordinate", - "Y coordinate of the actor", - -G_MAXINT, G_MAXINT, - 0, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_float ("y", + "Y coordinate", + "Y coordinate of the actor", + -G_MAXFLOAT, G_MAXFLOAT, + 0.0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_Y, pspec); + /** * ClutterActor:width: * @@ -2212,14 +3017,13 @@ clutter_actor_class_init (ClutterActorClass *klass) * natural size request of the actor to the given width. If read, returns * the allocated width if available, otherwise the width request. */ - g_object_class_install_property (object_class, - PROP_WIDTH, - g_param_spec_int ("width", - "Width", - "Width of the actor", - 0, G_MAXINT, - 0, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_float ("width", + "Width", + "Width of the actor", + 0.0, G_MAXFLOAT, + 0.0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_WIDTH, pspec); /** * ClutterActor:height: * @@ -2227,217 +3031,226 @@ clutter_actor_class_init (ClutterActorClass *klass) * natural size request of the actor to the given height. If read, returns * the allocated height if available, otherwise the height request. */ + pspec = g_param_spec_float ("height", + "Height", + "Height of the actor", + 0.0, G_MAXFLOAT, + 0.0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_HEIGHT, pspec); + + /** + * ClutterActor:fixed-x: + * + * The fixed X position of the actor in pixels. + * + * Writing this property sets #ClutterActor:fixed-position-set + * property as well, as a side effect + * + * Since: 0.8 + */ + pspec = g_param_spec_float ("fixed-x", + "Fixed X", + "Forced X position of the actor", + -G_MAXFLOAT, G_MAXFLOAT, + 0.0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_FIXED_X, pspec); + + /** + * ClutterActor:fixed-y: + * + * The fixed Y position of the actor in pixels. + * + * Writing this property sets the #ClutterActor:fixed-position-set + * property as well, as a side effect + * + * Since: 0.8 + */ + pspec = g_param_spec_float ("fixed-y", + "Fixed Y", + "Forced Y position of the actor", + -G_MAXFLOAT, G_MAXFLOAT, + 0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_FIXED_Y, pspec); + + /** + * ClutterActor:fixed-position-set: + * + * This flag controls whether the #ClutterActor:fixed-x and + * #ClutterActor:fixed-y properties are used + * + * Since: 0.8 + */ + pspec = g_param_spec_boolean ("fixed-position-set", + "Fixed position set", + "Whether to use fixed positioning " + "for the actor", + FALSE, + CLUTTER_PARAM_READWRITE); g_object_class_install_property (object_class, - PROP_HEIGHT, - g_param_spec_int ("height", - "Height", - "Height of the actor", - 0, G_MAXINT, - 0, - CLUTTER_PARAM_READWRITE)); + PROP_FIXED_POSITION_SET, + pspec); /** - * ClutterActor:fixed-x + * ClutterActor:min-width: * - * The fixed X position of the actor in ClutterUnits. Writing this - * property sets the fixed-position-set property as well, as a side effect. + * A forced minimum width request for the actor, in pixels + * + * Writing this property sets the #ClutterActor:min-width-set property + * as well, as a side effect. + * + *This property overrides the usual width request of the actor. * * Since: 0.8 */ - g_object_class_install_property - (object_class, - PROP_FIXED_X, - clutter_param_spec_unit ("fixed-x", - "Fixed X", - "Forced X position of the actor", - CLUTTER_MINUNIT, CLUTTER_MAXUNIT, - 0, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_float ("min-width", + "Min Width", + "Forced minimum width request for the actor", + 0.0, G_MAXFLOAT, + 0.0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_MIN_WIDTH, pspec); /** - * ClutterActor:fixed-y + * ClutterActor:min-height: * - * The fixed Y position of the actor in ClutterUnits. Writing - * this property sets the fixed-position-set property as well, as a side - * effect. + * A forced minimum height request for the actor, in pixels + * + * Writing this property sets the #ClutterActor:min-height-set property + * as well, as a side effect. This property overrides the usual height + * request of the actor. * * Since: 0.8 */ - g_object_class_install_property - (object_class, - PROP_FIXED_Y, - clutter_param_spec_unit ("fixed-y", - "Fixed Y", - "Forced Y position of the actor", - CLUTTER_MINUNIT, CLUTTER_MAXUNIT, - 0, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_float ("min-height", + "Min Height", + "Forced minimum height request for the actor", + 0.0, G_MAXFLOAT, + 0.0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_MIN_HEIGHT, pspec); + /** - * ClutterActor:fixed-position-set + * ClutterActor:natural-width: * - * This flag controls whether the fixed-x and fixed-y properties are used. + * A forced natural width request for the actor, in pixels + * + * Writing this property sets the #ClutterActor:natural-width-set + * property as well, as a side effect. This property overrides the + * usual width request of the actor * * Since: 0.8 */ - g_object_class_install_property - (object_class, - PROP_FIXED_POSITION_SET, - g_param_spec_boolean ("fixed-position-set", - "Fixed position set", - "Whether to use fixed positioning for the actor", - FALSE, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_float ("natural-width", + "Natural Width", + "Forced natural width request for the actor", + 0.0, G_MAXFLOAT, + 0.0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_NATURAL_WIDTH, pspec); + /** - * ClutterActor:min-width + * ClutterActor:natural-height: * - * A forced minimum width request for the actor, in ClutterUnits. - * Writing this property sets the min-width-set property as well, as a side - * effect. This property overrides the usual width request of the actor. + * A forced natural height request for the actor, in pixels + * + * Writing this property sets the #ClutterActor:natural-height-set + * property as well, as a side effect. This property overrides the + * usual height request of the actor * * Since: 0.8 */ - g_object_class_install_property - (object_class, - PROP_MIN_WIDTH, - clutter_param_spec_unit ("min-width", - "Min Width", - "Forced minimum width request for the actor", - 0, CLUTTER_MAXUNIT, - 0, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_float ("natural-height", + "Natural Height", + "Forced natural height request for the actor", + 0.0, G_MAXFLOAT, + 0.0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_NATURAL_HEIGHT, pspec); + /** - * ClutterActor:min-height + * ClutterActor:min-width-set: * - * A forced minimum height request for the actor, in - * ClutterUnits. Writing this property sets the min-height-set - * property as well, as a side effect. This property overrides the usual - * height request of the actor. + * This flag controls whether the #ClutterActor:min-width property + * is used * * Since: 0.8 */ - g_object_class_install_property - (object_class, - PROP_MIN_HEIGHT, - clutter_param_spec_unit ("min-height", - "Min Height", - "Forced minimum height request for the actor", - 0, CLUTTER_MAXUNIT, - 0, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_boolean ("min-width-set", + "Minimum width set", + "Whether to use the min-width property", + FALSE, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_MIN_WIDTH_SET, pspec); + /** - * ClutterActor:natural-width + * ClutterActor:min-height-set: * - * A forced natural width request for the actor, in ClutterUnits. - * Writing this property sets the natural-width-set property as - * well, as a side effect. This property overrides the usual width request - * of the actor. + * This flag controls whether the #ClutterActor:min-height property + * is used * * Since: 0.8 */ - g_object_class_install_property - (object_class, - PROP_NATURAL_WIDTH, - clutter_param_spec_unit ("natural-width", - "Natural Width", - "Forced natural width request for the actor", - 0, CLUTTER_MAXUNIT, - 0, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_boolean ("min-height-set", + "Minimum height set", + "Whether to use the min-height property", + FALSE, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_MIN_HEIGHT_SET, pspec); + /** - * ClutterActor:natural-height + * ClutterActor:natural-width-set: * - * A forced natural height request for the actor, in ClutterUnits. - * Writing this property sets the natural-height-set property as well, as - * a side effect. This property overrides the usual height request - * of the actor. + * This flag controls whether the #ClutterActor:natural-width property + * is used * * Since: 0.8 */ - g_object_class_install_property - (object_class, - PROP_NATURAL_HEIGHT, - clutter_param_spec_unit ("natural-height", - "Natural Height", - "Forced natural height request for the actor", - 0, CLUTTER_MAXUNIT, - 0, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_boolean ("natural-width-set", + "Natural width set", + "Whether to use the natural-width property", + FALSE, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, + PROP_NATURAL_WIDTH_SET, + pspec); + /** - * ClutterActor:min-width-set + * ClutterActor:natural-height-set: * - * This flag controls whether the min-width property is used. + * This flag controls whether the #ClutterActor:natural-height property + * is used * * Since: 0.8 */ - g_object_class_install_property - (object_class, - PROP_MIN_WIDTH_SET, - g_param_spec_boolean ("min-width-set", - "Minimum width set", - "Whether to use the min-width property", - FALSE, - CLUTTER_PARAM_READWRITE)); - /** - * ClutterActor:min-height-set - * - * This flag controls whether the min-height property is used. - * - * Since: 0.8 - */ - g_object_class_install_property - (object_class, - PROP_MIN_HEIGHT_SET, - g_param_spec_boolean ("min-height-set", - "Minimum height set", - "Whether to use the min-height property", - FALSE, - CLUTTER_PARAM_READWRITE)); - /** - * ClutterActor:natural-width-set - * - * This flag controls whether the natural-width property is used. - * - * Since: 0.8 - */ - g_object_class_install_property - (object_class, - PROP_NATURAL_WIDTH_SET, - g_param_spec_boolean ("natural-width-set", - "Natural width set", - "Whether to use the natural-width property", - FALSE, - CLUTTER_PARAM_READWRITE)); - /** - * ClutterActor:natural-height-set - * - * This flag controls whether the natural-height property is used. - * - * Since: 0.8 - */ - g_object_class_install_property - (object_class, - PROP_NATURAL_HEIGHT_SET, - g_param_spec_boolean ("natural-height-set", - "Natural height set", - "Whether to use the natural-height property", - FALSE, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_boolean ("natural-height-set", + "Natural height set", + "Whether to use the natural-height property", + FALSE, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, + PROP_NATURAL_HEIGHT_SET, + pspec); + /** * ClutterActor:allocation: * - * The allocation for the actor, in ClutterUnits. This is - * read-only, but you might monitor this property to know when an - * actor moves or resizes. + * The allocation for the actor, in pixels + * + * This is property is read-only, but you might monitor it to know when an + * actor moves or resizes * * Since: 0.8 */ - g_object_class_install_property (object_class, - PROP_ALLOCATION, - g_param_spec_boxed ("allocation", - "Allocation", - "The actor's allocation", - CLUTTER_TYPE_ACTOR_BOX, - CLUTTER_PARAM_READABLE)); + pspec = g_param_spec_boxed ("allocation", + "Allocation", + "The actor's allocation", + CLUTTER_TYPE_ACTOR_BOX, + CLUTTER_PARAM_READABLE); + g_object_class_install_property (object_class, PROP_ALLOCATION, pspec); + /** * ClutterActor:request-mode: * @@ -2455,8 +3268,8 @@ clutter_actor_class_init (ClutterActorClass *klass) * * |[ * ClutterRequestMode mode; - * ClutterUnit natural_width, min_width; - * ClutterUnit natural_height, min_height; + * gfloat natural_width, min_width; + * gfloat natural_height, min_height; * * g_object_get (G_OBJECT (child), "request-mode", &mode, NULL); * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH) @@ -2487,112 +3300,143 @@ clutter_actor_class_init (ClutterActorClass *klass) * * Since: 0.8 */ - g_object_class_install_property (object_class, - PROP_REQUEST_MODE, - g_param_spec_enum ("request-mode", - "Request Mode", - "The actor's request mode", - CLUTTER_TYPE_REQUEST_MODE, - CLUTTER_REQUEST_HEIGHT_FOR_WIDTH, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_enum ("request-mode", + "Request Mode", + "The actor's request mode", + CLUTTER_TYPE_REQUEST_MODE, + CLUTTER_REQUEST_HEIGHT_FOR_WIDTH, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_REQUEST_MODE, pspec); /** * ClutterActor:depth: * - * Depth of the actor. + * The position of the actor on the Z axis * * Since: 0.6 */ - g_object_class_install_property (object_class, - PROP_DEPTH, - g_param_spec_int ("depth", - "Depth", - "Depth of actor", - -G_MAXINT, G_MAXINT, - 0, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_float ("depth", + "Depth", + "Position on the Z axis", + -G_MAXFLOAT, G_MAXFLOAT, + 0.0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_DEPTH, pspec); + /** * ClutterActor:opacity: * - * Opacity of the actor. + * Opacity of the actor, between 0 (fully transparent) and + * 255 (fully opaque) */ - g_object_class_install_property (object_class, - PROP_OPACITY, - g_param_spec_uchar ("opacity", - "Opacity", - "Opacity of actor", - 0, 0xff, - 0xff, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_uchar ("opacity", + "Opacity", + "Opacity of actor", + 0, 255, + 255, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_OPACITY, pspec); + /** * ClutterActor:visible: * - * Whether the actor is visible or not. + * Whether the actor is set to be visible or not + * + * See also #ClutterActor:mapped */ - g_object_class_install_property (object_class, - PROP_VISIBLE, - g_param_spec_boolean ("visible", - "Visible", - "Whether the actor is visible or not", - FALSE, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_boolean ("visible", + "Visible", + "Whether the actor is visible or not", + FALSE, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_VISIBLE, pspec); + + /** + * ClutterActor:mapped: + * + * Whether the actor is mapped (will be painted when the stage + * to which it belongs is mapped) + * + * Since: 1.0 + */ + pspec = g_param_spec_boolean ("mapped", + "Mapped", + "Whether the actor will be painted", + FALSE, + CLUTTER_PARAM_READABLE); + g_object_class_install_property (object_class, PROP_MAPPED, pspec); + + /** + * ClutterActor:realized: + * + * Whether the actor has been realized + * + * Since: 1.0 + */ + pspec = g_param_spec_boolean ("realized", + "Realized", + "Whether the actor has been realized", + FALSE, + CLUTTER_PARAM_READABLE); + g_object_class_install_property (object_class, PROP_REALIZED, pspec); + /** * ClutterActor:reactive: * - * Whether the actor is reactive to events or not. + * Whether the actor is reactive to events or not + * + * Only reactive actors will emit event-related signals * * Since: 0.6 */ - g_object_class_install_property (object_class, - PROP_REACTIVE, - g_param_spec_boolean ("reactive", - "Reactive", - "Whether the actor " - "is reactive to " - "events or not", - FALSE, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_boolean ("reactive", + "Reactive", + "Whether the actor is reactive to events", + FALSE, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_REACTIVE, pspec); + /** * ClutterActor:has-clip: * - * Whether the actor has the clip property set or not. + * Whether the actor has the #ClutterActor:clip property set or not */ - g_object_class_install_property (object_class, - PROP_HAS_CLIP, - g_param_spec_boolean ("has-clip", - "Has Clip", - "Whether the actor " - "has a clip set or " - "not", - FALSE, - CLUTTER_PARAM_READABLE)); + pspec = g_param_spec_boolean ("has-clip", + "Has Clip", + "Whether the actor has a clip set", + FALSE, + CLUTTER_PARAM_READABLE); + g_object_class_install_property (object_class, PROP_HAS_CLIP, pspec); + /** * ClutterActor:clip: * - * The clip region for the actor. + * The clip region for the actor, in actor-relative coordinates + * + * Every part of the actor outside the clip region will not be + * painted */ - g_object_class_install_property (object_class, - PROP_CLIP, - g_param_spec_boxed ("clip", - "Clip", - "The clip region for " - "the actor", - CLUTTER_TYPE_GEOMETRY, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_boxed ("clip", + "Clip", + "The clip region for the actor", + CLUTTER_TYPE_GEOMETRY, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_CLIP, pspec); + /** * ClutterActor:name: * - * The name of the actor. + * The name of the actor * * Since: 0.2 */ - g_object_class_install_property (object_class, - PROP_NAME, - g_param_spec_string ("name", - "Name", - "Name of the actor", - NULL, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_string ("name", + "Name", + "Name of the actor", + NULL, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_NAME, pspec); + /** * ClutterActor:scale-x: * @@ -2600,16 +3444,14 @@ clutter_actor_class_init (ClutterActorClass *klass) * * Since: 0.6 */ - g_object_class_install_property - (object_class, - PROP_SCALE_X, - g_param_spec_double ("scale-x", - "Scale-X", - "Scale factor on the X axis", - 0.0, - G_MAXDOUBLE, - 1.0, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_double ("scale-x", + "Scale X", + "Scale factor on the X axis", + 0.0, G_MAXDOUBLE, + 1.0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_SCALE_X, pspec); + /** * ClutterActor:scale-y: * @@ -2617,16 +3459,13 @@ clutter_actor_class_init (ClutterActorClass *klass) * * Since: 0.6 */ - g_object_class_install_property - (object_class, - PROP_SCALE_Y, - g_param_spec_double ("scale-y", - "Scale-Y", - "Scale factor on the Y axis", - 0.0, - G_MAXDOUBLE, - 1.0, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_double ("scale-y", + "Scale Y", + "Scale factor on the Y axis", + 0.0, G_MAXDOUBLE, + 1.0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_SCALE_Y, pspec); /** * ClutterActor:scale-center-x: @@ -2635,11 +3474,12 @@ clutter_actor_class_init (ClutterActorClass *klass) * * Since: 1.0 */ - pspec = g_param_spec_int ("scale-center-x", - "Scale-Center-X", - "Horizontal scale center", - G_MININT, G_MAXINT, 0, - CLUTTER_PARAM_READWRITE); + pspec = g_param_spec_float ("scale-center-x", + "Scale-Center-X", + "Horizontal scale center", + -G_MAXFLOAT, G_MAXFLOAT, + 0.0, + CLUTTER_PARAM_READWRITE); g_object_class_install_property (object_class, PROP_SCALE_CENTER_X, pspec); /** @@ -2649,11 +3489,12 @@ clutter_actor_class_init (ClutterActorClass *klass) * * Since: 1.0 */ - pspec = g_param_spec_int ("scale-center-y", - "Scale-Center-Y", - "Vertical scale center", - G_MININT, G_MAXINT, 0, - CLUTTER_PARAM_READWRITE); + pspec = g_param_spec_float ("scale-center-y", + "Scale-Center-Y", + "Vertical scale center", + -G_MAXFLOAT, G_MAXFLOAT, + 0.0, + CLUTTER_PARAM_READWRITE); g_object_class_install_property (object_class, PROP_SCALE_CENTER_Y, pspec); /** @@ -2670,59 +3511,54 @@ clutter_actor_class_init (ClutterActorClass *klass) CLUTTER_GRAVITY_NONE, CLUTTER_PARAM_READWRITE); g_object_class_install_property (object_class, - PROP_SCALE_GRAVITY, pspec); + PROP_SCALE_GRAVITY, + pspec); /** * ClutterActor:rotation-angle-x: * - * The rotation angle on the X axis. + * The rotation angle on the X axis * * Since: 0.6 */ - g_object_class_install_property - (object_class, - PROP_ROTATION_ANGLE_X, - g_param_spec_double ("rotation-angle-x", - "Rotation Angle X", - "The rotation angle on the X axis", - -G_MAXDOUBLE, - G_MAXDOUBLE, - 0.0, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_double ("rotation-angle-x", + "Rotation Angle X", + "The rotation angle on the X axis", + -G_MAXDOUBLE, G_MAXDOUBLE, + 0.0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_ROTATION_ANGLE_X, pspec); + /** * ClutterActor:rotation-angle-y: * - * The rotation angle on the Y axis. + * The rotation angle on the Y axis * * Since: 0.6 */ - g_object_class_install_property - (object_class, - PROP_ROTATION_ANGLE_Y, - g_param_spec_double ("rotation-angle-y", - "Rotation Angle Y", - "The rotation angle on the Y axis", - -G_MAXDOUBLE, - G_MAXDOUBLE, - 0.0, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_double ("rotation-angle-y", + "Rotation Angle Y", + "The rotation angle on the Y axis", + -G_MAXDOUBLE, G_MAXDOUBLE, + 0.0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_ROTATION_ANGLE_Y, pspec); + /** * ClutterActor:rotation-angle-z: * - * The rotation angle on the Z axis. + * The rotation angle on the Z axis * * Since: 0.6 */ - g_object_class_install_property - (object_class, - PROP_ROTATION_ANGLE_Z, - g_param_spec_double ("rotation-angle-z", - "Rotation Angle Z", - "The rotation angle on the Z axis", - -G_MAXDOUBLE, - G_MAXDOUBLE, - 0.0, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_double ("rotation-angle-z", + "Rotation Angle Z", + "The rotation angle on the Z axis", + -G_MAXDOUBLE, G_MAXDOUBLE, + 0.0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_ROTATION_ANGLE_Z, pspec); + /** * ClutterActor:rotation-center-x: * @@ -2730,14 +3566,15 @@ clutter_actor_class_init (ClutterActorClass *klass) * * Since: 0.6 */ - g_object_class_install_property - (object_class, - PROP_ROTATION_CENTER_X, - g_param_spec_boxed ("rotation-center-x", - "Rotation Center X", - "The rotation center on the X axis", - CLUTTER_TYPE_VERTEX, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_boxed ("rotation-center-x", + "Rotation Center X", + "The rotation center on the X axis", + CLUTTER_TYPE_VERTEX, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, + PROP_ROTATION_CENTER_X, + pspec); + /** * ClutterActor:rotation-center-y: * @@ -2745,14 +3582,15 @@ clutter_actor_class_init (ClutterActorClass *klass) * * Since: 0.6 */ - g_object_class_install_property - (object_class, - PROP_ROTATION_CENTER_Y, - g_param_spec_boxed ("rotation-center-y", - "Rotation Center Y", - "The rotation center on the Y axis", - CLUTTER_TYPE_VERTEX, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_boxed ("rotation-center-y", + "Rotation Center Y", + "The rotation center on the Y axis", + CLUTTER_TYPE_VERTEX, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, + PROP_ROTATION_CENTER_Y, + pspec); + /** * ClutterActor:rotation-center-z: * @@ -2760,14 +3598,14 @@ clutter_actor_class_init (ClutterActorClass *klass) * * Since: 0.6 */ - g_object_class_install_property - (object_class, - PROP_ROTATION_CENTER_Z, - g_param_spec_boxed ("rotation-center-z", - "Rotation Center Z", - "The rotation center on the Z axis", - CLUTTER_TYPE_VERTEX, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_boxed ("rotation-center-z", + "Rotation Center Z", + "The rotation center on the Z axis", + CLUTTER_TYPE_VERTEX, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, + PROP_ROTATION_CENTER_Z, + pspec); /** * ClutterActor:rotation-center-z-gravity: @@ -2790,41 +3628,38 @@ clutter_actor_class_init (ClutterActorClass *klass) * ClutterActor:anchor-x: * * The X coordinate of an actor's anchor point, relative to - * the actor coordinate space, in pixels. + * the actor coordinate space, in pixels * * Since: 0.8 */ - g_object_class_install_property - (object_class, - PROP_ANCHOR_X, - g_param_spec_int ("anchor-x", - "Anchor X", - "X coordinate of the anchor point", - -G_MAXINT, G_MAXINT, - 0, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_float ("anchor-x", + "Anchor X", + "X coordinate of the anchor point", + -G_MAXFLOAT, G_MAXFLOAT, + 0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_ANCHOR_X, pspec); + /** * ClutterActor:anchor-y: * * The Y coordinate of an actor's anchor point, relative to - * the actor coordinate space, in pixels. + * the actor coordinate space, in pixels * * Since: 0.8 */ - g_object_class_install_property - (object_class, - PROP_ANCHOR_Y, - g_param_spec_int ("anchor-y", - "Anchor Y", - "Y coordinate of the anchor point", - -G_MAXINT, G_MAXINT, - 0, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_float ("anchor-y", + "Anchor Y", + "Y coordinate of the anchor point", + -G_MAXFLOAT, G_MAXFLOAT, + 0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_ANCHOR_Y, pspec); /** * ClutterActor:anchor-gravity: * - * The anchor point expressed as a #ClutterGravity. + * The anchor point expressed as a #ClutterGravity * * Since: 1.0 */ @@ -2847,15 +3682,14 @@ clutter_actor_class_init (ClutterActorClass *klass) * * Since: 0.8 */ - g_object_class_install_property - (object_class, - PROP_SHOW_ON_SET_PARENT, - g_param_spec_boolean ("show-on-set-parent", - "Show on set parent", - "Whether the actor is shown" - " when parented", - TRUE, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_boolean ("show-on-set-parent", + "Show on set parent", + "Whether the actor is shown when parented", + TRUE, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, + PROP_SHOW_ON_SET_PARENT, + pspec); /** * ClutterActor:clip-to-allocation: @@ -2889,7 +3723,7 @@ clutter_actor_class_init (ClutterActorClass *klass) * Since: 0.2 */ actor_signals[DESTROY] = - g_signal_new ("destroy", + g_signal_new (I_("destroy"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, G_STRUCT_OFFSET (ClutterActorClass, destroy), @@ -2906,7 +3740,7 @@ clutter_actor_class_init (ClutterActorClass *klass) * Since: 0.2 */ actor_signals[SHOW] = - g_signal_new ("show", + g_signal_new (I_("show"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (ClutterActorClass, show), @@ -2923,7 +3757,7 @@ clutter_actor_class_init (ClutterActorClass *klass) * Since: 0.2 */ actor_signals[HIDE] = - g_signal_new ("hide", + g_signal_new (I_("hide"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (ClutterActorClass, hide), @@ -2940,7 +3774,7 @@ clutter_actor_class_init (ClutterActorClass *klass) * Since: 0.2 */ actor_signals[PARENT_SET] = - g_signal_new ("parent-set", + g_signal_new (I_("parent-set"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, parent_set), @@ -3025,7 +3859,7 @@ clutter_actor_class_init (ClutterActorClass *klass) * Since: 0.6 */ actor_signals[EVENT] = - g_signal_new ("event", + g_signal_new (I_("event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, event), @@ -3047,7 +3881,7 @@ clutter_actor_class_init (ClutterActorClass *klass) * Since: 0.6 */ actor_signals[BUTTON_PRESS_EVENT] = - g_signal_new ("button-press-event", + g_signal_new (I_("button-press-event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, button_press_event), @@ -3069,7 +3903,7 @@ clutter_actor_class_init (ClutterActorClass *klass) * Since: 0.6 */ actor_signals[BUTTON_RELEASE_EVENT] = - g_signal_new ("button-release-event", + g_signal_new (I_("button-release-event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, button_release_event), @@ -3091,7 +3925,7 @@ clutter_actor_class_init (ClutterActorClass *klass) * Since: 0.6 */ actor_signals[SCROLL_EVENT] = - g_signal_new ("scroll-event", + g_signal_new (I_("scroll-event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, scroll_event), @@ -3113,7 +3947,7 @@ clutter_actor_class_init (ClutterActorClass *klass) * Since: 0.6 */ actor_signals[KEY_PRESS_EVENT] = - g_signal_new ("key-press-event", + g_signal_new (I_("key-press-event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, key_press_event), @@ -3136,7 +3970,7 @@ clutter_actor_class_init (ClutterActorClass *klass) * Since: 0.6 */ actor_signals[KEY_RELEASE_EVENT] = - g_signal_new ("key-release-event", + g_signal_new (I_("key-release-event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, key_release_event), @@ -3158,7 +3992,7 @@ clutter_actor_class_init (ClutterActorClass *klass) * Since: 0.6 */ actor_signals[MOTION_EVENT] = - g_signal_new ("motion-event", + g_signal_new (I_("motion-event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, motion_event), @@ -3168,35 +4002,35 @@ clutter_actor_class_init (ClutterActorClass *klass) CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** - * ClutterActor::focus-in: + * ClutterActor::key-focus-in: * @actor: the actor which now has key focus * * The ::focus-in signal is emitted when @actor recieves key focus. * * Since: 0.6 */ - actor_signals[FOCUS_IN] = - g_signal_new ("focus-in", + actor_signals[KEY_FOCUS_IN] = + g_signal_new (I_("key-focus-in"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ClutterActorClass, focus_in), + G_STRUCT_OFFSET (ClutterActorClass, key_focus_in), NULL, NULL, clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** - * ClutterActor::focus-out: + * ClutterActor::key-focus-out: * @actor: the actor which now has key focus * - * The ::focus-out signal is emitted when @actor loses key focus. + * The ::key-focus-out signal is emitted when @actor loses key focus. * * Since: 0.6 */ - actor_signals[FOCUS_OUT] = - g_signal_new ("focus-out", + actor_signals[KEY_FOCUS_OUT] = + g_signal_new (I_("key-focus-out"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ClutterActorClass, focus_out), + G_STRUCT_OFFSET (ClutterActorClass, key_focus_out), NULL, NULL, clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); @@ -3214,7 +4048,7 @@ clutter_actor_class_init (ClutterActorClass *klass) * Since: 0.6 */ actor_signals[ENTER_EVENT] = - g_signal_new ("enter-event", + g_signal_new (I_("enter-event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, enter_event), @@ -3236,7 +4070,7 @@ clutter_actor_class_init (ClutterActorClass *klass) * Since: 0.6 */ actor_signals[LEAVE_EVENT] = - g_signal_new ("leave-event", + g_signal_new (I_("leave-event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, leave_event), @@ -3264,7 +4098,7 @@ clutter_actor_class_init (ClutterActorClass *klass) * Since: 0.6 */ actor_signals[CAPTURED_EVENT] = - g_signal_new ("captured-event", + g_signal_new (I_("captured-event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, captured_event), @@ -3330,6 +4164,30 @@ clutter_actor_class_init (ClutterActorClass *klass) clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); + /** + * ClutterActor::map: + * @actor: the #ClutterActor to map + * + * The ::map virtual functon must be overridden in order to call + * clutter_actor_map() on any child actors if the actor is not a + * #ClutterContainer. When overriding, it is mandatory to chain up + * to the parent implementation. + * + * Since: 1.0 + */ + + /** + * ClutterActor::unmap: + * @actor: the #ClutterActor to unmap + * + * The ::unmap virtual functon must be overridden in order to call + * clutter_actor_unmap() on any child actors if the actor is not a + * #ClutterContainer. When overriding, it is mandatory to chain up + * to the parent implementation. + * + * Since: 1.0 + */ + /** * ClutterActor::pick: * @actor: the #ClutterActor that received the signal @@ -3358,10 +4216,39 @@ clutter_actor_class_init (ClutterActorClass *klass) G_TYPE_NONE, 1, CLUTTER_TYPE_COLOR); + /** + * ClutterActor::allocation-changed: + * @actor: the #ClutterActor that emitted the signal + * @box: a #ClutterActorBox with the new allocation + * @flags: #ClutterAllocationFlags for the allocation + * + * The ::allocation-changed signal is emitted when the + * #ClutterActor:allocation property changes. Usually, application + * code should just use the notifications for the :allocation property + * but if you want to track the allocation flags as well, for instance + * to know whether the absolute origin of @actor changed, then you might + * want use this signal instead. + * + * Since: 1.0 + */ + actor_signals[ALLOCATION_CHANGED] = + g_signal_new (I_("allocation-changed"), + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + clutter_marshal_VOID__BOXED_FLAGS, + G_TYPE_NONE, 2, + CLUTTER_TYPE_ACTOR_BOX, + CLUTTER_TYPE_ALLOCATION_FLAGS); + klass->show = clutter_actor_real_show; klass->show_all = clutter_actor_show; klass->hide = clutter_actor_real_hide; klass->hide_all = clutter_actor_hide; + klass->map = clutter_actor_real_map; + klass->unmap = clutter_actor_real_unmap; + klass->unrealize = clutter_actor_real_unrealize; klass->pick = clutter_actor_real_pick; klass->get_preferred_width = clutter_actor_real_get_preferred_width; klass->get_preferred_height = clutter_actor_real_get_preferred_height; @@ -3392,7 +4279,7 @@ clutter_actor_init (ClutterActor *self) priv->opacity_parent = NULL; priv->enable_model_view_transform = TRUE; - memset (priv->clip, 0, sizeof (ClutterUnit) * 4); + memset (priv->clip, 0, sizeof (gfloat) * 4); } /** @@ -3424,6 +4311,12 @@ clutter_actor_destroy (ClutterActor *self) { CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_IN_DESTRUCTION); + /* if we are destroying we want to unrealize ourselves + * first before the dispose run removes the parent + */ + if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL)) + clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNREALIZED); + g_object_run_dispose (G_OBJECT (self)); CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_IN_DESTRUCTION); @@ -3485,9 +4378,8 @@ clutter_actor_queue_relayout (ClutterActor *self) priv->needs_height_request = TRUE; priv->needs_allocation = TRUE; - /* always repaint also */ - if (CLUTTER_ACTOR_IS_VISIBLE (self)) - clutter_actor_queue_redraw (self); + /* always repaint also (no-op if not mapped) */ + clutter_actor_queue_redraw (self); /* We need to go all the way up the hierarchy */ if (priv->parent_actor) @@ -3518,15 +4410,15 @@ clutter_actor_queue_relayout (ClutterActor *self) */ void clutter_actor_get_preferred_size (ClutterActor *self, - ClutterUnit *min_width_p, - ClutterUnit *min_height_p, - ClutterUnit *natural_width_p, - ClutterUnit *natural_height_p) + gfloat *min_width_p, + gfloat *min_height_p, + gfloat *natural_width_p, + gfloat *natural_height_p) { ClutterActorPrivate *priv; - ClutterUnit for_width, for_height; - ClutterUnit min_width, min_height; - ClutterUnit natural_width, natural_height; + gfloat for_width, for_height; + gfloat min_width, min_height; + gfloat natural_width, natural_height; g_return_if_fail (CLUTTER_IS_ACTOR (self)); @@ -3594,9 +4486,9 @@ clutter_actor_get_preferred_size (ClutterActor *self, */ void clutter_actor_get_preferred_width (ClutterActor *self, - ClutterUnit for_height, - ClutterUnit *min_width_p, - ClutterUnit *natural_width_p) + gfloat for_height, + gfloat *min_width_p, + gfloat *natural_width_p) { ClutterActorClass *klass; ClutterActorPrivate *priv; @@ -3609,14 +4501,11 @@ clutter_actor_get_preferred_width (ClutterActor *self, if (priv->needs_width_request || priv->request_width_for_height != for_height) { - ClutterUnit min_width, natural_width; + gfloat min_width, natural_width; min_width = natural_width = 0; - CLUTTER_NOTE (LAYOUT, - "Width request for %" CLUTTER_UNITS_FORMAT " (%d px)", - for_height, - CLUTTER_UNITS_TO_DEVICE (for_height)); + CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height); klass->get_preferred_width (self, for_height, &min_width, @@ -3625,11 +4514,10 @@ clutter_actor_get_preferred_width (ClutterActor *self, if (natural_width < min_width - FLOAT_EPSILON) { g_warning ("Actor of type %s reported a natural width " - "of %" CLUTTER_UNITS_FORMAT " (%d px) lower " - "than min width %" CLUTTER_UNITS_FORMAT " (%d px)", + "of %.2f px lower than min width %.2f px", G_OBJECT_TYPE_NAME (self), - natural_width, CLUTTER_UNITS_TO_DEVICE (natural_width), - min_width, CLUTTER_UNITS_TO_DEVICE (min_width)); + natural_width, + min_width); } if (!priv->min_width_set) @@ -3670,9 +4558,9 @@ clutter_actor_get_preferred_width (ClutterActor *self, */ void clutter_actor_get_preferred_height (ClutterActor *self, - ClutterUnit for_width, - ClutterUnit *min_height_p, - ClutterUnit *natural_height_p) + gfloat for_width, + gfloat *min_height_p, + gfloat *natural_height_p) { ClutterActorClass *klass; ClutterActorPrivate *priv; @@ -3685,14 +4573,11 @@ clutter_actor_get_preferred_height (ClutterActor *self, if (priv->needs_height_request || priv->request_height_for_width != for_width) { - ClutterUnit min_height, natural_height; + gfloat min_height, natural_height; min_height = natural_height = 0; - CLUTTER_NOTE (LAYOUT, - "Width request for %" CLUTTER_UNITS_FORMAT " (%d px)", - for_width, - CLUTTER_UNITS_TO_DEVICE (for_width)); + CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_width); klass->get_preferred_height (self, for_width, &min_height, @@ -3701,11 +4586,10 @@ clutter_actor_get_preferred_height (ClutterActor *self, if (natural_height < min_height - FLOAT_EPSILON) { g_warning ("Actor of type %s reported a natural height " - "of %" CLUTTER_UNITS_FORMAT " (%d px) lower than " - "min height %" CLUTTER_UNITS_FORMAT " (%d px)", + "of %.2f px lower than min height %.2f px", G_OBJECT_TYPE_NAME (self), - natural_height, CLUTTER_UNITS_TO_DEVICE (natural_height), - min_height, CLUTTER_UNITS_TO_DEVICE (min_height)); + natural_height, + min_height); } if (!priv->min_height_set) @@ -3758,16 +4642,16 @@ clutter_actor_get_allocation_coords (ClutterActor *self, clutter_actor_get_allocation_box (self, &allocation); if (x_1) - *x_1 = CLUTTER_UNITS_TO_DEVICE (allocation.x1); + *x_1 = allocation.x1; if (y_1) - *y_1 = CLUTTER_UNITS_TO_DEVICE (allocation.y1); + *y_1 = allocation.y1; if (x_2) - *x_2 = CLUTTER_UNITS_TO_DEVICE (allocation.x2); + *x_2 = allocation.x2; if (y_2) - *y_2 = CLUTTER_UNITS_TO_DEVICE (allocation.y2); + *y_2 = allocation.y2; } /** @@ -3856,25 +4740,24 @@ clutter_actor_get_allocation_geometry (ClutterActor *self, * clutter_actor_allocate: * @self: A #ClutterActor * @box: new allocation of the actor, in parent-relative coordinates - * @absolute_origin_changed: whether the position of the parent has - * changed in stage coordinates + * @flags: flags that control the allocation * * Called by the parent of an actor to assign the actor its size. * Should never be called by applications (except when implementing * a container or layout manager). * * Actors can know from their allocation box whether they have moved - * with respect to their parent actor. The absolute_origin_changed - * parameter additionally indicates whether the parent has moved with - * respect to the stage, for example because a grandparent's origin - * has moved. + * with respect to their parent actor. The @flags parameter describes + * additional information about the allocation, for instance whether + * the parent has moved with respect to the stage, for example because + * a grandparent's origin has moved. * * Since: 0.8 */ void -clutter_actor_allocate (ClutterActor *self, - const ClutterActorBox *box, - gboolean absolute_origin_changed) +clutter_actor_allocate (ClutterActor *self, + const ClutterActorBox *box, + ClutterAllocationFlags flags) { ClutterActorPrivate *priv; ClutterActorClass *klass; @@ -3883,7 +4766,6 @@ clutter_actor_allocate (ClutterActor *self, g_return_if_fail (CLUTTER_IS_ACTOR (self)); priv = self->priv; - klass = CLUTTER_ACTOR_GET_CLASS (self); child_moved = (box->x1 != priv->allocation.x1 || box->y1 != priv->allocation.y1); @@ -3902,7 +4784,7 @@ clutter_actor_allocate (ClutterActor *self, */ if (!priv->needs_allocation && - !absolute_origin_changed && + !(flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED) && !child_moved && box->x2 == priv->allocation.x2 && box->y2 == priv->allocation.y2) @@ -3911,13 +4793,17 @@ clutter_actor_allocate (ClutterActor *self, return; } - /* When absolute_origin_changed is passed in to + /* When ABSOLUTE_ORIGIN_CHANGED is passed in to * clutter_actor_allocate(), it indicates whether the parent has its * absolute origin moved; when passed in to ClutterActor::allocate() * virtual method though, it indicates whether the child has its - * absolute origin moved. So we set it to TRUE if child_moved. + * absolute origin moved. So we set it when child_moved is TRUE */ - klass->allocate (self, box, absolute_origin_changed || child_moved); + if (child_moved) + flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED; + + klass = CLUTTER_ACTOR_GET_CLASS (self); + klass->allocate (self, box, flags); } /** @@ -3956,10 +4842,18 @@ void clutter_actor_get_geometry (ClutterActor *self, ClutterGeometry *geometry) { - g_return_if_fail (CLUTTER_IS_ACTOR (self)); + gfloat x, y, width, height; - clutter_actor_get_position (self, &geometry->x, &geometry->y); - clutter_actor_get_size (self, &geometry->width, &geometry->height); + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + g_return_if_fail (geometry != NULL); + + clutter_actor_get_position (self, &x, &y); + clutter_actor_get_size (self, &width, &height); + + geometry->x = (int) x; + geometry->y = (int) y; + geometry->width = (int) width; + geometry->height = (int) height; } /** @@ -3976,8 +4870,8 @@ clutter_actor_get_geometry (ClutterActor *self, */ void clutter_actor_set_position (ClutterActor *self, - gint x, - gint y) + gfloat x, + gfloat y) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); @@ -3989,35 +4883,6 @@ clutter_actor_set_position (ClutterActor *self, g_object_thaw_notify (G_OBJECT (self)); } -/** - * clutter_actor_set_positionu - * @self: A #ClutterActor - * @x: New left position of actor in #ClutterUnits - * @y: New top position of actor in #ClutterUnits - * - * Sets the actor's position in #ClutterUnits relative to any - * parent actor. - * - * If a layout manager is in use, this position will override the - * layout manager and force a fixed position. - * - * Since: 0.6 - */ -void -clutter_actor_set_positionu (ClutterActor *self, - ClutterUnit x, - ClutterUnit y) -{ - g_return_if_fail (CLUTTER_IS_ACTOR (self)); - - g_object_freeze_notify (G_OBJECT (self)); - - clutter_actor_set_xu (self, x); - clutter_actor_set_yu (self, y); - - g_object_thaw_notify (G_OBJECT (self)); -} - /** * clutter_actor_get_fixed_position_set: * @self: A #ClutterActor @@ -4058,6 +4923,7 @@ clutter_actor_set_fixed_position_set (ClutterActor *self, self->priv->position_set = is_set != FALSE; g_object_notify (G_OBJECT (self), "fixed-position-set"); + clutter_actor_queue_relayout (self); } @@ -4068,57 +4934,35 @@ clutter_actor_set_fixed_position_set (ClutterActor *self, * @dy: Distance to move Actor on Y axis. * * Moves an actor by the specified distance relative to its current - * position in pixels. This function modifies the fixed position of an - * actor and thus removes it from any layout management. Another way - * to move an actor is with an anchor point, see - * clutter_actor_set_anchor_point(). + * position in pixels. + * + * This function modifies the fixed position of an actor and thus removes + * it from any layout management. Another way to move an actor is with an + * anchor point, see clutter_actor_set_anchor_point(). * * Since: 0.2 */ void clutter_actor_move_by (ClutterActor *self, - gint dx, - gint dy) + gfloat dx, + gfloat dy) { - g_return_if_fail (CLUTTER_IS_ACTOR (self)); - - clutter_actor_move_byu (self, - CLUTTER_UNITS_FROM_DEVICE (dx), - CLUTTER_UNITS_FROM_DEVICE (dy)); -} - -/** - * clutter_actor_move_byu: - * @self: A #ClutterActor - * @dx: Distance to move Actor on X axis, in #ClutterUnits. - * @dy: Distance to move Actor on Y axis, in #ClutterUnits. - * - * Moves an actor by the specified distance relative to its current - * position. - * - * The move is accomplished by setting a fixed position, overriding - * any layout manager, see clutter_actor_set_positionu(). - * - * Since: 0.6 - */ -void -clutter_actor_move_byu (ClutterActor *self, - ClutterUnit dx, - ClutterUnit dy) -{ - ClutterUnit x, y; + ClutterActorPrivate *priv; + gfloat x, y; g_return_if_fail (CLUTTER_IS_ACTOR (self)); - x = self->priv->fixed_x; - y = self->priv->fixed_y; + priv = self->priv; - clutter_actor_set_positionu (self, x + dx, y + dy); + x = priv->fixed_x; + y = priv->fixed_y; + + clutter_actor_set_position (self, x + dx, y + dy); } static void clutter_actor_set_min_width (ClutterActor *self, - ClutterUnit min_width) + gfloat min_width) { ClutterActorPrivate *priv = self->priv; ClutterActorBox old = { 0, }; @@ -4152,7 +4996,7 @@ clutter_actor_set_min_width (ClutterActor *self, static void clutter_actor_set_min_height (ClutterActor *self, - ClutterUnit min_height) + gfloat min_height) { ClutterActorPrivate *priv = self->priv; @@ -4187,7 +5031,7 @@ clutter_actor_set_min_height (ClutterActor *self, static void clutter_actor_set_natural_width (ClutterActor *self, - ClutterUnit natural_width) + gfloat natural_width) { ClutterActorPrivate *priv = self->priv; ClutterActorBox old = { 0, }; @@ -4222,7 +5066,7 @@ clutter_actor_set_natural_width (ClutterActor *self, static void clutter_actor_set_natural_height (ClutterActor *self, - ClutterUnit natural_height) + gfloat natural_height) { ClutterActorPrivate *priv = self->priv; ClutterActorBox old = { 0, }; @@ -4373,34 +5217,8 @@ clutter_actor_set_request_mode (ClutterActor *self, */ void clutter_actor_set_size (ClutterActor *self, - gint width, - gint height) -{ - g_return_if_fail (CLUTTER_IS_ACTOR (self)); - - clutter_actor_set_sizeu (self, - CLUTTER_UNITS_FROM_DEVICE (width), - CLUTTER_UNITS_FROM_DEVICE (height)); -} - -/** - * clutter_actor_set_sizeu - * @self: A #ClutterActor - * @width: New width of actor in #ClutterUnits, or -1 - * @height: New height of actor in #ClutterUnits, or -1 - * - * Overrides the actor's size request in #ClutterUnits. If @width - * and/or @height are -1 the actor will use its normal size request (the - * override is removed). - * - * This function sets or unsets both the minimum and natural size. - * - * Since: 0.6 - */ -void -clutter_actor_set_sizeu (ClutterActor *self, - ClutterUnit width, - ClutterUnit height) + gfloat width, + gfloat height) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); @@ -4451,8 +5269,8 @@ clutter_actor_set_sizeu (ClutterActor *self, */ void clutter_actor_get_size (ClutterActor *self, - guint *width, - guint *height) + gfloat *width, + gfloat *height) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); @@ -4463,38 +5281,6 @@ clutter_actor_get_size (ClutterActor *self, *height = clutter_actor_get_height (self); } -/** - * clutter_actor_get_sizeu: - * @self: A #ClutterActor - * @width: return location for the width, or %NULL - * @height: return location for the height, or %NULL - * - * This function tries to "do what you mean" and return - * the size an actor will have. If the actor has a valid - * allocation, the allocation will be returned; otherwise, - * the actors natural size request will be returned. - * - * If you care whether you get the request vs. the allocation, you - * should probably call a different function like - * clutter_actor_get_allocation_coords() or - * clutter_actor_get_preferred_width(). - * - * Since: 0.6 - */ -void -clutter_actor_get_sizeu (ClutterActor *self, - ClutterUnit *width, - ClutterUnit *height) -{ - g_return_if_fail (CLUTTER_IS_ACTOR (self)); - - if (width) - *width = clutter_actor_get_widthu (self); - - if (height) - *height = clutter_actor_get_heightu (self); -} - /** * clutter_actor_get_position: * @self: a #ClutterActor @@ -4513,8 +5299,8 @@ clutter_actor_get_sizeu (ClutterActor *self, */ void clutter_actor_get_position (ClutterActor *self, - gint *x, - gint *y) + gfloat *x, + gfloat *y) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); @@ -4526,99 +5312,41 @@ clutter_actor_get_position (ClutterActor *self, } /** - * clutter_actor_get_positionu: - * @self: a #ClutterActor - * @x: (out): return location for the X coordinate, or %NULL - * @y: (out): return location for the Y coordinate, or %NULL - * - * This function tries to "do what you mean" and tell you where the - * actor is, prior to any transformations. Retrieves the fixed - * position of an actor in pixels, if one has been set; otherwise, if - * the allocation is valid, returns the actor's allocated position; - * otherwise, returns 0,0. - * - * The returned position is in #ClutterUnits. - * - * Since: 0.6 - */ -void -clutter_actor_get_positionu (ClutterActor *self, - ClutterUnit *x, - ClutterUnit *y) -{ - g_return_if_fail (CLUTTER_IS_ACTOR (self)); - - if (x) - *x = clutter_actor_get_xu (self); - - if (y) - *y = clutter_actor_get_yu (self); -} - -/** - * clutter_actor_get_transformed_positionu - * @self: A #ClutterActor - * @x: return location for the X coordinate, or %NULL - * @y: return location for the Y coordinate, or %NULL - * - * Gets the absolute position of an actor, in #ClutterUnits, - * relative to the stage. - * - * Since: 0.8 - */ -void -clutter_actor_get_transformed_positionu (ClutterActor *self, - ClutterUnit *x, - ClutterUnit *y) -{ - ClutterVertex v1 = { 0, }; - ClutterVertex v2 = { 0, }; - - clutter_actor_apply_transform_to_point (self, &v1, &v2); - - if (x) - *x = v2.x; - if (y) - *y = v2.y; -} - -/** - * clutter_actor_get_transformed_position + * clutter_actor_get_transformed_position: * @self: A #ClutterActor * @x: (out): return location for the X coordinate, or %NULL * @y: (out): return location for the Y coordinate, or %NULL * - * Gets the absolute position of an actor, in pixels, relative - * to the stage. + * Gets the absolute position of an actor, in pixels relative to the stage. * * Since: 0.8 */ void clutter_actor_get_transformed_position (ClutterActor *self, - gint *x, - gint *y) + gfloat *x, + gfloat *y) { - ClutterUnit xu, yu; + ClutterVertex v1; + ClutterVertex v2; - g_return_if_fail (CLUTTER_IS_ACTOR (self)); - - xu = yu = 0; - clutter_actor_get_transformed_positionu (self, &xu, &yu); + v1.x = v1.y = 0; + clutter_actor_apply_transform_to_point (self, &v1, &v2); if (x) - *x = CLUTTER_UNITS_TO_DEVICE (xu); + *x = v2.x; + if (y) - *y = CLUTTER_UNITS_TO_DEVICE (yu); + *y = v2.y; } /** - * clutter_actor_get_transformed_sizeu: + * clutter_actor_get_transformed_size: * @self: A #ClutterActor * @width: (out): return location for the width, or %NULL * @height: (out): return location for the height, or %NULL * - * Gets the absolute size of an actor in #ClutterUnitss, taking - * into account the scaling factors. + * Gets the absolute size of an actor in pixels, taking into account the + * scaling factors. * * If the actor has a valid allocation, the allocated size will be used. * If the actor has not a valid allocation then the preferred size will @@ -4640,9 +5368,9 @@ clutter_actor_get_transformed_position (ClutterActor *self, * Since: 0.8 */ void -clutter_actor_get_transformed_sizeu (ClutterActor *self, - ClutterUnit *width, - ClutterUnit *height) +clutter_actor_get_transformed_size (ClutterActor *self, + gfloat *width, + gfloat *height) { ClutterActorPrivate *priv; ClutterVertex v[4]; @@ -4658,11 +5386,11 @@ clutter_actor_get_transformed_sizeu (ClutterActor *self, */ if (priv->needs_allocation) { - ClutterUnit natural_width, natural_height; + gfloat natural_width, natural_height; ClutterActorBox box; /* make a fake allocation to transform */ - clutter_actor_get_positionu (self, &box.x1, &box.y1); + clutter_actor_get_position (self, &box.x1, &box.y1); natural_width = natural_height = 0; clutter_actor_get_preferred_size (self, NULL, NULL, @@ -4703,38 +5431,7 @@ clutter_actor_get_transformed_sizeu (ClutterActor *self, } /** - * clutter_actor_get_transformed_size: - * @self: A #ClutterActor - * @width: (out): return location for the width, or %NULL - * @height: (out): return location for the height, or %NULL - * - * Gets the absolute size of an actor taking into account - * any scaling factors - * - * Since: 0.8 - */ -void -clutter_actor_get_transformed_size (ClutterActor *self, - guint *width, - guint *height) -{ - ClutterUnit wu, hu; - - g_return_if_fail (CLUTTER_IS_ACTOR (self)); - - wu = hu = 0; - clutter_actor_get_transformed_sizeu (self, &wu, &hu); - - if (width) - *width = CLUTTER_UNITS_TO_DEVICE (wu); - - if (height) - *height = CLUTTER_UNITS_TO_DEVICE (hu); -} - - -/** - * clutter_actor_get_width + * clutter_actor_get_width: * @self: A #ClutterActor * * Retrieves the width of a #ClutterActor. @@ -4758,55 +5455,24 @@ clutter_actor_get_transformed_size (ClutterActor *self, * * Return value: the width of the actor, in pixels */ -guint +gfloat clutter_actor_get_width (ClutterActor *self) { + ClutterActorPrivate *priv; + g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); - return CLUTTER_UNITS_TO_DEVICE (clutter_actor_get_widthu (self)); -} + priv = self->priv; -/** - * clutter_actor_get_widthu - * @self: A #ClutterActor - * - * Retrieves the width of a #ClutterActor, in #ClutterUnits. - * - * If the actor has a valid allocation, this function will return the - * width of the allocated area given to the actor. - * - * If the actor does not have a valid allocation, this function will - * return the actor's natural width, that is the preferred width of - * the actor. - * - * If you care whether you get the preferred width or the width that - * has been assigned to the actor, you should probably call a different - * function like clutter_actor_get_allocation_coords() to retrieve the - * allocated size or clutter_actor_get_preferred_width() to retrieve the - * preferred width. - * - * If an actor has a fixed width, for instance a width that has been - * assigned using clutter_actor_set_width(), the width returned will - * be the same value. - * - * Return value: the width of the actor, in #ClutterUnits - * - * since: 0.6 - */ -ClutterUnit -clutter_actor_get_widthu (ClutterActor *self) -{ - g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); - - if (self->priv->needs_allocation) + if (priv->needs_allocation) { - ClutterUnit natural_width = 0; + gfloat natural_width = 0; if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH) clutter_actor_get_preferred_width (self, -1, NULL, &natural_width); else { - ClutterUnit natural_height = 0; + gfloat natural_height = 0; clutter_actor_get_preferred_height (self, -1, NULL, &natural_height); clutter_actor_get_preferred_width (self, natural_height, @@ -4817,11 +5483,11 @@ clutter_actor_get_widthu (ClutterActor *self) return natural_width; } else - return self->priv->allocation.x2 - self->priv->allocation.x1; + return priv->allocation.x2 - priv->allocation.x1; } /** - * clutter_actor_get_height + * clutter_actor_get_height: * @self: A #ClutterActor * * Retrieves the height of a #ClutterActor. @@ -4845,53 +5511,22 @@ clutter_actor_get_widthu (ClutterActor *self) * * Return value: the height of the actor, in pixels */ -guint +gfloat clutter_actor_get_height (ClutterActor *self) { + ClutterActorPrivate *priv; + g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); - return CLUTTER_UNITS_TO_DEVICE (clutter_actor_get_heightu (self)); -} + priv = self->priv; -/** - * clutter_actor_get_heightu - * @self: A #ClutterActor - * - * Retrieves the height of a #ClutterActor, in #ClutterUnits. - * - * If the actor has a valid allocation, this function will return the - * height of the allocated area given to the actor. - * - * If the actor does not have a valid allocation, this function will - * return the actor's natural height, that is the preferred height of - * the actor. - * - * If you care whether you get the preferred height or the height that - * has been assigned to the actor, you should probably call a different - * function like clutter_actor_get_allocation_coords() to retrieve the - * allocated size or clutter_actor_get_preferred_height() to retrieve the - * preferred height. - * - * If an actor has a fixed height, for instance a height that has been - * assigned using clutter_actor_set_height(), the height returned will - * be the same value. - * - * Return value: the height of the actor, in #ClutterUnits - * - * since: 0.6 - */ -ClutterUnit -clutter_actor_get_heightu (ClutterActor *self) -{ - g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); - - if (self->priv->needs_allocation) + if (priv->needs_allocation) { - ClutterUnit natural_height = 0; + gfloat natural_height = 0; - if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH) + if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH) { - ClutterUnit natural_width = 0; + gfloat natural_width = 0; clutter_actor_get_preferred_width (self, -1, NULL, &natural_width); clutter_actor_get_preferred_height (self, natural_width, @@ -4903,7 +5538,7 @@ clutter_actor_get_heightu (ClutterActor *self) return natural_height; } else - return self->priv->allocation.y2 - self->priv->allocation.y1; + return priv->allocation.y2 - priv->allocation.y1; } /** @@ -4920,28 +5555,7 @@ clutter_actor_get_heightu (ClutterActor *self) **/ void clutter_actor_set_width (ClutterActor *self, - guint width) -{ - g_return_if_fail (CLUTTER_IS_ACTOR (self)); - - clutter_actor_set_widthu (self, CLUTTER_UNITS_FROM_DEVICE (width)); -} - -/** - * clutter_actor_set_widthu - * @self: A #ClutterActor - * @width: Requested new width for the actor, in #ClutterUnits - * - * Forces a width on an actor, causing the actor's preferred width - * and height (if any) to be ignored. - * - * This function sets both the minimum and natural size of the actor. - * - * since: 0.6 - **/ -void -clutter_actor_set_widthu (ClutterActor *self, - ClutterUnit width) + gfloat width) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); @@ -4967,28 +5581,7 @@ clutter_actor_set_widthu (ClutterActor *self, **/ void clutter_actor_set_height (ClutterActor *self, - guint height) -{ - g_return_if_fail (CLUTTER_IS_ACTOR (self)); - - clutter_actor_set_heightu (self, CLUTTER_UNITS_FROM_DEVICE (height)); -} - -/** - * clutter_actor_set_heightu - * @self: A #ClutterActor - * @height: Requested new height for the actor, in #ClutterUnits - * - * Forces a height on an actor, causing the actor's preferred width - * and height (if any) to be ignored. - * - * This function sets both the minimum and natural size of the actor. - * - * since: 0.6 - **/ -void -clutter_actor_set_heightu (ClutterActor *self, - ClutterUnit height) + gfloat height) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); @@ -5014,40 +5607,21 @@ clutter_actor_set_heightu (ClutterActor *self, */ void clutter_actor_set_x (ClutterActor *self, - gint x) -{ - g_return_if_fail (CLUTTER_IS_ACTOR (self)); - - clutter_actor_set_xu (self, CLUTTER_UNITS_FROM_DEVICE (x)); -} - -/** - * clutter_actor_set_xu: - * @self: a #ClutterActor - * @x: the actor's position on the X axis, in #ClutterUnits - * - * Sets the actor's X coordinate, relative to its parent. - * - * Overrides any layout manager and forces a fixed position for - * the actor. - * - * Since: 0.6 - */ -void -clutter_actor_set_xu (ClutterActor *self, - ClutterUnit x) + gfloat x) { ClutterActorBox old = { 0, }; + ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); - if (self->priv->position_set && - self->priv->fixed_x == x) + priv = self->priv; + + if (priv->position_set && priv->fixed_x == x) return; clutter_actor_store_old_geometry (self, &old); - self->priv->fixed_x = x; + priv->fixed_x = x; clutter_actor_set_fixed_position_set (self, TRUE); clutter_actor_notify_if_geometry_changed (self, &old); @@ -5069,40 +5643,21 @@ clutter_actor_set_xu (ClutterActor *self, */ void clutter_actor_set_y (ClutterActor *self, - gint y) -{ - g_return_if_fail (CLUTTER_IS_ACTOR (self)); - - clutter_actor_set_yu (self, CLUTTER_UNITS_FROM_DEVICE (y)); -} - -/** - * clutter_actor_set_yu: - * @self: a #ClutterActor - * @y: the actor's position on the Y axis, in #ClutterUnits - * - * Sets the actor's Y coordinate, relative to its parent. - * - * Overrides any layout manager and forces a fixed position for - * the actor. - * - * Since: 0.6 - */ -void -clutter_actor_set_yu (ClutterActor *self, - ClutterUnit y) + gfloat y) { ClutterActorBox old = { 0, }; + ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); - if (self->priv->position_set && - self->priv->fixed_y == y) + priv = self->priv; + + if (priv->position_set && priv->fixed_y == y) return; clutter_actor_store_old_geometry (self, &old); - self->priv->fixed_y = y; + priv->fixed_y = y; clutter_actor_set_fixed_position_set (self, TRUE); clutter_actor_notify_if_geometry_changed (self, &old); @@ -5132,52 +5687,24 @@ clutter_actor_set_yu (ClutterActor *self, * Return value: the X coordinate, in pixels, ignoring any * transformation (i.e. scaling, rotation) */ -gint +gfloat clutter_actor_get_x (ClutterActor *self) { + ClutterActorPrivate *priv; + g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); - return CLUTTER_UNITS_TO_DEVICE (clutter_actor_get_xu (self)); -} + priv = self->priv; -/** - * clutter_actor_get_xu - * @self: A #ClutterActor - * - * Retrieves the X coordinate of a #ClutterActor, in #ClutterUnits. - * - * This function tries to "do what you mean", by returning the - * correct value depending on the actor's state. - * - * If the actor has a valid allocation, this function will return - * the X coordinate of the origin of the allocation box. - * - * If the actor has any fixed coordinate set using clutter_actor_set_x(), - * clutter_actor_set_position() or clutter_actor_set_geometry(), this - * function will return that coordinate. - * - * If both the allocation and a fixed position are missing, this function - * will return 0. - * - * Return value: the X coordinate, in #ClutterUnits, ignoring - * any transformation (i.e. scaling, rotation) - * - * Since: 0.6 - */ -ClutterUnit -clutter_actor_get_xu (ClutterActor *self) -{ - g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); - - if (self->priv->needs_allocation) + if (priv->needs_allocation) { - if (self->priv->position_set) - return self->priv->fixed_x; + if (priv->position_set) + return priv->fixed_x; else return 0; } else - return self->priv->allocation.x1; + return priv->allocation.x1; } /** @@ -5202,43 +5729,11 @@ clutter_actor_get_xu (ClutterActor *self) * Return value: the Y coordinate, in pixels, ignoring any * transformation (i.e. scaling, rotation) */ -gint +gfloat clutter_actor_get_y (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); - return CLUTTER_UNITS_TO_DEVICE (clutter_actor_get_yu (self)); -} - -/** - * clutter_actor_get_yu - * @self: A #ClutterActor - * - * Retrieves the Y coordinate of a #ClutterActor, in #ClutterUnits. - * - * This function tries to "do what you mean", by returning the - * correct value depending on the actor's state. - * - * If the actor has a valid allocation, this function will return - * the Y coordinate of the origin of the allocation box. - * - * If the actor has any fixed coordinate set using clutter_actor_set_y(), - * clutter_actor_set_position() or clutter_actor_set_geometry(), this - * function will return that coordinate. - * - * If both the allocation and a fixed position are missing, this function - * will return 0. - * - * Return value: the Y coordinate, in #ClutterUnits, ignoring - * any transformation (i.e. scaling, rotation) - * - * Since: 0.6 - */ -ClutterUnit -clutter_actor_get_yu (ClutterActor *self) -{ - g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); - if (self->priv->needs_allocation) { if (self->priv->position_set) @@ -5267,23 +5762,24 @@ clutter_actor_set_scale (ClutterActor *self, gdouble scale_x, gdouble scale_y) { + ClutterActorPrivate *priv; + g_return_if_fail (CLUTTER_IS_ACTOR (self)); - g_object_ref (self); + priv = self->priv; + g_object_freeze_notify (G_OBJECT (self)); - self->priv->scale_x = scale_x; + priv->scale_x = scale_x; g_object_notify (G_OBJECT (self), "scale-x"); - self->priv->scale_y = scale_y; + priv->scale_y = scale_y; g_object_notify (G_OBJECT (self), "scale-y"); - g_object_thaw_notify (G_OBJECT (self)); - if (CLUTTER_ACTOR_IS_VISIBLE (self)) clutter_actor_queue_redraw (self); - g_object_unref (self); + g_object_thaw_notify (G_OBJECT (self)); } /** @@ -5304,39 +5800,8 @@ void clutter_actor_set_scale_full (ClutterActor *self, gdouble scale_x, gdouble scale_y, - int center_x, - int center_y) -{ - g_return_if_fail (CLUTTER_IS_ACTOR (self)); - - clutter_actor_set_scale_fullu (self, scale_x, scale_y, - CLUTTER_UNITS_FROM_DEVICE (center_x), - CLUTTER_UNITS_FROM_DEVICE (center_y)); -} - -/** - * clutter_actor_set_scale_fullu: - * @self: A #ClutterActor - * @scale_x: double factor to scale actor by horizontally. - * @scale_y: double factor to scale actor by vertically. - * @center_x: X coordinate of the center of the scale. - * @center_y: Y coordinate of the center of the scale - * - * %ClutterUnit version of clutter_actor_set_scale_full(). - * - * Scales an actor with the given factors around the given center - * point. The center point is specified in - * %ClutterUnits relative to the anchor point (usually - * the top left corner of the actor). - * - * Since: 1.0 - */ -void -clutter_actor_set_scale_fullu (ClutterActor *self, - gdouble scale_x, - gdouble scale_y, - ClutterUnit center_x, - ClutterUnit center_y) + gfloat center_x, + gfloat center_y) { ClutterActorPrivate *priv; @@ -5444,45 +5909,15 @@ clutter_actor_get_scale (ClutterActor *self, */ void clutter_actor_get_scale_center (ClutterActor *self, - gint *center_x, - gint *center_y) -{ - ClutterUnit xu, yu; - - g_return_if_fail (CLUTTER_IS_ACTOR (self)); - - clutter_actor_get_scale_centeru (self, &xu, &yu); - - if (center_x) - *center_x = CLUTTER_UNITS_TO_DEVICE (xu); - if (center_y) - *center_y = CLUTTER_UNITS_TO_DEVICE (yu); -} - -/** - * clutter_actor_get_scale_centeru: - * @self: A #ClutterActor - * @center_x: (out): Location to store the X position of the scale center, or %NULL. - * @center_y: (out): Location to store the Y position of the scale center, or %NULL. - * - * ClutterUnits version of clutter_actor_get_scale_center(). - * - * Retrieves the scale center coordinate in units relative to the top - * left corner of the actor. If the scale center was specified using a - * #ClutterGravity this will calculate the unit offset using the - * current size of the actor. - * - * Since: 1.0 - */ -void -clutter_actor_get_scale_centeru (ClutterActor *self, - ClutterUnit *center_x, - ClutterUnit *center_y) + gfloat *center_x, + gfloat *center_y) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); clutter_anchor_coord_get_units (self, &self->priv->scale_center, - center_x, center_y, NULL); + center_x, + center_y, + NULL); } /** @@ -5517,12 +5952,20 @@ void clutter_actor_set_opacity (ClutterActor *self, guint8 opacity) { + ClutterActorPrivate *priv; + g_return_if_fail (CLUTTER_IS_ACTOR (self)); - self->priv->opacity = opacity; + priv = self->priv; - if (CLUTTER_ACTOR_IS_VISIBLE (self)) - clutter_actor_queue_redraw (self); + if (priv->opacity != opacity) + { + priv->opacity = opacity; + + clutter_actor_queue_redraw (self); + + g_object_notify (G_OBJECT (self), "opacity"); + } } /** @@ -5648,27 +6091,14 @@ clutter_actor_get_gid (ClutterActor *self) * @self: a #ClutterActor * @depth: Z co-ord * - * Sets the Z co-ordinate of @self to @depth. The Units of which are dependant - * on the perspective setup. + * Sets the Z coordinate of @self to @depth. + * + * The unit used by @depth is dependant on the perspective setup. See + * also clutter_stage_set_perspective(). */ void clutter_actor_set_depth (ClutterActor *self, - gint depth) -{ - clutter_actor_set_depthu (self, CLUTTER_UNITS_FROM_DEVICE (depth)); -} - -/** - * clutter_actor_set_depthu: - * @self: a #ClutterActor - * @depth: Z co-ordinate, in #ClutterUnits - * - * Sets the Z co-ordinate of @self to @depth in #ClutterUnits, the - * units of which are dependant on the perspective setup. - */ -void -clutter_actor_set_depthu (ClutterActor *self, - ClutterUnit depth) + gfloat depth) { ClutterActorPrivate *priv; @@ -5678,7 +6108,7 @@ clutter_actor_set_depthu (ClutterActor *self, if (priv->z != depth) { - /* Sets Z value. - FIXME: should invert ?*/ + /* Sets Z value - XXX 2.0: should we invert? */ priv->z = depth; if (priv->parent_actor && CLUTTER_IS_CONTAINER (priv->parent_actor)) @@ -5688,15 +6118,14 @@ clutter_actor_set_depthu (ClutterActor *self, /* We need to resort the container stacking order as to * correctly render alpha values. * - * FIXME: This is sub optimal. maybe queue the the sort + * FIXME: This is sub-optimal. maybe queue the the sort * before stacking */ parent = CLUTTER_CONTAINER (priv->parent_actor); clutter_container_sort_depth_order (parent); } - if (CLUTTER_ACTOR_IS_VISIBLE (self)) - clutter_actor_queue_redraw (self); + clutter_actor_queue_redraw (self); g_object_notify (G_OBJECT (self), "depth"); } @@ -5710,86 +6139,14 @@ clutter_actor_set_depthu (ClutterActor *self, * * Return value: the depth of the actor */ -gint +gfloat clutter_actor_get_depth (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1); - return CLUTTER_UNITS_TO_DEVICE (self->priv->z); -} - -/** - * clutter_actor_get_depthu: - * @self: a #ClutterActor - * - * Retrieves the depth of @self. - * - * Return value: the depth of the actor, in #ClutterUnits - * - * Since: 0.6 - */ -ClutterUnit -clutter_actor_get_depthu (ClutterActor *self) -{ - g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1); - return self->priv->z; } -/** - * clutter_actor_set_rotationu: - * @self: a #ClutterActor - * @axis: the axis of rotation - * @angle: the angle of rotation - * @x: X coordinate of the rotation center, in #ClutterUnits - * @y: Y coordinate of the rotation center, in #ClutterUnits - * @z: Z coordinate of the rotation center, in #ClutterUnits - * - * Sets the rotation angle of @self around the given axis. - * - * This function is the units based variant of clutter_actor_set_rotation(). - * - * Since: 0.8 - */ -void -clutter_actor_set_rotationu (ClutterActor *self, - ClutterRotateAxis axis, - gdouble angle, - ClutterUnit x, - ClutterUnit y, - ClutterUnit z) -{ - ClutterActorPrivate *priv; - - g_return_if_fail (CLUTTER_IS_ACTOR (self)); - - priv = self->priv; - - g_object_freeze_notify (G_OBJECT (self)); - - clutter_actor_set_rotation_internal (self, axis, angle); - - switch (axis) - { - case CLUTTER_X_AXIS: - clutter_anchor_coord_set_units (&priv->rx_center, x, y, z); - g_object_notify (G_OBJECT (self), "rotation-center-x"); - break; - case CLUTTER_Y_AXIS: - clutter_anchor_coord_set_units (&priv->ry_center, x, y, z); - g_object_notify (G_OBJECT (self), "rotation-center-y"); - break; - case CLUTTER_Z_AXIS: - if (priv->rz_center.is_fractional) - g_object_notify (G_OBJECT (self), "rotation-center-z-gravity"); - clutter_anchor_coord_set_units (&priv->rz_center, x, y, z); - g_object_notify (G_OBJECT (self), "rotation-center-z"); - break; - } - - g_object_thaw_notify (G_OBJECT (self)); -} - /** * clutter_actor_set_rotation: * @self: a #ClutterActor @@ -5812,22 +6169,47 @@ clutter_actor_set_rotationu (ClutterActor *self, * actor, set using clutter_actor_set_anchor_point(). If no anchor * point is set, the upper left corner is assumed as the origin. * - * Since: 0.6 + * Since: 0.8 */ void clutter_actor_set_rotation (ClutterActor *self, ClutterRotateAxis axis, gdouble angle, - gint x, - gint y, - gint z) + gfloat x, + gfloat y, + gfloat z) { + ClutterActorPrivate *priv; + g_return_if_fail (CLUTTER_IS_ACTOR (self)); - clutter_actor_set_rotationu (self, axis, angle, - CLUTTER_UNITS_FROM_DEVICE (x), - CLUTTER_UNITS_FROM_DEVICE (y), - CLUTTER_UNITS_FROM_DEVICE (z)); + priv = self->priv; + + g_object_freeze_notify (G_OBJECT (self)); + + clutter_actor_set_rotation_internal (self, axis, angle); + + switch (axis) + { + case CLUTTER_X_AXIS: + clutter_anchor_coord_set_units (&priv->rx_center, x, y, z); + g_object_notify (G_OBJECT (self), "rotation-center-x"); + break; + + case CLUTTER_Y_AXIS: + clutter_anchor_coord_set_units (&priv->ry_center, x, y, z); + g_object_notify (G_OBJECT (self), "rotation-center-y"); + break; + + case CLUTTER_Z_AXIS: + if (priv->rz_center.is_fractional) + g_object_notify (G_OBJECT (self), "rotation-center-z-gravity"); + clutter_anchor_coord_set_units (&priv->rz_center, x, y, z); + g_object_notify (G_OBJECT (self), "rotation-center-z"); + break; + } + + g_object_thaw_notify (G_OBJECT (self)); } /** @@ -5845,9 +6227,9 @@ clutter_actor_set_rotation (ClutterActor *self, * Since: 1.0 */ void -clutter_actor_set_z_rotation_from_gravity (ClutterActor *self, - gdouble angle, - ClutterGravity gravity) +clutter_actor_set_z_rotation_from_gravity (ClutterActor *self, + gdouble angle, + ClutterGravity gravity) { ClutterActorPrivate *priv; @@ -5872,31 +6254,26 @@ clutter_actor_set_z_rotation_from_gravity (ClutterActor *self, } /** - * clutter_actor_get_rotationu: + * clutter_actor_get_rotation: * @self: a #ClutterActor * @axis: the axis of rotation - * @x: (out): return value for the X coordinate of the center of rotation, - * in #ClutterUnits - * @y: (out): return value for the Y coordinate of the center of rotation, - * in #ClutterUnits - * @z: (out): return value for the Z coordinate of the center of rotation, - * in #ClutterUnits + * @x: (out): return value for the X coordinate of the center of rotation + * @y: (out): return value for the Y coordinate of the center of rotation + * @z: (out): return value for the Z coordinate of the center of rotation * * Retrieves the angle and center of rotation on the given axis, * set using clutter_actor_set_rotation(). * - * This function is the units based variant of clutter_actor_get_rotation(). - * * Return value: the angle of rotation * * Since: 0.8 */ gdouble -clutter_actor_get_rotationu (ClutterActor *self, - ClutterRotateAxis axis, - ClutterUnit *x, - ClutterUnit *y, - ClutterUnit *z) +clutter_actor_get_rotation (ClutterActor *self, + ClutterRotateAxis axis, + gfloat *x, + gfloat *y, + gfloat *z) { ClutterActorPrivate *priv; gdouble retval = 0; @@ -5929,50 +6306,6 @@ clutter_actor_get_rotationu (ClutterActor *self, return retval; } -/** - * clutter_actor_get_rotation: - * @self: a #ClutterActor - * @axis: the axis of rotation - * @x: (out): return value for the X coordinate of the center of rotation - * @y: (out): return value for the Y coordinate of the center of rotation - * @z: (out): return value for the Z coordinate of the center of rotation - * - * Retrieves the angle and center of rotation on the given axis, - * set using clutter_actor_set_angle(). - * - * The coordinates of the center returned by this function depend on - * the axis passed. - * - * Return value: the angle of rotation. - * - * Since: 0.6 - */ -gdouble -clutter_actor_get_rotation (ClutterActor *self, - ClutterRotateAxis axis, - gint *x, - gint *y, - gint *z) -{ - ClutterUnit xu, yu, zu; - gdouble angle; - - g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0); - - angle = clutter_actor_get_rotationu (self, axis, &xu, &yu, &zu); - - if (x) - *x = CLUTTER_UNITS_TO_DEVICE (xu); - - if (y) - *y = CLUTTER_UNITS_TO_DEVICE (yu); - - if (z) - *z = CLUTTER_UNITS_TO_DEVICE (zu); - - return angle; -} - /** * clutter_actor_get_z_rotation_gravity: * @self: A #ClutterActor @@ -5994,14 +6327,12 @@ clutter_actor_get_z_rotation_gravity (ClutterActor *self) } /** - * clutter_actor_set_clipu: + * clutter_actor_set_clip: * @self: A #ClutterActor - * @xoff: X offset of the clip rectangle, in #ClutterUnits - * @yoff: Y offset of the clip rectangle, in #ClutterUnits - * @width: Width of the clip rectangle, in #ClutterUnits - * @height: Height of the clip rectangle, in #ClutterUnits - * - * Unit-based variant of clutter_actor_set_clip() + * @xoff: X offset of the clip rectangle + * @yoff: Y offset of the clip rectangle + * @width: Width of the clip rectangle + * @height: Height of the clip rectangle * * Sets clip area for @self. The clip area is always computed from the * upper left corner of the actor, even if the anchor point is set @@ -6010,11 +6341,11 @@ clutter_actor_get_z_rotation_gravity (ClutterActor *self) * Since: 0.6 */ void -clutter_actor_set_clipu (ClutterActor *self, - ClutterUnit xoff, - ClutterUnit yoff, - ClutterUnit width, - ClutterUnit height) +clutter_actor_set_clip (ClutterActor *self, + gfloat xoff, + gfloat yoff, + gfloat width, + gfloat height) { ClutterActorPrivate *priv; @@ -6042,34 +6373,6 @@ clutter_actor_set_clipu (ClutterActor *self, g_object_notify (G_OBJECT (self), "clip"); } -/** - * clutter_actor_set_clip: - * @self: A #ClutterActor - * @xoff: X offset of the clip rectangle, in pixels - * @yoff: Y offset of the clip rectangle, in pixels - * @width: Width of the clip rectangle, in pixels - * @height: Height of the clip rectangle, in pixels - * - * Sets clip area in pixels for @self. The clip area is always computed - * from the upper left corner of the actor, even if the anchor point is - * set otherwise. - */ -void -clutter_actor_set_clip (ClutterActor *self, - gint xoff, - gint yoff, - gint width, - gint height) -{ - g_return_if_fail (CLUTTER_IS_ACTOR (self)); - - clutter_actor_set_clipu (self, - CLUTTER_UNITS_FROM_DEVICE (xoff), - CLUTTER_UNITS_FROM_DEVICE (yoff), - CLUTTER_UNITS_FROM_DEVICE (width), - CLUTTER_UNITS_FROM_DEVICE (height)); -} - /** * clutter_actor_remove_clip * @self: A #ClutterActor @@ -6110,25 +6413,23 @@ clutter_actor_has_clip (ClutterActor *self) } /** - * clutter_actor_get_clipu: + * clutter_actor_get_clip: * @self: a #ClutterActor * @xoff: (out): return location for the X offset of the clip rectangle, or %NULL * @yoff: (out): return location for the Y offset of the clip rectangle, or %NULL * @width: (out): return location for the width of the clip rectangle, or %NULL * @height: (out): return location for the height of the clip rectangle, or %NULL * - * Unit-based variant of clutter_actor_get_clip(). - * - * Gets the clip area for @self, in #ClutterUnits. + * Gets the clip area for @self, if any is set * * Since: 0.6 */ void -clutter_actor_get_clipu (ClutterActor *self, - ClutterUnit *xoff, - ClutterUnit *yoff, - ClutterUnit *width, - ClutterUnit *height) +clutter_actor_get_clip (ClutterActor *self, + gfloat *xoff, + gfloat *yoff, + gfloat *width, + gfloat *height) { ClutterActorPrivate *priv; @@ -6152,44 +6453,6 @@ clutter_actor_get_clipu (ClutterActor *self, *height = priv->clip[3]; } -/** - * clutter_actor_get_clip: - * @self: a #ClutterActor - * @xoff: (out): return location for the X offset of the clip rectangle, or %NULL - * @yoff: (out): return location for the Y offset of the clip rectangle, or %NULL - * @width: (out): return location for the width of the clip rectangle, or %NULL - * @height: (out): return location for the height of the clip rectangle, or %NULL - * - * Gets the clip area for @self, in pixels. - * - * Since: 0.6 - */ -void -clutter_actor_get_clip (ClutterActor *self, - gint *xoff, - gint *yoff, - gint *width, - gint *height) -{ - struct clipu { ClutterUnit x, y, width, height; } c = { 0, }; - - g_return_if_fail (CLUTTER_IS_ACTOR (self)); - - clutter_actor_get_clipu (self, &c.x, &c.y, &c.width, &c.height); - - if (xoff) - *xoff = CLUTTER_UNITS_TO_DEVICE (c.x); - - if (yoff) - *yoff = CLUTTER_UNITS_TO_DEVICE (c.y); - - if (width) - *width = CLUTTER_UNITS_TO_DEVICE (c.width); - - if (height) - *height = CLUTTER_UNITS_TO_DEVICE (c.height); -} - /** * clutter_actor_set_parent: * @self: A #ClutterActor @@ -6237,19 +6500,15 @@ clutter_actor_set_parent (ClutterActor *self, if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_REPARENT)) g_signal_emit (self, actor_signals[PARENT_SET], 0, NULL); - /* the invariant is: if the parent is realized, the we must be - * realized after set_parent(). the call to clutter_actor_show() - * will cause this anyway, but we need to maintain the invariant - * even for actors that have :show-on-set-parent set to FALSE + /* If parent is mapped or realized, we need to also be mapped or + * realized once we're inside the parent. */ - if (CLUTTER_ACTOR_IS_REALIZED (priv->parent_actor)) - clutter_actor_realize (self); + clutter_actor_update_map_state (self, MAP_STATE_CHECK); if (priv->show_on_set_parent) clutter_actor_show (self); - if (CLUTTER_ACTOR_IS_VISIBLE (priv->parent_actor) && - CLUTTER_ACTOR_IS_VISIBLE (self)) + if (CLUTTER_ACTOR_IS_MAPPED (self)) { clutter_actor_queue_redraw (self); } @@ -6296,6 +6555,8 @@ clutter_actor_get_parent (ClutterActor *self) * Retrieves the 'paint' visibility of an actor recursively checking for non * visible parents. * + * This is by definition the same as CLUTTER_ACTOR_IS_MAPPED(). + * * Return Value: TRUE if the actor is visibile and will be painted. * * Since: 0.8.4 @@ -6305,17 +6566,7 @@ clutter_actor_get_paint_visibility (ClutterActor *actor) { g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE); - do - { - if (!CLUTTER_ACTOR_IS_VISIBLE (actor)) - return FALSE; - - if (CLUTTER_PRIVATE_FLAGS (actor) & CLUTTER_ACTOR_IS_TOPLEVEL) - return TRUE; - } - while ((actor = clutter_actor_get_parent (actor)) != NULL); - - return FALSE; + return CLUTTER_ACTOR_IS_MAPPED (actor); } /** @@ -6335,8 +6586,7 @@ clutter_actor_unparent (ClutterActor *self) { ClutterActorPrivate *priv; ClutterActor *old_parent; - - gboolean show_on_set_parent_enabled = TRUE; + gboolean was_mapped; g_return_if_fail (CLUTTER_IS_ACTOR (self)); @@ -6345,47 +6595,29 @@ clutter_actor_unparent (ClutterActor *self) if (priv->parent_actor == NULL) return; - show_on_set_parent_enabled = priv->show_on_set_parent; + was_mapped = CLUTTER_ACTOR_IS_MAPPED (self); + + /* we need to unrealize *before* we set parent_actor to NULL, + * because in an unrealize method actors are dissociating from the + * stage, which means they need to be able to + * clutter_actor_get_stage(). This should unmap and unrealize, + * unless we're reparenting. + */ + clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNREALIZED); old_parent = priv->parent_actor; priv->parent_actor = NULL; - /* if we are uparenting we hide ourselves; if we are just reparenting - * there's no need to do that, as the paint is fast enough. - */ - if (CLUTTER_ACTOR_IS_REALIZED (self)) - { - if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_REPARENT)) - clutter_actor_hide (self); - } - - /* clutter_actor_hide() will set the :show-on-set-parent property - * to FALSE because the actor doesn't have a parent anymore; but - * we need to return the actor to its initial state, so we force - * the state of the :show-on-set-parent property to its value - * previous the unparenting - */ - priv->show_on_set_parent = show_on_set_parent_enabled; - - if (CLUTTER_ACTOR_IS_VISIBLE (self)) - clutter_actor_queue_redraw (self); - /* clutter_actor_reparent() will emit ::parent-set for us */ if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_REPARENT)) g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent); - /* Queue a redraw on old_parent */ - if (CLUTTER_ACTOR_IS_VISIBLE (old_parent)) + /* Queue a redraw on old_parent only if we were painted in the first + * place. Will be no-op if old parent is not shown. + */ + if (was_mapped && !CLUTTER_ACTOR_IS_MAPPED (self)) clutter_actor_queue_redraw (old_parent); - /* Could also need to relayout */ - if (old_parent->priv->needs_width_request || - old_parent->priv->needs_height_request || - old_parent->priv->needs_allocation) - { - clutter_actor_queue_relayout (old_parent); - } - /* remove the reference we acquired in clutter_actor_set_parent() */ g_object_unref (self); } @@ -6397,7 +6629,10 @@ clutter_actor_unparent (ClutterActor *self) * * This function resets the parent actor of @self. It is * logically equivalent to calling clutter_actor_unparent() - * and clutter_actor_set_parent(). + * and clutter_actor_set_parent(), but more efficiently + * implemented, ensures the child is not finalized + * when unparented, and emits the parent-set signal only + * one time. * * Since: 0.2 */ @@ -6450,6 +6685,9 @@ clutter_actor_reparent (ClutterActor *self, g_object_unref (self); CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_IN_REPARENT); + + /* the IN_REPARENT flag suspends state updates */ + clutter_actor_update_map_state (self, MAP_STATE_CHECK); } } /** @@ -6700,55 +6938,6 @@ clutter_actor_get_reactive (ClutterActor *actor) return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE; } -/** - * clutter_actor_set_anchor_point: - * @self: a #ClutterActor - * @anchor_x: X coordinate of the anchor point - * @anchor_y: Y coordinate of the anchor point - * - * Sets an anchor point for the @actor. The anchor point is a point in the - * coordinate space of an actor to which the actor position within its - * parent is relative; the default is (0, 0), i.e. the top-left corner of - * the actor. - * - * Since: 0.6 - */ -void -clutter_actor_set_anchor_point (ClutterActor *self, - gint anchor_x, - gint anchor_y) -{ - g_return_if_fail (CLUTTER_IS_ACTOR (self)); - - clutter_actor_set_anchor_pointu (self, - CLUTTER_UNITS_FROM_DEVICE (anchor_x), - CLUTTER_UNITS_FROM_DEVICE (anchor_y)); -} - -/** - * clutter_actor_move_anchor_point: - * @self: a #ClutterActor - * @anchor_x: X coordinate of the anchor point - * @anchor_y: Y coordinate of the anchor point - * - * Sets an anchor point for the @actor, and adjusts the actor postion so - * that the relative position of the actor toward its parent remains the - * same. - * - * Since: 0.6 - */ -void -clutter_actor_move_anchor_point (ClutterActor *self, - gint anchor_x, - gint anchor_y) -{ - g_return_if_fail (CLUTTER_IS_ACTOR (self)); - - clutter_actor_move_anchor_pointu (self, - CLUTTER_UNITS_FROM_DEVICE (anchor_x), - CLUTTER_UNITS_FROM_DEVICE (anchor_y)); -} - /** * clutter_actor_get_anchor_point: * @self: a #ClutterActor @@ -6761,30 +6950,26 @@ clutter_actor_move_anchor_point (ClutterActor *self, */ void clutter_actor_get_anchor_point (ClutterActor *self, - gint *anchor_x, - gint *anchor_y) + gfloat *anchor_x, + gfloat *anchor_y) { ClutterActorPrivate *priv; - ClutterUnit xu, yu; g_return_if_fail (CLUTTER_IS_ACTOR (self)); priv = self->priv; - clutter_anchor_coord_get_units (self, &priv->anchor, &xu, &yu, NULL); - - if (anchor_x) - *anchor_x = CLUTTER_UNITS_TO_DEVICE (xu); - - if (anchor_y) - *anchor_y = CLUTTER_UNITS_TO_DEVICE (yu); + clutter_anchor_coord_get_units (self, &priv->anchor, + anchor_x, + anchor_y, + NULL); } /** - * clutter_actor_set_anchor_pointu: + * clutter_actor_set_anchor_point: * @self: a #ClutterActor - * @anchor_x: X coordinate of the anchor point, in #ClutterUnits - * @anchor_y: Y coordinate of the anchor point, in #ClutterUnits + * @anchor_x: X coordinate of the anchor point + * @anchor_y: Y coordinate of the anchor point * * Sets an anchor point for @self. The anchor point is a point in the * coordinate space of an actor to which the actor position within its @@ -6794,13 +6979,13 @@ clutter_actor_get_anchor_point (ClutterActor *self, * Since: 0.6 */ void -clutter_actor_set_anchor_pointu (ClutterActor *self, - ClutterUnit anchor_x, - ClutterUnit anchor_y) +clutter_actor_set_anchor_point (ClutterActor *self, + gfloat anchor_x, + gfloat anchor_y) { ClutterActorPrivate *priv; gboolean changed = FALSE; - ClutterUnit old_anchor_x, old_anchor_y; + gfloat old_anchor_x, old_anchor_y; g_return_if_fail (CLUTTER_IS_ACTOR (self)); @@ -6809,7 +6994,9 @@ clutter_actor_set_anchor_pointu (ClutterActor *self, g_object_freeze_notify (G_OBJECT (self)); clutter_anchor_coord_get_units (self, &priv->anchor, - &old_anchor_x, &old_anchor_y, NULL); + &old_anchor_x, + &old_anchor_y, + NULL); if (priv->anchor.is_fractional) g_object_notify (G_OBJECT (self), "anchor-gravity"); @@ -6828,10 +7015,10 @@ clutter_actor_set_anchor_pointu (ClutterActor *self, clutter_anchor_coord_set_units (&priv->anchor, anchor_x, anchor_y, 0); - g_object_thaw_notify (G_OBJECT (self)); - if (changed && CLUTTER_ACTOR_IS_VISIBLE (self)) clutter_actor_queue_redraw (self); + + g_object_thaw_notify (G_OBJECT (self)); } /** @@ -6859,7 +7046,7 @@ clutter_actor_get_anchor_point_gravity (ClutterActor *self) } /** - * clutter_actor_move_anchor_pointu: + * clutter_actor_move_anchor_point: * @self: a #ClutterActor * @anchor_x: X coordinate of the anchor point * @anchor_y: Y coordinate of the anchor point @@ -6870,57 +7057,34 @@ clutter_actor_get_anchor_point_gravity (ClutterActor *self) * Since: 0.6 */ void -clutter_actor_move_anchor_pointu (ClutterActor *self, - ClutterUnit anchor_x, - ClutterUnit anchor_y) +clutter_actor_move_anchor_point (ClutterActor *self, + gfloat anchor_x, + gfloat anchor_y) { ClutterActorPrivate *priv; - ClutterUnit old_anchor_x, old_anchor_y; + gfloat old_anchor_x, old_anchor_y; g_return_if_fail (CLUTTER_IS_ACTOR (self)); priv = self->priv; clutter_anchor_coord_get_units (self, &priv->anchor, - &old_anchor_x, &old_anchor_y, NULL); + &old_anchor_x, + &old_anchor_y, + NULL); g_object_freeze_notify (G_OBJECT (self)); clutter_actor_set_anchor_point (self, anchor_x, anchor_y); if (priv->position_set) - clutter_actor_move_byu (self, - anchor_x - old_anchor_x, - anchor_y - old_anchor_y); + clutter_actor_move_by (self, + anchor_x - old_anchor_x, + anchor_y - old_anchor_y); g_object_thaw_notify (G_OBJECT (self)); } -/** - * clutter_actor_get_anchor_pointu: - * @self: a #ClutterActor - * @anchor_x: (out): return location for the X coordinate of the anchor point - * @anchor_y: (out): return location for the Y coordinate of the anchor point - * - * Gets the current anchor point of the @actor in #ClutterUnits. - * - * Since: 0.6 - */ -void -clutter_actor_get_anchor_pointu (ClutterActor *self, - ClutterUnit *anchor_x, - ClutterUnit *anchor_y) -{ - ClutterActorPrivate *priv; - - g_return_if_fail (CLUTTER_IS_ACTOR (self)); - - priv = self->priv; - - clutter_anchor_coord_get_units (self, &priv->anchor, - anchor_x, anchor_y, NULL); -} - /** * clutter_actor_move_anchor_point_from_gravity: * @self: a #ClutterActor @@ -6942,7 +7106,7 @@ void clutter_actor_move_anchor_point_from_gravity (ClutterActor *self, ClutterGravity gravity) { - ClutterUnit old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y; + gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y; ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); @@ -6952,15 +7116,19 @@ clutter_actor_move_anchor_point_from_gravity (ClutterActor *self, g_object_freeze_notify (G_OBJECT (self)); clutter_anchor_coord_get_units (self, &priv->anchor, - &old_anchor_x, &old_anchor_y, NULL); + &old_anchor_x, + &old_anchor_y, + NULL); clutter_actor_set_anchor_point_from_gravity (self, gravity); clutter_anchor_coord_get_units (self, &priv->anchor, - &new_anchor_x, &new_anchor_y, NULL); + &new_anchor_x, + &new_anchor_y, + NULL); if (priv->position_set) - clutter_actor_move_byu (self, - new_anchor_x - old_anchor_x, - new_anchor_y - old_anchor_y); + clutter_actor_move_by (self, + new_anchor_x - old_anchor_x, + new_anchor_y - old_anchor_y); g_object_thaw_notify (G_OBJECT (self)); } @@ -7009,13 +7177,13 @@ typedef enum PARSE_ANCHOR_Y } ParseDimension; -static ClutterUnit +static gfloat parse_units (ClutterActor *self, ParseDimension dimension, JsonNode *node) { GValue value = { 0, }; - ClutterUnit retval = 0; + gfloat retval = 0; if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE) return 0; @@ -7024,87 +7192,29 @@ parse_units (ClutterActor *self, if (G_VALUE_HOLDS (&value, G_TYPE_INT)) { - gint pixels = g_value_get_int (&value); - - retval = CLUTTER_UNITS_FROM_DEVICE (pixels); + retval = (gfloat) g_value_get_int (&value); + } + else if (G_VALUE_HOLDS (&value, G_TYPE_FLOAT)) + { + retval = g_value_get_float (&value); } else if (G_VALUE_HOLDS (&value, G_TYPE_STRING)) { - gint64 val; - gchar *end; + ClutterUnits units; + gboolean res; - val = g_ascii_strtoll (g_value_get_string (&value), &end, 10); - - /* skip whitespace */ - while (g_ascii_isspace (*end)) - end++; - - /* assume pixels */ - if (*end == '\0') + res = clutter_units_from_string (&units, g_value_get_string (&value)); + if (res) + retval = clutter_units_to_pixels (&units); + else { - retval = CLUTTER_UNITS_FROM_DEVICE (val); - goto out; + g_warning ("Invalid value '%s': integers, strings or floating point " + "values can be used for the x, y, width and height " + "properties. Valid modifiers for strings are 'px', 'mm', " + "'pt' and 'em'.", + g_value_get_string (&value)); + retval = 0; } - - if (strcmp (end, "px") == 0) - { - retval = CLUTTER_UNITS_FROM_DEVICE (val); - goto out; - } - - if (strcmp (end, "mm") == 0) - { - retval = CLUTTER_UNITS_FROM_MM (val); - goto out; - } - - if (strcmp (end, "pt") == 0) - { - retval = CLUTTER_UNITS_FROM_POINTS (val); - goto out; - } - - if (end[0] == '%' && end[1] == '\0') - { - ClutterActor *stage; - - if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL) - { - g_warning ("Unable to set percentage of %s on a top-level " - "actor of type '%s'", - (dimension == PARSE_X || - dimension == PARSE_WIDTH || - dimension == PARSE_ANCHOR_X) ? "width" : "height", - g_type_name (G_OBJECT_TYPE (self))); - retval = 0; - goto out; - } - - stage = clutter_actor_get_stage (self); - if (stage == NULL) - stage = clutter_stage_get_default (); - - if (dimension == PARSE_X || - dimension == PARSE_WIDTH || - dimension == PARSE_ANCHOR_X) - { - retval = clutter_actor_get_widthu (stage) * val; - } - else - { - retval = clutter_actor_get_heightu (stage) * val; - } - - goto out; - } - - g_warning ("Invalid value '%s': integers, strings or floating point " - "values can be used for the x, y, width and height " - "properties. Valid modifiers for strings are 'px', 'mm' " - "and '%%'.", - g_value_get_string (&value)); - - retval = 0; } else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE)) { @@ -7132,11 +7242,11 @@ parse_units (ClutterActor *self, dimension == PARSE_WIDTH || dimension == PARSE_ANCHOR_X) { - retval = clutter_actor_get_widthu (stage) * val; + retval = clutter_actor_get_width (stage) * val; } else { - retval = clutter_actor_get_heightu (stage) * val; + retval = clutter_actor_get_height (stage) * val; } } else @@ -7158,9 +7268,9 @@ typedef struct { gdouble angle; - ClutterUnit center_x; - ClutterUnit center_y; - ClutterUnit center_z; + gfloat center_x; + gfloat center_y; + gfloat center_z; } RotationInfo; static inline gboolean @@ -7327,8 +7437,8 @@ clutter_actor_parse_custom_node (ClutterScriptable *scriptable, (strcmp (name, "anchor_x") == 0) || (strcmp (name, "anchor_y") == 0)) { - ClutterUnit units; ParseDimension dimension; + gfloat units; if (name[0] == 'x') dimension = PARSE_X; @@ -7349,7 +7459,7 @@ clutter_actor_parse_custom_node (ClutterScriptable *scriptable, /* convert back to pixels: all properties are pixel-based */ g_value_init (value, G_TYPE_INT); - g_value_set_int (value, CLUTTER_UNITS_TO_DEVICE (units)); + g_value_set_int (value, units); retval = TRUE; } @@ -7378,7 +7488,18 @@ clutter_actor_set_custom_property (ClutterScriptable *scriptable, const gchar *name, const GValue *value) { - CLUTTER_NOTE (SCRIPT, "in ClutterActor::set_custom_property('%s')", name); +#ifdef CLUTTER_ENABLE_DEBUG + { + gchar *tmp = g_strdup_value_contents (value); + + CLUTTER_NOTE (SCRIPT, + "in ClutterActor::set_custom_property('%s') = %s", + name, + tmp); + + g_free (tmp); + } +#endif if (strcmp (name, "rotation") == 0) { @@ -7389,11 +7510,11 @@ clutter_actor_set_custom_property (ClutterScriptable *scriptable, info = g_value_get_pointer (value); - clutter_actor_set_rotationu (CLUTTER_ACTOR (scriptable), - info->axis, info->angle, - info->center_x, - info->center_y, - info->center_z); + clutter_actor_set_rotation (CLUTTER_ACTOR (scriptable), + info->axis, info->angle, + info->center_x, + info->center_y, + info->center_z); g_slice_free (RotationInfo, info); } @@ -7411,12 +7532,10 @@ clutter_scriptable_iface_init (ClutterScriptableIface *iface) /** * clutter_actor_transform_stage_point * @self: A #ClutterActor - * @x: (in): x screen coordinate of the point to unproject, in #ClutterUnits - * @y: (in): y screen coordinate of the point to unproject, in #ClutterUnits - * @x_out: (out): return location for the unprojected x coordinance, in - * #ClutterUnits - * @y_out: (out): return location for the unprojected y coordinance, in - * #ClutterUnits + * @x: (in): x screen coordinate of the point to unproject + * @y: (in): y screen coordinate of the point to unproject + * @x_out: (out): return location for the unprojected x coordinance + * @y_out: (out): return location for the unprojected y coordinance * * This function translates screen coordinates (@x, @y) to * coordinates relative to the actor. For example, it can be used to translate @@ -7431,7 +7550,8 @@ clutter_scriptable_iface_init (ClutterScriptableIface *iface) * * Note: This function is fairly computationally intensive. * - * Note: This function only works when the allocation is up-to-date, i.e. inside of paint() + * Note: This function only works when the allocation is up-to-date, + * i.e. inside of paint() * * Return value: %TRUE if conversion was successful. * @@ -7439,16 +7559,16 @@ clutter_scriptable_iface_init (ClutterScriptableIface *iface) */ gboolean clutter_actor_transform_stage_point (ClutterActor *self, - ClutterUnit x, - ClutterUnit y, - ClutterUnit *x_out, - ClutterUnit *y_out) + gfloat x, + gfloat y, + gfloat *x_out, + gfloat *y_out) { ClutterVertex v[4]; float ST[3][3]; float RQ[3][3]; int du, dv, xi, yi; - ClutterUnit px, py; + float px, py; float xf, yf, wf, det; ClutterActorPrivate *priv; @@ -7476,13 +7596,13 @@ clutter_actor_transform_stage_point (ClutterActor *self, /* Keeping these as ints simplifies the multiplication (no significant * loss of precision here). */ - du = CLUTTER_UNITS_TO_DEVICE (priv->allocation.x2 - priv->allocation.x1); - dv = CLUTTER_UNITS_TO_DEVICE (priv->allocation.y2 - priv->allocation.y1); + du = (int) (priv->allocation.x2 - priv->allocation.x1); + dv = (int) (priv->allocation.y2 - priv->allocation.y1); if (!du || !dv) return FALSE; -#define UX2FP CLUTTER_UNITS_TO_FLOAT +#define UX2FP(x) (x) #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c))) /* First, find mapping from unit uv square to xy quadrilateral; this @@ -7574,18 +7694,18 @@ clutter_actor_transform_stage_point (ClutterActor *self, * Now transform our point with the ST matrix; the notional w * coordinate is 1, hence the last part is simply added. */ - xi = CLUTTER_UNITS_TO_DEVICE (x); - yi = CLUTTER_UNITS_TO_DEVICE (y); + xi = (int) x; + yi = (int) y; xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0]; yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1]; wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2]; if (x_out) - *x_out = CLUTTER_UNITS_FROM_FLOAT (xf / wf); + *x_out = xf / wf; if (y_out) - *y_out = CLUTTER_UNITS_FROM_FLOAT (yf / wf); + *y_out = yf / wf; #undef UX2FP #undef DET2FP @@ -7606,7 +7726,7 @@ clutter_geometry_copy (const ClutterGeometry *geometry) static void clutter_geometry_free (ClutterGeometry *geometry) { - if (G_LIKELY (geometry)) + if (G_LIKELY (geometry != NULL)) g_slice_free (ClutterGeometry, geometry); } @@ -7637,7 +7757,7 @@ clutter_vertex_copy (const ClutterVertex *vertex) static void clutter_vertex_free (ClutterVertex *vertex) { - if (G_UNLIKELY (vertex)) + if (G_UNLIKELY (vertex != NULL)) g_slice_free (ClutterVertex, vertex); } @@ -7667,7 +7787,7 @@ clutter_actor_box_copy (const ClutterActorBox *box) static void clutter_actor_box_free (ClutterActorBox *box) { - if (G_LIKELY (box)) + if (G_LIKELY (box != NULL)) g_slice_free (ClutterActorBox, box); } @@ -7689,9 +7809,11 @@ clutter_actor_box_get_type (void) struct _ShaderData { ClutterShader *shader; - GHashTable *value_hash; /*< list of GValue's that should be set - * on the shader before each paint cycle - */ + + /* list of values that should be set on the shader + * before each paint cycle + */ + GHashTable *value_hash; }; static void @@ -7706,9 +7828,9 @@ static void destroy_shader_data (ClutterActor *self) { ClutterActorPrivate *actor_priv = self->priv; - ShaderData *shader_data = actor_priv->shader_data; + ShaderData *shader_data = actor_priv->shader_data; - if (!shader_data) + if (shader_data == NULL) return; if (shader_data->shader) @@ -7723,7 +7845,7 @@ destroy_shader_data (ClutterActor *self) shader_data->value_hash = NULL; } - g_free (shader_data); + g_slice_free (ShaderData, shader_data); actor_priv->shader_data = NULL; } @@ -7750,7 +7872,7 @@ clutter_actor_get_shader (ClutterActor *self) actor_priv = self->priv; shader_data = actor_priv->shader_data; - if (!shader_data) + if (shader_data == NULL) return NULL; return shader_data->shader; @@ -7762,6 +7884,7 @@ clutter_actor_get_shader (ClutterActor *self) * @shader: a #ClutterShader or %NULL to unset the shader. * * Sets the #ClutterShader to be used when rendering @self. + * * If @shader is %NULL it will unset any currently set shader * for the actor. * @@ -7779,30 +7902,33 @@ clutter_actor_set_shader (ClutterActor *self, g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); g_return_val_if_fail (shader == NULL || CLUTTER_IS_SHADER (shader), FALSE); - if (shader) + if (shader != NULL) g_object_ref (shader); else - /* if shader passed in is NULL we destroy the shader */ - destroy_shader_data (self); + { + /* if shader passed in is NULL we destroy the shader */ + destroy_shader_data (self); + return TRUE; + } actor_priv = self->priv; shader_data = actor_priv->shader_data; - if (!shader_data) + if (shader_data == NULL) { - actor_priv->shader_data = shader_data = g_new0 (ShaderData, 1); + actor_priv->shader_data = shader_data = g_slice_new (ShaderData); + shader_data->shader = NULL; shader_data->value_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, shader_value_free); } - if (shader_data->shader) + if (shader_data->shader != NULL) g_object_unref (shader_data->shader); shader_data->shader = shader; - if (CLUTTER_ACTOR_IS_VISIBLE (self)) - clutter_actor_queue_redraw (self); + clutter_actor_queue_redraw (self); return TRUE; } @@ -8040,36 +8166,48 @@ void clutter_actor_get_box_from_vertices (ClutterVertex vtx[4], ClutterActorBox *box) { - ClutterUnit x_1, x_2, y_1, y_2; + gfloat x_1, x_2, y_1, y_2; /* 4-way min/max */ x_1 = vtx[0].x; y_1 = vtx[0].y; + if (vtx[1].x < x_1) x_1 = vtx[1].x; + if (vtx[2].x < x_1) x_1 = vtx[2].x; + if (vtx[3].x < x_1) x_1 = vtx[3].x; + if (vtx[1].y < y_1) y_1 = vtx[1].y; + if (vtx[2].y < y_1) y_1 = vtx[2].y; + if (vtx[3].y < y_1) y_1 = vtx[3].y; x_2 = vtx[0].x; y_2 = vtx[0].y; + if (vtx[1].x > x_2) x_2 = vtx[1].x; + if (vtx[2].x > x_2) x_2 = vtx[2].x; + if (vtx[3].x > x_2) x_2 = vtx[3].x; + if (vtx[1].y > y_2) y_2 = vtx[1].y; + if (vtx[2].y > y_2) y_2 = vtx[2].y; + if (vtx[3].y > y_2) y_2 = vtx[3].y; @@ -8100,11 +8238,121 @@ clutter_actor_get_stage (ClutterActor *actor) return actor; } +/** + * clutter_actor_allocate_available_size: + * @self: a #ClutterActor + * @x: the actor's X coordinate + * @y: the actor's Y coordinate + * @available_width: the maximum available width, or -1 to use the + * actor's natural width + * @available_height: the maximum available height, or -1 to use the + * actor's natural height + * @flags: flags controlling the allocation + * + * Allocates @self taking into account the #ClutterActor's + * preferred size, but limiting it to the maximum available width + * and height provided. + * + * This function will do the right thing when dealing with the + * actor's request mode. + * + * The implementation of this function is equivalent to: + * + * |[ + * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH) + * { + * clutter_actor_get_preferred_width (self, available_height, + * &min_width, + * &natural_width); + * width = CLAMP (natural_width, min_width, available_width); + * + * clutter_actor_get_preferred_height (self, width, + * &min_height, + * &natural_height); + * height = CLAMP (natural_height, min_height, available_height); + * } + * else + * { + * clutter_actor_get_preferred_height (self, available_width, + * &min_height, + * &natural_height); + * height = CLAMP (natural_height, min_height, available_height); + * + * clutter_actor_get_preferred_width (self, height, + * &min_width, + * &natural_width); + * width = CLAMP (natural_width, min_width, available_width); + * } + * + * box.x1 = x; box.y1 = y; + * box.x2 = box.x1 + available_width; + * box.y2 = box.y1 + available_height; + * clutter_actor_allocate (self, &box, flags); + * ]| + * + * This function can be used by fluid layout managers to allocate + * an actor's preferred size without making it bigger than the area + * available for the container. + * + * Since: 1.0 + */ +void +clutter_actor_allocate_available_size (ClutterActor *self, + gfloat x, + gfloat y, + gfloat available_width, + gfloat available_height, + ClutterAllocationFlags flags) +{ + ClutterActorPrivate *priv; + gfloat width, height; + gfloat min_width, min_height; + gfloat natural_width, natural_height; + ClutterActorBox box; + + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + + priv = self->priv; + + switch (priv->request_mode) + { + case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH: + clutter_actor_get_preferred_width (self, available_height, + &min_width, + &natural_width); + width = CLAMP (natural_width, min_width, available_width); + + clutter_actor_get_preferred_height (self, width, + &min_height, + &natural_height); + height = CLAMP (natural_height, min_height, available_height); + break; + + case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT: + clutter_actor_get_preferred_height (self, available_width, + &min_height, + &natural_height); + height = CLAMP (natural_height, min_height, available_height); + + clutter_actor_get_preferred_width (self, height, + &min_width, + &natural_width); + width = CLAMP (natural_width, min_width, available_width); + break; + } + + + box.x1 = x; + box.y1 = y; + box.x2 = box.x1 + width; + box.y2 = box.y1 + height; + clutter_actor_allocate (self, &box, flags); +} + /** * clutter_actor_allocate_preferred_size: * @self: a #ClutterActor - * @absolute_origin_changed: whether the position of the parent has - * changed in stage coordinates + * @flags: flags controlling the allocation * * Allocates the natural size of @self. * @@ -8122,17 +8370,17 @@ clutter_actor_get_stage (ClutterActor *actor) * Since: 0.8 */ void -clutter_actor_allocate_preferred_size (ClutterActor *self, - gboolean absolute_origin_changed) +clutter_actor_allocate_preferred_size (ClutterActor *self, + ClutterAllocationFlags flags) { - ClutterUnit actor_x, actor_y; - ClutterUnit natural_width, natural_height; + gfloat actor_x, actor_y; + gfloat natural_width, natural_height; ClutterActorBox actor_box; g_return_if_fail (CLUTTER_IS_ACTOR (self)); - actor_x = clutter_actor_get_xu (self); - actor_y = clutter_actor_get_yu (self); + actor_x = clutter_actor_get_x (self); + actor_y = clutter_actor_get_y (self); clutter_actor_get_preferred_size (self, NULL, NULL, @@ -8144,7 +8392,7 @@ clutter_actor_allocate_preferred_size (ClutterActor *self, actor_box.x2 = actor_box.x1 + natural_width; actor_box.y2 = actor_box.y1 + natural_height; - clutter_actor_allocate (self, &actor_box, absolute_origin_changed); + clutter_actor_allocate (self, &actor_box, flags); } /** @@ -8303,23 +8551,43 @@ _clutter_actor_set_enable_model_view_transform (ClutterActor *self, self->priv->enable_model_view_transform = enable; } +void +_clutter_actor_set_enable_paint_unmapped (ClutterActor *self, + gboolean enable) +{ + ClutterActorPrivate *priv; + + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + + priv = self->priv; + + priv->enable_paint_unmapped = enable; + + if (priv->enable_paint_unmapped) + clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED); + else + clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED); +} + static void clutter_anchor_coord_get_units (ClutterActor *self, const AnchorCoord *coord, - ClutterUnit *x, - ClutterUnit *y, - ClutterUnit *z) + gfloat *x, + gfloat *y, + gfloat *z) { - if (G_UNLIKELY (coord->is_fractional)) + if (coord->is_fractional) { - ClutterUnit actor_width, actor_height; + gfloat actor_width, actor_height; - clutter_actor_get_sizeu (self, &actor_width, &actor_height); + clutter_actor_get_size (self, &actor_width, &actor_height); if (x) *x = actor_width * coord->v.fraction.x; + if (y) *y = actor_height * coord->v.fraction.y; + if (z) *z = 0; } @@ -8327,18 +8595,20 @@ clutter_anchor_coord_get_units (ClutterActor *self, { if (x) *x = coord->v.units.x; + if (y) *y = coord->v.units.y; + if (z) *z = coord->v.units.z; } } static void -clutter_anchor_coord_set_units (AnchorCoord *coord, - ClutterUnit x, - ClutterUnit y, - ClutterUnit z) +clutter_anchor_coord_set_units (AnchorCoord *coord, + gfloat x, + gfloat y, + gfloat z) { coord->is_fractional = FALSE; coord->v.units.x = x; @@ -8392,8 +8662,8 @@ clutter_anchor_coord_get_gravity (AnchorCoord *coord) } static void -clutter_anchor_coord_set_gravity (AnchorCoord *coord, - ClutterGravity gravity) +clutter_anchor_coord_set_gravity (AnchorCoord *coord, + ClutterGravity gravity) { switch (gravity) { @@ -8461,3 +8731,139 @@ clutter_anchor_coord_is_zero (const AnchorCoord *coord) && coord->v.units.y == 0.0 && coord->v.units.z == 0.0); } + +/** + * clutter_actor_get_flags: + * @self: a #ClutterActor + * + * Retrieves the flags set on @self + * + * Return value: a bitwise or of #ClutterActorFlags or 0 + * + * Since: 1.0 + */ +ClutterActorFlags +clutter_actor_get_flags (ClutterActor *self) +{ + g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); + + return self->flags; +} + +/** + * clutter_actor_set_flags: + * @self: a #ClutterActor + * @flags: the flags to set + * + * Sets @flags on @self + * + * This function will emit notifications for the changed properties + * + * Since: 1.0 + */ +void +clutter_actor_set_flags (ClutterActor *self, + ClutterActorFlags flags) +{ + ClutterActorFlags old_flags; + GObject *obj; + gboolean was_reactive_set, reactive_set; + gboolean was_realized_set, realized_set; + gboolean was_mapped_set, mapped_set; + gboolean was_visible_set, visible_set; + + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + + if (self->flags == flags) + return; + + obj = G_OBJECT (self); + g_object_freeze_notify (obj); + + old_flags = self->flags; + + was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0); + was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0); + was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0); + was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0); + + self->flags |= flags; + + reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0); + realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0); + mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0); + visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0); + + if (reactive_set != was_reactive_set) + g_object_notify (obj, "reactive"); + + if (realized_set != was_realized_set) + g_object_notify (obj, "realized"); + + if (mapped_set != was_mapped_set) + g_object_notify (obj, "mapped"); + + if (visible_set != was_visible_set) + g_object_notify (obj, "visible"); + + g_object_thaw_notify (obj); +} + +/** + * clutter_actor_unset_flags: + * @self: a #ClutterActor + * @flags: the flags to unset + * + * Unsets @flags on @self + * + * This function will emit notifications for the changed properties + * + * Since: 1.0 + */ +void +clutter_actor_unset_flags (ClutterActor *self, + ClutterActorFlags flags) +{ + ClutterActorFlags old_flags; + GObject *obj; + gboolean was_reactive_set, reactive_set; + gboolean was_realized_set, realized_set; + gboolean was_mapped_set, mapped_set; + gboolean was_visible_set, visible_set; + + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + + obj = G_OBJECT (self); + g_object_freeze_notify (obj); + + old_flags = self->flags; + + was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0); + was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0); + was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0); + was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0); + + self->flags &= ~flags; + + if (self->flags == old_flags) + return; + + reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0); + realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0); + mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0); + visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0); + + if (reactive_set != was_reactive_set) + g_object_notify (obj, "reactive"); + + if (realized_set != was_realized_set) + g_object_notify (obj, "realized"); + + if (mapped_set != was_mapped_set) + g_object_notify (obj, "mapped"); + + if (visible_set != was_visible_set) + g_object_notify (obj, "visible"); + + g_object_thaw_notify (obj); +} diff --git a/clutter/clutter-actor.h b/clutter/clutter-actor.h index 6ff80c3e5..9c7b9cd9b 100644 --- a/clutter/clutter-actor.h +++ b/clutter/clutter-actor.h @@ -74,10 +74,10 @@ G_BEGIN_DECLS */ #define CLUTTER_ACTOR_UNSET_FLAGS(a,f) (((ClutterActor*)(a))->flags &= ~(f)) -#define CLUTTER_ACTOR_IS_MAPPED(e) ((((ClutterActor*)(e))->flags & CLUTTER_ACTOR_MAPPED) != FALSE) -#define CLUTTER_ACTOR_IS_REALIZED(e) ((((ClutterActor*)(e))->flags & CLUTTER_ACTOR_REALIZED) != FALSE) -#define CLUTTER_ACTOR_IS_VISIBLE(e) (CLUTTER_ACTOR_IS_MAPPED (e) && CLUTTER_ACTOR_IS_REALIZED (e)) -#define CLUTTER_ACTOR_IS_REACTIVE(e) ((((ClutterActor*)(e))->flags & CLUTTER_ACTOR_REACTIVE) != FALSE) +#define CLUTTER_ACTOR_IS_MAPPED(a) ((((ClutterActor*)(a))->flags & CLUTTER_ACTOR_MAPPED) != FALSE) +#define CLUTTER_ACTOR_IS_REALIZED(a) ((((ClutterActor*)(a))->flags & CLUTTER_ACTOR_REALIZED) != FALSE) +#define CLUTTER_ACTOR_IS_VISIBLE(a) ((((ClutterActor*)(a))->flags & CLUTTER_ACTOR_VISIBLE) != FALSE) +#define CLUTTER_ACTOR_IS_REACTIVE(a) ((((ClutterActor*)(a))->flags & CLUTTER_ACTOR_REACTIVE) != FALSE) typedef struct _ClutterActorClass ClutterActorClass; typedef struct _ClutterActorBox ClutterActorBox; @@ -90,7 +90,8 @@ typedef struct _ClutterActorPrivate ClutterActorPrivate; * * Generic callback */ -typedef void (*ClutterCallback) (ClutterActor *actor, gpointer data); +typedef void (*ClutterCallback) (ClutterActor *actor, + gpointer data); /** * CLUTTER_CALLBACK @@ -102,11 +103,12 @@ typedef void (*ClutterCallback) (ClutterActor *actor, gpointer data); /** * ClutterActorFlags: - * @CLUTTER_ACTOR_MAPPED: the actor has been painted + * @CLUTTER_ACTOR_MAPPED: the actor will be painted (is visible, and inside a toplevel, and all parents visible) * @CLUTTER_ACTOR_REALIZED: the resources associated to the actor have been * allocated * @CLUTTER_ACTOR_REACTIVE: the actor 'reacts' to mouse events emmitting event * signals + * @CLUTTER_ACTOR_VISIBLE: the actor has been shown by the application program * * Flags used to signal the state of an actor. */ @@ -114,9 +116,28 @@ typedef enum { CLUTTER_ACTOR_MAPPED = 1 << 1, CLUTTER_ACTOR_REALIZED = 1 << 2, - CLUTTER_ACTOR_REACTIVE = 1 << 3 + CLUTTER_ACTOR_REACTIVE = 1 << 3, + CLUTTER_ACTOR_VISIBLE = 1 << 4 } ClutterActorFlags; +/** + * ClutterAllocationFlags: + * @CLUTTER_ALLOCATION_NONE: No flag set + * @CLUTTER_ABSOLUTE_ORIGIN_CHANGED: Whether the absolute origin of the + * actor has changed; this implies that any ancestor of the actor has + * been moved + * + * Flags passed to the #ClutterActor::allocate() virtual function and + * to the clutter_actor_allocate() function + * + * Since: 1.0 + */ +typedef enum +{ + CLUTTER_ALLOCATION_NONE = 0, + CLUTTER_ABSOLUTE_ORIGIN_CHANGED = 1 << 1 +} ClutterAllocationFlags; + /** * ClutterActorBox: * @x1: X coordinate of the top left corner @@ -126,15 +147,15 @@ typedef enum * * Bounding box of an actor. The coordinates of the top left and right bottom * corners of an actor. The coordinates of the two points are expressed in - * #ClutterUnits, that is are device-independent. If you want to obtain - * the box dimensions in pixels, use clutter_actor_get_geometry(). + * pixels with sub-pixel precision */ struct _ClutterActorBox { - ClutterUnit x1; - ClutterUnit y1; - ClutterUnit x2; - ClutterUnit y2; + gfloat x1; + gfloat y1; + + gfloat x2; + gfloat y2; }; GType clutter_actor_box_get_type (void) G_GNUC_CONST; @@ -177,6 +198,10 @@ struct _ClutterActor * it should chain up to the parent's implementation * @unrealize: virtual function, used to deallocate resources allocated * in ::realize; it should chain up to the parent's implementation + * @map: virtual function for containers and composite actors, to + * map their children; it must chain up to the parent's implementation + * @unmap: virtual function for containers and composite actors, to + * unmap their children; it must chain up to the parent's implementation * @paint: virtual function, used to paint the actor * @get_preferred_width: virtual function, used when querying the minimum * and natural widths of an actor for a given height; it is used by @@ -203,8 +228,8 @@ struct _ClutterActor * @enter_event: signal class closure for #ClutterActor::enter-event * @leave_event: signal class closure for #ClutterActor::leave-event * @captured_event: signal class closure for #ClutterActor::captured-event - * @focus_in: signal class closure for #ClutterActor::focus-in - * @focus_out: signal class closure for #ClutterActor::focus-out + * @key_focus_in: signal class closure for #ClutterActor::focus-in + * @key_focus_out: signal class closure for #ClutterActor::focus-out * * Base class for actors. */ @@ -220,6 +245,8 @@ struct _ClutterActorClass void (* hide_all) (ClutterActor *actor); void (* realize) (ClutterActor *actor); void (* unrealize) (ClutterActor *actor); + void (* map) (ClutterActor *actor); + void (* unmap) (ClutterActor *actor); void (* paint) (ClutterActor *actor); void (* parent_set) (ClutterActor *actor, ClutterActor *old_parent); @@ -232,17 +259,17 @@ struct _ClutterActorClass ClutterActor *leaf_that_queued); /* size negotiation */ - void (* get_preferred_width) (ClutterActor *actor, - ClutterUnit for_height, - ClutterUnit *min_width_p, - ClutterUnit *natural_width_p); - void (* get_preferred_height) (ClutterActor *actor, - ClutterUnit for_width, - ClutterUnit *min_height_p, - ClutterUnit *natural_height_p); - void (* allocate) (ClutterActor *actor, - const ClutterActorBox *box, - gboolean absolute_origin_changed); + void (* get_preferred_width) (ClutterActor *actor, + gfloat for_height, + gfloat *min_width_p, + gfloat *natural_width_p); + void (* get_preferred_height) (ClutterActor *actor, + gfloat for_width, + gfloat *min_height_p, + gfloat *natural_height_p); + void (* allocate) (ClutterActor *actor, + const ClutterActorBox *box, + ClutterAllocationFlags flags); /* event signals */ gboolean (* event) (ClutterActor *actor, ClutterEvent *event); @@ -264,8 +291,8 @@ struct _ClutterActorClass ClutterCrossingEvent *event); gboolean (* captured_event) (ClutterActor *actor, ClutterEvent *event); - void (* focus_in) (ClutterActor *actor); - void (* focus_out) (ClutterActor *actor); + void (* key_focus_in) (ClutterActor *actor); + void (* key_focus_out) (ClutterActor *actor); /*< private >*/ /* padding for future expansion */ @@ -274,12 +301,20 @@ struct _ClutterActorClass GType clutter_actor_get_type (void) G_GNUC_CONST; +void clutter_actor_set_flags (ClutterActor *self, + ClutterActorFlags flags); +void clutter_actor_unset_flags (ClutterActor *self, + ClutterActorFlags flags); +ClutterActorFlags clutter_actor_get_flags (ClutterActor *self); + void clutter_actor_show (ClutterActor *self); void clutter_actor_show_all (ClutterActor *self); void clutter_actor_hide (ClutterActor *self); void clutter_actor_hide_all (ClutterActor *self); void clutter_actor_realize (ClutterActor *self); void clutter_actor_unrealize (ClutterActor *self); +void clutter_actor_map (ClutterActor *self); +void clutter_actor_unmap (ClutterActor *self); void clutter_actor_paint (ClutterActor *self); void clutter_actor_pick (ClutterActor *self, const ClutterColor *color); @@ -289,23 +324,29 @@ void clutter_actor_destroy (ClutterActor /* size negotiation */ void clutter_actor_get_preferred_width (ClutterActor *self, - ClutterUnit for_height, - ClutterUnit *min_width_p, - ClutterUnit *natural_width_p); + gfloat for_height, + gfloat *min_width_p, + gfloat *natural_width_p); void clutter_actor_get_preferred_height (ClutterActor *self, - ClutterUnit for_width, - ClutterUnit *min_height_p, - ClutterUnit *natural_height_p); + gfloat for_width, + gfloat *min_height_p, + gfloat *natural_height_p); void clutter_actor_get_preferred_size (ClutterActor *self, - ClutterUnit *min_width_p, - ClutterUnit *min_height_p, - ClutterUnit *natural_width_p, - ClutterUnit *natural_height_p); + gfloat *min_width_p, + gfloat *min_height_p, + gfloat *natural_width_p, + gfloat *natural_height_p); void clutter_actor_allocate (ClutterActor *self, const ClutterActorBox *box, - gboolean absolute_origin_changed); + ClutterAllocationFlags flags); void clutter_actor_allocate_preferred_size (ClutterActor *self, - gboolean absolute_origin_changed); + ClutterAllocationFlags flags); +void clutter_actor_allocate_available_size (ClutterActor *self, + gfloat x, + gfloat y, + gfloat available_width, + gfloat available_height, + ClutterAllocationFlags flags); void clutter_actor_get_allocation_coords (ClutterActor *self, gint *x_1, gint *y_1, @@ -324,100 +365,60 @@ void clutter_actor_set_geometry (ClutterActor void clutter_actor_get_geometry (ClutterActor *self, ClutterGeometry *geometry); void clutter_actor_set_size (ClutterActor *self, - gint width, - gint height); -void clutter_actor_set_sizeu (ClutterActor *self, - ClutterUnit width, - ClutterUnit height); + gfloat width, + gfloat height); void clutter_actor_get_size (ClutterActor *self, - guint *width, - guint *height); -void clutter_actor_get_sizeu (ClutterActor *self, - ClutterUnit *width, - ClutterUnit *height); + gfloat *width, + gfloat *height); void clutter_actor_get_transformed_size (ClutterActor *self, - guint *width, - guint *height); -void clutter_actor_get_transformed_sizeu (ClutterActor *self, - ClutterUnit *width, - ClutterUnit *height); + gfloat *width, + gfloat *height); void clutter_actor_set_position (ClutterActor *self, - gint x, - gint y); -void clutter_actor_set_positionu (ClutterActor *self, - ClutterUnit x, - ClutterUnit y); + gfloat x, + gfloat y); void clutter_actor_get_position (ClutterActor *self, - gint *x, - gint *y); -void clutter_actor_get_positionu (ClutterActor *self, - ClutterUnit *x, - ClutterUnit *y); + gfloat *x, + gfloat *y); void clutter_actor_get_transformed_position (ClutterActor *self, - gint *x, - gint *y); -void clutter_actor_get_transformed_positionu (ClutterActor *self, - ClutterUnit *x, - ClutterUnit *y); + gfloat *x, + gfloat *y); gboolean clutter_actor_get_fixed_position_set (ClutterActor *self); void clutter_actor_set_fixed_position_set (ClutterActor *self, gboolean is_set); -guint clutter_actor_get_width (ClutterActor *self); -ClutterUnit clutter_actor_get_widthu (ClutterActor *self); -guint clutter_actor_get_height (ClutterActor *self); -ClutterUnit clutter_actor_get_heightu (ClutterActor *self); +gfloat clutter_actor_get_width (ClutterActor *self); +gfloat clutter_actor_get_height (ClutterActor *self); void clutter_actor_set_width (ClutterActor *self, - guint width); -void clutter_actor_set_widthu (ClutterActor *self, - ClutterUnit width); + gfloat width); void clutter_actor_set_height (ClutterActor *self, - guint height); -void clutter_actor_set_heightu (ClutterActor *self, - ClutterUnit height); -gint clutter_actor_get_x (ClutterActor *self); -ClutterUnit clutter_actor_get_xu (ClutterActor *self); -gint clutter_actor_get_y (ClutterActor *self); -ClutterUnit clutter_actor_get_yu (ClutterActor *self); + gfloat height); +gfloat clutter_actor_get_x (ClutterActor *self); +gfloat clutter_actor_get_y (ClutterActor *self); void clutter_actor_set_x (ClutterActor *self, - gint x); -void clutter_actor_set_xu (ClutterActor *self, - ClutterUnit x); + gfloat x); void clutter_actor_set_y (ClutterActor *self, - gint y); -void clutter_actor_set_yu (ClutterActor *self, - ClutterUnit y); + gfloat y); void clutter_actor_set_rotation (ClutterActor *self, ClutterRotateAxis axis, gdouble angle, - gint x, - gint y, - gint z); -void clutter_actor_set_rotationu (ClutterActor *self, - ClutterRotateAxis axis, - gdouble angle, - ClutterUnit x, - ClutterUnit y, - ClutterUnit z); + gfloat x, + gfloat y, + gfloat z); void clutter_actor_set_z_rotation_from_gravity (ClutterActor *self, gdouble angle, ClutterGravity gravity); gdouble clutter_actor_get_rotation (ClutterActor *self, ClutterRotateAxis axis, - gint *x, - gint *y, - gint *z); -gdouble clutter_actor_get_rotationu (ClutterActor *self, - ClutterRotateAxis axis, - ClutterUnit *x, - ClutterUnit *y, - ClutterUnit *z); + gfloat *x, + gfloat *y, + gfloat *z); ClutterGravity clutter_actor_get_z_rotation_gravity (ClutterActor *self); void clutter_actor_set_opacity (ClutterActor *self, guint8 opacity); guint8 clutter_actor_get_opacity (ClutterActor *self); + guint8 clutter_actor_get_paint_opacity (ClutterActor *self); gboolean clutter_actor_get_paint_visibility (ClutterActor *self); @@ -428,27 +429,17 @@ G_CONST_RETURN gchar *clutter_actor_get_name (ClutterActor guint32 clutter_actor_get_gid (ClutterActor *self); void clutter_actor_set_clip (ClutterActor *self, - gint xoff, - gint yoff, - gint width, - gint height); -void clutter_actor_set_clipu (ClutterActor *self, - ClutterUnit xoff, - ClutterUnit yoff, - ClutterUnit width, - ClutterUnit height); + gfloat xoff, + gfloat yoff, + gfloat width, + gfloat height); void clutter_actor_remove_clip (ClutterActor *self); gboolean clutter_actor_has_clip (ClutterActor *self); void clutter_actor_get_clip (ClutterActor *self, - gint *xoff, - gint *yoff, - gint *width, - gint *height); -void clutter_actor_get_clipu (ClutterActor *self, - ClutterUnit *xoff, - ClutterUnit *yoff, - ClutterUnit *width, - ClutterUnit *height); + gfloat *xoff, + gfloat *yoff, + gfloat *width, + gfloat *height); void clutter_actor_set_parent (ClutterActor *self, ClutterActor *parent); @@ -465,11 +456,8 @@ void clutter_actor_lower (ClutterActor void clutter_actor_raise_top (ClutterActor *self); void clutter_actor_lower_bottom (ClutterActor *self); void clutter_actor_set_depth (ClutterActor *self, - gint depth); -gint clutter_actor_get_depth (ClutterActor *self); -void clutter_actor_set_depthu (ClutterActor *self, - ClutterUnit depth); -ClutterUnit clutter_actor_get_depthu (ClutterActor *self); + gfloat depth); +gfloat clutter_actor_get_depth (ClutterActor *self); void clutter_actor_set_scale (ClutterActor *self, gdouble scale_x, @@ -477,13 +465,8 @@ void clutter_actor_set_scale (ClutterActor void clutter_actor_set_scale_full (ClutterActor *self, gdouble scale_x, gdouble scale_y, - int center_x, - int center_y); -void clutter_actor_set_scale_fullu (ClutterActor *self, - gdouble scale_x, - gdouble scale_y, - ClutterUnit center_x, - ClutterUnit center_y); + gfloat center_x, + gfloat center_y); void clutter_actor_set_scale_with_gravity (ClutterActor *self, gdouble scale_x, gdouble scale_y, @@ -492,19 +475,13 @@ void clutter_actor_get_scale (ClutterActor gdouble *scale_x, gdouble *scale_y); void clutter_actor_get_scale_center (ClutterActor *self, - gint *center_x, - gint *center_y); -void clutter_actor_get_scale_centeru (ClutterActor *self, - ClutterUnit *center_x, - ClutterUnit *center_y); + gfloat *center_x, + gfloat *center_y); ClutterGravity clutter_actor_get_scale_gravity (ClutterActor *self); void clutter_actor_move_by (ClutterActor *self, - gint dx, - gint dy); -void clutter_actor_move_byu (ClutterActor *self, - ClutterUnit dx, - ClutterUnit dy); + gfloat dx, + gfloat dy); void clutter_actor_set_reactive (ClutterActor *actor, gboolean reactive); @@ -530,34 +507,25 @@ void clutter_actor_set_shader_param_float (ClutterActor gfloat value); void clutter_actor_set_anchor_point (ClutterActor *self, - gint anchor_x, - gint anchor_y); + gfloat anchor_x, + gfloat anchor_y); void clutter_actor_move_anchor_point (ClutterActor *self, - gint anchor_x, - gint anchor_y); + gfloat anchor_x, + gfloat anchor_y); void clutter_actor_get_anchor_point (ClutterActor *self, - gint *anchor_x, - gint *anchor_y); + gfloat *anchor_x, + gfloat *anchor_y); ClutterGravity clutter_actor_get_anchor_point_gravity (ClutterActor *self); -void clutter_actor_set_anchor_pointu (ClutterActor *self, - ClutterUnit anchor_x, - ClutterUnit anchor_y); -void clutter_actor_move_anchor_pointu (ClutterActor *self, - ClutterUnit anchor_x, - ClutterUnit anchor_y); -void clutter_actor_get_anchor_pointu (ClutterActor *self, - ClutterUnit *anchor_x, - ClutterUnit *anchor_y); void clutter_actor_set_anchor_point_from_gravity (ClutterActor *self, ClutterGravity gravity); void clutter_actor_move_anchor_point_from_gravity (ClutterActor *self, ClutterGravity gravity); gboolean clutter_actor_transform_stage_point (ClutterActor *self, - ClutterUnit x, - ClutterUnit y, - ClutterUnit *x_out, - ClutterUnit *y_out); + gfloat x, + gfloat y, + gfloat *x_out, + gfloat *y_out); gboolean clutter_actor_is_rotated (ClutterActor *self); gboolean clutter_actor_is_scaled (ClutterActor *self); gboolean clutter_actor_should_pick_paint (ClutterActor *self); diff --git a/clutter/clutter-alpha.c b/clutter/clutter-alpha.c index a38a03f73..57b057aa1 100644 --- a/clutter/clutter-alpha.c +++ b/clutter/clutter-alpha.c @@ -603,9 +603,7 @@ clutter_ease_out_quad (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); - gdouble p = t / d; + gdouble p = clutter_timeline_get_progress (timeline); return -1.0 * p * (p - 2); } @@ -615,8 +613,8 @@ clutter_ease_in_out_quad (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); gdouble p = t / (d / 2); if (p < 1) @@ -632,9 +630,7 @@ clutter_ease_in_cubic (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); - gdouble p = t / d; + gdouble p = clutter_timeline_get_progress (timeline); return p * p * p; } @@ -644,8 +640,8 @@ clutter_ease_out_cubic (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); gdouble p = t / d - 1; return p * p * p + 1; @@ -656,8 +652,8 @@ clutter_ease_in_out_cubic (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); gdouble p = t / (d / 2); if (p < 1) @@ -673,9 +669,7 @@ clutter_ease_in_quart (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); - gdouble p = t / d; + gdouble p = clutter_timeline_get_progress (timeline); return p * p * p * p; } @@ -685,8 +679,8 @@ clutter_ease_out_quart (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); gdouble p = t / d - 1; return -1.0 * (p * p * p * p - 1); @@ -697,8 +691,8 @@ clutter_ease_in_out_quart (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); gdouble p = t / (d / 2); if (p < 1) @@ -714,9 +708,7 @@ clutter_ease_in_quint (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); - gdouble p = t / d; + gdouble p = clutter_timeline_get_progress (timeline); return p * p * p * p * p; } @@ -726,8 +718,8 @@ clutter_ease_out_quint (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); gdouble p = t / d - 1; return p * p * p * p * p + 1; @@ -738,8 +730,8 @@ clutter_ease_in_out_quint (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); gdouble p = t / (d / 2); if (p < 1) @@ -755,8 +747,8 @@ clutter_ease_in_sine (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); return -1.0 * cos (t / d * G_PI_2) + 1.0; } @@ -766,8 +758,8 @@ clutter_ease_out_sine (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); return sin (t / d * G_PI_2); } @@ -777,8 +769,8 @@ clutter_ease_in_out_sine (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); return -0.5 * (cos (G_PI * t / d) - 1); } @@ -788,8 +780,8 @@ clutter_ease_in_expo (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); return (t == 0) ? 0.0 : pow (2, 10 * (t / d - 1)); } @@ -799,8 +791,8 @@ clutter_ease_out_expo (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); return (t == d) ? 1.0 : -pow (2, -10 * t / d) + 1; } @@ -810,8 +802,8 @@ clutter_ease_in_out_expo (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); gdouble p; if (t == 0) @@ -835,9 +827,7 @@ clutter_ease_in_circ (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); - gdouble p = t / d; + gdouble p = clutter_timeline_get_progress (timeline); return -1.0 * (sqrt (1 - p * p) - 1); } @@ -847,8 +837,8 @@ clutter_ease_out_circ (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); gdouble p = t / d - 1; return sqrt (1 - p * p); @@ -859,8 +849,8 @@ clutter_ease_in_out_circ (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); gdouble p = t / (d / 2); if (p < 1) @@ -876,8 +866,8 @@ clutter_ease_in_elastic (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); gdouble p = d * .3; gdouble s = p / 4; gdouble q = t / d; @@ -895,8 +885,8 @@ clutter_ease_out_elastic (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); gdouble p = d * .3; gdouble s = p / 4; gdouble q = t / d; @@ -912,8 +902,8 @@ clutter_ease_in_out_elastic (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); gdouble p = d * (.3 * 1.5); gdouble s = p / 4; gdouble q = t / (d / 2); @@ -942,9 +932,7 @@ clutter_ease_in_back (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); - gdouble p = t / d; + gdouble p = clutter_timeline_get_progress (timeline); return p * p * ((1.70158 + 1) * p - 1.70158); } @@ -954,8 +942,8 @@ clutter_ease_out_back (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); gdouble p = t / d - 1; return p * p * ((1.70158 + 1) * p + 1.70158) + 1; @@ -966,8 +954,8 @@ clutter_ease_in_out_back (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); gdouble p = t / (d / 2); gdouble s = 1.70158 * 1.525; @@ -1019,8 +1007,8 @@ clutter_ease_in_bounce (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); return ease_in_bounce_internal (t, d); } @@ -1030,8 +1018,8 @@ clutter_ease_out_bounce (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); return ease_out_bounce_internal (t, d); } @@ -1041,8 +1029,8 @@ clutter_ease_in_out_bounce (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = alpha->priv->timeline; - gdouble t = clutter_timeline_get_current_frame (timeline); - gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble t = clutter_timeline_get_elapsed_time (timeline); + gdouble d = clutter_timeline_get_duration (timeline); if (t < d / 2) return ease_in_bounce_internal (t * 2, d) * 0.5; diff --git a/clutter/clutter-animatable.c b/clutter/clutter-animatable.c index fb2b88b19..e448a694f 100644 --- a/clutter/clutter-animatable.c +++ b/clutter/clutter-animatable.c @@ -86,9 +86,12 @@ clutter_animatable_get_type (void) * All implementation of the #ClutterAnimatable interface must * implement this function. * + * Return value: %TRUE if the value has been validated and can + * be applied to the #ClutterAnimatable, and %FALSE otherwise + * * Since: 1.0 */ -void +gboolean clutter_animatable_animate_property (ClutterAnimatable *animatable, ClutterAnimation *animation, const gchar *property_name, @@ -97,21 +100,27 @@ clutter_animatable_animate_property (ClutterAnimatable *animatable, gdouble progress, GValue *value) { - g_return_if_fail (CLUTTER_IS_ANIMATABLE (animatable)); - g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); - g_return_if_fail (property_name != NULL); - g_return_if_fail (initial_value != NULL && final_value != NULL); - g_return_if_fail (G_VALUE_TYPE (initial_value) != G_TYPE_INVALID); - g_return_if_fail (G_VALUE_TYPE (final_value) != G_TYPE_INVALID); - g_return_if_fail (value != NULL); - g_return_if_fail (G_VALUE_TYPE (value) == G_VALUE_TYPE (initial_value) && - G_VALUE_TYPE (value) == G_VALUE_TYPE (final_value)); + gboolean res; - CLUTTER_ANIMATABLE_GET_IFACE (animatable)->animate_property (animatable, - animation, - property_name, - initial_value, - final_value, - progress, - value); + g_return_val_if_fail (CLUTTER_IS_ANIMATABLE (animatable), FALSE); + g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), FALSE); + g_return_val_if_fail (property_name != NULL, FALSE); + g_return_val_if_fail (initial_value != NULL && final_value != NULL, FALSE); + g_return_val_if_fail (G_VALUE_TYPE (initial_value) != G_TYPE_INVALID, FALSE); + g_return_val_if_fail (G_VALUE_TYPE (final_value) != G_TYPE_INVALID, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (G_VALUE_TYPE (value) == G_VALUE_TYPE (initial_value) && + G_VALUE_TYPE (value) == G_VALUE_TYPE (final_value), + FALSE); + + res = + CLUTTER_ANIMATABLE_GET_IFACE (animatable)->animate_property (animatable, + animation, + property_name, + initial_value, + final_value, + progress, + value); + + return res; } diff --git a/clutter/clutter-animatable.h b/clutter/clutter-animatable.h index aee717ac4..71a88d65e 100644 --- a/clutter/clutter-animatable.h +++ b/clutter/clutter-animatable.h @@ -56,24 +56,24 @@ struct _ClutterAnimatableIface GTypeInterface parent_iface; /*< public >*/ - void (* animate_property) (ClutterAnimatable *animatable, - ClutterAnimation *animation, - const gchar *property_name, - const GValue *initial_value, - const GValue *final_value, - gdouble progress, - GValue *value); + gboolean (* animate_property) (ClutterAnimatable *animatable, + ClutterAnimation *animation, + const gchar *property_name, + const GValue *initial_value, + const GValue *final_value, + gdouble progress, + GValue *value); }; GType clutter_animatable_get_type (void) G_GNUC_CONST; -void clutter_animatable_animate_property (ClutterAnimatable *animatable, - ClutterAnimation *animation, - const gchar *property_name, - const GValue *initial_value, - const GValue *final_value, - gdouble progress, - GValue *value); +gboolean clutter_animatable_animate_property (ClutterAnimatable *animatable, + ClutterAnimation *animation, + const gchar *property_name, + const GValue *initial_value, + const GValue *final_value, + gdouble progress, + GValue *value); G_END_DECLS diff --git a/clutter/clutter-animation.c b/clutter/clutter-animation.c index 6eb7d85f3..f84368142 100644 --- a/clutter/clutter-animation.c +++ b/clutter/clutter-animation.c @@ -25,14 +25,43 @@ /** * SECTION:clutter-animation * @short_description: Simple implicit animations + * @See_Also: #ClutterAnimatable, #ClutterInterval, #ClutterAlpha, + * #ClutterTimeline * * #ClutterAnimation is an object providing simple, implicit animations * for #GObjects. * - * #ClutterAnimation instances will bind a #GObject property belonging - * to a #GObject to a #ClutterInterval, and will then use a #ClutterTimeline - * to interpolate the property between the initial and final values of the - * interval. + * #ClutterAnimation instances will bind one or more #GObject properties + * belonging to a #GObject to a #ClutterInterval, and will then use a + * #ClutterAlpha to interpolate the property between the initial and final + * values of the interval. + * + * The duration of the animation is set using clutter_animation_set_duration(). + * The easing mode of the animation is set using clutter_animation_set_mode(). + * + * If you want to control the animation you should retrieve the + * #ClutterTimeline using clutter_animation_get_timeline() and then + * use #ClutterTimeline functions like clutter_timeline_start(), + * clutter_timeline_pause() or clutter_timeline_stop(). + * + * A #ClutterAnimation will emit the #ClutterAnimation::completed signal + * when the #ClutterTimeline used by the animation is completed; unlike + * #ClutterTimeline, though, the #ClutterAnimation::completed will not be + * emitted if #ClutterAnimation:loop is set to %TRUE - that is, a looping + * animation never completes. + * + * If your animation depends on user control you can force its completion + * using clutter_animation_completed(). + * + * If the #GObject instance bound to a #ClutterAnimation implements the + * #ClutterAnimatable interface it is possible for that instance to + * control the way the initial and final states are interpolated. + * + * #ClutterAnimations are distinguished from #ClutterBehaviours + * because the former can only control #GObject properties of a single + * #GObject instance, while the latter can control multiple properties + * using accessor functions inside the #ClutterBehaviour::alpha_notify + * virtual function, and can control multiple #ClutterActors as well. * * For convenience, it is possible to use the clutter_actor_animate() * function call which will take care of setting up and tearing down @@ -85,16 +114,10 @@ struct _ClutterAnimationPrivate GHashTable *properties; - gulong mode; + ClutterAlpha *alpha; - guint loop : 1; - guint duration; - - ClutterTimeline *timeline; guint timeline_started_id; guint timeline_completed_id; - - ClutterAlpha *alpha; guint alpha_notify_id; }; @@ -122,48 +145,43 @@ static void clutter_animation_dispose (GObject *gobject) { ClutterAnimationPrivate *priv = CLUTTER_ANIMATION (gobject)->priv; + ClutterTimeline *timeline; - if (priv->object) + if (priv->alpha != NULL) + timeline = clutter_alpha_get_timeline (priv->alpha); + else + timeline = NULL; + + if (timeline != NULL && priv->timeline_started_id != 0) + g_signal_handler_disconnect (timeline, priv->timeline_started_id); + + if (timeline != NULL && priv->timeline_completed_id != 0) + g_signal_handler_disconnect (timeline, priv->timeline_completed_id); + + priv->timeline_started_id = 0; + priv->timeline_completed_id = 0; + + if (priv->alpha != NULL) + { + if (priv->alpha_notify_id != 0) + g_signal_handler_disconnect (priv->alpha, priv->alpha_notify_id); + + g_object_unref (priv->alpha); + } + + priv->alpha_notify_id = 0; + priv->alpha = NULL; + + if (priv->object != NULL) { g_object_weak_unref (G_OBJECT (gobject), on_animation_weak_notify, priv->object); g_object_set_qdata (priv->object, quark_object_animation, NULL); g_object_unref (priv->object); - priv->object = NULL; } - if (priv->timeline) - { - if (priv->timeline_started_id) - { - g_signal_handler_disconnect (priv->timeline, - priv->timeline_started_id); - priv->timeline_started_id = 0; - } - - if (priv->timeline_completed_id) - { - g_signal_handler_disconnect (priv->timeline, - priv->timeline_completed_id); - priv->timeline_completed_id = 0; - } - - g_object_unref (priv->timeline); - priv->timeline = NULL; - } - - if (priv->alpha) - { - if (priv->alpha_notify_id) - { - g_signal_handler_disconnect (priv->alpha, priv->alpha_notify_id); - priv->alpha_notify_id = 0; - } - - g_object_unref (priv->alpha); - priv->alpha = NULL; - } + priv->object = NULL; G_OBJECT_CLASS (clutter_animation_parent_class)->dispose (gobject); } @@ -214,7 +232,8 @@ clutter_animation_get_property (GObject *gobject, GValue *value, GParamSpec *pspec) { - ClutterAnimationPrivate *priv = CLUTTER_ANIMATION (gobject)->priv; + ClutterAnimation *animation = CLUTTER_ANIMATION (gobject); + ClutterAnimationPrivate *priv = animation->priv; switch (prop_id) { @@ -223,23 +242,23 @@ clutter_animation_get_property (GObject *gobject, break; case PROP_MODE: - g_value_set_ulong (value, priv->mode); + g_value_set_ulong (value, clutter_animation_get_mode (animation)); break; case PROP_DURATION: - g_value_set_uint (value, priv->duration); + g_value_set_uint (value, clutter_animation_get_duration (animation)); break; case PROP_LOOP: - g_value_set_boolean (value, priv->loop); + g_value_set_boolean (value, clutter_animation_get_loop (animation)); break; case PROP_TIMELINE: - g_value_set_object (value, priv->timeline); + g_value_set_object (value, clutter_animation_get_timeline (animation)); break; case PROP_ALPHA: - g_value_set_object (value, priv->alpha); + g_value_set_object (value, clutter_animation_get_alpha (animation)); break; default: @@ -370,7 +389,7 @@ clutter_animation_class_init (ClutterAnimationClass *klass) G_TYPE_NONE, 0); /** - * ClutterAniamtion::completed: + * ClutterAnimation::completed: * @animation: the animation that emitted the signal * * The ::completed signal is emitted once the animation has @@ -396,7 +415,6 @@ clutter_animation_init (ClutterAnimation *self) { self->priv = CLUTTER_ANIMATION_GET_PRIVATE (self); - self->priv->mode = CLUTTER_LINEAR; self->priv->properties = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, @@ -750,7 +768,7 @@ on_timeline_completed (ClutterTimeline *timeline, { CLUTTER_NOTE (ANIMATION, "Timeline [%p] complete", timeline); - if (!animation->priv->loop) + if (!clutter_animation_get_loop (animation)) g_signal_emit (animation, animation_signals[COMPLETED], 0); } @@ -781,6 +799,7 @@ on_alpha_notify (GObject *gobject, const gchar *p_name = p->data; ClutterInterval *interval; GValue value = { 0, }; + gboolean apply; interval = g_hash_table_lookup (priv->properties, p_name); g_assert (CLUTTER_IS_INTERVAL (interval)); @@ -794,23 +813,22 @@ on_alpha_notify (GObject *gobject, initial = clutter_interval_peek_initial_value (interval); final = clutter_interval_peek_final_value (interval); - CLUTTER_NOTE (ANIMATION, "Animatable property '%s'", p_name); - clutter_animatable_animate_property (animatable, animation, - p_name, - initial, final, - alpha_value, - &value); - - g_object_set_property (priv->object, p_name, &value); + apply = clutter_animatable_animate_property (animatable, animation, + p_name, + initial, final, + alpha_value, + &value); } else { - CLUTTER_NOTE (ANIMATION, "Standard property '%s'", p_name); - - if (clutter_interval_compute_value (interval, alpha_value, &value)) - g_object_set_property (priv->object, p_name, &value); + apply = clutter_interval_compute_value (interval, + alpha_value, + &value); } + if (apply) + g_object_set_property (priv->object, p_name, &value); + g_value_unset (&value); } @@ -819,6 +837,65 @@ on_alpha_notify (GObject *gobject, g_object_thaw_notify (priv->object); } +static ClutterAlpha * +clutter_animation_get_alpha_internal (ClutterAnimation *animation) +{ + ClutterAnimationPrivate *priv = animation->priv; + + if (priv->alpha == NULL) + { + ClutterAlpha *alpha; + + alpha = clutter_alpha_new (); + clutter_alpha_set_mode (alpha, CLUTTER_LINEAR); + + priv->alpha_notify_id = + g_signal_connect (alpha, "notify::alpha", + G_CALLBACK (on_alpha_notify), + animation); + + priv->alpha = g_object_ref_sink (alpha); + + g_object_notify (G_OBJECT (animation), "alpha"); + } + + return priv->alpha; +} + +static ClutterTimeline * +clutter_animation_get_timeline_internal (ClutterAnimation *animation) +{ + ClutterAnimationPrivate *priv = animation->priv; + ClutterTimeline *timeline; + ClutterAlpha *alpha; + + alpha = clutter_animation_get_alpha_internal (animation); + timeline = clutter_alpha_get_timeline (alpha); + if (timeline != NULL) + return timeline; + + timeline = g_object_new (CLUTTER_TYPE_TIMELINE, NULL); + + priv->timeline_started_id = + g_signal_connect (timeline, "started", + G_CALLBACK (on_timeline_started), + animation); + + priv->timeline_completed_id = + g_signal_connect (timeline, "completed", + G_CALLBACK (on_timeline_completed), + animation); + + clutter_alpha_set_timeline (alpha, timeline); + + /* the alpha owns the timeline now */ + g_object_unref (timeline); + + g_object_notify (G_OBJECT (animation), "timeline"); + + return timeline; +} + /* * Removes the animation pointer from the qdata section of the * actor attached to the animation @@ -924,16 +1001,6 @@ clutter_animation_get_object (ClutterAnimation *animation) return animation->priv->object; } -static inline void -clutter_animation_set_mode_internal (ClutterAnimation *animation, - ClutterAlpha *alpha) -{ - ClutterAnimationPrivate *priv = animation->priv; - - if (alpha) - clutter_alpha_set_mode (alpha, priv->mode); -} - /** * clutter_animation_set_mode: * @animation: a #ClutterAnimation @@ -943,22 +1010,26 @@ clutter_animation_set_mode_internal (ClutterAnimation *animation, * a logical id, either coming from the #ClutterAnimationMode enumeration * or the return value of clutter_alpha_register_func(). * + * This function will also set #ClutterAnimation:alpha if needed. + * * Since: 1.0 */ void clutter_animation_set_mode (ClutterAnimation *animation, gulong mode) { - ClutterAnimationPrivate *priv; + ClutterAlpha *alpha; g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); - priv = animation->priv; + g_object_freeze_notify (G_OBJECT (animation)); - priv->mode = mode; - clutter_animation_set_mode_internal (animation, priv->alpha); + alpha = clutter_animation_get_alpha_internal (animation); + clutter_alpha_set_mode (alpha, mode); g_object_notify (G_OBJECT (animation), "mode"); + + g_object_thaw_notify (G_OBJECT (animation)); } /** @@ -975,9 +1046,13 @@ clutter_animation_set_mode (ClutterAnimation *animation, gulong clutter_animation_get_mode (ClutterAnimation *animation) { + ClutterAlpha *alpha; + g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), CLUTTER_LINEAR); - return animation->priv->mode; + alpha = clutter_animation_get_alpha_internal (animation); + + return clutter_alpha_get_mode (alpha); } /** @@ -987,35 +1062,28 @@ clutter_animation_get_mode (ClutterAnimation *animation) * * Sets the duration of @animation in milliseconds. * + * This function will set #ClutterAnimation:alpha and + * #ClutterAnimation:timeline if needed. + * * Since: 1.0 */ void clutter_animation_set_duration (ClutterAnimation *animation, gint msecs) { - ClutterAnimationPrivate *priv; + ClutterTimeline *timeline; g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); - priv = animation->priv; + g_object_freeze_notify (G_OBJECT (animation)); - priv->duration = msecs; - - if (priv->timeline) - { - gboolean was_playing; - - was_playing = clutter_timeline_is_playing (priv->timeline); - if (was_playing) - clutter_timeline_stop (priv->timeline); - - clutter_timeline_set_duration (priv->timeline, msecs); - - if (was_playing) - clutter_timeline_start (priv->timeline); - } + timeline = clutter_animation_get_timeline_internal (animation); + clutter_timeline_set_duration (timeline, msecs); + clutter_timeline_rewind (timeline); g_object_notify (G_OBJECT (animation), "duration"); + + g_object_thaw_notify (G_OBJECT (animation)); } /** @@ -1028,27 +1096,27 @@ clutter_animation_set_duration (ClutterAnimation *animation, * A looping #ClutterAnimation will not emit the #ClutterAnimation::completed * signal when finished. * + * This function will set #ClutterAnimation:alpha and + * #ClutterAnimation:timeline if needed. + * * Since: 1.0 */ void clutter_animation_set_loop (ClutterAnimation *animation, gboolean loop) { - ClutterAnimationPrivate *priv; + ClutterTimeline *timeline; g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); - priv = animation->priv; + g_object_freeze_notify (G_OBJECT (animation)); - if (priv->loop != loop) - { - priv->loop = loop; + timeline = clutter_animation_get_timeline_internal (animation); + clutter_timeline_set_loop (timeline, loop); - if (priv->timeline) - clutter_timeline_set_loop (priv->timeline, priv->loop); + g_object_notify (G_OBJECT (animation), "loop"); - g_object_notify (G_OBJECT (animation), "loop"); - } + g_object_thaw_notify (G_OBJECT (animation)); } /** @@ -1064,9 +1132,13 @@ clutter_animation_set_loop (ClutterAnimation *animation, gboolean clutter_animation_get_loop (ClutterAnimation *animation) { + ClutterTimeline *timeline; + g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), FALSE); - return animation->priv->loop; + timeline = clutter_animation_get_timeline_internal (animation); + + return clutter_timeline_get_loop (timeline); } /** @@ -1082,26 +1154,23 @@ clutter_animation_get_loop (ClutterAnimation *animation) guint clutter_animation_get_duration (ClutterAnimation *animation) { + ClutterTimeline *timeline; + g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), 0); - return animation->priv->duration; + timeline = clutter_animation_get_timeline_internal (animation); + + return clutter_timeline_get_duration (timeline); } /** * clutter_animation_set_timeline: * @animation: a #ClutterAnimation - * @timeline: a #ClutterTimeline or %NULL + * @timeline: a #ClutterTimeline, or %NULL to unset the + * current #ClutterTimeline * * Sets the #ClutterTimeline used by @animation. * - * The #ClutterAnimation:duration and #ClutterAnimation:loop properties - * will be set using the corresponding #ClutterTimeline properties as a - * side effect. - * - * If @timeline is %NULL a new #ClutterTimeline will be constructed - * using the current values of the #ClutterAnimation:duration and - * #ClutterAnimation:loop properties. - * * Since: 1.0 */ void @@ -1109,62 +1178,50 @@ clutter_animation_set_timeline (ClutterAnimation *animation, ClutterTimeline *timeline) { ClutterAnimationPrivate *priv; + ClutterTimeline *cur_timeline; + ClutterAlpha *alpha; g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); g_return_if_fail (timeline == NULL || CLUTTER_IS_TIMELINE (timeline)); priv = animation->priv; - if (timeline != NULL && priv->timeline == timeline) + if (priv->alpha != NULL) + cur_timeline = clutter_alpha_get_timeline (priv->alpha); + else + cur_timeline = NULL; + + if (cur_timeline == timeline) return; g_object_freeze_notify (G_OBJECT (animation)); - if (priv->timeline != NULL) - { - if (priv->timeline_started_id) - g_signal_handler_disconnect (priv->timeline, - priv->timeline_started_id); + if (cur_timeline != NULL && priv->timeline_started_id != 0) + g_signal_handler_disconnect (cur_timeline, priv->timeline_started_id); - if (priv->timeline_completed_id) - g_signal_handler_disconnect (priv->timeline, - priv->timeline_completed_id); + if (cur_timeline != NULL && priv->timeline_completed_id != 0) + g_signal_handler_disconnect (cur_timeline, priv->timeline_completed_id); - g_object_unref (priv->timeline); - priv->timeline_started_id = 0; - priv->timeline_completed_id = 0; - priv->timeline = 0; - } + priv->timeline_started_id = 0; + priv->timeline_completed_id = 0; - if (timeline == NULL) - { - timeline = g_object_new (CLUTTER_TYPE_TIMELINE, - "duration", priv->duration, - "loop", priv->loop, - NULL); - } - else - { - g_object_ref (timeline); - - priv->duration = clutter_timeline_get_duration (timeline); - g_object_notify (G_OBJECT (animation), "duration"); - - priv->loop = clutter_timeline_get_loop (timeline); - g_object_notify (G_OBJECT (animation), "loop"); - } - - priv->timeline = timeline; + alpha = clutter_animation_get_alpha_internal (animation); + clutter_alpha_set_timeline (alpha, timeline); g_object_notify (G_OBJECT (animation), "timeline"); + g_object_notify (G_OBJECT (animation), "duration"); + g_object_notify (G_OBJECT (animation), "loop"); - priv->timeline_started_id = - g_signal_connect (timeline, "started", - G_CALLBACK (on_timeline_started), - animation); - priv->timeline_completed_id = - g_signal_connect (timeline, "completed", - G_CALLBACK (on_timeline_completed), - animation); + if (timeline) + { + priv->timeline_started_id = + g_signal_connect (timeline, "started", + G_CALLBACK (on_timeline_started), + animation); + priv->timeline_completed_id = + g_signal_connect (timeline, "completed", + G_CALLBACK (on_timeline_completed), + animation); + } g_object_thaw_notify (G_OBJECT (animation)); } @@ -1184,19 +1241,18 @@ clutter_animation_get_timeline (ClutterAnimation *animation) { g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), NULL); - return animation->priv->timeline; + return clutter_animation_get_timeline_internal (animation); } /** * clutter_animation_set_alpha: * @animation: a #ClutterAnimation - * @alpha: a #ClutterAlpha, or %NULL + * @alpha: a #ClutterAlpha, or %NULL to unset the current #ClutterAlpha * * Sets @alpha as the #ClutterAlpha used by @animation. * - * If @alpha is %NULL, a new #ClutterAlpha will be constructed from - * the current values of the #ClutterAnimation:mode and - * #ClutterAnimation:timeline properties. + * If @alpha is not %NULL, the #ClutterAnimation will take ownership + * of the #ClutterAlpha instance. * * Since: 1.0 */ @@ -1205,41 +1261,84 @@ clutter_animation_set_alpha (ClutterAnimation *animation, ClutterAlpha *alpha) { ClutterAnimationPrivate *priv; + ClutterTimeline *timeline; g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); g_return_if_fail (alpha == NULL || CLUTTER_IS_ALPHA (alpha)); priv = animation->priv; - if (!alpha) + if (priv->alpha == alpha) + return; + + g_object_freeze_notify (G_OBJECT (animation)); + + if (priv->alpha != NULL) + timeline = clutter_alpha_get_timeline (priv->alpha); + else + timeline = NULL; + + /* disconnect the old timeline first */ + if (timeline != NULL && priv->timeline_started_id != 0) { - ClutterTimeline *timeline; - - timeline = clutter_animation_get_timeline (animation); - - alpha = clutter_alpha_new (); - clutter_alpha_set_timeline (alpha, timeline); - clutter_animation_set_mode_internal (animation, alpha); + g_signal_handler_disconnect (timeline, priv->timeline_started_id); + priv->timeline_started_id = 0; } - g_object_ref_sink (alpha); - - if (priv->alpha) + if (timeline != NULL && priv->timeline_completed_id != 0) { - if (priv->alpha_notify_id) - g_signal_handler_disconnect (priv->alpha, priv->alpha_notify_id); + g_signal_handler_disconnect (timeline, priv->timeline_completed_id); + priv->timeline_completed_id = 0; + } - g_object_unref (priv->alpha); + /* then we need to disconnect the signal handler from the old alpha */ + if (priv->alpha_notify_id != 0) + { + g_signal_handler_disconnect (priv->alpha, priv->alpha_notify_id); priv->alpha_notify_id = 0; + } + + if (priv->alpha != NULL) + { + /* this will take care of any reference we hold on the timeline */ + g_object_unref (priv->alpha); priv->alpha = NULL; } - priv->alpha = alpha; + if (alpha == NULL) + goto out; + priv->alpha = g_object_ref_sink (alpha); priv->alpha_notify_id = - g_signal_connect (alpha, "notify::alpha", + g_signal_connect (priv->alpha, "notify::value", G_CALLBACK (on_alpha_notify), animation); + + /* if the alpha has a timeline then we use it, otherwise we create one */ + timeline = clutter_alpha_get_timeline (priv->alpha); + if (timeline != NULL) + { + priv->timeline_started_id = + g_signal_connect (timeline, "started", + G_CALLBACK (on_timeline_started), + animation); + priv->timeline_completed_id = + g_signal_connect (timeline, "completed", + G_CALLBACK (on_timeline_completed), + animation); + } + else + timeline = clutter_animation_get_timeline_internal (animation); + +out: + /* emit all relevant notifications */ + g_object_notify (G_OBJECT (animation), "mode"); + g_object_notify (G_OBJECT (animation), "duration"); + g_object_notify (G_OBJECT (animation), "loop"); + g_object_notify (G_OBJECT (animation), "alpha"); + g_object_notify (G_OBJECT (animation), "timeline"); + + g_object_thaw_notify (G_OBJECT (animation)); } /** @@ -1257,7 +1356,7 @@ clutter_animation_get_alpha (ClutterAnimation *animation) { g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), NULL); - return animation->priv->alpha; + return clutter_animation_get_alpha_internal (animation); } /** @@ -1298,8 +1397,12 @@ on_animation_completed (ClutterAnimation *animation) static void clutter_animation_start (ClutterAnimation *animation) { - if (G_LIKELY (animation->priv->timeline)) - clutter_timeline_start (animation->priv->timeline); + ClutterTimeline *timeline; + + timeline = clutter_animation_get_timeline_internal (animation); + + if (G_LIKELY (timeline != NULL)) + clutter_timeline_start (timeline); else { /* sanity check */ @@ -1545,7 +1648,7 @@ clutter_actor_animate_with_alpha (ClutterActor *actor, g_return_val_if_fail (first_property_name != NULL, NULL); timeline = clutter_alpha_get_timeline (alpha); - if (G_UNLIKELY (!timeline)) + if (timeline == NULL) { g_warning ("The passed ClutterAlpha does not have an " "associated ClutterTimeline."); @@ -1553,9 +1656,10 @@ clutter_actor_animate_with_alpha (ClutterActor *actor, } animation = g_object_get_qdata (G_OBJECT (actor), quark_object_animation); - if (G_LIKELY (!animation)) + if (animation == NULL) { animation = clutter_animation_new (); + clutter_animation_set_object (animation, G_OBJECT (actor)); g_signal_connect (animation, "completed", G_CALLBACK (on_animation_completed), @@ -1566,9 +1670,7 @@ clutter_actor_animate_with_alpha (ClutterActor *actor, else CLUTTER_NOTE (ANIMATION, "Reusing Animation [%p]", animation); - clutter_animation_set_timeline (animation, timeline); clutter_animation_set_alpha (animation, alpha); - clutter_animation_set_object (animation, G_OBJECT (actor)); va_start (args, first_property_name); clutter_animation_setup_valist (animation, first_property_name, args); @@ -1618,9 +1720,10 @@ clutter_actor_animate_with_timeline (ClutterActor *actor, g_return_val_if_fail (first_property_name != NULL, NULL); animation = g_object_get_qdata (G_OBJECT (actor), quark_object_animation); - if (G_LIKELY (!animation)) + if (animation == NULL) { animation = clutter_animation_new (); + clutter_animation_set_object (animation, G_OBJECT (actor)); g_signal_connect (animation, "completed", G_CALLBACK (on_animation_completed), @@ -1631,10 +1734,8 @@ clutter_actor_animate_with_timeline (ClutterActor *actor, else CLUTTER_NOTE (ANIMATION, "Reusing Animation [%p]", animation); - clutter_animation_set_timeline (animation, timeline); - clutter_animation_set_alpha (animation, NULL); clutter_animation_set_mode (animation, mode); - clutter_animation_set_object (animation, G_OBJECT (actor)); + clutter_animation_set_timeline (animation, timeline); va_start (args, first_property_name); clutter_animation_setup_valist (animation, first_property_name, args); @@ -1809,15 +1910,13 @@ clutter_actor_animate (ClutterActor *actor, g_return_val_if_fail (first_property_name != NULL, NULL); animation = g_object_get_qdata (G_OBJECT (actor), quark_object_animation); - if (G_LIKELY (!animation)) + if (animation == NULL) { /* if there is no animation already attached to the actor, * create one and set up the timeline and alpha using the * current values for duration, mode and loop */ animation = clutter_animation_new (); - clutter_animation_set_timeline (animation, NULL); - clutter_animation_set_alpha (animation, NULL); clutter_animation_set_object (animation, G_OBJECT (actor)); g_signal_connect (animation, "completed", @@ -1832,8 +1931,8 @@ clutter_actor_animate (ClutterActor *actor, /* force the update of duration and mode using the new * values coming from the parameters of this function */ - clutter_animation_set_duration (animation, duration); clutter_animation_set_mode (animation, mode); + clutter_animation_set_duration (animation, duration); va_start (args, first_property_name); clutter_animation_setup_valist (animation, first_property_name, args); @@ -1888,15 +1987,13 @@ clutter_actor_animatev (ClutterActor *actor, g_return_val_if_fail (values != NULL, NULL); animation = g_object_get_qdata (G_OBJECT (actor), quark_object_animation); - if (G_LIKELY (!animation)) + if (animation == NULL) { /* if there is no animation already attached to the actor, * create one and set up the timeline and alpha using the * current values for duration, mode and loop */ animation = clutter_animation_new (); - clutter_animation_set_timeline (animation, NULL); - clutter_animation_set_alpha (animation, NULL); clutter_animation_set_object (animation, G_OBJECT (actor)); g_signal_connect (animation, "completed", @@ -1911,8 +2008,8 @@ clutter_actor_animatev (ClutterActor *actor, /* force the update of duration and mode using the new * values coming from the parameters of this function */ - clutter_animation_set_duration (animation, duration); clutter_animation_set_mode (animation, mode); + clutter_animation_set_duration (animation, duration); clutter_animation_setupv (animation, n_properties, properties, values); clutter_animation_start (animation); @@ -1967,9 +2064,10 @@ clutter_actor_animate_with_timelinev (ClutterActor *actor, g_return_val_if_fail (values != NULL, NULL); animation = g_object_get_qdata (G_OBJECT (actor), quark_object_animation); - if (G_LIKELY (!animation)) + if (animation == NULL) { animation = clutter_animation_new (); + clutter_animation_set_object (animation, G_OBJECT (actor)); g_signal_connect (animation, "completed", G_CALLBACK (on_animation_completed), @@ -1980,10 +2078,8 @@ clutter_actor_animate_with_timelinev (ClutterActor *actor, else CLUTTER_NOTE (ANIMATION, "Reusing Animation [%p]", animation); - clutter_animation_set_timeline (animation, timeline); - clutter_animation_set_alpha (animation, NULL); clutter_animation_set_mode (animation, mode); - clutter_animation_set_object (animation, G_OBJECT (actor)); + clutter_animation_set_timeline (animation, timeline); clutter_animation_setupv (animation, n_properties, properties, values); clutter_animation_start (animation); @@ -2036,7 +2132,7 @@ clutter_actor_animate_with_alphav (ClutterActor *actor, g_return_val_if_fail (values != NULL, NULL); timeline = clutter_alpha_get_timeline (alpha); - if (G_UNLIKELY (!timeline)) + if (timeline == NULL) { g_warning ("The passed ClutterAlpha does not have an " "associated ClutterTimeline."); @@ -2044,9 +2140,10 @@ clutter_actor_animate_with_alphav (ClutterActor *actor, } animation = g_object_get_qdata (G_OBJECT (actor), quark_object_animation); - if (G_LIKELY (!animation)) + if (animation == NULL) { animation = clutter_animation_new (); + clutter_animation_set_object (animation, G_OBJECT (actor)); g_signal_connect (animation, "completed", G_CALLBACK (on_animation_completed), @@ -2057,9 +2154,7 @@ clutter_actor_animate_with_alphav (ClutterActor *actor, else CLUTTER_NOTE (ANIMATION, "Reusing Animation [%p]", animation); - clutter_animation_set_timeline (animation, timeline); clutter_animation_set_alpha (animation, alpha); - clutter_animation_set_object (animation, G_OBJECT (actor)); clutter_animation_setupv (animation, n_properties, properties, values); clutter_animation_start (animation); diff --git a/clutter/clutter-backend.c b/clutter/clutter-backend.c index becf9972f..cc5f10688 100644 --- a/clutter/clutter-backend.c +++ b/clutter/clutter-backend.c @@ -61,7 +61,8 @@ struct _ClutterBackendPrivate guint double_click_distance; gdouble resolution; - gdouble units_per_em; + + gfloat units_per_em; cairo_font_options_t *font_options; @@ -102,55 +103,74 @@ clutter_backend_dispose (GObject *gobject) G_OBJECT_CLASS (clutter_backend_parent_class)->dispose (gobject); } -static inline void -update_units_per_em (ClutterBackend *backend) +static gfloat +get_units_per_em (ClutterBackend *backend, + PangoFontDescription *font_desc) { - ClutterBackendPrivate *priv = backend->priv; - const gchar *font_name; + gfloat units_per_em = -1.0; + gboolean free_font_desc = FALSE; gdouble dpi; - font_name = clutter_backend_get_font_name (backend); dpi = clutter_backend_get_resolution (backend); - if (G_LIKELY (font_name != NULL && *font_name != '\0')) + if (font_desc == NULL) { - PangoFontDescription *font_desc; - gdouble font_size = 0; + const gchar *font_name = clutter_backend_get_font_name (backend); - font_desc = pango_font_description_from_string (font_name); - if (G_LIKELY (font_desc != NULL)) + if (G_LIKELY (font_name != NULL && *font_name != '\0')) { - gint pango_size; - gboolean is_absolute; - - pango_size = pango_font_description_get_size (font_desc); - is_absolute = - pango_font_description_get_size_is_absolute (font_desc); - if (!is_absolute) - font_size = ((gdouble) font_size) / PANGO_SCALE; - - pango_font_description_free (font_desc); + font_desc = pango_font_description_from_string (font_name); + free_font_desc = TRUE; } + } - /* 10 points at 96 DPI is 12 pixels */ - priv->units_per_em = 1.2 * font_size - * dpi - / 96.0; + if (font_desc != NULL) + { + gdouble font_size = 0; + gint pango_size; + gboolean is_absolute; + + pango_size = pango_font_description_get_size (font_desc); + is_absolute = pango_font_description_get_size_is_absolute (font_desc); + + /* "absolute" means "device units" (usually, pixels); otherwise, + * it means logical units (points) + */ + if (is_absolute) + font_size = (gdouble) pango_size / PANGO_SCALE; + else + font_size = (gdouble) pango_size / PANGO_SCALE + * dpi + / 96.0f; + + /* 10 points at 96 DPI is 13.3 pixels */ + units_per_em = (1.2f * font_size) + * dpi + / 96.0f; } else - priv->units_per_em = -1.0; + units_per_em = -1.0f; + + if (free_font_desc) + pango_font_description_free (font_desc); + + return units_per_em; } static void clutter_backend_real_resolution_changed (ClutterBackend *backend) { - update_units_per_em (backend); + backend->priv->units_per_em = get_units_per_em (backend, NULL); + + CLUTTER_NOTE (BACKEND, "Units per em: %.2f", backend->priv->units_per_em); } static void clutter_backend_real_font_changed (ClutterBackend *backend) { - update_units_per_em (backend); + backend->priv->units_per_em = get_units_per_em (backend, NULL); + + CLUTTER_NOTE (BACKEND, "Units per em: %.2f", backend->priv->units_per_em); } static void @@ -280,36 +300,63 @@ _clutter_backend_redraw (ClutterBackend *backend, klass->redraw (backend, stage); } +gboolean +_clutter_backend_create_context (ClutterBackend *backend, + gboolean is_offscreen, + GError **error) +{ + ClutterBackendClass *klass; + + g_return_val_if_fail (CLUTTER_IS_BACKEND (backend), FALSE); + + klass = CLUTTER_BACKEND_GET_CLASS (backend); + if (klass->create_context) + return klass->create_context (backend, is_offscreen, error); + + return TRUE; +} + void _clutter_backend_ensure_context (ClutterBackend *backend, ClutterStage *stage) { - ClutterBackendClass *klass; static ClutterStage *current_context_stage = NULL; + ClutterBackendClass *klass; g_return_if_fail (CLUTTER_IS_BACKEND (backend)); g_return_if_fail (CLUTTER_IS_STAGE (stage)); if (current_context_stage != stage || !CLUTTER_ACTOR_IS_REALIZED (stage)) { + ClutterStage *new_stage = NULL; + if (!CLUTTER_ACTOR_IS_REALIZED (stage)) { - CLUTTER_NOTE (MULTISTAGE, "Stage is not realized, unsetting"); - stage = NULL; + new_stage = NULL; + + CLUTTER_NOTE (MULTISTAGE, + "Stage [%p] is not realized, unsetting the stage", + stage); } else - CLUTTER_NOTE (MULTISTAGE, "Setting the new stage [%p]", stage); - + { + new_stage = stage; + + CLUTTER_NOTE (MULTISTAGE, + "Setting the new stage [%p]", + new_stage); + } + klass = CLUTTER_BACKEND_GET_CLASS (backend); if (G_LIKELY (klass->ensure_context)) - klass->ensure_context (backend, stage); + klass->ensure_context (backend, new_stage); /* FIXME: With a NULL stage and thus no active context it may make more * sense to clean the context but then re call with the default stage * so at least there is some kind of context in place (as to avoid * potential issue of GL calls with no context) */ - current_context_stage = stage; + current_context_stage = new_stage; /* if the new stage has a different size than the previous one * we need to update the viewport; we do it by simply setting the @@ -359,8 +406,9 @@ _clutter_backend_init_events (ClutterBackend *backend) klass->init_events (backend); } -ClutterUnit -_clutter_backend_get_units_per_em (ClutterBackend *backend) +gfloat +_clutter_backend_get_units_per_em (ClutterBackend *backend, + PangoFontDescription *font_desc) { ClutterBackendPrivate *priv; @@ -368,8 +416,12 @@ _clutter_backend_get_units_per_em (ClutterBackend *backend) priv = backend->priv; - if (G_UNLIKELY (priv->units_per_em < 0)) - update_units_per_em (backend); + /* recompute for the font description, but do not cache the result */ + if (font_desc != NULL) + return get_units_per_em (backend, font_desc); + + if (priv->units_per_em < 0) + priv->units_per_em = get_units_per_em (backend, NULL); return priv->units_per_em; } @@ -602,6 +654,8 @@ clutter_backend_get_font_options (ClutterBackend *backend) cairo_font_options_set_antialias (priv->font_options, CAIRO_ANTIALIAS_DEFAULT); + g_signal_emit (backend, backend_signals[FONT_CHANGED], 0); + return priv->font_options; } @@ -661,7 +715,12 @@ clutter_backend_get_font_name (ClutterBackend *backend) if (G_LIKELY (priv->font_name)) return priv->font_name; + /* if we have never been called then we need to set the + * default font and update everything that relies on the + * ::font-changed signal + */ priv->font_name = g_strdup (DEFAULT_FONT_NAME); + g_signal_emit (backend, backend_signals[FONT_CHANGED], 0); return priv->font_name; } diff --git a/clutter/clutter-backend.h b/clutter/clutter-backend.h index 12f138af7..6529100c4 100644 --- a/clutter/clutter-backend.h +++ b/clutter/clutter-backend.h @@ -77,6 +77,9 @@ struct _ClutterBackendClass ClutterFeatureFlags (* get_features) (ClutterBackend *backend); void (* redraw) (ClutterBackend *backend, ClutterStage *stage); + gboolean (* create_context) (ClutterBackend *backend, + gboolean is_offscreen, + GError **error); void (* ensure_context) (ClutterBackend *backend, ClutterStage *stage); diff --git a/clutter/clutter-behaviour.c b/clutter/clutter-behaviour.c index c3ef6b2af..99156a7f6 100644 --- a/clutter/clutter-behaviour.c +++ b/clutter/clutter-behaviour.c @@ -552,13 +552,16 @@ notify_cb (GObject *object, * @behave: a #ClutterBehaviour * @alpha: a #ClutterAlpha or %NULL to unset a previously set alpha * - * Binds @alpha to a #ClutterBehaviour. The #ClutterAlpha object + * Binds @alpha to a #ClutterBehaviour. The #ClutterAlpha object * is what makes a behaviour work: for each tick of the timeline * used by #ClutterAlpha a new value of the alpha parameter is * computed by the alpha function; the value should be used by * the #ClutterBehaviour to update one or more properties of the * actors to which the behaviour applies. * + * If @alpha is not %NULL, the #ClutterBehaviour will take ownership + * of the #ClutterAlpha instance. + * * Since: 0.2 */ void diff --git a/clutter/clutter-cairo-texture.c b/clutter/clutter-cairo-texture.c index 8c3e3519f..82c614cb5 100644 --- a/clutter/clutter-cairo-texture.c +++ b/clutter/clutter-cairo-texture.c @@ -325,9 +325,9 @@ clutter_cairo_texture_notify (GObject *object, static void clutter_cairo_texture_get_preferred_width (ClutterActor *actor, - ClutterUnit for_height, - ClutterUnit *min_width, - ClutterUnit *natural_width) + gfloat for_height, + gfloat *min_width, + gfloat *natural_width) { ClutterCairoTexturePrivate *priv = CLUTTER_CAIRO_TEXTURE (actor)->priv; @@ -335,14 +335,14 @@ clutter_cairo_texture_get_preferred_width (ClutterActor *actor, *min_width = 0; if (natural_width) - *natural_width = CLUTTER_UNITS_FROM_DEVICE (priv->width); + *natural_width = (gfloat) priv->width; } static void clutter_cairo_texture_get_preferred_height (ClutterActor *actor, - ClutterUnit for_width, - ClutterUnit *min_height, - ClutterUnit *natural_height) + gfloat for_width, + gfloat *min_height, + gfloat *natural_height) { ClutterCairoTexturePrivate *priv = CLUTTER_CAIRO_TEXTURE (actor)->priv; @@ -350,7 +350,7 @@ clutter_cairo_texture_get_preferred_height (ClutterActor *actor, *min_height = 0; if (natural_height) - *natural_height = CLUTTER_UNITS_FROM_DEVICE (priv->height); + *natural_height = (gfloat) priv->height; } static void diff --git a/clutter/clutter-clone.c b/clutter/clutter-clone.c index 8cb9b2b87..78bc4148a 100644 --- a/clutter/clutter-clone.c +++ b/clutter/clutter-clone.c @@ -65,16 +65,18 @@ struct _ClutterClonePrivate ClutterActor *clone_source; }; +static void clutter_clone_set_source_internal (ClutterClone *clone, + ClutterActor *source); static void clutter_clone_get_preferred_width (ClutterActor *self, - ClutterUnit for_height, - ClutterUnit *min_width_p, - ClutterUnit *natural_width_p) + gfloat for_height, + gfloat *min_width_p, + gfloat *natural_width_p) { ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv; ClutterActor *clone_source = priv->clone_source; - if (G_UNLIKELY (clone_source == NULL)) + if (clone_source == NULL) { if (min_width_p) *min_width_p = 0; @@ -91,14 +93,14 @@ clutter_clone_get_preferred_width (ClutterActor *self, static void clutter_clone_get_preferred_height (ClutterActor *self, - ClutterUnit for_width, - ClutterUnit *min_height_p, - ClutterUnit *natural_height_p) + gfloat for_width, + gfloat *min_height_p, + gfloat *natural_height_p) { ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv; ClutterActor *clone_source = priv->clone_source; - if (G_UNLIKELY (clone_source == NULL)) + if (clone_source == NULL) { if (min_height_p) *min_height_p = 0; @@ -120,6 +122,7 @@ clutter_clone_paint (ClutterActor *self) ClutterClonePrivate *priv = clone->priv; ClutterGeometry geom, clone_geom; gfloat x_scale, y_scale; + gboolean was_unmapped = FALSE; if (G_UNLIKELY (priv->clone_source == NULL)) return; @@ -153,23 +156,32 @@ clutter_clone_paint (ClutterActor *self) _clutter_actor_set_opacity_parent (priv->clone_source, self); _clutter_actor_set_enable_model_view_transform (priv->clone_source, FALSE); + if (!CLUTTER_ACTOR_IS_MAPPED (priv->clone_source)) + { + _clutter_actor_set_enable_paint_unmapped (priv->clone_source, TRUE); + was_unmapped = TRUE; + } + clutter_actor_paint (priv->clone_source); + if (was_unmapped) + _clutter_actor_set_enable_paint_unmapped (priv->clone_source, FALSE); + _clutter_actor_set_enable_model_view_transform (priv->clone_source, TRUE); _clutter_actor_set_opacity_parent (priv->clone_source, NULL); } static void -clutter_clone_allocate (ClutterActor *self, - const ClutterActorBox *box, - gboolean origin_changed) +clutter_clone_allocate (ClutterActor *self, + const ClutterActorBox *box, + ClutterAllocationFlags flags) { ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv; ClutterActorClass *parent_class; /* chain up */ parent_class = CLUTTER_ACTOR_CLASS (clutter_clone_parent_class); - parent_class->allocate (self, box, origin_changed); + parent_class->allocate (self, box, flags); if (G_UNLIKELY (priv->clone_source == NULL)) return; @@ -182,10 +194,7 @@ clutter_clone_allocate (ClutterActor *self, * paint cycle, we can safely give it as much size as it requires */ if (clutter_actor_get_parent (priv->clone_source) == NULL) - { - clutter_actor_allocate_preferred_size (priv->clone_source, - origin_changed); - } + clutter_actor_allocate_preferred_size (priv->clone_source, flags); } static void @@ -231,13 +240,7 @@ clutter_clone_get_property (GObject *gobject, static void clutter_clone_dispose (GObject *gobject) { - ClutterClonePrivate *priv = CLUTTER_CLONE (gobject)->priv; - - if (priv->clone_source) - { - g_object_unref (priv->clone_source); - priv->clone_source = NULL; - } + clutter_clone_set_source_internal (CLUTTER_CLONE (gobject), NULL); G_OBJECT_CLASS (clutter_clone_parent_class)->dispose (gobject); } @@ -302,6 +305,46 @@ clutter_clone_new (ClutterActor *source) return g_object_new (CLUTTER_TYPE_CLONE, "source", source, NULL); } +static void +clone_source_queue_redraw_cb (ClutterActor *source, + ClutterActor *origin, + ClutterClone *clone) +{ + clutter_actor_queue_redraw (CLUTTER_ACTOR (clone)); +} + +static void +clutter_clone_set_source_internal (ClutterClone *clone, + ClutterActor *source) +{ + ClutterClonePrivate *priv; + + g_return_if_fail (CLUTTER_IS_CLONE (clone)); + g_return_if_fail (source == NULL || CLUTTER_IS_ACTOR (source)); + + priv = clone->priv; + + if (priv->clone_source) + { + g_signal_handlers_disconnect_by_func (priv->clone_source, + (void *) clone_source_queue_redraw_cb, + clone); + g_object_unref (priv->clone_source); + priv->clone_source = NULL; + } + + if (source) + { + priv->clone_source = g_object_ref (source); + g_signal_connect (priv->clone_source, "queue-redraw", + G_CALLBACK (clone_source_queue_redraw_cb), clone); + } + + g_object_notify (G_OBJECT (clone), "source"); + + clutter_actor_queue_relayout (CLUTTER_ACTOR (clone)); +} + /** * clutter_clone_set_source: * @clone: a #ClutterClone @@ -315,24 +358,10 @@ void clutter_clone_set_source (ClutterClone *clone, ClutterActor *source) { - ClutterClonePrivate *priv; - g_return_if_fail (CLUTTER_IS_CLONE (clone)); g_return_if_fail (source == NULL || CLUTTER_IS_ACTOR (source)); - priv = clone->priv; - - if (priv->clone_source) - { - g_object_unref (priv->clone_source); - priv->clone_source = NULL; - } - - if (source) - priv->clone_source = g_object_ref (source); - - g_object_notify (G_OBJECT (clone), "source"); - + clutter_clone_set_source_internal (clone, source); clutter_actor_queue_relayout (CLUTTER_ACTOR (clone)); } diff --git a/clutter/clutter-color.c b/clutter/clutter-color.c index 3d40ea5c7..0ff170e59 100644 --- a/clutter/clutter-color.c +++ b/clutter/clutter-color.c @@ -398,7 +398,7 @@ clutter_color_from_string (ClutterColor *color, g_return_val_if_fail (str != NULL, FALSE); /* if the string contains a color encoded using the hexadecimal - * notations (#rrggbbaa or #rrggbb) we attempt a rough pass at + * notations (#rrggbbaa or #rgba) we attempt a rough pass at * parsing the color ourselves, as we need the alpha channel that * Pango can't retrieve. */ @@ -407,36 +407,34 @@ clutter_color_from_string (ClutterColor *color, gint32 result; if (sscanf (str + 1, "%x", &result)) - { - if (strlen (str) == 9) - { + { + if (strlen (str) == 9) + { /* #rrggbbaa */ - color->red = (result >> 24) & 0xff; - color->green = (result >> 16) & 0xff; - color->blue = (result >> 8) & 0xff; + color->red = (result >> 24) & 0xff; + color->green = (result >> 16) & 0xff; + color->blue = (result >> 8) & 0xff; - color->alpha = result & 0xff; + color->alpha = result & 0xff; - return TRUE; - } - else if (strlen (str) == 7) - { - /* #rrggbb */ - color->red = (result >> 16) & 0xff; - color->green = (result >> 8) & 0xff; - color->blue = result & 0xff; + return TRUE; + } + else if (strlen (str) == 5) + { + /* #rgba */ + color->red = ((result >> 12) & 0xf); + color->green = ((result >> 8) & 0xf); + color->blue = ((result >> 4) & 0xf); + color->alpha = result & 0xf; - color->alpha = 0xff; + color->red = (color->red << 4) | color->red; + color->green = (color->green << 4) | color->green; + color->blue = (color->blue << 4) | color->blue; + color->alpha = (color->alpha << 4) | color->alpha; - return TRUE; - } - } - - /* XXX - should we return FALSE here? it's not like - * Pango is endowed with mystical parsing powers and - * will be able to do better than the code above. - * still, it doesn't hurt - */ + return TRUE; + } + } } /* Fall back to pango for named colors */ diff --git a/clutter/clutter-container.c b/clutter/clutter-container.c index 63b4eab47..3f2296da6 100644 --- a/clutter/clutter-container.c +++ b/clutter/clutter-container.c @@ -449,7 +449,10 @@ clutter_container_get_children (ClutterContainer *container) * @callback: a function to be called for each child * @user_data: data to be passed to the function, or %NULL * - * Calls @callback for each child of @container. + * Calls @callback for each child of @container that was added + * by the application (with clutter_container_add_actor()). Does + * not iterate over "internal" children that are part of the + * container's own implementation, if any. * * Since: 0.4 */ @@ -473,6 +476,41 @@ clutter_container_foreach (ClutterContainer *container, iface->foreach (container, callback, user_data); } +/** + * clutter_container_foreach_with_internals: + * @container: a #ClutterContainer + * @callback: a function to be called for each child + * @user_data: data to be passed to the function, or %NULL + * + * Calls @callback for each child of @container, including "internal" + * children built in to the container itself that were never added + * by the application. + * + * Since: 1.0 + */ +void +clutter_container_foreach_with_internals (ClutterContainer *container, + ClutterCallback callback, + gpointer user_data) +{ + ClutterContainerIface *iface; + + g_return_if_fail (CLUTTER_IS_CONTAINER (container)); + g_return_if_fail (callback != NULL); + + iface = CLUTTER_CONTAINER_GET_IFACE (container); + if (!iface->foreach) + { + CLUTTER_CONTAINER_WARN_NOT_IMPLEMENTED (container, "foreach"); + return; + } + + if (iface->foreach_with_internals != NULL) + iface->foreach_with_internals (container, callback, user_data); + else + iface->foreach (container, callback, user_data); +} + /** * clutter_container_raise_child: * @container: a #ClutterContainer diff --git a/clutter/clutter-container.h b/clutter/clutter-container.h index 68cbd71fd..083bba167 100644 --- a/clutter/clutter-container.h +++ b/clutter/clutter-container.h @@ -52,6 +52,11 @@ typedef struct _ClutterContainerIface ClutterContainerIface; * implementation of this virtual function is required. * @foreach: virtual function for iterating over the container's children. * The implementation of this virtual function is required. + * @foreach_with_internals: virtual functions for iterating over the + * container's children, both added using the #ClutterContainer API + * and internal children. The implementation of this virtual function + * is required only if the #ClutterContainer implementation has + * internal children. * @raise: virtual function for raising a child * @lower: virtual function for lowering a child * @sort_depth_order: virtual function for sorting the children of a @@ -90,6 +95,10 @@ struct _ClutterContainerIface ClutterCallback callback, gpointer user_data); + void (* foreach_with_internals) (ClutterContainer *container, + ClutterCallback callback, + gpointer user_data); + /* child stacking */ void (* raise) (ClutterContainer *container, ClutterActor *actor, @@ -137,20 +146,22 @@ void clutter_container_remove_actor (ClutterContainer *container, void clutter_container_remove_valist (ClutterContainer *container, ClutterActor *first_actor, va_list var_args); -GList * clutter_container_get_children (ClutterContainer *container); -void clutter_container_foreach (ClutterContainer *container, - ClutterCallback callback, - gpointer user_data); -ClutterActor *clutter_container_find_child_by_name (ClutterContainer *container, - const gchar *child_name); -void clutter_container_raise_child (ClutterContainer *container, - ClutterActor *actor, - ClutterActor *sibling); -void clutter_container_lower_child (ClutterContainer *container, - ClutterActor *actor, - ClutterActor *sibling); -void clutter_container_sort_depth_order (ClutterContainer *container); - +GList * clutter_container_get_children (ClutterContainer *container); +void clutter_container_foreach (ClutterContainer *container, + ClutterCallback callback, + gpointer user_data); +void clutter_container_foreach_with_internals (ClutterContainer *container, + ClutterCallback callback, + gpointer user_data); +ClutterActor *clutter_container_find_child_by_name (ClutterContainer *container, + const gchar *child_name); +void clutter_container_raise_child (ClutterContainer *container, + ClutterActor *actor, + ClutterActor *sibling); +void clutter_container_lower_child (ClutterContainer *container, + ClutterActor *actor, + ClutterActor *sibling); +void clutter_container_sort_depth_order (ClutterContainer *container); GParamSpec * clutter_container_class_find_child_property (GObjectClass *klass, diff --git a/clutter/clutter-deprecated.h b/clutter/clutter-deprecated.h index 8e99ab951..8d0c99787 100644 --- a/clutter/clutter-deprecated.h +++ b/clutter/clutter-deprecated.h @@ -148,4 +148,24 @@ #define clutter_shader_set_uniform_1f clutter_shader_set_uniform_1f_REPLACED_BY_clutter_shader_set_uniform +#define clutter_actor_set_xu clutter_actor_set_xu_DEPRECATED_BY_clutter_actor_set_x +#define clutter_actor_set_yu clutter_actor_set_yu_DEPRECATED_BY_clutter_actor_set_y +#define clutter_actor_set_widthu clutter_actor_set_widthu_DEPRECATED_BY_clutter_actor_set_width +#define clutter_actor_set_heightu clutter_actor_set_heightu_DEPRECATED_BY_clutter_actor_set_height +#define clutter_actor_set_depthu clutter_actor_set_depthu_DEPRECATED_BY_clutter_actor_set_depth +#define clutter_actor_set_positionu clutter_actor_set_positionu_DEPRECATED_BY_clutter_actor_set_position +#define clutter_actor_set_sizeu clutter_actor_set_sizeu_DEPRECATED_BY_clutter_actor_set_size + +#define clutter_actor_set_anchor_pointu clutter_actor_set_anchor_pointu_DEPRECATED_BY_clutter_actor_set_anchor_point +#define clutter_actor_get_anchor_pointu clutter_actor_get_anchor_pointu_DEPRECATED_BY_clutter_actor_get_anchor_point +#define clutter_actor_move_byu clutter_actor_move_byu_DEPRECATED_BY_clutter_actor_move_by + +#define clutter_actor_get_xu clutter_actor_get_xu_DEPRECATED_BY_clutter_actor_get_x +#define clutter_actor_get_yu clutter_actor_get_yu_DEPRECATED_BY_clutter_actor_get_y +#define clutter_actor_get_widthu clutter_actor_get_widthu_DEPRECATED_BY_clutter_actor_get_width +#define clutter_actor_get_heightu clutter_actor_get_heightu_DEPRECATED_BY_clutter_actor_get_height +#define clutter_actor_get_depthu clutter_actor_get_depthu_DEPRECATED_BY_clutter_actor_get_depth +#define clutter_actor_get_positionu clutter_actor_get_positionu_DEPRECATED_BY_clutter_actor_get_position +#define clutter_actor_get_sizeu clutter_actor_get_sizeu_DEPRECATED_BY_clutter_actor_get_size + #endif /* CLUTTER_DEPRECATED_H */ diff --git a/clutter/clutter-enum-types.c.in b/clutter/clutter-enum-types.c.in index 4107f40a0..19fb9e502 100644 --- a/clutter/clutter-enum-types.c.in +++ b/clutter/clutter-enum-types.c.in @@ -3,15 +3,19 @@ /*** END file-header ***/ /*** BEGIN file-production ***/ + /* enumerations from "@filename@" */ #include "@filename@" + /*** END file-production ***/ /*** BEGIN value-header ***/ GType -@enum_name@_get_type(void) { - static GType etype = 0; - if (G_UNLIKELY (!etype)) +@enum_name@_get_type (void) +{ + static volatile gsize g_enum_type_id__volatile = 0; + + if (g_once_init_enter (&g_enum_type_id__volatile)) { static const G@Type@Value values[] = { /*** END value-header ***/ @@ -23,8 +27,14 @@ GType /*** BEGIN value-tail ***/ { 0, NULL, NULL } }; - etype = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); + GType g_enum_type_id; + + g_enum_type_id = + g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); + + g_once_init_leave (&g_enum_type_id__volatile, g_enum_type_id); } - return etype; + + return g_enum_type_id__volatile; } /*** END value-tail ***/ diff --git a/clutter/clutter-event.c b/clutter/clutter-event.c index 90d096b01..14eb109b3 100644 --- a/clutter/clutter-event.c +++ b/clutter/clutter-event.c @@ -120,10 +120,10 @@ clutter_event_get_state (ClutterEvent *event) */ void clutter_event_get_coords (ClutterEvent *event, - gint *x, - gint *y) + gfloat *x, + gfloat *y) { - gint event_x, event_y; + gfloat event_x, event_y; g_return_if_fail (event != NULL); @@ -141,15 +141,18 @@ clutter_event_get_coords (ClutterEvent *event, case CLUTTER_ENTER: case CLUTTER_LEAVE: break; + case CLUTTER_BUTTON_PRESS: case CLUTTER_BUTTON_RELEASE: event_x = event->button.x; event_y = event->button.y; break; + case CLUTTER_MOTION: event_x = event->motion.x; event_y = event->motion.y; break; + case CLUTTER_SCROLL: event_x = event->scroll.x; event_y = event->scroll.y; diff --git a/clutter/clutter-event.h b/clutter/clutter-event.h index 34583e7ee..984bdb194 100644 --- a/clutter/clutter-event.h +++ b/clutter/clutter-event.h @@ -221,8 +221,8 @@ typedef struct _ClutterInputDevice ClutterInputDevice; */ struct _ClutterAnyEvent { - ClutterEventType type; - guint32 time; + ClutterEventType type; + guint32 time; ClutterEventFlags flags; ClutterStage *stage; ClutterActor *source; @@ -290,8 +290,8 @@ struct _ClutterButtonEvent ClutterEventFlags flags; ClutterStage *stage; ClutterActor *source; - gint x; - gint y; + gfloat x; + gfloat y; ClutterModifierType modifier_state; guint32 button; guint click_count; @@ -322,8 +322,8 @@ struct _ClutterCrossingEvent ClutterEventFlags flags; ClutterStage *stage; ClutterActor *source; - gint x; - gint y; + gfloat x; + gfloat y; ClutterInputDevice *device; /* future use */ ClutterActor *related; }; @@ -352,8 +352,8 @@ struct _ClutterMotionEvent ClutterEventFlags flags; ClutterStage *stage; ClutterActor *source; - gint x; - gint y; + gfloat x; + gfloat y; ClutterModifierType modifier_state; gdouble *axes; /* Future use */ ClutterInputDevice *device; /* Future use */ @@ -384,8 +384,8 @@ struct _ClutterScrollEvent ClutterEventFlags flags; ClutterStage *stage; ClutterActor *source; - gint x; - gint y; + gfloat x; + gfloat y; ClutterScrollDirection direction; ClutterModifierType modifier_state; gdouble *axes; /* future use */ @@ -451,8 +451,8 @@ ClutterEventType clutter_event_type (ClutterEvent *event); guint32 clutter_event_get_time (ClutterEvent *event); ClutterModifierType clutter_event_get_state (ClutterEvent *event); void clutter_event_get_coords (ClutterEvent *event, - gint *x, - gint *y); + gfloat *x, + gfloat *y); gint clutter_event_get_device_id (ClutterEvent *event); ClutterActor* clutter_event_get_source (ClutterEvent *event); diff --git a/clutter/clutter-group.c b/clutter/clutter-group.c index 712acb464..0653e76f1 100644 --- a/clutter/clutter-group.c +++ b/clutter/clutter-group.c @@ -96,8 +96,7 @@ clutter_group_paint (ClutterActor *actor) g_assert (child != NULL); - if (CLUTTER_ACTOR_IS_VISIBLE (child)) - clutter_actor_paint (child); + clutter_actor_paint (child); } CLUTTER_NOTE (PAINT, "ClutterGroup paint leave '%s'", @@ -105,44 +104,36 @@ clutter_group_paint (ClutterActor *actor) : "unknown"); } -static void -clutter_group_realize (ClutterActor *actor) -{ - clutter_container_foreach (CLUTTER_CONTAINER (actor), - CLUTTER_CALLBACK (clutter_actor_realize), - NULL); -} - -static void -clutter_group_unrealize (ClutterActor *actor) -{ - clutter_container_foreach (CLUTTER_CONTAINER (actor), - CLUTTER_CALLBACK (clutter_actor_unrealize), - NULL); -} - static void clutter_group_pick (ClutterActor *actor, const ClutterColor *color) { + ClutterGroupPrivate *priv = CLUTTER_GROUP (actor)->priv; + GList *child_item; + /* Chain up so we get a bounding box pained (if we are reactive) */ CLUTTER_ACTOR_CLASS (clutter_group_parent_class)->pick (actor, color); - /* Just forward to the paint call which in turn will trigger - * the child actors also getting 'picked'. - */ - if (CLUTTER_ACTOR_IS_VISIBLE (actor)) - clutter_group_paint (actor); + for (child_item = priv->children; + child_item != NULL; + child_item = child_item->next) + { + ClutterActor *child = child_item->data; + + g_assert (child != NULL); + + clutter_actor_paint (child); + } } static void -clutter_fixed_layout_get_preferred_width (GList *children, - ClutterUnit *min_width_p, - ClutterUnit *natural_width_p) +clutter_fixed_layout_get_preferred_width (GList *children, + gfloat *min_width_p, + gfloat *natural_width_p) { GList *l; - ClutterUnit min_left, min_right; - ClutterUnit natural_left, natural_right; + gfloat min_left, min_right; + gfloat natural_left, natural_right; min_left = 0; min_right = 0; @@ -152,9 +143,9 @@ clutter_fixed_layout_get_preferred_width (GList *children, for (l = children; l != NULL; l = l->next) { ClutterActor *child = l->data; - ClutterUnit child_x, child_min, child_natural; + gfloat child_x, child_min, child_natural; - child_x = clutter_actor_get_xu (child); + child_x = clutter_actor_get_x (child); clutter_actor_get_preferred_size (child, &child_min, NULL, @@ -212,13 +203,13 @@ clutter_fixed_layout_get_preferred_width (GList *children, } static void -clutter_fixed_layout_get_preferred_height (GList *children, - ClutterUnit *min_height_p, - ClutterUnit *natural_height_p) +clutter_fixed_layout_get_preferred_height (GList *children, + gfloat *min_height_p, + gfloat *natural_height_p) { GList *l; - ClutterUnit min_top, min_bottom; - ClutterUnit natural_top, natural_bottom; + gfloat min_top, min_bottom; + gfloat natural_top, natural_bottom; min_top = 0; min_bottom = 0; @@ -228,9 +219,9 @@ clutter_fixed_layout_get_preferred_height (GList *children, for (l = children; l != NULL; l = l->next) { ClutterActor *child = l->data; - ClutterUnit child_y, child_min, child_natural; + gfloat child_y, child_min, child_natural; - child_y = clutter_actor_get_yu (child); + child_y = clutter_actor_get_y (child); clutter_actor_get_preferred_size (child, NULL, &child_min, @@ -288,23 +279,23 @@ clutter_fixed_layout_get_preferred_height (GList *children, } static void -clutter_fixed_layout_allocate (GList *children, - gboolean absolute_origin_changed) +clutter_fixed_layout_allocate (GList *children, + ClutterAllocationFlags flags) { GList *l; for (l = children; l != NULL; l = l->next) { ClutterActor *child = l->data; - clutter_actor_allocate_preferred_size (child, absolute_origin_changed); + clutter_actor_allocate_preferred_size (child, flags); } } static void clutter_group_get_preferred_width (ClutterActor *self, - ClutterUnit for_height, - ClutterUnit *min_width_p, - ClutterUnit *natural_width_p) + gfloat for_height, + gfloat *min_width_p, + gfloat *natural_width_p) { ClutterGroupPrivate *priv = CLUTTER_GROUP (self)->priv; @@ -316,9 +307,9 @@ clutter_group_get_preferred_width (ClutterActor *self, static void clutter_group_get_preferred_height (ClutterActor *self, - ClutterUnit for_width, - ClutterUnit *min_height_p, - ClutterUnit *natural_height_p) + gfloat for_width, + gfloat *min_height_p, + gfloat *natural_height_p) { ClutterGroupPrivate *priv = CLUTTER_GROUP (self)->priv; @@ -329,22 +320,21 @@ clutter_group_get_preferred_height (ClutterActor *self, } static void -clutter_group_allocate (ClutterActor *self, - const ClutterActorBox *box, - gboolean origin_changed) +clutter_group_allocate (ClutterActor *self, + const ClutterActorBox *box, + ClutterAllocationFlags flags) { ClutterGroupPrivate *priv = CLUTTER_GROUP (self)->priv; /* chain up to set actor->allocation */ - CLUTTER_ACTOR_CLASS (clutter_group_parent_class)->allocate (self, box, - origin_changed); + CLUTTER_ACTOR_CLASS (clutter_group_parent_class)->allocate (self, box, flags); /* Note that fixed-layout allocation of children does not care what * allocation the container received, so "box" is not passed in * here. We do not require that children's allocations are completely * contained by our own. */ - clutter_fixed_layout_allocate (priv->children, origin_changed); + clutter_fixed_layout_allocate (priv->children, flags); } static void @@ -587,8 +577,6 @@ clutter_group_class_init (ClutterGroupClass *klass) actor_class->pick = clutter_group_pick; actor_class->show_all = clutter_group_real_show_all; actor_class->hide_all = clutter_group_real_hide_all; - actor_class->realize = clutter_group_realize; - actor_class->unrealize = clutter_group_unrealize; actor_class->get_preferred_width = clutter_group_get_preferred_width; actor_class->get_preferred_height = clutter_group_get_preferred_height; diff --git a/clutter/clutter-interval.c b/clutter/clutter-interval.c index c4181945b..671c6e574 100644 --- a/clutter/clutter-interval.c +++ b/clutter/clutter-interval.c @@ -95,20 +95,7 @@ clutter_interval_real_validate (ClutterInterval *interval, GType pspec_gtype = G_PARAM_SPEC_VALUE_TYPE (pspec); /* check the GTypes we provide first */ - if (pspec_gtype == CLUTTER_TYPE_UNIT) - { - ClutterParamSpecUnit *pspec_unit = CLUTTER_PARAM_SPEC_UNIT (pspec); - ClutterUnit a, b; - - a = b = 0; - clutter_interval_get_interval (interval, &a, &b); - if ((a >= pspec_unit->minimum && a <= pspec_unit->maximum) && - (b >= pspec_unit->minimum && b <= pspec_unit->maximum)) - return TRUE; - else - return FALSE; - } - else if (pspec_gtype == COGL_TYPE_FIXED) + if (pspec_gtype == COGL_TYPE_FIXED) { ClutterParamSpecFixed *pspec_fixed = CLUTTER_PARAM_SPEC_FIXED (pspec); CoglFixed a, b; @@ -265,8 +252,16 @@ clutter_interval_real_compute_value (ClutterInterval *interval, { gdouble ia, ib, res; - ia = g_value_get_double (initial); - ib = g_value_get_double (final); + if (value_type == G_TYPE_DOUBLE) + { + ia = g_value_get_double (initial); + ib = g_value_get_double (final); + } + else + { + ia = g_value_get_float (initial); + ib = g_value_get_float (final); + } res = (factor * (ib - ia)) + ia; diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c index dd91a8c5e..055d7d6b0 100644 --- a/clutter/clutter-main.c +++ b/clutter/clutter-main.c @@ -41,6 +41,7 @@ #include "clutter-event.h" #include "clutter-backend.h" #include "clutter-main.h" +#include "clutter-master-clock.h" #include "clutter-feature.h" #include "clutter-actor.h" #include "clutter-stage.h" @@ -118,7 +119,7 @@ clutter_get_show_fps (void) void _clutter_stage_maybe_relayout (ClutterActor *stage) { - ClutterUnit natural_width, natural_height; + gfloat natural_width, natural_height; ClutterActorBox box = { 0, }; /* avoid reentrancy */ @@ -139,10 +140,10 @@ _clutter_stage_maybe_relayout (ClutterActor *stage) box.y2 = natural_height; CLUTTER_NOTE (ACTOR, "Allocating (0, 0 - %d, %d) for the stage", - CLUTTER_UNITS_TO_DEVICE (natural_width), - CLUTTER_UNITS_TO_DEVICE (natural_height)); + (int) natural_width, + (int) natural_height); - clutter_actor_allocate (stage, &box, FALSE); + clutter_actor_allocate (stage, &box, CLUTTER_ALLOCATION_NONE); CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_IN_RELAYOUT); } @@ -154,18 +155,20 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage) if (CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_SYNC_MATRICES) { ClutterPerspective perspective; - guint width, height; + gfloat width, height; clutter_actor_get_size (CLUTTER_ACTOR (stage), &width, &height); clutter_stage_get_perspective (stage, &perspective); - CLUTTER_NOTE (PAINT, "Setting up the viewport"); + CLUTTER_NOTE (PAINT, + "Setting up the viewport { w:%.2f, h:%.2f }", + width, height); - cogl_setup_viewport (width, height, - perspective.fovy, - perspective.aspect, - perspective.z_near, - perspective.z_far); + _cogl_setup_viewport (width, height, + perspective.fovy, + perspective.aspect, + perspective.z_near, + perspective.z_far); CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES); } @@ -181,14 +184,12 @@ void clutter_redraw (ClutterStage *stage) { ClutterMainContext *ctx; - static GTimer *timer = NULL; - static guint timer_n_frames = 0; + ClutterMasterClock *master_clock; + static GTimer *timer = NULL; + static guint timer_n_frames = 0; ctx = clutter_context_get_default (); - - CLUTTER_TIMESTAMP (SCHEDULER, "Redraw start for stage:%p", stage); - CLUTTER_NOTE (PAINT, " Redraw enter for stage:%p", stage); - CLUTTER_NOTE (MULTISTAGE, "Redraw called for stage:%p", stage); + master_clock = _clutter_master_clock_get_default (); /* Before we can paint, we have to be sure we have the latest layout */ _clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage)); @@ -209,10 +210,15 @@ clutter_redraw (ClutterStage *stage) /* Call through to the actual backend to do the painting down from * the stage. It will likely need to swap buffers, vblank sync etc - * which will be windowing system dependant. + * which will be windowing system dependent */ _clutter_backend_redraw (ctx->backend, stage); + /* prepare for the next frame; if anything queues a redraw as the + * result of a timeline, this will end up redrawing the scene + */ + _clutter_master_clock_advance (master_clock); + /* Complete FPS info */ if (G_UNLIKELY (clutter_get_show_fps ())) { @@ -226,7 +232,6 @@ clutter_redraw (ClutterStage *stage) } } - CLUTTER_NOTE (PAINT, " Redraw leave for stage:%p", stage); CLUTTER_TIMESTAMP (SCHEDULER, "Redraw finish for stage:%p", stage); } @@ -1053,6 +1058,8 @@ clutter_context_get_default (void) ctx->is_initialized = FALSE; ctx->motion_events_per_actor = TRUE; + ctx->master_clock = _clutter_master_clock_get_default (); + #ifdef CLUTTER_ENABLE_DEBUG ctx->timer = g_timer_new (); g_timer_start (ctx->timer); @@ -1932,8 +1939,8 @@ generate_enter_leave_events (ClutterEvent *event) { if (motion_current_actor) { - gint x, y; ClutterEvent cev; + gfloat x, y; cev.crossing.device = device; clutter_event_get_coords (event, &x, &y); @@ -2154,7 +2161,7 @@ clutter_do_event (ClutterEvent *event) case CLUTTER_SCROLL: { ClutterActor *actor; - gint x,y; + gfloat x, y; clutter_event_get_coords (event, &x, &y); @@ -2171,7 +2178,7 @@ clutter_do_event (ClutterEvent *event) if (event->type == CLUTTER_BUTTON_RELEASE) { CLUTTER_NOTE (EVENT, - "Release off stage received at %i, %i", + "Release off stage received at %.2f, %.2f", x, y); event->button.source = stage; @@ -2197,12 +2204,14 @@ clutter_do_event (ClutterEvent *event) /* FIXME: for an optimisation should check if there are - * actually any reactive actors and avoid the pick all togeather + * actually any reactive actors and avoid the pick all together * (signalling just the stage). Should be big help for gles. */ - CLUTTER_NOTE (EVENT, "Reactive event received at %i, %i - actor: %p", - x, y, actor); + CLUTTER_NOTE (EVENT, + "Reactive event received at %.2f, %.2f - actor: %p", + x, y, + actor); /* Create, enter/leave events if needed */ generate_enter_leave_events (event); @@ -2809,3 +2818,162 @@ clutter_get_font_map (void) return NULL; } + +typedef struct _ClutterRepaintFunction +{ + guint id; + GSourceFunc func; + gpointer data; + GDestroyNotify notify; +} ClutterRepaintFunction; + +/** + * clutter_threads_remove_repaint_func: + * @handle_id: an unsigned integer greater than zero + * + * Removes the repaint function with @handle_id as its id + * + * Since: 1.0 + */ +void +clutter_threads_remove_repaint_func (guint handle_id) +{ + ClutterRepaintFunction *repaint_func; + ClutterMainContext *context; + GList *l; + + g_return_if_fail (handle_id > 0); + + context = CLUTTER_CONTEXT (); + l = context->repaint_funcs; + while (l != NULL) + { + repaint_func = l->data; + + if (repaint_func->id == handle_id) + { + context->repaint_funcs = + g_list_remove_link (context->repaint_funcs, l); + + g_list_free (l); + + if (repaint_func->notify) + repaint_func->notify (repaint_func->data); + + g_slice_free (ClutterRepaintFunction, repaint_func); + + return; + } + + l = l->next; + } +} + +/** + * clutter_threads_add_repaint_func: + * @func: the function to be called within the paint cycle + * @data: data to be passed to the function, or %NULL + * @notify: function to be called when removing the repaint + * function, or %NULL + * + * Adds a function to be called whenever Clutter is repainting a Stage. + * If the function returns %FALSE it is automatically removed from the + * list of repaint functions and will not be called again. + * + * This function is guaranteed to be called from within the same thread + * that called clutter_main(), and while the Clutter lock is being held. + * + * A repaint function is useful to ensure that an update of the scenegraph + * is performed before the scenegraph is repainted; for instance, uploading + * a frame from a video into a #ClutterTexture. + * + * When the repaint function is removed (either because it returned %FALSE + * or because clutter_threads_remove_repaint_func() has been called) the + * @notify function will be called, if any is set. + * + * Return value: the ID (greater than 0) of the repaint function. You + * can use the returned integer to remove the repaint function by + * calling clutter_threads_remove_repaint_func(). + * + * Since: 1.0 + */ +guint +clutter_threads_add_repaint_func (GSourceFunc func, + gpointer data, + GDestroyNotify notify) +{ + static guint repaint_id = 1; + ClutterMainContext *context; + ClutterRepaintFunction *repaint_func; + + g_return_val_if_fail (func != NULL, 0); + + context = CLUTTER_CONTEXT (); + + /* XXX lock the context */ + + repaint_func = g_slice_new (ClutterRepaintFunction); + + repaint_func->id = repaint_id++; + repaint_func->func = func; + repaint_func->data = data; + repaint_func->notify = notify; + + context->repaint_funcs = g_list_prepend (context->repaint_funcs, + repaint_func); + + /* XXX unlock the context */ + + return repaint_func->id; +} + +/* + * _clutter_run_repaint_functions: + * + * Executes the repaint functions added using the + * clutter_threads_add_repaint_func() function. + * + * Must be called before calling clutter_redraw() and + * with the Clutter thread lock held. + */ +void +_clutter_run_repaint_functions (void) +{ + ClutterMainContext *context = CLUTTER_CONTEXT (); + ClutterRepaintFunction *repaint_func; + GList *reinvoke_list, *l; + + if (context->repaint_funcs == NULL) + return; + + reinvoke_list = NULL; + + /* consume the whole list while we execute the functions */ + while (context->repaint_funcs) + { + gboolean res = FALSE; + + repaint_func = context->repaint_funcs->data; + + l = context->repaint_funcs; + context->repaint_funcs = + g_list_remove_link (context->repaint_funcs, context->repaint_funcs); + + g_list_free (l); + + res = repaint_func->func (repaint_func->data); + + if (res) + reinvoke_list = g_list_prepend (reinvoke_list, repaint_func); + else + { + if (repaint_func->notify) + repaint_func->notify (repaint_func->data); + + g_slice_free (ClutterRepaintFunction, repaint_func); + } + } + + if (reinvoke_list) + context->repaint_funcs = reinvoke_list; +} diff --git a/clutter/clutter-main.h b/clutter/clutter-main.h index f45cda0f3..d6f1099d0 100644 --- a/clutter/clutter-main.h +++ b/clutter/clutter-main.h @@ -70,7 +70,7 @@ GQuark clutter_init_error_quark (void); * * Since: 0.8 */ -#define CLUTTER_PRIORITY_REDRAW (G_PRIORITY_DEFAULT + 10) +#define CLUTTER_PRIORITY_REDRAW (G_PRIORITY_HIGH_IDLE + 20) /** * CLUTTER_PRIORITY_TIMELINE: @@ -109,34 +109,38 @@ gboolean clutter_get_show_fps (void); gulong clutter_get_timestamp (void); /* Threading functions */ -void clutter_threads_init (void); -void clutter_threads_enter (void); -void clutter_threads_leave (void); -void clutter_threads_set_lock_functions (GCallback enter_fn, - GCallback leave_fn); -guint clutter_threads_add_idle (GSourceFunc func, - gpointer data); -guint clutter_threads_add_idle_full (gint priority, - GSourceFunc func, - gpointer data, - GDestroyNotify notify); -guint clutter_threads_add_timeout (guint interval, - GSourceFunc func, - gpointer data); -guint clutter_threads_add_timeout_full (gint priority, - guint interval, - GSourceFunc func, - gpointer data, - GDestroyNotify notify); -guint clutter_threads_add_frame_source (guint fps, - GSourceFunc func, - gpointer data); -guint clutter_threads_add_frame_source_full - (gint priority, - guint fps, - GSourceFunc func, - gpointer data, - GDestroyNotify notify); +void clutter_threads_init (void); +void clutter_threads_enter (void); +void clutter_threads_leave (void); +void clutter_threads_set_lock_functions (GCallback enter_fn, + GCallback leave_fn); +guint clutter_threads_add_idle (GSourceFunc func, + gpointer data); +guint clutter_threads_add_idle_full (gint priority, + GSourceFunc func, + gpointer data, + GDestroyNotify notify); +guint clutter_threads_add_timeout (guint interval, + GSourceFunc func, + gpointer data); +guint clutter_threads_add_timeout_full (gint priority, + guint interval, + GSourceFunc func, + gpointer data, + GDestroyNotify notify); +guint clutter_threads_add_frame_source (guint fps, + GSourceFunc func, + gpointer data); +guint clutter_threads_add_frame_source_full (gint priority, + guint fps, + GSourceFunc func, + gpointer data, + GDestroyNotify notify); + +guint clutter_threads_add_repaint_func (GSourceFunc func, + gpointer data, + GDestroyNotify notify); +void clutter_threads_remove_repaint_func (guint handle_id); void clutter_set_motion_events_enabled (gboolean enable); gboolean clutter_get_motion_events_enabled (void); @@ -158,7 +162,7 @@ void clutter_clear_glyph_cache (void); void clutter_set_font_flags (ClutterFontFlags flags); ClutterFontFlags clutter_get_font_flags (void); -ClutterInputDevice* clutter_get_input_device_for_id (gint id); +ClutterInputDevice *clutter_get_input_device_for_id (gint id); void clutter_grab_pointer_for_device (ClutterActor *actor, gint id); diff --git a/clutter/clutter-marshal.list b/clutter/clutter-marshal.list index d68ce4b27..069d73774 100644 --- a/clutter/clutter-marshal.list +++ b/clutter/clutter-marshal.list @@ -3,9 +3,11 @@ BOOLEAN:STRING,UINT,ENUM DOUBLE:VOID UINT:VOID VOID:BOXED +VOID:BOXED,FLAGS VOID:INT VOID:INT64,INT64,FLOAT,BOOLEAN VOID:INT,INT +VOID:FLOAT,FLOAT VOID:INT,INT,INT,INT VOID:OBJECT VOID:OBJECT,OBJECT,PARAM diff --git a/clutter/clutter-master-clock.c b/clutter/clutter-master-clock.c new file mode 100644 index 000000000..ea3440555 --- /dev/null +++ b/clutter/clutter-master-clock.c @@ -0,0 +1,477 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Authored By: Emmanuele Bassi + * + * Copyright (C) 2009 Intel Corporation. + * + * 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, see . + */ + +/* + * SECTION:clutter-master-clock + * @short_description: The master clock for all animations + * + * The #ClutterMasterClock class is responsible for advancing all + * #ClutterTimelines when a stage is being redrawn. The master clock + * makes sure that the scenegraph is always integrally updated before + * painting it. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "clutter-master-clock.h" +#include "clutter-debug.h" +#include "clutter-private.h" + +#define CLUTTER_MASTER_CLOCK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_MASTER_CLOCK, ClutterMasterClockClass)) +#define CLUTTER_IS_MASTER_CLOCK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_MASTER_CLOCK)) +#define CLUTTER_MASTER_CLASS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_MASTER_CLOCK, ClutterMasterClockClass)) + +typedef struct _ClutterClockSource ClutterClockSource; +typedef struct _ClutterMasterClockClass ClutterMasterClockClass; + +struct _ClutterMasterClock +{ + GObject parent_instance; + + /* the list of timelines handled by the clock */ + GSList *timelines; + + /* the previous state of the clock, used to compute + * the delta + */ + GTimeVal prev_tick; + gulong msecs_delta; + + /* an idle source, used by the Master Clock to queue + * a redraw on the stage and drive the animations + */ + GSource *source; + + /* a guard, so that we dispatch the last redraw even + * after the last timeline has been completed + */ + guint last_advance : 1; +}; + +struct _ClutterMasterClockClass +{ + GObjectClass parent_class; +}; + +struct _ClutterClockSource +{ + GSource source; + + ClutterMasterClock *master_clock; +}; + +static void on_timeline_started (ClutterTimeline *timeline, + ClutterMasterClock *master_clock); +static void on_timeline_completed (ClutterTimeline *timeline, + ClutterMasterClock *master_clock); +static void on_timeline_paused (ClutterTimeline *timeline, + ClutterMasterClock *master_clock); + +static gboolean clutter_clock_prepare (GSource *source, + gint *timeout); +static gboolean clutter_clock_check (GSource *source); +static gboolean clutter_clock_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data); + +static ClutterMasterClock *default_clock = NULL; + +static GSourceFuncs clock_funcs = { + clutter_clock_prepare, + clutter_clock_check, + clutter_clock_dispatch, + NULL +}; + +G_DEFINE_TYPE (ClutterMasterClock, clutter_master_clock, G_TYPE_OBJECT); + +/* + * has_running_timeline: + * @master_clock: a #ClutterMasterClock + * @filter: a #ClutterTimeline or %NULL + * + * Checks if @master_clock has any running timeline; if @filter + * is not %NULL then the timeline will be filtered from the + * list of timelines held by @master_clock + * + * Return value: %TRUE if the #ClutterMasterClock has at least + * one running timeline + */ +static gboolean +has_running_timeline (ClutterMasterClock *master_clock, + ClutterTimeline *filter) +{ + GSList *l; + + if (master_clock->last_advance) + return TRUE; + + if (master_clock->timelines == NULL) + return FALSE; + + for (l = master_clock->timelines; l != NULL; l = l->next) + { + /* if we get a timeline then we should filter it + * from the list of timelines we want to check + */ + if (filter != NULL && filter == l->data) + continue; + + if (clutter_timeline_is_playing (l->data)) + return TRUE; + } + + return FALSE; +} + +/* + * clutter_clock_source_new: + * @master_clock: a #ClutterMasterClock for the source + * + * The #ClutterClockSource is an idle GSource that will queue a redraw + * if @master_clock has at least a running #ClutterTimeline. The redraw + * will cause @master_clock to advance all timelines, thus advancing all + * animations as well. + * + * Return value: the newly created #GSource + */ +static GSource * +clutter_clock_source_new (ClutterMasterClock *master_clock) +{ + GSource *source = g_source_new (&clock_funcs, sizeof (ClutterClockSource)); + ClutterClockSource *clock_source = (ClutterClockSource *) source; + + clock_source->master_clock = master_clock; + + return source; +} + +static gboolean +clutter_clock_prepare (GSource *source, + gint *timeout) +{ + ClutterClockSource *clock_source = (ClutterClockSource *) source; + ClutterMasterClock *master_clock = clock_source->master_clock; + gboolean retval; + + /* just like an idle source, we are ready if nothing else is */ + *timeout = -1; + + retval = has_running_timeline (master_clock, NULL); + + return retval; +} + +static gboolean +clutter_clock_check (GSource *source) +{ + ClutterClockSource *clock_source = (ClutterClockSource *) source; + ClutterMasterClock *master_clock = clock_source->master_clock; + gboolean retval; + + retval = has_running_timeline (master_clock, NULL); + + return retval; +} + +static gboolean +clutter_clock_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + ClutterClockSource *clock_source = (ClutterClockSource *) source; + ClutterMasterClock *master_clock = clock_source->master_clock; + ClutterStageManager *stage_manager = clutter_stage_manager_get_default (); + const GSList *stages, *l; + + CLUTTER_NOTE (SCHEDULER, "Master clock [tick]"); + + stages = clutter_stage_manager_peek_stages (stage_manager); + + /* queue a redraw for each stage; this will advance each timeline + * held by the master clock of the amount of milliseconds elapsed + * since the last redraw + */ + for (l = stages; l != NULL; l = l->next) + clutter_actor_queue_redraw (l->data); + + /* if this is the remainder of an advancement, needed for the last + * timeline to finish its run, then we need to reset the prev_tick + */ + if (master_clock->last_advance) + { + master_clock->prev_tick.tv_sec = 0; + master_clock->last_advance = FALSE; + } + + return TRUE; +} + +static void +timeline_weak_ref (gpointer data, + GObject *object_pointer) +{ + ClutterMasterClock *master_clock = data; + + master_clock->timelines = + g_slist_remove (master_clock->timelines, object_pointer); + + if (master_clock->timelines == NULL) + master_clock->prev_tick.tv_sec = 0; +} + +static void +clutter_master_clock_finalize (GObject *gobject) +{ + ClutterMasterClock *master_clock = CLUTTER_MASTER_CLOCK (gobject); + GSList *l; + + for (l = master_clock->timelines; l != NULL; l = l->next) + { + ClutterTimeline *timeline = l->data; + + g_object_weak_unref (G_OBJECT (timeline), + timeline_weak_ref, + master_clock); + + g_signal_handlers_disconnect_by_func (timeline, + G_CALLBACK (on_timeline_started), + master_clock); + g_signal_handlers_disconnect_by_func (timeline, + G_CALLBACK (on_timeline_completed), + master_clock); + g_signal_handlers_disconnect_by_func (timeline, + G_CALLBACK (on_timeline_paused), + master_clock); + } + + g_slist_free (master_clock->timelines); + + G_OBJECT_CLASS (clutter_master_clock_parent_class)->finalize (gobject); +} + +static void +clutter_master_clock_class_init (ClutterMasterClockClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = clutter_master_clock_finalize; +} + +static void +clutter_master_clock_init (ClutterMasterClock *self) +{ + GSource *source; + + source = clutter_clock_source_new (self); + self->source = source; + + g_source_set_priority (source, CLUTTER_PRIORITY_REDRAW); + g_source_set_can_recurse (source, FALSE); + g_source_attach (source, NULL); +} + +/* + * _clutter_master_clock_get_default: + * + * Retrieves the default master clock. If this function has never + * been called before, the default master clock is created. + * + * Return value: the default master clock. The returned object is + * owned by Clutter and should not be modified or freed + */ +ClutterMasterClock * +_clutter_master_clock_get_default (void) +{ + if (G_LIKELY (default_clock != NULL)) + return default_clock; + + default_clock = g_object_new (CLUTTER_TYPE_MASTER_CLOCK, NULL); + + return default_clock; +} + +static void +on_timeline_started (ClutterTimeline *timeline, + ClutterMasterClock *master_clock) +{ + /* we want to reset the prev_tick if this is the first + * timeline; since timeline is playing we need to filter + * it out, otherwise has_running_timeline() will return + * TRUE and prev_tick will not be unset + */ + if (!has_running_timeline (master_clock, timeline)) + master_clock->prev_tick.tv_sec = 0; +} + +static void +on_timeline_completed (ClutterTimeline *timeline, + ClutterMasterClock *master_clock) +{ + /* if this is the last timeline we need to turn :last-advance + * on in order to queue the redraw of the scene for the last + * frame; otherwise the ClockSource will fail the prepare and + * check phases and the last frame will not be painted + */ + if (!has_running_timeline (master_clock, NULL)) + master_clock->last_advance = TRUE; +} + +static void +on_timeline_paused (ClutterTimeline *timeline, + ClutterMasterClock *master_clock) +{ + /* see the comment in on_timeline_completed */ + if (!has_running_timeline (master_clock, NULL)) + master_clock->last_advance = TRUE; +} + +/* + * _clutter_master_clock_add_timeline: + * @master_clock: a #ClutterMasterClock + * @timeline: a #ClutterTimeline + * + * Adds @timeline to the list of timelines held by the master + * clock. This function should be called during the instance + * creation phase of the timeline. + */ +void +_clutter_master_clock_add_timeline (ClutterMasterClock *master_clock, + ClutterTimeline *timeline) +{ + gboolean is_first = FALSE; + + if (g_slist_find (master_clock->timelines, timeline)) + return; + + is_first = (master_clock->timelines == NULL) ? TRUE : FALSE; + + master_clock->timelines = g_slist_prepend (master_clock->timelines, + timeline); + + g_object_weak_ref (G_OBJECT (timeline), + timeline_weak_ref, + master_clock); + + g_signal_connect (timeline, "started", + G_CALLBACK (on_timeline_started), + master_clock); + g_signal_connect (timeline, "completed", + G_CALLBACK (on_timeline_completed), + master_clock); + g_signal_connect (timeline, "paused", + G_CALLBACK (on_timeline_paused), + master_clock); +} + +/* + * _clutter_master_clock_remove_timeline: + * @master_clock: a #ClutterMasterClock + * @timeline: a #ClutterTimeline + * + * Removes @timeline from the list of timelines held by the + * master clock. This function should be called during the + * #ClutterTimeline finalization. + */ +void +_clutter_master_clock_remove_timeline (ClutterMasterClock *master_clock, + ClutterTimeline *timeline) +{ + if (!g_slist_find (master_clock->timelines, timeline)) + return; + + master_clock->timelines = g_slist_remove (master_clock->timelines, + timeline); + + g_object_weak_unref (G_OBJECT (timeline), + timeline_weak_ref, + master_clock); + + g_signal_handlers_disconnect_by_func (timeline, + G_CALLBACK (on_timeline_started), + master_clock); + g_signal_handlers_disconnect_by_func (timeline, + G_CALLBACK (on_timeline_completed), + master_clock); + g_signal_handlers_disconnect_by_func (timeline, + G_CALLBACK (on_timeline_paused), + master_clock); + + /* last timeline: unset the prev_tick so that we can start + * from scratch when we add a new timeline + */ + if (master_clock->timelines == NULL) + master_clock->prev_tick.tv_sec = 0; +} + +/* + * _clutter_master_clock_advance: + * @master_clock: a #ClutterMasterClock + * + * Advances all the timelines held by the master clock. This function + * should be called before calling clutter_redraw() to make sure that + * all the timelines are advanced and the scene is updated. + */ +void +_clutter_master_clock_advance (ClutterMasterClock *master_clock) +{ + GTimeVal cur_tick = { 0, }; + gulong msecs; + GSList *l; + + g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock)); + + if (master_clock->timelines == NULL) + return; + + g_get_current_time (&cur_tick); + + if (master_clock->prev_tick.tv_sec == 0) + master_clock->prev_tick = cur_tick; + + msecs = (cur_tick.tv_sec - master_clock->prev_tick.tv_sec) * 1000 + + (cur_tick.tv_usec - master_clock->prev_tick.tv_usec) / 1000; + + if (msecs == 0) + return; + + CLUTTER_NOTE (SCHEDULER, "Advancing %d timelines by %lu milliseconds", + g_slist_length (master_clock->timelines), + msecs); + + for (l = master_clock->timelines; l != NULL; l = l->next) + { + ClutterTimeline *timeline = l->data; + + if (clutter_timeline_is_playing (timeline)) + clutter_timeline_advance_delta (timeline, msecs); + } + + /* store the previous state so that we can use + * it for the next advancement + */ + master_clock->msecs_delta = msecs; + master_clock->prev_tick = cur_tick; +} diff --git a/clutter/clutter-master-clock.h b/clutter/clutter-master-clock.h new file mode 100644 index 000000000..5a3f7cd32 --- /dev/null +++ b/clutter/clutter-master-clock.h @@ -0,0 +1,48 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Authored By: Emmanuele Bassi + * + * Copyright (C) 2009 Intel Corporation. + * + * 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, see . + */ + +#ifndef __CLUTTER_MASTER_CLOCK_H__ +#define __CLUTTER_MASTER_CLOCK_H__ + +#include + +G_BEGIN_DECLS + +#define CLUTTER_TYPE_MASTER_CLOCK (clutter_master_clock_get_type ()) +#define CLUTTER_MASTER_CLOCK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_MASTER_CLOCK, ClutterMasterClock)) +#define CLUTTER_IS_MASTER_CLOCK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_MASTER_CLOCK)) + +typedef struct _ClutterMasterClock ClutterMasterClock; + +GType clutter_master_clock_get_type (void) G_GNUC_CONST; + +ClutterMasterClock *_clutter_master_clock_get_default (void); +void _clutter_master_clock_add_timeline (ClutterMasterClock *master_clock, + ClutterTimeline *timeline); +void _clutter_master_clock_remove_timeline (ClutterMasterClock *master_clock, + ClutterTimeline *timeline); +void _clutter_master_clock_advance (ClutterMasterClock *master_clock); + +G_END_DECLS + +#endif /* __CLUTTER_MASTER_CLOCK_H__ */ diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h index 741820187..6b62cee48 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -44,9 +44,11 @@ #include "clutter-event.h" #include "clutter-feature.h" #include "clutter-id-pool.h" +#include "clutter-master-clock.h" #include "clutter-stage-manager.h" #include "clutter-stage-window.h" #include "clutter-stage.h" +#include "clutter-timeline.h" G_BEGIN_DECLS @@ -65,12 +67,6 @@ typedef enum { CLUTTER_TEXTURE_IN_CLONE_PAINT = 1 << 6 /* Used for safety in clones */ } ClutterPrivateFlags; -typedef enum { - CLUTTER_PICK_NONE = 0, - CLUTTER_PICK_REACTIVE, - CLUTTER_PICK_ALL -} ClutterPickMode; - struct _ClutterInputDevice { gint id; @@ -133,6 +129,11 @@ struct _ClutterMainContext MultiTouch */ guint32 last_event_time; + + ClutterMasterClock *master_clock; + gulong redraw_count; + + GList *repaint_funcs; }; #define CLUTTER_CONTEXT() (clutter_context_get_default ()) @@ -185,6 +186,9 @@ ClutterActor *_clutter_backend_create_stage (ClutterBackend *backend, GError **error); void _clutter_backend_ensure_context (ClutterBackend *backend, ClutterStage *stage); +gboolean _clutter_backend_create_context (ClutterBackend *backend, + gboolean is_offscreen, + GError **error); void _clutter_backend_add_options (ClutterBackend *backend, GOptionGroup *group); @@ -196,21 +200,21 @@ void _clutter_backend_init_events (ClutterBackend *backend); ClutterFeatureFlags _clutter_backend_get_features (ClutterBackend *backend); -ClutterUnit _clutter_backend_get_units_per_em (ClutterBackend *backend); +gfloat _clutter_backend_get_units_per_em (ClutterBackend *backend, + PangoFontDescription *font_desc); void _clutter_feature_init (void); /* Picking code */ -ClutterActor *_clutter_do_pick (ClutterStage *stage, - gint x, - gint y, - ClutterPickMode mode); +ClutterActor *_clutter_do_pick (ClutterStage *stage, + gint x, + gint y, + ClutterPickMode mode); guint _clutter_pixel_to_id (guchar pixel[4]); void _clutter_id_to_color (guint id, ClutterColor *col); - /* use this function as the accumulator if you have a signal with * a G_TYPE_BOOLEAN return value; this will stop the emission as * soon as one handler returns TRUE @@ -223,12 +227,21 @@ gboolean _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint, void _clutter_actor_apply_modelview_transform_recursive (ClutterActor *self, ClutterActor *ancestor); +void _clutter_actor_rerealize (ClutterActor *self, + ClutterCallback callback, + void *data); + void _clutter_actor_set_opacity_parent (ClutterActor *self, ClutterActor *parent); void _clutter_actor_set_enable_model_view_transform (ClutterActor *self, gboolean enable); +void _clutter_actor_set_enable_paint_unmapped (ClutterActor *self, + gboolean enable); + +void _clutter_run_repaint_functions (void); + G_END_DECLS #endif /* _HAVE_CLUTTER_PRIVATE_H */ diff --git a/clutter/clutter-shader.c b/clutter/clutter-shader.c index e2ba66ce7..0ff17b431 100644 --- a/clutter/clutter-shader.c +++ b/clutter/clutter-shader.c @@ -451,16 +451,22 @@ clutter_shader_glsl_bind (ClutterShader *self, cogl_shader_compile (shader); if (!cogl_shader_is_compiled (shader)) { - gchar error_buf[512]; + gchar *log_buf; - cogl_shader_get_info_log (shader, 512, error_buf); + log_buf = cogl_shader_get_info_log (shader); + /* translators: the first %s is the type of the shader, either + * Vertex shader or Fragment shader; the second %s is the actual + * error as reported by COGL + */ g_set_error (error, CLUTTER_SHADER_ERROR, CLUTTER_SHADER_ERROR_COMPILE, _("%s compilation failed: %s"), shader_type == CLUTTER_VERTEX_SHADER ? _("Vertex shader") : _("Fragment shader"), - error_buf); + log_buf); + + g_free (log_buf); return FALSE; } diff --git a/clutter/clutter-stage-manager.c b/clutter/clutter-stage-manager.c index 65ea52097..1d9401143 100644 --- a/clutter/clutter-stage-manager.c +++ b/clutter/clutter-stage-manager.c @@ -224,8 +224,9 @@ clutter_stage_manager_get_default_stage (ClutterStageManager *stage_manager) * * Lists all currently used stages. * - * Return value: (transfer container) (element-type ClutterStage): a newly allocated list - * of #ClutterStage objects. Use g_slist_free() to deallocate it when done. + * Return value: (transfer container) (element-type ClutterStage): a newly + * allocated list of #ClutterStage objects. Use g_slist_free() to + * deallocate it when done. * * Since: 0.8 */ @@ -235,6 +236,25 @@ clutter_stage_manager_list_stages (ClutterStageManager *stage_manager) return g_slist_copy (stage_manager->stages); } +/** + * clutter_stage_manager_list_stage: + * @stage_manager: a #ClutterStageManager + * + * Lists all currently used stages. + * + * Return value: (transfer none) (element-type ClutterStage): a pointer + * to the internal list of #ClutterStage objects. The returned list + * is owned by the #ClutterStageManager and should never be modified + * or freed + * + * Since: 1.0 + */ +const GSList * +clutter_stage_manager_peek_stages (ClutterStageManager *stage_manager) +{ + return stage_manager->stages; +} + void _clutter_stage_manager_add_stage (ClutterStageManager *stage_manager, ClutterStage *stage) diff --git a/clutter/clutter-stage-manager.h b/clutter/clutter-stage-manager.h index f2484d7e9..c8a36eca9 100644 --- a/clutter/clutter-stage-manager.h +++ b/clutter/clutter-stage-manager.h @@ -61,6 +61,7 @@ void clutter_stage_manager_set_default_stage (ClutterStageManage ClutterStage *stage); ClutterStage * clutter_stage_manager_get_default_stage (ClutterStageManager *stage_manager); GSList * clutter_stage_manager_list_stages (ClutterStageManager *stage_manager); +const GSList * clutter_stage_manager_peek_stages (ClutterStageManager *stage_manager); G_END_DECLS diff --git a/clutter/clutter-stage-window.h b/clutter/clutter-stage-window.h index 8efdbd20c..a46662acd 100644 --- a/clutter/clutter-stage-window.h +++ b/clutter/clutter-stage-window.h @@ -27,6 +27,10 @@ struct _ClutterStageWindowIface gboolean cursor_visible); void (* set_user_resizable) (ClutterStageWindow *stage_window, gboolean is_resizable); + + void (* show) (ClutterStageWindow *stage_window, + gboolean do_raise); + void (* hide) (ClutterStageWindow *stage_window); }; GType clutter_stage_window_get_type (void) G_GNUC_CONST; diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index a4c0fcc1f..75cfc47a4 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -59,6 +59,7 @@ #include "clutter-color.h" #include "clutter-util.h" #include "clutter-marshal.h" +#include "clutter-master-clock.h" #include "clutter-enum-types.h" #include "clutter-private.h" #include "clutter-debug.h" @@ -86,7 +87,7 @@ struct _ClutterStagePrivate gchar *title; ClutterActor *key_focused_actor; - guint update_idle; /* repaint idler id */ + guint update_idle; /* repaint idler id */ guint is_fullscreen : 1; guint is_offscreen : 1; @@ -126,9 +127,9 @@ static const ClutterColor default_stage_color = { 255, 255, 255, 255 }; static void clutter_stage_get_preferred_width (ClutterActor *self, - ClutterUnit for_height, - ClutterUnit *min_width_p, - ClutterUnit *natural_width_p) + gfloat for_height, + gfloat *min_width_p, + gfloat *natural_width_p) { ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; @@ -142,9 +143,9 @@ clutter_stage_get_preferred_width (ClutterActor *self, static void clutter_stage_get_preferred_height (ClutterActor *self, - ClutterUnit for_width, - ClutterUnit *min_height_p, - ClutterUnit *natural_height_p) + gfloat for_width, + gfloat *min_height_p, + gfloat *natural_height_p) { ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; @@ -156,11 +157,14 @@ clutter_stage_get_preferred_height (ClutterActor *self, natural_height_p); } static void -clutter_stage_allocate (ClutterActor *self, - const ClutterActorBox *box, - gboolean origin_changed) +clutter_stage_allocate (ClutterActor *self, + const ClutterActorBox *box, + ClutterAllocationFlags flags) { ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; + gboolean origin_changed; + + origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED) ? TRUE : FALSE; g_assert (priv->impl != NULL); @@ -168,30 +172,31 @@ clutter_stage_allocate (ClutterActor *self, * then we simply ignore any allocation request and override the * allocation chain. */ - if (G_LIKELY (!clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))) + if ((!clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))) { ClutterActorClass *klass; - CLUTTER_NOTE (ACTOR, "Following allocation to %dx%d (origin %s)", - CLUTTER_UNITS_TO_DEVICE (box->x2 - box->x1), - CLUTTER_UNITS_TO_DEVICE (box->y2 - box->y1), + CLUTTER_NOTE (LAYOUT, + "Following allocation to %dx%d (origin %s)", + (int) (box->x2 - box->x1), + (int) (box->y2 - box->y1), origin_changed ? "changed" : "not changed"); klass = CLUTTER_ACTOR_CLASS (clutter_stage_parent_class); - klass->allocate (self, box, origin_changed); + klass->allocate (self, box, flags); klass = CLUTTER_ACTOR_GET_CLASS (priv->impl); - klass->allocate (priv->impl, box, origin_changed); + klass->allocate (priv->impl, box, flags); } else { ClutterActorBox override = { 0, }; ClutterActorClass *klass; - ClutterUnit natural_width, natural_height; + gfloat natural_width, natural_height; /* propagate the allocation */ klass = CLUTTER_ACTOR_GET_CLASS (priv->impl); - klass->allocate (self, box, origin_changed); + klass->allocate (self, box, flags); /* get the preferred size from the backend */ clutter_actor_get_preferred_size (priv->impl, @@ -203,9 +208,18 @@ clutter_stage_allocate (ClutterActor *self, override.x2 = natural_width; override.y2 = natural_height; + CLUTTER_NOTE (LAYOUT, + "Overrigin original allocation of %dx%d " + "with %dx%d (origin %s)", + (int) (box->x2 - box->x1), + (int) (box->y2 - box->y1), + (int) (override.x2), + (int) (override.y2), + origin_changed ? "changed" : "not changed"); + /* and store the overridden allocation */ klass = CLUTTER_ACTOR_CLASS (clutter_stage_parent_class); - klass->allocate (self, &override, origin_changed); + klass->allocate (self, &override, flags); } } @@ -257,7 +271,7 @@ clutter_stage_pick (ClutterActor *self, * Chain up to the groups paint howerer so our children get picked * - clutter_group_pick */ - CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->paint (self); + CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->pick (self, color); } static void @@ -265,21 +279,23 @@ clutter_stage_realize (ClutterActor *self) { ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; - CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED); - /* Make sure the viewport and projection matrix are valid for the - first paint (which will likely occur before the ConfigureNotify - is received) */ + * first paint (which will likely occur before the ConfigureNotify + * is received) + */ CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_SYNC_MATRICES); g_assert (priv->impl != NULL); - CLUTTER_ACTOR_GET_CLASS (priv->impl)->realize (priv->impl); + clutter_actor_realize (priv->impl); /* ensure that the stage is using the context if the * realization sequence was successful */ if (CLUTTER_ACTOR_IS_REALIZED (priv->impl)) - clutter_stage_ensure_current (CLUTTER_STAGE (self)); + { + CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED); + clutter_stage_ensure_current (CLUTTER_STAGE (self)); + } else CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED); } @@ -289,12 +305,9 @@ clutter_stage_unrealize (ClutterActor *self) { ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; - /* unset the flag */ - CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED); - /* and then unrealize the implementation */ g_assert (priv->impl != NULL); - CLUTTER_ACTOR_GET_CLASS (priv->impl)->unrealize (priv->impl); + clutter_actor_unrealize (priv->impl); clutter_stage_ensure_current (CLUTTER_STAGE (self)); } @@ -303,33 +316,60 @@ static void clutter_stage_show (ClutterActor *self) { ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; - - g_assert (priv->impl != NULL); - - if (!CLUTTER_ACTOR_IS_REALIZED (priv->impl)) - clutter_actor_realize (priv->impl); - - clutter_actor_show (priv->impl); + ClutterStageWindow *impl; CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->show (self); + + g_assert (priv->impl != NULL); + impl = CLUTTER_STAGE_WINDOW (priv->impl); + CLUTTER_STAGE_WINDOW_GET_IFACE (impl)->show (impl, TRUE); } static void clutter_stage_hide (ClutterActor *self) { ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; + ClutterStageWindow *impl; g_assert (priv->impl != NULL); - clutter_actor_hide (priv->impl); + impl = CLUTTER_STAGE_WINDOW (priv->impl); + CLUTTER_STAGE_WINDOW_GET_IFACE (impl)->hide (impl); CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->hide (self); } +static void +clutter_stage_emit_key_focus_event (ClutterStage *stage, + gboolean focus_in) +{ + ClutterStagePrivate *priv = stage->priv; + + if (priv->key_focused_actor == NULL) + return; + + if (focus_in) + g_signal_emit_by_name (priv->key_focused_actor, "key-focus-in"); + else + g_signal_emit_by_name (priv->key_focused_actor, "key-focus-out"); +} + +static void +clutter_stage_real_activate (ClutterStage *stage) +{ + clutter_stage_emit_key_focus_event (stage, TRUE); +} + +static void +clutter_stage_real_deactivate (ClutterStage *stage) +{ + clutter_stage_emit_key_focus_event (stage, FALSE); +} + static void clutter_stage_real_fullscreen (ClutterStage *stage) { ClutterStagePrivate *priv = stage->priv; - ClutterUnit natural_width, natural_height; + gfloat natural_width, natural_height; ClutterActorBox box; /* we need to force an allocation here because the size @@ -348,7 +388,9 @@ clutter_stage_real_fullscreen (ClutterStage *stage) box.x2 = natural_width; box.y2 = natural_height; - clutter_actor_allocate (CLUTTER_ACTOR (stage), &box, FALSE); + clutter_actor_allocate (CLUTTER_ACTOR (stage), + &box, + CLUTTER_ALLOCATION_NONE); } static gboolean @@ -356,23 +398,48 @@ redraw_update_idle (gpointer user_data) { ClutterStage *stage = user_data; ClutterStagePrivate *priv = stage->priv; + ClutterMasterClock *master_clock; - /* clutter_redraw() will also call maybe_relayout(), but since a relayout can - * queue a redraw, we want to do the relayout before we clear the update_idle - * to avoid painting the stage twice. Calling maybe_relayout() twice in a row - * is cheap because of caching of requested and allocated size. + /* before we redraw we advance the master clock of one tick; this means + * that all the timelines that need advancing will be advanced by one + * frame. this will cause multiple redraw requests, so we do this before + * we ask for a relayout and before we do the actual redraw. this ensures + * that we paint the most updated scenegraph state and that all animations + * are in sync with the paint process. + */ + CLUTTER_NOTE (PAINT, "Avdancing master clock"); + master_clock = _clutter_master_clock_get_default (); + _clutter_master_clock_advance (master_clock); + + /* run the (eventual) repaint functions; since those might end up queuing + * a relayout or a redraw we need to execute them before maybe_relayout() + */ + CLUTTER_NOTE (PAINT, "Repaint functions"); + _clutter_run_repaint_functions (); + + /* clutter_redraw() will also call maybe_relayout(), but since a relayout + * can queue a redraw, we want to do the relayout before we clear the + * update_idle to avoid painting the stage twice. Calling maybe_relayout() + * twice in a row is cheap because of caching of requested and allocated + * size. */ _clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage)); - if (priv->update_idle) - { - g_source_remove (priv->update_idle); - priv->update_idle = 0; - } - - CLUTTER_NOTE (MULTISTAGE, "redrawing via idle for stage:%p", stage); + /* redrawing will advance the master clock */ + CLUTTER_NOTE (PAINT, "redrawing via idle for stage[%p]", stage); clutter_redraw (stage); + /* reset the guard, so that new redraws are possible */ + priv->update_idle = 0; + + if (CLUTTER_CONTEXT ()->redraw_count > 0) + { + CLUTTER_NOTE (SCHEDULER, "Queued %lu redraws during the last cycle", + CLUTTER_CONTEXT ()->redraw_count); + + CLUTTER_CONTEXT ()->redraw_count = 0; + } + return FALSE; } @@ -383,17 +450,28 @@ clutter_stage_real_queue_redraw (ClutterActor *actor, ClutterStage *stage = CLUTTER_STAGE (actor); ClutterStagePrivate *priv = stage->priv; + CLUTTER_NOTE (PAINT, "Redraw request number %lu", + CLUTTER_CONTEXT ()->redraw_count + 1); + if (priv->update_idle == 0) { - CLUTTER_TIMESTAMP (SCHEDULER, "Adding idle source for stage: %p", stage); + CLUTTER_NOTE (PAINT, "Adding idle source for stage: %p", stage); - /* FIXME: weak_ref self in case we dissapear before paint? */ priv->update_idle = clutter_threads_add_idle_full (CLUTTER_PRIORITY_REDRAW, redraw_update_idle, stage, NULL); } + else + CLUTTER_CONTEXT ()->redraw_count += 1; +} + +static void +set_offscreen_while_unrealized (ClutterActor *actor, + void *data) +{ + CLUTTER_STAGE (actor)->priv->is_offscreen = GPOINTER_TO_INT (data); } static void @@ -417,24 +495,26 @@ clutter_stage_set_property (GObject *object, break; case PROP_OFFSCREEN: - if (priv->is_offscreen == g_value_get_boolean (value)) - return; + { + gboolean was_showing; - if (CLUTTER_ACTOR_IS_REALIZED (actor)) - { - /* Backend needs to check this prop and handle accordingly - * in realise. - * FIXME: More 'obvious' implementation needed? - */ - clutter_actor_unrealize (actor); - priv->is_offscreen = g_value_get_boolean (value); - clutter_actor_realize (actor); + if (priv->is_offscreen == g_value_get_boolean (value)) + return; - if (!CLUTTER_ACTOR_IS_REALIZED (actor)) - priv->is_offscreen = ~g_value_get_boolean (value); - } - else - priv->is_offscreen = g_value_get_boolean (value); + was_showing = CLUTTER_ACTOR_IS_VISIBLE (actor); + + /* Backend needs to check this prop and handle accordingly + * in realise. + * FIXME: More 'obvious' implementation needed? + */ + _clutter_actor_rerealize (actor, + set_offscreen_while_unrealized, + GINT_TO_POINTER (g_value_get_boolean (value))); + + if (was_showing && + !CLUTTER_ACTOR_IS_REALIZED (actor)) + priv->is_offscreen = ~g_value_get_boolean (value); + } break; case PROP_FULLSCREEN: @@ -536,7 +616,7 @@ clutter_stage_dispose (GObject *object) ClutterStagePrivate *priv = stage->priv; ClutterStageManager *stage_manager = clutter_stage_manager_get_default (); - clutter_actor_unrealize (CLUTTER_ACTOR (object)); + clutter_actor_hide (CLUTTER_ACTOR (object)); if (priv->update_idle) { @@ -548,8 +628,9 @@ clutter_stage_dispose (GObject *object) if (priv->impl) { - CLUTTER_NOTE (MISC, "Disposing of the stage implementation"); - g_object_unref (priv->impl); + CLUTTER_NOTE (BACKEND, "Disposing of the stage implementation"); + clutter_actor_hide (priv->impl); + clutter_actor_destroy (priv->impl); priv->impl = NULL; } @@ -783,6 +864,8 @@ clutter_stage_class_init (ClutterStageClass *klass) G_TYPE_NONE, 0); klass->fullscreen = clutter_stage_real_fullscreen; + klass->activate = clutter_stage_real_activate; + klass->deactivate = clutter_stage_real_deactivate; g_type_class_add_private (gobject_class, sizeof (ClutterStagePrivate)); } @@ -813,6 +896,9 @@ clutter_stage_init (ClutterStage *self) else g_object_ref_sink (priv->impl); + /* make sure that the implementation is considered a top level */ + CLUTTER_SET_PRIVATE_FLAGS (priv->impl, CLUTTER_ACTOR_IS_TOPLEVEL); + priv->is_offscreen = FALSE; priv->is_fullscreen = FALSE; priv->is_user_resizable = FALSE; @@ -1244,20 +1330,26 @@ clutter_stage_read_pixels (ClutterStage *stage, /** * clutter_stage_get_actor_at_pos: * @stage: a #ClutterStage + * @pick_mode: how the scene graph should be painted * @x: X coordinate to check * @y: Y coordinate to check * * Checks the scene at the coordinates @x and @y and returns a pointer * to the #ClutterActor at those coordinates. * - * Return value: (transfer none): the actor at the specified coordinates, if any + * By using @pick_mode it is possible to control which actors will be + * painted and thus available. + * + * Return value: (transfer none): the actor at the specified coordinates, + * if any */ ClutterActor * -clutter_stage_get_actor_at_pos (ClutterStage *stage, - gint x, - gint y) +clutter_stage_get_actor_at_pos (ClutterStage *stage, + ClutterPickMode pick_mode, + gint x, + gint y) { - return _clutter_do_pick (stage, x, y, CLUTTER_PICK_ALL); + return _clutter_do_pick (stage, x, y, pick_mode); } /** @@ -1428,12 +1520,12 @@ clutter_stage_set_key_focus (ClutterStage *stage, g_object_weak_unref (G_OBJECT (priv->key_focused_actor), on_key_focused_weak_notify, stage); - g_signal_emit_by_name (priv->key_focused_actor, "focus-out"); + g_signal_emit_by_name (priv->key_focused_actor, "key-focus-out"); priv->key_focused_actor = NULL; } else - g_signal_emit_by_name (stage, "focus-out"); + g_signal_emit_by_name (stage, "key-focus-out"); if (actor) { @@ -1442,10 +1534,10 @@ clutter_stage_set_key_focus (ClutterStage *stage, g_object_weak_ref (G_OBJECT (actor), on_key_focused_weak_notify, stage); - g_signal_emit_by_name (priv->key_focused_actor, "focus-in"); + g_signal_emit_by_name (priv->key_focused_actor, "key-focus-in"); } else - g_signal_emit_by_name (stage, "focus-in"); + g_signal_emit_by_name (stage, "key-focus-in"); } /** diff --git a/clutter/clutter-stage.h b/clutter/clutter-stage.h index d2001a9db..298443efe 100644 --- a/clutter/clutter-stage.h +++ b/clutter/clutter-stage.h @@ -79,6 +79,22 @@ G_BEGIN_DECLS #define CLUTTER_STAGE_HEIGHT() \ (clutter_actor_get_height (clutter_stage_get_default ())) +/** + * ClutterPickMode: + * @CLUTTER_PICK_NONE: Do not paint any actor + * @CLUTTER_PICK_REACTIVE: Paint only the reactive actors + * @CLUTTER_PICK_ALL: Paint all actors + * + * Controls the paint cycle of the scene graph when in pick mode + * + * Since: 1.0 + */ +typedef enum { + CLUTTER_PICK_NONE = 0, + CLUTTER_PICK_REACTIVE, + CLUTTER_PICK_ALL +} ClutterPickMode; + typedef struct _ClutterPerspective ClutterPerspective; typedef struct _ClutterFog ClutterFog; @@ -192,6 +208,7 @@ void clutter_stage_show_cursor (ClutterStage *stage); void clutter_stage_hide_cursor (ClutterStage *stage); ClutterActor *clutter_stage_get_actor_at_pos (ClutterStage *stage, + ClutterPickMode pick_mode, gint x, gint y); guchar * clutter_stage_read_pixels (ClutterStage *stage, diff --git a/clutter/clutter-text.c b/clutter/clutter-text.c index a3de0b72d..ec3484744 100644 --- a/clutter/clutter-text.c +++ b/clutter/clutter-text.c @@ -87,10 +87,10 @@ struct _LayoutCache PangoLayout *layout; /* The width that was used to generate this layout */ - ClutterUnit width; + gfloat width; /* The height that was used to generate this layout */ - ClutterUnit height; + gfloat height; /* A number representing the age of this cache (so that when a * new layout is needed the last used cache is replaced) @@ -240,8 +240,8 @@ clutter_text_clear_selection (ClutterText *self) static PangoLayout * clutter_text_create_layout_no_cache (ClutterText *text, - ClutterUnit allocation_width, - ClutterUnit allocation_height) + gfloat allocation_width, + gfloat allocation_height) { ClutterTextPrivate *priv = text->priv; PangoLayout *layout; @@ -322,7 +322,7 @@ clutter_text_create_layout_no_cache (ClutterText *text, gint width; width = allocation_width > 0 - ? CLUTTER_UNITS_TO_PANGO_UNIT (allocation_width) + ? (allocation_width * 1024) : -1; pango_layout_set_width (layout, width); @@ -345,7 +345,7 @@ clutter_text_create_layout_no_cache (ClutterText *text, gint height; height = allocation_height > 0 - ? CLUTTER_UNITS_TO_PANGO_UNIT (allocation_height) + ? (allocation_height * 1024) : -1; pango_layout_set_height (layout, height); @@ -390,8 +390,8 @@ clutter_text_font_changed_cb (ClutterText *text) */ static PangoLayout * clutter_text_create_layout (ClutterText *text, - ClutterUnit allocation_width, - ClutterUnit allocation_height) + gfloat allocation_width, + gfloat allocation_height) { ClutterTextPrivate *priv = text->priv; LayoutCache *oldest_cache = priv->cached_layouts; @@ -456,16 +456,17 @@ clutter_text_create_layout (ClutterText *text, static gint clutter_text_coords_to_position (ClutterText *text, - gint x, - gint y) + gfloat x, + gfloat y) { + ClutterTextPrivate *priv = text->priv; gint index_; gint px, py; gint trailing; /* Take any offset due to scrolling into account */ - if (text->priv->single_line_mode) - x += text->priv->text_x * -1; + if (priv->single_line_mode) + x += priv->text_x * -1; px = x * PANGO_SCALE; py = y * PANGO_SCALE; @@ -494,9 +495,9 @@ clutter_text_coords_to_position (ClutterText *text, gboolean clutter_text_position_to_coords (ClutterText *self, gint position, - ClutterUnit *x, - ClutterUnit *y, - ClutterUnit *line_height) + gfloat *x, + gfloat *y, + gfloat *line_height) { ClutterTextPrivate *priv; PangoRectangle rect; @@ -537,7 +538,7 @@ clutter_text_position_to_coords (ClutterText *self, if (x) { - *x = CLUTTER_UNITS_FROM_PANGO_UNIT (rect.x); + *x = (gfloat) rect.x / 1024.0f; /* Take any offset due to scrolling into account */ if (priv->single_line_mode) @@ -545,10 +546,10 @@ clutter_text_position_to_coords (ClutterText *self, } if (y) - *y = CLUTTER_UNITS_FROM_PANGO_UNIT (rect.y); + *y = (gfloat) rect.y / 1024.0f; if (line_height) - *line_height = CLUTTER_UNITS_FROM_PANGO_UNIT (rect.height); + *line_height = (gfloat) rect.height / 1024.0f; return TRUE; } @@ -557,7 +558,7 @@ static inline void clutter_text_ensure_cursor_position (ClutterText *self) { ClutterTextPrivate *priv = self->priv; - ClutterUnit x, y, cursor_height; + gfloat x, y, cursor_height; ClutterGeometry cursor_pos = { 0, }; gboolean x_changed, y_changed; gboolean width_changed, height_changed; @@ -961,7 +962,7 @@ cursor_paint (ClutterText *self) gint i; gint index_; gint maxindex; - ClutterUnit y, height; + gfloat y, height; line = pango_layout_get_line_readonly (layout, line_no); pango_layout_line_x_to_index (line, G_MAXINT, &maxindex, NULL); @@ -982,22 +983,20 @@ cursor_paint (ClutterText *self) gint range_x; gint range_width; - range_x = ranges[i * 2] - / PANGO_SCALE; + range_x = ranges[i * 2] / PANGO_SCALE; /* Account for any scrolling in single line mode */ if (priv->single_line_mode) - range_x += priv->text_x; + range_x += priv->text_x; range_width = (ranges[i * 2 + 1] - ranges[i * 2]) / PANGO_SCALE; cogl_rectangle (range_x, - CLUTTER_UNITS_TO_DEVICE (y), + y, range_x + range_width, - CLUTTER_UNITS_TO_DEVICE (y) - + CLUTTER_UNITS_TO_DEVICE (height)); + y + height); } g_free (ranges); @@ -1164,7 +1163,7 @@ clutter_text_button_press (ClutterActor *actor, ClutterText *self = CLUTTER_TEXT (actor); ClutterTextPrivate *priv = self->priv; gboolean res = FALSE; - ClutterUnit x, y; + gfloat x, y; gint index_; /* we'll steal keyfocus if we do not have it */ @@ -1182,18 +1181,15 @@ clutter_text_button_press (ClutterActor *actor, return TRUE; } - x = CLUTTER_UNITS_FROM_INT (event->x); - y = CLUTTER_UNITS_FROM_INT (event->y); - - res = clutter_actor_transform_stage_point (actor, x, y, &x, &y); + res = clutter_actor_transform_stage_point (actor, + event->x, + event->y, + &x, &y); if (res) { gint offset; - index_ = clutter_text_coords_to_position (self, - CLUTTER_UNITS_TO_INT (x), - CLUTTER_UNITS_TO_INT (y)); - + index_ = clutter_text_coords_to_position (self, x, y); offset = bytes_to_offset (priv->text, index_); /* what we select depends on the number of button clicks we @@ -1229,32 +1225,30 @@ static gboolean clutter_text_motion (ClutterActor *actor, ClutterMotionEvent *mev) { - ClutterText *ttext = CLUTTER_TEXT (actor); - ClutterTextPrivate *priv = ttext->priv; - ClutterUnit x, y; - gint index_; - const gchar *text; + ClutterText *self = CLUTTER_TEXT (actor); + ClutterTextPrivate *priv = self->priv; + gfloat x, y; + gint index_, offset; + gboolean res; if (!priv->in_select_drag) return FALSE; - text = clutter_text_get_text (ttext); + res = clutter_actor_transform_stage_point (actor, + mev->x, mev->y, + &x, &y); + if (!res) + return FALSE; - x = CLUTTER_UNITS_FROM_INT (mev->x); - y = CLUTTER_UNITS_FROM_INT (mev->y); - - clutter_actor_transform_stage_point (actor, x, y, &x, &y); - - index_ = clutter_text_coords_to_position (ttext, - CLUTTER_UNITS_TO_INT (x), - CLUTTER_UNITS_TO_INT (y)); + index_ = clutter_text_coords_to_position (self, x, y); + offset = bytes_to_offset (priv->text, index_); if (priv->selectable) - clutter_text_set_cursor_position (ttext, bytes_to_offset (text, index_)); + clutter_text_set_cursor_position (self, offset); else { - clutter_text_set_cursor_position (ttext, bytes_to_offset (text, index_)); - clutter_text_set_selection_bound (ttext, bytes_to_offset (text, index_)); + clutter_text_set_cursor_position (self, offset); + clutter_text_set_selection_bound (self, offset); } return TRUE; @@ -1264,8 +1258,8 @@ static gboolean clutter_text_button_release (ClutterActor *actor, ClutterButtonEvent *bev) { - ClutterText *ttext = CLUTTER_TEXT (actor); - ClutterTextPrivate *priv = ttext->priv; + ClutterText *self = CLUTTER_TEXT (actor); + ClutterTextPrivate *priv = self->priv; if (priv->in_select_drag) { @@ -1380,11 +1374,11 @@ clutter_text_paint (ClutterActor *self) pango_layout_get_extents (layout, NULL, &logical_rect); cogl_clip_push (0, 0, - CLUTTER_UNITS_TO_FLOAT (alloc.x2 - alloc.x1), - CLUTTER_UNITS_TO_FLOAT (alloc.y2 - alloc.y1)); + (alloc.x2 - alloc.x1), + (alloc.y2 - alloc.y1)); clip_set = TRUE; - actor_width = (CLUTTER_UNITS_TO_DEVICE (alloc.x2 - alloc.x1)) + actor_width = (alloc.x2 - alloc.x1) - 2 * TEXT_PADDING; text_width = logical_rect.width / PANGO_SCALE; @@ -1449,16 +1443,16 @@ clutter_text_paint (ClutterActor *self) static void clutter_text_get_preferred_width (ClutterActor *self, - ClutterUnit for_height, - ClutterUnit *min_width_p, - ClutterUnit *natural_width_p) + gfloat for_height, + gfloat *min_width_p, + gfloat *natural_width_p) { ClutterText *text = CLUTTER_TEXT (self); ClutterTextPrivate *priv = text->priv; PangoRectangle logical_rect = { 0, }; PangoLayout *layout; gint logical_width; - ClutterUnit layout_width; + gfloat layout_width; layout = clutter_text_create_layout (text, -1, -1); @@ -1471,7 +1465,7 @@ clutter_text_get_preferred_width (ClutterActor *self, logical_width = logical_rect.x + logical_rect.width; layout_width = logical_width > 0 - ? CLUTTER_UNITS_FROM_PANGO_UNIT (logical_width) + ? (logical_width / 1024.0f) : 1; if (min_width_p) @@ -1493,9 +1487,9 @@ clutter_text_get_preferred_width (ClutterActor *self, static void clutter_text_get_preferred_height (ClutterActor *self, - ClutterUnit for_width, - ClutterUnit *min_height_p, - ClutterUnit *natural_height_p) + gfloat for_width, + gfloat *min_height_p, + gfloat *natural_height_p) { ClutterTextPrivate *priv = CLUTTER_TEXT (self)->priv; @@ -1512,7 +1506,7 @@ clutter_text_get_preferred_height (ClutterActor *self, PangoLayout *layout; PangoRectangle logical_rect = { 0, }; gint logical_height; - ClutterUnit layout_height; + gfloat layout_height; layout = clutter_text_create_layout (CLUTTER_TEXT (self), for_width, -1); @@ -1524,7 +1518,7 @@ clutter_text_get_preferred_height (ClutterActor *self, * the height accordingly */ logical_height = logical_rect.y + logical_rect.height; - layout_height = CLUTTER_UNITS_FROM_PANGO_UNIT (logical_height); + layout_height = (gfloat) logical_height / 1024.0f; if (min_height_p) { @@ -1534,13 +1528,13 @@ clutter_text_get_preferred_height (ClutterActor *self, if (priv->ellipsize && priv->wrap) { PangoLayoutLine *line; - ClutterUnit line_height; + gfloat line_height; line = pango_layout_get_line_readonly (layout, 0); pango_layout_line_get_extents (line, NULL, &logical_rect); logical_height = logical_rect.y + logical_rect.height; - line_height = CLUTTER_UNITS_FROM_PANGO_UNIT (logical_height); + line_height = (gfloat) logical_height / 1024.0f; *min_height_p = line_height; } @@ -1554,9 +1548,9 @@ clutter_text_get_preferred_height (ClutterActor *self, } static void -clutter_text_allocate (ClutterActor *self, - const ClutterActorBox *box, - gboolean origin_changed) +clutter_text_allocate (ClutterActor *self, + const ClutterActorBox *box, + ClutterAllocationFlags flags) { ClutterText *text = CLUTTER_TEXT (self); ClutterActorClass *parent_class; @@ -1569,7 +1563,7 @@ clutter_text_allocate (ClutterActor *self, box->y2 - box->y1); parent_class = CLUTTER_ACTOR_CLASS (clutter_text_parent_class); - parent_class->allocate (self, box, origin_changed); + parent_class->allocate (self, box, flags); } static gboolean @@ -3362,11 +3356,11 @@ clutter_text_set_markup (ClutterText *self, PangoLayout * clutter_text_get_layout (ClutterText *self) { - ClutterUnit width, height; + gfloat width, height; g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL); - clutter_actor_get_sizeu (CLUTTER_ACTOR (self), &width, &height); + clutter_actor_get_size (CLUTTER_ACTOR (self), &width, &height); return clutter_text_create_layout (self, width, height); } diff --git a/clutter/clutter-texture.c b/clutter/clutter-texture.c index 918e3c110..3181ff81e 100644 --- a/clutter/clutter-texture.c +++ b/clutter/clutter-texture.c @@ -77,10 +77,8 @@ typedef struct _ClutterTextureAsyncData ClutterTextureAsyncData; struct _ClutterTexturePrivate { - gint width; - gint height; - gint max_tile_waste; - ClutterTextureQuality filter_quality; + gfloat width; + gfloat height; CoglHandle material; gboolean no_slice; @@ -136,7 +134,7 @@ enum PROP_0, PROP_NO_SLICE, PROP_MAX_TILE_WASTE, - PROP_PIXEL_FORMAT, /* Texture format */ + PROP_PIXEL_FORMAT, PROP_SYNC_SIZE, PROP_REPEAT_Y, PROP_REPEAT_X, @@ -177,36 +175,35 @@ clutter_texture_error_quark (void) return g_quark_from_static_string ("clutter-texture-error-quark"); } +static const struct +{ + gint min_filter; + gint mag_filter; +} +clutter_texture_quality_filters[] = + { + /* CLUTTER_TEXTURE_QUALITY_LOW */ + { COGL_MATERIAL_FILTER_NEAREST, COGL_MATERIAL_FILTER_NEAREST }, + + /* CLUTTER_TEXTURE_QUALITY_MEDIUM */ + { COGL_MATERIAL_FILTER_LINEAR, COGL_MATERIAL_FILTER_LINEAR }, + + /* CLUTTER_TEXTURE_QUALITY_HIGH */ + { COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR, COGL_MATERIAL_FILTER_LINEAR } + }; + static inline void clutter_texture_quality_to_filters (ClutterTextureQuality quality, gint *min_filter_p, gint *mag_filter_p) { - gint min_filter, mag_filter; - - switch (quality) - { - case CLUTTER_TEXTURE_QUALITY_LOW: - min_filter = COGL_TEXTURE_FILTER_NEAREST; - mag_filter = COGL_TEXTURE_FILTER_NEAREST; - break; - - case CLUTTER_TEXTURE_QUALITY_MEDIUM: - min_filter = COGL_TEXTURE_FILTER_LINEAR; - mag_filter = COGL_TEXTURE_FILTER_LINEAR; - break; - - case CLUTTER_TEXTURE_QUALITY_HIGH: - min_filter = COGL_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR; - mag_filter = COGL_TEXTURE_FILTER_LINEAR; - break; - } + g_return_if_fail (quality < G_N_ELEMENTS (clutter_texture_quality_filters)); if (min_filter_p) - *min_filter_p = min_filter; + *min_filter_p = clutter_texture_quality_filters[quality].min_filter; if (mag_filter_p) - *mag_filter_p = mag_filter; + *mag_filter_p = clutter_texture_quality_filters[quality].mag_filter; } static void @@ -217,7 +214,10 @@ texture_free_gl_resources (ClutterTexture *texture) CLUTTER_MARK(); if (priv->material != COGL_INVALID_HANDLE) - cogl_material_remove_layer (priv->material, 0); + /* We want to keep the layer so that the filter settings will + remain but we want to free its resources so we clear the + texture handle */ + cogl_material_set_layer (priv->material, 0, COGL_INVALID_HANDLE); } static void @@ -286,31 +286,20 @@ clutter_texture_realize (ClutterActor *actor) if (priv->fbo_source) { CoglTextureFlags flags = COGL_TEXTURE_NONE; - gint min_filter, mag_filter; - gint max_waste = -1; CoglHandle tex; /* Handle FBO's */ - if (!priv->no_slice) - max_waste = priv->max_tile_waste; - - if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH) - flags |= COGL_TEXTURE_AUTO_MIPMAP; + if (priv->no_slice) + flags |= COGL_TEXTURE_NO_SLICING; tex = cogl_texture_new_with_size (priv->width, priv->height, - max_waste, flags, + flags, COGL_PIXEL_FORMAT_RGBA_8888); cogl_material_set_layer (priv->material, 0, tex); - clutter_texture_quality_to_filters (priv->filter_quality, - &min_filter, - &mag_filter); - - cogl_texture_set_filters (tex, min_filter, mag_filter); - priv->fbo_handle = cogl_offscreen_new_to_texture (tex); /* The material now has a reference to the texture so it will @@ -337,19 +326,15 @@ clutter_texture_realize (ClutterActor *actor) } else { - if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_READ_PIXELS)) - { - /* Dont allow realization with no data - note set_data - * will set realize flags. - */ - CLUTTER_NOTE (TEXTURE, - "Texture has no image data cannot realize"); - - CLUTTER_NOTE (TEXTURE, "flags %i", actor->flags); - CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED); - CLUTTER_NOTE (TEXTURE, "flags %i", actor->flags); - return; - } + /* If we have no data, then realization is a no-op but + * we still want to be in REALIZED state to maintain + * invariants. We may have already created the texture + * if someone set some data earlier, or we may create it + * later if someone sets some data later. The fact that + * we may have created it earlier is really a bug, since + * it means ClutterTexture can have GL resources without + * being realized. + */ } CLUTTER_NOTE (TEXTURE, "Texture realized"); @@ -357,9 +342,9 @@ clutter_texture_realize (ClutterActor *actor) static void clutter_texture_get_preferred_width (ClutterActor *self, - ClutterUnit for_height, - ClutterUnit *min_width_p, - ClutterUnit *natural_width_p) + gfloat for_height, + gfloat *min_width_p, + gfloat *natural_width_p) { ClutterTexture *texture = CLUTTER_TEXTURE (self); ClutterTexturePrivate *priv = texture->priv; @@ -376,19 +361,14 @@ clutter_texture_get_preferred_width (ClutterActor *self, for_height < 0 || priv->height <= 0) { - *natural_width_p = CLUTTER_UNITS_FROM_DEVICE (priv->width); + *natural_width_p = priv->width; } else { /* Set the natural width so as to preserve the aspect ratio */ - gfloat ratio, height; + gfloat ratio = priv->width / priv->height; - ratio = (float)(priv->width) / (float)(priv->height); - - height = CLUTTER_UNITS_TO_FLOAT (for_height); - - *natural_width_p = - CLUTTER_UNITS_FROM_FLOAT (ratio * height); + *natural_width_p = ratio * for_height; } } } @@ -401,9 +381,9 @@ clutter_texture_get_preferred_width (ClutterActor *self, static void clutter_texture_get_preferred_height (ClutterActor *self, - ClutterUnit for_width, - ClutterUnit *min_height_p, - ClutterUnit *natural_height_p) + gfloat for_width, + gfloat *min_height_p, + gfloat *natural_height_p) { ClutterTexture *texture = CLUTTER_TEXTURE (self); ClutterTexturePrivate *priv = texture->priv; @@ -420,19 +400,14 @@ clutter_texture_get_preferred_height (ClutterActor *self, for_width < 0 || priv->width <= 0) { - *natural_height_p = CLUTTER_UNITS_FROM_DEVICE (priv->height); + *natural_height_p = priv->height; } else { /* Set the natural height so as to preserve the aspect ratio */ - gfloat ratio, width; + gfloat ratio = priv->height / priv->width; - ratio = (float)(priv->height) / (float)(priv->width); - - width = CLUTTER_UNITS_TO_FLOAT (for_width); - - *natural_height_p = - CLUTTER_UNITS_FROM_FLOAT (ratio * width); + *natural_height_p = ratio * for_width; } } } @@ -444,20 +419,21 @@ clutter_texture_get_preferred_height (ClutterActor *self, } static void -clutter_texture_allocate (ClutterActor *self, - const ClutterActorBox *box, - gboolean origin_changed) +clutter_texture_allocate (ClutterActor *self, + const ClutterActorBox *box, + ClutterAllocationFlags flags) { ClutterTexturePrivate *priv = CLUTTER_TEXTURE (self)->priv; /* chain up to set actor->allocation */ - CLUTTER_ACTOR_CLASS (clutter_texture_parent_class)->allocate (self, box, - origin_changed); + CLUTTER_ACTOR_CLASS (clutter_texture_parent_class)->allocate (self, + box, + flags); /* If we adopted the source fbo then allocate that at its preferred size */ if (priv->fbo_source && clutter_actor_get_parent (priv->fbo_source) == self) - clutter_actor_allocate_preferred_size (priv->fbo_source, origin_changed); + clutter_actor_allocate_preferred_size (priv->fbo_source, flags); } static void @@ -466,7 +442,7 @@ clutter_texture_set_fbo_projection (ClutterActor *self) ClutterTexturePrivate *priv = CLUTTER_TEXTURE (self)->priv; ClutterVertex verts[4]; gfloat viewport[4]; - ClutterUnit x_min, x_max, y_min, y_max; + gfloat x_min, x_max, y_min, y_max; gfloat tx_min, tx_max, ty_min, ty_max; gfloat tan_angle, near_size; ClutterPerspective perspective; @@ -501,13 +477,13 @@ clutter_texture_set_fbo_projection (ClutterActor *self) /* Convert the coordinates back to [-1,1] range */ cogl_get_viewport (viewport); - tx_min = (CLUTTER_UNITS_TO_FLOAT (x_min) / viewport[2]) + tx_min = (x_min / viewport[2]) * 2 - 1.0; - tx_max = (CLUTTER_UNITS_TO_FLOAT (x_max) / viewport[2]) + tx_max = (x_max / viewport[2]) * 2 - 1.0; - ty_min = (CLUTTER_UNITS_TO_FLOAT (y_min) / viewport[3]) + ty_min = (y_min / viewport[3]) * 2 - 1.0; - ty_max = (CLUTTER_UNITS_TO_FLOAT (y_max) / viewport[3]) + ty_max = (y_max / viewport[3]) * 2 - 1.0; /* Set up a projection matrix so that the actor will be projected as @@ -528,7 +504,7 @@ clutter_texture_paint (ClutterActor *self) { ClutterTexture *texture = CLUTTER_TEXTURE (self); ClutterTexturePrivate *priv = texture->priv; - gint x_1, y_1, x_2, y_2; + ClutterActorBox box = { 0, }; CoglColor transparent_col; gfloat t_w, t_h; guint8 paint_opacity = clutter_actor_get_paint_opacity (self); @@ -541,9 +517,6 @@ clutter_texture_paint (ClutterActor *self) return; } - if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR(texture))) - clutter_actor_realize (CLUTTER_ACTOR(texture)); - if (priv->fbo_handle != COGL_INVALID_HANDLE) { ClutterMainContext *context; @@ -567,19 +540,20 @@ clutter_texture_paint (ClutterActor *self) if ((stage = clutter_actor_get_stage (self))) { - guint stage_width, stage_height; - ClutterActor *source_parent; + gfloat stage_width, stage_height; + ClutterActor *source_parent; clutter_stage_get_perspective (CLUTTER_STAGE (stage), &perspective); clutter_actor_get_size (stage, &stage_width, &stage_height); /* Use below to set the modelview matrix as if the viewport was still the same size as the stage */ - cogl_setup_viewport (stage_width, stage_height, - perspective.fovy, - perspective.aspect, - perspective.z_near, - perspective.z_far); + _cogl_setup_viewport (stage_width, stage_height, + perspective.fovy, + perspective.aspect, + perspective.z_near, + perspective.z_far); + /* Use a projection matrix that makes the actor appear as it would if it was rendered at its normal screen location */ clutter_texture_set_fbo_projection (self); @@ -636,28 +610,28 @@ clutter_texture_paint (ClutterActor *self) cogl_material_set_color4ub (priv->material, 0xff, 0xff, 0xff, paint_opacity); - clutter_actor_get_allocation_coords (self, &x_1, &y_1, &x_2, &y_2); + clutter_actor_get_allocation_box (self, &box); - CLUTTER_NOTE (PAINT, "paint to x1: %i, y1: %i x2: %i, y2: %i " + CLUTTER_NOTE (PAINT, "paint to x1: %f, y1: %f x2: %f, y2: %f " "opacity: %i", - x_1, y_1, x_2, y_2, + box.x1, box.y1, box.x2, box.y2, clutter_actor_get_opacity (self)); if (priv->repeat_x && priv->width > 0) - t_w = (float) (x_2 - x_1) / (float) (priv->width); + t_w = (box.x2 - box.x1) / priv->width; else t_w = 1.0; if (priv->repeat_y && priv->height > 0) - t_h = (float) (y_2 - y_1) / (float) (priv->height); + t_h = (box.y2 - box.y1) / priv->height; else t_h = 1.0; /* Paint will have translated us */ cogl_set_source (priv->material); cogl_rectangle_with_texture_coords (0, 0, - (float) (x_2 - x_1), - (float) (y_2 - y_1), + box.x2 - box.x1, + box.y2 - box.y1, 0, 0, t_w, t_h); } @@ -791,10 +765,6 @@ clutter_texture_set_property (GObject *object, switch (prop_id) { - case PROP_MAX_TILE_WASTE: - clutter_texture_set_max_tile_waste (texture, g_value_get_int (value)); - break; - case PROP_SYNC_SIZE: clutter_texture_set_sync_size (texture, g_value_get_boolean (value)); break; @@ -876,14 +846,14 @@ clutter_texture_get_property (GObject *object, switch (prop_id) { - case PROP_MAX_TILE_WASTE: - g_value_set_int (value, clutter_texture_get_max_tile_waste (texture)); - break; - case PROP_PIXEL_FORMAT: g_value_set_enum (value, clutter_texture_get_pixel_format (texture)); break; + case PROP_MAX_TILE_WASTE: + g_value_set_int (value, clutter_texture_get_max_tile_waste (texture)); + break; + case PROP_SYNC_SIZE: g_value_set_boolean (value, priv->sync_actor_size); break; @@ -962,6 +932,14 @@ clutter_texture_class_init (ClutterTextureClass *klass) FALSE, G_PARAM_CONSTRUCT_ONLY | CLUTTER_PARAM_READWRITE)); + g_object_class_install_property + (gobject_class, PROP_MAX_TILE_WASTE, + g_param_spec_int ("tile-waste", + "Tile Waste", + "Maximum waste area of a sliced texture", + -1, G_MAXINT, + COGL_TEXTURE_MAX_WASTE, + CLUTTER_PARAM_READABLE)); g_object_class_install_property (gobject_class, PROP_REPEAT_X, @@ -990,19 +968,6 @@ clutter_texture_class_init (ClutterTextureClass *klass) CLUTTER_TEXTURE_QUALITY_MEDIUM, G_PARAM_CONSTRUCT | CLUTTER_PARAM_READWRITE)); - g_object_class_install_property - (gobject_class, PROP_MAX_TILE_WASTE, - g_param_spec_int ("tile-waste", - "Tile dimension to waste", - "Max wastage dimension of a texture when using " - "sliced textures or -1 to disable slicing. " - "Bigger values use less textures, " - "smaller values less texture memory.", - -1, - G_MAXINT, - 63, - G_PARAM_CONSTRUCT_ONLY | CLUTTER_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, PROP_PIXEL_FORMAT, g_param_spec_enum ("pixel-format", @@ -1112,9 +1077,9 @@ clutter_texture_class_init (ClutterTextureClass *klass) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterTextureClass, size_change), NULL, NULL, - clutter_marshal_VOID__INT_INT, + clutter_marshal_VOID__FLOAT_FLOAT, G_TYPE_NONE, - 2, G_TYPE_INT, G_TYPE_INT); + 2, G_TYPE_FLOAT, G_TYPE_FLOAT); /** * ClutterTexture::pixbuf-change: * @texture: the texture which received the signal @@ -1215,8 +1180,6 @@ clutter_texture_init (ClutterTexture *self) self->priv = priv = CLUTTER_TEXTURE_GET_PRIVATE (self); - priv->max_tile_waste = 63; - priv->filter_quality = CLUTTER_TEXTURE_QUALITY_MEDIUM; priv->repeat_x = FALSE; priv->repeat_y = FALSE; priv->sync_actor_size = TRUE; @@ -1256,12 +1219,6 @@ clutter_texture_save_to_local_data (ClutterTexture *texture) /* Align to 4 bytes */ priv->local_data_rowstride = (priv->local_data_width * bpp + 3) & ~3; - /* Store the filter quality and max_tile_waste from the texture - properties so that they will be restored the data is loaded - again */ - priv->max_tile_waste = clutter_texture_get_max_tile_waste (texture); - priv->filter_quality = clutter_texture_get_filter_quality (texture); - priv->local_data = g_malloc (priv->local_data_rowstride * priv->local_data_height); @@ -1396,6 +1353,12 @@ clutter_texture_get_cogl_texture (ClutterTexture *texture) * @cogl_tex. A reference to the texture is taken so if the handle is * no longer needed it should be deref'd with cogl_handle_unref. * + * This should not be called on an unrealizable texture (one that + * isn't inside a stage). (Currently the ClutterTexture + * implementation relies on being able to have a GL texture while + * unrealized, which means you can get away with it, but it's + * not correct and may change in the future.) + * * Since: 0.8 */ void @@ -1409,6 +1372,12 @@ clutter_texture_set_cogl_texture (ClutterTexture *texture, g_return_if_fail (CLUTTER_IS_TEXTURE (texture)); g_return_if_fail (cogl_is_texture (cogl_tex)); + /* FIXME this implementation should realize the actor if it's in a + * stage, and warn and return if not in a stage yet. However, right + * now everything would break if we did that, so we just fudge it + * and we're broken: we can have a texture without being realized. + */ + priv = texture->priv; width = cogl_texture_get_width (cogl_tex); @@ -1424,6 +1393,14 @@ clutter_texture_set_cogl_texture (ClutterTexture *texture, /* Remove old texture */ texture_free_gl_resources (texture); + + /* Free any saved data so realization doesn't resend it to GL */ + if (priv->local_data) + { + g_free (priv->local_data); + priv->local_data = NULL; + } + /* Use the new texture */ cogl_material_set_layer (priv->material, 0, cogl_tex); @@ -1436,12 +1413,10 @@ clutter_texture_set_cogl_texture (ClutterTexture *texture, priv->width = width; priv->height = height; - CLUTTER_NOTE (TEXTURE, "set size %ix%i\n", + CLUTTER_NOTE (TEXTURE, "set size %.2fx%.2f\n", priv->width, priv->height); - CLUTTER_ACTOR_SET_FLAGS (CLUTTER_ACTOR (texture), CLUTTER_ACTOR_REALIZED); - if (size_change) { g_signal_emit (texture, texture_signals[SIZE_CHANGE], 0, @@ -1475,17 +1450,16 @@ clutter_texture_set_from_data (ClutterTexture *texture, ClutterTexturePrivate *priv = texture->priv; CoglHandle new_texture = COGL_INVALID_HANDLE; CoglTextureFlags flags = COGL_TEXTURE_NONE; - gint min_filter, mag_filter; - gint max_waste = -1; - if (!priv->no_slice) - max_waste = priv->max_tile_waste; + if (priv->no_slice) + flags |= COGL_TEXTURE_NO_SLICING; - if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH) - flags |= COGL_TEXTURE_AUTO_MIPMAP; + /* FIXME if we are not realized, we should store the data + * for future use, instead of creating the texture. + */ new_texture = cogl_texture_new_from_data (width, height, - max_waste, flags, + flags, source_format, COGL_PIXEL_FORMAT_ANY, rowstride, @@ -1500,12 +1474,6 @@ clutter_texture_set_from_data (ClutterTexture *texture, return FALSE; } - clutter_texture_quality_to_filters (priv->filter_quality, - &min_filter, - &mag_filter); - - cogl_texture_set_filters (new_texture, min_filter, mag_filter); - clutter_texture_set_cogl_texture (texture, new_texture); cogl_handle_unref (new_texture); @@ -1530,25 +1498,23 @@ clutter_texture_set_from_data (ClutterTexture *texture, * * Sets #ClutterTexture image data. * - * Note: This function is likely to change in future versions. - * * Return value: %TRUE on success, %FALSE on failure. * * Since: 0.4. - **/ + */ gboolean -clutter_texture_set_from_rgb_data (ClutterTexture *texture, - const guchar *data, - gboolean has_alpha, - gint width, - gint height, - gint rowstride, - gint bpp, - ClutterTextureFlags flags, - GError **error) +clutter_texture_set_from_rgb_data (ClutterTexture *texture, + const guchar *data, + gboolean has_alpha, + gint width, + gint height, + gint rowstride, + gint bpp, + ClutterTextureFlags flags, + GError **error) { ClutterTexturePrivate *priv; - CoglPixelFormat source_format; + CoglPixelFormat source_format; g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), FALSE); @@ -1561,9 +1527,13 @@ clutter_texture_set_from_rgb_data (ClutterTexture *texture, { g_set_error (error, CLUTTER_TEXTURE_ERROR, CLUTTER_TEXTURE_ERROR_BAD_FORMAT, - "Unsupported BPP"); + "Unsupported bits per pixel value '%d': " + "Clutter supports only a BPP value of 4 " + "for RGBA data", + bpp); return FALSE; } + source_format = COGL_PIXEL_FORMAT_RGBA_8888; } else @@ -1572,11 +1542,16 @@ clutter_texture_set_from_rgb_data (ClutterTexture *texture, { g_set_error (error, CLUTTER_TEXTURE_ERROR, CLUTTER_TEXTURE_ERROR_BAD_FORMAT, - "Unsupported BPP"); + "Unsupported bits per pixel value '%d': " + "Clutter supports only a BPP value of 3 " + "for RGB data", + bpp); return FALSE; } + source_format = COGL_PIXEL_FORMAT_RGB_888; } + if ((flags & CLUTTER_TEXTURE_RGB_FLAG_BGR)) source_format |= COGL_BGR_BIT; if ((flags & CLUTTER_TEXTURE_RGB_FLAG_PREMULT)) @@ -1601,8 +1576,6 @@ clutter_texture_set_from_rgb_data (ClutterTexture *texture, * Sets a #ClutterTexture from YUV image data. If an error occurred, * %FALSE is returned and @error is set. * - * This function is likely to change in future versions. - * * Return value: %TRUE if the texture was successfully updated * * Since: 0.4 @@ -1634,7 +1607,7 @@ clutter_texture_set_from_yuv_data (ClutterTexture *texture, { g_set_error (error, CLUTTER_TEXTURE_ERROR, CLUTTER_TEXTURE_ERROR_BAD_FORMAT, - "YUV2 not supported"); + "YUV2 textues are not supported"); return FALSE; } @@ -1663,20 +1636,16 @@ clutter_texture_async_load_complete (ClutterTexture *self, ClutterTexturePrivate *priv = self->priv; CoglHandle handle; CoglTextureFlags flags = COGL_TEXTURE_NONE; - gint waste = -1; priv->async_data = NULL; if (error == NULL) { - if (!priv->no_slice) - waste = priv->max_tile_waste; - - if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH) - flags |= COGL_TEXTURE_AUTO_MIPMAP; + if (priv->no_slice) + flags |= COGL_TEXTURE_NO_SLICING; handle = cogl_texture_new_from_bitmap (bitmap, - waste, flags, + flags, COGL_PIXEL_FORMAT_ANY); clutter_texture_set_cogl_texture (self, handle); if (priv->load_size_async) @@ -1908,8 +1877,6 @@ clutter_texture_set_from_file (ClutterTexture *texture, CoglHandle new_texture = COGL_INVALID_HANDLE; GError *internal_error = NULL; CoglTextureFlags flags = COGL_TEXTURE_NONE; - gint min_filter, mag_filter; - gint max_waste = -1; priv = texture->priv; @@ -1918,14 +1885,11 @@ clutter_texture_set_from_file (ClutterTexture *texture, if (priv->load_data_async) return clutter_texture_async_load (texture, filename, error); - if (!priv->no_slice) - max_waste = priv->max_tile_waste; - - if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH) - flags |= COGL_TEXTURE_AUTO_MIPMAP; + if (priv->no_slice) + flags |= COGL_TEXTURE_NO_SLICING; new_texture = cogl_texture_new_from_file (filename, - max_waste, flags, + flags, COGL_PIXEL_FORMAT_ANY, &internal_error); if (new_texture == COGL_INVALID_HANDLE) @@ -1945,12 +1909,6 @@ clutter_texture_set_from_file (ClutterTexture *texture, return FALSE; } - clutter_texture_quality_to_filters (priv->filter_quality, - &min_filter, - &mag_filter); - - cogl_texture_set_filters (new_texture, min_filter, mag_filter); - clutter_texture_set_cogl_texture (texture, new_texture); cogl_handle_unref (new_texture); @@ -1991,33 +1949,14 @@ clutter_texture_set_filter_quality (ClutterTexture *texture, if (filter_quality != old_quality) { - CoglHandle cogl_texture = clutter_texture_get_cogl_texture (texture); gint min_filter, mag_filter; - priv->filter_quality = filter_quality; - - clutter_texture_quality_to_filters (priv->filter_quality, + clutter_texture_quality_to_filters (filter_quality, &min_filter, &mag_filter); - /* Is this actually needed - causes problems with TFP mipmaps */ - if (cogl_texture != COGL_INVALID_HANDLE) - cogl_texture_set_filters (cogl_texture, min_filter, mag_filter); - - if ((old_quality == CLUTTER_TEXTURE_QUALITY_HIGH || - filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH) && - CLUTTER_ACTOR_IS_REALIZED (texture)) - { - gboolean was_visible; - - was_visible = CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (texture)); - - clutter_actor_unrealize (CLUTTER_ACTOR (texture)); - clutter_actor_realize (CLUTTER_ACTOR (texture)); - - if (was_visible) - clutter_actor_show (CLUTTER_ACTOR (texture)); - } + cogl_material_set_layer_filters (priv->material, 0, + min_filter, mag_filter); g_object_notify (G_OBJECT (texture), "filter-quality"); @@ -2040,46 +1979,28 @@ ClutterTextureQuality clutter_texture_get_filter_quality (ClutterTexture *texture) { ClutterTexturePrivate *priv; + const GList *layers; + CoglMaterialFilter min_filter, mag_filter; + int i; g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), 0); priv = texture->priv; - return priv->filter_quality; -} + layers = cogl_material_get_layers (priv->material); + if (layers == NULL) + return CLUTTER_TEXTURE_QUALITY_MEDIUM; -/** - * clutter_texture_set_max_tile_waste - * @texture: A #ClutterTexture - * @max_tile_waste: Maximum amount of waste in pixels or -1 - * - * Sets the maximum number of pixels in either axis that can be wasted - * for an individual texture slice. If -1 is specified then the - * texture is forced not to be sliced and the texture creation will - * fail if the hardware can't create a texture large enough. - * - * The value is only used when first creating a texture so changing it - * after the texture data has been set has no effect. - * - * Since: 0.8 - */ -void -clutter_texture_set_max_tile_waste (ClutterTexture *texture, - gint max_tile_waste) -{ - ClutterTexturePrivate *priv; - CoglHandle cogl_texture; + min_filter = cogl_material_layer_get_min_filter (layers->data); + mag_filter = cogl_material_layer_get_mag_filter (layers->data); - g_return_if_fail (CLUTTER_IS_TEXTURE (texture)); + for (i = 0; i < G_N_ELEMENTS (clutter_texture_quality_filters); i++) + if (clutter_texture_quality_filters[i].min_filter == min_filter + && clutter_texture_quality_filters[i].mag_filter == mag_filter) + return i; - priv = texture->priv; - cogl_texture = clutter_texture_get_cogl_texture (texture); - - /* There's no point in changing the max_tile_waste if the texture - has already been created because it will be overridden with the - value from the texture handle */ - if (cogl_texture == COGL_INVALID_HANDLE) - priv->max_tile_waste = max_tile_waste; + /* Unknown filter combination */ + return CLUTTER_TEXTURE_QUALITY_LOW; } /** @@ -2090,7 +2011,7 @@ clutter_texture_set_max_tile_waste (ClutterTexture *texture, * -1 if slicing is disabled. * * Return value: The maximum waste or -1 if the texture waste is - * unlimited. + * unlimited. * * Since: 0.8 */ @@ -2103,13 +2024,12 @@ clutter_texture_get_max_tile_waste (ClutterTexture *texture) g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), 0); priv = texture->priv; + cogl_texture = clutter_texture_get_cogl_texture (texture); if (cogl_texture == COGL_INVALID_HANDLE) - return texture->priv->max_tile_waste; + return priv->no_slice ? -1 : COGL_TEXTURE_MAX_WASTE; else - /* If we have a valid texture handle then use the value from that - instead */ return cogl_texture_get_max_waste (cogl_texture); } @@ -2247,8 +2167,15 @@ clutter_texture_set_area_from_rgb_data (ClutterTexture *texture, if ((flags & CLUTTER_TEXTURE_RGB_FLAG_PREMULT)) source_format |= COGL_PREMULT_BIT; - clutter_actor_realize (CLUTTER_ACTOR (texture)); + /* attempt to realize ... */ + if (!CLUTTER_ACTOR_IS_REALIZED (texture) && + clutter_actor_get_stage (CLUTTER_ACTOR (texture)) != NULL) + clutter_actor_realize (CLUTTER_ACTOR (texture)); + /* due to the fudging of clutter_texture_set_cogl_texture() + * which allows setting a texture pre-realize, we may end + * up having a texture even if we couldn't realize yet. + */ cogl_texture = clutter_texture_get_cogl_texture (texture); if (cogl_texture == COGL_INVALID_HANDLE) { @@ -2287,14 +2214,13 @@ on_fbo_source_size_change (GObject *object, ClutterTexture *texture) { ClutterTexturePrivate *priv = texture->priv; - guint w, h; + gfloat w, h; clutter_actor_get_transformed_size (priv->fbo_source, &w, &h); if (w != priv->width || h != priv->height) { CoglTextureFlags flags = COGL_TEXTURE_NONE; - gint min_filter, mag_filter; CoglHandle tex; /* tear down the FBO */ @@ -2306,23 +2232,15 @@ on_fbo_source_size_change (GObject *object, priv->width = w; priv->height = h; - if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH) - flags |= COGL_TEXTURE_AUTO_MIPMAP; + flags |= COGL_TEXTURE_NO_SLICING; tex = cogl_texture_new_with_size (MAX (priv->width, 1), MAX (priv->height, 1), - -1, flags, COGL_PIXEL_FORMAT_RGBA_8888); cogl_material_set_layer (priv->material, 0, tex); - clutter_texture_quality_to_filters (priv->filter_quality, - &min_filter, - &mag_filter); - - cogl_texture_set_filters (tex, min_filter, mag_filter); - priv->fbo_handle = cogl_offscreen_new_to_texture (tex); /* The material now has a reference to the texture so it will @@ -2332,8 +2250,6 @@ on_fbo_source_size_change (GObject *object, if (priv->fbo_handle == COGL_INVALID_HANDLE) { g_warning ("%s: Offscreen texture creation failed", G_STRLOC); - CLUTTER_ACTOR_UNSET_FLAGS (CLUTTER_ACTOR (texture), - CLUTTER_ACTOR_REALIZED); return; } @@ -2439,7 +2355,7 @@ clutter_texture_new_from_actor (ClutterActor *actor) { ClutterTexture *texture; ClutterTexturePrivate *priv; - guint w, h; + gfloat w, h; g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL); @@ -2509,8 +2425,8 @@ clutter_texture_new_from_actor (ClutterActor *actor) G_CALLBACK(on_fbo_parent_change), texture); - priv->width = w; - priv->height = h; + priv->width = w; + priv->height = h; clutter_actor_set_size (CLUTTER_ACTOR (texture), priv->width, priv->height); @@ -2764,7 +2680,7 @@ clutter_texture_get_keep_aspect_ratio (ClutterTexture *texture) /** * clutter_texture_set_load_async: * @texture: a #ClutterTexture - * @load_sync: %TRUE if the texture should asynchronously load data + * @load_async: %TRUE if the texture should asynchronously load data * from a filename * * Sets whether @texture should use a worker thread to load the data diff --git a/clutter/clutter-texture.h b/clutter/clutter-texture.h index 1049910f1..40f84e81a 100644 --- a/clutter/clutter-texture.h +++ b/clutter/clutter-texture.h @@ -202,9 +202,6 @@ void clutter_texture_get_base_size (ClutterTexture void clutter_texture_set_filter_quality (ClutterTexture *texture, ClutterTextureQuality filter_quality); ClutterTextureQuality clutter_texture_get_filter_quality (ClutterTexture *texture); -void clutter_texture_set_max_tile_waste (ClutterTexture *texture, - gint max_tile_waste); -gint clutter_texture_get_max_tile_waste (ClutterTexture *texture); CoglHandle clutter_texture_get_cogl_texture (ClutterTexture *texture); void clutter_texture_set_cogl_texture (ClutterTexture *texture, CoglHandle cogl_tex); @@ -221,6 +218,7 @@ void clutter_texture_get_repeat (ClutterTexture gboolean *repeat_x, gboolean *repeat_y); CoglPixelFormat clutter_texture_get_pixel_format (ClutterTexture *texture); +gint clutter_texture_get_max_tile_waste (ClutterTexture *texture); void clutter_texture_set_keep_aspect_ratio (ClutterTexture *texture, gboolean keep_aspect); gboolean clutter_texture_get_keep_aspect_ratio (ClutterTexture *texture); diff --git a/clutter/clutter-timeline.c b/clutter/clutter-timeline.c index 4eaeeb66c..d74a10786 100644 --- a/clutter/clutter-timeline.c +++ b/clutter/clutter-timeline.c @@ -83,13 +83,13 @@ #include "config.h" #endif -#include "clutter-timeout-pool.h" -#include "clutter-timeline.h" -#include "clutter-main.h" -#include "clutter-marshal.h" -#include "clutter-private.h" #include "clutter-debug.h" #include "clutter-enum-types.h" +#include "clutter-main.h" +#include "clutter-marshal.h" +#include "clutter-master-clock.h" +#include "clutter-private.h" +#include "clutter-timeline.h" G_DEFINE_TYPE (ClutterTimeline, clutter_timeline, G_TYPE_OBJECT); @@ -97,29 +97,26 @@ struct _ClutterTimelinePrivate { ClutterTimelineDirection direction; - guint timeout_id; guint delay_id; - gint current_frame_num; - - guint fps; - guint n_frames; + /* The total length in milliseconds of this timeline */ + guint duration; guint delay; - gint skipped_frames; + /* The current amount of elapsed time */ + gint elapsed_time; + /* The elapsed time since the last frame was fired */ + gint msecs_delta; - GTimeVal prev_frame_timeval; - guint msecs_delta; - - GHashTable *markers_by_frame; GHashTable *markers_by_name; - guint loop : 1; + guint loop : 1; + guint is_playing : 1; }; typedef struct { gchar *name; - guint frame_num; + guint msecs; GQuark quark; } TimelineMarker; @@ -127,8 +124,6 @@ enum { PROP_0, - PROP_FPS, - PROP_NUM_FRAMES, PROP_LOOP, PROP_DELAY, PROP_DURATION, @@ -146,77 +141,17 @@ enum LAST_SIGNAL }; -static guint timeline_signals[LAST_SIGNAL] = { 0, }; -static gint timeline_use_pool = -1; -static ClutterTimeoutPool *timeline_pool = NULL; - -static inline void -timeline_pool_init (void) -{ - if (timeline_use_pool == -1) - { - const gchar *timeline_env; - - timeline_env = g_getenv ("CLUTTER_TIMELINE"); - if (timeline_env && timeline_env[0] != '\0' && - strcmp (timeline_env, "no-pool") == 0) - { - timeline_use_pool = FALSE; - } - else - { - timeline_pool = clutter_timeout_pool_new (CLUTTER_PRIORITY_TIMELINE); - timeline_use_pool = TRUE; - } - } -} - -static guint -timeout_add (guint fps, - GSourceFunc func, - gpointer data, - GDestroyNotify notify) -{ - guint res; - - if (G_LIKELY (timeline_use_pool)) - { - g_assert (timeline_pool != NULL); - res = clutter_timeout_pool_add (timeline_pool, - fps, - func, data, notify); - } - else - { - res = clutter_threads_add_frame_source_full (CLUTTER_PRIORITY_TIMELINE, - fps, - func, data, notify); - } - - return res; -} - -static void -timeout_remove (guint tag) -{ - if (G_LIKELY (timeline_use_pool)) - { - g_assert (timeline_pool != NULL); - clutter_timeout_pool_remove (timeline_pool, tag); - } - else - g_source_remove (tag); -} +static guint timeline_signals[LAST_SIGNAL] = { 0, }; static TimelineMarker * timeline_marker_new (const gchar *name, - guint frame_num) + guint msecs) { TimelineMarker *marker = g_slice_new0 (TimelineMarker); marker->name = g_strdup (name); marker->quark = g_quark_from_string (marker->name); - marker->frame_num = frame_num; + marker->msecs = msecs; return marker; } @@ -249,14 +184,6 @@ clutter_timeline_set_property (GObject *object, switch (prop_id) { - case PROP_FPS: - clutter_timeline_set_speed (timeline, g_value_get_uint (value)); - break; - - case PROP_NUM_FRAMES: - clutter_timeline_set_n_frames (timeline, g_value_get_uint (value)); - break; - case PROP_LOOP: priv->loop = g_value_get_boolean (value); break; @@ -293,14 +220,6 @@ clutter_timeline_get_property (GObject *object, switch (prop_id) { - case PROP_FPS: - g_value_set_uint (value, priv->fps); - break; - - case PROP_NUM_FRAMES: - g_value_set_uint (value, priv->n_frames); - break; - case PROP_LOOP: g_value_set_boolean (value, priv->loop); break; @@ -326,14 +245,16 @@ clutter_timeline_get_property (GObject *object, static void clutter_timeline_finalize (GObject *object) { - ClutterTimelinePrivate *priv = CLUTTER_TIMELINE (object)->priv; - - if (priv->markers_by_frame) - g_hash_table_destroy (priv->markers_by_frame); + ClutterTimeline *self = CLUTTER_TIMELINE (object); + ClutterTimelinePrivate *priv = self->priv; + ClutterMasterClock *master_clock; if (priv->markers_by_name) g_hash_table_destroy (priv->markers_by_name); + master_clock = _clutter_master_clock_get_default (); + _clutter_master_clock_remove_timeline (master_clock, self); + G_OBJECT_CLASS (clutter_timeline_parent_class)->finalize (object); } @@ -351,12 +272,6 @@ clutter_timeline_dispose (GObject *object) priv->delay_id = 0; } - if (priv->timeout_id) - { - timeout_remove (priv->timeout_id); - priv->timeout_id = 0; - } - G_OBJECT_CLASS (clutter_timeline_parent_class)->dispose (object); } @@ -366,8 +281,6 @@ clutter_timeline_class_init (ClutterTimelineClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); GParamSpec *pspec; - timeline_pool_init (); - object_class->set_property = clutter_timeline_set_property; object_class->get_property = clutter_timeline_get_property; object_class->finalize = clutter_timeline_finalize; @@ -375,36 +288,6 @@ clutter_timeline_class_init (ClutterTimelineClass *klass) g_type_class_add_private (klass, sizeof (ClutterTimelinePrivate)); - /** - * ClutterTimeline:fps: - * - * Number of frames per second. Because of the nature of the main - * loop used by Clutter, we can only accept a granularity of one - * frame per millisecond. - * - * This value is to be considered a best approximation. - */ - pspec = g_param_spec_uint ("fps", - "Frames Per Second", - "Frames per second", - 1, 1000, - 60, - CLUTTER_PARAM_READWRITE); - g_object_class_install_property (object_class, PROP_FPS, pspec); - - /** - * ClutterTimeline:num-frames: - * - * Total number of frames for the timeline. - */ - pspec = g_param_spec_uint ("num-frames", - "Total number of frames", - "Total number of frames", - 1, G_MAXUINT, - 1, - CLUTTER_PARAM_READWRITE); - g_object_class_install_property (object_class, PROP_NUM_FRAMES, pspec); - /** * ClutterTimeline:loop: * @@ -468,11 +351,11 @@ clutter_timeline_class_init (ClutterTimelineClass *klass) /** * ClutterTimeline::new-frame: * @timeline: the timeline which received the signal - * @frame_num: the number of the new frame between 0 and - * ClutterTimeline:num-frames + * @msecs: the elapsed time between 0 and duration * - * The ::new-frame signal is emitted each time a new frame in the - * timeline is reached. + * The ::new-frame signal is emitted for each timeline running + * timeline before a new frame is drawn to give animations a chance + * to update the scene. */ timeline_signals[NEW_FRAME] = g_signal_new (I_("new-frame"), @@ -533,18 +416,18 @@ clutter_timeline_class_init (ClutterTimelineClass *klass) * ClutterTimeline::marker-reached: * @timeline: the #ClutterTimeline which received the signal * @marker_name: the name of the marker reached - * @frame_num: the frame number + * @msecs: the elapsed time * * The ::marker-reached signal is emitted each time a timeline - * reaches a marker set with clutter_timeline_add_marker_at_frame() - * or clutter_timeline_add_marker_at_time(). This signal is - * detailed with the name of the marker as well, so it is - * possible to connect a callback to the ::marker-reached signal - * for a specific marker with: + * reaches a marker set with + * clutter_timeline_add_marker_at_time(). This signal is detailed + * with the name of the marker as well, so it is possible to connect + * a callback to the ::marker-reached signal for a specific marker + * with: * * - * clutter_timeline_add_marker_at_frame (timeline, "foo", 24); - * clutter_timeline_add_marker_at_frame (timeline, "bar", 48); + * clutter_timeline_add_marker_at_time (timeline, "foo", 500); + * clutter_timeline_add_marker_at_time (timeline, "bar", 750); * * g_signal_connect (timeline, "marker-reached", * G_CALLBACK (each_marker_reached), NULL); @@ -577,51 +460,57 @@ static void clutter_timeline_init (ClutterTimeline *self) { ClutterTimelinePrivate *priv; + ClutterMasterClock *master_clock; self->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (self, CLUTTER_TYPE_TIMELINE, ClutterTimelinePrivate); - priv->fps = clutter_get_default_frame_rate (); - priv->n_frames = 0; - priv->msecs_delta = 0; + priv->duration = 0; + priv->delay = 0; + priv->elapsed_time = 0; + + master_clock = _clutter_master_clock_get_default (); + _clutter_master_clock_add_timeline (master_clock, self); +} + +static void +check_if_marker_hit (const gchar *name, + TimelineMarker *marker, + ClutterTimeline *timeline) +{ + ClutterTimelinePrivate *priv = timeline->priv; + + if (priv->direction == CLUTTER_TIMELINE_FORWARD + ? (marker->msecs > priv->elapsed_time - priv->msecs_delta + && marker->msecs <= priv->elapsed_time) + : (marker->msecs >= priv->elapsed_time + && marker->msecs < priv->elapsed_time + priv->msecs_delta)) + { + CLUTTER_NOTE (SCHEDULER, "Marker '%s' reached", name); + + g_signal_emit (timeline, timeline_signals[MARKER_REACHED], + marker->quark, + name, + marker->msecs); + } } static void emit_frame_signal (ClutterTimeline *timeline) { ClutterTimelinePrivate *priv = timeline->priv; - gint i; g_signal_emit (timeline, timeline_signals[NEW_FRAME], 0, - priv->current_frame_num); + priv->elapsed_time); /* shortcircuit here if we don't have any marker installed */ - if (priv->markers_by_name == NULL || - priv->markers_by_frame == NULL) + if (priv->markers_by_name == NULL) return; - for (i = priv->skipped_frames; i >= 0; i--) - { - gint frame_num; - GSList *markers, *l; - - frame_num = priv->current_frame_num - + (priv->direction == CLUTTER_TIMELINE_FORWARD ? -i : i); - markers = g_hash_table_lookup (priv->markers_by_frame, - GUINT_TO_POINTER (frame_num)); - for (l = markers; l; l = l->next) - { - TimelineMarker *marker = l->data; - - CLUTTER_NOTE (SCHEDULER, "Marker '%s' reached", marker->name); - - g_signal_emit (timeline, timeline_signals[MARKER_REACHED], - marker->quark, - marker->name, - marker->frame_num); - } - } + g_hash_table_foreach (priv->markers_by_name, + (GHFunc) check_if_marker_hit, + timeline); } static gboolean @@ -629,68 +518,29 @@ is_complete (ClutterTimeline *timeline) { ClutterTimelinePrivate *priv = timeline->priv; - return ((priv->direction == CLUTTER_TIMELINE_FORWARD) && - (priv->current_frame_num >= priv->n_frames)) || - ((priv->direction == CLUTTER_TIMELINE_BACKWARD) && - (priv->current_frame_num <= 0)); + return (priv->direction == CLUTTER_TIMELINE_FORWARD + ? priv->elapsed_time >= priv->duration + : priv->elapsed_time <= 0); } static gboolean -timeline_timeout_func (gpointer data) +clutter_timeline_advance_internal (ClutterTimeline *timeline) { - ClutterTimeline *timeline = data; ClutterTimelinePrivate *priv; - GTimeVal timeval; - guint n_frames, speed; - gulong msecs; priv = timeline->priv; g_object_ref (timeline); - /* Figure out potential frame skips */ - g_get_current_time (&timeval); - CLUTTER_TIMESTAMP (SCHEDULER, "Timeline [%p] activated (cur: %d)\n", timeline, - priv->current_frame_num); + priv->elapsed_time); - if (!priv->prev_frame_timeval.tv_sec) - { - CLUTTER_NOTE (SCHEDULER, - "Timeline [%p] recieved timeout before being initialised!", - timeline); - priv->prev_frame_timeval = timeval; - } - - /* Interpolate the current frame based on the timeval of the - * previous frame */ - msecs = (timeval.tv_sec - priv->prev_frame_timeval.tv_sec) * 1000; - msecs += (timeval.tv_usec - priv->prev_frame_timeval.tv_usec) / 1000; - priv->msecs_delta = msecs; - - /* we need to avoid fps > 1000 */ - speed = MAX (1000 / priv->fps, 1); - - n_frames = msecs / speed; - if (n_frames == 0) - n_frames = 1; - - priv->skipped_frames = n_frames - 1; - - if (priv->skipped_frames) - CLUTTER_TIMESTAMP (SCHEDULER, - "Timeline [%p], skipping %d frames\n", - timeline, - priv->skipped_frames); - - priv->prev_frame_timeval = timeval; - - /* Advance frames */ + /* Advance time */ if (priv->direction == CLUTTER_TIMELINE_FORWARD) - priv->current_frame_num += n_frames; + priv->elapsed_time += priv->msecs_delta; else - priv->current_frame_num -= n_frames; + priv->elapsed_time -= priv->msecs_delta; /* If we have not reached the end of the timeline: */ if (!is_complete (timeline)) @@ -699,7 +549,7 @@ timeline_timeout_func (gpointer data) emit_frame_signal (timeline); /* Signal pauses timeline ? */ - if (!priv->timeout_id) + if (!priv->is_playing) { g_object_unref (timeline); return FALSE; @@ -712,30 +562,23 @@ timeline_timeout_func (gpointer data) { /* Handle loop or stop */ ClutterTimelineDirection saved_direction = priv->direction; - guint overflow_frame_num = priv->current_frame_num; - gint end_frame; + guint overflow_msecs = priv->elapsed_time; + gint end_msecs; - /* Update the current frame number in case the signal handlers - want to take a peek. Don't count skipped frames that run past - the end of the timeline */ + /* Update the current elapsed time in case the signal handlers + want to take a peek. */ if (priv->direction == CLUTTER_TIMELINE_FORWARD) - { - priv->skipped_frames -= priv->current_frame_num - priv->n_frames; - priv->current_frame_num = priv->n_frames; - } + priv->elapsed_time = priv->duration; else if (priv->direction == CLUTTER_TIMELINE_BACKWARD) - { - priv->skipped_frames += priv->current_frame_num; - priv->current_frame_num = 0; - } + priv->elapsed_time = 0; - end_frame = priv->current_frame_num; + end_msecs = priv->elapsed_time; /* Emit the signal */ emit_frame_signal (timeline); - /* Did the signal handler modify the current_frame_num */ - if (priv->current_frame_num != end_frame) + /* Did the signal handler modify the elapsed time? */ + if (priv->elapsed_time != end_msecs) { g_object_unref (timeline); return TRUE; @@ -745,13 +588,12 @@ timeline_timeout_func (gpointer data) * on the last frame we will still go ahead and send the * completed signal */ CLUTTER_NOTE (SCHEDULER, - "Timeline [%p] completed (cur: %d, tot: %d, drop: %d)", + "Timeline [%p] completed (cur: %d, tot: %d)", timeline, - priv->current_frame_num, - priv->n_frames, - n_frames - 1); + priv->elapsed_time, + priv->msecs_delta); - if (!priv->loop && priv->timeout_id) + if (!priv->loop && priv->is_playing) { /* We remove the timeout now, so that the completed signal handler * may choose to re-start the timeline @@ -759,20 +601,19 @@ timeline_timeout_func (gpointer data) * XXX Perhaps we should remove this earlier, and regardless * of priv->loop. Are we limiting the things that could be done in * the above new-frame signal handler */ - timeout_remove (priv->timeout_id); - priv->timeout_id = 0; + priv->is_playing = FALSE; } g_signal_emit (timeline, timeline_signals[COMPLETED], 0); /* Again check to see if the user has manually played with - * current_frame_num, before we finally stop or loop the timeline */ + * the elapsed time, before we finally stop or loop the timeline */ - if (priv->current_frame_num != end_frame && - !(/* Except allow moving from frame 0 -> n_frame (or vica-versa) + if (priv->elapsed_time != end_msecs && + !(/* Except allow changing time from 0 -> duration (or vice-versa) since these are considered equivalent */ - (priv->current_frame_num == 0 && end_frame == priv->n_frames) || - (priv->current_frame_num == priv->n_frames && end_frame == 0) + (priv->elapsed_time == 0 && end_msecs == priv->duration) || + (priv->elapsed_time == priv->duration && end_msecs == 0) )) { g_object_unref (timeline); @@ -783,16 +624,13 @@ timeline_timeout_func (gpointer data) { /* We try and interpolate smoothly around a loop */ if (saved_direction == CLUTTER_TIMELINE_FORWARD) - priv->current_frame_num = overflow_frame_num - priv->n_frames; + priv->elapsed_time = overflow_msecs - priv->duration; else - priv->current_frame_num = priv->n_frames + overflow_frame_num; + priv->elapsed_time = priv->duration + overflow_msecs; /* Or if the direction changed, we try and bounce */ if (priv->direction != saved_direction) - { - priv->current_frame_num = priv->n_frames - - priv->current_frame_num; - } + priv->elapsed_time = priv->duration - priv->elapsed_time; g_object_unref (timeline); return TRUE; @@ -801,39 +639,12 @@ timeline_timeout_func (gpointer data) { clutter_timeline_rewind (timeline); - priv->prev_frame_timeval.tv_sec = 0; - priv->prev_frame_timeval.tv_usec = 0; - g_object_unref (timeline); return FALSE; } } } -static guint -timeline_timeout_add (ClutterTimeline *timeline, - guint fps, - GSourceFunc func, - gpointer data, - GDestroyNotify notify) -{ - ClutterTimelinePrivate *priv; - GTimeVal timeval; - - priv = timeline->priv; - - if (priv->prev_frame_timeval.tv_sec == 0) - { - g_get_current_time (&timeval); - priv->prev_frame_timeval = timeval; - } - - priv->skipped_frames = 0; - priv->msecs_delta = 0; - - return timeout_add (fps, func, data, notify); -} - static gboolean delay_timeout_func (gpointer data) { @@ -841,11 +652,8 @@ delay_timeout_func (gpointer data) ClutterTimelinePrivate *priv = timeline->priv; priv->delay_id = 0; - - priv->timeout_id = timeline_timeout_add (timeline, - priv->fps, - timeline_timeout_func, - timeline, NULL); + priv->msecs_delta = 0; + priv->is_playing = TRUE; g_signal_emit (timeline, timeline_signals[STARTED], 0); @@ -867,24 +675,20 @@ clutter_timeline_start (ClutterTimeline *timeline) priv = timeline->priv; - if (priv->delay_id || priv->timeout_id) + if (priv->delay_id || priv->is_playing) return; - if (priv->n_frames == 0) + if (priv->duration == 0) return; if (priv->delay) - { - priv->delay_id = g_timeout_add (priv->delay, - (GSourceFunc)delay_timeout_func, - timeline); - } + priv->delay_id = clutter_threads_add_timeout (priv->delay, + delay_timeout_func, + timeline); else { - priv->timeout_id = timeline_timeout_add (timeline, - priv->fps, - timeline_timeout_func, - timeline, NULL); + priv->msecs_delta = 0; + priv->is_playing = TRUE; g_signal_emit (timeline, timeline_signals[STARTED], 0); } @@ -905,20 +709,17 @@ clutter_timeline_pause (ClutterTimeline *timeline) priv = timeline->priv; + if (priv->delay_id == 0 || !priv->is_playing) + return; + if (priv->delay_id) { g_source_remove (priv->delay_id); priv->delay_id = 0; } - if (priv->timeout_id) - { - timeout_remove (priv->timeout_id); - priv->timeout_id = 0; - } - - priv->prev_frame_timeval.tv_sec = 0; - priv->prev_frame_timeval.tv_usec = 0; + priv->msecs_delta = 0; + priv->is_playing = FALSE; g_signal_emit (timeline, timeline_signals[PAUSED], 0); } @@ -993,19 +794,19 @@ clutter_timeline_rewind (ClutterTimeline *timeline) if (priv->direction == CLUTTER_TIMELINE_FORWARD) clutter_timeline_advance (timeline, 0); else if (priv->direction == CLUTTER_TIMELINE_BACKWARD) - clutter_timeline_advance (timeline, priv->n_frames); + clutter_timeline_advance (timeline, priv->duration); } /** * clutter_timeline_skip: * @timeline: A #ClutterTimeline - * @n_frames: Number of frames to skip + * @msecs: Amount of time to skip * - * Advance timeline by the requested number of frames. + * Advance timeline by the requested time in milliseconds */ void clutter_timeline_skip (ClutterTimeline *timeline, - guint n_frames) + guint msecs) { ClutterTimelinePrivate *priv; @@ -1015,35 +816,38 @@ clutter_timeline_skip (ClutterTimeline *timeline, if (priv->direction == CLUTTER_TIMELINE_FORWARD) { - priv->current_frame_num += n_frames; + priv->elapsed_time += msecs; - if (priv->current_frame_num > priv->n_frames) - priv->current_frame_num = 1; + if (priv->elapsed_time > priv->duration) + priv->elapsed_time = 1; } else if (priv->direction == CLUTTER_TIMELINE_BACKWARD) { - priv->current_frame_num -= n_frames; + priv->elapsed_time -= msecs; - if (priv->current_frame_num < 1) - priv->current_frame_num = priv->n_frames - 1; + if (priv->elapsed_time < 1) + priv->elapsed_time = priv->duration - 1; } + + priv->msecs_delta = 0; } /** * clutter_timeline_advance: * @timeline: A #ClutterTimeline - * @frame_num: Frame number to advance to + * @msecs: Time to advance to * - * Advance timeline to the requested frame number. + * Advance timeline to the requested point. The point is given as a + * time in milliseconds since the timeline started. * * The @timeline will not emit the #ClutterTimeline::new-frame - * signal for @frame_num. The first ::new-frame signal after the call to - * clutter_timeline_advance() will be emitted for a frame following - * @frame_num. + * signal for the given time. The first ::new-frame signal after the call to + * clutter_timeline_advance() will be emit the skipped markers. + * */ void clutter_timeline_advance (ClutterTimeline *timeline, - guint frame_num) + guint msecs) { ClutterTimelinePrivate *priv; @@ -1051,133 +855,23 @@ clutter_timeline_advance (ClutterTimeline *timeline, priv = timeline->priv; - priv->current_frame_num = CLAMP (frame_num, 0, priv->n_frames); + priv->elapsed_time = CLAMP (msecs, 0, priv->duration); } /** - * clutter_timeline_get_current_frame: + * clutter_timeline_get_elapsed_time: * @timeline: A #ClutterTimeline * - * Request the current frame number of the timeline. + * Request the current time position of the timeline. * - * Return value: current frame number - */ -gint -clutter_timeline_get_current_frame (ClutterTimeline *timeline) -{ - g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), 0); - - return timeline->priv->current_frame_num; -} - -/** - * clutter_timeline_get_n_frames: - * @timeline: A #ClutterTimeline - * - * Request the total number of frames for the #ClutterTimeline. - * - * Return value: the number of frames + * Return value: current elapsed time in milliseconds. */ guint -clutter_timeline_get_n_frames (ClutterTimeline *timeline) +clutter_timeline_get_elapsed_time (ClutterTimeline *timeline) { g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), 0); - return timeline->priv->n_frames; -} - -/** - * clutter_timeline_set_n_frames: - * @timeline: a #ClutterTimeline - * @n_frames: the number of frames - * - * Sets the total number of frames for @timeline - */ -void -clutter_timeline_set_n_frames (ClutterTimeline *timeline, - guint n_frames) -{ - ClutterTimelinePrivate *priv; - - g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); - g_return_if_fail (n_frames > 0); - - priv = timeline->priv; - - if (priv->n_frames != n_frames) - { - g_object_freeze_notify (G_OBJECT (timeline)); - - priv->n_frames = n_frames; - - g_object_notify (G_OBJECT (timeline), "num-frames"); - g_object_notify (G_OBJECT (timeline), "duration"); - - g_object_thaw_notify (G_OBJECT (timeline)); - } -} - -/** - * clutter_timeline_set_speed: - * @timeline: A #ClutterTimeline - * @fps: New speed of timeline as frames per second, - * between 1 and 1000 - * - * Sets the speed of @timeline in frames per second. - */ -void -clutter_timeline_set_speed (ClutterTimeline *timeline, - guint fps) -{ - ClutterTimelinePrivate *priv; - - g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); - g_return_if_fail (fps > 0 && fps <= 1000); - - priv = timeline->priv; - - if (priv->fps != fps) - { - g_object_ref (timeline); - - priv->fps = fps; - - /* if the timeline is playing restart */ - if (priv->timeout_id) - { - timeout_remove (priv->timeout_id); - - priv->timeout_id = timeline_timeout_add (timeline, - priv->fps, - timeline_timeout_func, - timeline, NULL); - } - - g_object_freeze_notify (G_OBJECT (timeline)); - - g_object_notify (G_OBJECT (timeline), "duration"); - g_object_notify (G_OBJECT (timeline), "fps"); - - g_object_thaw_notify (G_OBJECT (timeline)); - - g_object_unref (timeline); - } -} - -/** - * clutter_timeline_get_speed: - * @timeline: a #ClutterTimeline - * - * Gets the frames per second played by @timeline - * - * Return value: the number of frames per second. - */ -guint -clutter_timeline_get_speed (ClutterTimeline *timeline) -{ - g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), 0); - - return timeline->priv->fps; + return timeline->priv->elapsed_time; } /** @@ -1193,7 +887,7 @@ clutter_timeline_is_playing (ClutterTimeline *timeline) { g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), FALSE); - return (timeline->priv->timeout_id != 0); + return timeline->priv->is_playing; } /** @@ -1217,8 +911,7 @@ clutter_timeline_clone (ClutterTimeline *timeline) g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), NULL); copy = g_object_new (CLUTTER_TYPE_TIMELINE, - "fps", clutter_timeline_get_speed (timeline), - "num-frames", clutter_timeline_get_n_frames (timeline), + "duration", clutter_timeline_get_duration (timeline), "loop", clutter_timeline_get_loop (timeline), "delay", clutter_timeline_get_delay (timeline), "direction", clutter_timeline_get_direction (timeline), @@ -1231,9 +924,7 @@ clutter_timeline_clone (ClutterTimeline *timeline) * clutter_timeline_new_for_duration: * @msecs: Duration of the timeline in milliseconds * - * Creates a new #ClutterTimeline with a duration of @msecs using - * the value of the ClutterTimeline:fps property to compute the - * equivalent number of frames. + * Creates a new #ClutterTimeline with a duration of @msecs. * * Return value: the newly created #ClutterTimeline instance. Use * g_object_unref() when done using it @@ -1241,36 +932,13 @@ clutter_timeline_clone (ClutterTimeline *timeline) * Since: 0.6 */ ClutterTimeline * -clutter_timeline_new_for_duration (guint msecs) +clutter_timeline_new (guint msecs) { return g_object_new (CLUTTER_TYPE_TIMELINE, "duration", msecs, NULL); } -/** - * clutter_timeline_new: - * @n_frames: the number of frames - * @fps: the number of frames per second - * - * Create a new #ClutterTimeline instance. - * - * Return Value: the newly created #ClutterTimeline instance. Use - * g_object_unref() when done using it - */ -ClutterTimeline* -clutter_timeline_new (guint n_frames, - guint fps) -{ - g_return_val_if_fail (n_frames > 0, NULL); - g_return_val_if_fail (fps > 0 && fps <= 1000, NULL); - - return g_object_new (CLUTTER_TYPE_TIMELINE, - "fps", fps, - "num-frames", n_frames, - NULL); -} - /** * clutter_timeline_get_delay: * @timeline: a #ClutterTimeline @@ -1335,7 +1003,7 @@ clutter_timeline_get_duration (ClutterTimeline *timeline) priv = timeline->priv; - return priv->n_frames * 1000 / priv->fps; + return priv->duration; } /** @@ -1353,18 +1021,18 @@ clutter_timeline_set_duration (ClutterTimeline *timeline, guint msecs) { ClutterTimelinePrivate *priv; - guint n_frames; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); + g_return_if_fail (msecs > 0); priv = timeline->priv; - n_frames = msecs * priv->fps / 1000; - if (n_frames < 1) - n_frames = 1; + if (priv->duration != msecs) + { + priv->duration = msecs; - /* this will notify :duration as well */ - clutter_timeline_set_n_frames (timeline, n_frames); + g_object_notify (G_OBJECT (timeline), "duration"); + } } /** @@ -1386,7 +1054,7 @@ clutter_timeline_get_progress (ClutterTimeline *timeline) priv = timeline->priv; - return (gdouble) priv->current_frame_num / (gdouble) priv->n_frames; + return (gdouble) priv->elapsed_time / (gdouble) priv->duration; } /** @@ -1449,8 +1117,8 @@ clutter_timeline_set_direction (ClutterTimeline *timeline, { priv->direction = direction; - if (priv->current_frame_num == 0) - priv->current_frame_num = priv->n_frames; + if (priv->elapsed_time == 0) + priv->elapsed_time = priv->duration; g_object_notify (G_OBJECT (timeline), "direction"); } @@ -1459,119 +1127,85 @@ clutter_timeline_set_direction (ClutterTimeline *timeline, /** * clutter_timeline_get_delta: * @timeline: a #ClutterTimeline - * @msecs: return location for the milliseconds elapsed since the last - * frame, or %NULL * - * Retrieves the number of frames and the amount of time elapsed since - * the last ClutterTimeline::new-frame signal. + * Retrieves the amount of time elapsed since the last + * ClutterTimeline::new-frame signal. * * This function is only useful inside handlers for the ::new-frame * signal, and its behaviour is undefined if the timeline is not * playing. * - * Return value: the amount of frames elapsed since the last one + * Return value: the amount of time in milliseconds elapsed since the + * last frame * * Since: 0.6 */ guint -clutter_timeline_get_delta (ClutterTimeline *timeline, - guint *msecs) +clutter_timeline_get_delta (ClutterTimeline *timeline) { ClutterTimelinePrivate *priv; g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), 0); if (!clutter_timeline_is_playing (timeline)) - { - if (msecs) - *msecs = 0; - - return 0; - } + return 0; priv = timeline->priv; - if (msecs) - *msecs = timeline->priv->msecs_delta; + return timeline->priv->msecs_delta; +} - return priv->skipped_frames + 1; +/* + * clutter_timeline_advance_delta: + * @timeline: a #ClutterTimeline + * @msecs: advance in milliseconds + * + * Advances @timeline by @msecs. This function is called by the master + * clock and it is used to advance a timeline by the amount of milliseconds + * elapsed since the last redraw operation. The @timeline will use this + * interval to emit the #ClutterTimeline::new-frame signal and eventually + * skip frames. + */ +void +clutter_timeline_advance_delta (ClutterTimeline *timeline, + guint msecs) +{ + ClutterTimelinePrivate *priv; + + g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); + + priv = timeline->priv; + + priv->msecs_delta = msecs; + + clutter_timeline_advance_internal (timeline); } static inline void clutter_timeline_add_marker_internal (ClutterTimeline *timeline, const gchar *marker_name, - guint frame_num) + guint msecs) { ClutterTimelinePrivate *priv = timeline->priv; TimelineMarker *marker; - GSList *markers; - /* create the hash tables that will hold the markers */ - if (G_UNLIKELY (priv->markers_by_name == NULL || - priv->markers_by_frame == NULL)) - { - priv->markers_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, - NULL, - timeline_marker_free); - priv->markers_by_frame = g_hash_table_new (NULL, NULL); - } + /* create the hash table that will hold the markers */ + if (G_UNLIKELY (priv->markers_by_name == NULL)) + priv->markers_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, + NULL, + timeline_marker_free); marker = g_hash_table_lookup (priv->markers_by_name, marker_name); if (G_UNLIKELY (marker)) { - g_warning ("A marker named '%s' already exists on frame %d", + g_warning ("A marker named '%s' already exists at time %d", marker->name, - marker->frame_num); + marker->msecs); return; } - marker = timeline_marker_new (marker_name, frame_num); + marker = timeline_marker_new (marker_name, msecs); g_hash_table_insert (priv->markers_by_name, marker->name, marker); - - markers = g_hash_table_lookup (priv->markers_by_frame, - GUINT_TO_POINTER (frame_num)); - if (!markers) - { - markers = g_slist_prepend (NULL, marker); - g_hash_table_insert (priv->markers_by_frame, - GUINT_TO_POINTER (frame_num), - markers); - } - else - { - markers = g_slist_prepend (markers, marker); - g_hash_table_replace (priv->markers_by_frame, - GUINT_TO_POINTER (frame_num), - markers); - } -} - -/** - * clutter_timeline_add_marker_at_frame: - * @timeline: a #ClutterTimeline - * @marker_name: the unique name for this marker - * @frame_num: the marker's frame - * - * Adds a named marker at @frame_num. Markers are unique string identifiers - * for a specific frame. Once @timeline reaches @frame_num, it will emit - * a ::marker-reached signal for each marker attached to that frame. - * - * A marker can be removed with clutter_timeline_remove_marker(). The - * timeline can be advanced to a marker using - * clutter_timeline_advance_to_marker(). - * - * Since: 0.8 - */ -void -clutter_timeline_add_marker_at_frame (ClutterTimeline *timeline, - const gchar *marker_name, - guint frame_num) -{ - g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); - g_return_if_fail (marker_name != NULL); - g_return_if_fail (frame_num <= clutter_timeline_get_n_frames (timeline)); - - clutter_timeline_add_marker_internal (timeline, marker_name, frame_num); } /** @@ -1580,9 +1214,15 @@ clutter_timeline_add_marker_at_frame (ClutterTimeline *timeline, * @marker_name: the unique name for this marker * @msecs: position of the marker in milliseconds * - * Time-based variant of clutter_timeline_add_marker_at_frame(). + * Adds a named marker that will be hit when the timeline has been + * running for @msecs milliseconds. Markers are unique string + * identifiers for a given time. Once @timeline reaches + * @msecs, it will emit a ::marker-reached signal for each marker + * attached to that time. * - * Adds a named marker at @msecs. + * A marker can be removed with clutter_timeline_remove_marker(). The + * timeline can be advanced to a marker using + * clutter_timeline_advance_to_marker(). * * Since: 0.8 */ @@ -1591,24 +1231,38 @@ clutter_timeline_add_marker_at_time (ClutterTimeline *timeline, const gchar *marker_name, guint msecs) { - guint frame_num; - g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); g_return_if_fail (marker_name != NULL); g_return_if_fail (msecs <= clutter_timeline_get_duration (timeline)); - frame_num = msecs * timeline->priv->fps / 1000; + clutter_timeline_add_marker_internal (timeline, marker_name, msecs); +} - clutter_timeline_add_marker_internal (timeline, marker_name, frame_num); +struct CollectMarkersClosure +{ + guint msecs; + GArray *markers; +}; + +static void +collect_markers (const gchar *key, + TimelineMarker *marker, + struct CollectMarkersClosure *data) +{ + if (marker->msecs == data->msecs) + { + gchar *name_copy = g_strdup (key); + g_array_append_val (data->markers, name_copy); + } } /** * clutter_timeline_list_markers: * @timeline: a #ClutterTimeline - * @frame_num: the frame number to check, or -1 + * @msecs: the time to check, or -1 * @n_markers: the number of markers returned * - * Retrieves the list of markers at @frame_num. If @frame_num is a + * Retrieves the list of markers at time @msecs. If @frame_num is a * negative integer, all the markers attached to @timeline will be * returned. * @@ -1620,7 +1274,7 @@ clutter_timeline_add_marker_at_time (ClutterTimeline *timeline, */ gchar ** clutter_timeline_list_markers (ClutterTimeline *timeline, - gint frame_num, + gint msecs, gsize *n_markers) { ClutterTimelinePrivate *priv; @@ -1631,8 +1285,7 @@ clutter_timeline_list_markers (ClutterTimeline *timeline, priv = timeline->priv; - if (G_UNLIKELY (priv->markers_by_name == NULL || - priv->markers_by_frame == NULL)) + if (G_UNLIKELY (priv->markers_by_name == NULL)) { if (n_markers) *n_markers = 0; @@ -1640,7 +1293,7 @@ clutter_timeline_list_markers (ClutterTimeline *timeline, return NULL; } - if (frame_num < 0) + if (msecs < 0) { GList *markers, *l; @@ -1654,14 +1307,17 @@ clutter_timeline_list_markers (ClutterTimeline *timeline, } else { - GSList *markers, *l; + struct CollectMarkersClosure data; - markers = g_hash_table_lookup (priv->markers_by_frame, - GUINT_TO_POINTER (frame_num)); - retval = g_new0 (gchar*, g_slist_length (markers) + 1); + data.msecs = msecs; + data.markers = g_array_new (TRUE, FALSE, sizeof (gchar *)); - for (i = 0, l = markers; l != NULL; i++, l = l->next) - retval[i] = g_strdup (((TimelineMarker *) l->data)->name); + g_hash_table_foreach (priv->markers_by_name, + (GHFunc) collect_markers, + &data); + + i = data.markers->len; + retval = (gchar **) g_array_free (data.markers, FALSE); } if (n_markers) @@ -1675,10 +1331,10 @@ clutter_timeline_list_markers (ClutterTimeline *timeline, * @timeline: a #ClutterTimeline * @marker_name: the name of the marker * - * Advances @timeline to the frame of the given @marker_name. + * Advances @timeline to the time of the given @marker_name. * * Like clutter_timeline_advance(), this function will not - * emit the #ClutterTimeline::new-frame for the frame where @marker_name + * emit the #ClutterTimeline::new-frame for the time where @marker_name * is set, nor it will emit #ClutterTimeline::marker-reached for * @marker_name. * @@ -1696,8 +1352,7 @@ clutter_timeline_advance_to_marker (ClutterTimeline *timeline, priv = timeline->priv; - if (G_UNLIKELY (priv->markers_by_name == NULL || - priv->markers_by_frame == NULL)) + if (G_UNLIKELY (priv->markers_by_name == NULL)) { g_warning ("No marker named '%s' found.", marker_name); return; @@ -1710,7 +1365,7 @@ clutter_timeline_advance_to_marker (ClutterTimeline *timeline, return; } - clutter_timeline_advance (timeline, marker->frame_num); + clutter_timeline_advance (timeline, marker->msecs); } /** @@ -1728,15 +1383,13 @@ clutter_timeline_remove_marker (ClutterTimeline *timeline, { ClutterTimelinePrivate *priv; TimelineMarker *marker; - GSList *markers; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); g_return_if_fail (marker_name != NULL); priv = timeline->priv; - if (G_UNLIKELY (priv->markers_by_name == NULL || - priv->markers_by_frame == NULL)) + if (G_UNLIKELY (priv->markers_by_name == NULL)) { g_warning ("No marker named '%s' found.", marker_name); return; @@ -1749,31 +1402,6 @@ clutter_timeline_remove_marker (ClutterTimeline *timeline, return; } - /* remove from the list of markers at the same frame */ - markers = g_hash_table_lookup (priv->markers_by_frame, - GUINT_TO_POINTER (marker->frame_num)); - if (G_LIKELY (markers)) - { - markers = g_slist_remove (markers, marker); - if (!markers) - { - /* no markers left, remove the slot */ - g_hash_table_remove (priv->markers_by_frame, - GUINT_TO_POINTER (marker->frame_num)); - } - else - g_hash_table_replace (priv->markers_by_frame, - GUINT_TO_POINTER (marker->frame_num), - markers); - } - else - { - /* uh-oh, dangling marker; this should never happen */ - g_warning ("Dangling marker %s at frame %d", - marker->name, - marker->frame_num); - } - /* this will take care of freeing the marker as well */ g_hash_table_remove (priv->markers_by_name, marker_name); } @@ -1796,8 +1424,7 @@ clutter_timeline_has_marker (ClutterTimeline *timeline, g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), FALSE); g_return_val_if_fail (marker_name != NULL, FALSE); - if (G_UNLIKELY (timeline->priv->markers_by_name == NULL || - timeline->priv->markers_by_frame == NULL)) + if (G_UNLIKELY (timeline->priv->markers_by_name == NULL)) return FALSE; return NULL != g_hash_table_lookup (timeline->priv->markers_by_name, diff --git a/clutter/clutter-timeline.h b/clutter/clutter-timeline.h index bd8a90151..3b372408f 100644 --- a/clutter/clutter-timeline.h +++ b/clutter/clutter-timeline.h @@ -112,17 +112,12 @@ struct _ClutterTimelineClass GType clutter_timeline_get_type (void) G_GNUC_CONST; -ClutterTimeline *clutter_timeline_new (guint n_frames, - guint fps); -ClutterTimeline *clutter_timeline_new_for_duration (guint msecs); +ClutterTimeline *clutter_timeline_new (guint msecs); ClutterTimeline *clutter_timeline_clone (ClutterTimeline *timeline); guint clutter_timeline_get_duration (ClutterTimeline *timeline); void clutter_timeline_set_duration (ClutterTimeline *timeline, guint msecs); -guint clutter_timeline_get_speed (ClutterTimeline *timeline); -void clutter_timeline_set_speed (ClutterTimeline *timeline, - guint fps); ClutterTimelineDirection clutter_timeline_get_direction (ClutterTimeline *timeline); void clutter_timeline_set_direction (ClutterTimeline *timeline, ClutterTimelineDirection direction); @@ -134,38 +129,35 @@ void clutter_timeline_set_loop (ClutterTimeline *timeli gboolean clutter_timeline_get_loop (ClutterTimeline *timeline); void clutter_timeline_rewind (ClutterTimeline *timeline); void clutter_timeline_skip (ClutterTimeline *timeline, - guint n_frames); + guint msecs); void clutter_timeline_advance (ClutterTimeline *timeline, - guint frame_num); -gint clutter_timeline_get_current_frame (ClutterTimeline *timeline); + guint msecs); +guint clutter_timeline_get_elapsed_time (ClutterTimeline *timeline); gdouble clutter_timeline_get_progress (ClutterTimeline *timeline); CoglFixed clutter_timeline_get_progressx (ClutterTimeline *timeline); -void clutter_timeline_set_n_frames (ClutterTimeline *timeline, - guint n_frames); -guint clutter_timeline_get_n_frames (ClutterTimeline *timeline); gboolean clutter_timeline_is_playing (ClutterTimeline *timeline); void clutter_timeline_set_delay (ClutterTimeline *timeline, guint msecs); guint clutter_timeline_get_delay (ClutterTimeline *timeline); -guint clutter_timeline_get_delta (ClutterTimeline *timeline, - guint *msecs); +guint clutter_timeline_get_delta (ClutterTimeline *timeline); -void clutter_timeline_add_marker_at_frame (ClutterTimeline *timeline, - const gchar *marker_name, - guint frame_num); void clutter_timeline_add_marker_at_time (ClutterTimeline *timeline, const gchar *marker_name, guint msecs); void clutter_timeline_remove_marker (ClutterTimeline *timeline, const gchar *marker_name); gchar ** clutter_timeline_list_markers (ClutterTimeline *timeline, - gint frame_num, + gint msecs, gsize *n_markers) G_GNUC_MALLOC; gboolean clutter_timeline_has_marker (ClutterTimeline *timeline, const gchar *marker_name); void clutter_timeline_advance_to_marker (ClutterTimeline *timeline, const gchar *marker_name); +/*< private >*/ +void clutter_timeline_advance_delta (ClutterTimeline *timeline, + guint msecs); + G_END_DECLS #endif /* _CLUTTER_TIMELINE_H__ */ diff --git a/clutter/clutter-types.h b/clutter/clutter-types.h index 1d9ba450b..88921ad95 100644 --- a/clutter/clutter-types.h +++ b/clutter/clutter-types.h @@ -106,15 +106,15 @@ GType clutter_geometry_get_type (void) G_GNUC_CONST; * @y: Y coordinate of the vertex * @z: Z coordinate of the vertex * - * Vertex of an actor in 3D space, expressed in device independent units. + * Vertex of an actor in 3D space, expressed in pixels * * Since: 0.4 */ struct _ClutterVertex { - ClutterUnit x; - ClutterUnit y; - ClutterUnit z; + gfloat x; + gfloat y; + gfloat z; }; GType clutter_vertex_get_type (void) G_GNUC_CONST; diff --git a/clutter/clutter-units.c b/clutter/clutter-units.c index 1263886b3..97b2d9a05 100644 --- a/clutter/clutter-units.c +++ b/clutter/clutter-units.c @@ -27,68 +27,39 @@ /** * SECTION:clutter-units - * @short_description: A logical distance unit. + * @short_description: A logical distance unit * - * Clutter units are logical units with granularity greater than that of the - * device units; they are used by #ClutterActorBox and the units-based family - * of #ClutterActor functions. To convert between Clutter units and device - * units, use %CLUTTER_UNITS_FROM_DEVICE and %CLUTTER_UNITS_TO_DEVICE macros. + * #ClutterUnits is a structure holding a logical distance value along with + * its type, expressed as a value of the #ClutterUnitType enumeration. It is + * possible to use #ClutterUnits to store a position or a size in units + * different than pixels, and convert them whenever needed (for instance + * inside the #ClutterActor::allocate() virtual function, or inside the + * #ClutterActor::get_preferred_width() and #ClutterActor::get_preferred_height() + * virtual functions. * - * #ClutterUnits can be converted from other units like millimeters, - * typographic points (at the current resolution) and percentages. It is - * also possible to convert fixed point values to and from #ClutterUnit - * values. - * - * In order to register a #ClutterUnit property, the #ClutterParamSpecUnit + * In order to register a #ClutterUnits property, the #ClutterParamSpecUnits * #GParamSpec sub-class should be used: * * |[ * GParamSpec *pspec; * - * pspec = clutter_param_spec_unit ("width", - * "Width", - * "Width of the actor, in units", - * 0, CLUTTER_MAXUNIT, - * 0, - * G_PARAM_READWRITE); + * pspec = clutter_param_spec_units ("active-width", + * "Width", + * "Width of the active area, in millimeters", + * CLUTTER_UNIT_MM, + * 0.0, 12.0, + * 12.0, + * G_PARAM_READWRITE); * g_object_class_install_property (gobject_class, PROP_WIDTH, pspec); * ]| * - * A #GValue holding units can be manipulated using clutter_value_set_unit() - * and clutter_value_get_unit(). #GValues containing a #ClutterUnit - * value can also be transformed to #GValues containing integer - * values - with a loss of precision: + * A #GValue holding units can be manipulated using clutter_value_set_units() + * and clutter_value_get_units(). #GValues containing a #ClutterUnits + * value can also be transformed to #GValues initialized with + * %G_TYPE_INT, %G_TYPE_FLOAT and %G_TYPE_STRING through implicit conversion + * and using g_value_transform(). * - * |[ - * static gboolean - * units_to_int (const GValue *src, - * GValue *dest) - * { - * g_return_val_if_fail (CLUTTER_VALUE_HOLDS_UNIT (src), FALSE); - * - * g_value_init (dest, G_TYPE_INT); - * return g_value_transform (src, &dest); - * } - * ]| - * - * The code above is equivalent to: - * - * |[ - * static gboolean - * units_to_int (const GValue *src, - * GValue *dest) - * { - * g_return_val_if_fail (CLUTTER_VALUE_HOLDS_UNIT (src), FALSE); - * - * g_value_init (dest, G_TYPE_INT); - * g_value_set_int (dest, - * CLUTTER_UNITS_TO_INT (clutter_value_get_unit (src))); - * - * return TRUE; - * } - * ]| - * - * #ClutterUnit is available since Clutter 0.4 + * #ClutterUnits is available since Clutter 1.0 */ #ifdef HAVE_CONFIG_H @@ -105,19 +76,8 @@ #define FLOAT_EPSILON (1e-30) -/** - * clutter_units_mm: - * @mm: millimeters to convert - * - * Converts a value in millimeters to #ClutterUnits at - * the current DPI. - * - * Return value: the value in units - * - * Since: 1.0 - */ -ClutterUnit -clutter_units_mm (gdouble mm) +static gfloat +units_mm_to_pixels (gfloat mm) { ClutterBackend *backend; gdouble dpi; @@ -130,19 +90,8 @@ clutter_units_mm (gdouble mm) return mm * dpi / 25.4; } -/** - * clutter_units_pt: - * @pt: typographic points to convert - * - * Converts a value in typographic points to #ClutterUnits - * at the current DPI. - * - * Return value: the value in units - * - * Since: 1.0 - */ -ClutterUnit -clutter_units_pt (gdouble pt) +static gfloat +units_pt_to_pixels (gfloat pt) { ClutterBackend *backend; gdouble dpi; @@ -155,41 +104,213 @@ clutter_units_pt (gdouble pt) return pt * dpi / 72.0; } +static gfloat +units_em_to_pixels (const gchar *font_name, + gfloat em) +{ + ClutterBackend *backend = clutter_get_default_backend (); + + if (font_name == NULL || *font_name == '\0') + return em * _clutter_backend_get_units_per_em (backend, NULL); + else + { + PangoFontDescription *font_desc; + gfloat res; + + font_desc = pango_font_description_from_string (font_name); + if (font_desc == NULL) + res = -1.0; + else + { + res = em * _clutter_backend_get_units_per_em (backend, font_desc); + + pango_font_description_free (font_desc); + } + + return res; + } +} + /** - * clutter_units_em: - * @em: em to convert + * clutter_units_mm: + * @units: a #ClutterUnits + * @mm: millimeters * - * Converts a value in em to #ClutterUnits at the - * current DPI - * - * Return value: the value in units + * Stores a value in millimiters inside @units * * Since: 1.0 */ -ClutterUnit -clutter_units_em (gdouble em) +void +clutter_units_mm (ClutterUnits *units, + gfloat mm) { - ClutterBackend *backend; + g_return_if_fail (units != NULL); - backend = clutter_get_default_backend (); + units->unit_type = CLUTTER_UNIT_MM; + units->value = mm; + units->pixels = units_mm_to_pixels (mm); + units->pixels_set = TRUE; +} - return em * _clutter_backend_get_units_per_em (backend); +/** + * clutter_units_pt: + * @units: a #ClutterUnits + * @pt: typographic points + * + * Stores a value in typographic points inside @units + * + * Since: 1.0 + */ +void +clutter_units_pt (ClutterUnits *units, + gfloat pt) +{ + g_return_if_fail (units != NULL); + + units->unit_type = CLUTTER_UNIT_POINT; + units->value = pt; + units->pixels = units_pt_to_pixels (pt); + units->pixels_set = TRUE; +} + +/** + * clutter_units_em: + * @units: a #ClutterUnits + * @em: em + * + * Stores a value in em inside @units, using the default font + * name as returned by clutter_backend_get_font_name() + * + * Since: 1.0 + */ +void +clutter_units_em (ClutterUnits *units, + gfloat em) +{ + g_return_if_fail (units != NULL); + + units->unit_type = CLUTTER_UNIT_EM; + units->value = em; + units->pixels = units_em_to_pixels (NULL, em); + units->pixels_set = TRUE; +} + +/** + * clutter_units_em_for_font: + * @units: a #ClutterUnits + * @font_name: the font name and size + * @em: em + * + * Stores a value in em inside @units using @font_name + * + * Since: 1.0 + */ +void +clutter_units_em_for_font (ClutterUnits *units, + const gchar *font_name, + gfloat em) +{ + g_return_if_fail (units != NULL); + + units->unit_type = CLUTTER_UNIT_EM; + units->value = em; + units->pixels = units_em_to_pixels (font_name, em); + units->pixels_set = TRUE; } /** * clutter_units_pixels: - * @px: pixels to convert + * @units: a #ClutterUnits + * @px: pixels * - * Converts a value in pixels to #ClutterUnits - * - * Return value: the value in units + * Stores a value in pixels inside @units * * Since: 1.0 */ -ClutterUnit -clutter_units_pixels (gint px) +void +clutter_units_pixels (ClutterUnits *units, + gint px) { - return CLUTTER_UNITS_FROM_INT (px); + g_return_if_fail (units != NULL); + + units->unit_type = CLUTTER_UNIT_PIXEL; + units->value = px; + units->pixels = px; + units->pixels_set = TRUE; +} + +/** + * clutter_units_get_unit_type: + * @units: a #ClutterUnits + * + * Retrieves the unit type of the value stored inside @units + * + * Return value: a unit type + * + * Since: 1.0 + */ +ClutterUnitType +clutter_units_get_unit_type (const ClutterUnits *units) +{ + g_return_val_if_fail (units != NULL, CLUTTER_UNIT_PIXEL); + + return units->unit_type; +} + +/** + * clutter_units_get_unit_value: + * @units: a #ClutterUnits + * + * Retrieves the value stored inside @units + * + * Return value: the value stored inside a #ClutterUnits + * + * Since: 1.0 + */ +gfloat +clutter_units_get_unit_value (const ClutterUnits *units) +{ + g_return_val_if_fail (units != NULL, 0.0); + + return units->value; +} + +/** + * clutter_units_copy: + * @units: the #ClutterUnits to copy + * + * Copies @units + * + * Return value: the newly created copy of a #ClutterUnits structure. + * Use clutter_units_free() to free the allocated resources + * + * Since: 1.0 + */ +ClutterUnits * +clutter_units_copy (const ClutterUnits *units) +{ + if (units != NULL) + return g_slice_dup (ClutterUnits, units); + + return NULL; +} + +/** + * clutter_units_free: + * @units: the #ClutterUnits to free + * + * Frees the resources allocated by @units + * + * You should only call this function on a #ClutterUnits + * created using clutter_units_copy() + * + * Since: 1.0 + */ +void +clutter_units_free (ClutterUnits *units) +{ + if (units != NULL) + g_slice_free (ClutterUnits, units); } /** @@ -202,156 +323,294 @@ clutter_units_pixels (gint px) * * Since: 1.0 */ -gint -clutter_units_to_pixels (ClutterUnit units) +gfloat +clutter_units_to_pixels (ClutterUnits *units) { - return CLUTTER_UNITS_TO_INT (units); + g_return_val_if_fail (units != NULL, 0.0); + + if (units->pixels_set) + return units->pixels; + + switch (units->unit_type) + { + case CLUTTER_UNIT_MM: + units->pixels = units_mm_to_pixels (units->value); + break; + + case CLUTTER_UNIT_POINT: + units->pixels = units_pt_to_pixels (units->value); + break; + + case CLUTTER_UNIT_EM: + units->pixels = units_em_to_pixels (NULL, units->value); + break; + + case CLUTTER_UNIT_PIXEL: + units->pixels = units->value; + break; + } + + units->pixels_set = TRUE; + + return units->pixels; +} + +/** + * clutter_units_from_string: + * @units: a #ClutterUnits + * @str: the string to convert + * + * Parses a value and updates @units with it + * + * A #ClutterUnits expressed in string should match: + * + * |[ + * number: [0-9] + * unit_value: + + * unit_name: px|pt|mm|em + * units: + * ]| + * + * For instance, these are valid strings: + * + * |[ + * 10 px + * 5 em + * 24 pt + * 12.6 mm + * ]| + * + * Return value: %TRUE if the string was successfully parsed + * + * Since: 1.0 + */ +gboolean +clutter_units_from_string (ClutterUnits *units, + const gchar *str) +{ + ClutterUnitType unit_type; + gfloat value; + + g_return_val_if_fail (units != NULL, FALSE); + g_return_val_if_fail (str != NULL, FALSE); + + /* Ensure that the first character is a digit */ + while (g_ascii_isspace (*str)) + str++; + + if (*str == '\0') + return FALSE; + + if (!g_ascii_isdigit (*str)) + return FALSE; + + /* integer part */ + value = (gfloat) strtoul (str, (char **) &str, 10); + + if (*str == '.' || *str == ',') + { + glong frac = 100000; + + while (g_ascii_isdigit (*++str)) + { + frac += (*str - '0') * frac; + frac /= 10; + } + + value += (1.0f / (gfloat) frac); + } + + /* assume pixels by default, if no unit is specified */ + if (str == '\0') + unit_type = CLUTTER_UNIT_PIXEL; + else + { + while (g_ascii_isspace (*str)) + str++; + + if (strncmp (str, "em", 2) == 0) + unit_type = CLUTTER_UNIT_EM; + else if (strncmp (str, "mm", 2) == 0) + unit_type = CLUTTER_UNIT_MM; + else if (strncmp (str, "pt", 2) == 0) + unit_type = CLUTTER_UNIT_POINT; + else if (strncmp (str, "px", 2) == 0) + unit_type = CLUTTER_UNIT_PIXEL; + else + return FALSE; + } + + units->unit_type = unit_type; + units->value = value; + units->pixels_set = FALSE; + + return TRUE; +} + +static const gchar * +clutter_unit_type_name (ClutterUnitType unit_type) +{ + switch (unit_type) + { + case CLUTTER_UNIT_MM: + return "mm"; + + case CLUTTER_UNIT_POINT: + return "pt"; + + case CLUTTER_UNIT_EM: + return "em"; + + case CLUTTER_UNIT_PIXEL: + return "px"; + } + + g_warning ("Invalid unit type %d", (int) unit_type); + + return ""; +} + +/** + * clutter_units_to_string: + * @units: a #ClutterUnits + * + * Converts @units into a string + * + * See clutter_units_from_string() for the units syntax and for + * examples of outputs + * + * Return value: a newly allocated string containing the encoded + * #ClutterUnits value. Use g_free() to free the string + * + * Since: 1.0 + */ +gchar * +clutter_units_to_string (const ClutterUnits *units) +{ + const gchar *unit_name; + gchar *fmt; + + g_return_val_if_fail (units != NULL, NULL); + + switch (units->unit_type) + { + case CLUTTER_UNIT_MM: + unit_name = "mm"; + fmt = g_strdup_printf ("%.2f", units->value); + break; + + case CLUTTER_UNIT_POINT: + unit_name = "pt"; + fmt = g_strdup_printf ("%.1f", units->value); + break; + + case CLUTTER_UNIT_EM: + unit_name = "em"; + fmt = g_strdup_printf ("%.2f", units->value); + break; + + case CLUTTER_UNIT_PIXEL: + unit_name = "px"; + fmt = g_strdup_printf ("%d", (int) units->value); + break; + } + + return g_strconcat (fmt, " ", unit_name, NULL); } /* * GValue and GParamSpec integration */ -static GTypeInfo _info = { - 0, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - 0, - NULL, - NULL, -}; - -static GTypeFundamentalInfo _finfo = { 0, }; - +/* units to integer */ static void -clutter_value_init_unit (GValue *value) +clutter_value_transform_units_int (const GValue *src, + GValue *dest) { - value->data[0].v_float = 0.0; + dest->data[0].v_int = clutter_units_to_pixels (src->data[0].v_pointer); } +/* integer to units */ static void -clutter_value_copy_unit (const GValue *src, - GValue *dest) +clutter_value_transform_int_units (const GValue *src, + GValue *dest) { - dest->data[0].v_float = src->data[0].v_float; -} - -static gchar * -clutter_value_collect_unit (GValue *value, - guint n_collect_values, - GTypeCValue *collect_values, - guint collect_flags) -{ - value->data[0].v_float = collect_values[0].v_double; - - return NULL; -} - -static gchar * -clutter_value_lcopy_unit (const GValue *value, - guint n_collect_values, - GTypeCValue *collect_values, - guint collect_flags) -{ - gfloat *units_p = collect_values[0].v_pointer; - - if (!units_p) - return g_strdup_printf ("value location for '%s' passed as NULL", - G_VALUE_TYPE_NAME (value)); - - *units_p = value->data[0].v_float; - - return NULL; + clutter_units_pixels (dest->data[0].v_pointer, src->data[0].v_int); } +/* units to float */ static void -clutter_value_transform_unit_int (const GValue *src, - GValue *dest) +clutter_value_transform_units_float (const GValue *src, + GValue *dest) { - dest->data[0].v_int = CLUTTER_UNITS_TO_INT (src->data[0].v_float); + dest->data[0].v_float = clutter_units_to_pixels (src->data[0].v_pointer); } +/* float to units */ static void -clutter_value_transform_int_unit (const GValue *src, - GValue *dest) +clutter_value_transform_float_units (const GValue *src, + GValue *dest) { - dest->data[0].v_float = CLUTTER_UNITS_FROM_INT (src->data[0].v_int); + clutter_units_pixels (dest->data[0].v_pointer, src->data[0].v_float); } +/* units to string */ static void -clutter_value_transform_unit_float (const GValue *src, - GValue *dest) +clutter_value_transform_units_string (const GValue *src, + GValue *dest) { - dest->data[0].v_float = CLUTTER_UNITS_TO_FLOAT (src->data[0].v_float); + gchar *string = clutter_units_to_string (src->data[0].v_pointer); + + g_value_take_string (dest, string); } +/* string to units */ static void -clutter_value_transform_float_unit (const GValue *src, - GValue *dest) +clutter_value_transform_string_units (const GValue *src, + GValue *dest) { - dest->data[0].v_float = CLUTTER_UNITS_FROM_FLOAT (src->data[0].v_float); -} + ClutterUnits units = { CLUTTER_UNIT_PIXEL, 0.0f }; -#if 0 -static void -clutter_value_transform_unit_fixed (const GValue *src, - GValue *dest) -{ - dest->data[0].v_int = CLUTTER_UNITS_TO_FIXED (src->data[0].v_float); -} + clutter_units_from_string (&units, g_value_get_string (src)); -static void -clutter_value_transform_fixed_unit (const GValue *src, - GValue *dest) -{ - dest->data[0].v_float = CLUTTER_UNITS_FROM_FIXED (src->data[0].v_int); + clutter_value_set_units (dest, &units); } -#endif - -static const GTypeValueTable _clutter_unit_value_table = { - clutter_value_init_unit, - NULL, - clutter_value_copy_unit, - NULL, - "d", - clutter_value_collect_unit, - "p", - clutter_value_lcopy_unit -}; GType -clutter_unit_get_type (void) +clutter_units_get_type (void) { - static GType _clutter_unit_type = 0; + static volatile gsize clutter_units_type__volatile = 0; - if (G_UNLIKELY (_clutter_unit_type == 0)) + if (g_once_init_enter (&clutter_units_type__volatile)) { - _info.value_table = & _clutter_unit_value_table; - _clutter_unit_type = - g_type_register_fundamental (g_type_fundamental_next (), - I_("ClutterUnit"), - &_info, &_finfo, 0); + GType clutter_units_type = + g_boxed_type_register_static (I_("ClutterUnits"), + (GBoxedCopyFunc) clutter_units_copy, + (GBoxedFreeFunc) clutter_units_free); - g_value_register_transform_func (_clutter_unit_type, G_TYPE_INT, - clutter_value_transform_unit_int); - g_value_register_transform_func (G_TYPE_INT, _clutter_unit_type, - clutter_value_transform_int_unit); + g_value_register_transform_func (clutter_units_type, G_TYPE_INT, + clutter_value_transform_units_int); + g_value_register_transform_func (G_TYPE_INT, clutter_units_type, + clutter_value_transform_int_units); - g_value_register_transform_func (_clutter_unit_type, G_TYPE_FLOAT, - clutter_value_transform_unit_float); - g_value_register_transform_func (G_TYPE_FLOAT, _clutter_unit_type, - clutter_value_transform_float_unit); + g_value_register_transform_func (clutter_units_type, G_TYPE_FLOAT, + clutter_value_transform_units_float); + g_value_register_transform_func (G_TYPE_FLOAT, clutter_units_type, + clutter_value_transform_float_units); + + g_value_register_transform_func (clutter_units_type, G_TYPE_STRING, + clutter_value_transform_units_string); + g_value_register_transform_func (G_TYPE_STRING, clutter_units_type, + clutter_value_transform_string_units); + + g_once_init_leave (&clutter_units_type__volatile, clutter_units_type); } - return _clutter_unit_type; + return clutter_units_type__volatile; } /** - * clutter_value_set_unit: + * clutter_value_set_units: * @value: a #GValue initialized to #CLUTTER_TYPE_UNIT * @units: the units to set * @@ -360,16 +619,16 @@ clutter_unit_get_type (void) * Since: 0.8 */ void -clutter_value_set_unit (GValue *value, - ClutterUnit units) +clutter_value_set_units (GValue *value, + const ClutterUnits *units) { - g_return_if_fail (CLUTTER_VALUE_HOLDS_UNIT (value)); + g_return_if_fail (CLUTTER_VALUE_HOLDS_UNITS (value)); - value->data[0].v_float = units; + value->data[0].v_pointer = clutter_units_copy (units); } /** - * clutter_value_get_unit: + * clutter_value_get_units: * @value: a #GValue initialized to #CLUTTER_TYPE_UNIT * * Gets the #ClutterUnits contained in @value. @@ -378,76 +637,113 @@ clutter_value_set_unit (GValue *value, * * Since: 0.8 */ -ClutterUnit +G_CONST_RETURN ClutterUnits * clutter_value_get_unit (const GValue *value) { - g_return_val_if_fail (CLUTTER_VALUE_HOLDS_UNIT (value), 0); + g_return_val_if_fail (CLUTTER_VALUE_HOLDS_UNITS (value), NULL); - return value->data[0].v_float; + return value->data[0].v_pointer; } static void -param_unit_init (GParamSpec *pspec) +param_units_init (GParamSpec *pspec) { - ClutterParamSpecUnit *uspec = CLUTTER_PARAM_SPEC_UNIT (pspec); + ClutterParamSpecUnits *uspec = CLUTTER_PARAM_SPEC_UNITS (pspec); - uspec->minimum = CLUTTER_MINUNIT; - uspec->maximum = CLUTTER_MAXUNIT; - uspec->default_value = 0; + uspec->minimum = -G_MAXFLOAT; + uspec->maximum = G_MAXFLOAT; + uspec->default_value = 0.0f; + uspec->default_type = CLUTTER_UNIT_PIXEL; } static void -param_unit_set_default (GParamSpec *pspec, - GValue *value) +param_units_set_default (GParamSpec *pspec, + GValue *value) { - value->data[0].v_float = CLUTTER_PARAM_SPEC_UNIT (pspec)->default_value; + ClutterParamSpecUnits *uspec = CLUTTER_PARAM_SPEC_UNITS (pspec); + ClutterUnits units; + + units.unit_type = uspec->default_type; + units.value = uspec->default_value; + units.pixels_set = FALSE; + + clutter_value_set_units (value, &units); } static gboolean -param_unit_validate (GParamSpec *pspec, - GValue *value) +param_units_validate (GParamSpec *pspec, + GValue *value) { - ClutterParamSpecUnit *uspec = CLUTTER_PARAM_SPEC_UNIT (pspec); - gfloat oval = value->data[0].v_float; + ClutterParamSpecUnits *uspec = CLUTTER_PARAM_SPEC_UNITS (pspec); + ClutterUnits *units = value->data[0].v_pointer; + ClutterUnitType otype = units->unit_type; + gfloat oval = units->value; - g_assert (CLUTTER_IS_PARAM_SPEC_UNIT (pspec)); + g_assert (CLUTTER_IS_PARAM_SPEC_UNITS (pspec)); - value->data[0].v_float = CLAMP (value->data[0].v_float, - uspec->minimum, - uspec->maximum); + if (otype != uspec->default_type) + { + gchar *str = clutter_units_to_string (units); - return value->data[0].v_float != oval; + g_warning ("The units value of '%s' does not have the same unit " + "type as declared by the ClutterParamSpecUnits of '%s'", + str, + clutter_unit_type_name (otype)); + + g_free (str); + + return FALSE; + } + + units->value = CLAMP (units->value, + uspec->minimum, + uspec->maximum); + + return units->value != oval; } static gint -param_unit_values_cmp (GParamSpec *pspec, - const GValue *value1, - const GValue *value2) +param_units_values_cmp (GParamSpec *pspec, + const GValue *value1, + const GValue *value2) { - gfloat epsilon = FLOAT_EPSILON; + ClutterUnits *units1 = value1->data[0].v_pointer; + ClutterUnits *units2 = value2->data[0].v_pointer; + gfloat v1, v2; - if (value1->data[0].v_float < value2->data[0].v_float) - return - (value2->data[0].v_float - value1->data[0].v_float > epsilon); + if (units1->unit_type == units2->unit_type) + { + v1 = units1->value; + v2 = units2->value; + } else - return value1->data[0].v_float - value2->data[0].v_float > epsilon; + { + v1 = clutter_units_to_pixels (units1); + v2 = clutter_units_to_pixels (units2); + } + + if (v1 < v2) + return - (v2 - v1 > FLOAT_EPSILON); + else + return v1 - v2 > FLOAT_EPSILON; } GType -clutter_param_unit_get_type (void) +clutter_param_units_get_type (void) { static GType pspec_type = 0; if (G_UNLIKELY (pspec_type == 0)) { const GParamSpecTypeInfo pspec_info = { - sizeof (ClutterParamSpecUnit), + sizeof (ClutterParamSpecUnits), 16, - param_unit_init, - CLUTTER_TYPE_UNIT, + param_units_init, + CLUTTER_TYPE_UNITS, NULL, - param_unit_set_default, - param_unit_validate, - param_unit_values_cmp, + param_units_set_default, + param_units_validate, + param_units_values_cmp, }; pspec_type = g_param_type_register_static (I_("ClutterParamSpecUnit"), @@ -458,38 +754,42 @@ clutter_param_unit_get_type (void) } /** - * clutter_param_spec_unit: + * clutter_param_spec_units: * @name: name of the property * @nick: short name * @blurb: description (can be translatable) + * @default_type: the default type for the #ClutterUnits * @minimum: lower boundary * @maximum: higher boundary * @default_value: default value * @flags: flags for the param spec * - * Creates a #GParamSpec for properties using #ClutterUnits. + * Creates a #GParamSpec for properties using #ClutterUnits. * * Return value: the newly created #GParamSpec * - * Since: 0.8 + * Since: 1.0 */ GParamSpec * -clutter_param_spec_unit (const gchar *name, - const gchar *nick, - const gchar *blurb, - ClutterUnit minimum, - ClutterUnit maximum, - ClutterUnit default_value, - GParamFlags flags) +clutter_param_spec_units (const gchar *name, + const gchar *nick, + const gchar *blurb, + ClutterUnitType default_type, + gfloat minimum, + gfloat maximum, + gfloat default_value, + GParamFlags flags) { - ClutterParamSpecUnit *uspec; + ClutterParamSpecUnits *uspec; g_return_val_if_fail (default_value >= minimum && default_value <= maximum, NULL); - uspec = g_param_spec_internal (CLUTTER_TYPE_PARAM_UNIT, + uspec = g_param_spec_internal (CLUTTER_TYPE_PARAM_UNITS, name, nick, blurb, flags); + + uspec->default_type = default_type; uspec->minimum = minimum; uspec->maximum = maximum; uspec->default_value = default_value; diff --git a/clutter/clutter-units.h b/clutter/clutter-units.h index c2db312eb..873f78410 100644 --- a/clutter/clutter-units.h +++ b/clutter/clutter-units.h @@ -25,250 +25,144 @@ */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) -#error "Only can be included directly.h" +#error "Only can be included directly." #endif #ifndef __CLUTTER_UNITS_H__ #define __CLUTTER_UNITS_H__ #include -#include + +#include G_BEGIN_DECLS /** - * ClutterUnit: + * ClutterUnitType: + * @CLUTTER_UNIT_PIXEL: Unit expressed in pixels (with subpixel precision) + * @CLUTTER_UNIT_EM: Unit expressed in em + * @CLUTTER_UNIT_MM: Unit expressed in millimeters + * @CLUTTER_UNIT_POINT: Unit expressed in points * - * Device independent unit used by Clutter. The value held can be - * transformed into other units, likes pixels + * The type of unit in which a value is expressed * - * Since: 0.4 - */ -typedef float ClutterUnit; - -/** - * CLUTTER_UNITS_FROM_INT: - * @x: integer value - * - * Converts @x from an integer value to #ClutterUnits - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_FROM_INT(x) ((float)(x)) - -/** - * CLUTTER_UNITS_TO_INT: - * @x: value in #ClutterUnits - * - * Converts @x from a #ClutterUnit value into an integer - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_TO_INT(x) ((int)(x)) - -/** - * CLUTTER_UNITS_FROM_FLOAT: - * @x: float value - * - * Converts @x from a floating point value to #ClutterUnits - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_FROM_FLOAT(x) (x) - -/** - * CLUTTER_UNITS_TO_FLOAT: - * @x: value in #ClutterUnits - * - * Converts @x from a #ClutterUnit value into a float - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_TO_FLOAT(x) (x) - -/** - * CLUTTER_UNITS_FROM_FIXED: - * @x: #CoglFixed value - * - * Converts @x from a fixed point value to #ClutterUnits - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_FROM_FIXED(x) (COGL_FIXED_TO_FLOAT (x)) - -/** - * CLUTTER_UNITS_TO_FIXED: - * @x: value in #ClutterUnits - * - * Converts @x from a #ClutterUnit value into a #CoglFixed - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_TO_FIXED(x) (COGL_FIXED_FROM_FLOAT (x)) - -/** - * CLUTTER_UNITS_FORMAT: - * - * Format string that should be used for scanning and printing units. - * It is a string literal, but it does not include the percent sign to - * allow precision and length modifiers between the percent sign and - * the format: - * - * |[ - * g_print ("%" CLUTTER_UNITS_FORMAT, units); - * ]| + * This enumeration might be expanded at later date * * Since: 1.0 */ -#define CLUTTER_UNITS_FORMAT "f" +typedef enum { + CLUTTER_UNIT_PIXEL, + CLUTTER_UNIT_EM, + CLUTTER_UNIT_MM, + CLUTTER_UNIT_POINT +} ClutterUnitType; /** - * CLUTTER_UNITS_FROM_DEVICE: - * @x: value in pixels + * ClutterUnits: * - * Converts @x from pixels to #ClutterUnits - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_FROM_DEVICE(x) (clutter_units_pixels ((x))) - -/** - * CLUTTER_UNITS_TO_DEVICE: - * @x: value in #ClutterUnits - * - * Converts @x from #ClutterUnits to pixels - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_TO_DEVICE(x) (clutter_units_to_pixels ((x))) - -/** - * CLUTTER_UNITS_FROM_PANGO_UNIT: - * @x: value in Pango units - * - * Converts a value in Pango units to #ClutterUnits - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_FROM_PANGO_UNIT(x) ((float)((x) / 1024.0)) - -/** - * CLUTTER_UNITS_TO_PANGO_UNIT: - * @x: value in #ClutterUnits - * - * Converts a value in #ClutterUnits to Pango units - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_TO_PANGO_UNIT(x) ((int)((x) * 1024)) - -/** - * CLUTTER_UNITS_FROM_MM: - * @x: a value in millimeters - * - * Converts a value in millimeters into #ClutterUnits - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_FROM_MM(x) (clutter_units_mm (x)) - -/** - * CLUTTER_UNITS_FROM_POINTS: - * @x: a value in typographic points - * - * Converts a value in typographic points into #ClutterUnits - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_FROM_POINTS(x) (clutter_units_pt (x)) - -/** - * CLUTTER_UNITS_FROM_EM: - * @x: a value in em - * - * Converts a value in em into #ClutterUnits + * An opaque structure, to be used to store sizing and positioning + * values along with their unit. * * Since: 1.0 */ -#define CLUTTER_UNITS_FROM_EM(x) (clutter_units_em (x)) +typedef struct _ClutterUnits ClutterUnits; -ClutterUnit clutter_units_mm (gdouble mm); -ClutterUnit clutter_units_pt (gdouble pt); -ClutterUnit clutter_units_em (gdouble em); -ClutterUnit clutter_units_pixels (gint px); +struct _ClutterUnits +{ + /*< private >*/ + ClutterUnitType unit_type; -gint clutter_units_to_pixels (ClutterUnit units); + gfloat value; -#define CLUTTER_TYPE_UNIT (clutter_unit_get_type ()) -#define CLUTTER_TYPE_PARAM_UNIT (clutter_param_unit_get_type ()) -#define CLUTTER_PARAM_SPEC_UNIT(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), CLUTTER_TYPE_PARAM_UNIT, ClutterParamSpecUnit)) -#define CLUTTER_IS_PARAM_SPEC_UNIT(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), CLUTTER_TYPE_PARAM_UNIT)) + /* pre-filled by the provided constructors */ + gfloat pixels; + guint pixels_set; -/** - * CLUTTER_MAXUNIT: - * - * Higher boundary for a #ClutterUnit - * - * Since: 0.8 - */ -#define CLUTTER_MAXUNIT (G_MAXFLOAT) + /* padding for eventual expansion */ + gint64 __padding_1; + gint64 __padding_2; +}; -/** - * CLUTTER_MINUNIT: - * - * Lower boundary for a #ClutterUnit - * - * Since: 0.8 - */ -#define CLUTTER_MINUNIT (-G_MAXFLOAT) +GType clutter_units_get_type (void) G_GNUC_CONST; +ClutterUnitType clutter_units_get_unit_type (const ClutterUnits *units); +gfloat clutter_units_get_unit_value (const ClutterUnits *units); + +ClutterUnits * clutter_units_copy (const ClutterUnits *units); +void clutter_units_free (ClutterUnits *units); + +void clutter_units_pixels (ClutterUnits *units, + gint px); +void clutter_units_em (ClutterUnits *units, + gfloat em); +void clutter_units_em_for_font (ClutterUnits *units, + const gchar *font_name, + gfloat em); +void clutter_units_mm (ClutterUnits *units, + gfloat mm); +void clutter_units_pt (ClutterUnits *units, + gfloat pt); + +gfloat clutter_units_to_pixels (ClutterUnits *units); + +gchar * clutter_units_to_string (const ClutterUnits *units); +gboolean clutter_units_from_string (ClutterUnits *units, + const gchar *str); + +#define CLUTTER_TYPE_UNITS (clutter_units_get_type ()) +#define CLUTTER_TYPE_PARAM_UNITS (clutter_param_units_get_type ()) +#define CLUTTER_PARAM_SPEC_UNITS(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), CLUTTER_TYPE_PARAM_UNITS, ClutterParamSpecUnits)) +#define CLUTTER_IS_PARAM_SPEC_UNITS(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), CLUTTER_TYPE_PARAM_UNITS)) /** * CLUTTER_VALUE_HOLDS_UNIT: * @x: a #GValue * - * Evaluates to %TRUE if @x holds #ClutterUnits. + * Evaluates to %TRUE if @x holds a #ClutterUnits value * * Since: 0.8 */ -#define CLUTTER_VALUE_HOLDS_UNIT(x) (G_VALUE_HOLDS ((x), CLUTTER_TYPE_UNIT)) +#define CLUTTER_VALUE_HOLDS_UNITS(x) (G_VALUE_HOLDS ((x), CLUTTER_TYPE_UNITS)) -typedef struct _ClutterParamSpecUnit ClutterParamSpecUnit; +typedef struct _ClutterParamSpecUnits ClutterParamSpecUnits; /** - * ClutterParamSpecUnit: + * ClutterParamSpecUnits: + * @default_type: default type + * @default_value: default value * @minimum: lower boundary * @maximum: higher boundary - * @default_value: default value * * #GParamSpec subclass for unit based properties. * - * Since: 0.8 + * Since: 1.0 */ -struct _ClutterParamSpecUnit +struct _ClutterParamSpecUnits { /*< private >*/ - GParamSpec parent_instance; + GParamSpec parent_instance; /*< public >*/ - ClutterUnit minimum; - ClutterUnit maximum; - ClutterUnit default_value; + ClutterUnitType default_type; + + gfloat default_value; + gfloat minimum; + gfloat maximum; }; -GType clutter_unit_get_type (void) G_GNUC_CONST; -GType clutter_param_unit_get_type (void) G_GNUC_CONST; +GType clutter_param_units_get_type (void) G_GNUC_CONST; -void clutter_value_set_unit (GValue *value, - ClutterUnit units); -ClutterUnit clutter_value_get_unit (const GValue *value); +GParamSpec * clutter_param_spec_units (const gchar *name, + const gchar *nick, + const gchar *blurb, + ClutterUnitType default_type, + gfloat minimum, + gfloat maximum, + gfloat default_value, + GParamFlags flags); -GParamSpec *clutter_param_spec_unit (const gchar *name, - const gchar *nick, - const gchar *blurb, - ClutterUnit minimum, - ClutterUnit maximum, - ClutterUnit default_value, - GParamFlags flags); +void clutter_value_set_units (GValue *value, + const ClutterUnits *units); +G_CONST_RETURN ClutterUnits *clutter_value_get_units (const GValue *value); G_END_DECLS diff --git a/clutter/cogl/Makefile.am b/clutter/cogl/Makefile.am index 225b66100..cae798703 100644 --- a/clutter/cogl/Makefile.am +++ b/clutter/cogl/Makefile.am @@ -1,3 +1,9 @@ +NULL = + +V = @ +Q = $(V:1=) +QUIET_GEN = $(Q:@=@echo ' GEN '$@;) + SUBDIRS = common $(CLUTTER_COGL) BUILT_SOURCES = cogl.h @@ -23,29 +29,42 @@ CLEANFILES = $(pc_files) AM_CPPFLAGS = $(CLUTTER_CFLAGS) $(CLUTTER_DEBUG_CFLAGS) $(MAINTAINER_CFLAGS) +# COGL installed headers cogl_headers = \ - $(top_srcdir)/clutter/cogl/cogl-bitmap.h \ - $(top_srcdir)/clutter/cogl/cogl-color.h \ - $(top_srcdir)/clutter/cogl/cogl-debug.h \ - $(top_srcdir)/clutter/cogl/cogl-fixed.h \ - $(top_srcdir)/clutter/cogl/cogl-material.h \ - $(top_srcdir)/clutter/cogl/cogl-matrix.h \ - $(top_srcdir)/clutter/cogl/cogl-offscreen.h \ - $(top_srcdir)/clutter/cogl/cogl-path.h \ - $(top_srcdir)/clutter/cogl/cogl-shader.h \ - $(top_srcdir)/clutter/cogl/cogl-texture.h \ - $(top_srcdir)/clutter/cogl/cogl-types.h \ - $(top_srcdir)/clutter/cogl/cogl-vertex-buffer.h + $(top_srcdir)/clutter/cogl/cogl-bitmap.h \ + $(top_srcdir)/clutter/cogl/cogl-color.h \ + $(top_srcdir)/clutter/cogl/cogl-debug.h \ + $(top_srcdir)/clutter/cogl/cogl-deprecated.h \ + $(top_srcdir)/clutter/cogl/cogl-fixed.h \ + $(top_srcdir)/clutter/cogl/cogl-material.h \ + $(top_srcdir)/clutter/cogl/cogl-matrix.h \ + $(top_srcdir)/clutter/cogl/cogl-offscreen.h \ + $(top_srcdir)/clutter/cogl/cogl-path.h \ + $(top_srcdir)/clutter/cogl/cogl-shader.h \ + $(top_srcdir)/clutter/cogl/cogl-texture.h \ + $(top_srcdir)/clutter/cogl/cogl-types.h \ + $(top_srcdir)/clutter/cogl/cogl-vertex-buffer.h \ + $(top_builddir)/clutter/cogl/cogl-defines-@CLUTTER_COGL@.h \ + $(top_builddir)/clutter/cogl/cogl-enum-types.h \ + $(top_builddir)/clutter/cogl/cogl.h \ + $(NULL) + +# this is copied in from common/ to make cogl.h work, but we +# need to clean it up ourselves once we're done +DISTCLEANFILES = cogl-enum-types.h # HACK - gobject-introspection can't scan a library in another directory # so we create a libclutter-cogl.la that's just identical to the one # in the subdir noinst_LTLIBRARIES = libclutter-cogl.la -libclutter_cogl_la_LIBADD = $(CLUTTER_COGL)/libclutter-cogl.la +libclutter_cogl_la_LIBADD = $(CLUTTER_COGL)/libclutter-cogl-$(CLUTTER_COGL).la libclutter_cogl_la_SOURCES = $(cogl_headers) +coglincludedir = $(includedir)/clutter-@CLUTTER_API_VERSION@/cogl +coglinclude_HEADERS = $(cogl_headers) + if HAVE_INTROSPECTION -Cogl-@CLUTTER_API_VERSION@.gir: $(INTROSPECTION_SCANNER) $(CLUTTER_COGL)/libclutter-cogl.la +Cogl-@CLUTTER_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libclutter-cogl.la $(QUIET_GEN)$(INTROSPECTION_SCANNER) -v \ --namespace Cogl --nsversion=@CLUTTER_API_VERSION@ \ -I$(top_srcdir)/clutter/cogl \ @@ -59,8 +78,6 @@ Cogl-@CLUTTER_API_VERSION@.gir: $(INTROSPECTION_SCANNER) $(CLUTTER_COGL)/libclut --libtool="$(top_builddir)/doltlibtool" \ --pkg gobject-2.0 \ --output $@ \ - $(top_builddir)/clutter/cogl/cogl-defines-@CLUTTER_COGL@.h \ - $(top_builddir)/clutter/cogl/cogl.h \ $(cogl_headers) BUILT_GIRSOURCES = Cogl-@CLUTTER_API_VERSION@.gir diff --git a/clutter/cogl/cogl-debug.h b/clutter/cogl/cogl-debug.h index b31a36c52..8aa1e8f87 100644 --- a/clutter/cogl/cogl-debug.h +++ b/clutter/cogl/cogl-debug.h @@ -29,15 +29,16 @@ G_BEGIN_DECLS typedef enum { - COGL_DEBUG_MISC = 1 << 0, - COGL_DEBUG_TEXTURE = 1 << 1, - COGL_DEBUG_MATERIAL = 1 << 2, - COGL_DEBUG_SHADER = 1 << 3, - COGL_DEBUG_OFFSCREEN = 1 << 4, - COGL_DEBUG_DRAW = 1 << 5, - COGL_DEBUG_PANGO = 1 << 6, - COGL_DEBUG_RECTANGLES = 1 << 7, - COGL_DEBUG_HANDLE = 1 << 8 + COGL_DEBUG_MISC = 1 << 0, + COGL_DEBUG_TEXTURE = 1 << 1, + COGL_DEBUG_MATERIAL = 1 << 2, + COGL_DEBUG_SHADER = 1 << 3, + COGL_DEBUG_OFFSCREEN = 1 << 4, + COGL_DEBUG_DRAW = 1 << 5, + COGL_DEBUG_PANGO = 1 << 6, + COGL_DEBUG_RECTANGLES = 1 << 7, + COGL_DEBUG_HANDLE = 1 << 8, + COGL_DEBUG_BLEND_STRINGS = 1 << 9 } CoglDebugFlags; #ifdef COGL_ENABLE_DEBUG @@ -69,3 +70,4 @@ extern guint cogl_debug_flags; G_END_DECLS #endif /* __COGL_DEBUG_H__ */ + diff --git a/clutter/cogl/cogl-deprecated.h b/clutter/cogl/cogl-deprecated.h index 2111e48b4..24dc5b28b 100644 --- a/clutter/cogl/cogl-deprecated.h +++ b/clutter/cogl/cogl-deprecated.h @@ -23,6 +23,14 @@ #ifndef COGL_DEPRECATED_H -#define cogl_color cogl_color_REPLACED_BY_cogl_set_source_color +#define cogl_color cogl_color_REPLACED_BY_cogl_set_source_color +#define cogl_enable_depth_test cogl_enable_depth_test_RENAMED_TO_cogl_set_depth_test_enabled +#define cogl_enable_backface_culling cogl_enable_backface_culling_RENAMED_TO_cogl_set_backface_culling_enabled + +#define cogl_texture_rectangle cogl_texture_rectangle_REPLACE_BY_cogl_set_source_texture_AND_cogl_rectangle_with_texture_coords + +#define cogl_texture_multiple_rectangles cogl_texture_multiple_rectangles_REPLACED_BY_cogl_set_source_texture_AND_cogl_rectangles_with_texture_coords + +#define cogl_texture_polygon cogl_texture_polygon_REPLACED_BY_cogl_set_source_texture_AND_cogl_polygon #endif diff --git a/clutter/cogl/cogl-material.h b/clutter/cogl/cogl-material.h index 95a474831..66fbd8d5c 100644 --- a/clutter/cogl/cogl-material.h +++ b/clutter/cogl/cogl-material.h @@ -43,6 +43,51 @@ G_BEGIN_DECLS * blended together. */ +/** + * CoglMaterialFilter: + * @COGL_MATERIAL_FILTER_NEAREST: Measuring in manhatten distance from the, + * current pixel center, use the nearest texture + * texel. + * @COGL_MATERIAL_FILTER_LINEAR: Use the weighted average of the 4 texels + * nearest the current pixel center. + * @COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST: Select the mimap level whose + * texel size most closely matches + * the current pixel, and use the + * COGL_MATERIAL_FILTER_NEAREST + * criterion. + * @COGL_MATERIAL_FILTER_LINEAR_MIPMAP_NEAREST: Select the mimap level whose + * texel size most closely matches + * the current pixel, and use the + * COGL_MATERIAL_FILTER_LINEAR + * criterion. + * @COGL_MATERIAL_FILTER_NEAREST_MIPMAP_LINEAR: Select the two mimap levels + * whose texel size most closely + * matches the current pixel, use + * the COGL_MATERIAL_FILTER_NEAREST + * criterion on each one and take + * their weighted average. + * @COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR: Select the two mimap levels + * whose texel size most closely + * matches the current pixel, use + * the COGL_MATERIAL_FILTER_LINEAR + * criterion on each one and take + * their weighted average. + * + * Texture filtering is used whenever the current pixel maps either to more + * than one texture element (texel) or less than one. These filter enums + * correspond to different strategies used to come up with a pixel color, by + * possibly referring to multiple neighbouring texels and taking a weighted + * average or simply using the nearest texel. + */ +typedef enum _CoglMaterialFilter +{ + COGL_MATERIAL_FILTER_NEAREST = GL_NEAREST, + COGL_MATERIAL_FILTER_LINEAR = GL_LINEAR, + COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST = GL_NEAREST_MIPMAP_NEAREST, + COGL_MATERIAL_FILTER_LINEAR_MIPMAP_NEAREST = GL_LINEAR_MIPMAP_NEAREST, + COGL_MATERIAL_FILTER_NEAREST_MIPMAP_LINEAR = GL_NEAREST_MIPMAP_LINEAR, + COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR = GL_LINEAR_MIPMAP_LINEAR +} CoglMaterialFilter; /** * cogl_material_new: @@ -367,80 +412,90 @@ void cogl_material_set_alpha_test_function (CoglHandle material, float alpha_reference); /** - * CoglMaterialBlendFactor: - * @COGL_MATERIAL_BLEND_FACTOR_ZERO: (0, 0, 0, 0) - * @COGL_MATERIAL_BLEND_FACTOR_ONE: (1, 1, 1, 1) - * @COGL_MATERIAL_BLEND_FACTOR_SRC_COLOR: (Rs, Gs, Bs, As) - * @COGL_MATERIAL_BLEND_FACTOR_DST_COLOR: (Rd, Gd, Bd, Ad) - * @COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR: (1-Rs, 1-Gs, 1-Bs, 1-As) - * @COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_COLOR: (1-Rd, 1-Gd, 1-Bd, 1-Ad) - * @COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA: (As, As, As, As) - * @COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA: (1-As, 1-As, 1-As, 1-As) - * @COGL_MATERIAL_BLEND_FACTOR_DST_ALPHA: (Ad, Ad, Ad, Ad) - * @COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA: (1-Ad, 1-Ad, 1-Ad, 1-Ad) - * @COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA_SATURATE: (f,f,f,1) where f=MIN(As,1-Ad) + * cogl_material_set_blend: + * @material: A CoglMaterial object + * @blend_string: A Cogl blend string + * describing the desired blend function. + * @error: A GError that may report lack of driver support if you give + * separate blend string statements for the alpha channel and RGB + * channels since some drivers or backends such as GLES 1.1 dont + * support this. + * + * If not already familiar; please refer + * here for an overview of what blend + * strings are and there syntax. * * Blending occurs after the alpha test function, and combines fragments with * the framebuffer. - * - * A fixed function is used to determine the blended color, which is based on - * the incoming source color of your fragment (Rs, Gs, Bs, As), a source - * factor (Sr, Sg, Sb, Sa), a destination color (Rd, Rg, Rb, Ra) and - * a destination factor (Dr, Dg, Db, Da), and is given by these equations: - * + + * Currently the only blend function Cogl exposes is ADD(). So any valid + * blend statements will be of the form: + * * - * R = Rs*Sr + Rd*Dr - * G = Gs*Sg + Gd*Dg - * B = Bs*Sb + Bd*Db - * A = As*Sa + Ad*Da + * <channel-mask>=ADD(SRC_COLOR*(<factor>), DST_COLOR*(<factor>)) * * - * All factors have a range [0, 1] + * NOTE: The brackets around blend factors are currently not optional! * - * The factors are selected with the following constants: + * This is the list of source-names usable as blend factors: + * + * SRC_COLOR: The color of the in comming fragment + * DST_COLOR: The color of the framebuffer + * + * CONSTANT: The constant set via cogl_material_set_blend_constant() + * + * The source names can be used according to the + * color-source and factor syntax, + * so for example "(1-SRC_COLOR[A])" would be a valid factor, as would + * "(CONSTANT[RGB])" + * + * These can also be used as factors: + * + * 0: (0, 0, 0, 0) + * 1: (1, 1, 1, 1) + * SRC_ALPHA_SATURATE_FACTOR: (f,f,f,1) + * where f=MIN(SRC_COLOR[A],1-DST_COLOR[A]) + * + * + * Remember; all color components are normalized to the range [0, 1] before + * computing the result of blending. + * + *
+ * Examples + * Blend a non-premultiplied source over a destination with + * premultiplied alpha: + * + * "RGB = ADD(SRC_COLOR*(SRC_COLOR[A]), DST_COLOR*(1-SRC_COLOR[A]))" + * "A = ADD(SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))" + * + * Blend a premultiplied source over a destination with premultiplied alpha: + * + * "RGBA = ADD(SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))" + * + *
+ * + * Returns: TRUE if the blend string was successfully parsed, and the described + * blending is supported by the underlying driver/hardware. If there + * was an error, it returns FALSE. + * + * Since: 1.0 */ -typedef enum _CoglMaterialBlendFactor -{ - COGL_MATERIAL_BLEND_FACTOR_ZERO = GL_ZERO, - COGL_MATERIAL_BLEND_FACTOR_ONE = GL_ONE, - COGL_MATERIAL_BLEND_FACTOR_SRC_COLOR = GL_SRC_COLOR, - COGL_MATERIAL_BLEND_FACTOR_DST_COLOR = GL_DST_COLOR, - COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = GL_ONE_MINUS_SRC_COLOR, - COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_COLOR = GL_ONE_MINUS_DST_COLOR, - COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA = GL_SRC_ALPHA, - COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = GL_ONE_MINUS_SRC_ALPHA, - COGL_MATERIAL_BLEND_FACTOR_DST_ALPHA = GL_DST_ALPHA, - COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = GL_ONE_MINUS_DST_ALPHA, - COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA_SATURATE = GL_SRC_ALPHA_SATURATE, -} CoglMaterialBlendFactor; +gboolean cogl_material_set_blend (CoglHandle material, + const char *blend_string, + GError **error); /** - * cogl_material_set_blend_factors: + * cogl_material_set_blend_constant: * @material: A CoglMaterial object - * @src_factor: Chooses the @CoglMaterialBlendFactor you want plugged in to - * the blend equation. - * @dst_factor: Chooses the @CoglMaterialBlendFactor you want plugged in to - * the blend equation. + * @constant_color: The constant color you want * - * This function lets you control how primitives using this material will get - * blended with the contents of your framebuffer. The blended RGBA components - * are calculated like this: + * When blending is setup to reference a CONSTANT blend factor then + * blending will depend on the constant set with this function. * - * (RsSr+RdDr, GsSg+GdDg, BsSb+BsSb, AsSa+AdDa) - * - * Where (Rs,Gs,Bs,As) represents your source - material- color, - * (Rd,Gd,Bd,Ad) represents your destination - framebuffer - color, - * (Sr,Sg,Sb,Sa) represents your source blend factor and - * (Dr,Dg,Db,Da) represents you destination blend factor. - * - * All factors lie in the range [0,1] and incoming color components are also - * normalized to the range [0,1] - * - * Since 1.0 + * Since: 1.0 */ -void cogl_material_set_blend_factors (CoglHandle material, - CoglMaterialBlendFactor src_factor, - CoglMaterialBlendFactor dst_factor); +void cogl_material_set_blend_constant (CoglHandle material, + CoglColor *constant_color); /** * cogl_material_set_layer: @@ -460,7 +515,7 @@ void cogl_material_set_blend_factors (CoglHandle material, * Since 1.0 */ void cogl_material_set_layer (CoglHandle material, - gint layer_index, + int layer_index, CoglHandle texture); /** @@ -473,233 +528,112 @@ void cogl_material_set_layer (CoglHandle material, void cogl_material_remove_layer (CoglHandle material, gint layer_index); + /** - * CoglMaterialLayerCombineFunc: - * @COGL_MATERIAL_LAYER_COMBINE_FUNC_REPLACE: Arg0 - * @COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE: Arg0 x Arg1 - * @COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD: Arg0 + Arg1 - * @COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD_SIGNED: Arg0 + Arg1 - 0.5 - * @COGL_MATERIAL_LAYER_COMBINE_FUNC_INTERPOLATE: Arg0 x Arg + Arg1 x (1-Arg2) - * @COGL_MATERIAL_LAYER_COMBINE_FUNC_SUBTRACT: Arg0 - Arg1 - * @COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGB: 4 x ((Arg0r - 0.5) x (Arg1r - 0.5)) + - * @COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGBA: ((Arg0b - 0.5) x (Arg1b - 0.5)) + + * cogl_material_set_layer_combine: + * @material: A CoglMaterial object + * @layer_index: Specifies the layer you want define a combine function for + * @blend_string: A Cogl blend string + * describing the desired texture combine function. + * @error: A GError that may report parse errors or lack of GPU/driver support. * - * A material may comprise of 1 or more layers that can be combined using a - * number of different functions. By default layers are modulated, which is - * to say the components of the current source layer S are simply multipled - * together with the combined results of the previous layer P like this: + * If not already familiar; you can refer + * here for an overview of what blend + * strings are and there syntax. * + * These are all the functions available for texture combining: + * + * REPLACE(arg0) = arg0 + * MODULATE(arg0, arg1) = arg0 x arg1 + * ADD(arg0, arg1) = arg0 + arg1 + * ADD_SIGNED(arg0, arg1) = arg0 + arg1 - 0.5 + * INTERPOLATE(arg0, arg1, arg2) = + * arg0 x arg2 + arg1 x (1 - arg2) + * SUBTRACT(arg0, arg1) = arg0 - arg1 + * + * DOT3_RGB(arg0, arg1) = * - * (Rs*Rp, Gs*Gp, Bs*Bp, As*Ap) + * 4 x ((arg0[R] - 0.5)) * (arg1[R] - 0.5) + + * (arg0[G] - 0.5)) * (arg1[G] - 0.5) + + * (arg0[B] - 0.5)) * (arg1[B] - 0.5)) * - * - * For more advanced techniques, Cogl exposes the fixed function texture - * combining capabilities of your GPU to give you greater control. - */ -typedef enum _CoglMaterialLayerCombineFunc -{ - COGL_MATERIAL_LAYER_COMBINE_FUNC_REPLACE = CGL_REPLACE, - COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE = CGL_MODULATE, - COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD = CGL_ADD, - COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD_SIGNED = CGL_ADD_SIGNED, - COGL_MATERIAL_LAYER_COMBINE_FUNC_INTERPOLATE = CGL_INTERPOLATE, - COGL_MATERIAL_LAYER_COMBINE_FUNC_SUBTRACT = CGL_SUBTRACT, - COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGB = CGL_DOT3_RGB, - COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGBA = CGL_DOT3_RGBA -} CoglMaterialLayerCombineFunc; - -/** - * CoglMaterialLayerCombineChannels: - * @COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB: Modify the function or argument - * src/op for the RGB components of a - * layer - * @COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA: Modify the function or argument - * src/op for the Alpha component of a - * layer - * @COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA: Modify the function or argument - * src/op for all the components of a - * layer - * - * Cogl optionally lets you describe 2 seperate combine modes for a single - * layer; 1 for the RGB components, and 1 for the Alpha component, so in this - * case you would repeat the 3 steps documented with the - * @cogl_material_set_layer_combine_function function for each channel - * selector. - * - * (Note: you can't have different modes for each channel, so if you need more - * control you will need to use a glsl fragment shader) - */ -typedef enum _CoglMaterialLayerCombineChannels -{ - COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB, - COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA, - COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA -} CoglMaterialLayerCombineChannels; - -/** - * cogl_material_set_layer_combine_function: - * @material: A CoglMaterial object - * @layer_index: Specifies the layer whos combine mode you want to modify - * @channels: Specifies which channels combine mode you want to modify - * (RGB, ALPHA, or RGBA) - * @func: Specifies the function you want to use for combining fragments - * of the specified layer with the results of previously combined - * layers. - * - * There are three basic steps to describing how a layer should be combined: - * - * - * Choose a function. * - * - * Specify the source color for each argument of the chosen function. (Note - * the functions don't all take the same number of arguments) - * - * - * Specify an operator for each argument that can modify the corresponding - * source color before the function is applied. - * - * - * - * Cogl optionally lets you describe 2 seperate combine modes for a single - * layer; 1 for the RGB components, and 1 for the Alpha component, so in this - * case you would repeat the 3 steps for each channel selector. - * - * (Note: you can't have different modes for each channel, so if you need more - * control you will need to use a glsl fragment shader) - * - * For example here is how you could elect to use the ADD function for all - * components of layer 1 in your material: + * DOT3_RGBA(arg0, arg1) = * - * //Step 1: Choose a function. Note the ADD function takes 2 arguments... - * cogl_material_set_layer_combine_function (material, - * 1, - * COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA) - * COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD); - * //Step 2: Specify the source color for the 2 ADD function arguments... - * cogl_material_set_layer_combine_arg_src (material, - * 1,//layer index - * 0,//argument index - * COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS); - * cogl_material_set_layer_combine_arg_src (material, - * 1,//layer index - * 1,//argument index - * COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA) - * COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE); - * //Step 3: Specify the operators used to modify the arguments... - * cogl_material_set_layer_combine_arg_op (material, - * 1,//layer index - * 0,//argument index - * COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA, - * COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR); - * cogl_material_set_layer_combine_arg_op (material, - * 1,//layer index - * 1,//argument index - * COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA, - * COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR); + * 4 x ((arg0[R] - 0.5)) * (arg1[R] - 0.5) + + * (arg0[G] - 0.5)) * (arg1[G] - 0.5) + + * (arg0[B] - 0.5)) * (arg1[B] - 0.5)) * - */ -void cogl_material_set_layer_combine_function (CoglHandle material, - gint layer_index, - CoglMaterialLayerCombineChannels channels, - CoglMaterialLayerCombineFunc func); - -/** - * CoglMaterialLayerCombineSrc: - * @COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE: The fragment color of the current texture layer - * @COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE0: The fragment color of texture unit 0 - * @COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE1: The fragment color of texture unit 1 - * @COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE2: The fragment color of texture unit 2..7 - * @COGL_MATERIAL_LAYER_COMBINE_SRC_CONSTANT: A fixed constant color (TODO: no API yet to specify the actual color!) - * @COGL_MATERIAL_LAYER_COMBINE_SRC_PRIMARY_COLOR: The basic color of the primitive ignoring texturing - * @COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS: The result of combining all previous layers + * + * * - * Note for the constants @COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE0..n the - * numbers may not correspond to the indices you choose for your layers since - * your layer indices don't need to be contiguous. If you need to use these - * it would probably be sensible to ensure the layer indices do infact - * correspond. + * Refer to the + * color-source syntax for + * describing the arguments. The valid source names for texture combining + * are: + * + * + * TEXTURE: Use the color from the current texture layer + * + * + * TEXTURE_0, TEXTURE_1, etc: Use the color from the specified texture layer + * + * + * CONSTANT: Use the color from the constant given with + * cogl_material_set_layer_constant() + * + * + * PRIMARY: Use the color of the material as set with cogl_material_set_color() + * + * + * PREVIOUS: Either use the texture color from the previous layer, or if this + * is layer 0, use the color of the material as set with + * cogl_material_set_color() + * + * + *
+ * Example + * This is effectively what the default blending is: + * + * "RGBA = MODULATE (PREVIOUS, TEXTURE)" + * + * This could be used to cross-fade between two images, using the alpha + * component of a constant as the interpolator. The constant color + * is given by calling cogl_material_set_layer_constant. + * + * RGBA = INTERPOLATE (PREVIOUS, TEXTURE, CONSTANT[A]) + * + *
+ * Note: you can't give a multiplication factor for arguments as you can + * with blending. + * + * Returns: TRUE if the blend string was successfully parsed, and the described + * texture combining is supported by the underlying driver/hardware. + * If there was an error, it returns FALSE. + * + * Since: 1.0 */ -typedef enum _CoglMaterialLayerCombineSrc -{ - COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE = GL_TEXTURE, - - /* Can we find a nicer way... */ - COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE0 = GL_TEXTURE0, - COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE1 = GL_TEXTURE1, - COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE2 = GL_TEXTURE2, - COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE3 = GL_TEXTURE3, - COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE4 = GL_TEXTURE4, - COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE5 = GL_TEXTURE5, - COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE6 = GL_TEXTURE6, - COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE7 = GL_TEXTURE7, - /* .. who would ever need more than 8 texture layers.. :-) */ - - COGL_MATERIAL_LAYER_COMBINE_SRC_CONSTANT = CGL_CONSTANT, - COGL_MATERIAL_LAYER_COMBINE_SRC_PRIMARY_COLOR = CGL_PRIMARY_COLOR, - COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS = CGL_PREVIOUS -} CoglMaterialLayerCombineSrc; +gboolean +cogl_material_set_layer_combine (CoglHandle material, + gint layer_index, + const char *blend_string, + GError **error); /** - * cogl_material_set_layer_combine_arg_src: + * cogl_material_set_layer_combine_constant: * @material: A CoglMaterial object - * @layer_index: - * @argument: - * @channels: - * @src: + * @layer_index: Specifies the layer you want to specify a constant used + * for texture combining + * @color_constant: The constant color you want * - */ -void cogl_material_set_layer_combine_arg_src (CoglHandle material, - gint layer_index, - gint argument, - CoglMaterialLayerCombineChannels channels, - CoglMaterialLayerCombineSrc src); - -typedef enum _CoglMaterialLayerCombineOp -{ - COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR = GL_SRC_COLOR, - COGL_MATERIAL_LAYER_COMBINE_OP_ONE_MINUS_SRC_COLOR = GL_ONE_MINUS_SRC_COLOR, - - COGL_MATERIAL_LAYER_COMBINE_OP_SRC_ALPHA = GL_SRC_ALPHA, - COGL_MATERIAL_LAYER_COMBINE_OP_ONE_MINUS_SRC_ALPHA = GL_ONE_MINUS_SRC_ALPHA -} CoglMaterialLayerCombineOp; - -/** - * cogl_material_set_layer_combine_arg_op: - * @material: A CoglMaterial object - * @layer_index: - * @argument: - * @channels: - * @op: + * When you are using the 'CONSTANT' color source in a layer combine + * description then you can use this function to define its value. * + * Since 1.0 */ -void cogl_material_set_layer_combine_arg_op (CoglHandle material, - gint layer_index, - gint argument, - CoglMaterialLayerCombineChannels channels, - CoglMaterialLayerCombineOp op); - -/* TODO: */ -#if 0 - I think it would be be really neat to support a simple string description - of the fixed function texture combine modes exposed above. I think we can - consider this stuff to be set in stone from the POV that more advanced - texture combine functions are catered for with GLSL, so it seems reasonable - to find a concise string representation that can represent all the above - modes in a *much* more readable/useable fashion. I think somthing like - this would be quite nice: - - "MODULATE(TEXTURE[RGB], PREVIOUS[A])" - "ADD(TEXTURE[A],PREVIOUS[RGB])" - "INTERPOLATE(TEXTURE[1-A], PREVIOUS[RGB])" - -void cogl_material_set_layer_rgb_combine (CoglHandle material - gint layer_index, - const char *combine_description); -void cogl_material_set_layer_alpha_combine (CoglHandle material - gint layer_index, - const char *combine_description); -#endif +void cogl_material_set_layer_combine_constant (CoglHandle material, + int layer_index, + CoglColor *constant); /** * cogl_material_set_layer_matrix: @@ -709,38 +643,9 @@ void cogl_material_set_layer_alpha_combine (CoglHandle material * and rotate a single layer of a material used to fill your geometry. */ void cogl_material_set_layer_matrix (CoglHandle material, - gint layer_index, + int layer_index, CoglMatrix *matrix); - -/** - * SECTION:cogl-material-internals - * @short_description: Functions for creating custom primitives that make use - * of Cogl materials for filling. - * - * Normally you shouldn't need to use this API directly, but if you need to - * developing a custom/specialised primitive - probably using raw OpenGL - then - * this API aims to expose enough of the material internals to support being - * able to fill your geometry according to a given Cogl material. - */ - - -/** - * cogl_material_get_cogl_enable_flags: - * @material: A CoglMaterial object - * - * This determines what flags need to be passed to cogl_enable before this - * material can be used. Normally you shouldn't need to use this function - * directly since Cogl will do this internally, but if you are developing - * custom primitives directly with OpenGL you may want to use this. - * - * Note: This API is hopfully just a stop-gap solution. Ideally cogl_enable - * will be replaced. - */ -/* TODO: find a nicer solution! */ -gulong -cogl_material_get_cogl_enable_flags (CoglHandle handle); - /** * cogl_material_get_layers: * @material: A CoglMaterial object @@ -748,24 +653,20 @@ cogl_material_get_cogl_enable_flags (CoglHandle handle); * This function lets you access a materials internal list of layers * for iteration. * - * Note: Normally you shouldn't need to use this function directly since - * Cogl will do this internally, but if you are developing custom primitives - * directly with OpenGL, you will need to iterate the layers that you want - * to texture with. - * - * Note: This function may return more layers than OpenGL can use at once - * so it's your responsability limit yourself to - * CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS. - * - * Note: It's a bit out of the ordinary to return a const GList *, but it - * was considered sensible to try and avoid list manipulation for every - * primitive emitted in a scene, every frame. + * Returns: A list of #CoglHandle's that can be passed to the + * cogl_material_layer_* functions. */ const GList *cogl_material_get_layers (CoglHandle material_handle); /** * CoglMaterialLayerType: - * @COGL_MATERIAL_LAYER_TYPE_TEXTURE: The layer represents a CoglTexture + * @COGL_MATERIAL_LAYER_TYPE_TEXTURE: The layer represents a + * Cogl texture + * + * Available types of layers for a #CoglMaterial. This enumeration + * might be expanded in later versions. + * + * Since: 1.0 */ typedef enum _CoglMaterialLayerType { @@ -774,17 +675,12 @@ typedef enum _CoglMaterialLayerType /** * cogl_material_layer_get_type: - * @layer_handle: A CoglMaterialLayer handle + * @layer_handle: A Cogl material layer handle * * Currently there is only one type of layer defined: * COGL_MATERIAL_LAYER_TYPE_TEXTURE, but considering we may add purely GLSL * based layers in the future, you should write code that checks the type * first. - * - * Note: Normally you shouldn't need to use this function directly since - * Cogl will do this internally, but if you are developing custom primitives - * directly with OpenGL, you will need to iterate the layers that you want - * to texture with, and thus should be checking the layer types. */ CoglMaterialLayerType cogl_material_layer_get_type (CoglHandle layer_handle); @@ -792,75 +688,58 @@ CoglMaterialLayerType cogl_material_layer_get_type (CoglHandle layer_handle); * cogl_material_layer_get_texture: * @layer_handle: A CoglMaterialLayer handle * - * This lets you extract a CoglTexture handle for a specific layer. Normally - * you shouldn't need to use this function directly since Cogl will do this - * internally, but if you are developing custom primitives directly with - * OpenGL you may need this. + * This lets you extract a CoglTexture handle for a specific layer. * * Note: In the future, we may support purely GLSL based layers which will - * likley return COGL_INVALID_HANDLE if you try to get the texture. - * Considering this, you should always call cogl_material_layer_get_type - * first, to check it is of type COGL_MATERIAL_LAYER_TYPE_TEXTURE. + * likely return COGL_INVALID_HANDLE if you try to get the texture. + * Considering this, you can call cogl_material_layer_get_type first, + * to check it is of type COGL_MATERIAL_LAYER_TYPE_TEXTURE. + * + * Note: It is possible for a layer object of type + * COGL_MATERIAL_LAYER_TYPE_TEXTURE to be realized before a texture + * object has been associated with the layer. For example this happens + * if you setup layer combining for a given layer index before calling + * cogl_material_set_layer for that index. + * + * Returns: A CoglHandle to the layers texture object or COGL_INVALID_HANDLE + * if a texture has not been set yet. */ CoglHandle cogl_material_layer_get_texture (CoglHandle layer_handle); /** - * CoglMaterialLayerFlags: - * @COGL_MATERIAL_LAYER_FLAG_USER_MATRIX: Means the user has supplied a - * custom texture matrix. + * cogl_material_layer_get_min_filter: + * @layer_handle: a #CoglHandle for a material layer. + * + * Query the currently set downscaling filter for a cogl material layer. + * + * Returns: the current downscaling filter for a cogl material layer. */ -typedef enum _CoglMaterialLayerFlags -{ - COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX = 1L<<0 -} CoglMaterialLayerFlags; -/* XXX: NB: if you add flags here you will need to update - * CoglMaterialLayerPrivFlags!!! */ +CoglMaterialFilter cogl_material_layer_get_min_filter (CoglHandle layer_handle); /** - * cogl_material_layer_get_flags: - * @layer_handle: A CoglMaterialLayer layer handle + * cogl_material_layer_get_mag_filter: + * @layer_handle: a #CoglHandle for a material layer. * - * This lets you get a number of flag attributes about the layer. Normally - * you shouldn't need to use this function directly since Cogl will do this - * internally, but if you are developing custom primitives directly with - * OpenGL you may need this. + * Query the currently set downscaling filter for a cogl material layer. + * + * Returns: the current downscaling filter for a cogl material layer. */ -gulong cogl_material_layer_get_flags (CoglHandle layer_handle); +CoglMaterialFilter cogl_material_layer_get_mag_filter (CoglHandle layer_handle); /** - * CoglMaterialFlushOption: - * @COGL_MATERIAL_FLUSH_FALLBACK_MASK: Follow this by a guin32 mask - * of the layers that can't be supported with the user supplied texture - * and need to be replaced with fallback textures. (1 = fallback, and the - * least significant bit = layer 0) - * @COGL_MATERIAL_FLUSH_DISABLE_MASK: Follow this by a guint32 mask - * of the layers that you want to completly disable texturing for - * (1 = fallback, and the least significant bit = layer 0) - * @COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE: Follow this by a GLuint OpenGL texture - * name to override the texture used for layer 0 of the material. This is - * intended for dealing with sliced textures where you will need to point - * to each of the texture slices in turn when drawing your geometry. - * Passing a value of 0 is the same as not passing the option at all. - */ -typedef enum _CoglMaterialFlushOption -{ - COGL_MATERIAL_FLUSH_FALLBACK_MASK = 1, - COGL_MATERIAL_FLUSH_DISABLE_MASK, - COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE, -} CoglMaterialFlushOption; - -/** - * cogl_material_flush_gl_state: - * @material: A CoglMaterial object - * @...: A NULL terminated list of (CoglMaterialFlushOption, data) pairs + * cogl_material_set_layer_filters: + * @handle: a #CoglHandle to a material. + * @layer_index: the layer number to change. + * @min_filter: the filter used when scaling a texture down. + * @mag_filter: the filter used when magnifying a texture. * - * This function commits the state of the specified CoglMaterial - including - * the texture state for all the layers - to the OpenGL[ES] driver. - * - * Since 1.0 + * Changes the decimation and interpolation filters used when a texture is + * drawn at other scales than 100%. */ -void cogl_material_flush_gl_state (CoglHandle material, - ...) G_GNUC_NULL_TERMINATED; +void cogl_material_set_layer_filters (CoglHandle handle, + gint layer_index, + CoglMaterialFilter min_filter, + CoglMaterialFilter mag_filter); G_END_DECLS diff --git a/clutter/cogl/cogl-matrix.h b/clutter/cogl/cogl-matrix.h index ca643f146..3ee94aeb5 100644 --- a/clutter/cogl/cogl-matrix.h +++ b/clutter/cogl/cogl-matrix.h @@ -199,22 +199,50 @@ void cogl_matrix_frustum (CoglMatrix *matrix, float z_far); /** - * cogl_matrix_transform_point: + * cogl_matrix_perspective: * @matrix: A 4x4 transformation matrix - * @x: The X component of your points position [in:out] - * @y: The Y component of your points position [in:out] - * @z: The Z component of your points position [in:out] - * @w: The W component of your points position [in:out] + * @fov_y: A field of view angle for the Y axis + * @aspect: The ratio of width to height determining the field of view angle + * for the x axis. + * @z_near: The distance to the near clip plane. + * Never pass 0 and always pass a positive number. + * @z_far: The distance to the far clip plane. (Should always be positive) * - * This transforms a point whos position is given and returned - * as four float components. + * Multiplies the matrix by the described perspective matrix + * + * Note: you should be careful not to have to great a z_far / z_near ratio + * since that will reduce the effectiveness of depth testing since there wont + * be enough precision to identify the depth of objects near to each other. */ void -cogl_matrix_transform_point (const CoglMatrix *matrix, - float *x, - float *y, - float *z, - float *w); +cogl_matrix_perspective (CoglMatrix *matrix, + float fov_y, + float aspect, + float z_near, + float z_far); + +/** + * cogl_matrix_ortho: + * @matrix: A 4x4 transformation matrix + * @left: The coordinate for the left clipping plane + * @right: The coordinate for the right clipping plane + * @bottom: The coordinate for the bottom clipping plane + * @top: The coordinate for the top clipping plane + * @z_near: The coordinate for the near clipping plane (may be negative if + * the plane is behind the viewer) + * @z_far: The coordinate for the far clipping plane (may be negative if + * the plane is behind the viewer) + * + * Multiples the matrix by a parallel projection matrix. + */ +void +cogl_matrix_ortho (CoglMatrix *matrix, + float left, + float right, + float bottom, + float top, + float z_near, + float z_far); /** * cogl_matrix_init_from_array: @@ -234,6 +262,24 @@ void cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array); */ const float *cogl_matrix_get_array (const CoglMatrix *matrix); +/** + * cogl_matrix_transform_point: + * @matrix: A 4x4 transformation matrix + * @x: The X component of your points position [in:out] + * @y: The Y component of your points position [in:out] + * @z: The Z component of your points position [in:out] + * @w: The W component of your points position [in:out] + * + * This transforms a point whos position is given and returned + * as four float components. + */ +void +cogl_matrix_transform_point (const CoglMatrix *matrix, + float *x, + float *y, + float *z, + float *w); + G_END_DECLS #endif /* __COGL_MATRIX_H */ diff --git a/clutter/cogl/cogl-shader.h b/clutter/cogl/cogl-shader.h index 59c75ede6..9eec9bb40 100644 --- a/clutter/cogl/cogl-shader.h +++ b/clutter/cogl/cogl-shader.h @@ -46,9 +46,12 @@ G_BEGIN_DECLS * CoglShaderType: * @COGL_SHADER_TYPE_VERTEX: A program for proccessing vertices * @COGL_SHADER_TYPE_FRAGMENT: A program for processing fragments + * + * Types of shaders + * + * Since: 1.0 */ -typedef enum _CoglShaderType -{ +typedef enum { COGL_SHADER_TYPE_VERTEX, COGL_SHADER_TYPE_FRAGMENT } CoglShaderType; @@ -103,7 +106,7 @@ gboolean cogl_is_shader (CoglHandle handle); * one. */ void cogl_shader_source (CoglHandle shader, - const char *source); + const gchar *source); /** * cogl_shader_compile: * @handle: #CoglHandle for a shader. @@ -111,29 +114,30 @@ void cogl_shader_source (CoglHandle shader, * Compiles the shader, no return value, but the shader is now ready for * linking into a program. */ -void cogl_shader_compile (CoglHandle handle); +void cogl_shader_compile (CoglHandle handle); /** * cogl_shader_get_info_log: * @handle: #CoglHandle for a shader. - * @size: maximum number of bytes to retrieve. - * @buffer: location for info log. * * Retrieves the information log for a coglobject, can be used in conjunction - * with #cogl_shader_get_parameteriv to retrieve the compiler warnings/error + * with cogl_shader_get_parameteriv() to retrieve the compiler warnings/error * messages that caused a shader to not compile correctly, mainly useful for * debugging purposes. + * + * Return value: a newly allocated string containing the info log. Use + * g_free() to free it */ -void cogl_shader_get_info_log (CoglHandle handle, - size_t size, - char *buffer); +gchar * cogl_shader_get_info_log (CoglHandle handle); /** * cogl_shader_get_type: * @handle: #CoglHandle for a shader. * - * Returns: COGL_SHADER_TYPE_VERTEX if the shader is a vertex processor - * or COGL_SHADER_TYPE_FRAGMENT if the shader is a frament processor + * Retrieves the type of a shader #CoglHandle + * + * Return value: %COGL_SHADER_TYPE_VERTEX if the shader is a vertex processor + * or %COGL_SHADER_TYPE_FRAGMENT if the shader is a frament processor */ CoglShaderType cogl_shader_get_type (CoglHandle handle); @@ -141,7 +145,9 @@ CoglShaderType cogl_shader_get_type (CoglHandle handle); * cogl_shader_is_compiled: * @handle: #CoglHandle for a shader. * - * Returns: TRUE if the shader object has sucessfully be compiled else FALSE + * Retrieves whether a shader #CoglHandle has been compiled + * + * Return value: %TRUE if the shader object has sucessfully be compiled */ gboolean cogl_shader_is_compiled (CoglHandle handle); diff --git a/clutter/cogl/cogl-texture.h b/clutter/cogl/cogl-texture.h index 6a8b00a01..15cadc879 100644 --- a/clutter/cogl/cogl-texture.h +++ b/clutter/cogl/cogl-texture.h @@ -41,12 +41,12 @@ G_BEGIN_DECLS * loading and manipulating textures. */ +#define COGL_TEXTURE_MAX_WASTE 127 + /** * cogl_texture_new_with_size: * @width: width of texture in pixels. * @height: height of texture in pixels. - * @max_waste: maximum extra horizontal and|or vertical margin pixels - * to make the texture fit GPU limitations * @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE * @internal_format: the #CoglPixelFormat to use for the GPU storage of the * texture. @@ -60,15 +60,12 @@ G_BEGIN_DECLS */ CoglHandle cogl_texture_new_with_size (guint width, guint height, - gint max_waste, CoglTextureFlags flags, CoglPixelFormat internal_format); /** * cogl_texture_new_from_file: * @filename: the file to load - * @max_waste: maximum extra horizontal and|or vertical margin pixels - * to make the texture fit GPU limitations * @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE * @internal_format: the #CoglPixelFormat to use for the GPU storage of the * texture @@ -82,7 +79,6 @@ CoglHandle cogl_texture_new_with_size (guint width, * Since: 0.8 */ CoglHandle cogl_texture_new_from_file (const gchar *filename, - gint max_waste, CoglTextureFlags flags, CoglPixelFormat internal_format, GError **error); @@ -91,8 +87,6 @@ CoglHandle cogl_texture_new_from_file (const gchar *filename, * cogl_texture_new_from_data: * @width: width of texture in pixels * @height: height of texture in pixels - * @max_waste: maximum extra horizontal and|or vertical margin pixels - * to make the texture fit GPU limitations * @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE * @format: the #CoglPixelFormat the buffer is stored in in RAM * @internal_format: the #CoglPixelFormat that will be used for storing @@ -110,7 +104,6 @@ CoglHandle cogl_texture_new_from_file (const gchar *filename, */ CoglHandle cogl_texture_new_from_data (guint width, guint height, - gint max_waste, CoglTextureFlags flags, CoglPixelFormat format, CoglPixelFormat internal_format, @@ -136,19 +129,17 @@ CoglHandle cogl_texture_new_from_data (guint width, * * Since: 0.8 */ -CoglHandle cogl_texture_new_from_foreign (GLuint gl_handle, - GLenum gl_target, - GLuint width, - GLuint height, - GLuint x_pot_waste, - GLuint y_pot_waste, - CoglPixelFormat format); +CoglHandle cogl_texture_new_from_foreign (GLuint gl_handle, + GLenum gl_target, + GLuint width, + GLuint height, + GLuint x_pot_waste, + GLuint y_pot_waste, + CoglPixelFormat format); /** * cogl_texture_new_from_bitmap: * @bmp_handle: A CoglBitmap handle - * @max_waste: maximum extra horizontal and|or vertical margin pixels - * to make the texture fit GPU limitations * @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE * @internal_format: the #CoglPixelFormat to use for the GPU storage of the * texture @@ -160,10 +151,9 @@ CoglHandle cogl_texture_new_from_foreign (GLuint gl_handle, * * Since: 1.0 */ -CoglHandle cogl_texture_new_from_bitmap (CoglHandle bmp_handle, - gint max_waste, - CoglTextureFlags flags, - CoglPixelFormat internal_format); +CoglHandle cogl_texture_new_from_bitmap (CoglHandle bmp_handle, + CoglTextureFlags flags, + CoglPixelFormat internal_format); /** * cogl_is_texture: @@ -228,72 +218,6 @@ guint cogl_texture_get_rowstride (CoglHandle handle); */ gint cogl_texture_get_max_waste (CoglHandle handle); -/** - * CoglTextureFilter: - * @COGL_TEXTURE_FILTER_NEAREST: Measuring in manhatten distance from the, - * current pixel center, use the nearest texture - * texel. - * @COGL_TEXTURE_FILTER_LINEAR: Use the weighted average of the 4 texels - * nearest the current pixel center. - * @COGL_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST: Select the mimap level whose - * texel size most closely matches - * the current pixel, and use the - * COGL_TEXTURE_FILTER_NEAREST - * criterion. - * @COGL_TEXTURE_FILTER_LINEAR_MIPMAP_NEAREST: Select the mimap level whose - * texel size most closely matches - * the current pixel, and use the - * COGL_TEXTURE_FILTER_LINEAR - * criterion. - * @COGL_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR: Select the two mimap levels - * whose texel size most closely - * matches the current pixel, use - * the COGL_TEXTURE_FILTER_NEAREST - * criterion on each one and take - * their weighted average. - * @COGL_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR: Select the two mimap levels - * whose texel size most closely - * matches the current pixel, use - * the COGL_TEXTURE_FILTER_LINEAR - * criterion on each one and take - * their weighted average. - * - * Texture filtering is used whenever the current pixel maps either to more - * than one texture element (texel) or less than one. These filter enums - * correspond to different strategies used to come up with a pixel color, by - * possibly referring to multiple neighbouring texels and taking a weighted - * average or simply using the nearest texel. - */ -typedef enum _CoglTextureFilter -{ - COGL_TEXTURE_FILTER_NEAREST = GL_NEAREST, - COGL_TEXTURE_FILTER_LINEAR = GL_LINEAR, - COGL_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST = GL_NEAREST_MIPMAP_NEAREST, - COGL_TEXTURE_FILTER_LINEAR_MIPMAP_NEAREST = GL_LINEAR_MIPMAP_NEAREST, - COGL_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR = GL_NEAREST_MIPMAP_LINEAR, - COGL_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR = GL_LINEAR_MIPMAP_LINEAR -} CoglTextureFilter; - -/** - * cogl_texture_get_min_filter: - * @handle: a #CoglHandle for a texture. - * - * Query the currently set downscaling filter for a cogl texture. - * - * Returns: the current downscaling filter for a cogl texture. - */ -CoglTextureFilter cogl_texture_get_min_filter (CoglHandle handle); - -/** - * cogl_texture_get_mag_filter: - * @handle: a #CoglHandle for a texture. - * - * Query the currently set downscaling filter for a cogl texture. - * - * Returns: the current downscaling filter for a cogl texture. - */ -CoglTextureFilter cogl_texture_get_mag_filter (CoglHandle handle); - /** * cogl_texture_is_sliced: * @handle: a #CoglHandle for a texture. @@ -343,20 +267,6 @@ gint cogl_texture_get_data (CoglHandle handle, guint rowstride, guchar *data); -/** - * cogl_texture_set_filters: - * @handle: a #CoglHandle. - * @min_filter: the filter used when scaling the texture down. - * @mag_filter: the filter used when magnifying the texture. - * - * Changes the decimation and interpolation filters used when the texture is - * drawn at other scales than 100%. - */ -void cogl_texture_set_filters (CoglHandle handle, - CoglTextureFilter min_filter, - CoglTextureFilter mag_filter); - - /** * cogl_texture_set_region: * @handle: a #CoglHandle. diff --git a/clutter/cogl/cogl-types.h b/clutter/cogl/cogl-types.h index a4ecd4193..0a1360dde 100644 --- a/clutter/cogl/cogl-types.h +++ b/clutter/cogl/cogl-types.h @@ -123,8 +123,7 @@ typedef struct _CoglTextureVertex CoglTextureVertex; * * Since: 0.8 */ -typedef enum -{ +typedef enum { /*< prefix=COGL_PIXEL_FORMAT >*/ COGL_PIXEL_FORMAT_ANY = 0, COGL_PIXEL_FORMAT_A_8 = 1 | COGL_A_BIT, @@ -135,60 +134,21 @@ typedef enum COGL_PIXEL_FORMAT_G_8 = 8, COGL_PIXEL_FORMAT_RGB_888 = COGL_PIXEL_FORMAT_24, + COGL_PIXEL_FORMAT_BGR_888 = (COGL_PIXEL_FORMAT_24 | COGL_BGR_BIT), - COGL_PIXEL_FORMAT_BGR_888 = (COGL_PIXEL_FORMAT_24 | - COGL_BGR_BIT), - - COGL_PIXEL_FORMAT_RGBA_8888 = COGL_PIXEL_FORMAT_32 | - COGL_A_BIT, - - COGL_PIXEL_FORMAT_BGRA_8888 = (COGL_PIXEL_FORMAT_32 | - COGL_A_BIT | - COGL_BGR_BIT), - - COGL_PIXEL_FORMAT_ARGB_8888 = (COGL_PIXEL_FORMAT_32 | - COGL_A_BIT | - COGL_AFIRST_BIT), - - COGL_PIXEL_FORMAT_ABGR_8888 = (COGL_PIXEL_FORMAT_32 | - COGL_A_BIT | - COGL_BGR_BIT | - COGL_AFIRST_BIT), - - COGL_PIXEL_FORMAT_RGBA_8888_PRE = (COGL_PIXEL_FORMAT_32 | - COGL_A_BIT | - COGL_PREMULT_BIT), - - COGL_PIXEL_FORMAT_BGRA_8888_PRE = (COGL_PIXEL_FORMAT_32 | - COGL_A_BIT | - COGL_PREMULT_BIT | - COGL_BGR_BIT), - - COGL_PIXEL_FORMAT_ARGB_8888_PRE = (COGL_PIXEL_FORMAT_32 | - COGL_A_BIT | - COGL_PREMULT_BIT | - COGL_AFIRST_BIT), - - COGL_PIXEL_FORMAT_ABGR_8888_PRE = (COGL_PIXEL_FORMAT_32 | - COGL_A_BIT | - COGL_PREMULT_BIT | - COGL_BGR_BIT | - COGL_AFIRST_BIT), - - COGL_PIXEL_FORMAT_RGBA_4444_PRE = (COGL_PIXEL_FORMAT_RGBA_4444 | - COGL_A_BIT | - COGL_PREMULT_BIT), - - COGL_PIXEL_FORMAT_RGBA_5551_PRE = (COGL_PIXEL_FORMAT_RGBA_5551 | - COGL_A_BIT | - COGL_PREMULT_BIT), - + COGL_PIXEL_FORMAT_RGBA_8888 = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT), + COGL_PIXEL_FORMAT_BGRA_8888 = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_BGR_BIT), + COGL_PIXEL_FORMAT_ARGB_8888 = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_AFIRST_BIT), + COGL_PIXEL_FORMAT_ABGR_8888 = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_BGR_BIT | COGL_AFIRST_BIT), + COGL_PIXEL_FORMAT_RGBA_8888_PRE = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_PREMULT_BIT), + COGL_PIXEL_FORMAT_BGRA_8888_PRE = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_PREMULT_BIT | COGL_BGR_BIT), + COGL_PIXEL_FORMAT_ARGB_8888_PRE = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_PREMULT_BIT | COGL_AFIRST_BIT), + COGL_PIXEL_FORMAT_ABGR_8888_PRE = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_PREMULT_BIT | COGL_BGR_BIT | COGL_AFIRST_BIT), + COGL_PIXEL_FORMAT_RGBA_4444_PRE = (COGL_PIXEL_FORMAT_RGBA_4444 | COGL_A_BIT | COGL_PREMULT_BIT), + COGL_PIXEL_FORMAT_RGBA_5551_PRE = (COGL_PIXEL_FORMAT_RGBA_5551 | COGL_A_BIT | COGL_PREMULT_BIT), } CoglPixelFormat; -#define COGL_TYPE_PIXEL_FORMAT (cogl_pixel_format_get_type ()) -GType cogl_pixel_format_get_type (void) G_GNUC_CONST; - /** * CoglFeatureFlags: * @COGL_FEATURE_TEXTURE_RECTANGLE: ARB_texture_rectangle support @@ -222,9 +182,6 @@ typedef enum COGL_FEATURE_VBOS = (1 << 11) } CoglFeatureFlags; -#define COGL_TYPE_FEATURE_FLAGS (cogl_feature_flags_get_type ()) -GType cogl_feature_flags_get_type (void) G_GNUC_CONST; - /** * CoglBufferTarget: * @COGL_WINDOW_BUFFER: FIXME @@ -240,9 +197,6 @@ typedef enum COGL_OFFSCREEN_BUFFER = (1 << 2) } CoglBufferTarget; -#define COGL_TYPE_BUFFER_TARGET (cogl_buffer_target_get_type ()) -GType cogl_buffer_target_get_type (void) G_GNUC_CONST; - /** * CoglColor: * @@ -290,21 +244,23 @@ struct _CoglTextureVertex /** * CoglTextureFlags: * @COGL_TEXTURE_NONE: No flags specified - * @COGL_TEXTURE_AUTO_MIPMAP: Enables the automatic generation of the - * mipmap pyramid from the base level image whenever it is updated + * @COGL_TEXTURE_NO_AUTO_MIPMAP: Disables the automatic generation of + * the mipmap pyramid from the base level image whenever it is + * updated. The mipmaps are only generated when the texture is + * rendered with a mipmap filter so it should be free to leave out + * this flag when using other filtering modes. + * @COGL_TEXTURE_NO_SLICING: Disables the slicing of the texture * * Flags to pass to the cogl_texture_new_* family of functions. * * Since: 1.0 */ typedef enum { - COGL_TEXTURE_NONE = 0, - COGL_TEXTURE_AUTO_MIPMAP = 1 << 0 + COGL_TEXTURE_NONE = 0, + COGL_TEXTURE_NO_AUTO_MIPMAP = 1 << 0, + COGL_TEXTURE_NO_SLICING = 1 << 1 } CoglTextureFlags; -#define COGL_TYPE_TEXTURE_FLAGS (cogl_texture_flags_get_type ()) -GType cogl_texture_flags_get_type (void) G_GNUC_CONST; - /** * CoglFogMode: * @COGL_FOG_MODE_LINEAR: Calculates the fog blend factor as: @@ -333,16 +289,12 @@ GType cogl_texture_flags_get_type (void) G_GNUC_CONST; * * Since: 1.0 */ -typedef enum _CoglFogMode -{ +typedef enum { COGL_FOG_MODE_LINEAR, COGL_FOG_MODE_EXPONENTIAL, COGL_FOG_MODE_EXPONENTIAL_SQUARED } CoglFogMode; -#define COGL_TYPE_FOG_MODE (cogl_fog_mode_get_type ()) -GType cogl_fog_mode_get_type (void) G_GNUC_CONST; - G_END_DECLS #endif /* __COGL_TYPES_H__ */ diff --git a/clutter/cogl/cogl-vertex-buffer.h b/clutter/cogl/cogl-vertex-buffer.h index 717281db0..f01b5d3dd 100644 --- a/clutter/cogl/cogl-vertex-buffer.h +++ b/clutter/cogl/cogl-vertex-buffer.h @@ -94,6 +94,29 @@ cogl_vertex_buffer_new (guint n_vertices); guint cogl_vertex_buffer_get_n_vertices (CoglHandle handle); +/** + * CoglAttributeType: + * @COGL_ATTRIBUTE_TYPE_BYTE: Data is the same size of a byte + * @COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE: Data is the same size of an + * unsigned byte + * @COGL_ATTRIBUTE_TYPE_SHORT: Data is the same size of a short integer + * @COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT: Data is the same size of + * an unsigned short integer + * @COGL_ATTRIBUTE_TYPE_FLOAT: Data is the same size of a float + * + * Data types for the components of cogl_vertex_buffer_add() + * + * Since: 1.0 + */ +typedef enum _CoglAttributeType +{ + COGL_ATTRIBUTE_TYPE_BYTE = GL_BYTE, + COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE = GL_UNSIGNED_BYTE, + COGL_ATTRIBUTE_TYPE_SHORT = GL_SHORT, + COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT = GL_UNSIGNED_SHORT, + COGL_ATTRIBUTE_TYPE_FLOAT = GL_FLOAT +} CoglAttributeType; + /** * cogl_vertex_buffer_add: * @handle: A vertex buffer handle @@ -111,10 +134,9 @@ cogl_vertex_buffer_get_n_vertices (CoglHandle handle); * the name can have a detail component, E.g. * "gl_Color::active" or "gl_Color::inactive" * @n_components: The number of components per attribute and must be 1,2,3 or 4 - * @gl_type: Specifies the data type of each component (GL_BYTE, GL_UNSIGNED_BYTE, - * GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT or GL_FLOAT) + * @type: a #CoglAttributeType specifying the data type of each component. * @normalized: If GL_TRUE, this specifies that values stored in an integer - * format should be mapped into the range [-1.0, 1.0] or [0.1, 1.0] + * format should be mapped into the range [-1.0, 1.0] or [0.0, 1.0] * for unsigned values. If GL_FALSE they are converted to floats * directly. * @stride: This specifies the number of bytes from the start of one attribute @@ -156,13 +178,13 @@ cogl_vertex_buffer_get_n_vertices (CoglHandle handle); * (Though you can have multiple groups of interleved attributes) */ void -cogl_vertex_buffer_add (CoglHandle handle, - const char *attribute_name, - guint8 n_components, - GLenum gl_type, - gboolean normalized, - guint16 stride, - const void *pointer); +cogl_vertex_buffer_add (CoglHandle handle, + const char *attribute_name, + guint8 n_components, + CoglAttributeType type, + gboolean normalized, + guint16 stride, + const void *pointer); /** * cogl_vertex_buffer_delete: @@ -226,21 +248,37 @@ void cogl_vertex_buffer_enable (CoglHandle handle, const char *attribute_name); +/** + * CoglVerticesMode: + * @COGL_VERTICES_MODE_POINTS: FIXME, equivalent to %GL_POINTS + * @COGL_VERTICES_MODE_LINE_STRIP: FIXME, equivalent to %GL_LINE_STRIP + * @COGL_VERTICES_MODE_LINE_LOOP: FIXME, equivalent to %GL_LINE_LOOP + * @COGL_VERTICES_MODE_LINES: FIXME, equivalent to %GL_LINES + * @COGL_VERTICES_MODE_TRIANGLE_STRIP: FIXME, equivalent to %GL_TRIANGLE_STRIP + * @COGL_VERTICES_MODE_TRIANGLE_FAN: FIXME, equivalent to %GL_TRIANGLE_FAN + * @COGL_VERTICES_MODE_TRIANGLES: FIXME, equivalent to %GL_TRIANGLES + * + * How vertices passed to cogl_vertex_buffer_draw() and + * cogl_vertex_buffer_draw_elements() should be interpreted + * + * Since: 1.0 + */ +typedef enum _CoglVerticesMode +{ + COGL_VERTICES_MODE_POINTS = GL_POINTS, + COGL_VERTICES_MODE_LINE_STRIP = GL_LINE_STRIP, + COGL_VERTICES_MODE_LINE_LOOP = GL_LINE_LOOP, + COGL_VERTICES_MODE_LINES = GL_LINES, + COGL_VERTICES_MODE_TRIANGLE_STRIP = GL_TRIANGLE_STRIP, + COGL_VERTICES_MODE_TRIANGLE_FAN = GL_TRIANGLE_FAN, + COGL_VERTICES_MODE_TRIANGLES = GL_TRIANGLES +} CoglVerticesMode; + /** * cogl_vertex_buffer_draw: * @handle: A vertex buffer handle - * @mode: Specifies how the vertices should be interpreted, and should be - * a valid GL primitive type: - * - * GL_POINTS - * GL_LINE_STRIP - * GL_LINE_LOOP - * GL_LINES - * GL_TRIANGLE_STRIP - * GL_TRIANGLE_FAN - * GL_TRIANGLES - * - * (Note: only types available in GLES are listed) + * @mode: A #CoglVerticesMode specifying how the vertices should be + * interpreted. * @first: Specifies the index of the first vertex you want to draw with * @count: Specifies the number of vertices you want to draw. * @@ -251,52 +289,90 @@ cogl_vertex_buffer_enable (CoglHandle handle, * drawing. */ void -cogl_vertex_buffer_draw (CoglHandle handle, - GLenum mode, - GLint first, - GLsizei count); +cogl_vertex_buffer_draw (CoglHandle handle, + CoglVerticesMode mode, + int first, + int count); + +/** + * CoglIndicesType: + * @COGL_INDICES_TYPE_UNSIGNED_BYTE: Your indices are unsigned bytes + * @COGL_INDICES_TYPE_UNSIGNED_SHORT: Your indices are unsigned shorts + * @COGL_INDICES_TYPE_UNSIGNED_INT: You indices are unsigned integers + * + * You should aim to use the smallest data type that gives you enough + * range, since it reduces the size of your index array and can help + * reduce the demand on memory bandwidth. + */ +typedef enum _CoglIndicesType +{ + COGL_INDICES_TYPE_UNSIGNED_BYTE, + COGL_INDICES_TYPE_UNSIGNED_SHORT, + COGL_INDICES_TYPE_UNSIGNED_INT +} CoglIndicesType; + +/** + * cogl_vertex_buffer_indices_new: + * @indices_type: a #CoglIndicesType specifying the data type used for + * the indices. + * @indices_array: Specifies the address of your array of indices + * @indices_len: The number of indices in indices_array + * + * Depending on how much geometry you are submitting it can be worthwhile + * optimizing the number of redundant vertices you submit. Using an index + * array allows you to reference vertices multiple times, for example + * during triangle strips. + * + * Returns: A CoglHandle for the indices which you can pass to + * cogl_vertex_buffer_draw_elements(). + */ +CoglHandle +cogl_vertex_buffer_indices_new (CoglIndicesType indices_type, + const void *indices_array, + int indices_len); + +/** + * cogl_vertex_buffer_delete_indices: + * @handle: A vertex buffer handle + * @indices_id: The identifier for a an array of indices previously added to + * the given Cogl vertex buffer using + * cogl_vertex_buffer_add_indices(). + * + * Frees the resources associated with a previously added array of vertex + * indices. + */ +void +cogl_vertex_buffer_delete_indices (CoglHandle handle, + int indices_id); /** * cogl_vertex_buffer_draw_elements: * @handle: A vertex buffer handle - * @mode: Specifies how the vertices should be interpreted, and should be - * a valid GL primitive type: - * - * GL_POINTS - * GL_LINE_STRIP - * GL_LINE_LOOP - * GL_LINES - * GL_TRIANGLE_STRIP - * GL_TRIANGLE_FAN - * GL_TRIANGLES - * - * (Note: only types available in GLES are listed) + * @mode: A #CoglVerticesMode specifying how the vertices should be + * interpreted. + * @indices: A CoglHandle for a set of indices allocated via + * cogl_vertex_buffer_indices_new () * @min_index: Specifies the minimum vertex index contained in indices * @max_index: Specifies the maximum vertex index contained in indices + * @indices_offset: An offset into named indices. The offset marks the first + * index to use for drawing. * @count: Specifies the number of vertices you want to draw. - * @indices_type: Specifies the data type used for the indices, and must be - * one of: - * - * GL_UNSIGNED_BYTE - * GL_UNSIGNED_SHORT - * GL_UNSIGNED_INT - * - * @indices: Specifies the address of your array of indices * * This function lets you use an array of indices to specify the vertices - * within your vertex buffer that you want to draw. + * within your vertex buffer that you want to draw. The indices themselves + * are created by calling cogl_vertex_buffer_indices_new () * * Any un-submitted attribute changes are automatically submitted before * drawing. */ void -cogl_vertex_buffer_draw_elements (CoglHandle handle, - GLenum mode, - GLuint min_index, - GLuint max_index, - GLsizei count, - GLenum indices_type, - const GLvoid *indices); +cogl_vertex_buffer_draw_elements (CoglHandle handle, + CoglVerticesMode mode, + CoglHandle indices, + int min_index, + int max_index, + int indices_offset, + int count); /** * cogl_vertex_buffer_ref: @@ -318,6 +394,46 @@ cogl_vertex_buffer_ref (CoglHandle handle); void cogl_vertex_buffer_unref (CoglHandle handle); +/** + * cogl_vertex_buffer_indices_get_for_quads: + * @n_indices: the number of indices in the vertex buffer. + * + * Creates a vertex buffer containing the indices needed to draw pairs + * of triangles from a list of vertices grouped as quads. There will + * be at least @n_indices entries in the buffer (but there may be + * more). + * + * The indices will follow this pattern: + * + * 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7 ... etc + * + * For example, if you submit vertices for a quad like this: + * + * |[ + * 0 3 + * ######## + * # # + * # # + * ######## + * 1 2 + * ]| + * + * Then you can request 6 indices to render two triangles like this: + * + * |[ + * 0 0 3 + * ## ######## + * # ## ## # + * # ## ## # + * ######## ## + * 1 2 2 + * ]| + * + * Returns: A %CoglHandle containing the indices. The handled is + * owned by Cogl and should not be modified or unref'd. + */ +CoglHandle +cogl_vertex_buffer_indices_get_for_quads (guint n_indices); G_END_DECLS diff --git a/clutter/cogl/cogl.h.in b/clutter/cogl/cogl.h.in index bd3698312..a468cf717 100644 --- a/clutter/cogl/cogl.h.in +++ b/clutter/cogl/cogl.h.in @@ -45,6 +45,7 @@ #include #include #include +#include G_BEGIN_DECLS @@ -55,22 +56,6 @@ G_BEGIN_DECLS * General utility functions for COGL. */ -/* Context manipulation */ - -/** - * cogl_create_context: - * - * FIXME - */ -gboolean cogl_create_context (void); - -/** - * cogl_destroy_context: - * - * FIXME - */ -void cogl_destroy_context (void); - /** * cogl_get_option_group: * @@ -187,7 +172,30 @@ void cogl_frustum (float left, float z_far); /** - * cogl_setup_viewport: + * cogl_ortho: + * @left: The coordinate for the left clipping plane + * @right: The coordinate for the right clipping plane + * @bottom: The coordinate for the bottom clipping plane + * @top: The coordinate for the top clipping plane + * @near: The coordinate for the near clipping plane (may be negative if + * the plane is behind the viewer) + * @far: The coordinate for the far clipping plane (may be negative if + * the plane is behind the viewer) + * + * Replaces the current projection matrix with a parallel projection + * matrix. + * + * Since: 1.0 + */ +void cogl_ortho (float left, + float right, + float bottom, + float top, + float near, + float far); + +/* + * _cogl_setup_viewport: * @width: Width of the viewport * @height: Height of the viewport * @fovy: Field of view angle in degrees @@ -201,9 +209,11 @@ void cogl_frustum (float left, * with one that has a viewing angle of @fovy along the y-axis and a * view scaled according to @aspect along the x-axis. The view is * clipped according to @z_near and @z_far on the z-axis. + * + * This function is used only by Clutter. */ -void cogl_setup_viewport (guint width, - guint height, +void _cogl_setup_viewport (guint width, + guint height, float fovy, float aspect, float z_near, @@ -288,6 +298,14 @@ void cogl_rotate (float angle, */ void cogl_get_modelview_matrix (CoglMatrix *matrix); +/** + * cogl_set_modelview_matrix: + * @matrix: pointer to a CoglMatrix to set as the new model-view matrix + * + * Loads matrix as the new model-view matrix. + */ +void cogl_set_modelview_matrix (CoglMatrix *matrix); + /** * cogl_get_projection_matrix: * @matrix: pointer to a CoglMatrix to recieve the matrix @@ -296,6 +314,14 @@ void cogl_get_modelview_matrix (CoglMatrix *matrix); */ void cogl_get_projection_matrix (CoglMatrix *matrix); +/** + * cogl_set_projection_matrix: + * @matrix: pointer to a CoglMatrix to set as the new projection matrix + * + * Loads matrix as the new projection matrix. + */ +void cogl_set_projection_matrix (CoglMatrix *matrix); + /** * cogl_get_viewport: * @v: pointer to a 4 element array of #floats to @@ -308,7 +334,7 @@ void cogl_get_projection_matrix (CoglMatrix *matrix); void cogl_get_viewport (float v[4]); /** - * cogl_enable_depth_test: + * cogl_set_depth_test_enable: * @setting: %TRUE to enable depth testing or %FALSE to disable. * * Sets whether depth testing is enabled. If it is disabled then the @@ -317,10 +343,19 @@ void cogl_get_viewport (float v[4]); * clutter_actor_lower(), otherwise it will also take into account the * actor's depth. Depth testing is disabled by default. */ -void cogl_enable_depth_test (gboolean setting); +void cogl_set_depth_test_enable (gboolean setting); /** - * cogl_enable_backface_culling: + * cogl_get_depth_test_enable: + * + * Queries if depth testing has been enabled via cogl_set_depth_test_enable() + * + * Returns: TRUE if depth testing is enabled else FALSE + */ +gboolean cogl_get_depth_test_enable (void); + +/** + * cogl_set_backface_culling_enabled: * @setting: %TRUE to enable backface culling or %FALSE to disable. * * Sets whether textures positioned so that their backface is showing @@ -329,7 +364,17 @@ void cogl_enable_depth_test (gboolean setting); * only affects calls to the cogl_rectangle* family of functions and * cogl_vertex_buffer_draw*. Backface culling is disabled by default. */ -void cogl_enable_backface_culling (gboolean setting); +void cogl_set_backface_culling_enabled (gboolean setting); + +/** + * cogl_get_backface_culling_enabled: + * + * Queries if backface culling has been enabled via + * cogl_set_backface_culling_enabled() + * + * Returns: TRUE if backface culling is enabled else FALSE + */ +gboolean cogl_get_backface_culling_enabled (void); /** * cogl_set_fog: @@ -368,9 +413,12 @@ void cogl_disable_fog (void); * @COGL_BUFFER_BIT_COLOR: Selects the primary color buffer * @COGL_BUFFER_BIT_DEPTH: Selects the depth buffer * @COGL_BUFFER_BIT_STENCIL: Selects the stencil buffer + * + * Types of auxiliary buffers + * + * Since: 1.0 */ -typedef enum _CoglBufferBit -{ +typedef enum { COGL_BUFFER_BIT_COLOR = 1L<<0, COGL_BUFFER_BIT_DEPTH = 1L<<1, COGL_BUFFER_BIT_STENCIL = 1L<<2 @@ -379,13 +427,14 @@ typedef enum _CoglBufferBit /** * cogl_clear: * @color: Background color to clear to - * @buffers: A mask of @CoglBufferBit's identifying which auxiliary - * buffers to clear + * @buffers: A mask of #CoglBufferBit's identifying which auxiliary + * buffers to clear * * Clears all the auxiliary buffers identified in the @buffers mask, and if * that includes the color buffer then the specified @color is used. */ -void cogl_clear (const CoglColor *color, gulong buffers); +void cogl_clear (const CoglColor *color, + gulong buffers); /** * cogl_set_source: @@ -628,7 +677,24 @@ void cogl_push_draw_buffer (void); */ void cogl_pop_draw_buffer (void); -/** + +/* + * Internal API available only to Clutter. + * + * These are typically only to deal with the poor seperation of + * responsabilities that currently exists between Clutter and Cogl. + * Eventually a lot of the backend code currently in Clutter will + * move down into Cogl and these functions will be removed. + */ + +void _cogl_destroy_context (void); + +/* XXX: Removed before we release Clutter 1.0 since the implementation + * wasn't complete, and so we assume no one is using this yet. Util we + * have some one with a good usecase, we can't pretend to support breaking + * out into raw OpenGL. */ +#if 0 +/* * cogl_flush_gl_state: * @flags: flags controlling what is flushed; currently unused, pass in 0 * @@ -642,6 +708,7 @@ void cogl_pop_draw_buffer (void); * Since: 1.0 */ void cogl_flush_gl_state (int flags); +#endif /* private */ void _cogl_set_indirect_context (gboolean indirect); diff --git a/clutter/cogl/common/Makefile.am b/clutter/cogl/common/Makefile.am index 138893a14..7a7dd8232 100644 --- a/clutter/cogl/common/Makefile.am +++ b/clutter/cogl/common/Makefile.am @@ -1,3 +1,10 @@ +NULL = + +V = @ +Q = $(V:1=) +QUIET_GEN = $(Q:@=@echo ' GEN '$@;) +QUIET_CP = $(Q:@=@echo ' CP '$@;) + INCLUDES = \ -I$(top_srcdir) \ -I$(top_srcdir)/clutter \ @@ -9,12 +16,49 @@ INCLUDES = \ -DG_LOG_DOMAIN=\"Cogl-Common\" \ -DCLUTTER_COMPILATION +cogl_public_h = \ + $(top_srcdir)/clutter/cogl/cogl-bitmap.h \ + $(top_srcdir)/clutter/cogl/cogl-color.h \ + $(top_srcdir)/clutter/cogl/cogl-debug.h \ + $(top_srcdir)/clutter/cogl/cogl-fixed.h \ + $(top_srcdir)/clutter/cogl/cogl-material.h \ + $(top_srcdir)/clutter/cogl/cogl-matrix.h \ + $(top_srcdir)/clutter/cogl/cogl-offscreen.h \ + $(top_srcdir)/clutter/cogl/cogl-path.h \ + $(top_srcdir)/clutter/cogl/cogl-shader.h \ + $(top_srcdir)/clutter/cogl/cogl-texture.h \ + $(top_srcdir)/clutter/cogl/cogl-types.h \ + $(top_srcdir)/clutter/cogl/cogl-vertex-buffer.h \ + $(top_builddir)/clutter/cogl/cogl.h \ + $(NULL) + noinst_LTLIBRARIES = libclutter-cogl-common.la -EXTRA_DIST = stb_image.c + +cogl-enum-types.h: stamp-cogl-enum-types.h + @true +stamp-cogl-enum-types.h: $(cogl_public_h) Makefile + $(QUIET_GEN)( $(GLIB_MKENUMS) \ + --template $(srcdir)/cogl-enum-types.h.in \ + $(cogl_public_h) ) > xgen-ceth \ + && (cmp -s xgen-ceth cogl-enum-types.h || cp -f xgen-ceth cogl-enum-types.h) \ + && cp -f cogl-enum-types.h $(top_builddir)/clutter/cogl/cogl-enum-types.h \ + && rm -f xgen-ceth \ + && echo timestamp > $(@F) + +cogl-enum-types.c: cogl-enum-types.h + $(QUIET_GEN)( $(GLIB_MKENUMS) \ + --template $(srcdir)/cogl-enum-types.c.in \ + $(cogl_public_h) ) > xgen-cetc \ + && cp -f xgen-cetc cogl-enum-types.c \ + && rm -f xgen-cetc + +BUILT_SOURCES = cogl-enum-types.h cogl-enum-types.c libclutter_cogl_common_la_CPPFLAGS = $(CLUTTER_CFLAGS) $(COGL_DEBUG_CFLAGS) $(CLUTTER_DEBUG_CFLAGS) $(MAINTAINER_CFLAGS) libclutter_cogl_common_la_LIBADD = -lm $(CLUTTER_LIBS) libclutter_cogl_common_la_SOURCES = \ + $(top_builddir)/clutter/cogl/common/cogl-enum-types.h \ + $(top_builddir)/clutter/cogl/common/cogl-enum-types.c \ cogl-handle.h \ cogl-internal.h \ cogl.c \ @@ -39,4 +83,11 @@ libclutter_cogl_common_la_SOURCES = \ cogl-matrix-stack.h \ cogl-material.c \ cogl-material-private.h \ - cogl-debug.c + cogl-blend-string.c \ + cogl-blend-string.h \ + cogl-debug.c \ + $(NULL) + +EXTRA_DIST = stb_image.c cogl-enum-types.h.in cogl-enum-types.c.in +CLEANFILES = stamp-cogl-enum-types.h +DISTCLEANFILES = cogl-enum-types.h cogl-enum-types.c diff --git a/clutter/cogl/common/cogl-blend-string.c b/clutter/cogl/common/cogl-blend-string.c new file mode 100644 index 000000000..2e7bdd8d3 --- /dev/null +++ b/clutter/cogl/common/cogl-blend-string.c @@ -0,0 +1,999 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2009 Intel Corporation. + * + * 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. + * + * Authors: + * Robert Bragg + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include + +#include "cogl.h" +#include "cogl-internal.h" +#include "cogl-context.h" +#include "cogl-debug.h" +#include "cogl-blend-string.h" + +typedef enum _ParserState +{ + PARSER_STATE_EXPECT_DEST_CHANNELS, + PARSER_STATE_SCRAPING_DEST_CHANNELS, + PARSER_STATE_EXPECT_FUNCTION_NAME, + PARSER_STATE_SCRAPING_FUNCTION_NAME, + PARSER_STATE_EXPECT_ARG_START, + PARSER_STATE_EXPECT_STATEMENT_END +} ParserState; + +typedef enum _ParserArgState +{ + PARSER_ARG_STATE_START, + PARSER_ARG_STATE_EXPECT_MINUS, + PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME, + PARSER_ARG_STATE_SCRAPING_COLOR_SRC_NAME, + PARSER_ARG_STATE_MAYBE_COLOR_MASK, + PARSER_ARG_STATE_SCRAPING_MASK, + PARSER_ARG_STATE_MAYBE_MULT, + PARSER_ARG_STATE_EXPECT_OPEN_PAREN, + PARSER_ARG_STATE_EXPECT_FACTOR, + PARSER_ARG_STATE_MAYBE_SRC_ALPHA_SATURATE, + PARSER_ARG_STATE_MAYBE_MINUS, + PARSER_ARG_STATE_EXPECT_CLOSE_PAREN, + PARSER_ARG_STATE_EXPECT_END +} ParserArgState; + + +#define DEFINE_COLOR_SOURCE(NAME, NAME_LEN) \ + {.type = COGL_BLEND_STRING_COLOR_SOURCE_ ## NAME, \ + .name = #NAME, \ + .name_len = NAME_LEN} + +static CoglBlendStringColorSourceInfo blending_color_sources[] = { + DEFINE_COLOR_SOURCE (SRC_COLOR, 9), + DEFINE_COLOR_SOURCE (DST_COLOR, 9), + DEFINE_COLOR_SOURCE (CONSTANT, 8) +}; + +static CoglBlendStringColorSourceInfo tex_combine_color_sources[] = { + DEFINE_COLOR_SOURCE (TEXTURE, 7), + /* DEFINE_COLOR_SOURCE (TEXTURE_N, *) - handled manually */ + DEFINE_COLOR_SOURCE (PRIMARY, 7), + DEFINE_COLOR_SOURCE (CONSTANT, 8), + DEFINE_COLOR_SOURCE (PREVIOUS, 8) +}; + +static CoglBlendStringColorSourceInfo tex_combine_texture_n_color_source = { + .type = COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N, + .name = "TEXTURE_N", + .name_len = 0 +}; + +#undef DEFINE_COLOR_SOURCE + +#define DEFINE_FUNCTION(NAME, NAME_LEN, ARGC) \ + { .type = COGL_BLEND_STRING_FUNCTION_ ## NAME, \ + .name = #NAME, \ + .name_len = NAME_LEN, \ + .argc = ARGC } + +/* NB: These must be sorted so any name that's a subset of another + * comes later than the longer name. */ +static CoglBlendStringFunctionInfo tex_combine_functions[] = { + DEFINE_FUNCTION (AUTO_COMPOSITE, 14, 0), + DEFINE_FUNCTION (REPLACE, 7, 1), + DEFINE_FUNCTION (MODULATE, 8, 2), + DEFINE_FUNCTION (ADD_SIGNED, 10, 2), + DEFINE_FUNCTION (ADD, 3, 2), + DEFINE_FUNCTION (INTERPOLATE, 11, 3), + DEFINE_FUNCTION (SUBTRACT, 8, 2), + DEFINE_FUNCTION (DOT3_RGBA, 9, 2), + DEFINE_FUNCTION (DOT3_RGB, 8, 2) +}; + +static CoglBlendStringFunctionInfo blend_functions[] = { + DEFINE_FUNCTION (AUTO_COMPOSITE, 14, 0), + DEFINE_FUNCTION (ADD, 3, 2) +}; + +#undef DEFINE_FUNCTION + +GQuark +_cogl_blend_string_error_quark (void) +{ + return g_quark_from_static_string ("cogl-blend-string-error-quark"); +} + +void +_cogl_blend_string_split_rgba_statement (CoglBlendStringStatement *statement, + CoglBlendStringStatement *rgb, + CoglBlendStringStatement *a) +{ + int i; + + memcpy (rgb, statement, sizeof (CoglBlendStringStatement)); + memcpy (a, statement, sizeof (CoglBlendStringStatement)); + + rgb->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB; + a->mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA; + + for (i = 0; i < statement->function->argc; i++) + { + CoglBlendStringArgument *arg = &statement->args[i]; + CoglBlendStringArgument *rgb_arg = &rgb->args[i]; + CoglBlendStringArgument *a_arg = &a->args[i]; + + if (arg->source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA) + { + rgb_arg->source.mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB; + a_arg->source.mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA; + } + + if (arg->factor.is_color && + arg->factor.source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA) + { + rgb_arg->factor.source.mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB; + a_arg->factor.source.mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA; + } + } +} + +static gboolean +validate_tex_combine_statements (CoglBlendStringStatement *statements, + int n_statements, + GError **error) +{ + int i, j; + const char *error_string; + CoglBlendStringError detail = COGL_BLEND_STRING_ERROR_INVALID_ERROR; + + for (i = 0; i < n_statements; i++) + { +#ifdef HAVE_COGL_GLES2 + if (statements[i].function->type != COGL_BLEND_STRING_FUNCTION_MODULATE) + { + error_string = "Using anything but MODULATE() for texture combining" + " under GLES 2 is currently unsupported"; + detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR; + goto error; + } +#endif + for (j = 0; j < statements[i].function->argc; j++) + { + CoglBlendStringArgument *arg = &statements[i].args[j]; + if (arg->source.is_zero) + { + error_string = "You can't use the constant '0' as a texture " + "combine argument"; + goto error; + } + if (!arg->factor.is_one) + { + error_string = "Argument factors are only relevant to blending " + "not texture combining"; + goto error; + } +#ifdef HAVE_COGL_GLES2 + if (arg->source.info->type == COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT) + { + error_string = "Using a constant for texture combining isn't " + "currently supported with GLES 2 " + "(TODO: glTexEnvf)"; + detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR; + goto error; + } +#endif + } + } + + return TRUE; + +error: + g_set_error (error, + COGL_BLEND_STRING_ERROR, + detail, + "Invalid texture combine string: %s", + error_string); + + if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS) + { + g_debug ("Invalid texture combine string: %s", + error_string); + } + return FALSE; +} + +static gboolean +validate_blend_statements (CoglBlendStringStatement *statements, + int n_statements, + GError **error) +{ + int i, j; + const char *error_string; + CoglBlendStringError detail = COGL_BLEND_STRING_ERROR_INVALID_ERROR; + +#ifdef HAVE_COGL_GL + _COGL_GET_CONTEXT (ctx, 0); +#endif + +#ifdef HAVE_COGL_GL + if (n_statements == 2) + { + /* glBlendEquationSeperate is GL 2.0 only */ + if (!ctx->pf_glBlendEquationSeparate && + statements[0].function->type != statements[1].function->type) + { + error_string = "Separate blend functions for the RGB an A " + "channels isn't supported by the driver"; + detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR; + goto error; + } + } +#elif defined(HAVE_COGL_GLES) + if (n_statements != 1) + { + error_string = "Separate blend functions for the RGB an A " + "channels isn't supported by the GLES 1"; + detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR; + goto error; + } +#endif + + for (i = 0; i < n_statements; i++) + for (j = 0; j < statements[i].function->argc; j++) + { + CoglBlendStringArgument *arg = &statements[i].args[j]; + + if (arg->source.is_zero) + continue; + + if ((j == 0 && + arg->source.info->type != + COGL_BLEND_STRING_COLOR_SOURCE_SRC_COLOR) + || (j == 1 && + arg->source.info->type != + COGL_BLEND_STRING_COLOR_SOURCE_DST_COLOR)) + { + error_string = "For blending you must always use SRC_COLOR " + "for arg0 and DST_COLOR for arg1"; + goto error; + } + +#ifdef HAVE_COGL_GLES + if (arg->factor.is_color && + arg->factor.source.info->type == COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT) + { + error_string = "GLES Doesn't support constant blend factors"; + detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR; + goto error; + } +#endif + } + + return TRUE; + +error: + g_set_error (error, + COGL_BLEND_STRING_ERROR, + detail, + "Invalid blend string: %s", + error_string); + return FALSE; +} + +static gboolean +validate_statements_for_context (CoglBlendStringStatement *statements, + int n_statements, + CoglBlendStringContext context, + GError **error) +{ + const char *error_string; + + if (n_statements == 1) + { + if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_ALPHA) + { + error_string = "You need to also give a blend statement for the RGB" + "channels"; + goto error; + } + else if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB) + { + error_string = "You need to also give a blend statement for the " + "Alpha channel"; + goto error; + } + } + + if (context == COGL_BLEND_STRING_CONTEXT_BLENDING) + return validate_blend_statements (statements, n_statements, error); + else + return validate_tex_combine_statements (statements, n_statements, error); + +error: + g_set_error (error, + COGL_BLEND_STRING_ERROR, + COGL_BLEND_STRING_ERROR_INVALID_ERROR, + "Invalid %s string: %s", + context == COGL_BLEND_STRING_CONTEXT_BLENDING ? + "blend" : "texture combine", + error_string); + + if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS) + { + g_debug ("Invalid %s string: %s", + context == COGL_BLEND_STRING_CONTEXT_BLENDING ? + "blend" : "texture combine", + error_string); + } + + return FALSE; +} + +static void +print_argument (CoglBlendStringArgument *arg) +{ + const char *mask_names[] = { + "RGB", + "A", + "RGBA" + }; + + g_print (" Arg:\n"); + g_print (" is zero = %s\n", arg->source.is_zero ? "yes" : "no"); + if (!arg->source.is_zero) + { + g_print (" color source = %s\n", arg->source.info->name); + g_print (" one minus = %s\n", arg->source.one_minus ? "yes" : "no"); + g_print (" mask = %s\n", mask_names[arg->source.mask]); + g_print (" texture = %d\n", arg->source.texture); + g_print ("\n"); + g_print (" factor is_one = %s\n", arg->factor.is_one ? "yes" : "no"); + g_print (" factor is_src_alpha_saturate = %s\n", + arg->factor.is_src_alpha_saturate ? "yes" : "no"); + g_print (" factor is_color = %s\n", arg->factor.is_color ? "yes" : "no"); + if (arg->factor.is_color) + { + g_print (" factor color:is zero = %s\n", + arg->factor.source.is_zero ? "yes" : "no"); + g_print (" factor color:color source = %s\n", + arg->factor.source.info->name); + g_print (" factor color:one minus = %s\n", + arg->factor.source.one_minus ? "yes" : "no"); + g_print (" factor color:mask = %s\n", + mask_names[arg->factor.source.mask]); + g_print (" factor color:texture = %d\n", + arg->factor.source.texture); + } + } +} + +static void +print_statement (int num, CoglBlendStringStatement *statement) +{ + const char *mask_names[] = { + "RGB", + "A", + "RGBA" + }; + int i; + g_print ("Statement %d:\n", num); + g_print (" Destination channel mask = %s\n", + mask_names[statement->mask]); + g_print (" Function = %s\n", statement->function->name); + for (i = 0; i < statement->function->argc; i++) + print_argument (&statement->args[i]); +} + +static const CoglBlendStringFunctionInfo * +get_function_info (const char *mark, + const char *p, + CoglBlendStringContext context) +{ + size_t len = p - mark; + CoglBlendStringFunctionInfo *functions; + size_t array_len; + int i; + + if (context == COGL_BLEND_STRING_CONTEXT_BLENDING) + { + functions = blend_functions; + array_len = G_N_ELEMENTS (blend_functions); + } + else + { + functions = tex_combine_functions; + array_len = G_N_ELEMENTS (tex_combine_functions); + } + + for (i = 0; i < array_len; i++) + { + if (len >= functions[i].name_len + && strncmp (mark, functions[i].name, functions[i].name_len) == 0) + return &functions[i]; + } + return NULL; +} + +static const CoglBlendStringColorSourceInfo * +get_color_src_info (const char *mark, + const char *p, + CoglBlendStringContext context) +{ + size_t len = p - mark; + CoglBlendStringColorSourceInfo *sources; + size_t array_len; + int i; + + if (context == COGL_BLEND_STRING_CONTEXT_BLENDING) + { + sources = blending_color_sources; + array_len = G_N_ELEMENTS (blending_color_sources); + } + else + { + sources = tex_combine_color_sources; + array_len = G_N_ELEMENTS (tex_combine_color_sources); + } + + for (i = 0; i < array_len; i++) + { + if (len >= sources[i].name_len + && strncmp (mark, sources[i].name, sources[i].name_len) == 0) + return &sources[i]; + } + + if (len >= 9 && + strncmp (mark, "TEXTURE_", 8) == 0 && + g_ascii_isdigit (mark[8])) + { + return &tex_combine_texture_n_color_source; + } + + return NULL; +} + +static gboolean +is_symbol_char (const char c) +{ + return (g_ascii_isalpha (c) || c == '_') ? TRUE : FALSE; +} + +static gboolean +parse_argument (const char *string, /* original user string */ + const char **ret_p, /* start of argument IN:OUT */ + const CoglBlendStringStatement *statement, + int current_arg, + CoglBlendStringArgument *arg, /* OUT */ + CoglBlendStringContext context, + GError **error) +{ + const char *p = *ret_p; + const char *mark; + const char *error_string; + ParserArgState state = PARSER_ARG_STATE_START; + gboolean parsing_factor = FALSE; + + arg->source.is_zero = FALSE; + arg->source.info = NULL; + arg->source.texture = 0; + arg->source.one_minus = FALSE; + arg->source.mask = statement->mask; + + arg->factor.is_one = FALSE; + arg->factor.is_color = FALSE; + arg->factor.is_src_alpha_saturate = FALSE; + + arg->factor.source.is_zero = FALSE; + arg->factor.source.info = NULL; + arg->factor.source.texture = 0; + arg->factor.source.one_minus = FALSE; + arg->factor.source.mask = statement->mask; + + do + { + if (g_ascii_isspace (*p)) + continue; + + if (*p == '\0') + { + error_string = "Unexpected end of string while parsing argument"; + goto error; + } + + switch (state) + { + case PARSER_ARG_STATE_START: + if (*p == '1') + state = PARSER_ARG_STATE_EXPECT_MINUS; + else if (*p == '0') + { + arg->source.is_zero = TRUE; + state = PARSER_ARG_STATE_EXPECT_END; + } + else + { + p--; /* backtrack */ + state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME; + } + continue; + + case PARSER_ARG_STATE_EXPECT_MINUS: + if (*p != '-') + { + error_string = "expected a '-' following the 1"; + goto error; + } + arg->source.one_minus = TRUE; + state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME; + continue; + + case PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME: + if (!is_symbol_char (*p)) + { + error_string = "expected a color source name"; + goto error; + } + state = PARSER_ARG_STATE_SCRAPING_COLOR_SRC_NAME; + mark = p; + if (parsing_factor) + arg->factor.is_color = TRUE; + + /* fall through */ + case PARSER_ARG_STATE_SCRAPING_COLOR_SRC_NAME: + if (!is_symbol_char (*p)) + { + CoglBlendStringColorSource *source = + parsing_factor ? &arg->factor.source : &arg->source; + source->info = get_color_src_info (mark, p, context); + if (!source->info) + { + error_string = "Unknown color source name"; + goto error; + } + if (source->info->type == + COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N) + { + char *endp; + source->texture = + strtoul (&mark[strlen ("TEXTURE_")], &endp, 10); + if (mark == endp) + { + error_string = "invalid texture number given with " + "TEXTURE_N color source"; + goto error; + } + p = endp; + } + state = PARSER_ARG_STATE_MAYBE_COLOR_MASK; + } + else + continue; + + /* fall through */ + case PARSER_ARG_STATE_MAYBE_COLOR_MASK: + if (*p != '[') + { + p--; /* backtrack */ + if (!parsing_factor) + state = PARSER_ARG_STATE_MAYBE_MULT; + else + state = PARSER_ARG_STATE_EXPECT_END; + continue; + } + state = PARSER_ARG_STATE_SCRAPING_MASK; + mark = p; + + /* fall through */ + case PARSER_ARG_STATE_SCRAPING_MASK: + if (*p == ']') + { + size_t len = p - mark; + CoglBlendStringColorSource *source = + parsing_factor ? &arg->factor.source : &arg->source; + + if (len == 5 && strncmp (mark, "[RGBA", len) == 0) + { + if (statement->mask != COGL_BLEND_STRING_CHANNEL_MASK_RGBA) + { + error_string = "You can't use an RGBA color mask if the " + "statement hasn't also got an RGBA= mask"; + goto error; + } + source->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGBA; + } + else if (len == 4 && strncmp (mark, "[RGB", len) == 0) + source->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB; + else if (len == 2 && strncmp (mark, "[A", len) == 0) + source->mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA; + else + { + error_string = "Expected a channel mask of [RGBA]" + "[RGB] or [A]"; + goto error; + } + if (parsing_factor) + state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN; + else + state = PARSER_ARG_STATE_MAYBE_MULT; + } + continue; + + case PARSER_ARG_STATE_EXPECT_OPEN_PAREN: + if (*p != '(') + { + error_string = "Expected '(' before blend factor - the parser " + "currently requires that all blend factors " + "following a '*' be surrounded in brackets"; + goto error; + } + parsing_factor = TRUE; + state = PARSER_ARG_STATE_EXPECT_FACTOR; + continue; + + case PARSER_ARG_STATE_EXPECT_FACTOR: + if (*p == '1') + state = PARSER_ARG_STATE_MAYBE_MINUS; + else if (*p == '0') + { + arg->source.is_zero = TRUE; + state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN; + } + else + { + state = PARSER_ARG_STATE_MAYBE_SRC_ALPHA_SATURATE; + mark = p; + } + continue; + + case PARSER_ARG_STATE_MAYBE_SRC_ALPHA_SATURATE: + if (!is_symbol_char (*p)) + { + size_t len = p - mark; + if (len >= strlen ("SRC_ALPHA_SATURATE") && + strncmp (mark, "SRC_ALPHA_SATURATE", len) == 0) + { + arg->factor.is_src_alpha_saturate = TRUE; + state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN; + } + else + { + state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME; + p = mark - 1; /* backtrack */ + } + } + continue; + + case PARSER_ARG_STATE_MAYBE_MINUS: + if (*p == '-') + { + arg->factor.source.one_minus = TRUE; + state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME; + } + else + { + arg->factor.is_one = TRUE; + state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN; + } + continue; + + case PARSER_ARG_STATE_EXPECT_CLOSE_PAREN: + if (*p != ')') + { + error_string = "Expected closing parenthesis after blend factor"; + goto error; + } + state = PARSER_ARG_STATE_EXPECT_END; + continue; + + case PARSER_ARG_STATE_MAYBE_MULT: + if (*p == '*') + { + state = PARSER_ARG_STATE_EXPECT_OPEN_PAREN; + continue; + } + arg->factor.is_one = TRUE; + state = PARSER_ARG_STATE_EXPECT_END; + + /* fall through */ + case PARSER_ARG_STATE_EXPECT_END: + if (*p != ',' && *p != ')') + { + error_string = "expected , or )"; + goto error; + } + + *ret_p = p - 1; + return TRUE; + } + } + while (p++); + +error: + { + int offset = p - string; + g_set_error (error, + COGL_BLEND_STRING_ERROR, + COGL_BLEND_STRING_ERROR_ARGUMENT_PARSE_ERROR, + "Syntax error for argument %d at offset %d: %s", + current_arg, + offset, + error_string); + + if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS) + { + g_debug ("Syntax error for argument %d at offset %d: %s", + current_arg, offset, error_string); + } + return FALSE; + } +} + +int +_cogl_blend_string_compile (const char *string, + CoglBlendStringContext context, + CoglBlendStringStatement *statements, + GError **error) +{ + const char *p = string; + const char *mark; + const char *error_string; + ParserState state = PARSER_STATE_EXPECT_DEST_CHANNELS; + CoglBlendStringStatement *statement = statements; + int current_statement = 0; + int current_arg = 0; + int remaining_argc; + +#if 0 + cogl_debug_flags |= COGL_DEBUG_BLEND_STRINGS; +#endif + + if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS) + { + COGL_NOTE (BLEND_STRINGS, "Compiling %s string:\n%s\n", + context == COGL_BLEND_STRING_CONTEXT_BLENDING ? + "blend" : "texture combine", + string); + } + + do + { + if (g_ascii_isspace (*p)) + continue; + + if (*p == '\0') + { + switch (state) + { + case PARSER_STATE_EXPECT_DEST_CHANNELS: + if (current_statement != 0) + goto finished; + error_string = "Empty statement"; + goto error; + case PARSER_STATE_SCRAPING_DEST_CHANNELS: + error_string = "Expected an '=' following the destination " + "channel mask"; + goto error; + case PARSER_STATE_EXPECT_FUNCTION_NAME: + error_string = "Expected a function name"; + goto error; + case PARSER_STATE_SCRAPING_FUNCTION_NAME: + error_string = "Expected parenthesis after the function name"; + goto error; + case PARSER_STATE_EXPECT_ARG_START: + error_string = "Expected to find the start of an argument"; + goto error; + case PARSER_STATE_EXPECT_STATEMENT_END: + error_string = "Expected closing parenthesis for statement"; + goto error; + } + } + + switch (state) + { + case PARSER_STATE_EXPECT_DEST_CHANNELS: + mark = p; + state = PARSER_STATE_SCRAPING_DEST_CHANNELS; + + /* fall through */ + case PARSER_STATE_SCRAPING_DEST_CHANNELS: + if (*p != '=') + continue; + if (strncmp (mark, "RGBA", 4) == 0) + statement->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGBA; + else if (strncmp (mark, "RGB", 3) == 0) + statement->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB; + else if (strncmp (mark, "A", 1) == 0) + statement->mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA; + else + { + error_string = "Unknown destination channel mask; " + "expected RGBA=, RGB= or A="; + goto error; + } + state = PARSER_STATE_EXPECT_FUNCTION_NAME; + continue; + + case PARSER_STATE_EXPECT_FUNCTION_NAME: + mark = p; + state = PARSER_STATE_SCRAPING_FUNCTION_NAME; + + /* fall through */ + case PARSER_STATE_SCRAPING_FUNCTION_NAME: + if (*p != '(') + { + if (!is_symbol_char (*p)) + { + error_string = "non alpha numeric character in function" + "name"; + goto error; + } + continue; + } + statement->function = get_function_info (mark, p, context); + if (!statement->function) + { + error_string = "Unknown function name"; + goto error; + } + remaining_argc = statement->function->argc; + current_arg = 0; + state = PARSER_STATE_EXPECT_ARG_START; + + /* fall through */ + case PARSER_STATE_EXPECT_ARG_START: + if (*p != '(' && *p != ',') + continue; + if (remaining_argc) + { + p++; /* parse_argument expects to see the first char of the arg */ + if (!parse_argument (string, &p, statement, + current_arg, &statement->args[current_arg], + context, error)) + return 0; + current_arg++; + remaining_argc--; + } + if (!remaining_argc) + state = PARSER_STATE_EXPECT_STATEMENT_END; + continue; + + case PARSER_STATE_EXPECT_STATEMENT_END: + if (*p != ')') + { + error_string = "Expected end of statement"; + goto error; + } + state = PARSER_STATE_EXPECT_DEST_CHANNELS; + if (current_statement++ == 1) + goto finished; + statement = &statements[current_statement]; + } + } + while (p++); + +finished: + + if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS) + { + if (current_statement > 0) + print_statement (0, &statements[0]); + if (current_statement > 1) + print_statement (1, &statements[1]); + } + + if (!validate_statements_for_context (statements, + current_statement, + context, + error)) + return 0; + + return current_statement; + +error: + { + int offset = p - string; + g_set_error (error, + COGL_BLEND_STRING_ERROR, + COGL_BLEND_STRING_ERROR_PARSE_ERROR, + "Syntax error at offset %d: %s", + offset, + error_string); + + if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS) + { + g_debug ("Syntax error at offset %d: %s", + offset, error_string); + } + return 0; + } +} + +/* + * INTERNAL TESTING CODE ... + */ + +struct _TestString +{ + const char *string; + CoglBlendStringContext context; +}; + +int +_cogl_blend_string_test (void) +{ + struct _TestString strings[] = { + {" A = MODULATE ( TEXTURE[RGB], PREVIOUS[A], PREVIOUS[A] ) ", + COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE }, + {" RGB = MODULATE ( TEXTURE[RGB], PREVIOUS[A] ) ", + COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE }, + {"A=ADD(TEXTURE[A],PREVIOUS[RGB])", + COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE }, + {"A=ADD(TEXTURE[A],PREVIOUS[RGB])", + COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE }, + + {"RGBA = ADD(SRC_COLOR*(SRC_COLOR[A]), DST_COLOR*(1-SRC_COLOR[A]))", + COGL_BLEND_STRING_CONTEXT_BLENDING }, + {"RGB = ADD(SRC_COLOR, DST_COLOR*(0))", + COGL_BLEND_STRING_CONTEXT_BLENDING }, + {"RGB = ADD(SRC_COLOR, 0)", + COGL_BLEND_STRING_CONTEXT_BLENDING }, + {"RGB = ADD()", + COGL_BLEND_STRING_CONTEXT_BLENDING }, + {"RGB = ADD(SRC_COLOR, 0, DST_COLOR)", + COGL_BLEND_STRING_CONTEXT_BLENDING }, + {NULL} + }; + int i; + + GError *error = NULL; + for (i = 0; strings[i].string; i++) + { + CoglBlendStringStatement statements[2]; + int count = _cogl_blend_string_compile (strings[i].string, + strings[i].context, + statements, + &error); + if (!count) + { + g_print ("Failed to parse string:\n%s\n%s\n", + strings[i].string, + error->message); + g_error_free (error); + error = NULL; + continue; + } + g_print ("Original:\n"); + g_print ("%s\n", strings[i].string); + if (count > 0) + print_statement (0, &statements[0]); + if (count > 1) + print_statement (1, &statements[1]); + } + + return 0; +} + diff --git a/clutter/cogl/common/cogl-blend-string.h b/clutter/cogl/common/cogl-blend-string.h new file mode 100644 index 000000000..a3e3888f8 --- /dev/null +++ b/clutter/cogl/common/cogl-blend-string.h @@ -0,0 +1,151 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2009 Intel Corporation. + * + * 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. + * + * Authors: + * Robert Bragg + */ + +#ifndef COGL_BLEND_STRING_H +#define COGL_BLEND_STRING_H + +#include +#include + +typedef enum _CoglBlendStringContext +{ + COGL_BLEND_STRING_CONTEXT_BLENDING, + COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE +} CoglBlendStringContext; + +#define COGL_BLEND_STRING_ERROR _cogl_blend_string_error_quark () + +typedef enum _CoglBlendStringError +{ + COGL_BLEND_STRING_ERROR_PARSE_ERROR, + COGL_BLEND_STRING_ERROR_ARGUMENT_PARSE_ERROR, + COGL_BLEND_STRING_ERROR_INVALID_ERROR, + COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR +} CoglBlendStringError; + +/* NB: debug stringify code will get upset if these + * are re-ordered */ +typedef enum _CoglBlendStringChannelMask +{ + COGL_BLEND_STRING_CHANNEL_MASK_RGB, + COGL_BLEND_STRING_CHANNEL_MASK_ALPHA, + COGL_BLEND_STRING_CHANNEL_MASK_RGBA +} CoglBlendStringChannelMask; + +typedef enum _CoglBlendStringColorSourceType +{ + /* blending */ + COGL_BLEND_STRING_COLOR_SOURCE_SRC_COLOR, + COGL_BLEND_STRING_COLOR_SOURCE_DST_COLOR, + + /* shared */ + COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT, + + /* texture combining */ + COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE, + COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N, + COGL_BLEND_STRING_COLOR_SOURCE_PRIMARY, + COGL_BLEND_STRING_COLOR_SOURCE_PREVIOUS +} CoglBlendStringColorSourceType; + +typedef struct _CoglBlendStringColorSourceInfo +{ + CoglBlendStringColorSourceType type; + const char *name; + size_t name_len; +} CoglBlendStringColorSourceInfo; + +typedef struct _CoglBlendStringColorSource +{ + gboolean is_zero; + const CoglBlendStringColorSourceInfo *info; + int texture; /* for the TEXTURE_N color source */ + gboolean one_minus; + CoglBlendStringChannelMask mask; +} CoglBlendStringColorSource; + +typedef struct _CoglBlendStringFactor +{ + gboolean is_one; + gboolean is_src_alpha_saturate; + gboolean is_color; + CoglBlendStringColorSource source; +} CoglBlendStringFactor; + +typedef struct _CoglBlendStringArgument +{ + CoglBlendStringColorSource source; + CoglBlendStringFactor factor; +} CoglBlendStringArgument; + +typedef enum _CoglBlendStringFunctionType +{ + /* shared */ + COGL_BLEND_STRING_FUNCTION_AUTO_COMPOSITE, + COGL_BLEND_STRING_FUNCTION_ADD, + + /* texture combine only */ + COGL_BLEND_STRING_FUNCTION_REPLACE, + COGL_BLEND_STRING_FUNCTION_MODULATE, + COGL_BLEND_STRING_FUNCTION_ADD_SIGNED, + COGL_BLEND_STRING_FUNCTION_INTERPOLATE, + COGL_BLEND_STRING_FUNCTION_SUBTRACT, + COGL_BLEND_STRING_FUNCTION_DOT3_RGB, + COGL_BLEND_STRING_FUNCTION_DOT3_RGBA +} CoglBlendStringFunctionType; + +typedef struct _CoglBlendStringFunctionInfo +{ + enum _CoglBlendStringFunctionType type; + const char *name; + size_t name_len; + int argc; +} CoglBlendStringFunctionInfo; + +typedef struct _CoglBlendStringStatement +{ + CoglBlendStringChannelMask mask; + const CoglBlendStringFunctionInfo *function; + CoglBlendStringArgument args[3]; +} CoglBlendStringStatement; + + +gboolean +_cogl_blend_string_compile (const char *string, + CoglBlendStringContext context, + CoglBlendStringStatement *statements, + GError **error); + +void +_cogl_blend_string_split_rgba_statement (CoglBlendStringStatement *statement, + CoglBlendStringStatement *rgb, + CoglBlendStringStatement *a); + +GQuark +_cogl_blend_string_error_quark (void); + +#endif /* COGL_BLEND_STRING_H */ + diff --git a/clutter/cogl/common/cogl-current-matrix.c b/clutter/cogl/common/cogl-current-matrix.c index 0080af0d1..6d069bc66 100644 --- a/clutter/cogl/common/cogl-current-matrix.c +++ b/clutter/cogl/common/cogl-current-matrix.c @@ -45,6 +45,9 @@ #define glFrustum(L,R,B,T,N,F) \ glFrustumf((GLfloat)L, (GLfloat)R, (GLfloat)B, \ (GLfloat)T, (GLfloat)N, (GLfloat)F) + +#define glOrtho glOrthof + #endif #include @@ -209,30 +212,57 @@ _cogl_current_matrix_frustum (float left, } void -_cogl_current_matrix_ortho (float left, - float right, - float bottom, - float top, - float near_val, - float far_val) +_cogl_current_matrix_perspective (float fov_y, + float aspect, + float z_near, + float z_far) +{ + _COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL); + + if (current_stack != NULL) + _cogl_matrix_stack_perspective (current_stack, + fov_y, aspect, z_near, z_far); + else + { + /* NB: There is no glPerspective() (only gluPerspective()) so we use + * cogl_matrix_perspective: */ + CoglMatrix matrix; + _cogl_get_matrix (ctx->matrix_mode, &matrix); + cogl_matrix_perspective (&matrix, + fov_y, aspect, z_near, z_far); + _cogl_current_matrix_load (&matrix); + } +} + +void +_cogl_current_matrix_ortho (float left, + float right, + float bottom, + float top, + float near_val, + float far_val) { -#if 0 _COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL); if (current_stack != NULL) _cogl_matrix_stack_ortho (current_stack, left, right, - top, bottom, + bottom, top, near_val, far_val); else - GE (glOrtho (left, right, bottom, top, near_val, far_val)); + { +#ifdef HAVE_COGL_GLES2 + /* NB: GLES 2 has no glOrtho(): */ + CoglMatrix matrix; + _cogl_get_matrix (ctx->matrix_mode, &matrix); + cogl_matrix_ortho (&matrix, + left, right, bottom, top, near_val, far_val); + _cogl_current_matrix_load (&matrix); #else - /* Nobody is using glOrtho right now anyway, so not bothering */ - g_warning ("%s not implemented, need to code cogl_matrix_ortho() if you need" - " this function", - G_STRFUNC); + GE (glOrtho (left, right, bottom, top, near_val, far_val)); #endif + } } void @@ -276,6 +306,12 @@ _cogl_get_matrix (CoglMatrixMode mode, } } +void +_cogl_set_matrix (const CoglMatrix *matrix) +{ + _cogl_current_matrix_load (matrix); +} + void _cogl_current_matrix_state_init (void) { @@ -354,85 +390,19 @@ cogl_rotate (float angle, float x, float y, float z) } void -_cogl_set_matrix (const CoglMatrix *matrix) -{ - _cogl_current_matrix_load (matrix); -} - -void -cogl_get_modelview_matrix (CoglMatrix *matrix) -{ - _cogl_get_matrix (COGL_MATRIX_MODELVIEW, - matrix); -} - -void -cogl_get_projection_matrix (CoglMatrix *matrix) -{ - _cogl_get_matrix (COGL_MATRIX_PROJECTION, - matrix); -} - -void -cogl_perspective (float fovy, +cogl_perspective (float fov_y, float aspect, - float zNear, - float zFar) + float z_near, + float z_far) { - float xmax, ymax; - float x, y, c, d; - float fovy_rad_half = (fovy * G_PI) / 360; - CoglMatrix perspective; - GLfloat m[16]; + float ymax = z_near * tanf (fov_y * G_PI / 360.0); - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - memset (&m[0], 0, sizeof (m)); - - _cogl_set_current_matrix (COGL_MATRIX_PROJECTION); - _cogl_current_matrix_identity (); - - /* - * Based on the original algorithm in perspective(): - * - * 1) xmin = -xmax => xmax + xmin == 0 && xmax - xmin == 2 * xmax - * same true for y, hence: a == 0 && b == 0; - * - * 2) When working with small numbers, we are loosing significant - * precision - */ - ymax = (zNear * (sinf (fovy_rad_half) / cosf (fovy_rad_half))); - xmax = (ymax * aspect); - - x = (zNear / xmax); - y = (zNear / ymax); - c = (-(zFar + zNear) / ( zFar - zNear)); - d = (-(2 * zFar) * zNear) / (zFar - zNear); - -#define M(row,col) m[col*4+row] - M(0,0) = x; - M(1,1) = y; - M(2,2) = c; - M(2,3) = d; - M(3,2) = -1.0; - - cogl_matrix_init_from_array (&perspective, m); - _cogl_current_matrix_multiply (&perspective); - - _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW); - - /* Calculate and store the inverse of the matrix */ - memset (ctx->inverse_projection, 0, sizeof (float) * 16); - -#define m ctx->inverse_projection - M(0, 0) = (1.0 / x); - M(1, 1) = (1.0 / y); - M(2, 3) = -1.0; - M(3, 2) = (1.0 / d); - M(3, 3) = (c / d); -#undef m - -#undef M + cogl_frustum (-ymax * aspect, /* left */ + ymax * aspect, /* right */ + -ymax, /* bottom */ + ymax, /* top */ + z_near, + z_far); } void @@ -474,4 +444,65 @@ cogl_frustum (float left, M(3,2) = 1.0 / d; M(3,3) = c / d; #undef M + + _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW); } + +void +cogl_ortho (float left, + float right, + float bottom, + float top, + float z_near, + float z_far) +{ + CoglMatrix ortho; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + cogl_matrix_init_identity (&ortho); + cogl_matrix_ortho (&ortho, left, right, bottom, top, z_near, z_far); + _cogl_set_current_matrix (COGL_MATRIX_PROJECTION); + _cogl_current_matrix_load (&ortho); + + /* Calculate and store the inverse of the matrix */ + memset (ctx->inverse_projection, 0, sizeof (float) * 16); + +#define M(row,col) ctx->inverse_projection[col*4+row] + M(0,0) = 1.0 / ortho.xx; + M(0,3) = -ortho.xw; + M(1,1) = 1.0 / ortho.yy; + M(1,3) = -ortho.yw; + M(2,2) = 1.0 / ortho.zz; + M(2,3) = -ortho.zw; + M(3,3) = 1.0; +#undef M +} + +void +cogl_get_modelview_matrix (CoglMatrix *matrix) +{ + _cogl_get_matrix (COGL_MATRIX_MODELVIEW, + matrix); +} + +void +cogl_set_modelview_matrix (CoglMatrix *matrix) +{ + _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW); + _cogl_current_matrix_load (matrix); +} + +void +cogl_get_projection_matrix (CoglMatrix *matrix) +{ + _cogl_get_matrix (COGL_MATRIX_PROJECTION, + matrix); +} + +void +cogl_set_projection_matrix (CoglMatrix *matrix) +{ + _cogl_set_current_matrix (COGL_MATRIX_PROJECTION); + _cogl_current_matrix_load (matrix); +} + diff --git a/clutter/cogl/common/cogl-debug.c b/clutter/cogl/common/cogl-debug.c index 85721fc22..b6dfd7559 100644 --- a/clutter/cogl/common/cogl-debug.c +++ b/clutter/cogl/common/cogl-debug.c @@ -39,7 +39,8 @@ static const GDebugKey cogl_debug_keys[] = { { "draw", COGL_DEBUG_DRAW }, { "pango", COGL_DEBUG_PANGO }, { "rectangles", COGL_DEBUG_RECTANGLES }, - { "handle", COGL_DEBUG_HANDLE } + { "handle", COGL_DEBUG_HANDLE }, + { "blend-strings", COGL_DEBUG_BLEND_STRINGS } }; static const gint n_cogl_debug_keys = G_N_ELEMENTS (cogl_debug_keys); diff --git a/clutter/cogl/common/cogl-enum-types.c.in b/clutter/cogl/common/cogl-enum-types.c.in new file mode 100644 index 000000000..157180dfe --- /dev/null +++ b/clutter/cogl/common/cogl-enum-types.c.in @@ -0,0 +1,41 @@ +/*** BEGIN file-header ***/ +#include "cogl-enum-types.h" +#include "cogl.h" +/*** END file-header ***/ + +/*** BEGIN file-production ***/ + +/* enumerations from "@filename@" */ +#include "@filename@" + +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +GType +@enum_name@_get_type (void) +{ + static volatile gsize g_enum_type_id__volatile = 0; + + if (g_once_init_enter (&g_enum_type_id__volatile)) + { + static const G@Type@Value values[] = { +/*** END value-header ***/ + +/*** BEGIN value-production ***/ + { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, +/*** END value-production ***/ + +/*** BEGIN value-tail ***/ + { 0, NULL, NULL } + }; + GType g_enum_type_id; + + g_enum_type_id = + g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); + + g_once_init_leave (&g_enum_type_id__volatile, g_enum_type_id); + } + + return g_enum_type_id__volatile; +} +/*** END value-tail ***/ diff --git a/clutter/cogl/common/cogl-enum-types.h.in b/clutter/cogl/common/cogl-enum-types.h.in new file mode 100644 index 000000000..23d705dee --- /dev/null +++ b/clutter/cogl/common/cogl-enum-types.h.in @@ -0,0 +1,25 @@ +/*** BEGIN file-header ***/ +#ifndef __COGL_ENUM_TYPES_H__ +#define __COGL_ENUM_TYPES_H__ + +#include + +G_BEGIN_DECLS + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ +/* enumerations from "@filename@" */ +/*** END file-production ***/ + +/*** BEGIN file-tail ***/ +G_END_DECLS + +#endif /* !__CLUTTER_ENUM_TYPES_H__ */ +/*** END file-tail ***/ + +/*** BEGIN value-header ***/ +GType @enum_name@_get_type (void) G_GNUC_CONST; +#define COGL_TYPE_@ENUMSHORT@ (@enum_name@_get_type()) + +/*** END value-header ***/ diff --git a/clutter/cogl/common/cogl-handle.h b/clutter/cogl/common/cogl-handle.h index 7851932db..6caee0e71 100644 --- a/clutter/cogl/common/cogl-handle.h +++ b/clutter/cogl/common/cogl-handle.h @@ -82,7 +82,7 @@ typedef struct _CoglHandleObject static CoglHandleClass _cogl_##type_name##_class; \ \ static GQuark \ -_cogl_##type_name##_get_type (void) \ +_cogl_handle_##type_name##_get_type (void) \ { \ static GQuark type = 0; \ if (!type) \ @@ -99,13 +99,13 @@ _cogl_##type_name##_handle_new (Cogl##TypeName *new_obj) \ obj->klass = &_cogl_##type_name##_class; \ if (!obj->klass->type) \ { \ - obj->klass->type = _cogl_##type_name##_get_type (); \ - obj->klass->virt_free = _cogl_##type_name##_free; \ - } \ + obj->klass->type = _cogl_handle_##type_name##_get_type ();\ + obj->klass->virt_free = _cogl_##type_name##_free; \ + } \ \ - _COGL_HANDLE_DEBUG_NEW (TypeName, obj); \ - return (CoglHandle) new_obj; \ - } \ + _COGL_HANDLE_DEBUG_NEW (TypeName, obj); \ + return (CoglHandle) new_obj; \ +} \ \ Cogl##TypeName * \ _cogl_##type_name##_pointer_from_handle (CoglHandle handle) \ @@ -121,7 +121,8 @@ cogl_is_##type_name (CoglHandle handle) \ if (handle == COGL_INVALID_HANDLE) \ return FALSE; \ \ - return (obj->klass->type == _cogl_##type_name##_get_type ()); \ + return (obj->klass->type == \ + _cogl_handle_##type_name##_get_type ()); \ } \ \ CoglHandle G_GNUC_DEPRECATED \ diff --git a/clutter/cogl/common/cogl-material-private.h b/clutter/cogl/common/cogl-material-private.h index 05d4242dd..e61ab97bd 100644 --- a/clutter/cogl/common/cogl-material-private.h +++ b/clutter/cogl/common/cogl-material-private.h @@ -68,15 +68,20 @@ struct _CoglMaterialLayer CoglHandle texture; /*!< The texture for this layer, or COGL_INVALID_HANDLE for an empty layer */ + CoglMaterialFilter mag_filter; + CoglMaterialFilter min_filter; + /* Determines how the color of individual texture fragments * are calculated. */ - CoglMaterialLayerCombineFunc texture_combine_rgb_func; - CoglMaterialLayerCombineSrc texture_combine_rgb_src[3]; - CoglMaterialLayerCombineOp texture_combine_rgb_op[3]; + GLint texture_combine_rgb_func; + GLint texture_combine_rgb_src[3]; + GLint texture_combine_rgb_op[3]; - CoglMaterialLayerCombineFunc texture_combine_alpha_func; - CoglMaterialLayerCombineSrc texture_combine_alpha_src[3]; - CoglMaterialLayerCombineOp texture_combine_alpha_op[3]; + GLint texture_combine_alpha_func; + GLint texture_combine_alpha_src[3]; + GLint texture_combine_alpha_op[3]; + + GLfloat texture_combine_constant[4]; /* TODO: Support purely GLSL based material layers */ @@ -114,11 +119,104 @@ struct _CoglMaterial GLfloat alpha_func_reference; /* Determines how this material is blended with other primitives */ - CoglMaterialBlendFactor blend_src_factor; - CoglMaterialBlendFactor blend_dst_factor; +#ifndef HAVE_COGL_GLES + GLenum blend_equation_rgb; + GLenum blend_equation_alpha; + GLint blend_src_factor_alpha; + GLint blend_dst_factor_alpha; + GLfloat blend_constant[4]; +#endif + GLint blend_src_factor_rgb; + GLint blend_dst_factor_rgb; GList *layers; }; +/* + * SECTION:cogl-material-internals + * @short_description: Functions for creating custom primitives that make use + * of Cogl materials for filling. + * + * Normally you shouldn't need to use this API directly, but if you need to + * developing a custom/specialised primitive - probably using raw OpenGL - then + * this API aims to expose enough of the material internals to support being + * able to fill your geometry according to a given Cogl material. + */ + + +/* + * cogl_material_get_cogl_enable_flags: + * @material: A CoglMaterial object + * + * This determines what flags need to be passed to cogl_enable before this + * material can be used. Normally you shouldn't need to use this function + * directly since Cogl will do this internally, but if you are developing + * custom primitives directly with OpenGL you may want to use this. + * + * Note: This API is hopfully just a stop-gap solution. Ideally cogl_enable + * will be replaced. + */ +/* TODO: find a nicer solution! */ +gulong _cogl_material_get_cogl_enable_flags (CoglHandle handle); + +/* + * CoglMaterialLayerFlags: + * @COGL_MATERIAL_LAYER_FLAG_USER_MATRIX: Means the user has supplied a + * custom texture matrix. + */ +typedef enum _CoglMaterialLayerFlags +{ + COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX = 1L<<0 +} CoglMaterialLayerFlags; +/* XXX: NB: if you add flags here you will need to update + * CoglMaterialLayerPrivFlags!!! */ + +/* + * cogl_material_layer_get_flags: + * @layer_handle: A CoglMaterialLayer layer handle + * + * This lets you get a number of flag attributes about the layer. Normally + * you shouldn't need to use this function directly since Cogl will do this + * internally, but if you are developing custom primitives directly with + * OpenGL you may need this. + */ +gulong _cogl_material_layer_get_flags (CoglHandle layer_handle); + +/* + * CoglMaterialFlushOption: + * @COGL_MATERIAL_FLUSH_FALLBACK_MASK: Follow this by a guin32 mask + * of the layers that can't be supported with the user supplied texture + * and need to be replaced with fallback textures. (1 = fallback, and the + * least significant bit = layer 0) + * @COGL_MATERIAL_FLUSH_DISABLE_MASK: Follow this by a guint32 mask + * of the layers that you want to completly disable texturing for + * (1 = fallback, and the least significant bit = layer 0) + * @COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE: Follow this by a GLuint OpenGL texture + * name to override the texture used for layer 0 of the material. This is + * intended for dealing with sliced textures where you will need to point + * to each of the texture slices in turn when drawing your geometry. + * Passing a value of 0 is the same as not passing the option at all. + */ +typedef enum _CoglMaterialFlushOption +{ + COGL_MATERIAL_FLUSH_FALLBACK_MASK = 1, + COGL_MATERIAL_FLUSH_DISABLE_MASK, + COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE, +} CoglMaterialFlushOption; + +/* + * cogl_material_flush_gl_state: + * @material: A CoglMaterial object + * @...: A NULL terminated list of (CoglMaterialFlushOption, data) pairs + * + * This function commits the state of the specified CoglMaterial - including + * the texture state for all the layers - to the OpenGL[ES] driver. + * + * Since 1.0 + */ +void _cogl_material_flush_gl_state (CoglHandle material, + ...) G_GNUC_NULL_TERMINATED; + + #endif /* __COGL_MATERIAL_PRIVATE_H */ diff --git a/clutter/cogl/common/cogl-material.c b/clutter/cogl/common/cogl-material.c index c456cac6a..66a4b0c96 100644 --- a/clutter/cogl/common/cogl-material.c +++ b/clutter/cogl/common/cogl-material.c @@ -35,6 +35,7 @@ #include "cogl-material-private.h" #include "cogl-texture-private.h" +#include "cogl-blend-string.h" #include #include @@ -50,6 +51,10 @@ #ifdef HAVE_COGL_GL #define glActiveTexture ctx->pf_glActiveTexture #define glClientActiveTexture ctx->pf_glClientActiveTexture +#define glBlendFuncSeparate ctx->pf_glBlendFuncSeparate +#define glBlendEquation ctx->pf_glBlendEquation +#define glBlendColor ctx->pf_glBlendColor +#define glBlendEquationSeparate ctx->pf_glBlendEquationSeparate #endif static void _cogl_material_free (CoglMaterial *tex); @@ -60,6 +65,12 @@ COGL_HANDLE_DEFINE (MaterialLayer, material_layer); /* #define DISABLE_MATERIAL_CACHE 1 */ +GQuark +_cogl_material_error_quark (void) +{ + return g_quark_from_static_string ("cogl-material-error-quark"); +} + CoglHandle cogl_material_new (void) { @@ -88,8 +99,18 @@ cogl_material_new (void) material->flags |= COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC; /* Not the same as the GL default, but seems saner... */ - material->blend_src_factor = COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA; - material->blend_dst_factor = COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; +#ifndef HAVE_COGL_GLES + material->blend_equation_rgb = GL_FUNC_ADD; + material->blend_equation_alpha = GL_FUNC_ADD; + material->blend_src_factor_alpha = GL_SRC_ALPHA; + material->blend_dst_factor_alpha = GL_ONE_MINUS_SRC_ALPHA; + material->blend_constant[0] = 0; + material->blend_constant[1] = 0; + material->blend_constant[2] = 0; + material->blend_constant[3] = 0; +#endif + material->blend_src_factor_rgb = GL_SRC_ALPHA; + material->blend_dst_factor_rgb = GL_ONE_MINUS_SRC_ALPHA; material->flags |= COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC; material->layers = NULL; @@ -408,20 +429,177 @@ cogl_material_set_alpha_test_function (CoglHandle handle, material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC; } +GLenum +arg_to_gl_blend_factor (CoglBlendStringArgument *arg) +{ + if (arg->source.is_zero) + return GL_ZERO; + if (arg->factor.is_one) + return GL_ONE; + else if (arg->factor.is_src_alpha_saturate) + return GL_SRC_ALPHA_SATURATE; + else if (arg->factor.source.info->type == + COGL_BLEND_STRING_COLOR_SOURCE_SRC_COLOR) + { + if (arg->factor.source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB) + { + if (arg->factor.source.one_minus) + return GL_ONE_MINUS_SRC_COLOR; + else + return GL_SRC_COLOR; + } + else + { + if (arg->factor.source.one_minus) + return GL_ONE_MINUS_SRC_ALPHA; + else + return GL_SRC_ALPHA; + } + } + else if (arg->factor.source.info->type == + COGL_BLEND_STRING_COLOR_SOURCE_DST_COLOR) + { + if (arg->factor.source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB) + { + if (arg->factor.source.one_minus) + return GL_ONE_MINUS_DST_COLOR; + else + return GL_DST_COLOR; + } + else + { + if (arg->factor.source.one_minus) + return GL_ONE_MINUS_DST_ALPHA; + else + return GL_DST_ALPHA; + } + } +#ifndef HAVE_COGL_GLES + else if (arg->factor.source.info->type == + COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT) + { + if (arg->factor.source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB) + { + if (arg->factor.source.one_minus) + return GL_ONE_MINUS_CONSTANT_COLOR; + else + return GL_CONSTANT_COLOR; + } + else + { + if (arg->factor.source.one_minus) + return GL_ONE_MINUS_CONSTANT_ALPHA; + else + return GL_CONSTANT_ALPHA; + } + } +#endif + + g_warning ("Unable to determine valid blend factor from blend string\n"); + return GL_ONE; +} + void -cogl_material_set_blend_factors (CoglHandle handle, - CoglMaterialBlendFactor src_factor, - CoglMaterialBlendFactor dst_factor) +setup_blend_state (CoglBlendStringStatement *statement, + GLenum *blend_equation, + GLint *blend_src_factor, + GLint *blend_dst_factor) +{ +#ifndef HAVE_COGL_GLES + switch (statement->function->type) + { + case COGL_BLEND_STRING_FUNCTION_ADD: + *blend_equation = GL_FUNC_ADD; + break; + /* TODO - add more */ + default: + g_warning ("Unsupported blend function given"); + *blend_equation = GL_FUNC_ADD; + } +#endif + + *blend_src_factor = arg_to_gl_blend_factor (&statement->args[0]); + *blend_dst_factor = arg_to_gl_blend_factor (&statement->args[1]); +} + +gboolean +cogl_material_set_blend (CoglHandle handle, + const char *blend_description, + GError **error) { CoglMaterial *material; + CoglBlendStringStatement statements[2]; + CoglBlendStringStatement split[2]; + CoglBlendStringStatement *rgb; + CoglBlendStringStatement *a; + int count; + + g_return_val_if_fail (cogl_is_material (handle), FALSE); + + material = _cogl_material_pointer_from_handle (handle); + + count = + _cogl_blend_string_compile (blend_description, + COGL_BLEND_STRING_CONTEXT_BLENDING, + statements, + error); + if (!count) + return FALSE; + + if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA) + { + _cogl_blend_string_split_rgba_statement (statements, + &split[0], &split[1]); + rgb = &split[0]; + a = &split[1]; + } + else + { + rgb = &statements[0]; + a = &statements[1]; + } + +#ifndef HAVE_COGL_GLES + setup_blend_state (rgb, + &material->blend_equation_rgb, + &material->blend_src_factor_rgb, + &material->blend_dst_factor_rgb); + setup_blend_state (a, + &material->blend_equation_alpha, + &material->blend_src_factor_alpha, + &material->blend_dst_factor_alpha); +#else + setup_blend_state (rgb, + NULL, + &material->blend_src_factor_rgb, + &material->blend_dst_factor_rgb); +#endif + + material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC; + + return TRUE; +} + +void +cogl_material_set_blend_constant (CoglHandle handle, + CoglColor *constant_color) +{ +#ifndef HAVE_COGL_GLES + CoglMaterial *material; + GLfloat *constant; g_return_if_fail (cogl_is_material (handle)); material = _cogl_material_pointer_from_handle (handle); - material->blend_src_factor = src_factor; - material->blend_dst_factor = dst_factor; + + constant = material->blend_constant; + constant[0] = cogl_color_get_red_float (constant_color); + constant[1] = cogl_color_get_green_float (constant_color); + constant[2] = cogl_color_get_blue_float (constant_color); + constant[3] = cogl_color_get_alpha_float (constant_color); material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC; +#endif } /* Asserts that a layer corresponding to the given index exists. If no @@ -459,25 +637,22 @@ _cogl_material_get_layer (CoglMaterial *material, layer_handle = _cogl_material_layer_handle_new (layer); layer->index = index_; layer->flags = COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE; + layer->mag_filter = COGL_MATERIAL_FILTER_LINEAR; + layer->min_filter = COGL_MATERIAL_FILTER_LINEAR; layer->texture = COGL_INVALID_HANDLE; /* Choose the same default combine mode as OpenGL: * MODULATE(PREVIOUS[RGBA],TEXTURE[RGBA]) */ - layer->texture_combine_rgb_func = COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE; - layer->texture_combine_rgb_src[0] = COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS; - layer->texture_combine_rgb_src[1] = COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE; - layer->texture_combine_rgb_op[0] = COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR; - layer->texture_combine_rgb_op[1] = COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR; - layer->texture_combine_alpha_func = - COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE; - layer->texture_combine_alpha_src[0] = - COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS; - layer->texture_combine_alpha_src[1] = - COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE; - layer->texture_combine_alpha_op[0] = - COGL_MATERIAL_LAYER_COMBINE_OP_SRC_ALPHA; - layer->texture_combine_alpha_op[1] = - COGL_MATERIAL_LAYER_COMBINE_OP_SRC_ALPHA; + layer->texture_combine_rgb_func = GL_MODULATE; + layer->texture_combine_rgb_src[0] = GL_PREVIOUS; + layer->texture_combine_rgb_src[1] = GL_TEXTURE; + layer->texture_combine_rgb_op[0] = GL_SRC_COLOR; + layer->texture_combine_rgb_op[1] = GL_SRC_COLOR; + layer->texture_combine_alpha_func = GL_MODULATE; + layer->texture_combine_alpha_src[0] = GL_PREVIOUS; + layer->texture_combine_alpha_src[1] = GL_TEXTURE; + layer->texture_combine_alpha_op[0] = GL_SRC_ALPHA; + layer->texture_combine_alpha_op[1] = GL_SRC_ALPHA; cogl_matrix_init_identity (&layer->matrix); @@ -498,7 +673,8 @@ cogl_material_set_layer (CoglHandle material_handle, int n_layers; g_return_if_fail (cogl_is_material (material_handle)); - g_return_if_fail (cogl_is_texture (texture_handle)); + g_return_if_fail (texture_handle == COGL_INVALID_HANDLE + || cogl_is_texture (texture_handle)); material = _cogl_material_pointer_from_handle (material_handle); layer = _cogl_material_get_layer (material_handle, layer_index, TRUE); @@ -519,7 +695,8 @@ cogl_material_set_layer (CoglHandle material_handle, * MAX_COMBINED_TEXTURE_IMAGE_UNITS layers. */ } - cogl_handle_ref (texture_handle); + if (texture_handle) + cogl_handle_ref (texture_handle); if (layer->texture) cogl_handle_unref (layer->texture); @@ -530,104 +707,164 @@ cogl_material_set_layer (CoglHandle material_handle, layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY; } -void -cogl_material_set_layer_combine_function ( - CoglHandle handle, - gint layer_index, - CoglMaterialLayerCombineChannels channels, - CoglMaterialLayerCombineFunc func) +static void +setup_texture_combine_state (CoglBlendStringStatement *statement, + GLint *texture_combine_func, + GLint *texture_combine_src, + GLint *texture_combine_op) +{ + int i; + + switch (statement->function->type) + { + case COGL_BLEND_STRING_FUNCTION_AUTO_COMPOSITE: + *texture_combine_func = GL_MODULATE; /* FIXME */ + break; + case COGL_BLEND_STRING_FUNCTION_REPLACE: + *texture_combine_func = GL_REPLACE; + break; + case COGL_BLEND_STRING_FUNCTION_MODULATE: + *texture_combine_func = GL_MODULATE; + break; + case COGL_BLEND_STRING_FUNCTION_ADD: + *texture_combine_func = GL_ADD; + break; + case COGL_BLEND_STRING_FUNCTION_ADD_SIGNED: + *texture_combine_func = GL_ADD_SIGNED; + break; + case COGL_BLEND_STRING_FUNCTION_INTERPOLATE: + *texture_combine_func = GL_INTERPOLATE; + break; + case COGL_BLEND_STRING_FUNCTION_SUBTRACT: + *texture_combine_func = GL_SUBTRACT; + break; + case COGL_BLEND_STRING_FUNCTION_DOT3_RGB: + *texture_combine_func = GL_DOT3_RGB; + break; + case COGL_BLEND_STRING_FUNCTION_DOT3_RGBA: + *texture_combine_func = GL_DOT3_RGBA; + break; + } + + for (i = 0; i < statement->function->argc; i++) + { + CoglBlendStringArgument *arg = &statement->args[i]; + + switch (arg->source.info->type) + { + case COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT: + texture_combine_src[i] = GL_CONSTANT; + break; + case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE: + texture_combine_src[i] = GL_TEXTURE; + break; + case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N: + texture_combine_src[i] = + GL_TEXTURE0 + arg->source.texture; + break; + case COGL_BLEND_STRING_COLOR_SOURCE_PRIMARY: + texture_combine_src[i] = GL_PRIMARY_COLOR; + break; + case COGL_BLEND_STRING_COLOR_SOURCE_PREVIOUS: + texture_combine_src[i] = GL_PREVIOUS; + break; + default: + g_warning ("Unexpected texture combine source"); + texture_combine_src[i] = GL_TEXTURE; + } + + if (arg->source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB) + { + if (statement->args[i].source.one_minus) + texture_combine_op[i] = GL_ONE_MINUS_SRC_COLOR; + else + texture_combine_op[i] = GL_SRC_COLOR; + } + else + { + if (statement->args[i].source.one_minus) + texture_combine_op[i] = GL_ONE_MINUS_SRC_ALPHA; + else + texture_combine_op[i] = GL_SRC_ALPHA; + } + } +} + +gboolean +cogl_material_set_layer_combine (CoglHandle handle, + gint layer_index, + const char *combine_description, + GError **error) { CoglMaterial *material; CoglMaterialLayer *layer; - gboolean set_alpha_func = FALSE; - gboolean set_rgb_func = FALSE; + CoglBlendStringStatement statements[2]; + CoglBlendStringStatement split[2]; + CoglBlendStringStatement *rgb; + CoglBlendStringStatement *a; + int count; + + g_return_val_if_fail (cogl_is_material (handle), FALSE); + + material = _cogl_material_pointer_from_handle (handle); + layer = _cogl_material_get_layer (material, layer_index, TRUE); + + count = + _cogl_blend_string_compile (combine_description, + COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE, + statements, + error); + if (!count) + return FALSE; + + if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA) + { + _cogl_blend_string_split_rgba_statement (statements, + &split[0], &split[1]); + rgb = &split[0]; + a = &split[1]; + } + else + { + rgb = &statements[0]; + a = &statements[1]; + } + + setup_texture_combine_state (rgb, + &layer->texture_combine_rgb_func, + layer->texture_combine_rgb_src, + layer->texture_combine_rgb_op); + + setup_texture_combine_state (a, + &layer->texture_combine_alpha_func, + layer->texture_combine_alpha_src, + layer->texture_combine_alpha_op); + + + layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY; + layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE; + return TRUE; +} + +void +cogl_material_set_layer_combine_constant (CoglHandle handle, + gint layer_index, + CoglColor *constant_color) +{ + CoglMaterial *material; + CoglMaterialLayer *layer; + GLfloat *constant; g_return_if_fail (cogl_is_material (handle)); material = _cogl_material_pointer_from_handle (handle); layer = _cogl_material_get_layer (material, layer_index, TRUE); - if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA) - set_alpha_func = set_rgb_func = TRUE; - else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB) - set_rgb_func = TRUE; - else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA) - set_alpha_func = TRUE; - - if (set_rgb_func) - layer->texture_combine_rgb_func = func; - if (set_alpha_func) - layer->texture_combine_alpha_func = func; - - layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY; - layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE; -} - -void -cogl_material_set_layer_combine_arg_src ( - CoglHandle handle, - gint layer_index, - gint argument, - CoglMaterialLayerCombineChannels channels, - CoglMaterialLayerCombineSrc src) -{ - CoglMaterial *material; - CoglMaterialLayer *layer; - gboolean set_arg_alpha_src = FALSE; - gboolean set_arg_rgb_src = FALSE; - - g_return_if_fail (cogl_is_material (handle)); - g_return_if_fail (argument >=0 && argument <= 3); - - material = _cogl_material_pointer_from_handle (handle); - layer = _cogl_material_get_layer (material, layer_index, TRUE); - - if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA) - set_arg_alpha_src = set_arg_rgb_src = TRUE; - else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB) - set_arg_rgb_src = TRUE; - else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA) - set_arg_alpha_src = TRUE; - - if (set_arg_rgb_src) - layer->texture_combine_rgb_src[argument] = src; - if (set_arg_alpha_src) - layer->texture_combine_alpha_src[argument] = src; - - layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY; - layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE; -} - -void -cogl_material_set_layer_combine_arg_op ( - CoglHandle material_handle, - gint layer_index, - gint argument, - CoglMaterialLayerCombineChannels channels, - CoglMaterialLayerCombineOp op) -{ - CoglMaterial *material; - CoglMaterialLayer *layer; - gboolean set_arg_alpha_op = FALSE; - gboolean set_arg_rgb_op = FALSE; - - g_return_if_fail (cogl_is_material (material_handle)); - g_return_if_fail (argument >=0 && argument <= 3); - - material = _cogl_material_pointer_from_handle (material_handle); - layer = _cogl_material_get_layer (material, layer_index, TRUE); - - if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA) - set_arg_alpha_op = set_arg_rgb_op = TRUE; - else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB) - set_arg_rgb_op = TRUE; - else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA) - set_arg_alpha_op = TRUE; - - if (set_arg_rgb_op) - layer->texture_combine_rgb_op[argument] = op; - if (set_arg_alpha_op) - layer->texture_combine_alpha_op[argument] = op; + constant = layer->texture_combine_constant; + constant[0] = cogl_color_get_red_float (constant_color); + constant[1] = cogl_color_get_green_float (constant_color); + constant[2] = cogl_color_get_blue_float (constant_color); + constant[3] = cogl_color_get_alpha_float (constant_color); layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY; layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE; @@ -690,7 +927,7 @@ cogl_material_remove_layer (CoglHandle material_handle, /* XXX: This API is hopfully just a stop-gap solution. Ideally cogl_enable * will be replaced. */ gulong -cogl_material_get_cogl_enable_flags (CoglHandle material_handle) +_cogl_material_get_cogl_enable_flags (CoglHandle material_handle) { CoglMaterial *material; gulong enable_flags = 0; @@ -713,7 +950,7 @@ cogl_material_get_cogl_enable_flags (CoglHandle material_handle) * probably sensible to try and avoid list manipulation for every * primitive emitted in a scene, every frame. * - * Alternativly; we could either add a _foreach function, or maybe + * Alternatively; we could either add a _foreach function, or maybe * a function that gets a passed a buffer (that may be stack allocated) * by the caller. */ @@ -748,7 +985,7 @@ cogl_material_layer_get_texture (CoglHandle layer_handle) } gulong -cogl_material_layer_get_flags (CoglHandle layer_handle) +_cogl_material_layer_get_flags (CoglHandle layer_handle) { CoglMaterialLayer *layer; @@ -760,25 +997,34 @@ cogl_material_layer_get_flags (CoglHandle layer_handle) } static guint -get_n_args_for_combine_func (CoglMaterialLayerCombineFunc func) +get_n_args_for_combine_func (GLint func) { switch (func) { - case COGL_MATERIAL_LAYER_COMBINE_FUNC_REPLACE: + case GL_REPLACE: return 1; - case COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE: - case COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD: - case COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD_SIGNED: - case COGL_MATERIAL_LAYER_COMBINE_FUNC_SUBTRACT: - case COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGB: - case COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGBA: + case GL_MODULATE: + case GL_ADD: + case GL_ADD_SIGNED: + case GL_SUBTRACT: + case GL_DOT3_RGB: + case GL_DOT3_RGBA: return 2; - case COGL_MATERIAL_LAYER_COMBINE_FUNC_INTERPOLATE: + case GL_INTERPOLATE: return 3; } return 0; } +static gboolean +is_mipmap_filter (CoglMaterialFilter filter) +{ + return (filter == COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST + || filter == COGL_MATERIAL_FILTER_LINEAR_MIPMAP_NEAREST + || filter == COGL_MATERIAL_FILTER_NEAREST_MIPMAP_LINEAR + || filter == COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR); +} + static void _cogl_material_layer_flush_gl_sampler_state (CoglMaterialLayer *layer, CoglLayerInfo *gl_layer_info) @@ -851,6 +1097,9 @@ _cogl_material_layer_flush_gl_sampler_state (CoglMaterialLayer *layer, GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, layer->texture_combine_alpha_op[2])); } + + GE (glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, + layer->texture_combine_constant)); } #ifndef DISABLE_MATERIAL_CACHE @@ -976,6 +1225,13 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material, GE (glActiveTexture (GL_TEXTURE0 + i)); + _cogl_texture_set_filters (layer->texture, + layer->min_filter, + layer->mag_filter); + if (is_mipmap_filter (layer->min_filter) + || is_mipmap_filter (layer->mag_filter)) + _cogl_texture_ensure_mipmaps (layer->texture); + /* FIXME: We could be more clever here and only bind the texture if it is different from gl_layer_info->gl_texture to avoid redundant GL calls. However a few other places in Cogl and @@ -1122,12 +1378,44 @@ _cogl_material_flush_base_gl_state (CoglMaterial *material) if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC && material->flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC)) { - GE (glBlendFunc (material->blend_src_factor, material->blend_dst_factor)); +#if defined (HAVE_COGL_GLES2) + gboolean have_blend_equation_seperate = TRUE; +#elif defined (HAVE_COGL_GL) + gboolean have_blend_equation_seperate = FALSE; + if (ctx->pf_glBlendEquationSeparate) /* Only GL 2.0 + */ + have_blend_equation_seperate = TRUE; +#endif + +#ifndef HAVE_COGL_GLES /* GLES 1 only has glBlendFunc */ + if (material->blend_src_factor_rgb != material->blend_src_factor_alpha + || (material->blend_src_factor_rgb != + material->blend_src_factor_alpha)) + { + if (have_blend_equation_seperate && + material->blend_equation_rgb != material->blend_equation_alpha) + GE (glBlendEquationSeparate (material->blend_equation_rgb, + material->blend_equation_alpha)); + else + GE (glBlendEquation (material->blend_equation_rgb)); + + GE (glBlendFuncSeparate (material->blend_src_factor_rgb, + material->blend_dst_factor_rgb, + material->blend_src_factor_alpha, + material->blend_dst_factor_alpha)); + GE (glBlendColor (material->blend_constant[0], + material->blend_constant[1], + material->blend_constant[2], + material->blend_constant[3])); + } + else +#endif + GE (glBlendFunc (material->blend_src_factor_rgb, + material->blend_dst_factor_rgb)); } } void -cogl_material_flush_gl_state (CoglHandle handle, ...) +_cogl_material_flush_gl_state (CoglHandle handle, ...) { CoglMaterial *material; va_list ap; @@ -1204,3 +1492,44 @@ cogl_set_source_texture (CoglHandle texture_handle) cogl_set_source (ctx->default_material); } +CoglMaterialFilter +cogl_material_layer_get_min_filter (CoglHandle layer_handle) +{ + CoglMaterialLayer *layer; + + g_return_val_if_fail (cogl_is_material_layer (layer_handle), 0); + + layer = _cogl_material_layer_pointer_from_handle (layer_handle); + + return layer->min_filter; +} + +CoglMaterialFilter +cogl_material_layer_get_mag_filter (CoglHandle layer_handle) +{ + CoglMaterialLayer *layer; + + g_return_val_if_fail (cogl_is_material_layer (layer_handle), 0); + + layer = _cogl_material_layer_pointer_from_handle (layer_handle); + + return layer->mag_filter; +} + +void +cogl_material_set_layer_filters (CoglHandle handle, + gint layer_index, + CoglMaterialFilter min_filter, + CoglMaterialFilter mag_filter) +{ + CoglMaterial *material; + CoglMaterialLayer *layer; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + layer = _cogl_material_get_layer (material, layer_index, TRUE); + + layer->min_filter = min_filter; + layer->mag_filter = mag_filter; +} diff --git a/clutter/cogl/common/cogl-matrix-stack.c b/clutter/cogl/common/cogl-matrix-stack.c index a72af000d..6ba909840 100644 --- a/clutter/cogl/common/cogl-matrix-stack.c +++ b/clutter/cogl/common/cogl-matrix-stack.c @@ -257,6 +257,59 @@ _cogl_matrix_stack_multiply (CoglMatrixStack *stack, stack->flushed_state = NULL; } +void +_cogl_matrix_stack_frustum (CoglMatrixStack *stack, + float left, + float right, + float bottom, + float top, + float z_near, + float z_far) +{ + CoglMatrixState *state; + + state = _cogl_matrix_stack_top_mutable (stack); + cogl_matrix_frustum (&state->matrix, + left, right, bottom, top, + z_near, z_far); + /* mark dirty */ + stack->flushed_state = NULL; +} + +void +_cogl_matrix_stack_perspective (CoglMatrixStack *stack, + float fov_y, + float aspect, + float z_near, + float z_far) +{ + CoglMatrixState *state; + + state = _cogl_matrix_stack_top_mutable (stack); + cogl_matrix_perspective (&state->matrix, + fov_y, aspect, z_near, z_far); + /* mark dirty */ + stack->flushed_state = NULL; +} + +void +_cogl_matrix_stack_ortho (CoglMatrixStack *stack, + float left, + float right, + float bottom, + float top, + float z_near, + float z_far) +{ + CoglMatrixState *state; + + state = _cogl_matrix_stack_top_mutable (stack); + cogl_matrix_ortho (&state->matrix, + left, right, bottom, top, z_near, z_far); + /* mark dirty */ + stack->flushed_state = NULL; +} + void _cogl_matrix_stack_get (CoglMatrixStack *stack, CoglMatrix *matrix) @@ -280,25 +333,6 @@ _cogl_matrix_stack_set (CoglMatrixStack *stack, stack->flushed_state = NULL; } -void -_cogl_matrix_stack_frustum (CoglMatrixStack *stack, - float left, - float right, - float bottom, - float top, - float z_near, - float z_far) -{ - CoglMatrixState *state; - - state = _cogl_matrix_stack_top_mutable (stack); - cogl_matrix_frustum (&state->matrix, - left, right, bottom, top, - z_near, z_far); - /* mark dirty */ - stack->flushed_state = NULL; -} - void _cogl_matrix_stack_flush_to_gl (CoglMatrixStack *stack, GLenum gl_mode) diff --git a/clutter/cogl/common/cogl-matrix-stack.h b/clutter/cogl/common/cogl-matrix-stack.h index 00db51685..a766f4bbc 100644 --- a/clutter/cogl/common/cogl-matrix-stack.h +++ b/clutter/cogl/common/cogl-matrix-stack.h @@ -51,10 +51,6 @@ void _cogl_matrix_stack_rotate (CoglMatrixStack *stack, float z); void _cogl_matrix_stack_multiply (CoglMatrixStack *stack, const CoglMatrix *matrix); -void _cogl_matrix_stack_get (CoglMatrixStack *stack, - CoglMatrix *matrix); -void _cogl_matrix_stack_set (CoglMatrixStack *stack, - const CoglMatrix *matrix); void _cogl_matrix_stack_frustum (CoglMatrixStack *stack, float left, float right, @@ -62,6 +58,22 @@ void _cogl_matrix_stack_frustum (CoglMatrixStack *stack, float top, float z_near, float z_far); +void _cogl_matrix_stack_perspective (CoglMatrixStack *stack, + float fov_y, + float aspect, + float z_near, + float z_far); +void _cogl_matrix_stack_ortho (CoglMatrixStack *stack, + float left, + float right, + float bottom, + float top, + float z_near, + float z_far); +void _cogl_matrix_stack_get (CoglMatrixStack *stack, + CoglMatrix *matrix); +void _cogl_matrix_stack_set (CoglMatrixStack *stack, + const CoglMatrix *matrix); void _cogl_matrix_stack_flush_to_gl (CoglMatrixStack *stack, GLenum gl_mode); diff --git a/clutter/cogl/common/cogl-matrix.c b/clutter/cogl/common/cogl-matrix.c index 6b6f20fae..45f367d73 100644 --- a/clutter/cogl/common/cogl-matrix.c +++ b/clutter/cogl/common/cogl-matrix.c @@ -151,21 +151,6 @@ cogl_matrix_invert (CoglMatrix *matrix) } #endif -void -cogl_matrix_transform_point (const CoglMatrix *matrix, - float *x, - float *y, - float *z, - float *w) -{ - float _x = *x, _y = *y, _z = *z, _w = *w; - - *x = matrix->xx * _x + matrix->xy * _y + matrix->xz * _z + matrix->xw * _w; - *y = matrix->yx * _x + matrix->yy * _y + matrix->yz * _z + matrix->yw * _w; - *z = matrix->zx * _x + matrix->zy * _y + matrix->zz * _z + matrix->zw * _w; - *w = matrix->wx * _x + matrix->wy * _y + matrix->wz * _z + matrix->ww * _w; -} - void cogl_matrix_frustum (CoglMatrix *matrix, float left, @@ -208,6 +193,62 @@ cogl_matrix_frustum (CoglMatrix *matrix, cogl_matrix_multiply (matrix, matrix, &frustum); } +void +cogl_matrix_perspective (CoglMatrix *matrix, + float fov_y, + float aspect, + float z_near, + float z_far) +{ + float ymax = z_near * tan (fov_y * G_PI / 360.0); + + cogl_matrix_frustum (matrix, + -ymax * aspect, /* left */ + ymax * aspect, /* right */ + -ymax, /* bottom */ + ymax, /* top */ + z_near, + z_far); +} + +void +cogl_matrix_ortho (CoglMatrix *matrix, + float left, + float right, + float bottom, + float top, + float near, + float far) +{ + CoglMatrix ortho; + + /* column 0 */ + ortho.xx = 2.0 / (right - left); + ortho.yx = 0.0; + ortho.zx = 0.0; + ortho.wx = 0.0; + + /* column 1 */ + ortho.xy = 0.0; + ortho.yy = 2.0 / (top - bottom); + ortho.zy = 0.0; + ortho.wy = 0.0; + + /* column 2 */ + ortho.xz = 0.0; + ortho.yz = 0.0; + ortho.zz = -2.0 / (far - near); + ortho.wz = 0.0; + + /* column 3 */ + ortho.xw = -(right + left) / (right - left); + ortho.yw = -(top + bottom) / (top - bottom); + ortho.zw = -(far + near) / (far - near); + ortho.ww = 1.0; + + cogl_matrix_multiply (matrix, matrix, &ortho); +} + void cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array) { @@ -220,3 +261,19 @@ cogl_matrix_get_array (const CoglMatrix *matrix) return (float *)matrix; } +void +cogl_matrix_transform_point (const CoglMatrix *matrix, + float *x, + float *y, + float *z, + float *w) +{ + float _x = *x, _y = *y, _z = *z, _w = *w; + + *x = matrix->xx * _x + matrix->xy * _y + matrix->xz * _z + matrix->xw * _w; + *y = matrix->yx * _x + matrix->yy * _y + matrix->yz * _z + matrix->yw * _w; + *z = matrix->zx * _x + matrix->zy * _y + matrix->zz * _z + matrix->zw * _w; + *w = matrix->wx * _x + matrix->wy * _y + matrix->wz * _z + matrix->ww * _w; +} + + diff --git a/clutter/cogl/common/cogl-primitives.c b/clutter/cogl/common/cogl-primitives.c index 224769ca2..598015521 100644 --- a/clutter/cogl/common/cogl-primitives.c +++ b/clutter/cogl/common/cogl-primitives.c @@ -29,7 +29,8 @@ #include "cogl-internal.h" #include "cogl-context.h" #include "cogl-texture-private.h" -#include "cogl-material.h" +#include "cogl-material-private.h" +#include "cogl-vertex-buffer-private.h" #include #include @@ -39,16 +40,8 @@ #ifdef HAVE_COGL_GL -#define glDrawRangeElements ctx->pf_glDrawRangeElements #define glClientActiveTexture ctx->pf_glClientActiveTexture -#else - -/* GLES doesn't have glDrawRangeElements, so we simply pretend it does - * but that it makes no use of the start, end constraints: */ -#define glDrawRangeElements(mode, start, end, count, type, indices) \ - glDrawElements (mode, count, type, indices) - #endif /* these are defined in the particular backend */ @@ -63,7 +56,6 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start, gint batch_len, GLfloat *vertex_pointer) { - int needed_indices; gsize stride; int i; gulong enable_flags = 0; @@ -72,35 +64,6 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start, _COGL_GET_CONTEXT (ctx, NO_RETVAL); - /* The indices are always the same sequence regardless of the vertices so we - * only need to change it if there are more vertices than ever before. */ - needed_indices = batch_len * 6; - if (needed_indices > ctx->static_indices->len) - { - int old_len = ctx->static_indices->len; - int vert_num = old_len / 6 * 4; - GLushort *q; - - /* Add two triangles for each quad to the list of - indices. That makes six new indices but two of the - vertices in the triangles are shared. */ - g_array_set_size (ctx->static_indices, needed_indices); - q = &g_array_index (ctx->static_indices, GLushort, old_len); - - for (i = old_len; - i < ctx->static_indices->len; - i += 6, vert_num += 4) - { - *(q++) = vert_num + 0; - *(q++) = vert_num + 1; - *(q++) = vert_num + 3; - - *(q++) = vert_num + 1; - *(q++) = vert_num + 2; - *(q++) = vert_num + 3; - } - } - /* XXX NB: * Our vertex data is arranged as follows: * 4 vertices per quad: 2 GLfloats per position, @@ -112,16 +75,16 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start, disable_mask = (1 << batch_start->n_layers) - 1; disable_mask = ~disable_mask; - cogl_material_flush_gl_state (ctx->source_material, - COGL_MATERIAL_FLUSH_FALLBACK_MASK, - batch_start->fallback_mask, - COGL_MATERIAL_FLUSH_DISABLE_MASK, - disable_mask, - /* Redundant when dealing with unsliced - * textures but does no harm... */ - COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE, - batch_start->layer0_override_texture, - NULL); + _cogl_material_flush_gl_state (ctx->source_material, + COGL_MATERIAL_FLUSH_FALLBACK_MASK, + batch_start->fallback_mask, + COGL_MATERIAL_FLUSH_DISABLE_MASK, + disable_mask, + /* Redundant when dealing with unsliced + * textures but does no harm... */ + COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE, + batch_start->layer0_override_texture, + NULL); for (i = 0; i < batch_start->n_layers; i++) { @@ -140,7 +103,7 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start, /* FIXME: This api is a bit yukky, ideally it will be removed if we * re-work the cogl_enable mechanism */ - enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material); + enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material); if (ctx->enable_backface_culling) enable_flags |= COGL_ENABLE_BACKFACE_CULLING; @@ -150,12 +113,32 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start, GE (glVertexPointer (2, GL_FLOAT, stride, vertex_pointer)); _cogl_current_matrix_state_flush (); - GE (glDrawRangeElements (GL_TRIANGLES, - 0, ctx->static_indices->len - 1, - 6 * batch_len, - GL_UNSIGNED_SHORT, - ctx->static_indices->data)); +#ifdef HAVE_COGL_GL + + GE( glDrawArrays (GL_QUADS, 0, batch_len * 4) ); + +#else /* HAVE_COGL_GL */ + + /* GLES doesn't support GL_QUADS so we will use GL_TRIANGLES and + indices */ + { + int needed_indices = batch_len * 6; + CoglHandle indices_handle + = cogl_vertex_buffer_indices_get_for_quads (needed_indices); + CoglVertexBufferIndices *indices + = _cogl_vertex_buffer_indices_pointer_from_handle (indices_handle); + + GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, + GPOINTER_TO_UINT (indices->vbo_name))); + GE (glDrawElements (GL_TRIANGLES, + 6 * batch_len, + indices->type, + NULL)); + GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0)); + } + +#endif /* HAVE_COGL_GL */ /* DEBUGGING CODE XXX: * This path will cause all rectangles to be drawn with a red, green @@ -177,7 +160,7 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start, color == 1 ? 0xff : 0x00, color == 2 ? 0xff : 0x00, 0xff); - cogl_material_flush_gl_state (outline, NULL); + _cogl_material_flush_gl_state (outline, NULL); _cogl_current_matrix_state_flush (); GE( glDrawArrays (GL_LINE_LOOP, 4 * i, 4) ); } @@ -791,7 +774,7 @@ _cogl_rectangles_with_multitexture_coords ( /* We don't support multi texturing using textures with any waste if the * user has supplied a custom texture matrix, since we don't know if * the result will end up trying to texture from the waste area. */ - flags = cogl_material_layer_get_flags (layer); + flags = _cogl_material_layer_get_flags (layer); if (flags & COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX && _cogl_texture_span_has_waste (texture, 0, 0)) { @@ -1041,13 +1024,13 @@ _cogl_texture_sliced_polygon (CoglTextureVertex *vertices, v += stride; } - cogl_material_flush_gl_state (ctx->source_material, - COGL_MATERIAL_FLUSH_DISABLE_MASK, - (guint32)~1, /* disable all except the + _cogl_material_flush_gl_state (ctx->source_material, + COGL_MATERIAL_FLUSH_DISABLE_MASK, + (guint32)~1, /* disable all except the first layer */ - COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE, - gl_handle, - NULL); + COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE, + gl_handle, + NULL); _cogl_current_matrix_state_flush (); GE( glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) ); @@ -1136,10 +1119,10 @@ _cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices, c[3] = cogl_color_get_alpha_float (&vertices[i].color); } - cogl_material_flush_gl_state (ctx->source_material, - COGL_MATERIAL_FLUSH_FALLBACK_MASK, - fallback_mask, - NULL); + _cogl_material_flush_gl_state (ctx->source_material, + COGL_MATERIAL_FLUSH_FALLBACK_MASK, + fallback_mask, + NULL); _cogl_current_matrix_state_flush (); GE (glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices)); @@ -1175,7 +1158,6 @@ cogl_polygon (CoglTextureVertex *vertices, { CoglHandle layer = (CoglHandle)tmp->data; CoglHandle tex_handle = cogl_material_layer_get_texture (layer); - CoglTexture *tex = _cogl_texture_pointer_from_handle (tex_handle); if (i == 0 && cogl_texture_is_sliced (tex_handle)) { @@ -1203,7 +1185,8 @@ cogl_polygon (CoglTextureVertex *vertices, use_sliced_polygon_fallback = TRUE; n_layers = 1; - if (tex->min_filter != GL_NEAREST || tex->mag_filter != GL_NEAREST) + if (cogl_material_layer_get_min_filter (layer) != GL_NEAREST + || cogl_material_layer_get_mag_filter (layer) != GL_NEAREST) { static gboolean warning_seen = FALSE; if (!warning_seen) @@ -1217,11 +1200,14 @@ cogl_polygon (CoglTextureVertex *vertices, } #ifdef HAVE_COGL_GL - /* Temporarily change the wrapping mode on all of the slices to use - * a transparent border - * XXX: it's doesn't look like we save/restore this, like the comment - * implies? */ - _cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_BORDER); + { + CoglTexture *tex = _cogl_texture_pointer_from_handle (tex_handle); + /* Temporarily change the wrapping mode on all of the slices to use + * a transparent border + * XXX: it's doesn't look like we save/restore this, like + * the comment implies? */ + _cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_BORDER); + } #endif break; } @@ -1254,7 +1240,7 @@ cogl_polygon (CoglTextureVertex *vertices, /* Prepare GL state */ enable_flags = COGL_ENABLE_VERTEX_ARRAY; - enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material); + enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material); if (ctx->enable_backface_culling) enable_flags |= COGL_ENABLE_BACKFACE_CULLING; diff --git a/clutter/cogl/common/cogl-util.c b/clutter/cogl/common/cogl-util.c index d71b9ffd8..2d86f73f3 100644 --- a/clutter/cogl/common/cogl-util.c +++ b/clutter/cogl/common/cogl-util.c @@ -103,159 +103,6 @@ cogl_handle_get_type (void) return our_type; } -GType -cogl_pixel_format_get_type (void) -{ - static GType gtype = 0; - - if (G_UNLIKELY (gtype == 0)) - { - static const GEnumValue values[] = { - { COGL_PIXEL_FORMAT_ANY, "COGL_PIXEL_FORMAT_ANY", "any" }, - { COGL_PIXEL_FORMAT_A_8, "COGL_PIXEL_FORMAT_A_8", "a-8" }, - { COGL_PIXEL_FORMAT_RGB_565, "COGL_PIXEL_FORMAT_RGB_565", "rgb-565" }, - { COGL_PIXEL_FORMAT_RGBA_4444, "COGL_PIXEL_FORMAT_RGBA_4444", "rgba-4444" }, - { COGL_PIXEL_FORMAT_RGBA_5551, "COGL_PIXEL_FORMAT_RGBA_5551", "rgba-5551" }, - { COGL_PIXEL_FORMAT_YUV, "COGL_PIXEL_FORMAT_YUV", "yuv" }, - { COGL_PIXEL_FORMAT_G_8, "COGL_PIXEL_FORMAT_G_8", "g-8" }, - { COGL_PIXEL_FORMAT_RGB_888, "COGL_PIXEL_FORMAT_RGB_888", "rgb-888" }, - { COGL_PIXEL_FORMAT_BGR_888, "COGL_PIXEL_FORMAT_BGR_888", "bgr-888" }, - { COGL_PIXEL_FORMAT_RGBA_8888, "COGL_PIXEL_FORMAT_RGBA_8888", "rgba-8888" }, - { COGL_PIXEL_FORMAT_BGRA_8888, "COGL_PIXEL_FORMAT_BGRA_8888", "bgra-8888" }, - { COGL_PIXEL_FORMAT_ARGB_8888, "COGL_PIXEL_FORMAT_ARGB_8888", "argb-8888" }, - { COGL_PIXEL_FORMAT_ABGR_8888, "COGL_PIXEL_FORMAT_ABGR_8888", "abgr-8888" }, - { COGL_PIXEL_FORMAT_RGBA_8888_PRE, "COGL_PIXEL_FORMAT_RGBA_8888_PRE", "rgba-8888-pre" }, - { COGL_PIXEL_FORMAT_BGRA_8888_PRE, "COGL_PIXEL_FORMAT_BGRA_8888_PRE", "bgra-8888-pre" }, - { COGL_PIXEL_FORMAT_ARGB_8888_PRE, "COGL_PIXEL_FORMAT_ARGB_8888_PRE", "argb-8888-pre" }, - { COGL_PIXEL_FORMAT_ABGR_8888_PRE, "COGL_PIXEL_FORMAT_ABGR_8888_PRE", "abgr-8888-pre" }, - { COGL_PIXEL_FORMAT_RGBA_4444_PRE, "COGL_PIXEL_FORMAT_RGBA_4444_PRE", "rgba-4444-pre" }, - { COGL_PIXEL_FORMAT_RGBA_5551_PRE, "COGL_PIXEL_FORMAT_RGBA_5551_PRE", "rgba-5551-pre" }, - { 0, NULL, NULL } - }; - - gtype = - g_enum_register_static (g_intern_static_string ("CoglPixelFormat"), - values); - } - - return gtype; -} - -GType -cogl_feature_flags_get_type (void) -{ - static GType gtype = 0; - - if (G_UNLIKELY (gtype == 0)) - { - static const GFlagsValue values[] = { - { COGL_FEATURE_TEXTURE_RECTANGLE, "COGL_FEATURE_TEXTURE_RECTANGLE", "texture-rectangle" }, - { COGL_FEATURE_TEXTURE_NPOT, "COGL_FEATURE_TEXTURE_NPOT", "texture-npot" }, - { COGL_FEATURE_TEXTURE_YUV, "COGL_FEATURE_TEXTURE_YUV", "yuv" }, - { COGL_FEATURE_TEXTURE_READ_PIXELS, "COGL_FEATURE_TEXTURE_READ_PIXELS", "read-pixels" }, - { COGL_FEATURE_SHADERS_GLSL, "COGL_FEATURE_SHADERS_GLSL", "shaders-glsl" }, - { COGL_FEATURE_OFFSCREEN, "COGL_FEATURE_OFFSCREEN", "offscreen" }, - { COGL_FEATURE_OFFSCREEN_MULTISAMPLE, "COGL_FEATURE_OFFSCREEN_MULTISAMPLE", "offscreen-multisample" }, - { COGL_FEATURE_OFFSCREEN_BLIT, "COGL_FEATURE_OFFSCREEN_BLIT", "offscreen-blit" }, - { COGL_FEATURE_FOUR_CLIP_PLANES, "COGL_FEATURE_FOUR_CLIP_PLANES", "four-clip-planes" }, - { COGL_FEATURE_STENCIL_BUFFER, "COGL_FEATURE_STENCIL_BUFFER", "stencil-buffer" }, - { 0, NULL, NULL } - }; - - gtype = - g_flags_register_static (g_intern_static_string ("CoglFeatureFlags"), - values); - } - - return gtype; -} - -GType -cogl_buffer_target_get_type (void) -{ - static GType gtype = 0; - - if (G_UNLIKELY (gtype == 0)) - { - static const GFlagsValue values[] = { - { COGL_WINDOW_BUFFER, "COGL_WINDOW_BUFFER", "window-buffer" }, - { COGL_OFFSCREEN_BUFFER, "COGL_OFFSCREEN_BUFFER", "offscreen-buffer" }, - { 0, NULL, NULL } - }; - - gtype = - g_flags_register_static (g_intern_static_string ("CoglBufferTarget"), - values); - } - - return gtype; -} - -GType -cogl_matrix_mode_get_type (void) -{ - static GType gtype = 0; - - if (G_UNLIKELY (gtype == 0)) - { - static const GEnumValue values[] = { - { COGL_MATRIX_MODELVIEW, "COGL_MATRIX_MODELVIEW", "modelview" }, - { COGL_MATRIX_PROJECTION, "COGL_MATRIX_PROJECTION", "projection" }, - { COGL_MATRIX_TEXTURE, "COGL_MATRIX_TEXTURE", "texture" }, - { 0, NULL, NULL } - }; - - gtype = - g_enum_register_static (g_intern_static_string ("CoglMatrixMode"), - values); - } - - return gtype; -} - -GType -cogl_texture_flags_get_type (void) -{ - static GType gtype = 0; - - if (G_UNLIKELY (gtype == 0)) - { - static const GFlagsValue values[] = { - { COGL_TEXTURE_NONE, "COGL_TEXTURE_NONE", "none" }, - { COGL_TEXTURE_AUTO_MIPMAP, "COGL_TEXTURE_AUTO_MIPMAP", "auto-mipmap" }, - { 0, NULL, NULL } - }; - - gtype = - g_flags_register_static (g_intern_static_string ("CoglTextureFlags"), - values); - } - - return gtype; -} - -GType -cogl_fog_mode_get_type (void) -{ - static GType gtype = 0; - - if (G_UNLIKELY (gtype == 0)) - { - static const GEnumValue values[] = { - { COGL_FOG_MODE_LINEAR, "COGL_FOG_MODE_LINEAR", "linear" }, - { COGL_FOG_MODE_EXPONENTIAL, "COGL_FOG_MODE_EXPONENTIAL", "exponential" }, - { COGL_FOG_MODE_EXPONENTIAL_SQUARED, "COGL_FOG_MODE_EXPONENTIAL_SQUARED", "exponential-squared" }, - { 0, NULL, NULL } - }; - - gtype = - g_enum_register_static (g_intern_static_string ("CoglFogMode"), - values); - } - - return gtype; -} - /* * CoglFixed */ diff --git a/clutter/cogl/common/cogl-vertex-buffer-private.h b/clutter/cogl/common/cogl-vertex-buffer-private.h index 68a709b54..558765303 100644 --- a/clutter/cogl/common/cogl-vertex-buffer-private.h +++ b/clutter/cogl/common/cogl-vertex-buffer-private.h @@ -99,9 +99,9 @@ typedef struct _CoglVertexBufferAttrib union _u { const void *pointer; - gsize vbo_offset; + size_t vbo_offset; } u; - gsize span_bytes; + size_t span_bytes; guint16 stride; guint8 n_components; guint8 texture_unit; @@ -129,25 +129,41 @@ typedef struct _CoglVertexBufferVBO { CoglVertexBufferVBOFlags flags; - /* Note: this is a pointer to handle fallbacks, and normally holds - * a GLuint value */ - gpointer vbo_name; /*!< The name of the corresponding buffer object */ - gsize vbo_bytes; /*!< The lengh of the allocated buffer object in bytes */ + /* Note: this is a pointer to handle fallbacks. It normally holds + * a GLuint VBO name, but when the driver doesn't support VBOs then + * this simply points to an malloc'd buffer. */ + void *vbo_name; /*!< The name of the corresponding buffer object */ + size_t vbo_bytes; /*!< The lengh of the allocated buffer object in bytes */ GList *attributes; } CoglVertexBufferVBO; +typedef struct _CoglVertexBufferIndices +{ + CoglHandleObject _parent; + + /* Note: this is a pointer to handle fallbacks. It normally holds + * a GLuint VBO name, but when the driver doesn't support VBOs then + * this simply points to an malloc'd buffer. */ + void *vbo_name; + GLenum type; +} CoglVertexBufferIndices; typedef struct _CoglVertexBuffer { CoglHandleObject _parent; - guint n_vertices; /*!< The number of vertices in the buffer */ - GList *submitted_vbos; /* The VBOs currently submitted to the GPU */ + int n_vertices; /*!< The number of vertices in the buffer */ + GList *submitted_vbos; /* The VBOs currently submitted to the GPU */ /* Note: new_attributes is normally NULL and only valid while * modifying a buffer. */ - GList *new_attributes; /*!< attributes pending submission */ + GList *new_attributes; /*!< attributes pending submission */ + } CoglVertexBuffer; +CoglVertexBuffer *_cogl_vertex_buffer_pointer_from_handle (CoglHandle handle); +CoglVertexBufferIndices * + _cogl_vertex_buffer_indices_pointer_from_handle (CoglHandle handle); + #endif /* __COGL_VERTEX_BUFFER_H */ diff --git a/clutter/cogl/common/cogl-vertex-buffer.c b/clutter/cogl/common/cogl-vertex-buffer.c index f6fa6ba89..a36bb1cec 100644 --- a/clutter/cogl/common/cogl-vertex-buffer.c +++ b/clutter/cogl/common/cogl-vertex-buffer.c @@ -136,6 +136,7 @@ #include "cogl-handle.h" #include "cogl-vertex-buffer-private.h" #include "cogl-texture-private.h" +#include "cogl-material-private.h" #define PAD_FOR_ALIGNMENT(VAR, TYPE_SIZE) \ (VAR = TYPE_SIZE + ((VAR - 1) & ~(TYPE_SIZE - 1))) @@ -200,8 +201,10 @@ #endif /* HAVE_COGL_GL */ static void _cogl_vertex_buffer_free (CoglVertexBuffer *buffer); +static void _cogl_vertex_buffer_indices_free (CoglVertexBufferIndices *buffer_indices); COGL_HANDLE_DEFINE (VertexBuffer, vertex_buffer); +COGL_HANDLE_DEFINE (VertexBufferIndices, vertex_buffer_indices); CoglHandle cogl_vertex_buffer_new (guint n_vertices) @@ -411,13 +414,13 @@ get_gl_type_size (CoglVertexBufferAttribFlags flags) } void -cogl_vertex_buffer_add (CoglHandle handle, - const char *attribute_name, - guint8 n_components, - GLenum gl_type, - gboolean normalized, - guint16 stride, - const void *pointer) +cogl_vertex_buffer_add (CoglHandle handle, + const char *attribute_name, + guint8 n_components, + CoglAttributeType type, + gboolean normalized, + guint16 stride, + const void *pointer) { CoglVertexBuffer *buffer; GQuark name_quark = g_quark_from_string (attribute_name); @@ -485,7 +488,7 @@ cogl_vertex_buffer_add (CoglHandle handle, attribute->u.pointer = pointer; attribute->texture_unit = texture_unit; - flags |= get_attribute_gl_type_flag_from_gl_type (gl_type); + flags |= get_attribute_gl_type_flag_from_gl_type (type); flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED; /* Note: We currently just assume, if an attribute is *ever* updated @@ -1638,14 +1641,14 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer) } } - cogl_material_flush_gl_state (ctx->source_material, - COGL_MATERIAL_FLUSH_FALLBACK_MASK, - fallback_mask, - COGL_MATERIAL_FLUSH_DISABLE_MASK, - disable_mask, - NULL); + _cogl_material_flush_gl_state (ctx->source_material, + COGL_MATERIAL_FLUSH_FALLBACK_MASK, + fallback_mask, + COGL_MATERIAL_FLUSH_DISABLE_MASK, + disable_mask, + NULL); - enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material); + enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material); if (ctx->enable_backface_culling) enable_flags |= COGL_ENABLE_BACKFACE_CULLING; @@ -1716,23 +1719,21 @@ disable_state_for_drawing_buffer (CoglVertexBuffer *buffer) } void -cogl_vertex_buffer_draw (CoglHandle handle, - GLenum mode, - GLint first, - GLsizei count) +cogl_vertex_buffer_draw (CoglHandle handle, + CoglVerticesMode mode, + int first, + int count) { CoglVertexBuffer *buffer; if (!cogl_is_vertex_buffer (handle)) return; - cogl_clip_ensure (); - buffer = _cogl_vertex_buffer_pointer_from_handle (handle); - enable_state_for_drawing_buffer (buffer); - + cogl_clip_ensure (); _cogl_current_matrix_state_flush (); + enable_state_for_drawing_buffer (buffer); /* FIXME: flush cogl cache */ GE (glDrawArrays (mode, first, count)); @@ -1740,35 +1741,127 @@ cogl_vertex_buffer_draw (CoglHandle handle, disable_state_for_drawing_buffer (buffer); } +static int +get_indices_type_size (GLuint indices_type) +{ + if (indices_type == GL_UNSIGNED_BYTE) + return sizeof (GLubyte); + if (indices_type == GL_UNSIGNED_SHORT) + return sizeof (GLushort); + else + { + g_critical ("Unknown indices type %d\n", indices_type); + return 0; + } +} + +CoglHandle +cogl_vertex_buffer_indices_new (CoglIndicesType indices_type, + const void *indices_array, + int indices_len) +{ + gboolean fallback = + (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE; + size_t indices_bytes; + CoglVertexBufferIndices *indices; + + _COGL_GET_CONTEXT (ctx, 0); + + indices = g_slice_alloc (sizeof (CoglVertexBufferIndices)); + + if (indices_type == COGL_INDICES_TYPE_UNSIGNED_BYTE) + indices->type = GL_UNSIGNED_BYTE; + else if (indices_type == COGL_INDICES_TYPE_UNSIGNED_SHORT) + indices->type = GL_UNSIGNED_SHORT; + else + { + g_critical ("unknown indices type %d", indices_type); + g_slice_free (CoglVertexBufferIndices, indices); + return 0; + } + + indices_bytes = get_indices_type_size (indices->type) * indices_len; + if (fallback) + { + indices->vbo_name = g_malloc (indices_len); + memcpy (indices->vbo_name, indices_array, indices_bytes); + } + else + { + GE (glGenBuffers (1, (GLuint *)&indices->vbo_name)); + GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, + GPOINTER_TO_UINT (indices->vbo_name))); + GE (glBufferData (GL_ELEMENT_ARRAY_BUFFER, + indices_bytes, + indices_array, + GL_STATIC_DRAW)); + GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0)); + } + + return _cogl_vertex_buffer_indices_handle_new (indices); +} + void -cogl_vertex_buffer_draw_elements (CoglHandle handle, - GLenum mode, - GLuint min_index, - GLuint max_index, - GLsizei count, - GLenum indices_type, - const GLvoid *indices) +_cogl_vertex_buffer_indices_free (CoglVertexBufferIndices *indices) +{ + gboolean fallback = + (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + if (fallback) + g_free (indices->vbo_name); + else + GE (glDeleteBuffers (1, (GLuint *)&indices->vbo_name)); + + g_slice_free (CoglVertexBufferIndices, indices); +} + +void +cogl_vertex_buffer_draw_elements (CoglHandle handle, + CoglVerticesMode mode, + CoglHandle indices_handle, + int min_index, + int max_index, + int indices_offset, + int count) { CoglVertexBuffer *buffer; + gboolean fallback = + (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE; + size_t byte_offset; + CoglVertexBufferIndices *indices = NULL; _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (!cogl_is_vertex_buffer (handle)) return; - cogl_clip_ensure (); - buffer = _cogl_vertex_buffer_pointer_from_handle (handle); + if (!cogl_is_vertex_buffer_indices (indices_handle)) + return; + + indices = _cogl_vertex_buffer_indices_pointer_from_handle (indices_handle); + + cogl_clip_ensure (); + _cogl_current_matrix_state_flush (); enable_state_for_drawing_buffer (buffer); - _cogl_current_matrix_state_flush (); + byte_offset = indices_offset * get_indices_type_size (indices->type); + if (fallback) + byte_offset = (size_t)(((char *)indices->vbo_name) + byte_offset); + else + GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, + GPOINTER_TO_UINT (indices->vbo_name))); /* FIXME: flush cogl cache */ GE (glDrawRangeElements (mode, min_index, max_index, - count, indices_type, indices)); + count, indices->type, (void *)byte_offset)); disable_state_for_drawing_buffer (buffer); + + GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0)); } static void @@ -1778,8 +1871,92 @@ _cogl_vertex_buffer_free (CoglVertexBuffer *buffer) for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next) cogl_vertex_buffer_vbo_free (tmp->data, TRUE); + g_list_free (buffer->submitted_vbos); + for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next) cogl_vertex_buffer_attribute_free (tmp->data); + g_list_free (buffer->new_attributes); g_slice_free (CoglVertexBuffer, buffer); } + +CoglHandle +cogl_vertex_buffer_indices_get_for_quads (guint n_indices) +{ + _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE); + + /* Check if the indices would fit in a byte array */ + if (n_indices <= 256 / 4 * 6) + { + /* Generate the byte array if we haven't already */ + if (ctx->quad_indices_byte == COGL_INVALID_HANDLE) + { + guint8 *byte_array = g_malloc (256 / 4 * 6 * sizeof (guint8)); + guint8 *p = byte_array; + int i, vert_num = 0; + + for (i = 0; i < 256 / 4; i++) + { + *(p++) = vert_num + 0; + *(p++) = vert_num + 1; + *(p++) = vert_num + 2; + *(p++) = vert_num + 0; + *(p++) = vert_num + 2; + *(p++) = vert_num + 3; + vert_num += 4; + } + + ctx->quad_indices_byte + = cogl_vertex_buffer_indices_new (COGL_INDICES_TYPE_UNSIGNED_BYTE, + byte_array, + 256 / 4 * 6); + + g_free (byte_array); + } + + return ctx->quad_indices_byte; + } + else + { + if (ctx->quad_indices_short_len < n_indices) + { + guint16 *short_array; + guint16 *p; + int i, vert_num = 0; + + if (ctx->quad_indices_short != COGL_INVALID_HANDLE) + cogl_handle_unref (ctx->quad_indices_short); + /* Pick a power of two >= MAX (512, n_indices) */ + if (ctx->quad_indices_short_len == 0) + ctx->quad_indices_short_len = 512; + while (ctx->quad_indices_short_len < n_indices) + ctx->quad_indices_short_len *= 2; + + /* Over-allocate to generate a whole number of quads */ + p = short_array = g_malloc ((ctx->quad_indices_short_len + + 5) / 6 * 6 + * sizeof (guint16)); + + /* Fill in the complete quads */ + for (i = 0; i < ctx->quad_indices_short_len; i += 6) + { + *(p++) = vert_num + 0; + *(p++) = vert_num + 1; + *(p++) = vert_num + 2; + *(p++) = vert_num + 0; + *(p++) = vert_num + 2; + *(p++) = vert_num + 3; + vert_num += 4; + } + + ctx->quad_indices_short + = cogl_vertex_buffer_indices_new (COGL_INDICES_TYPE_UNSIGNED_SHORT, + short_array, + ctx->quad_indices_short_len); + + g_free (short_array); + } + + return ctx->quad_indices_short; + } +} diff --git a/clutter/cogl/common/cogl.c b/clutter/cogl/common/cogl.c index 2495d8172..336303917 100644 --- a/clutter/cogl/common/cogl.c +++ b/clutter/cogl/common/cogl.c @@ -42,6 +42,7 @@ typedef CoglFuncPtr (*GLXGetProcAddressProc) (const guint8 *procName); #include "cogl-internal.h" #include "cogl-util.h" #include "cogl-context.h" +#include "cogl-material-private.h" #if defined (HAVE_COGL_GLES2) || defined (HAVE_COGL_GLES) #include "cogl-gles2-wrapper.h" @@ -213,30 +214,39 @@ cogl_get_enable () } void -cogl_enable_depth_test (gboolean setting) +cogl_set_depth_test_enabled (gboolean setting) { if (setting) { glEnable (GL_DEPTH_TEST); - glEnable (GL_ALPHA_TEST); glDepthFunc (GL_LEQUAL); - glAlphaFunc (GL_GREATER, 0.1); } else - { - glDisable (GL_DEPTH_TEST); - glDisable (GL_ALPHA_TEST); - } + glDisable (GL_DEPTH_TEST); +} + +gboolean +cogl_get_depth_test_enabled (void) +{ + return glIsEnabled (GL_DEPTH_TEST) == GL_TRUE ? TRUE : FALSE; } void -cogl_enable_backface_culling (gboolean setting) +cogl_set_backface_culling_enabled (gboolean setting) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); ctx->enable_backface_culling = setting; } +gboolean +cogl_get_backface_culling_enabled (void) +{ + _COGL_GET_CONTEXT (ctx, FALSE); + + return ctx->enable_backface_culling; +} + void cogl_set_source_color (const CoglColor *color) { @@ -375,7 +385,7 @@ _cogl_add_stencil_clip (float x_offset, { _COGL_GET_CONTEXT (ctx, NO_RETVAL); - cogl_material_flush_gl_state (ctx->stencil_material, NULL); + _cogl_material_flush_gl_state (ctx->stencil_material, NULL); if (first) { @@ -465,12 +475,12 @@ cogl_viewport (guint width, } void -cogl_setup_viewport (guint width, - guint height, - float fovy, - float aspect, - float z_near, - float z_far) +_cogl_setup_viewport (guint width, + guint height, + float fovy, + float aspect, + float z_near, + float z_far) { float z_camera; CoglMatrix projection_matrix; @@ -478,7 +488,7 @@ cogl_setup_viewport (guint width, GE( glViewport (0, 0, width, height) ); /* For Ortho projection. - * _cogl_current_matrix_ortho (0, width << 16, 0, height << 16, -1 << 16, 1 << 16); + * _cogl_current_matrix_ortho (0, width, 0, height, -1, 1); */ cogl_perspective (fovy, aspect, z_near, z_far); @@ -532,7 +542,7 @@ cogl_setup_viewport (guint width, } CoglFeatureFlags -cogl_get_features () +cogl_get_features (void) { _COGL_GET_CONTEXT (ctx, 0); @@ -653,9 +663,11 @@ cogl_disable_fog (void) glDisable (GL_FOG); } +#if 0 void cogl_flush_gl_state (int flags) { _cogl_current_matrix_state_flush (); } +#endif diff --git a/clutter/cogl/gl/Makefile.am b/clutter/cogl/gl/Makefile.am index 367f674f2..1aab5b649 100644 --- a/clutter/cogl/gl/Makefile.am +++ b/clutter/cogl/gl/Makefile.am @@ -35,11 +35,6 @@ cogl_sources = \ cogl-context.c \ $(NULL) -coglincludedir = $(includedir)/clutter-@CLUTTER_API_VERSION@/cogl -coglinclude_HEADERS = \ - $(cogl_headers) \ - $(top_builddir)/clutter/cogl/cogl.h - INCLUDES = \ -I$(top_srcdir)/clutter/cogl \ -I$(top_srcdir)/clutter/cogl/common \ @@ -50,12 +45,12 @@ INCLUDES = \ -DG_LOG_DOMAIN=\"Cogl-GL\" \ -DCLUTTER_COMPILATION -noinst_LTLIBRARIES = libclutter-cogl.la +noinst_LTLIBRARIES = libclutter-cogl-gl.la -libclutter_cogl_la_CPPFLAGS = $(CLUTTER_CFLAGS) $(COGL_DEBUG_CFLAGS) $(CLUTTER_DEBUG_CFLAGS) $(MAINTAINER_CFLAGS) -libclutter_cogl_la_LIBADD = -lm $(CLUTTER_LIBS) $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la -libclutter_cogl_la_DEPENDENCIES = $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la -libclutter_cogl_la_SOURCES = \ +libclutter_cogl_gl_la_CPPFLAGS = $(CLUTTER_CFLAGS) $(COGL_DEBUG_CFLAGS) $(CLUTTER_DEBUG_CFLAGS) $(MAINTAINER_CFLAGS) +libclutter_cogl_gl_la_LIBADD = -lm $(CLUTTER_LIBS) $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la +libclutter_cogl_gl_la_DEPENDENCIES = $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la +libclutter_cogl_gl_la_SOURCES = \ $(top_builddir)/clutter/cogl/cogl.h \ $(cogl_headers) \ $(cogl_priv_headers) \ diff --git a/clutter/cogl/gl/cogl-context.c b/clutter/cogl/gl/cogl-context.c index 986da8aa8..201e05db7 100644 --- a/clutter/cogl/gl/cogl-context.c +++ b/clutter/cogl/gl/cogl-context.c @@ -37,7 +37,7 @@ static CoglContext *_context = NULL; static gboolean gl_is_indirect = FALSE; -gboolean +static gboolean cogl_create_context () { GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 }; @@ -69,7 +69,6 @@ cogl_create_context () _context->journal = g_array_new (FALSE, FALSE, sizeof (CoglJournalEntry)); _context->logged_vertices = g_array_new (FALSE, FALSE, sizeof (GLfloat)); - _context->static_indices = g_array_new (FALSE, FALSE, sizeof (GLushort)); _context->polygon_vertices = g_array_new (FALSE, FALSE, sizeof (CoglTextureGLVertex)); @@ -136,6 +135,9 @@ cogl_create_context () _context->pf_glActiveTexture = NULL; _context->pf_glClientActiveTexture = NULL; + _context->pf_glBlendFuncSeparate = NULL; + _context->pf_glBlendEquationSeparate = NULL; + /* Initialise the clip stack */ _cogl_clip_stack_state_init (); @@ -146,8 +148,7 @@ cogl_create_context () _context->default_gl_texture_2d_tex = cogl_texture_new_from_data (1, /* width */ 1, /* height */ - -1, /* max waste */ - COGL_TEXTURE_NONE, /* flags */ + COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_RGBA_8888, /* data format */ /* internal format */ COGL_PIXEL_FORMAT_RGBA_8888, @@ -156,8 +157,7 @@ cogl_create_context () _context->default_gl_texture_rect_tex = cogl_texture_new_from_data (1, /* width */ 1, /* height */ - -1, /* max waste */ - COGL_TEXTURE_NONE, /* flags */ + COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_RGBA_8888, /* data format */ /* internal format */ COGL_PIXEL_FORMAT_RGBA_8888, @@ -165,16 +165,20 @@ cogl_create_context () default_texture_data); cogl_set_source (_context->default_material); - cogl_material_flush_gl_state (_context->source_material, NULL); + _cogl_material_flush_gl_state (_context->source_material, NULL); enable_flags = - cogl_material_get_cogl_enable_flags (_context->source_material); + _cogl_material_get_cogl_enable_flags (_context->source_material); cogl_enable (enable_flags); + _context->quad_indices_byte = COGL_INVALID_HANDLE; + _context->quad_indices_short = COGL_INVALID_HANDLE; + _context->quad_indices_short_len = 0; + return TRUE; } void -cogl_destroy_context () +_cogl_destroy_context () { if (_context == NULL) return; @@ -199,13 +203,16 @@ cogl_destroy_context () if (_context->logged_vertices) g_array_free (_context->logged_vertices, TRUE); - if (_context->static_indices) - g_array_free (_context->static_indices, TRUE); if (_context->polygon_vertices) g_array_free (_context->polygon_vertices, TRUE); if (_context->current_layers) g_array_free (_context->current_layers, TRUE); + if (_context->quad_indices_byte) + cogl_handle_unref (_context->quad_indices_byte); + if (_context->quad_indices_short) + cogl_handle_unref (_context->quad_indices_short); + g_free (_context); } diff --git a/clutter/cogl/gl/cogl-context.h b/clutter/cogl/gl/cogl-context.h index 2660ed812..d845a6c12 100644 --- a/clutter/cogl/gl/cogl-context.h +++ b/clutter/cogl/gl/cogl-context.h @@ -78,7 +78,6 @@ typedef struct * can batch things together. */ GArray *journal; GArray *logged_vertices; - GArray *static_indices; GArray *polygon_vertices; /* Some simple caching, to minimize state changes... */ @@ -102,6 +101,12 @@ typedef struct floatVec2 path_nodes_max; CoglHandle stencil_material; + /* Pre-generated VBOs containing indices to generate GL_TRIANGLES + out of a vertex array of quads */ + CoglHandle quad_indices_byte; + guint quad_indices_short_len; + CoglHandle quad_indices_short; + /* Relying on glext.h to define these */ COGL_PFNGLGENRENDERBUFFERSEXTPROC pf_glGenRenderbuffersEXT; COGL_PFNGLDELETERENDERBUFFERSEXTPROC pf_glDeleteRenderbuffersEXT; @@ -115,6 +120,7 @@ typedef struct COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC pf_glDeleteFramebuffersEXT; COGL_PFNGLBLITFRAMEBUFFEREXTPROC pf_glBlitFramebufferEXT; COGL_PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC pf_glRenderbufferStorageMultisampleEXT; + COGL_PFNGLGENERATEMIPMAPEXTPROC pf_glGenerateMipmapEXT; COGL_PFNGLCREATEPROGRAMOBJECTARBPROC pf_glCreateProgramObjectARB; COGL_PFNGLCREATESHADEROBJECTARBPROC pf_glCreateShaderObjectARB; @@ -164,6 +170,11 @@ typedef struct COGL_PFNGLACTIVETEXTUREPROC pf_glActiveTexture; COGL_PFNGLCLIENTACTIVETEXTUREPROC pf_glClientActiveTexture; + + COGL_PFNGLBLENDEQUATIONPROC pf_glBlendEquation; + COGL_PFNGLBLENDCOLORPROC pf_glBlendColor; + COGL_PFNGLBLENDFUNCSEPARATEPROC pf_glBlendFuncSeparate; + COGL_PFNGLBLENDEQUATIONSEPARATEPROC pf_glBlendEquationSeparate; } CoglContext; CoglContext * diff --git a/clutter/cogl/gl/cogl-defines.h.in b/clutter/cogl/gl/cogl-defines.h.in index 8e2df9ec3..025b4cad0 100644 --- a/clutter/cogl/gl/cogl-defines.h.in +++ b/clutter/cogl/gl/cogl-defines.h.in @@ -773,6 +773,10 @@ typedef void GLsizei width, GLsizei height); +typedef void + (APIENTRYP COGL_PFNGLGENERATEMIPMAPEXTPROC) + (GLenum target); + typedef GLhandleARB (APIENTRYP COGL_PFNGLCREATEPROGRAMOBJECTARBPROC) (void); @@ -1020,6 +1024,29 @@ typedef void (APIENTRYP COGL_PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture); +typedef void + (APIENTRYP COGL_PFNGLBLENDFUNCSEPARATEPROC) + (GLenum srcRGB, + GLenum dstRGB, + GLenum srcAlpha, + GLenum dstAlpha); + +typedef void + (APIENTRYP COGL_PFNGLBLENDEQUATIONSEPARATEPROC) + (GLenum modeRGB, + GLenum modeAlpha); + +typedef void + (APIENTRYP COGL_PFNGLBLENDEQUATIONPROC) + (GLenum mode); + +typedef void + (APIENTRYP COGL_PFNGLBLENDCOLORPROC) + (GLclampf red, + GLclampf green, + GLclampf blue, + GLclampf alpha); + G_END_DECLS #endif diff --git a/clutter/cogl/gl/cogl-primitives.c b/clutter/cogl/gl/cogl-primitives.c index f3c11c134..6c106f9ec 100644 --- a/clutter/cogl/gl/cogl-primitives.c +++ b/clutter/cogl/gl/cogl-primitives.c @@ -29,6 +29,7 @@ #include "cogl-internal.h" #include "cogl-context.h" #include "cogl-clip-stack.h" +#include "cogl-material-private.h" #include #include @@ -78,13 +79,13 @@ _cogl_path_stroke_nodes () _COGL_GET_CONTEXT (ctx, NO_RETVAL); - enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material); + enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material); cogl_enable (enable_flags); - cogl_material_flush_gl_state (ctx->source_material, - COGL_MATERIAL_FLUSH_DISABLE_MASK, - (guint32)~0, /* disable all texture layers */ - NULL); + _cogl_material_flush_gl_state (ctx->source_material, + COGL_MATERIAL_FLUSH_DISABLE_MASK, + (guint32)~0, /* disable all texture layers */ + NULL); _cogl_current_matrix_state_flush (); while (path_start < ctx->path_nodes->len) @@ -133,10 +134,10 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* Just setup a simple material that doesn't use texturing... */ - cogl_material_flush_gl_state (ctx->stencil_material, NULL); + _cogl_material_flush_gl_state (ctx->stencil_material, NULL); enable_flags |= - cogl_material_get_cogl_enable_flags (ctx->source_material); + _cogl_material_get_cogl_enable_flags (ctx->source_material); cogl_enable (enable_flags); _cogl_path_get_bounds (nodes_min, nodes_max, diff --git a/clutter/cogl/gl/cogl-shader.c b/clutter/cogl/gl/cogl-shader.c index 944e6736f..de3302e6a 100644 --- a/clutter/cogl/gl/cogl-shader.c +++ b/clutter/cogl/gl/cogl-shader.c @@ -108,22 +108,23 @@ cogl_shader_compile (CoglHandle handle) glCompileShaderARB (shader->gl_handle); } -void -cogl_shader_get_info_log (CoglHandle handle, - size_t size, - char *buffer) +gchar * +cogl_shader_get_info_log (CoglHandle handle) { CoglShader *shader; + char buffer[512]; int len; - _COGL_GET_CONTEXT (ctx, NO_RETVAL); + _COGL_GET_CONTEXT (ctx, NULL); if (!cogl_is_shader (handle)) - return; + return NULL; shader = _cogl_shader_pointer_from_handle (handle); - glGetInfoLogARB (shader->gl_handle, size-1, &len, buffer); + glGetInfoLogARB (shader->gl_handle, 511, &len, buffer); buffer[len]='\0'; + + return g_strdup (buffer); } CoglShaderType diff --git a/clutter/cogl/gl/cogl-texture-private.h b/clutter/cogl/gl/cogl-texture-private.h index 7cf6fe951..365a47921 100644 --- a/clutter/cogl/gl/cogl-texture-private.h +++ b/clutter/cogl/gl/cogl-texture-private.h @@ -30,6 +30,7 @@ typedef struct _CoglTexture CoglTexture; typedef struct _CoglTexSliceSpan CoglTexSliceSpan; typedef struct _CoglSpanIter CoglSpanIter; +typedef struct _CoglTexturePixel CoglTexturePixel; struct _CoglTexSliceSpan { @@ -55,6 +56,18 @@ struct _CoglSpanIter gboolean intersects; }; +/* This is used to store the first pixel of each slice. This is only + used when glGenerateMipmap is not available */ +struct _CoglTexturePixel +{ + /* We need to store the format of the pixel because we store the + data in the source format which might end up being different for + each slice if a subregion is updated with a different format */ + GLenum gl_format; + GLenum gl_type; + guint8 data[4]; +}; + struct _CoglTexture { CoglHandleObject _parent; @@ -68,11 +81,17 @@ struct _CoglTexture GArray *slice_y_spans; GArray *slice_gl_handles; gint max_waste; - CoglTextureFilter min_filter; - CoglTextureFilter mag_filter; + GLenum min_filter; + GLenum mag_filter; gboolean is_foreign; GLint wrap_mode; gboolean auto_mipmap; + gboolean mipmaps_dirty; + + /* This holds a copy of the first pixel in each slice. It is only + used to force an automatic update of the mipmaps when + glGenerateMipmap is not available. */ + CoglTexturePixel *first_pixels; }; /* To improve batching of geometry when submitting vertices to OpenGL we @@ -93,6 +112,14 @@ void _cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, GLenum wrap_mode); +void +_cogl_texture_set_filters (CoglHandle handle, + GLenum min_filter, + GLenum mag_filter); + +void +_cogl_texture_ensure_mipmaps (CoglHandle handle); + gboolean _cogl_texture_span_has_waste (CoglTexture *tex, gint x_span_index, diff --git a/clutter/cogl/gl/cogl-texture.c b/clutter/cogl/gl/cogl-texture.c index 643b11899..215e14c78 100644 --- a/clutter/cogl/gl/cogl-texture.c +++ b/clutter/cogl/gl/cogl-texture.c @@ -49,6 +49,7 @@ #define glDrawRangeElements ctx->pf_glDrawRangeElements #define glActiveTexture ctx->pf_glActiveTexture #define glClientActiveTexture ctx->pf_glClientActiveTexture +#define glGenerateMipmap ctx->pf_glGenerateMipmapEXT #else @@ -247,11 +248,12 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) /* Iterate horizontal slices */ for (x = 0; x < tex->slice_x_spans->len; ++x) { + gint slice_num = y * tex->slice_x_spans->len + x; + x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x); /* Pick the gl texture object handle */ - gl_handle = g_array_index (tex->slice_gl_handles, GLuint, - y * tex->slice_x_spans->len + x); + gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num); /* Setup gl alignment to match rowstride and top-left corner */ prep_for_gl_pixels_upload (tex->bitmap.rowstride, @@ -259,6 +261,17 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) y_span->start, bpp); + /* Keep a copy of the first pixel if needed */ + if (tex->first_pixels) + { + memcpy (tex->first_pixels[slice_num].data, + tex->bitmap.data + x_span->start * bpp + + y_span->start * tex->bitmap.rowstride, + bpp); + tex->first_pixels[slice_num].gl_format = tex->gl_format; + tex->first_pixels[slice_num].gl_type = tex->gl_type; + } + /* Upload new image data */ GE( glBindTexture (tex->gl_target, gl_handle) ); @@ -343,6 +356,8 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) if (waste_buf) g_free (waste_buf); + tex->mipmaps_dirty = TRUE; + return TRUE; } @@ -494,6 +509,8 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, _cogl_span_iter_next (&x_iter), source_x += inter_w ) { + gint slice_num; + /* Discard slices out of the subregion early */ if (!x_iter.intersects) { @@ -516,10 +533,10 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, local_y = (y_iter.intersect_start - y_iter.pos); + slice_num = y_iter.index * tex->slice_x_spans->len + x_iter.index; + /* Pick slice GL handle */ - gl_handle = g_array_index (tex->slice_gl_handles, GLuint, - y_iter.index * tex->slice_x_spans->len + - x_iter.index); + gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num); /* Setup gl alignment to match rowstride and top-left corner */ prep_for_gl_pixels_upload (source_bmp->rowstride, @@ -527,6 +544,17 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, source_y, bpp); + /* Keep a copy of the first pixel if needed */ + if (tex->first_pixels && local_x == 0 && local_y == 0) + { + memcpy (tex->first_pixels[slice_num].data, + source_bmp->data + source_x * bpp + + source_y * source_bmp->rowstride, + bpp); + tex->first_pixels[slice_num].gl_format = source_gl_format; + tex->first_pixels[slice_num].gl_type = source_gl_type; + } + /* Upload new image data */ GE( glBindTexture (tex->gl_target, gl_handle) ); @@ -640,14 +668,16 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, if (waste_buf) g_free (waste_buf); + tex->mipmaps_dirty = TRUE; + return TRUE; } static gint -_cogl_rect_slices_for_size (gint size_to_fill, - gint max_span_size, - gint max_waste, - GArray *out_spans) +_cogl_rect_slices_for_size (gint size_to_fill, + gint max_span_size, + gint max_waste, + GArray *out_spans) { gint n_spans = 0; CoglTexSliceSpan span; @@ -679,10 +709,10 @@ _cogl_rect_slices_for_size (gint size_to_fill, } static gint -_cogl_pot_slices_for_size (gint size_to_fill, - gint max_span_size, - gint max_waste, - GArray *out_spans) +_cogl_pot_slices_for_size (gint size_to_fill, + gint max_span_size, + gint max_waste, + GArray *out_spans) { gint n_spans = 0; CoglTexSliceSpan span; @@ -693,7 +723,8 @@ _cogl_pot_slices_for_size (gint size_to_fill, span.waste = 0; /* Fix invalid max_waste */ - if (max_waste < 0) max_waste = 0; + if (max_waste < 0) + max_waste = 0; while (TRUE) { @@ -826,10 +857,10 @@ _cogl_texture_slices_create (CoglTexture *tex) /* Check if size supported else bail out */ if (!_cogl_texture_size_supported (tex->gl_target, - tex->gl_format, - tex->gl_type, - max_width, - max_height)) + tex->gl_format, + tex->gl_type, + max_width, + max_height)) { return FALSE; } @@ -912,6 +943,14 @@ _cogl_texture_slices_create (CoglTexture *tex) g_array_set_size (tex->slice_gl_handles, n_slices); + /* Allocate some space to store a copy of the first pixel of each + slice. This is only needed to glGenerateMipmap (which is part of + the FBO extension) is not available */ + if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) + tex->first_pixels = NULL; + else + tex->first_pixels = g_new (CoglTexturePixel, n_slices); + /* Wrap mode not yet set */ tex->wrap_mode = GL_FALSE; @@ -940,14 +979,6 @@ _cogl_texture_slices_create (CoglTexture *tex) /* Setup texture parameters */ GE( glBindTexture (tex->gl_target, gl_handles[y * n_x_slices + x]) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MAG_FILTER, - tex->mag_filter) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER, - tex->min_filter) ); - - if (tex->auto_mipmap) - GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, - GL_TRUE) ); /* Use a transparent border color so that we can leave the color buffer alone when using texture co-ordinates @@ -984,6 +1015,9 @@ _cogl_texture_slices_free (CoglTexture *tex) g_array_free (tex->slice_gl_handles, TRUE); } + + if (tex->first_pixels != NULL) + g_free (tex->first_pixels); } gboolean @@ -1199,11 +1233,10 @@ _cogl_texture_free (CoglTexture *tex) } CoglHandle -cogl_texture_new_with_size (guint width, - guint height, - gint max_waste, - CoglTextureFlags flags, - CoglPixelFormat internal_format) +cogl_texture_new_with_size (guint width, + guint height, + CoglTextureFlags flags, + CoglPixelFormat internal_format) { CoglTexture *tex; gint bpp; @@ -1221,7 +1254,8 @@ cogl_texture_new_with_size (guint width, tex = (CoglTexture*) g_malloc (sizeof (CoglTexture)); tex->is_foreign = FALSE; - tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0); + tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; + tex->mipmaps_dirty = TRUE; tex->bitmap.width = width; tex->bitmap.height = height; @@ -1234,9 +1268,14 @@ cogl_texture_new_with_size (guint width, tex->slice_y_spans = NULL; tex->slice_gl_handles = NULL; - tex->max_waste = max_waste; - tex->min_filter = COGL_TEXTURE_FILTER_NEAREST; - tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST; + if (flags & COGL_TEXTURE_NO_SLICING) + tex->max_waste = -1; + else + tex->max_waste = COGL_TEXTURE_MAX_WASTE; + + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; /* Find closest GL format match */ tex->bitmap.format = @@ -1258,7 +1297,6 @@ cogl_texture_new_with_size (guint width, CoglHandle cogl_texture_new_from_data (guint width, guint height, - gint max_waste, CoglTextureFlags flags, CoglPixelFormat format, CoglPixelFormat internal_format, @@ -1282,7 +1320,8 @@ cogl_texture_new_from_data (guint width, tex = (CoglTexture*) g_malloc (sizeof (CoglTexture)); tex->is_foreign = FALSE; - tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0); + tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; + tex->mipmaps_dirty = TRUE; tex->bitmap.width = width; tex->bitmap.height = height; @@ -1295,9 +1334,14 @@ cogl_texture_new_from_data (guint width, tex->slice_y_spans = NULL; tex->slice_gl_handles = NULL; - tex->max_waste = max_waste; - tex->min_filter = COGL_TEXTURE_FILTER_NEAREST; - tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST; + if (flags & COGL_TEXTURE_NO_SLICING) + tex->max_waste = -1; + else + tex->max_waste = COGL_TEXTURE_MAX_WASTE; + + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; /* FIXME: If upload fails we should set some kind of * error flag but still return texture handle (this @@ -1328,10 +1372,9 @@ cogl_texture_new_from_data (guint width, } CoglHandle -cogl_texture_new_from_bitmap (CoglHandle bmp_handle, - gint max_waste, - CoglTextureFlags flags, - CoglPixelFormat internal_format) +cogl_texture_new_from_bitmap (CoglHandle bmp_handle, + CoglTextureFlags flags, + CoglPixelFormat internal_format) { CoglTexture *tex; CoglBitmap *bmp = (CoglBitmap *)bmp_handle; @@ -1342,7 +1385,8 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle, tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture)); tex->is_foreign = FALSE; - tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0); + tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; + tex->mipmaps_dirty = TRUE; tex->bitmap = *bmp; tex->bitmap_owner = FALSE; @@ -1351,9 +1395,14 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle, tex->slice_y_spans = NULL; tex->slice_gl_handles = NULL; - tex->max_waste = max_waste; - tex->min_filter = COGL_TEXTURE_FILTER_NEAREST; - tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST; + if (flags & COGL_TEXTURE_NO_SLICING) + tex->max_waste = -1; + else + tex->max_waste = COGL_TEXTURE_MAX_WASTE; + + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; /* FIXME: If upload fails we should set some kind of * error flag but still return texture handle if the @@ -1388,13 +1437,12 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle, CoglHandle cogl_texture_new_from_file (const gchar *filename, - gint max_waste, CoglTextureFlags flags, CoglPixelFormat internal_format, GError **error) { - CoglHandle bmp; - CoglHandle handle; + CoglHandle bmp; + CoglHandle handle; g_return_val_if_fail (error == NULL || *error == NULL, COGL_INVALID_HANDLE); @@ -1402,10 +1450,7 @@ cogl_texture_new_from_file (const gchar *filename, if (bmp == COGL_INVALID_HANDLE) return COGL_INVALID_HANDLE; - handle = cogl_texture_new_from_bitmap (bmp, - max_waste, - flags, - internal_format); + handle = cogl_texture_new_from_bitmap (bmp, flags, internal_format); cogl_handle_unref (bmp); return handle; @@ -1433,8 +1478,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle, GLint gl_int_format = 0; GLint gl_width = 0; GLint gl_height = 0; - GLint gl_min_filter; - GLint gl_mag_filter; GLint gl_gen_mipmap; guint bpp; CoglTexture *tex; @@ -1482,14 +1525,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle, GL_TEXTURE_HEIGHT, &gl_height) ); - GE( glGetTexParameteriv (gl_target, - GL_TEXTURE_MIN_FILTER, - &gl_min_filter) ); - - GE( glGetTexParameteriv (gl_target, - GL_TEXTURE_MAG_FILTER, - &gl_mag_filter) ); - GE( glGetTexParameteriv (gl_target, GL_GENERATE_MIPMAP, &gl_gen_mipmap) ); @@ -1508,18 +1543,16 @@ cogl_texture_new_from_foreign (GLuint gl_handle, return COGL_INVALID_HANDLE; /* Try and match to a cogl format */ - if (!_cogl_pixel_format_from_gl_internal (gl_int_format, - &format)) - { - return COGL_INVALID_HANDLE; - } + if (!_cogl_pixel_format_from_gl_internal (gl_int_format, &format)) + return COGL_INVALID_HANDLE; /* Create new texture */ - tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture)); + tex = (CoglTexture *) g_malloc (sizeof (CoglTexture)); /* Setup bitmap info */ tex->is_foreign = TRUE; tex->auto_mipmap = (gl_gen_mipmap == GL_TRUE) ? TRUE : FALSE; + tex->mipmaps_dirty = TRUE; bpp = _cogl_get_format_bpp (format); tex->bitmap.format = format; @@ -1533,8 +1566,9 @@ cogl_texture_new_from_foreign (GLuint gl_handle, tex->gl_format = gl_int_format; tex->gl_type = GL_UNSIGNED_BYTE; - tex->min_filter = gl_min_filter; - tex->mag_filter = gl_mag_filter; + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; tex->max_waste = 0; /* Wrap mode not yet set */ @@ -1680,36 +1714,10 @@ cogl_texture_get_gl_texture (CoglHandle handle, return TRUE; } -CoglTextureFilter -cogl_texture_get_min_filter (CoglHandle handle) -{ - CoglTexture *tex; - - if (!cogl_is_texture (handle)) - return 0; - - tex = _cogl_texture_pointer_from_handle (handle); - - return tex->min_filter; -} - -CoglTextureFilter -cogl_texture_get_mag_filter (CoglHandle handle) -{ - CoglTexture *tex; - - if (!cogl_is_texture (handle)) - return 0; - - tex = _cogl_texture_pointer_from_handle (handle); - - return tex->mag_filter; -} - void -cogl_texture_set_filters (CoglHandle handle, - CoglTextureFilter min_filter, - CoglTextureFilter mag_filter) +_cogl_texture_set_filters (CoglHandle handle, + GLenum min_filter, + GLenum mag_filter) { CoglTexture *tex; GLuint gl_handle; @@ -1720,14 +1728,18 @@ cogl_texture_set_filters (CoglHandle handle, tex = _cogl_texture_pointer_from_handle (handle); - /* Store new values */ - tex->min_filter = min_filter; - tex->mag_filter = mag_filter; - /* Make sure slices were created */ if (tex->slice_gl_handles == NULL) return; + if (min_filter == tex->min_filter + && mag_filter == tex->mag_filter) + return; + + /* Store new values */ + tex->min_filter = min_filter; + tex->mag_filter = mag_filter; + /* Apply new filters to every slice */ for (i=0; islice_gl_handles->len; ++i) { @@ -1740,6 +1752,52 @@ cogl_texture_set_filters (CoglHandle handle, } } +void +_cogl_texture_ensure_mipmaps (CoglHandle handle) +{ + CoglTexture *tex; + int i; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + if (!cogl_is_texture (handle)) + return; + + tex = _cogl_texture_pointer_from_handle (handle); + + /* Only update if the mipmaps are dirty */ + if (!tex->auto_mipmap || !tex->mipmaps_dirty) + return; + + /* Make sure slices were created */ + if (tex->slice_gl_handles == NULL) + return; + + /* Regenerate the mipmaps on every slice */ + for (i = 0; i < tex->slice_gl_handles->len; i++) + { + GLuint gl_handle = g_array_index (tex->slice_gl_handles, GLuint, i); + GE( glBindTexture (tex->gl_target, gl_handle) ); + + /* glGenerateMipmap is defined in the FBO extension */ + if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) + GE( glGenerateMipmap (tex->gl_target) ); + else + { + CoglTexturePixel *pixel = tex->first_pixels + i; + /* Temporarily enable automatic mipmap generation and + re-upload the first pixel to cause a regeneration */ + GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GL_TRUE) ); + GE( glTexSubImage2D (tex->gl_target, 0, 0, 0, 1, 1, + pixel->gl_format, pixel->gl_type, + pixel->data) ); + GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GL_FALSE) ); + } + } + + tex->mipmaps_dirty = FALSE; +} + gboolean cogl_texture_set_region (CoglHandle handle, gint src_x, diff --git a/clutter/cogl/gl/cogl.c b/clutter/cogl/gl/cogl.c index b2c5417e7..748c082ac 100644 --- a/clutter/cogl/gl/cogl.c +++ b/clutter/cogl/gl/cogl.c @@ -399,6 +399,10 @@ _cogl_features_init (void) (COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC) cogl_get_proc_address ("glDeleteFramebuffersEXT"); + ctx->pf_glGenerateMipmapEXT = + (COGL_PFNGLGENERATEMIPMAPEXTPROC) + cogl_get_proc_address ("glGenerateMipmapEXT"); + if (ctx->pf_glGenRenderbuffersEXT && ctx->pf_glBindRenderbufferEXT && ctx->pf_glRenderbufferStorageEXT && @@ -407,7 +411,8 @@ _cogl_features_init (void) ctx->pf_glFramebufferTexture2DEXT && ctx->pf_glFramebufferRenderbufferEXT && ctx->pf_glCheckFramebufferStatusEXT && - ctx->pf_glDeleteFramebuffersEXT) + ctx->pf_glDeleteFramebuffersEXT && + ctx->pf_glGenerateMipmapEXT) flags |= COGL_FEATURE_OFFSCREEN; } @@ -486,6 +491,23 @@ _cogl_features_init (void) (COGL_PFNGLCLIENTACTIVETEXTUREPROC) cogl_get_proc_address ("glClientActiveTexture"); + ctx->pf_glBlendEquation = + (COGL_PFNGLBLENDEQUATIONPROC) + cogl_get_proc_address ("glBlendEquation"); + ctx->pf_glBlendColor = + (COGL_PFNGLBLENDCOLORPROC) + cogl_get_proc_address ("glBlendColor"); + + /* Available in 1.4 */ + ctx->pf_glBlendFuncSeparate = + (COGL_PFNGLBLENDFUNCSEPARATEPROC) + cogl_get_proc_address ("glBlendFuncSeparate"); + + /* Available in 2.0 */ + ctx->pf_glBlendEquationSeparate = + (COGL_PFNGLBLENDEQUATIONSEPARATEPROC) + cogl_get_proc_address ("glBlendEquationSeparate"); + /* Cache features */ ctx->feature_flags = flags; ctx->features_cached = TRUE; diff --git a/clutter/cogl/gles/Makefile.am b/clutter/cogl/gles/Makefile.am index 3f84b4b2f..3ce5365a7 100644 --- a/clutter/cogl/gles/Makefile.am +++ b/clutter/cogl/gles/Makefile.am @@ -27,12 +27,12 @@ INCLUDES = \ -DG_LOG_DOMAIN=\"Cogl-GLES\" \ -DCLUTTER_COMPILATION -noinst_LTLIBRARIES = libclutter-cogl.la +noinst_LTLIBRARIES = libclutter-cogl-gles.la -libclutter_cogl_la_CPPFLAGS = $(CLUTTER_CFLAGS) $(COGL_DEBUG_CFLAGS) $(CLUTTER_DEBUG_CFLAGS) $(MAINTAINER_CFLAGS) -libclutter_cogl_la_LIBADD = -lm $(CLUTTER_LIBS) $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la -libclutter_cogl_la_DEPENDENCIES = $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la -libclutter_cogl_la_SOURCES = \ +libclutter_cogl_gles_la_CPPFLAGS = $(CLUTTER_CFLAGS) $(COGL_DEBUG_CFLAGS) $(CLUTTER_DEBUG_CFLAGS) $(MAINTAINER_CFLAGS) +libclutter_cogl_gles_la_LIBADD = -lm $(CLUTTER_LIBS) $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la +libclutter_cogl_gles_la_DEPENDENCIES = $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la +libclutter_cogl_gles_la_SOURCES = \ $(top_builddir)/clutter/cogl/cogl.h \ $(top_builddir)/clutter/cogl/cogl-defines-gles.h \ $(top_builddir)/clutter/cogl/cogl-color.h \ @@ -60,7 +60,7 @@ libclutter_cogl_la_SOURCES = \ cogl-shader.c if USE_GLES2_WRAPPER -libclutter_cogl_la_SOURCES += \ +libclutter_cogl_gles_la_SOURCES += \ cogl-gles2-wrapper.c \ cogl-fixed-vertex-shader.h \ cogl-fixed-vertex-shader.c \ diff --git a/clutter/cogl/gles/cogl-context.c b/clutter/cogl/gles/cogl-context.c index d70d59d35..293ac4689 100644 --- a/clutter/cogl/gles/cogl-context.c +++ b/clutter/cogl/gles/cogl-context.c @@ -39,7 +39,7 @@ static CoglContext *_context = NULL; static gboolean gl_is_indirect = FALSE; -gboolean +static gboolean cogl_create_context () { GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 }; @@ -72,7 +72,6 @@ cogl_create_context () _context->journal = g_array_new (FALSE, FALSE, sizeof (CoglJournalEntry)); _context->logged_vertices = g_array_new (FALSE, FALSE, sizeof (GLfloat)); - _context->static_indices = g_array_new (FALSE, FALSE, sizeof (GLushort)); _context->polygon_vertices = g_array_new (FALSE, FALSE, sizeof (CoglTextureGLVertex)); @@ -107,8 +106,7 @@ cogl_create_context () _context->default_gl_texture_2d_tex = cogl_texture_new_from_data (1, /* width */ 1, /* height */ - -1, /* max waste */ - COGL_TEXTURE_NONE, /* flags */ + COGL_TEXTURE_NO_SLICING, /* flags */ COGL_PIXEL_FORMAT_RGBA_8888, /* data format */ /* internal format */ COGL_PIXEL_FORMAT_RGBA_8888, @@ -117,8 +115,7 @@ cogl_create_context () _context->default_gl_texture_rect_tex = cogl_texture_new_from_data (1, /* width */ 1, /* height */ - -1, /* max waste */ - COGL_TEXTURE_NONE, /* flags */ + COGL_TEXTURE_NO_SLICING, /* flags */ COGL_PIXEL_FORMAT_RGBA_8888, /* data format */ /* internal format */ COGL_PIXEL_FORMAT_RGBA_8888, @@ -126,16 +123,20 @@ cogl_create_context () default_texture_data); cogl_set_source (_context->default_material); - cogl_material_flush_gl_state (_context->source_material, NULL); + _cogl_material_flush_gl_state (_context->source_material, NULL); enable_flags = - cogl_material_get_cogl_enable_flags (_context->source_material); + _cogl_material_get_cogl_enable_flags (_context->source_material); cogl_enable (enable_flags); + _context->quad_indices_byte = COGL_INVALID_HANDLE; + _context->quad_indices_short = COGL_INVALID_HANDLE; + _context->quad_indices_short_len = 0; + return TRUE; } void -cogl_destroy_context () +_cogl_destroy_context () { if (_context == NULL) return; @@ -160,13 +161,16 @@ cogl_destroy_context () if (_context->logged_vertices) g_array_free (_context->logged_vertices, TRUE); - if (_context->static_indices) - g_array_free (_context->static_indices, TRUE); if (_context->polygon_vertices) g_array_free (_context->polygon_vertices, TRUE); if (_context->current_layers) g_array_free (_context->current_layers, TRUE); + if (_context->quad_indices_byte) + cogl_handle_unref (_context->quad_indices_byte); + if (_context->quad_indices_short) + cogl_handle_unref (_context->quad_indices_short); + g_free (_context); } diff --git a/clutter/cogl/gles/cogl-context.h b/clutter/cogl/gles/cogl-context.h index 3542e038d..2e39f2bc0 100644 --- a/clutter/cogl/gles/cogl-context.h +++ b/clutter/cogl/gles/cogl-context.h @@ -80,7 +80,6 @@ typedef struct * can batch things together. */ GArray *journal; GArray *logged_vertices; - GArray *static_indices; GArray *polygon_vertices; /* Some simple caching, to minimize state changes... */ @@ -104,6 +103,12 @@ typedef struct floatVec2 path_nodes_max; CoglHandle stencil_material; + /* Pre-generated VBOs containing indices to generate GL_TRIANGLES + out of a vertex array of quads */ + CoglHandle quad_indices_byte; + guint quad_indices_short_len; + CoglHandle quad_indices_short; + #ifdef HAVE_COGL_GLES2 CoglGles2Wrapper gles2; @@ -111,7 +116,6 @@ typedef struct supported */ GLint viewport_store[4]; #endif - } CoglContext; CoglContext * diff --git a/clutter/cogl/gles/cogl-gles2-wrapper.c b/clutter/cogl/gles/cogl-gles2-wrapper.c index 523676dd2..979ade598 100644 --- a/clutter/cogl/gles/cogl-gles2-wrapper.c +++ b/clutter/cogl/gles/cogl-gles2-wrapper.c @@ -89,13 +89,13 @@ cogl_gles2_wrapper_create_shader (GLenum type, const char *source) if (!status) { - char log[1024]; + char shader_log[1024]; GLint len; - glGetShaderInfoLog (shader, sizeof (log) - 1, &len, log); - log[len] = '\0'; + glGetShaderInfoLog (shader, sizeof (shader_log) - 1, &len, shader_log); + shader_log[len] = '\0'; - g_critical ("%s", log); + g_critical ("%s", shader_log); glDeleteShader (shader); @@ -538,9 +538,9 @@ cogl_gles2_wrapper_get_program (const CoglGles2WrapperSettings *settings) CoglShader *shader = _cogl_shader_pointer_from_handle ((CoglHandle) node->data); - if (shader->type == CGL_VERTEX_SHADER) + if (shader->type == COGL_SHADER_TYPE_VERTEX) custom_vertex_shader = TRUE; - else if (shader->type == CGL_FRAGMENT_SHADER) + else if (shader->type == COGL_SHADER_TYPE_FRAGMENT) custom_fragment_shader = TRUE; } } @@ -581,13 +581,13 @@ cogl_gles2_wrapper_get_program (const CoglGles2WrapperSettings *settings) if (!status) { - char log[1024]; + char shader_log[1024]; GLint len; - glGetProgramInfoLog (program->program, sizeof (log) - 1, &len, log); - log[len] = '\0'; + glGetProgramInfoLog (program->program, sizeof (shader_log) - 1, &len, shader_log); + shader_log[len] = '\0'; - g_critical ("%s", log); + g_critical ("%s", shader_log); glDeleteProgram (program->program); g_slice_free (CoglGles2WrapperProgram, program); @@ -1300,13 +1300,20 @@ cogl_gles2_wrapper_bind_texture (GLenum target, GLuint texture, } void -cogl_wrap_glTexEnvi (GLenum target, GLenum pname, GLfloat param) +cogl_wrap_glTexEnvi (GLenum target, GLenum pname, GLint param) { /* This function is only used to set the texture mode once to GL_MODULATE. The shader is hard-coded to modulate the texture so nothing needs to be done here. */ } +void +cogl_wrap_glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params) +{ + /* FIXME: Currently needed to support texture combining using + * COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT */ +} + void cogl_wrap_glClientActiveTexture (GLenum texture) { diff --git a/clutter/cogl/gles/cogl-gles2-wrapper.h b/clutter/cogl/gles/cogl-gles2-wrapper.h index bd7f6d978..51bee2d5c 100644 --- a/clutter/cogl/gles/cogl-gles2-wrapper.h +++ b/clutter/cogl/gles/cogl-gles2-wrapper.h @@ -259,6 +259,7 @@ struct _CoglGles2WrapperShader #define GL_TEXTURE_ENV 0x2300 #define GL_TEXTURE_ENV_MODE 0x2200 +#define GL_TEXTURE_ENV_COLOR 0x2201 #define GL_MODULATE 0x2100 #define GL_EXP 0x8000 @@ -327,7 +328,8 @@ void cogl_wrap_glColorPointer (GLint size, GLenum type, GLsizei stride, void cogl_wrap_glNormalPointer (GLenum type, GLsizei stride, const GLvoid *pointer); -void cogl_wrap_glTexEnvi (GLenum target, GLenum pname, GLfloat param); +void cogl_wrap_glTexEnvi (GLenum target, GLenum pname, GLint param); +void cogl_wrap_glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params); void cogl_wrap_glClientActiveTexture (GLenum texture); void cogl_wrap_glActiveTexture (GLenum texture); @@ -384,6 +386,7 @@ void _cogl_gles2_clear_cache_for_program (CoglHandle program); #define glColorPointer cogl_wrap_glColorPointer #define glNormalPointer cogl_wrap_glNormalPointer #define glTexEnvi cogl_wrap_glTexEnvi +#define glTexEnvfv cogl_wrap_glTexEnvfv #define glActiveTexture cogl_wrap_glActiveTexture #define glClientActiveTexture cogl_wrap_glClientActiveTexture #define glEnableClientState cogl_wrap_glEnableClientState diff --git a/clutter/cogl/gles/cogl-primitives.c b/clutter/cogl/gles/cogl-primitives.c index 1e03e1ea2..d8dee0ba6 100644 --- a/clutter/cogl/gles/cogl-primitives.c +++ b/clutter/cogl/gles/cogl-primitives.c @@ -29,6 +29,7 @@ #include "cogl-internal.h" #include "cogl-context.h" #include "cogl-clip-stack.h" +#include "cogl-material-private.h" #include #include @@ -78,13 +79,13 @@ _cogl_path_stroke_nodes () _COGL_GET_CONTEXT (ctx, NO_RETVAL); - enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material); + enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material); cogl_enable (enable_flags); - cogl_material_flush_gl_state (ctx->source_material, - COGL_MATERIAL_FLUSH_DISABLE_MASK, - (guint32)~0, /* disable all texture layers */ - NULL); + _cogl_material_flush_gl_state (ctx->source_material, + COGL_MATERIAL_FLUSH_DISABLE_MASK, + (guint32)~0, /* disable all texture layers */ + NULL); _cogl_current_matrix_state_flush (); while (path_start < ctx->path_nodes->len) @@ -139,10 +140,10 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* Just setup a simple material that doesn't use texturing... */ - cogl_material_flush_gl_state (ctx->stencil_material, NULL); + _cogl_material_flush_gl_state (ctx->stencil_material, NULL); enable_flags |= - cogl_material_get_cogl_enable_flags (ctx->source_material); + _cogl_material_get_cogl_enable_flags (ctx->source_material); cogl_enable (enable_flags); _cogl_path_get_bounds (nodes_min, nodes_max, @@ -361,30 +362,30 @@ _cogl_path_fill_nodes_scanlines (CoglPathNode *path, while (iter) { GSList *next = iter->next; - GLfloat x0, x1; - GLfloat y0, y1; + GLfloat x_0, x_1; + GLfloat y_0, y_1; if (!next) break; - x0 = GPOINTER_TO_INT (iter->data); - x1 = GPOINTER_TO_INT (next->data); - y0 = bounds_y + i; - y1 = bounds_y + i + 1.0625f; + x_0 = GPOINTER_TO_INT (iter->data); + x_1 = GPOINTER_TO_INT (next->data); + y_0 = bounds_y + i; + y_1 = bounds_y + i + 1.0625f; /* render scanlines 1.0625 high to avoid gaps when transformed */ - coords[span_no * 12 + 0] = x0; - coords[span_no * 12 + 1] = y0; - coords[span_no * 12 + 2] = x1; - coords[span_no * 12 + 3] = y0; - coords[span_no * 12 + 4] = x1; - coords[span_no * 12 + 5] = y1; - coords[span_no * 12 + 6] = x0; - coords[span_no * 12 + 7] = y0; - coords[span_no * 12 + 8] = x0; - coords[span_no * 12 + 9] = y1; - coords[span_no * 12 + 10] = x1; - coords[span_no * 12 + 11] = y1; + coords[span_no * 12 + 0] = x_0; + coords[span_no * 12 + 1] = y_0; + coords[span_no * 12 + 2] = x_1; + coords[span_no * 12 + 3] = y_0; + coords[span_no * 12 + 4] = x_1; + coords[span_no * 12 + 5] = y_1; + coords[span_no * 12 + 6] = x_0; + coords[span_no * 12 + 7] = y_0; + coords[span_no * 12 + 8] = x_0; + coords[span_no * 12 + 9] = y_1; + coords[span_no * 12 + 10] = x_1; + coords[span_no * 12 + 11] = y_1; span_no ++; iter = next->next; } diff --git a/clutter/cogl/gles/cogl-shader.c b/clutter/cogl/gles/cogl-shader.c index ff5f0c58a..23109be34 100644 --- a/clutter/cogl/gles/cogl-shader.c +++ b/clutter/cogl/gles/cogl-shader.c @@ -99,22 +99,23 @@ cogl_shader_compile (CoglHandle handle) glCompileShader (shader->gl_handle); } -void -cogl_shader_get_info_log (CoglHandle handle, - size_t size, - char *buffer) +gchar * +cogl_shader_get_info_log (CoglHandle handle) { CoglShader *shader; + char buffer[512]; int len = 0; - _COGL_GET_CONTEXT (ctx, NO_RETVAL); + _COGL_GET_CONTEXT (ctx, NULL); if (!cogl_is_shader (handle)) - return; + return NULL; shader = _cogl_shader_pointer_from_handle (handle); - glGetShaderInfoLog (shader->gl_handle, size - 1, &len, buffer); + glGetShaderInfoLog (shader->gl_handle, 511, &len, buffer); buffer[len] = '\0'; + + return g_strdup (buffer); } CoglShaderType @@ -199,11 +200,10 @@ cogl_shader_compile (CoglHandle shader_handle) { } -void -cogl_shader_get_info_log (CoglHandle handle, - size_t size, - char *buffer) +gchar * +cogl_shader_get_info_log (CoglHandle handle) { + return NULL; } CoglShaderType diff --git a/clutter/cogl/gles/cogl-texture-private.h b/clutter/cogl/gles/cogl-texture-private.h index 7cf6fe951..365a47921 100644 --- a/clutter/cogl/gles/cogl-texture-private.h +++ b/clutter/cogl/gles/cogl-texture-private.h @@ -30,6 +30,7 @@ typedef struct _CoglTexture CoglTexture; typedef struct _CoglTexSliceSpan CoglTexSliceSpan; typedef struct _CoglSpanIter CoglSpanIter; +typedef struct _CoglTexturePixel CoglTexturePixel; struct _CoglTexSliceSpan { @@ -55,6 +56,18 @@ struct _CoglSpanIter gboolean intersects; }; +/* This is used to store the first pixel of each slice. This is only + used when glGenerateMipmap is not available */ +struct _CoglTexturePixel +{ + /* We need to store the format of the pixel because we store the + data in the source format which might end up being different for + each slice if a subregion is updated with a different format */ + GLenum gl_format; + GLenum gl_type; + guint8 data[4]; +}; + struct _CoglTexture { CoglHandleObject _parent; @@ -68,11 +81,17 @@ struct _CoglTexture GArray *slice_y_spans; GArray *slice_gl_handles; gint max_waste; - CoglTextureFilter min_filter; - CoglTextureFilter mag_filter; + GLenum min_filter; + GLenum mag_filter; gboolean is_foreign; GLint wrap_mode; gboolean auto_mipmap; + gboolean mipmaps_dirty; + + /* This holds a copy of the first pixel in each slice. It is only + used to force an automatic update of the mipmaps when + glGenerateMipmap is not available. */ + CoglTexturePixel *first_pixels; }; /* To improve batching of geometry when submitting vertices to OpenGL we @@ -93,6 +112,14 @@ void _cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, GLenum wrap_mode); +void +_cogl_texture_set_filters (CoglHandle handle, + GLenum min_filter, + GLenum mag_filter); + +void +_cogl_texture_ensure_mipmaps (CoglHandle handle); + gboolean _cogl_texture_span_has_waste (CoglTexture *tex, gint x_span_index, diff --git a/clutter/cogl/gles/cogl-texture.c b/clutter/cogl/gles/cogl-texture.c index 1564faf2a..1929184c0 100644 --- a/clutter/cogl/gles/cogl-texture.c +++ b/clutter/cogl/gles/cogl-texture.c @@ -225,11 +225,12 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) /* Iterate horizontal slices */ for (x = 0; x < tex->slice_x_spans->len; ++x) { + gint slice_num = y * tex->slice_x_spans->len + x; + x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x); /* Pick the gl texture object handle */ - gl_handle = g_array_index (tex->slice_gl_handles, GLuint, - y * tex->slice_x_spans->len + x); + gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num); /* FIXME: might optimize by not copying to intermediate slice bitmap when source rowstride = bpp * width and the texture @@ -258,6 +259,16 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) slice_bmp.width, slice_bmp.height); + /* Keep a copy of the first pixel if needed */ + if (tex->first_pixels) + { + memcpy (tex->first_pixels[slice_num].data, + slice_bmp.data, + bpp); + tex->first_pixels[slice_num].gl_format = tex->gl_format; + tex->first_pixels[slice_num].gl_type = tex->gl_type; + } + /* Upload new image data */ GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle, tex->gl_intformat) ); @@ -338,9 +349,6 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) waste_buf) ); } - if (tex->auto_mipmap) - cogl_wrap_glGenerateMipmap (tex->gl_target); - /* Free temp bitmap */ g_free (slice_bmp.data); } @@ -349,6 +357,8 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) if (waste_buf) g_free (waste_buf); + tex->mipmaps_dirty = TRUE; + return TRUE; } @@ -442,6 +452,7 @@ _cogl_texture_download_from_gl (CoglTexture *tex, gint bpp; GLint viewport[4]; CoglBitmap alpha_bmp; + CoglHandle prev_source; _COGL_GET_CONTEXT (ctx, FALSE); @@ -477,31 +488,21 @@ _cogl_texture_download_from_gl (CoglTexture *tex, if (ctx->texture_download_material == COGL_INVALID_HANDLE) { ctx->texture_download_material = cogl_material_new (); - cogl_material_set_layer_combine_function ( - ctx->texture_download_material, - 0, /* layer */ - COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB, - COGL_MATERIAL_LAYER_COMBINE_FUNC_REPLACE); - cogl_material_set_layer_combine_arg_src ( - ctx->texture_download_material, - 0, /* layer */ - 0, /* arg */ - COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB, - COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE); - cogl_material_set_blend_factors (ctx->texture_download_material, - COGL_MATERIAL_BLEND_FACTOR_ONE, - COGL_MATERIAL_BLEND_FACTOR_ZERO); + cogl_material_set_blend (ctx->texture_download_material, + "RGBA = ADD (SRC_COLOR, 0)", + NULL); } + prev_source = cogl_handle_ref (ctx->source_material); + cogl_set_source (ctx->texture_download_material); + cogl_material_set_layer (ctx->texture_download_material, 0, tex); - cogl_material_set_layer_combine_arg_op ( - ctx->texture_download_material, - 0, /* layer */ - 0, /* arg */ - COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB, - COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR); - cogl_material_flush_gl_state (ctx->texture_download_material, NULL); + cogl_material_set_layer_combine (ctx->texture_download_material, + 0, /* layer */ + "RGBA = REPLACE (TEXTURE)", + NULL); + _cogl_texture_draw_and_read (tex, target_bmp, viewport); /* Check whether texture has alpha and framebuffer not */ @@ -534,13 +535,11 @@ _cogl_texture_download_from_gl (CoglTexture *tex, alpha_bmp.height); /* Draw alpha values into RGB channels */ - cogl_material_set_layer_combine_arg_op ( - ctx->texture_download_material, - 0, /* layer */ - 0, /* arg */ - COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB, - COGL_MATERIAL_LAYER_COMBINE_OP_SRC_ALPHA); - cogl_material_flush_gl_state (ctx->texture_download_material, NULL); + cogl_material_set_layer_combine (ctx->texture_download_material, + 0, /* layer */ + "RGBA = REPLACE (TEXTURE[A])", + NULL); + _cogl_texture_draw_and_read (tex, &alpha_bmp, viewport); /* Copy temp R to target A */ @@ -568,6 +567,10 @@ _cogl_texture_download_from_gl (CoglTexture *tex, _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW); _cogl_current_matrix_pop (); + /* restore the original material */ + cogl_set_source (prev_source); + cogl_handle_unref (prev_source); + return TRUE; } @@ -631,6 +634,8 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, _cogl_span_iter_next (&x_iter), source_x += inter_w ) { + gint slice_num; + /* Discard slices out of the subregion early */ if (!x_iter.intersects) { @@ -653,10 +658,10 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, local_y = (y_iter.intersect_start - y_iter.pos); + slice_num = y_iter.index * tex->slice_x_spans->len + x_iter.index; + /* Pick slice GL handle */ - gl_handle = g_array_index (tex->slice_gl_handles, GLuint, - y_iter.index * tex->slice_x_spans->len + - x_iter.index); + gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num); /* FIXME: might optimize by not copying to intermediate slice bitmap when source rowstride = bpp * width and the texture @@ -685,6 +690,15 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, slice_bmp.width, slice_bmp.height); + /* Keep a copy of the first pixel if needed */ + if (tex->first_pixels && local_x == 0 && local_y == 0) + { + memcpy (tex->first_pixels[slice_num].data, + slice_bmp.data, bpp); + tex->first_pixels[slice_num].gl_format = source_gl_format; + tex->first_pixels[slice_num].gl_type = source_gl_type; + } + /* Upload new image data */ GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle, tex->gl_intformat) ); @@ -794,9 +808,6 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, waste_buf) ); } - if (tex->auto_mipmap) - cogl_wrap_glGenerateMipmap (tex->gl_target); - /* Free temp bitmap */ g_free (slice_bmp.data); } @@ -805,6 +816,8 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, if (waste_buf) g_free (waste_buf); + tex->mipmaps_dirty = TRUE; + return TRUE; } @@ -858,7 +871,8 @@ _cogl_pot_slices_for_size (gint size_to_fill, span.waste = 0; /* Fix invalid max_waste */ - if (max_waste < 0) max_waste = 0; + if (max_waste < 0) + max_waste = 0; while (TRUE) { @@ -866,7 +880,9 @@ _cogl_pot_slices_for_size (gint size_to_fill, if (size_to_fill > span.size) { /* Not yet - add a span of this size */ - if (out_spans) g_array_append_val (out_spans, span); + if (out_spans) + g_array_append_val (out_spans, span); + span.start += span.size; size_to_fill -= span.size; n_spans++; @@ -875,7 +891,9 @@ _cogl_pot_slices_for_size (gint size_to_fill, { /* Yes and waste is small enough */ span.waste = span.size - size_to_fill; - if (out_spans) g_array_append_val (out_spans, span); + if (out_spans) + g_array_append_val (out_spans, span); + return ++n_spans; } else @@ -971,10 +989,10 @@ _cogl_texture_slices_create (CoglTexture *tex) /* Check if size supported else bail out */ if (!_cogl_texture_size_supported (tex->gl_target, - tex->gl_format, - tex->gl_type, - max_width, - max_height)) + tex->gl_format, + tex->gl_type, + max_width, + max_height)) { return FALSE; } @@ -1057,6 +1075,14 @@ _cogl_texture_slices_create (CoglTexture *tex) g_array_set_size (tex->slice_gl_handles, n_slices); + /* Allocate some space to store a copy of the first pixel of each + slice. This is only needed to glGenerateMipmap (which is part of + the FBO extension) is not available */ + if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) + tex->first_pixels = NULL; + else + tex->first_pixels = g_new (CoglTexturePixel, n_slices); + /* Wrap mode not yet set */ tex->wrap_mode = GL_FALSE; @@ -1087,20 +1113,11 @@ _cogl_texture_slices_create (CoglTexture *tex) GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handles[y * n_x_slices + x], tex->gl_intformat) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MAG_FILTER, - tex->mag_filter) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER, - tex->min_filter) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, tex->wrap_mode) ); GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, tex->wrap_mode) ); - if (tex->auto_mipmap) - GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, - GL_TRUE) ); - /* Pass NULL data to init size and internal format */ GE( glTexImage2D (tex->gl_target, 0, tex->gl_intformat, x_span->size, y_span->size, 0, @@ -1130,6 +1147,9 @@ _cogl_texture_slices_free (CoglTexture *tex) g_array_free (tex->slice_gl_handles, TRUE); } + + if (tex->first_pixels != NULL) + g_free (tex->first_pixels); } gboolean @@ -1288,11 +1308,10 @@ _cogl_texture_free (CoglTexture *tex) } CoglHandle -cogl_texture_new_with_size (guint width, - guint height, - gint max_waste, - CoglTextureFlags flags, - CoglPixelFormat internal_format) +cogl_texture_new_with_size (guint width, + guint height, + CoglTextureFlags flags, + CoglPixelFormat internal_format) { CoglTexture *tex; gint bpp; @@ -1310,7 +1329,8 @@ cogl_texture_new_with_size (guint width, tex = (CoglTexture*) g_malloc (sizeof (CoglTexture)); tex->is_foreign = FALSE; - tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0); + tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; + tex->mipmaps_dirty = TRUE; tex->bitmap.width = width; tex->bitmap.height = height; @@ -1323,9 +1343,14 @@ cogl_texture_new_with_size (guint width, tex->slice_y_spans = NULL; tex->slice_gl_handles = NULL; - tex->max_waste = max_waste; - tex->min_filter = CGL_NEAREST; - tex->mag_filter = CGL_NEAREST; + if (flags & COGL_TEXTURE_NO_SLICING) + tex->max_waste = -1; + else + tex->max_waste = COGL_TEXTURE_MAX_WASTE; + + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; /* Find closest GL format match */ tex->bitmap.format = @@ -1347,7 +1372,6 @@ cogl_texture_new_with_size (guint width, CoglHandle cogl_texture_new_from_data (guint width, guint height, - gint max_waste, CoglTextureFlags flags, CoglPixelFormat format, CoglPixelFormat internal_format, @@ -1371,7 +1395,8 @@ cogl_texture_new_from_data (guint width, tex = (CoglTexture*) g_malloc (sizeof (CoglTexture)); tex->is_foreign = FALSE; - tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0); + tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; + tex->mipmaps_dirty = TRUE; tex->bitmap.width = width; tex->bitmap.height = height; @@ -1384,9 +1409,14 @@ cogl_texture_new_from_data (guint width, tex->slice_y_spans = NULL; tex->slice_gl_handles = NULL; - tex->max_waste = max_waste; - tex->min_filter = CGL_NEAREST; - tex->mag_filter = CGL_NEAREST; + if (flags & COGL_TEXTURE_NO_SLICING) + tex->max_waste = -1; + else + tex->max_waste = COGL_TEXTURE_MAX_WASTE; + + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; /* FIXME: If upload fails we should set some kind of * error flag but still return texture handle (this @@ -1417,10 +1447,9 @@ cogl_texture_new_from_data (guint width, } CoglHandle -cogl_texture_new_from_bitmap (CoglHandle bmp_handle, - gint max_waste, - CoglTextureFlags flags, - CoglPixelFormat internal_format) +cogl_texture_new_from_bitmap (CoglHandle bmp_handle, + CoglTextureFlags flags, + CoglPixelFormat internal_format) { CoglTexture *tex; CoglBitmap *bmp = (CoglBitmap *)bmp_handle; @@ -1429,7 +1458,8 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle, tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture)); tex->is_foreign = FALSE; - tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0); + tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; + tex->mipmaps_dirty = TRUE; tex->bitmap = *bmp; tex->bitmap_owner = TRUE; @@ -1439,9 +1469,14 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle, tex->slice_y_spans = NULL; tex->slice_gl_handles = NULL; - tex->max_waste = max_waste; - tex->min_filter = CGL_NEAREST; - tex->mag_filter = CGL_NEAREST; + if (flags & COGL_TEXTURE_NO_SLICING) + tex->max_waste = -1; + else + tex->max_waste = COGL_TEXTURE_MAX_WASTE; + + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; /* FIXME: If upload fails we should set some kind of * error flag but still return texture handle if the @@ -1476,7 +1511,6 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle, CoglHandle cogl_texture_new_from_file (const gchar *filename, - gint max_waste, CoglTextureFlags flags, CoglPixelFormat internal_format, GError **error) @@ -1490,10 +1524,7 @@ cogl_texture_new_from_file (const gchar *filename, if (bmp == COGL_INVALID_HANDLE) return COGL_INVALID_HANDLE; - handle = cogl_texture_new_from_bitmap (bmp, - max_waste, - flags, - internal_format); + handle = cogl_texture_new_from_bitmap (bmp, flags, internal_format); cogl_handle_unref (bmp); return handle; @@ -1521,8 +1552,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle, GLint gl_int_format = 0; GLint gl_width = 0; GLint gl_height = 0; - GLint gl_min_filter; - GLint gl_mag_filter; GLint gl_gen_mipmap; guint bpp; CoglTexture *tex; @@ -1569,14 +1598,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle, gl_height = height + y_pot_waste; #endif - GE( glGetTexParameteriv (gl_target, - GL_TEXTURE_MIN_FILTER, - &gl_min_filter) ); - - GE( glGetTexParameteriv (gl_target, - GL_TEXTURE_MAG_FILTER, - &gl_mag_filter) ); - GE( glGetTexParameteriv (gl_target, GL_GENERATE_MIPMAP, &gl_gen_mipmap) ); @@ -1607,6 +1628,7 @@ cogl_texture_new_from_foreign (GLuint gl_handle, /* Setup bitmap info */ tex->is_foreign = TRUE; tex->auto_mipmap = (gl_gen_mipmap == GL_TRUE) ? TRUE : FALSE; + tex->mipmaps_dirty = TRUE; bpp = _cogl_get_format_bpp (format); tex->bitmap.format = format; @@ -1620,8 +1642,9 @@ cogl_texture_new_from_foreign (GLuint gl_handle, tex->gl_format = gl_int_format; tex->gl_type = GL_UNSIGNED_BYTE; - tex->min_filter = gl_min_filter; - tex->mag_filter = gl_mag_filter; + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; tex->max_waste = 0; /* Wrap mode not yet set */ @@ -1767,36 +1790,10 @@ cogl_texture_get_gl_texture (CoglHandle handle, return TRUE; } -CoglTextureFilter -cogl_texture_get_min_filter (CoglHandle handle) -{ - CoglTexture *tex; - - if (!cogl_is_texture (handle)) - return 0; - - tex = _cogl_texture_pointer_from_handle (handle); - - return tex->min_filter; -} - -CoglTextureFilter -cogl_texture_get_mag_filter (CoglHandle handle) -{ - CoglTexture *tex; - - if (!cogl_is_texture (handle)) - return 0; - - tex = _cogl_texture_pointer_from_handle (handle); - - return tex->mag_filter; -} - void -cogl_texture_set_filters (CoglHandle handle, - CoglTextureFilter min_filter, - CoglTextureFilter mag_filter) +_cogl_texture_set_filters (CoglHandle handle, + GLenum min_filter, + GLenum mag_filter) { CoglTexture *tex; GLuint gl_handle; @@ -1807,14 +1804,18 @@ cogl_texture_set_filters (CoglHandle handle, tex = _cogl_texture_pointer_from_handle (handle); - /* Store new values */ - tex->min_filter = min_filter; - tex->mag_filter = mag_filter; - /* Make sure slices were created */ if (tex->slice_gl_handles == NULL) return; + if (min_filter == tex->min_filter + && mag_filter == tex->mag_filter) + return; + + /* Store new values */ + tex->min_filter = min_filter; + tex->mag_filter = mag_filter; + /* Apply new filters to every slice */ for (i=0; islice_gl_handles->len; ++i) { @@ -1827,6 +1828,52 @@ cogl_texture_set_filters (CoglHandle handle, } } +void +_cogl_texture_ensure_mipmaps (CoglHandle handle) +{ + CoglTexture *tex; + int i; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + if (!cogl_is_texture (handle)) + return; + + tex = _cogl_texture_pointer_from_handle (handle); + + /* Only update if the mipmaps are dirty */ + if (!tex->auto_mipmap || !tex->mipmaps_dirty) + return; + + /* Make sure slices were created */ + if (tex->slice_gl_handles == NULL) + return; + + /* Regenerate the mipmaps on every slice */ + for (i = 0; i < tex->slice_gl_handles->len; i++) + { + GLuint gl_handle = g_array_index (tex->slice_gl_handles, GLuint, i); + GE( glBindTexture (tex->gl_target, gl_handle) ); + + /* glGenerateMipmap is defined in the FBO extension */ + if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) + GE( cogl_wrap_glGenerateMipmap (tex->gl_target) ); + else + { + CoglTexturePixel *pixel = tex->first_pixels + i; + /* Temporarily enable automatic mipmap generation and + re-upload the first pixel to cause a regeneration */ + GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GL_TRUE) ); + GE( glTexSubImage2D (tex->gl_target, 0, 0, 0, 1, 1, + pixel->gl_format, pixel->gl_type, + pixel->data) ); + GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GL_FALSE) ); + } + } + + tex->mipmaps_dirty = FALSE; +} + gboolean cogl_texture_set_region (CoglHandle handle, gint src_x, diff --git a/clutter/eglnative/clutter-stage-egl.c b/clutter/eglnative/clutter-stage-egl.c index 1d7f59603..3d134b27d 100644 --- a/clutter/eglnative/clutter-stage-egl.c +++ b/clutter/eglnative/clutter-stage-egl.c @@ -49,7 +49,8 @@ clutter_stage_egl_unrealize (ClutterActor *actor) CLUTTER_MARK(); - CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->unrealize (actor); + if (CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->unrealize != NULL) + CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->unrealize (actor); if (stage_egl->egl_surface) { @@ -220,9 +221,9 @@ clutter_stage_egl_realize (ClutterActor *actor) static void clutter_stage_egl_get_preferred_width (ClutterActor *self, - ClutterUnit for_height, - ClutterUnit *min_width_p, - ClutterUnit *natural_width_p) + gfloat for_height, + gfloat *min_width_p, + gfloat *natural_width_p) { ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (self); @@ -235,9 +236,9 @@ clutter_stage_egl_get_preferred_width (ClutterActor *self, static void clutter_stage_egl_get_preferred_height (ClutterActor *self, - ClutterUnit for_width, - ClutterUnit *min_height_p, - ClutterUnit *natural_height_p) + gfloat for_width, + gfloat *min_height_p, + gfloat *natural_height_p) { ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (self); @@ -253,8 +254,6 @@ clutter_stage_egl_dispose (GObject *gobject) { ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (gobject); - clutter_actor_unrealize (CLUTTER_ACTOR (stage_egl)); - G_OBJECT_CLASS (clutter_stage_egl_parent_class)->dispose (gobject); } diff --git a/clutter/eglx/clutter-stage-egl.c b/clutter/eglx/clutter-stage-egl.c index 5add2a862..f272e1c9f 100644 --- a/clutter/eglx/clutter-stage-egl.c +++ b/clutter/eglx/clutter-stage-egl.c @@ -38,7 +38,8 @@ clutter_stage_egl_unrealize (ClutterActor *actor) g_object_get (stage_x11->wrapper, "offscreen", &was_offscreen, NULL); - CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->unrealize (actor); + if (CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->unrealize != NULL) + CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->unrealize (actor); clutter_x11_trap_x_errors (); @@ -204,7 +205,7 @@ clutter_stage_egl_realize (ClutterActor *actor) } /* FIXME, do these in a clutterstage_x11_realise? */ - clutter_stage_x11_fix_window_size (stage_x11); + clutter_stage_x11_fix_window_size (stage_x11, -1, -1); clutter_stage_x11_set_wm_protocols (stage_x11); if (stage_egl->egl_surface != EGL_NO_SURFACE) @@ -275,9 +276,6 @@ clutter_stage_egl_dispose (GObject *gobject) ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (gobject); ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (gobject); - if (stage_x11->xwin) - clutter_actor_unrealize (CLUTTER_ACTOR (stage_egl)); - G_OBJECT_CLASS (clutter_stage_egl_parent_class)->dispose (gobject); } diff --git a/clutter/fruity/clutter-fruity.c b/clutter/fruity/clutter-fruity.c index 1198c5903..75cbcf1a3 100644 --- a/clutter/fruity/clutter-fruity.c +++ b/clutter/fruity/clutter-fruity.c @@ -393,6 +393,10 @@ typedef struct { stage_fruity = CLUTTER_STAGE_EGL(backend_fruity->stage); alive = FALSE; + /* FIXME why is this unrealize here? is the intent to destroy the stage? + * or hide it? Trying to clean up all manual unrealization so + * clutter_actor_unrealize() can be made private to clutter-actor.c + */ clutter_actor_unrealize (CLUTTER_ACTOR (stage_fruity)); clutter_main_quit (); } diff --git a/clutter/fruity/clutter-stage-fruity.c b/clutter/fruity/clutter-stage-fruity.c index 1f6b192fb..e85e0635c 100644 --- a/clutter/fruity/clutter-stage-fruity.c +++ b/clutter/fruity/clutter-stage-fruity.c @@ -45,7 +45,8 @@ clutter_stage_egl_unrealize (ClutterActor *actor) CLUTTER_MARK(); - CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->unrealize (actor); + if (CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->unrealize != NULL) + CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->unrealize (actor); if (stage_egl->egl_surface) { @@ -189,9 +190,9 @@ clutter_stage_egl_realize (ClutterActor *actor) static void clutter_stage_egl_get_preferred_width (ClutterActor *self, - ClutterUnit for_height, - ClutterUnit *min_width_p, - ClutterUnit *natural_width_p) + gfloat for_height, + gfloat *min_width_p, + gfloat *natural_width_p) { ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (self); @@ -204,9 +205,9 @@ clutter_stage_egl_get_preferred_width (ClutterActor *self, static void clutter_stage_egl_get_preferred_height (ClutterActor *self, - ClutterUnit for_width, - ClutterUnit *min_height_p, - ClutterUnit *natural_height_p) + gfloat for_width, + gfloat *min_height_p, + gfloat *natural_height_p) { ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (self); @@ -222,8 +223,6 @@ clutter_stage_egl_dispose (GObject *gobject) { ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (gobject); - clutter_actor_unrealize (CLUTTER_ACTOR (stage_egl)); - G_OBJECT_CLASS (clutter_stage_egl_parent_class)->dispose (gobject); } diff --git a/clutter/glx/clutter-backend-glx.c b/clutter/glx/clutter-backend-glx.c index 41f00b159..d9fef911d 100644 --- a/clutter/glx/clutter-backend-glx.c +++ b/clutter/glx/clutter-backend-glx.c @@ -219,7 +219,7 @@ clutter_backend_glx_constructor (GType gtype, static gboolean check_vblank_env (const char *name) { - if (clutter_vblank_name && !strcasecmp(clutter_vblank_name, name)) + if (clutter_vblank_name && !g_ascii_strcasecmp (clutter_vblank_name, name)) return TRUE; return FALSE; @@ -354,6 +354,57 @@ clutter_backend_glx_get_features (ClutterBackend *backend) return flags; } +static gboolean +clutter_backend_glx_create_context (ClutterBackend *backend, + gboolean is_offscreen, + GError **error) +{ + ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend); + ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend); + + if (backend_glx->gl_context == None) + { + XVisualInfo *xvisinfo; + + xvisinfo = + clutter_backend_x11_get_visual_info (backend_x11, is_offscreen); + + CLUTTER_NOTE (GL, "Creating GL Context (display: %p, %s)", + backend_x11->xdpy, + is_offscreen ? "offscreen" : "onscreen"); + + backend_glx->gl_context = glXCreateContext (backend_x11->xdpy, + xvisinfo, + 0, + is_offscreen ? False : True); + + XFree (xvisinfo); + + if (backend_glx->gl_context == None) + { + g_set_error (error, CLUTTER_INIT_ERROR, + CLUTTER_INIT_ERROR_BACKEND, + "Unable to create suitable %s GL context", + is_offscreen ? "offscreen" : "onscreen"); + return FALSE; + } + + if (!is_offscreen) + { + gboolean is_direct; + + is_direct = glXIsDirect (backend_x11->xdpy, + backend_glx->gl_context); + + CLUTTER_NOTE (GL, "Setting %s context", + is_direct ? "direct" : "indirect"); + _cogl_set_indirect_context (!is_direct); + } + } + + return TRUE; +} + static void clutter_backend_glx_ensure_context (ClutterBackend *backend, ClutterStage *stage) @@ -434,8 +485,11 @@ clutter_backend_glx_redraw (ClutterBackend *backend, ClutterStageWindow *impl; impl = _clutter_stage_get_window (stage); - if (!impl) - return; + if (G_UNLIKELY (impl == NULL)) + { + CLUTTER_NOTE (BACKEND, "Stage [%p] has no implementation", stage); + return; + } g_assert (CLUTTER_IS_STAGE_GLX (impl)); @@ -445,23 +499,28 @@ clutter_backend_glx_redraw (ClutterBackend *backend, /* this will cause the stage implementation to be painted */ clutter_actor_paint (CLUTTER_ACTOR (stage)); - /* Why this paint is done in backend as likely GL windowing system - * specific calls, like swapping buffers. - */ - if (stage_x11->xwin) + if (stage_x11->xwin != None) { + /* wait for the next vblank */ + CLUTTER_NOTE (BACKEND, "Waiting for vblank"); clutter_backend_glx_wait_for_vblank (CLUTTER_BACKEND_GLX (backend)); + + /* push on the screen */ + CLUTTER_NOTE (BACKEND, "glXSwapBuffers (display: %p, window: 0x%lx)", + stage_x11->xdpy, + (unsigned long) stage_x11->xwin); glXSwapBuffers (stage_x11->xdpy, stage_x11->xwin); } else { /* offscreen */ glXWaitGL (); + CLUTTER_GLERR (); } } -static ClutterActor* +static ClutterActor * clutter_backend_glx_create_stage (ClutterBackend *backend, ClutterStage *wrapper, GError **error) @@ -483,19 +542,67 @@ clutter_backend_glx_create_stage (ClutterBackend *backend, stage_x11->backend = backend_x11; stage_x11->wrapper = wrapper; - CLUTTER_NOTE (BACKEND, "GLX stage created (display:%p, screen:%d, root:%u)", + CLUTTER_NOTE (BACKEND, + "GLX stage created[%p] (dpy:%p, screen:%d, root:%u, wrap:%p)", + stage, stage_x11->xdpy, stage_x11->xscreen, - (unsigned int) stage_x11->xwin_root); + (unsigned int) stage_x11->xwin_root, + wrapper); return stage; } +static XVisualInfo * +clutter_backend_glx_get_visual_info (ClutterBackendX11 *backend_x11, + gboolean for_offscreen) +{ + XVisualInfo *xvisinfo; + int onscreen_gl_attributes[] = { + GLX_RGBA, + GLX_DOUBLEBUFFER, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_STENCIL_SIZE, 1, + 0 + }; + int offscreen_gl_attributes[] = { + GLX_RGBA, + GLX_USE_GL, + GLX_DEPTH_SIZE, 0, + GLX_ALPHA_SIZE, 0, + GLX_STENCIL_SIZE, 1, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + 0 + }; + + if (backend_x11->xdpy == None || backend_x11->xscreen == None) + return NULL; + + CLUTTER_NOTE (BACKEND, + "Retrieving GL visual (for %s use), dpy: %p, xscreen; %p (%d)", + for_offscreen ? "offscreen" : "onscreen", + backend_x11->xdpy, + backend_x11->xscreen, + backend_x11->xscreen_num); + + xvisinfo = glXChooseVisual (backend_x11->xdpy, + backend_x11->xscreen_num, + for_offscreen ? offscreen_gl_attributes + : onscreen_gl_attributes); + + return xvisinfo; +} + static void clutter_backend_glx_class_init (ClutterBackendGLXClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass); + ClutterBackendX11Class *backendx11_class = CLUTTER_BACKEND_X11_CLASS (klass); gobject_class->constructor = clutter_backend_glx_constructor; gobject_class->dispose = clutter_backend_glx_dispose; @@ -507,7 +614,10 @@ clutter_backend_glx_class_init (ClutterBackendGLXClass *klass) backend_class->add_options = clutter_backend_glx_add_options; backend_class->get_features = clutter_backend_glx_get_features; backend_class->redraw = clutter_backend_glx_redraw; + backend_class->create_context = clutter_backend_glx_create_context; backend_class->ensure_context = clutter_backend_glx_ensure_context; + + backendx11_class->get_visual_info = clutter_backend_glx_get_visual_info; } static void diff --git a/clutter/glx/clutter-glx-texture-pixmap.c b/clutter/glx/clutter-glx-texture-pixmap.c index c1a02206e..366643021 100644 --- a/clutter/glx/clutter-glx-texture-pixmap.c +++ b/clutter/glx/clutter-glx-texture-pixmap.c @@ -135,14 +135,6 @@ texture_bind (ClutterGLXTexturePixmap *tex) /* FIXME: fire off an error here? */ glBindTexture (target, handle); - if (clutter_texture_get_filter_quality (CLUTTER_TEXTURE (tex)) - == CLUTTER_TEXTURE_QUALITY_HIGH && tex->priv->can_mipmap) - { - cogl_texture_set_filters (cogl_tex, - COGL_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR, - COGL_TEXTURE_FILTER_LINEAR); - } - return TRUE; } @@ -167,6 +159,18 @@ on_glx_texture_pixmap_pre_paint (ClutterGLXTexturePixmap *texture, texture->priv->mipmap_generate_queued = 0; } + /* Disable mipmaps if we can't support them */ + if (clutter_texture_get_filter_quality (CLUTTER_TEXTURE (texture)) + == CLUTTER_TEXTURE_QUALITY_HIGH + && !texture->priv->can_mipmap) + { + CoglHandle material + = clutter_texture_get_cogl_material (CLUTTER_TEXTURE (texture)); + + cogl_material_set_layer_filters (material, 0, + COGL_MATERIAL_FILTER_LINEAR, + COGL_MATERIAL_FILTER_LINEAR); + } } static void @@ -214,9 +218,9 @@ clutter_glx_texture_pixmap_init (ClutterGLXTexturePixmap *self) if ((rect_env = g_getenv ("CLUTTER_PIXMAP_TEXTURE_RECTANGLE"))) { - if (strcasecmp (rect_env, "force") == 0) + if (g_ascii_strcasecmp (rect_env, "force") == 0) _rectangle_state = CLUTTER_GLX_RECTANGLE_FORCE; - else if (strcasecmp (rect_env, "disable") == 0) + else if (g_ascii_strcasecmp (rect_env, "disable") == 0) _rectangle_state = CLUTTER_GLX_RECTANGLE_DISALLOW; else if (rect_env[0]) g_warning ("Unknown value for CLUTTER_PIXMAP_TEXTURE_RECTANGLE, " @@ -360,7 +364,7 @@ create_cogl_texture (ClutterTexture *texture, { handle = cogl_texture_new_with_size (width, height, - -1, FALSE, + COGL_TEXTURE_NO_SLICING, cogl_format | COGL_BGR_BIT); using_rectangle = FALSE; diff --git a/clutter/glx/clutter-stage-glx.c b/clutter/glx/clutter-stage-glx.c index 12f54cb38..7a845654c 100644 --- a/clutter/glx/clutter-stage-glx.c +++ b/clutter/glx/clutter-stage-glx.c @@ -67,10 +67,8 @@ clutter_stage_glx_unrealize (ClutterActor *actor) g_object_get (stage_x11->wrapper, "offscreen", &was_offscreen, NULL); - /* Chain up so all children get unrealized, needed to move texture data - * across contexts - */ - CLUTTER_ACTOR_CLASS (clutter_stage_glx_parent_class)->unrealize (actor); + if (CLUTTER_ACTOR_CLASS (clutter_stage_glx_parent_class)->unrealize != NULL) + CLUTTER_ACTOR_CLASS (clutter_stage_glx_parent_class)->unrealize (actor); clutter_x11_trap_x_errors (); @@ -99,6 +97,12 @@ clutter_stage_glx_unrealize (ClutterActor *actor) stage_x11->xwin = None; } + if (stage_x11->xvisinfo != None) + { + XFree (stage_x11->xvisinfo); + stage_x11->xvisinfo = None; + } + XSync (stage_x11->xdpy, False); clutter_x11_untrap_x_errors (); @@ -111,42 +115,29 @@ clutter_stage_glx_realize (ClutterActor *actor) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor); ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (actor); + ClutterBackend *backend; ClutterBackendGLX *backend_glx; ClutterBackendX11 *backend_x11; gboolean is_offscreen; - CLUTTER_NOTE (MISC, "Realizing main stage"); + CLUTTER_NOTE (ACTOR, "Realizing stage '%s' [%p]", + G_OBJECT_TYPE_NAME (actor), + actor); g_object_get (stage_x11->wrapper, "offscreen", &is_offscreen, NULL); - backend_glx = CLUTTER_BACKEND_GLX (clutter_get_default_backend ()); - backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ()); + backend = clutter_get_default_backend (); + backend_glx = CLUTTER_BACKEND_GLX (backend); + backend_x11 = CLUTTER_BACKEND_X11 (backend); if (G_LIKELY (!is_offscreen)) { - int gl_attributes[] = - { - GLX_RGBA, - GLX_DOUBLEBUFFER, - GLX_RED_SIZE, 1, - GLX_GREEN_SIZE, 1, - GLX_BLUE_SIZE, 1, - GLX_STENCIL_SIZE, 1, - 0 - }; + GError *error; - if (stage_x11->xvisinfo) - { - XFree (stage_x11->xvisinfo); - stage_x11->xvisinfo = None; - } + stage_x11->xvisinfo = + clutter_backend_x11_get_visual_info (backend_x11, FALSE); - /* The following check seems strange */ if (stage_x11->xvisinfo == None) - stage_x11->xvisinfo = glXChooseVisual (stage_x11->xdpy, - stage_x11->xscreen, - gl_attributes); - if (!stage_x11->xvisinfo) { g_critical ("Unable to find suitable GL visual."); goto fail; @@ -208,25 +199,17 @@ clutter_stage_glx_realize (ClutterActor *actor) } /* no user resize.. */ - clutter_stage_x11_fix_window_size (stage_x11); + clutter_stage_x11_fix_window_size (stage_x11, -1, -1); clutter_stage_x11_set_wm_protocols (stage_x11); - if (G_UNLIKELY (backend_glx->gl_context == None)) + /* ask for a context; a no-op, if a context already exists */ + error = NULL; + _clutter_backend_create_context (backend, FALSE, &error); + if (error) { - CLUTTER_NOTE (GL, "Creating GL Context"); - backend_glx->gl_context = glXCreateContext (stage_x11->xdpy, - stage_x11->xvisinfo, - 0, - True); - - if (backend_glx->gl_context == None) - { - g_critical ("Unable to create suitable GL context."); - goto fail; - } - - _cogl_set_indirect_context (!glXIsDirect (stage_x11->xdpy, - backend_glx->gl_context)); + g_critical ("Unable to realize stage: %s", error->message); + g_error_free (error); + goto fail; } CLUTTER_NOTE (BACKEND, "Marking stage as realized"); @@ -234,33 +217,23 @@ clutter_stage_glx_realize (ClutterActor *actor) } else { - int gl_attributes[] = { - GLX_DEPTH_SIZE, 0, - GLX_ALPHA_SIZE, 0, - GLX_RED_SIZE, 1, - GLX_GREEN_SIZE, 1, - GLX_BLUE_SIZE, 1, - GLX_USE_GL, - GLX_RGBA, - 0 - }; + GError *error; - if (stage_x11->xvisinfo) - XFree (stage_x11->xvisinfo); + if (stage_x11->xvisinfo != None) + { + XFree (stage_x11->xvisinfo); + stage_x11->xvisinfo = None; + } - stage_x11->xvisinfo = NULL; + stage_x11->xvisinfo = + clutter_backend_x11_get_visual_info (backend_x11, TRUE); - CLUTTER_NOTE (GL, "glXChooseVisual"); - stage_x11->xvisinfo = glXChooseVisual (stage_x11->xdpy, - stage_x11->xscreen, - gl_attributes); - if (!stage_x11->xvisinfo) + if (stage_x11->xvisinfo == None) { g_critical ("Unable to find suitable GL visual."); goto fail; } - stage_x11->xpixmap = XCreatePixmap (stage_x11->xdpy, stage_x11->xwin_root, stage_x11->xwin_width, @@ -272,25 +245,20 @@ clutter_stage_glx_realize (ClutterActor *actor) stage_x11->xvisinfo, stage_x11->xpixmap); - if (backend_glx->gl_context == None) + /* ask for a context; a no-op, if a context already exists + * + * FIXME: we probably need a seperate offscreen context here + * - though it likely makes most sense to drop offscreen stages + * and rely on FBO's instead and GLXPixmaps seems mostly broken + * anyway.. + */ + error = NULL; + _clutter_backend_create_context (backend, TRUE, &error); + if (error) { - CLUTTER_NOTE (GL, "Creating GL Context"); - - /* FIXME: we probably need a seperate offscreen context here - * - though it likely makes most sense to drop offscreen stages - * and rely on FBO's instead and GLXPixmaps seems mostly broken - * anyway.. - */ - backend_glx->gl_context = glXCreateContext (stage_x11->xdpy, - stage_x11->xvisinfo, - 0, - False); - - if (backend_glx->gl_context == None) - { - g_critical ("Unable to create suitable GL context."); - goto fail; - } + g_critical ("Unable to realize stage: %s", error->message); + g_error_free (error); + goto fail; } CLUTTER_NOTE (BACKEND, "Marking stage as realized"); @@ -310,12 +278,6 @@ fail: static void clutter_stage_glx_dispose (GObject *gobject) { - ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (gobject); - ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (gobject); - - if (stage_x11->xwin) - clutter_actor_unrealize (CLUTTER_ACTOR (stage_glx)); - G_OBJECT_CLASS (clutter_stage_glx_parent_class)->dispose (gobject); } diff --git a/clutter/osx/clutter-stage-osx.c b/clutter/osx/clutter-stage-osx.c index cb60b3676..cb04b22cb 100644 --- a/clutter/osx/clutter-stage-osx.c +++ b/clutter/osx/clutter-stage-osx.c @@ -367,9 +367,9 @@ clutter_stage_osx_hide (ClutterActor *actor) static void clutter_stage_osx_get_preferred_width (ClutterActor *actor, - ClutterUnit for_height, - ClutterUnit *min_width_p, - ClutterUnit *natural_width_p) + gfloat for_height, + gfloat *min_width_p, + gfloat *natural_width_p) { ClutterStageOSX *self = CLUTTER_STAGE_OSX (actor); gboolean is_resizable; @@ -394,9 +394,9 @@ clutter_stage_osx_get_preferred_width (ClutterActor *actor, static void clutter_stage_osx_get_preferred_height (ClutterActor *actor, - ClutterUnit for_width, - ClutterUnit *min_height_p, - ClutterUnit *natural_height_p) + gfloat for_width, + gfloat *min_height_p, + gfloat *natural_height_p) { ClutterStageOSX *self = CLUTTER_STAGE_OSX (actor); gboolean is_resizable; @@ -420,9 +420,9 @@ clutter_stage_osx_get_preferred_height (ClutterActor *actor, } static void -clutter_stage_osx_allocate (ClutterActor *actor, - const ClutterActorBox *box, - gboolean origin_changed) +clutter_stage_osx_allocate (ClutterActor *actor, + const ClutterActorBox *box, + ClutterAllocationFlags flags) { ClutterStageOSX *self = CLUTTER_STAGE_OSX (actor); ClutterActorClass *parent_class; @@ -452,7 +452,7 @@ clutter_stage_osx_allocate (ClutterActor *actor, /* chain up */ parent_class = CLUTTER_ACTOR_CLASS (clutter_stage_osx_parent_class); - parent_class->allocate (actor, box, origin_changed); + parent_class->allocate (actor, box, flags); } /*************************************************************************/ diff --git a/clutter/pango/Makefile.am b/clutter/pango/Makefile.am index 1d2d22402..97e180d6d 100644 --- a/clutter/pango/Makefile.am +++ b/clutter/pango/Makefile.am @@ -1,4 +1,5 @@ source_c = \ + cogl-pango-display-list.c \ cogl-pango-fontmap.c \ cogl-pango-render.c \ cogl-pango-glyph-cache.c @@ -6,26 +7,27 @@ source_c = \ source_h = cogl-pango.h source_h_priv = \ + cogl-pango-display-list.h \ cogl-pango-private.h \ cogl-pango-glyph-cache.h noinst_LTLIBRARIES = libcoglpango.la -libcoglpango_la_SOURCES = \ - $(source_c) \ - $(source_h) \ - $(source_h_priv) +libcoglpango_la_SOURCES = $(source_c) $(source_h) $(source_h_priv) +libcoglpango_la_CPPFLAGS = $(CLUTTER_CFLAGS) +libcoglpango_la_LIBADD = $(CLUTTER_LIBS) INCLUDES = \ - @GCC_FLAGS@ @CLUTTER_CFLAGS@ \ - $(CLUTTER_DEBUG_CFLAGS) \ - $(MAINTAINER_CFLAGS) \ - -DCLUTTER_COMPILATION \ - -I$(top_srcdir) \ - -I$(top_srcdir)/clutter \ - -I$(top_srcdir)/clutter/cogl \ - -I$(top_builddir)/clutter \ - -I$(top_builddir)/clutter/cogl + -DCLUTTER_COMPILATION \ + -DG_LOG_DOMAIN=\"CoglPango\" \ + -I$(top_srcdir) \ + -I$(top_srcdir)/clutter \ + -I$(top_srcdir)/clutter/cogl \ + -I$(top_builddir)/clutter \ + -I$(top_builddir)/clutter/cogl \ + $(CLUTTER_DEBUG_CFLAGS) \ + $(COGL_DEBUG_CFLAGS) \ + $(MAINTAINER_CFLAGS) coglpangoheadersdir = $(includedir)/clutter-@CLUTTER_MAJORMINOR@/cogl coglpangoheaders_HEADERS = $(source_h) diff --git a/clutter/pango/cogl-pango-display-list.c b/clutter/pango/cogl-pango-display-list.c new file mode 100644 index 000000000..70f640517 --- /dev/null +++ b/clutter/pango/cogl-pango-display-list.c @@ -0,0 +1,353 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Authored By Neil Roberts + * + * Copyright (C) 2009 Intel Corporation. + * + * 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, see . + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "cogl-pango-display-list.h" + +typedef enum +{ + COGL_PANGO_DISPLAY_LIST_TEXTURE, + COGL_PANGO_DISPLAY_LIST_RECTANGLE, + COGL_PANGO_DISPLAY_LIST_TRAPEZOID +} CoglPangoDisplayListNodeType; + +typedef struct _CoglPangoDisplayListNode CoglPangoDisplayListNode; +typedef struct _CoglPangoDisplayListVertex CoglPangoDisplayListVertex; + +struct _CoglPangoDisplayList +{ + CoglColor color; + GSList *nodes; + GSList *last_node; +}; + +struct _CoglPangoDisplayListNode +{ + CoglPangoDisplayListNodeType type; + + CoglColor color; + + union + { + struct + { + /* The texture to render these coords from */ + CoglHandle texture; + /* Array of vertex data to render out of this texture */ + GArray *verts; + /* A VBO representing those vertices */ + CoglHandle vertex_buffer; + } texture; + + struct + { + float x_1, y_1; + float x_2, y_2; + } rectangle; + + struct + { + float y_1; + float x_11; + float x_21; + float y_2; + float x_12; + float x_22; + } trapezoid; + } d; +}; + +struct _CoglPangoDisplayListVertex +{ + float x, y, t_x, t_y; +}; + +CoglPangoDisplayList * +_cogl_pango_display_list_new (void) +{ + return g_slice_new0 (CoglPangoDisplayList); +} + +static void +_cogl_pango_display_list_append_node (CoglPangoDisplayList *dl, + CoglPangoDisplayListNode *node) +{ + if (dl->last_node) + dl->last_node = dl->last_node->next = g_slist_prepend (NULL, node); + else + dl->last_node = dl->nodes = g_slist_prepend (NULL, node); +} + +void +_cogl_pango_display_list_set_color (CoglPangoDisplayList *dl, + const CoglColor *color) +{ + dl->color = *color; +} + +void +_cogl_pango_display_list_add_texture (CoglPangoDisplayList *dl, + CoglHandle texture, + float x_1, float y_1, + float x_2, float y_2, + float tx_1, float ty_1, + float tx_2, float ty_2) +{ + CoglPangoDisplayListNode *node; + CoglPangoDisplayListVertex *verts; + + /* Add to the last node if it is a texture node with the same + target texture */ + if (dl->last_node + && (node = dl->last_node->data)->type == COGL_PANGO_DISPLAY_LIST_TEXTURE + && node->d.texture.texture == texture + && !memcmp (&dl->color, &node->color, sizeof (CoglColor))) + { + /* Get rid of the vertex buffer so that it will be recreated */ + if (node->d.texture.vertex_buffer != COGL_INVALID_HANDLE) + { + cogl_vertex_buffer_unref (node->d.texture.vertex_buffer); + node->d.texture.vertex_buffer = COGL_INVALID_HANDLE; + } + } + else + { + /* Otherwise create a new node */ + node = g_slice_new (CoglPangoDisplayListNode); + + node->type = COGL_PANGO_DISPLAY_LIST_TEXTURE; + node->color = dl->color; + node->d.texture.texture = cogl_texture_ref (texture); + node->d.texture.verts + = g_array_new (FALSE, FALSE, sizeof (CoglPangoDisplayListVertex)); + node->d.texture.vertex_buffer = COGL_INVALID_HANDLE; + + _cogl_pango_display_list_append_node (dl, node); + } + + g_array_set_size (node->d.texture.verts, + node->d.texture.verts->len + 4); + verts = &g_array_index (node->d.texture.verts, + CoglPangoDisplayListVertex, + node->d.texture.verts->len - 4); + + verts->x = x_1; + verts->y = y_1; + verts->t_x = tx_1; + verts->t_y = ty_1; + verts++; + verts->x = x_1; + verts->y = y_2; + verts->t_x = tx_1; + verts->t_y = ty_2; + verts++; + verts->x = x_2; + verts->y = y_2; + verts->t_x = tx_2; + verts->t_y = ty_2; + verts++; + verts->x = x_2; + verts->y = y_1; + verts->t_x = tx_2; + verts->t_y = ty_1; +} + +void +_cogl_pango_display_list_add_rectangle (CoglPangoDisplayList *dl, + float x_1, float y_1, + float x_2, float y_2) +{ + CoglPangoDisplayListNode *node = g_slice_new (CoglPangoDisplayListNode); + + node->type = COGL_PANGO_DISPLAY_LIST_RECTANGLE; + node->color = dl->color; + node->d.rectangle.x_1 = x_1; + node->d.rectangle.y_1 = y_1; + node->d.rectangle.x_2 = x_2; + node->d.rectangle.y_2 = y_2; + + _cogl_pango_display_list_append_node (dl, node); +} + +void +_cogl_pango_display_list_add_trapezoid (CoglPangoDisplayList *dl, + float y_1, + float x_11, + float x_21, + float y_2, + float x_12, + float x_22) +{ + CoglPangoDisplayListNode *node = g_slice_new (CoglPangoDisplayListNode); + + node->type = COGL_PANGO_DISPLAY_LIST_TRAPEZOID; + node->color = dl->color; + node->d.trapezoid.y_1 = y_1; + node->d.trapezoid.x_11 = x_11; + node->d.trapezoid.x_21 = x_21; + node->d.trapezoid.y_2 = y_2; + node->d.trapezoid.x_12 = x_12; + node->d.trapezoid.x_22 = x_22; + + _cogl_pango_display_list_append_node (dl, node); +} + +static void +_cogl_pango_display_list_render_texture (CoglHandle material, + CoglPangoDisplayListNode *node) +{ + cogl_material_set_layer (material, 0, node->d.texture.texture); + cogl_material_set_color (material, &node->color); + cogl_set_source (material); + + if (node->d.texture.vertex_buffer == COGL_INVALID_HANDLE) + { + CoglHandle vb = cogl_vertex_buffer_new (node->d.texture.verts->len); + + cogl_vertex_buffer_add (vb, "gl_Vertex", 2, + COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, + sizeof (CoglPangoDisplayListVertex), + &g_array_index (node->d.texture.verts, + CoglPangoDisplayListVertex, 0).x); + cogl_vertex_buffer_add (vb, "gl_MultiTexCoord0", 2, + COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, + sizeof (CoglPangoDisplayListVertex), + &g_array_index (node->d.texture.verts, + CoglPangoDisplayListVertex, + 0).t_x); + cogl_vertex_buffer_submit (vb); + + node->d.texture.vertex_buffer = vb; + } + + +#ifdef CLUTTER_COGL_HAS_GL + + cogl_vertex_buffer_draw (node->d.texture.vertex_buffer, + GL_QUADS, + 0, node->d.texture.verts->len); + +#else /* CLUTTER_COGL_HAS_GL */ + { + /* GLES doesn't support GL_QUADS so instead we use a VBO with + indexed vertices to generate GL_TRIANGLES from the quads */ + + int n_indices = node->d.texture.verts->len / 4 * 6; + CoglHandle indices_vbo + = cogl_vertex_buffer_indices_get_for_quads (n_indices); + + cogl_vertex_buffer_draw_elements (node->d.texture.vertex_buffer, + COGL_VERTICES_MODE_TRIANGLES, + indices_vbo, + 0, node->d.texture.verts->len - 1, + 0, n_indices); + } +#endif /* CLUTTER_COGL_HAS_GL */ +} + +void +_cogl_pango_display_list_render (CoglPangoDisplayList *dl, + CoglHandle glyph_material, + CoglHandle solid_material) +{ + GSList *l; + + for (l = dl->nodes; l; l = l->next) + { + CoglPangoDisplayListNode *node = l->data; + + switch (node->type) + { + case COGL_PANGO_DISPLAY_LIST_TEXTURE: + _cogl_pango_display_list_render_texture (glyph_material, node); + break; + + case COGL_PANGO_DISPLAY_LIST_RECTANGLE: + cogl_material_set_color (solid_material, &node->color); + cogl_set_source (solid_material); + cogl_rectangle (node->d.rectangle.x_1, + node->d.rectangle.y_1, + node->d.rectangle.x_2, + node->d.rectangle.y_2); + break; + + case COGL_PANGO_DISPLAY_LIST_TRAPEZOID: + { + float points[8]; + + points[0] = node->d.trapezoid.x_11; + points[1] = node->d.trapezoid.y_1; + points[2] = node->d.trapezoid.x_12; + points[3] = node->d.trapezoid.y_2; + points[4] = node->d.trapezoid.x_22; + points[5] = node->d.trapezoid.y_2; + points[6] = node->d.trapezoid.x_21; + points[7] = node->d.trapezoid.y_1; + + cogl_material_set_color (solid_material, &node->color); + cogl_set_source (solid_material); + cogl_path_polygon (points, 4); + cogl_path_fill (); + } + break; + } + } +} + +static void +_cogl_pango_display_list_node_free (CoglPangoDisplayListNode *node) +{ + if (node->type == COGL_PANGO_DISPLAY_LIST_TEXTURE) + { + g_array_free (node->d.texture.verts, TRUE); + if (node->d.texture.texture != COGL_INVALID_HANDLE) + cogl_texture_unref (node->d.texture.texture); + if (node->d.texture.vertex_buffer != COGL_INVALID_HANDLE) + cogl_vertex_buffer_unref (node->d.texture.vertex_buffer); + } + + g_slice_free (CoglPangoDisplayListNode, node); +} + +void +_cogl_pango_display_list_clear (CoglPangoDisplayList *dl) +{ + g_slist_foreach (dl->nodes, (GFunc) _cogl_pango_display_list_node_free, NULL); + g_slist_free (dl->nodes); + dl->nodes = NULL; + dl->last_node = NULL; +} + +void +_cogl_pango_display_list_free (CoglPangoDisplayList *dl) +{ + _cogl_pango_display_list_clear (dl); + g_slice_free (CoglPangoDisplayList, dl); +} diff --git a/clutter/pango/cogl-pango-display-list.h b/clutter/pango/cogl-pango-display-list.h new file mode 100644 index 000000000..a2b123208 --- /dev/null +++ b/clutter/pango/cogl-pango-display-list.h @@ -0,0 +1,68 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Authored By Neil Roberts + * + * Copyright (C) 2009 Intel Corporation. + * + * 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, see . + */ + +#ifndef __COGL_PANGO_DISPLAY_LIST_H__ +#define __COGL_PANGO_DISPLAY_LIST_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _CoglPangoDisplayList CoglPangoDisplayList; + +CoglPangoDisplayList *_cogl_pango_display_list_new (void); + +void _cogl_pango_display_list_set_color (CoglPangoDisplayList *dl, + const CoglColor *color); + +void _cogl_pango_display_list_add_texture (CoglPangoDisplayList *dl, + CoglHandle texture, + float x_1, float y_1, + float x_2, float y_2, + float tx_1, float ty_1, + float tx_2, float ty_2); + +void _cogl_pango_display_list_add_rectangle (CoglPangoDisplayList *dl, + float x_1, float y_1, + float x_2, float y_2); + +void _cogl_pango_display_list_add_trapezoid (CoglPangoDisplayList *dl, + float y_1, + float x_11, + float x_21, + float y_2, + float x_12, + float x_22); + +void _cogl_pango_display_list_render (CoglPangoDisplayList *dl, + CoglHandle glyph_material, + CoglHandle solid_material); + +void _cogl_pango_display_list_clear (CoglPangoDisplayList *dl); + +void _cogl_pango_display_list_free (CoglPangoDisplayList *dl); + +G_END_DECLS + +#endif /* __COGL_PANGO_DISPLAY_LIST_H__ */ diff --git a/clutter/pango/cogl-pango-glyph-cache.c b/clutter/pango/cogl-pango-glyph-cache.c index 892255623..df26f672f 100644 --- a/clutter/pango/cogl-pango-glyph-cache.c +++ b/clutter/pango/cogl-pango-glyph-cache.c @@ -51,10 +51,6 @@ struct _CoglPangoGlyphCache /* List of horizontal bands of glyphs */ CoglPangoGlyphCacheBand *bands; - - /* If TRUE all of the textures will be created with automatic mipmap - generation enabled */ - gboolean use_mipmapping; }; struct _CoglPangoGlyphCacheKey @@ -177,7 +173,7 @@ cogl_pango_glyph_cache_free_bands (CoglPangoGlyphCacheBand *node) } CoglPangoGlyphCache * -cogl_pango_glyph_cache_new (gboolean use_mipmapping) +cogl_pango_glyph_cache_new (void) { CoglPangoGlyphCache *cache; @@ -191,7 +187,6 @@ cogl_pango_glyph_cache_new (gboolean use_mipmapping) cache->textures = NULL; cache->bands = NULL; - cache->use_mipmapping = use_mipmapping; return cache; } @@ -272,7 +267,6 @@ cogl_pango_glyph_cache_set (CoglPangoGlyphCache *cache, texture = texture->next); if (texture == NULL) { - CoglTextureFlags flags = COGL_TEXTURE_NONE; guchar *clear_data; /* Allocate a new texture that is the nearest power of two @@ -291,13 +285,10 @@ cogl_pango_glyph_cache_set (CoglPangoGlyphCache *cache, clear_data = g_malloc0 (texture->texture_size * texture->texture_size); - if (cache->use_mipmapping) - flags |= COGL_TEXTURE_AUTO_MIPMAP; - texture->texture = cogl_texture_new_from_data (texture->texture_size, texture->texture_size, - 32, flags, + COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_A_8, COGL_PIXEL_FORMAT_A_8, texture->texture_size, @@ -308,15 +299,6 @@ cogl_pango_glyph_cache_set (CoglPangoGlyphCache *cache, texture->space_remaining = texture->texture_size; texture->next = cache->textures; cache->textures = texture; - - if (cache->use_mipmapping) - cogl_texture_set_filters (texture->texture, - COGL_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR, - COGL_TEXTURE_FILTER_LINEAR); - else - cogl_texture_set_filters (texture->texture, - COGL_TEXTURE_FILTER_LINEAR, - COGL_TEXTURE_FILTER_LINEAR); } band = g_slice_new (CoglPangoGlyphCacheBand); diff --git a/clutter/pango/cogl-pango-glyph-cache.h b/clutter/pango/cogl-pango-glyph-cache.h index 33364e1c7..ab5265afa 100644 --- a/clutter/pango/cogl-pango-glyph-cache.h +++ b/clutter/pango/cogl-pango-glyph-cache.h @@ -49,7 +49,7 @@ struct _CoglPangoGlyphCacheValue }; CoglPangoGlyphCache * -cogl_pango_glyph_cache_new (gboolean use_mipmapping); +cogl_pango_glyph_cache_new (void); void cogl_pango_glyph_cache_free (CoglPangoGlyphCache *cache); diff --git a/clutter/pango/cogl-pango-render.c b/clutter/pango/cogl-pango-render.c index ba9395b21..89c89c481 100644 --- a/clutter/pango/cogl-pango-render.c +++ b/clutter/pango/cogl-pango-render.c @@ -36,6 +36,7 @@ #include "cogl-pango-private.h" #include "cogl-pango-glyph-cache.h" +#include "cogl-pango-display-list.h" struct _CoglPangoRenderer { @@ -48,16 +49,11 @@ struct _CoglPangoRenderer /* The material used for solid fills. (boxes, rectangles + trapezoids) */ CoglHandle solid_material; - /* Two caches of glyphs as textures, one with mipmapped textures and - one without */ + /* Caches of glyphs as textures */ CoglPangoGlyphCache *glyph_cache; - CoglPangoGlyphCache *mipmapped_glyph_cache; - gboolean use_mipmapping; - - /* Array of rectangles to draw from the current texture */ - GArray *glyph_rectangles; - CoglHandle glyph_texture; + /* The current display list that is being built */ + CoglPangoDisplayList *display_list; }; struct _CoglPangoRendererClass @@ -65,19 +61,18 @@ struct _CoglPangoRendererClass PangoRendererClass class_instance; }; -static void -cogl_pango_renderer_glyphs_end (CoglPangoRenderer *priv) +typedef struct _CoglPangoRendererQdata CoglPangoRendererQdata; + +/* An instance of this struct gets attached to each PangoLayout to + cache the VBO and to detect changes to the layout */ +struct _CoglPangoRendererQdata { - if (priv->glyph_rectangles->len > 0) - { - float *rectangles = (float *) priv->glyph_rectangles->data; - cogl_material_set_layer (priv->glyph_material, 0, priv->glyph_texture); - cogl_set_source (priv->glyph_material); - cogl_rectangles_with_texture_coords (rectangles, - priv->glyph_rectangles->len / 8); - g_array_set_size (priv->glyph_rectangles, 0); - } -} + /* The cache of the geometry for the layout */ + CoglPangoDisplayList *display_list; + /* A reference to the first line of the layout. This is just used to + detect changes */ + PangoLayoutLine *first_line; +}; static void cogl_pango_renderer_draw_glyph (CoglPangoRenderer *priv, @@ -86,25 +81,19 @@ cogl_pango_renderer_draw_glyph (CoglPangoRenderer *priv, float y1) { float x2, y2; - float *p; - if (priv->glyph_rectangles->len > 0 - && priv->glyph_texture != cache_value->texture) - cogl_pango_renderer_glyphs_end (priv); - - priv->glyph_texture = cache_value->texture; + g_return_if_fail (priv->display_list != NULL); x2 = x1 + (float) cache_value->draw_width; y2 = y1 + (float) cache_value->draw_height; - g_array_set_size (priv->glyph_rectangles, priv->glyph_rectangles->len + 8); - p = &g_array_index (priv->glyph_rectangles, float, - priv->glyph_rectangles->len - 8); - - *(p++) = x1; *(p++) = y1; - *(p++) = x2; *(p++) = y2; - *(p++) = cache_value->tx1; *(p++) = cache_value->ty1; - *(p++) = cache_value->tx2; *(p++) = cache_value->ty2; + _cogl_pango_display_list_add_texture (priv->display_list, + cache_value->texture, + x1, y1, x2, y2, + cache_value->tx1, + cache_value->ty1, + cache_value->tx2, + cache_value->ty2); } static void cogl_pango_renderer_finalize (GObject *object); @@ -143,32 +132,17 @@ cogl_pango_renderer_init (CoglPangoRenderer *priv) * RGB channels are defined as (0, 0, 0) we don't want to modulate the RGB * channels, instead we want to simply replace them with our solid font * color... - * - * XXX: we could really do with a neat string based way for describing - * combine modes, like: "REPLACE(PREVIOUS[RGB])" - * XXX: potentially materials could have a fuzzy default combine mode - * such that they default to this for component alpha textures? This would - * give the same semantics as the old-style GL_MODULATE mode but sounds a - * bit hacky. */ - cogl_material_set_layer_combine_function ( - priv->glyph_material, - 0, /* layer */ - COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB, - COGL_MATERIAL_LAYER_COMBINE_FUNC_REPLACE); - cogl_material_set_layer_combine_arg_src ( - priv->glyph_material, - 0, /* layer */ - 0, /* arg */ - COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB, - COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS); + cogl_material_set_layer_combine (priv->glyph_material, 0, /* layer */ + "RGB = REPLACE (PREVIOUS)" + "A = MODULATE (PREVIOUS, TEXTURE)", + NULL); priv->solid_material = cogl_material_new (); - priv->glyph_cache = cogl_pango_glyph_cache_new (FALSE); - priv->mipmapped_glyph_cache = cogl_pango_glyph_cache_new (TRUE); - priv->use_mipmapping = FALSE; - priv->glyph_rectangles = g_array_new (FALSE, FALSE, sizeof (float)); + priv->glyph_cache = cogl_pango_glyph_cache_new (); + + _cogl_pango_renderer_set_use_mipmapping (priv, FALSE); } static void @@ -189,9 +163,7 @@ cogl_pango_renderer_finalize (GObject *object) { CoglPangoRenderer *priv = COGL_PANGO_RENDERER (object); - cogl_pango_glyph_cache_free (priv->mipmapped_glyph_cache); cogl_pango_glyph_cache_free (priv->glyph_cache); - g_array_free (priv->glyph_rectangles, TRUE); G_OBJECT_CLASS (cogl_pango_renderer_parent_class)->finalize (object); } @@ -213,6 +185,27 @@ cogl_pango_get_renderer_from_context (PangoContext *context) return COGL_PANGO_RENDERER (renderer); } +static GQuark +cogl_pango_render_get_qdata_key (void) +{ + static GQuark key = 0; + + if (G_UNLIKELY (key == 0)) + key = g_quark_from_static_string ("CoglPangoDisplayList"); + + return key; +} + +static void +cogl_pango_render_qdata_destroy (CoglPangoRendererQdata *qdata) +{ + if (qdata->display_list) + _cogl_pango_display_list_free (qdata->display_list); + if (qdata->first_line) + pango_layout_line_unref (qdata->first_line); + g_slice_free (CoglPangoRendererQdata, qdata); +} + /** * cogl_pango_render_layout_subpixel: * @layout: a #PangoLayout @@ -232,17 +225,67 @@ cogl_pango_render_layout_subpixel (PangoLayout *layout, const CoglColor *color, int flags) { - PangoContext *context; - CoglPangoRenderer *priv; + PangoContext *context; + CoglPangoRenderer *priv; + CoglPangoRendererQdata *qdata; context = pango_layout_get_context (layout); priv = cogl_pango_get_renderer_from_context (context); if (G_UNLIKELY (!priv)) return; - priv->color = *color; + qdata = g_object_get_qdata (G_OBJECT (layout), + cogl_pango_render_get_qdata_key ()); - pango_renderer_draw_layout (PANGO_RENDERER (priv), layout, x, y); + if (qdata == NULL) + { + qdata = g_slice_new0 (CoglPangoRendererQdata); + g_object_set_qdata_full (G_OBJECT (layout), + cogl_pango_render_get_qdata_key (), + qdata, + (GDestroyNotify) + cogl_pango_render_qdata_destroy); + } + + /* Check if the layout has changed since the last build of the + display list. This trick was suggested by Behdad Esfahbod here: + http://mail.gnome.org/archives/gtk-i18n-list/2009-May/msg00019.html */ + if (qdata->display_list && qdata->first_line + && qdata->first_line->layout != layout) + { + _cogl_pango_display_list_free (qdata->display_list); + qdata->display_list = NULL; + } + + if (qdata->display_list == NULL) + { + qdata->display_list = _cogl_pango_display_list_new (); + + priv->color = *color; + priv->display_list = qdata->display_list; + pango_renderer_draw_layout (PANGO_RENDERER (priv), layout, 0, 0); + priv->display_list = NULL; + } + + cogl_push_matrix (); + cogl_translate (x / (gfloat) PANGO_SCALE, y / (gfloat) PANGO_SCALE, 0); + _cogl_pango_display_list_render (qdata->display_list, + priv->glyph_material, + priv->solid_material); + cogl_pop_matrix (); + + /* Keep a reference to the first line of the layout so we can detect + changes */ + if (qdata->first_line) + { + pango_layout_line_unref (qdata->first_line); + qdata->first_line = NULL; + } + if (pango_layout_get_line_count (layout) > 0) + { + qdata->first_line = pango_layout_get_line (layout, 0); + pango_layout_line_ref (qdata->first_line); + } } /** @@ -296,29 +339,50 @@ cogl_pango_render_layout_line (PangoLayoutLine *line, if (G_UNLIKELY (!priv)) return; + priv->display_list = _cogl_pango_display_list_new (); priv->color = *color; pango_renderer_draw_layout_line (PANGO_RENDERER (priv), line, x, y); + + cogl_material_set_color (priv->glyph_material, color); + cogl_material_set_color (priv->solid_material, color); + _cogl_pango_display_list_render (priv->display_list, + priv->glyph_material, + priv->solid_material); + + _cogl_pango_display_list_free (priv->display_list); + priv->display_list = NULL; } void _cogl_pango_renderer_clear_glyph_cache (CoglPangoRenderer *renderer) { cogl_pango_glyph_cache_clear (renderer->glyph_cache); - cogl_pango_glyph_cache_clear (renderer->mipmapped_glyph_cache); } void _cogl_pango_renderer_set_use_mipmapping (CoglPangoRenderer *renderer, - gboolean value) + gboolean value) { - renderer->use_mipmapping = value; + if (value) + cogl_material_set_layer_filters (renderer->glyph_material, 0, + COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR, + COGL_MATERIAL_FILTER_LINEAR); + else + cogl_material_set_layer_filters (renderer->glyph_material, 0, + COGL_MATERIAL_FILTER_LINEAR, + COGL_MATERIAL_FILTER_LINEAR); } gboolean _cogl_pango_renderer_get_use_mipmapping (CoglPangoRenderer *renderer) { - return renderer->use_mipmapping; + const GList *layers = cogl_material_get_layers (renderer->glyph_material); + + g_return_val_if_fail (layers != NULL, FALSE); + + return (cogl_material_layer_get_min_filter (layers->data) + == COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR); } static CoglPangoGlyphCacheValue * @@ -328,12 +392,8 @@ cogl_pango_renderer_get_cached_glyph (PangoRenderer *renderer, { CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer); CoglPangoGlyphCacheValue *value; - CoglPangoGlyphCache *glyph_cache; - glyph_cache = priv->use_mipmapping ? priv->mipmapped_glyph_cache - : priv->glyph_cache; - - value = cogl_pango_glyph_cache_lookup (glyph_cache, font, glyph); + value = cogl_pango_glyph_cache_lookup (priv->glyph_cache, font, glyph); if (value == NULL) { cairo_surface_t *surface; @@ -365,7 +425,7 @@ cogl_pango_renderer_get_cached_glyph (PangoRenderer *renderer, /* Copy the glyph to the cache */ value = - cogl_pango_glyph_cache_set (glyph_cache, font, glyph, + cogl_pango_glyph_cache_set (priv->glyph_cache, font, glyph, cairo_image_surface_get_data (surface), cairo_image_surface_get_width (surface), cairo_image_surface_get_height (surface), @@ -444,8 +504,7 @@ cogl_pango_renderer_set_color_for_part (PangoRenderer *renderer, else color = priv->color; - cogl_material_set_color (priv->solid_material, &color); - cogl_material_set_color (priv->glyph_material, &color); + _cogl_pango_display_list_set_color (priv->display_list, &color); } static void @@ -457,12 +516,13 @@ cogl_pango_renderer_draw_box (PangoRenderer *renderer, { CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer); - cogl_set_source (priv->solid_material); - cogl_path_rectangle (x, - y - height, - x + width, - y); - cogl_path_stroke (); + g_return_if_fail (priv->display_list != NULL); + + _cogl_pango_display_list_add_rectangle (priv->display_list, + x, + y - height, + x + width, + y); } static void @@ -500,6 +560,8 @@ cogl_pango_renderer_draw_rectangle (PangoRenderer *renderer, CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer); float x1, x2, y1, y2; + g_return_if_fail (priv->display_list != NULL); + cogl_pango_renderer_set_color_for_part (renderer, part); cogl_pango_renderer_get_device_units (renderer, @@ -509,8 +571,8 @@ cogl_pango_renderer_draw_rectangle (PangoRenderer *renderer, x + width, y + height, &x2, &y2); - cogl_set_source (priv->solid_material); - cogl_rectangle (x1, y1, x2, y2); + _cogl_pango_display_list_add_rectangle (priv->display_list, + x1, y1, x2, y2); } static void @@ -526,6 +588,8 @@ cogl_pango_renderer_draw_trapezoid (PangoRenderer *renderer, CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer); float points[8]; + g_return_if_fail (priv->display_list != NULL); + points[0] = (x11); points[1] = (y1); points[2] = (x12); @@ -537,9 +601,13 @@ cogl_pango_renderer_draw_trapezoid (PangoRenderer *renderer, cogl_pango_renderer_set_color_for_part (renderer, part); - cogl_set_source (priv->solid_material); - cogl_path_polygon (points, 4); - cogl_path_fill (); + _cogl_pango_display_list_add_trapezoid (priv->display_list, + y1, + x11, + x21, + y2, + x12, + x22); } static void @@ -570,8 +638,6 @@ cogl_pango_renderer_draw_glyphs (PangoRenderer *renderer, { PangoFontMetrics *metrics; - cogl_pango_renderer_glyphs_end (priv); - if (font == NULL || (metrics = pango_font_get_metrics (font, NULL)) == NULL) { @@ -603,15 +669,11 @@ cogl_pango_renderer_draw_glyphs (PangoRenderer *renderer, gi->glyph); if (cache_value == NULL) - { - cogl_pango_renderer_glyphs_end (priv); - - cogl_pango_renderer_draw_box (renderer, - x, - y, - PANGO_UNKNOWN_GLYPH_WIDTH, - PANGO_UNKNOWN_GLYPH_HEIGHT); - } + cogl_pango_renderer_draw_box (renderer, + x, + y, + PANGO_UNKNOWN_GLYPH_WIDTH, + PANGO_UNKNOWN_GLYPH_HEIGHT); else { float width, height; @@ -628,6 +690,4 @@ cogl_pango_renderer_draw_glyphs (PangoRenderer *renderer, xi += gi->geometry.width; } - - cogl_pango_renderer_glyphs_end (priv); } diff --git a/clutter/sdl/clutter-stage-sdl.c b/clutter/sdl/clutter-stage-sdl.c index 17a8bd0eb..e1cf387ab 100644 --- a/clutter/sdl/clutter-stage-sdl.c +++ b/clutter/sdl/clutter-stage-sdl.c @@ -103,9 +103,9 @@ clutter_stage_sdl_realize (ClutterActor *actor) static void clutter_stage_sdl_get_preferred_width (ClutterActor *self, - ClutterUnit for_height, - ClutterUnit *min_width_p, - ClutterUnit *natural_width_p) + gfloat for_height, + gfloat *min_width_p, + gfloat *natural_width_p) { ClutterStageSDL *stage_sdl = CLUTTER_STAGE_SDL (self); @@ -118,9 +118,9 @@ clutter_stage_sdl_get_preferred_width (ClutterActor *self, static void clutter_stage_sdl_get_preferred_height (ClutterActor *self, - ClutterUnit for_width, - ClutterUnit *min_height_p, - ClutterUnit *natural_height_p) + gfloat for_width, + gfloat *min_height_p, + gfloat *natural_height_p) { ClutterStageSDL *stage_sdl = CLUTTER_STAGE_SDL (self); @@ -132,9 +132,9 @@ clutter_stage_sdl_get_preferred_height (ClutterActor *self, } static void -clutter_stage_sdl_allocate (ClutterActor *self, - const ClutterActorBox *box, - gboolean origin_changed) +clutter_stage_sdl_allocate (ClutterActor *self, + const ClutterActorBox *box, + ClutterAllocationFlags flags) { ClutterStageSDL *stage_sdl = CLUTTER_STAGE_SDL (self); gint new_width, new_height; @@ -162,7 +162,7 @@ clutter_stage_sdl_allocate (ClutterActor *self, } parent_class = CLUTTER_ACTOR_CLASS (clutter_stage_sdl_parent_class); - parent_class->allocate (self, box, origin_changed); + parent_class->allocate (self, box, flags); } static void @@ -199,8 +199,6 @@ clutter_stage_sdl_dispose (GObject *gobject) { ClutterStageSDL *stage_sdl = CLUTTER_STAGE_SDL (gobject); - clutter_actor_unrealize (CLUTTER_ACTOR (stage_sdl)); - G_OBJECT_CLASS (clutter_stage_sdl_parent_class)->dispose (gobject); } diff --git a/clutter/win32/clutter-event-win32.c b/clutter/win32/clutter-event-win32.c index 9c4a3c943..0ef57f7be 100644 --- a/clutter/win32/clutter-event-win32.c +++ b/clutter/win32/clutter-event-win32.c @@ -359,7 +359,7 @@ message_translate (ClutterBackend *backend, { WORD new_width = LOWORD (msg->lParam); WORD new_height = HIWORD (msg->lParam); - guint old_width, old_height; + gfloat old_width, old_height; clutter_actor_get_size (CLUTTER_ACTOR (stage), &old_width, &old_height); diff --git a/clutter/win32/clutter-stage-win32.c b/clutter/win32/clutter-stage-win32.c index 5ce8a16c6..0b45a49f5 100644 --- a/clutter/win32/clutter-stage-win32.c +++ b/clutter/win32/clutter-stage-win32.c @@ -81,9 +81,9 @@ clutter_stage_win32_hide (ClutterActor *actor) static void clutter_stage_win32_get_preferred_width (ClutterActor *self, - ClutterUnit for_height, - ClutterUnit *min_width_p, - ClutterUnit *natural_width_p) + gfloat for_height, + gfloat *min_width_p, + gfloat *natural_width_p) { ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (self); int width; @@ -105,9 +105,9 @@ clutter_stage_win32_get_preferred_width (ClutterActor *self, static void clutter_stage_win32_get_preferred_height (ClutterActor *self, - ClutterUnit for_width, - ClutterUnit *min_height_p, - ClutterUnit *natural_height_p) + gfloat for_width, + gfloat *min_height_p, + gfloat *natural_height_p) { ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (self); int height; @@ -187,18 +187,18 @@ _clutter_stage_win32_get_min_max_info (ClutterStageWin32 *stage_win32, } static void -clutter_stage_win32_allocate (ClutterActor *self, - const ClutterActorBox *box, - gboolean origin_changed) +clutter_stage_win32_allocate (ClutterActor *self, + const ClutterActorBox *box, + ClutterAllocationFlags flags) { ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (self); gint new_width, new_height; - new_width = ABS (CLUTTER_UNITS_TO_INT (box->x2 - box->x1)); - new_height = ABS (CLUTTER_UNITS_TO_INT (box->y2 - box->y1)); + new_width = ABS (box->x2 - box->x1); + new_height = ABS (box->y2 - box->y1); - if (new_width != stage_win32->win_width - || new_height != stage_win32->win_height) + if (new_width != stage_win32->win_width || + new_height != stage_win32->win_height) { /* Ignore size requests if we are in full screen mode */ if ((stage_win32->state & CLUTTER_STAGE_STATE_FULLSCREEN) == 0) @@ -226,7 +226,7 @@ clutter_stage_win32_allocate (ClutterActor *self, } CLUTTER_ACTOR_CLASS (clutter_stage_win32_parent_class) - ->allocate (self, box, origin_changed); + ->allocate (self, box, flags); } static void @@ -574,10 +574,8 @@ clutter_stage_win32_unrealize (ClutterActor *actor) CLUTTER_NOTE (BACKEND, "Unrealizing stage"); - /* Chain up so all children get unrealized, needed to move texture - * data across contexts - */ - CLUTTER_ACTOR_CLASS (clutter_stage_win32_parent_class)->unrealize (actor); + if (CLUTTER_ACTOR_CLASS (clutter_stage_win32_parent_class)->unrealize != NULL) + CLUTTER_ACTOR_CLASS (clutter_stage_win32_parent_class)->unrealize (actor); if (stage_win32->client_dc) { @@ -602,9 +600,6 @@ clutter_stage_win32_dispose (GObject *gobject) { ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (gobject); - if (stage_win32->hwnd) - clutter_actor_unrealize (CLUTTER_ACTOR (gobject)); - G_OBJECT_CLASS (clutter_stage_win32_parent_class)->dispose (gobject); } @@ -749,6 +744,12 @@ clutter_win32_set_stage_foreign (ClutterStage *stage, impl = _clutter_stage_get_window (stage); stage_win32 = CLUTTER_STAGE_WIN32 (impl); + /* FIXME this needs updating to use _clutter_actor_rerealize(), + * see the analogous code in x11 backend. Probably best if + * win32 maintainer does it so they can be sure it compiles + * and works. + */ + clutter_actor_unrealize (actor); if (!GetClientRect (hwnd, &client_rect)) @@ -779,8 +780,8 @@ clutter_win32_set_stage_foreign (ClutterStage *stage, void clutter_stage_win32_map (ClutterStageWin32 *stage_win32) { - CLUTTER_ACTOR_SET_FLAGS (stage_win32, CLUTTER_ACTOR_MAPPED); - CLUTTER_ACTOR_SET_FLAGS (stage_win32->wrapper, CLUTTER_ACTOR_MAPPED); + clutter_actor_map (CLUTTER_ACTOR (stage_win32)); + clutter_actor_map (CLUTTER_ACTOR (stage_win32->wrapper)); clutter_actor_queue_relayout (CLUTTER_ACTOR (stage_win32->wrapper)); } @@ -788,6 +789,6 @@ clutter_stage_win32_map (ClutterStageWin32 *stage_win32) void clutter_stage_win32_unmap (ClutterStageWin32 *stage_win32) { - CLUTTER_ACTOR_UNSET_FLAGS (stage_win32, CLUTTER_ACTOR_MAPPED); - CLUTTER_ACTOR_UNSET_FLAGS (stage_win32->wrapper, CLUTTER_ACTOR_MAPPED); + clutter_actor_unmap (CLUTTER_ACTOR (stage_win32)); + clutter_actor_unmap (CLUTTER_ACTOR (stage_win32->wrapper)); } diff --git a/clutter/x11/clutter-backend-x11.c b/clutter/x11/clutter-backend-x11.c index b8d17ab72..6580c5dc7 100644 --- a/clutter/x11/clutter-backend-x11.c +++ b/clutter/x11/clutter-backend-x11.c @@ -39,8 +39,13 @@ #include "clutter-backend-x11.h" #include "clutter-stage-x11.h" #include "clutter-x11.h" + #include +#ifdef HAVE_XINPUT +#include +#endif + #include "../clutter-event.h" #include "../clutter-main.h" #include "../clutter-debug.h" @@ -53,15 +58,18 @@ G_DEFINE_TYPE (ClutterBackendX11, clutter_backend_x11, CLUTTER_TYPE_BACKEND); struct _ClutterX11XInputDevice { ClutterInputDevice device; -#ifdef USE_XINPUT + +#ifdef HAVE_XINPUT XDevice *xdevice; XEventClass xevent_list[5]; /* MAX 5 event types */ int num_events; #endif - ClutterX11InputDeviceType type; /* FIXME: generic to ClutterInputDevice? */ + + /* FIXME: generic to ClutterInputDevice? */ + ClutterX11InputDeviceType type; }; -#ifdef USE_XINPUT +#ifdef HAVE_XINPUT void _clutter_x11_register_xinput (); #endif @@ -185,7 +193,7 @@ clutter_backend_x11_post_parse (ClutterBackend *backend, clutter_backend_set_resolution (backend, dpi); -#ifdef USE_XINPUT +#ifdef HAVE_XINPUT _clutter_x11_register_xinput (); #endif @@ -630,11 +638,10 @@ clutter_x11_remove_filter (ClutterX11FilterFunc func, } } -#ifdef USE_XINPUT - void _clutter_x11_register_xinput () { +#ifdef HAVE_XINPUT XDeviceInfo *xdevices = NULL; XDeviceInfo *info = NULL; @@ -669,7 +676,15 @@ _clutter_x11_register_xinput () backend_singleton->have_xinput = TRUE; - ext = XGetExtensionVersion(backend_singleton->xdpy, INAME); +#if defined(HAVE_XQUERY_INPUT_VERSION) + ext = XQueryInputVersion (backend_singleton->xdpy, XI_2_Major, XI_2_Minor); +#elif defined(HAVE_XGET_EXTENSION_VERSION) + ext = XGetExtensionVersion (backend_singleton->xdpy, INAME); +#else + g_critical ("XInput does not have XGetExtensionVersion nor " + "XQueryInputVersion"); + return; +#endif if (!ext || (ext == (XExtensionVersion*) NoSuchExtension)) { @@ -807,6 +822,7 @@ _clutter_x11_register_xinput () g_slist_free (context->input_devices); context->input_devices = NULL; } +#endif /* HAVE_XINPUT */ } void @@ -818,6 +834,7 @@ _clutter_x11_unregister_xinput () void _clutter_x11_select_events (Window xwin) { +#ifdef HAVE_XINPUT GSList *list_it; ClutterX11XInputDevice *device = NULL; @@ -842,11 +859,13 @@ _clutter_x11_select_events (Window xwin) device->xevent_list, device->num_events); } +#endif /* HAVE_XINPUT */ } ClutterX11XInputDevice * _clutter_x11_get_device_for_xid (XID id) { +#ifdef HAVE_XINPUT GSList *list_it; ClutterX11XInputDevice *device = NULL; ClutterMainContext *context; @@ -869,17 +888,18 @@ _clutter_x11_get_device_for_xid (XID id) return device; } +#endif /* HAVE_XINPUT */ + return NULL; } -#endif /* FIXME: This nasty little func needs moving elsewhere.. */ -GSList* +GSList * clutter_x11_get_input_devices (void) { +#ifdef HAVE_XINPUT ClutterMainContext *context; -#ifdef USE_XINPUT if (!backend_singleton) { g_critical ("X11 backend has not been initialised"); @@ -889,9 +909,9 @@ clutter_x11_get_input_devices (void) context = clutter_context_get_default (); return context->input_devices; -#else +#else /* !HAVE_XINPUT */ return NULL; -#endif +#endif /* HAVE_XINPUT */ } /** @@ -923,7 +943,7 @@ clutter_x11_get_input_device_type (ClutterX11XInputDevice *device) gboolean clutter_x11_has_xinput (void) { -#ifdef USE_XINPUT +#ifdef HAVE_XINPUT if (!backend_singleton) { g_critical ("X11 backend has not been initialised"); @@ -939,9 +959,9 @@ clutter_x11_has_xinput (void) gboolean clutter_x11_has_composite_extension (void) { - static gboolean have_composite = FALSE, done_check = FALSE; - int error = 0, event = 0; - Display *dpy; + static gboolean have_composite = FALSE, done_check = FALSE; + int error = 0, event = 0; + Display *dpy; if (done_check) return have_composite; @@ -969,3 +989,17 @@ clutter_x11_has_composite_extension (void) return have_composite; } +XVisualInfo * +clutter_backend_x11_get_visual_info (ClutterBackendX11 *backend_x11, + gboolean for_offscreen) +{ + ClutterBackendX11Class *klass; + + g_return_val_if_fail (CLUTTER_IS_BACKEND_X11 (backend_x11), NULL); + + klass = CLUTTER_BACKEND_X11_GET_CLASS (backend_x11); + if (klass->get_visual_info) + return klass->get_visual_info (backend_x11, for_offscreen); + + return NULL; +} diff --git a/clutter/x11/clutter-backend-x11.h b/clutter/x11/clutter-backend-x11.h index 3b51e12fa..04b36cfc5 100644 --- a/clutter/x11/clutter-backend-x11.h +++ b/clutter/x11/clutter-backend-x11.h @@ -28,10 +28,6 @@ #include #include -#ifdef USE_XINPUT -#include -#endif - #include "clutter-x11.h" G_BEGIN_DECLS @@ -79,10 +75,8 @@ struct _ClutterBackendX11 Atom atom_NET_WM_NAME; Atom atom_UTF8_STRING; -#ifdef USE_XINPUT - int event_types[CLUTTER_X11_XINPUT_LAST_EVENT]; - gboolean have_xinput; -#endif + int event_types[CLUTTER_X11_XINPUT_LAST_EVENT]; + gboolean have_xinput; Time last_event_time; }; @@ -90,6 +84,9 @@ struct _ClutterBackendX11 struct _ClutterBackendX11Class { ClutterBackendClass parent_class; + + XVisualInfo *(* get_visual_info) (ClutterBackendX11 *backend, + gboolean for_offscreen); }; void _clutter_backend_x11_events_init (ClutterBackend *backend); @@ -120,7 +117,10 @@ clutter_backend_x11_add_options (ClutterBackend *backend, ClutterFeatureFlags clutter_backend_x11_get_features (ClutterBackend *backend); -#ifdef USE_XINPUT +XVisualInfo * +clutter_backend_x11_get_visual_info (ClutterBackendX11 *backend_x11, + gboolean for_offscreen); + void _clutter_x11_register_xinput (void); @@ -129,7 +129,6 @@ _clutter_x11_unregister_xinput (void); ClutterX11XInputDevice * _clutter_x11_get_device_for_xid (XID id); -#endif void _clutter_x11_select_events (Window xwin); diff --git a/clutter/x11/clutter-event-x11.c b/clutter/x11/clutter-event-x11.c index 84cba9ff8..e2c478aed 100644 --- a/clutter/x11/clutter-event-x11.c +++ b/clutter/x11/clutter-event-x11.c @@ -43,7 +43,7 @@ #include -#ifdef USE_XINPUT +#ifdef HAVE_XINPUT #include #endif @@ -263,7 +263,7 @@ set_user_time (ClutterBackendX11 *backend_x11, } } -#if 0 /* See XInput keyboard comment below USE_XINPUT */ +#if 0 /* See XInput keyboard comment below HAVE_XINPUT */ static void convert_xdevicekey_to_xkey (XDeviceKeyEvent *xkev, XEvent *xevent) { @@ -282,7 +282,7 @@ convert_xdevicekey_to_xkey (XDeviceKeyEvent *xkev, XEvent *xevent) xevent->xkey.keycode = xkev->keycode; xevent->xkey.same_screen = xkev->same_screen; } -#endif /* USE_XINPUT */ +#endif /* HAVE_XINPUT */ static void translate_key_event (ClutterBackend *backend, @@ -479,15 +479,16 @@ event_translate (ClutterBackend *backend, xevent->xconfigure.width, xevent->xconfigure.height); - clutter_actor_set_size (CLUTTER_ACTOR (stage), - xevent->xconfigure.width, - xevent->xconfigure.height); + stage_x11->xwin_width = xevent->xconfigure.width; + stage_x11->xwin_height = xevent->xconfigure.height; /* the resize process is complete, so we can ask the stage * to set up the GL viewport with the new size */ CLUTTER_SET_PRIVATE_FLAGS (CLUTTER_ACTOR (stage_x11->wrapper), CLUTTER_ACTOR_SYNC_MATRICES); + + clutter_actor_queue_relayout (CLUTTER_ACTOR (stage_x11->wrapper)); } res = FALSE; break; @@ -552,12 +553,10 @@ event_translate (ClutterBackend *backend, break; case MapNotify: - clutter_stage_x11_map (stage_x11); res = FALSE; break; case UnmapNotify: - clutter_stage_x11_unmap (stage_x11); res = FALSE; break; @@ -738,7 +737,7 @@ event_translate (ClutterBackend *backend, } else { /* XInput fun.. Needs clean up. */ -#ifdef USE_XINPUT +#ifdef HAVE_XINPUT int *ev_types = backend_x11->event_types; CLUTTER_NOTE (EVENT, "XInput event type: %d", xevent->type); @@ -799,8 +798,7 @@ event_translate (ClutterBackend *backend, xbev->button == 6 || xbev->button == 7) { - res = FALSE; - goto out; + return FALSE; } event->button.type = event->type = CLUTTER_BUTTON_RELEASE; @@ -863,7 +861,7 @@ event_translate (ClutterBackend *backend, } #endif else -#endif +#endif /* HAVE_XINPUT */ { CLUTTER_NOTE (EVENT, "Uknown Event"); res = FALSE; @@ -871,7 +869,6 @@ event_translate (ClutterBackend *backend, } } - out: return res; } diff --git a/clutter/x11/clutter-stage-x11.c b/clutter/x11/clutter-stage-x11.c index aa091710f..e49457450 100644 --- a/clutter/x11/clutter-stage-x11.c +++ b/clutter/x11/clutter-stage-x11.c @@ -85,7 +85,9 @@ send_wmspec_change_state (ClutterBackendX11 *backend_x11, } void -clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11) +clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11, + gint new_width, + gint new_height) { gboolean resize; @@ -94,16 +96,23 @@ clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11) if (stage_x11->xwin != None && stage_x11->is_foreign_xwin == FALSE) { XSizeHints *size_hints; - ClutterUnit min_width, min_height; + gfloat min_width, min_height; size_hints = XAllocSizeHints(); - clutter_actor_get_preferred_width (CLUTTER_ACTOR (stage_x11), - -1, - &min_width, NULL); - clutter_actor_get_preferred_height (CLUTTER_ACTOR (stage_x11), - min_width, - &min_height, NULL); + if (new_width < 0) + clutter_actor_get_preferred_width (CLUTTER_ACTOR (stage_x11), + -1, + &min_width, NULL); + else + min_width = new_width; + + if (new_height < 0) + clutter_actor_get_preferred_height (CLUTTER_ACTOR (stage_x11), + min_width, + &min_height, NULL); + else + min_height = new_height; size_hints->flags = 0; @@ -111,8 +120,8 @@ clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11) restrictions on the window size */ if (!stage_x11->fullscreen_on_map) { - size_hints->min_width = CLUTTER_UNITS_TO_DEVICE (min_width); - size_hints->min_height = CLUTTER_UNITS_TO_DEVICE (min_height); + size_hints->min_width = (int) min_width; + size_hints->min_height = (int) min_height; size_hints->flags = PMinSize; if (!resize) @@ -129,34 +138,6 @@ clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11) } } -static void -clutter_stage_x11_show (ClutterActor *actor) -{ - ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor); - - CLUTTER_ACTOR_CLASS (clutter_stage_x11_parent_class)->show (actor); - - if (stage_x11->xwin) - { - /* Fire off a redraw to avoid flicker on first map. - * Appears not to work perfectly on intel drivers at least. - */ - clutter_redraw (stage_x11->wrapper); - - XSync (stage_x11->xdpy, FALSE); - XMapWindow (stage_x11->xdpy, stage_x11->xwin); - } -} - -static void -clutter_stage_x11_hide (ClutterActor *actor) -{ - ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor); - - if (stage_x11->xwin) - XUnmapWindow (stage_x11->xdpy, stage_x11->xwin); -} - void clutter_stage_x11_set_wm_protocols (ClutterStageX11 *stage_x11) { @@ -172,9 +153,9 @@ clutter_stage_x11_set_wm_protocols (ClutterStageX11 *stage_x11) static void clutter_stage_x11_get_preferred_width (ClutterActor *self, - ClutterUnit for_height, - ClutterUnit *min_width_p, - ClutterUnit *natural_width_p) + gfloat for_height, + gfloat *min_width_p, + gfloat *natural_width_p) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (self); gboolean resize; @@ -186,10 +167,10 @@ clutter_stage_x11_get_preferred_width (ClutterActor *self, width = DisplayWidth (stage_x11->xdpy, stage_x11->xscreen); if (min_width_p) - *min_width_p = CLUTTER_UNITS_FROM_DEVICE (width); + *min_width_p = width; if (natural_width_p) - *natural_width_p = CLUTTER_UNITS_FROM_DEVICE (width); + *natural_width_p = width; return; } @@ -198,22 +179,21 @@ clutter_stage_x11_get_preferred_width (ClutterActor *self, if (min_width_p) { - /* FIXME need API to set this */ if (resize) - *min_width_p = CLUTTER_UNITS_FROM_DEVICE (1); + *min_width_p = 1; /* FIXME need API to set this */ else - *min_width_p = CLUTTER_UNITS_FROM_DEVICE (stage_x11->xwin_width); + *min_width_p = stage_x11->xwin_width; } if (natural_width_p) - *natural_width_p = CLUTTER_UNITS_FROM_DEVICE (stage_x11->xwin_width); + *natural_width_p = stage_x11->xwin_width; } static void clutter_stage_x11_get_preferred_height (ClutterActor *self, - ClutterUnit for_width, - ClutterUnit *min_height_p, - ClutterUnit *natural_height_p) + gfloat for_width, + gfloat *min_height_p, + gfloat *natural_height_p) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (self); gboolean resize; @@ -225,10 +205,10 @@ clutter_stage_x11_get_preferred_height (ClutterActor *self, height = DisplayHeight (stage_x11->xdpy, stage_x11->xscreen); if (min_height_p) - *min_height_p = CLUTTER_UNITS_FROM_DEVICE (height); + *min_height_p = height; if (natural_height_p) - *natural_height_p = CLUTTER_UNITS_FROM_DEVICE (height); + *natural_height_p = height; return; } @@ -238,28 +218,26 @@ clutter_stage_x11_get_preferred_height (ClutterActor *self, if (min_height_p) { if (resize) - *min_height_p = CLUTTER_UNITS_FROM_DEVICE (1); /* FIXME need API - * to set this - */ + *min_height_p = 1; /* FIXME need API to set this */ else - *min_height_p = CLUTTER_UNITS_FROM_DEVICE (stage_x11->xwin_height); + *min_height_p = stage_x11->xwin_height; } if (natural_height_p) - *natural_height_p = CLUTTER_UNITS_FROM_DEVICE (stage_x11->xwin_height); + *natural_height_p = stage_x11->xwin_height; } static void -clutter_stage_x11_allocate (ClutterActor *self, - const ClutterActorBox *box, - gboolean origin_changed) +clutter_stage_x11_allocate (ClutterActor *self, + const ClutterActorBox *box, + ClutterAllocationFlags flags) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (self); ClutterActorClass *parent_class; gint new_width, new_height; - new_width = ABS (CLUTTER_UNITS_TO_INT (box->x2 - box->x1)); - new_height = ABS (CLUTTER_UNITS_TO_INT (box->y2 - box->y1)); + new_width = ABS ((int) (box->x2 - box->x1)); + new_height = ABS ((int) (box->y2 - box->y1)); if (new_width == 0 || new_height == 0) { @@ -271,6 +249,10 @@ clutter_stage_x11_allocate (ClutterActor *self, new_height = 1; } + CLUTTER_NOTE (BACKEND, "New allocation received: (%d, %d)", + new_width, + new_height); + if (new_width != stage_x11->xwin_width || new_height != stage_x11->xwin_height) { @@ -292,19 +274,18 @@ clutter_stage_x11_allocate (ClutterActor *self, stage_x11->xwin_height); } - clutter_stage_x11_fix_window_size (stage_x11); + clutter_stage_x11_fix_window_size (stage_x11, new_width, new_height); if (stage_x11->xpixmap != None) { /* Need to recreate to resize */ - clutter_actor_unrealize (self); - clutter_actor_realize (self); + _clutter_actor_rerealize (self, NULL, NULL); } } /* chain up to fill in actor->priv->allocation */ parent_class = CLUTTER_ACTOR_CLASS (clutter_stage_x11_parent_class); - parent_class->allocate (self, box, origin_changed); + parent_class->allocate (self, box, flags); } static inline void @@ -444,7 +425,7 @@ clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window, the maximum and minimum window hints. Otherwise metacity will honour the restrictions and not fullscreen correctly. */ - clutter_stage_x11_fix_window_size (stage_x11); + clutter_stage_x11_fix_window_size (stage_x11, -1, -1); send_wmspec_change_state (backend_x11, stage_x11->xwin, backend_x11->atom_NET_WM_STATE_FULLSCREEN, @@ -474,7 +455,7 @@ clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window, /* Fix the window size to restore the minimum/maximum restriction */ - clutter_stage_x11_fix_window_size (stage_x11); + clutter_stage_x11_fix_window_size (stage_x11, -1, -1); } } } @@ -507,7 +488,104 @@ clutter_stage_x11_set_user_resizable (ClutterStageWindow *stage_window, { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); - clutter_stage_x11_fix_window_size (stage_x11); + clutter_stage_x11_fix_window_size (stage_x11, -1, -1); +} + +#define STAGE_X11_IS_MAPPED(s) ((((ClutterStageX11 *) (s))->wm_state & STAGE_X11_WITHDRAWN) == 0) + +static void +update_wm_hints (ClutterStageX11 *stage_x11) +{ + XWMHints wm_hints; + + if (stage_x11->wm_state & STAGE_X11_WITHDRAWN) + return; + + wm_hints.flags = StateHint; + wm_hints.initial_state = NormalState; + + XSetWMHints (stage_x11->xdpy, stage_x11->xwin, &wm_hints); +} + +static void +set_stage_state (ClutterStageX11 *stage_x11, + ClutterStageX11State unset_flags, + ClutterStageX11State set_flags) +{ + ClutterStageX11State new_stage_state, old_stage_state; + + old_stage_state = stage_x11->wm_state; + + new_stage_state = old_stage_state; + new_stage_state |= set_flags; + new_stage_state &= ~unset_flags; + + if (new_stage_state == old_stage_state) + return; + + stage_x11->wm_state = new_stage_state; +} + +static void +clutter_stage_x11_show (ClutterStageWindow *stage_window, + gboolean do_raise) +{ + ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); + + if (stage_x11->xwin != None) + { + if (do_raise) + XRaiseWindow (stage_x11->xdpy, stage_x11->xwin); + + if (!STAGE_X11_IS_MAPPED (stage_x11)) + { + CLUTTER_NOTE (BACKEND, "Mapping stage[%lu] (%d, %d)", + (unsigned long) stage_x11->xwin, + stage_x11->xwin_width, + stage_x11->xwin_height); + + update_wm_hints (stage_x11); + + if (stage_x11->fullscreen_on_map) + clutter_stage_x11_set_fullscreen (stage_window, TRUE); + else + clutter_stage_x11_set_fullscreen (stage_window, FALSE); + + set_stage_state (stage_x11, STAGE_X11_WITHDRAWN, 0); + + clutter_stage_ensure_viewport (CLUTTER_STAGE (stage_x11->wrapper)); + } + + g_assert (STAGE_X11_IS_MAPPED (stage_x11)); + + XMapWindow (stage_x11->xdpy, stage_x11->xwin); + + clutter_actor_map (CLUTTER_ACTOR (stage_x11)); + clutter_actor_map (CLUTTER_ACTOR (stage_x11->wrapper)); + + clutter_actor_queue_relayout (CLUTTER_ACTOR (stage_x11->wrapper)); + } +} + +static void +clutter_stage_x11_hide (ClutterStageWindow *stage_window) +{ + ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); + + if (stage_x11->xwin != None) + { + if (STAGE_X11_IS_MAPPED (stage_x11)) + set_stage_state (stage_x11, 0, STAGE_X11_WITHDRAWN); + + g_assert (!STAGE_X11_IS_MAPPED (stage_x11)); + + clutter_actor_unmap (CLUTTER_ACTOR (stage_x11)); + clutter_actor_unmap (CLUTTER_ACTOR (stage_x11->wrapper)); + + XWithdrawWindow (stage_x11->xdpy, + stage_x11->xwin, + 0); + } } static ClutterActor * @@ -529,11 +607,6 @@ clutter_stage_x11_finalize (GObject *gobject) static void clutter_stage_x11_dispose (GObject *gobject) { - ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (gobject); - - if (stage_x11->xwin) - clutter_actor_unrealize (CLUTTER_ACTOR (stage_x11)); - G_OBJECT_CLASS (clutter_stage_x11_parent_class)->dispose (gobject); } @@ -547,8 +620,6 @@ clutter_stage_x11_class_init (ClutterStageX11Class *klass) gobject_class->dispose = clutter_stage_x11_dispose; actor_class->realize = clutter_stage_x11_realize; - actor_class->show = clutter_stage_x11_show; - actor_class->hide = clutter_stage_x11_hide; actor_class->get_preferred_width = clutter_stage_x11_get_preferred_width; actor_class->get_preferred_height = clutter_stage_x11_get_preferred_height; @@ -567,6 +638,8 @@ clutter_stage_x11_init (ClutterStageX11 *stage) stage->xwin_height = 480; stage->xvisinfo = None; + stage->wm_state = STAGE_X11_WITHDRAWN; + stage->is_foreign_xwin = FALSE; stage->fullscreen_on_map = FALSE; stage->is_cursor_visible = TRUE; @@ -586,6 +659,8 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface) iface->set_fullscreen = clutter_stage_x11_set_fullscreen; iface->set_cursor_visible = clutter_stage_x11_set_cursor_visible; iface->set_user_resizable = clutter_stage_x11_set_user_resizable; + iface->show = clutter_stage_x11_show; + iface->hide = clutter_stage_x11_hide; } /** @@ -662,13 +737,56 @@ XVisualInfo * clutter_x11_get_stage_visual (ClutterStage *stage) { ClutterStageWindow *impl; + ClutterStageX11 *stage_x11; + gboolean is_offscreen = FALSE; g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL); + g_object_get (G_OBJECT (stage), "offscreen", &is_offscreen, NULL); + impl = _clutter_stage_get_window (stage); g_assert (CLUTTER_IS_STAGE_X11 (impl)); - return CLUTTER_STAGE_X11 (impl)->xvisinfo; + stage_x11 = CLUTTER_STAGE_X11 (impl); + + if (stage_x11->xvisinfo == NULL) + { + ClutterBackendX11 *backend_x11 = stage_x11->backend; + + stage_x11->xvisinfo = + clutter_backend_x11_get_visual_info (backend_x11, is_offscreen); + } + + return stage_x11->xvisinfo; +} + +typedef struct { + ClutterStageX11 *stage_x11; + ClutterGeometry geom; + Window xwindow; +} ForeignWindowData; + +static void +set_foreign_window_callback (ClutterActor *actor, + void *data) +{ + ForeignWindowData *fwd = data; + + CLUTTER_NOTE (BACKEND, "Setting foreign window (0x%x)", (int) fwd->xwindow); + + fwd->stage_x11->xwin = fwd->xwindow; + fwd->stage_x11->is_foreign_xwin = TRUE; + + fwd->stage_x11->xwin_width = fwd->geom.width; + fwd->stage_x11->xwin_height = fwd->geom.height; + + clutter_actor_set_geometry (actor, &fwd->geom); + + /* calling this with the stage unrealized will unset the stage + * from the GL context; once the stage is realized the GL context + * will be set again + */ + clutter_stage_ensure_current (CLUTTER_STAGE (actor)); } /** @@ -693,7 +811,7 @@ clutter_x11_set_stage_foreign (ClutterStage *stage, guint width, height, border, depth; Window root_return; Status status; - ClutterGeometry geom; + ForeignWindowData fwd; g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); g_return_val_if_fail (xwindow != None, FALSE); @@ -721,49 +839,18 @@ clutter_x11_set_stage_foreign (ClutterStage *stage, return FALSE; } - clutter_actor_unrealize (actor); + fwd.stage_x11 = stage_x11; + fwd.xwindow = xwindow; + fwd.geom.x = x; + fwd.geom.y = y; + fwd.geom.width = width; + fwd.geom.height = height; - CLUTTER_NOTE (BACKEND, "Setting foreign window (0x%x)", (int) xwindow); + _clutter_actor_rerealize (actor, + set_foreign_window_callback, + &fwd); - stage_x11->xwin = xwindow; - stage_x11->is_foreign_xwin = TRUE; - - geom.x = x; - geom.y = y; - geom.width = stage_x11->xwin_width = width; - geom.height = stage_x11->xwin_height = height; - - clutter_actor_set_geometry (actor, &geom); - clutter_actor_realize (actor); - - CLUTTER_SET_PRIVATE_FLAGS (actor, CLUTTER_ACTOR_SYNC_MATRICES); + clutter_stage_ensure_viewport (stage); return TRUE; } - -void -clutter_stage_x11_map (ClutterStageX11 *stage_x11) -{ - /* set the mapped flag on the implementation */ - CLUTTER_ACTOR_SET_FLAGS (stage_x11, CLUTTER_ACTOR_MAPPED); - - /* and on the wrapper itself */ - CLUTTER_ACTOR_SET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_MAPPED); - - if (stage_x11->fullscreen_on_map) - clutter_stage_fullscreen (CLUTTER_STAGE (stage_x11->wrapper)); - else - clutter_stage_unfullscreen (CLUTTER_STAGE (stage_x11->wrapper)); - - clutter_actor_queue_relayout (CLUTTER_ACTOR (stage_x11->wrapper)); -} - -void -clutter_stage_x11_unmap (ClutterStageX11 *stage_x11) -{ - /* like above, unset the MAPPED stage on both the implementation and - * the wrapper - */ - CLUTTER_ACTOR_UNSET_FLAGS (stage_x11, CLUTTER_ACTOR_MAPPED); - CLUTTER_ACTOR_UNSET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_MAPPED); -} diff --git a/clutter/x11/clutter-stage-x11.h b/clutter/x11/clutter-stage-x11.h index c1a913950..7c71e48c7 100644 --- a/clutter/x11/clutter-stage-x11.h +++ b/clutter/x11/clutter-stage-x11.h @@ -41,6 +41,11 @@ G_BEGIN_DECLS typedef struct _ClutterStageX11 ClutterStageX11; typedef struct _ClutterStageX11Class ClutterStageX11Class; +typedef enum +{ + STAGE_X11_WITHDRAWN = 1 << 1 +} ClutterStageX11State; + struct _ClutterStageX11 { ClutterGroup parent_instance; @@ -62,10 +67,10 @@ struct _ClutterStageX11 ClutterBackendX11 *backend; ClutterStageState state; -#ifdef USE_XINPUT - int event_types[CLUTTER_X11_XINPUT_LAST_EVENT]; - GList *devices; -#endif + ClutterStageX11State wm_state; + + int event_types[CLUTTER_X11_XINPUT_LAST_EVENT]; + GList *devices; ClutterStage *wrapper; }; @@ -78,7 +83,9 @@ struct _ClutterStageX11Class GType clutter_stage_x11_get_type (void) G_GNUC_CONST; /* Private to subclasses */ -void clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11); +void clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11, + gint new_width, + gint new_height); void clutter_stage_x11_set_wm_protocols (ClutterStageX11 *stage_x11); void clutter_stage_x11_map (ClutterStageX11 *stage_x11); void clutter_stage_x11_unmap (ClutterStageX11 *stage_x11); diff --git a/configure.ac b/configure.ac index dc09a7cdc..65ef287c1 100644 --- a/configure.ac +++ b/configure.ac @@ -5,19 +5,29 @@ m4_define([clutter_major_version], [0]) m4_define([clutter_minor_version], [9]) m4_define([clutter_micro_version], [3]) -m4_define([clutter_version], - [clutter_major_version.clutter_minor_version.clutter_micro_version]) +m4_define([clutter_version], [clutter_major_version.clutter_minor_version.clutter_micro_version]) +m4_define([clutter_api_version], [clutter_major_version.clutter_minor_version]) -m4_define([clutter_api_version], - [clutter_major_version.clutter_minor_version]) - -# increase the interface age by 2 for each release; -# if the API changes, set to 0 +# increase the interface age by 2 for each release; if the API changes, +# set to 0. interface_age and binary_age are used to create the soname +# of the shared object: +# +# ( * 100 + ) - +# +# this allows using the same soname for different micro-releases in case +# no API was added or deprecated. for instance: +# +# clutter 1.2.0 -> 100 * 2 + 0 = 200, interface age = 0 -> 200 +# clutter 1.2.2 -> 100 * 2 + 2 = 202, interface age = 2 -> 200 +# clutter 1.2.4 -> 100 * 2 + 4 = 204, interface age = 4 -> 200 +# [ API addition, deprecation ] +# clutter 1.2.6 -> 100 * 2 + 6 = 206, interface age = 0 -> 206 +# ... +# m4_define([clutter_interface_age], [0]) -m4_define([clutter_binary_age], - [m4_eval(100 * clutter_minor_version + clutter_micro_version)]) +m4_define([clutter_binary_age], [m4_eval(100 * clutter_minor_version + clutter_micro_version)]) -AC_PREREQ(2.53) +AC_PREREQ([2.59]) AC_INIT([clutter], [clutter_version], @@ -33,7 +43,7 @@ CLUTTER_MINOR_VERSION=clutter_minor_version CLUTTER_MICRO_VERSION=clutter_micro_version CLUTTER_VERSION=clutter_version CLUTTER_API_VERSION=clutter_api_version -CLUTTER_MAJORMINOR=clutter_api_version +CLUTTER_MAJORMINOR=clutter_major_version.clutter_minor_version AC_SUBST(CLUTTER_MAJOR_VERSION) AC_SUBST(CLUTTER_MINOR_VERSION) AC_SUBST(CLUTTER_MICRO_VERSION) @@ -41,10 +51,9 @@ AC_SUBST(CLUTTER_VERSION) AC_SUBST(CLUTTER_API_VERSION) AC_SUBST(CLUTTER_MAJORMINOR) -m4_define([lt_current], - [m4_eval(100 * clutter_minor_version + clutter_micro_version - clutter_interface_age)]) +m4_define([lt_current], [m4_eval(clutter_binary_age - clutter_interface_age)]) m4_define([lt_revision], [clutter_interface_age]) -m4_define([lt_age], [m4_eval(clutter_binary_age - clutter_interface_age)]) +m4_define([lt_age], [m4_eval(clutter_binary_age - clutter_interface_age)]) CLUTTER_LT_CURRENT=lt_current CLUTTER_LT_REV=lt_revision CLUTTER_LT_AGE=lt_age @@ -58,17 +67,10 @@ dnl ======================================================================== # Checks for programs. AM_PROG_CC_C_O -#_AM_DEPENDENCIES([OBJC]) -#AC_PROG_OBJC AC_DISABLE_STATIC AC_PROG_LIBTOOL DOLT -# Make libtool respect the make -s switch (kudos to jacob berman) -changequote(,)dnl -LIBTOOL="${LIBTOOL} \$(shell echo \"\$(MFLAGS)\" | awk '/^[^ ]*s/ { print \"--silent\" }')" -changequote([,])dnl - # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h]) @@ -79,7 +81,7 @@ AC_C_CONST # Checks for library functions. AC_FUNC_MALLOC AC_FUNC_MMAP -AC_CHECK_FUNCS([memset munmap strcasecmp strdup]) +AC_CHECK_FUNCS([memset memcpy strcasecmp]) AC_PATH_PROG([GLIB_MKENUMS], [glib-mkenums]) AC_PATH_PROG([GLIB_GENMARSHAL], [glib-genmarshal]) @@ -88,404 +90,267 @@ PKG_PROG_PKG_CONFIG dnl ======================================================================== -# Peek which flavour the user wants so that we can couple the osx flavour with -# quartz imageloader. -if test "x$with_flavour" = "xosx"; then - imagebackend="quartz" -else - imagebackend="gdk-pixbuf" -fi - -AC_ARG_WITH([imagebackend], - AC_HELP_STRING([--with-imagebackend=@<:@gdk-pixbuf/quartz/internal@:>@], - [Select COGL image loading backend]), - imagebackend=$with_imagebackend) - -case $imagebackend in - - quartz) - AC_DEFINE([USE_QUARTZ], 1, [Use Core Graphics (Quartz) for loading image files]) - ;; - - gdk-pixbuf) - AC_DEFINE([USE_GDKPIXBUF], 1, [Use GdkPixbuf for loading image files]) - ;; - - internal) - ;; - - -esac - - -dnl ======================================================================== - +# defaults backendextra= backendextralib= clutterbackend=glx -AC_ARG_WITH([flavour], - AC_HELP_STRING([--with-flavour=@<:@glx/eglx/eglnative/sdl/osx/win32/fruity@:>@], - [Select the Clutter backend]), - clutterbackend=$with_flavour) - -case $clutterbackend in - glx|eglx|eglnative|sdl|osx|win32|fruity) ;; - *) AC_MSG_ERROR([Invalid flavour $clutterbackend]) ;; -esac - -glesversion=1.1 -AC_ARG_WITH([gles], - AC_HELP_STRING([--with-gles=@<:@1.1/2.0@:>@], - [Select Clutter GLES version (for EGL backends)]), - glesversion=$with_gles) - -case $glesversion in - 1.1|2.0) ;; - *) AC_MSG_ERROR([Invalid GL ES version $glesversion]) -esac - -if test "x$clutterbackend" = "xfruity" -then - if test "x$glesversion" != "x1.1"; then - AC_MSG_ERROR([Fruity backend only supports GL ES 1.1.]); - fi - glesversion="fruity" -fi - -BACKEND_PC_FILES="" -X11_PC_FILES="" - -# Check for X though could be redundant if backend does not need it. -AC_MSG_CHECKING([for X11]) -PKG_CHECK_EXISTS([x11], [have_x11=yes], [have_x11=no]) -if test "x$have_x11" = "xno"; then - AC_PATH_X - - if test x"$no_x" = "yes" ; then - if test "x$clutterbackend" = "xglx" or "x$clutterbackend" = "xeglx" - then - AC_MSG_ERROR([No X11 Libraries found and required by backend.]) - fi - - AC_MSG_RESULT([not found]) - else - if test x"$x_includes" != x"NONE" && test -n "$x_includes" ; then - X11_CFLAGS=-I`echo $x_includes | sed -e "s/:/ -I/g"` - fi - - if test x"$x_libraries" != x"NONE" && test -n "$x_libraries" ; then - X11_LIBS=-L`echo $x_libraries | sed -e "s/:/ -L/g"` - fi - - AC_MSG_RESULT([found]) - fi -else - X11_PC_FILES="x11" - AC_MSG_RESULT([found]) -fi - -AC_MSG_CHECKING([for XFIXES extension >= 3]) -PKG_CHECK_EXISTS([xfixes >= 3], [have_xfixes=yes], [have_xfixes=no]) -if test "x$have_xfixes" = "xyes"; then - AC_DEFINE(HAVE_XFIXES, 1, [Define to 1 if we have the XFIXES X extension]) - X11_LIBS="$X11_LIBS -lXfixes" - X11_PC_FILES="$X11_PC_FILES xfixes" - AC_MSG_RESULT([found]) -else - AC_MSG_RESULT([not found]) -fi - -AC_MSG_CHECKING([for XDAMAGE extension]) -PKG_CHECK_EXISTS([xdamage], [have_xdamage=yes], [have_xdamage=no]) -if test "x$have_xdamage" = "xyes"; then - AC_DEFINE(HAVE_XDAMAGE, 1, [Define to 1 if we have the XDAMAGE X extension]) - X11_LIBS="$X11_LIBS -lXdamage" - X11_PC_FILES="$X11_PC_FILES xdamage" - AC_MSG_RESULT([found]) -else - AC_MSG_RESULT([not found]) -fi - -AC_MSG_CHECKING([for XCOMPOSITE extension >= 0.4]) -PKG_CHECK_EXISTS([xcomposite >= 0.4], [have_xcomposite=yes], [have_xcomposite=no]) -if test "x$have_xcomposite" = "xyes"; then - AC_DEFINE(HAVE_XCOMPOSITE, 1, [Define to 1 if we have the XCOMPOSITE X extension]) - X11_LIBS="$X11_LIBS -lXcomposite" - X11_PC_FILES="$X11_PC_FILES xcomposite" - AC_MSG_RESULT([found]) -else - AC_MSG_RESULT([not found]) -fi - -x11_tests=no - -# Currently require all extentions, may not for actual release. -if test "x$clutterbackend" = "xglx" || test "x$clutterbackend" = "xeglx" -then - if test "x$have_xdamage" = "xno" || test "x$have_xfixes" = "xno" || test "x$have_xcomposite" = "xno"; then - AC_MSG_ERROR([Required backend X11 Libraries not found.]) - fi - - if test "x$have_xcomposite" = "xyes"; then - x11_tests=yes - fi -fi - -AM_CONDITIONAL(X11_TESTS, test "x$x11_tests" != "xno") - -xinput=no -AC_ARG_ENABLE(xinput, - AS_HELP_STRING([--enable-xinput], - ["Use the XINPUT X extension"]),[ - if test "x$enableval" = "xyes" ; then - PKG_CHECK_MODULES(XINPUT,[xi], - xinput=yes, - xinput=no) - fi], - [xinput=yes]) - -if test "x$xinput" = "xyes"; then - AC_DEFINE(USE_XINPUT, 1, Use the XINPUT X extension) - X11_LIBS="$X11_LIBS -lXi" - BACKEND_PC_FILES="$X11_PC_FILES xi" -fi - -dnl This is only used to decide whether to build -dnl tests/tools/disable-npots.la -AC_CHECK_LIB(dl, dlopen, HAVE_LIBDL=yes, HAVE_LIBDL=no) -AM_CONDITIONAL(HAVE_LIBDL, test "x$HAVE_LIBDL" != "xno") - clutter_gl_header="" -use_gles2_wrapper="no" +glesversion=1.1 +use_gles2_wrapper=no -if test "x$clutterbackend" = "xeglnative" || test "x$clutterbackend" = "xeglx" || test "x$clutterbackend" = "xfruity" -then -case $glesversion in +AC_ARG_WITH([flavour], + [AC_HELP_STRING([--with-flavour=@<:@glx/eglx/eglnative/sdl/osx/win32/fruity@:>@], + [Select the Clutter backend])], + [clutterbackend=$with_flavour]) - 1*) - clutter_gl_header="GLES/gl.h" - CLUTTER_COGL="gles" - AC_DEFINE([HAVE_COGL_GLES], 1, [Have GL/ES for rendering]) +AC_ARG_WITH([gles], + [AC_HELP_STRING([--with-gles=@<:@1.1/2.0@:>@], + [Select Clutter GLES version (for EGL backends)])], + [glesversion=$with_gles]) - AC_CHECK_HEADERS([GLES/egl.h],, - [AC_MSG_ERROR([Unable to locate required GLES headers])]) - AC_CHECK_HEADERS([$clutter_gl_header],, - [AC_MSG_ERROR([Unable to locate required GLES headers])]) +# the fruity backend requires a different handling for GLES +AS_IF([test "x$clutterbackend" = "xfruity"], [glesversion=fruity]) + +# backend specific pkg-config files +BACKEND_PC_FILES="" + +# This is only used to decide whether to build tests/tools/disable-npots.la +AC_CHECK_LIB(dl, [dlopen], [HAVE_LIBDL=yes], [HAVE_LIBDL=no]) +AM_CONDITIONAL(HAVE_LIBDL, [test "x$HAVE_LIBDL" = "xyes"]) + +dnl === COGL GLES backend ===================================================== + +AS_IF([test "x$clutterbackend" = "xeglnative" || + test "x$clutterbackend" = "xeglx" || + test "x$clutterbackend" = "xfruity"], + + [ + AS_CASE([$glesversion], + + [1*], + [ + clutter_gl_header="GLES/gl.h" + + CLUTTER_COGL="gles" + AC_DEFINE([HAVE_COGL_GLES], 1, [Have GL/ES for rendering]) + + AC_CHECK_HEADERS([GLES/egl.h], + [], + [AC_MSG_ERROR([Unable to locate required GLES headers])]) - # check for upper/lower case libgles_em - # The powervr sdk uses lower case. - AC_CHECK_LIB(GLES_CM, eglInitialize, HAVE_LIBGLES=yes, HAVE_LIBGLES=no) - if test "x$HAVE_LIBGLES" = "xno"; then + # check for upper/lower case libgles_em + # The powervr sdk uses lower case. + AC_CHECK_LIB(GLES_CM, [eglInitialize], + [HAVE_LIBGLES=yes], + [HAVE_LIBGLES=no]) - AC_CHECK_LIB(GLESv1_CM, eglInitialize, HAVE_LIBGLES=yes, HAVE_LIBGLES=no) - if test "x$HAVE_LIBGLES" = "xno"; then + AS_IF([test "x$HAVE_LIBGLES" = "xyes"], + [GLES_LIBS="-lGLES_CM"], + [ + AC_CHECK_LIB(GLESv1_CM, [eglInitialize], + [HAVE_LIBGLES=yes], + [HAVE_LIBGLES=no]) - AC_CHECK_LIB(gles_cm, eglInitialize, HAVE_LIBGLES=yes, HAVE_LIBGLES=no) - if test "x$HAVE_LIBGLES" = "xno"; then - AC_MSG_ERROR([GLES library not found and egl backend requested.]); - else - GLES_LIBS="-lgles_cm" - fi - else - GLES_LIBS="-lGLESv1_CM" - fi + AS_IF([test "x$HAVE_LIBGLES" = "xyes"], + [GLES_LIBS="-lGLESv1_CM"], + [ + AC_CHECK_LIB(gles_cm, [eglInitialize], + [HAVE_LIBGLES=yes], + [HAVE_LIBGLES=no]) - else - GLES_LIBS="-lGLES_CM" - fi - ;; - 2*) - clutter_gl_header="GLES2/gl2.h" - CLUTTER_COGL="gles" - AC_DEFINE([HAVE_COGL_GLES2], 1, [Have GL/ES for rendering]) + AS_IF([test "x$HAVE_LIBGLES" = "xyes"], + [GLES_LIBS="-lgles_cm"], + [ + AC_MSG_ERROR([GLES library not found and egl backend requested.]) + ] + ) + ] + ) + ] + ) + ], - AC_CHECK_HEADERS([EGL/egl.h],, - [AC_MSG_ERROR([Unable to locate required GLES headers])]) + [2*], + [ + clutter_gl_header="GLES2/gl2.h" + use_gles2_wrapper=yes + CLUTTER_COGL="gles" + AC_DEFINE([HAVE_COGL_GLES2], 1, [Have GL/ES for rendering]) - AC_CHECK_HEADERS([$clutter_gl_header],, - [AC_MSG_ERROR([Unable to locate required GLES headers])]) + AC_CHECK_HEADERS([EGL/egl.h], + [], + [AC_MSG_ERROR([Unable to locate required GLES headers])]) - GLES_LIBS="-lGLESv2 -lEGL" + GLES_LIBS="-lGLESv2 -lEGL" + ], - use_gles2_wrapper=yes - ;; - fruity) - CLUTTER_COGL="gles" - AC_DEFINE([HAVE_COGL_GLES], 1, [Have GL/ES for rendering]) + [fruity], + [ + clutter_gl_header="GLES/gl.h" + CLUTTER_COGL="gles" + AC_DEFINE([HAVE_COGL_GLES], 1, [Have GL/ES for rendering]) - clutter_gl_header="GLES/gl.h" - CLUTTER_COGL="gles" - AC_DEFINE([HAVE_COGL_GLES], 1, [Have GL/ES for rendering]) + AC_CHECK_HEADERS([GLES/egl.h], + [], + [AC_MSG_ERROR([Unable to locate required GLES headers])]) + ], - AC_CHECK_HEADERS([GLES/egl.h],, + [AC_MSG_ERROR([Unknown argument for --with-gles])] + ) + ] +) + +AM_CONDITIONAL(USE_GLES2_WRAPPER, [test "x$use_gles2_wrapper" = "xyes"]) + +dnl === Clutter windowing system backend ====================================== + +AS_CASE([$clutterbackend], + + [sdl], + [ + clutter_gl_header="GL/gl.h" + CLUTTER_FLAVOUR="sdl" + CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_SDL" + AC_DEFINE([HAVE_CLUTTER_SDL], [1], [Have the SDL backend]) + + CLUTTER_COGL="gl" + AC_DEFINE([HAVE_COGL_GL], [1], [Have GL for rendering]) + + AC_PATH_PROG(SDL_CONFIG, [sdl-config]) + AS_IF([test "x$SDL_CONFIG" = "x"], + [AC_MSG_ERROR([No sdl-config binary found in path])], + [ + SDL_CFLAGS=`$SDL_CONFIG --cflags` + SDL_LIBS=`$SDL_CONFIG --libs` + + AS_CASE([$host], + + [*mingw32*], + [ + # Use -lopengl32 under Windows instead of -lGL + SDL_LIBS="$SDL_LIBS -lopengl32" + CLUTTER_LT_LDFLAGS="$CLUTTER_LT_LDFLAGS -no-undefined" + ], + + [ + AC_CHECK_LIB(GL, [glEnable], [HAVE_LIBGL=yes], [HAVE_LIBGL=no]) + AS_IF([test "x$HAVE_LIBGL" = "xno"], [AC_MSG_ERROR([libGL not found])]) + SDL_LIBS="$SDL_LIBS -lGL" + ] + ) + ] + ) + ], + + [glx], + [ + clutter_gl_header="GL/gl.h" + CLUTTER_FLAVOUR="glx" + CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_GLX" + AC_DEFINE([HAVE_CLUTTER_GLX], [1], [Have the GLX backend]) + + CLUTTER_COGL="gl" + AC_DEFINE([HAVE_COGL_GL], [1], [Have GL for rendering]) + + AC_CHECK_HEADERS([GL/glx.h], + [], + [AC_MSG_ERROR([Unable to locate required GLX headers])]) + + AC_CHECK_LIB(GL, [glXCreateContext], + [HAVE_LIBGLX=yes], + [AC_MSG_ERROR([Required GLX library not found])]) + + GLX_LIBS="$X11_LIBS -lGL" + GLX_CFLAGS="$X11_CFLAGS" + + backendextra=x11 + backendextralib="x11/libclutter-x11.la" + + # Mesa 7.3 added a GL pkg-config file, finally + PKG_CHECK_EXISTS([gl], [BACKEND_PC_FILES="$BACKEND_PC_FILES gl"], []) + ], + + [eglx], + [ + # the GL header is defined in the COGL checks above + CLUTTER_FLAVOUR="eglx" + CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_EGL" + AC_DEFINE([HAVE_CLUTTER_EGL], [1], [Have the EGL backend]) + + EGL_LIBS="$GLES_LIBS $X11_LIBS" + EGL_CFLAGS="$GLES_CFLAGS $X11_CFLAGS" + + backendextra=x11 + backendextralib="x11/libclutter-x11.la" + + # Mesa 7.3 added a GL pkg-config file, finally + PKG_CHECK_EXISTS([gl], [BACKEND_PC_FILES="$BACKEND_PC_FILES gl"], []) + ], + + [eglnative], + [ + # the GL header is defined in the COGL checks above + CLUTTER_FLAVOUR="eglnative" + CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_EGLNATIVE" + AC_DEFINE([HAVE_CLUTTER_EGL], [1], [Have the EGL backend]) + + PKG_CHECK_MODULES(TSLIB, [tslib-1.0], [have_tslib=yes], [have_tslib=no]) + AS_IF([test "x$have_tslib" = "xyes"], + [AC_DEFINE([HAVE_TSLIB], [1], [Have tslib for touchscreen handling])] + ) + + EGL_LIBS="$GLES_LIBS $TSLIB_LIBS" + EGL_CFLAGS="$TSLIB_CFLAGS" + ], + + [fruity], + [ + # the GL header is defined in the COGL checks above + CLUTTER_FLAVOUR="fruity" + CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_FRUITY" + AC_DEFINE([HAVE_CLUTTER_FRUITY], [1], [Have the Fruity backend]) + + EGL_LIBS="-ObjC -framework Foundation -framework CoreFoundation -framework CoreGraphics -framework CoreSurface -framework GraphicsServices -framework OpenGLES -framework LayerKit -framework UIKit" + EGL_CFLAGS="" + ], + + [osx], + [ + clutter_gl_header="OpenGL/gl.h" + CLUTTER_FLAVOUR="osx" + CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_OSX" + AC_DEFINE([HAVE_CLUTTER_OSX], [1], [Have the OSX backend]) + + CLUTTER_COGL="gl" + AC_DEFINE([HAVE_COGL_GL], [1], [Have GL for rendering]) + + OSX_LIBS="-framework Cocoa -framework OpenGL" + ], + + [win32], + [ + clutter_gl_header="GL/gl.h" + CLUTTER_FLAVOUR="win32" + CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_WIN32" + AC_DEFINE([HAVE_CLUTTER_WIN32], [1], [Have the Win32 backend]) + + CLUTTER_COGL="gl" + AC_DEFINE([HAVE_COGL_GL], [1], [Have GL for rendering]) + + WIN32_CFLAGS="-D_WIN32_WINNT=0x0500" + WIN32_LIBS="-lopengl32 -lgdi32 -lwinmm" + CLUTTER_LT_LDFLAGS="$CLUTTER_LT_LDFLAGS -no-undefined" + ], + + [AC_MSG_ERROR([Invalid backend for Clutter: use glx, sdl, osx, win32, eglx, eglnative or fruity])] +) + +# at this point we must have a GL header to check +AS_IF([test "x$clutter_gl_header" = "x"], [AC_MSG_ERROR([Internal error: no GL header set])]) +AC_CHECK_HEADERS([$clutter_gl_header], + [], [AC_MSG_ERROR([Unable to locate required GLES headers])]) - AC_CHECK_HEADERS([$clutter_gl_header],, - [AC_MSG_ERROR([Unable to locate required GLES headers])]) - ;; - - *) AC_MSG_ERROR([Invalid GL ES Version '$glesversion' specified]) - ;; - -esac -fi - -AM_CONDITIONAL(USE_GLES2_WRAPPER, test "x$use_gles2_wrapper" != "xno") - -case $clutterbackend in - - sdl) - - clutter_gl_header="GL/gl.h" - CLUTTER_FLAVOUR="sdl" - CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_SDL" - AC_DEFINE([HAVE_CLUTTER_SDL], 1, [Have the SDL backend]) - - CLUTTER_COGL="gl" - AC_DEFINE([HAVE_COGL_GL], 1, [Have GL for rendering]) - - AC_PATH_PROG(SDL_CONFIG, sdl-config) - if test "x$SDL_CONFIG" = "x"; then - AC_MSG_ERROR([[No sdl-config binary found in path and SDL flavour requested.]]) - else - SDL_CFLAGS=`$SDL_CONFIG --cflags` - SDL_LIBS=`$SDL_CONFIG --libs` - - AC_CHECK_HEADERS([$clutter_gl_header],, - [AC_MSG_ERROR([Unable to locate required GL headers])]) - - dnl Use -lopengl32 under Windows instead of -lGL - case "$host" in - *mingw32*) - SDL_LIBS="$SDL_LIBS -lopengl32" - CLUTTER_LT_LDFLAGS="$CLUTTER_LT_LDFLAGS -no-undefined" - ;; - *) - AC_CHECK_LIB(GL, glEnable, HAVE_LIBGL=yes, HAVE_LIBGL=no) - if test "x$HAVE_LIBGL" = "xno"; then - AC_MSG_ERROR([libGL not found]); - fi - SDL_LIBS="$SDL_LIBS -lGL" - ;; - esac - fi - ;; - - glx) - - clutter_gl_header="GL/gl.h" - CLUTTER_FLAVOUR="glx" - CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_GLX" - AC_DEFINE([HAVE_CLUTTER_GLX], 1, [Have the GLX backend]) - - PKG_CHECK_EXISTS([gl], [have_gl_pc=yes], [have_gl_pc=no]) - - CLUTTER_COGL="gl" - AC_DEFINE([HAVE_COGL_GL], 1, [Have GL for rendering]) - - AC_CHECK_HEADERS([$clutter_gl_header],, - [AC_MSG_ERROR([Unable to locate required GL headers])]) - AC_CHECK_HEADERS([GL/glx.h],, - [AC_MSG_ERROR([Unable to locate required GLX headers])]) - - AC_CHECK_LIB(GL, glXCreateContext, HAVE_LIBGLX=yes, HAVE_LIBGLX=no) - - if test "x$HAVE_LIBGLX" = "xno"; then - AC_MSG_ERROR([GLX not found and GLX backend requested]); - fi - - GLX_LIBS="$X11_LIBS -lGL" - GLX_CFLAGS="$X11_CFLAGS" - backendextra=x11 - backendextralib="x11/libclutter-x11.la" - - # Mesa 7.3 added a GL pkg-config file, finally - if test "x$have_gl_pc" = "xyes"; then - BACKEND_PC_FILES="$BACKEND_PC_FILES gl" - fi - - BACKEND_PC_FILES="$BACKEND_PC_FILES $X11_PC_FILES" - ;; - - eglx) - - CLUTTER_FLAVOUR="eglx" - CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_EGL" - AC_DEFINE([HAVE_CLUTTER_EGL], 1, [Have the EGL backend]) - - EGL_LIBS="$GLES_LIBS $X11_LIBS" - EGL_CFLAGS="$GLES_CFLAGS $X11_CFLAGS" - backendextra=x11 - backendextralib="x11/libclutter-x11.la" - ;; - - eglnative) - - CLUTTER_FLAVOUR="eglnative" - CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_EGLNATIVE" - AC_DEFINE([HAVE_CLUTTER_EGL], 1, [Have the EGL backend]) - - PKG_CHECK_MODULES(TSLIB, tslib-1.0, [have_tslib=yes], [have_tslib=no]) - if test x$have_tslib = xyes; then - AC_DEFINE([HAVE_TSLIB], 1, [Have tslib for touchscreen handling]) - fi - - EGL_LIBS="$GLES_LIBS $TSLIB_LIBS" - EGL_CFLAGS="$TSLIB_CFLAGS" - - BACKEND_PC_FILES="$BACKEND_PC_FILES $X11_PC_FILES" - ;; - - fruity) - - CLUTTER_FLAVOUR="fruity" - CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_FRUITY" - AC_DEFINE([HAVE_CLUTTER_FRUITY], 1, [We're building a fruity version of the eglnative backend]) - - EGL_LIBS="-ObjC -framework Foundation -framework CoreFoundation -framework CoreGraphics -framework CoreSurface -framework GraphicsServices -framework OpenGLES -framework LayerKit -framework UIKit" - EGL_CFLAGS="" - ;; - - osx) - - clutter_gl_header="OpenGL/gl.h" - CLUTTER_FLAVOUR="osx" - CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_OSX" - AC_DEFINE([HAVE_CLUTTER_OSX], [1], [Have the OSX backend]) - - CLUTTER_COGL="gl" - AC_DEFINE([HAVE_COGL_GL], [1], [Have GL for rendering]) - - OSX_LIBS="-framework Cocoa -framework OpenGL" - AC_CHECK_HEADERS([$clutter_gl_header],, - [AC_MSG_ERROR([Unable to locate required GL headers])]) - ;; - - win32) - - clutter_gl_header="GL/gl.h" - CLUTTER_FLAVOUR="win32" - CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_WIN32" - AC_DEFINE([HAVE_CLUTTER_WIN32], 1, [Have the Win32 backend]) - - CLUTTER_COGL="gl" - AC_DEFINE([HAVE_COGL_GL], 1, [Have GL for rendering]) - - AC_CHECK_HEADERS([$clutter_gl_header],, - [AC_MSG_ERROR([Unable to locate required GL headers])]) - - WIN32_CFLAGS="-D_WIN32_WINNT=0x0500" - WIN32_LIBS="-lopengl32 -lgdi32 -lwinmm" - CLUTTER_LT_LDFLAGS="$CLUTTER_LT_LDFLAGS -no-undefined" - ;; - - *) AC_MSG_ERROR([Invalid backend for Clutter: use glx,sdl,osx,win32,eglx, eglnative or fruity]) - ;; - -esac - - - CLUTTER_GL_HEADER=$clutter_gl_header @@ -498,10 +363,185 @@ AC_SUBST(CLUTTER_COGL) AC_SUBST(CLUTTER_GL_HEADER) AC_SUBST(CLUTTER_STAGE_TYPE) -clutterbackendlib=libclutter$CLUTTER_REAL-$clutterbackend-$CLUTTER_MAJORMINOR.la +clutterbackendlib=libclutter-$clutterbackend-$CLUTTER_API_VERSION.la AC_SUBST([clutterbackendlib]) -dnl ======================================================================== +dnl === Image loading backend ================================================= +IMAGE_PC_FILES="" + +# Peek which flavour the user wants so that we can couple the osx flavour with +# quartz imageloader. +AS_IF([test "x$with_flavour" = "xosx"], [imagebackend=quartz], [imagebackend=gdk-pixbuf]) + +AC_ARG_WITH([imagebackend], + [AC_HELP_STRING([--with-imagebackend=@<:@gdk-pixbuf/quartz/internal@:>@], + [Select COGL image loading backend])], + [imagebackend=$with_imagebackend]) + +AS_CASE([$imagebackend], + + [quartz], + [AC_DEFINE([USE_QUARTZ], 1, [Use Core Graphics (Quartz) for loading image data])], + + [gdk-pixbuf], + [ + AC_DEFINE([USE_GDKPIXBUF], 1, [Use GdkPixbuf for loading image data]) + IMAGE_PC_FILES="gdk-pixbuf-2.0" + ], + + [internal], + [AC_DEFINE([USE_INTERNAL], 1, [Use internal image decoding for loading image data])], + + [AC_MSG_ERROR([Unknown argument for --with-imagebackend])] +) + +dnl === X11 checks, only for X11-based backends =============================== +X11_PC_FILES="" +x11_tests=no + +AS_IF([test "x$clutterbackend" = "xglx" || test "x$clutterbackend" = "xeglx"], + [ + # base X11 includes and libraries + AC_MSG_CHECKING([for X11]) + + # start with pkg-config + PKG_CHECK_EXISTS([x11], [have_x11=yes], [have_x11=no]) + AS_IF([test "x$have_x11" = "xyes"], + [ + X11_PC_FILES="x11" + AC_MSG_RESULT([found]) + ], + [ + # no pkg-config, let's go old school + AC_PATH_X + + AS_IF([test "x$no_x" = "xyes"], + [AC_MSG_ERROR([No X11 Libraries found])], + [ + AS_IF([test "x$x_includes" != "xNONE" && test -n "$x_includes"], + [X11_CFLAGS=-I`echo $x_includes | sed -e "s/:/ -I/g"`]) + + AS_IF([test "x$x_libraries" != "xNONE" && test -n "$x_libraries"], + [X11_LIBS=-L`echo $x_libraries | sed -e "s/:/ -L/g"`]) + + AC_MSG_RESULT([found]) + ] + ) + ] + ) + + # XFIXES (required) + AC_MSG_CHECKING([for XFIXES extension >= 3]) + PKG_CHECK_EXISTS([xfixes >= 3], [have_xfixes=yes], [have_xfixes=no]) + AS_IF([test "x$have_xfixes" = "xyes"], + [ + AC_DEFINE(HAVE_XFIXES, [1], [Define to 1 if we have the XFIXES X extension]) + + X11_LIBS="$X11_LIBS -lXfixes" + X11_PC_FILES="$X11_PC_FILES xfixes" + + AC_MSG_RESULT([found]) + ], + [AC_MSG_ERROR([Not found])] + ) + + # XDAMAGE (required) + AC_MSG_CHECKING([for XDAMAGE extension]) + PKG_CHECK_EXISTS([xdamage], [have_xdamage=yes], [have_xdamage=no]) + AS_IF([test "x$have_xdamage" = "xyes"], + [ + AC_DEFINE(HAVE_XDAMAGE, [1], [Define to 1 if we have the XDAMAGE X extension]) + + X11_LIBS="$X11_LIBS -lXdamage" + X11_PC_FILES="$X11_PC_FILES xdamage" + + AC_MSG_RESULT([found]) + ], + [AC_MSG_ERROR([not found])] + ) + + # XCOMPOSITE (optional) + AC_MSG_CHECKING([for XCOMPOSITE extension >= 0.4]) + PKG_CHECK_EXISTS([xcomposite >= 0.4], [have_xcomposite=yes], [have_xcomposite=no]) + AS_IF([test "x$have_xcomposite" = "xyes"], + [ + AC_DEFINE(HAVE_XCOMPOSITE, [1], [Define to 1 if we have the XCOMPOSITE X extension]) + + X11_LIBS="$X11_LIBS -lXcomposite" + X11_PC_FILES="$X11_PC_FILES xcomposite" + + AC_MSG_RESULT([found]) + ], + [AC_MSG_RESULT([not found])] + ) + + # XINPUT (optional) - FIXME this is wrong + xinput=no + AC_MSG_CHECKING([for XINPUT extension]) + AC_ARG_ENABLE([xinput], + [AS_HELP_STRING([--enable-xinput], [Use the XINPUT X extension])], + [ + AS_IF([test "x$enableval" = "xyes"], + [PKG_CHECK_MODULES(XINPUT, [xi], [xinput=yes], [xinput=no])] + ) + ], + [xinput=no]) + + AS_CASE([$xinput], + + [yes], + [ + AC_DEFINE(HAVE_XINPUT, 1, Use the XINPUT X extension) + + # ugh, this is insane + AC_TRY_COMPILE([#include ], + [ + XExtensionVersion *res; + res = XGetExtensionVersion (NULL, INAME); + ], + [have_xget_extension_version=yes], + [have_xget_extension_version=no]) + + AC_TRY_COMPILE([#include ], + [ + XExtensionVersion *res; + res = XQueryInputVersion (NULL, XI_2_Major, XI_2_Minor); + ], + [have_xquery_input_version=yes], + [have_xquery_input_version=no]) + + AS_IF([test "x$have_xget_extension_version" = "xyes"], + [ + AC_DEFINE([HAVE_XGET_EXTENSION_VERSION], + [1], + [Define to 1 if we have XGetExtensionVersion]) + ]) + + AS_IF([test "x$have_xquery_input_version" = "xyes"], + [ + AC_DEFINE([HAVE_XQUERY_INPUT_VERSION], + [1], + [Define to 1 if we have XQueryInputVersion]) + ]) + + X11_LIBS="$X11_LIBS -lXi" + X11_PC_FILES="$X11_PC_FILES xi" + + AC_MSG_RESULT([found]) + ], + + [no], + [AC_MSG_RESULT([not found or disabled])], + ) + + # X11-specific tests are enabled conditionally + AS_IF([test "x$have_xcomposite" = "xyes"], [x11_tests=yes], [x11_tests=no]) + ] +) + +AM_CONDITIONAL(X11_TESTS, [test "x$x11_tests" = "xyes"]) + +dnl === JSON parser check ===================================================== # allow building clutter with an external dependency on json-glib # using the --with-json=check argument, but keep the default to @@ -512,118 +552,128 @@ AC_ARG_WITH([json], [], [with_json=internal]) -case $with_json in - internal|check) ;; - *) AC_MSG_ERROR([Invalid value for the JSON library: use internal or check]) ;; -esac +AS_CASE([$with_json], -if test "x$with_json" = "xinternal"; then - JSON_PREFIX=json - have_json=no -else - # if the user asked for it and if we have json-glib installed, - # prefer the system library instead of the internal copy - AC_MSG_CHECKING([for installed JSON-GLib]) - PKG_CHECK_EXISTS(json-glib-1.0, [have_json=yes], [have_json=no]) - if test "x$have_json" = "xyes"; then - JSON_PREFIX=json-glib - JSON_GLIB_PC=json-glib-1.0 - AC_DEFINE(HAVE_JSON_GLIB, 1, [Have the JSON-GLib library installed]) - AC_MSG_RESULT([found]) - else - JSON_PREFIX=json - AC_MSG_RESULT([not found, using internal copy]) - fi -fi + [internal], + [ + JSON_PREFIX=json + have_json=no + ], + + [check], + [ + AC_MSG_CHECKING([for installed JSON-GLib]) + PKG_CHECK_EXISTS([json-glib-1.0], [have_json=yes], [have_json=no]) + AS_IF([test "x$have_json" = "xyes"], + [ + JSON_PREFIX=json-glib + JSON_GLIB_PC=json-glib-1.0 + + AC_DEFINE(HAVE_JSON_GLIB, 1, [Have the JSON-GLib library installed]) + + AC_MSG_RESULT([found]) + ], + [ + JSON_PREFIX=json + AC_MSG_RESULT([not found, using internal copy]) + ] + ) + ], + + [AC_MSG_ERROR([Unknown argument for --with-json])] +) AC_SUBST(JSON_PREFIX) AM_CONDITIONAL(LOCAL_JSON_GLIB, test "x$have_json" = "xno") +dnl === Dependencies, compiler flags and linker libraries ===================== CLUTTER_REQUIRES="cairo >= 1.4 pangocairo >= 1.20 gobject-2.0 >= 2.16 gthread-2.0 gmodule-no-export-2.0 $BACKEND_PC_FILES $JSON_GLIB_PC" -if test "x$imagebackend" = "xgdk-pixbuf"; then - CLUTTER_REQUIRES="$CLUTTER_REQUIRES gdk-pixbuf-2.0" -fi - PKG_CHECK_MODULES(CLUTTER_DEPS, [$CLUTTER_REQUIRES]) AC_SUBST(CLUTTER_REQUIRES) -# prefixes for fixing gtk-doc references -GLIB_PREFIX="`$PKG_CONFIG --variable=prefix glib-2.0`" -PANGO_PREFIX="`$PKG_CONFIG --variable=prefix pango`" -AC_SUBST(GLIB_PREFIX) -AC_SUBST(PANGO_PREFIX) +CLUTTER_CFLAGS="$SDL_CFLAGS $EGL_CFLAGS $GLX_CFLAGS $OSX_CFLAGS $WIN32_CFLAGS $CLUTTER_DEPS_CFLAGS" +CLUTTER_LIBS="$SDL_LIBS $EGL_LIBS $GLX_LIBS $OSX_LIBS $WIN32_LIBS $CLUTTER_DEPS_LIBS" -dnl ======================================================================== +AC_SUBST(CLUTTER_CFLAGS) +AC_SUBST(CLUTTER_LIBS) -if test "x$GCC" = "xyes"; then - GCC_FLAGS="-g -Wall" -fi +dnl === Enable debug level ==================================================== -dnl = Enable debug level =================================================== - -m4_define([debug_default], - m4_if(m4_eval(clutter_minor_version % 2), [1], [yes], [minimum])) - -AC_ARG_ENABLE(debug, - AC_HELP_STRING([--enable-debug=@<:@no/minimum/yes@:>@], - [turn on debugging. yes; All glib asserts, checks and runtime clutter verbose messages. minimum; Just glib cast checks and runtime clutter verbose messagaes. no; No glib asserts or checks and no runtime clutter verbose messages. @<:@default=debug_default@:>@]), -, - enable_debug=debug_default) - -if test "x$enable_debug" = "xyes"; then - test "$cflags_set" = set || CFLAGS="$CFLAGS -g" - CLUTTER_DEBUG_CFLAGS="-DCLUTTER_ENABLE_DEBUG -DCOGL_ENABLE_DEBUG" -else - if test "x$enable_debug" = "xno"; then - CLUTTER_DEBUG_CFLAGS="-DG_DISABLE_ASSERT -DG_DISABLE_CHECKS -DG_DISABLE_CAST_CHECKS" - else # minimum - CLUTTER_DEBUG_CFLAGS="-DCLUTTER_ENABLE_DEBUG -DCOGL_ENABLE_DEBUG -DG_DISABLE_CAST_CHECKS" - fi -fi - -AC_SUBST(CLUTTER_DEBUG_CFLAGS) - -m4_define([cogl_debug_default], [no]) -AC_ARG_ENABLE([cogl-debug], - [AC_HELP_STRING([--enable-cogl-debug=@<:@no/yes@:>@], - [Turn on COGL debugging])], +m4_define([debug_default], [m4_if(m4_eval(clutter_minor_version % 2), [1], [yes], [minimum])]) +AC_ARG_ENABLE([debug], + [AC_HELP_STRING([--enable-debug=@<:@no/minimum/yes@:>@], + [Control Clutter debugging level @<:@default=debug_default@:>@])], [], - [enable_debug=cogl_debug_default]) + [enable_debug=debug_default]) AS_CASE([$enable_debug], - [yes], [COGL_DEBUG_CFLAGS="-DCOGL_GL_DEBUG -DCOGL_HANDLE_DEBUG -DCOGL_ENABLE_DEBUG"], + [yes], + [ + test "$cflags_set" = set || CFLAGS="$CFLAGS -g" + CLUTTER_DEBUG_CFLAGS="-DCLUTTER_ENABLE_DEBUG" + ], - [no], [COGL_DEBUG_CFLAGS=""], + [minimum], + [CLUTTER_DEBUG_CFLAGS="-DCLUTTER_ENABLE_DEBUG -DG_DISABLE_CAST_CHECKS"], - [*], [AC_MSG_ERROR([Invalid value for --enable-cogl-debug])] + [no], + [CLUTTER_DEBUG_CFLAGS="-DG_DISABLE_ASSERT -DG_DISABLE_CHECKS -DG_DISABLE_CAST_CHECKS"], + + [AC_MSG_ERROR([Unknown argument for --enable-debug])] +) + +AC_SUBST(CLUTTER_DEBUG_CFLAGS) + +m4_define([cogl_debug_default], [m4_if(m4_eval(clutter_minor_version % 2), [1], [minimum], [no])]) +AC_ARG_ENABLE([cogl-debug], + [AC_HELP_STRING([--enable-cogl-debug=@<:@no/yes@:>@], + [Control COGL debugging level @<:@default=cogl_debug_default@:>@])], + [], + [enable_cogl_debug=cogl_debug_default]) + +AS_CASE([$enable_cogl_debug], + + [yes], + [COGL_DEBUG_CFLAGS="-DCOGL_GL_DEBUG -DCOGL_HANDLE_DEBUG -DCOGL_ENABLE_DEBUG"], + + [minimum], + [COGL_DEBUG_CFLAGS="-DCOGL_ENABLE_DEBUG"], + + [no], + [COGL_DEBUG_CFLAGS=""], + + [AC_MSG_ERROR([Invalid value for --enable-cogl-debug])] ) AC_SUBST(COGL_DEBUG_CFLAGS) -dnl = Enable strict compiler flags ========================================= +dnl === Enable strict compiler flags ========================================== # use strict compiler flags only on development releases -#m4_define([maintainer_flags_default], -# m4_if(m4_eval(clutter_minor_version % 2), [1], [yes], [no])) -m4_define([maintainer_flags_default], [no]) +m4_define([maintainer_flags_default], [m4_if(m4_eval(clutter_minor_version % 2), [1], [yes], +[no])]) AC_ARG_ENABLE([maintainer-flags], - AC_HELP_STRING([--enable-maintainer-flags=@<:@no/yes@:>@], - [Use strict compiler flags @<:@default=maintainer_flags_default@:>@]),, - enable_maintainer_flags=maintainer_flags_default) + [AC_HELP_STRING([--enable-maintainer-flags=@<:@no/yes@:>@], + [Use strict compiler flags @<:@default=maintainer_flags_default@:>@])], + [], + [enable_maintainer_flags=maintainer_flags_default]) + +AS_IF([test "x$enable_maintainer_flags" = "xyes" && test "x$GCC" = "xyes"], + [ + MAINTAINER_CFLAGS="-Werror -Wall -Wshadow -Wcast-align -Wno-strict-aliasing -Wno-uninitialized -Wempty-body -Wformat-security -Winit-self" + ] +) -if test "x$enable_maintainer_flags" = "xyes"; then - MAINTAINER_CFLAGS="-Werror -Wall -Wshadow -Wcast-align -Wno-strict-aliasing -Wno-uninitialized -Wempty-body -Wformat-security -Winit-self" -fi AC_SUBST(MAINTAINER_CFLAGS) -dnl = GObject-Introspection check ========================================== +dnl === GObject-Introspection check =========================================== GOBJECT_INTROSPECTION_CHECK([0.6.3]) -dnl = GTK Doc check ======================================================== +dnl === GTK Doc check ========================================================= GTK_DOC_CHECK([1.11]) @@ -635,49 +685,52 @@ GTK_DOC_CHECK([1.11]) # # we use autogen.sh as it exists only inside the SVN checkouts, and it # is not packaged into tarballs. -AM_CONDITIONAL([BUILD_GTK_DOC], - [test "x$enable_gtk_doc" = "xyes" || test ! -f "autogen.sh"]) +AM_CONDITIONAL([BUILD_GTK_DOC], [test "x$enable_gtk_doc" = "xyes" || test ! -f "autogen.sh"]) -dnl = Manual =============================================================== +# prefixes for fixing gtk-doc references +GLIB_PREFIX="`$PKG_CONFIG --variable=prefix glib-2.0`" +PANGO_PREFIX="`$PKG_CONFIG --variable=prefix pango`" +AC_SUBST(GLIB_PREFIX) +AC_SUBST(PANGO_PREFIX) -AC_ARG_ENABLE(manual, - AC_HELP_STRING([--enable-manual=@<:@no/yes@:>@], - [Build application developers manual. Requires jw and xmlto binaries.]), - enable_manual=$enableval, enable_manual=no) +dnl === Manual ================================================================ -if test "x$enable_manual" = "xyes"; then - AC_PATH_PROG(JW, jw, no) - if test "x$JW" = "xno"; then - AC_MSG_ERROR(['jw' program needed by the manual not found in path]) - fi +AC_ARG_ENABLE([manual], + [AC_HELP_STRING([--enable-manual=@<:@no/yes@:>@], + [Build application developers manual. Requires jw and xmlto.])], + [enable_manual=$enableval], + [enable_manual=no]) - AC_PATH_PROG(XMLTO, xmlto, no) - if test "x$XMLTO" = "xno"; then - AC_MSG_ERROR(['xmlto' program needed by the manual not found in path]) - fi -fi +AS_IF([test "x$enable_manual" = "xyes"], + [ + AC_PATH_PROG(JW, [jw], [no]) + AS_IF([test "x$JW" = "xno"], + [AC_MSG_ERROR(['jw' program needed by the manual not found in path])] + ) -AM_CONDITIONAL(ENABLE_MANUAL, test "x$enable_manual" != "xno") + AC_PATH_PROG(XMLTO, [xmlto], [no]) + AS_IF([test "x$XMLTO" = "xno"], + [AC_MSG_ERROR(['xmlto' program needed by the manual not found in path])] + ) + ] +) -dnl ======================================================================== +AM_CONDITIONAL(ENABLE_MANUAL, [test "x$enable_manual" = "xyes"]) -AC_SUBST(GCC_FLAGS) - -CLUTTER_CFLAGS="$SDL_CFLAGS $EGL_CFLAGS $GLX_CFLAGS $OSX_CFLAGS $WIN32_CFLAGS $CLUTTER_DEPS_CFLAGS" -CLUTTER_LIBS="$SDL_LIBS $EGL_LIBS $GLX_LIBS $OSX_LIBS $WIN32_LIBS $CLUTTER_DEPS_LIBS" - -AC_SUBST(CLUTTER_CFLAGS) -AC_SUBST(CLUTTER_LIBS) +dnl === I18N ================================================================== GETTEXT_PACKAGE="clutter-$CLUTTER_API_VERSION" AC_SUBST(GETTEXT_PACKAGE) -AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", +AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, + "$GETTEXT_PACKAGE", [The prefix for our gettext translation domains.]) ALL_LINGUAS="" AM_GLIB_GNU_GETTEXT GLIB_DEFINE_LOCALEDIR(LOCALEDIR) +dnl =========================================================================== + SHAVE_INIT([build/autotools], [enable]) AC_CONFIG_FILES([ @@ -718,9 +771,9 @@ AC_CONFIG_FILES([ doc/Makefile doc/reference/Makefile doc/reference/clutter/Makefile - doc/reference/clutter/version.xml + doc/reference/clutter/clutter-docs.xml doc/reference/cogl/Makefile - doc/reference/cogl/version.xml + doc/reference/cogl/cogl-docs.xml doc/manual/clutter-manual.xml doc/manual/Makefile po/Makefile.in @@ -729,7 +782,7 @@ AC_CONFIG_FILES([ AC_OUTPUT -dnl ======================================================================== +dnl === Summary =============================================================== echo "" echo " Clutter $VERSION" @@ -741,40 +794,37 @@ echo " Flavour: ${clutterbackend}/${CLUTTER_COGL}" if test "x$clutterbackend" = "xeglx" || test "x$clutterbackend" = "xglx"; then echo " XInput: ${xinput}" fi -echo " GL Headers: ${CLUTTER_GL_HEADER}" +echo " GL headers: ${CLUTTER_GL_HEADER}" echo " Image backend: ${imagebackend}" echo " Target library: ${clutterbackendlib}" -echo " Clutter Debug level: ${enable_debug}" -echo " Enable COGL debug flags: ${enable_cogl_debug}" +echo " Clutter debug level: ${enable_debug}" +echo " COGL debug level: ${enable_cogl_debug}" echo " Compiler flags: ${CPPFLAGS} ${MAINTAINER_CFLAGS}" -echo " Build API Documentation: ${enable_gtk_doc}" -echo " Build Manual Documentation: ${enable_manual}" -echo " Build Introspection data: ${enable_introspection}" +echo " Build API documentation: ${enable_gtk_doc}" +echo " Build manual documentation: ${enable_manual}" +echo " Build introspection data: ${enable_introspection}" echo "" - # you can add more configuration options or flags that will bring up the # the experimental/unstable warning summary. if test "x$imagebackend" = "xinternal"; then experimental_stuff="$experimental_stuff imagebackend: $imagebackend\n" fi + if test "x$clutterbackend" = "xfruity"; then experimental_stuff="$experimental_stuff clutterbackend: $clutterbackend\n" fi - if test "x$experimental_stuff" != "x"; then -echo "" -echo "☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠" -echo " *WARNING*" -echo "" -echo " Experimental features configured, stability of your build either uses" -echo " experimental backends or experimental and unsupported features:" -echo "" -echo -e "$experimental_stuff" -echo "☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠" -echo "" + echo "" + echo "☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠" + echo " *WARNING*" + echo "" + echo " The stability of your build might be affected by one or more" + echo " experimental backends or experimental and unsupported features:" + echo "" + echo -e "$experimental_stuff" + echo "☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠" + echo "" fi - - diff --git a/doc/clutter-actor-invariants.txt b/doc/clutter-actor-invariants.txt index c64f84cc6..b7c74659f 100644 --- a/doc/clutter-actor-invariants.txt +++ b/doc/clutter-actor-invariants.txt @@ -28,20 +28,56 @@ ClutterActor. a. Public ClutterActor Flags CLUTTER_ACTOR_REALIZED - Set by clutter_actor_realize(), unset by clutter_actor_unrealize(). - Means: the actor has GPU resources associated to its paint cycle. - Once realized an actor needs to be explicitly unrealized unless - being destroyed. Hide, reparent etc will not unrealize. + Means: the actor has GPU resources associated to its paint + cycle. + + Set by clutter_actor_realize(), unset by + clutter_actor_unrealize(). Generally set implicitly when the + actor becomes MAPPED (see below). + + May only be set if one of the actor's ancestors is a toplevel. + May only be set if all of the actor's ancestors are realized. + + Once realized an actor remains realized until removed from the + toplevel. Hide, reparent will not unrealize; but unparent or + destroy will unrealize since they remove the actor from the + toplevel. CLUTTER_ACTOR_MAPPED - Set by clutter_actor_show(), unset by clutter_actor_hide() - May only be set if CLUTTER_ACTOR_IS_REALIZED (actor). - Means: the actor has been set as visible + Means: the actor will be painted if the stage is mapped. + + On non-toplevels, will be set if all of the following are + true, and unset otherwise: + * the actor's VISIBLE flag is set + * all of the actor's non-toplevel ancestors have the MAPPED + flag set + * the actor has a toplevel ancestor + * the toplevel ancestor's VISIBLE flag is set + * the toplevel ancestor's REALIZED flag is set + + On toplevels, MAPPED is set asynchronously when the window + system notifies Clutter that the toplevel has been made + visible on the screen. + + The MAPPED flag requires that an actor is REALIZED. When + Clutter sets the MAPPED flag, it forces realization; this is + the "normal" way for realization to occur, though explicit + realization with clutter_actor_realize() is permitted. CLUTTER_ACTOR_VISIBLE - Implies: CLUTTER_ACTOR_IS_REALIZED (actor) - && - CLUTTER_ACTOR_IS_MAPPED (actor) + Means: the actor's "visible" property was set to true by + the application programmer. + + Set by clutter_actor_show(), unset by clutter_actor_hide(). + + This is an application-controlled property, while MAPPED and + REALIZED are usually managed by Clutter (with the exception + that applications can "realize early" with + clutter_actor_realize()). + + If VISIBLE is unset, the actor (and any children) must + be immediately unmapped, to maintain the invariants for + the MAPPED flag. CLUTTER_ACTOR_REACTIVE Set and unset by clutter_actor_set_reactive() @@ -51,7 +87,7 @@ CLUTTER_ACTOR_REACTIVE parent implementation. In the case of ClutterGroup it being marked unreactive does not mark all children unreactive. * Clutter stage is always reactive. - + b. Private ClutterActor flags @@ -63,7 +99,18 @@ CLUTTER_ACTOR_IS_TOPLEVEL Set internally by the initialization of ClutterStage CLUTTER_ACTOR_IN_REPARENT - Set internally by clutter_actor_reparent() + Set internally by clutter_actor_reparent(). This flag + optimizes the reparent process by avoiding the need + to pass through an unrealized state when the actor is + removed from the old parent. + +CLUTTER_ACTOR_ABOUT_TO_UNPARENT + Set internally during part of clutter_actor_unparent(). + Causes the actor to pretend it has no parent, then + update invariants; which effectively forces the actor + to unrealize. The purpose of this is to unrealize _before_ the + actor is removed from the stage, so unrealize implementations + can use clutter_actor_get_stage(). CLUTTER_ACTOR_SYNC_MATRICES Set internally by ClutterStage implementations @@ -101,68 +148,118 @@ In the following 1) CLUTTER_ACTOR_IN_DESTRUCTION => !CLUTTER_ACTOR_IS_MAPPED (actor) && !CLUTTER_ACTOR_IS_REALIZED (actor) - clutter_actor_destroy() will cause an actor to be hidden - and unrealized. + clutter_actor_destroy() will cause an actor to be unparented, + which means the actor must be unmapped and unrealized as + well. 2) CLUTTER_ACTOR_IS_MAPPED (actor) => CLUTTER_ACTOR_IS_REALIZED (actor) - calling clutter_actor_show() on an unrealized actor will cause - a realization to happen. + when an actor is mapped, it must first be realized. + + This is the most common way an actor becomes realized. 3) if clutter_actor_set_parent (actor, parent): - CLUTTER_ACTOR_IS_REALIZED (parent) => CLUTTER_ACTOR_IS_REALIZED (actor) + ((parent_is_not_toplevel && CLUTTER_ACTOR_IS_MAPPED (parent)) || + (parent_is_toplevel && CLUTTER_ACTOR_IS_VISIBLE(parent))) && + CLUTTER_ACTOR_IS_VISIBLE (actor) + => CLUTTER_ACTOR_IS_MAPPED (actor) - calling clutter_actor_set_parent() on an actor and a realized - parent will cause a realization on the actor. + calling clutter_actor_set_parent() on an actor and a mapped + parent will map the actor if it has been shown. 4) if clutter_actor_unparent (actor): CLUTTER_ACTOR_IS_MAPPED (actor) <=> CLUTTER_ACTOR_IN_REPARENT - calling clutter_actor_unparent() on an actor will hide the actor; - calling clutter_actor_reparent() on an actor will leave the actor - in the same state. + calling clutter_actor_unparent() on an actor will unmap and + unrealize the actor since it no longer has a toplevel. - Neither will unrealize. + calling clutter_actor_reparent() on an actor will leave the + actor mapped and realized (if it was before) until it has a + new parent, at which point the invariants implied by the new + parent's state are applied. + +5) CLUTTER_ACTOR_IS_REALIZED(actor) => CLUTTER_ACTOR_IS_REALIZED(parent) + + Actors may only be realized if their parent is realized. + However, they may be unrealized even though their parent + is realized. + + This implies that an actor may not be realized unless + it has a parent, or is a toplevel. + + Since only toplevels can realize without a parent, no actor + can be realized unless it either is a toplevel or has a + toplevel ancestor. + + As long as they are unmapped, actors may be unrealized. This + will force all children of the actor to be unrealized, since + children may not be realized while parents are unrealized. + +6) CLUTTER_ACTOR_IS_MAPPED(actor) <=> + ( ( (CLUTTER_ACTOR_IS_VISIBLE(toplevel_parent) && + CLUTTER_ACTOR_IS_REALIZED(toplevel_parent)) || + CLUTTER_ACTOR_IS_MAPPED(non_toplevel_parent) ) ) && + CLUTTER_ACTOR_IS_VISIBLE(actor) + + Actors _must_ be mapped if and only if they are visible and + their parent is mapped, or they are visible and their + parent is a toplevel that's realized and visible. + + This invariant enables us to track whether an actor will + be painted (whether it's MAPPED) without ever traversing + the actor graph. iii. State changes ------------------------------------------------------------------------------- clutter_actor_show: - 1. if !CLUTTER_ACTOR_REALIZED calls clutter_actor_realize - 2. sets CLUTTER_ACTOR_MAPPED + 1. sets VISIBLE + 2. sets MAPPED if invariants are met; mapping in turn sets + REALIZED clutter_actor_hide: - 1. sets !CLUTTER_ACTOR_MAPPED + 1. sets !VISIBLE + 2. unsets MAPPED if actor was mapped previously + 3. does not affect REALIZED clutter_actor_destroy: 1. sets CLUTTER_ACTOR_IN_DESTRUCTION + 2. unparents the actor, which in turn implies unmap and unrealize clutter_actor_realize: - sets CLUTTER_ACTOR_REALIZED + 1. attempts to set REALIZED on all parents, failing if + invariants are not met, e.g. not in a toplevel yet + 2. sets REALIZED on actor if parent was successfully realized -clutter_actor_unrealized: - 1. if CLUTTER_ACTOR_MAPPED calls clutter_actor_hide - 2. sets !CLUTTER_ACTOR_REALIZED +clutter_actor_unrealize: + 1. sets !VISIBLE which forces !MAPPED + 2. sets !REALIZED + 3. !MAPPED and !REALIZED forces unmap and unrealize of all + children clutter_actor_set_parent: 1. sets actor->parent - 2. if parent is CLUTTER_ACTOR_REALIZED calls clutter_actor_realize - 3. if actor->show_on_set_parent is TRUE calls clutter_actor_show + 2. if actor->show_on_set_parent is TRUE calls clutter_actor_show + 3. sets MAPPED if all prerequisites are now met for map 4. if !CLUTTER_ACTOR_IN_REPARENT emits ::parent-set with old_parent set to NULL -clutter_actor_unset_parent: +clutter_actor_unparent: 1. unsets actor->parent - 2. if !CLUTTER_ACTOR_IN_REPARENT calls clutter_actor_hide + 2. if !CLUTTER_ACTOR_IN_REPARENT, sets !MAPPED and !REALIZED + since the invariants for those flags are no longer met 3. if !CLUTTER_ACTOR_IN_REPARENT emits ::parent-set with old_parent set to the previous parent clutter_actor_reparent: 1. sets CLUTTER_ACTOR_IN_REPARENT 2. emits ::parent-set with old_parent set to the previous parent - equivalent to: + equivalent to: clutter_actor_unparent clutter_actor_set_parent + 3. updates state of the actor to match invariants + (may change MAPPED or REALIZED in either direction, + depending on state of the new parent) iv. Responsibilities of a ClutterActor @@ -173,24 +270,27 @@ clutter_actor_reparent: When adding an actor to a container, the container must: 1. call clutter_actor_set_parent (actor, container) - 2. call clutter_actor_queue_relayout (container) + 2. call clutter_actor_queue_relayout (container) if + adding the actor changes the container's preferred + size b. Removing from a container When removing an actor from a container, the container must: 1. call clutter_actor_unparent (actor) - 2. call clutter_actor_queue_relayout (container) + 2. call clutter_actor_queue_relayout (container) if removing + the actor changes the container's preferred size Notes: * here a container actor is any actor that contains children actors; it does not imply the implementation of the ClutterContainer interface. -* clutter_actor_unparent() will hide the actor except in the special case - when CLUTTER_ACTOR_IN_REPARENT is set. +* clutter_actor_unparent() will unmap and unrealize the actor except + in the special case when CLUTTER_ACTOR_IN_REPARENT is set. -* 'Composite' Clutter actors need to pass down any allocations to children. +* 'Composite' Clutter actors need to pass down any allocations to children. c. Initial state diff --git a/doc/reference/clutter/Makefile.am b/doc/reference/clutter/Makefile.am index a5773a2ed..61d7fc16c 100644 --- a/doc/reference/clutter/Makefile.am +++ b/doc/reference/clutter/Makefile.am @@ -72,6 +72,7 @@ IGNORE_HFILES=\ clutter-keysyms.h \ clutter-keysyms-table.h \ clutter-marshal.h \ + clutter-master-clock.h \ clutter-model-private.h \ clutter-private.h \ clutter-id-pool.h \ @@ -112,7 +113,6 @@ HTML_IMAGES=\ # Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). # e.g. content_files=running.sgml building.sgml changes-2.0.sgml content_files= \ - version.xml \ subclassing-ClutterActor.xml \ clutter-animation-tutorial.xml \ creating-behaviours.xml \ @@ -146,7 +146,6 @@ include $(top_srcdir)/gtk-doc.make # Other files to distribute # e.g. EXTRA_DIST += version.xml.in EXTRA_DIST += \ - version.xml.in \ actor-box.png \ easing-modes.png \ easing-modes.svg \ diff --git a/doc/reference/clutter/clutter-docs.xml b/doc/reference/clutter/clutter-docs.xml.in similarity index 99% rename from doc/reference/clutter/clutter-docs.xml rename to doc/reference/clutter/clutter-docs.xml.in index 48f0a0fd7..61e1126f2 100644 --- a/doc/reference/clutter/clutter-docs.xml +++ b/doc/reference/clutter/clutter-docs.xml.in @@ -1,7 +1,7 @@ + ]> diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt index 8aefb9350..ff8e0fd2e 100644 --- a/doc/reference/clutter/clutter-sections.txt +++ b/doc/reference/clutter/clutter-sections.txt @@ -27,44 +27,35 @@ clutter_media_get_type
clutter-units Unit conversion -ClutterUnit -CLUTTER_UNITS_FORMAT -CLUTTER_UNITS_FROM_FLOAT -CLUTTER_UNITS_TO_FLOAT -CLUTTER_UNITS_FROM_INT -CLUTTER_UNITS_TO_INT - - -CLUTTER_UNITS_FROM_DEVICE -CLUTTER_UNITS_TO_DEVICE -CLUTTER_UNITS_FROM_FIXED -CLUTTER_UNITS_TO_FIXED -CLUTTER_UNITS_FROM_PANGO_UNIT -CLUTTER_UNITS_TO_PANGO_UNIT -CLUTTER_UNITS_FROM_MM -CLUTTER_UNITS_FROM_POINTS -CLUTTER_UNITS_FROM_EM +ClutterUnitType +ClutterUnits clutter_units_mm clutter_units_pt clutter_units_em +clutter_units_em_for_font clutter_units_pixels clutter_units_to_pixels +clutter_units_copy +clutter_units_free +clutter_units_get_unit_type +clutter_units_get_unit_value +clutter_units_from_string +clutter_units_to_string -CLUTTER_MAXUNIT -CLUTTER_MINUNIT -ClutterParamSpecUnit -clutter_param_spec_unit -CLUTTER_VALUE_HOLDS_UNIT -clutter_value_set_unit -clutter_value_get_unit +ClutterParamSpecUnits +clutter_param_spec_units +CLUTTER_VALUE_HOLDS_UNITS +clutter_value_set_units +clutter_value_get_units + -CLUTTER_TYPE_UNIT -CLUTTER_TYPE_PARAM_UNIT -CLUTTER_PARAM_SPEC_UNIT -CLUTTER_IS_PARAM_SPEC_UNIT -clutter_unit_get_type -clutter_param_unit_get_type +CLUTTER_TYPE_UNITS +CLUTTER_TYPE_PARAM_UNITS +CLUTTER_PARAM_SPEC_UNITS +CLUTTER_IS_PARAM_SPEC_UNITS +clutter_units_get_type +clutter_param_units_get_type
@@ -186,6 +177,7 @@ clutter_container_remove clutter_container_remove_valist clutter_container_get_children clutter_container_foreach +clutter_container_foreach_with_internals clutter_container_find_child_by_name @@ -275,6 +267,11 @@ CLUTTER_CALLBACK ClutterCallback ClutterActor ClutterActorClass +clutter_actor_set_flags +clutter_actor_unset_flags +clutter_actor_get_flags + + clutter_actor_show clutter_actor_show_all clutter_actor_hide @@ -288,10 +285,13 @@ clutter_actor_destroy clutter_actor_event clutter_actor_pick clutter_actor_should_pick_paint +clutter_actor_map +clutter_actor_unmap clutter_actor_allocate clutter_actor_allocate_preferred_size +clutter_actor_allocate_available_size clutter_actor_get_allocation_coords clutter_actor_get_allocation_box clutter_actor_get_allocation_geometry @@ -386,34 +386,6 @@ clutter_actor_set_shader_param clutter_actor_set_shader_param_float clutter_actor_set_shader_param_int - -clutter_actor_set_depthu -clutter_actor_get_depthu -clutter_actor_set_heightu -clutter_actor_get_heightu -clutter_actor_set_widthu -clutter_actor_get_widthu -clutter_actor_set_xu -clutter_actor_get_xu -clutter_actor_set_yu -clutter_actor_get_yu -clutter_actor_set_positionu -clutter_actor_get_positionu -clutter_actor_set_sizeu -clutter_actor_get_sizeu -clutter_actor_set_scale_fullu -clutter_actor_get_scale_centeru -clutter_actor_set_anchor_pointu -clutter_actor_get_anchor_pointu -clutter_actor_move_anchor_pointu -clutter_actor_set_clipu -clutter_actor_get_clipu -clutter_actor_set_rotationu -clutter_actor_get_rotationu -clutter_actor_move_byu -clutter_actor_get_transformed_positionu -clutter_actor_get_transformed_sizeu - clutter_actor_grab_key_focus clutter_actor_get_pango_context @@ -458,10 +430,9 @@ clutter_texture_set_from_yuv_data clutter_texture_set_area_from_rgb_data clutter_texture_get_base_size clutter_texture_get_pixel_format +clutter_texture_get_max_tile_waste clutter_texture_get_filter_quality clutter_texture_set_filter_quality -clutter_texture_get_max_tile_waste -clutter_texture_set_max_tile_waste clutter_texture_get_cogl_texture clutter_texture_set_cogl_texture clutter_texture_get_cogl_material @@ -509,6 +480,7 @@ clutter_stage_fullscreen clutter_stage_unfullscreen clutter_stage_show_cursor clutter_stage_hide_cursor +ClutterPickMode clutter_stage_get_actor_at_pos clutter_stage_ensure_current clutter_stage_ensure_viewport @@ -560,18 +532,13 @@ clutter_stage_add ClutterTimeline ClutterTimelineClass clutter_timeline_new -clutter_timeline_new_for_duration clutter_timeline_clone -clutter_timeline_set_speed -clutter_timeline_get_speed clutter_timeline_set_duration clutter_timeline_get_duration clutter_timeline_set_loop clutter_timeline_get_loop -clutter_timeline_set_n_frames -clutter_timeline_get_n_frames clutter_timeline_set_delay clutter_timeline_get_delay ClutterTimelineDirection @@ -585,14 +552,13 @@ clutter_timeline_stop clutter_timeline_rewind clutter_timeline_skip clutter_timeline_advance -clutter_timeline_get_current_frame +clutter_timeline_get_elapsed_time clutter_timeline_get_delta clutter_timeline_get_progress clutter_timeline_get_progressx clutter_timeline_is_playing -clutter_timeline_add_marker_at_frame clutter_timeline_add_marker_at_time clutter_timeline_has_marker clutter_timeline_list_markers @@ -609,6 +575,7 @@ CLUTTER_TIMELINE_GET_CLASS ClutterTimelinePrivate clutter_timeline_get_type +clutter_timeline_advance_delta
@@ -1034,6 +1001,8 @@ clutter_threads_add_timeout clutter_threads_add_timeout_full clutter_threads_add_frame_source clutter_threads_add_frame_source_full +clutter_threads_add_repaint_func +clutter_threads_remove_repaint_func clutter_get_keyboard_grab @@ -1526,6 +1495,7 @@ clutter_cairo_texture_get_surface_size clutter_cairo_texture_create clutter_cairo_texture_create_region +clutter_cairo_texture_clear clutter_cairo_set_source_color diff --git a/doc/reference/clutter/version.xml.in b/doc/reference/clutter/version.xml.in deleted file mode 100644 index 7fc1bf340..000000000 --- a/doc/reference/clutter/version.xml.in +++ /dev/null @@ -1 +0,0 @@ -@CLUTTER_VERSION@ \ No newline at end of file diff --git a/doc/reference/cogl/Makefile.am b/doc/reference/cogl/Makefile.am index 82b96928f..9888caaa3 100644 --- a/doc/reference/cogl/Makefile.am +++ b/doc/reference/cogl/Makefile.am @@ -24,7 +24,7 @@ DOC_SOURCE_DIR=../../../clutter/cogl SCANGOBJ_OPTIONS=--type-init-func="g_type_init()" # Extra options to supply to gtkdoc-scan. -# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" +# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" SCAN_OPTIONS=--deprecated-guards="COGL_DISABLE_DEPRECATED" # Extra options to supply to gtkdoc-mkdb. @@ -70,12 +70,14 @@ HTML_IMAGES= # Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). # e.g. content_files=running.sgml building.sgml changes-2.0.sgml -content_files= version.xml +content_files = \ + blend-strings.xml # SGML files where gtk-doc abbrevations (#GtkWidget) are expanded # These files must be listed here *and* in content_files # e.g. expand_content_files=running.sgml -expand_content_files= +expand_content_files = \ + blend-strings.xml # CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. # Only needed if you are using gtkdoc-scangobj to dynamically query widget @@ -91,4 +93,3 @@ include $(top_srcdir)/gtk-doc.make # Other files to distribute # e.g. EXTRA_DIST += version.xml.in -EXTRA_DIST += version.xml.in diff --git a/doc/reference/cogl/blend-strings.xml b/doc/reference/cogl/blend-strings.xml new file mode 100644 index 000000000..9c3c8d3c9 --- /dev/null +++ b/doc/reference/cogl/blend-strings.xml @@ -0,0 +1,130 @@ + + +]> + + + +Material Blend Strings +3 +COGL Library + + + +Material Blend Strings +A simple syntax and grammar for describing blending and texture +combining functions. + + + +Cogl Blend Strings + +Describing GPU blending and texture combining states is rather awkward to do +in a consise but also readable fashion. Cogl helps by supporting +string based descriptions using a simple syntax. + + +
+Some examples + +Here is an example used for blending: + +"RGBA = ADD (SRC_COLOR * (SRC_COLOR[A]), DST_COLOR * (1-SRC_COLOR[A]))" + +In OpenGL terms this replaces glBlendFunc[Separate] and +glBlendEquation[Separate] + +Actually in this case it's more verbose than the GL equivalent: + + +glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + +But unless you are familiar with OpenGL or refer to its API documentation +you wouldn't know that the default function used by OpenGL is GL_FUNC_ADD +nor would you know that the above arguments determine what the source color +and destination color will be multiplied by before being adding. + + +Here is an example used for texture combining: + +"RGB = REPLACE (PREVIOUS)" +"A = MODULATE (PREVIOUS, TEXTURE)" + + +In OpenGL terms this replaces glTexEnv, and the above example is equivalent +to this OpenGL code: + + + glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); + glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); + glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE); + glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); + + +
+ +
+Here's the syntax + + +<statement>: + <channel-mask>=<function-name>(<arg-list>) + + You can either use a single statement with an RGBA channel-mask or you can use + two statements; one with an A channel-mask and the other with an RGB + channel-mask. + +<channel-mask>: + A or RGB or RGBA + +<function-name>: + [A-Za-z_]* + +<arg-list>: + <arg>,<arg> + or <arg> + or "" + + I.e. functions may take 0 or more arguments + +<arg>: + <color-source> + 1 - <color-source> : Only intended for texture combining + <color-source> * ( <factor> ) : Only intended for blending + 0 : Only intended for blending + + See the blending or texture combining sections for further notes and examples. + +<color-source>: + <source-name>[<channel-mask>] + <source-name> + + See the blending or texture combining sections for the list of source-names + valid in each context. + + If a channel mask is not given then the channel mask of the statement + is assumed instead. + +<factor>: + 0 + 1 + <color-source> + 1-<color-source> + SRC_ALPHA_SATURATE + + +
+ + +
+ + +
diff --git a/doc/reference/cogl/cogl-docs.xml b/doc/reference/cogl/cogl-docs.xml.in similarity index 97% rename from doc/reference/cogl/cogl-docs.xml rename to doc/reference/cogl/cogl-docs.xml.in index ba5d2cf89..7f9c1c26b 100644 --- a/doc/reference/cogl/cogl-docs.xml +++ b/doc/reference/cogl/cogl-docs.xml.in @@ -1,7 +1,7 @@ + ]> @@ -55,6 +55,7 @@ + diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index 3032a6863..872e02d11 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -15,33 +15,35 @@ COGL_UNPREMULT_MASK CoglPixelFormat CoglBufferTarget -cogl_create_context -cogl_destroy_context - CoglFeatureFlags cogl_get_features cogl_features_available cogl_check_extension cogl_get_proc_address -cogl_perspective -cogl_frustum -cogl_setup_viewport -cogl_viewport -cogl_get_modelview_matrix -cogl_get_projection_matrix -cogl_get_viewport - cogl_push_matrix cogl_pop_matrix cogl_scale cogl_translate cogl_rotate +cogl_frustum +cogl_perspective +cogl_ortho + +cogl_get_modelview_matrix +cogl_set_modelview_matrix +cogl_get_projection_matrix +cogl_set_projection_matrix +cogl_viewport +cogl_setup_viewport +cogl_get_viewport cogl_clear cogl_get_bitmasks -cogl_enable_depth_test -cogl_enable_backface_culling +cogl_set_depth_test_enabled +cogl_get_depth_test_enabled +cogl_set_backface_culling_enabled +cogl_get_backface_culling_enabled CoglFogMode cogl_set_fog @@ -130,12 +132,9 @@ cogl_texture_get_height cogl_texture_get_format cogl_texture_get_rowstride cogl_texture_get_max_waste -cogl_texture_get_min_filter -cogl_texture_get_mag_filter cogl_texture_is_sliced cogl_texture_get_gl_texture cogl_texture_get_data -cogl_texture_set_filters cogl_texture_set_region
@@ -307,7 +306,11 @@ cogl_vertex_buffer_submit cogl_vertex_buffer_disable cogl_vertex_buffer_enable cogl_vertex_buffer_draw +CoglIndicesType +cogl_vertex_buffer_add_indices +cogl_vertex_buffer_delete_indices cogl_vertex_buffer_draw_elements +cogl_vertex_buffer_indices_get_for_quads CoglVertexBufferAttribFlags COGL_VERTEX_BUFFER_ATTRIB_FLAG_GL_TYPE_MASK @@ -349,41 +352,35 @@ cogl_material_set_specular cogl_material_get_specular cogl_material_set_shininess cogl_material_get_shininess - CoglMaterialAlphaFunc cogl_material_set_alpha_test_function CoglMaterialBlendFactor -cogl_material_set_blend_factors +cogl_material_set_blend +cogl_material_set_blend_constant cogl_material_set_layer cogl_material_remove_layer -CoglMaterialLayerCombineFunc -cogl_material_set_layer_combine_function -CoglMaterialLayerCombineChannels -CoglMaterialLayerCombineSrc -cogl_material_set_layer_combine_arg_src -CoglMaterialLayerCombineOp -cogl_material_set_layer_combine_arg_op +cogl_material_set_layer_combine +cogl_material_set_layer_combine_constant cogl_material_set_layer_matrix +cogl_material_get_layers +CoglMaterialFilter +cogl_material_set_layer_filters +cogl_material_layer_get_type +cogl_material_layer_get_texture +cogl_material_layer_get_min_filter +cogl_material_layer_get_mag_filter CoglMaterial CoglMaterialFlags CoglMaterialLayerPrivFlags -cogl_material_set_layer_alpha_combine -cogl_material_set_layer_rgb_combine
cogl-material-internals Material Internals -cogl_material_get_cogl_enable_flags -CoglMaterialFlushOption -cogl_material_flush_gl_state CoglMaterialLayer cogl_material_get_layers CoglMaterialLayerType cogl_material_layer_get_type -CoglMaterialLayerFlags -cogl_material_layer_get_flags cogl_material_layer_get_texture -cogl_material_layer_flush_gl_sampler_state
diff --git a/doc/reference/cogl/version.xml.in b/doc/reference/cogl/version.xml.in deleted file mode 100644 index 7fc1bf340..000000000 --- a/doc/reference/cogl/version.xml.in +++ /dev/null @@ -1 +0,0 @@ -@CLUTTER_VERSION@ \ No newline at end of file diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am index 5fd68034a..ecbcb1f8f 100644 --- a/tests/conform/Makefile.am +++ b/tests/conform/Makefile.am @@ -7,10 +7,8 @@ test_conformance_SOURCES = \ test-conform-common.c \ test-conform-common.h \ \ - test-timeline-dup-frames.c \ test-timeline-interpolate.c \ test-timeline-rewind.c \ - test-timeline-smoothness.c \ test-timeline.c \ test-vertex-buffer-contiguous.c \ test-vertex-buffer-interleved.c \ @@ -28,6 +26,9 @@ test_conformance_SOURCES = \ test-anchors.c \ test-npot-texture.c \ test-model.c \ + test-blend-strings.c \ + test-color.c \ + test-clutter-units.c \ $(NULL) # For convenience, this provides a way to easily run individual unit tests: @@ -59,7 +60,7 @@ clean-wrappers: # NB: BUILT_SOURCES here a misnomer. We aren't building source, just inserting # a phony rule that will generate symlink scripts for running individual tests BUILT_SOURCES = wrappers - + test_conformance_CFLAGS = \ -I$(top_srcdir)/ \ -I$(top_srcdir)/clutter \ @@ -77,6 +78,9 @@ test_conformance_LDADD = $(top_builddir)/clutter/libclutter-@CLUTTER_FLAVOUR@-@C test: @gtester -o=test-conformance-results.xml ./test-conformance +test-verbose: + @gtester --verbose -o=test-conformance-result.xml ./test-conformance + test-report-normal: @gtester -o=test-conformance-results.xml -k ./test-conformance \ && ( gtester-report test-conformance-results.xml \ diff --git a/tests/conform/test-actor-invariants.c b/tests/conform/test-actor-invariants.c index 315abeed6..77eea9ad2 100644 --- a/tests/conform/test-actor-invariants.c +++ b/tests/conform/test-actor-invariants.c @@ -21,15 +21,38 @@ test_initial_state (TestConformSimpleFixture *fixture, } void -test_realized (TestConformSimpleFixture *fixture, - gconstpointer data) +test_shown_not_parented (TestConformSimpleFixture *fixture, + gconstpointer data) { ClutterActor *actor; actor = clutter_rectangle_new (); + clutter_actor_show (actor); + + g_assert (!CLUTTER_ACTOR_IS_REALIZED (actor)); + g_assert (!CLUTTER_ACTOR_IS_MAPPED (actor)); + g_assert (CLUTTER_ACTOR_IS_VISIBLE (actor)); + + clutter_actor_destroy (actor); +} + +void +test_realized (TestConformSimpleFixture *fixture, + gconstpointer data) +{ + ClutterActor *actor; + ClutterActor *stage; + + stage = clutter_stage_get_default (); + + actor = clutter_rectangle_new (); + g_assert (!(CLUTTER_ACTOR_IS_REALIZED (actor))); + clutter_actor_hide (actor); /* don't show, so won't map */ + clutter_container_add_actor (CLUTTER_CONTAINER (stage), + actor); clutter_actor_realize (actor); g_assert (CLUTTER_ACTOR_IS_REALIZED (actor)); @@ -45,33 +68,130 @@ test_mapped (TestConformSimpleFixture *fixture, gconstpointer data) { ClutterActor *actor; + ClutterActor *stage; + + stage = clutter_stage_get_default (); actor = clutter_rectangle_new (); g_assert (!(CLUTTER_ACTOR_IS_REALIZED (actor))); g_assert (!(CLUTTER_ACTOR_IS_MAPPED (actor))); - clutter_actor_show (actor); + clutter_container_add_actor (CLUTTER_CONTAINER (stage), + actor); g_assert (CLUTTER_ACTOR_IS_REALIZED (actor)); g_assert (CLUTTER_ACTOR_IS_MAPPED (actor)); - g_assert (CLUTTER_ACTOR_IS_VISIBLE (actor)); clutter_actor_destroy (actor); } +void +test_realize_not_recursive (TestConformSimpleFixture *fixture, + gconstpointer data) +{ + ClutterActor *actor, *group; + ClutterActor *stage; + + stage = clutter_stage_get_default (); + + group = clutter_group_new (); + + actor = clutter_rectangle_new (); + + clutter_actor_hide (group); /* don't show, so won't map */ + clutter_actor_hide (actor); /* don't show, so won't map */ + + g_assert (!(CLUTTER_ACTOR_IS_REALIZED (group))); + g_assert (!(CLUTTER_ACTOR_IS_REALIZED (actor))); + + clutter_container_add_actor (CLUTTER_CONTAINER (stage), + group); + clutter_container_add_actor (CLUTTER_CONTAINER (group), + actor); + + clutter_actor_realize (group); + + g_assert (CLUTTER_ACTOR_IS_REALIZED (group)); + + g_assert (!(CLUTTER_ACTOR_IS_MAPPED (group))); + g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (group))); + + /* realizing group did not realize the child */ + g_assert (!CLUTTER_ACTOR_IS_REALIZED (actor)); + g_assert (!(CLUTTER_ACTOR_IS_MAPPED (actor))); + g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (actor))); + + clutter_actor_destroy (group); +} + +void +test_map_recursive (TestConformSimpleFixture *fixture, + gconstpointer data) +{ + ClutterActor *actor, *group; + ClutterActor *stage; + + stage = clutter_stage_get_default (); + + group = clutter_group_new (); + + actor = clutter_rectangle_new (); + + clutter_actor_hide (group); /* hide at first */ + clutter_actor_show (actor); /* show at first */ + + g_assert (!(CLUTTER_ACTOR_IS_REALIZED (group))); + g_assert (!(CLUTTER_ACTOR_IS_REALIZED (actor))); + g_assert (!(CLUTTER_ACTOR_IS_MAPPED (group))); + g_assert (!(CLUTTER_ACTOR_IS_MAPPED (actor))); + g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (group))); + g_assert ((CLUTTER_ACTOR_IS_VISIBLE (actor))); + + clutter_container_add_actor (CLUTTER_CONTAINER (stage), + group); + clutter_container_add_actor (CLUTTER_CONTAINER (group), + actor); + + g_assert (!(CLUTTER_ACTOR_IS_REALIZED (group))); + g_assert (!(CLUTTER_ACTOR_IS_REALIZED (actor))); + g_assert (!(CLUTTER_ACTOR_IS_MAPPED (group))); + g_assert (!(CLUTTER_ACTOR_IS_MAPPED (actor))); + g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (group))); + g_assert ((CLUTTER_ACTOR_IS_VISIBLE (actor))); + + /* show group, which should map and realize both + * group and child. + */ + clutter_actor_show (group); + g_assert (CLUTTER_ACTOR_IS_REALIZED (group)); + g_assert (CLUTTER_ACTOR_IS_REALIZED (actor)); + g_assert (CLUTTER_ACTOR_IS_MAPPED (group)); + g_assert (CLUTTER_ACTOR_IS_MAPPED (actor)); + g_assert (CLUTTER_ACTOR_IS_VISIBLE (group)); + g_assert (CLUTTER_ACTOR_IS_VISIBLE (actor)); + + clutter_actor_destroy (group); +} + void test_show_on_set_parent (TestConformSimpleFixture *fixture, gconstpointer data) { ClutterActor *actor, *group; gboolean show_on_set_parent; + ClutterActor *stage; + + stage = clutter_stage_get_default (); group = clutter_group_new (); g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (group))); + clutter_container_add_actor (CLUTTER_CONTAINER (stage), + group); + actor = clutter_rectangle_new (); g_object_get (G_OBJECT (actor), "show-on-set-parent", &show_on_set_parent, @@ -94,8 +214,9 @@ test_show_on_set_parent (TestConformSimpleFixture *fixture, "show-on-set-parent", &show_on_set_parent, NULL); - g_assert (CLUTTER_ACTOR_IS_REALIZED (actor)); - g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (actor))); + g_assert (!CLUTTER_ACTOR_IS_REALIZED (actor)); + g_assert (!CLUTTER_ACTOR_IS_MAPPED (actor)); + g_assert (CLUTTER_ACTOR_IS_VISIBLE (actor)); g_assert (show_on_set_parent == TRUE); clutter_actor_destroy (actor); diff --git a/tests/conform/test-anchors.c b/tests/conform/test-anchors.c index f0211241f..e4d906ff6 100644 --- a/tests/conform/test-anchors.c +++ b/tests/conform/test-anchors.c @@ -20,8 +20,8 @@ #define NOTIFY_ROTATION_CENTER_Z (1 << 13) #define NOTIFY_ROTATION_CENTER_Z_GRAVITY (1 << 14) -#define RECT_WIDTH 100 -#define RECT_HEIGHT 80 +#define RECT_WIDTH 100.0 +#define RECT_HEIGHT 80.0 /* Allow the transformed position by off by a certain number of pixels */ @@ -36,7 +36,8 @@ typedef struct _TestState static const struct { ClutterGravity gravity; - gint x_pos, y_pos; + gfloat x_pos; + gfloat y_pos; } gravities[] = { { CLUTTER_GRAVITY_NORTH, RECT_WIDTH / 2, 0 }, @@ -50,23 +51,25 @@ static const struct { CLUTTER_GRAVITY_CENTER, RECT_WIDTH / 2, RECT_HEIGHT / 2 } }; -static const char * const -properties[] = - { "anchor-x", - "anchor-y", - "anchor-gravity", - "scale-x", - "scale-y", - "scale-center-x", - "scale-center-y", - "scale-gravity", - "rotation-angle-x", - "rotation-angle-y", - "rotation-angle-z", - "rotation-center-x", - "rotation-center-y", - "rotation-center-z", - "rotation-center-z-gravity" }; +static const char * const properties[] = { + "anchor-x", + "anchor-y", + "anchor-gravity", + "scale-x", + "scale-y", + "scale-center-x", + "scale-center-y", + "scale-gravity", + "rotation-angle-x", + "rotation-angle-y", + "rotation-angle-z", + "rotation-center-x", + "rotation-center-y", + "rotation-center-z", + "rotation-center-z-gravity" +}; + +static const int n_properties = G_N_ELEMENTS (properties); static void notify_cb (GObject *object, GParamSpec *pspec, TestState *state) @@ -75,10 +78,11 @@ notify_cb (GObject *object, GParamSpec *pspec, TestState *state) int new_flags = 0; int flag = 1; - for (i = 0; i < G_N_ELEMENTS (properties); i++) + for (i = 0; i < n_properties; i++) { if (!strcmp (properties[i], pspec->name)) new_flags |= flag; + flag <<= 1; } @@ -87,43 +91,30 @@ notify_cb (GObject *object, GParamSpec *pspec, TestState *state) state->notifications |= new_flags; } -#define assert_notifications(flags) \ - do \ - { \ - g_assert (state->notifications == (flags)); \ - state->notifications = 0; \ - } while (0) +#define assert_notifications(flags) G_STMT_START { \ + g_assert (state->notifications == (flags)); \ + state->notifications = 0; } G_STMT_END /* Helper macro to assert the transformed position. This needs to be a macro so that the assertion failure will report the right line number */ -#define assert_coords(state, x_1, y_1, x_2, y_2) \ - do \ - { \ - ClutterVertex verts[4]; \ - clutter_actor_get_abs_allocation_vertices ((state)->rect, verts); \ - check_coords ((state), (x_1), (y_1), (x_2), (y_2), verts); \ - g_assert (approx_equal ((x_1), \ - CLUTTER_UNITS_TO_DEVICE (verts[0].x))); \ - g_assert (approx_equal ((y_1), \ - CLUTTER_UNITS_TO_DEVICE (verts[0].y))); \ - g_assert (approx_equal ((x_2), \ - CLUTTER_UNITS_TO_DEVICE (verts[3].x))); \ - g_assert (approx_equal ((y_2), \ - CLUTTER_UNITS_TO_DEVICE (verts[3].y))); \ - } while (0) +#define assert_coords(state, x_1, y_1, x_2, y_2) G_STMT_START { \ + ClutterVertex verts[4]; \ + clutter_actor_get_abs_allocation_vertices ((state)->rect, verts); \ + check_coords ((state), (x_1), (y_1), (x_2), (y_2), verts); \ + g_assert (approx_equal ((x_1), verts[0].x)); \ + g_assert (approx_equal ((y_1), verts[0].y)); \ + g_assert (approx_equal ((x_2), verts[3].x)); \ + g_assert (approx_equal ((y_2), verts[3].y)); } G_STMT_END #define assert_position(state, x, y) \ assert_coords((state), (x), (y), (x) + RECT_WIDTH, (y) + RECT_HEIGHT) -#define assert_vertex_and_free(v, xc, yc, zc) \ - do \ - { \ - g_assert (approx_equal (CLUTTER_UNITS_TO_DEVICE (v->x), xc) \ - && approx_equal (CLUTTER_UNITS_TO_DEVICE (v->y), yc) \ - && approx_equal (CLUTTER_UNITS_TO_DEVICE (v->z), zc)); \ - g_boxed_free (CLUTTER_TYPE_VERTEX, v); \ - } while (0) +#define assert_vertex_and_free(v, xc, yc, zc) G_STMT_START { \ + g_assert (approx_equal (v->x, xc) && \ + approx_equal (v->y, yc) && \ + approx_equal (v->z, zc)); \ + g_boxed_free (CLUTTER_TYPE_VERTEX, v); } G_STMT_END static inline gboolean approx_equal (int a, int b) @@ -133,28 +124,31 @@ approx_equal (int a, int b) static void check_coords (TestState *state, - gint x_1, gint y_1, gint x_2, gint y_2, + gint x_1, + gint y_1, + gint x_2, + gint y_2, const ClutterVertex *verts) { if (g_test_verbose ()) g_print ("checking that (%i,%i,%i,%i) \xe2\x89\x88 (%i,%i,%i,%i): %s\n", x_1, y_1, x_2, y_2, - CLUTTER_UNITS_TO_DEVICE (verts[0].x), - CLUTTER_UNITS_TO_DEVICE (verts[0].y), - CLUTTER_UNITS_TO_DEVICE (verts[3].x), - CLUTTER_UNITS_TO_DEVICE (verts[3].y), - approx_equal (x_1, CLUTTER_UNITS_TO_DEVICE (verts[0].x)) - && approx_equal (y_1, CLUTTER_UNITS_TO_DEVICE (verts[0].y)) - && approx_equal (x_2, CLUTTER_UNITS_TO_DEVICE (verts[3].x)) - && approx_equal (y_2, CLUTTER_UNITS_TO_DEVICE (verts[3].y)) - ? "yes" : "NO"); + (int) (verts[0].x), + (int) (verts[0].y), + (int) (verts[3].x), + (int) (verts[3].y), + approx_equal (x_1, verts[0].x) && + approx_equal (y_1, verts[0].y) && + approx_equal (x_2, verts[3].x) && + approx_equal (y_2, verts[3].y) ? "yes" + : "NO"); } static void test_anchor_point (TestState *state) { ClutterActor *rect = state->rect; - gint anchor_x, anchor_y; + gfloat anchor_x, anchor_y; ClutterGravity anchor_gravity; int i; @@ -164,7 +158,8 @@ test_anchor_point (TestState *state) g_assert (clutter_actor_get_width (rect) == RECT_WIDTH); g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT); g_object_get (rect, - "anchor-x", &anchor_x, "anchor-y", &anchor_y, + "anchor-x", &anchor_x, + "anchor-y", &anchor_y, "anchor-gravity", &anchor_gravity, NULL); g_assert (anchor_x == 0); @@ -174,7 +169,8 @@ test_anchor_point (TestState *state) /* Change the anchor point */ clutter_actor_set_anchor_point (rect, 20, 30); g_object_get (rect, - "anchor-x", &anchor_x, "anchor-y", &anchor_y, + "anchor-x", &anchor_x, + "anchor-y", &anchor_y, "anchor-gravity", &anchor_gravity, NULL); g_assert (anchor_x == 20); @@ -186,7 +182,8 @@ test_anchor_point (TestState *state) /* Move the anchor point */ clutter_actor_move_anchor_point (rect, 40, 50); g_object_get (rect, - "anchor-x", &anchor_x, "anchor-y", &anchor_y, + "anchor-x", &anchor_x, + "anchor-y", &anchor_y, "anchor-gravity", &anchor_gravity, NULL); g_assert (anchor_x == 40); @@ -214,7 +211,8 @@ test_anchor_point (TestState *state) g_object_set (rect, "anchor-gravity", gravities[i].gravity, NULL); g_object_get (rect, - "anchor-x", &anchor_x, "anchor-y", &anchor_y, + "anchor-x", &anchor_x, + "anchor-y", &anchor_y, "anchor-gravity", &anchor_gravity, NULL); g_assert (anchor_x == gravities[i].x_pos); @@ -232,7 +230,8 @@ test_anchor_point (TestState *state) it is set from the gravity */ clutter_actor_set_size (rect, RECT_WIDTH * 2, RECT_HEIGHT * 2); g_object_get (rect, - "anchor-x", &anchor_x, "anchor-y", &anchor_y, + "anchor-x", &anchor_x, + "anchor-y", &anchor_y, "anchor-gravity", &anchor_gravity, NULL); g_assert (anchor_x == RECT_WIDTH); @@ -261,7 +260,8 @@ test_anchor_point (TestState *state) size when it is set from units */ clutter_actor_set_size (rect, RECT_WIDTH * 2, RECT_HEIGHT * 2); g_object_get (rect, - "anchor-x", &anchor_x, "anchor-y", &anchor_y, + "anchor-x", &anchor_x, + "anchor-y", &anchor_y, "anchor-gravity", &anchor_gravity, NULL); g_assert (anchor_x == 20); @@ -281,7 +281,7 @@ test_scale_center (TestState *state) { ClutterActor *rect = state->rect; gdouble scale_x, scale_y; - gint center_x, center_y; + gfloat center_x, center_y; ClutterGravity gravity; int i; @@ -291,8 +291,10 @@ test_scale_center (TestState *state) g_assert (clutter_actor_get_width (rect) == RECT_WIDTH); g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT); g_object_get (rect, - "scale-center-x", ¢er_x, "scale-center-y", ¢er_y, - "scale-x", &scale_x, "scale-y", &scale_y, + "scale-center-x", ¢er_x, + "scale-center-y", ¢er_y, + "scale-x", &scale_x, + "scale-y", &scale_y, "scale-gravity", &gravity, NULL); g_assert (center_x == 0); @@ -308,8 +310,10 @@ test_scale_center (TestState *state) g_assert (clutter_actor_get_width (rect) == RECT_WIDTH); g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT); g_object_get (rect, - "scale-center-x", ¢er_x, "scale-center-y", ¢er_y, - "scale-x", &scale_x, "scale-y", &scale_y, + "scale-center-x", ¢er_x, + "scale-center-y", ¢er_y, + "scale-x", &scale_x, + "scale-y", &scale_y, "scale-gravity", &gravity, NULL); g_assert (center_x == 0); @@ -321,8 +325,12 @@ test_scale_center (TestState *state) assert_coords (state, 100, 200, 100 + RECT_WIDTH * 2, 200 + RECT_HEIGHT * 3); /* Change the scale and center */ - g_object_set (rect, "scale-x", 4.0, "scale-y", 2.0, - "scale-center-x", 10, "scale-center-y", 20, NULL); + g_object_set (rect, + "scale-x", 4.0, + "scale-y", 2.0, + "scale-center-x", 10.0, + "scale-center-y", 20.0, + NULL); g_assert (clutter_actor_get_x (rect) == 100); g_assert (clutter_actor_get_y (rect) == 200); g_assert (clutter_actor_get_width (rect) == RECT_WIDTH); @@ -388,8 +396,10 @@ test_scale_center (TestState *state) gravity property changes */ clutter_actor_set_scale_full (rect, 4, 2, 10, 20); g_object_get (rect, - "scale-center-x", ¢er_x, "scale-center-y", ¢er_y, - "scale-x", &scale_x, "scale-y", &scale_y, + "scale-center-x", ¢er_x, + "scale-center-y", ¢er_y, + "scale-x", &scale_x, + "scale-y", &scale_y, "scale-gravity", &gravity, NULL); g_assert (center_x == 10); @@ -417,8 +427,8 @@ test_rotate_center (TestState *state) gdouble angle_x, angle_y, angle_z; ClutterVertex *center_x, *center_y, *center_z; ClutterGravity z_center_gravity; - guint stage_width, stage_height; - gint rect_x, rect_y; + gfloat stage_width, stage_height; + gfloat rect_x, rect_y; int i; /* Position the rectangle at the center of the stage so that @@ -426,16 +436,17 @@ test_rotate_center (TestState *state) appear as a flat line. This makes verifying the transformations easier */ clutter_actor_get_size (clutter_actor_get_stage (rect), - &stage_width, &stage_height); + &stage_width, + &stage_height); rect_x = stage_width / 2; rect_y = stage_height / 2; clutter_actor_set_position (rect, rect_x, rect_y); /* Assert the default settings */ - g_assert (clutter_actor_get_x (rect) == rect_x); - g_assert (clutter_actor_get_y (rect) == rect_y); - g_assert (clutter_actor_get_width (rect) == RECT_WIDTH); - g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT); + g_assert_cmpfloat (clutter_actor_get_x (rect), ==, rect_x); + g_assert_cmpfloat (clutter_actor_get_y (rect), ==, rect_y); + g_assert_cmpfloat (clutter_actor_get_width (rect), ==, RECT_WIDTH); + g_assert_cmpfloat (clutter_actor_get_height (rect), ==, RECT_HEIGHT); g_object_get (rect, "rotation-angle-x", &angle_x, "rotation-angle-y", &angle_y, @@ -482,16 +493,14 @@ test_rotate_center (TestState *state) if (i == CLUTTER_X_AXIS) { g_assert (angle_x == 90.0); - assert_coords (state, rect_x, rect_y, - CLUTTER_UNITS_TO_DEVICE (verts[3].x), rect_y); + assert_coords (state, rect_x, rect_y, verts[3].x, rect_y); } else g_assert (angle_x == 0.0); if (i == CLUTTER_Y_AXIS) { g_assert (angle_y == 90.0); - assert_coords (state, rect_x, rect_y, - rect_x, CLUTTER_UNITS_TO_DEVICE (verts[3].y)); + assert_coords (state, rect_x, rect_y, rect_x, verts[3].y); } else g_assert (angle_y == 0.0); @@ -499,7 +508,8 @@ test_rotate_center (TestState *state) { g_assert (angle_z == 90.0); assert_coords (state, rect_x, rect_y, - rect_x - RECT_HEIGHT, rect_y + RECT_WIDTH); + rect_x - RECT_HEIGHT, + rect_y + RECT_WIDTH); } else g_assert (angle_z == 0.0); @@ -545,8 +555,8 @@ test_rotate_center (TestState *state) { g_assert (angle_x == 90.0); assert_coords (state, - CLUTTER_UNITS_TO_DEVICE (verts[0].x), rect_y + 20, - CLUTTER_UNITS_TO_DEVICE (verts[3].x), rect_y + 20); + verts[0].x, rect_y + 20, + verts[3].x, rect_y + 20); assert_vertex_and_free (center_x, 10, 20, 0); } else @@ -558,8 +568,8 @@ test_rotate_center (TestState *state) { g_assert (angle_y == 90.0); assert_coords (state, - rect_x + 10, CLUTTER_UNITS_TO_DEVICE (verts[0].y), - rect_x + 10, CLUTTER_UNITS_TO_DEVICE (verts[3].y)); + rect_x + 10, verts[0].y, + rect_x + 10, verts[3].y); assert_vertex_and_free (center_y, 10, 20, 0); } else diff --git a/tests/conform/test-backface-culling.c b/tests/conform/test-backface-culling.c index 034dcb70a..5d8b7ba62 100644 --- a/tests/conform/test-backface-culling.c +++ b/tests/conform/test-backface-culling.c @@ -11,20 +11,23 @@ static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff }; /* Size the texture so that it is just off a power of two to enourage it so use software tiling when NPOTs aren't available */ -#define TEXTURE_SIZE 33 +#define TEXTURE_SIZE 257 #else /* CLUTTER_COGL_HAS_GL */ /* We can't use the funny-sized texture on GL ES because it will break cogl_texture_polygon. However there is only one code path for rendering quads so there is no need */ -#define TEXTURE_SIZE 32 +#define TEXTURE_SIZE 32 #endif /* CLUTTER_COGL_HAS_GL */ /* Amount of pixels to skip off the top, bottom, left and right of the texture when reading back the stage */ -#define TEST_INSET 4 +#define TEST_INSET 4 + +/* Size to actually render the texture at */ +#define TEXTURE_RENDER_SIZE 32 typedef struct _TestState { @@ -42,15 +45,15 @@ validate_part (int xnum, int ynum, gboolean shown) /* Read the appropriate part but skip out a few pixels around the edges */ pixels = clutter_stage_read_pixels (CLUTTER_STAGE (stage), - xnum * TEXTURE_SIZE + TEST_INSET, - ynum * TEXTURE_SIZE + TEST_INSET, - TEXTURE_SIZE - TEST_INSET * 2, - TEXTURE_SIZE - TEST_INSET * 2); + xnum * TEXTURE_RENDER_SIZE + TEST_INSET, + ynum * TEXTURE_RENDER_SIZE + TEST_INSET, + TEXTURE_RENDER_SIZE - TEST_INSET * 2, + TEXTURE_RENDER_SIZE - TEST_INSET * 2); /* Make sure every pixels is the appropriate color */ for (p = pixels; - p < pixels + ((TEXTURE_SIZE - TEST_INSET * 2) - * (TEXTURE_SIZE - TEST_INSET * 2)); + p < pixels + ((TEXTURE_RENDER_SIZE - TEST_INSET * 2) + * (TEXTURE_RENDER_SIZE - TEST_INSET * 2)); p += 4) { if (p[0] != (shown ? 255 : 0)) @@ -104,8 +107,13 @@ on_paint (ClutterActor *actor, TestState *state) { int i; int frame_num; + CoglHandle material = cogl_material_new (); - cogl_enable_backface_culling (TRUE); + cogl_material_set_layer_filters (material, 0, + COGL_MATERIAL_FILTER_NEAREST, + COGL_MATERIAL_FILTER_NEAREST); + + cogl_set_backface_culling_enabled (TRUE); cogl_push_matrix (); @@ -114,31 +122,28 @@ on_paint (ClutterActor *actor, TestState *state) the first */ for (i = 0; i < 2; i++) { - float x1 = 0, x2, y1 = 0, y2 = (float)(TEXTURE_SIZE); + float x1 = 0, x2, y1 = 0, y2 = (float)(TEXTURE_RENDER_SIZE); CoglTextureVertex verts[4]; + cogl_set_source (material); + memset (verts, 0, sizeof (verts)); - /* Set the color to white so that all the textures will be drawn - at their own color */ - cogl_set_source_color4f (1.0, 1.0, - 1.0, 1.0); - - x2 = x1 + (float)(TEXTURE_SIZE); + x2 = x1 + (float)(TEXTURE_RENDER_SIZE); /* Draw a front-facing texture */ - cogl_set_source_texture (state->texture); + cogl_material_set_layer (material, 0, state->texture); cogl_rectangle (x1, y1, x2, y2); x1 = x2; - x2 = x1 + (float)(TEXTURE_SIZE); + x2 = x1 + (float)(TEXTURE_RENDER_SIZE); /* Draw a back-facing texture */ - cogl_set_source_texture (state->texture); + cogl_material_set_layer (material, 0, state->texture); cogl_rectangle (x2, y1, x1, y2); x1 = x2; - x2 = x1 + (float)(TEXTURE_SIZE); + x2 = x1 + (float)(TEXTURE_RENDER_SIZE); /* Draw a front-facing texture polygon */ verts[0].x = x1; verts[0].y = y2; @@ -149,11 +154,11 @@ on_paint (ClutterActor *actor, TestState *state) verts[1].tx = 1.0; verts[1].ty = 0; verts[2].tx = 1.0; verts[2].ty = 1.0; verts[3].tx = 0; verts[3].ty = 1.0; - cogl_set_source_texture (state->texture); + cogl_material_set_layer (material, 0, state->texture); cogl_polygon (verts, 4, FALSE); x1 = x2; - x2 = x1 + (float)(TEXTURE_SIZE); + x2 = x1 + (float)(TEXTURE_RENDER_SIZE); /* Draw a back-facing texture polygon */ verts[0].x = x1; verts[0].y = y1; @@ -164,11 +169,11 @@ on_paint (ClutterActor *actor, TestState *state) verts[1].tx = 1.0; verts[1].ty = 0; verts[2].tx = 1.0; verts[2].ty = 1.0; verts[3].tx = 0; verts[3].ty = 1.0; - cogl_set_source_texture (state->texture); + cogl_material_set_layer (material, 0, state->texture); cogl_polygon (verts, 4, FALSE); x1 = x2; - x2 = x1 + (float)(TEXTURE_SIZE); + x2 = x1 + (float)(TEXTURE_RENDER_SIZE); /* Draw a regular rectangle (this should always show) */ cogl_set_source_color4f (1.0, 0, 0, 1.0); @@ -176,12 +181,14 @@ on_paint (ClutterActor *actor, TestState *state) /* The second time round draw beneath the first with backface culling disabled */ - cogl_translate (0, TEXTURE_SIZE, 0); - cogl_enable_backface_culling (FALSE); + cogl_translate (0, TEXTURE_RENDER_SIZE, 0); + cogl_set_backface_culling_enabled (FALSE); } cogl_pop_matrix (); + cogl_handle_unref (material); + /* XXX: Experiments have shown that for some buggy drivers, when using * glReadPixels there is some kind of race, so we delay our test for a * few frames and a few seconds: @@ -221,7 +228,6 @@ make_texture (void) tex = cogl_texture_new_from_data (TEXTURE_SIZE, TEXTURE_SIZE, - 8, COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_RGBA_8888, COGL_PIXEL_FORMAT_ANY, diff --git a/tests/conform/test-binding-pool.c b/tests/conform/test-binding-pool.c index 64cf11ee6..9c2b1b7cf 100644 --- a/tests/conform/test-binding-pool.c +++ b/tests/conform/test-binding-pool.c @@ -154,20 +154,16 @@ key_group_paint (ClutterActor *actor) clutter_actor_get_allocation_box (child, &box); - box.x1 -= CLUTTER_UNITS_FROM_DEVICE (2); - box.y1 -= CLUTTER_UNITS_FROM_DEVICE (2); - box.x2 += CLUTTER_UNITS_FROM_DEVICE (2); - box.y2 += CLUTTER_UNITS_FROM_DEVICE (2); + box.x1 -= 2; + box.y1 -= 2; + box.x2 += 2; + box.y2 += 2; cogl_set_source_color4ub (255, 255, 0, 224); - cogl_rectangle (CLUTTER_UNITS_TO_DEVICE (box.x1), - CLUTTER_UNITS_TO_DEVICE (box.y1), - CLUTTER_UNITS_TO_DEVICE (box.x2), - CLUTTER_UNITS_TO_DEVICE (box.y2)); + cogl_rectangle (box.x1, box.y1, box.x2, box.y2); } - if (CLUTTER_ACTOR_IS_VISIBLE (child)) - clutter_actor_paint (child); + clutter_actor_paint (child); } g_list_free (children); @@ -273,19 +269,19 @@ test_binding_pool (TestConformSimpleFixture *fixture, clutter_container_add (CLUTTER_CONTAINER (key_group), g_object_new (CLUTTER_TYPE_RECTANGLE, - "width", 50, - "height", 50, - "x", 0, "y", 0, + "width", 50.0, + "height", 50.0, + "x", 0.0, "y", 0.0, NULL), g_object_new (CLUTTER_TYPE_RECTANGLE, - "width", 50, - "height", 50, - "x", 75, "y", 0, + "width", 50.0, + "height", 50.0, + "x", 75.0, "y", 0.0, NULL), g_object_new (CLUTTER_TYPE_RECTANGLE, - "width", 50, - "height", 50, - "x", 150, "y", 0, + "width", 50.0, + "height", 50.0, + "x", 150.0, "y", 0.0, NULL), NULL); diff --git a/tests/conform/test-blend-strings.c b/tests/conform/test-blend-strings.c new file mode 100644 index 000000000..01979964d --- /dev/null +++ b/tests/conform/test-blend-strings.c @@ -0,0 +1,410 @@ + +#include +#include +#include + +#include "test-conform-common.h" + +static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff }; + +#define QUAD_WIDTH 20 + +#define RED 0 +#define GREEN 1 +#define BLUE 2 +#define ALPHA 3 + +#define MASK_RED(COLOR) ((COLOR & 0xff000000) >> 24); +#define MASK_GREEN(COLOR) ((COLOR & 0xff0000) >> 16); +#define MASK_BLUE(COLOR) ((COLOR & 0xff00) >> 8); +#define MASK_ALPHA(COLOR) (COLOR & 0xff); + +#define BLEND_CONSTANT_UNUSED 0xDEADBEEF +#define TEX_CONSTANT_UNUSED 0xDEADBEEF + +typedef struct _TestState +{ + guint frame; + ClutterGeometry stage_geom; +} TestState; + + +static void +check_pixel (GLubyte *pixel, guint32 color) +{ + guint8 r = MASK_RED (color); + guint8 g = MASK_GREEN (color); + guint8 b = MASK_BLUE (color); + guint8 a = MASK_ALPHA (color); + + if (g_test_verbose ()) + g_print (" expected = %x, %x, %x, %x\n", + r, g, b, a); + /* FIXME - allow for hardware in-precision */ + g_assert (pixel[RED] == r); + g_assert (pixel[GREEN] == g); + g_assert (pixel[BLUE] == b); + + /* FIXME + * We ignore the alpha, since we don't know if our render target is + * RGB or RGBA */ + /* g_assert (pixel[ALPHA] == a); */ +} + +static void +test_blend (TestState *state, + int x, + int y, + guint32 src_color, + guint32 dst_color, + const char *blend_string, + guint32 blend_constant, + guint32 expected_result) +{ + /* src color */ + guint8 Sr = MASK_RED (src_color); + guint8 Sg = MASK_GREEN (src_color); + guint8 Sb = MASK_BLUE (src_color); + guint8 Sa = MASK_ALPHA (src_color); + /* dest color */ + guint8 Dr = MASK_RED (dst_color); + guint8 Dg = MASK_GREEN (dst_color); + guint8 Db = MASK_BLUE (dst_color); + guint8 Da = MASK_ALPHA (dst_color); + /* blend constant - when applicable */ + guint8 Br = MASK_RED (blend_constant); + guint8 Bg = MASK_GREEN (blend_constant); + guint8 Bb = MASK_BLUE (blend_constant); + guint8 Ba = MASK_ALPHA (blend_constant); + CoglColor blend_const_color; + + CoglHandle material; + gboolean status; + GError *error = NULL; + GLubyte pixel[4]; + GLint y_off; + GLint x_off; + + /* First write out the destination color without any blending... */ + material = cogl_material_new (); + cogl_material_set_color4ub (material, Dr, Dg, Db, Da); + cogl_material_set_blend (material, "RGBA = ADD (SRC_COLOR, 0)", NULL); + cogl_set_source (material); + cogl_rectangle (x * QUAD_WIDTH, + y * QUAD_WIDTH, + x * QUAD_WIDTH + QUAD_WIDTH, + y * QUAD_WIDTH + QUAD_WIDTH); + cogl_material_unref (material); + + /* + * Now blend a rectangle over our well defined destination: + */ + + material = cogl_material_new (); + cogl_material_set_color4ub (material, Sr, Sg, Sb, Sa); + + status = cogl_material_set_blend (material, blend_string, &error); + if (!status) + { + /* It's not strictly a test failure; you need a more capable GPU or + * driver to test this blend string. */ + g_debug ("Failed to test blend string %s: %s", + blend_string, error->message); + } + + cogl_color_set_from_4ub (&blend_const_color, Br, Bg, Bb, Ba); + cogl_material_set_blend_constant (material, &blend_const_color); + + cogl_set_source (material); + cogl_rectangle (x * QUAD_WIDTH, + y * QUAD_WIDTH, + x * QUAD_WIDTH + QUAD_WIDTH, + y * QUAD_WIDTH + QUAD_WIDTH); + cogl_material_unref (material); + + /* See what we got... */ + + /* NB: glReadPixels is done in GL screen space so y = 0 is at the bottom */ + y_off = state->stage_geom.height - y * QUAD_WIDTH - (QUAD_WIDTH / 2); + x_off = x * QUAD_WIDTH + (QUAD_WIDTH / 2); + + /* XXX: + * We haven't always had good luck with GL drivers implementing glReadPixels + * reliably and skipping the first two frames improves our chances... */ + if (state->frame <= 2) + return; + + glReadPixels (x_off, y_off, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel); + if (g_test_verbose ()) + { + g_print ("test_blend (%d, %d):\n%s\n", x, y, blend_string); + g_print (" src color = %02x, %02x, %02x, %02x\n", Sr, Sg, Sb, Sa); + g_print (" dst color = %02x, %02x, %02x, %02x\n", Dr, Dg, Db, Da); + if (blend_constant != BLEND_CONSTANT_UNUSED) + g_print (" blend constant = %02x, %02x, %02x, %02x\n", + Br, Bg, Bb, Ba); + else + g_print (" blend constant = UNUSED\n"); + g_print (" result = %x, %x, %x, %x\n", + pixel[RED], pixel[GREEN], pixel[BLUE], pixel[ALPHA]); + } + + check_pixel (pixel, expected_result); +} + +static CoglHandle +make_texture (guint32 color) +{ + guchar *tex_data, *p; + guint8 r = MASK_RED (color); + guint8 g = MASK_GREEN (color); + guint8 b = MASK_BLUE (color); + guint8 a = MASK_ALPHA (color); + CoglHandle tex; + + tex_data = g_malloc (QUAD_WIDTH * QUAD_WIDTH * 4); + + for (p = tex_data + QUAD_WIDTH * QUAD_WIDTH * 4; p > tex_data;) + { + *(--p) = a; + *(--p) = b; + *(--p) = g; + *(--p) = r; + } + + tex = cogl_texture_new_from_data (QUAD_WIDTH, + QUAD_WIDTH, + COGL_TEXTURE_NONE, + COGL_PIXEL_FORMAT_RGBA_8888, + COGL_PIXEL_FORMAT_ANY, + QUAD_WIDTH * 4, + tex_data); + + g_free (tex_data); + + return tex; +} + +static void +test_tex_combine (TestState *state, + int x, + int y, + guint32 tex0_color, + guint32 tex1_color, + guint32 combine_constant, + const char *combine_string, + guint32 expected_result) +{ + CoglHandle tex0, tex1; + + /* combine constant - when applicable */ + guint8 Cr = MASK_RED (combine_constant); + guint8 Cg = MASK_GREEN (combine_constant); + guint8 Cb = MASK_BLUE (combine_constant); + guint8 Ca = MASK_ALPHA (combine_constant); + CoglColor combine_const_color; + + CoglHandle material; + gboolean status; + GError *error = NULL; + GLubyte pixel[4]; + GLint y_off; + GLint x_off; + + + tex0 = make_texture (tex0_color); + tex1 = make_texture (tex1_color); + + material = cogl_material_new (); + + cogl_material_set_color4ub (material, 0x80, 0x80, 0x80, 0x80); + cogl_material_set_blend (material, "RGBA = ADD (SRC_COLOR, 0)", NULL); + + cogl_material_set_layer (material, 0, tex0); + cogl_material_set_layer_combine (material, 0, + "RGBA = REPLACE (TEXTURE)", NULL); + + cogl_material_set_layer (material, 1, tex1); + status = cogl_material_set_layer_combine (material, 1, + combine_string, &error); + if (!status) + { + /* It's not strictly a test failure; you need a more capable GPU or + * driver to test this texture combine string. */ + g_debug ("Failed to test texture combine string %s: %s", + combine_string, error->message); + } + + cogl_color_set_from_4ub (&combine_const_color, Cr, Cg, Cb, Ca); + cogl_material_set_layer_combine_constant (material, 1, &combine_const_color); + + cogl_set_source (material); + cogl_rectangle (x * QUAD_WIDTH, + y * QUAD_WIDTH, + x * QUAD_WIDTH + QUAD_WIDTH, + y * QUAD_WIDTH + QUAD_WIDTH); + cogl_material_unref (material); + + cogl_handle_unref (tex0); + cogl_handle_unref (tex1); + + /* See what we got... */ + + /* NB: glReadPixels is done in GL screen space so y = 0 is at the bottom */ + y_off = state->stage_geom.height - y * QUAD_WIDTH - (QUAD_WIDTH / 2); + x_off = x * QUAD_WIDTH + (QUAD_WIDTH / 2); + + /* XXX: + * We haven't always had good luck with GL drivers implementing glReadPixels + * reliably and skipping the first two frames improves our chances... */ + if (state->frame <= 2) + return; + + glReadPixels (x_off, y_off, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel); + if (g_test_verbose ()) + { + g_print ("test_tex_combine (%d, %d):\n%s\n", x, y, combine_string); + g_print (" texture 0 color = 0x%08lX\n", (unsigned long)tex0_color); + g_print (" texture 1 color = 0x%08lX\n", (unsigned long)tex1_color); + if (combine_constant != TEX_CONSTANT_UNUSED) + g_print (" combine constant = %02x, %02x, %02x, %02x\n", + Cr, Cg, Cb, Ca); + else + g_print (" combine constant = UNUSED\n"); + g_print (" result = %02x, %02x, %02x, %02x\n", + pixel[RED], pixel[GREEN], pixel[BLUE], pixel[ALPHA]); + } + + check_pixel (pixel, expected_result); +} + +static void +on_paint (ClutterActor *actor, TestState *state) +{ + int frame_num; + + test_blend (state, 0, 0, /* position */ + 0xff0000ff, /* src */ + 0xffffffff, /* dst */ + "RGBA = ADD (SRC_COLOR, 0)", + BLEND_CONSTANT_UNUSED, + 0xff0000ff); /* expected */ + + test_blend (state, 1, 0, /* position */ + 0x11223344, /* src */ + 0x11223344, /* dst */ + "RGBA = ADD (SRC_COLOR, DST_COLOR)", + BLEND_CONSTANT_UNUSED, + 0x22446688); /* expected */ + + test_blend (state, 2, 0, /* position */ + 0x80808080, /* src */ + 0xffffffff, /* dst */ + "RGBA = ADD (SRC_COLOR * (CONSTANT), 0)", + 0x80808080, /* constant (RGBA all = 0.5 when normalized) */ + 0x40404040); /* expected */ + + test_blend (state, 3, 0, /* position */ + 0x80000080, /* src (alpha = 0.5 when normalized) */ + 0x40000000, /* dst */ + "RGBA = ADD (SRC_COLOR * (SRC_COLOR[A])," + " DST_COLOR * (1-SRC_COLOR[A]))", + BLEND_CONSTANT_UNUSED, + 0x60000040); /* expected */ + + /* XXX: + * For all texture combine tests tex0 will use a combine mode of + * "RGBA = REPLACE (TEXTURE)" + */ + + test_tex_combine (state, 4, 0, /* position */ + 0x11111111, /* texture 0 color */ + 0x22222222, /* texture 1 color */ + TEX_CONSTANT_UNUSED, + "RGBA = ADD (PREVIOUS, TEXTURE)", /* tex combine */ + 0x33333333); /* expected */ + + test_tex_combine (state, 5, 0, /* position */ + 0x40404040, /* texture 0 color */ + 0x80808080, /* texture 1 color (RGBA all = 0.5) */ + TEX_CONSTANT_UNUSED, + "RGBA = MODULATE (PREVIOUS, TEXTURE)", /* tex combine */ + 0x20202020); /* expected */ + + test_tex_combine (state, 6, 0, /* position */ + 0xffffff80, /* texture 0 color (alpha = 0.5) */ + 0xDEADBE40, /* texture 1 color */ + TEX_CONSTANT_UNUSED, + "RGB = REPLACE (PREVIOUS)" + "A = MODULATE (PREVIOUS, TEXTURE)", /* tex combine */ + 0xffffff20); /* expected */ + + /* XXX: we are assuming test_tex_combine creates a material with + * a color of 0x80808080 (i.e. the "PRIMARY" color) */ + test_tex_combine (state, 7, 0, /* position */ + 0xffffff80, /* texture 0 color (alpha = 0.5) */ + 0xDEADBE20, /* texture 1 color */ + TEX_CONSTANT_UNUSED, + "RGB = REPLACE (PREVIOUS)" + "A = MODULATE (PRIMARY, TEXTURE)", /* tex combine */ + 0xffffff10); /* expected */ + + /* XXX: Experiments have shown that for some buggy drivers, when using + * glReadPixels there is some kind of race, so we delay our test for a + * few frames and a few seconds: + */ + frame_num = state->frame++; + if (frame_num < 2) + g_usleep (G_USEC_PER_SEC); + + /* Comment this out if you want visual feedback for what this test paints */ +#if 1 + if (frame_num == 2) + clutter_main_quit (); +#endif +} + +static gboolean +queue_redraw (gpointer stage) +{ + clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); + + return TRUE; +} + +void +test_blend_strings (TestConformSimpleFixture *fixture, + gconstpointer data) +{ + TestState state; + ClutterActor *stage; + ClutterActor *group; + guint idle_source; + + state.frame = 0; + + stage = clutter_stage_get_default (); + + clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); + clutter_actor_get_geometry (stage, &state.stage_geom); + + group = clutter_group_new (); + clutter_container_add_actor (CLUTTER_CONTAINER (stage), group); + + /* We force continuous redrawing of the stage, since we need to skip + * the first few frames, and we wont be doing anything else that + * will trigger redrawing. */ + idle_source = g_idle_add (queue_redraw, stage); + + g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state); + + clutter_actor_show_all (stage); + + clutter_main (); + + g_source_remove (idle_source); + + if (g_test_verbose ()) + g_print ("OK\n"); +} + diff --git a/tests/conform/test-clutter-units.c b/tests/conform/test-clutter-units.c new file mode 100644 index 000000000..2a590c68f --- /dev/null +++ b/tests/conform/test-clutter-units.c @@ -0,0 +1,58 @@ +#include +#include + +#include "test-conform-common.h" + +void +test_units_constructors (TestConformSimpleFixture *fixture, + gconstpointer data) +{ + ClutterUnits units; + + clutter_units_pixels (&units, 100); + g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_PIXEL); + g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 100.0); + g_assert_cmpfloat (clutter_units_to_pixels (&units), ==, 100.0); + + clutter_units_em (&units, 5.0); + g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_EM); + g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 5.0); + g_assert_cmpfloat (clutter_units_to_pixels (&units), !=, 5.0); +} + +void +test_units_string (TestConformSimpleFixture *fixture, + gconstpointer data) +{ + ClutterUnits units; + gchar *string; + + g_assert (clutter_units_from_string (&units, "5 em") == TRUE); + g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_EM); + g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 5); + + g_assert (clutter_units_from_string (&units, " 16 mm") == TRUE); + g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_MM); + g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 16); + + g_assert (clutter_units_from_string (&units, "1 pony") == FALSE); + + clutter_units_pt (&units, 24.0); + string = clutter_units_to_string (&units); + g_assert_cmpstr (string, ==, "24.0 pt"); + g_free (string); + + clutter_units_em (&units, 3.0); + string = clutter_units_to_string (&units); + g_assert_cmpstr (string, ==, "3.00 em"); + + units.unit_type = CLUTTER_UNIT_PIXEL; + units.value = 0; + + g_assert (clutter_units_from_string (&units, string) == TRUE); + g_assert (clutter_units_get_unit_type (&units) != CLUTTER_UNIT_PIXEL); + g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_EM); + g_assert_cmpint ((int) clutter_units_get_unit_value (&units), ==, 3); + + g_free (string); +} diff --git a/tests/conform/test-color.c b/tests/conform/test-color.c new file mode 100644 index 000000000..65dc83fc2 --- /dev/null +++ b/tests/conform/test-color.c @@ -0,0 +1,71 @@ +#include +#include + +#include "test-conform-common.h" + +void +test_color_from_string (TestConformSimpleFixture *fixture, + gconstpointer data) +{ + ClutterColor color; + + clutter_color_from_string (&color, "#ff0000ff"); + if (g_test_verbose ()) + { + g_print ("color = { %x, %x, %x, %x }, expected = { 0xff, 0, 0, 0xff }\n", + color.red, + color.green, + color.blue, + color.alpha); + } + g_assert (color.red == 0xff); + g_assert (color.green == 0); + g_assert (color.blue == 0); + g_assert (color.alpha == 0xff); + + clutter_color_from_string (&color, "#0f0f"); + if (g_test_verbose ()) + { + g_print ("color = { %x, %x, %x, %x }, expected = { 0, 0xff, 0, 0xff }\n", + color.red, + color.green, + color.blue, + color.alpha); + } + g_assert (color.red == 0); + g_assert (color.green == 0xff); + g_assert (color.blue == 0); + g_assert (color.alpha == 0xff); + + clutter_color_from_string (&color, "#0000ff"); + if (g_test_verbose ()) + { + g_print ("color = { %x, %x, %x, %x }, expected = { 0, 0, 0xff, 0xff }\n", + color.red, + color.green, + color.blue, + color.alpha); + } + g_assert (color.red == 0); + g_assert (color.green == 0); + g_assert (color.blue == 0xff); + g_assert (color.alpha == 0xff); +} + +void +test_color_to_string (TestConformSimpleFixture *fixture, + gconstpointer data) +{ + ClutterColor color; + gchar *str; + + color.red = 0xcc; + color.green = 0xcc; + color.blue = 0xcc; + color.alpha = 0x22; + + str = clutter_color_to_string (&color); + g_assert_cmpstr (str, ==, "#cccccc22"); + + g_free (str); +} diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c index 1996e03d7..b6b211b87 100644 --- a/tests/conform/test-conform-main.c +++ b/tests/conform/test-conform-main.c @@ -60,11 +60,10 @@ int main (int argc, char **argv) { TestConformSharedState *shared_state = g_new0 (TestConformSharedState, 1); - const gchar *display; #ifdef HAVE_CLUTTER_GLX /* on X11 we need a display connection to run the test suite */ - display = g_getenv ("DISPLAY"); + const gchar *display = g_getenv ("DISPLAY"); if (!display || *display == '\0') { g_print ("No DISPLAY found. Unable to run the conformance " @@ -86,11 +85,8 @@ main (int argc, char **argv) shared_state->argv_addr = &argv; TEST_CONFORM_SIMPLE ("/timeline", test_timeline); - TEST_CONFORM_SKIP (!g_test_slow (), "/timeline", test_timeline_dup_frames); - TEST_CONFORM_SKIP (!g_test_slow (), "/timeline", test_timeline_dup_frames); TEST_CONFORM_SKIP (!g_test_slow (), "/timeline", test_timeline_interpolate); TEST_CONFORM_SKIP (!g_test_slow (), "/timeline", test_timeline_rewind); - TEST_CONFORM_SKIP (!g_test_slow (), "/timeline", test_timeline_smoothness); TEST_CONFORM_SIMPLE ("/picking", test_pick); @@ -116,7 +112,10 @@ main (int argc, char **argv) TEST_CONFORM_SIMPLE ("/fixed", test_fixed_constants); TEST_CONFORM_SIMPLE ("/invariants", test_initial_state); + TEST_CONFORM_SIMPLE ("/invariants", test_shown_not_parented); TEST_CONFORM_SIMPLE ("/invariants", test_realized); + TEST_CONFORM_SIMPLE ("/invariants", test_realize_not_recursive); + TEST_CONFORM_SIMPLE ("/invariants", test_map_recursive); TEST_CONFORM_SIMPLE ("/invariants", test_mapped); TEST_CONFORM_SIMPLE ("/invariants", test_show_on_set_parent); @@ -141,5 +140,13 @@ main (int argc, char **argv) TEST_CONFORM_SIMPLE ("/model", test_list_model_iterate); TEST_CONFORM_SIMPLE ("/model", test_list_model_filter); + TEST_CONFORM_SIMPLE ("/material", test_blend_strings); + + TEST_CONFORM_SIMPLE ("/color", test_color_from_string); + TEST_CONFORM_SIMPLE ("/color", test_color_to_string); + + TEST_CONFORM_SIMPLE ("/units", test_units_constructors); + TEST_CONFORM_SIMPLE ("/units", test_units_string); + return g_test_run (); } diff --git a/tests/conform/test-npot-texture.c b/tests/conform/test-npot-texture.c index c1f762c00..69ede37a2 100644 --- a/tests/conform/test-npot-texture.c +++ b/tests/conform/test-npot-texture.c @@ -7,15 +7,20 @@ static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff }; /* Non-power-of-two sized texture that should cause slicing */ -#define TEXTURE_SIZE 191 +#define TEXTURE_SIZE 257 /* Number of times to split the texture up on each axis */ -#define PARTS 2 +#define PARTS 2 /* The texture is split into four parts, each with a different colour */ -#define PART_SIZE (TEXTURE_SIZE / PARTS) +#define PART_SIZE (TEXTURE_SIZE / PARTS) /* Amount of pixels to skip off the top, bottom, left and right of the texture when reading back the stage */ -#define TEST_INSET 4 +#define TEST_INSET 4 + +/* Size to actually render the texture at */ +#define TEXTURE_RENDER_SIZE 128 +/* The size of a part once rendered */ +#define PART_RENDER_SIZE (TEXTURE_RENDER_SIZE / PARTS) static const ClutterColor corner_colors[PARTS * PARTS] = { @@ -41,15 +46,15 @@ validate_part (int xnum, int ynum, const ClutterColor *color) /* Read the appropriate part but skip out a few pixels around the edges */ pixels = clutter_stage_read_pixels (CLUTTER_STAGE (stage), - xnum * PART_SIZE + TEST_INSET, - ynum * PART_SIZE + TEST_INSET, - PART_SIZE - TEST_INSET * 2, - PART_SIZE - TEST_INSET * 2); + xnum * PART_RENDER_SIZE + TEST_INSET, + ynum * PART_RENDER_SIZE + TEST_INSET, + PART_RENDER_SIZE - TEST_INSET * 2, + PART_RENDER_SIZE - TEST_INSET * 2); /* Make sure every pixels is the appropriate color */ for (p = pixels; - p < pixels + ((PART_SIZE - TEST_INSET * 2) - * (PART_SIZE - TEST_INSET * 2)); + p < pixels + ((PART_RENDER_SIZE - TEST_INSET * 2) + * (PART_RENDER_SIZE - TEST_INSET * 2)); p += 4) { if (p[0] != color->red) @@ -88,7 +93,7 @@ on_paint (ClutterActor *actor, TestState *state) /* Just render the texture in the top left corner */ cogl_set_source_texture (state->texture); - cogl_rectangle (0, 0, TEXTURE_SIZE, TEXTURE_SIZE); + cogl_rectangle (0, 0, TEXTURE_RENDER_SIZE, TEXTURE_RENDER_SIZE); /* XXX: Experiments have shown that for some buggy drivers, when using * glReadPixels there is some kind of race, so we delay our test for a @@ -152,7 +157,6 @@ make_texture (void) tex = cogl_texture_new_from_data (TEXTURE_SIZE, TEXTURE_SIZE, - 8, COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_RGBA_8888, COGL_PIXEL_FORMAT_ANY, diff --git a/tests/conform/test-pick.c b/tests/conform/test-pick.c index 0001abeba..e85883748 100644 --- a/tests/conform/test-pick.c +++ b/tests/conform/test-pick.c @@ -68,6 +68,7 @@ on_timeout (State *state) guint32 gid; ClutterActor *actor = clutter_stage_get_actor_at_pos (CLUTTER_STAGE (state->stage), + CLUTTER_PICK_ALL, x * state->actor_width + state->actor_width / 2, y * state->actor_height diff --git a/tests/conform/test-timeline-dup-frames.c b/tests/conform/test-timeline-dup-frames.c deleted file mode 100644 index 32a906084..000000000 --- a/tests/conform/test-timeline-dup-frames.c +++ /dev/null @@ -1,101 +0,0 @@ -#include -#include -#include - -#include "test-conform-common.h" - -/* We use a nice slow timeline for this test since we - * dont want the timeouts to interpolate the timeline - * forward multiple frames */ -#define TEST_TIMELINE_FPS 10 -#define TEST_TIMELINE_FRAME_COUNT 20 - -typedef struct _TestState { - ClutterTimeline *timeline; - gint prev_frame; - gint completion_count; - gint passed; -}TestState; - - -static void -new_frame_cb (ClutterTimeline *timeline, - gint frame_num, - TestState *state) -{ - gint current_frame = clutter_timeline_get_current_frame (state->timeline); - - if (state->prev_frame - != clutter_timeline_get_current_frame (state->timeline)) - { - g_test_message ("timeline previous frame=%-4i " - "actual frame=%-4i (OK)\n", - state->prev_frame, - current_frame); - } - else - { - g_test_message ("timeline previous frame=%-4i " - "actual frame=%-4i (FAILED)\n", - state->prev_frame, - current_frame); - - state->passed = FALSE; - } - - state->prev_frame = current_frame; -} - - -static void -completed_cb (ClutterTimeline *timeline, - TestState *state) -{ - state->completion_count++; - - if (state->completion_count == 2) - { - if (state->passed) - { - g_test_message ("Passed\n"); - clutter_main_quit (); - } - else - { - g_test_message ("Failed\n"); - exit (EXIT_FAILURE); - } - } -} - - -void -test_timeline_dup_frames (TestConformSimpleFixture *fixture, - gconstpointer data) -{ - TestState state; - - state.timeline = - clutter_timeline_new (TEST_TIMELINE_FRAME_COUNT, - TEST_TIMELINE_FPS); - clutter_timeline_set_loop (state.timeline, TRUE); - g_signal_connect (G_OBJECT(state.timeline), - "new-frame", - G_CALLBACK(new_frame_cb), - &state); - g_signal_connect (G_OBJECT(state.timeline), - "completed", - G_CALLBACK(completed_cb), - &state); - - state.prev_frame = -1; - state.completion_count = 0; - state.passed = TRUE; - - clutter_timeline_start (state.timeline); - - clutter_main(); - - g_object_unref (state.timeline); -} - diff --git a/tests/conform/test-timeline-interpolate.c b/tests/conform/test-timeline-interpolate.c index 56af892ef..c4837a5ec 100644 --- a/tests/conform/test-timeline-interpolate.c +++ b/tests/conform/test-timeline-interpolate.c @@ -9,20 +9,24 @@ * will interpolate the number frames that should have * passed between timeouts. */ #define TEST_TIMELINE_FPS 1000 -#define TEST_TIMELINE_FRAME_COUNT 5000 +#define TEST_TIMELINE_DURATION 5000 /* We are at the mercy of the system scheduler so this * may not be a very reliable tolerance. */ #define TEST_ERROR_TOLERANCE 20 -typedef struct _TestState { - ClutterTimeline *timeline; - GTimeVal start_time; - guint new_frame_counter; - gint expected_frame; - gint completion_count; - gboolean passed; -}TestState; +typedef struct _TestState +{ + ClutterTimeline *timeline; + GTimeVal start_time; + guint new_frame_counter; + gint expected_frame; + gint completion_count; + gboolean passed; + guint source_id; + GTimeVal prev_tick; + gulong msecs_delta; +} TestState; static void @@ -38,7 +42,7 @@ new_frame_cb (ClutterTimeline *timeline, g_get_current_time (¤t_time); - current_frame = clutter_timeline_get_current_frame (state->timeline); + current_frame = clutter_timeline_get_elapsed_time (state->timeline); msec_diff = (current_time.tv_sec - state->start_time.tv_sec) * 1000; msec_diff += (current_time.tv_usec - state->start_time.tv_usec)/1000; @@ -46,13 +50,13 @@ new_frame_cb (ClutterTimeline *timeline, /* If we expect to have interpolated past the end of the timeline * we keep track of the overflow so we can determine when * the next timeout will happen. We then clip expected_frames - * to TEST_TIMELINE_FRAME_COUNT since clutter-timeline + * to TEST_TIMELINE_DURATION since clutter-timeline * semantics guaranty this frame is always signaled before * looping */ - if (state->expected_frame > TEST_TIMELINE_FRAME_COUNT) + if (state->expected_frame > TEST_TIMELINE_DURATION) { - loop_overflow = state->expected_frame - TEST_TIMELINE_FRAME_COUNT; - state->expected_frame = TEST_TIMELINE_FRAME_COUNT; + loop_overflow = state->expected_frame - TEST_TIMELINE_DURATION; + state->expected_frame = TEST_TIMELINE_DURATION; } if (current_frame >= (state->expected_frame-TEST_ERROR_TOLERANCE) @@ -95,10 +99,10 @@ new_frame_cb (ClutterTimeline *timeline, g_usleep (1000000); } - if (current_frame >= TEST_TIMELINE_FRAME_COUNT) + if (current_frame >= TEST_TIMELINE_DURATION) { state->expected_frame += loop_overflow; - state->expected_frame -= TEST_TIMELINE_FRAME_COUNT; + state->expected_frame -= TEST_TIMELINE_DURATION; g_test_message ("End of timeline reached: " "Wrapping expected frame too %i\n", state->expected_frame); @@ -130,6 +134,29 @@ completed_cb (ClutterTimeline *timeline, } } +static gboolean +frame_tick (gpointer data) +{ + TestState *state = data; + GTimeVal cur_tick = { 0, }; + gulong msecs; + + g_get_current_time (&cur_tick); + + if (state->prev_tick.tv_sec == 0) + state->prev_tick = cur_tick; + + msecs = (cur_tick.tv_sec - state->prev_tick.tv_sec) * 1000 + + (cur_tick.tv_usec - state->prev_tick.tv_usec) / 1000; + + if (clutter_timeline_is_playing (state->timeline)) + clutter_timeline_advance_delta (state->timeline, msecs); + + state->msecs_delta = msecs; + state->prev_tick = cur_tick; + + return TRUE; +} void test_timeline_interpolate (TestConformSimpleFixture *fixture, @@ -138,8 +165,7 @@ test_timeline_interpolate (TestConformSimpleFixture *fixture, TestState state; state.timeline = - clutter_timeline_new (TEST_TIMELINE_FRAME_COUNT, - TEST_TIMELINE_FPS); + clutter_timeline_new (TEST_TIMELINE_DURATION); clutter_timeline_set_loop (state.timeline, TRUE); g_signal_connect (G_OBJECT(state.timeline), "new-frame", @@ -154,12 +180,18 @@ test_timeline_interpolate (TestConformSimpleFixture *fixture, state.new_frame_counter = 0; state.passed = TRUE; state.expected_frame = 0; + state.prev_tick.tv_sec = 0; + state.prev_tick.tv_usec = 0; + state.msecs_delta = 0; + + state.source_id = + clutter_threads_add_frame_source (60, frame_tick, &state); g_get_current_time (&state.start_time); clutter_timeline_start (state.timeline); clutter_main(); + g_source_remove (state.source_id); g_object_unref (state.timeline); } - diff --git a/tests/conform/test-timeline-rewind.c b/tests/conform/test-timeline-rewind.c index 26ac93387..b1cfa13c0 100644 --- a/tests/conform/test-timeline-rewind.c +++ b/tests/conform/test-timeline-rewind.c @@ -4,15 +4,17 @@ #include "test-conform-common.h" -#define TEST_TIMELINE_FPS 10 -#define TEST_TIMELINE_FRAME_COUNT 5 +#define TEST_TIMELINE_DURATION 500 #define TEST_WATCHDOG_KICK_IN_SECONDS 10 -typedef struct _TestState { - ClutterTimeline *timeline; - gint rewind_count; -}TestState; - +typedef struct _TestState +{ + ClutterTimeline *timeline; + gint rewind_count; + guint source_id; + GTimeVal prev_tick; + gulong msecs_delta; +} TestState; static gboolean watchdog_timeout (TestState *state) @@ -34,15 +36,14 @@ watchdog_timeout (TestState *state) return FALSE; } - static void new_frame_cb (ClutterTimeline *timeline, gint frame_num, TestState *state) { - gint current_frame = clutter_timeline_get_current_frame (timeline); + gint elapsed_time = clutter_timeline_get_elapsed_time (timeline); - if (current_frame == TEST_TIMELINE_FRAME_COUNT) + if (elapsed_time == TEST_TIMELINE_DURATION) { g_test_message ("new-frame signal recieved (end of timeline)\n"); g_test_message ("Rewinding timeline\n"); @@ -51,7 +52,7 @@ new_frame_cb (ClutterTimeline *timeline, } else { - if (current_frame == 0) + if (elapsed_time == 0) { g_test_message ("new-frame signal recieved (start of timeline)\n"); } @@ -68,6 +69,29 @@ new_frame_cb (ClutterTimeline *timeline, } } +static gboolean +frame_tick (gpointer data) +{ + TestState *state = data; + GTimeVal cur_tick = { 0, }; + gulong msecs; + + g_get_current_time (&cur_tick); + + if (state->prev_tick.tv_sec == 0) + state->prev_tick = cur_tick; + + msecs = (cur_tick.tv_sec - state->prev_tick.tv_sec) * 1000 + + (cur_tick.tv_usec - state->prev_tick.tv_usec) / 1000; + + if (clutter_timeline_is_playing (state->timeline)) + clutter_timeline_advance_delta (state->timeline, msecs); + + state->msecs_delta = msecs; + state->prev_tick = cur_tick; + + return TRUE; +} void test_timeline_rewind (TestConformSimpleFixture *fixture, @@ -76,8 +100,7 @@ test_timeline_rewind (TestConformSimpleFixture *fixture, TestState state; state.timeline = - clutter_timeline_new (TEST_TIMELINE_FRAME_COUNT, - TEST_TIMELINE_FPS); + clutter_timeline_new (TEST_TIMELINE_DURATION); g_signal_connect (G_OBJECT(state.timeline), "new-frame", G_CALLBACK(new_frame_cb), @@ -88,11 +111,17 @@ test_timeline_rewind (TestConformSimpleFixture *fixture, (GSourceFunc)watchdog_timeout, &state); state.rewind_count = 0; + state.prev_tick.tv_sec = 0; + state.prev_tick.tv_usec = 0; + state.msecs_delta = 0; + + state.source_id = + clutter_threads_add_frame_source (60, frame_tick, &state); clutter_timeline_start (state.timeline); clutter_main(); + g_source_remove (state.source_id); g_object_unref (state.timeline); } - diff --git a/tests/conform/test-timeline-smoothness.c b/tests/conform/test-timeline-smoothness.c deleted file mode 100644 index 9b0b5ae47..000000000 --- a/tests/conform/test-timeline-smoothness.c +++ /dev/null @@ -1,115 +0,0 @@ -#include -#include -#include - -#include "test-conform-common.h" - -#define TEST_TIMELINE_FPS 10 -#define TEST_TIMELINE_FRAME_COUNT 20 -#define TEST_ERROR_TOLERANCE 5 - -typedef struct _TestState { - ClutterTimeline *timeline; - GTimeVal start_time; - GTimeVal prev_frame_time; - guint frame; - gint completion_count; - gint passed; -}TestState; - - -static void -new_frame_cb (ClutterTimeline *timeline, - gint frame_num, - TestState *state) -{ - GTimeVal current_time; - glong total_elapsed_ms; - glong frame_elapsed_ms = 0; - gchar *bump = ""; - - g_get_current_time (¤t_time); - - total_elapsed_ms = (current_time.tv_sec - state->start_time.tv_sec) * 1000; - total_elapsed_ms += (current_time.tv_usec - state->start_time.tv_usec)/1000; - - if (state->frame>0) - { - frame_elapsed_ms = - (current_time.tv_sec - state->prev_frame_time.tv_sec) * 1000; - frame_elapsed_ms += - (current_time.tv_usec - state->prev_frame_time.tv_usec)/1000; - - if (ABS(frame_elapsed_ms - (1000/TEST_TIMELINE_FPS)) - > TEST_ERROR_TOLERANCE) - { - state->passed = FALSE; - bump = " (BUMP)"; - } - } - - g_test_message ("timeline frame=%-2d total elapsed=%-4li(ms) " - "since last frame=%-4li(ms)%s\n", - clutter_timeline_get_current_frame(state->timeline), - total_elapsed_ms, - frame_elapsed_ms, - bump); - - state->prev_frame_time = current_time; - state->frame++; -} - - -static void -completed_cb (ClutterTimeline *timeline, - TestState *state) -{ - state->completion_count++; - - if (state->completion_count == 2) - { - if (state->passed) - { - g_test_message ("Passed\n"); - clutter_main_quit (); - } - else - { - g_test_message ("Failed\n"); - exit (EXIT_FAILURE); - } - } -} - - -void -test_timeline_smoothness (TestConformSimpleFixture *fixture, - gconstpointer data) -{ - TestState state; - - state.timeline = - clutter_timeline_new (TEST_TIMELINE_FRAME_COUNT, - TEST_TIMELINE_FPS); - clutter_timeline_set_loop (state.timeline, TRUE); - g_signal_connect (G_OBJECT(state.timeline), - "new-frame", - G_CALLBACK(new_frame_cb), - &state); - g_signal_connect (G_OBJECT(state.timeline), - "completed", - G_CALLBACK(completed_cb), - &state); - - state.frame = 0; - state.completion_count = 0; - state.passed = TRUE; - - g_get_current_time (&state.start_time); - clutter_timeline_start (state.timeline); - - clutter_main(); - - g_object_unref (state.timeline); -} - diff --git a/tests/conform/test-timeline.c b/tests/conform/test-timeline.c index 47218f13d..900a3feb9 100644 --- a/tests/conform/test-timeline.c +++ b/tests/conform/test-timeline.c @@ -15,6 +15,7 @@ for. */ #define FRAME_COUNT 10 +#define FPS 30 typedef struct _TimelineData TimelineData; @@ -53,13 +54,21 @@ timeline_complete_cb (ClutterTimeline *timeline, static void timeline_new_frame_cb (ClutterTimeline *timeline, - gint frame_no, + gint msec, TimelineData *data) { + /* Calculate an approximate frame number from the duration with + rounding */ + int frame_no = ((msec * FRAME_COUNT + (FRAME_COUNT * 1000 / FPS) / 2) + / (FRAME_COUNT * 1000 / FPS)); + if (g_test_verbose ()) g_print ("%i: Doing frame %d, delta = %i\n", data->timeline_num, frame_no, - clutter_timeline_get_delta (timeline, NULL)); + clutter_timeline_get_delta (timeline)); + + g_assert (frame_no >= 0 && frame_no <= FRAME_COUNT); + data->frame_hit_count[frame_no]++; } @@ -72,7 +81,7 @@ timeline_marker_reached_cb (ClutterTimeline *timeline, if (g_test_verbose ()) g_print ("%i: Marker '%s' (%d) reached, delta = %i\n", data->timeline_num, marker_name, frame_num, - clutter_timeline_get_delta (timeline, NULL)); + clutter_timeline_get_delta (timeline)); data->markers_hit = g_slist_prepend (data->markers_hit, g_strdup (marker_name)); } @@ -128,7 +137,7 @@ check_timeline (ClutterTimeline *timeline, if (check_missed_frames) { for (i = 0; i < FRAME_COUNT; i++) - if (data->frame_hit_count[i + frame_offset] != 1) + if (data->frame_hit_count[i + frame_offset] < 1) missed_frame_count++; if (missed_frame_count) @@ -156,7 +165,7 @@ check_timeline (ClutterTimeline *timeline, } static gboolean -timeout_cb (gpointer data) +timeout_cb (gpointer data G_GNUC_UNUSED) { clutter_main_quit (); @@ -172,10 +181,51 @@ delay_cb (gpointer data) return TRUE; } +typedef struct _FrameCounter FrameCounter; + +struct _FrameCounter +{ + GTimeVal prev_tick; + gulong msecs_delta; + + GSList *timelines; +}; + +static gboolean +frame_tick (gpointer data) +{ + FrameCounter *counter = data; + GTimeVal cur_tick = { 0, }; + GSList *l; + gulong msecs; + + g_get_current_time (&cur_tick); + + if (counter->prev_tick.tv_sec == 0) + counter->prev_tick = cur_tick; + + msecs = (cur_tick.tv_sec - counter->prev_tick.tv_sec) * 1000 + + (cur_tick.tv_usec - counter->prev_tick.tv_usec) / 1000; + + for (l = counter->timelines; l != NULL; l = l->next) + { + ClutterTimeline *timeline = l->data; + + if (clutter_timeline_is_playing (timeline)) + clutter_timeline_advance_delta (timeline, msecs); + } + + counter->msecs_delta = msecs; + counter->prev_tick = cur_tick; + + return TRUE; +} + void test_timeline (TestConformSimpleFixture *fixture, gconstpointer data) { + FrameCounter *counter; ClutterTimeline *timeline_1; TimelineData data_1; ClutterTimeline *timeline_2; @@ -185,35 +235,51 @@ test_timeline (TestConformSimpleFixture *fixture, gchar **markers; gsize n_markers; guint delay_tag; + guint source_id; + + counter = g_new0 (FrameCounter, 1); + + source_id = clutter_threads_add_frame_source (FPS, frame_tick, counter); timeline_data_init (&data_1, 1); - timeline_1 = clutter_timeline_new (FRAME_COUNT, 30); - clutter_timeline_add_marker_at_frame (timeline_1, "foo", 5); - clutter_timeline_add_marker_at_frame (timeline_1, "bar", 5); - clutter_timeline_add_marker_at_frame (timeline_1, "baz", 5); - clutter_timeline_add_marker_at_frame (timeline_1, "near-end-marker", 9); - clutter_timeline_add_marker_at_frame (timeline_1, "end-marker", 10); - markers = clutter_timeline_list_markers (timeline_1, 5, &n_markers); + timeline_1 = clutter_timeline_new (FRAME_COUNT * 1000 / FPS); + clutter_timeline_add_marker_at_time (timeline_1, "foo", 5 * 1000 / FPS); + clutter_timeline_add_marker_at_time (timeline_1, "bar", 5 * 1000 / FPS); + clutter_timeline_add_marker_at_time (timeline_1, "baz", 5 * 1000 / FPS); + clutter_timeline_add_marker_at_time (timeline_1, "near-end-marker", + 9 * 1000 / FPS); + clutter_timeline_add_marker_at_time (timeline_1, "end-marker", + 10 * 1000 / FPS); + markers = clutter_timeline_list_markers (timeline_1, 5 * 1000 / FPS, + &n_markers); g_assert (markers != NULL); g_assert (n_markers == 3); g_strfreev (markers); + counter->timelines = g_slist_prepend (counter->timelines, timeline_1); + timeline_data_init (&data_2, 2); timeline_2 = clutter_timeline_clone (timeline_1); - clutter_timeline_add_marker_at_frame (timeline_2, "bar", 2); + clutter_timeline_add_marker_at_time (timeline_2, "bar", 2 * 1000 / FPS); markers = clutter_timeline_list_markers (timeline_2, -1, &n_markers); g_assert (markers != NULL); g_assert (n_markers == 1); g_assert (strcmp (markers[0], "bar") == 0); g_strfreev (markers); + counter->timelines = g_slist_prepend (counter->timelines, timeline_2); + timeline_data_init (&data_3, 3); timeline_3 = clutter_timeline_clone (timeline_1); clutter_timeline_set_direction (timeline_3, CLUTTER_TIMELINE_BACKWARD); - clutter_timeline_add_marker_at_frame (timeline_3, "foo", 5); - clutter_timeline_add_marker_at_frame (timeline_3, "baz", 8); - clutter_timeline_add_marker_at_frame (timeline_3, "near-end-marker", 1); - clutter_timeline_add_marker_at_frame (timeline_3, "end-marker", 0); + clutter_timeline_add_marker_at_time (timeline_3, "foo", 5 * 1000 / FPS); + clutter_timeline_add_marker_at_time (timeline_3, "baz", 8 * 1000 / FPS); + clutter_timeline_add_marker_at_time (timeline_3, "near-end-marker", + 1 * 1000 / FPS); + clutter_timeline_add_marker_at_time (timeline_3, "end-marker", + 0 * 1000 / FPS); + + counter->timelines = g_slist_prepend (counter->timelines, timeline_3); g_signal_connect (timeline_1, "marker-reached", G_CALLBACK (timeline_marker_reached_cb), @@ -293,4 +359,9 @@ test_timeline (TestConformSimpleFixture *fixture, timeline_data_destroy (&data_3); g_source_remove (delay_tag); + + g_source_remove (source_id); + + g_slist_free (counter->timelines); + g_free (counter); } diff --git a/tests/conform/test-vertex-buffer-contiguous.c b/tests/conform/test-vertex-buffer-contiguous.c index 8b386e650..29558bcbd 100644 --- a/tests/conform/test-vertex-buffer-contiguous.c +++ b/tests/conform/test-vertex-buffer-contiguous.c @@ -184,8 +184,7 @@ test_vertex_buffer_contiguous (TestConformSimpleFixture *fixture, g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state); state.texture = cogl_texture_new_from_data (2, 2, - 0, /* max waste */ - COGL_TEXTURE_NONE, + COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_RGBA_8888, COGL_PIXEL_FORMAT_ANY, 0, /* auto calc row stride */ diff --git a/tests/interactive/test-actor-clone.c b/tests/interactive/test-actor-clone.c index fc595abc5..d2f15f066 100644 --- a/tests/interactive/test-actor-clone.c +++ b/tests/interactive/test-actor-clone.c @@ -48,16 +48,18 @@ input_cb (ClutterActor *stage, { ClutterButtonEvent *button_event; ClutterActor *e; - gint x, y; + gfloat x, y; clutter_event_get_coords (event, &x, &y); button_event = (ClutterButtonEvent *) event; - g_print ("*** button press event (button:%d) at %d, %d ***\n", + g_print ("*** button press event (button:%d) at %.2f, %.2f ***\n", button_event->button, x, y); - e = clutter_stage_get_actor_at_pos (CLUTTER_STAGE (stage), x, y); + e = clutter_stage_get_actor_at_pos (CLUTTER_STAGE (stage), + CLUTTER_PICK_ALL, + x, y); /* only allow hiding the clones */ if (e && CLUTTER_IS_CLONE (e)) @@ -103,12 +105,13 @@ frame_cb (ClutterTimeline *timeline, { SuperOH *oh = data; gint i; + float rotation = clutter_timeline_get_progress (timeline) * 360.0f; /* Rotate everything clockwise about stage center*/ clutter_actor_set_rotation (oh->group, CLUTTER_Z_AXIS, - frame_num, + rotation, oh->stage_width / 2, oh->stage_height / 2, 0); @@ -124,7 +127,7 @@ frame_cb (ClutterTimeline *timeline, */ clutter_actor_set_rotation (oh->hand[i], CLUTTER_Z_AXIS, - -6.0 * frame_num, + -6.0 * rotation, 0, 0, 0); } } @@ -176,7 +179,7 @@ test_actor_clone_main (int argc, char *argv[]) oh = g_new (SuperOH, 1); /* Create a timeline to manage animation */ - oh->timeline = clutter_timeline_new (360, 60); + oh->timeline = clutter_timeline_new (6000); clutter_timeline_set_loop (oh->timeline, TRUE); /* fire a callback for frame change */ @@ -213,6 +216,11 @@ test_actor_clone_main (int argc, char *argv[]) clutter_container_add_actor (CLUTTER_CONTAINER (tmp), real_hand); clutter_container_add_actor (CLUTTER_CONTAINER (stage), tmp); + /* now hide the group so that we can verify that hidden source actors + * still get painted by the Clone + */ + clutter_actor_hide (real_hand); + /* create a new group to hold multiple actors in a group */ oh->group = clutter_group_new(); diff --git a/tests/interactive/test-actors.c b/tests/interactive/test-actors.c index 403931f1b..33fa2d995 100644 --- a/tests/interactive/test-actors.c +++ b/tests/interactive/test-actors.c @@ -48,16 +48,18 @@ input_cb (ClutterActor *stage, { ClutterButtonEvent *button_event; ClutterActor *e; - gint x, y; + gfloat x, y; clutter_event_get_coords (event, &x, &y); button_event = (ClutterButtonEvent *) event; - g_print ("*** button press event (button:%d) at %d, %d ***\n", + g_print ("*** button press event (button:%d) at %.2f, %.2f ***\n", button_event->button, x, y); - e = clutter_stage_get_actor_at_pos (CLUTTER_STAGE (stage), x, y); + e = clutter_stage_get_actor_at_pos (CLUTTER_STAGE (stage), + CLUTTER_PICK_ALL, + x, y); /* only allow hiding the clones */ if (e && (CLUTTER_IS_TEXTURE (e) || CLUTTER_IS_CLONE (e))) @@ -96,17 +98,18 @@ input_cb (ClutterActor *stage, /* Timeline handler */ static void frame_cb (ClutterTimeline *timeline, - gint frame_num, + gint msecs, gpointer data) { SuperOH *oh = data; gint i; + float rotation = clutter_timeline_get_progress (timeline) * 360.0f; /* Rotate everything clockwise about stage center*/ clutter_actor_set_rotation (oh->group, CLUTTER_Z_AXIS, - frame_num, + rotation, oh->stage_width / 2, oh->stage_height / 2, 0); @@ -118,7 +121,7 @@ frame_cb (ClutterTimeline *timeline, */ clutter_actor_set_rotation (oh->hand[i], CLUTTER_Z_AXIS, - -6.0 * frame_num, + -6.0 * rotation, 0, 0, 0); } } @@ -170,7 +173,7 @@ test_actors_main (int argc, char *argv[]) oh->stage = stage; /* Create a timeline to manage animation */ - oh->timeline = clutter_timeline_new (360, 60); + oh->timeline = clutter_timeline_new (6000); clutter_timeline_set_loop (oh->timeline, TRUE); /* fire a callback for frame change */ diff --git a/tests/interactive/test-animation.c b/tests/interactive/test-animation.c index 54cf0fe89..7b31a8912 100644 --- a/tests/interactive/test-animation.c +++ b/tests/interactive/test-animation.c @@ -21,8 +21,8 @@ on_button_press (ClutterActor *actor, gpointer dummy) { ClutterAnimation *animation; - gint old_x, old_y, new_x, new_y; - guint old_width, old_height, new_width, new_height; + gfloat old_x, old_y, new_x, new_y; + gfloat old_width, old_height, new_width, new_height; gdouble new_angle; ClutterVertex vertex = { 0, }; ClutterColor new_color = { 0, }; @@ -60,8 +60,9 @@ on_button_press (ClutterActor *actor, new_color.alpha = 0x88; } - vertex.x = CLUTTER_UNITS_FROM_FLOAT ((float) new_width / 2); - vertex.y = CLUTTER_UNITS_FROM_FLOAT ((float) new_height / 2); + vertex.x = new_width / 2; + vertex.y = new_height / 2; + vertex.z = 0.0; animation = clutter_actor_animate (actor, CLUTTER_EASE_IN_EXPO, 2000, diff --git a/tests/interactive/test-behave.c b/tests/interactive/test-behave.c index c685366df..4a794f57b 100644 --- a/tests/interactive/test-behave.c +++ b/tests/interactive/test-behave.c @@ -164,7 +164,7 @@ test_behave_main (int argc, char *argv[]) clutter_container_add (CLUTTER_CONTAINER (group), rect, hand, NULL); /* Make a timeline */ - timeline = clutter_timeline_new_for_duration (4000); /* num frames, fps */ + timeline = clutter_timeline_new (4000); /* num frames, fps */ clutter_timeline_set_loop (timeline, TRUE); g_signal_connect (timeline, "completed", G_CALLBACK (timeline_completed), diff --git a/tests/interactive/test-binding-pool.c b/tests/interactive/test-binding-pool.c index 1fb74d8fb..62ecc3cf5 100644 --- a/tests/interactive/test-binding-pool.c +++ b/tests/interactive/test-binding-pool.c @@ -161,20 +161,16 @@ key_group_paint (ClutterActor *actor) clutter_actor_get_allocation_box (child, &box); - box.x1 -= CLUTTER_UNITS_FROM_DEVICE (2); - box.y1 -= CLUTTER_UNITS_FROM_DEVICE (2); - box.x2 += CLUTTER_UNITS_FROM_DEVICE (2); - box.y2 += CLUTTER_UNITS_FROM_DEVICE (2); + box.x1 -= 2; + box.y1 -= 2; + box.x2 += 2; + box.y2 += 2; cogl_set_source_color4ub (255, 255, 0, 224); - cogl_rectangle (CLUTTER_UNITS_TO_DEVICE (box.x1), - CLUTTER_UNITS_TO_DEVICE (box.y1), - CLUTTER_UNITS_TO_DEVICE (box.x2), - CLUTTER_UNITS_TO_DEVICE (box.y2)); + cogl_rectangle (box.x1, box.y1, box.x2, box.y2); } - if (CLUTTER_ACTOR_IS_VISIBLE (child)) - clutter_actor_paint (child); + clutter_actor_paint (child); } g_list_free (children); diff --git a/tests/interactive/test-clip.c b/tests/interactive/test-clip.c index bb1dfa536..d756c100a 100644 --- a/tests/interactive/test-clip.c +++ b/tests/interactive/test-clip.c @@ -300,7 +300,7 @@ test_clip_main (int argc, char **argv) stub_actor = clutter_rectangle_new (); clutter_container_add (CLUTTER_CONTAINER (data.stage), stub_actor, NULL); - data.hand = cogl_texture_new_from_file ("redhand.png", 64, + data.hand = cogl_texture_new_from_file ("redhand.png", COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_ANY, NULL); diff --git a/tests/interactive/test-clutter-cairo-flowers.c b/tests/interactive/test-clutter-cairo-flowers.c index c66531672..2abd6c39d 100644 --- a/tests/interactive/test-clutter-cairo-flowers.c +++ b/tests/interactive/test-clutter-cairo-flowers.c @@ -166,40 +166,39 @@ void foo(void) { g_usleep(10000000); } int test_clutter_cairo_flowers_main (int argc, char **argv) { - int i; - ClutterActor *stage; - ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff }; - Flower *flowers[N_FLOWERS]; + int i; + ClutterActor *stage; + ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff }; + Flower *flowers[N_FLOWERS]; - srand(time(NULL)); + srand (time (NULL)); clutter_init (&argc, &argv); stage = clutter_stage_get_default (); - clutter_stage_set_color (CLUTTER_STAGE (stage), - &stage_color); - - g_object_set(stage, "fullscreen", TRUE, NULL); + clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); + clutter_stage_fullscreen (CLUTTER_STAGE (stage)); for (i=0; i< N_FLOWERS; i++) { flowers[i] = g_new0(Flower, 1); flowers[i]->ctex = make_flower_actor(); - flowers[i]->x = rand() % clutter_actor_get_width(stage) - - (PETAL_MIN+PETAL_VAR)*2; - flowers[i]->y = rand() % clutter_actor_get_height(stage); - flowers[i]->rv = rand() % 5 + 1; - flowers[i]->v = rand() % 10 + 2; + flowers[i]->x = rand() % (int) clutter_actor_get_width (stage) + - (PETAL_MIN + PETAL_VAR) * 2; + flowers[i]->y = rand() % (int) clutter_actor_get_height (stage); + flowers[i]->rv = rand() % 5 + 1; + flowers[i]->v = rand() % 10 + 2; - clutter_group_add (CLUTTER_GROUP(stage), flowers[i]->ctex); + clutter_container_add_actor (CLUTTER_CONTAINER (stage), + flowers[i]->ctex); clutter_actor_set_position (flowers[i]->ctex, flowers[i]->x, flowers[i]->y); } g_timeout_add (50, tick, flowers); - clutter_actor_show_all (CLUTTER_ACTOR (stage)); + clutter_actor_show (stage); g_signal_connect (stage, "key-press-event", G_CALLBACK (clutter_main_quit), @@ -207,6 +206,6 @@ test_clutter_cairo_flowers_main (int argc, char **argv) clutter_main(); - return 1; + return EXIT_SUCCESS; } diff --git a/tests/interactive/test-cogl-multitexture.c b/tests/interactive/test-cogl-multitexture.c index a45b4f965..6d7047845 100644 --- a/tests/interactive/test-cogl-multitexture.c +++ b/tests/interactive/test-cogl-multitexture.c @@ -9,8 +9,6 @@ #include #include -#define TIMELINE_FRAME_COUNT 200 - typedef struct _TestMultiLayerMaterialState { ClutterActor *group; @@ -45,9 +43,7 @@ material_rectangle_paint (ClutterActor *actor, gpointer data) TestMultiLayerMaterialState *state = data; cogl_set_source (state->material); - cogl_rectangle_with_multitexture_coords (0, 0, - TIMELINE_FRAME_COUNT, - TIMELINE_FRAME_COUNT, + cogl_rectangle_with_multitexture_coords (0, 0, 200, 200, state->tex_coords, 12); } @@ -86,21 +82,18 @@ test_cogl_multitexture_main (int argc, char *argv[]) G_CALLBACK(material_rectangle_paint), state); state->alpha_tex = - cogl_texture_new_from_file ("./redhand_alpha.png", - -1, /* disable slicing */ - TRUE, + cogl_texture_new_from_file ("redhand_alpha.png", + COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_ANY, NULL); state->redhand_tex = - cogl_texture_new_from_file ("./redhand.png", - -1, /* disable slicing */ - TRUE, + cogl_texture_new_from_file ("redhand.png", + COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_ANY, NULL); state->light_tex0 = - cogl_texture_new_from_file ("./light0.png", - -1, /* disable slicing */ - TRUE, + cogl_texture_new_from_file ("light0.png", + COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_ANY, NULL); @@ -122,8 +115,8 @@ test_cogl_multitexture_main (int argc, char *argv[]) clutter_container_add_actor (CLUTTER_CONTAINER(stage), state->group); - timeline = clutter_timeline_new (TIMELINE_FRAME_COUNT, 26 /* fps */); - g_object_set (timeline, "loop", TRUE, NULL); + timeline = clutter_timeline_new (7692); + clutter_timeline_set_loop (timeline, TRUE); g_signal_connect (timeline, "new-frame", G_CALLBACK (frame_cb), state); diff --git a/tests/interactive/test-cogl-offscreen.c b/tests/interactive/test-cogl-offscreen.c index 366053dc9..8b9d8e8f7 100644 --- a/tests/interactive/test-cogl-offscreen.c +++ b/tests/interactive/test-cogl-offscreen.c @@ -143,13 +143,13 @@ test_coglbox_init (TestCoglbox *self) self->priv = priv = TEST_COGLBOX_GET_PRIVATE(self); printf ("Loading redhand.png\n"); - priv->texhand_id = cogl_texture_new_from_file ("redhand.png", 0, + priv->texhand_id = cogl_texture_new_from_file ("redhand.png", COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_ANY, NULL); printf ("Creating texture with size\n"); - priv->texture_id = cogl_texture_new_with_size (200, 200, 0, + priv->texture_id = cogl_texture_new_with_size (200, 200, COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_RGB_888); diff --git a/tests/interactive/test-cogl-primitives.c b/tests/interactive/test-cogl-primitives.c index 5f20e9bea..fb5adb378 100644 --- a/tests/interactive/test-cogl-primitives.c +++ b/tests/interactive/test-cogl-primitives.c @@ -81,8 +81,8 @@ static PaintFunc paint_func []= static void paint_cb (ClutterActor *self, ClutterTimeline *tl) { - gint paint_index = (clutter_timeline_get_current_frame (tl) - % G_N_ELEMENTS (paint_func)); + gint paint_index = (clutter_timeline_get_progress (tl) + * G_N_ELEMENTS (paint_func)); cogl_push_matrix (); @@ -108,8 +108,7 @@ test_cogl_primitives_main (int argc, char *argv[]) clutter_init(&argc, &argv); - /* One frame for each paint function at one frame per second */ - tl = clutter_timeline_new (G_N_ELEMENTS (paint_func), 1); + tl = clutter_timeline_new (G_N_ELEMENTS (paint_func) * 1000); clutter_timeline_set_loop (tl, TRUE); clutter_timeline_start (tl); diff --git a/tests/interactive/test-cogl-tex-convert.c b/tests/interactive/test-cogl-tex-convert.c index f0ac101a9..bd10d8773 100644 --- a/tests/interactive/test-cogl-tex-convert.c +++ b/tests/interactive/test-cogl-tex-convert.c @@ -144,22 +144,22 @@ test_coglbox_init (TestCoglbox *self) self->priv = priv = TEST_COGLBOX_GET_PRIVATE(self); priv->cogl_tex_id[0] = - cogl_texture_new_from_file ("redhand.png", 0, + cogl_texture_new_from_file ("redhand.png", COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_ANY, NULL); priv->cogl_tex_id[1] = - cogl_texture_new_from_file ("redhand.png", 0, + cogl_texture_new_from_file ("redhand.png", COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_BGRA_8888, NULL); priv->cogl_tex_id[2] = - cogl_texture_new_from_file ("redhand.png", 0, + cogl_texture_new_from_file ("redhand.png", COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_ARGB_8888, NULL); priv->cogl_tex_id[3] = - cogl_texture_new_from_file ("redhand.png", 0, + cogl_texture_new_from_file ("redhand.png", COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_G_8, NULL); } diff --git a/tests/interactive/test-cogl-tex-getset.c b/tests/interactive/test-cogl-tex-getset.c index 18c5a2ce2..b85bd7665 100644 --- a/tests/interactive/test-cogl-tex-getset.c +++ b/tests/interactive/test-cogl-tex-getset.c @@ -132,7 +132,7 @@ test_coglbox_init (TestCoglbox *self) /* Load image from file */ priv->cogl_tex_id[0] = - cogl_texture_new_from_file ("redhand.png", 40, + cogl_texture_new_from_file ("redhand.png", COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_ANY, NULL); @@ -168,7 +168,7 @@ test_coglbox_init (TestCoglbox *self) /* Create new texture from modified data */ priv->cogl_tex_id[1] = - cogl_texture_new_from_data (width, height, 0, + cogl_texture_new_from_data (width, height, COGL_TEXTURE_NONE, format, format, rowstride, data); diff --git a/tests/interactive/test-cogl-tex-polygon.c b/tests/interactive/test-cogl-tex-polygon.c index 0132802a4..851e27169 100644 --- a/tests/interactive/test-cogl-tex-polygon.c +++ b/tests/interactive/test-cogl-tex-polygon.c @@ -173,14 +173,17 @@ test_coglbox_paint (ClutterActor *self) : priv->not_sliced_tex; int tex_width = cogl_texture_get_width (tex_handle); int tex_height = cogl_texture_get_height (tex_handle); + CoglHandle material = cogl_material_new (); - cogl_texture_set_filters (tex_handle, - priv->use_linear_filtering - ? COGL_TEXTURE_FILTER_LINEAR : - COGL_TEXTURE_FILTER_NEAREST, - priv->use_linear_filtering - ? COGL_TEXTURE_FILTER_LINEAR : - COGL_TEXTURE_FILTER_NEAREST); + cogl_material_set_layer (material, 0, tex_handle); + + cogl_material_set_layer_filters (material, 0, + priv->use_linear_filtering + ? COGL_MATERIAL_FILTER_LINEAR : + COGL_MATERIAL_FILTER_NEAREST, + priv->use_linear_filtering + ? COGL_MATERIAL_FILTER_LINEAR : + COGL_MATERIAL_FILTER_NEAREST); cogl_push_matrix (); cogl_translate (tex_width / 2, 0, 0); @@ -188,7 +191,7 @@ test_coglbox_paint (ClutterActor *self) cogl_translate (-tex_width / 2, 0, 0); /* Draw a hand and refect it */ - cogl_set_source_texture (tex_handle); + cogl_set_source (material); cogl_rectangle_with_texture_coords (0, 0, tex_width, tex_height, 0, 0, 1, 1); test_coglbox_fade_texture (tex_handle, @@ -217,6 +220,8 @@ test_coglbox_paint (ClutterActor *self) 1, 1); cogl_pop_matrix (); + + cogl_handle_unref (material); } static void @@ -248,7 +253,7 @@ test_coglbox_init (TestCoglbox *self) priv->use_sliced = FALSE; priv->sliced_tex = - cogl_texture_new_from_file ("redhand.png", 10, + cogl_texture_new_from_file ("redhand.png", COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_ANY, &error); @@ -265,8 +270,8 @@ test_coglbox_init (TestCoglbox *self) } priv->not_sliced_tex = - cogl_texture_new_from_file ("redhand.png", -1, - COGL_TEXTURE_NONE, + cogl_texture_new_from_file ("redhand.png", + COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_ANY, &error); if (priv->not_sliced_tex == COGL_INVALID_HANDLE) @@ -370,8 +375,8 @@ test_cogl_tex_polygon_main (int argc, char *argv[]) clutter_container_add_actor (CLUTTER_CONTAINER (stage), coglbox); /* Timeline for animation */ - timeline = clutter_timeline_new (360, 60); /* num frames, fps */ - g_object_set (timeline, "loop", TRUE, NULL); /* have it loop */ + timeline = clutter_timeline_new (6000); + clutter_timeline_set_loop (timeline, TRUE); g_signal_connect (timeline, "new-frame", G_CALLBACK (frame_cb), coglbox); clutter_timeline_start (timeline); diff --git a/tests/interactive/test-cogl-tex-tile.c b/tests/interactive/test-cogl-tex-tile.c index 1402d2e28..05eb52c75 100644 --- a/tests/interactive/test-cogl-tex-tile.c +++ b/tests/interactive/test-cogl-tex-tile.c @@ -143,14 +143,10 @@ test_coglbox_init (TestCoglbox *self) TestCoglboxPrivate *priv; self->priv = priv = TEST_COGLBOX_GET_PRIVATE(self); - priv->cogl_tex_id = cogl_texture_new_from_file ("redhand.png", 0, + priv->cogl_tex_id = cogl_texture_new_from_file ("redhand.png", COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_ANY, NULL); - - cogl_texture_set_filters (priv->cogl_tex_id, - COGL_TEXTURE_FILTER_LINEAR, - COGL_TEXTURE_FILTER_LINEAR); } static void @@ -202,8 +198,8 @@ test_cogl_tex_tile_main (int argc, char *argv[]) clutter_container_add_actor (CLUTTER_CONTAINER (stage), coglbox); /* Timeline for animation */ - timeline = clutter_timeline_new (360, 60); /* num frames, fps */ - g_object_set (timeline, "loop", TRUE, NULL); /* have it loop */ + timeline = clutter_timeline_new (6000); /* num frames, fps */ + clutter_timeline_set_loop (timeline, TRUE); g_signal_connect (timeline, "new-frame", G_CALLBACK (frame_cb), coglbox); clutter_timeline_start (timeline); diff --git a/tests/interactive/test-cogl-vertex-buffer.c b/tests/interactive/test-cogl-vertex-buffer.c index 903cbfc23..4fad21d07 100644 --- a/tests/interactive/test-cogl-vertex-buffer.c +++ b/tests/interactive/test-cogl-vertex-buffer.c @@ -49,6 +49,7 @@ typedef struct _TestState GLubyte *quad_mesh_colors; GLushort *static_indices; guint n_static_indices; + CoglHandle indices; ClutterTimeline *timeline; } TestState; @@ -58,8 +59,7 @@ frame_cb (ClutterTimeline *timeline, TestState *state) { guint x, y; - guint n_frames = clutter_timeline_get_n_frames (timeline); - float period_progress = ((float)frame_num / (float)n_frames) * 2.0 * G_PI; + float period_progress = clutter_timeline_get_progress (timeline); float period_progress_sin = sinf (period_progress); float wave_shift = period_progress * WAVE_SPEED; float ripple_shift = period_progress * RIPPLE_SPEED; @@ -139,12 +139,13 @@ on_paint (ClutterActor *actor, TestState *state) { cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); cogl_vertex_buffer_draw_elements (state->buffer, - GL_TRIANGLE_STRIP, - 0, - (MESH_WIDTH + 1) * (MESH_HEIGHT + 1), - state->n_static_indices, - GL_UNSIGNED_SHORT, - state->static_indices); + COGL_VERTICES_MODE_TRIANGLE_STRIP, + state->indices, + 0, /* min index */ + (MESH_WIDTH + 1) * + (MESH_HEIGHT + 1), /* max index */ + 0, /* indices offset */ + state->n_static_indices); } static void @@ -220,6 +221,11 @@ init_static_index_arrays (TestState *state) } #undef MESH_INDEX + + state->indices = + cogl_vertex_buffer_indices_new (COGL_INDICES_TYPE_UNSIGNED_SHORT, + state->static_indices, + state->n_static_indices); } static float @@ -280,7 +286,7 @@ init_quad_mesh (TestState *state) cogl_vertex_buffer_add (state->buffer, "gl_Vertex", 3, /* n components */ - GL_FLOAT, + COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, /* normalized */ 0, /* stride */ state->quad_mesh_verts); @@ -288,7 +294,7 @@ init_quad_mesh (TestState *state) cogl_vertex_buffer_add (state->buffer, "gl_Color", 4, /* n components */ - GL_UNSIGNED_BYTE, + COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE, FALSE, /* normalized */ 0, /* stride */ state->quad_mesh_colors); @@ -347,7 +353,7 @@ test_cogl_vertex_buffer_main (int argc, char *argv[]) (stage_geom.width / 2.0) - (dummy_width / 2.0), (stage_geom.height / 2.0) - (dummy_height / 2.0)); - state.timeline = clutter_timeline_new (360, 60); + state.timeline = clutter_timeline_new (6000); clutter_timeline_set_loop (state.timeline, TRUE); g_signal_connect (state.timeline, "new-frame", @@ -368,6 +374,7 @@ test_cogl_vertex_buffer_main (int argc, char *argv[]) clutter_main (); cogl_handle_unref (state.buffer); + cogl_handle_unref (state.indices); g_source_remove (idle_source); diff --git a/tests/interactive/test-depth.c b/tests/interactive/test-depth.c index 39799c4bd..7f5d1edd0 100644 --- a/tests/interactive/test-depth.c +++ b/tests/interactive/test-depth.c @@ -26,7 +26,7 @@ raise_top (gpointer ignored) static ClutterActor * clone_box (ClutterActor *original) { - guint width, height; + gfloat width, height; ClutterActor *group; ClutterActor *clone; @@ -35,38 +35,39 @@ clone_box (ClutterActor *original) group = clutter_group_new (); clone = clutter_clone_new (original); clutter_container_add_actor (CLUTTER_CONTAINER (group), clone); - clutter_actor_set_depth (clone, width/2); + clutter_actor_set_depth (clone, width / 2); clone = clutter_clone_new (original); clutter_container_add_actor (CLUTTER_CONTAINER (group), clone); - clutter_actor_set_rotation (clone, CLUTTER_Y_AXIS, 180, width/2, 0, 0); - clutter_actor_set_depth (clone, -(gint)width/2); + clutter_actor_set_rotation (clone, CLUTTER_Y_AXIS, 180, width / 2, 0, 0); + clutter_actor_set_depth (clone, -width / 2); clone = clutter_clone_new (original); clutter_container_add_actor (CLUTTER_CONTAINER (group), clone); clutter_actor_set_rotation (clone, CLUTTER_Y_AXIS, 90, 0, 0, 0); - clutter_actor_set_depth (clone, width/2); + clutter_actor_set_depth (clone, width / 2); clutter_actor_set_position (clone, 0, 0); clone = clutter_clone_new (original); clutter_container_add_actor (CLUTTER_CONTAINER (group), clone); clutter_actor_set_rotation (clone, CLUTTER_Y_AXIS, 90, 0, 0, 0); - clutter_actor_set_depth (clone, width/2); + clutter_actor_set_depth (clone, width / 2); clutter_actor_set_position (clone, width, 0); clone = clutter_clone_new (original); clutter_container_add_actor (CLUTTER_CONTAINER (group), clone); clutter_actor_set_rotation (clone, CLUTTER_X_AXIS, 90, 0, 0, 0); - clutter_actor_set_depth (clone, -(gint)width/2); + clutter_actor_set_depth (clone, -width / 2); clutter_actor_set_position (clone, 0, height); clone = clutter_clone_new (original); clutter_container_add_actor (CLUTTER_CONTAINER (group), clone); clutter_actor_set_rotation (clone, CLUTTER_X_AXIS, 90, 0, 0, 0); - clutter_actor_set_depth (clone, -(gint)width/2); + clutter_actor_set_depth (clone, -width / 2); clutter_actor_set_position (clone, 0, 0); clutter_actor_show_all (group); + return group; } @@ -78,8 +79,8 @@ janus_group (const gchar *front_text, ClutterColor red = {0xff, 0x00, 0x00, 0xff}; ClutterColor green = {0x00, 0xff, 0x00, 0xff}; ClutterActor *group, *rectangle, *front, *back; - guint width, height; - guint width2, height2; + gfloat width, height; + gfloat width2, height2; group = clutter_group_new (); rectangle = clutter_rectangle_new_with_color (&slide_color); @@ -93,11 +94,12 @@ janus_group (const gchar *front_text, if (width2 > width) width = width2; + if (height2 > height) height = height2; clutter_actor_set_size (rectangle, width, height); - clutter_actor_set_rotation (back, CLUTTER_Y_AXIS, 180, width/2, 0, 0); + clutter_actor_set_rotation (back, CLUTTER_Y_AXIS, 180, width / 2, 0, 0); clutter_container_add (CLUTTER_CONTAINER (group), back, rectangle, front, NULL); @@ -155,7 +157,7 @@ test_depth_main (int argc, char *argv[]) clutter_container_add_actor (CLUTTER_CONTAINER (stage), label); /* 3 seconds, at 60 fps */ - timeline = clutter_timeline_new (180, 60); + timeline = clutter_timeline_new (3000); g_signal_connect (timeline, "completed", G_CALLBACK (timeline_completed), NULL); diff --git a/tests/interactive/test-easing.c b/tests/interactive/test-easing.c index a8ff176f7..e39fc7e21 100644 --- a/tests/interactive/test-easing.c +++ b/tests/interactive/test-easing.c @@ -53,8 +53,8 @@ on_button_press (ClutterActor *actor, if (event->button == 3) { gchar *text; - guint stage_width, stage_height; - guint label_width, label_height; + gfloat stage_width, stage_height; + gfloat label_width, label_height; current_mode = (current_mode + 1 < n_easing_modes) ? current_mode + 1 : 0; @@ -110,8 +110,8 @@ test_easing_main (int argc, char *argv[]) ClutterColor stage_color = { 0x66, 0x66, 0xdd, 0xff }; ClutterColor rect_color = { 0x44, 0xdd, 0x44, 0xff }; gchar *text; - guint stage_width, stage_height; - guint label_width, label_height; + gfloat stage_width, stage_height; + gfloat label_width, label_height; clutter_init (&argc, &argv); diff --git a/tests/interactive/test-fullscreen.c b/tests/interactive/test-fullscreen.c index 36948cf74..2952a8eb4 100644 --- a/tests/interactive/test-fullscreen.c +++ b/tests/interactive/test-fullscreen.c @@ -15,7 +15,7 @@ static int state = START; static void on_fullscreen (ClutterStage *stage) { - g_debug ("fullscreen set, size: %dx%d, mapped: %s", + g_debug ("fullscreen set, size: %.2fx%.2f, mapped: %s", clutter_actor_get_width (CLUTTER_ACTOR (stage)), clutter_actor_get_height (CLUTTER_ACTOR (stage)), CLUTTER_ACTOR_IS_MAPPED (stage) ? "true" : "false"); @@ -24,7 +24,7 @@ on_fullscreen (ClutterStage *stage) static void on_unfullscreen (ClutterStage *stage) { - g_debug ("fullscreen unset, size: %dx%d, mapped: %s", + g_debug ("fullscreen unset, size: %.2fx%.2f, mapped: %s", clutter_actor_get_width (CLUTTER_ACTOR (stage)), clutter_actor_get_height (CLUTTER_ACTOR (stage)), CLUTTER_ACTOR_IS_MAPPED (stage) ? "true" : "false"); @@ -85,7 +85,7 @@ test_fullscreen_main (int argc, char *argv[]) clutter_stage_fullscreen (CLUTTER_STAGE (stage)); clutter_actor_show (stage); - g_debug ("stage size: %dx%d, mapped: %s", + g_debug ("stage size: %.2fx%.2f, mapped: %s", clutter_actor_get_width (stage), clutter_actor_get_height (stage), CLUTTER_ACTOR_IS_MAPPED (stage) ? "true" : "false"); diff --git a/tests/interactive/test-layout.c b/tests/interactive/test-layout.c index 25da8ef6a..5d2dcaffc 100644 --- a/tests/interactive/test-layout.c +++ b/tests/interactive/test-layout.c @@ -52,12 +52,12 @@ G_DEFINE_TYPE_WITH_CODE (MyThing, struct _MyThingPrivate { - GList *children; + GList *children; - ClutterUnit spacing; - ClutterUnit padding; + gfloat spacing; + gfloat padding; - guint use_transformed_box : 1; + guint use_transformed_box : 1; }; /* Add, remove, foreach, copied from ClutterGroup code. */ @@ -139,11 +139,11 @@ my_thing_set_property (GObject *gobject, switch (prop_id) { case PROP_SPACING: - priv->spacing = clutter_value_get_unit (value); + priv->spacing = g_value_get_float (value); break; case PROP_PADDING: - priv->padding = clutter_value_get_unit (value); + priv->padding = g_value_get_float (value); break; case PROP_USE_TRANSFORMED_BOX: @@ -174,11 +174,11 @@ my_thing_get_property (GObject *gobject, switch (prop_id) { case PROP_SPACING: - clutter_value_set_unit (value, priv->spacing); + g_value_set_float (value, priv->spacing); break; case PROP_PADDING: - clutter_value_set_unit (value, priv->padding); + g_value_set_float (value, priv->padding); break; case PROP_USE_TRANSFORMED_BOX: @@ -214,14 +214,14 @@ my_thing_dispose (GObject *gobject) static void my_thing_get_preferred_width (ClutterActor *self, - ClutterUnit for_height, - ClutterUnit *min_width_p, - ClutterUnit *natural_width_p) + gfloat for_height, + gfloat *min_width_p, + gfloat *natural_width_p) { MyThingPrivate *priv; GList *l; - ClutterUnit min_left, min_right; - ClutterUnit natural_left, natural_right; + gfloat min_left, min_right; + gfloat natural_left, natural_right; priv = MY_THING (self)->priv; @@ -233,11 +233,11 @@ my_thing_get_preferred_width (ClutterActor *self, for (l = priv->children; l != NULL; l = l->next) { ClutterActor *child; - ClutterUnit child_x, child_min, child_natural; + gfloat child_x, child_min, child_natural; child = l->data; - child_x = clutter_actor_get_xu (child); + child_x = clutter_actor_get_x (child); clutter_actor_get_preferred_size (child, &child_min, NULL, @@ -292,14 +292,14 @@ my_thing_get_preferred_width (ClutterActor *self, static void my_thing_get_preferred_height (ClutterActor *self, - ClutterUnit for_width, - ClutterUnit *min_height_p, - ClutterUnit *natural_height_p) + gfloat for_width, + gfloat *min_height_p, + gfloat *natural_height_p) { MyThingPrivate *priv; GList *l; - ClutterUnit min_top, min_bottom; - ClutterUnit natural_top, natural_bottom; + gfloat min_top, min_bottom; + gfloat natural_top, natural_bottom; priv = MY_THING (self)->priv; @@ -311,11 +311,11 @@ my_thing_get_preferred_height (ClutterActor *self, for (l = priv->children; l != NULL; l = l->next) { ClutterActor *child; - ClutterUnit child_y, child_min, child_natural; + gfloat child_y, child_min, child_natural; child = l->data; - child_y = clutter_actor_get_yu (child); + child_y = clutter_actor_get_y (child); clutter_actor_get_preferred_size (child, NULL, &child_min, @@ -369,17 +369,16 @@ my_thing_get_preferred_height (ClutterActor *self, } static void -my_thing_allocate (ClutterActor *self, - const ClutterActorBox *box, - gboolean origin_changed) +my_thing_allocate (ClutterActor *self, + const ClutterActorBox *box, + ClutterAllocationFlags flags) { MyThingPrivate *priv; - ClutterUnit current_x, current_y, max_row_height; + gfloat current_x, current_y, max_row_height; GList *l; /* chain up to set actor->allocation */ - CLUTTER_ACTOR_CLASS (my_thing_parent_class)->allocate (self, box, - origin_changed); + CLUTTER_ACTOR_CLASS (my_thing_parent_class)->allocate (self, box, flags); priv = MY_THING (self)->priv; @@ -394,7 +393,7 @@ my_thing_allocate (ClutterActor *self, for (l = priv->children; l != NULL; l = l->next) { ClutterActor *child; - ClutterUnit natural_width, natural_height; + gfloat natural_width, natural_height; ClutterActorBox child_box; child = l->data; @@ -418,7 +417,7 @@ my_thing_allocate (ClutterActor *self, child_box.x2 = child_box.x1 + natural_width; child_box.y2 = child_box.y1 + natural_height; - clutter_actor_allocate (child, &child_box, origin_changed); + clutter_actor_allocate (child, &child_box, flags); /* if we take into account the transformation of the children * then we first check if it's transformed; then we get the @@ -435,7 +434,7 @@ my_thing_allocate (ClutterActor *self, ClutterActorBox transformed_box = { 0, }; /* origin */ - if (!origin_changed) + if (!(flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED)) { v1.x = 0; v1.y = 0; @@ -490,8 +489,7 @@ my_thing_paint (ClutterActor *actor) g_assert (child != NULL); - if (CLUTTER_ACTOR_IS_VISIBLE (child)) - clutter_actor_paint (child); + clutter_actor_paint (child); } cogl_pop_matrix(); @@ -518,21 +516,21 @@ my_thing_class_init (MyThingClass *klass) g_object_class_install_property (gobject_class, PROP_SPACING, - clutter_param_spec_unit ("spacing", - "Spacing", - "Spacing of the thing", - 0, CLUTTER_MAXUNIT, - 0, - G_PARAM_READWRITE)); + g_param_spec_float ("spacing", + "Spacing", + "Spacing of the thing", + 0, G_MAXFLOAT, + 0, + G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_PADDING, - clutter_param_spec_unit ("padding", - "Padding", - "Padding around the thing", - 0, CLUTTER_MAXUNIT, - 0, - G_PARAM_READWRITE)); + g_param_spec_float ("padding", + "Padding", + "Padding around the thing", + 0, G_MAXFLOAT, + 0, + G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_USE_TRANSFORMED_BOX, @@ -552,14 +550,13 @@ my_thing_init (MyThing *thing) } ClutterActor * -my_thing_new (gint padding, - gint spacing) +my_thing_new (gfloat padding, + gfloat spacing) { return g_object_new (MY_TYPE_THING, - "padding", CLUTTER_UNITS_FROM_DEVICE (padding), - "spacing", CLUTTER_UNITS_FROM_DEVICE (spacing), + "padding", padding, + "spacing", spacing, NULL); - } /* test code */ @@ -592,13 +589,13 @@ static void increase_property_value (ClutterActor *actor, const char *property_name) { - ClutterUnit value; + gfloat value; g_object_get (G_OBJECT (actor), property_name, &value, NULL); - value = value + CLUTTER_UNITS_FROM_DEVICE (10); + value = value + 10.0; g_object_set (G_OBJECT (box), property_name, value, @@ -609,13 +606,13 @@ static void decrease_property_value (ClutterActor *actor, const char *property_name) { - ClutterUnit value; + gfloat value; g_object_get (G_OBJECT (actor), property_name, &value, NULL); - value = MAX (0, value - CLUTTER_UNITS_FROM_DEVICE (10)); + value = MAX (0, value - 10.0); g_object_set (G_OBJECT (box), property_name, value, @@ -748,7 +745,7 @@ test_layout_main (int argc, char *argv[]) { ClutterActor *stage, *instructions; ClutterAlpha *alpha; - gint i; + gint i, size; GError *error = NULL; clutter_init (&argc, &argv); @@ -758,7 +755,7 @@ test_layout_main (int argc, char *argv[]) clutter_color_from_string (&bg_color, "Red"); - main_timeline = clutter_timeline_new_for_duration (2000); + main_timeline = clutter_timeline_new (2000); clutter_timeline_set_loop (main_timeline, TRUE); g_signal_connect (main_timeline, "new-frame", G_CALLBACK (relayout_on_frame), @@ -776,7 +773,12 @@ test_layout_main (int argc, char *argv[]) if (error) g_error ("Unable to load 'redhand.png': %s", error->message); - for (i = 0; i < 33; i++) + size = g_random_int_range (MIN_SIZE, MAX_SIZE); + clutter_actor_set_size (icon, size, size); + clutter_behaviour_apply (behaviour, icon); + clutter_container_add_actor (CLUTTER_CONTAINER (box), icon); + + for (i = 1; i < 33; i++) { ClutterActor *clone = create_item (); diff --git a/tests/interactive/test-multistage.c b/tests/interactive/test-multistage.c index 21f6427ae..1cc1fc8ab 100644 --- a/tests/interactive/test-multistage.c +++ b/tests/interactive/test-multistage.c @@ -72,8 +72,8 @@ on_button_press (ClutterActor *actor, win_title = g_strdup_printf ("Stage:%p", new_stage); clutter_stage_set_title (CLUTTER_STAGE(new_stage), win_title); - timeline = clutter_timeline_new_for_duration (2000); - g_object_set (timeline, "loop", TRUE, NULL); + timeline = clutter_timeline_new (2000); + clutter_timeline_set_loop (timeline, TRUE); alpha = clutter_alpha_new_full (timeline, CLUTTER_LINEAR); r_behave = clutter_behaviour_rotate_new (alpha, diff --git a/tests/interactive/test-paint-wrapper.c b/tests/interactive/test-paint-wrapper.c index 0a7f7550e..e84d72c84 100644 --- a/tests/interactive/test-paint-wrapper.c +++ b/tests/interactive/test-paint-wrapper.c @@ -51,7 +51,7 @@ input_cb (ClutterStage *stage, { ClutterButtonEvent *button_event; ClutterActor *e; - gint x, y; + gfloat x, y; clutter_event_get_coords (event, &x, &y); @@ -59,7 +59,7 @@ input_cb (ClutterStage *stage, g_print ("*** button press event (button:%d) ***\n", button_event->button); - e = clutter_stage_get_actor_at_pos (stage, x, y); + e = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, x, y); if (e && (CLUTTER_IS_TEXTURE (e) || CLUTTER_IS_CLONE (e))) { @@ -88,17 +88,18 @@ input_cb (ClutterStage *stage, /* Timeline handler */ static void frame_cb (ClutterTimeline *timeline, - gint frame_num, + gint msecs, gpointer data) { - SuperOH *oh = (SuperOH *)data; - gint i; + SuperOH *oh = (SuperOH *)data; + gint i; + float rotation = clutter_timeline_get_progress (timeline) * 360.0f; /* Rotate everything clockwise about stage center*/ clutter_actor_set_rotation (CLUTTER_ACTOR (oh->group), CLUTTER_Z_AXIS, - frame_num, + rotation, CLUTTER_STAGE_WIDTH () / 2, CLUTTER_STAGE_HEIGHT () / 2, 0); @@ -116,7 +117,7 @@ frame_cb (ClutterTimeline *timeline, * unit based functions to fix. */ clutter_actor_set_rotation (oh->hand[i], CLUTTER_Z_AXIS, - - 6.0 * frame_num, 0, 0, 0); + - 6.0 * rotation, 0, 0, 0); } } @@ -125,7 +126,7 @@ hand_pre_paint (ClutterActor *actor, gpointer user_data) { SuperOH *oh = (SuperOH *) user_data; - guint w, h; + gfloat w, h; int actor_num; for (actor_num = 0; oh->hand[actor_num] != actor; actor_num++); @@ -145,7 +146,7 @@ hand_post_paint (ClutterActor *actor, gpointer user_data) { SuperOH *oh = (SuperOH *) user_data; - guint w, h; + gfloat w, h; int actor_num; for (actor_num = 0; oh->hand[actor_num] != actor; actor_num++); @@ -208,8 +209,8 @@ test_paint_wrapper_main (int argc, char *argv[]) oh = g_new(SuperOH, 1); /* Create a timeline to manage animation */ - timeline = clutter_timeline_new (360, 60); /* num frames, fps */ - g_object_set (timeline, "loop", TRUE, NULL); /* have it loop */ + timeline = clutter_timeline_new (6000); + clutter_timeline_set_loop (timeline, TRUE); /* fire a callback for frame change */ g_signal_connect (timeline, "new-frame", G_CALLBACK (frame_cb), oh); diff --git a/tests/interactive/test-pixmap.c b/tests/interactive/test-pixmap.c index 882eff0b3..eb10427b7 100644 --- a/tests/interactive/test-pixmap.c +++ b/tests/interactive/test-pixmap.c @@ -233,7 +233,7 @@ test_pixmap_main (int argc, char **argv) clutter_actor_set_position (stage, 0, 150); clutter_stage_set_color (CLUTTER_STAGE (stage), &gry); - timeline = clutter_timeline_new (60*5, 60); + timeline = clutter_timeline_new (5000); g_signal_connect (timeline, "completed", G_CALLBACK (timeline_completed), NULL); diff --git a/tests/interactive/test-project.c b/tests/interactive/test-project.c index 7c9403014..f61fff4bf 100644 --- a/tests/interactive/test-project.c +++ b/tests/interactive/test-project.c @@ -21,19 +21,17 @@ init_handles () clutter_actor_set_position (p[i], 0, 0); clutter_group_add (CLUTTER_GROUP (main_stage), p[i]); - clutter_actor_set_positionu (p[i], - v[i].x - - clutter_actor_get_widthu (p[i])/2, - v[i].y - - clutter_actor_get_heightu (p[i])/2); + clutter_actor_set_position (p[i], + v[i].x - clutter_actor_get_width (p[i]) / 2, + v[i].y - clutter_actor_get_height (p[i]) / 2); clutter_actor_raise_top (p[i]); clutter_actor_show (p[i]); } - v1.x = clutter_actor_get_widthu (rect) / 2; - v1.y = clutter_actor_get_heightu (rect) / 2; + v1.x = clutter_actor_get_width (rect) / 2; + v1.y = clutter_actor_get_height (rect) / 2; v1.z = 0; clutter_actor_apply_transform_to_point (rect, &v1, &v2); @@ -41,11 +39,9 @@ init_handles () clutter_actor_set_size (p[4], 5, 5); clutter_actor_set_position (p[4], 0, 0); clutter_group_add (CLUTTER_GROUP (main_stage), p[4]); - clutter_actor_set_positionu (p[4], - v2.x - - clutter_actor_get_widthu (p[4])/2, - v2.y - - clutter_actor_get_heightu (p[4])/2); + clutter_actor_set_position (p[4], + v2.x - clutter_actor_get_width (p[4]) / 2, + v2.y - clutter_actor_get_height (p[4]) / 2); clutter_actor_raise_top (p[4]); @@ -62,21 +58,19 @@ place_handles () clutter_actor_get_abs_allocation_vertices (rect, v); for (i = 0; i < 4; ++i) { - clutter_actor_set_positionu (p[i], - v[i].x - - clutter_actor_get_widthu (p[i])/2, - v[i].y - - clutter_actor_get_heightu (p[i])/2); + clutter_actor_set_position (p[i], + v[i].x - clutter_actor_get_width (p[i])/2, + v[i].y - clutter_actor_get_height (p[i])/2); } - v1.x = clutter_actor_get_widthu (rect)/2; - v1.y = clutter_actor_get_heightu (rect)/2; + v1.x = clutter_actor_get_width (rect) / 2; + v1.y = clutter_actor_get_height (rect) / 2; v1.z = 0; clutter_actor_apply_transform_to_point (rect, &v1, &v2); - clutter_actor_set_positionu (p[4], - v2.x - clutter_actor_get_widthu (p[4])/2, - v2.y - clutter_actor_get_heightu (p[4])/2); + clutter_actor_set_position (p[4], + v2.x - clutter_actor_get_width (p[4])/2, + v2.y - clutter_actor_get_height (p[4])/2); } #define M(m,row,col) (m)[col*4+row] @@ -103,12 +97,14 @@ on_event (ClutterStage *stage, { case CLUTTER_BUTTON_PRESS: { - gint x, y; - ClutterActor * actor; + ClutterActor *actor; + gfloat x, y; clutter_event_get_coords (event, &x, &y); - actor = clutter_stage_get_actor_at_pos (stage, x, y); + actor = clutter_stage_get_actor_at_pos (stage, + CLUTTER_PICK_ALL, + x, y); if (actor != CLUTTER_ACTOR (stage)) { @@ -122,10 +118,10 @@ on_event (ClutterStage *stage, { if (dragging) { - gint x, y; - gint i; ClutterActorBox box1, box2; - ClutterUnit xp, yp; + gfloat x, y; + gfloat xp, yp; + gint i; i = find_handle_index (dragging); @@ -137,23 +133,17 @@ on_event (ClutterStage *stage, clutter_actor_get_allocation_box (dragging, &box1); clutter_actor_get_allocation_box (rect, &box2); - xp = CLUTTER_UNITS_FROM_DEVICE (x - 3) - box1.x1; - yp = CLUTTER_UNITS_FROM_DEVICE (y - 3) - box1.y1; + xp = (x - 3) - box1.x1; + yp = (y - 3) - box1.y1; if (i == 4) { - g_debug ("moving box by %f, %f", - CLUTTER_UNITS_TO_FLOAT (xp), - CLUTTER_UNITS_TO_FLOAT (yp)); - - clutter_actor_move_byu (rect, xp, yp); + g_debug ("moving box by %f, %f", xp, yp); + clutter_actor_move_by (rect, xp, yp); } else { - g_debug ("adjusting box by %f, %f, handle %d", - CLUTTER_UNITS_TO_FLOAT (xp), - CLUTTER_UNITS_TO_FLOAT (yp), - i); + g_debug ("adjusting box by %f, %f, handle %d", xp, yp, i); switch (i) { diff --git a/tests/interactive/test-rotate.c b/tests/interactive/test-rotate.c index 0c234714f..ee11ef353 100644 --- a/tests/interactive/test-rotate.c +++ b/tests/interactive/test-rotate.c @@ -44,8 +44,8 @@ test_rotate_main (int argc, char *argv[]) clutter_container_add_actor (CLUTTER_CONTAINER (stage), label); /* Make a timeline */ - timeline = clutter_timeline_new (200, 26); /* num frames, fps */ - g_object_set (timeline, "loop", TRUE, NULL); + timeline = clutter_timeline_new (7692); /* num frames, fps */ + clutter_timeline_set_loop (timeline, TRUE); /* Set an alpha func to power behaviour */ alpha = clutter_alpha_new_full (timeline, CLUTTER_LINEAR); diff --git a/tests/interactive/test-scale.c b/tests/interactive/test-scale.c index 7a2d86fdf..cf2a14552 100644 --- a/tests/interactive/test-scale.c +++ b/tests/interactive/test-scale.c @@ -86,7 +86,7 @@ test_scale_main (int argc, char *argv[]) clutter_group_add (CLUTTER_GROUP (stage), rect); - timeline = clutter_timeline_new_for_duration (750); + timeline = clutter_timeline_new (750); alpha = clutter_alpha_new_with_func (timeline, my_ramp_func, NULL, NULL); diff --git a/tests/interactive/test-score.c b/tests/interactive/test-score.c index b80f415c3..d5f073ddc 100644 --- a/tests/interactive/test-score.c +++ b/tests/interactive/test-score.c @@ -61,28 +61,28 @@ test_score_main (int argc, char **argv) clutter_init (&argc, &argv); - timeline_1 = clutter_timeline_new_for_duration (1000); + timeline_1 = clutter_timeline_new (1000); g_object_set_data_full (G_OBJECT (timeline_1), "timeline-name", g_strdup ("Timeline 1"), g_free); - timeline_2 = clutter_timeline_new_for_duration (1000); + timeline_2 = clutter_timeline_new (1000); clutter_timeline_add_marker_at_time (timeline_2, "foo", 500); g_object_set_data_full (G_OBJECT (timeline_2), "timeline-name", g_strdup ("Timeline 2"), g_free); - timeline_3 = clutter_timeline_new_for_duration (1000); + timeline_3 = clutter_timeline_new (1000); g_object_set_data_full (G_OBJECT (timeline_3), "timeline-name", g_strdup ("Timeline 3"), g_free); - timeline_4 = clutter_timeline_new_for_duration (1000); + timeline_4 = clutter_timeline_new (1000); g_object_set_data_full (G_OBJECT (timeline_4), "timeline-name", g_strdup ("Timeline 4"), g_free); - timeline_5 = clutter_timeline_new_for_duration (1000); + timeline_5 = clutter_timeline_new (1000); g_object_set_data_full (G_OBJECT (timeline_5), "timeline-name", g_strdup ("Timeline 5"), g_free); diff --git a/tests/interactive/test-shader.c b/tests/interactive/test-shader.c index 1101d8246..ecb8d2251 100644 --- a/tests/interactive/test-shader.c +++ b/tests/interactive/test-shader.c @@ -218,7 +218,8 @@ set_shader_num (ClutterActor *actor, gint new_no) error = NULL; g_object_set (G_OBJECT (shader), - "fragment-source", shaders[shader_no].source, NULL); + "fragment-source", shaders[shader_no].source, + NULL); /* try to bind the shader, provoking an error we catch if there is issues * with the shader sources we've provided. At a later stage it should be diff --git a/tests/interactive/test-stage-read-pixels.c b/tests/interactive/test-stage-read-pixels.c index b0d813970..2b5ec78ee 100644 --- a/tests/interactive/test-stage-read-pixels.c +++ b/tests/interactive/test-stage-read-pixels.c @@ -65,17 +65,18 @@ on_motion_idle (gpointer user_data) { CallbackData *data = (CallbackData *) user_data; guchar *pixels, *p; - guint stage_width, stage_height; + gfloat stage_width, stage_height; gint x, y; data->idle_source = 0; clutter_actor_get_size (data->stage, &stage_width, &stage_height); - x = CLAMP (data->event.x - TEX_SIZE / 2, 0, (int) stage_width - TEX_SIZE); - y = CLAMP (data->event.y - TEX_SIZE / 2, 0, (int) stage_height - TEX_SIZE); + x = CLAMP (data->event.x - TEX_SIZE / 2, 0, stage_width - TEX_SIZE); + y = CLAMP (data->event.y - TEX_SIZE / 2, 0, stage_height - TEX_SIZE); - clutter_actor_set_position (data->box, x + TEX_SIZE / 2 - 1, + clutter_actor_set_position (data->box, + x + TEX_SIZE / 2 - 1, y + TEX_SIZE / 2 - 1); clutter_actor_show (data->box); /* Redraw so that the layouting will be done and the box will be @@ -83,7 +84,8 @@ on_motion_idle (gpointer user_data) clutter_redraw (CLUTTER_STAGE (data->stage)); pixels = clutter_stage_read_pixels (CLUTTER_STAGE (data->stage), - x, y, TEX_SIZE, TEX_SIZE); + x, y, + TEX_SIZE, TEX_SIZE); /* Make a red dot in the center */ p = pixels + (TEX_SIZE / 2 - DOT_SIZE / 2) * TEX_SIZE * 4 diff --git a/tests/interactive/test-text-field.c b/tests/interactive/test-text-field.c index fbb51de68..d77ce41a4 100644 --- a/tests/interactive/test-text-field.c +++ b/tests/interactive/test-text-field.c @@ -9,18 +9,14 @@ on_entry_paint (ClutterActor *actor, gpointer data) { ClutterActorBox allocation = { 0, }; - ClutterUnit width, height; + gfloat width, height; clutter_actor_get_allocation_box (actor, &allocation); width = allocation.x2 - allocation.x1; height = allocation.y2 - allocation.y1; cogl_set_source_color4ub (255, 255, 255, 255); - cogl_path_round_rectangle (0, 0, - CLUTTER_UNITS_TO_FLOAT (width), - CLUTTER_UNITS_TO_FLOAT (height), - 4.0, - COGL_ANGLE_FROM_DEG (1.0)); + cogl_path_round_rectangle (0, 0, width, height, 4.0, 1.0); cogl_path_stroke (); } @@ -94,13 +90,21 @@ test_text_field_main (gint argc, ClutterColor entry_color = {0x33, 0xff, 0x33, 0xff}; ClutterColor label_color = {0xff, 0xff, 0xff, 0xff}; ClutterColor background_color = {0x00, 0x00, 0x00, 0xff}; - guint width, height; + ClutterUnits h_padding, v_padding; + gfloat width, height; clutter_init (&argc, &argv); stage = clutter_stage_get_default (); clutter_stage_set_color (CLUTTER_STAGE (stage), &background_color); + clutter_units_em_for_font (&h_padding, FONT, 2.0); /* 2em */ + clutter_units_em_for_font (&v_padding, FONT, 3.0); /* 3em */ + + g_print ("padding: h:%.2f px, v:%.2f px\n", + clutter_units_to_pixels (&h_padding), + clutter_units_to_pixels (&v_padding)); + text = create_label (&label_color, "Input field: "); clutter_actor_set_position (text, 10, 10); clutter_container_add_actor (CLUTTER_CONTAINER (stage), text); @@ -109,15 +113,21 @@ test_text_field_main (gint argc, height = clutter_actor_get_height (text); text = create_entry (&entry_color, "some text", 0, 0); - clutter_actor_set_position (text, width + 10 + 12, 10); + clutter_actor_set_position (text, + width + 10 + clutter_units_to_pixels (&h_padding), + 10); clutter_container_add_actor (CLUTTER_CONTAINER (stage), text); text = create_label (&label_color, "A very long password field: "); - clutter_actor_set_position (text, 10, height + 12); + clutter_actor_set_position (text, + 10, + height + 10 + clutter_units_to_pixels (&v_padding)); clutter_container_add_actor (CLUTTER_CONTAINER (stage), text); text = create_entry (&entry_color, "password", '*', 8); - clutter_actor_set_position (text, width + 10 + 12, height + 12); + clutter_actor_set_position (text, + width + 10 + clutter_units_to_pixels (&h_padding), + height + 10 + clutter_units_to_pixels (&v_padding)); clutter_container_add_actor (CLUTTER_CONTAINER (stage), text); clutter_actor_show (stage); diff --git a/tests/interactive/test-texture-async.c b/tests/interactive/test-texture-async.c index c80171ce6..4625a35fd 100644 --- a/tests/interactive/test-texture-async.c +++ b/tests/interactive/test-texture-async.c @@ -61,7 +61,7 @@ static gboolean task (gpointer foo) for (i=0; i<3; i++) { - timeline = clutter_timeline_new (60*5, 60); + timeline = clutter_timeline_new (5000); alpha = clutter_alpha_new_full (timeline, CLUTTER_LINEAR); depth_behavior = clutter_behaviour_depth_new (alpha, -2500, 0); clutter_behaviour_apply (depth_behavior, image[i]); diff --git a/tests/interactive/test-texture-quality.c b/tests/interactive/test-texture-quality.c index 5501059f7..214923d25 100644 --- a/tests/interactive/test-texture-quality.c +++ b/tests/interactive/test-texture-quality.c @@ -77,7 +77,7 @@ test_texture_quality_main (int argc, char *argv[]) (clutter_actor_get_height (stage) - clutter_actor_get_height (image))/2); clutter_container_add (CLUTTER_CONTAINER (stage), image, NULL); - timeline = clutter_timeline_new (60*5, 60); + timeline = clutter_timeline_new (5000); g_signal_connect (timeline, "completed", G_CALLBACK (timeline_completed), NULL); diff --git a/tests/interactive/test-threads.c b/tests/interactive/test-threads.c index a8843329b..fb2d4d4e3 100644 --- a/tests/interactive/test-threads.c +++ b/tests/interactive/test-threads.c @@ -211,7 +211,7 @@ test_threads_main (int argc, char *argv[]) rect, progress_rect, NULL); - timeline = clutter_timeline_new (150, 50); + timeline = clutter_timeline_new (3000); clutter_timeline_set_loop (timeline, TRUE); alpha = clutter_alpha_new_full (timeline, CLUTTER_LINEAR); diff --git a/tests/interactive/test-unproject.c b/tests/interactive/test-unproject.c index 95a83cfde..6c1e857e2 100644 --- a/tests/interactive/test-unproject.c +++ b/tests/interactive/test-unproject.c @@ -23,18 +23,17 @@ on_event (ClutterStage *stage, { case CLUTTER_BUTTON_PRESS: { - gint x, y; - ClutterActor * actor; - ClutterUnit xu2, yu2; + ClutterActor *actor; + gfloat xu2, yu2; + gfloat x, y; clutter_event_get_coords (event, &x, &y); - actor = clutter_stage_get_actor_at_pos (stage, x, y); + actor = clutter_stage_get_actor_at_pos (stage, + CLUTTER_PICK_ALL, + x, y); - if (clutter_actor_transform_stage_point (actor, - CLUTTER_UNITS_FROM_DEVICE (x), - CLUTTER_UNITS_FROM_DEVICE (y), - &xu2, &yu2)) + if (clutter_actor_transform_stage_point (actor, x, y, &xu2, &yu2)) { gchar *txt; @@ -42,16 +41,14 @@ on_event (ClutterStage *stage, txt = g_strdup_printf ("Click on rectangle\n" "Screen coords: [%d, %d]\n" "Local coords : [%d, %d]", - x, y, - CLUTTER_UNITS_TO_DEVICE (xu2), - CLUTTER_UNITS_TO_DEVICE (yu2)); + (int) x, (int) y, + (int) xu2, (int) yu2); else txt = g_strdup_printf ("Click on stage\n" "Screen coords: [%d, %d]\n" "Local coords : [%d, %d]", - x, y, - CLUTTER_UNITS_TO_DEVICE (xu2), - CLUTTER_UNITS_TO_DEVICE (yu2)); + (int) x, (int) y, + (int) xu2, (int) yu2); clutter_text_set_text (CLUTTER_TEXT (label), txt); g_free (txt); diff --git a/tests/interactive/test-viewport.c b/tests/interactive/test-viewport.c index 65a7f2048..f406a7439 100644 --- a/tests/interactive/test-viewport.c +++ b/tests/interactive/test-viewport.c @@ -36,7 +36,7 @@ test_viewport_main (int argc, char *argv[]) clutter_container_add_actor (CLUTTER_CONTAINER (stage), hand); /* Make a timeline */ - timeline = clutter_timeline_new (200, 26); /* num frames, fps */ + timeline = clutter_timeline_new (7692); clutter_timeline_set_loop (timeline, TRUE); /* Set an alpha func to power behaviour */