static void clutter_deform_effect_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterDeformEffect *self = CLUTTER_DEFORM_EFFECT (gobject); switch (prop_id) { case PROP_X_TILES: clutter_deform_effect_set_n_tiles (self, g_value_get_uint (value), self->priv->y_tiles); break; case PROP_Y_TILES: clutter_deform_effect_set_n_tiles (self, self->priv->x_tiles, g_value_get_uint (value)); break; case PROP_BACK_MATERIAL: clutter_deform_effect_set_back_material (self, g_value_get_boxed (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } }
static void clutter_deform_effect_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterDeformEffectPrivate *priv = CLUTTER_DEFORM_EFFECT (gobject)->priv; switch (prop_id) { case PROP_X_TILES: g_value_set_uint (value, priv->x_tiles); break; case PROP_Y_TILES: g_value_set_uint (value, priv->y_tiles); break; case PROP_BACK_MATERIAL: g_value_set_boxed (value, priv->back_pipeline); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } }
static void clutter_deform_effect_set_actor (ClutterActorMeta *meta, ClutterActor *actor) { ClutterDeformEffectPrivate *priv = CLUTTER_DEFORM_EFFECT (meta)->priv; if (priv->allocation_id != 0) { ClutterActor *old_actor = clutter_actor_meta_get_actor (meta); if (old_actor != NULL) g_signal_handler_disconnect (old_actor, priv->allocation_id); priv->allocation_id = 0; } /* we need to invalidate the VBO whenever the allocation of the actor * changes */ if (actor != NULL) priv->allocation_id = g_signal_connect (actor, "allocation-changed", G_CALLBACK (vbo_invalidate), meta); priv->is_dirty = TRUE; CLUTTER_ACTOR_META_CLASS (clutter_deform_effect_parent_class)->set_actor (meta, actor); }
static void clutter_deform_effect_finalize (GObject *gobject) { ClutterDeformEffect *self = CLUTTER_DEFORM_EFFECT (gobject); clutter_deform_effect_free_arrays (self); clutter_deform_effect_free_back_pipeline (self); G_OBJECT_CLASS (clutter_deform_effect_parent_class)->finalize (gobject); }
/** * clutter_page_turn_effect_set_radius: * @effect: a #ClutterPageTurnEffect: * @radius: the radius of the page curling, in pixels * * Sets the radius of the page curling * * Since: 1.4 */ void clutter_page_turn_effect_set_radius (ClutterPageTurnEffect *effect, gfloat radius) { g_return_if_fail (CLUTTER_IS_PAGE_TURN_EFFECT (effect)); effect->radius = radius; clutter_deform_effect_invalidate (CLUTTER_DEFORM_EFFECT (effect)); g_object_notify_by_pspec (G_OBJECT (effect), obj_props[PROP_RADIUS]); }
/** * clutter_page_turn_effect_set_angle: * @effect: #ClutterPageTurnEffect * @angle: the angle of the page curl, in degrees * * Sets the angle of the page curling, in degrees * * Since: 1.4 */ void clutter_page_turn_effect_set_angle (ClutterPageTurnEffect *effect, gdouble angle) { g_return_if_fail (CLUTTER_IS_PAGE_TURN_EFFECT (effect)); g_return_if_fail (angle >= 0.0 && angle <= 360.0); effect->angle = angle; clutter_deform_effect_invalidate (CLUTTER_DEFORM_EFFECT (effect)); g_object_notify_by_pspec (G_OBJECT (effect), obj_props[PROP_ANGLE]); }
/** * clutter_page_turn_effect_set_period: * @effect: a #ClutterPageTurnEffect * @period: the period of the page curl, between 0.0 and 1.0 * * Sets the period of the page curling, between 0.0 (no curling) * and 1.0 (fully curled) * * Since: 1.4 */ void clutter_page_turn_effect_set_period (ClutterPageTurnEffect *effect, gdouble period) { g_return_if_fail (CLUTTER_IS_PAGE_TURN_EFFECT (effect)); g_return_if_fail (period >= 0.0 && period <= 1.0); effect->period = period; clutter_deform_effect_invalidate (CLUTTER_DEFORM_EFFECT (effect)); g_object_notify_by_pspec (G_OBJECT (effect), obj_props[PROP_PERIOD]); }
static void clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect) { ClutterDeformEffect *self= CLUTTER_DEFORM_EFFECT (effect); ClutterDeformEffectPrivate *priv = self->priv; CoglHandle material; CoglPipeline *pipeline; CoglDepthState depth_state; CoglFramebuffer *fb = cogl_get_draw_framebuffer (); if (priv->is_dirty) { ClutterRect rect; gboolean mapped_buffer; CoglVertexP3T2C4 *verts; ClutterActor *actor; gfloat width, height; guint opacity; gint i, j; actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect)); opacity = clutter_actor_get_paint_opacity (actor); /* if we don't have a target size, fall back to the actor's * allocation, though wrong it might be */ if (clutter_offscreen_effect_get_target_rect (effect, &rect)) { width = clutter_rect_get_width (&rect); height = clutter_rect_get_height (&rect); } else clutter_actor_get_size (actor, &width, &height); /* XXX ideally, the sub-classes should tell us what they * changed in the texture vertices; we then would be able to * avoid resubmitting the same data, if it did not change. for * the time being, we resubmit everything */ verts = cogl_buffer_map (COGL_BUFFER (priv->buffer), COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_MAP_HINT_DISCARD); /* If the map failed then we'll resort to allocating a temporary buffer */ if (verts == NULL) { mapped_buffer = FALSE; verts = g_malloc (sizeof (*verts) * priv->n_vertices); } else mapped_buffer = TRUE; for (i = 0; i < priv->y_tiles + 1; i++) { for (j = 0; j < priv->x_tiles + 1; j++) { CoglVertexP3T2C4 *vertex_out; CoglTextureVertex vertex; /* CoglTextureVertex isn't an ideal structure to use for this because it contains a CoglColor. The internal layout of CoglColor is mean to be private so Clutter can not pass a pointer to it as a vertex attribute. Also it contains padding so we end up storing more data in the vertex buffer than we need to. Instead we let the application modify a dummy vertex and then copy the details back out to a more well-defined struct */ vertex.tx = (float) j / priv->x_tiles; vertex.ty = (float) i / priv->y_tiles; vertex.x = width * vertex.tx; vertex.y = height * vertex.ty; vertex.z = 0.0f; cogl_color_init_from_4ub (&vertex.color, 255, 255, 255, opacity); clutter_deform_effect_deform_vertex (self, width, height, &vertex); vertex_out = verts + i * (priv->x_tiles + 1) + j; vertex_out->x = vertex.x; vertex_out->y = vertex.y; vertex_out->z = vertex.z; vertex_out->s = vertex.tx; vertex_out->t = vertex.ty; vertex_out->r = cogl_color_get_red_byte (&vertex.color); vertex_out->g = cogl_color_get_green_byte (&vertex.color); vertex_out->b = cogl_color_get_blue_byte (&vertex.color); vertex_out->a = cogl_color_get_alpha_byte (&vertex.color); } } if (mapped_buffer) cogl_buffer_unmap (COGL_BUFFER (priv->buffer)); else { cogl_buffer_set_data (COGL_BUFFER (priv->buffer), 0, /* offset */ verts, sizeof (*verts) * priv->n_vertices); g_free (verts); } priv->is_dirty = FALSE; } material = clutter_offscreen_effect_get_target (effect); pipeline = COGL_PIPELINE (material); /* enable depth testing */ cogl_depth_state_init (&depth_state); cogl_depth_state_set_test_enabled (&depth_state, TRUE); cogl_pipeline_set_depth_state (pipeline, &depth_state, NULL); /* enable backface culling if we have a back material */ if (priv->back_pipeline != NULL) cogl_pipeline_set_cull_face_mode (pipeline, COGL_PIPELINE_CULL_FACE_MODE_BACK); /* draw the front */ if (material != NULL) cogl_framebuffer_draw_primitive (fb, pipeline, priv->primitive); /* draw the back */ if (priv->back_pipeline != NULL) { CoglPipeline *back_pipeline; /* We probably shouldn't be modifying the user's material so instead we make a temporary copy */ back_pipeline = cogl_pipeline_copy (priv->back_pipeline); cogl_pipeline_set_depth_state (back_pipeline, &depth_state, NULL); cogl_pipeline_set_cull_face_mode (back_pipeline, COGL_PIPELINE_CULL_FACE_MODE_FRONT); cogl_framebuffer_draw_primitive (fb, back_pipeline, priv->primitive); cogl_object_unref (back_pipeline); } if (G_UNLIKELY (priv->lines_primitive != NULL)) { CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); CoglPipeline *lines_pipeline = cogl_pipeline_new (ctx); cogl_pipeline_set_color4f (lines_pipeline, 1.0, 0, 0, 1.0); cogl_framebuffer_draw_primitive (fb, lines_pipeline, priv->lines_primitive); cogl_object_unref (lines_pipeline); } }
static void clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect) { ClutterDeformEffect *self= CLUTTER_DEFORM_EFFECT (effect); ClutterDeformEffectPrivate *priv = self->priv; gboolean is_depth_enabled, is_cull_enabled; CoglHandle material; gint n_tiles; if (priv->is_dirty) { ClutterActor *actor; gfloat width, height; guint opacity; gint i, j; actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect)); opacity = clutter_actor_get_paint_opacity (actor); /* if we don't have a target size, fall back to the actor's * allocation, though wrong it might be */ if (!clutter_offscreen_effect_get_target_size (effect, &width, &height)) clutter_actor_get_size (actor, &width, &height); for (i = 0; i < priv->y_tiles + 1; i++) { for (j = 0; j < priv->x_tiles + 1; j++) { CoglTextureVertex *vertex; vertex = &priv->vertices[(i * (priv->x_tiles + 1)) + j]; vertex->tx = (float) j / priv->x_tiles; vertex->ty = (float) i / priv->y_tiles; vertex->x = width * vertex->tx; vertex->y = height * vertex->ty; vertex->z = 0.0f; cogl_color_init_from_4ub (&vertex->color, 255, 255, 255, opacity); _clutter_deform_effect_deform_vertex (self, width, height, vertex); } } /* XXX in theory, the sub-classes should tell us what they changed * in the texture vertices; we then would be able to avoid resubmitting * the same data, if it did not change. for the time being, we resubmit * everything */ cogl_vertex_buffer_add (priv->vbo, "gl_Vertex", 3, COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, sizeof (CoglTextureVertex), &priv->vertices->x); cogl_vertex_buffer_add (priv->vbo, "gl_MultiTexCoord0", 2, COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, sizeof (CoglTextureVertex), &priv->vertices->tx); cogl_vertex_buffer_add (priv->vbo, "gl_Color", 4, COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE, FALSE, sizeof (CoglTextureVertex), &priv->vertices->color); priv->is_dirty = FALSE; } /* enable depth test, if it's not already enabled */ is_depth_enabled = cogl_get_depth_test_enabled (); if (!is_depth_enabled) cogl_set_depth_test_enabled (TRUE); /* enable backface culling if it's not already enabled and if * we have a back material */ is_cull_enabled = cogl_get_backface_culling_enabled (); if (priv->back_material != COGL_INVALID_HANDLE && !is_cull_enabled) cogl_set_backface_culling_enabled (TRUE); else if (priv->back_material == COGL_INVALID_HANDLE && is_cull_enabled) cogl_set_backface_culling_enabled (FALSE); n_tiles = (priv->x_tiles + 1) * (priv->y_tiles + 1); /* draw the front */ material = clutter_offscreen_effect_get_target (effect); if (material != COGL_INVALID_HANDLE) { cogl_set_source (material); cogl_vertex_buffer_draw_elements (priv->vbo, COGL_VERTICES_MODE_TRIANGLE_STRIP, priv->indices, 0, n_tiles, 0, priv->n_indices); } /* draw the back */ material = priv->back_material; if (material != COGL_INVALID_HANDLE) { cogl_set_source (priv->back_material); cogl_vertex_buffer_draw_elements (priv->vbo, COGL_VERTICES_MODE_TRIANGLE_STRIP, priv->back_indices, 0, n_tiles, 0, priv->n_indices); } /* restore the previous state */ if (!is_depth_enabled) cogl_set_depth_test_enabled (FALSE); if (priv->back_material != COGL_INVALID_HANDLE && !is_cull_enabled) cogl_set_backface_culling_enabled (FALSE); else if (priv->back_material == COGL_INVALID_HANDLE && is_cull_enabled) cogl_set_backface_culling_enabled (TRUE); }