From 4f663384c77788e5d8b64c02175d7c8c5a0415de Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Mon, 23 Mar 2009 10:15:00 -0400 Subject: [PATCH 001/138] Add ClutterContainer::foreach_with_internals() Bug 1517 - clutter_container_foreach_with_internals() This allows us to iterate over all children (for things like maintaining map/realize invariants) or only children that apps added and care about. Signed-off-by: Emmanuele Bassi --- clutter/clutter-container.c | 40 ++++++++++++++++++++++++++++++++++++- clutter/clutter-container.h | 34 ++++++++++++++++++------------- 2 files changed, 59 insertions(+), 15 deletions(-) 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..dc1a60151 100644 --- a/clutter/clutter-container.h +++ b/clutter/clutter-container.h @@ -90,6 +90,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 +141,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, From 60645727036d9b0945b9ce71606d6067a54dd1e7 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 24 Apr 2009 14:59:18 +0100 Subject: [PATCH 002/138] [x11] Use XWithdrawWindow() Bug 1516 - Does not withdraw toplevels correctly clutter_stage_x11_hide() needs to use XWithdrawWindow(), not XUnmapWindow(). As it stands now, if the window is already unmapped (say the WM has minimized it), then the WM will not know that Clutter has closed the window and will keep the window managed, showing it in the task list and so forth. --- clutter/x11/clutter-stage-x11.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clutter/x11/clutter-stage-x11.c b/clutter/x11/clutter-stage-x11.c index aa091710f..2c4592ace 100644 --- a/clutter/x11/clutter-stage-x11.c +++ b/clutter/x11/clutter-stage-x11.c @@ -154,7 +154,7 @@ clutter_stage_x11_hide (ClutterActor *actor) ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor); if (stage_x11->xwin) - XUnmapWindow (stage_x11->xdpy, stage_x11->xwin); + XWithdrawWindow (stage_x11->xdpy, stage_x11->xwin, stage_x11->xscreen); } void From 08ba42a5ab4d42a76b4c1ff30bf37d6e3177de11 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 24 Apr 2009 15:05:02 +0100 Subject: [PATCH 003/138] Allow passing the pick mode to get_actor_at_pos() Bug 1513 - Allow passing in ClutterPickMode to clutter_stage_get_actor_at_pos() At the moment, clutter_stage_get_actor_at_pos() uses CLUTTER_PICK_ALL internally to find an actor. It would be useful to allow passing in ClutterPickMode to clutter_stage_get_actor_at_pos(), so that the caller can specify CLUTTER_PICK_REACTIVE as a criteria. --- clutter/clutter-private.h | 6 ------ clutter/clutter-stage.c | 16 +++++++++++----- clutter/clutter-stage.h | 17 +++++++++++++++++ doc/reference/clutter/clutter-sections.txt | 1 + tests/conform/test-pick.c | 1 + tests/interactive/test-actor-clone.c | 4 +++- tests/interactive/test-actors.c | 4 +++- tests/interactive/test-paint-wrapper.c | 2 +- tests/interactive/test-project.c | 4 +++- tests/interactive/test-unproject.c | 4 +++- 10 files changed, 43 insertions(+), 16 deletions(-) diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h index 741820187..912a05c01 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -65,12 +65,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; diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index a9a7bf942..14b9505c3 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -1242,20 +1242,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); } /** 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/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt index 7d645072e..cd7df4967 100644 --- a/doc/reference/clutter/clutter-sections.txt +++ b/doc/reference/clutter/clutter-sections.txt @@ -496,6 +496,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 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/interactive/test-actor-clone.c b/tests/interactive/test-actor-clone.c index fc595abc5..5aadbb042 100644 --- a/tests/interactive/test-actor-clone.c +++ b/tests/interactive/test-actor-clone.c @@ -57,7 +57,9 @@ input_cb (ClutterActor *stage, 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)) diff --git a/tests/interactive/test-actors.c b/tests/interactive/test-actors.c index 403931f1b..fcaa49275 100644 --- a/tests/interactive/test-actors.c +++ b/tests/interactive/test-actors.c @@ -57,7 +57,9 @@ input_cb (ClutterActor *stage, 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))) diff --git a/tests/interactive/test-paint-wrapper.c b/tests/interactive/test-paint-wrapper.c index 0a7f7550e..ac650d6c8 100644 --- a/tests/interactive/test-paint-wrapper.c +++ b/tests/interactive/test-paint-wrapper.c @@ -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))) { diff --git a/tests/interactive/test-project.c b/tests/interactive/test-project.c index 7c9403014..f62fd9c1c 100644 --- a/tests/interactive/test-project.c +++ b/tests/interactive/test-project.c @@ -108,7 +108,9 @@ on_event (ClutterStage *stage, 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)) { diff --git a/tests/interactive/test-unproject.c b/tests/interactive/test-unproject.c index 95a83cfde..188757b72 100644 --- a/tests/interactive/test-unproject.c +++ b/tests/interactive/test-unproject.c @@ -29,7 +29,9 @@ on_event (ClutterStage *stage, 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), From b73ee6992c68559f04f8d3e42d337b1c39a57933 Mon Sep 17 00:00:00 2001 From: Johan Bilien Date: Fri, 24 Apr 2009 15:07:49 +0100 Subject: [PATCH 004/138] Unnecessary glColorMask on alpha drops performance Bug 1228 - Unnecessary glColorMask on alpha drops performance With DRI2, alpha is allowed in the window's framebuffer Signed-off-by: Emmanuele Bassi --- clutter/cogl/gl/cogl-fbo.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/clutter/cogl/gl/cogl-fbo.c b/clutter/cogl/gl/cogl-fbo.c index 13463d345..501871976 100644 --- a/clutter/cogl/gl/cogl-fbo.c +++ b/clutter/cogl/gl/cogl-fbo.c @@ -321,13 +321,7 @@ cogl_draw_buffer (CoglBufferTarget target, CoglHandle offscreen) /* Bind window framebuffer object */ GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0) ); - - if (target == COGL_WINDOW_BUFFER) - { - /* Draw to RGB channels */ - GE( glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE) ); - } - else if (target == COGL_MASK_BUFFER) + if (target == COGL_MASK_BUFFER) { /* Draw only to ALPHA channel */ GE( glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE) ); From 125bded81455df73b37ed459f360ced0135db65a Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Thu, 2 Apr 2009 09:16:43 -0400 Subject: [PATCH 005/138] Enforce invariants on mapped, realized, visibility states Bug 1138 - No trackable "mapped" state * Add a VISIBLE flag tracking application programmer's expected showing-state for the actor, allowing us to always ensure we keep what the app wants while tracking internal implementation state separately. * Make MAPPED reflect whether the actor will be painted; add notification on a ClutterActor::mapped property. Keep MAPPED state updated as the actor is shown, ancestors are shown, actor is reparented, etc. * Require a stage and realized parents to realize; this means at realization time the correct window system and GL resources are known. But unparented actors can no longer be realized. * Allow children to be unrealized even if parent is realized. Otherwise in effect either all actors or no actors are realized, i.e. it becomes a stage-global flag. * Allow clutter_actor_realize() to "fail" if not inside a toplevel * Rework clutter_actor_unrealize() so internally we have a flavor that does not mess with visibility flag * Add _clutter_actor_rerealize() to encapsulate a somewhat tricky operation we were doing in a couple of places * Do not realize/unrealize children in ClutterGroup, ClutterActor already does it * Do not realize impl by hand in clutter_stage_show(), since showing impl already does that * Do not unrealize in various dispose() methods, since ClutterActor dispose implementation already does it and chaining up is mandatory * ClutterTexture uses COGL while unrealizable (before it's added to a stage). Previously this breakage was affecting ClutterActor because we had to allow realize outside a stage. Move the breakage to ClutterTexture, by making ClutterTexture just use COGL while not realized. * Unrealize before we set parent to NULL in clutter_actor_unparent(). This means unrealize() implementations can get to the stage. Because actors need the stage in order to detach from stage. * Update clutter-actor-invariants.txt to reflect latest changes * Remove explicit hide/unrealize from ClutterActor::dispose since unparent already forces those Instead just assert that unparent() occurred and did the right thing. * Check whether parent implements unrealize before chaining up Needed because ClutterGroup no longer has to implement unrealize. * Perform unrealize in the default handler for the signal. This allows non-containers that have children to work properly, and allows containers to override how it's done. * Add map/unmap virtual methods and set MAPPED flag on self and children in there. This allows subclasses to hook map/unmap. These are not signals, because notify::mapped is better for anything it's legitimate for a non-subclass to do. Signed-off-by: Emmanuele Bassi --- clutter/clutter-actor.c | 819 +++++++++++++++++++++++--- clutter/clutter-actor.h | 12 +- clutter/clutter-group.c | 18 - clutter/clutter-private.h | 4 + clutter/clutter-stage.c | 56 +- clutter/clutter-texture.c | 81 ++- clutter/eglnative/clutter-stage-egl.c | 5 +- clutter/eglx/clutter-stage-egl.c | 6 +- clutter/fruity/clutter-fruity.c | 4 + clutter/fruity/clutter-stage-fruity.c | 5 +- clutter/glx/clutter-stage-glx.c | 12 +- clutter/sdl/clutter-stage-sdl.c | 2 - clutter/win32/clutter-stage-win32.c | 15 +- clutter/x11/clutter-stage-x11.c | 69 ++- doc/clutter-actor-invariants.txt | 180 ++++-- tests/conform/test-actor-invariants.c | 133 ++++- tests/conform/test-conform-main.c | 3 + 17 files changed, 1145 insertions(+), 279 deletions(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 5d9d95d6a..3c9890a5f 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -136,6 +136,14 @@ * * 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 */ @@ -145,6 +153,15 @@ * * 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 */ @@ -152,7 +169,12 @@ * CLUTTER_ACTOR_IS_VISIBLE: * @e: 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 */ @@ -210,6 +232,23 @@ 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 @@ -343,6 +382,7 @@ enum PROP_OPACITY, PROP_VISIBLE, + PROP_MAPPED, PROP_REACTIVE, PROP_SCALE_X, @@ -430,6 +470,9 @@ 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, @@ -471,22 +514,404 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ClutterActor, clutter_scriptable_iface_init)); +/* FIXME 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 void +clutter_actor_verify_map_state (ClutterActor *self) +{ + 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 (self->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 (self->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 (self->priv->parent_actor), + self->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 (self->priv->parent_actor == NULL) + { + if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL) + { + if (!CLUTTER_ACTOR_IS_VISIBLE (self)) + 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 + { + if (!CLUTTER_ACTOR_IS_VISIBLE (self->priv->parent_actor)) + { + g_warning ("Actor should not be mapped if parent is not visible"); + } + + if (!CLUTTER_ACTOR_IS_REALIZED (self->priv->parent_actor)) + { + g_warning ("Actor should not be mapped if parent is not realized"); + } + + if (!(CLUTTER_PRIVATE_FLAGS (self->priv->parent_actor) & + CLUTTER_ACTOR_IS_TOPLEVEL)) + { + if (!CLUTTER_ACTOR_IS_MAPPED (self->priv->parent_actor)) + g_warning ("Actor is mapped but its non-toplevel parent is not mapped"); + } + } + } + } +} + +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)) + g_warning ("Clutter toplevel is not visible, but is somehow still mapped"); + } + else + { + ClutterActorPrivate *priv; + gboolean should_be_mapped; + gboolean may_be_realized; + gboolean must_be_realized; + ClutterActor *parent; + + priv = self->priv; + + should_be_mapped = FALSE; + may_be_realized = TRUE; + must_be_realized = FALSE; + + parent = priv->parent_actor; + + 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 (!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); + } + } + } + + /* check all invariants were kept */ + clutter_actor_verify_map_state (self); +} + +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 (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 "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. + **/ +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 (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"); + + 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 "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. + **/ +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 +937,8 @@ clutter_actor_show (ClutterActor *self) g_return_if_fail (CLUTTER_IS_ACTOR (self)); + clutter_actor_verify_map_state (self); /* FIXME leave this for debugging only */ + priv = self->priv; g_object_freeze_notify (G_OBJECT (self)); @@ -556,11 +983,12 @@ 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 +1014,8 @@ clutter_actor_hide (ClutterActor *self) g_return_if_fail (CLUTTER_IS_ACTOR (self)); + clutter_actor_verify_map_state (self); /* FIXME leave this for debugging only */ + priv = self->priv; g_object_freeze_notify (G_OBJECT (self)); @@ -596,7 +1026,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 +1061,225 @@ 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)); + clutter_actor_verify_map_state (self); /* FIXME leave this for debugging only */ + 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) + 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_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_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 (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)); + + clutter_actor_verify_map_state (self); /* FIXME leave this for debugging only */ + + 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); - - CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED); g_signal_emit (self, actor_signals[UNREALIZE], 0); + + CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_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)); + + clutter_actor_verify_map_state (self); /* FIXME leave this for debugging only */ + + 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 @@ -892,7 +1503,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,7 +1521,7 @@ 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() */ @@ -1562,17 +2173,11 @@ clutter_actor_paint (ClutterActor *self) priv = self->priv; - 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); @@ -1985,7 +2590,11 @@ clutter_actor_get_property (GObject *object, break; case PROP_VISIBLE: g_value_set_boolean (value, - (CLUTTER_ACTOR_IS_VISIBLE (actor) != FALSE)); + CLUTTER_ACTOR_IS_VISIBLE (actor)); + break; + case PROP_MAPPED: + g_value_set_boolean (value, + CLUTTER_ACTOR_IS_MAPPED (actor)); break; case PROP_HAS_CLIP: g_value_set_boolean (value, priv->has_clip); @@ -2123,7 +2732,11 @@ clutter_actor_dispose (GObject *object) priv->parent_actor = NULL; } - clutter_actor_unrealize (self); + /* parent should be gone */ + g_assert (priv->parent_actor == NULL); + /* 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); @@ -2527,6 +3140,19 @@ clutter_actor_class_init (ClutterActorClass *klass) "Whether the actor is visible or not", FALSE, CLUTTER_PARAM_READWRITE)); + + /** + * ClutterActor:mapped: + * + * Whether the actor is mapped (will be painted when stage is mapped). + */ + g_object_class_install_property (object_class, + PROP_MAPPED, + g_param_spec_boolean ("mapped", + "Mapped", + "Whether the actor will be painted", + FALSE, + G_PARAM_READABLE)); /** * ClutterActor:reactive: * @@ -3321,6 +3947,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 @@ -3353,6 +4003,9 @@ clutter_actor_class_init (ClutterActorClass *klass) 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; @@ -3473,9 +4126,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) @@ -6225,19 +6877,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); } @@ -6284,6 +6932,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 @@ -6293,17 +6943,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); } /** @@ -6323,8 +6963,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)); @@ -6333,47 +6972,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); } @@ -6385,7 +7006,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 */ @@ -6438,6 +7062,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); } } /** diff --git a/clutter/clutter-actor.h b/clutter/clutter-actor.h index 6ff80c3e5..c4941ecdd 100644 --- a/clutter/clutter-actor.h +++ b/clutter/clutter-actor.h @@ -76,7 +76,7 @@ G_BEGIN_DECLS #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_VISIBLE(e) ((((ClutterActor*)(e))->flags & CLUTTER_ACTOR_VISIBLE) != FALSE) #define CLUTTER_ACTOR_IS_REACTIVE(e) ((((ClutterActor*)(e))->flags & CLUTTER_ACTOR_REACTIVE) != FALSE) typedef struct _ClutterActorClass ClutterActorClass; @@ -102,11 +102,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,7 +115,8 @@ 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; /** @@ -220,6 +222,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); @@ -280,6 +284,8 @@ void clutter_actor_hide (ClutterActor 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); diff --git a/clutter/clutter-group.c b/clutter/clutter-group.c index 712acb464..a6a15d4ee 100644 --- a/clutter/clutter-group.c +++ b/clutter/clutter-group.c @@ -105,22 +105,6 @@ 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) @@ -587,8 +571,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-private.h b/clutter/clutter-private.h index 912a05c01..f102a0b90 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -217,6 +217,10 @@ 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); diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index 14b9505c3..9e3576264 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -263,15 +263,13 @@ 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) */ 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 @@ -287,12 +285,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)); } @@ -304,9 +299,6 @@ clutter_stage_show (ClutterActor *self) g_assert (priv->impl != NULL); - if (!CLUTTER_ACTOR_IS_REALIZED (priv->impl)) - clutter_actor_realize (priv->impl); - clutter_actor_show (priv->impl); CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->show (self); @@ -394,6 +386,14 @@ clutter_stage_real_queue_redraw (ClutterActor *actor, } } +static void +set_offscreen_while_unrealized (ClutterActor *actor, + void *data) +{ + CLUTTER_STAGE (actor)->priv->is_offscreen = + GPOINTER_TO_INT (data); +} + static void clutter_stage_set_property (GObject *object, guint prop_id, @@ -415,24 +415,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: @@ -534,7 +536,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) { diff --git a/clutter/clutter-texture.c b/clutter/clutter-texture.c index 52dc01c98..50c2e5de0 100644 --- a/clutter/clutter-texture.c +++ b/clutter/clutter-texture.c @@ -335,19 +335,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"); @@ -539,9 +535,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; @@ -1392,6 +1385,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 @@ -1405,6 +1404,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); @@ -1420,6 +1425,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,8 +1449,6 @@ clutter_texture_set_cogl_texture (ClutterTexture *texture, 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, @@ -1480,6 +1491,10 @@ clutter_texture_set_from_data (ClutterTexture *texture, 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, source_format, @@ -2004,15 +2019,8 @@ clutter_texture_set_filter_quality (ClutterTexture *texture, 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)); + _clutter_actor_rerealize (CLUTTER_ACTOR (texture), + NULL, NULL); } g_object_notify (G_OBJECT (texture), "filter-quality"); @@ -2172,9 +2180,13 @@ clutter_texture_get_base_size (ClutterTexture *texture, /* Attempt to realize, mainly for subclasses ( such as labels ) * which may not create pixbuf data and thus base size until - * realization happens. + * realization happens. If we aren't in a stage we can't realize + * though. Doing this here is probably just broken; instead + * we could virtualize get_base_size, or have the subclasses + * create the pixbufs sooner, or something better. */ - if (!CLUTTER_ACTOR_IS_REALIZED (texture)) + if (!CLUTTER_ACTOR_IS_REALIZED (texture) && + clutter_actor_get_stage (CLUTTER_ACTOR (texture)) != NULL) clutter_actor_realize (CLUTTER_ACTOR (texture)); if (width) @@ -2251,8 +2263,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) { @@ -2329,8 +2348,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; } diff --git a/clutter/eglnative/clutter-stage-egl.c b/clutter/eglnative/clutter-stage-egl.c index 1d7f59603..7e766ed71 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) { @@ -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..97a8631ca 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 (); @@ -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..ea1603a58 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) { @@ -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-stage-glx.c b/clutter/glx/clutter-stage-glx.c index 12f54cb38..650cf9445 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 (); @@ -310,12 +308,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/sdl/clutter-stage-sdl.c b/clutter/sdl/clutter-stage-sdl.c index 17a8bd0eb..215c28307 100644 --- a/clutter/sdl/clutter-stage-sdl.c +++ b/clutter/sdl/clutter-stage-sdl.c @@ -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-stage-win32.c b/clutter/win32/clutter-stage-win32.c index 5ce8a16c6..7d233c6c2 100644 --- a/clutter/win32/clutter-stage-win32.c +++ b/clutter/win32/clutter-stage-win32.c @@ -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)) diff --git a/clutter/x11/clutter-stage-x11.c b/clutter/x11/clutter-stage-x11.c index 2c4592ace..56a33d9cf 100644 --- a/clutter/x11/clutter-stage-x11.c +++ b/clutter/x11/clutter-stage-x11.c @@ -297,8 +297,7 @@ clutter_stage_x11_allocate (ClutterActor *self, if (stage_x11->xpixmap != None) { /* Need to recreate to resize */ - clutter_actor_unrealize (self); - clutter_actor_realize (self); + _clutter_actor_rerealize (self, NULL, NULL); } } @@ -529,11 +528,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); } @@ -671,6 +665,29 @@ clutter_x11_get_stage_visual (ClutterStage *stage) return CLUTTER_STAGE_X11 (impl)->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); +} + /** * clutter_x11_set_stage_foreign: * @stage: a #ClutterStage @@ -693,7 +710,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,20 +738,16 @@ 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); - - 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_actor_rerealize (actor, + set_foreign_window_callback, + &fwd); CLUTTER_SET_PRIVATE_FLAGS (actor, CLUTTER_ACTOR_SYNC_MATRICES); @@ -744,11 +757,11 @@ clutter_x11_set_stage_foreign (ClutterStage *stage, void clutter_stage_x11_map (ClutterStageX11 *stage_x11) { - /* set the mapped flag on the implementation */ - CLUTTER_ACTOR_SET_FLAGS (stage_x11, CLUTTER_ACTOR_MAPPED); + /* set the mapped state on the wrapper */ + clutter_actor_map (CLUTTER_ACTOR (stage_x11->wrapper)); - /* and on the wrapper itself */ - CLUTTER_ACTOR_SET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_MAPPED); + /* and on the implementation second */ + clutter_actor_map (CLUTTER_ACTOR (stage_x11)); if (stage_x11->fullscreen_on_map) clutter_stage_fullscreen (CLUTTER_STAGE (stage_x11->wrapper)); @@ -762,8 +775,8 @@ void clutter_stage_x11_unmap (ClutterStageX11 *stage_x11) { /* like above, unset the MAPPED stage on both the implementation and - * the wrapper + * the wrapper, but unmap in reverse order from map */ - CLUTTER_ACTOR_UNSET_FLAGS (stage_x11, CLUTTER_ACTOR_MAPPED); - CLUTTER_ACTOR_UNSET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_MAPPED); + clutter_actor_unmap (CLUTTER_ACTOR (stage_x11)); + clutter_actor_unmap (CLUTTER_ACTOR (stage_x11->wrapper)); } 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/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-conform-main.c b/tests/conform/test-conform-main.c index d4ea35dfc..8a75b8868 100644 --- a/tests/conform/test-conform-main.c +++ b/tests/conform/test-conform-main.c @@ -116,7 +116,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); From 51f4e9680b599d040d9200cb0bd19a024999c22d Mon Sep 17 00:00:00 2001 From: Johan Bilien Date: Wed, 8 Apr 2009 10:33:39 +0100 Subject: [PATCH 006/138] Relinquish the focus when unmapped while owning it Bug 1547 - when an actor is unmapped while owning the focus, it should release it When an actor is unmapped while owning the focus, the should release it. Signed-off-by: Emmanuele Bassi --- clutter/clutter-actor.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 3c9890a5f..28f1749d7 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -869,6 +869,20 @@ clutter_actor_real_unmap (ClutterActor *self) */ 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); } From 678f99677fb9f6c1d443da1c27753c5cbe768118 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Sat, 21 Mar 2009 20:39:32 +0000 Subject: [PATCH 007/138] Use a single master "clock" to drive timelines Currently, all timelines install a timeout inside the TimeoutPool they share. Every time the main loop spins, all the timeouts are updated. This, in turn, will usually lead to redraws being queued on the stages. This behaviour leads to the potential starvation of timelines and to excessive redraws. One lesson learned from the games developers is that the scenegraph should be prepared in its entirety before the GL paint sequence is initiated. This means making sure that every ::new-frame signal handler is called before clutter_redraw() is invoked. In order to do so a TimeoutPool is not enough: we need a master clock. The clock will be responsible for advancing all the active timelines created inside a scene, but only when the stage is being redrawn. The sequence is: + queue_redraw() is invoked on an actor and bubbles up to the stage + if no redraw() has already been scheduled, install an idle handler with a known priority + inside the idle handler: - advance the master clock, which will in turn advance every playing timeline by the amount of milliseconds elapsed since the last redraw; this will make every playing timeline emit the ::new-frame signal - queue a relayout - call the redraw() method of the backend This way we trade multiple timeouts with a single frame source that only runs if a timeline is playing and queues redraws on the various stages. --- clutter/Makefile.am | 2 + clutter/clutter-main.c | 7 +- clutter/clutter-master-clock.c | 364 +++++++++++++++++++++++++++++++++ clutter/clutter-master-clock.h | 48 +++++ clutter/clutter-private.h | 5 + clutter/clutter-stage.c | 53 +++-- clutter/clutter-timeline.c | 249 +++++++--------------- 7 files changed, 539 insertions(+), 189 deletions(-) create mode 100644 clutter/clutter-master-clock.c create mode 100644 clutter/clutter-master-clock.h diff --git a/clutter/Makefile.am b/clutter/Makefile.am index 4f53a5a2e..fa4d87a06 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 \ diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c index 31b24d23f..9e0163a51 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" @@ -181,14 +182,12 @@ void clutter_redraw (ClutterStage *stage) { ClutterMainContext *ctx; - static GTimer *timer = NULL; - static guint timer_n_frames = 0; + 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); /* Before we can paint, we have to be sure we have the latest layout */ _clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage)); diff --git a/clutter/clutter-master-clock.c b/clutter/clutter-master-clock.c new file mode 100644 index 000000000..2a7e53124 --- /dev/null +++ b/clutter/clutter-master-clock.c @@ -0,0 +1,364 @@ +/* + * 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 _ClutterMasterClockClass ClutterMasterClockClass; + +struct _ClutterMasterClock +{ + GObject parent_instance; + + GSList *timelines; + + GTimeVal prev_tick; + gulong msecs_delta; + + gulong tick_id; +}; + +struct _ClutterMasterClockClass +{ + GObjectClass parent_class; +}; + +static ClutterMasterClock *default_clock = NULL; + +static void on_timeline_start (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); + +G_DEFINE_TYPE (ClutterMasterClock, clutter_master_clock, G_TYPE_OBJECT); + +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) + { + if (master_clock->tick_id != 0) + { + g_source_remove (master_clock->tick_id); + master_clock->tick_id = 0; + } + + master_clock->prev_tick.tv_sec = 0; + } +} + +static void +clutter_master_clock_finalize (GObject *gobject) +{ + ClutterMasterClock *master_clock = CLUTTER_MASTER_CLOCK (gobject); + GSList *l; + + if (master_clock->tick_id != 0) + { + g_source_remove (master_clock->tick_id); + master_clock->tick_id = 0; + } + + 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_start), + 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) +{ +} + +/* + * _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 gboolean +master_clock_tick (gpointer data) +{ + ClutterStageManager *stage_manager = clutter_stage_manager_get_default (); + GSList *stages, *l; + + CLUTTER_NOTE (SCHEDULER, "Master clock [tick]"); + + stages = clutter_stage_manager_list_stages (stage_manager); + + for (l = stages; l != NULL; l = l->next) + clutter_actor_queue_redraw (l->data); + + g_slist_free (stages); + + return TRUE; +} + +static gboolean +has_running_timeline (ClutterMasterClock *master_clock) +{ + GSList *l; + + for (l = master_clock->timelines; l != NULL; l = l->next) + { + if (clutter_timeline_is_playing (l->data)) + return TRUE; + } + + return FALSE; +} + +static void +on_timeline_start (ClutterTimeline *timeline, + ClutterMasterClock *master_clock) +{ + if (has_running_timeline (master_clock) && + master_clock->tick_id == 0) + { + master_clock->prev_tick.tv_sec = 0; + + master_clock->tick_id = + clutter_threads_add_frame_source (clutter_get_default_frame_rate (), + master_clock_tick, + master_clock); + } +} + +static void +on_timeline_completed (ClutterTimeline *timeline, + ClutterMasterClock *master_clock) +{ + if (!has_running_timeline (master_clock) && + master_clock->tick_id != 0) + { + master_clock->prev_tick.tv_sec = 0; + + g_source_remove (master_clock->tick_id); + master_clock->tick_id = 0; + } +} + +static void +on_timeline_paused (ClutterTimeline *timeline, + ClutterMasterClock *master_clock) +{ + if (!has_running_timeline (master_clock) && + master_clock->tick_id != 0) + { + master_clock->prev_tick.tv_sec = 0; + + g_source_remove (master_clock->tick_id); + master_clock->tick_id = 0; + } +} + +/* + * _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_start), + 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_start), + 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); + + if (master_clock->timelines == NULL) + { + if (master_clock->tick_id != 0) + { + g_source_remove (master_clock->tick_id); + master_clock->tick_id = 0; + } + + 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)); + + 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; + + 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_set_delta (timeline, msecs); + } + + 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 f102a0b90..cb6627cbe 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -47,6 +47,7 @@ #include "clutter-stage-manager.h" #include "clutter-stage-window.h" #include "clutter-stage.h" +#include "clutter-timeline.h" G_BEGIN_DECLS @@ -127,6 +128,8 @@ struct _ClutterMainContext MultiTouch */ guint32 last_event_time; + + gulong redraw_count; }; #define CLUTTER_CONTEXT() (clutter_context_get_default ()) @@ -204,6 +207,8 @@ guint _clutter_pixel_to_id (guchar pixel[4]); void _clutter_id_to_color (guint id, ClutterColor *col); +void _clutter_timeline_set_delta (ClutterTimeline *timeline, + guint msecs); /* use this function as the accumulator if you have a signal with * a G_TYPE_BOOLEAN return value; this will stop the emission as diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index 9e3576264..2f9320d9d 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; @@ -346,24 +347,42 @@ redraw_update_idle (gpointer user_data) { ClutterStage *stage = user_data; ClutterStagePrivate *priv = stage->priv; + ClutterMasterClock *master_clock; + gboolean retval = FALSE; - /* 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); + + /* 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); + CLUTTER_NOTE (PAINT, "redrawing via idle for stage[%p]", stage); clutter_redraw (stage); - return FALSE; + if (CLUTTER_CONTEXT ()->redraw_count > 0) + { + CLUTTER_NOTE (PAINT, "Queued %lu redraws during the last cycle", + CLUTTER_CONTEXT ()->redraw_count); + + CLUTTER_CONTEXT ()->redraw_count = 0; + } + + priv->update_idle = 0; + + return retval; } static void @@ -373,17 +392,21 @@ 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 diff --git a/clutter/clutter-timeline.c b/clutter/clutter-timeline.c index 72abc0b48..57b517cef 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,7 +97,6 @@ struct _ClutterTimelinePrivate { ClutterTimelineDirection direction; - guint timeout_id; guint delay_id; gint current_frame_num; @@ -108,13 +107,14 @@ struct _ClutterTimelinePrivate gint skipped_frames; - GTimeVal prev_frame_timeval; guint msecs_delta; + guint frame_interval; GHashTable *markers_by_frame; GHashTable *markers_by_name; - guint loop : 1; + guint loop : 1; + guint is_playing : 1; }; typedef struct { @@ -146,67 +146,7 @@ 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, @@ -326,7 +266,9 @@ clutter_timeline_get_property (GObject *object, static void clutter_timeline_finalize (GObject *object) { - ClutterTimelinePrivate *priv = CLUTTER_TIMELINE (object)->priv; + ClutterTimeline *self = CLUTTER_TIMELINE (object); + ClutterTimelinePrivate *priv = self->priv; + ClutterMasterClock *master_clock; if (priv->markers_by_frame) g_hash_table_destroy (priv->markers_by_frame); @@ -334,6 +276,9 @@ clutter_timeline_finalize (GObject *object) 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 +296,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 +305,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; @@ -577,14 +514,19 @@ 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->frame_interval = 1000 / priv->fps; priv->n_frames = 0; priv->msecs_delta = 0; + + master_clock = _clutter_master_clock_get_default (); + _clutter_master_clock_add_timeline (master_clock, self); } static void @@ -636,43 +578,23 @@ is_complete (ClutterTimeline *timeline) } 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; + guint n_frames, speed; 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); - 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; + n_frames = priv->msecs_delta / speed; if (n_frames == 0) n_frames = 1; @@ -684,8 +606,6 @@ timeline_timeout_func (gpointer data) timeline, priv->skipped_frames); - priv->prev_frame_timeval = timeval; - /* Advance frames */ if (priv->direction == CLUTTER_TIMELINE_FORWARD) priv->current_frame_num += n_frames; @@ -699,7 +619,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; @@ -751,7 +671,7 @@ timeline_timeout_func (gpointer data) priv->n_frames, n_frames - 1); - 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,8 +679,7 @@ 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); @@ -769,7 +688,7 @@ timeline_timeout_func (gpointer data) * current_frame_num, 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) + !(/* Except allow moving from frame 0 -> n_frame (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) @@ -791,7 +710,7 @@ timeline_timeout_func (gpointer data) if (priv->direction != saved_direction) { priv->current_frame_num = priv->n_frames - - priv->current_frame_num; + - priv->current_frame_num; } g_object_unref (timeline); @@ -801,39 +720,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 +733,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 +756,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) 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 +790,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); } @@ -1027,6 +909,8 @@ clutter_timeline_skip (ClutterTimeline *timeline, if (priv->current_frame_num < 1) priv->current_frame_num = priv->n_frames - 1; } + + priv->msecs_delta = 0; } /** @@ -1141,17 +1025,9 @@ clutter_timeline_set_speed (ClutterTimeline *timeline, g_object_ref (timeline); priv->fps = fps; + priv->frame_interval = 1000 / priv->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); - } + /* FIXME if the timeline is playing restart */ g_object_freeze_notify (G_OBJECT (timeline)); @@ -1193,7 +1069,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; } /** @@ -1495,6 +1371,39 @@ clutter_timeline_get_delta (ClutterTimeline *timeline, return priv->skipped_frames + 1; } +/* + * clutter_timeline_set_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_set_delta (ClutterTimeline *timeline, + guint msecs) +{ + ClutterTimelinePrivate *priv; + + g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); + + priv = timeline->priv; + + priv->msecs_delta += msecs; + + if (priv->msecs_delta < priv->frame_interval) + return; + else + { + clutter_timeline_advance_internal (timeline); + + priv->msecs_delta = 0; + } +} + static inline void clutter_timeline_add_marker_internal (ClutterTimeline *timeline, const gchar *marker_name, From e260296cb5a8acef0ba2c9a10b6dec1dca787081 Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Fri, 27 Feb 2009 14:43:47 -0500 Subject: [PATCH 008/138] [clone] Redraw when the source changes Bug 1484 - Redraw ClutterClone when the source changes, even for !visible sources Connect to ::queue-redraw on the clone source and queue a redraw. This allows redrawing the Clone when the source changes, even in case of a non visible source actor. http://bugzilla.openedhand.com/show_bug.cgi?id=1484 Signed-off-by: Emmanuele Bassi --- clutter/clutter-clone.c | 66 +++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/clutter/clutter-clone.c b/clutter/clutter-clone.c index 8cb9b2b87..017d7cf92 100644 --- a/clutter/clutter-clone.c +++ b/clutter/clutter-clone.c @@ -65,6 +65,8 @@ 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, @@ -231,13 +233,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 +298,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 +351,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)); } From bb156970defbd7479d512ab5b5aeb78fd1fefd75 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Wed, 25 Mar 2009 14:18:00 +0000 Subject: [PATCH 009/138] Render pango layouts with vertex buffers When rendering a pango layout CoglPangoRenderer now records the operations into a list called a CoglPangoDisplayList. The entries in the list are either glyph renderings from a texture, rectangles or trapezoids. Multiple consecutive glyph renderings from the same glyph cache texture are combined into a single entry. Note the CoglPangoDisplayList has nothing to do with a GL display list. After the display list is built it is attached to the PangoLayout with g_object_set_qdata so that next time the layout is rendered it can bypass rebuilding it. The glyph rendering entries are drawn via a VBO. The VBO is attached to the display list so it can be used multiple times. This makes the common case of rendering a PangoLayout contained in a single texture subsequent times usually boil down to a single call to glDrawArrays with an already uploaded VBO. The VBOs are accessed via the cogl_vertex_buffer API so if VBOs are not available in GL it will resort to a fallback. Note this will fall apart if the pango layout is altered after the first render. I can't find a way to detect when the layout is altered. However this won't affect ClutterText because it creates a new PangoLayout whenever any properties are changed. --- clutter/pango/Makefile.am | 2 + clutter/pango/cogl-pango-display-list.c | 330 ++++++++++++++++++++++++ clutter/pango/cogl-pango-display-list.h | 68 +++++ clutter/pango/cogl-pango-render.c | 145 ++++++----- 4 files changed, 482 insertions(+), 63 deletions(-) create mode 100644 clutter/pango/cogl-pango-display-list.c create mode 100644 clutter/pango/cogl-pango-display-list.h diff --git a/clutter/pango/Makefile.am b/clutter/pango/Makefile.am index 1d2d22402..e567e3ba2 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,6 +7,7 @@ source_c = \ source_h = cogl-pango.h source_h_priv = \ + cogl-pango-display-list.h \ cogl-pango-private.h \ cogl-pango-glyph-cache.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..ecef23f58 --- /dev/null +++ b/clutter/pango/cogl-pango-display-list.c @@ -0,0 +1,330 @@ +/* + * 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, GL_FLOAT, FALSE, + sizeof (CoglPangoDisplayListVertex), + &g_array_index (node->d.texture.verts, + CoglPangoDisplayListVertex, 0).x); + cogl_vertex_buffer_add (vb, "gl_MultiTexCoord0", 2, GL_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; + } + + cogl_vertex_buffer_draw (node->d.texture.vertex_buffer, + GL_QUADS, 0, node->d.texture.verts->len); +} + +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-render.c b/clutter/pango/cogl-pango-render.c index ba9395b21..91bcbe9f1 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 { @@ -55,9 +56,8 @@ struct _CoglPangoRenderer 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,20 +65,6 @@ struct _CoglPangoRendererClass PangoRendererClass class_instance; }; -static void -cogl_pango_renderer_glyphs_end (CoglPangoRenderer *priv) -{ - 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); - } -} - static void cogl_pango_renderer_draw_glyph (CoglPangoRenderer *priv, CoglPangoGlyphCacheValue *cache_value, @@ -86,25 +72,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); @@ -168,7 +148,6 @@ cogl_pango_renderer_init (CoglPangoRenderer *priv) 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)); } static void @@ -191,7 +170,6 @@ cogl_pango_renderer_finalize (GObject *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 +191,17 @@ cogl_pango_get_renderer_from_context (PangoContext *context) return COGL_PANGO_RENDERER (renderer); } +static GQuark +cogl_pango_render_get_display_list_key (void) +{ + static GQuark key = 0; + + if (G_UNLIKELY (key == 0)) + key = g_quark_from_static_string ("CoglPangoDisplayList"); + + return key; +} + /** * cogl_pango_render_layout_subpixel: * @layout: a #PangoLayout @@ -232,17 +221,37 @@ cogl_pango_render_layout_subpixel (PangoLayout *layout, const CoglColor *color, int flags) { - PangoContext *context; - CoglPangoRenderer *priv; + PangoContext *context; + CoglPangoRenderer *priv; + CoglPangoDisplayList *display_list; context = pango_layout_get_context (layout); priv = cogl_pango_get_renderer_from_context (context); if (G_UNLIKELY (!priv)) return; - priv->color = *color; + display_list = g_object_get_qdata (G_OBJECT (layout), + cogl_pango_render_get_display_list_key ()); - pango_renderer_draw_layout (PANGO_RENDERER (priv), layout, x, y); + if (display_list == NULL) + { + priv->display_list = display_list =_cogl_pango_display_list_new (); + priv->color = *color; + g_object_set_qdata_full (G_OBJECT (layout), + cogl_pango_render_get_display_list_key (), + display_list, + (GDestroyNotify) _cogl_pango_display_list_free); + pango_renderer_draw_layout (PANGO_RENDERER (priv), layout, 0, 0); + + priv->display_list = NULL; + } + + cogl_push_matrix (); + cogl_translate (x, y, 0); + _cogl_pango_display_list_render (display_list, + priv->glyph_material, + priv->solid_material); + cogl_pop_matrix (); } /** @@ -296,9 +305,19 @@ 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 @@ -444,8 +463,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 +475,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 +519,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 +530,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 +547,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 +560,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 +597,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 +628,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 +649,4 @@ cogl_pango_renderer_draw_glyphs (PangoRenderer *renderer, xi += gi->geometry.width; } - - cogl_pango_renderer_glyphs_end (priv); } From 5d2d8297e26780d95f46c77d5865c1cb77959d07 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 1 May 2009 12:31:06 +0100 Subject: [PATCH 010/138] [actor] Use foreach_with_internals() ClutterContainer provides a foreach_with_internals() vfunc for iterating over all of a container's children, be them added using the Container API or be them internal to the container itself. We should be using the foreach_with_internals() function instead of the plain foreach(). --- clutter/clutter-actor.c | 55 ++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 28f1749d7..2231434a2 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -814,31 +814,30 @@ clutter_actor_real_map (ClutterActor *self) clutter_actor_queue_redraw (self); if (CLUTTER_IS_CONTAINER (self)) - clutter_container_foreach (CLUTTER_CONTAINER (self), - CLUTTER_CALLBACK (clutter_actor_map), - NULL); + 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 + * 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 "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. + * 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) { @@ -859,9 +858,9 @@ clutter_actor_real_unmap (ClutterActor *self) g_assert (CLUTTER_ACTOR_IS_MAPPED (self)); if (CLUTTER_IS_CONTAINER (self)) - clutter_container_foreach (CLUTTER_CONTAINER (self), - CLUTTER_CALLBACK (clutter_actor_unmap), - NULL); + 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 @@ -893,17 +892,17 @@ clutter_actor_real_unmap (ClutterActor *self) * 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 "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. + * 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) { @@ -1141,9 +1140,9 @@ clutter_actor_real_unrealize (ClutterActor *self) g_assert (!CLUTTER_ACTOR_IS_MAPPED (self)); if (CLUTTER_IS_CONTAINER (self)) - clutter_container_foreach (CLUTTER_CONTAINER (self), - CLUTTER_CALLBACK (clutter_actor_unrealize_not_hiding), - NULL); + clutter_container_foreach_with_internals (CLUTTER_CONTAINER (self), + CLUTTER_CALLBACK (clutter_actor_unrealize_not_hiding), + NULL); } /** From 1a87e4e2520a57d26a4e83e7f69f26d2cfab3d4c Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 1 May 2009 12:33:42 +0100 Subject: [PATCH 011/138] [clone] Allow painting hidden source actors With the introduction of the map/unmap flags and the split of the visible state from the mapped state we require that every part of a scene graph branch is mapped in order to be painted. This breaks the ability of a ClutterClone to paint an hidden source actor. In order to fix this we need to introduce an override flag, similar in spirit to the current modelview and paint opacity overrides that Clone is already using. The override flag, when set, will force a temporary map on a Clone source (and its children). --- clutter/clutter-actor.c | 129 +++++++++++++++++++++++++++++--------- clutter/clutter-clone.c | 10 +++ clutter/clutter-private.h | 3 + 3 files changed, 112 insertions(+), 30 deletions(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 2231434a2..9bbe536d2 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -328,7 +328,8 @@ struct _ClutterActorPrivate PangoContext *pango_context; ClutterActor *opacity_parent; - gboolean enable_model_view_transform; + guint enable_model_view_transform : 1; + guint enable_paint_unmapped : 1; }; enum @@ -514,13 +515,16 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ClutterActor, clutter_scriptable_iface_init)); -/* FIXME this is for debugging only, remove once working (or leave in - * only in some debug mode). Should leave it for a little while +#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 void +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, @@ -528,22 +532,20 @@ clutter_actor_verify_map_state (ClutterActor *self) */ if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_REPARENT)) { - if (self->priv->parent_actor == NULL) + 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"); - } + g_warning ("Realized non-toplevel actor should have a parent"); } - else if (!CLUTTER_ACTOR_IS_REALIZED (self->priv->parent_actor)) + else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent_actor)) { - g_warning ("Realized actor %s %p has an unrealized parent %s %p", + g_warning ("Realized actor %s[%p] has an unrealized parent %s[%p]", G_OBJECT_TYPE_NAME (self), self, - G_OBJECT_TYPE_NAME (self->priv->parent_actor), - self->priv->parent_actor); + G_OBJECT_TYPE_NAME (priv->parent_actor), + priv->parent_actor); } } } @@ -558,7 +560,7 @@ clutter_actor_verify_map_state (ClutterActor *self) */ if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_REPARENT)) { - if (self->priv->parent_actor == NULL) + if (priv->parent_actor == NULL) { if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL) { @@ -573,27 +575,47 @@ clutter_actor_verify_map_state (ClutterActor *self) } else { - if (!CLUTTER_ACTOR_IS_VISIBLE (self->priv->parent_actor)) + 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) { - g_warning ("Actor should not be mapped if parent is not visible"); + if (parent->priv->enable_paint_unmapped) + return; + + parent = parent->priv->parent_actor; } - if (!CLUTTER_ACTOR_IS_REALIZED (self->priv->parent_actor)) + if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent_actor)) { - g_warning ("Actor should not be mapped if parent is not realized"); + g_warning ("Actor should not be mapped if parent " + "is not visible"); } - if (!(CLUTTER_PRIVATE_FLAGS (self->priv->parent_actor) & + 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 (self->priv->parent_actor)) - g_warning ("Actor is mapped but its non-toplevel parent is not mapped"); + 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) @@ -745,13 +767,28 @@ clutter_actor_update_map_state (ClutterActor *self, } } + /* 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"); + g_warning ("Attempting to map a child that does not " + "meet the necessary invariants"); } /* If in reparent, we temporarily suspend unmap and unrealize. @@ -782,7 +819,8 @@ clutter_actor_update_map_state (ClutterActor *self, 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"); + 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 @@ -790,9 +828,7 @@ clutter_actor_update_map_state (ClutterActor *self, * happens) */ if (CLUTTER_ACTOR_IS_REALIZED (self)) - { - clutter_actor_set_mapped (self, TRUE); - } + clutter_actor_set_mapped (self, TRUE); } } @@ -950,7 +986,10 @@ clutter_actor_show (ClutterActor *self) g_return_if_fail (CLUTTER_IS_ACTOR (self)); - clutter_actor_verify_map_state (self); /* FIXME leave this for debugging only */ +#ifdef CLUTTER_ENABLE_DEBUG + /* FIXME leave this for debugging only */ + clutter_actor_verify_map_state (self); +#endif priv = self->priv; @@ -1027,7 +1066,10 @@ clutter_actor_hide (ClutterActor *self) g_return_if_fail (CLUTTER_IS_ACTOR (self)); - clutter_actor_verify_map_state (self); /* FIXME leave this for debugging only */ +#ifdef CLUTTER_ENABLE_DEBUG + /* FIXME leave this for debugging only */ + clutter_actor_verify_map_state (self); +#endif priv = self->priv; @@ -1092,7 +1134,10 @@ clutter_actor_realize (ClutterActor *self) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); - clutter_actor_verify_map_state (self); /* FIXME leave this for debugging only */ +#ifdef CLUTTER_ENABLE_DEBUG + /* FIXME leave this for debugging only */ + clutter_actor_verify_map_state (self); +#endif if (CLUTTER_ACTOR_IS_REALIZED (self)) return; @@ -1183,7 +1228,10 @@ clutter_actor_unrealize (ClutterActor *self) g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self)); - clutter_actor_verify_map_state (self); /* FIXME leave this for debugging only */ +#ifdef CLUTTER_ENABLE_DEBUG + /* FIXME leave this for debugging only */ + clutter_actor_verify_map_state (self); +#endif clutter_actor_hide (self); @@ -1265,7 +1313,10 @@ _clutter_actor_rerealize (ClutterActor *self, g_return_if_fail (CLUTTER_IS_ACTOR (self)); - clutter_actor_verify_map_state (self); /* FIXME leave this for debugging only */ +#ifdef CLUTTER_ENABLE_DEBUG + /* FIXME leave this for debugging only */ + clutter_actor_verify_map_state (self); +#endif was_realized = CLUTTER_ACTOR_IS_REALIZED (self); was_mapped = CLUTTER_ACTOR_IS_MAPPED (self); @@ -8931,6 +8982,24 @@ _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, diff --git a/clutter/clutter-clone.c b/clutter/clutter-clone.c index 017d7cf92..16bd60be1 100644 --- a/clutter/clutter-clone.c +++ b/clutter/clutter-clone.c @@ -122,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; @@ -155,8 +156,17 @@ 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); } diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h index cb6627cbe..9f89312a3 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -232,6 +232,9 @@ void _clutter_actor_set_opacity_parent (ClutterActor *self, void _clutter_actor_set_enable_model_view_transform (ClutterActor *self, gboolean enable); +void _clutter_actor_set_enable_paint_unmapped (ClutterActor *self, + gboolean enable); + G_END_DECLS #endif /* _HAVE_CLUTTER_PRIVATE_H */ From 71473466fa2cc4783934b2cdbcb709d50a0e37b8 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 1 May 2009 12:42:30 +0100 Subject: [PATCH 012/138] [gitignore] Ignore the new invariants units --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index c0630e0a7..859ddb74e 100644 --- a/.gitignore +++ b/.gitignore @@ -189,6 +189,9 @@ stamp-h1 /tests/conform/test-list-model-populate /tests/conform/test-npot-texture /tests/conform/redhand.png +/tests/conform/test-map-recursive +/tests/conform/test-realize-not-recursive +/tests/conform/test-shown-not-parented /tests/micro-bench/test-glyph-perf /tests/micro-bench/test-text /tests/tools/disable-npots.sh From d7a1a168ba1039cd4711bda60015667dbf1fcb27 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 1 May 2009 12:42:37 +0100 Subject: [PATCH 013/138] [tests] Verify that Clone can paint hidden sources With the change in commit 87e4e2 painting of hidden source actors in ClutterClone was fixed. This commit changes the test-actor-clone to visually verify this. --- tests/interactive/test-actor-clone.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/interactive/test-actor-clone.c b/tests/interactive/test-actor-clone.c index 5aadbb042..82fb8142e 100644 --- a/tests/interactive/test-actor-clone.c +++ b/tests/interactive/test-actor-clone.c @@ -215,6 +215,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(); From 5be29cf9bc6ee5789f4f8473aee8ec72a77034c9 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 1 May 2009 15:05:51 +0100 Subject: [PATCH 014/138] [timeline] Expose the msec advancement The method of ClutterTimeline that advances the timeline by a delta (in millisecond) is going to be useful for testing the timeline's behaviour -- and unbreak the timeline test suite that was broken by the MasterClock merge. --- clutter/clutter-master-clock.c | 2 +- clutter/clutter-private.h | 3 --- clutter/clutter-timeline.c | 16 +++++++--------- clutter/clutter-timeline.h | 4 ++++ 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/clutter/clutter-master-clock.c b/clutter/clutter-master-clock.c index 2a7e53124..a417dbbca 100644 --- a/clutter/clutter-master-clock.c +++ b/clutter/clutter-master-clock.c @@ -356,7 +356,7 @@ _clutter_master_clock_advance (ClutterMasterClock *master_clock) ClutterTimeline *timeline = l->data; if (clutter_timeline_is_playing (timeline)) - _clutter_timeline_set_delta (timeline, msecs); + clutter_timeline_advance_delta (timeline, msecs); } master_clock->msecs_delta = msecs; diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h index 9f89312a3..e669a640b 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -207,9 +207,6 @@ guint _clutter_pixel_to_id (guchar pixel[4]); void _clutter_id_to_color (guint id, ClutterColor *col); -void _clutter_timeline_set_delta (ClutterTimeline *timeline, - guint msecs); - /* 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 diff --git a/clutter/clutter-timeline.c b/clutter/clutter-timeline.c index 57b517cef..9e000702f 100644 --- a/clutter/clutter-timeline.c +++ b/clutter/clutter-timeline.c @@ -1022,21 +1022,19 @@ clutter_timeline_set_speed (ClutterTimeline *timeline, if (priv->fps != fps) { - g_object_ref (timeline); + g_object_freeze_notify (G_OBJECT (timeline)); priv->fps = fps; priv->frame_interval = 1000 / priv->fps; - /* FIXME if the timeline is playing restart */ - - g_object_freeze_notify (G_OBJECT (timeline)); + /* if the timeline is playing restart */ + if (priv->is_playing) + clutter_timeline_rewind (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); } } @@ -1372,7 +1370,7 @@ clutter_timeline_get_delta (ClutterTimeline *timeline, } /* - * clutter_timeline_set_delta: + * clutter_timeline_advance_delta: * @timeline: a #ClutterTimeline * @msecs: advance in milliseconds * @@ -1383,8 +1381,8 @@ clutter_timeline_get_delta (ClutterTimeline *timeline, * skip frames. */ void -_clutter_timeline_set_delta (ClutterTimeline *timeline, - guint msecs) +clutter_timeline_advance_delta (ClutterTimeline *timeline, + guint msecs) { ClutterTimelinePrivate *priv; diff --git a/clutter/clutter-timeline.h b/clutter/clutter-timeline.h index bd8a90151..7d829ebaa 100644 --- a/clutter/clutter-timeline.h +++ b/clutter/clutter-timeline.h @@ -166,6 +166,10 @@ gboolean clutter_timeline_has_marker (ClutterTimeline *timeli 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__ */ From cf28c023a051eef96c9aa9c8ebffff75f470470a Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 1 May 2009 15:08:42 +0100 Subject: [PATCH 015/138] [tests] Manually advance the timelines The units in the Timeline test suite just rely on the timeline being a timeout automatically advanced by the main loop. This is not the case anymore, since the merge of the master-clock. To make the test units work again we need to "emulate" the master clock without effectively having a stage to redraw; we do this by creating a frame source and manually advancing the timelines we create for test purposes, using the advance_msecs() "protected" method. --- tests/conform/test-timeline-dup-frames.c | 40 +++++++++++++-- tests/conform/test-timeline-interpolate.c | 52 ++++++++++++++++---- tests/conform/test-timeline-rewind.c | 46 +++++++++++++++--- tests/conform/test-timeline-smoothness.c | 41 ++++++++++++++-- tests/conform/test-timeline.c | 59 ++++++++++++++++++++++- 5 files changed, 214 insertions(+), 24 deletions(-) diff --git a/tests/conform/test-timeline-dup-frames.c b/tests/conform/test-timeline-dup-frames.c index 32a906084..0d8c3ff3e 100644 --- a/tests/conform/test-timeline-dup-frames.c +++ b/tests/conform/test-timeline-dup-frames.c @@ -10,13 +10,16 @@ #define TEST_TIMELINE_FPS 10 #define TEST_TIMELINE_FRAME_COUNT 20 -typedef struct _TestState { +typedef struct _TestState +{ ClutterTimeline *timeline; gint prev_frame; gint completion_count; gint passed; -}TestState; - + guint source_id; + GTimeVal prev_tick; + gulong msecs_delta; +} TestState; static void new_frame_cb (ClutterTimeline *timeline, @@ -68,6 +71,30 @@ completed_cb (ClutterTimeline *timeline, } } +static gboolean +frame_tick (gpointer data) +{ + TestState *state = data; + GTimeVal cur_tick = { 0, }; + GSList *l; + 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_dup_frames (TestConformSimpleFixture *fixture, @@ -91,11 +118,18 @@ test_timeline_dup_frames (TestConformSimpleFixture *fixture, state.prev_frame = -1; state.completion_count = 0; state.passed = TRUE; + 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-interpolate.c b/tests/conform/test-timeline-interpolate.c index 56af892ef..1e9ca1578 100644 --- a/tests/conform/test-timeline-interpolate.c +++ b/tests/conform/test-timeline-interpolate.c @@ -15,14 +15,18 @@ * 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 @@ -130,6 +134,30 @@ completed_cb (ClutterTimeline *timeline, } } +static gboolean +frame_tick (gpointer data) +{ + TestState *state = data; + GTimeVal cur_tick = { 0, }; + GSList *l; + 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, @@ -154,12 +182,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..b13aaa419 100644 --- a/tests/conform/test-timeline-rewind.c +++ b/tests/conform/test-timeline-rewind.c @@ -8,11 +8,14 @@ #define TEST_TIMELINE_FRAME_COUNT 5 #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,7 +37,6 @@ watchdog_timeout (TestState *state) return FALSE; } - static void new_frame_cb (ClutterTimeline *timeline, gint frame_num, @@ -68,6 +70,30 @@ new_frame_cb (ClutterTimeline *timeline, } } +static gboolean +frame_tick (gpointer data) +{ + TestState *state = data; + GTimeVal cur_tick = { 0, }; + GSList *l; + 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, @@ -88,11 +114,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 index 9b0b5ae47..9824c639d 100644 --- a/tests/conform/test-timeline-smoothness.c +++ b/tests/conform/test-timeline-smoothness.c @@ -8,15 +8,18 @@ #define TEST_TIMELINE_FRAME_COUNT 20 #define TEST_ERROR_TOLERANCE 5 -typedef struct _TestState { +typedef struct _TestState +{ ClutterTimeline *timeline; GTimeVal start_time; GTimeVal prev_frame_time; guint frame; gint completion_count; gint passed; -}TestState; - + guint source_id; + GTimeVal prev_tick; + gulong msecs_delta; +} TestState; static void new_frame_cb (ClutterTimeline *timeline, @@ -81,6 +84,30 @@ completed_cb (ClutterTimeline *timeline, } } +static gboolean +frame_tick (gpointer data) +{ + TestState *state = data; + GTimeVal cur_tick = { 0, }; + GSList *l; + 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_smoothness (TestConformSimpleFixture *fixture, @@ -104,12 +131,18 @@ test_timeline_smoothness (TestConformSimpleFixture *fixture, state.frame = 0; state.completion_count = 0; state.passed = TRUE; + 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.c b/tests/conform/test-timeline.c index 47218f13d..091440f6d 100644 --- a/tests/conform/test-timeline.c +++ b/tests/conform/test-timeline.c @@ -156,7 +156,7 @@ check_timeline (ClutterTimeline *timeline, } static gboolean -timeout_cb (gpointer data) +timeout_cb (gpointer data G_GNUC_UNUSED) { clutter_main_quit (); @@ -172,10 +172,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,6 +226,11 @@ 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 (60, frame_tick, counter); timeline_data_init (&data_1, 1); timeline_1 = clutter_timeline_new (FRAME_COUNT, 30); @@ -198,6 +244,8 @@ test_timeline (TestConformSimpleFixture *fixture, 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); @@ -207,6 +255,8 @@ test_timeline (TestConformSimpleFixture *fixture, 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); @@ -215,6 +265,8 @@ test_timeline (TestConformSimpleFixture *fixture, clutter_timeline_add_marker_at_frame (timeline_3, "near-end-marker", 1); clutter_timeline_add_marker_at_frame (timeline_3, "end-marker", 0); + counter->timelines = g_slist_prepend (counter->timelines, timeline_3); + g_signal_connect (timeline_1, "marker-reached", G_CALLBACK (timeline_marker_reached_cb), &data_1); @@ -293,4 +345,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); } From fa9efe4828834a62b694232d61124f4b0703d922 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 30 Apr 2009 18:47:59 +0100 Subject: [PATCH 016/138] Accumulate small deltas The clutter frame source tries to average out the frame deltas so that if one frame takes 1 interval plus a little bit of extra time then the next frame will be 1 interval minus that little bit of extra time. Therefore the deltas can sometimes be less than the frame interval. ClutterTimeline should accumulate these small differences otherwise it will end up missing out frames so the total duration of the timeline will be a lot longer. For example this was causing test-actors to appear to run very slow. --- clutter/clutter-timeline.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clutter/clutter-timeline.c b/clutter/clutter-timeline.c index 9e000702f..e21a5ec3b 100644 --- a/clutter/clutter-timeline.c +++ b/clutter/clutter-timeline.c @@ -1398,7 +1398,9 @@ clutter_timeline_advance_delta (ClutterTimeline *timeline, { clutter_timeline_advance_internal (timeline); - priv->msecs_delta = 0; + /* Keep the remainder of the frame time so that it will be + counted towards the next time if the delta is short */ + priv->msecs_delta %= priv->frame_interval; } } From fc991e9b67d659fff143f953fe2996c27f406c8a Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 5 May 2009 15:36:29 +0100 Subject: [PATCH 017/138] [actor] Add the :realized property The :realized property is the only missing property for an actor flag. --- clutter/clutter-actor.c | 46 ++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 9bbe536d2..9797d4508 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -382,8 +382,10 @@ enum PROP_CLIP_TO_ALLOCATION, PROP_OPACITY, + PROP_VISIBLE, PROP_MAPPED, + PROP_REALIZED, PROP_REACTIVE, PROP_SCALE_X, @@ -1167,6 +1169,7 @@ clutter_actor_realize (ClutterActor *self) } CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED); + g_object_notify (G_OBJECT (self), "realized"); g_signal_emit (self, actor_signals[REALIZE], 0); @@ -1281,6 +1284,8 @@ clutter_actor_unrealize_not_hiding (ClutterActor *self) g_signal_emit (self, actor_signals[UNREALIZE], 0); CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED); + + g_object_notify (G_OBJECT (self), "realized"); } /** @@ -2653,12 +2658,13 @@ clutter_actor_get_property (GObject *object, g_value_set_string (value, priv->name); break; case PROP_VISIBLE: - g_value_set_boolean (value, - CLUTTER_ACTOR_IS_VISIBLE (actor)); + g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor)); break; case PROP_MAPPED: - g_value_set_boolean (value, - CLUTTER_ACTOR_IS_MAPPED (actor)); + 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); @@ -3208,15 +3214,31 @@ clutter_actor_class_init (ClutterActorClass *klass) /** * ClutterActor:mapped: * - * Whether the actor is mapped (will be painted when stage is mapped). + * Whether the actor is mapped (will be painted when stage is mapped) + * + * Since: 1.0 */ - g_object_class_install_property (object_class, - PROP_MAPPED, - g_param_spec_boolean ("mapped", - "Mapped", - "Whether the actor will be painted", - FALSE, - G_PARAM_READABLE)); + 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: * From 72562cda5847946d9f1d4124290b6c06c7921f2b Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 5 May 2009 15:37:41 +0100 Subject: [PATCH 018/138] [actor] Add ActorFlags accessor methods The flags field of ClutterActor should have accessor methods for, language bindings. Also, the set_flags() and unset_flags() methods should actively emit notifications for the changed properties. --- clutter/clutter-actor.c | 148 ++++++++++++++++++++++++++++++++++++++-- clutter/clutter-actor.h | 17 +++-- 2 files changed, 156 insertions(+), 9 deletions(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 9797d4508..b859433ed 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -132,7 +132,7 @@ /** * CLUTTER_ACTOR_IS_MAPPED: - * @e: a #ClutterActor + * @a: a #ClutterActor * * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set. * @@ -149,7 +149,7 @@ /** * CLUTTER_ACTOR_IS_REALIZED: - * @e: a #ClutterActor + * @a: a #ClutterActor * * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set. * @@ -167,7 +167,7 @@ /** * CLUTTER_ACTOR_IS_VISIBLE: - * @e: a #ClutterActor + * @a: a #ClutterActor * * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden. * Equivalent to the ClutterActor::visible object property. @@ -181,10 +181,12 @@ /** * 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 */ @@ -901,6 +903,7 @@ clutter_actor_real_unmap (ClutterActor *self) NULL); CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED); + /* notify on parent mapped after potentially unmapping * children, so apps see a bottom-up notification. */ @@ -1038,6 +1041,7 @@ clutter_actor_real_hide (ClutterActor *self) if (CLUTTER_ACTOR_IS_VISIBLE (self)) { 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 * (?) @@ -9180,3 +9184,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 c4941ecdd..83d78247d 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) ((((ClutterActor*)(e))->flags & CLUTTER_ACTOR_VISIBLE) != FALSE) -#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 @@ -278,6 +279,12 @@ 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); From 7afdfb080b2f6ecb94ea5d10a9709be71e2ddb9f Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 6 May 2009 16:42:57 +0100 Subject: [PATCH 019/138] [docs] Document the destructor for Timeline The rest of the API reference lists the destructor for the class inside the constructor's return value -- except Timeline. --- clutter/clutter-timeline.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clutter/clutter-timeline.c b/clutter/clutter-timeline.c index e21a5ec3b..761c5e1c5 100644 --- a/clutter/clutter-timeline.c +++ b/clutter/clutter-timeline.c @@ -1109,7 +1109,8 @@ clutter_timeline_clone (ClutterTimeline *timeline) * the value of the ClutterTimeline:fps property to compute the * equivalent number of frames. * - * Return value: the newly created #ClutterTimeline + * Return value: the newly created #ClutterTimeline instance. Use + * g_object_unref() when done using it * * Since: 0.6 */ @@ -1128,7 +1129,8 @@ clutter_timeline_new_for_duration (guint msecs) * * Create a new #ClutterTimeline instance. * - * Return Value: a new #ClutterTimeline + * Return Value: the newly created #ClutterTimeline instance. Use + * g_object_unref() when done using it */ ClutterTimeline* clutter_timeline_new (guint n_frames, From c2abdd5e820134c6281e38339ef141b1e1ed8bf0 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 6 May 2009 16:43:52 +0100 Subject: [PATCH 020/138] [docs] Add Animation get_type() function We need to reference clutter_animation_get_type() if we want the properties, signals and object hierarchy to show up in the API reference --- doc/reference/clutter/clutter.types | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/reference/clutter/clutter.types b/doc/reference/clutter/clutter.types index 7734a16c8..6926447d9 100644 --- a/doc/reference/clutter/clutter.types +++ b/doc/reference/clutter/clutter.types @@ -29,3 +29,4 @@ clutter_child_meta_get_type clutter_cairo_texture_get_type clutter_text_get_type clutter_animatable_get_type +clutter_animation_get_type From d6d208da7de44b1a266957ad69acff6ee0f2fd4d Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 6 May 2009 16:44:47 +0100 Subject: [PATCH 021/138] Remove Units from the public API With the recent change to internal floating point values, ClutterUnit has become a redundant type, defined to be a float. All integer entry points are being internally converted to floating point values to be passed to the GL pipeline with the least amount of conversion. ClutterUnit is thus exposed as just a "pixel with fractionary bits", and not -- as users might think -- as generic, resolution and device independent units. not that it was the case, but a definitive amount of people was convinced it did provide this "feature", and was flummoxed about the mere existence of this type. So, having ClutterUnit exposed in the public API doubles the entry points and has the following disadvantages: - we have to maintain twice the amount of entry points in ClutterActor - we still do an integer-to-float implicit conversion - we introduce a weird impedance between pixels and "pixels with fractionary bits" - language bindings will have to choose what to bind, and resort to manually overriding the API + *except* for language bindings based on GObject-Introspection, as they cannot do manual overrides, thus will replicate the entire set of entry points For these reason, we should coalesces every Actor entry point for pixels and for ClutterUnit into a single entry point taking a float, like: void clutter_actor_set_x (ClutterActor *self, gfloat x); void clutter_actor_get_size (ClutterActor *self, gfloat *width, gfloat *height); gfloat clutter_actor_get_height (ClutterActor *self); etc. The issues I have identified are: - we'll have a two cases of compiler warnings: - printf() format of the return values from %d to %f - clutter_actor_get_size() taking floats instead of unsigned ints - we'll have a problem with varargs when passing an integer instead of a floating point value, except on 64bit platforms where the size of a float is the same as the size of an int To be clear: the *intent* of the API should not change -- we still use pixels everywhere -- but: - we remove ambiguity in the API with regard to pixels and units - we remove entry points we get to maintain for the whole 1.0 version of the API - we make things simpler to bind for both manual language bindings and automatic (gobject-introspection based) ones - we have the simplest API possible while still exposing the capabilities of the underlying GL implementation --- clutter/clutter-actor.c | 2591 ++++++----------- clutter/clutter-actor.h | 223 +- clutter/clutter-animation.c | 3 + clutter/clutter-backend.c | 11 +- clutter/clutter-behaviour.c | 5 +- clutter/clutter-cairo-texture.c | 16 +- clutter/clutter-clone.c | 16 +- clutter/clutter-deprecated.h | 20 + clutter/clutter-event.c | 9 +- clutter/clutter-event.h | 24 +- clutter/clutter-group.c | 40 +- clutter/clutter-main.c | 22 +- clutter/clutter-private.h | 10 +- clutter/clutter-stage.c | 34 +- clutter/clutter-text.c | 50 +- clutter/clutter-texture.c | 63 +- clutter/clutter-types.h | 8 +- clutter/eglnative/clutter-stage-egl.c | 12 +- clutter/fruity/clutter-stage-fruity.c | 12 +- clutter/osx/clutter-stage-osx.c | 12 +- clutter/sdl/clutter-stage-sdl.c | 12 +- clutter/win32/clutter-stage-win32.c | 12 +- clutter/x11/clutter-stage-x11.c | 14 +- tests/conform/test-anchors.c | 15 +- tests/conform/test-timeline-dup-frames.c | 1 - tests/conform/test-timeline-interpolate.c | 1 - tests/conform/test-timeline-rewind.c | 1 - tests/conform/test-timeline-smoothness.c | 1 - tests/interactive/test-actor-clone.c | 4 +- tests/interactive/test-actors.c | 4 +- tests/interactive/test-animation.c | 12 +- .../interactive/test-clutter-cairo-flowers.c | 10 +- tests/interactive/test-depth.c | 24 +- tests/interactive/test-easing.c | 12 +- tests/interactive/test-fullscreen.c | 6 +- tests/interactive/test-layout.c | 16 +- tests/interactive/test-paint-wrapper.c | 6 +- tests/interactive/test-project.c | 46 +- tests/interactive/test-stage-read-pixels.c | 12 +- tests/interactive/test-unproject.c | 21 +- 40 files changed, 1346 insertions(+), 2065 deletions(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index b859433ed..6dca8ff3d 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -256,64 +256,65 @@ 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; - 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; @@ -330,8 +331,6 @@ struct _ClutterActorPrivate PangoContext *pango_context; ClutterActor *opacity_parent; - guint enable_model_view_transform : 1; - guint enable_paint_unmapped : 1; }; enum @@ -343,8 +342,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, @@ -352,8 +350,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, @@ -458,13 +455,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, @@ -480,37 +477,30 @@ static void clutter_actor_update_map_state (ClutterActor *self, 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, @@ -678,14 +668,17 @@ clutter_actor_update_map_state (ClutterActor *self, { 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. @@ -697,28 +690,26 @@ clutter_actor_update_map_state (ClutterActor *self, break; } - if (CLUTTER_ACTOR_IS_MAPPED (self) && - !CLUTTER_ACTOR_IS_VISIBLE (self)) - g_warning ("Clutter toplevel is not visible, but is somehow still mapped"); + if (CLUTTER_ACTOR_IS_MAPPED (self) && !CLUTTER_ACTOR_IS_VISIBLE (self)) + { + g_warning ("Clutter toplevel is not visible, but is " + "somehow still mapped"); + } } else { - ClutterActorPrivate *priv; + ClutterActorPrivate *priv = self->priv; + ClutterActor *parent = priv->parent_actor; gboolean should_be_mapped; gboolean may_be_realized; gboolean must_be_realized; - ClutterActor *parent; - priv = self->priv; should_be_mapped = FALSE; may_be_realized = TRUE; must_be_realized = FALSE; - parent = priv->parent_actor; - - if (parent == NULL || - change == MAP_STATE_MAKE_UNREALIZED) + if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED) { may_be_realized = FALSE; } @@ -992,7 +983,6 @@ clutter_actor_show (ClutterActor *self) g_return_if_fail (CLUTTER_IS_ACTOR (self)); #ifdef CLUTTER_ENABLE_DEBUG - /* FIXME leave this for debugging only */ clutter_actor_verify_map_state (self); #endif @@ -1073,7 +1063,6 @@ clutter_actor_hide (ClutterActor *self) g_return_if_fail (CLUTTER_IS_ACTOR (self)); #ifdef CLUTTER_ENABLE_DEBUG - /* FIXME leave this for debugging only */ clutter_actor_verify_map_state (self); #endif @@ -1141,7 +1130,6 @@ clutter_actor_realize (ClutterActor *self) g_return_if_fail (CLUTTER_IS_ACTOR (self)); #ifdef CLUTTER_ENABLE_DEBUG - /* FIXME leave this for debugging only */ clutter_actor_verify_map_state (self); #endif @@ -1236,7 +1224,6 @@ clutter_actor_unrealize (ClutterActor *self) g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self)); #ifdef CLUTTER_ENABLE_DEBUG - /* FIXME leave this for debugging only */ clutter_actor_verify_map_state (self); #endif @@ -1323,7 +1310,6 @@ _clutter_actor_rerealize (ClutterActor *self, g_return_if_fail (CLUTTER_IS_ACTOR (self)); #ifdef CLUTTER_ENABLE_DEBUG - /* FIXME leave this for debugging only */ clutter_actor_verify_map_state (self); #endif @@ -1369,8 +1355,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, @@ -1442,9 +1428,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 @@ -1461,9 +1447,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 @@ -1490,8 +1476,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. @@ -1506,20 +1493,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; @@ -1527,19 +1514,19 @@ 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 @@ -1627,9 +1614,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 @@ -1677,7 +1664,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, @@ -1697,9 +1684,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); @@ -1714,18 +1701,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(); @@ -1737,16 +1724,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, @@ -1755,18 +1742,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(); @@ -1778,16 +1765,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; } /** @@ -1815,7 +1802,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]; @@ -1863,7 +1850,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]; @@ -1909,8 +1896,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(); @@ -1943,8 +1930,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 @@ -1956,7 +1943,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 (); @@ -2037,7 +2024,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 (); @@ -2117,7 +2104,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 (); @@ -2143,9 +2130,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); @@ -2157,29 +2144,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); } @@ -2211,7 +2202,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 (); @@ -2262,22 +2253,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; } @@ -2379,10 +2368,10 @@ clutter_actor_set_property (GObject *object, clutter_actor_set_height (actor, g_value_get_int (value)); break; case PROP_FIXED_X: - clutter_actor_set_xu (actor, clutter_value_get_unit (value)); + clutter_actor_set_x (actor, clutter_value_get_unit (value)); break; case PROP_FIXED_Y: - clutter_actor_set_yu (actor, clutter_value_get_unit (value)); + clutter_actor_set_y (actor, clutter_value_get_unit (value)); break; case PROP_FIXED_POSITION_SET: clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value)); @@ -2441,30 +2430,34 @@ clutter_actor_set_property (GObject *object, break; case PROP_SCALE_CENTER_X: { - int center_x = g_value_get_int (value); - ClutterUnit center_y; + gint center_x = g_value_get_int (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_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: @@ -2552,26 +2545,26 @@ clutter_actor_set_property (GObject *object, break; case PROP_ANCHOR_X: { - int anchor_x = g_value_get_int (value); - ClutterUnit anchor_y; + gint anchor_x = g_value_get_int (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); + gint anchor_y = g_value_get_int (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: @@ -2677,10 +2670,10 @@ clutter_actor_get_property (GObject *object, { 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); } @@ -2696,15 +2689,19 @@ clutter_actor_get_property (GObject *object, break; case PROP_SCALE_CENTER_X: { - gint center; + gfloat center; + clutter_actor_get_scale_center (actor, ¢er, NULL); + g_value_set_int (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); } break; @@ -2727,8 +2724,10 @@ clutter_actor_get_property (GObject *object, { 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); } @@ -2737,8 +2736,10 @@ clutter_actor_get_property (GObject *object, { 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); } @@ -2747,8 +2748,10 @@ clutter_actor_get_property (GObject *object, { 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); } @@ -2758,18 +2761,24 @@ clutter_actor_get_property (GObject *object, 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_int (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_int (value, anchor_y); } break; case PROP_ANCHOR_GRAVITY: @@ -2860,14 +2869,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_int ("x", + "X coordinate", + "X coordinate of the actor", + -G_MAXINT, G_MAXINT, + 0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_X, pspec); + /** * ClutterActor:y: * @@ -2875,14 +2884,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_int ("y", + "Y coordinate", + "Y coordinate of the actor", + -G_MAXINT, G_MAXINT, + 0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_Y, pspec); + /** * ClutterActor:width: * @@ -2890,14 +2899,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_int ("width", + "Width", + "Width of the actor", + 0, G_MAXINT, + 0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_WIDTH, pspec); /** * ClutterActor:height: * @@ -2905,217 +2913,230 @@ 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_int ("height", + "Height", + "Height of the actor", + 0, G_MAXINT, + 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 = clutter_param_spec_unit ("fixed-x", + "Fixed X", + "Forced X position of the actor", + CLUTTER_MINUNIT, CLUTTER_MAXUNIT, + 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 = clutter_param_spec_unit ("fixed-y", + "Fixed Y", + "Forced Y position of the actor", + CLUTTER_MINUNIT, CLUTTER_MAXUNIT, + 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 = clutter_param_spec_unit ("min-width", + "Min Width", + "Forced minimum width request " + "for the actor", + 0, CLUTTER_MAXUNIT, + 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 = clutter_param_spec_unit ("min-height", + "Min Height", + "Forced minimum height request " + "for the actor", + 0, CLUTTER_MAXUNIT, + 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 = clutter_param_spec_unit ("natural-width", + "Natural Width", + "Forced natural width request " + "for the actor", + 0, CLUTTER_MAXUNIT, + 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 = clutter_param_spec_unit ("natural-height", + "Natural Height", + "Forced natural height request " + "for the actor", + 0, CLUTTER_MAXUNIT, + 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: * @@ -3133,8 +3154,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) @@ -3165,14 +3186,13 @@ 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: @@ -3181,44 +3201,47 @@ clutter_actor_class_init (ClutterActorClass *klass) * * 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_int ("depth", + "Depth", + "Depth of actor", + -G_MAXINT, G_MAXINT, + 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, 0xff, + 0xff, + 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 stage is mapped) + * Whether the actor is mapped (will be painted when the stage + * to which it belongs is mapped) * * Since: 1.0 */ @@ -3246,60 +3269,60 @@ clutter_actor_class_init (ClutterActorClass *klass) /** * 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: * @@ -3307,16 +3330,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: * @@ -3324,16 +3345,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: @@ -3377,59 +3395,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: * @@ -3437,14 +3450,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: * @@ -3452,14 +3466,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: * @@ -3467,14 +3482,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: @@ -3497,41 +3512,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_int ("anchor-x", + "Anchor X", + "X coordinate of the anchor point", + -G_MAXINT, G_MAXINT, + 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_int ("anchor-y", + "Anchor Y", + "Y coordinate of the anchor point", + -G_MAXINT, G_MAXINT, + 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 */ @@ -3554,15 +3566,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: @@ -3596,7 +3607,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), @@ -3613,7 +3624,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), @@ -3630,7 +3641,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), @@ -3647,7 +3658,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), @@ -3732,7 +3743,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), @@ -3754,7 +3765,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), @@ -3776,7 +3787,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), @@ -3798,7 +3809,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), @@ -3820,7 +3831,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), @@ -3843,7 +3854,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), @@ -3865,7 +3876,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), @@ -3883,7 +3894,7 @@ clutter_actor_class_init (ClutterActorClass *klass) * Since: 0.6 */ actor_signals[FOCUS_IN] = - g_signal_new ("focus-in", + g_signal_new (I_("focus-in"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, focus_in), @@ -3900,7 +3911,7 @@ clutter_actor_class_init (ClutterActorClass *klass) * Since: 0.6 */ actor_signals[FOCUS_OUT] = - g_signal_new ("focus-out", + g_signal_new (I_("focus-out"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, focus_out), @@ -3921,7 +3932,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), @@ -3943,7 +3954,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), @@ -3971,7 +3982,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), @@ -4126,7 +4137,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); } /** @@ -4248,15 +4259,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)); @@ -4324,9 +4335,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; @@ -4339,14 +4350,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, @@ -4355,11 +4363,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) @@ -4400,9 +4407,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; @@ -4415,14 +4422,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, @@ -4431,11 +4435,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) @@ -4488,16 +4491,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; } /** @@ -4686,10 +4689,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; } /** @@ -4706,8 +4717,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)); @@ -4719,35 +4730,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 @@ -4788,6 +4770,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); } @@ -4798,57 +4781,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, }; @@ -4882,7 +4843,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; @@ -4917,7 +4878,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, }; @@ -4952,7 +4913,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, }; @@ -5103,34 +5064,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)); @@ -5181,8 +5116,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)); @@ -5193,38 +5128,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 @@ -5243,8 +5146,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)); @@ -5256,99 +5159,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 @@ -5370,9 +5215,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]; @@ -5388,11 +5233,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, @@ -5433,38 +5278,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. @@ -5488,55 +5302,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, @@ -5547,11 +5330,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. @@ -5575,53 +5358,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, @@ -5633,7 +5385,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; } /** @@ -5650,28 +5402,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)); @@ -5697,28 +5428,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)); @@ -5744,40 +5454,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); @@ -5799,40 +5490,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); @@ -5862,52 +5534,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; } /** @@ -5932,43 +5576,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) @@ -5997,23 +5609,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)); } /** @@ -6034,39 +5647,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; @@ -6174,45 +5756,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); } /** @@ -6247,12 +5799,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"); + } } /** @@ -6378,27 +5938,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; @@ -6408,7 +5955,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)) @@ -6418,15 +5965,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"); } @@ -6440,86 +5986,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 @@ -6542,22 +6016,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)); } /** @@ -6575,9 +6074,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; @@ -6602,31 +6101,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; @@ -6659,50 +6153,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 @@ -6724,14 +6174,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 @@ -6740,11 +6188,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; @@ -6772,34 +6220,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 @@ -6840,25 +6260,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; @@ -6882,44 +6300,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 @@ -7405,55 +6785,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 @@ -7466,30 +6797,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 @@ -7499,13 +6826,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)); @@ -7514,7 +6841,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"); @@ -7533,10 +6862,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)); } /** @@ -7564,7 +6893,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 @@ -7575,57 +6904,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 @@ -7647,7 +6953,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)); @@ -7657,15 +6963,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)); } @@ -7714,13 +7024,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; @@ -7729,9 +7039,7 @@ 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 = g_value_get_int (&value); } else if (G_VALUE_HOLDS (&value, G_TYPE_STRING)) { @@ -7747,13 +7055,13 @@ parse_units (ClutterActor *self, /* assume pixels */ if (*end == '\0') { - retval = CLUTTER_UNITS_FROM_DEVICE (val); + retval = val; goto out; } if (strcmp (end, "px") == 0) { - retval = CLUTTER_UNITS_FROM_DEVICE (val); + retval = val; goto out; } @@ -7793,11 +7101,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; } goto out; @@ -7837,11 +7145,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 @@ -7863,9 +7171,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 @@ -8032,8 +7340,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; @@ -8054,7 +7362,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; } @@ -8094,11 +7402,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); } @@ -8116,12 +7424,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 @@ -8136,7 +7442,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. * @@ -8144,16 +7451,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; @@ -8181,13 +7488,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 @@ -8279,18 +7586,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 @@ -8311,7 +7618,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); } @@ -8342,7 +7649,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); } @@ -8372,7 +7679,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); } @@ -8394,9 +7701,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 @@ -8411,9 +7720,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) @@ -8487,13 +7796,15 @@ clutter_actor_set_shader (ClutterActor *self, if (shader) 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); + } 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); shader_data->value_hash = @@ -8501,7 +7812,7 @@ clutter_actor_set_shader (ClutterActor *self, g_free, shader_value_free); } - if (shader_data->shader) + if (shader_data->shader != NULL) g_object_unref (shader_data->shader); shader_data->shader = shader; @@ -8745,36 +8056,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; @@ -8830,14 +8153,14 @@ void clutter_actor_allocate_preferred_size (ClutterActor *self, gboolean absolute_origin_changed) { - 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, @@ -9029,20 +8352,22 @@ _clutter_actor_set_enable_paint_unmapped (ClutterActor *self, 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; } @@ -9050,18 +8375,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; @@ -9115,8 +8442,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) { diff --git a/clutter/clutter-actor.h b/clutter/clutter-actor.h index 83d78247d..098023c70 100644 --- a/clutter/clutter-actor.h +++ b/clutter/clutter-actor.h @@ -129,15 +129,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; @@ -238,13 +238,13 @@ struct _ClutterActorClass /* size negotiation */ void (* 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); void (* 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); void (* allocate) (ClutterActor *actor, const ClutterActorBox *box, gboolean absolute_origin_changed); @@ -302,18 +302,18 @@ 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); @@ -337,100 +337,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); @@ -441,27 +401,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); @@ -478,11 +428,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, @@ -490,13 +437,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, @@ -505,19 +447,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); @@ -543,34 +479,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-animation.c b/clutter/clutter-animation.c index 24b9c3f08..59076e847 100644 --- a/clutter/clutter-animation.c +++ b/clutter/clutter-animation.c @@ -1196,6 +1196,9 @@ clutter_animation_get_timeline (ClutterAnimation *animation) * 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 */ void diff --git a/clutter/clutter-backend.c b/clutter/clutter-backend.c index becf9972f..3a02e7794 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; @@ -133,12 +134,12 @@ update_units_per_em (ClutterBackend *backend) } /* 10 points at 96 DPI is 12 pixels */ - priv->units_per_em = 1.2 * font_size + priv->units_per_em = 1.2f * font_size * dpi - / 96.0; + / 96.0f; } else - priv->units_per_em = -1.0; + priv->units_per_em = -1.0f; } static void @@ -359,7 +360,7 @@ _clutter_backend_init_events (ClutterBackend *backend) klass->init_events (backend); } -ClutterUnit +gfloat _clutter_backend_get_units_per_em (ClutterBackend *backend) { ClutterBackendPrivate *priv; 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 f638ff9c9..ab3f46445 100644 --- a/clutter/clutter-cairo-texture.c +++ b/clutter/clutter-cairo-texture.c @@ -319,9 +319,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; @@ -329,14 +329,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; @@ -344,7 +344,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 16bd60be1..a8ba17cd4 100644 --- a/clutter/clutter-clone.c +++ b/clutter/clutter-clone.c @@ -69,14 +69,14 @@ 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; @@ -93,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; 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-event.c b/clutter/clutter-event.c index a275c4da9..84db43b39 100644 --- a/clutter/clutter-event.c +++ b/clutter/clutter-event.c @@ -119,10 +119,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); @@ -140,15 +140,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 a6a15d4ee..8e528501c 100644 --- a/clutter/clutter-group.c +++ b/clutter/clutter-group.c @@ -120,13 +120,13 @@ clutter_group_pick (ClutterActor *actor, } 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; @@ -136,9 +136,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, @@ -196,13 +196,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; @@ -212,9 +212,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, @@ -286,9 +286,9 @@ clutter_fixed_layout_allocate (GList *children, 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; @@ -300,9 +300,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; diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c index 9e0163a51..9c693e59e 100644 --- a/clutter/clutter-main.c +++ b/clutter/clutter-main.c @@ -119,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 */ @@ -140,8 +140,8 @@ _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); @@ -155,7 +155,7 @@ _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); @@ -1931,8 +1931,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); @@ -2153,7 +2153,7 @@ clutter_do_event (ClutterEvent *event) case CLUTTER_SCROLL: { ClutterActor *actor; - gint x,y; + gfloat x, y; clutter_event_get_coords (event, &x, &y); @@ -2170,7 +2170,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; @@ -2196,12 +2196,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); diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h index e669a640b..95b39e3b7 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -193,15 +193,15 @@ 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); 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]); diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index 2f9320d9d..5908241f4 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -127,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; @@ -143,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; @@ -169,13 +169,14 @@ 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); @@ -188,7 +189,7 @@ clutter_stage_allocate (ClutterActor *self, { 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); @@ -204,6 +205,15 @@ 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); @@ -320,7 +330,7 @@ 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 diff --git a/clutter/clutter-text.c b/clutter/clutter-text.c index 9ece4b8d7..4e9ded547 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; @@ -386,8 +386,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; @@ -484,9 +484,9 @@ clutter_text_coords_to_position (ClutterText *text, static 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 = self->priv; PangoRectangle rect; @@ -535,7 +535,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; @@ -922,7 +922,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); @@ -1119,7 +1119,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 */ @@ -1186,9 +1186,9 @@ clutter_text_motion (ClutterActor *actor, { ClutterText *ttext = CLUTTER_TEXT (actor); ClutterTextPrivate *priv = ttext->priv; - ClutterUnit x, y; - gint index_; - const gchar *text; + gfloat x, y; + gint index_; + const gchar *text; if (!priv->in_select_drag) return FALSE; @@ -1401,16 +1401,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); @@ -1440,9 +1440,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) { ClutterText *text = CLUTTER_TEXT (self); @@ -1459,7 +1459,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 (text, for_width, -1); @@ -3284,11 +3284,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 50c2e5de0..147261dc0 100644 --- a/clutter/clutter-texture.c +++ b/clutter/clutter-texture.c @@ -77,8 +77,8 @@ typedef struct _ClutterTextureAsyncData ClutterTextureAsyncData; struct _ClutterTexturePrivate { - gint width; - gint height; + gfloat width; + gfloat height; gint max_tile_waste; ClutterTextureQuality filter_quality; CoglHandle material; @@ -351,9 +351,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; @@ -370,19 +370,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; } } } @@ -395,9 +390,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; @@ -414,19 +409,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; } } } @@ -460,7 +450,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; @@ -495,13 +485,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 @@ -558,8 +548,8 @@ 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); @@ -571,6 +561,7 @@ clutter_texture_paint (ClutterActor *self) 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); @@ -1445,7 +1436,7 @@ 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); @@ -2310,7 +2301,7 @@ 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); @@ -2453,7 +2444,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); @@ -2523,8 +2514,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); 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/eglnative/clutter-stage-egl.c b/clutter/eglnative/clutter-stage-egl.c index 7e766ed71..3d134b27d 100644 --- a/clutter/eglnative/clutter-stage-egl.c +++ b/clutter/eglnative/clutter-stage-egl.c @@ -221,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); @@ -236,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); diff --git a/clutter/fruity/clutter-stage-fruity.c b/clutter/fruity/clutter-stage-fruity.c index ea1603a58..76dc1351f 100644 --- a/clutter/fruity/clutter-stage-fruity.c +++ b/clutter/fruity/clutter-stage-fruity.c @@ -190,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); @@ -205,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); diff --git a/clutter/osx/clutter-stage-osx.c b/clutter/osx/clutter-stage-osx.c index cb60b3676..b29070c5b 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; diff --git a/clutter/sdl/clutter-stage-sdl.c b/clutter/sdl/clutter-stage-sdl.c index 215c28307..43259b369 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); diff --git a/clutter/win32/clutter-stage-win32.c b/clutter/win32/clutter-stage-win32.c index 7d233c6c2..f49549416 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; diff --git a/clutter/x11/clutter-stage-x11.c b/clutter/x11/clutter-stage-x11.c index 56a33d9cf..9aff476a6 100644 --- a/clutter/x11/clutter-stage-x11.c +++ b/clutter/x11/clutter-stage-x11.c @@ -94,7 +94,7 @@ 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(); @@ -172,9 +172,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; @@ -211,9 +211,9 @@ clutter_stage_x11_get_preferred_width (ClutterActor *self, 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; diff --git a/tests/conform/test-anchors.c b/tests/conform/test-anchors.c index f0211241f..f3118b4fd 100644 --- a/tests/conform/test-anchors.c +++ b/tests/conform/test-anchors.c @@ -417,8 +417,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 +426,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, diff --git a/tests/conform/test-timeline-dup-frames.c b/tests/conform/test-timeline-dup-frames.c index 0d8c3ff3e..de41f1f0e 100644 --- a/tests/conform/test-timeline-dup-frames.c +++ b/tests/conform/test-timeline-dup-frames.c @@ -76,7 +76,6 @@ frame_tick (gpointer data) { TestState *state = data; GTimeVal cur_tick = { 0, }; - GSList *l; gulong msecs; g_get_current_time (&cur_tick); diff --git a/tests/conform/test-timeline-interpolate.c b/tests/conform/test-timeline-interpolate.c index 1e9ca1578..5779b0902 100644 --- a/tests/conform/test-timeline-interpolate.c +++ b/tests/conform/test-timeline-interpolate.c @@ -139,7 +139,6 @@ frame_tick (gpointer data) { TestState *state = data; GTimeVal cur_tick = { 0, }; - GSList *l; gulong msecs; g_get_current_time (&cur_tick); diff --git a/tests/conform/test-timeline-rewind.c b/tests/conform/test-timeline-rewind.c index b13aaa419..c46e7a5ff 100644 --- a/tests/conform/test-timeline-rewind.c +++ b/tests/conform/test-timeline-rewind.c @@ -75,7 +75,6 @@ frame_tick (gpointer data) { TestState *state = data; GTimeVal cur_tick = { 0, }; - GSList *l; gulong msecs; g_get_current_time (&cur_tick); diff --git a/tests/conform/test-timeline-smoothness.c b/tests/conform/test-timeline-smoothness.c index 9824c639d..ab34d7e4e 100644 --- a/tests/conform/test-timeline-smoothness.c +++ b/tests/conform/test-timeline-smoothness.c @@ -89,7 +89,6 @@ frame_tick (gpointer data) { TestState *state = data; GTimeVal cur_tick = { 0, }; - GSList *l; gulong msecs; g_get_current_time (&cur_tick); diff --git a/tests/interactive/test-actor-clone.c b/tests/interactive/test-actor-clone.c index 82fb8142e..92c7f79f8 100644 --- a/tests/interactive/test-actor-clone.c +++ b/tests/interactive/test-actor-clone.c @@ -48,12 +48,12 @@ 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); diff --git a/tests/interactive/test-actors.c b/tests/interactive/test-actors.c index fcaa49275..eb2c49df3 100644 --- a/tests/interactive/test-actors.c +++ b/tests/interactive/test-actors.c @@ -48,12 +48,12 @@ 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); diff --git a/tests/interactive/test-animation.c b/tests/interactive/test-animation.c index 54cf0fe89..032400f63 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, }; @@ -65,10 +65,10 @@ on_button_press (ClutterActor *actor, animation = clutter_actor_animate (actor, CLUTTER_EASE_IN_EXPO, 2000, - "x", new_x, - "y", new_y, - "width", new_width, - "height", new_height, + "x", (int) new_x, + "y", (int) new_y, + "width", (int) new_width, + "height", (int) new_height, "color", &new_color, "rotation-angle-z", new_angle, "fixed::rotation-center-z", &vertex, diff --git a/tests/interactive/test-clutter-cairo-flowers.c b/tests/interactive/test-clutter-cairo-flowers.c index c66531672..746d62313 100644 --- a/tests/interactive/test-clutter-cairo-flowers.c +++ b/tests/interactive/test-clutter-cairo-flowers.c @@ -186,11 +186,11 @@ test_clutter_cairo_flowers_main (int argc, char **argv) { 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_actor_set_position (flowers[i]->ctex, diff --git a/tests/interactive/test-depth.c b/tests/interactive/test-depth.c index 39799c4bd..2f8491077 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); diff --git a/tests/interactive/test-easing.c b/tests/interactive/test-easing.c index a8ff176f7..296812da3 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; @@ -94,8 +94,8 @@ on_button_press (ClutterActor *actor, animation = clutter_actor_animate (rectangle, cur_mode, 2000, - "x", event->x, - "y", event->y, + "x", (int) event->x, + "y", (int) event->y, "color", &color, NULL); } @@ -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..ecd5ce8e4 100644 --- a/tests/interactive/test-layout.c +++ b/tests/interactive/test-layout.c @@ -237,7 +237,7 @@ my_thing_get_preferred_width (ClutterActor *self, 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, @@ -315,7 +315,7 @@ my_thing_get_preferred_height (ClutterActor *self, 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, @@ -490,8 +490,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(); @@ -748,7 +747,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); @@ -776,7 +775,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-paint-wrapper.c b/tests/interactive/test-paint-wrapper.c index ac650d6c8..ac346f5da 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); @@ -125,7 +125,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 +145,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++); diff --git a/tests/interactive/test-project.c b/tests/interactive/test-project.c index f62fd9c1c..25481f3f7 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,8 +97,8 @@ 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); @@ -124,7 +118,7 @@ on_event (ClutterStage *stage, { if (dragging) { - gint x, y; + gfloat x, y; gint i; ClutterActorBox box1, box2; ClutterUnit xp, yp; @@ -148,7 +142,7 @@ on_event (ClutterStage *stage, CLUTTER_UNITS_TO_FLOAT (xp), CLUTTER_UNITS_TO_FLOAT (yp)); - clutter_actor_move_byu (rect, xp, yp); + clutter_actor_move_by (rect, xp, yp); } else { 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-unproject.c b/tests/interactive/test-unproject.c index 188757b72..6c1e857e2 100644 --- a/tests/interactive/test-unproject.c +++ b/tests/interactive/test-unproject.c @@ -23,9 +23,9 @@ 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); @@ -33,10 +33,7 @@ on_event (ClutterStage *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; @@ -44,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); From ab1dcb803333a9a063d91312a1710c28ece951cd Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 6 May 2009 17:01:44 +0100 Subject: [PATCH 022/138] [animation] Remove InitiallyUnowned from Animation ClutterAnimation currently inherits the initial floating reference semantics from GInitiallyUnowned. An Animation is, though, meant to be used as a top-level object, like a Timeline or a Behaviour, and not "owned" by another object. For this reason, the initial floating reference does not make any sense. --- clutter/clutter-animation.c | 18 ++++++++---------- clutter/clutter-animation.h | 4 ++-- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/clutter/clutter-animation.c b/clutter/clutter-animation.c index 59076e847..1625c15f8 100644 --- a/clutter/clutter-animation.c +++ b/clutter/clutter-animation.c @@ -102,7 +102,7 @@ static guint animation_signals[LAST_SIGNAL] = { 0, }; static GQuark quark_object_animation = 0; -G_DEFINE_TYPE (ClutterAnimation, clutter_animation, G_TYPE_INITIALLY_UNOWNED); +G_DEFINE_TYPE (ClutterAnimation, clutter_animation, G_TYPE_OBJECT); static void on_animation_weak_notify (gpointer data, GObject *animation_pointer); @@ -853,9 +853,8 @@ on_animation_weak_notify (gpointer data, * lifetime of a #ClutterAnimation instance, so you should consider using * those functions instead of manually creating an animation. * - * Return value: the newly created #ClutterAnimation. Use g_object_ref_sink() - * to take ownership of the Animation instance, and g_object_unref() to - * release the associated resources + * Return value: the newly created #ClutterAnimation. Use g_object_unref() + * to release the associated resources * * Since: 1.0 */ @@ -886,8 +885,6 @@ clutter_animation_set_object (ClutterAnimation *animation, priv = animation->priv; - g_object_ref (object); - if (priv->object) { g_object_weak_unref (G_OBJECT (animation), @@ -897,13 +894,14 @@ clutter_animation_set_object (ClutterAnimation *animation, g_object_unref (priv->object); } - priv->object = object; + priv->object = g_object_ref (object); g_object_weak_ref (G_OBJECT (animation), on_animation_weak_notify, priv->object); - g_object_set_qdata (G_OBJECT (priv->object), - quark_object_animation, - animation); + g_object_set_qdata_full (G_OBJECT (priv->object), + quark_object_animation, + animation, + NULL); g_object_notify (G_OBJECT (animation), "object"); } diff --git a/clutter/clutter-animation.h b/clutter/clutter-animation.h index 0990309ce..d8cf74d8c 100644 --- a/clutter/clutter-animation.h +++ b/clutter/clutter-animation.h @@ -59,7 +59,7 @@ typedef struct _ClutterAnimationClass ClutterAnimationClass; struct _ClutterAnimation { /*< private >*/ - GInitiallyUnowned parent_instance; + GObject parent_instance; ClutterAnimationPrivate *priv; }; @@ -77,7 +77,7 @@ struct _ClutterAnimation struct _ClutterAnimationClass { /*< private >*/ - GInitiallyUnownedClass parent_class; + GObjectClass parent_class; /*< public >*/ void (* started) (ClutterAnimation *animation); From a28b9f31eb9f4c4a1d4520350f268549e4d37c5a Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 6 May 2009 17:08:25 +0100 Subject: [PATCH 023/138] [text] Add ClutterText::delete_selection() Add a method for deleting the current selection inside a Text actor. This is useful for subclasses. See bug: http://bugzilla.openedhand.com/show_bug.cgi?id=1521 Based on a patch by: Raymond Liu --- clutter/clutter-text.c | 47 +++++++++++++++------- clutter/clutter-text.h | 1 + doc/reference/clutter/clutter-sections.txt | 1 + 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/clutter/clutter-text.c b/clutter/clutter-text.c index 4e9ded547..b0b1a194b 100644 --- a/clutter/clutter-text.c +++ b/clutter/clutter-text.c @@ -411,10 +411,10 @@ clutter_text_create_layout (ClutterText *text, /* If this cached layout is using the same size then we can * just return that directly */ - CLUTTER_NOTE (ACTOR, "ClutterText: %p: cache hit for size %i x %i", + CLUTTER_NOTE (ACTOR, "ClutterText: %p: cache hit for size %.2fx%.2f", text, - CLUTTER_UNITS_TO_DEVICE (allocation_width), - CLUTTER_UNITS_TO_DEVICE (allocation_height)); + allocation_width, + allocation_height); return priv->cached_layouts[i].layout; } @@ -425,10 +425,10 @@ clutter_text_create_layout (ClutterText *text, } } - CLUTTER_NOTE (ACTOR, "ClutterText: %p: cache miss for size %i x %i", + CLUTTER_NOTE (ACTOR, "ClutterText: %p: cache miss for size %.2fx%.2f", text, - CLUTTER_UNITS_TO_DEVICE (allocation_width), - CLUTTER_UNITS_TO_DEVICE (allocation_height)); + allocation_width, + allocation_height); /* If we make it here then we didn't have a cached version so we need to recreate the layout */ @@ -545,10 +545,10 @@ clutter_text_ensure_cursor_position (ClutterText *self) &x, &y, &cursor_height); - cursor_pos.x = CLUTTER_UNITS_TO_DEVICE (x); - cursor_pos.y = CLUTTER_UNITS_TO_DEVICE (y); + cursor_pos.x = x; + cursor_pos.y = y; cursor_pos.width = priv->cursor_size; - cursor_pos.height = CLUTTER_UNITS_TO_DEVICE (cursor_height) - 2; + cursor_pos.height = cursor_height - 2; x_changed = priv->cursor_pos.x != cursor_pos.x; y_changed = priv->cursor_pos.y != cursor_pos.y; @@ -563,13 +563,30 @@ clutter_text_ensure_cursor_position (ClutterText *self) } } -static gboolean -clutter_text_truncate_selection (ClutterText *self) +/** + * clutter_text_delete_selection: + * @self: a #ClutterText + * + * Deletes the currently selected text + * + * This function is only useful in subclasses of #ClutterText + * + * Return value: %TRUE if text was deleted or if the text actor + * is empty, and %FALSE otherwise + * + * Since: 1.0 + */ +gboolean +clutter_text_delete_selection (ClutterText *self) { - ClutterTextPrivate *priv = self->priv; + ClutterTextPrivate *priv; gint start_index; gint end_index; + g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE); + + priv = self->priv; + if (!priv->text) return TRUE; @@ -1287,7 +1304,7 @@ clutter_text_key_press (ClutterActor *actor, /* truncate the eventual selection so that the * Unicode character can replace it */ - clutter_text_truncate_selection (self); + clutter_text_delete_selection (self); clutter_text_insert_unichar (self, key_unichar); return TRUE; @@ -1715,7 +1732,7 @@ clutter_text_real_del_next (ClutterText *self, gint pos; gint len; - if (clutter_text_truncate_selection (self)) + if (clutter_text_delete_selection (self)) return TRUE; pos = priv->position; @@ -1737,7 +1754,7 @@ clutter_text_real_del_prev (ClutterText *self, gint pos; gint len; - if (clutter_text_truncate_selection (self)) + if (clutter_text_delete_selection (self)) return TRUE; pos = priv->position; diff --git a/clutter/clutter-text.h b/clutter/clutter-text.h index fd7eb07c5..01b058cf7 100644 --- a/clutter/clutter-text.h +++ b/clutter/clutter-text.h @@ -186,6 +186,7 @@ void clutter_text_set_selection_color (ClutterText *sel const ClutterColor *color); void clutter_text_get_selection_color (ClutterText *self, ClutterColor *color); +gboolean clutter_text_delete_selection (ClutterText *self); void clutter_text_set_password_char (ClutterText *self, gunichar wc); gunichar clutter_text_get_password_char (ClutterText *self); diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt index cd7df4967..e8c8a46ad 100644 --- a/doc/reference/clutter/clutter-sections.txt +++ b/doc/reference/clutter/clutter-sections.txt @@ -1584,6 +1584,7 @@ clutter_text_insert_text clutter_text_insert_unichar clutter_text_delete_chars clutter_text_delete_text +clutter_text_delete_selection clutter_text_get_chars clutter_text_set_cursor_color clutter_text_get_cursor_color From d0ad5a8abb732ae9b80d036116b6c2c1e5bef985 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 6 May 2009 17:18:12 +0100 Subject: [PATCH 024/138] [text] Expose position_to_coords() The clutter_text_position_to_coords() is useful for ClutterText subclasses. See bug: http://bugzilla.openedhand.com/show_bug.cgi?id=1521 Based on a patch by: Raymond Liu --- clutter/clutter-text.c | 16 ++++++++++++---- clutter/clutter-text.h | 5 +++++ doc/reference/clutter/clutter-sections.txt | 1 + 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/clutter/clutter-text.c b/clutter/clutter-text.c index b0b1a194b..0f56462f5 100644 --- a/clutter/clutter-text.c +++ b/clutter/clutter-text.c @@ -469,7 +469,7 @@ clutter_text_coords_to_position (ClutterText *text, return index_ + trailing; } -/* +/** * clutter_text_position_to_coords: * @self: a #ClutterText * @position: position in characters @@ -480,19 +480,28 @@ clutter_text_coords_to_position (ClutterText *text, * Retrieves the coordinates of the given @position. * * Return value: %TRUE if the conversion was successful + * + * Since: 1.0 */ -static gboolean +gboolean clutter_text_position_to_coords (ClutterText *self, gint position, gfloat *x, gfloat *y, gfloat *line_height) { - ClutterTextPrivate *priv = self->priv; + ClutterTextPrivate *priv; PangoRectangle rect; gint password_char_bytes = 1; gint index_; + g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE); + + priv = self->priv; + + if (position < -1 || position > priv->n_chars) + return FALSE; + if (priv->password_char != 0) password_char_bytes = g_unichar_to_utf8 (priv->password_char, NULL); @@ -527,7 +536,6 @@ clutter_text_position_to_coords (ClutterText *self, if (line_height) *line_height = CLUTTER_UNITS_FROM_PANGO_UNIT (rect.height); - /* FIXME: should return false if coords were outside text */ return TRUE; } diff --git a/clutter/clutter-text.h b/clutter/clutter-text.h index 01b058cf7..f34ff967a 100644 --- a/clutter/clutter-text.h +++ b/clutter/clutter-text.h @@ -198,6 +198,11 @@ void clutter_text_set_single_line_mode (ClutterText *sel gboolean clutter_text_get_single_line_mode (ClutterText *self); gboolean clutter_text_activate (ClutterText *self); +gboolean clutter_text_position_to_coords (ClutterText *self, + gint position, + gfloat *x, + gfloat *y, + gfloat *line_height); G_END_DECLS diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt index e8c8a46ad..af7e7feea 100644 --- a/doc/reference/clutter/clutter-sections.txt +++ b/doc/reference/clutter/clutter-sections.txt @@ -1599,6 +1599,7 @@ clutter_text_get_cursor_size clutter_text_activate +clutter_text_position_to_coords CLUTTER_IS_TEXT From 515350a77fb42317f5a0643702733e0dbaffc2aa Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 6 May 2009 17:56:40 +0100 Subject: [PATCH 025/138] [actor] Rename focus-in and focus-out signals For consistency, and since those signals are key-related, the ::focus-in signal is not ::key-focus-in and the ::focus-out signal is now ::key-focus-out. --- clutter/clutter-actor.c | 22 +++++++++++----------- clutter/clutter-actor.h | 8 ++++---- clutter/clutter-stage.c | 6 +++--- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 6dca8ff3d..9d26463be 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -417,8 +417,8 @@ enum HIDE, DESTROY, PARENT_SET, - FOCUS_IN, - FOCUS_OUT, + KEY_FOCUS_IN, + KEY_FOCUS_OUT, PAINT, PICK, REALIZE, @@ -3886,35 +3886,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 (I_("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 (I_("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); diff --git a/clutter/clutter-actor.h b/clutter/clutter-actor.h index 098023c70..38039a670 100644 --- a/clutter/clutter-actor.h +++ b/clutter/clutter-actor.h @@ -206,8 +206,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. */ @@ -269,8 +269,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 */ diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index 5908241f4..e218dea90 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -1472,7 +1472,7 @@ clutter_stage_set_key_focus (ClutterStage *stage, 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) { @@ -1481,10 +1481,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"); } /** From 4cb3fa872825d2903e8c50733eb171b729a1272a Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 6 May 2009 17:57:34 +0100 Subject: [PATCH 026/138] [docs] Update documentation Remove the units-based API and add the missing symbols. Also, do not let gtk-doc check the master clock header, since it's private. --- doc/reference/clutter/Makefile.am | 1 + doc/reference/clutter/clutter-sections.txt | 37 ++++++---------------- 2 files changed, 10 insertions(+), 28 deletions(-) diff --git a/doc/reference/clutter/Makefile.am b/doc/reference/clutter/Makefile.am index a5773a2ed..b2489466c 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 \ diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt index af7e7feea..96f9937f1 100644 --- a/doc/reference/clutter/clutter-sections.txt +++ b/doc/reference/clutter/clutter-sections.txt @@ -186,6 +186,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 +276,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,6 +294,8 @@ clutter_actor_destroy clutter_actor_event clutter_actor_pick clutter_actor_should_pick_paint +clutter_actor_map +clutter_actor_unmap clutter_actor_allocate @@ -386,34 +394,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 @@ -597,6 +577,7 @@ CLUTTER_TIMELINE_GET_CLASS ClutterTimelinePrivate clutter_timeline_get_type +clutter_timeline_advance_delta
From 8ec1c3e2fbb25c32f6d14f697995c438ea4fb755 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 7 May 2009 11:18:51 +0100 Subject: [PATCH 027/138] Fix remaining ::focus-in signal emission Commit 515350a7 renamed ::focus-in and ::focus-out to ::key-focus-in and ::key-focus-out respectively. One signal emission for ::focus-out escaped the renaming in ClutterStage. --- clutter/clutter-stage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index e218dea90..d5235550c 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -1467,7 +1467,7 @@ 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; } From f2c25fd4f7d8a22dcb91461ebb86d1c74565c89b Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 7 May 2009 14:16:01 +0100 Subject: [PATCH 028/138] Allow specifying the font for the em conversion Currently, the conversion from em to units is done by using the default font name inside the backend. For actors using their own font/text layout we need a way to specify the font name along with the quantity we wish to transform. --- clutter/clutter-backend.c | 91 ++++++++++++++++++++++++++------------- clutter/clutter-private.h | 3 +- clutter/clutter-units.c | 47 ++++++++++++++++++-- clutter/clutter-units.h | 13 +++--- 4 files changed, 115 insertions(+), 39 deletions(-) diff --git a/clutter/clutter-backend.c b/clutter/clutter-backend.c index 3a02e7794..35d97fdcc 100644 --- a/clutter/clutter-backend.c +++ b/clutter/clutter-backend.c @@ -103,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 ClutterUnit +get_units_per_em (ClutterBackend *backend, + PangoFontDescription *font_desc) { - ClutterBackendPrivate *priv = backend->priv; - const gchar *font_name; + ClutterUnit 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.2f * font_size - * dpi - / 96.0f; + 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.0f; + 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 @@ -361,7 +380,8 @@ _clutter_backend_init_events (ClutterBackend *backend) } gfloat -_clutter_backend_get_units_per_em (ClutterBackend *backend) +_clutter_backend_get_units_per_em (ClutterBackend *backend, + PangoFontDescription *font_desc) { ClutterBackendPrivate *priv; @@ -369,8 +389,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; } @@ -603,6 +627,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; } @@ -662,7 +688,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-private.h b/clutter/clutter-private.h index 95b39e3b7..768ab9dbc 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -193,7 +193,8 @@ void _clutter_backend_init_events (ClutterBackend *backend); ClutterFeatureFlags _clutter_backend_get_features (ClutterBackend *backend); -gfloat _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); diff --git a/clutter/clutter-units.c b/clutter/clutter-units.c index 1263886b3..a0ccddc05 100644 --- a/clutter/clutter-units.c +++ b/clutter/clutter-units.c @@ -169,11 +169,52 @@ clutter_units_pt (gdouble pt) ClutterUnit clutter_units_em (gdouble em) { - ClutterBackend *backend; + ClutterBackend *backend = clutter_get_default_backend (); - backend = clutter_get_default_backend (); + return em * _clutter_backend_get_units_per_em (backend, NULL); +} - return em * _clutter_backend_get_units_per_em (backend); +/** + * clutter_units_em_for_font: + * @font_name: the font name and size + * @em: em to convert + * + * Converts a value in em to #ClutterUnits at the + * current DPI for the given font name. + * + * The @font_name string must be in a format that + * pango_font_description_from_string() can parse, like + * for clutter_text_set_font_name() or clutter_backend_set_font_name(). + * + * Return value: the value in units + * + * Since: 1.0 + */ +ClutterUnit +clutter_units_em_for_font (const gchar *font_name, + gdouble 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; + } } /** diff --git a/clutter/clutter-units.h b/clutter/clutter-units.h index c2db312eb..0439df433 100644 --- a/clutter/clutter-units.h +++ b/clutter/clutter-units.h @@ -32,7 +32,8 @@ #define __CLUTTER_UNITS_H__ #include -#include + +#include G_BEGIN_DECLS @@ -192,10 +193,12 @@ typedef float ClutterUnit; */ #define CLUTTER_UNITS_FROM_EM(x) (clutter_units_em (x)) -ClutterUnit clutter_units_mm (gdouble mm); -ClutterUnit clutter_units_pt (gdouble pt); -ClutterUnit clutter_units_em (gdouble em); -ClutterUnit clutter_units_pixels (gint px); +ClutterUnit clutter_units_mm (gdouble mm); +ClutterUnit clutter_units_pt (gdouble pt); +ClutterUnit clutter_units_em (gdouble em); +ClutterUnit clutter_units_em_for_font (const gchar *font_name, + gdouble em); +ClutterUnit clutter_units_pixels (gint px); gint clutter_units_to_pixels (ClutterUnit units); From 33ef1675f5d5d750833a5d2eb9373afe44adb0c5 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 7 May 2009 18:46:36 +0100 Subject: [PATCH 029/138] [script] Allow parsing units in em When creating an actor, using "em" as a unit should result in an implicit conversion, like for "mm" and "pt". --- clutter/clutter-actor.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 9d26463be..39973c5cf 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -7065,6 +7065,12 @@ parse_units (ClutterActor *self, goto out; } + if (strcmp (end, "em") == 0) + { + retval = CLUTTER_UNITS_FROM_EM (val); + goto out; + } + if (strcmp (end, "mm") == 0) { retval = CLUTTER_UNITS_FROM_MM (val); From e41452fc0c465c92a5d26c28b4c744ae73829d58 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 7 May 2009 19:16:20 +0100 Subject: [PATCH 030/138] [tests] Check em to unit conversion We should be able to position elements of the stage using em as a unit, and converting values into pixels. --- tests/interactive/test-text-field.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/interactive/test-text-field.c b/tests/interactive/test-text-field.c index 260fc5fca..ceb07a7a8 100644 --- a/tests/interactive/test-text-field.c +++ b/tests/interactive/test-text-field.c @@ -91,13 +91,19 @@ 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; + gfloat width, height; + gfloat h_padding, v_padding; clutter_init (&argc, &argv); stage = clutter_stage_get_default (); clutter_stage_set_color (CLUTTER_STAGE (stage), &background_color); + h_padding = clutter_units_em_for_font (FONT, 2.0); /* 2em */ + v_padding = clutter_units_em_for_font (FONT, 3.0); /* 3em */ + + g_print ("padding: h:%.2f px, v:%.2f px\n", h_padding, v_padding); + text = create_label (&label_color, "Input field: "); clutter_actor_set_position (text, 10, 10); clutter_container_add_actor (CLUTTER_CONTAINER (stage), text); @@ -106,15 +112,17 @@ 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, 10 + width + 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 + 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 + h_padding, + height + 10 + v_padding); clutter_container_add_actor (CLUTTER_CONTAINER (stage), text); clutter_actor_show (stage); From 081813fd61400dec7183cb5d151dff3bbbbc8b34 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 7 May 2009 18:39:07 +0100 Subject: [PATCH 031/138] [animation] Do not leak timelines The timeline created when calling set_timeline(NULL) is referenced even though we implicitly own it. When the Animation is destroyed, the timeline is then leaked. Thanks to: Richard Heatley Fixes bug: http://bugzilla.openedhand.com/show_bug.cgi?id=1548 --- clutter/clutter-animation.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/clutter/clutter-animation.c b/clutter/clutter-animation.c index 1625c15f8..73dd6ffd0 100644 --- a/clutter/clutter-animation.c +++ b/clutter/clutter-animation.c @@ -1115,12 +1115,12 @@ clutter_animation_set_timeline (ClutterAnimation *animation, priv = animation->priv; - if (timeline && priv->timeline == timeline) + if (timeline != NULL && priv->timeline == timeline) return; g_object_freeze_notify (G_OBJECT (animation)); - if (priv->timeline) + if (priv->timeline != NULL) { if (priv->timeline_started_id) g_signal_handler_disconnect (priv->timeline, @@ -1136,13 +1136,17 @@ clutter_animation_set_timeline (ClutterAnimation *animation, priv->timeline = 0; } - if (!timeline) - timeline = g_object_new (CLUTTER_TYPE_TIMELINE, - "duration", priv->duration, - "loop", priv->loop, - NULL); + 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"); @@ -1150,7 +1154,7 @@ clutter_animation_set_timeline (ClutterAnimation *animation, g_object_notify (G_OBJECT (animation), "loop"); } - priv->timeline = g_object_ref (timeline); + priv->timeline = timeline; g_object_notify (G_OBJECT (animation), "timeline"); priv->timeline_started_id = From ab9c7671f57a03ab34dac97bbd3a787b5f0ab65d Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 7 May 2009 18:47:50 +0100 Subject: [PATCH 032/138] [group] Implement pick Currently, picking in ClutterGroup pollutes the CLUTTER_DEBUG=paint logs since it just calls the paint function. Reimplementing the pick doesn't make us lose anything -- it might even be slightly faster since we don't have to do a (typed) cast and a class dereference. --- clutter/clutter-group.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/clutter/clutter-group.c b/clutter/clutter-group.c index 8e528501c..148309b97 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'", @@ -109,14 +108,22 @@ 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 From 86bc31bd55fec32ed70abc19f0f2c4514d1c8e29 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 7 May 2009 19:07:21 +0100 Subject: [PATCH 033/138] [clock] Rework the master clock The master clock is currently advanced using a frame source driven by the default frame rate. This breaks the sync to vblank because the vblanking rate could be different than 60 Hz -- or it might be completely disabled (e.g. with CLUTTER_VBLANK=none). We should be using the main loop to check if we have timelines playing, and if so queue a redraw on the stages we own. We should also prepare the subsequent frame at the end of the redraw process, so if there are new redraw we will have the scene already in place. This makes Clutter redraw at the maximum frame rate, which is limited by the vblanking frequency. --- clutter/clutter-main.c | 14 +- clutter/clutter-master-clock.c | 247 +++++++++++++++++++++------------ clutter/clutter-private.h | 2 + clutter/clutter-stage.c | 10 +- 4 files changed, 173 insertions(+), 100 deletions(-) diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c index 9c693e59e..59fa41f72 100644 --- a/clutter/clutter-main.c +++ b/clutter/clutter-main.c @@ -182,12 +182,12 @@ void clutter_redraw (ClutterStage *stage) { ClutterMainContext *ctx; + ClutterMasterClock *master_clock; static GTimer *timer = NULL; static guint timer_n_frames = 0; ctx = clutter_context_get_default (); - - CLUTTER_NOTE (PAINT, " Redraw enter 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)); @@ -208,10 +208,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 ())) { @@ -225,7 +230,6 @@ clutter_redraw (ClutterStage *stage) } } - CLUTTER_NOTE (PAINT, " Redraw leave for stage:%p", stage); CLUTTER_TIMESTAMP (SCHEDULER, "Redraw finish for stage:%p", stage); } @@ -1052,6 +1056,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); diff --git a/clutter/clutter-master-clock.c b/clutter/clutter-master-clock.c index a417dbbca..8b10238f2 100644 --- a/clutter/clutter-master-clock.c +++ b/clutter/clutter-master-clock.c @@ -43,18 +43,31 @@ #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; - gulong tick_id; + /* 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 @@ -62,36 +75,135 @@ struct _ClutterMasterClockClass GObjectClass parent_class; }; -static ClutterMasterClock *default_clock = NULL; +struct _ClutterClockSource +{ + GSource source; -static void on_timeline_start (ClutterTimeline *timeline, + 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); +static gboolean +_clutter_master_clock_has_running_timeline (ClutterMasterClock *master_clock) +{ + 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 (clutter_timeline_is_playing (l->data)) + return TRUE; + } + + return FALSE; +} + +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; + + *timeout = -1; + + retval = _clutter_master_clock_has_running_timeline (master_clock); + + return retval; +} + +static gboolean +clutter_clock_check (GSource *source) +{ + ClutterClockSource *clock_source = (ClutterClockSource *) source; + ClutterMasterClock *master_clock = clock_source->master_clock; + gboolean retval; + + retval = _clutter_master_clock_has_running_timeline (master_clock); + + 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 (); + GSList *stages, *l; + + CLUTTER_NOTE (SCHEDULER, "Master clock [tick]"); + + stages = clutter_stage_manager_list_stages (stage_manager); + + for (l = stages; l != NULL; l = l->next) + clutter_actor_queue_redraw (l->data); + + g_slist_free (stages); + + if (master_clock->last_advance) + { + master_clock->last_advance = FALSE; + master_clock->prev_tick.tv_sec = 0; + } + + 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); + master_clock->timelines = + g_slist_remove (master_clock->timelines, object_pointer); if (master_clock->timelines == NULL) - { - if (master_clock->tick_id != 0) - { - g_source_remove (master_clock->tick_id); - master_clock->tick_id = 0; - } - - master_clock->prev_tick.tv_sec = 0; - } + master_clock->prev_tick.tv_sec = 0; } static void @@ -100,12 +212,6 @@ clutter_master_clock_finalize (GObject *gobject) ClutterMasterClock *master_clock = CLUTTER_MASTER_CLOCK (gobject); GSList *l; - if (master_clock->tick_id != 0) - { - g_source_remove (master_clock->tick_id); - master_clock->tick_id = 0; - } - for (l = master_clock->timelines; l != NULL; l = l->next) { ClutterTimeline *timeline = l->data; @@ -115,7 +221,7 @@ clutter_master_clock_finalize (GObject *gobject) master_clock); g_signal_handlers_disconnect_by_func (timeline, - G_CALLBACK (on_timeline_start), + G_CALLBACK (on_timeline_started), master_clock); g_signal_handlers_disconnect_by_func (timeline, G_CALLBACK (on_timeline_completed), @@ -141,6 +247,14 @@ clutter_master_clock_class_init (ClutterMasterClockClass *klass) 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); } /* @@ -163,80 +277,34 @@ _clutter_master_clock_get_default (void) return default_clock; } -static gboolean -master_clock_tick (gpointer data) -{ - ClutterStageManager *stage_manager = clutter_stage_manager_get_default (); - GSList *stages, *l; - - CLUTTER_NOTE (SCHEDULER, "Master clock [tick]"); - - stages = clutter_stage_manager_list_stages (stage_manager); - - for (l = stages; l != NULL; l = l->next) - clutter_actor_queue_redraw (l->data); - - g_slist_free (stages); - - return TRUE; -} - -static gboolean -has_running_timeline (ClutterMasterClock *master_clock) -{ - GSList *l; - - for (l = master_clock->timelines; l != NULL; l = l->next) - { - if (clutter_timeline_is_playing (l->data)) - return TRUE; - } - - return FALSE; -} - static void -on_timeline_start (ClutterTimeline *timeline, - ClutterMasterClock *master_clock) +on_timeline_started (ClutterTimeline *timeline, + ClutterMasterClock *master_clock) { - if (has_running_timeline (master_clock) && - master_clock->tick_id == 0) - { - master_clock->prev_tick.tv_sec = 0; - - master_clock->tick_id = - clutter_threads_add_frame_source (clutter_get_default_frame_rate (), - master_clock_tick, - master_clock); - } + if (!_clutter_master_clock_has_running_timeline (master_clock)) + master_clock->prev_tick.tv_sec = 0; } static void on_timeline_completed (ClutterTimeline *timeline, ClutterMasterClock *master_clock) { - if (!has_running_timeline (master_clock) && - master_clock->tick_id != 0) - { - master_clock->prev_tick.tv_sec = 0; - - g_source_remove (master_clock->tick_id); - master_clock->tick_id = 0; - } + /* 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 (!_clutter_master_clock_has_running_timeline (master_clock)) + master_clock->last_advance = TRUE; } static void on_timeline_paused (ClutterTimeline *timeline, ClutterMasterClock *master_clock) { - if (!has_running_timeline (master_clock) && - master_clock->tick_id != 0) - { - master_clock->prev_tick.tv_sec = 0; - - g_source_remove (master_clock->tick_id); - master_clock->tick_id = 0; - } + /* see the comment in on_timeline_completed */ + if (!_clutter_master_clock_has_running_timeline (master_clock)) + master_clock->last_advance = TRUE; } /* @@ -267,7 +335,7 @@ _clutter_master_clock_add_timeline (ClutterMasterClock *master_clock, master_clock); g_signal_connect (timeline, "started", - G_CALLBACK (on_timeline_start), + G_CALLBACK (on_timeline_started), master_clock); g_signal_connect (timeline, "completed", G_CALLBACK (on_timeline_completed), @@ -301,7 +369,7 @@ _clutter_master_clock_remove_timeline (ClutterMasterClock *master_clock, master_clock); g_signal_handlers_disconnect_by_func (timeline, - G_CALLBACK (on_timeline_start), + G_CALLBACK (on_timeline_started), master_clock); g_signal_handlers_disconnect_by_func (timeline, G_CALLBACK (on_timeline_completed), @@ -311,15 +379,7 @@ _clutter_master_clock_remove_timeline (ClutterMasterClock *master_clock, master_clock); if (master_clock->timelines == NULL) - { - if (master_clock->tick_id != 0) - { - g_source_remove (master_clock->tick_id); - master_clock->tick_id = 0; - } - - master_clock->prev_tick.tv_sec = 0; - } + master_clock->prev_tick.tv_sec = 0; } /* @@ -339,6 +399,9 @@ _clutter_master_clock_advance (ClutterMasterClock *master_clock) 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) diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h index 768ab9dbc..30870ee62 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -44,6 +44,7 @@ #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" @@ -129,6 +130,7 @@ struct _ClutterMainContext guint32 last_event_time; + ClutterMasterClock *master_clock; gulong redraw_count; }; diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index d5235550c..d34f43f6a 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -379,20 +379,22 @@ redraw_update_idle (gpointer user_data) */ _clutter_stage_maybe_relayout (CLUTTER_ACTOR (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 (PAINT, "Queued %lu redraws during the last cycle", + CLUTTER_NOTE (SCHEDULER, "Queued %lu redraws during the last cycle", CLUTTER_CONTEXT ()->redraw_count); CLUTTER_CONTEXT ()->redraw_count = 0; } - priv->update_idle = 0; - - return retval; + return FALSE; } static void From 533c9c536530bd43931793010f76714580f6b166 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 7 May 2009 19:14:29 +0100 Subject: [PATCH 034/138] [debug] Show the actor name/type on queue_redraw() --- clutter/clutter-actor.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 39973c5cf..1ce681583 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -1588,6 +1588,9 @@ clutter_actor_real_queue_redraw (ClutterActor *self, 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 From 9f3927c460cbc4d50eae2b78826cc5347cb37c16 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 7 May 2009 19:14:48 +0100 Subject: [PATCH 035/138] [stage] Chain up to the correct vfunc when picking The stage is chaining up to the ClutterGroup::paint instead of the ClutterGroup::pick method. This works anyway because we detect the stage by default, but it's not a reliable solution in case we decide to change the picking further on. --- clutter/clutter-stage.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index d34f43f6a..8780b2d67 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -266,7 +266,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 @@ -358,7 +358,6 @@ redraw_update_idle (gpointer user_data) ClutterStage *stage = user_data; ClutterStagePrivate *priv = stage->priv; ClutterMasterClock *master_clock; - gboolean retval = FALSE; /* 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 From 91126558d35c58a94f674ad93d9561e4c5ab3bff Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 8 May 2009 17:14:49 +0100 Subject: [PATCH 036/138] [actor] Relax some of the invariants checks When destroying a top-level actor we can actually relax the verification of the map state, since it might be fully asynchronous and we might not re-enter inside the mainloop in time to receive the unmap notification. --- clutter/clutter-actor.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 1ce681583..ef6d0d662 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -558,8 +558,11 @@ clutter_actor_verify_map_state (ClutterActor *self) { if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL) { - if (!CLUTTER_ACTOR_IS_VISIBLE (self)) - g_warning ("Toplevel actor is mapped but not visible"); + if (!CLUTTER_ACTOR_IS_VISIBLE (self) && + !(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_DESTRUCTION)) + { + g_warning ("Toplevel actor is mapped but not visible"); + } } else { @@ -690,7 +693,9 @@ clutter_actor_update_map_state (ClutterActor *self, break; } - if (CLUTTER_ACTOR_IS_MAPPED (self) && !CLUTTER_ACTOR_IS_VISIBLE (self)) + if (CLUTTER_ACTOR_IS_MAPPED (self) && + !CLUTTER_ACTOR_IS_VISIBLE (self) && + !(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_DESTRUCTION)) { g_warning ("Clutter toplevel is not visible, but is " "somehow still mapped"); @@ -1139,7 +1144,7 @@ clutter_actor_realize (ClutterActor *self) /* 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) + if (self->priv->parent_actor != NULL) clutter_actor_realize (self->priv->parent_actor); if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL) @@ -2820,9 +2825,13 @@ clutter_actor_dispose (GObject *object) /* parent should be gone */ g_assert (priv->parent_actor == NULL); - /* can't be mapped or realized with no parent */ - g_assert (!CLUTTER_ACTOR_IS_MAPPED (self)); - g_assert (!CLUTTER_ACTOR_IS_REALIZED (self)); + + 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); From 5bcde25cbbfcfefc850605fb0ddf8e818d2413fa Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 8 May 2009 17:17:48 +0100 Subject: [PATCH 037/138] Tentative fix for multi-stage support on GLX The fix for bug 1138 broke multi-stage support on GLX, causing X11 to segfault with the following stack trace: Backtrace: 0: /usr/X11R6/bin/X(xf86SigHandler+0x7e) [0x80c91fe] 1: [0xb7eea400] 2: /usr/lib/xorg/modules/extensions//libglx.so [0xb7ae880c] 3: /usr/lib/xorg/modules/extensions//libglx.so [0xb7aec0d6] 4: /usr/X11R6/bin/X [0x8154c24] 5: /usr/X11R6/bin/X(Dispatch+0x314) [0x808de54] 6: /usr/X11R6/bin/X(main+0x4b5) [0x8074795] 7: /lib/i686/cmov/libc.so.6(__libc_start_main+0xe5) [0xb7c75775] 8: /usr/X11R6/bin/X(FontFileCompleteXLFD+0x21d) [0x8073a81] which I can only track down to clutter_backend_glx_ensure_current() being passed a NULL stage -- something that happens when a stage is not correct realized. That should lead to a glXMakeCurrent(None) and not to a segmentation fault, though. --- clutter/clutter-backend.c | 14 +++++++++++--- clutter/clutter-stage.c | 18 +++++++++++++----- clutter/glx/clutter-backend-glx.c | 7 +++++-- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/clutter/clutter-backend.c b/clutter/clutter-backend.c index 35d97fdcc..90e4ad2a3 100644 --- a/clutter/clutter-backend.c +++ b/clutter/clutter-backend.c @@ -304,8 +304,8 @@ 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)); @@ -314,8 +314,16 @@ _clutter_backend_ensure_context (ClutterBackend *backend, { if (!CLUTTER_ACTOR_IS_REALIZED (stage)) { - CLUTTER_NOTE (MULTISTAGE, "Stage is not realized, unsetting"); - stage = NULL; + CLUTTER_NOTE (MULTISTAGE, + "Stage [%p] is not realized, realizing", + stage); + + /* if we are asked to ensure a particular stage we need + * to make sure that is has been realized; calling + * realized() twice in a row is cheap, since the method + * will check first + */ + clutter_actor_realize (CLUTTER_ACTOR (stage)); } else CLUTTER_NOTE (MULTISTAGE, "Setting the new stage [%p]", stage); diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index 8780b2d67..3087dc260 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -275,8 +275,9 @@ clutter_stage_realize (ClutterActor *self) ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; /* 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); @@ -286,7 +287,10 @@ clutter_stage_realize (ClutterActor *self) * 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); } @@ -582,8 +586,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; } @@ -847,6 +852,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; diff --git a/clutter/glx/clutter-backend-glx.c b/clutter/glx/clutter-backend-glx.c index 41f00b159..7ddc1ad6e 100644 --- a/clutter/glx/clutter-backend-glx.c +++ b/clutter/glx/clutter-backend-glx.c @@ -483,10 +483,13 @@ 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; } From 0acb98e987f456d67db11f85ccca909d67922362 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 11 May 2009 12:43:56 +0100 Subject: [PATCH 038/138] [actor] Conditionally verify the map state The verify_map_state() internal method is conditionally compiled if we have CLUTTER_ENABLE_DEBUG set; for this reason, all calls to that method should be made conditional. --- clutter/clutter-actor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index ef6d0d662..59e80df03 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -709,7 +709,6 @@ clutter_actor_update_map_state (ClutterActor *self, gboolean may_be_realized; gboolean must_be_realized; - should_be_mapped = FALSE; may_be_realized = TRUE; must_be_realized = FALSE; @@ -832,8 +831,10 @@ clutter_actor_update_map_state (ClutterActor *self, } } +#ifdef CLUTTER_ENABLE_DEBUG /* check all invariants were kept */ clutter_actor_verify_map_state (self); +#endif } static void From 9582fddb24fba071ea77aa2396aa5288639c3217 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 11 May 2009 12:39:46 +0100 Subject: [PATCH 039/138] [x11] Do not needlessly check XVisualInfo Since we are destroying any previously set VisualInfo we keep we know for sure that stage->xvisinfo is going to be None; hence, no reason to check this condition. --- clutter/glx/clutter-stage-glx.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/clutter/glx/clutter-stage-glx.c b/clutter/glx/clutter-stage-glx.c index 650cf9445..9616f9371 100644 --- a/clutter/glx/clutter-stage-glx.c +++ b/clutter/glx/clutter-stage-glx.c @@ -126,25 +126,23 @@ clutter_stage_glx_realize (ClutterActor *actor) { GLX_RGBA, GLX_DOUBLEBUFFER, - GLX_RED_SIZE, 1, - GLX_GREEN_SIZE, 1, - GLX_BLUE_SIZE, 1, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, GLX_STENCIL_SIZE, 1, 0 }; - if (stage_x11->xvisinfo) + if (stage_x11->xvisinfo != None) { XFree (stage_x11->xvisinfo); stage_x11->xvisinfo = None; } - /* The following check seems strange */ + stage_x11->xvisinfo = glXChooseVisual (stage_x11->xdpy, + stage_x11->xscreen, + gl_attributes); 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; From d19f6feb45cfedfedda997967954ea892c4cfb92 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 11 May 2009 12:43:37 +0100 Subject: [PATCH 040/138] [stage] Chain up ::show before showing the implementation When showing a Stage for the first time we end up realizing the stage implementation before realizing the wrapper. This leads to segmentation faults or errors coming from the backend because we're fumbling the state and realization sequence. --- clutter/clutter-stage.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index 3087dc260..22e891ad4 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -312,11 +312,11 @@ clutter_stage_show (ClutterActor *self) { ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; + CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->show (self); + g_assert (priv->impl != NULL); clutter_actor_show (priv->impl); - - CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->show (self); } static void @@ -324,10 +324,10 @@ clutter_stage_hide (ClutterActor *self) { ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; + CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->hide (self); + g_assert (priv->impl != NULL); clutter_actor_hide (priv->impl); - - CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->hide (self); } static void From 8b7c6955de2c09c1f3d9c0e1b349966b6a63062e Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 11 May 2009 12:36:55 +0100 Subject: [PATCH 041/138] [backend] Unset the current stage if it is unrealized This commit reverts part of commit 5bcde25c - specifically the part that forced a realization of the stage if we are ensuring the GL context with it. This makes Clutter behave like it did prior to commit 5bcde25c: if we are asked to ensure the GL context with an unrealized stage we simply pass NULL to the backend implementation. --- clutter/clutter-backend.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/clutter/clutter-backend.c b/clutter/clutter-backend.c index 90e4ad2a3..d827719bc 100644 --- a/clutter/clutter-backend.c +++ b/clutter/clutter-backend.c @@ -312,32 +312,35 @@ _clutter_backend_ensure_context (ClutterBackend *backend, if (current_context_stage != stage || !CLUTTER_ACTOR_IS_REALIZED (stage)) { + ClutterStage *new_stage = NULL; + if (!CLUTTER_ACTOR_IS_REALIZED (stage)) { - CLUTTER_NOTE (MULTISTAGE, - "Stage [%p] is not realized, realizing", - stage); + new_stage = NULL; - /* if we are asked to ensure a particular stage we need - * to make sure that is has been realized; calling - * realized() twice in a row is cheap, since the method - * will check first - */ - clutter_actor_realize (CLUTTER_ACTOR (stage)); + 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 From 0b7e459d481d84683adf65b8ea6c0c5502aa97c0 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 11 May 2009 12:36:14 +0100 Subject: [PATCH 042/138] Add more debugging notes --- clutter/clutter-actor.c | 5 +++++ clutter/glx/clutter-stage-glx.c | 4 +++- clutter/x11/clutter-stage-x11.c | 14 ++++++++------ 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 59e80df03..9320c7361 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -1166,6 +1166,11 @@ clutter_actor_realize (ClutterActor *self) 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"); diff --git a/clutter/glx/clutter-stage-glx.c b/clutter/glx/clutter-stage-glx.c index 9616f9371..f8d2d4987 100644 --- a/clutter/glx/clutter-stage-glx.c +++ b/clutter/glx/clutter-stage-glx.c @@ -113,7 +113,9 @@ clutter_stage_glx_realize (ClutterActor *actor) 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); diff --git a/clutter/x11/clutter-stage-x11.c b/clutter/x11/clutter-stage-x11.c index 9aff476a6..af2f87620 100644 --- a/clutter/x11/clutter-stage-x11.c +++ b/clutter/x11/clutter-stage-x11.c @@ -757,11 +757,12 @@ clutter_x11_set_stage_foreign (ClutterStage *stage, void clutter_stage_x11_map (ClutterStageX11 *stage_x11) { - /* set the mapped state on the wrapper */ - clutter_actor_map (CLUTTER_ACTOR (stage_x11->wrapper)); + CLUTTER_NOTE (BACKEND, "Mapping stage '%s' [%p]", + G_OBJECT_TYPE_NAME (stage_x11), + stage_x11); - /* and on the implementation second */ clutter_actor_map (CLUTTER_ACTOR (stage_x11)); + clutter_actor_map (CLUTTER_ACTOR (stage_x11->wrapper)); if (stage_x11->fullscreen_on_map) clutter_stage_fullscreen (CLUTTER_STAGE (stage_x11->wrapper)); @@ -774,9 +775,10 @@ clutter_stage_x11_map (ClutterStageX11 *stage_x11) void clutter_stage_x11_unmap (ClutterStageX11 *stage_x11) { - /* like above, unset the MAPPED stage on both the implementation and - * the wrapper, but unmap in reverse order from map - */ + CLUTTER_NOTE (BACKEND, "Unmapping stage '%s' [%p]", + G_OBJECT_TYPE_NAME (stage_x11), + stage_x11); + clutter_actor_unmap (CLUTTER_ACTOR (stage_x11)); clutter_actor_unmap (CLUTTER_ACTOR (stage_x11->wrapper)); } From 4b285e02bc85e92612485b5ebea568b90951be40 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 11 May 2009 18:17:30 +0100 Subject: [PATCH 043/138] [x11] Unset the GL context when re-realizing Setting the stage window using the set_stage_foreign() method will lead to a re-realization. We need to make sure that the Drawable currently associated to the GL context is set to None, to avoid a BadDrawable error or, if we're unlucky, a segfault in the X server. --- clutter/x11/clutter-stage-x11.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/clutter/x11/clutter-stage-x11.c b/clutter/x11/clutter-stage-x11.c index af2f87620..360417dbd 100644 --- a/clutter/x11/clutter-stage-x11.c +++ b/clutter/x11/clutter-stage-x11.c @@ -686,6 +686,12 @@ set_foreign_window_callback (ClutterActor *actor, 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)); } /** @@ -749,7 +755,7 @@ clutter_x11_set_stage_foreign (ClutterStage *stage, set_foreign_window_callback, &fwd); - CLUTTER_SET_PRIVATE_FLAGS (actor, CLUTTER_ACTOR_SYNC_MATRICES); + clutter_stage_ensure_viewport (stage); return TRUE; } From dd95939d260e19bac8119d430ff3d9b9279c0234 Mon Sep 17 00:00:00 2001 From: Raymond Liu Date: Thu, 7 May 2009 18:20:19 +0800 Subject: [PATCH 044/138] Emit key focus signal when stage state changes When the stage state changes between active/deactive, send out key-focus-in/key-focus-out signal for the current key focused actor on the stage. Fixes bug: http://bugzilla.openedhand.com/show_bug.cgi?id=1503 Signed-off-by: Emmanuele Bassi --- clutter/clutter-stage.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index 22e891ad4..3d9dd5b3b 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -330,6 +330,33 @@ clutter_stage_hide (ClutterActor *self) clutter_actor_hide (priv->impl); } +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) { @@ -822,6 +849,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)); } From e59a19bd03964aacfa64479fdb51555350992989 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 13 May 2009 21:49:45 +0100 Subject: [PATCH 045/138] [x11] Abstract XVisualInfo creation The XVisualInfo for GL is created when a stage is being realized. When embedding Clutter inside another toolkit we might not want to realize a stage to extract the XVisualInfo, then set the stage window using a foreign X Window -- which will cause a re-realization. Instead, we should abstract as much as possible into the X11 backend. Unfortunately, the XVisualInfo for GL is requested using GLX API; for this reason we have to create a ClutterBackendX11 method that we override inside the ClutterBackendGLX implementation. This also allows us to move a little bit of complexity from out of the stage realization, which is currently a very delicate and hard to debug section. --- clutter/glx/clutter-backend-glx.c | 67 ++++++++++++++++++++++++++++--- clutter/glx/clutter-stage-glx.c | 44 +++++--------------- clutter/x11/clutter-backend-x11.c | 14 +++++++ clutter/x11/clutter-backend-x11.h | 7 ++++ clutter/x11/clutter-stage-x11.c | 16 +++++++- 5 files changed, 107 insertions(+), 41 deletions(-) diff --git a/clutter/glx/clutter-backend-glx.c b/clutter/glx/clutter-backend-glx.c index 7ddc1ad6e..c255aeacc 100644 --- a/clutter/glx/clutter-backend-glx.c +++ b/clutter/glx/clutter-backend-glx.c @@ -434,8 +434,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,18 +448,23 @@ 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 (); } } @@ -494,11 +502,56 @@ clutter_backend_glx_create_stage (ClutterBackend *backend, 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; @@ -511,6 +564,8 @@ clutter_backend_glx_class_init (ClutterBackendGLXClass *klass) backend_class->get_features = clutter_backend_glx_get_features; backend_class->redraw = clutter_backend_glx_redraw; 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-stage-glx.c b/clutter/glx/clutter-stage-glx.c index f8d2d4987..fb47ae9da 100644 --- a/clutter/glx/clutter-stage-glx.c +++ b/clutter/glx/clutter-stage-glx.c @@ -124,26 +124,14 @@ clutter_stage_glx_realize (ClutterActor *actor) 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 - }; - if (stage_x11->xvisinfo != None) { XFree (stage_x11->xvisinfo); stage_x11->xvisinfo = None; } - stage_x11->xvisinfo = glXChooseVisual (stage_x11->xdpy, - stage_x11->xscreen, - gl_attributes); + stage_x11->xvisinfo = + clutter_backend_x11_get_visual_info (backend_x11, FALSE); if (stage_x11->xvisinfo == None) { g_critical ("Unable to find suitable GL visual."); @@ -232,27 +220,15 @@ 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 - }; + if (stage_x11->xvisinfo != None) + { + XFree (stage_x11->xvisinfo); + stage_x11->xvisinfo = None; + } - if (stage_x11->xvisinfo) - XFree (stage_x11->xvisinfo); - - stage_x11->xvisinfo = NULL; - - CLUTTER_NOTE (GL, "glXChooseVisual"); - stage_x11->xvisinfo = glXChooseVisual (stage_x11->xdpy, - stage_x11->xscreen, - gl_attributes); - if (!stage_x11->xvisinfo) + stage_x11->xvisinfo = + clutter_backend_x11_get_visual_info (backend_x11, TRUE); + if (stage_x11->xvisinfo == None) { g_critical ("Unable to find suitable GL visual."); goto fail; diff --git a/clutter/x11/clutter-backend-x11.c b/clutter/x11/clutter-backend-x11.c index 28fe3e825..d5537c206 100644 --- a/clutter/x11/clutter-backend-x11.c +++ b/clutter/x11/clutter-backend-x11.c @@ -969,3 +969,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..4f75359c8 100644 --- a/clutter/x11/clutter-backend-x11.h +++ b/clutter/x11/clutter-backend-x11.h @@ -90,6 +90,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,6 +123,10 @@ clutter_backend_x11_add_options (ClutterBackend *backend, ClutterFeatureFlags clutter_backend_x11_get_features (ClutterBackend *backend); +XVisualInfo * +clutter_backend_x11_get_visual_info (ClutterBackendX11 *backend_x11, + gboolean for_offscreen); + #ifdef USE_XINPUT void _clutter_x11_register_xinput (void); diff --git a/clutter/x11/clutter-stage-x11.c b/clutter/x11/clutter-stage-x11.c index 360417dbd..dc6277e9e 100644 --- a/clutter/x11/clutter-stage-x11.c +++ b/clutter/x11/clutter-stage-x11.c @@ -656,13 +656,27 @@ 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 { From 1d7a79f343760d192619629de8e1ca9547007c13 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 13 May 2009 22:20:19 +0100 Subject: [PATCH 046/138] Update the redraw priority The master clock is using the redraw priority to create the source that will be used to spin the paint sequence if something is being animated using a timeline. Unfortunately, the priority is too high and this causes starvation when embedding into other toolkits -- like gtk+. Thanks to Havoc Pennington for catching this. --- clutter/clutter-main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clutter/clutter-main.h b/clutter/clutter-main.h index f45cda0f3..43f345592 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: From aa1246e8917f0977bd03b97c206d4c2a01ff8599 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 13 May 2009 22:21:48 +0100 Subject: [PATCH 047/138] [backend] Abstract the GL context creation This is the another step into abstracting the backend operations that are currently spread all across the board back into the backend implementations where they belong. The GL context creation, for instance, is demanded to the stage realization which makes it a critical path for every operation that is GL-context bound. This usually does not make any difference since we realize the default stage, but at some point we might start looking into avoiding the default stage realization in order to make the Clutter startup faster. It also makes the code maintainable because every part is self contained and can be reworked with the minimum amount of pain. --- clutter/clutter-backend.c | 16 +++++++ clutter/clutter-backend.h | 3 ++ clutter/clutter-private.h | 3 ++ clutter/glx/clutter-backend-glx.c | 54 +++++++++++++++++++++- clutter/glx/clutter-stage-glx.c | 76 ++++++++++++++----------------- 5 files changed, 110 insertions(+), 42 deletions(-) diff --git a/clutter/clutter-backend.c b/clutter/clutter-backend.c index d827719bc..e423edb21 100644 --- a/clutter/clutter-backend.c +++ b/clutter/clutter-backend.c @@ -300,6 +300,22 @@ _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) 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-private.h b/clutter/clutter-private.h index 30870ee62..fe0c9b39a 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -184,6 +184,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); diff --git a/clutter/glx/clutter-backend-glx.c b/clutter/glx/clutter-backend-glx.c index c255aeacc..edad15894 100644 --- a/clutter/glx/clutter-backend-glx.c +++ b/clutter/glx/clutter-backend-glx.c @@ -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) @@ -469,7 +520,7 @@ clutter_backend_glx_redraw (ClutterBackend *backend, } } -static ClutterActor* +static ClutterActor * clutter_backend_glx_create_stage (ClutterBackend *backend, ClutterStage *wrapper, GError **error) @@ -563,6 +614,7 @@ 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; diff --git a/clutter/glx/clutter-stage-glx.c b/clutter/glx/clutter-stage-glx.c index fb47ae9da..7e139e777 100644 --- a/clutter/glx/clutter-stage-glx.c +++ b/clutter/glx/clutter-stage-glx.c @@ -97,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 (); @@ -109,6 +115,7 @@ 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; @@ -119,19 +126,17 @@ clutter_stage_glx_realize (ClutterActor *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)) { - if (stage_x11->xvisinfo != None) - { - XFree (stage_x11->xvisinfo); - stage_x11->xvisinfo = None; - } + GError *error; stage_x11->xvisinfo = clutter_backend_x11_get_visual_info (backend_x11, FALSE); + if (stage_x11->xvisinfo == None) { g_critical ("Unable to find suitable GL visual."); @@ -197,22 +202,14 @@ clutter_stage_glx_realize (ClutterActor *actor) clutter_stage_x11_fix_window_size (stage_x11); 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"); @@ -220,6 +217,8 @@ clutter_stage_glx_realize (ClutterActor *actor) } else { + GError *error; + if (stage_x11->xvisinfo != None) { XFree (stage_x11->xvisinfo); @@ -228,13 +227,13 @@ clutter_stage_glx_realize (ClutterActor *actor) stage_x11->xvisinfo = clutter_backend_x11_get_visual_info (backend_x11, TRUE); + 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, @@ -246,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"); From 3428e4dd1d1f852521efbc4b1590370b050173b1 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 20 May 2009 17:26:39 +0100 Subject: [PATCH 048/138] [actor] Do not try to dereference NULL data If the shader_data bound to an Actor is NULL we should not try to access its members. --- clutter/clutter-actor.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 9320c7361..2927e898f 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -7761,7 +7761,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; } @@ -7788,7 +7788,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; @@ -7800,6 +7800,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. * @@ -7817,20 +7818,22 @@ 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); + return TRUE; } actor_priv = self->priv; shader_data = actor_priv->shader_data; - if (shader_data != NULL) + 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, @@ -7841,8 +7844,7 @@ clutter_actor_set_shader (ClutterActor *self, shader_data->shader = shader; - if (CLUTTER_ACTOR_IS_VISIBLE (self)) - clutter_actor_queue_redraw (self); + clutter_actor_queue_redraw (self); return TRUE; } From 1985fa75b1929b005d4b5ff46d62ae840f62f38d Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 20 May 2009 17:38:58 +0100 Subject: [PATCH 049/138] [texture] Use a box instead of int coordinates Most of the operations involving the texture's allocated area require floats -- either for computations or for setting the geometry into COGL. So it doesn't make any sense to use get_allocation_coords() and cast everything to floats. --- clutter/clutter-texture.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/clutter/clutter-texture.c b/clutter/clutter-texture.c index 65501d2d4..083b4bbef 100644 --- a/clutter/clutter-texture.c +++ b/clutter/clutter-texture.c @@ -514,7 +514,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); @@ -620,28 +620,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); } From 085be4cebc6f021d8deb114e7984fdfc49665f40 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 21 May 2009 12:09:16 +0100 Subject: [PATCH 050/138] [cogl-pango-render] Fix the positioning when calling cogl_pango_render_layout When a position is given to cogl_pango_render_layout_subpixel it translates the GL matrix by the coordinates. However it was not dividing by PANGO_SCALE so the coordinates were completely wrong. --- clutter/pango/cogl-pango-render.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clutter/pango/cogl-pango-render.c b/clutter/pango/cogl-pango-render.c index 91bcbe9f1..a3b5e2e39 100644 --- a/clutter/pango/cogl-pango-render.c +++ b/clutter/pango/cogl-pango-render.c @@ -247,7 +247,7 @@ cogl_pango_render_layout_subpixel (PangoLayout *layout, } cogl_push_matrix (); - cogl_translate (x, y, 0); + cogl_translate (x / (gfloat) PANGO_SCALE, y / (gfloat) PANGO_SCALE, 0); _cogl_pango_display_list_render (display_list, priv->glyph_material, priv->solid_material); From 3fc64dfaa799828c3e0743df60de4255dac58d60 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 21 May 2009 12:17:12 +0100 Subject: [PATCH 051/138] [pango-render] Keep a reference to the first line to detect layout changes In order to cope with the situation where an application renders with a PangoLayout, makes some changes and then renders again with the same layout, CoglPangoRenderer needs to detect that the changes have occured so that it can recreate the display list. This is acheived by keeping a reference to the first line of the layout. When the layout is changed Pango will clear the layout pointer in the first line and create a new line. So if the layout pointer in the line becomes NULL then we know the layout has changed. This trick was suggested by Behdad Esfahbod in this email: http://mail.gnome.org/archives/gtk-i18n-list/2009-May/msg00019.html --- clutter/pango/cogl-pango-render.c | 81 +++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 14 deletions(-) diff --git a/clutter/pango/cogl-pango-render.c b/clutter/pango/cogl-pango-render.c index a3b5e2e39..99dd40d3f 100644 --- a/clutter/pango/cogl-pango-render.c +++ b/clutter/pango/cogl-pango-render.c @@ -65,6 +65,19 @@ struct _CoglPangoRendererClass PangoRendererClass class_instance; }; +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 +{ + /* 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, CoglPangoGlyphCacheValue *cache_value, @@ -192,7 +205,7 @@ cogl_pango_get_renderer_from_context (PangoContext *context) } static GQuark -cogl_pango_render_get_display_list_key (void) +cogl_pango_render_get_qdata_key (void) { static GQuark key = 0; @@ -202,6 +215,16 @@ cogl_pango_render_get_display_list_key (void) 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 @@ -221,37 +244,67 @@ cogl_pango_render_layout_subpixel (PangoLayout *layout, const CoglColor *color, int flags) { - PangoContext *context; - CoglPangoRenderer *priv; - CoglPangoDisplayList *display_list; + 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; - display_list = g_object_get_qdata (G_OBJECT (layout), - cogl_pango_render_get_display_list_key ()); + qdata = g_object_get_qdata (G_OBJECT (layout), + cogl_pango_render_get_qdata_key ()); - if (display_list == NULL) + if (qdata == NULL) { - priv->display_list = display_list =_cogl_pango_display_list_new (); - priv->color = *color; + qdata = g_slice_new0 (CoglPangoRendererQdata); g_object_set_qdata_full (G_OBJECT (layout), - cogl_pango_render_get_display_list_key (), - display_list, - (GDestroyNotify) _cogl_pango_display_list_free); - pango_renderer_draw_layout (PANGO_RENDERER (priv), layout, 0, 0); + 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 (display_list, + _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); + } } /** From 7e18109f9bec0afba900534a9c96035ae1f32dd7 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 21 May 2009 15:49:14 +0100 Subject: [PATCH 052/138] [cogl-pango-display-list] Use GL_TRIANGLES under GLES GLES doesn't support GL_QUADS. This patch makes it use GL_TRIANGLES instead in that case. Unfortunately this means submitting two extra vertices per quad. It could be better to use indexed elements once CoglVertexBuffers gains support for that. --- clutter/pango/cogl-pango-display-list.c | 28 ++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/clutter/pango/cogl-pango-display-list.c b/clutter/pango/cogl-pango-display-list.c index ecef23f58..b87b609f9 100644 --- a/clutter/pango/cogl-pango-display-list.c +++ b/clutter/pango/cogl-pango-display-list.c @@ -41,6 +41,13 @@ typedef enum typedef struct _CoglPangoDisplayListNode CoglPangoDisplayListNode; typedef struct _CoglPangoDisplayListVertex CoglPangoDisplayListVertex; +#ifdef HAVE_CLUTTER_GLX +#define COGL_PANGO_DISPLAY_LIST_DRAW_MODE GL_QUADS +#else +/* GLES doesn't support GL_QUADS so we use GL_TRIANGLES instead */ +#define COGL_PANGO_DISPLAY_LIST_DRAW_MODE GL_TRIANGLES +#endif + struct _CoglPangoDisplayList { CoglColor color; @@ -177,6 +184,24 @@ _cogl_pango_display_list_add_texture (CoglPangoDisplayList *dl, verts->y = y_1; verts->t_x = tx_2; verts->t_y = ty_1; + +#ifndef HAVE_CLUTTER_GLX + + /* GLES doesn't support GL_QUADS so we use GL_TRIANGLES instead with + two extra vertices per quad. FIXME: It might be better to use + indexed elements here but cogl vertex buffers don't currently + support storing the indices */ + + g_array_set_size (node->d.texture.verts, + node->d.texture.verts->len + 2); + verts = &g_array_index (node->d.texture.verts, + CoglPangoDisplayListVertex, + node->d.texture.verts->len - 6); + + verts[4] = verts[0]; + verts[5] = verts[2]; + +#endif /* HAVE_CLUTTER_GLX */ } void @@ -246,7 +271,8 @@ _cogl_pango_display_list_render_texture (CoglHandle material, } cogl_vertex_buffer_draw (node->d.texture.vertex_buffer, - GL_QUADS, 0, node->d.texture.verts->len); + COGL_PANGO_DISPLAY_LIST_DRAW_MODE, + 0, node->d.texture.verts->len); } void From 309f680d323f25a83f0a529e499f84f301708e79 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 22 May 2009 01:23:29 +0100 Subject: [PATCH 053/138] [texture] size-change closure is now VOID:FLOAT,FLOAT Now that everything is float, the marsharlling function of the size-change signal should reflect that fact. Signed-off-by: Emmanuele Bassi --- clutter/clutter-marshal.list | 1 + clutter/clutter-texture.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/clutter/clutter-marshal.list b/clutter/clutter-marshal.list index d68ce4b27..995c5c712 100644 --- a/clutter/clutter-marshal.list +++ b/clutter/clutter-marshal.list @@ -6,6 +6,7 @@ VOID:BOXED 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-texture.c b/clutter/clutter-texture.c index 083b4bbef..55d3fda24 100644 --- a/clutter/clutter-texture.c +++ b/clutter/clutter-texture.c @@ -1096,9 +1096,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 From 5cde6a598f7b846615b817002389fcae954f612a Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Sat, 23 May 2009 19:32:24 +0100 Subject: [PATCH 054/138] [git ignore] Add test-text-perf --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 43c6e2473..895779f82 100644 --- a/.gitignore +++ b/.gitignore @@ -196,7 +196,7 @@ stamp-h1 /tests/conform/test-map-recursive /tests/conform/test-realize-not-recursive /tests/conform/test-shown-not-parented -/tests/micro-bench/test-glyph-perf +/tests/micro-bench/test-text-perf /tests/micro-bench/test-text /tests/micro-bench/test-picking /tests/tools/disable-npots.sh From 87465355d3415a28fc6b3e4f62611cc3192516d8 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 30 Mar 2009 13:49:03 +0100 Subject: [PATCH 055/138] Add repaint functions Sometimes it is necessary for third party code to have a function called during the redraw process, so that you can update the scenegraph before it is painted. --- clutter/clutter-main.c | 159 ++++++++++++++++++++++++++++++++++++++ clutter/clutter-main.h | 62 ++++++++------- clutter/clutter-private.h | 4 + clutter/clutter-stage.c | 9 ++- 4 files changed, 203 insertions(+), 31 deletions(-) diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c index 922b5fb0e..b5f5c3785 100644 --- a/clutter/clutter-main.c +++ b/clutter/clutter-main.c @@ -2816,3 +2816,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 43f345592..a5365f0d9 100644 --- a/clutter/clutter-main.h +++ b/clutter/clutter-main.h @@ -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 handler_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-private.h b/clutter/clutter-private.h index fe0c9b39a..6b62cee48 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -132,6 +132,8 @@ struct _ClutterMainContext ClutterMasterClock *master_clock; gulong redraw_count; + + GList *repaint_funcs; }; #define CLUTTER_CONTEXT() (clutter_context_get_default ()) @@ -238,6 +240,8 @@ void _clutter_actor_set_enable_model_view_transform (ClutterActor *self, 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-stage.c b/clutter/clutter-stage.c index 86d22c569..c6f736e4e 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -403,6 +403,12 @@ redraw_update_idle (gpointer user_data) 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() @@ -457,8 +463,7 @@ static void set_offscreen_while_unrealized (ClutterActor *actor, void *data) { - CLUTTER_STAGE (actor)->priv->is_offscreen = - GPOINTER_TO_INT (data); + CLUTTER_STAGE (actor)->priv->is_offscreen = GPOINTER_TO_INT (data); } static void From 71498a6376f3c45e6fec228251ec11b9c2dc4cd1 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Sat, 23 May 2009 19:18:18 +0100 Subject: [PATCH 056/138] [cogl] Remove max_waste argument from Texture ctors The CoglTexture constructors expose the "max-waste" argument for controlling the maximum amount of wasted areas for slicing or, if set to -1, disables slicing. Slicing is really relevant only for large images that are never repeated, so it's a useful feature only in controlled use cases. Specifying the amount of wasted area is, on the other hand, just a way to mess up this feature; 99% the times, you either pull this number out of thin air, hoping it's right, or you try to do the right thing and you choose the wrong number anyway. Instead, we can use the CoglTextureFlags to control whether the texture should not be sliced (useful for Clutter-GST and for the texture-from-pixmap actors) and provide a reasonable value for enabling the slicing ourself. At some point, we might even provide a way to change the default at compile time or at run time, for particular platforms. Since max_waste is gone, the :tile-waste property of ClutterTexture becomes read-only, and it proxies the cogl_texture_get_max_waste() function. Inside Clutter, the only cases where the max_waste argument was not set to -1 are in the Pango glyph cache (which is a POT texture anyway) and inside the test cases where we want to force slicing; for the latter we can create larger textures that will be bigger than the threshold we set. Signed-off-by: Emmanuele Bassi Signed-off-by: Robert Bragg Signed-off-by: Neil Roberts --- clutter/clutter-texture.c | 116 +++++------------- clutter/clutter-texture.h | 4 +- clutter/cogl/cogl-texture.h | 34 ++--- clutter/cogl/cogl-types.h | 4 +- clutter/cogl/common/cogl-util.c | 1 + clutter/cogl/gl/cogl-context.c | 6 +- clutter/cogl/gl/cogl-texture.c | 81 ++++++------ clutter/cogl/gles/cogl-context.c | 6 +- clutter/cogl/gles/cogl-texture.c | 60 +++++---- clutter/glx/clutter-glx-texture-pixmap.c | 2 +- clutter/pango/cogl-pango-glyph-cache.c | 2 +- tests/conform/test-backface-culling.c | 36 +++--- tests/conform/test-npot-texture.c | 28 +++-- tests/conform/test-vertex-buffer-contiguous.c | 3 +- tests/interactive/test-clip.c | 2 +- tests/interactive/test-cogl-multitexture.c | 18 +-- tests/interactive/test-cogl-offscreen.c | 4 +- tests/interactive/test-cogl-tex-convert.c | 8 +- tests/interactive/test-cogl-tex-getset.c | 4 +- tests/interactive/test-cogl-tex-polygon.c | 6 +- tests/interactive/test-cogl-tex-tile.c | 2 +- 21 files changed, 191 insertions(+), 236 deletions(-) diff --git a/clutter/clutter-texture.c b/clutter/clutter-texture.c index 55d3fda24..2321f6304 100644 --- a/clutter/clutter-texture.c +++ b/clutter/clutter-texture.c @@ -79,7 +79,6 @@ struct _ClutterTexturePrivate { gfloat width; gfloat height; - gint max_tile_waste; ClutterTextureQuality filter_quality; CoglHandle material; gboolean no_slice; @@ -136,7 +135,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, @@ -287,20 +286,19 @@ clutter_texture_realize (ClutterActor *actor) { 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->no_slice) + flags |= COGL_TEXTURE_NO_SLICING; if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH) flags |= COGL_TEXTURE_AUTO_MIPMAP; 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); @@ -775,10 +773,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; @@ -860,14 +854,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; @@ -946,6 +940,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, @@ -974,19 +976,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", @@ -1199,7 +1188,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; @@ -1240,10 +1228,9 @@ 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); + /* Store the filter quality from the texture properties so that + * they will be restored the data is loaded again + */ priv->filter_quality = clutter_texture_get_filter_quality (texture); priv->local_data = g_malloc (priv->local_data_rowstride @@ -1478,10 +1465,9 @@ clutter_texture_set_from_data (ClutterTexture *texture, 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; @@ -1491,7 +1477,7 @@ clutter_texture_set_from_data (ClutterTexture *texture, */ new_texture = cogl_texture_new_from_data (width, height, - max_waste, flags, + flags, source_format, COGL_PIXEL_FORMAT_ANY, rowstride, @@ -1669,20 +1655,19 @@ 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->no_slice) + flags |= COGL_TEXTURE_NO_SLICING; if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH) flags |= COGL_TEXTURE_AUTO_MIPMAP; 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) @@ -1915,7 +1900,6 @@ clutter_texture_set_from_file (ClutterTexture *texture, GError *internal_error = NULL; CoglTextureFlags flags = COGL_TEXTURE_NONE; gint min_filter, mag_filter; - gint max_waste = -1; priv = texture->priv; @@ -1924,14 +1908,14 @@ 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->no_slice) + flags |= COGL_TEXTURE_NO_SLICING; if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH) flags |= COGL_TEXTURE_AUTO_MIPMAP; new_texture = cogl_texture_new_from_file (filename, - max_waste, flags, + flags, COGL_PIXEL_FORMAT_ANY, &internal_error); if (new_texture == COGL_INVALID_HANDLE) @@ -2047,40 +2031,6 @@ clutter_texture_get_filter_quality (ClutterTexture *texture) return priv->filter_quality; } -/** - * 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; - - g_return_if_fail (CLUTTER_IS_TEXTURE (texture)); - - 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; -} - /** * clutter_texture_get_max_tile_waste * @texture: A #ClutterTexture @@ -2089,7 +2039,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 */ @@ -2102,13 +2052,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); } @@ -2312,12 +2261,13 @@ on_fbo_source_size_change (GObject *object, priv->width = w; priv->height = h; + flags |= COGL_TEXTURE_NO_SLICING; + if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH) flags |= COGL_TEXTURE_AUTO_MIPMAP; tex = cogl_texture_new_with_size (MAX (priv->width, 1), MAX (priv->height, 1), - -1, flags, COGL_PIXEL_FORMAT_RGBA_8888); 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/cogl/cogl-texture.h b/clutter/cogl/cogl-texture.h index 6a8b00a01..d4cc4e812 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: diff --git a/clutter/cogl/cogl-types.h b/clutter/cogl/cogl-types.h index a4ecd4193..719ecd087 100644 --- a/clutter/cogl/cogl-types.h +++ b/clutter/cogl/cogl-types.h @@ -292,6 +292,7 @@ struct _CoglTextureVertex * @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_SLICING: Disables the slicing of the texture * * Flags to pass to the cogl_texture_new_* family of functions. * @@ -299,7 +300,8 @@ struct _CoglTextureVertex */ typedef enum { COGL_TEXTURE_NONE = 0, - COGL_TEXTURE_AUTO_MIPMAP = 1 << 0 + COGL_TEXTURE_AUTO_MIPMAP = 1 << 0, + COGL_TEXTURE_NO_SLICING = 1 << 1 } CoglTextureFlags; #define COGL_TYPE_TEXTURE_FLAGS (cogl_texture_flags_get_type ()) diff --git a/clutter/cogl/common/cogl-util.c b/clutter/cogl/common/cogl-util.c index d71b9ffd8..2b9ccba27 100644 --- a/clutter/cogl/common/cogl-util.c +++ b/clutter/cogl/common/cogl-util.c @@ -223,6 +223,7 @@ cogl_texture_flags_get_type (void) static const GFlagsValue values[] = { { COGL_TEXTURE_NONE, "COGL_TEXTURE_NONE", "none" }, { COGL_TEXTURE_AUTO_MIPMAP, "COGL_TEXTURE_AUTO_MIPMAP", "auto-mipmap" }, + { COGL_TEXTURE_NO_SLICING, "COGL_TEXTURE_NO_SLICING", "no-slicing" }, { 0, NULL, NULL } }; diff --git a/clutter/cogl/gl/cogl-context.c b/clutter/cogl/gl/cogl-context.c index 986da8aa8..2c17408c2 100644 --- a/clutter/cogl/gl/cogl-context.c +++ b/clutter/cogl/gl/cogl-context.c @@ -146,8 +146,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 +155,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, diff --git a/clutter/cogl/gl/cogl-texture.c b/clutter/cogl/gl/cogl-texture.c index ce2ee11ed..80e428eba 100644 --- a/clutter/cogl/gl/cogl-texture.c +++ b/clutter/cogl/gl/cogl-texture.c @@ -644,10 +644,10 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, } 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 +679,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 +693,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 +827,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; } @@ -1199,11 +1200,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; @@ -1234,7 +1234,11 @@ cogl_texture_new_with_size (guint width, tex->slice_y_spans = NULL; tex->slice_gl_handles = NULL; - tex->max_waste = max_waste; + if (flags & COGL_TEXTURE_NO_SLICING) + tex->max_waste = -1; + else + tex->max_waste = COGL_TEXTURE_MAX_WASTE; + tex->min_filter = COGL_TEXTURE_FILTER_NEAREST; tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST; @@ -1258,7 +1262,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, @@ -1295,7 +1298,11 @@ cogl_texture_new_from_data (guint width, tex->slice_y_spans = NULL; tex->slice_gl_handles = NULL; - tex->max_waste = max_waste; + if (flags & COGL_TEXTURE_NO_SLICING) + tex->max_waste = -1; + else + tex->max_waste = COGL_TEXTURE_MAX_WASTE; + tex->min_filter = COGL_TEXTURE_FILTER_NEAREST; tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST; @@ -1328,10 +1335,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; @@ -1352,7 +1358,11 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle, tex->slice_y_spans = NULL; tex->slice_gl_handles = NULL; - tex->max_waste = max_waste; + if (flags & COGL_TEXTURE_NO_SLICING) + tex->max_waste = -1; + else + tex->max_waste = COGL_TEXTURE_MAX_WASTE; + tex->min_filter = COGL_TEXTURE_FILTER_NEAREST; tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST; @@ -1389,13 +1399,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); @@ -1403,10 +1412,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; @@ -1509,14 +1515,11 @@ 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; diff --git a/clutter/cogl/gles/cogl-context.c b/clutter/cogl/gles/cogl-context.c index d70d59d35..f187c0b88 100644 --- a/clutter/cogl/gles/cogl-context.c +++ b/clutter/cogl/gles/cogl-context.c @@ -107,8 +107,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 +116,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, diff --git a/clutter/cogl/gles/cogl-texture.c b/clutter/cogl/gles/cogl-texture.c index 1564faf2a..8f4cf733e 100644 --- a/clutter/cogl/gles/cogl-texture.c +++ b/clutter/cogl/gles/cogl-texture.c @@ -858,7 +858,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 +867,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 +878,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 +976,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; } @@ -1288,11 +1293,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; @@ -1323,7 +1327,11 @@ cogl_texture_new_with_size (guint width, tex->slice_y_spans = NULL; tex->slice_gl_handles = NULL; - tex->max_waste = max_waste; + if (flags & COGL_TEXTURE_NO_SLICING) + tex->max_waste = -1; + else + tex->max_waste = COGL_TEXTURE_MAX_WASTE; + tex->min_filter = CGL_NEAREST; tex->mag_filter = CGL_NEAREST; @@ -1347,7 +1355,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, @@ -1384,7 +1391,11 @@ cogl_texture_new_from_data (guint width, tex->slice_y_spans = NULL; tex->slice_gl_handles = NULL; - tex->max_waste = max_waste; + if (flags & COGL_TEXTURE_NO_SLICING) + tex->max_waste = -1; + else + tex->max_waste = COGL_TEXTURE_MAX_WASTE; + tex->min_filter = CGL_NEAREST; tex->mag_filter = CGL_NEAREST; @@ -1417,10 +1428,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; @@ -1439,7 +1449,11 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle, tex->slice_y_spans = NULL; tex->slice_gl_handles = NULL; - tex->max_waste = max_waste; + if (flags & COGL_TEXTURE_NO_SLICING) + tex->max_waste = -1; + else + tex->max_waste = COGL_TEXTURE_MAX_WASTE; + tex->min_filter = CGL_NEAREST; tex->mag_filter = CGL_NEAREST; @@ -1476,7 +1490,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 +1503,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; diff --git a/clutter/glx/clutter-glx-texture-pixmap.c b/clutter/glx/clutter-glx-texture-pixmap.c index c1a02206e..3c8393df6 100644 --- a/clutter/glx/clutter-glx-texture-pixmap.c +++ b/clutter/glx/clutter-glx-texture-pixmap.c @@ -360,7 +360,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/pango/cogl-pango-glyph-cache.c b/clutter/pango/cogl-pango-glyph-cache.c index 892255623..9be1e83b8 100644 --- a/clutter/pango/cogl-pango-glyph-cache.c +++ b/clutter/pango/cogl-pango-glyph-cache.c @@ -297,7 +297,7 @@ cogl_pango_glyph_cache_set (CoglPangoGlyphCache *cache, texture->texture = cogl_texture_new_from_data (texture->texture_size, texture->texture_size, - 32, flags, + flags, COGL_PIXEL_FORMAT_A_8, COGL_PIXEL_FORMAT_A_8, texture->texture_size, diff --git a/tests/conform/test-backface-culling.c b/tests/conform/test-backface-culling.c index 034dcb70a..00f36bfba 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)) @@ -114,7 +117,7 @@ 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]; memset (verts, 0, sizeof (verts)); @@ -124,21 +127,21 @@ on_paint (ClutterActor *actor, TestState *state) 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_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_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; @@ -153,7 +156,7 @@ on_paint (ClutterActor *actor, TestState *state) 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; @@ -168,7 +171,7 @@ on_paint (ClutterActor *actor, TestState *state) 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,7 +179,7 @@ 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_translate (0, TEXTURE_RENDER_SIZE, 0); cogl_enable_backface_culling (FALSE); } @@ -221,7 +224,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-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-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-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-cogl-multitexture.c b/tests/interactive/test-cogl-multitexture.c index a45b4f965..cddf2b4ca 100644 --- a/tests/interactive/test-cogl-multitexture.c +++ b/tests/interactive/test-cogl-multitexture.c @@ -86,21 +86,21 @@ 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_TEXTURE_AUTO_MIPMAP, 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_TEXTURE_AUTO_MIPMAP, 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_TEXTURE_AUTO_MIPMAP, COGL_PIXEL_FORMAT_ANY, NULL); 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-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..540d832a4 100644 --- a/tests/interactive/test-cogl-tex-polygon.c +++ b/tests/interactive/test-cogl-tex-polygon.c @@ -248,7 +248,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 +265,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) diff --git a/tests/interactive/test-cogl-tex-tile.c b/tests/interactive/test-cogl-tex-tile.c index 1402d2e28..0325add6a 100644 --- a/tests/interactive/test-cogl-tex-tile.c +++ b/tests/interactive/test-cogl-tex-tile.c @@ -143,7 +143,7 @@ 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); From ec374c7ab9d5b98230a90a4be7b8ca6f5337f2b8 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 25 May 2009 12:41:16 +0100 Subject: [PATCH 057/138] [build] Clean up cogl-pango Makefile --- clutter/pango/Makefile.am | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/clutter/pango/Makefile.am b/clutter/pango/Makefile.am index e567e3ba2..97e180d6d 100644 --- a/clutter/pango/Makefile.am +++ b/clutter/pango/Makefile.am @@ -13,21 +13,21 @@ source_h_priv = \ 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) From b05d4be19d07a834120bac6bbeacca31daae51b9 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 25 May 2009 12:42:17 +0100 Subject: [PATCH 058/138] Use GLib variant of strcasecmp() The GLib version of strcasecmp() ignores any non-ASCII character, unlike the original which is locale-dependent. --- clutter/glx/clutter-backend-glx.c | 2 +- clutter/glx/clutter-glx-texture-pixmap.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clutter/glx/clutter-backend-glx.c b/clutter/glx/clutter-backend-glx.c index edad15894..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; diff --git a/clutter/glx/clutter-glx-texture-pixmap.c b/clutter/glx/clutter-glx-texture-pixmap.c index 3c8393df6..b6a677a84 100644 --- a/clutter/glx/clutter-glx-texture-pixmap.c +++ b/clutter/glx/clutter-glx-texture-pixmap.c @@ -214,9 +214,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, " From 0d1c626a86fdec432d5bb7ca78aec76ec1fecf7e Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 25 May 2009 14:04:53 +0100 Subject: [PATCH 059/138] [build] Spring cleanup of configure.ac Let's try to bring configure.ac into this century, shall we? * Use the proper shell macros AS_IF and AS_CASE instead of if...fi and case...esac * Check for X11 and relative extensions only when building for GLX and EGLX backends * Add documentation on the behaviour of binary_age and interface_age * Coalesce all the common checks to avoid redundancy * Escape everything that requires escaping --- configure.ac | 1059 +++++++++++++++++++++++++------------------------- 1 file changed, 535 insertions(+), 524 deletions(-) diff --git a/configure.ac b/configure.ac index 9c421a941..f61da5352 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,260 @@ 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) + if test "x$HAVE_LIBGLES" = "xno" + then + AC_CHECK_LIB(GLESv1_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 + if test "x$HAVE_LIBGLES" = "xno" + then + AC_CHECK_LIB(gles_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 + 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 + else + GLES_LIBS="-lGLES_CM" + fi + ], - 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]) + [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([EGL/egl.h],, - [AC_MSG_ERROR([Unable to locate required GLES headers])]) + AC_CHECK_HEADERS([EGL/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])]) + GLES_LIBS="-lGLESv2 -lEGL" + ], - GLES_LIBS="-lGLESv2 -lEGL" + [fruity], + [ + clutter_gl_header="GLES/gl.h" + CLUTTER_COGL="gles" + AC_DEFINE([HAVE_COGL_GLES], 1, [Have GL/ES for rendering]) - use_gles2_wrapper=yes - ;; - fruity) - 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])]) + ], - clutter_gl_header="GLES/gl.h" - CLUTTER_COGL="gles" - AC_DEFINE([HAVE_COGL_GLES], 1, [Have GL/ES for rendering]) + [AC_MSG_ERROR([Unknown argument for --with-gles])] + ) + ] +) - AC_CHECK_HEADERS([GLES/egl.h],, +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` + + # Use -lopengl32 under Windows instead of -lGL + AS_CASE([$host], + + [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]) + 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 +356,152 @@ 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="" + +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=yes]) + + AS_CASE([$xinput], + + [yes], + [ + AC_DEFINE(USE_XINPUT, 1, Use the XINPUT X extension) + + 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 +512,129 @@ 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") -CLUTTER_REQUIRES="cairo >= 1.4 pangocairo >= 1.18 gobject-2.0 >= 2.16 gthread-2.0 gmodule-no-export-2.0 $BACKEND_PC_FILES $JSON_GLIB_PC" +dnl === Dependencies, compiler flags and linker libraries ===================== -if test "x$imagebackend" = "xgdk-pixbuf"; then - CLUTTER_REQUIRES="$CLUTTER_REQUIRES gdk-pixbuf-2.0" -fi +CLUTTER_REQUIRES="cairo >= 1.4 pangocairo >= 1.18 gobject-2.0 >= 2.16 gthread-2.0 gmodule-no-export-2.0 $IMAGE_PC_FILES $BACKEND_PC_FILES $X11_PC_FILES $JSON_GLIB_PC" 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 -DCOGL_ENABLE_DEBUG" + ], - [no], [COGL_DEBUG_CFLAGS=""], + [minimum], + [CLUTTER_DEBUG_CFLAGS="-DCLUTTER_ENABLE_DEBUG -DCOGL_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 +646,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([ @@ -729,7 +743,7 @@ AC_CONFIG_FILES([ AC_OUTPUT -dnl ======================================================================== +dnl === Summary =============================================================== echo "" echo " Clutter $VERSION" @@ -752,29 +766,26 @@ 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 - - From 733508b80d30a0946061c55e599f1348ea895140 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 25 May 2009 16:52:53 +0100 Subject: [PATCH 060/138] [build] More spring clean fixes * Remove the last if...fi with AS_IF * Put back the regexp for the mingw32 check that commit 0d1c626a inadvertedly removed --- configure.ac | 51 +++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/configure.ac b/configure.ac index f61da5352..ff6c29172 100644 --- a/configure.ac +++ b/configure.ac @@ -121,7 +121,7 @@ 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" = "xeglx" || test "x$clutterbackend" = "xfruity"], [ @@ -141,27 +141,34 @@ AS_IF([test "x$clutterbackend" = "xeglnative" || # 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 - 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_CHECK_LIB(gles_cm, eglInitialize, HAVE_LIBGLES=yes, HAVE_LIBGLES=no) + AS_IF([test "x$HAVE_LIBGLES" = "xyes"], + [GLES_LIBS="-lGLES_CM"], + [ + AC_CHECK_LIB(GLESv1_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 - else - GLES_LIBS="-lGLES_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]) + + AS_IF([test "x$HAVE_LIBGLES" = "xyes"], + [GLES_LIBS="-lgles_cm"], + [ + AC_MSG_ERROR([GLES library not found and egl backend requested.]) + ] + ) + ] + ) + ] + ) ], [2*], @@ -217,11 +224,11 @@ AS_CASE([$clutterbackend], SDL_CFLAGS=`$SDL_CONFIG --cflags` SDL_LIBS=`$SDL_CONFIG --libs` - # Use -lopengl32 under Windows instead of -lGL AS_CASE([$host], - [mingw32], + [*mingw32*], [ + # Use -lopengl32 under Windows instead of -lGL SDL_LIBS="$SDL_LIBS -lopengl32" CLUTTER_LT_LDFLAGS="$CLUTTER_LT_LDFLAGS -no-undefined" ], From 387ab4c142c8c3b4708e08be540b279fcda8ffd8 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 25 May 2009 17:16:44 +0100 Subject: [PATCH 061/138] [doap] Update Long overdue update of the DOAP file for Clutter * Repository update * Add authors --- clutter.doap | 61 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 17 deletions(-) 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 + - - - - + + + + From 331d43196da1a76fe5abe138639674b0cb9fbd47 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 26 May 2009 17:23:24 +0100 Subject: [PATCH 062/138] [build] Decouple COGL debug level from Clutter's Using --enable-debug, which controls Clutter's debug level, also defines COGL_ENABLE_DEBUG. This should be left to --enable-cogl-debug instead, since it's the configure switch that controls COGL debug level. --- configure.ac | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index ff6c29172..4524d3df3 100644 --- a/configure.ac +++ b/configure.ac @@ -581,11 +581,11 @@ AS_CASE([$enable_debug], [yes], [ test "$cflags_set" = set || CFLAGS="$CFLAGS -g" - CLUTTER_DEBUG_CFLAGS="-DCLUTTER_ENABLE_DEBUG -DCOGL_ENABLE_DEBUG" + CLUTTER_DEBUG_CFLAGS="-DCLUTTER_ENABLE_DEBUG" ], [minimum], - [CLUTTER_DEBUG_CFLAGS="-DCLUTTER_ENABLE_DEBUG -DCOGL_ENABLE_DEBUG -DG_DISABLE_CAST_CHECKS"], + [CLUTTER_DEBUG_CFLAGS="-DCLUTTER_ENABLE_DEBUG -DG_DISABLE_CAST_CHECKS"], [no], [CLUTTER_DEBUG_CFLAGS="-DG_DISABLE_ASSERT -DG_DISABLE_CHECKS -DG_DISABLE_CAST_CHECKS"], @@ -762,15 +762,15 @@ 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 From 1f44c3584c9040a6745f052ad7ce7ffd9dc399a9 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 27 May 2009 11:52:40 +0100 Subject: [PATCH 063/138] [animation] Defer the timeline handling to the Alpha The Animation should not directly manipulate a Timeline instance, but it should defer to the Alpha all handling of the timeline. This means that: - set_duration() and set_loop() will either create a Timeline or will set the :duration and :loop properties on the Timeline; if the Timeline must be created, and no Alpha instance is available, then a new Alpha instance will be created as well and the newly create Timeline will be assigned to the Alpha - if set_mode() on an Animation instance without an Alpha, the Alpha will be created; a Timeline will also be created - set_alpha() will replace the Alpha; if the new Alpha does not have a Timeline associated then a Timeline will be created using the current :duration and :loop properties of Animation; otherwise, if the replaced Alpha had a timeline, the timeline will be transferred to the new one --- clutter/clutter-animation.c | 350 ++++++++++++++++++++++++------------ 1 file changed, 235 insertions(+), 115 deletions(-) diff --git a/clutter/clutter-animation.c b/clutter/clutter-animation.c index 73dd6ffd0..34056c6d3 100644 --- a/clutter/clutter-animation.c +++ b/clutter/clutter-animation.c @@ -85,16 +85,15 @@ struct _ClutterAnimationPrivate GHashTable *properties; + ClutterAlpha *alpha; + gulong mode; guint loop : 1; guint duration; - ClutterTimeline *timeline; guint timeline_started_id; guint timeline_completed_id; - - ClutterAlpha *alpha; guint alpha_notify_id; }; @@ -122,38 +121,25 @@ static void clutter_animation_dispose (GObject *gobject) { ClutterAnimationPrivate *priv = CLUTTER_ANIMATION (gobject)->priv; + ClutterTimeline *timeline; - if (priv->object) - { - 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) + timeline = clutter_animation_get_timeline (CLUTTER_ANIMATION (gobject)); + if (timeline != NULL) { if (priv->timeline_started_id) { - g_signal_handler_disconnect (priv->timeline, - priv->timeline_started_id); + g_signal_handler_disconnect (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); + g_signal_handler_disconnect (timeline, priv->timeline_completed_id); priv->timeline_completed_id = 0; } - - g_object_unref (priv->timeline); - priv->timeline = NULL; } - if (priv->alpha) + if (priv->alpha != NULL) { if (priv->alpha_notify_id) { @@ -165,6 +151,16 @@ clutter_animation_dispose (GObject *gobject) 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; + } + G_OBJECT_CLASS (clutter_animation_parent_class)->dispose (gobject); } @@ -214,7 +210,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) { @@ -235,11 +232,11 @@ clutter_animation_get_property (GObject *gobject, 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: @@ -794,7 +791,6 @@ 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, @@ -805,8 +801,6 @@ on_alpha_notify (GObject *gobject, } 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); } @@ -819,6 +813,70 @@ 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, priv->mode); + + priv->alpha_notify_id = + g_signal_connect (alpha, "notify::alpha", + G_CALLBACK (on_alpha_notify), + animation); + + priv->alpha = g_object_ref_sink (alpha); + } + + return priv->alpha; +} + +static ClutterTimeline * +clutter_animation_get_timeline_internal (ClutterAnimation *animation) +{ + ClutterAlpha *alpha; + + alpha = clutter_animation_get_alpha_internal (animation); + + return clutter_alpha_get_timeline (alpha); +} + +static inline void +clutter_animation_create_timeline (ClutterAnimation *animation) +{ + ClutterAnimationPrivate *priv = animation->priv; + ClutterTimeline *timeline; + ClutterAlpha *alpha; + + alpha = clutter_animation_get_alpha_internal (animation); + + timeline = g_object_new (CLUTTER_TYPE_TIMELINE, + "duration", priv->duration, + "loop", priv->loop, + NULL); + clutter_alpha_set_timeline (alpha, 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); + + /* since we are creating it ourselves, we can offload + * the ownership of the timeline to the alpha itself + */ + g_object_unref (timeline); +} + /* * Removes the animation pointer from the qdata section of the * actor attached to the animation @@ -926,12 +984,17 @@ clutter_animation_get_object (ClutterAnimation *animation) static inline void clutter_animation_set_mode_internal (ClutterAnimation *animation, - ClutterAlpha *alpha) + gulong mode) { ClutterAnimationPrivate *priv = animation->priv; + ClutterAlpha *alpha; - if (alpha) - clutter_alpha_set_mode (alpha, priv->mode); + priv->mode = mode; + + alpha = clutter_animation_get_alpha_internal (animation); + clutter_alpha_set_mode (alpha, priv->mode); + + g_object_notify (G_OBJECT (animation), "mode"); } /** @@ -949,16 +1012,9 @@ void clutter_animation_set_mode (ClutterAnimation *animation, gulong mode) { - ClutterAnimationPrivate *priv; - g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); - priv = animation->priv; - - priv->mode = mode; - clutter_animation_set_mode_internal (animation, priv->alpha); - - g_object_notify (G_OBJECT (animation), "mode"); + clutter_animation_set_mode_internal (animation, mode); } /** @@ -994,6 +1050,8 @@ clutter_animation_set_duration (ClutterAnimation *animation, gint msecs) { ClutterAnimationPrivate *priv; + ClutterTimeline *timeline; + ClutterAlpha *alpha; g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); @@ -1001,18 +1059,22 @@ clutter_animation_set_duration (ClutterAnimation *animation, priv->duration = msecs; - if (priv->timeline) + alpha = clutter_animation_get_alpha_internal (animation); + timeline = clutter_alpha_get_timeline (alpha); + if (timeline == NULL) + clutter_animation_create_timeline (animation); + else { gboolean was_playing; - was_playing = clutter_timeline_is_playing (priv->timeline); + was_playing = clutter_timeline_is_playing (timeline); if (was_playing) - clutter_timeline_stop (priv->timeline); + clutter_timeline_stop (timeline); - clutter_timeline_set_duration (priv->timeline, msecs); + clutter_timeline_set_duration (timeline, priv->duration); if (was_playing) - clutter_timeline_start (priv->timeline); + clutter_timeline_start (timeline); } g_object_notify (G_OBJECT (animation), "duration"); @@ -1035,20 +1097,26 @@ clutter_animation_set_loop (ClutterAnimation *animation, gboolean loop) { ClutterAnimationPrivate *priv; + ClutterTimeline *timeline; + ClutterAlpha *alpha; g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); priv = animation->priv; - if (priv->loop != loop) - { - priv->loop = loop; + if (priv->loop == loop) + return; - if (priv->timeline) - clutter_timeline_set_loop (priv->timeline, priv->loop); + priv->loop = loop; - g_object_notify (G_OBJECT (animation), "loop"); - } + alpha = clutter_animation_get_alpha_internal (animation); + timeline = clutter_alpha_get_timeline (alpha); + if (timeline == NULL) + clutter_animation_create_timeline (animation); + else + clutter_timeline_set_loop (timeline, priv->loop); + + g_object_notify (G_OBJECT (animation), "loop"); } /** @@ -1109,32 +1177,28 @@ 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) + cur_timeline = clutter_animation_get_timeline_internal (animation); + 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 (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 (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) { @@ -1145,8 +1209,6 @@ clutter_animation_set_timeline (ClutterAnimation *animation, } else { - g_object_ref (timeline); - priv->duration = clutter_timeline_get_duration (timeline); g_object_notify (G_OBJECT (animation), "duration"); @@ -1154,7 +1216,8 @@ clutter_animation_set_timeline (ClutterAnimation *animation, 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"); priv->timeline_started_id = @@ -1184,7 +1247,7 @@ 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); } /** @@ -1195,8 +1258,8 @@ clutter_animation_get_timeline (ClutterAnimation *animation) * 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. + * the current value of the #ClutterAnimation:mode and the current + * #ClutterAnimation:timeline. * * If @alpha is not %NULL, the #ClutterAnimation will take ownership * of the #ClutterAlpha instance. @@ -1208,41 +1271,102 @@ 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; + + /* retrieve the old timeline, if any */ + if (priv->alpha != NULL) { - ClutterTimeline *timeline; + timeline = clutter_alpha_get_timeline (priv->alpha); + if (timeline != NULL) + g_object_ref (timeline); + } + else + timeline = NULL; - timeline = clutter_animation_get_timeline (animation); + if (alpha == NULL) + { + /* this will create a new alpha */ + alpha = clutter_animation_get_alpha_internal (animation); - alpha = clutter_alpha_new (); - clutter_alpha_set_timeline (alpha, timeline); - clutter_animation_set_mode_internal (animation, alpha); + /* if we had a timeline before, we should have the same timeline now */ + if (timeline != NULL) + { + clutter_alpha_set_timeline (alpha, timeline); + g_object_unref (timeline); + } + else + clutter_animation_create_timeline (animation); + } + else + { + if (timeline != NULL) + { + /* if we had a timeline before then we need to disconnect + * the signal handlers from it + */ + if (priv->timeline_started_id != 0) + g_signal_handler_disconnect (timeline, priv->timeline_started_id); + + if (priv->timeline_completed_id != 0) + g_signal_handler_disconnect (timeline, priv->timeline_completed_id); + + /* we don't need this timeline anymore */ + g_object_unref (timeline); + } + + /* 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) + { + g_object_unref (priv->alpha); + priv->alpha = NULL; + } + + priv->alpha = g_object_ref_sink (alpha); + priv->alpha_notify_id = + g_signal_connect (priv->alpha, "notify::value", + G_CALLBACK (on_alpha_notify), + animation); + + /* if the alpha has a timeline then we use it */ + timeline = clutter_alpha_get_timeline (priv->alpha); + if (timeline != NULL) + { + priv->duration = clutter_timeline_get_duration (timeline); + priv->loop = clutter_timeline_get_loop (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); + } + else + clutter_animation_create_timeline (animation); } - g_object_ref_sink (alpha); - - if (priv->alpha) - { - if (priv->alpha_notify_id) - g_signal_handler_disconnect (priv->alpha, priv->alpha_notify_id); - - g_object_unref (priv->alpha); - priv->alpha_notify_id = 0; - priv->alpha = NULL; - } - - priv->alpha = alpha; - - priv->alpha_notify_id = - g_signal_connect (alpha, "notify::alpha", - G_CALLBACK (on_alpha_notify), - animation); + /* 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"); } /** @@ -1301,8 +1425,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 */ @@ -1548,7 +1676,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."); @@ -1556,7 +1684,7 @@ 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 (); @@ -1569,7 +1697,6 @@ 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)); @@ -1621,7 +1748,7 @@ 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 (); @@ -1635,7 +1762,6 @@ clutter_actor_animate_with_timeline (ClutterActor *actor, 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)); @@ -1812,15 +1938,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", @@ -1835,8 +1959,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); @@ -1891,15 +2015,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", @@ -1914,8 +2036,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); @@ -1970,7 +2092,7 @@ 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 (); @@ -1984,7 +2106,6 @@ clutter_actor_animate_with_timelinev (ClutterActor *actor, 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_setupv (animation, n_properties, properties, values); @@ -2039,7 +2160,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."); @@ -2047,7 +2168,7 @@ 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 (); @@ -2060,7 +2181,6 @@ 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); From 7edaf8ece8af8c1f9bf7dd25263ec16dee5adf69 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 27 May 2009 12:12:11 +0100 Subject: [PATCH 064/138] [animation] Proxy properties whenever possible The Animation class should proxy the :mode, :duration and :loop properties whenever possible, to avoid them going out of sync when changed using the Alpha and Timeline instances directly. Currently, if Timeline:duration is changed, querying Animation:duration will yield the old value, but the animation itself (being driven by the Timeline) will use the Timeline's :duration new value. This holds for the :loop and :mode properties as well. Instead, the getters for the Animation's :duration, :loop and :mode properties should ask the relevant object -- if any. The loop, duration and mode values inside AnimationPrivate should only be used if no Timeline or no Alpha instances are available, or when creating new instances. --- clutter/clutter-animation.c | 60 ++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/clutter/clutter-animation.c b/clutter/clutter-animation.c index 34056c6d3..e7c596618 100644 --- a/clutter/clutter-animation.c +++ b/clutter/clutter-animation.c @@ -220,15 +220,15 @@ 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: @@ -747,7 +747,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); } @@ -1031,9 +1031,16 @@ clutter_animation_set_mode (ClutterAnimation *animation, gulong clutter_animation_get_mode (ClutterAnimation *animation) { + ClutterAnimationPrivate *priv; + g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), CLUTTER_LINEAR); - return animation->priv->mode; + priv = animation->priv; + + if (priv->alpha != NULL) + return clutter_alpha_get_mode (priv->alpha); + + return priv->mode; } /** @@ -1104,17 +1111,16 @@ clutter_animation_set_loop (ClutterAnimation *animation, priv = animation->priv; - if (priv->loop == loop) - return; - - priv->loop = loop; - alpha = clutter_animation_get_alpha_internal (animation); timeline = clutter_alpha_get_timeline (alpha); if (timeline == NULL) - clutter_animation_create_timeline (animation); + { + priv->loop = loop; + + clutter_animation_create_timeline (animation); + } else - clutter_timeline_set_loop (timeline, priv->loop); + clutter_timeline_set_loop (timeline, loop); g_object_notify (G_OBJECT (animation), "loop"); } @@ -1132,9 +1138,22 @@ clutter_animation_set_loop (ClutterAnimation *animation, gboolean clutter_animation_get_loop (ClutterAnimation *animation) { + ClutterAnimationPrivate *priv; + g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), FALSE); - return animation->priv->loop; + priv = animation->priv; + + if (priv->alpha != NULL) + { + ClutterTimeline *timeline; + + timeline = clutter_alpha_get_timeline (priv->alpha); + if (timeline != NULL) + return clutter_timeline_get_loop (timeline); + } + + return priv->loop; } /** @@ -1150,9 +1169,22 @@ clutter_animation_get_loop (ClutterAnimation *animation) guint clutter_animation_get_duration (ClutterAnimation *animation) { + ClutterAnimationPrivate *priv; + g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), 0); - return animation->priv->duration; + priv = animation->priv; + + if (priv->alpha != NULL) + { + ClutterTimeline *timeline; + + timeline = clutter_alpha_get_timeline (priv->alpha); + if (timeline != NULL) + return clutter_timeline_get_duration (timeline); + } + + return priv->duration; } /** From 6fff1bcdc6cd90bfc75eff765c7512545fedded9 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 27 May 2009 13:01:31 +0100 Subject: [PATCH 065/138] [animatable] Allow validation in ::animate_property The Animatable interface implementation will always have the computed value applied, whilst the non-Animatable objects go through the interval validation first to avoid incurring in assertions and warnings. The Animatable::animate_property() should also be able to validate the property it's supposed to interpolate, and eventually discard it. This requires adding a return value to the virtual function (and its wrapper function). The Animation code will then apply the computed value only if the animate_property() returns TRUE -- unifying the code path with the non-Animatable objects. --- clutter/clutter-animatable.c | 43 ++++++++++++++++++++++-------------- clutter/clutter-animatable.h | 28 +++++++++++------------ clutter/clutter-animation.c | 21 ++++++++++-------- 3 files changed, 52 insertions(+), 40 deletions(-) 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 e7c596618..3584ebb17 100644 --- a/clutter/clutter-animation.c +++ b/clutter/clutter-animation.c @@ -778,6 +778,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)); @@ -791,20 +792,22 @@ on_alpha_notify (GObject *gobject, initial = clutter_interval_peek_initial_value (interval); final = clutter_interval_peek_final_value (interval); - 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 { - 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); } From ccd3b4c8863a2a0568d903b4b0273ad05cc17c39 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 27 May 2009 18:28:37 +0100 Subject: [PATCH 066/138] [animation] Simplify the Animation code After long deliberation, the Animation class handling of the :mode, :duration and :loop properties, as well as the conditions for creating the Alpha and Timeline instances, came out as far too complicated for their own good. This is a rework of the API/parameters matrix and behaviour: - :mode accessors will create an Alpha, if needed - :duration and :loop accessors will create an Alpha and a Timeline if needed - :alpha will set or unset the Alpha - :timeline will set or unset the Timeline Plus, more documentation on the Animation class itself. Many thanks to Jonas Bonn for the feedback and the ideas. --- clutter/clutter-animation.c | 432 +++++++++++++++--------------------- 1 file changed, 180 insertions(+), 252 deletions(-) diff --git a/clutter/clutter-animation.c b/clutter/clutter-animation.c index 3584ebb17..5cba38595 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 @@ -87,11 +116,6 @@ struct _ClutterAnimationPrivate ClutterAlpha *alpha; - gulong mode; - - guint loop : 1; - guint duration; - guint timeline_started_id; guint timeline_completed_id; guint alpha_notify_id; @@ -123,34 +147,31 @@ clutter_animation_dispose (GObject *gobject) ClutterAnimationPrivate *priv = CLUTTER_ANIMATION (gobject)->priv; ClutterTimeline *timeline; - timeline = clutter_animation_get_timeline (CLUTTER_ANIMATION (gobject)); - if (timeline != NULL) - { - if (priv->timeline_started_id) - { - g_signal_handler_disconnect (timeline, priv->timeline_started_id); - priv->timeline_started_id = 0; - } + if (priv->alpha != NULL) + timeline = clutter_alpha_get_timeline (priv->alpha); + else + timeline = NULL; - if (priv->timeline_completed_id) - { - g_signal_handler_disconnect (timeline, priv->timeline_completed_id); - priv->timeline_completed_id = 0; - } - } + 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) - { - g_signal_handler_disconnect (priv->alpha, priv->alpha_notify_id); - priv->alpha_notify_id = 0; - } + if (priv->alpha_notify_id != 0) + g_signal_handler_disconnect (priv->alpha, priv->alpha_notify_id); g_object_unref (priv->alpha); - priv->alpha = NULL; } + priv->alpha_notify_id = 0; + priv->alpha = NULL; + if (priv->object != NULL) { g_object_weak_unref (G_OBJECT (gobject), @@ -158,9 +179,10 @@ clutter_animation_dispose (GObject *gobject) priv->object); g_object_set_qdata (priv->object, quark_object_animation, NULL); g_object_unref (priv->object); - priv->object = NULL; } + priv->object = NULL; + G_OBJECT_CLASS (clutter_animation_parent_class)->dispose (gobject); } @@ -393,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, @@ -826,7 +847,7 @@ clutter_animation_get_alpha_internal (ClutterAnimation *animation) ClutterAlpha *alpha; alpha = clutter_alpha_new (); - clutter_alpha_set_mode (alpha, priv->mode); + clutter_alpha_set_mode (alpha, CLUTTER_LINEAR); priv->alpha_notify_id = g_signal_connect (alpha, "notify::alpha", @@ -834,6 +855,8 @@ clutter_animation_get_alpha_internal (ClutterAnimation *animation) animation); priv->alpha = g_object_ref_sink (alpha); + + g_object_notify (G_OBJECT (animation), "alpha"); } return priv->alpha; @@ -841,28 +864,17 @@ clutter_animation_get_alpha_internal (ClutterAnimation *animation) static ClutterTimeline * clutter_animation_get_timeline_internal (ClutterAnimation *animation) -{ - ClutterAlpha *alpha; - - alpha = clutter_animation_get_alpha_internal (animation); - - return clutter_alpha_get_timeline (alpha); -} - -static inline void -clutter_animation_create_timeline (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, - "duration", priv->duration, - "loop", priv->loop, - NULL); - clutter_alpha_set_timeline (alpha, timeline); + timeline = g_object_new (CLUTTER_TYPE_TIMELINE, NULL); priv->timeline_started_id = g_signal_connect (timeline, "started", @@ -874,10 +886,14 @@ clutter_animation_create_timeline (ClutterAnimation *animation) G_CALLBACK (on_timeline_completed), animation); - /* since we are creating it ourselves, we can offload - * the ownership of the timeline to the alpha itself - */ + 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; } /* @@ -985,21 +1001,6 @@ clutter_animation_get_object (ClutterAnimation *animation) return animation->priv->object; } -static inline void -clutter_animation_set_mode_internal (ClutterAnimation *animation, - gulong mode) -{ - ClutterAnimationPrivate *priv = animation->priv; - ClutterAlpha *alpha; - - priv->mode = mode; - - alpha = clutter_animation_get_alpha_internal (animation); - clutter_alpha_set_mode (alpha, priv->mode); - - g_object_notify (G_OBJECT (animation), "mode"); -} - /** * clutter_animation_set_mode: * @animation: a #ClutterAnimation @@ -1009,15 +1010,30 @@ 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) { + ClutterTimeline *timeline; + ClutterAlpha *alpha; + g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); - clutter_animation_set_mode_internal (animation, mode); + g_object_freeze_notify (G_OBJECT (animation)); + + alpha = clutter_animation_get_alpha_internal (animation); + clutter_alpha_set_mode (alpha, mode); + + timeline = clutter_animation_get_timeline_internal (animation); + clutter_alpha_set_timeline (alpha, timeline); + + g_object_notify (G_OBJECT (animation), "mode"); + + g_object_thaw_notify (G_OBJECT (animation)); } /** @@ -1034,16 +1050,13 @@ clutter_animation_set_mode (ClutterAnimation *animation, gulong clutter_animation_get_mode (ClutterAnimation *animation) { - ClutterAnimationPrivate *priv; + ClutterAlpha *alpha; g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), CLUTTER_LINEAR); - priv = animation->priv; + alpha = clutter_animation_get_alpha_internal (animation); - if (priv->alpha != NULL) - return clutter_alpha_get_mode (priv->alpha); - - return priv->mode; + return clutter_alpha_get_mode (alpha); } /** @@ -1053,39 +1066,22 @@ 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; - ClutterAlpha *alpha; g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); - priv = animation->priv; - - priv->duration = msecs; - - alpha = clutter_animation_get_alpha_internal (animation); - timeline = clutter_alpha_get_timeline (alpha); - if (timeline == NULL) - clutter_animation_create_timeline (animation); - else - { - gboolean was_playing; - - was_playing = clutter_timeline_is_playing (timeline); - if (was_playing) - clutter_timeline_stop (timeline); - - clutter_timeline_set_duration (timeline, priv->duration); - - if (was_playing) - clutter_timeline_start (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"); } @@ -1100,30 +1096,21 @@ 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; - ClutterAlpha *alpha; g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); - priv = animation->priv; - - alpha = clutter_animation_get_alpha_internal (animation); - timeline = clutter_alpha_get_timeline (alpha); - if (timeline == NULL) - { - priv->loop = loop; - - clutter_animation_create_timeline (animation); - } - else - clutter_timeline_set_loop (timeline, loop); + timeline = clutter_animation_get_timeline_internal (animation); + clutter_timeline_set_loop (timeline, loop); g_object_notify (G_OBJECT (animation), "loop"); } @@ -1141,22 +1128,13 @@ clutter_animation_set_loop (ClutterAnimation *animation, gboolean clutter_animation_get_loop (ClutterAnimation *animation) { - ClutterAnimationPrivate *priv; + ClutterTimeline *timeline; g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), FALSE); - priv = animation->priv; + timeline = clutter_animation_get_timeline_internal (animation); - if (priv->alpha != NULL) - { - ClutterTimeline *timeline; - - timeline = clutter_alpha_get_timeline (priv->alpha); - if (timeline != NULL) - return clutter_timeline_get_loop (timeline); - } - - return priv->loop; + return clutter_timeline_get_loop (timeline); } /** @@ -1172,39 +1150,23 @@ clutter_animation_get_loop (ClutterAnimation *animation) guint clutter_animation_get_duration (ClutterAnimation *animation) { - ClutterAnimationPrivate *priv; + ClutterTimeline *timeline; g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), 0); - priv = animation->priv; + timeline = clutter_animation_get_timeline_internal (animation); - if (priv->alpha != NULL) - { - ClutterTimeline *timeline; - - timeline = clutter_alpha_get_timeline (priv->alpha); - if (timeline != NULL) - return clutter_timeline_get_duration (timeline); - } - - return priv->duration; + 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 @@ -1220,49 +1182,42 @@ clutter_animation_set_timeline (ClutterAnimation *animation, priv = animation->priv; - cur_timeline = clutter_animation_get_timeline_internal (animation); + 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_started_id != 0) + if (cur_timeline != NULL && priv->timeline_started_id != 0) g_signal_handler_disconnect (cur_timeline, priv->timeline_started_id); - if (priv->timeline_completed_id != 0) + if (cur_timeline != NULL && priv->timeline_completed_id != 0) g_signal_handler_disconnect (cur_timeline, priv->timeline_completed_id); 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 - { - 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"); - } - 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)); } @@ -1288,14 +1243,10 @@ clutter_animation_get_timeline (ClutterAnimation *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 value of the #ClutterAnimation:mode and the current - * #ClutterAnimation:timeline. - * * If @alpha is not %NULL, the #ClutterAnimation will take ownership * of the #ClutterAlpha instance. * @@ -1316,85 +1267,62 @@ clutter_animation_set_alpha (ClutterAnimation *animation, if (priv->alpha == alpha) return; - /* retrieve the old timeline, if any */ if (priv->alpha != NULL) - { - timeline = clutter_alpha_get_timeline (priv->alpha); - if (timeline != NULL) - g_object_ref (timeline); - } + timeline = clutter_alpha_get_timeline (priv->alpha); else timeline = NULL; - if (alpha == NULL) + /* disconnect the old timeline first */ + if (timeline != NULL && priv->timeline_started_id != 0) { - /* this will create a new alpha */ - alpha = clutter_animation_get_alpha_internal (animation); + g_signal_handler_disconnect (timeline, priv->timeline_started_id); + priv->timeline_started_id = 0; + } - /* if we had a timeline before, we should have the same timeline now */ - if (timeline != NULL) - { - clutter_alpha_set_timeline (alpha, timeline); - g_object_unref (timeline); - } - else - clutter_animation_create_timeline (animation); + if (timeline != NULL && priv->timeline_completed_id != 0) + { + g_signal_handler_disconnect (timeline, priv->timeline_completed_id); + priv->timeline_completed_id = 0; + } + + /* 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; + } + + if (alpha == NULL) + return; + + priv->alpha = g_object_ref_sink (alpha); + priv->alpha_notify_id = + 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 - { - if (timeline != NULL) - { - /* if we had a timeline before then we need to disconnect - * the signal handlers from it - */ - if (priv->timeline_started_id != 0) - g_signal_handler_disconnect (timeline, priv->timeline_started_id); - - if (priv->timeline_completed_id != 0) - g_signal_handler_disconnect (timeline, priv->timeline_completed_id); - - /* we don't need this timeline anymore */ - g_object_unref (timeline); - } - - /* 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) - { - g_object_unref (priv->alpha); - priv->alpha = NULL; - } - - priv->alpha = g_object_ref_sink (alpha); - priv->alpha_notify_id = - g_signal_connect (priv->alpha, "notify::value", - G_CALLBACK (on_alpha_notify), - animation); - - /* if the alpha has a timeline then we use it */ - timeline = clutter_alpha_get_timeline (priv->alpha); - if (timeline != NULL) - { - priv->duration = clutter_timeline_get_duration (timeline); - priv->loop = clutter_timeline_get_loop (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); - } - else - clutter_animation_create_timeline (animation); - } + timeline = clutter_animation_get_timeline_internal (animation); /* emit all relevant notifications */ g_object_notify (G_OBJECT (animation), "mode"); @@ -1419,7 +1347,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); } /** @@ -1722,6 +1650,7 @@ clutter_actor_animate_with_alpha (ClutterActor *actor, 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), @@ -1733,7 +1662,6 @@ clutter_actor_animate_with_alpha (ClutterActor *actor, CLUTTER_NOTE (ANIMATION, "Reusing Animation [%p]", animation); 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); @@ -1786,6 +1714,7 @@ clutter_actor_animate_with_timeline (ClutterActor *actor, 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), @@ -1796,9 +1725,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_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); @@ -2130,6 +2058,7 @@ clutter_actor_animate_with_timelinev (ClutterActor *actor, 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), @@ -2140,9 +2069,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_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); @@ -2206,6 +2134,7 @@ clutter_actor_animate_with_alphav (ClutterActor *actor, 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), @@ -2217,7 +2146,6 @@ clutter_actor_animate_with_alphav (ClutterActor *actor, CLUTTER_NOTE (ANIMATION, "Reusing Animation [%p]", animation); 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); From ef1a771fde77e29b8bf327905674da59ea3d0bf0 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Wed, 27 May 2009 23:39:18 +0100 Subject: [PATCH 067/138] [build] Fixes some compiler warnings when building for GLES 2 There were a number of variables shadowing other symbols, and an unused display variable. --- clutter/cogl/gles/cogl-gles2-wrapper.c | 20 +++++++------- clutter/cogl/gles/cogl-primitives.c | 36 +++++++++++++------------- tests/conform/test-conform-main.c | 3 +-- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/clutter/cogl/gles/cogl-gles2-wrapper.c b/clutter/cogl/gles/cogl-gles2-wrapper.c index 523676dd2..aec15b7a0 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); diff --git a/clutter/cogl/gles/cogl-primitives.c b/clutter/cogl/gles/cogl-primitives.c index 1e03e1ea2..24b6b0759 100644 --- a/clutter/cogl/gles/cogl-primitives.c +++ b/clutter/cogl/gles/cogl-primitives.c @@ -361,30 +361,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/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c index b31ab524b..46ccef07a 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 " From 33994caa71fea904a80971a15216e6d7fa48712c Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Mon, 11 May 2009 00:40:41 +0100 Subject: [PATCH 068/138] [cogl-material] Support string based blending and layer combine descriptions Setting up layer combine functions and blend modes is very awkward to do programatically. This adds a parser for string based descriptions which are more consise and readable. E.g. a material layer combine function could now be given as: "RGBA = ADD (TEXTURE[A], PREVIOUS[RGB])" or "RGB = REPLACE (PREVIOUS)" "A = MODULATE (PREVIOUS, TEXTURE)" The simple syntax and grammar are only designed to expose standard fixed function hardware, more advanced combining must be done with shaders. This includes standalone documentation of blend strings covering the aspects that are common to blending and texture combining, and adds documentation with examples specific to the new cogl_material_set_blend() and cogl_material_layer_set_combine() functions. Note: The hope is to remove the now redundant bits of the material API before 1.0 --- clutter/cogl/cogl-debug.h | 20 +- clutter/cogl/cogl-material.h | 244 ++++- clutter/cogl/common/Makefile.am | 2 + clutter/cogl/common/cogl-blend-string.c | 999 ++++++++++++++++++++ clutter/cogl/common/cogl-blend-string.h | 151 +++ clutter/cogl/common/cogl-debug.c | 3 +- clutter/cogl/common/cogl-material-private.h | 13 +- clutter/cogl/common/cogl-material.c | 406 +++++++- clutter/cogl/gl/cogl-context.c | 3 + clutter/cogl/gl/cogl-context.h | 3 + clutter/cogl/gl/cogl-defines.h.in | 12 + clutter/cogl/gl/cogl.c | 10 + clutter/cogl/gles/cogl-gles2-wrapper.c | 9 +- clutter/cogl/gles/cogl-gles2-wrapper.h | 5 +- clutter/cogl/gles/cogl-texture.c | 49 +- doc/reference/cogl/Makefile.am | 9 +- doc/reference/cogl/blend-strings.xml | 130 +++ doc/reference/cogl/cogl-docs.xml | 1 + doc/reference/cogl/cogl-sections.txt | 4 + tests/conform/Makefile.am | 3 +- tests/conform/test-blend-strings.c | 410 ++++++++ tests/conform/test-conform-main.c | 2 + 22 files changed, 2404 insertions(+), 84 deletions(-) create mode 100644 clutter/cogl/common/cogl-blend-string.c create mode 100644 clutter/cogl/common/cogl-blend-string.h create mode 100644 doc/reference/cogl/blend-strings.xml create mode 100644 tests/conform/test-blend-strings.c 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-material.h b/clutter/cogl/cogl-material.h index 95a474831..d69ae276c 100644 --- a/clutter/cogl/cogl-material.h +++ b/clutter/cogl/cogl-material.h @@ -43,7 +43,6 @@ G_BEGIN_DECLS * blended together. */ - /** * cogl_material_new: * @@ -378,10 +377,12 @@ void cogl_material_set_alpha_test_function (CoglHandle material, * @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_CONSTANT: (Rc, Gc, Bc, Ac) + * @COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_CONSTANT: (1-Rc, 1-Gc, 1-Bc, 1-Ac) + * @COGL_MATERIAL_BLEND_FACTOR_CONSTANT_ALPHA: (Ac, Ac, Ac, Ac) + * @COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA: (1-Ac, 1-Ac, 1-Ac, 1-Ac) * @COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA_SATURATE: (f,f,f,1) where f=MIN(As,1-Ad) * - * 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 @@ -411,6 +412,14 @@ typedef enum _CoglMaterialBlendFactor 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, +#ifdef HAVE_COGL_GL + COGL_MATERIAL_BLEND_FACTOR_CONSTANT = GL_CONSTANT_COLOR, + COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_CONSTANT = + GL_ONE_MINUS_CONSTANT_COLOR, + COGL_MATERIAL_BLEND_FACTOR_CONSTANT_ALPHA = GL_CONSTANT_ALPHA, + COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = + GL_ONE_MINUS_CONSTANT_ALPHA, +#endif COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA_SATURATE = GL_SRC_ALPHA_SATURATE, } CoglMaterialBlendFactor; @@ -442,6 +451,92 @@ void cogl_material_set_blend_factors (CoglHandle material, CoglMaterialBlendFactor src_factor, CoglMaterialBlendFactor dst_factor); +/** + * 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. + + * Currently the only blend function Cogl exposes is ADD(). So any valid + * blend statements will be of the form: + * + * + * <channel-mask>=ADD(SRC_COLOR*(<factor>), DST_COLOR*(<factor>)) + * + * + * NOTE: The brackets around blend factors are currently not optional! + * + * 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 + */ +gboolean cogl_material_set_blend (CoglHandle material, + const char *blend_string, + GError **error); + +/** + * cogl_material_set_blend_constant: + * @material: A CoglMaterial object + * @constant_color: The constant color you want + * + * When blending is setup to reference a CONSTANT blend factor then + * blending will depend on the constant set with this function. + * + * Since: 1.0 + */ +void cogl_material_set_blend_constant (CoglHandle material, + CoglColor *constant_color); + /** * cogl_material_set_layer: * @material: A CoglMaterial object @@ -460,7 +555,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,6 +568,113 @@ void cogl_material_set_layer (CoglHandle material, void cogl_material_remove_layer (CoglHandle material, gint layer_index); + +/** + * 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. + * + * 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) = + * + * 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)) + * + * + * DOT3_RGBA(arg0, arg1) = + * + * 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)) + * + * + * + * + * 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 + */ +gboolean +cogl_material_set_layer_combine (CoglHandle material, + gint layer_index, + const char *blend_string, + GError **error); + +/** + * cogl_material_set_layer_combine_constant: + * @material: A CoglMaterial object + * @layer_index: Specifies the layer you want to specify a constant used + * for texture combining + * @color_constant: The constant color you want + * + * 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_constant (CoglHandle material, + int layer_index, + CoglColor *constant); + /** * CoglMaterialLayerCombineFunc: * @COGL_MATERIAL_LAYER_COMBINE_FUNC_REPLACE: Arg0 @@ -600,7 +802,7 @@ typedef enum _CoglMaterialLayerCombineChannels * */ void cogl_material_set_layer_combine_function (CoglHandle material, - gint layer_index, + int layer_index, CoglMaterialLayerCombineChannels channels, CoglMaterialLayerCombineFunc func); @@ -650,8 +852,8 @@ typedef enum _CoglMaterialLayerCombineSrc * */ void cogl_material_set_layer_combine_arg_src (CoglHandle material, - gint layer_index, - gint argument, + int layer_index, + int argument, CoglMaterialLayerCombineChannels channels, CoglMaterialLayerCombineSrc src); @@ -674,33 +876,11 @@ typedef enum _CoglMaterialLayerCombineOp * */ void cogl_material_set_layer_combine_arg_op (CoglHandle material, - gint layer_index, - gint argument, + int layer_index, + int 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 - /** * cogl_material_set_layer_matrix: * @material: A CoglMaterial object @@ -709,7 +889,7 @@ 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); diff --git a/clutter/cogl/common/Makefile.am b/clutter/cogl/common/Makefile.am index 138893a14..c4e6eb2f7 100644 --- a/clutter/cogl/common/Makefile.am +++ b/clutter/cogl/common/Makefile.am @@ -39,4 +39,6 @@ libclutter_cogl_common_la_SOURCES = \ cogl-matrix-stack.h \ cogl-material.c \ cogl-material-private.h \ + cogl-blend-string.c \ + cogl-blend-string.h \ cogl-debug.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-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-material-private.h b/clutter/cogl/common/cogl-material-private.h index 05d4242dd..f0e053eff 100644 --- a/clutter/cogl/common/cogl-material-private.h +++ b/clutter/cogl/common/cogl-material-private.h @@ -78,6 +78,8 @@ struct _CoglMaterialLayer CoglMaterialLayerCombineSrc texture_combine_alpha_src[3]; CoglMaterialLayerCombineOp texture_combine_alpha_op[3]; + GLfloat texture_combine_constant[4]; + /* TODO: Support purely GLSL based material layers */ CoglMatrix matrix; @@ -114,8 +116,15 @@ 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; + CoglMaterialBlendFactor blend_dst_factor_alpha; + CoglMaterialBlendFactor blend_src_factor_alpha; + GLfloat blend_constant[4]; +#endif + CoglMaterialBlendFactor blend_src_factor_rgb; + CoglMaterialBlendFactor blend_dst_factor_rgb; GList *layers; }; diff --git a/clutter/cogl/common/cogl-material.c b/clutter/cogl/common/cogl-material.c index c456cac6a..cc1ae0691 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,8 @@ #ifdef HAVE_COGL_GL #define glActiveTexture ctx->pf_glActiveTexture #define glClientActiveTexture ctx->pf_glClientActiveTexture +#define glBlendFuncSeparate ctx->pf_glBlendFuncSeparate +#define glBlendEquationSeparate ctx->pf_glBlendEquationSeparate #endif static void _cogl_material_free (CoglMaterial *tex); @@ -60,6 +63,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 +97,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,6 +427,179 @@ 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 +setup_blend_state (CoglBlendStringStatement *statement, + GLenum *blend_equation, + CoglMaterialBlendFactor *blend_src_factor, + CoglMaterialBlendFactor *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); + + 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 +} + void cogl_material_set_blend_factors (CoglHandle handle, CoglMaterialBlendFactor src_factor, @@ -418,8 +610,12 @@ cogl_material_set_blend_factors (CoglHandle handle, 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; + material->blend_src_factor_rgb = src_factor; + material->blend_dst_factor_rgb = dst_factor; +#ifndef HAVE_COGL_GLES + material->blend_src_factor_alpha = src_factor; + material->blend_dst_factor_alpha = dst_factor; +#endif material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC; } @@ -530,6 +726,169 @@ cogl_material_set_layer (CoglHandle material_handle, layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY; } +static void +setup_texture_combine_state (CoglBlendStringStatement *statement, + CoglMaterialLayerCombineFunc *texture_combine_func, + CoglMaterialLayerCombineSrc *texture_combine_src, + CoglMaterialLayerCombineOp *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; + 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); + + 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; +} + void cogl_material_set_layer_combine_function ( CoglHandle handle, @@ -713,7 +1072,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. */ @@ -851,6 +1210,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 @@ -1122,7 +1484,39 @@ _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)); } } diff --git a/clutter/cogl/gl/cogl-context.c b/clutter/cogl/gl/cogl-context.c index 2c17408c2..b5d89f30b 100644 --- a/clutter/cogl/gl/cogl-context.c +++ b/clutter/cogl/gl/cogl-context.c @@ -136,6 +136,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 (); diff --git a/clutter/cogl/gl/cogl-context.h b/clutter/cogl/gl/cogl-context.h index 2660ed812..f490d39ac 100644 --- a/clutter/cogl/gl/cogl-context.h +++ b/clutter/cogl/gl/cogl-context.h @@ -164,6 +164,9 @@ typedef struct COGL_PFNGLACTIVETEXTUREPROC pf_glActiveTexture; COGL_PFNGLCLIENTACTIVETEXTUREPROC pf_glClientActiveTexture; + + 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..bde93c559 100644 --- a/clutter/cogl/gl/cogl-defines.h.in +++ b/clutter/cogl/gl/cogl-defines.h.in @@ -1020,6 +1020,18 @@ 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); + G_END_DECLS #endif diff --git a/clutter/cogl/gl/cogl.c b/clutter/cogl/gl/cogl.c index b2c5417e7..8fcd3eabd 100644 --- a/clutter/cogl/gl/cogl.c +++ b/clutter/cogl/gl/cogl.c @@ -486,6 +486,16 @@ _cogl_features_init (void) (COGL_PFNGLCLIENTACTIVETEXTUREPROC) cogl_get_proc_address ("glClientActiveTexture"); + /* 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/cogl-gles2-wrapper.c b/clutter/cogl/gles/cogl-gles2-wrapper.c index aec15b7a0..979ade598 100644 --- a/clutter/cogl/gles/cogl-gles2-wrapper.c +++ b/clutter/cogl/gles/cogl-gles2-wrapper.c @@ -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-texture.c b/clutter/cogl/gles/cogl-texture.c index 8f4cf733e..99a18f154 100644 --- a/clutter/cogl/gles/cogl-texture.c +++ b/clutter/cogl/gles/cogl-texture.c @@ -442,6 +442,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 +478,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 +525,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 +557,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; } diff --git a/doc/reference/cogl/Makefile.am b/doc/reference/cogl/Makefile.am index 82b96928f..c2f075e4d 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,15 @@ 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 = \ + version.xml \ + 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 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 index ba5d2cf89..87d665f42 100644 --- a/doc/reference/cogl/cogl-docs.xml +++ b/doc/reference/cogl/cogl-docs.xml @@ -55,6 +55,7 @@ + diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index 3032a6863..ca7664132 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -354,6 +354,8 @@ 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 @@ -363,6 +365,8 @@ 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 CoglMaterial diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am index 5fd68034a..253cb64ed 100644 --- a/tests/conform/Makefile.am +++ b/tests/conform/Makefile.am @@ -28,6 +28,7 @@ test_conformance_SOURCES = \ test-anchors.c \ test-npot-texture.c \ test-model.c \ + test-blend-strings.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 \ 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-conform-main.c b/tests/conform/test-conform-main.c index 46ccef07a..ff614ae98 100644 --- a/tests/conform/test-conform-main.c +++ b/tests/conform/test-conform-main.c @@ -143,5 +143,7 @@ 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); + return g_test_run (); } From f28d5e481b7e01b241618a10e7fde834de3ac2b2 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Sat, 23 May 2009 16:23:00 +0100 Subject: [PATCH 069/138] [cogl-material] Removes all the API made redundant by the blend strings API This removes the following API: cogl_material_set_blend_factors cogl_material_set_layer_combine_function cogl_material_set_layer_combine_arg_src cogl_material_set_layer_combine_arg_op These were rather awkward to use, so since it's expected very few people are using them at this point and it should be straight forward to switch over to blend strings, the API is being removed before we release Clutter 1.0. --- clutter/cogl/cogl-material.h | 293 -------------------- clutter/cogl/common/cogl-material-private.h | 20 +- clutter/cogl/common/cogl-material.c | 176 ++---------- clutter/pango/cogl-pango-render.c | 22 +- doc/reference/cogl/cogl-sections.txt | 11 - 5 files changed, 38 insertions(+), 484 deletions(-) diff --git a/clutter/cogl/cogl-material.h b/clutter/cogl/cogl-material.h index d69ae276c..cf364d3fa 100644 --- a/clutter/cogl/cogl-material.h +++ b/clutter/cogl/cogl-material.h @@ -365,92 +365,6 @@ void cogl_material_set_alpha_test_function (CoglHandle material, CoglMaterialAlphaFunc alpha_func, 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_CONSTANT: (Rc, Gc, Bc, Ac) - * @COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_CONSTANT: (1-Rc, 1-Gc, 1-Bc, 1-Ac) - * @COGL_MATERIAL_BLEND_FACTOR_CONSTANT_ALPHA: (Ac, Ac, Ac, Ac) - * @COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA: (1-Ac, 1-Ac, 1-Ac, 1-Ac) - * @COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA_SATURATE: (f,f,f,1) where f=MIN(As,1-Ad) - * - * - * 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: - * - * - * R = Rs*Sr + Rd*Dr - * G = Gs*Sg + Gd*Dg - * B = Bs*Sb + Bd*Db - * A = As*Sa + Ad*Da - * - * - * All factors have a range [0, 1] - * - * The factors are selected with the following constants: - */ -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, -#ifdef HAVE_COGL_GL - COGL_MATERIAL_BLEND_FACTOR_CONSTANT = GL_CONSTANT_COLOR, - COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_CONSTANT = - GL_ONE_MINUS_CONSTANT_COLOR, - COGL_MATERIAL_BLEND_FACTOR_CONSTANT_ALPHA = GL_CONSTANT_ALPHA, - COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = - GL_ONE_MINUS_CONSTANT_ALPHA, -#endif - COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA_SATURATE = GL_SRC_ALPHA_SATURATE, -} CoglMaterialBlendFactor; - -/** - * cogl_material_set_blend_factors: - * @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. - * - * 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: - * - * (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 - */ -void cogl_material_set_blend_factors (CoglHandle material, - CoglMaterialBlendFactor src_factor, - CoglMaterialBlendFactor dst_factor); - /** * cogl_material_set_blend: * @material: A CoglMaterial object @@ -675,212 +589,6 @@ void cogl_material_set_layer_combine_constant (CoglHandle ma int layer_index, CoglColor *constant); -/** - * 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)) + - * - * 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: - * - * - * (Rs*Rp, Gs*Gp, Bs*Bp, As*Ap) - * - * - * 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: - * - * //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); - * - */ -void cogl_material_set_layer_combine_function (CoglHandle material, - int 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. - */ -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; - -/** - * cogl_material_set_layer_combine_arg_src: - * @material: A CoglMaterial object - * @layer_index: - * @argument: - * @channels: - * @src: - * - */ -void cogl_material_set_layer_combine_arg_src (CoglHandle material, - int layer_index, - int 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: - * - */ -void cogl_material_set_layer_combine_arg_op (CoglHandle material, - int layer_index, - int argument, - CoglMaterialLayerCombineChannels channels, - CoglMaterialLayerCombineOp op); - /** * cogl_material_set_layer_matrix: * @material: A CoglMaterial object @@ -892,7 +600,6 @@ void cogl_material_set_layer_matrix (CoglHandle material, int layer_index, CoglMatrix *matrix); - /** * SECTION:cogl-material-internals * @short_description: Functions for creating custom primitives that make use diff --git a/clutter/cogl/common/cogl-material-private.h b/clutter/cogl/common/cogl-material-private.h index f0e053eff..5d3cecfd9 100644 --- a/clutter/cogl/common/cogl-material-private.h +++ b/clutter/cogl/common/cogl-material-private.h @@ -70,13 +70,13 @@ struct _CoglMaterialLayer /* 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]; @@ -119,12 +119,12 @@ struct _CoglMaterial #ifndef HAVE_COGL_GLES GLenum blend_equation_rgb; GLenum blend_equation_alpha; - CoglMaterialBlendFactor blend_dst_factor_alpha; - CoglMaterialBlendFactor blend_src_factor_alpha; + GLint blend_src_factor_alpha; + GLint blend_dst_factor_alpha; GLfloat blend_constant[4]; #endif - CoglMaterialBlendFactor blend_src_factor_rgb; - CoglMaterialBlendFactor blend_dst_factor_rgb; + GLint blend_src_factor_rgb; + GLint blend_dst_factor_rgb; GList *layers; }; diff --git a/clutter/cogl/common/cogl-material.c b/clutter/cogl/common/cogl-material.c index cc1ae0691..aef14cd00 100644 --- a/clutter/cogl/common/cogl-material.c +++ b/clutter/cogl/common/cogl-material.c @@ -500,8 +500,8 @@ arg_to_gl_blend_factor (CoglBlendStringArgument *arg) void setup_blend_state (CoglBlendStringStatement *statement, GLenum *blend_equation, - CoglMaterialBlendFactor *blend_src_factor, - CoglMaterialBlendFactor *blend_dst_factor) + GLint *blend_src_factor, + GLint *blend_dst_factor) { #ifndef HAVE_COGL_GLES switch (statement->function->type) @@ -600,26 +600,6 @@ cogl_material_set_blend_constant (CoglHandle handle, #endif } -void -cogl_material_set_blend_factors (CoglHandle handle, - CoglMaterialBlendFactor src_factor, - CoglMaterialBlendFactor dst_factor) -{ - CoglMaterial *material; - - g_return_if_fail (cogl_is_material (handle)); - - material = _cogl_material_pointer_from_handle (handle); - material->blend_src_factor_rgb = src_factor; - material->blend_dst_factor_rgb = dst_factor; -#ifndef HAVE_COGL_GLES - material->blend_src_factor_alpha = src_factor; - material->blend_dst_factor_alpha = dst_factor; -#endif - - material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC; -} - /* Asserts that a layer corresponding to the given index exists. If no * match is found, then a new empty layer is added. */ @@ -659,21 +639,16 @@ _cogl_material_get_layer (CoglMaterial *material, /* 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); @@ -728,9 +703,9 @@ cogl_material_set_layer (CoglHandle material_handle, static void setup_texture_combine_state (CoglBlendStringStatement *statement, - CoglMaterialLayerCombineFunc *texture_combine_func, - CoglMaterialLayerCombineSrc *texture_combine_src, - CoglMaterialLayerCombineOp *texture_combine_op) + GLint *texture_combine_func, + GLint *texture_combine_src, + GLint *texture_combine_op) { int i; @@ -889,109 +864,6 @@ cogl_material_set_layer_combine_constant (CoglHandle handle, layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE; } -void -cogl_material_set_layer_combine_function ( - CoglHandle handle, - gint layer_index, - CoglMaterialLayerCombineChannels channels, - CoglMaterialLayerCombineFunc func) -{ - CoglMaterial *material; - CoglMaterialLayer *layer; - gboolean set_alpha_func = FALSE; - gboolean set_rgb_func = FALSE; - - 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; - - layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY; - layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE; -} - void cogl_material_set_layer_matrix (CoglHandle material_handle, gint layer_index, @@ -1119,20 +991,20 @@ 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; diff --git a/clutter/pango/cogl-pango-render.c b/clutter/pango/cogl-pango-render.c index 99dd40d3f..898c11ee3 100644 --- a/clutter/pango/cogl-pango-render.c +++ b/clutter/pango/cogl-pango-render.c @@ -136,25 +136,11 @@ 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 (); diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index ca7664132..3b32cda5b 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -349,22 +349,13 @@ 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 @@ -372,8 +363,6 @@ cogl_material_set_layer_matrix CoglMaterial CoglMaterialFlags CoglMaterialLayerPrivFlags -cogl_material_set_layer_alpha_combine -cogl_material_set_layer_rgb_combine
From f322da3794f6556648566ebcf6b83f59f88e7a5b Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Sat, 23 May 2009 17:42:10 +0100 Subject: [PATCH 070/138] [material] Reduce the material API in preperation for releasing Clutter 1.0 There were a number of functions intended to support creating of new primitives using materials, but at this point they aren't used outside of Cogl so until someone has a usecase and we can get feedback on this API, it's being removed before we release Clutter 1.0. --- clutter/cogl/cogl-material.h | 129 +++----------------- clutter/cogl/common/cogl-handle.h | 17 +-- clutter/cogl/common/cogl-material-private.h | 86 +++++++++++++ clutter/cogl/common/cogl-material.c | 6 +- clutter/cogl/common/cogl-primitives.c | 50 ++++---- clutter/cogl/common/cogl-vertex-buffer.c | 15 +-- clutter/cogl/common/cogl.c | 3 +- clutter/cogl/gl/cogl-context.c | 4 +- clutter/cogl/gl/cogl-primitives.c | 15 +-- clutter/cogl/gles/cogl-context.c | 4 +- clutter/cogl/gles/cogl-primitives.c | 15 +-- doc/reference/cogl/cogl-sections.txt | 3 + 12 files changed, 174 insertions(+), 173 deletions(-) diff --git a/clutter/cogl/cogl-material.h b/clutter/cogl/cogl-material.h index cf364d3fa..da822564e 100644 --- a/clutter/cogl/cogl-material.h +++ b/clutter/cogl/cogl-material.h @@ -600,34 +600,6 @@ void cogl_material_set_layer_matrix (CoglHandle material, 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 @@ -635,24 +607,15 @@ 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 */ typedef enum _CoglMaterialLayerType { @@ -661,17 +624,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); @@ -679,75 +637,24 @@ 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. - */ -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; G_END_DECLS 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 5d3cecfd9..9b2170ecf 100644 --- a/clutter/cogl/common/cogl-material-private.h +++ b/clutter/cogl/common/cogl-material-private.h @@ -129,5 +129,91 @@ struct _CoglMaterial 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 aef14cd00..7e8567a6e 100644 --- a/clutter/cogl/common/cogl-material.c +++ b/clutter/cogl/common/cogl-material.c @@ -921,7 +921,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; @@ -979,7 +979,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; @@ -1393,7 +1393,7 @@ _cogl_material_flush_base_gl_state (CoglMaterial *material) } void -cogl_material_flush_gl_state (CoglHandle handle, ...) +_cogl_material_flush_gl_state (CoglHandle handle, ...) { CoglMaterial *material; va_list ap; diff --git a/clutter/cogl/common/cogl-primitives.c b/clutter/cogl/common/cogl-primitives.c index 224769ca2..42e4d41cb 100644 --- a/clutter/cogl/common/cogl-primitives.c +++ b/clutter/cogl/common/cogl-primitives.c @@ -29,7 +29,7 @@ #include "cogl-internal.h" #include "cogl-context.h" #include "cogl-texture-private.h" -#include "cogl-material.h" +#include "cogl-material-private.h" #include #include @@ -112,16 +112,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 +140,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; @@ -177,7 +177,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 +791,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 +1041,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 +1136,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)); @@ -1254,7 +1254,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-vertex-buffer.c b/clutter/cogl/common/cogl-vertex-buffer.c index f6fa6ba89..842551b04 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))) @@ -1638,14 +1639,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; diff --git a/clutter/cogl/common/cogl.c b/clutter/cogl/common/cogl.c index 2495d8172..8b85924f6 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" @@ -375,7 +376,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) { diff --git a/clutter/cogl/gl/cogl-context.c b/clutter/cogl/gl/cogl-context.c index b5d89f30b..db5541148 100644 --- a/clutter/cogl/gl/cogl-context.c +++ b/clutter/cogl/gl/cogl-context.c @@ -166,9 +166,9 @@ 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); return TRUE; 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/gles/cogl-context.c b/clutter/cogl/gles/cogl-context.c index f187c0b88..1d2d02843 100644 --- a/clutter/cogl/gles/cogl-context.c +++ b/clutter/cogl/gles/cogl-context.c @@ -124,9 +124,9 @@ 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); return TRUE; diff --git a/clutter/cogl/gles/cogl-primitives.c b/clutter/cogl/gles/cogl-primitives.c index 24b6b0759..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, diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index 3b32cda5b..1041ded78 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -359,6 +359,9 @@ cogl_material_remove_layer cogl_material_set_layer_combine cogl_material_set_layer_combine_constant cogl_material_set_layer_matrix +cogl_material_get_layers +cogl_material_layer_get_type +cogl_material_layer_get_texture CoglMaterial CoglMaterialFlags From 68214fe4b88603c73a77d5cc543f8688a0bde82c Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Sat, 23 May 2009 17:52:18 +0100 Subject: [PATCH 071/138] [cogl] Remove cogl_flush_gl_state from the API This is being 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 someone with a good usecase, we can't pretend to support breaking out into raw OpenGL. --- clutter/cogl/cogl.h.in | 8 +++++++- clutter/cogl/common/cogl.c | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/clutter/cogl/cogl.h.in b/clutter/cogl/cogl.h.in index bd3698312..af4b26597 100644 --- a/clutter/cogl/cogl.h.in +++ b/clutter/cogl/cogl.h.in @@ -628,7 +628,12 @@ void cogl_push_draw_buffer (void); */ void cogl_pop_draw_buffer (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 +647,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/cogl.c b/clutter/cogl/common/cogl.c index 8b85924f6..81c43bd5e 100644 --- a/clutter/cogl/common/cogl.c +++ b/clutter/cogl/common/cogl.c @@ -654,9 +654,11 @@ cogl_disable_fog (void) glDisable (GL_FOG); } +#if 0 void cogl_flush_gl_state (int flags) { _cogl_current_matrix_state_flush (); } +#endif From 6bb66866660018e90c2c1663e02fca3f0b818050 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Sun, 24 May 2009 04:04:38 +0100 Subject: [PATCH 072/138] [cogl-vertex-buffers] Support putting index arrays into VBOS It's now possible to add arrays of indices to a Cogl vertex buffer and they will be put into an OpenGL vertex buffer object. Since it's quite common for index arrays to be static it saves the OpenGL driver from having to validate them repeatedly. This changes the cogl_vertex_buffer_draw_elements API: It's no longer possible to provide a pointer to an index array at draw time. So cogl_vertex_buffer_draw_elements now takes an indices identifier that should correspond to an idendifier returned when calling cogl_vertex_buffer_add_indices () --- clutter/cogl/cogl-vertex-buffer.h | 79 ++++++--- .../cogl/common/cogl-vertex-buffer-private.h | 33 +++- clutter/cogl/common/cogl-vertex-buffer.c | 161 ++++++++++++++++-- doc/reference/cogl/cogl-sections.txt | 2 + tests/interactive/test-cogl-vertex-buffer.c | 17 +- 5 files changed, 244 insertions(+), 48 deletions(-) diff --git a/clutter/cogl/cogl-vertex-buffer.h b/clutter/cogl/cogl-vertex-buffer.h index 717281db0..580ecfa10 100644 --- a/clutter/cogl/cogl-vertex-buffer.h +++ b/clutter/cogl/cogl-vertex-buffer.h @@ -256,6 +256,54 @@ cogl_vertex_buffer_draw (CoglHandle handle, GLint first, GLsizei 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_add_indices: + * @handle: A vertex buffer handle + * @id: Any unique number. It's used to identify the indices when you later + * call cogl_vertex_buffer_draw_elements() + * @min_index: Specifies the minimum vertex index contained in indices + * @max_index: Specifies the maximum vertex index contained in indices + * @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. + * + * You should aim to use the COGL_INDICES_TYPE_UNSIGNED_SHORT when possible + * and correctly reflect the range of index values in the {min,max}_index + * arguments. This allows Cogl to optimize the internal storage used for + * the indices and reduce the demand for memory bandwidth. + */ +void +cogl_vertex_buffer_add_indices (CoglHandle handle, + int id, + unsigned int min_index, + unsigned int max_index, + CoglIndicesType indices_type, + const void *indices_array, + size_t indices_len); + /** * cogl_vertex_buffer_draw_elements: * @handle: A vertex buffer handle @@ -270,33 +318,26 @@ cogl_vertex_buffer_draw (CoglHandle handle, * GL_TRIANGLE_FAN * GL_TRIANGLES * - * (Note: only types available in GLES are listed) - * @min_index: Specifies the minimum vertex index contained in indices - * @max_index: Specifies the maximum vertex index contained in indices + * @indices_id: The identifier for a an array of indices previously added to + * the given Cogl vertex buffer using + * cogl_vertex_buffer_add_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 given by calling cogl_vertex_buffer_add_indices () * * 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, + GLenum mode, + int indices_id, + unsigned int indices_offset, + unsigned int count); /** * cogl_vertex_buffer_ref: diff --git a/clutter/cogl/common/cogl-vertex-buffer-private.h b/clutter/cogl/common/cogl-vertex-buffer-private.h index 68a709b54..cc87b1828 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,24 +129,39 @@ 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 +{ + int id; + /* 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; + GLuint min_index; + GLuint max_index; +} 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 */ + + GList *indices; /*!< A list of associated index arrays */ + } CoglVertexBuffer; #endif /* __COGL_VERTEX_BUFFER_H */ diff --git a/clutter/cogl/common/cogl-vertex-buffer.c b/clutter/cogl/common/cogl-vertex-buffer.c index 842551b04..cd450ea93 100644 --- a/clutter/cogl/common/cogl-vertex-buffer.c +++ b/clutter/cogl/common/cogl-vertex-buffer.c @@ -214,6 +214,8 @@ cogl_vertex_buffer_new (guint n_vertices) buffer->submitted_vbos = NULL; buffer->new_attributes = NULL; + buffer->indices = NULL; + /* return COGL_INVALID_HANDLE; */ return _cogl_vertex_buffer_handle_new (buffer); } @@ -1727,13 +1729,11 @@ cogl_vertex_buffer_draw (CoglHandle handle, 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)); @@ -1741,35 +1741,158 @@ cogl_vertex_buffer_draw (CoglHandle handle, disable_state_for_drawing_buffer (buffer); } +static void +free_vertex_buffer_indices (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); +} + +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; + } +} + 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_add_indices (CoglHandle handle, + int id, + unsigned int min_index, + unsigned int max_index, + CoglIndicesType indices_type, + const void *indices_array, + size_t indices_len) { CoglVertexBuffer *buffer; + GList *l; + gboolean fallback = + (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE; + size_t indices_bytes; + CoglVertexBufferIndices *indices; _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (!cogl_is_vertex_buffer (handle)) return; - cogl_clip_ensure (); + buffer = _cogl_vertex_buffer_pointer_from_handle (handle); + + for (l = buffer->indices; l; l = l->next) + { + CoglVertexBufferIndices *current_indices = l->data; + if (current_indices->id == id) + { + free_vertex_buffer_indices (l->data); + buffer->indices = g_list_delete_link (buffer->indices, l); + break; + } + } + + indices = g_slice_alloc (sizeof (CoglVertexBufferIndices)); + indices->id = id; + indices->min_index = min_index; + indices->max_index = max_index; + + 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; + } + + 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)); + } + + buffer->indices = g_list_prepend (buffer->indices, indices); +} + +void +cogl_vertex_buffer_draw_elements (CoglHandle handle, + GLenum mode, + int indices_id, + unsigned int indices_offset, + unsigned int count) +{ + CoglVertexBuffer *buffer; + gboolean fallback = + (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE; + size_t byte_offset; + GList *l; + CoglVertexBufferIndices *indices = NULL; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + if (!cogl_is_vertex_buffer (handle)) + return; buffer = _cogl_vertex_buffer_pointer_from_handle (handle); + cogl_clip_ensure (); + _cogl_current_matrix_state_flush (); enable_state_for_drawing_buffer (buffer); - _cogl_current_matrix_state_flush (); + for (l = buffer->indices; l; l = l->next) + { + CoglVertexBufferIndices *current_indices = l->data; + if (current_indices->id == indices_id) + { + indices = current_indices; + break; + } + } + if (!indices) + return; + + 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)); + GE (glDrawRangeElements (mode, indices->min_index, indices->max_index, + count, indices->type, (void *)byte_offset)); disable_state_for_drawing_buffer (buffer); + + GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0)); } static void @@ -1779,8 +1902,16 @@ _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); + + for (tmp = buffer->indices; tmp != NULL; tmp = tmp->next) + free_vertex_buffer_indices (tmp->data); + g_list_free (buffer->indices); g_slice_free (CoglVertexBuffer, buffer); } + diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index 1041ded78..8b1d5161c 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -307,6 +307,8 @@ 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_draw_elements CoglVertexBufferAttribFlags diff --git a/tests/interactive/test-cogl-vertex-buffer.c b/tests/interactive/test-cogl-vertex-buffer.c index 903cbfc23..5a0d45e31 100644 --- a/tests/interactive/test-cogl-vertex-buffer.c +++ b/tests/interactive/test-cogl-vertex-buffer.c @@ -140,11 +140,9 @@ 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); + 0, /* indices identifier */ + 0, /* indices offset */ + state->n_static_indices); } static void @@ -220,6 +218,15 @@ init_static_index_arrays (TestState *state) } #undef MESH_INDEX + + cogl_vertex_buffer_add_indices (state->buffer, + 0, /* identifier */ + 0, /* min index */ + (MESH_WIDTH + 1) * + (MESH_HEIGHT + 1), /* max index */ + COGL_INDICES_TYPE_UNSIGNED_SHORT, + state->static_indices, + state->n_static_indices); } static float From d51faed66095259f17467dceba0cc0cd02dcd042 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Sun, 24 May 2009 11:33:29 +0100 Subject: [PATCH 073/138] [cogl-vertex-buffer] Seal GL types from the public API We now have CoglAttributeType and CoglVerticesMode typedefs to replace the use of GLenum in the public API. --- clutter/cogl/cogl-vertex-buffer.h | 118 ++++++++++++-------- clutter/cogl/common/cogl-vertex-buffer.c | 48 ++++---- tests/interactive/test-cogl-vertex-buffer.c | 6 +- 3 files changed, 96 insertions(+), 76 deletions(-) diff --git a/clutter/cogl/cogl-vertex-buffer.h b/clutter/cogl/cogl-vertex-buffer.h index 580ecfa10..4d229bd63 100644 --- a/clutter/cogl/cogl-vertex-buffer.h +++ b/clutter/cogl/cogl-vertex-buffer.h @@ -94,6 +94,24 @@ cogl_vertex_buffer_new (guint n_vertices); guint cogl_vertex_buffer_get_n_vertices (CoglHandle handle); +/** + * CoglAttributeType: + * @COGL_ATTRIBUTE_TYPE_BYTE: + * @COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE: + * @COGL_ATTRIBUTE_TYPE_SHORT: + * @COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT: + * @COGL_ATTRIBUTE_TYPE_FLOAT: + * + */ +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 +129,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 +173,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 +243,33 @@ void cogl_vertex_buffer_enable (CoglHandle handle, const char *attribute_name); +/** + * CoglVerticesMode: + * COGL_VERTICES_MODE_POINTS: + * COGL_VERTICES_MODE_LINE_STRIP: + * COGL_VERTICES_MODE_LINE_LOOP: + * COGL_VERTICES_MODE_LINES: + * COGL_VERTICES_MODE_TRIANGLE_STRIP: + * COGL_VERTICES_MODE_TRIANGLE_FAN: + * COGL_VERTICES_MODE_TRIANGLES: + * + */ +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,10 +280,10 @@ 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: @@ -296,28 +325,19 @@ typedef enum _CoglIndicesType * the indices and reduce the demand for memory bandwidth. */ void -cogl_vertex_buffer_add_indices (CoglHandle handle, - int id, - unsigned int min_index, - unsigned int max_index, - CoglIndicesType indices_type, - const void *indices_array, - size_t indices_len); +cogl_vertex_buffer_add_indices (CoglHandle handle, + int id, + int min_index, + int max_index, + CoglIndicesType indices_type, + const void *indices_array, + int indices_len); /** * 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 - * + * @mode: A #CoglVerticesMode specifying how the vertices should be + * interpreted. * @indices_id: The identifier for a an array of indices previously added to * the given Cogl vertex buffer using * cogl_vertex_buffer_add_indices(). @@ -333,11 +353,11 @@ cogl_vertex_buffer_add_indices (CoglHandle handle, * drawing. */ void -cogl_vertex_buffer_draw_elements (CoglHandle handle, - GLenum mode, - int indices_id, - unsigned int indices_offset, - unsigned int count); +cogl_vertex_buffer_draw_elements (CoglHandle handle, + CoglVerticesMode mode, + int indices_id, + int indices_offset, + int count); /** * cogl_vertex_buffer_ref: diff --git a/clutter/cogl/common/cogl-vertex-buffer.c b/clutter/cogl/common/cogl-vertex-buffer.c index cd450ea93..7c8269765 100644 --- a/clutter/cogl/common/cogl-vertex-buffer.c +++ b/clutter/cogl/common/cogl-vertex-buffer.c @@ -414,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); @@ -488,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 @@ -1719,10 +1719,10 @@ 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; @@ -1772,13 +1772,13 @@ get_indices_type_size (GLuint indices_type) } void -cogl_vertex_buffer_add_indices (CoglHandle handle, - int id, - unsigned int min_index, - unsigned int max_index, - CoglIndicesType indices_type, - const void *indices_array, - size_t indices_len) +cogl_vertex_buffer_add_indices (CoglHandle handle, + int id, + int min_index, + int max_index, + CoglIndicesType indices_type, + const void *indices_array, + int indices_len) { CoglVertexBuffer *buffer; GList *l; @@ -1843,11 +1843,11 @@ cogl_vertex_buffer_add_indices (CoglHandle handle, } void -cogl_vertex_buffer_draw_elements (CoglHandle handle, - GLenum mode, - int indices_id, - unsigned int indices_offset, - unsigned int count) +cogl_vertex_buffer_draw_elements (CoglHandle handle, + CoglVerticesMode mode, + int indices_id, + int indices_offset, + int count) { CoglVertexBuffer *buffer; gboolean fallback = diff --git a/tests/interactive/test-cogl-vertex-buffer.c b/tests/interactive/test-cogl-vertex-buffer.c index 5a0d45e31..8a3751665 100644 --- a/tests/interactive/test-cogl-vertex-buffer.c +++ b/tests/interactive/test-cogl-vertex-buffer.c @@ -139,7 +139,7 @@ on_paint (ClutterActor *actor, TestState *state) { cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); cogl_vertex_buffer_draw_elements (state->buffer, - GL_TRIANGLE_STRIP, + COGL_VERTICES_MODE_TRIANGLE_STRIP, 0, /* indices identifier */ 0, /* indices offset */ state->n_static_indices); @@ -287,7 +287,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); @@ -295,7 +295,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); From 59bd824404c34b20defb2e8e76335185e714efc7 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Tue, 26 May 2009 16:27:36 +0100 Subject: [PATCH 074/138] [vbo indices] tweak add_indices api to return an id and add delete_indices api Originally cogl_vertex_buffer_add_indices let the user pass in their own unique ID for the indices; now the Id is generated internally and returned to the caller. --- clutter/cogl/cogl-vertex-buffer.h | 30 ++++++++---- clutter/cogl/common/cogl-vertex-buffer.c | 52 ++++++++++++++------- doc/reference/cogl/cogl-sections.txt | 1 + tests/interactive/test-cogl-vertex-buffer.c | 19 ++++---- 4 files changed, 67 insertions(+), 35 deletions(-) diff --git a/clutter/cogl/cogl-vertex-buffer.h b/clutter/cogl/cogl-vertex-buffer.h index 4d229bd63..1887db566 100644 --- a/clutter/cogl/cogl-vertex-buffer.h +++ b/clutter/cogl/cogl-vertex-buffer.h @@ -305,8 +305,6 @@ typedef enum _CoglIndicesType /** * cogl_vertex_buffer_add_indices: * @handle: A vertex buffer handle - * @id: Any unique number. It's used to identify the indices when you later - * call cogl_vertex_buffer_draw_elements() * @min_index: Specifies the minimum vertex index contained in indices * @max_index: Specifies the maximum vertex index contained in indices * @indices_type: a #CoglIndicesType specifying the data type used for @@ -319,20 +317,36 @@ typedef enum _CoglIndicesType * array allows you to reference vertices multiple times, for example * during triangle strips. * - * You should aim to use the COGL_INDICES_TYPE_UNSIGNED_SHORT when possible - * and correctly reflect the range of index values in the {min,max}_index - * arguments. This allows Cogl to optimize the internal storage used for - * the indices and reduce the demand for memory bandwidth. + * You should aim to use the smallest data type possible and correctly reflect + * the range of index values in the {min,max}_index arguments. This allows Cogl + * to optimize the internal storage used for the indices and reduce the demand + * for memory bandwidth. + * + * Returns: An identifier (greater than 0) for the indices which you can + * pass to cogl_vertex_buffer_draw_elements(). */ -void +int cogl_vertex_buffer_add_indices (CoglHandle handle, - int id, int min_index, int max_index, 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 diff --git a/clutter/cogl/common/cogl-vertex-buffer.c b/clutter/cogl/common/cogl-vertex-buffer.c index 7c8269765..096a4a47c 100644 --- a/clutter/cogl/common/cogl-vertex-buffer.c +++ b/clutter/cogl/common/cogl-vertex-buffer.c @@ -1771,9 +1771,8 @@ get_indices_type_size (GLuint indices_type) } } -void +int cogl_vertex_buffer_add_indices (CoglHandle handle, - int id, int min_index, int max_index, CoglIndicesType indices_type, @@ -1781,32 +1780,23 @@ cogl_vertex_buffer_add_indices (CoglHandle handle, int indices_len) { CoglVertexBuffer *buffer; - GList *l; gboolean fallback = (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE; size_t indices_bytes; CoglVertexBufferIndices *indices; - _COGL_GET_CONTEXT (ctx, NO_RETVAL); + static int next_indices_id = 1; + + + _COGL_GET_CONTEXT (ctx, 0); if (!cogl_is_vertex_buffer (handle)) - return; + return 0; buffer = _cogl_vertex_buffer_pointer_from_handle (handle); - for (l = buffer->indices; l; l = l->next) - { - CoglVertexBufferIndices *current_indices = l->data; - if (current_indices->id == id) - { - free_vertex_buffer_indices (l->data); - buffer->indices = g_list_delete_link (buffer->indices, l); - break; - } - } - indices = g_slice_alloc (sizeof (CoglVertexBufferIndices)); - indices->id = id; + indices->id = next_indices_id; indices->min_index = min_index; indices->max_index = max_index; @@ -1818,7 +1808,7 @@ cogl_vertex_buffer_add_indices (CoglHandle handle, { g_critical ("unknown indices type %d", indices_type); g_slice_free (CoglVertexBufferIndices, indices); - return; + return 0; } indices_bytes = get_indices_type_size (indices->type) * indices_len; @@ -1840,6 +1830,32 @@ cogl_vertex_buffer_add_indices (CoglHandle handle, } buffer->indices = g_list_prepend (buffer->indices, indices); + + return next_indices_id++; +} + +void +cogl_vertex_buffer_delete_indices (CoglHandle handle, + int indices_id) +{ + CoglVertexBuffer *buffer; + GList *l; + + if (!cogl_is_vertex_buffer (handle)) + return; + + buffer = _cogl_vertex_buffer_pointer_from_handle (handle); + + for (l = buffer->indices; l; l = l->next) + { + CoglVertexBufferIndices *current_indices = l->data; + if (current_indices->id == indices_id) + { + free_vertex_buffer_indices (l->data); + buffer->indices = g_list_delete_link (buffer->indices, l); + return; + } + } } void diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index 8b1d5161c..25f5e98c8 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -309,6 +309,7 @@ cogl_vertex_buffer_enable cogl_vertex_buffer_draw CoglIndicesType cogl_vertex_buffer_add_indices +cogl_vertex_buffer_delete_indices cogl_vertex_buffer_draw_elements CoglVertexBufferAttribFlags diff --git a/tests/interactive/test-cogl-vertex-buffer.c b/tests/interactive/test-cogl-vertex-buffer.c index 8a3751665..4cc3b481d 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; + int indices_id; ClutterTimeline *timeline; } TestState; @@ -140,7 +141,7 @@ on_paint (ClutterActor *actor, TestState *state) cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); cogl_vertex_buffer_draw_elements (state->buffer, COGL_VERTICES_MODE_TRIANGLE_STRIP, - 0, /* indices identifier */ + state->indices_id, 0, /* indices offset */ state->n_static_indices); } @@ -219,14 +220,14 @@ init_static_index_arrays (TestState *state) #undef MESH_INDEX - cogl_vertex_buffer_add_indices (state->buffer, - 0, /* identifier */ - 0, /* min index */ - (MESH_WIDTH + 1) * - (MESH_HEIGHT + 1), /* max index */ - COGL_INDICES_TYPE_UNSIGNED_SHORT, - state->static_indices, - state->n_static_indices); + state->indices_id = + cogl_vertex_buffer_add_indices (state->buffer, + 0, /* min index */ + (MESH_WIDTH + 1) * + (MESH_HEIGHT + 1), /* max index */ + COGL_INDICES_TYPE_UNSIGNED_SHORT, + state->static_indices, + state->n_static_indices); } static float From 12c8ff8606c2fb6212e59c50842e04b634f7c4b2 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Tue, 26 May 2009 15:41:53 +0100 Subject: [PATCH 075/138] [cogl] Remove cogl_{create,destroy}_context from the public API cogl_create_context is dealt with internally when _cogl_get_default context is called, and cogl_destroy_context is currently never called. It might be nicer later to get an object back when creating a context so Cogl can support multiple contexts, so these functions are being removed from the API until we get a chance to address context management properly. For now cogl_destroy_context is still exported as _cogl_destroy_context so Clutter could at least install a library deinit handler to call it. --- clutter/cogl/cogl.h.in | 28 ++++++++++++---------------- clutter/cogl/gl/cogl-context.c | 4 ++-- clutter/cogl/gles/cogl-context.c | 4 ++-- doc/reference/cogl/cogl-sections.txt | 3 --- 4 files changed, 16 insertions(+), 23 deletions(-) diff --git a/clutter/cogl/cogl.h.in b/clutter/cogl/cogl.h.in index af4b26597..b5bb55d10 100644 --- a/clutter/cogl/cogl.h.in +++ b/clutter/cogl/cogl.h.in @@ -55,22 +55,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: * @@ -628,6 +612,18 @@ 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 diff --git a/clutter/cogl/gl/cogl-context.c b/clutter/cogl/gl/cogl-context.c index db5541148..39415a02a 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 }; @@ -175,7 +175,7 @@ cogl_create_context () } void -cogl_destroy_context () +_cogl_destroy_context () { if (_context == NULL) return; diff --git a/clutter/cogl/gles/cogl-context.c b/clutter/cogl/gles/cogl-context.c index 1d2d02843..5b6ce7c1b 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 }; @@ -133,7 +133,7 @@ cogl_create_context () } void -cogl_destroy_context () +_cogl_destroy_context () { if (_context == NULL) return; diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index 25f5e98c8..6ee2d9517 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -15,9 +15,6 @@ COGL_UNPREMULT_MASK CoglPixelFormat CoglBufferTarget -cogl_create_context -cogl_destroy_context - CoglFeatureFlags cogl_get_features cogl_features_available From 96188bab621d4a342d67a1e0a85dd1dcb3bdee68 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Tue, 26 May 2009 11:33:54 +0100 Subject: [PATCH 076/138] [cogl matrix] Support ortho and perspective projections. This adds cogl_matrix api for multiplying matrices either by a perspective or ortho projective transform. The internal matrix stack and current-matrix APIs also have corresponding support added. New public API: cogl_matrix_perspective cogl_matrix_ortho cogl_ortho cogl_set_modelview_matrix cogl_set_projection_matrix --- clutter/cogl/cogl-matrix.h | 70 +++++-- clutter/cogl/cogl.h.in | 39 ++++ clutter/cogl/common/cogl-current-matrix.c | 213 +++++++++++++--------- clutter/cogl/common/cogl-matrix-stack.c | 72 ++++++-- clutter/cogl/common/cogl-matrix-stack.h | 20 +- clutter/cogl/common/cogl-matrix.c | 87 +++++++-- doc/reference/cogl/cogl-sections.txt | 19 +- 7 files changed, 371 insertions(+), 149 deletions(-) diff --git a/clutter/cogl/cogl-matrix.h b/clutter/cogl/cogl-matrix.h index ca643f146..bd7b579c7 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 + * @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) + * + * Multiples the matrix by a parallel projection matrix. + */ +void +cogl_matrix_ortho (CoglMatrix *matrix, + float left, + float right, + float bottom, + float top, + float near, + float 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.h.in b/clutter/cogl/cogl.h.in index b5bb55d10..e66cbc394 100644 --- a/clutter/cogl/cogl.h.in +++ b/clutter/cogl/cogl.h.in @@ -170,6 +170,29 @@ void cogl_frustum (float left, float z_near, float z_far); +/** + * 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 @@ -272,6 +295,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 @@ -280,6 +311,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 diff --git a/clutter/cogl/common/cogl-current-matrix.c b/clutter/cogl/common/cogl-current-matrix.c index 0080af0d1..e01987c95 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, + float far) { -#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, - near_val, - far_val); + bottom, top, + near, + far); 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, far); + _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, far)); #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 near, + float far) +{ + CoglMatrix ortho; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + cogl_matrix_init_identity (&ortho); + cogl_matrix_ortho (&ortho, left, right, bottom, top, near, 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-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/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index 6ee2d9517..5855a90b1 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -21,19 +21,22 @@ 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 From 605243d95285ad57cf55dc7674884f3ed4b09524 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Tue, 26 May 2009 16:55:11 +0100 Subject: [PATCH 077/138] [cogl] renamed cogl_enable_* to cogl_set_*_enabled + added getters cogl_enable_depth_test and cogl_enable_backface_culling have been renamed and now have corresponding getters, the new functions are: cogl_set_depth_test_enabled cogl_get_depth_test_enabled cogl_set_backface_culling_enabled cogl_get_backface_culling_enabled --- README | 3 +++ clutter/cogl/cogl-deprecated.h | 1 + clutter/cogl/cogl.h.in | 27 +++++++++++++++++++++++---- clutter/cogl/common/cogl.c | 25 +++++++++++++++++-------- doc/reference/cogl/cogl-sections.txt | 6 ++++-- tests/conform/test-backface-culling.c | 4 ++-- 6 files changed, 50 insertions(+), 16 deletions(-) diff --git a/README b/README index e28a467f3..97521a4b3 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/cogl/cogl-deprecated.h b/clutter/cogl/cogl-deprecated.h index 2111e48b4..41e77b3d6 100644 --- a/clutter/cogl/cogl-deprecated.h +++ b/clutter/cogl/cogl-deprecated.h @@ -24,5 +24,6 @@ #ifndef COGL_DEPRECATED_H #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 #endif diff --git a/clutter/cogl/cogl.h.in b/clutter/cogl/cogl.h.in index e66cbc394..188af09cd 100644 --- a/clutter/cogl/cogl.h.in +++ b/clutter/cogl/cogl.h.in @@ -331,7 +331,7 @@ void cogl_set_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 @@ -340,10 +340,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 @@ -352,7 +361,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: diff --git a/clutter/cogl/common/cogl.c b/clutter/cogl/common/cogl.c index 81c43bd5e..adeb479d2 100644 --- a/clutter/cogl/common/cogl.c +++ b/clutter/cogl/common/cogl.c @@ -214,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) { diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index 5855a90b1..c34585ff1 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -40,8 +40,10 @@ 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 diff --git a/tests/conform/test-backface-culling.c b/tests/conform/test-backface-culling.c index 00f36bfba..bfddcf105 100644 --- a/tests/conform/test-backface-culling.c +++ b/tests/conform/test-backface-culling.c @@ -108,7 +108,7 @@ on_paint (ClutterActor *actor, TestState *state) int i; int frame_num; - cogl_enable_backface_culling (TRUE); + cogl_set_backface_culling_enabled (TRUE); cogl_push_matrix (); @@ -180,7 +180,7 @@ on_paint (ClutterActor *actor, TestState *state) /* The second time round draw beneath the first with backface culling disabled */ cogl_translate (0, TEXTURE_RENDER_SIZE, 0); - cogl_enable_backface_culling (FALSE); + cogl_set_backface_culling_enabled (FALSE); } cogl_pop_matrix (); From 57cb20dc0685889b5eaa89d409a47d67d15450fb Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Tue, 26 May 2009 18:25:00 +0100 Subject: [PATCH 078/138] [deprecated defines] Adds some missing cogl_texture_* deprecated defines To assist people porting code from 0.8, the cogl_texture_* functions that have been replaced now have defines that give some hint as to how they should be replaced. --- clutter/cogl/cogl-deprecated.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/clutter/cogl/cogl-deprecated.h b/clutter/cogl/cogl-deprecated.h index 41e77b3d6..3ccac603d 100644 --- a/clutter/cogl/cogl-deprecated.h +++ b/clutter/cogl/cogl-deprecated.h @@ -26,4 +26,12 @@ #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_texture_rectangle \ + cogl_texture_rectangle_REPLACE_BY_cogl_set_source_texture_plus_cogl_rectangle_with_texture_coords + +#define cogl_texture_multiple_rectangles \ + cogl_texture_multiple_rectangles_REPLACED_BY_cogl_set_source_texture_plus_cogl_rectangles_with_texture_coords + +#define cogl_texture_polygon cogl_texture_polygon_REPLACED_BY_cogl_set_source_texture_plus_cogl_polygon + #endif From f0849fc3e25185e86464cadcc98a7bcdac1b0ab8 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Thu, 28 May 2009 02:03:16 +0100 Subject: [PATCH 079/138] [cogl journal] If we are only flushing one quad use a TRIANGLE_FAN At the moment Cogl doesn't do much batching of quads so most of the time we are flushing a single quad at a time. This patch simplifies how we submit those quads to OpenGL by using glDrawArrays with GL_TRIANGLE_FAN mode instead of sending indexed vertices using GL_TRIANGLES mode. Note: I hope to follow up soon with changes that improve our batching and also move the indices into a VBO so they don't need to be re-validated every time we call glDrawElements. --- clutter/cogl/common/cogl-primitives.c | 80 +++++++++++++++------------ 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/clutter/cogl/common/cogl-primitives.c b/clutter/cogl/common/cogl-primitives.c index 42e4d41cb..ff5401d50 100644 --- a/clutter/cogl/common/cogl-primitives.c +++ b/clutter/cogl/common/cogl-primitives.c @@ -72,35 +72,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, @@ -150,11 +121,52 @@ _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)); + + + if (batch_len > 1) + { + /* 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; + } + } + + GE (glDrawRangeElements (GL_TRIANGLES, + 0, ctx->static_indices->len - 1, + 6 * batch_len, + GL_UNSIGNED_SHORT, + ctx->static_indices->data)); + } + else + { + GE (glDrawArrays (GL_TRIANGLE_FAN, + 0, /* first */ + 4)); /* n vertices */ + } /* DEBUGGING CODE XXX: From be826ed4e7b9e834da0055f4e5d253c22204b870 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Thu, 28 May 2009 12:49:29 +0100 Subject: [PATCH 080/138] [cogl vertex buffers] Give indices a CoglHandle so they are shareable Previously indices were tightly bound to a particular Cogl vertex buffer but we would like to be able to share indices so now we have cogl_vertex_buffer_indices_new () which returns a CoglHandle. In particular we could like to have a shared set of indices for drawing lists of quads that can be shared between the pango renderer and the Cogl journal. --- clutter/cogl/cogl-vertex-buffer.h | 34 +++---- .../cogl/common/cogl-vertex-buffer-private.h | 7 +- clutter/cogl/common/cogl-vertex-buffer.c | 97 +++++-------------- tests/interactive/test-cogl-vertex-buffer.c | 16 +-- 4 files changed, 46 insertions(+), 108 deletions(-) diff --git a/clutter/cogl/cogl-vertex-buffer.h b/clutter/cogl/cogl-vertex-buffer.h index 1887db566..ba2cef8b2 100644 --- a/clutter/cogl/cogl-vertex-buffer.h +++ b/clutter/cogl/cogl-vertex-buffer.h @@ -303,10 +303,7 @@ typedef enum _CoglIndicesType } CoglIndicesType; /** - * cogl_vertex_buffer_add_indices: - * @handle: A vertex buffer handle - * @min_index: Specifies the minimum vertex index contained in indices - * @max_index: Specifies the maximum vertex index contained in indices + * 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 @@ -317,19 +314,11 @@ typedef enum _CoglIndicesType * array allows you to reference vertices multiple times, for example * during triangle strips. * - * You should aim to use the smallest data type possible and correctly reflect - * the range of index values in the {min,max}_index arguments. This allows Cogl - * to optimize the internal storage used for the indices and reduce the demand - * for memory bandwidth. - * - * Returns: An identifier (greater than 0) for the indices which you can - * pass to cogl_vertex_buffer_draw_elements(). + * Returns: A CoglHandle for the indices which you can pass to + * cogl_vertex_buffer_draw_elements(). */ -int -cogl_vertex_buffer_add_indices (CoglHandle handle, - int min_index, - int max_index, - CoglIndicesType indices_type, +CoglHandle +cogl_vertex_buffer_indices_new (CoglIndicesType indices_type, const void *indices_array, int indices_len); @@ -352,16 +341,17 @@ cogl_vertex_buffer_delete_indices (CoglHandle handle, * @handle: A vertex buffer handle * @mode: A #CoglVerticesMode specifying how the vertices should be * interpreted. - * @indices_id: The identifier for a an array of indices previously added to - * the given Cogl vertex buffer using - * cogl_vertex_buffer_add_indices(). + * @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. * * This function lets you use an array of indices to specify the vertices * within your vertex buffer that you want to draw. The indices themselves - * are given by calling cogl_vertex_buffer_add_indices () + * are created by calling cogl_vertex_buffer_indices_new () * * Any un-submitted attribute changes are automatically submitted before * drawing. @@ -369,7 +359,9 @@ cogl_vertex_buffer_delete_indices (CoglHandle handle, void cogl_vertex_buffer_draw_elements (CoglHandle handle, CoglVerticesMode mode, - int indices_id, + CoglHandle indices, + int min_index, + int max_index, int indices_offset, int count); diff --git a/clutter/cogl/common/cogl-vertex-buffer-private.h b/clutter/cogl/common/cogl-vertex-buffer-private.h index cc87b1828..17f8725e4 100644 --- a/clutter/cogl/common/cogl-vertex-buffer-private.h +++ b/clutter/cogl/common/cogl-vertex-buffer-private.h @@ -139,14 +139,13 @@ typedef struct _CoglVertexBufferVBO typedef struct _CoglVertexBufferIndices { - int id; + 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; - GLuint min_index; - GLuint max_index; } CoglVertexBufferIndices; typedef struct _CoglVertexBuffer @@ -160,8 +159,6 @@ typedef struct _CoglVertexBuffer * modifying a buffer. */ GList *new_attributes; /*!< attributes pending submission */ - GList *indices; /*!< A list of associated index arrays */ - } CoglVertexBuffer; #endif /* __COGL_VERTEX_BUFFER_H */ diff --git a/clutter/cogl/common/cogl-vertex-buffer.c b/clutter/cogl/common/cogl-vertex-buffer.c index 096a4a47c..b3c36f0ec 100644 --- a/clutter/cogl/common/cogl-vertex-buffer.c +++ b/clutter/cogl/common/cogl-vertex-buffer.c @@ -201,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) @@ -214,8 +216,6 @@ cogl_vertex_buffer_new (guint n_vertices) buffer->submitted_vbos = NULL; buffer->new_attributes = NULL; - buffer->indices = NULL; - /* return COGL_INVALID_HANDLE; */ return _cogl_vertex_buffer_handle_new (buffer); } @@ -1741,22 +1741,6 @@ cogl_vertex_buffer_draw (CoglHandle handle, disable_state_for_drawing_buffer (buffer); } -static void -free_vertex_buffer_indices (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); -} - static int get_indices_type_size (GLuint indices_type) { @@ -1771,34 +1755,19 @@ get_indices_type_size (GLuint indices_type) } } -int -cogl_vertex_buffer_add_indices (CoglHandle handle, - int min_index, - int max_index, - CoglIndicesType indices_type, +CoglHandle +cogl_vertex_buffer_indices_new (CoglIndicesType indices_type, const void *indices_array, int indices_len) { - CoglVertexBuffer *buffer; gboolean fallback = (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE; size_t indices_bytes; CoglVertexBufferIndices *indices; - static int next_indices_id = 1; - - _COGL_GET_CONTEXT (ctx, 0); - if (!cogl_is_vertex_buffer (handle)) - return 0; - - buffer = _cogl_vertex_buffer_pointer_from_handle (handle); - indices = g_slice_alloc (sizeof (CoglVertexBufferIndices)); - indices->id = next_indices_id; - indices->min_index = min_index; - indices->max_index = max_index; if (indices_type == COGL_INDICES_TYPE_UNSIGNED_BYTE) indices->type = GL_UNSIGNED_BYTE; @@ -1829,39 +1798,31 @@ cogl_vertex_buffer_add_indices (CoglHandle handle, GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0)); } - buffer->indices = g_list_prepend (buffer->indices, indices); - - return next_indices_id++; + return _cogl_vertex_buffer_indices_handle_new (indices); } void -cogl_vertex_buffer_delete_indices (CoglHandle handle, - int indices_id) +_cogl_vertex_buffer_indices_free (CoglVertexBufferIndices *indices) { - CoglVertexBuffer *buffer; - GList *l; + gboolean fallback = + (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE; - if (!cogl_is_vertex_buffer (handle)) - return; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); - buffer = _cogl_vertex_buffer_pointer_from_handle (handle); + if (fallback) + g_free (indices->vbo_name); + else + GE (glDeleteBuffers (1, (GLuint *)&indices->vbo_name)); - for (l = buffer->indices; l; l = l->next) - { - CoglVertexBufferIndices *current_indices = l->data; - if (current_indices->id == indices_id) - { - free_vertex_buffer_indices (l->data); - buffer->indices = g_list_delete_link (buffer->indices, l); - return; - } - } + g_slice_free (CoglVertexBufferIndices, indices); } void cogl_vertex_buffer_draw_elements (CoglHandle handle, CoglVerticesMode mode, - int indices_id, + CoglHandle indices_handle, + int min_index, + int max_index, int indices_offset, int count) { @@ -1869,7 +1830,6 @@ cogl_vertex_buffer_draw_elements (CoglHandle handle, gboolean fallback = (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE; size_t byte_offset; - GList *l; CoglVertexBufferIndices *indices = NULL; _COGL_GET_CONTEXT (ctx, NO_RETVAL); @@ -1879,22 +1839,15 @@ cogl_vertex_buffer_draw_elements (CoglHandle handle, 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); - for (l = buffer->indices; l; l = l->next) - { - CoglVertexBufferIndices *current_indices = l->data; - if (current_indices->id == indices_id) - { - indices = current_indices; - break; - } - } - if (!indices) - return; - byte_offset = indices_offset * get_indices_type_size (indices->type); if (fallback) byte_offset = (size_t)(((char *)indices->vbo_name) + byte_offset); @@ -1903,7 +1856,7 @@ cogl_vertex_buffer_draw_elements (CoglHandle handle, GPOINTER_TO_UINT (indices->vbo_name))); /* FIXME: flush cogl cache */ - GE (glDrawRangeElements (mode, indices->min_index, indices->max_index, + GE (glDrawRangeElements (mode, min_index, max_index, count, indices->type, (void *)byte_offset)); disable_state_for_drawing_buffer (buffer); @@ -1924,10 +1877,6 @@ _cogl_vertex_buffer_free (CoglVertexBuffer *buffer) cogl_vertex_buffer_attribute_free (tmp->data); g_list_free (buffer->new_attributes); - for (tmp = buffer->indices; tmp != NULL; tmp = tmp->next) - free_vertex_buffer_indices (tmp->data); - g_list_free (buffer->indices); - g_slice_free (CoglVertexBuffer, buffer); } diff --git a/tests/interactive/test-cogl-vertex-buffer.c b/tests/interactive/test-cogl-vertex-buffer.c index 4cc3b481d..093e32a4a 100644 --- a/tests/interactive/test-cogl-vertex-buffer.c +++ b/tests/interactive/test-cogl-vertex-buffer.c @@ -49,7 +49,7 @@ typedef struct _TestState GLubyte *quad_mesh_colors; GLushort *static_indices; guint n_static_indices; - int indices_id; + CoglHandle indices; ClutterTimeline *timeline; } TestState; @@ -141,7 +141,10 @@ on_paint (ClutterActor *actor, TestState *state) cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); cogl_vertex_buffer_draw_elements (state->buffer, COGL_VERTICES_MODE_TRIANGLE_STRIP, - state->indices_id, + state->indices, + 0, /* min index */ + (MESH_WIDTH + 1) * + (MESH_HEIGHT + 1), /* max index */ 0, /* indices offset */ state->n_static_indices); } @@ -220,12 +223,8 @@ init_static_index_arrays (TestState *state) #undef MESH_INDEX - state->indices_id = - cogl_vertex_buffer_add_indices (state->buffer, - 0, /* min index */ - (MESH_WIDTH + 1) * - (MESH_HEIGHT + 1), /* max index */ - COGL_INDICES_TYPE_UNSIGNED_SHORT, + state->indices = + cogl_vertex_buffer_indices_new (COGL_INDICES_TYPE_UNSIGNED_SHORT, state->static_indices, state->n_static_indices); } @@ -376,6 +375,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); From 32018584c0eda5bd29d4f3a773e7d243a740cbc4 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 28 May 2009 12:52:00 +0100 Subject: [PATCH 081/138] [cogl deprecated] Add backface culling deprecation The backface culling enabling function was split and renamed, just like the depth testing one, so we need to add the macro to the cogl-deprecated.h header. --- clutter/cogl/cogl-deprecated.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/clutter/cogl/cogl-deprecated.h b/clutter/cogl/cogl-deprecated.h index 3ccac603d..24dc5b28b 100644 --- a/clutter/cogl/cogl-deprecated.h +++ b/clutter/cogl/cogl-deprecated.h @@ -23,15 +23,14 @@ #ifndef COGL_DEPRECATED_H -#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_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_plus_cogl_rectangle_with_texture_coords +#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_plus_cogl_rectangles_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_plus_cogl_polygon +#define cogl_texture_polygon cogl_texture_polygon_REPLACED_BY_cogl_set_source_texture_AND_cogl_polygon #endif From 7252c141970eaa7c17214e9890b917221be70fd0 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 28 May 2009 13:03:19 +0100 Subject: [PATCH 082/138] [cogl] Make cogl_setup_viewport() a private function The setup_viewport() function should only be used by Clutter and not by application code. It can be emulated by changing the Stage size and perspective and requeueing a redraw after calling clutter_stage_ensure_viewport(). --- clutter/clutter-main.c | 14 ++++++++------ clutter/clutter-texture.c | 10 +++++----- clutter/cogl/cogl.h.in | 10 ++++++---- clutter/cogl/common/cogl.c | 16 ++++++++-------- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c index b5f5c3785..a4a690b46 100644 --- a/clutter/clutter-main.c +++ b/clutter/clutter-main.c @@ -160,13 +160,15 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage) 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); } diff --git a/clutter/clutter-texture.c b/clutter/clutter-texture.c index 2321f6304..3bb1e6448 100644 --- a/clutter/clutter-texture.c +++ b/clutter/clutter-texture.c @@ -556,11 +556,11 @@ clutter_texture_paint (ClutterActor *self) /* 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 */ diff --git a/clutter/cogl/cogl.h.in b/clutter/cogl/cogl.h.in index 188af09cd..a671aa00d 100644 --- a/clutter/cogl/cogl.h.in +++ b/clutter/cogl/cogl.h.in @@ -193,8 +193,8 @@ void cogl_ortho (float left, float near, float far); -/** - * cogl_setup_viewport: +/* + * _cogl_setup_viewport: * @width: Width of the viewport * @height: Height of the viewport * @fovy: Field of view angle in degrees @@ -208,9 +208,11 @@ void cogl_ortho (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, diff --git a/clutter/cogl/common/cogl.c b/clutter/cogl/common/cogl.c index adeb479d2..336303917 100644 --- a/clutter/cogl/common/cogl.c +++ b/clutter/cogl/common/cogl.c @@ -475,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; @@ -488,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); @@ -542,7 +542,7 @@ cogl_setup_viewport (guint width, } CoglFeatureFlags -cogl_get_features () +cogl_get_features (void) { _COGL_GET_CONTEXT (ctx, 0); From e51fbebd67e04182438c7f24d5db7b0f678c3f56 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 28 May 2009 17:18:10 +0100 Subject: [PATCH 083/138] [git ignore] Add blend strings test --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 895779f82..83d8e5981 100644 --- a/.gitignore +++ b/.gitignore @@ -196,6 +196,7 @@ stamp-h1 /tests/conform/test-map-recursive /tests/conform/test-realize-not-recursive /tests/conform/test-shown-not-parented +/tests/conform/test-blend-strings /tests/micro-bench/test-text-perf /tests/micro-bench/test-text /tests/micro-bench/test-picking From 7b75f93db1ad29ef4c81c20ee8434876d54aa358 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 28 May 2009 17:18:13 +0100 Subject: [PATCH 084/138] [docs] Fixes for the API reference * Add unused symbols * Document and sync argument names with their gtk-doc counterpart * Add missing descriptions --- clutter/clutter-actor.h | 4 +++ clutter/clutter-animation.c | 2 +- clutter/clutter-container.h | 5 ++++ clutter/clutter-main.h | 2 +- clutter/clutter-texture.c | 2 +- clutter/cogl/cogl-material.h | 5 ++++ clutter/cogl/cogl-shader.h | 14 +++++++-- clutter/cogl/cogl-vertex-buffer.h | 33 ++++++++++++++-------- clutter/cogl/cogl.h.in | 4 +++ doc/reference/clutter/clutter-sections.txt | 7 +++-- doc/reference/cogl/cogl-sections.txt | 6 ---- 11 files changed, 58 insertions(+), 26 deletions(-) diff --git a/clutter/clutter-actor.h b/clutter/clutter-actor.h index 38039a670..086b64d10 100644 --- a/clutter/clutter-actor.h +++ b/clutter/clutter-actor.h @@ -180,6 +180,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 diff --git a/clutter/clutter-animation.c b/clutter/clutter-animation.c index 5cba38595..d1bd5b830 100644 --- a/clutter/clutter-animation.c +++ b/clutter/clutter-animation.c @@ -389,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 diff --git a/clutter/clutter-container.h b/clutter/clutter-container.h index dc1a60151..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 diff --git a/clutter/clutter-main.h b/clutter/clutter-main.h index a5365f0d9..d6f1099d0 100644 --- a/clutter/clutter-main.h +++ b/clutter/clutter-main.h @@ -140,7 +140,7 @@ guint clutter_threads_add_frame_source_full (gint priority, guint clutter_threads_add_repaint_func (GSourceFunc func, gpointer data, GDestroyNotify notify); -void clutter_threads_remove_repaint_func (guint handler_id); +void clutter_threads_remove_repaint_func (guint handle_id); void clutter_set_motion_events_enabled (gboolean enable); gboolean clutter_get_motion_events_enabled (void); diff --git a/clutter/clutter-texture.c b/clutter/clutter-texture.c index 3bb1e6448..956d00578 100644 --- a/clutter/clutter-texture.c +++ b/clutter/clutter-texture.c @@ -2718,7 +2718,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/cogl/cogl-material.h b/clutter/cogl/cogl-material.h index da822564e..504c173fa 100644 --- a/clutter/cogl/cogl-material.h +++ b/clutter/cogl/cogl-material.h @@ -616,6 +616,11 @@ const GList *cogl_material_get_layers (CoglHandle material_handle); * CoglMaterialLayerType: * @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 { diff --git a/clutter/cogl/cogl-shader.h b/clutter/cogl/cogl-shader.h index 59c75ede6..f5280722f 100644 --- a/clutter/cogl/cogl-shader.h +++ b/clutter/cogl/cogl-shader.h @@ -46,6 +46,10 @@ 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 { @@ -132,8 +136,10 @@ void 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 +147,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-vertex-buffer.h b/clutter/cogl/cogl-vertex-buffer.h index ba2cef8b2..ab37dbced 100644 --- a/clutter/cogl/cogl-vertex-buffer.h +++ b/clutter/cogl/cogl-vertex-buffer.h @@ -96,12 +96,17 @@ cogl_vertex_buffer_get_n_vertices (CoglHandle handle); /** * CoglAttributeType: - * @COGL_ATTRIBUTE_TYPE_BYTE: - * @COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE: - * @COGL_ATTRIBUTE_TYPE_SHORT: - * @COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT: - * @COGL_ATTRIBUTE_TYPE_FLOAT: + * @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 { @@ -245,14 +250,18 @@ cogl_vertex_buffer_enable (CoglHandle handle, /** * CoglVerticesMode: - * COGL_VERTICES_MODE_POINTS: - * COGL_VERTICES_MODE_LINE_STRIP: - * COGL_VERTICES_MODE_LINE_LOOP: - * COGL_VERTICES_MODE_LINES: - * COGL_VERTICES_MODE_TRIANGLE_STRIP: - * COGL_VERTICES_MODE_TRIANGLE_FAN: - * COGL_VERTICES_MODE_TRIANGLES: + * @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 { diff --git a/clutter/cogl/cogl.h.in b/clutter/cogl/cogl.h.in index a671aa00d..611d358ba 100644 --- a/clutter/cogl/cogl.h.in +++ b/clutter/cogl/cogl.h.in @@ -412,6 +412,10 @@ 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 { diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt index 20457729d..67c1eb866 100644 --- a/doc/reference/clutter/clutter-sections.txt +++ b/doc/reference/clutter/clutter-sections.txt @@ -47,6 +47,7 @@ CLUTTER_UNITS_FROM_EM clutter_units_mm clutter_units_pt clutter_units_em +clutter_units_em_for_font clutter_units_pixels clutter_units_to_pixels @@ -438,10 +439,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 @@ -1016,6 +1016,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 @@ -1508,6 +1510,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/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index c34585ff1..9d49ea53f 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -376,15 +376,9 @@ CoglMaterialLayerPrivFlags
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
From 3248bb1b755ae23cfb1a2eabd7a72b803faa5a31 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 29 May 2009 12:31:47 +0100 Subject: [PATCH 085/138] [cogl] Generate enumeration GTypes COGL is starting to have more enumerations than I can handle by hand. Let's use glib-mkenums and be done with it. --- .gitignore | 3 + clutter/cogl/Makefile.am | 40 +++--- clutter/cogl/cogl-shader.h | 5 +- clutter/cogl/cogl-types.h | 79 ++---------- clutter/cogl/cogl.h.in | 11 +- clutter/cogl/common/Makefile.am | 53 +++++++- clutter/cogl/common/cogl-enum-types.c.in | 33 +++++ clutter/cogl/common/cogl-enum-types.h.in | 25 ++++ clutter/cogl/common/cogl-util.c | 154 ----------------------- clutter/cogl/gl/Makefile.am | 5 - 10 files changed, 159 insertions(+), 249 deletions(-) create mode 100644 clutter/cogl/common/cogl-enum-types.c.in create mode 100644 clutter/cogl/common/cogl-enum-types.h.in diff --git a/.gitignore b/.gitignore index 83d8e5981..2c2298771 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 diff --git a/clutter/cogl/Makefile.am b/clutter/cogl/Makefile.am index 225b66100..1490ec68a 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,19 +29,24 @@ 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-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) # 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 @@ -44,6 +55,9 @@ noinst_LTLIBRARIES = libclutter-cogl.la libclutter_cogl_la_LIBADD = $(CLUTTER_COGL)/libclutter-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 $(QUIET_GEN)$(INTROSPECTION_SCANNER) -v \ @@ -59,8 +73,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-shader.h b/clutter/cogl/cogl-shader.h index f5280722f..d0b0ce13e 100644 --- a/clutter/cogl/cogl-shader.h +++ b/clutter/cogl/cogl-shader.h @@ -51,8 +51,7 @@ G_BEGIN_DECLS * * Since: 1.0 */ -typedef enum _CoglShaderType -{ +typedef enum { COGL_SHADER_TYPE_VERTEX, COGL_SHADER_TYPE_FRAGMENT } CoglShaderType; @@ -115,7 +114,7 @@ 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: diff --git a/clutter/cogl/cogl-types.h b/clutter/cogl/cogl-types.h index 719ecd087..3aa6f5c3c 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: * @@ -304,9 +258,6 @@ typedef enum { 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: @@ -335,16 +286,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.h.in b/clutter/cogl/cogl.h.in index 611d358ba..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 @@ -417,8 +418,7 @@ void cogl_disable_fog (void); * * 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 @@ -427,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: diff --git a/clutter/cogl/common/Makefile.am b/clutter/cogl/common/Makefile.am index c4e6eb2f7..df50a1d16 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 + $(QUIET_CP)cp -f $(@F) $(top_builddir)/clutter/cogl/cogl-enum-types.h + +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) \ + && 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 \ @@ -41,4 +85,9 @@ libclutter_cogl_common_la_SOURCES = \ cogl-material-private.h \ cogl-blend-string.c \ cogl-blend-string.h \ - cogl-debug.c + cogl-debug.c \ + $(NULL) + +EXTRA_DIST = stb_image.c cogl-enum-types.h.in cogl-enum-types.h.in +CLEANFILES = stamp-cogl-enum-types.h +DISTCLEANFILES = cogl-enum-types.h cogl-enum-types.c 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..f2c01c78c --- /dev/null +++ b/clutter/cogl/common/cogl-enum-types.c.in @@ -0,0 +1,33 @@ +/*** 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 GType etype = 0; + + if (G_UNLIKELY (!etype)) + { + static const G@Type@Value values[] = { +/*** END value-header ***/ + +/*** BEGIN value-production ***/ + { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, +/*** END value-production ***/ + +/*** BEGIN value-tail ***/ + { 0, NULL, NULL } + }; + etype = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); + } + + return etype; +} +/*** 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-util.c b/clutter/cogl/common/cogl-util.c index 2b9ccba27..2d86f73f3 100644 --- a/clutter/cogl/common/cogl-util.c +++ b/clutter/cogl/common/cogl-util.c @@ -103,160 +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" }, - { COGL_TEXTURE_NO_SLICING, "COGL_TEXTURE_NO_SLICING", "no-slicing" }, - { 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/gl/Makefile.am b/clutter/cogl/gl/Makefile.am index 367f674f2..dc33e0bb1 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 \ From b4861cbd21210b99294b93ea18bbfb4724a0aca6 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 29 May 2009 12:40:23 +0100 Subject: [PATCH 086/138] Use g_once when registering enumeration types Just like we do with GObject types and G_DEFINE_TYPE, we should use the g_once_init_enter/g_once_init_leave mechanism to make the GType registration of enumeration types thread safe. --- clutter/clutter-enum-types.c.in | 20 +++++++++++++++----- clutter/cogl/common/cogl-enum-types.c.in | 18 +++++++++++++----- 2 files changed, 28 insertions(+), 10 deletions(-) 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/cogl/common/cogl-enum-types.c.in b/clutter/cogl/common/cogl-enum-types.c.in index f2c01c78c..157180dfe 100644 --- a/clutter/cogl/common/cogl-enum-types.c.in +++ b/clutter/cogl/common/cogl-enum-types.c.in @@ -4,16 +4,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; +@enum_name@_get_type (void) +{ + static volatile gsize g_enum_type_id__volatile = 0; - if (G_UNLIKELY (!etype)) + if (g_once_init_enter (&g_enum_type_id__volatile)) { static const G@Type@Value values[] = { /*** END value-header ***/ @@ -25,9 +28,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 ***/ From e565c1f1dbfdb29fcaa7065d078f524c8432c12c Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 29 May 2009 12:50:48 +0100 Subject: [PATCH 087/138] [build] Encode the target into the backend library The libclutter-cogl internal object should be the only dependency for Clutter, since we are already copying it inside clutter/cogl for the introspection scanner. For this reason, the backend-specific, real internal object should be built with the backend encoded into the file name, like libclutter-common. This makes the build output a little bit more clear: instead of having two: LINK libclutter-cogl-common.la ... LINK libclutter-cogl.la LINK libclutter-cogl.la We'll have: LINK libclutter-cogl-common.la ... LINK libclutter-cogl-gl.la LINK libclutter-cogl.la Same applies for the GLES backend. --- clutter/cogl/Makefile.am | 4 ++-- clutter/cogl/gl/Makefile.am | 10 +++++----- clutter/cogl/gles/Makefile.am | 12 ++++++------ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/clutter/cogl/Makefile.am b/clutter/cogl/Makefile.am index 1490ec68a..4cbcef334 100644 --- a/clutter/cogl/Makefile.am +++ b/clutter/cogl/Makefile.am @@ -52,14 +52,14 @@ cogl_headers = \ # 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 \ diff --git a/clutter/cogl/gl/Makefile.am b/clutter/cogl/gl/Makefile.am index dc33e0bb1..1aab5b649 100644 --- a/clutter/cogl/gl/Makefile.am +++ b/clutter/cogl/gl/Makefile.am @@ -45,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/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 \ From cfb95084651b0ea199eecef5993d7fc2da3586fa Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Fri, 29 May 2009 14:23:16 +0100 Subject: [PATCH 088/138] [configure] Always execute the AM_CONDITIONAL call for X11_TESTS Automake gets upset if an AM_CONDITIONAL call is itself conditionally executed. --- configure.ac | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4524d3df3..419a0c402 100644 --- a/configure.ac +++ b/configure.ac @@ -397,6 +397,7 @@ AS_CASE([$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"], [ @@ -504,10 +505,11 @@ AS_IF([test "x$clutterbackend" = "xglx" || test "x$clutterbackend" = "xeglx"], # 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"]) ] ) +AM_CONDITIONAL(X11_TESTS, [test "x$x11_tests" = "xyes"]) + dnl === JSON parser check ===================================================== # allow building clutter with an external dependency on json-glib From cbbc1a9ca36972ee0bf0612605c5176ce9b63b7f Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 29 May 2009 14:27:55 +0100 Subject: [PATCH 089/138] [build] Copy cogl-enum-types.h under the guard We avoid rebuilding cogl-enum-types.h and cogl-enum-types.c by using a "guard" -- a stamp file that will block Makefile. Since we need cogl-enum-types.h into /clutter/cogl as well for the cogl.h include to work, if we copy the cogl-enum-types.h unconditionally it will cause a rebuild of the whole COGL; which will cause a full rebuild. To solve this, we can copy the header file when generating it under the stamp file. --- clutter/cogl/common/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clutter/cogl/common/Makefile.am b/clutter/cogl/common/Makefile.am index df50a1d16..a61ed8dda 100644 --- a/clutter/cogl/common/Makefile.am +++ b/clutter/cogl/common/Makefile.am @@ -35,13 +35,13 @@ cogl_public_h = \ noinst_LTLIBRARIES = libclutter-cogl-common.la cogl-enum-types.h: stamp-cogl-enum-types.h - $(QUIET_CP)cp -f $(@F) $(top_builddir)/clutter/cogl/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) From 63c7cc0175461a08e5b1d3f3b78e37d581a03ffd Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 29 May 2009 14:25:19 +0100 Subject: [PATCH 090/138] [master clock] Handle Timeline::started signal correctly The "started" signal is sent first after the timeline has been set to the 'running' state. For this reason, checking if the clock has any running timelines running will always return true in the "started" signal handler: the timeline that sent the signal is running. What needs to be checked in the signal handler is if there are any timelines running other than the one that emitted the ::started signal, which we know is running anyway. This prevents frames from being lost at the beginning of an animation when a timeline is started after a quiescent period. Fixes bug: http://bugzilla.openedhand.com/show_bug.cgi?id=1617 Signed-off-by: Jonas Bonn Signed-off-by: Emmanuele Bassi --- clutter/clutter-master-clock.c | 67 ++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 7 deletions(-) diff --git a/clutter/clutter-master-clock.c b/clutter/clutter-master-clock.c index 8b10238f2..430edd3aa 100644 --- a/clutter/clutter-master-clock.c +++ b/clutter/clutter-master-clock.c @@ -107,8 +107,21 @@ static GSourceFuncs clock_funcs = { 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 -_clutter_master_clock_has_running_timeline (ClutterMasterClock *master_clock) +has_running_timeline (ClutterMasterClock *master_clock, + ClutterTimeline *filter) { GSList *l; @@ -120,6 +133,12 @@ _clutter_master_clock_has_running_timeline (ClutterMasterClock *master_clock) 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; } @@ -127,6 +146,17 @@ _clutter_master_clock_has_running_timeline (ClutterMasterClock *master_clock) 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) { @@ -146,9 +176,10 @@ clutter_clock_prepare (GSource *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 = _clutter_master_clock_has_running_timeline (master_clock); + retval = has_running_timeline (master_clock, NULL); return retval; } @@ -160,7 +191,7 @@ clutter_clock_check (GSource *source) ClutterMasterClock *master_clock = clock_source->master_clock; gboolean retval; - retval = _clutter_master_clock_has_running_timeline (master_clock); + retval = has_running_timeline (master_clock, NULL); return retval; } @@ -177,17 +208,25 @@ clutter_clock_dispatch (GSource *source, CLUTTER_NOTE (SCHEDULER, "Master clock [tick]"); + /* FIXME - we need peek_stages() to avoid the copy */ stages = clutter_stage_manager_list_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); g_slist_free (stages); + /* 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->last_advance = FALSE; master_clock->prev_tick.tv_sec = 0; + master_clock->last_advance = FALSE; } return TRUE; @@ -281,7 +320,12 @@ static void on_timeline_started (ClutterTimeline *timeline, ClutterMasterClock *master_clock) { - if (!_clutter_master_clock_has_running_timeline (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; } @@ -294,7 +338,7 @@ on_timeline_completed (ClutterTimeline *timeline, * frame; otherwise the ClockSource will fail the prepare and * check phases and the last frame will not be painted */ - if (!_clutter_master_clock_has_running_timeline (master_clock)) + if (!has_running_timeline (master_clock, NULL)) master_clock->last_advance = TRUE; } @@ -303,7 +347,7 @@ on_timeline_paused (ClutterTimeline *timeline, ClutterMasterClock *master_clock) { /* see the comment in on_timeline_completed */ - if (!_clutter_master_clock_has_running_timeline (master_clock)) + if (!has_running_timeline (master_clock, NULL)) master_clock->last_advance = TRUE; } @@ -378,6 +422,9 @@ _clutter_master_clock_remove_timeline (ClutterMasterClock *master_clock, 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; } @@ -410,6 +457,9 @@ _clutter_master_clock_advance (ClutterMasterClock *master_clock) 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); @@ -422,6 +472,9 @@ _clutter_master_clock_advance (ClutterMasterClock *master_clock) 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; } From 5d4974ed365d9882945f211f1dadd067b4b2d8b1 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 29 May 2009 14:45:53 +0100 Subject: [PATCH 091/138] [stage manager] Add peek_stages() We need an method for StageManager that returns a const pointer to the internal list, to avoid the copy. --- clutter/clutter-stage-manager.c | 24 ++++++++++++++++++++++-- clutter/clutter-stage-manager.h | 1 + 2 files changed, 23 insertions(+), 2 deletions(-) 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 From c5e659d5922b406059c94545c1a5c773f61b2379 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 29 May 2009 14:52:49 +0100 Subject: [PATCH 092/138] [master clock] Use StageManager::peek_stages() Use the new StageManager::peek_stages() method to avoid a copy of the stages list. --- clutter/clutter-master-clock.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/clutter/clutter-master-clock.c b/clutter/clutter-master-clock.c index 430edd3aa..ea3440555 100644 --- a/clutter/clutter-master-clock.c +++ b/clutter/clutter-master-clock.c @@ -204,12 +204,11 @@ clutter_clock_dispatch (GSource *source, ClutterClockSource *clock_source = (ClutterClockSource *) source; ClutterMasterClock *master_clock = clock_source->master_clock; ClutterStageManager *stage_manager = clutter_stage_manager_get_default (); - GSList *stages, *l; + const GSList *stages, *l; CLUTTER_NOTE (SCHEDULER, "Master clock [tick]"); - /* FIXME - we need peek_stages() to avoid the copy */ - stages = clutter_stage_manager_list_stages (stage_manager); + 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 @@ -218,8 +217,6 @@ clutter_clock_dispatch (GSource *source, for (l = stages; l != NULL; l = l->next) clutter_actor_queue_redraw (l->data); - g_slist_free (stages); - /* 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 */ From 1187972e45b8c64ad25c2a243b0112bbde84e3e6 Mon Sep 17 00:00:00 2001 From: Jonas Bonn Date: Thu, 28 May 2009 09:40:09 +0200 Subject: [PATCH 093/138] [animation] Final cleanups to new Animation model Just a couple of final cleanups after the reimplementation of the Animation model. i) _set_mode does not need to set the timeline on the alpha ii) freeze notifications around the setting of a new alpha Signed-off-by: Jonas Bonn Signed-off-by: Emmanuele Bassi --- clutter/clutter-animation.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/clutter/clutter-animation.c b/clutter/clutter-animation.c index d1bd5b830..9fbb71f20 100644 --- a/clutter/clutter-animation.c +++ b/clutter/clutter-animation.c @@ -1018,7 +1018,6 @@ void clutter_animation_set_mode (ClutterAnimation *animation, gulong mode) { - ClutterTimeline *timeline; ClutterAlpha *alpha; g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); @@ -1028,9 +1027,6 @@ clutter_animation_set_mode (ClutterAnimation *animation, alpha = clutter_animation_get_alpha_internal (animation); clutter_alpha_set_mode (alpha, mode); - timeline = clutter_animation_get_timeline_internal (animation); - clutter_alpha_set_timeline (alpha, timeline); - g_object_notify (G_OBJECT (animation), "mode"); g_object_thaw_notify (G_OBJECT (animation)); @@ -1267,6 +1263,8 @@ clutter_animation_set_alpha (ClutterAnimation *animation, if (priv->alpha == alpha) return; + g_object_freeze_notify (G_OBJECT (animation)); + if (priv->alpha != NULL) timeline = clutter_alpha_get_timeline (priv->alpha); else @@ -1300,7 +1298,7 @@ clutter_animation_set_alpha (ClutterAnimation *animation, } if (alpha == NULL) - return; + goto out; priv->alpha = g_object_ref_sink (alpha); priv->alpha_notify_id = @@ -1324,12 +1322,15 @@ clutter_animation_set_alpha (ClutterAnimation *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)); } /** From faec5c468ba77e61a3f724be49f031be65ef2011 Mon Sep 17 00:00:00 2001 From: Jonas Bonn Date: Thu, 28 May 2009 09:47:45 +0200 Subject: [PATCH 094/138] Freeze notifiers around property setters Notifications should be fired off from both the internal timeline and the wrapping animation here, so notifiers should be frozen around these property setters. Signed-off-by: Jonas Bonn Signed-off-by: Emmanuele Bassi --- clutter/clutter-animation.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/clutter/clutter-animation.c b/clutter/clutter-animation.c index 9fbb71f20..f84368142 100644 --- a/clutter/clutter-animation.c +++ b/clutter/clutter-animation.c @@ -1075,11 +1075,15 @@ clutter_animation_set_duration (ClutterAnimation *animation, g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); + g_object_freeze_notify (G_OBJECT (animation)); + 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)); } /** @@ -1105,10 +1109,14 @@ clutter_animation_set_loop (ClutterAnimation *animation, g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); + g_object_freeze_notify (G_OBJECT (animation)); + timeline = clutter_animation_get_timeline_internal (animation); clutter_timeline_set_loop (timeline, loop); g_object_notify (G_OBJECT (animation), "loop"); + + g_object_thaw_notify (G_OBJECT (animation)); } /** From 936f638a4234b0dd9f5122447bf09f8fcde1ac26 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 29 May 2009 17:10:27 +0100 Subject: [PATCH 095/138] [build] Fix dist issues * cogl-deprecated.h is not being installed * cogl-enum-types.c.in is not part of the dist --- clutter/cogl/Makefile.am | 1 + clutter/cogl/common/Makefile.am | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/clutter/cogl/Makefile.am b/clutter/cogl/Makefile.am index 4cbcef334..5dec59880 100644 --- a/clutter/cogl/Makefile.am +++ b/clutter/cogl/Makefile.am @@ -34,6 +34,7 @@ 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-deprecated.h \ $(top_srcdir)/clutter/cogl/cogl-fixed.h \ $(top_srcdir)/clutter/cogl/cogl-material.h \ $(top_srcdir)/clutter/cogl/cogl-matrix.h \ diff --git a/clutter/cogl/common/Makefile.am b/clutter/cogl/common/Makefile.am index a61ed8dda..7a7dd8232 100644 --- a/clutter/cogl/common/Makefile.am +++ b/clutter/cogl/common/Makefile.am @@ -88,6 +88,6 @@ libclutter_cogl_common_la_SOURCES = \ cogl-debug.c \ $(NULL) -EXTRA_DIST = stb_image.c cogl-enum-types.h.in cogl-enum-types.h.in +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 From 293eeed507460ef6a9168264b04f119acf567eb7 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 29 May 2009 17:50:58 +0100 Subject: [PATCH 096/138] [build] Remove cogl-enum-types.h on distclean The cogl-enum-types.h file is created by glib-mkenums under /clutter/cogl/common, and then copied in /clutter/cogl in order to make the inclusion of that file work inside cogl.h. Since we're copying it in a different location, the Makefile for that location has to clean up the copy. --- clutter/cogl/Makefile.am | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clutter/cogl/Makefile.am b/clutter/cogl/Makefile.am index 5dec59880..cae798703 100644 --- a/clutter/cogl/Makefile.am +++ b/clutter/cogl/Makefile.am @@ -49,6 +49,10 @@ cogl_headers = \ $(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 From 4afe1e9a8b7822522e990989ad156df49bfc29e3 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 29 May 2009 17:53:19 +0100 Subject: [PATCH 097/138] [actor] Add allocate_available_size() The allocate_available_size() method is a convenience method in the same spirit as allocate_preferred_size(). While the latter will allocate the preferred size of an actor regardless of the available size provided by the actor's parent -- and thus it's suitable for simple fixed layout managers like ClutterGroup -- the former will take into account the available size provided by the parent and never allocate more than that; it is, thus, suitable for simple fluid layout managers. --- clutter/clutter-actor.c | 112 +++++++++++++++++++++ clutter/clutter-actor.h | 6 ++ doc/reference/clutter/clutter-sections.txt | 1 + 3 files changed, 119 insertions(+) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 3dc06e635..3d6cab872 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -8166,6 +8166,118 @@ 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 + * @absolute_origin_changed: whether the position of the parent has + * changed in stage coordinates + * + * 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, absolute_origin_changed); + * ]| + * + * 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, + gboolean absolute_origin_changed) +{ + 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, absolute_origin_changed); +} + /** * clutter_actor_allocate_preferred_size: * @self: a #ClutterActor diff --git a/clutter/clutter-actor.h b/clutter/clutter-actor.h index 086b64d10..e30f85b66 100644 --- a/clutter/clutter-actor.h +++ b/clutter/clutter-actor.h @@ -323,6 +323,12 @@ void clutter_actor_allocate (ClutterActor gboolean absolute_origin_changed); void clutter_actor_allocate_preferred_size (ClutterActor *self, gboolean absolute_origin_changed); +void clutter_actor_allocate_available_size (ClutterActor *self, + gfloat x, + gfloat y, + gfloat available_width, + gfloat available_height, + gboolean absolute_origin_changed); void clutter_actor_get_allocation_coords (ClutterActor *self, gint *x_1, gint *y_1, diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt index 67c1eb866..142d28b82 100644 --- a/doc/reference/clutter/clutter-sections.txt +++ b/doc/reference/clutter/clutter-sections.txt @@ -301,6 +301,7 @@ 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 From 67544f38d4dc93bd1be477656171681c5acf9721 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 28 May 2009 13:47:18 +0100 Subject: [PATCH 098/138] [cogl-vertex-buffer] Add cogl_vertex_buffer_indices_get_for_quads This function can be used as an efficient way of drawing groups of quads without using GL_QUADS. It generates a VBO containing the indices needed to render using pairs of GL_TRIANGLES. The VBO is globally cached so that it only needs to be uploaded whenever more indices are requested than ever before. --- clutter/cogl/cogl-vertex-buffer.h | 40 ++++++++++++ clutter/cogl/common/cogl-vertex-buffer.c | 80 ++++++++++++++++++++++++ clutter/cogl/gl/cogl-context.c | 9 +++ clutter/cogl/gl/cogl-context.h | 6 ++ clutter/cogl/gles/cogl-context.c | 9 +++ clutter/cogl/gles/cogl-context.h | 7 ++- doc/reference/cogl/cogl-sections.txt | 1 + 7 files changed, 151 insertions(+), 1 deletion(-) diff --git a/clutter/cogl/cogl-vertex-buffer.h b/clutter/cogl/cogl-vertex-buffer.h index ab37dbced..f01b5d3dd 100644 --- a/clutter/cogl/cogl-vertex-buffer.h +++ b/clutter/cogl/cogl-vertex-buffer.h @@ -394,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/common/cogl-vertex-buffer.c b/clutter/cogl/common/cogl-vertex-buffer.c index b3c36f0ec..a36bb1cec 100644 --- a/clutter/cogl/common/cogl-vertex-buffer.c +++ b/clutter/cogl/common/cogl-vertex-buffer.c @@ -1880,3 +1880,83 @@ _cogl_vertex_buffer_free (CoglVertexBuffer *buffer) 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/gl/cogl-context.c b/clutter/cogl/gl/cogl-context.c index 39415a02a..16fcb3e12 100644 --- a/clutter/cogl/gl/cogl-context.c +++ b/clutter/cogl/gl/cogl-context.c @@ -171,6 +171,10 @@ cogl_create_context () _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; } @@ -207,6 +211,11 @@ _cogl_destroy_context () 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 f490d39ac..f5ca54cb2 100644 --- a/clutter/cogl/gl/cogl-context.h +++ b/clutter/cogl/gl/cogl-context.h @@ -102,6 +102,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; diff --git a/clutter/cogl/gles/cogl-context.c b/clutter/cogl/gles/cogl-context.c index 5b6ce7c1b..d3ec31c5d 100644 --- a/clutter/cogl/gles/cogl-context.c +++ b/clutter/cogl/gles/cogl-context.c @@ -129,6 +129,10 @@ cogl_create_context () _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; } @@ -165,6 +169,11 @@ _cogl_destroy_context () 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..9c1d44fbe 100644 --- a/clutter/cogl/gles/cogl-context.h +++ b/clutter/cogl/gles/cogl-context.h @@ -104,6 +104,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 +117,6 @@ typedef struct supported */ GLint viewport_store[4]; #endif - } CoglContext; CoglContext * diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index 9d49ea53f..f596ee042 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -313,6 +313,7 @@ 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 From 97921a7d137bde2b73cfb2dabea89c14e30510a9 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Fri, 29 May 2009 11:38:03 +0100 Subject: [PATCH 099/138] [pango-display-list] Use indexed vertices on GLES Now that CoglVertexBuffers support indices we can use them with GLES to avoid duplicating vertices. Regular GL still uses GL_QUADS because it is shown to still have a performance benefit over indices with the Intel drivers. --- clutter/pango/cogl-pango-display-list.c | 47 +++++++++++-------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/clutter/pango/cogl-pango-display-list.c b/clutter/pango/cogl-pango-display-list.c index b87b609f9..6d46fa8b3 100644 --- a/clutter/pango/cogl-pango-display-list.c +++ b/clutter/pango/cogl-pango-display-list.c @@ -41,13 +41,6 @@ typedef enum typedef struct _CoglPangoDisplayListNode CoglPangoDisplayListNode; typedef struct _CoglPangoDisplayListVertex CoglPangoDisplayListVertex; -#ifdef HAVE_CLUTTER_GLX -#define COGL_PANGO_DISPLAY_LIST_DRAW_MODE GL_QUADS -#else -/* GLES doesn't support GL_QUADS so we use GL_TRIANGLES instead */ -#define COGL_PANGO_DISPLAY_LIST_DRAW_MODE GL_TRIANGLES -#endif - struct _CoglPangoDisplayList { CoglColor color; @@ -184,24 +177,6 @@ _cogl_pango_display_list_add_texture (CoglPangoDisplayList *dl, verts->y = y_1; verts->t_x = tx_2; verts->t_y = ty_1; - -#ifndef HAVE_CLUTTER_GLX - - /* GLES doesn't support GL_QUADS so we use GL_TRIANGLES instead with - two extra vertices per quad. FIXME: It might be better to use - indexed elements here but cogl vertex buffers don't currently - support storing the indices */ - - g_array_set_size (node->d.texture.verts, - node->d.texture.verts->len + 2); - verts = &g_array_index (node->d.texture.verts, - CoglPangoDisplayListVertex, - node->d.texture.verts->len - 6); - - verts[4] = verts[0]; - verts[5] = verts[2]; - -#endif /* HAVE_CLUTTER_GLX */ } void @@ -270,9 +245,29 @@ _cogl_pango_display_list_render_texture (CoglHandle material, node->d.texture.vertex_buffer = vb; } + +#ifdef CLUTTER_COGL_HAS_GL + cogl_vertex_buffer_draw (node->d.texture.vertex_buffer, - COGL_PANGO_DISPLAY_LIST_DRAW_MODE, + 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 From 3b70e0b6b7a3c01c9e9d0c15f39b676877eee119 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Fri, 29 May 2009 11:52:21 +0100 Subject: [PATCH 100/138] [pango-display-list] Use the CoglAttributeType macros instead of GL_FLOAT Cogl now has an enum for the VBO attribute type so we should use that instead of the GL enums. --- clutter/pango/cogl-pango-display-list.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clutter/pango/cogl-pango-display-list.c b/clutter/pango/cogl-pango-display-list.c index 6d46fa8b3..70f640517 100644 --- a/clutter/pango/cogl-pango-display-list.c +++ b/clutter/pango/cogl-pango-display-list.c @@ -231,11 +231,13 @@ _cogl_pango_display_list_render_texture (CoglHandle material, { CoglHandle vb = cogl_vertex_buffer_new (node->d.texture.verts->len); - cogl_vertex_buffer_add (vb, "gl_Vertex", 2, GL_FLOAT, FALSE, + 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, GL_FLOAT, FALSE, + cogl_vertex_buffer_add (vb, "gl_MultiTexCoord0", 2, + COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, sizeof (CoglPangoDisplayListVertex), &g_array_index (node->d.texture.verts, CoglPangoDisplayListVertex, From 8b71fa1acbb8580e61ce30fd6a48a4bf0024ba97 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Sun, 31 May 2009 15:06:16 +0100 Subject: [PATCH 101/138] [docs] Remove misleading text The documentation for ClutterTexture's set_from_rgb_data() and set_from_yuv_data() says: Note: This function is likely to change in future versions. This is not true, since they'll remain for the whole 1.x API cycle. --- clutter/clutter-texture.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/clutter/clutter-texture.c b/clutter/clutter-texture.c index 956d00578..267c8e24b 100644 --- a/clutter/clutter-texture.c +++ b/clutter/clutter-texture.c @@ -1522,25 +1522,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); @@ -1593,8 +1591,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 From bafa448666a73dd06b69b6167138c3c43e854482 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Sun, 31 May 2009 15:07:58 +0100 Subject: [PATCH 102/138] [texture] Increase verbosity of error messages The GError messages in set_from_rgb_data() and set_from_yuv_data() are a little bit too thin on details. --- clutter/clutter-texture.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/clutter/clutter-texture.c b/clutter/clutter-texture.c index 267c8e24b..ac53b73fc 100644 --- a/clutter/clutter-texture.c +++ b/clutter/clutter-texture.c @@ -1551,9 +1551,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 @@ -1562,11 +1566,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)) @@ -1622,7 +1631,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; } From c759aeb6a720043b8b74242d5e18da405be3825d Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Sun, 31 May 2009 15:15:46 +0100 Subject: [PATCH 103/138] Uniformly use floats in Actor properties All the underlying implementation and the public entry points have been switched to floats; the only missing bits are the Actor properties that deal with positioning and sizing. This usually means a major pain when dealing with GValues and varargs functions. While GValue will warn you when dealing with the wrong conversions, varags will simply die an horrible (and hard to debug) death via segfault. Nothing much to do here, except warn people in the release notes and hope for the best. --- clutter/clutter-actor.c | 353 +++++++++++------- clutter/clutter-interval.c | 12 +- tests/conform/Makefile.am | 3 + tests/conform/test-anchors.c | 145 +++---- tests/conform/test-binding-pool.c | 18 +- tests/interactive/test-animation.c | 8 +- .../interactive/test-clutter-cairo-flowers.c | 23 +- tests/interactive/test-cogl-multitexture.c | 2 +- tests/interactive/test-cogl-tex-polygon.c | 2 +- tests/interactive/test-cogl-tex-tile.c | 2 +- tests/interactive/test-easing.c | 4 +- tests/interactive/test-layout.c | 17 +- tests/interactive/test-multistage.c | 2 +- tests/interactive/test-paint-wrapper.c | 2 +- tests/interactive/test-rotate.c | 2 +- tests/interactive/test-shader.c | 3 +- 16 files changed, 346 insertions(+), 252 deletions(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 3d6cab872..ac3f42dad 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -2369,91 +2369,109 @@ 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_x (actor, clutter_value_get_unit (value)); + clutter_actor_set_x (actor, g_value_get_float (value)); break; + case PROP_FIXED_Y: - clutter_actor_set_y (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: { - gint center_x = g_value_get_int (value); + gfloat center_x = g_value_get_float (value); gfloat center_y; clutter_anchor_coord_get_units (actor, &priv->scale_center, @@ -2467,9 +2485,10 @@ clutter_actor_set_property (GObject *object, center_y); } break; + case PROP_SCALE_CENTER_Y: { - 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, @@ -2483,21 +2502,24 @@ clutter_actor_set_property (GObject *object, 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)) { @@ -2505,24 +2527,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; @@ -2536,6 +2563,7 @@ clutter_actor_set_property (GObject *object, center->z); } break; + case PROP_ROTATION_CENTER_Y: { const ClutterVertex *center; @@ -2549,6 +2577,7 @@ clutter_actor_set_property (GObject *object, center->z); } break; + case PROP_ROTATION_CENTER_Z: { const ClutterVertex *center; @@ -2562,13 +2591,15 @@ 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: { - gint anchor_x = g_value_get_int (value); + gfloat anchor_x = g_value_get_float (value); gfloat anchor_y; clutter_anchor_coord_get_units (actor, &priv->anchor, @@ -2578,10 +2609,11 @@ clutter_actor_set_property (GObject *object, clutter_actor_set_anchor_point (actor, anchor_x, anchor_y); } break; + case PROP_ANCHOR_Y: { - gint anchor_y = g_value_get_int (value); - gfloat anchor_x; + gfloat anchor_y = g_value_get_int (value); + gfloat anchor_x; clutter_anchor_coord_get_units (actor, &priv->anchor, &anchor_x, @@ -2590,13 +2622,16 @@ clutter_actor_set_property (GObject *object, 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; @@ -2609,86 +2644,107 @@ 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)); 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, }; @@ -2701,48 +2757,59 @@ clutter_actor_get_property (GObject *object, 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: { 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: { 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; @@ -2755,6 +2822,7 @@ clutter_actor_get_property (GObject *object, g_value_set_boxed (value, ¢er); } break; + case PROP_ROTATION_CENTER_Y: { ClutterVertex center; @@ -2767,6 +2835,7 @@ clutter_actor_get_property (GObject *object, g_value_set_boxed (value, ¢er); } break; + case PROP_ROTATION_CENTER_Z: { ClutterVertex center; @@ -2779,9 +2848,11 @@ clutter_actor_get_property (GObject *object, 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: { gfloat anchor_x; @@ -2790,9 +2861,10 @@ clutter_actor_get_property (GObject *object, &anchor_x, NULL, NULL); - g_value_set_int (value, anchor_x); + g_value_set_float (value, anchor_x); } break; + case PROP_ANCHOR_Y: { gfloat anchor_y; @@ -2801,15 +2873,18 @@ clutter_actor_get_property (GObject *object, NULL, &anchor_y, NULL); - g_value_set_int (value, anchor_y); + 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; @@ -2896,12 +2971,12 @@ 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. */ - pspec = 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); /** @@ -2911,12 +2986,12 @@ 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. */ - pspec = 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); /** @@ -2926,12 +3001,12 @@ 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. */ - pspec = 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: @@ -2940,12 +3015,12 @@ 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_int ("height", - "Height", - "Height of the actor", - 0, G_MAXINT, - 0, - CLUTTER_PARAM_READWRITE); + 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); /** @@ -2958,12 +3033,12 @@ clutter_actor_class_init (ClutterActorClass *klass) * * Since: 0.8 */ - pspec = 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 ("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); /** @@ -2976,12 +3051,12 @@ clutter_actor_class_init (ClutterActorClass *klass) * * Since: 0.8 */ - pspec = 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 ("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); /** @@ -3014,13 +3089,12 @@ clutter_actor_class_init (ClutterActorClass *klass) * * Since: 0.8 */ - pspec = 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 ("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); /** @@ -3034,13 +3108,12 @@ clutter_actor_class_init (ClutterActorClass *klass) * * Since: 0.8 */ - pspec = 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_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); /** @@ -3054,13 +3127,12 @@ clutter_actor_class_init (ClutterActorClass *klass) * * Since: 0.8 */ - pspec = 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_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); /** @@ -3074,13 +3146,12 @@ clutter_actor_class_init (ClutterActorClass *klass) * * Since: 0.8 */ - pspec = 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_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); /** @@ -3224,16 +3295,16 @@ clutter_actor_class_init (ClutterActorClass *klass) /** * ClutterActor:depth: * - * Depth of the actor. + * The position of the actor on the Z axis * * Since: 0.6 */ - pspec = 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); /** @@ -3245,8 +3316,8 @@ clutter_actor_class_init (ClutterActorClass *klass) pspec = g_param_spec_uchar ("opacity", "Opacity", "Opacity of actor", - 0, 0xff, - 0xff, + 0, 255, + 255, CLUTTER_PARAM_READWRITE); g_object_class_install_property (object_class, PROP_OPACITY, pspec); @@ -3387,11 +3458,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); /** @@ -3401,11 +3473,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); /** @@ -3543,12 +3616,12 @@ clutter_actor_class_init (ClutterActorClass *klass) * * Since: 0.8 */ - pspec = 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); /** @@ -3559,12 +3632,12 @@ clutter_actor_class_init (ClutterActorClass *klass) * * Since: 0.8 */ - pspec = 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); /** diff --git a/clutter/clutter-interval.c b/clutter/clutter-interval.c index c4181945b..469c217db 100644 --- a/clutter/clutter-interval.c +++ b/clutter/clutter-interval.c @@ -265,8 +265,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/tests/conform/Makefile.am b/tests/conform/Makefile.am index 253cb64ed..82e104b87 100644 --- a/tests/conform/Makefile.am +++ b/tests/conform/Makefile.am @@ -78,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-anchors.c b/tests/conform/test-anchors.c index f3118b4fd..4549275da 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,31 @@ 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), 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)));\ + } 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 (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); } G_STMT_END static inline gboolean approx_equal (int a, int b) @@ -133,7 +125,10 @@ 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 ()) @@ -154,7 +149,7 @@ 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 +159,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 +170,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 +183,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 +212,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 +231,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 +261,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 +282,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 +292,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 +311,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 +326,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 +397,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); diff --git a/tests/conform/test-binding-pool.c b/tests/conform/test-binding-pool.c index 64cf11ee6..acbedfdb6 100644 --- a/tests/conform/test-binding-pool.c +++ b/tests/conform/test-binding-pool.c @@ -273,19 +273,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/interactive/test-animation.c b/tests/interactive/test-animation.c index 032400f63..3fde8a68a 100644 --- a/tests/interactive/test-animation.c +++ b/tests/interactive/test-animation.c @@ -65,10 +65,10 @@ on_button_press (ClutterActor *actor, animation = clutter_actor_animate (actor, CLUTTER_EASE_IN_EXPO, 2000, - "x", (int) new_x, - "y", (int) new_y, - "width", (int) new_width, - "height", (int) new_height, + "x", new_x, + "y", new_y, + "width", new_width, + "height", new_height, "color", &new_color, "rotation-angle-z", new_angle, "fixed::rotation-center-z", &vertex, diff --git a/tests/interactive/test-clutter-cairo-flowers.c b/tests/interactive/test-clutter-cairo-flowers.c index 746d62313..2abd6c39d 100644 --- a/tests/interactive/test-clutter-cairo-flowers.c +++ b/tests/interactive/test-clutter-cairo-flowers.c @@ -166,21 +166,19 @@ 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++) { @@ -192,14 +190,15 @@ test_clutter_cairo_flowers_main (int argc, char **argv) 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 cddf2b4ca..df7360260 100644 --- a/tests/interactive/test-cogl-multitexture.c +++ b/tests/interactive/test-cogl-multitexture.c @@ -123,7 +123,7 @@ test_cogl_multitexture_main (int argc, char *argv[]) state->group); timeline = clutter_timeline_new (TIMELINE_FRAME_COUNT, 26 /* fps */); - g_object_set (timeline, "loop", TRUE, NULL); + clutter_timeline_set_loop (timeline, TRUE); g_signal_connect (timeline, "new-frame", G_CALLBACK (frame_cb), state); diff --git a/tests/interactive/test-cogl-tex-polygon.c b/tests/interactive/test-cogl-tex-polygon.c index 540d832a4..b7252b50a 100644 --- a/tests/interactive/test-cogl-tex-polygon.c +++ b/tests/interactive/test-cogl-tex-polygon.c @@ -371,7 +371,7 @@ test_cogl_tex_polygon_main (int argc, char *argv[]) /* Timeline for animation */ timeline = clutter_timeline_new (360, 60); /* num frames, fps */ - g_object_set (timeline, "loop", TRUE, NULL); /* have it loop */ + 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 0325add6a..07f395db6 100644 --- a/tests/interactive/test-cogl-tex-tile.c +++ b/tests/interactive/test-cogl-tex-tile.c @@ -203,7 +203,7 @@ test_cogl_tex_tile_main (int argc, char *argv[]) /* Timeline for animation */ timeline = clutter_timeline_new (360, 60); /* num frames, fps */ - g_object_set (timeline, "loop", TRUE, NULL); /* have it loop */ + 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-easing.c b/tests/interactive/test-easing.c index 296812da3..e39fc7e21 100644 --- a/tests/interactive/test-easing.c +++ b/tests/interactive/test-easing.c @@ -94,8 +94,8 @@ on_button_press (ClutterActor *actor, animation = clutter_actor_animate (rectangle, cur_mode, 2000, - "x", (int) event->x, - "y", (int) event->y, + "x", event->x, + "y", event->y, "color", &color, NULL); } diff --git a/tests/interactive/test-layout.c b/tests/interactive/test-layout.c index ecd5ce8e4..93783723e 100644 --- a/tests/interactive/test-layout.c +++ b/tests/interactive/test-layout.c @@ -551,14 +551,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 */ @@ -591,13 +590,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, @@ -608,13 +607,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, diff --git a/tests/interactive/test-multistage.c b/tests/interactive/test-multistage.c index 21f6427ae..40caa40f6 100644 --- a/tests/interactive/test-multistage.c +++ b/tests/interactive/test-multistage.c @@ -73,7 +73,7 @@ on_button_press (ClutterActor *actor, clutter_stage_set_title (CLUTTER_STAGE(new_stage), win_title); timeline = clutter_timeline_new_for_duration (2000); - g_object_set (timeline, "loop", TRUE, NULL); + 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 ac346f5da..ac53221e5 100644 --- a/tests/interactive/test-paint-wrapper.c +++ b/tests/interactive/test-paint-wrapper.c @@ -209,7 +209,7 @@ test_paint_wrapper_main (int argc, char *argv[]) /* 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 */ + 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-rotate.c b/tests/interactive/test-rotate.c index 0c234714f..6fea09ca0 100644 --- a/tests/interactive/test-rotate.c +++ b/tests/interactive/test-rotate.c @@ -45,7 +45,7 @@ test_rotate_main (int argc, char *argv[]) /* Make a timeline */ timeline = clutter_timeline_new (200, 26); /* num frames, fps */ - g_object_set (timeline, "loop", TRUE, NULL); + 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-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 From 097400747e112d01cbd4ecb72401abcca41158f9 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 1 Jun 2009 12:51:23 +0100 Subject: [PATCH 104/138] [git ignore] Add report XML output file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2c2298771..0333c9d70 100644 --- a/.gitignore +++ b/.gitignore @@ -200,6 +200,7 @@ stamp-h1 /tests/conform/test-realize-not-recursive /tests/conform/test-shown-not-parented /tests/conform/test-blend-strings +/tests/conform/test-conformance-result.xml /tests/micro-bench/test-text-perf /tests/micro-bench/test-text /tests/micro-bench/test-picking From 86230eb9fa134c3df50634e9196477c82d20a403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Sat, 30 May 2009 23:58:03 +0300 Subject: [PATCH 105/138] build: don't double install clutter-version.h Automake 1.11 installs several files in one command, and it fails if the same file is installed two times. See NEWS for details: http://lists.gnu.org/archive/html/automake/2009-05/msg00093.html Signed-off-by: Emmanuele Bassi --- clutter/Makefile.am | 1 - 1 file changed, 1 deletion(-) diff --git a/clutter/Makefile.am b/clutter/Makefile.am index e8c80b20b..b1107d6b3 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -236,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 From 6cd1cb21cc0b629535994ad41e4fc78613fe0319 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 1 Jun 2009 15:51:59 +0100 Subject: [PATCH 106/138] [introspection] Remove Cogl symbols from Clutter GIR The GIR file for Clutter still contains symbols from COGL, even though we provide a Cogl GIR as well. The Clutter GIR should depend on the Cogl GIR instead. --- clutter/Makefile.am | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/clutter/Makefile.am b/clutter/Makefile.am index b1107d6b3..1eef4019b 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -249,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) \ @@ -261,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" \ @@ -269,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 From 5c26cc6ba7ab9b90bfe4aa2612a56c191c8b1204 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Mon, 1 Jun 2009 17:10:22 +0100 Subject: [PATCH 107/138] Use GL_QUADS for flushing a quad batch Instead of using GL_TRIANGLES and uploading the indices every time, it now uses GL_QUADS instead on OpenGL. Under GLES it still uses indices but it uses the new cogl_vertex_buffer_indices_get_for_quads function to avoid uploading the vertices every time. This requires the _cogl_vertex_buffer_indices_pointer_from_handle function to be exposed privately to the rest of Cogl. The static_indices array has been removed from the Cogl context. --- clutter/cogl/common/cogl-primitives.c | 71 ++++++------------- .../cogl/common/cogl-vertex-buffer-private.h | 4 ++ clutter/cogl/gl/cogl-context.c | 3 - clutter/cogl/gl/cogl-context.h | 1 - clutter/cogl/gles/cogl-context.c | 3 - clutter/cogl/gles/cogl-context.h | 1 - 6 files changed, 25 insertions(+), 58 deletions(-) diff --git a/clutter/cogl/common/cogl-primitives.c b/clutter/cogl/common/cogl-primitives.c index ff5401d50..c43fbde49 100644 --- a/clutter/cogl/common/cogl-primitives.c +++ b/clutter/cogl/common/cogl-primitives.c @@ -30,6 +30,7 @@ #include "cogl-context.h" #include "cogl-texture-private.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; @@ -122,52 +114,31 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start, GE (glVertexPointer (2, GL_FLOAT, stride, vertex_pointer)); _cogl_current_matrix_state_flush (); +#ifdef HAVE_COGL_GL - if (batch_len > 1) - { - /* 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; + GE( glDrawArrays (GL_QUADS, 0, batch_len * 4) ); - /* 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); +#else /* HAVE_COGL_GL */ - 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; + /* 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); - *(q++) = vert_num + 1; - *(q++) = vert_num + 2; - *(q++) = vert_num + 3; - } - } - - GE (glDrawRangeElements (GL_TRIANGLES, - 0, ctx->static_indices->len - 1, - 6 * batch_len, - GL_UNSIGNED_SHORT, - ctx->static_indices->data)); - } - else - { - GE (glDrawArrays (GL_TRIANGLE_FAN, - 0, /* first */ - 4)); /* n vertices */ - } + 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 diff --git a/clutter/cogl/common/cogl-vertex-buffer-private.h b/clutter/cogl/common/cogl-vertex-buffer-private.h index 17f8725e4..558765303 100644 --- a/clutter/cogl/common/cogl-vertex-buffer-private.h +++ b/clutter/cogl/common/cogl-vertex-buffer-private.h @@ -161,5 +161,9 @@ typedef struct _CoglVertexBuffer } 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/gl/cogl-context.c b/clutter/cogl/gl/cogl-context.c index 16fcb3e12..201e05db7 100644 --- a/clutter/cogl/gl/cogl-context.c +++ b/clutter/cogl/gl/cogl-context.c @@ -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)); @@ -204,8 +203,6 @@ _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) diff --git a/clutter/cogl/gl/cogl-context.h b/clutter/cogl/gl/cogl-context.h index f5ca54cb2..10e56e510 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... */ diff --git a/clutter/cogl/gles/cogl-context.c b/clutter/cogl/gles/cogl-context.c index d3ec31c5d..293ac4689 100644 --- a/clutter/cogl/gles/cogl-context.c +++ b/clutter/cogl/gles/cogl-context.c @@ -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)); @@ -162,8 +161,6 @@ _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) diff --git a/clutter/cogl/gles/cogl-context.h b/clutter/cogl/gles/cogl-context.h index 9c1d44fbe..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... */ From 61deeafa71a81384978bd199f0df6e88d0904a52 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 1 Jun 2009 16:31:32 +0100 Subject: [PATCH 108/138] [cogl-shader] Make get_info_log() slightly nicer The cogl_shader_get_info_log() function is very inconvenient for language bindings and for regular use, as it requires a static buffer to be filled -- basically just providing a wrapper around glGetInfoLogARB(). Since COGL aims to be a more convenient API than raw GL we should just make cogl_shader_get_info_log() return an allocated string with the GLSL compiler log. --- clutter/clutter-shader.c | 12 +++++++++--- clutter/cogl/cogl-shader.h | 13 ++++++------- clutter/cogl/gl/cogl-shader.c | 15 ++++++++------- clutter/cogl/gles/cogl-shader.c | 15 ++++++++------- 4 files changed, 31 insertions(+), 24 deletions(-) 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/cogl/cogl-shader.h b/clutter/cogl/cogl-shader.h index d0b0ce13e..9eec9bb40 100644 --- a/clutter/cogl/cogl-shader.h +++ b/clutter/cogl/cogl-shader.h @@ -106,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. @@ -119,17 +119,16 @@ 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: 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/gles/cogl-shader.c b/clutter/cogl/gles/cogl-shader.c index ff5f0c58a..11cbe0c33 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 From ffd5fb172b390f7fbdeadce3dda181a67a1e7916 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 1 Jun 2009 17:35:41 +0100 Subject: [PATCH 109/138] [docs] Rework the API reference version generation Clutter copies the gtk-doc from the usual gtk+ template, and has a version.xml.in containing only: @VERSION@ Without a newline at the end. Unfortunately, it appears that autoconf has started adding a newline to the generated version.xml which then is used as the payload for the "version" XML entity. Instead of using a secondary file we can make configure generate the whole clutter-docs.xml and cogl-docs.xml files from a template; this way we also get the ability to substitute more autoconf variables into the documentation -- if needs be. --- .gitignore | 4 ++-- configure.ac | 4 ++-- doc/reference/clutter/Makefile.am | 2 -- .../clutter/{clutter-docs.xml => clutter-docs.xml.in} | 2 +- doc/reference/clutter/version.xml.in | 1 - doc/reference/cogl/Makefile.am | 2 -- doc/reference/cogl/{cogl-docs.xml => cogl-docs.xml.in} | 2 +- doc/reference/cogl/version.xml.in | 1 - 8 files changed, 6 insertions(+), 12 deletions(-) rename doc/reference/clutter/{clutter-docs.xml => clutter-docs.xml.in} (99%) delete mode 100644 doc/reference/clutter/version.xml.in rename doc/reference/cogl/{cogl-docs.xml => cogl-docs.xml.in} (98%) delete mode 100644 doc/reference/cogl/version.xml.in diff --git a/.gitignore b/.gitignore index 0333c9d70..917592bf0 100644 --- a/.gitignore +++ b/.gitignore @@ -39,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 @@ -52,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 diff --git a/configure.ac b/configure.ac index 419a0c402..49911ee9f 100644 --- a/configure.ac +++ b/configure.ac @@ -741,9 +741,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 diff --git a/doc/reference/clutter/Makefile.am b/doc/reference/clutter/Makefile.am index b2489466c..61d7fc16c 100644 --- a/doc/reference/clutter/Makefile.am +++ b/doc/reference/clutter/Makefile.am @@ -113,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 \ @@ -147,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/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 c2f075e4d..9888caaa3 100644 --- a/doc/reference/cogl/Makefile.am +++ b/doc/reference/cogl/Makefile.am @@ -71,7 +71,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 \ blend-strings.xml # SGML files where gtk-doc abbrevations (#GtkWidget) are expanded @@ -94,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/cogl-docs.xml b/doc/reference/cogl/cogl-docs.xml.in similarity index 98% rename from doc/reference/cogl/cogl-docs.xml rename to doc/reference/cogl/cogl-docs.xml.in index 87d665f42..7f9c1c26b 100644 --- a/doc/reference/cogl/cogl-docs.xml +++ b/doc/reference/cogl/cogl-docs.xml.in @@ -1,7 +1,7 @@ + ]> 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 From bd13a4ddc486586bc1051080cbe64c2d90ee853e Mon Sep 17 00:00:00 2001 From: Robert Staudinger Date: Mon, 1 Jun 2009 18:54:46 +0200 Subject: [PATCH 110/138] [color] Add support for the "#rgba" color format clutter_color_from_string() only supported the "#rrggbbaa" format with alpha channel, this patch adds support for "#rgba". Colors in "#rrggbb" format were parsed manually, this is now left to the pango color parsing fallback, since that's handling it just fine. Signed-off-by: Emmanuele Bassi --- clutter/clutter-color.c | 50 ++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 26 deletions(-) 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 */ From b6f1322e07f0fd678a48f1128eae6cba8b8211d7 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 1 Jun 2009 18:43:47 +0100 Subject: [PATCH 111/138] [tests] Add ClutterColor conformance tests Add a conformance test unit for the to_string() and from_string() methods. --- .gitignore | 2 + tests/conform/Makefile.am | 1 + tests/conform/test-color.c | 71 +++++++++++++++++++++++++++++++ tests/conform/test-conform-main.c | 3 ++ 4 files changed, 77 insertions(+) create mode 100644 tests/conform/test-color.c diff --git a/.gitignore b/.gitignore index 917592bf0..561b69b44 100644 --- a/.gitignore +++ b/.gitignore @@ -200,6 +200,8 @@ stamp-h1 /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-conformance-result.xml /tests/micro-bench/test-text-perf /tests/micro-bench/test-text diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am index 82e104b87..be19c0408 100644 --- a/tests/conform/Makefile.am +++ b/tests/conform/Makefile.am @@ -29,6 +29,7 @@ test_conformance_SOURCES = \ test-npot-texture.c \ test-model.c \ test-blend-strings.c \ + test-color.c \ $(NULL) # For convenience, this provides a way to easily run individual unit tests: 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 ff614ae98..fc0daacdc 100644 --- a/tests/conform/test-conform-main.c +++ b/tests/conform/test-conform-main.c @@ -145,5 +145,8 @@ main (int argc, char **argv) TEST_CONFORM_SIMPLE ("/material", test_blend_strings); + TEST_CONFORM_SIMPLE ("/color", test_color_from_string); + TEST_CONFORM_SIMPLE ("/color", test_color_to_string); + return g_test_run (); } From 762873e79e501c949f3ef55cbac20276b6f6ed4e Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 3 Jun 2009 12:02:56 +0100 Subject: [PATCH 112/138] [master clock] Avoid excessive redraws Currently, the clock source spins a redraw every time there is at least a timeline running. If the timelines were not advanced in the previous frame, though, because their interval is larger than the vblanking interval then this will lead to excessive redraws of the scenegraph even if nothing has changed. To avoid this a simple guard should be set by the MasterClock::advance method in case no timeline was effectively advanced, and checked before dispatching the stage redraws. --- clutter/clutter-master-clock.c | 21 ++++++++++++++++++++- clutter/clutter-timeline.c | 10 +++++++--- clutter/clutter-timeline.h | 2 +- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/clutter/clutter-master-clock.c b/clutter/clutter-master-clock.c index ea3440555..0cfb493e6 100644 --- a/clutter/clutter-master-clock.c +++ b/clutter/clutter-master-clock.c @@ -68,6 +68,11 @@ struct _ClutterMasterClock * after the last timeline has been completed */ guint last_advance : 1; + + /* a guard, so that we dispatch the redraws only if + * any timeline did advance + */ + guint has_advanced : 1; }; struct _ClutterMasterClockClass @@ -208,6 +213,17 @@ clutter_clock_dispatch (GSource *source, CLUTTER_NOTE (SCHEDULER, "Master clock [tick]"); + /* do not force a redraw if no timeline has advanced; this might + * happen if we only have timelines with intervals smaller than + * the vblank interval + */ + if (master_clock->has_advanced) + { + master_clock->has_advanced = FALSE; + + return TRUE; + } + stages = clutter_stage_manager_peek_stages (stage_manager); /* queue a redraw for each stage; this will advance each timeline @@ -438,6 +454,7 @@ void _clutter_master_clock_advance (ClutterMasterClock *master_clock) { GTimeVal cur_tick = { 0, }; + gboolean has_advanced; gulong msecs; GSList *l; @@ -461,12 +478,13 @@ _clutter_master_clock_advance (ClutterMasterClock *master_clock) g_slist_length (master_clock->timelines), msecs); + has_advanced = FALSE; 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); + has_advanced = clutter_timeline_advance_delta (timeline, msecs); } /* store the previous state so that we can use @@ -474,4 +492,5 @@ _clutter_master_clock_advance (ClutterMasterClock *master_clock) */ master_clock->msecs_delta = msecs; master_clock->prev_tick = cur_tick; + master_clock->has_advanced = has_advanced; } diff --git a/clutter/clutter-timeline.c b/clutter/clutter-timeline.c index 761c5e1c5..44cdb5152 100644 --- a/clutter/clutter-timeline.c +++ b/clutter/clutter-timeline.c @@ -1381,21 +1381,23 @@ clutter_timeline_get_delta (ClutterTimeline *timeline, * elapsed since the last redraw operation. The @timeline will use this * interval to emit the #ClutterTimeline::new-frame signal and eventually * skip frames. + * + * Return value: %TRUE if the timeline advanced */ -void +gboolean clutter_timeline_advance_delta (ClutterTimeline *timeline, guint msecs) { ClutterTimelinePrivate *priv; - g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); + g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), FALSE); priv = timeline->priv; priv->msecs_delta += msecs; if (priv->msecs_delta < priv->frame_interval) - return; + return FALSE; else { clutter_timeline_advance_internal (timeline); @@ -1403,6 +1405,8 @@ clutter_timeline_advance_delta (ClutterTimeline *timeline, /* Keep the remainder of the frame time so that it will be counted towards the next time if the delta is short */ priv->msecs_delta %= priv->frame_interval; + + return TRUE; } } diff --git a/clutter/clutter-timeline.h b/clutter/clutter-timeline.h index 7d829ebaa..7bd0e1bd7 100644 --- a/clutter/clutter-timeline.h +++ b/clutter/clutter-timeline.h @@ -167,7 +167,7 @@ void clutter_timeline_advance_to_marker (ClutterTimeline *timeli const gchar *marker_name); /*< private >*/ -void clutter_timeline_advance_delta (ClutterTimeline *timeline, +gboolean clutter_timeline_advance_delta (ClutterTimeline *timeline, guint msecs); G_END_DECLS From 181ba67114d8bd88c0b7091ad9033ebee6bff63c Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 3 Jun 2009 14:03:25 +0100 Subject: [PATCH 113/138] Revert commit 762873e7 The commit 762873e79e501c949f3ef55cbac20276b6f6ed4e is completely and utterly wrong and I should have never pushed it. Serves me well for trying to work on three different branches and on three different things. --- clutter/clutter-master-clock.c | 21 +-------------------- clutter/clutter-timeline.c | 10 +++------- clutter/clutter-timeline.h | 2 +- 3 files changed, 5 insertions(+), 28 deletions(-) diff --git a/clutter/clutter-master-clock.c b/clutter/clutter-master-clock.c index 0cfb493e6..ea3440555 100644 --- a/clutter/clutter-master-clock.c +++ b/clutter/clutter-master-clock.c @@ -68,11 +68,6 @@ struct _ClutterMasterClock * after the last timeline has been completed */ guint last_advance : 1; - - /* a guard, so that we dispatch the redraws only if - * any timeline did advance - */ - guint has_advanced : 1; }; struct _ClutterMasterClockClass @@ -213,17 +208,6 @@ clutter_clock_dispatch (GSource *source, CLUTTER_NOTE (SCHEDULER, "Master clock [tick]"); - /* do not force a redraw if no timeline has advanced; this might - * happen if we only have timelines with intervals smaller than - * the vblank interval - */ - if (master_clock->has_advanced) - { - master_clock->has_advanced = FALSE; - - return TRUE; - } - stages = clutter_stage_manager_peek_stages (stage_manager); /* queue a redraw for each stage; this will advance each timeline @@ -454,7 +438,6 @@ void _clutter_master_clock_advance (ClutterMasterClock *master_clock) { GTimeVal cur_tick = { 0, }; - gboolean has_advanced; gulong msecs; GSList *l; @@ -478,13 +461,12 @@ _clutter_master_clock_advance (ClutterMasterClock *master_clock) g_slist_length (master_clock->timelines), msecs); - has_advanced = FALSE; for (l = master_clock->timelines; l != NULL; l = l->next) { ClutterTimeline *timeline = l->data; if (clutter_timeline_is_playing (timeline)) - has_advanced = clutter_timeline_advance_delta (timeline, msecs); + clutter_timeline_advance_delta (timeline, msecs); } /* store the previous state so that we can use @@ -492,5 +474,4 @@ _clutter_master_clock_advance (ClutterMasterClock *master_clock) */ master_clock->msecs_delta = msecs; master_clock->prev_tick = cur_tick; - master_clock->has_advanced = has_advanced; } diff --git a/clutter/clutter-timeline.c b/clutter/clutter-timeline.c index 44cdb5152..761c5e1c5 100644 --- a/clutter/clutter-timeline.c +++ b/clutter/clutter-timeline.c @@ -1381,23 +1381,21 @@ clutter_timeline_get_delta (ClutterTimeline *timeline, * elapsed since the last redraw operation. The @timeline will use this * interval to emit the #ClutterTimeline::new-frame signal and eventually * skip frames. - * - * Return value: %TRUE if the timeline advanced */ -gboolean +void clutter_timeline_advance_delta (ClutterTimeline *timeline, guint msecs) { ClutterTimelinePrivate *priv; - g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), FALSE); + g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); priv = timeline->priv; priv->msecs_delta += msecs; if (priv->msecs_delta < priv->frame_interval) - return FALSE; + return; else { clutter_timeline_advance_internal (timeline); @@ -1405,8 +1403,6 @@ clutter_timeline_advance_delta (ClutterTimeline *timeline, /* Keep the remainder of the frame time so that it will be counted towards the next time if the delta is short */ priv->msecs_delta %= priv->frame_interval; - - return TRUE; } } diff --git a/clutter/clutter-timeline.h b/clutter/clutter-timeline.h index 7bd0e1bd7..7d829ebaa 100644 --- a/clutter/clutter-timeline.h +++ b/clutter/clutter-timeline.h @@ -167,7 +167,7 @@ void clutter_timeline_advance_to_marker (ClutterTimeline *timeli const gchar *marker_name); /*< private >*/ -gboolean clutter_timeline_advance_delta (ClutterTimeline *timeline, +void clutter_timeline_advance_delta (ClutterTimeline *timeline, guint msecs); G_END_DECLS From 6825b9db1c1eaeab151d4ca9cc4f5ec923cbcde0 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 3 Jun 2009 12:59:16 +0100 Subject: [PATCH 114/138] [actor] Unrealize on destroy If the application code calls for destruction of an actor we need to make sure that the actor is unrealized before running the dispose sequence; otherwise, we might trigger an assertion failure on composite actors. --- clutter/clutter-actor.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index ac3f42dad..b57b41c0d 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -4269,6 +4269,11 @@ 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 + */ + 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); From daa95b561e1dda0c13624fdbde602c36dc786842 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 4 Jun 2009 11:48:51 +0100 Subject: [PATCH 115/138] Rename 'near' and 'far' variables to 'z_near' and 'z_far' The Windows headers define near and far to be empty so it breaks the build. --- clutter/cogl/cogl-matrix.h | 12 ++++++------ clutter/cogl/common/cogl-current-matrix.c | 18 +++++++++--------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/clutter/cogl/cogl-matrix.h b/clutter/cogl/cogl-matrix.h index bd7b579c7..3ee94aeb5 100644 --- a/clutter/cogl/cogl-matrix.h +++ b/clutter/cogl/cogl-matrix.h @@ -228,10 +228,10 @@ cogl_matrix_perspective (CoglMatrix *matrix, * @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) + * @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. */ @@ -241,8 +241,8 @@ cogl_matrix_ortho (CoglMatrix *matrix, float right, float bottom, float top, - float near, - float far); + float z_near, + float z_far); /** * cogl_matrix_init_from_array: diff --git a/clutter/cogl/common/cogl-current-matrix.c b/clutter/cogl/common/cogl-current-matrix.c index e01987c95..6d069bc66 100644 --- a/clutter/cogl/common/cogl-current-matrix.c +++ b/clutter/cogl/common/cogl-current-matrix.c @@ -239,8 +239,8 @@ _cogl_current_matrix_ortho (float left, float right, float bottom, float top, - float near, - float far) + float near_val, + float far_val) { _COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL); @@ -248,8 +248,8 @@ _cogl_current_matrix_ortho (float left, _cogl_matrix_stack_ortho (current_stack, left, right, bottom, top, - near, - far); + near_val, + far_val); else { #ifdef HAVE_COGL_GLES2 @@ -257,10 +257,10 @@ _cogl_current_matrix_ortho (float left, CoglMatrix matrix; _cogl_get_matrix (ctx->matrix_mode, &matrix); cogl_matrix_ortho (&matrix, - left, right, bottom, top, near, far); + left, right, bottom, top, near_val, far_val); _cogl_current_matrix_load (&matrix); #else - GE (glOrtho (left, right, bottom, top, near, far)); + GE (glOrtho (left, right, bottom, top, near_val, far_val)); #endif } } @@ -453,14 +453,14 @@ cogl_ortho (float left, float right, float bottom, float top, - float near, - float far) + 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, near, far); + cogl_matrix_ortho (&ortho, left, right, bottom, top, z_near, z_far); _cogl_set_current_matrix (COGL_MATRIX_PROJECTION); _cogl_current_matrix_load (&ortho); From f89ff7f3835edab93de1c67895b6a754abffc5eb Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 4 Jun 2009 11:50:06 +0100 Subject: [PATCH 116/138] Load glBlendEquation and glBlendColor using cogl_get_proc_address These are defined since OpenGL 1.2 and since Windows doesn't export any functions defined after 1.1 we need to load them dynamically. --- clutter/cogl/common/cogl-material.c | 2 ++ clutter/cogl/gl/cogl-context.h | 2 ++ clutter/cogl/gl/cogl-defines.h.in | 11 +++++++++++ clutter/cogl/gl/cogl.c | 7 +++++++ 4 files changed, 22 insertions(+) diff --git a/clutter/cogl/common/cogl-material.c b/clutter/cogl/common/cogl-material.c index 7e8567a6e..85f9f343b 100644 --- a/clutter/cogl/common/cogl-material.c +++ b/clutter/cogl/common/cogl-material.c @@ -52,6 +52,8 @@ #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 diff --git a/clutter/cogl/gl/cogl-context.h b/clutter/cogl/gl/cogl-context.h index 10e56e510..3db4c0e9e 100644 --- a/clutter/cogl/gl/cogl-context.h +++ b/clutter/cogl/gl/cogl-context.h @@ -170,6 +170,8 @@ 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; diff --git a/clutter/cogl/gl/cogl-defines.h.in b/clutter/cogl/gl/cogl-defines.h.in index bde93c559..4805ea5b3 100644 --- a/clutter/cogl/gl/cogl-defines.h.in +++ b/clutter/cogl/gl/cogl-defines.h.in @@ -1032,6 +1032,17 @@ typedef void (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.c b/clutter/cogl/gl/cogl.c index 8fcd3eabd..608bc364e 100644 --- a/clutter/cogl/gl/cogl.c +++ b/clutter/cogl/gl/cogl.c @@ -486,6 +486,13 @@ _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) From af68945486ff20adb8d386af5dd0b76a50eca098 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 4 Jun 2009 11:50:52 +0100 Subject: [PATCH 117/138] [clutter-event-win32] Fix the argument types to clutter_actor_get_size clutter_actor_get_size now takes float pointers so it was issuing a warning. --- clutter/win32/clutter-event-win32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); From fa0b33ec30a0e95e6dc0731abe698e16135b19db Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 4 Jun 2009 11:59:17 +0100 Subject: [PATCH 118/138] [clutter-stage-win32] Call clutter_actor_map instead of setting the flags The clutter_actor_map and unmap functions need to be called to properly update the mapped state. This matches the changes to the X11 stage in 125bded8. --- clutter/win32/clutter-stage-win32.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clutter/win32/clutter-stage-win32.c b/clutter/win32/clutter-stage-win32.c index f49549416..f83c3c873 100644 --- a/clutter/win32/clutter-stage-win32.c +++ b/clutter/win32/clutter-stage-win32.c @@ -780,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)); } @@ -789,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)); } From c20886c5e36fa92a8bfa79a5c24d73d4c558b9ae Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 4 Jun 2009 12:04:47 +0100 Subject: [PATCH 119/138] [gles/cogl-shader] Fix parameter spec for cogl_shader_get_info_log The stub version of cogl_shader_get_info_log needed to be updated to match the changes to the function signature in 61deeafa. --- clutter/cogl/gles/cogl-shader.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/clutter/cogl/gles/cogl-shader.c b/clutter/cogl/gles/cogl-shader.c index 11cbe0c33..74d0add8e 100644 --- a/clutter/cogl/gles/cogl-shader.c +++ b/clutter/cogl/gles/cogl-shader.c @@ -200,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 From 9c7afe0c5bf99e38c6fd4584b8fa3b0ed02cf996 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 4 Jun 2009 13:05:12 +0100 Subject: [PATCH 120/138] [timeline] Remove the concept of frames from timelines Timelines no longer work in terms of a frame rate and a number of frames but instead just have a duration in milliseconds. This better matches the working of the master clock where if any timelines are running it will redraw as fast as possible rather than limiting to the lowest rated timeline. Most applications will just create animations and expect them to finish in a certain amount of time without caring about how many frames are drawn. If a frame is going to be drawn it might as well update all of the animations to some fraction of the total animation rather than rounding to the nearest whole frame. The 'frame_num' parameter of the new-frame signal is now 'msecs' which is a number of milliseconds progressed along the timeline. Applications should use clutter_timeline_get_progress instead of the frame number. Markers can now only be attached at a time value. The position is stored in milliseconds rather than at a frame number. test-timeline-smoothness and test-timeline-dup-frames have been removed because they no longer make sense. --- clutter/clutter-alpha.c | 116 ++-- clutter/clutter-timeline.c | 640 ++++++-------------- clutter/clutter-timeline.h | 24 +- doc/reference/clutter/clutter-sections.txt | 8 +- tests/conform/Makefile.am | 2 - tests/conform/test-conform-main.c | 3 - tests/conform/test-timeline-dup-frames.c | 134 ---- tests/conform/test-timeline-interpolate.c | 19 +- tests/conform/test-timeline-rewind.c | 12 +- tests/conform/test-timeline-smoothness.c | 147 ----- tests/conform/test-timeline.c | 48 +- tests/interactive/test-actor-clone.c | 7 +- tests/interactive/test-actors.c | 9 +- tests/interactive/test-behave.c | 2 +- tests/interactive/test-cogl-multitexture.c | 8 +- tests/interactive/test-cogl-primitives.c | 7 +- tests/interactive/test-cogl-tex-polygon.c | 2 +- tests/interactive/test-cogl-tex-tile.c | 2 +- tests/interactive/test-cogl-vertex-buffer.c | 5 +- tests/interactive/test-depth.c | 2 +- tests/interactive/test-layout.c | 2 +- tests/interactive/test-multistage.c | 2 +- tests/interactive/test-paint-wrapper.c | 13 +- tests/interactive/test-pixmap.c | 2 +- tests/interactive/test-rotate.c | 2 +- tests/interactive/test-scale.c | 2 +- tests/interactive/test-score.c | 10 +- tests/interactive/test-texture-async.c | 2 +- tests/interactive/test-texture-quality.c | 2 +- tests/interactive/test-threads.c | 2 +- tests/interactive/test-viewport.c | 2 +- 31 files changed, 324 insertions(+), 914 deletions(-) delete mode 100644 tests/conform/test-timeline-dup-frames.c delete mode 100644 tests/conform/test-timeline-smoothness.c 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-timeline.c b/clutter/clutter-timeline.c index 761c5e1c5..d74a10786 100644 --- a/clutter/clutter-timeline.c +++ b/clutter/clutter-timeline.c @@ -99,18 +99,15 @@ struct _ClutterTimelinePrivate 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; - guint msecs_delta; - guint frame_interval; - - GHashTable *markers_by_frame; GHashTable *markers_by_name; guint loop : 1; @@ -119,7 +116,7 @@ struct _ClutterTimelinePrivate 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, @@ -150,13 +145,13 @@ 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; } @@ -189,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; @@ -233,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; @@ -270,9 +249,6 @@ clutter_timeline_finalize (GObject *object) ClutterTimelinePrivate *priv = self->priv; ClutterMasterClock *master_clock; - if (priv->markers_by_frame) - g_hash_table_destroy (priv->markers_by_frame); - if (priv->markers_by_name) g_hash_table_destroy (priv->markers_by_name); @@ -312,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: * @@ -405,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"), @@ -470,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); @@ -520,50 +466,51 @@ clutter_timeline_init (ClutterTimeline *self) G_TYPE_INSTANCE_GET_PRIVATE (self, CLUTTER_TYPE_TIMELINE, ClutterTimelinePrivate); - priv->fps = clutter_get_default_frame_rate (); - priv->frame_interval = 1000 / priv->fps; - 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 @@ -571,17 +518,15 @@ 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 clutter_timeline_advance_internal (ClutterTimeline *timeline) { ClutterTimelinePrivate *priv; - guint n_frames, speed; priv = timeline->priv; @@ -589,28 +534,13 @@ clutter_timeline_advance_internal (ClutterTimeline *timeline) CLUTTER_TIMESTAMP (SCHEDULER, "Timeline [%p] activated (cur: %d)\n", timeline, - priv->current_frame_num); + priv->elapsed_time); - /* we need to avoid fps > 1000 */ - speed = MAX (1000 / priv->fps, 1); - - n_frames = priv->msecs_delta / 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); - - /* 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)) @@ -632,30 +562,23 @@ clutter_timeline_advance_internal (ClutterTimeline *timeline) { /* 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; @@ -665,11 +588,10 @@ clutter_timeline_advance_internal (ClutterTimeline *timeline) * 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->is_playing) { @@ -685,13 +607,13 @@ clutter_timeline_advance_internal (ClutterTimeline *timeline) 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 vice-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); @@ -702,16 +624,13 @@ clutter_timeline_advance_internal (ClutterTimeline *timeline) { /* 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; @@ -759,7 +678,7 @@ clutter_timeline_start (ClutterTimeline *timeline) if (priv->delay_id || priv->is_playing) return; - if (priv->n_frames == 0) + if (priv->duration == 0) return; if (priv->delay) @@ -875,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; @@ -897,17 +816,17 @@ 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; @@ -916,18 +835,19 @@ clutter_timeline_skip (ClutterTimeline *timeline, /** * 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; @@ -935,123 +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_freeze_notify (G_OBJECT (timeline)); - - priv->fps = fps; - priv->frame_interval = 1000 / priv->fps; - - /* if the timeline is playing restart */ - if (priv->is_playing) - clutter_timeline_rewind (timeline); - - g_object_notify (G_OBJECT (timeline), "duration"); - g_object_notify (G_OBJECT (timeline), "fps"); - - g_object_thaw_notify (G_OBJECT (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; } /** @@ -1091,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), @@ -1105,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 @@ -1115,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 @@ -1209,7 +1003,7 @@ clutter_timeline_get_duration (ClutterTimeline *timeline) priv = timeline->priv; - return priv->n_frames * 1000 / priv->fps; + return priv->duration; } /** @@ -1227,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"); + } } /** @@ -1260,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; } /** @@ -1323,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"); } @@ -1333,42 +1127,32 @@ 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 priv->skipped_frames + 1; + return timeline->priv->msecs_delta; } /* @@ -1392,95 +1176,36 @@ clutter_timeline_advance_delta (ClutterTimeline *timeline, priv = timeline->priv; - priv->msecs_delta += msecs; + priv->msecs_delta = msecs; - if (priv->msecs_delta < priv->frame_interval) - return; - else - { - clutter_timeline_advance_internal (timeline); - - /* Keep the remainder of the frame time so that it will be - counted towards the next time if the delta is short */ - priv->msecs_delta %= priv->frame_interval; - } + 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); } /** @@ -1489,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 */ @@ -1500,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. * @@ -1529,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; @@ -1540,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; @@ -1549,7 +1293,7 @@ clutter_timeline_list_markers (ClutterTimeline *timeline, return NULL; } - if (frame_num < 0) + if (msecs < 0) { GList *markers, *l; @@ -1563,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) @@ -1584,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. * @@ -1605,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; @@ -1619,7 +1365,7 @@ clutter_timeline_advance_to_marker (ClutterTimeline *timeline, return; } - clutter_timeline_advance (timeline, marker->frame_num); + clutter_timeline_advance (timeline, marker->msecs); } /** @@ -1637,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; @@ -1658,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); } @@ -1705,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 7d829ebaa..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,32 +129,25 @@ 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); diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt index 142d28b82..58079f476 100644 --- a/doc/reference/clutter/clutter-sections.txt +++ b/doc/reference/clutter/clutter-sections.txt @@ -542,18 +542,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 @@ -567,14 +562,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 diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am index be19c0408..556d39278 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 \ diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c index fc0daacdc..22f63a541 100644 --- a/tests/conform/test-conform-main.c +++ b/tests/conform/test-conform-main.c @@ -85,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); diff --git a/tests/conform/test-timeline-dup-frames.c b/tests/conform/test-timeline-dup-frames.c deleted file mode 100644 index de41f1f0e..000000000 --- a/tests/conform/test-timeline-dup-frames.c +++ /dev/null @@ -1,134 +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; - guint source_id; - GTimeVal prev_tick; - gulong msecs_delta; -} 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); - } - } -} - -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_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; - 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-interpolate.c b/tests/conform/test-timeline-interpolate.c index 5779b0902..c4837a5ec 100644 --- a/tests/conform/test-timeline-interpolate.c +++ b/tests/conform/test-timeline-interpolate.c @@ -9,7 +9,7 @@ * 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. */ @@ -42,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; @@ -50,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) @@ -99,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); @@ -165,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", diff --git a/tests/conform/test-timeline-rewind.c b/tests/conform/test-timeline-rewind.c index c46e7a5ff..b1cfa13c0 100644 --- a/tests/conform/test-timeline-rewind.c +++ b/tests/conform/test-timeline-rewind.c @@ -4,8 +4,7 @@ #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 @@ -42,9 +41,9 @@ 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"); @@ -53,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"); } @@ -101,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), diff --git a/tests/conform/test-timeline-smoothness.c b/tests/conform/test-timeline-smoothness.c deleted file mode 100644 index ab34d7e4e..000000000 --- a/tests/conform/test-timeline-smoothness.c +++ /dev/null @@ -1,147 +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; - guint source_id; - GTimeVal prev_tick; - gulong msecs_delta; -} 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); - } - } -} - -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_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; - 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.c b/tests/conform/test-timeline.c index 091440f6d..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) @@ -230,16 +239,19 @@ test_timeline (TestConformSimpleFixture *fixture, counter = g_new0 (FrameCounter, 1); - source_id = clutter_threads_add_frame_source (60, frame_tick, counter); + 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); @@ -248,7 +260,7 @@ test_timeline (TestConformSimpleFixture *fixture, 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); @@ -260,10 +272,12 @@ test_timeline (TestConformSimpleFixture *fixture, 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); diff --git a/tests/interactive/test-actor-clone.c b/tests/interactive/test-actor-clone.c index 92c7f79f8..d2f15f066 100644 --- a/tests/interactive/test-actor-clone.c +++ b/tests/interactive/test-actor-clone.c @@ -105,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); @@ -126,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); } } @@ -178,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 */ diff --git a/tests/interactive/test-actors.c b/tests/interactive/test-actors.c index eb2c49df3..33fa2d995 100644 --- a/tests/interactive/test-actors.c +++ b/tests/interactive/test-actors.c @@ -98,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); @@ -120,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); } } @@ -172,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-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-cogl-multitexture.c b/tests/interactive/test-cogl-multitexture.c index df7360260..9d7af690a 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); } @@ -122,7 +118,7 @@ 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 */); + 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-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-polygon.c b/tests/interactive/test-cogl-tex-polygon.c index b7252b50a..0e30f74a0 100644 --- a/tests/interactive/test-cogl-tex-polygon.c +++ b/tests/interactive/test-cogl-tex-polygon.c @@ -370,7 +370,7 @@ 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 */ + 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 07f395db6..5d40e1344 100644 --- a/tests/interactive/test-cogl-tex-tile.c +++ b/tests/interactive/test-cogl-tex-tile.c @@ -202,7 +202,7 @@ 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 */ + 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 093e32a4a..4fad21d07 100644 --- a/tests/interactive/test-cogl-vertex-buffer.c +++ b/tests/interactive/test-cogl-vertex-buffer.c @@ -59,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; @@ -354,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", diff --git a/tests/interactive/test-depth.c b/tests/interactive/test-depth.c index 2f8491077..7f5d1edd0 100644 --- a/tests/interactive/test-depth.c +++ b/tests/interactive/test-depth.c @@ -157,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-layout.c b/tests/interactive/test-layout.c index 93783723e..5fca0e2b9 100644 --- a/tests/interactive/test-layout.c +++ b/tests/interactive/test-layout.c @@ -756,7 +756,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), diff --git a/tests/interactive/test-multistage.c b/tests/interactive/test-multistage.c index 40caa40f6..1cc1fc8ab 100644 --- a/tests/interactive/test-multistage.c +++ b/tests/interactive/test-multistage.c @@ -72,7 +72,7 @@ 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); + timeline = clutter_timeline_new (2000); clutter_timeline_set_loop (timeline, TRUE); alpha = clutter_alpha_new_full (timeline, CLUTTER_LINEAR); diff --git a/tests/interactive/test-paint-wrapper.c b/tests/interactive/test-paint-wrapper.c index ac53221e5..e84d72c84 100644 --- a/tests/interactive/test-paint-wrapper.c +++ b/tests/interactive/test-paint-wrapper.c @@ -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); } } @@ -208,7 +209,7 @@ 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 */ + timeline = clutter_timeline_new (6000); clutter_timeline_set_loop (timeline, TRUE); /* fire a callback for frame change */ 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-rotate.c b/tests/interactive/test-rotate.c index 6fea09ca0..ee11ef353 100644 --- a/tests/interactive/test-rotate.c +++ b/tests/interactive/test-rotate.c @@ -44,7 +44,7 @@ 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 */ + timeline = clutter_timeline_new (7692); /* num frames, fps */ clutter_timeline_set_loop (timeline, TRUE); /* Set an alpha func to power behaviour */ 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-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-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 */ From 26f07abc6566e88828a9d8ca9419b1de3bec7c46 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Wed, 3 Jun 2009 15:22:42 +0100 Subject: [PATCH 121/138] [cogl-material] Allow setting a layer with an invalid texture handle It was previously possible to create a material layer with no texture by setting some property on it such as the matrix. However it was not possible to get back to that state without removing the layer and recreating it. It is useful to be able to remove the texture to free resources without forgetting the state of the layer so we can put a different texture in later. --- clutter/cogl/common/cogl-material.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clutter/cogl/common/cogl-material.c b/clutter/cogl/common/cogl-material.c index 85f9f343b..f3e7bb417 100644 --- a/clutter/cogl/common/cogl-material.c +++ b/clutter/cogl/common/cogl-material.c @@ -671,7 +671,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); @@ -692,7 +693,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); From 046e571bae28790cb4d3e59d83e838a553fe15f0 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 2 Jun 2009 18:44:30 +0100 Subject: [PATCH 122/138] Remove usage of Units and macros The ClutterUnit and relative macros should not be used when dealing with pixels -- which is to say, all the time when inside Clutter. --- clutter/clutter-backend.c | 4 +- clutter/clutter-interval.c | 15 +---- clutter/clutter-text.c | 90 +++++++++++++-------------- clutter/x11/clutter-stage-x11.c | 31 +++++---- tests/conform/test-anchors.c | 54 ++++++++-------- tests/conform/test-binding-pool.c | 16 ++--- tests/interactive/test-animation.c | 5 +- tests/interactive/test-binding-pool.c | 16 ++--- tests/interactive/test-layout.c | 68 ++++++++++---------- tests/interactive/test-project.c | 20 +++--- tests/interactive/test-text-field.c | 8 +-- 11 files changed, 143 insertions(+), 184 deletions(-) diff --git a/clutter/clutter-backend.c b/clutter/clutter-backend.c index e423edb21..cc5f10688 100644 --- a/clutter/clutter-backend.c +++ b/clutter/clutter-backend.c @@ -103,11 +103,11 @@ clutter_backend_dispose (GObject *gobject) G_OBJECT_CLASS (clutter_backend_parent_class)->dispose (gobject); } -static ClutterUnit +static gfloat get_units_per_em (ClutterBackend *backend, PangoFontDescription *font_desc) { - ClutterUnit units_per_em = -1.0; + gfloat units_per_em = -1.0; gboolean free_font_desc = FALSE; gdouble dpi; diff --git a/clutter/clutter-interval.c b/clutter/clutter-interval.c index 469c217db..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; diff --git a/clutter/clutter-text.c b/clutter/clutter-text.c index d267da612..de3ee0b5e 100644 --- a/clutter/clutter-text.c +++ b/clutter/clutter-text.c @@ -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); @@ -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; @@ -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; } @@ -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); @@ -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; + ClutterText *self = CLUTTER_TEXT (actor); + ClutterTextPrivate *priv = self->priv; gfloat x, y; - gint index_; - const gchar *text; + 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; @@ -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) : 1; if (min_width_p) @@ -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; } diff --git a/clutter/x11/clutter-stage-x11.c b/clutter/x11/clutter-stage-x11.c index dc6277e9e..ebf693097 100644 --- a/clutter/x11/clutter-stage-x11.c +++ b/clutter/x11/clutter-stage-x11.c @@ -111,8 +111,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) @@ -186,10 +186,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,15 +198,14 @@ 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 @@ -225,10 +224,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,15 +237,13 @@ 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 @@ -258,8 +255,8 @@ clutter_stage_x11_allocate (ClutterActor *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) { diff --git a/tests/conform/test-anchors.c b/tests/conform/test-anchors.c index 4549275da..e4d906ff6 100644 --- a/tests/conform/test-anchors.c +++ b/tests/conform/test-anchors.c @@ -102,20 +102,19 @@ notify_cb (GObject *object, GParamSpec *pspec, TestState *state) 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)));\ - } G_STMT_END + 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) G_STMT_START { \ - 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); } G_STMT_END +#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) @@ -134,15 +133,15 @@ check_coords (TestState *state, 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 @@ -494,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); @@ -511,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); @@ -557,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 @@ -570,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-binding-pool.c b/tests/conform/test-binding-pool.c index acbedfdb6..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); diff --git a/tests/interactive/test-animation.c b/tests/interactive/test-animation.c index 3fde8a68a..7b31a8912 100644 --- a/tests/interactive/test-animation.c +++ b/tests/interactive/test-animation.c @@ -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-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-layout.c b/tests/interactive/test-layout.c index 93783723e..989b68e64 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,7 +233,7 @@ 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; @@ -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,7 +311,7 @@ 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; @@ -374,7 +374,7 @@ my_thing_allocate (ClutterActor *self, gboolean origin_changed) { 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 */ @@ -394,7 +394,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; @@ -517,21 +517,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, diff --git a/tests/interactive/test-project.c b/tests/interactive/test-project.c index 25481f3f7..f61fff4bf 100644 --- a/tests/interactive/test-project.c +++ b/tests/interactive/test-project.c @@ -118,10 +118,10 @@ on_event (ClutterStage *stage, { if (dragging) { - gfloat x, y; - gint i; ClutterActorBox box1, box2; - ClutterUnit xp, yp; + gfloat x, y; + gfloat xp, yp; + gint i; i = find_handle_index (dragging); @@ -133,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)); - + 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-text-field.c b/tests/interactive/test-text-field.c index 783fc465c..7acc60521 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 (); } From 1580ffb884fa1864e9bd53934ae2d1258c3b7dbe Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 3 Jun 2009 10:09:56 +0100 Subject: [PATCH 123/138] Remove a stray g_value_get_int() Now that all properties are float, using g_value_get_int() to retrieve the value of the :anchor-x property is going to print out a warning. --- clutter/clutter-actor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index b57b41c0d..9d98dcd92 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -2612,7 +2612,7 @@ clutter_actor_set_property (GObject *object, case PROP_ANCHOR_Y: { - gfloat 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, From 0d5e17ecd12c680e52144e9f3493616cf96cbd05 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 3 Jun 2009 11:12:09 +0100 Subject: [PATCH 124/138] [units] Rework Units into logical distance value Units as they have been implemented since Clutter 0.4 have always been misdefined as "logical distance unit", while they were just pixels with fractionary bits. Units should be reworked to be opaque structures to hold a value and its unit type, that can be then converted into pixels when Clutter needs to paint or compute size requisitions and perform allocations. The previous API should be completely removed to avoid collisions, and a new type: ClutterUnits should be added; the ability to install GObject properties using ClutterUnits should be maintained. --- .gitignore | 2 + clutter/clutter-actor.c | 111 +-- clutter/clutter-units.c | 781 +++++++++++++-------- clutter/clutter-units.h | 279 +++----- doc/reference/clutter/clutter-sections.txt | 50 +- tests/conform/Makefile.am | 1 + tests/conform/test-clutter-units.c | 58 ++ tests/conform/test-conform-main.c | 3 + tests/interactive/test-text-field.c | 22 +- 9 files changed, 714 insertions(+), 593 deletions(-) create mode 100644 tests/conform/test-clutter-units.c diff --git a/.gitignore b/.gitignore index 561b69b44..c726ce016 100644 --- a/.gitignore +++ b/.gitignore @@ -202,6 +202,8 @@ stamp-h1 /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 diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 9d98dcd92..39999a27a 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -2903,7 +2903,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; @@ -7147,91 +7147,29 @@ parse_units (ClutterActor *self, if (G_VALUE_HOLDS (&value, G_TYPE_INT)) { - retval = g_value_get_int (&value); + 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 = 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 = val; - goto out; - } - - if (strcmp (end, "em") == 0) - { - retval = CLUTTER_UNITS_FROM_EM (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_width (stage) * val; - } - else - { - retval = clutter_actor_get_height (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)) { @@ -7505,7 +7443,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) { diff --git a/clutter/clutter-units.c b/clutter/clutter-units.c index a0ccddc05..2488a109a 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,44 +104,9 @@ clutter_units_pt (gdouble pt) return pt * dpi / 72.0; } -/** - * clutter_units_em: - * @em: em to convert - * - * Converts a value in em to #ClutterUnits at the - * current DPI - * - * Return value: the value in units - * - * Since: 1.0 - */ -ClutterUnit -clutter_units_em (gdouble em) -{ - ClutterBackend *backend = clutter_get_default_backend (); - - return em * _clutter_backend_get_units_per_em (backend, NULL); -} - -/** - * clutter_units_em_for_font: - * @font_name: the font name and size - * @em: em to convert - * - * Converts a value in em to #ClutterUnits at the - * current DPI for the given font name. - * - * The @font_name string must be in a format that - * pango_font_description_from_string() can parse, like - * for clutter_text_set_font_name() or clutter_backend_set_font_name(). - * - * Return value: the value in units - * - * Since: 1.0 - */ -ClutterUnit -clutter_units_em_for_font (const gchar *font_name, - gdouble em) +static gfloat +units_em_to_pixels (const gchar *font_name, + gfloat em) { ClutterBackend *backend = clutter_get_default_backend (); @@ -218,19 +132,185 @@ clutter_units_em_for_font (const gchar *font_name, } /** - * clutter_units_pixels: - * @px: pixels to convert + * clutter_units_mm: + * @units: a #ClutterUnits + * @mm: millimeters * - * Converts a value in pixels to #ClutterUnits - * - * Return value: the value in units + * Stores a value in millimiters inside @units * * Since: 1.0 */ -ClutterUnit -clutter_units_pixels (gint px) +void +clutter_units_mm (ClutterUnits *units, + gfloat mm) { - return CLUTTER_UNITS_FROM_INT (px); + g_return_if_fail (units != NULL); + + units->unit_type = CLUTTER_UNIT_MM; + units->value = mm; + units->pixels = units_mm_to_pixels (mm); + units->pixels_set = TRUE; +} + +/** + * 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: + * @units: a #ClutterUnits + * @px: pixels + * + * Stores a value in pixels inside @units + * + * Since: 1.0 + */ +void +clutter_units_pixels (ClutterUnits *units, + gint 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); } /** @@ -243,156 +323,271 @@ 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; +} + +/** + * 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 * @@ -401,16 +596,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. @@ -419,76 +614,98 @@ 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; + 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); + units->value = CLAMP (units->value, + uspec->minimum, + uspec->maximum); - return value->data[0].v_float != oval; + 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"), @@ -499,38 +716,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 0439df433..873f78410 100644 --- a/clutter/clutter-units.h +++ b/clutter/clutter-units.h @@ -25,7 +25,7 @@ */ #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__ @@ -38,240 +38,131 @@ 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_em_for_font (const gchar *font_name, - 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/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt index 142d28b82..f29e8c0fe 100644 --- a/doc/reference/clutter/clutter-sections.txt +++ b/doc/reference/clutter/clutter-sections.txt @@ -27,45 +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
diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am index be19c0408..99cedbefc 100644 --- a/tests/conform/Makefile.am +++ b/tests/conform/Makefile.am @@ -30,6 +30,7 @@ test_conformance_SOURCES = \ 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: 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-conform-main.c b/tests/conform/test-conform-main.c index fc0daacdc..d05ae9d3a 100644 --- a/tests/conform/test-conform-main.c +++ b/tests/conform/test-conform-main.c @@ -148,5 +148,8 @@ main (int argc, char **argv) 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/interactive/test-text-field.c b/tests/interactive/test-text-field.c index 7acc60521..d77ce41a4 100644 --- a/tests/interactive/test-text-field.c +++ b/tests/interactive/test-text-field.c @@ -90,18 +90,20 @@ 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}; + ClutterUnits h_padding, v_padding; gfloat width, height; - gfloat h_padding, v_padding; clutter_init (&argc, &argv); stage = clutter_stage_get_default (); clutter_stage_set_color (CLUTTER_STAGE (stage), &background_color); - h_padding = clutter_units_em_for_font (FONT, 2.0); /* 2em */ - v_padding = clutter_units_em_for_font (FONT, 3.0); /* 3em */ + 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", h_padding, v_padding); + 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); @@ -111,17 +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, 10 + width + h_padding, 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 + v_padding); + 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 + h_padding, - height + 10 + v_padding); + 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); From 0187bb396524435fe32696176bcb234f36be326f Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 3 Jun 2009 14:02:06 +0100 Subject: [PATCH 125/138] [actor] Use flags to control allocations Instead of passing a boolean value, the ::allocate virtual function should use a bitmask and flags. This gives us room for expansion without breaking API/ABI, and allows to encode more information to the allocation process instead of just changes of absolute origin. --- clutter/clutter-actor.c | 64 ++++++++++++++--------------- clutter/clutter-actor.h | 46 ++++++++++++++------- clutter/clutter-clone.c | 13 +++--- clutter/clutter-group.c | 17 ++++---- clutter/clutter-main.c | 2 +- clutter/clutter-stage.c | 21 ++++++---- clutter/clutter-text.c | 8 ++-- clutter/clutter-texture.c | 13 +++--- clutter/osx/clutter-stage-osx.c | 8 ++-- clutter/sdl/clutter-stage-sdl.c | 8 ++-- clutter/win32/clutter-stage-win32.c | 16 ++++---- clutter/x11/clutter-stage-x11.c | 8 ++-- tests/interactive/test-layout.c | 13 +++--- 13 files changed, 128 insertions(+), 109 deletions(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 39999a27a..9721e1bc3 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -1541,9 +1541,9 @@ clutter_actor_notify_if_geometry_changed (ClutterActor *self, } 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; @@ -4697,25 +4697,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; @@ -4724,7 +4723,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); @@ -4743,7 +4741,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) @@ -4752,13 +4750,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); } /** @@ -8202,8 +8204,7 @@ clutter_actor_get_stage (ClutterActor *actor) * actor's natural width * @available_height: the maximum available height, or -1 to use the * actor's natural height - * @absolute_origin_changed: whether the position of the parent has - * changed in stage coordinates + * @flags: flags controlling the allocation * * Allocates @self taking into account the #ClutterActor's * preferred size, but limiting it to the maximum available width @@ -8243,7 +8244,7 @@ clutter_actor_get_stage (ClutterActor *actor) * box.x1 = x; box.y1 = y; * box.x2 = box.x1 + available_width; * box.y2 = box.y1 + available_height; - * clutter_actor_allocate (self, &box, absolute_origin_changed); + * clutter_actor_allocate (self, &box, flags); * ]| * * This function can be used by fluid layout managers to allocate @@ -8253,12 +8254,12 @@ clutter_actor_get_stage (ClutterActor *actor) * Since: 1.0 */ void -clutter_actor_allocate_available_size (ClutterActor *self, - gfloat x, - gfloat y, - gfloat available_width, - gfloat available_height, - gboolean absolute_origin_changed) +clutter_actor_allocate_available_size (ClutterActor *self, + gfloat x, + gfloat y, + gfloat available_width, + gfloat available_height, + ClutterAllocationFlags flags) { ClutterActorPrivate *priv; gfloat width, height; @@ -8302,14 +8303,13 @@ clutter_actor_allocate_available_size (ClutterActor *self, box.y1 = y; box.x2 = box.x1 + width; box.y2 = box.y1 + height; - clutter_actor_allocate (self, &box, absolute_origin_changed); + 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. * @@ -8327,8 +8327,8 @@ clutter_actor_allocate_available_size (ClutterActor *self, * Since: 0.8 */ void -clutter_actor_allocate_preferred_size (ClutterActor *self, - gboolean absolute_origin_changed) +clutter_actor_allocate_preferred_size (ClutterActor *self, + ClutterAllocationFlags flags) { gfloat actor_x, actor_y; gfloat natural_width, natural_height; @@ -8349,7 +8349,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); } /** diff --git a/clutter/clutter-actor.h b/clutter/clutter-actor.h index e30f85b66..9c7b9cd9b 100644 --- a/clutter/clutter-actor.h +++ b/clutter/clutter-actor.h @@ -120,6 +120,24 @@ typedef enum 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 @@ -241,17 +259,17 @@ struct _ClutterActorClass ClutterActor *leaf_that_queued); /* size negotiation */ - 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, - 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); @@ -320,15 +338,15 @@ void clutter_actor_get_preferred_size (ClutterActor 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, - gboolean absolute_origin_changed); + ClutterAllocationFlags flags); void clutter_actor_get_allocation_coords (ClutterActor *self, gint *x_1, gint *y_1, diff --git a/clutter/clutter-clone.c b/clutter/clutter-clone.c index a8ba17cd4..78bc4148a 100644 --- a/clutter/clutter-clone.c +++ b/clutter/clutter-clone.c @@ -172,16 +172,16 @@ clutter_clone_paint (ClutterActor *self) } 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; @@ -194,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 diff --git a/clutter/clutter-group.c b/clutter/clutter-group.c index 148309b97..0653e76f1 100644 --- a/clutter/clutter-group.c +++ b/clutter/clutter-group.c @@ -279,15 +279,15 @@ 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); } } @@ -320,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 diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c index a4a690b46..055d7d6b0 100644 --- a/clutter/clutter-main.c +++ b/clutter/clutter-main.c @@ -143,7 +143,7 @@ _clutter_stage_maybe_relayout (ClutterActor *stage) (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); } diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index c6f736e4e..0e6825f32 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -157,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); @@ -180,10 +183,10 @@ clutter_stage_allocate (ClutterActor *self, 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 { @@ -193,7 +196,7 @@ clutter_stage_allocate (ClutterActor *self, /* 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, @@ -216,7 +219,7 @@ clutter_stage_allocate (ClutterActor *self, /* and store the overridden allocation */ klass = CLUTTER_ACTOR_CLASS (clutter_stage_parent_class); - klass->allocate (self, &override, origin_changed); + klass->allocate (self, &override, flags); } } @@ -382,7 +385,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 diff --git a/clutter/clutter-text.c b/clutter/clutter-text.c index de3ee0b5e..f8d0f43eb 100644 --- a/clutter/clutter-text.c +++ b/clutter/clutter-text.c @@ -1548,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; @@ -1563,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 diff --git a/clutter/clutter-texture.c b/clutter/clutter-texture.c index ac53b73fc..dfb54b2dd 100644 --- a/clutter/clutter-texture.c +++ b/clutter/clutter-texture.c @@ -428,20 +428,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 diff --git a/clutter/osx/clutter-stage-osx.c b/clutter/osx/clutter-stage-osx.c index b29070c5b..cb04b22cb 100644 --- a/clutter/osx/clutter-stage-osx.c +++ b/clutter/osx/clutter-stage-osx.c @@ -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/sdl/clutter-stage-sdl.c b/clutter/sdl/clutter-stage-sdl.c index 43259b369..e1cf387ab 100644 --- a/clutter/sdl/clutter-stage-sdl.c +++ b/clutter/sdl/clutter-stage-sdl.c @@ -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 diff --git a/clutter/win32/clutter-stage-win32.c b/clutter/win32/clutter-stage-win32.c index f83c3c873..0b45a49f5 100644 --- a/clutter/win32/clutter-stage-win32.c +++ b/clutter/win32/clutter-stage-win32.c @@ -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 diff --git a/clutter/x11/clutter-stage-x11.c b/clutter/x11/clutter-stage-x11.c index ebf693097..6458d459c 100644 --- a/clutter/x11/clutter-stage-x11.c +++ b/clutter/x11/clutter-stage-x11.c @@ -247,9 +247,9 @@ clutter_stage_x11_get_preferred_height (ClutterActor *self, } 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; @@ -300,7 +300,7 @@ clutter_stage_x11_allocate (ClutterActor *self, /* 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 diff --git a/tests/interactive/test-layout.c b/tests/interactive/test-layout.c index 989b68e64..ea94ecab4 100644 --- a/tests/interactive/test-layout.c +++ b/tests/interactive/test-layout.c @@ -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; 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; @@ -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; From 5ebb59e6b0a11c156e1f246a852986f15080f297 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 4 Jun 2009 12:00:58 +0100 Subject: [PATCH 126/138] [actor] Add the ::allocation-changed signal Sometimes it is useful to be able to track changes in the allocation flags, like the absolute origin, inside children of a container. Using the notify::allocation signal is not enough, in these cases, so we need a specific signal that gives us both the allocation box and the allocation flags. --- clutter/clutter-actor.c | 43 +++++++++++++++++++++++++++++++++++- clutter/clutter-marshal.list | 1 + 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 9721e1bc3..e34962566 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -273,6 +273,7 @@ struct _ClutterActorPrivate gfloat request_natural_height; ClutterActorBox allocation; + ClutterAllocationFlags allocation_flags; guint position_set : 1; guint min_width_set : 1; @@ -434,6 +435,7 @@ enum MOTION_EVENT, ENTER_EVENT, LEAVE_EVENT, + ALLOCATION_CHANGED, LAST_SIGNAL }; @@ -1547,6 +1549,7 @@ clutter_actor_real_allocate (ClutterActor *self, { 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); @@ -1556,13 +1559,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); @@ -4200,6 +4215,32 @@ 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; diff --git a/clutter/clutter-marshal.list b/clutter/clutter-marshal.list index 995c5c712..069d73774 100644 --- a/clutter/clutter-marshal.list +++ b/clutter/clutter-marshal.list @@ -3,6 +3,7 @@ BOOLEAN:STRING,UINT,ENUM DOUBLE:VOID UINT:VOID VOID:BOXED +VOID:BOXED,FLAGS VOID:INT VOID:INT64,INT64,FLOAT,BOOLEAN VOID:INT,INT From 876dc22633a62c3eb451d9f491d97cddadf6d3c0 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 4 Jun 2009 12:15:15 +0100 Subject: [PATCH 127/138] [units] Validate units against the ParamSpec When declaring a property using ClutterParamSpecUnits we pass a default type to limit the type of units we accept as valid values for the property. This means that we need to add the unit type check as part of the validation process. --- clutter/clutter-units.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/clutter/clutter-units.c b/clutter/clutter-units.c index 2488a109a..97b2d9a05 100644 --- a/clutter/clutter-units.c +++ b/clutter/clutter-units.c @@ -447,6 +447,29 @@ clutter_units_from_string (ClutterUnits *units, 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 @@ -653,10 +676,25 @@ param_units_validate (GParamSpec *pspec, { 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_UNITS (pspec)); + if (otype != uspec->default_type) + { + gchar *str = clutter_units_to_string (units); + + 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); From 0a4a28a950ae5022684742d18144c1cb9b6a96d1 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 4 Jun 2009 13:41:32 +0100 Subject: [PATCH 128/138] [xinput] Check for the XInput entry points Apparently, the XInput extension is using the same pkg-config file ('xi') for both the 1.x and the 2.x API, so we need to check for both the 1.x XGetExtensionVersion and the 2.x XQueryInputVersion. --- clutter/x11/clutter-backend-x11.c | 36 ++++++++++++++++++++++--------- clutter/x11/clutter-backend-x11.h | 12 ++--------- clutter/x11/clutter-event-x11.c | 8 +++---- clutter/x11/clutter-stage-x11.h | 6 ++---- configure.ac | 33 +++++++++++++++++++++++++++- 5 files changed, 66 insertions(+), 29 deletions(-) diff --git a/clutter/x11/clutter-backend-x11.c b/clutter/x11/clutter-backend-x11.c index 07e8b45e9..ab3760f0d 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,7 +638,7 @@ clutter_x11_remove_filter (ClutterX11FilterFunc func, } } -#ifdef USE_XINPUT +#ifdef HAVE_XINPUT void _clutter_x11_register_xinput () @@ -669,7 +677,15 @@ _clutter_x11_register_xinput () backend_singleton->have_xinput = TRUE; - ext = XGetExtensionVersion(backend_singleton->xdpy, INAME); +#ifdef HAVE_XGET_EXTENSION_VERSION + ext = XGetExtensionVersion (backend_singleton->xdpy, INAME); +#elif HAVE_XQUERY_INPUT_VERSION + ext = XQueryInputVersion (backend_singleton->xdpy, XI_2_Major, XI_2_Minor); +#else + g_critical ("XInput does not have XGetExtensionVersion nor " + "XQueryInputVersion"); + return; +#endif if (!ext || (ext == (XExtensionVersion*) NoSuchExtension)) { @@ -879,7 +895,7 @@ clutter_x11_get_input_devices (void) { ClutterMainContext *context; -#ifdef USE_XINPUT +#ifdef HAVE_XINPUT if (!backend_singleton) { g_critical ("X11 backend has not been initialised"); @@ -889,9 +905,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 +939,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"); diff --git a/clutter/x11/clutter-backend-x11.h b/clutter/x11/clutter-backend-x11.h index 4f75359c8..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; }; @@ -127,7 +121,6 @@ XVisualInfo * clutter_backend_x11_get_visual_info (ClutterBackendX11 *backend_x11, gboolean for_offscreen); -#ifdef USE_XINPUT void _clutter_x11_register_xinput (void); @@ -136,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..5c81738d0 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, @@ -738,7 +738,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); diff --git a/clutter/x11/clutter-stage-x11.h b/clutter/x11/clutter-stage-x11.h index c1a913950..eac4192a6 100644 --- a/clutter/x11/clutter-stage-x11.h +++ b/clutter/x11/clutter-stage-x11.h @@ -62,10 +62,8 @@ struct _ClutterStageX11 ClutterBackendX11 *backend; ClutterStageState state; -#ifdef USE_XINPUT - int event_types[CLUTTER_X11_XINPUT_LAST_EVENT]; - GList *devices; -#endif + int event_types[CLUTTER_X11_XINPUT_LAST_EVENT]; + GList *devices; ClutterStage *wrapper; }; diff --git a/configure.ac b/configure.ac index 49911ee9f..f321f97d4 100644 --- a/configure.ac +++ b/configure.ac @@ -491,7 +491,38 @@ AS_IF([test "x$clutterbackend" = "xglx" || test "x$clutterbackend" = "xeglx"], [yes], [ - AC_DEFINE(USE_XINPUT, 1, Use the XINPUT X extension) + 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" From e4ff24bcff4881ddadaf3bb52d74ee71061504fc Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 4 Jun 2009 16:27:21 +0100 Subject: [PATCH 129/138] [x11] Rework map/unmap and resizing The mapping and unmapping of the X11 stage implementation is a bit bong. It's asynchronous, for starters, when it really can avoid it by tracking the state internally. The ordering of the map/unmap sequence is also broken with respect to the resizing. By tracking the state internally into StageX11 we can safely remove the MapNotify and UnmapNotify X event handling. In theory, we should use _NET_WM_STATE a lot more, and reuse the X11 state flags for fullscreening as well. --- clutter/clutter-actor.c | 5 +- clutter/clutter-stage-window.h | 4 + clutter/clutter-stage.c | 13 ++- clutter/glx/clutter-stage-glx.c | 2 +- clutter/x11/clutter-event-x11.c | 9 +- clutter/x11/clutter-stage-x11.c | 195 ++++++++++++++++++++------------ clutter/x11/clutter-stage-x11.h | 11 +- 7 files changed, 155 insertions(+), 84 deletions(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index e34962566..071aa9e90 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -699,8 +699,9 @@ clutter_actor_update_map_state (ClutterActor *self, !CLUTTER_ACTOR_IS_VISIBLE (self) && !(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_DESTRUCTION)) { - g_warning ("Clutter toplevel is not visible, but is " - "somehow still mapped"); + g_warning ("Clutter toplevel of type '%s' is not visible, but " + "it is somehow still mapped", + G_OBJECT_TYPE_NAME (self)); } } else 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 0e6825f32..75cfc47a4 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -316,23 +316,26 @@ static void clutter_stage_show (ClutterActor *self) { ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; + ClutterStageWindow *impl; CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->show (self); g_assert (priv->impl != NULL); - - clutter_actor_show (priv->impl); + 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; - - CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->hide (self); + 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 diff --git a/clutter/glx/clutter-stage-glx.c b/clutter/glx/clutter-stage-glx.c index 7e139e777..7a845654c 100644 --- a/clutter/glx/clutter-stage-glx.c +++ b/clutter/glx/clutter-stage-glx.c @@ -199,7 +199,7 @@ 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); /* ask for a context; a no-op, if a context already exists */ diff --git a/clutter/x11/clutter-event-x11.c b/clutter/x11/clutter-event-x11.c index 5c81738d0..ec3ad72db 100644 --- a/clutter/x11/clutter-event-x11.c +++ b/clutter/x11/clutter-event-x11.c @@ -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; diff --git a/clutter/x11/clutter-stage-x11.c b/clutter/x11/clutter-stage-x11.c index 6458d459c..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; @@ -98,12 +100,19 @@ clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11) 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; @@ -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) - XWithdrawWindow (stage_x11->xdpy, stage_x11->xwin, stage_x11->xscreen); -} - void clutter_stage_x11_set_wm_protocols (ClutterStageX11 *stage_x11) { @@ -268,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) { @@ -289,7 +274,7 @@ 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) { @@ -440,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, @@ -470,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); } } } @@ -503,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 * @@ -538,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; @@ -558,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; @@ -577,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; } /** @@ -770,32 +854,3 @@ clutter_x11_set_stage_foreign (ClutterStage *stage, return TRUE; } - -void -clutter_stage_x11_map (ClutterStageX11 *stage_x11) -{ - CLUTTER_NOTE (BACKEND, "Mapping stage '%s' [%p]", - G_OBJECT_TYPE_NAME (stage_x11), - stage_x11); - - clutter_actor_map (CLUTTER_ACTOR (stage_x11)); - clutter_actor_map (CLUTTER_ACTOR (stage_x11->wrapper)); - - 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) -{ - CLUTTER_NOTE (BACKEND, "Unmapping stage '%s' [%p]", - G_OBJECT_TYPE_NAME (stage_x11), - stage_x11); - - clutter_actor_unmap (CLUTTER_ACTOR (stage_x11)); - clutter_actor_unmap (CLUTTER_ACTOR (stage_x11->wrapper)); -} diff --git a/clutter/x11/clutter-stage-x11.h b/clutter/x11/clutter-stage-x11.h index eac4192a6..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,6 +67,8 @@ struct _ClutterStageX11 ClutterBackendX11 *backend; ClutterStageState state; + ClutterStageX11State wm_state; + int event_types[CLUTTER_X11_XINPUT_LAST_EVENT]; GList *devices; @@ -76,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); From 5ea3b47144720dfa1692cc085537300e4d24d97c Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 4 Jun 2009 16:50:19 +0100 Subject: [PATCH 130/138] [actor] Force unrealization on destroy only for non-toplevels We cannot force unrealization on toplevels ourselves, so we need to check inside clutter_actor_destroy() if we want to avoid a warning. --- clutter/clutter-actor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 071aa9e90..3aac1c1fc 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -4314,7 +4314,8 @@ clutter_actor_destroy (ClutterActor *self) /* if we are destroying we want to unrealize ourselves * first before the dispose run removes the parent */ - clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNREALIZED); + 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)); From c27f42981961eed79ef32e4b4fd7081098619844 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 4 Jun 2009 17:28:35 +0100 Subject: [PATCH 131/138] [text] Fix Pango unit to pixels conversion When going from Pango units to pixels we need to divide by 1024, and not multiply by 1024. --- clutter/clutter-text.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clutter/clutter-text.c b/clutter/clutter-text.c index f8d0f43eb..ec3484744 100644 --- a/clutter/clutter-text.c +++ b/clutter/clutter-text.c @@ -1465,7 +1465,7 @@ clutter_text_get_preferred_width (ClutterActor *self, logical_width = logical_rect.x + logical_rect.width; layout_width = logical_width > 0 - ? (logical_width * 1024) + ? (logical_width / 1024.0f) : 1; if (min_width_p) From 54d8aadf1d86bf6cfacc5346c02a13f3a2577268 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 4 Jun 2009 16:04:57 +0100 Subject: [PATCH 132/138] [cogl] Move the texture filters to be a property of the material layer The texture filters are now a property of the material layer rather than the texture object. Whenever a texture is painted with a material it sets the filters on all of the GL textures in the Cogl texture. The filter is cached so that it won't be changed unnecessarily. The automatic mipmap generation has changed so that the mipmaps are only generated when the texture is painted instead of every time the data changes. Changing the texture sets a flag to mark that the mipmaps are dirty. This works better if the FBO extension is available because we can use glGenerateMipmap. If the extension is not available it will temporarily enable automatic mipmap generation and reupload the first pixel of each slice. This requires tracking the data for the first pixel. The COGL_TEXTURE_AUTO_MIPMAP flag has been replaced with COGL_TEXTURE_NO_AUTO_MIPMAP so that it will default to auto-mipmapping. The mipmap generation is now effectively free if you are not using a mipmap filter mode so you would only want to disable it if you had some special reason to generate your own mipmaps. ClutterTexture no longer has to store its own copy of the filter mode. Instead it stores it in the material and the property is directly set and read from that. This fixes problems with the filters getting out of sync when a cogl handle is set on the texture directly. It also avoids the mess of having to rerealize the texture if the filter quality changes to HIGH because Cogl will take of generating the mipmaps if needed. --- clutter/clutter-texture.c | 132 +++++--------- clutter/cogl/cogl-material.h | 80 +++++++++ clutter/cogl/cogl-texture.h | 80 --------- clutter/cogl/cogl-types.h | 13 +- clutter/cogl/common/cogl-material-private.h | 3 + clutter/cogl/common/cogl-material.c | 59 ++++++ clutter/cogl/common/cogl-primitives.c | 3 +- clutter/cogl/gl/cogl-context.h | 1 + clutter/cogl/gl/cogl-defines.h.in | 4 + clutter/cogl/gl/cogl-texture-private.h | 31 +++- clutter/cogl/gl/cogl-texture.c | 189 +++++++++++++------- clutter/cogl/gl/cogl.c | 7 +- clutter/glx/clutter-glx-texture-pixmap.c | 20 ++- clutter/pango/cogl-pango-glyph-cache.c | 22 +-- clutter/pango/cogl-pango-glyph-cache.h | 2 +- clutter/pango/cogl-pango-render.c | 40 +++-- doc/reference/cogl/cogl-sections.txt | 7 +- tests/conform/test-backface-culling.c | 22 ++- tests/interactive/test-cogl-multitexture.c | 9 +- tests/interactive/test-cogl-tex-polygon.c | 21 ++- tests/interactive/test-cogl-tex-tile.c | 4 - 21 files changed, 427 insertions(+), 322 deletions(-) diff --git a/clutter/clutter-texture.c b/clutter/clutter-texture.c index dfb54b2dd..3181ff81e 100644 --- a/clutter/clutter-texture.c +++ b/clutter/clutter-texture.c @@ -79,7 +79,6 @@ struct _ClutterTexturePrivate { gfloat width; gfloat height; - ClutterTextureQuality filter_quality; CoglHandle material; gboolean no_slice; @@ -176,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 @@ -216,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 @@ -285,7 +286,6 @@ clutter_texture_realize (ClutterActor *actor) if (priv->fbo_source) { CoglTextureFlags flags = COGL_TEXTURE_NONE; - gint min_filter, mag_filter; CoglHandle tex; /* Handle FBO's */ @@ -293,9 +293,6 @@ clutter_texture_realize (ClutterActor *actor) if (priv->no_slice) flags |= COGL_TEXTURE_NO_SLICING; - if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH) - flags |= COGL_TEXTURE_AUTO_MIPMAP; - tex = cogl_texture_new_with_size (priv->width, priv->height, flags, @@ -303,12 +300,6 @@ clutter_texture_realize (ClutterActor *actor) 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 @@ -1189,7 +1180,6 @@ clutter_texture_init (ClutterTexture *self) self->priv = priv = CLUTTER_TEXTURE_GET_PRIVATE (self); - priv->filter_quality = CLUTTER_TEXTURE_QUALITY_MEDIUM; priv->repeat_x = FALSE; priv->repeat_y = FALSE; priv->sync_actor_size = TRUE; @@ -1229,11 +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 from the texture properties so that - * they will be restored the data is loaded again - */ - priv->filter_quality = clutter_texture_get_filter_quality (texture); - priv->local_data = g_malloc (priv->local_data_rowstride * priv->local_data_height); @@ -1465,14 +1450,10 @@ 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; 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. */ @@ -1493,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); @@ -1669,9 +1644,6 @@ clutter_texture_async_load_complete (ClutterTexture *self, if (priv->no_slice) flags |= COGL_TEXTURE_NO_SLICING; - if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH) - flags |= COGL_TEXTURE_AUTO_MIPMAP; - handle = cogl_texture_new_from_bitmap (bitmap, flags, COGL_PIXEL_FORMAT_ANY); @@ -1905,7 +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; priv = texture->priv; @@ -1917,9 +1888,6 @@ clutter_texture_set_from_file (ClutterTexture *texture, if (priv->no_slice) flags |= COGL_TEXTURE_NO_SLICING; - if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH) - flags |= COGL_TEXTURE_AUTO_MIPMAP; - new_texture = cogl_texture_new_from_file (filename, flags, COGL_PIXEL_FORMAT_ANY, @@ -1941,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); @@ -1987,26 +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)) - { - _clutter_actor_rerealize (CLUTTER_ACTOR (texture), - NULL, NULL); - } + cogl_material_set_layer_filters (priv->material, 0, + min_filter, mag_filter); g_object_notify (G_OBJECT (texture), "filter-quality"); @@ -2029,12 +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; + + min_filter = cogl_material_layer_get_min_filter (layers->data); + mag_filter = cogl_material_layer_get_mag_filter (layers->data); + + 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; + + /* Unknown filter combination */ + return CLUTTER_TEXTURE_QUALITY_LOW; } /** @@ -2255,7 +2221,6 @@ on_fbo_source_size_change (GObject *object, if (w != priv->width || h != priv->height) { CoglTextureFlags flags = COGL_TEXTURE_NONE; - gint min_filter, mag_filter; CoglHandle tex; /* tear down the FBO */ @@ -2269,9 +2234,6 @@ on_fbo_source_size_change (GObject *object, flags |= COGL_TEXTURE_NO_SLICING; - if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH) - flags |= COGL_TEXTURE_AUTO_MIPMAP; - tex = cogl_texture_new_with_size (MAX (priv->width, 1), MAX (priv->height, 1), flags, @@ -2279,12 +2241,6 @@ on_fbo_source_size_change (GObject *object, 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 diff --git a/clutter/cogl/cogl-material.h b/clutter/cogl/cogl-material.h index 504c173fa..66fbd8d5c 100644 --- a/clutter/cogl/cogl-material.h +++ b/clutter/cogl/cogl-material.h @@ -43,6 +43,52 @@ 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: * @@ -660,6 +706,40 @@ CoglMaterialLayerType cogl_material_layer_get_type (CoglHandle layer_handle); */ CoglHandle cogl_material_layer_get_texture (CoglHandle layer_handle); +/** + * 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. + */ +CoglMaterialFilter cogl_material_layer_get_min_filter (CoglHandle layer_handle); + +/** + * cogl_material_layer_get_mag_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. + */ +CoglMaterialFilter cogl_material_layer_get_mag_filter (CoglHandle layer_handle); + +/** + * 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. + * + * Changes the decimation and interpolation filters used when a texture is + * drawn at other scales than 100%. + */ +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-texture.h b/clutter/cogl/cogl-texture.h index d4cc4e812..15cadc879 100644 --- a/clutter/cogl/cogl-texture.h +++ b/clutter/cogl/cogl-texture.h @@ -218,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. @@ -333,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 3aa6f5c3c..0a1360dde 100644 --- a/clutter/cogl/cogl-types.h +++ b/clutter/cogl/cogl-types.h @@ -244,8 +244,11 @@ 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. @@ -253,9 +256,9 @@ struct _CoglTextureVertex * Since: 1.0 */ typedef enum { - COGL_TEXTURE_NONE = 0, - COGL_TEXTURE_AUTO_MIPMAP = 1 << 0, - COGL_TEXTURE_NO_SLICING = 1 << 1 + COGL_TEXTURE_NONE = 0, + COGL_TEXTURE_NO_AUTO_MIPMAP = 1 << 0, + COGL_TEXTURE_NO_SLICING = 1 << 1 } CoglTextureFlags; /** diff --git a/clutter/cogl/common/cogl-material-private.h b/clutter/cogl/common/cogl-material-private.h index 9b2170ecf..e61ab97bd 100644 --- a/clutter/cogl/common/cogl-material-private.h +++ b/clutter/cogl/common/cogl-material-private.h @@ -68,6 +68,9 @@ 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. */ GLint texture_combine_rgb_func; diff --git a/clutter/cogl/common/cogl-material.c b/clutter/cogl/common/cogl-material.c index f3e7bb417..66a4b0c96 100644 --- a/clutter/cogl/common/cogl-material.c +++ b/clutter/cogl/common/cogl-material.c @@ -637,6 +637,8 @@ _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: @@ -1014,6 +1016,15 @@ get_n_args_for_combine_func (GLint func) 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) @@ -1214,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 @@ -1474,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-primitives.c b/clutter/cogl/common/cogl-primitives.c index c43fbde49..03fe43180 100644 --- a/clutter/cogl/common/cogl-primitives.c +++ b/clutter/cogl/common/cogl-primitives.c @@ -1186,7 +1186,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) diff --git a/clutter/cogl/gl/cogl-context.h b/clutter/cogl/gl/cogl-context.h index 3db4c0e9e..d845a6c12 100644 --- a/clutter/cogl/gl/cogl-context.h +++ b/clutter/cogl/gl/cogl-context.h @@ -120,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; diff --git a/clutter/cogl/gl/cogl-defines.h.in b/clutter/cogl/gl/cogl-defines.h.in index 4805ea5b3..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); 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 80e428eba..e2c6c264f 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,6 +668,8 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, if (waste_buf) g_free (waste_buf); + tex->mipmaps_dirty = TRUE; + return TRUE; } @@ -913,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; @@ -941,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 @@ -985,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 @@ -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; @@ -1239,8 +1273,9 @@ cogl_texture_new_with_size (guint width, else tex->max_waste = COGL_TEXTURE_MAX_WASTE; - tex->min_filter = COGL_TEXTURE_FILTER_NEAREST; - tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST; + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; /* Find closest GL format match */ tex->bitmap.format = @@ -1285,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; @@ -1303,8 +1339,9 @@ cogl_texture_new_from_data (guint width, else tex->max_waste = COGL_TEXTURE_MAX_WASTE; - tex->min_filter = COGL_TEXTURE_FILTER_NEAREST; - tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST; + /* 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 @@ -1348,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 = TRUE; @@ -1363,8 +1401,9 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle, else tex->max_waste = COGL_TEXTURE_MAX_WASTE; - tex->min_filter = COGL_TEXTURE_FILTER_NEAREST; - tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST; + /* 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 @@ -1440,8 +1479,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; @@ -1489,14 +1526,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) ); @@ -1524,6 +1553,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; @@ -1537,8 +1567,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 */ @@ -1684,36 +1715,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; @@ -1724,14 +1729,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) { @@ -1744,6 +1753,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 608bc364e..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; } diff --git a/clutter/glx/clutter-glx-texture-pixmap.c b/clutter/glx/clutter-glx-texture-pixmap.c index b6a677a84..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 diff --git a/clutter/pango/cogl-pango-glyph-cache.c b/clutter/pango/cogl-pango-glyph-cache.c index 9be1e83b8..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, - 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 898c11ee3..89c89c481 100644 --- a/clutter/pango/cogl-pango-render.c +++ b/clutter/pango/cogl-pango-render.c @@ -49,12 +49,8 @@ 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; /* The current display list that is being built */ CoglPangoDisplayList *display_list; @@ -144,9 +140,9 @@ cogl_pango_renderer_init (CoglPangoRenderer *priv) 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_cache = cogl_pango_glyph_cache_new (); + + _cogl_pango_renderer_set_use_mipmapping (priv, FALSE); } static void @@ -167,7 +163,6 @@ 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_OBJECT_CLASS (cogl_pango_renderer_parent_class)->finalize (object); @@ -363,20 +358,31 @@ 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 * @@ -386,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; @@ -423,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), diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index f596ee042..872e02d11 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -132,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
@@ -366,8 +363,12 @@ 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 diff --git a/tests/conform/test-backface-culling.c b/tests/conform/test-backface-culling.c index bfddcf105..5d8b7ba62 100644 --- a/tests/conform/test-backface-culling.c +++ b/tests/conform/test-backface-culling.c @@ -107,6 +107,11 @@ on_paint (ClutterActor *actor, TestState *state) { int i; int frame_num; + CoglHandle material = cogl_material_new (); + + cogl_material_set_layer_filters (material, 0, + COGL_MATERIAL_FILTER_NEAREST, + COGL_MATERIAL_FILTER_NEAREST); cogl_set_backface_culling_enabled (TRUE); @@ -120,24 +125,21 @@ on_paint (ClutterActor *actor, TestState *state) float x1 = 0, x2, y1 = 0, y2 = (float)(TEXTURE_RENDER_SIZE); CoglTextureVertex verts[4]; - memset (verts, 0, sizeof (verts)); + cogl_set_source (material); - /* 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); + memset (verts, 0, sizeof (verts)); 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_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; @@ -152,7 +154,7 @@ 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; @@ -167,7 +169,7 @@ 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; @@ -185,6 +187,8 @@ on_paint (ClutterActor *actor, TestState *state) 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: diff --git a/tests/interactive/test-cogl-multitexture.c b/tests/interactive/test-cogl-multitexture.c index df7360260..c10182760 100644 --- a/tests/interactive/test-cogl-multitexture.c +++ b/tests/interactive/test-cogl-multitexture.c @@ -87,20 +87,17 @@ test_cogl_multitexture_main (int argc, char *argv[]) state->alpha_tex = cogl_texture_new_from_file ("redhand_alpha.png", - COGL_TEXTURE_NO_SLICING | - COGL_TEXTURE_AUTO_MIPMAP, + COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_ANY, NULL); state->redhand_tex = cogl_texture_new_from_file ("redhand.png", - COGL_TEXTURE_NO_SLICING | - COGL_TEXTURE_AUTO_MIPMAP, + COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_ANY, NULL); state->light_tex0 = cogl_texture_new_from_file ("light0.png", - COGL_TEXTURE_NO_SLICING | - COGL_TEXTURE_AUTO_MIPMAP, + COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_ANY, NULL); diff --git a/tests/interactive/test-cogl-tex-polygon.c b/tests/interactive/test-cogl-tex-polygon.c index b7252b50a..4378a7bd0 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 diff --git a/tests/interactive/test-cogl-tex-tile.c b/tests/interactive/test-cogl-tex-tile.c index 07f395db6..2c700b533 100644 --- a/tests/interactive/test-cogl-tex-tile.c +++ b/tests/interactive/test-cogl-tex-tile.c @@ -147,10 +147,6 @@ test_coglbox_init (TestCoglbox *self) 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 From eff82a546d2ae6747ae32f639f07a6d182114016 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 4 Jun 2009 22:10:33 +0100 Subject: [PATCH 133/138] [gles/cogl-shader] Add a missing semicolon cogl_shader_get_info_log was missing a semicolon which broke the build on GLES 2. --- clutter/cogl/gles/cogl-shader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clutter/cogl/gles/cogl-shader.c b/clutter/cogl/gles/cogl-shader.c index 74d0add8e..23109be34 100644 --- a/clutter/cogl/gles/cogl-shader.c +++ b/clutter/cogl/gles/cogl-shader.c @@ -103,7 +103,7 @@ gchar * cogl_shader_get_info_log (CoglHandle handle) { CoglShader *shader; - char buffer[512] + char buffer[512]; int len = 0; _COGL_GET_CONTEXT (ctx, NULL); From 6efbb92c5899dfadac4f366bee709f5154180967 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 4 Jun 2009 22:12:33 +0100 Subject: [PATCH 134/138] Update the GLES backend to have the layer filters in the material This reflects the changes made in 54d8aadf1d86 for the GLES backend. --- clutter/cogl/gles/cogl-texture-private.h | 31 +++- clutter/cogl/gles/cogl-texture.c | 192 ++++++++++++++--------- 2 files changed, 147 insertions(+), 76 deletions(-) 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 99a18f154..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; } @@ -624,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) { @@ -646,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 @@ -678,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) ); @@ -787,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); } @@ -798,6 +816,8 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, if (waste_buf) g_free (waste_buf); + tex->mipmaps_dirty = TRUE; + return TRUE; } @@ -1055,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; @@ -1085,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, @@ -1128,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 @@ -1307,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; @@ -1325,8 +1348,9 @@ cogl_texture_new_with_size (guint width, else tex->max_waste = COGL_TEXTURE_MAX_WASTE; - tex->min_filter = CGL_NEAREST; - tex->mag_filter = CGL_NEAREST; + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; /* Find closest GL format match */ tex->bitmap.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; @@ -1389,8 +1414,9 @@ cogl_texture_new_from_data (guint width, else tex->max_waste = COGL_TEXTURE_MAX_WASTE; - tex->min_filter = CGL_NEAREST; - tex->mag_filter = CGL_NEAREST; + /* 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 @@ -1432,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; @@ -1447,8 +1474,9 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle, else tex->max_waste = COGL_TEXTURE_MAX_WASTE; - tex->min_filter = CGL_NEAREST; - tex->mag_filter = CGL_NEAREST; + /* 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 @@ -1524,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; @@ -1572,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) ); @@ -1610,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; @@ -1623,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 */ @@ -1770,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; @@ -1810,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) { @@ -1830,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, From 810e936164028043682b014a8e9b531fb373f317 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 4 Jun 2009 22:15:41 +0100 Subject: [PATCH 135/138] [clutter-stage-egl] Pass -1,-1 to clutter_stage_x11_fix_window_size This reflects the changes made to e4ff24bc for the egl stage. --- clutter/eglx/clutter-stage-egl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clutter/eglx/clutter-stage-egl.c b/clutter/eglx/clutter-stage-egl.c index 97a8631ca..f272e1c9f 100644 --- a/clutter/eglx/clutter-stage-egl.c +++ b/clutter/eglx/clutter-stage-egl.c @@ -205,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) From fa3ed19db56db26cadd37ea73539f1bd59254ef4 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 4 Jun 2009 22:20:18 +0100 Subject: [PATCH 136/138] [cogl-primitives] Fix an unused variable warning when building GLES The 'tex' variable is only used if #ifdef'd GL code so it was throwing an error under GLES. The variable is now moved into a block inside the #ifdef. --- clutter/cogl/common/cogl-primitives.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/clutter/cogl/common/cogl-primitives.c b/clutter/cogl/common/cogl-primitives.c index 03fe43180..598015521 100644 --- a/clutter/cogl/common/cogl-primitives.c +++ b/clutter/cogl/common/cogl-primitives.c @@ -1158,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)) { @@ -1201,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; } From 745ca8a62ca52eedfad850e556f160f36eb32953 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 5 Jun 2009 12:06:09 +0100 Subject: [PATCH 137/138] [xinput] Invert the XI extension version check Since having XQueryInputVersion means also having XGetExtensionVersion we need to check the former first to avoid the deprecation warning. --- clutter/x11/clutter-backend-x11.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clutter/x11/clutter-backend-x11.c b/clutter/x11/clutter-backend-x11.c index ab3760f0d..55e2d06fd 100644 --- a/clutter/x11/clutter-backend-x11.c +++ b/clutter/x11/clutter-backend-x11.c @@ -677,10 +677,10 @@ _clutter_x11_register_xinput () backend_singleton->have_xinput = TRUE; -#ifdef HAVE_XGET_EXTENSION_VERSION - ext = XGetExtensionVersion (backend_singleton->xdpy, INAME); -#elif HAVE_XQUERY_INPUT_VERSION +#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"); From cbb748f7c042e250b9383c59236645966c5ad47e Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 5 Jun 2009 12:26:29 +0100 Subject: [PATCH 138/138] [x11] Disable XInput by default The XInput support in Clutter is still using XI 1.x. This will never work correctly, and we are all waiting for XInput 2 anyway. The changes internally should be minimal, so we can leave everything in place, but it's better to disable XInput support by default -- at least for the time being. --- clutter/x11/clutter-backend-x11.c | 20 ++++++++++++-------- clutter/x11/clutter-event-x11.c | 6 ++---- configure.ac | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/clutter/x11/clutter-backend-x11.c b/clutter/x11/clutter-backend-x11.c index 55e2d06fd..6580c5dc7 100644 --- a/clutter/x11/clutter-backend-x11.c +++ b/clutter/x11/clutter-backend-x11.c @@ -638,11 +638,10 @@ clutter_x11_remove_filter (ClutterX11FilterFunc func, } } -#ifdef HAVE_XINPUT - void _clutter_x11_register_xinput () { +#ifdef HAVE_XINPUT XDeviceInfo *xdevices = NULL; XDeviceInfo *info = NULL; @@ -823,6 +822,7 @@ _clutter_x11_register_xinput () g_slist_free (context->input_devices); context->input_devices = NULL; } +#endif /* HAVE_XINPUT */ } void @@ -834,6 +834,7 @@ _clutter_x11_unregister_xinput () void _clutter_x11_select_events (Window xwin) { +#ifdef HAVE_XINPUT GSList *list_it; ClutterX11XInputDevice *device = NULL; @@ -858,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; @@ -885,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 HAVE_XINPUT if (!backend_singleton) { g_critical ("X11 backend has not been initialised"); @@ -955,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; diff --git a/clutter/x11/clutter-event-x11.c b/clutter/x11/clutter-event-x11.c index ec3ad72db..e2c478aed 100644 --- a/clutter/x11/clutter-event-x11.c +++ b/clutter/x11/clutter-event-x11.c @@ -798,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; @@ -862,7 +861,7 @@ event_translate (ClutterBackend *backend, } #endif else -#endif +#endif /* HAVE_XINPUT */ { CLUTTER_NOTE (EVENT, "Uknown Event"); res = FALSE; @@ -870,7 +869,6 @@ event_translate (ClutterBackend *backend, } } - out: return res; } diff --git a/configure.ac b/configure.ac index f321f97d4..a70833ad2 100644 --- a/configure.ac +++ b/configure.ac @@ -485,7 +485,7 @@ AS_IF([test "x$clutterbackend" = "xglx" || test "x$clutterbackend" = "xeglx"], [PKG_CHECK_MODULES(XINPUT, [xi], [xinput=yes], [xinput=no])] ) ], - [xinput=yes]) + [xinput=no]) AS_CASE([$xinput],