/** * clutter_paint_volume_get_depth: * @pv: a #ClutterPaintVolume * * Retrieves the depth of the volume's, axis aligned, bounding box. * * In other words; this takes into account what actor's coordinate * space @pv belongs too and conceptually fits an axis aligned box * around the volume. It returns the size of that bounding box as * measured along the z-axis. * * If, for example, clutter_actor_get_transformed_paint_volume() * is used to transform a 2D child actor that is 100px wide, 100px * high and 0px deep into container coordinates then the depth might * not simply be 0px if the child actor has a 3D rotation applied to * it. * * Remember: if clutter_actor_get_transformed_paint_volume() is * used then the transformed volume will be defined relative to the * container actor and in container coordinates a 2D child actor * can have a 3D bounding volume. * * There are no accuracy guarantees for the reported depth, * except that it must always be greater than, or equal to, the actor's * depth. This is because actors may report simple, loose fitting paint * volumes for efficiency. * * Return value: the depth, in units of @pv's local coordinate system. * * Since: 1.6 */ gfloat clutter_paint_volume_get_depth (const ClutterPaintVolume *pv) { g_return_val_if_fail (pv != NULL, 0.0); if (pv->is_empty) return 0; else if (!pv->is_axis_aligned) { ClutterPaintVolume tmp; float depth; _clutter_paint_volume_copy_static (pv, &tmp); _clutter_paint_volume_axis_align (&tmp); depth = tmp.vertices[4].z - tmp.vertices[0].z; clutter_paint_volume_free (&tmp); return depth; } else return pv->vertices[4].z - pv->vertices[0].z; }
/** * clutter_paint_volume_get_height: * @pv: a #ClutterPaintVolume * * Retrieves the height of the volume's, axis aligned, bounding box. * * In other words; this takes into account what actor's coordinate * space @pv belongs too and conceptually fits an axis aligned box * around the volume. It returns the size of that bounding box as * measured along the y-axis. * * If, for example, clutter_actor_get_transformed_paint_volume() * is used to transform a 2D child actor that is 100px wide, 100px * high and 0px deep into container coordinates then the height might * not simply be 100px if the child actor has a 3D rotation applied to * it. * * Remember: if clutter_actor_get_transformed_paint_volume() is * used then a transformed child volume will be defined relative to the * ancestor container actor and so a 2D child actor * can have a 3D bounding volume. * * There are no accuracy guarantees for the reported height, * except that it must always be greater than, or equal to, the actor's * height. This is because actors may report simple, loose fitting paint * volumes for efficiency. * * Return value: the height, in units of @pv's local coordinate system. * * Since: 1.6 */ gfloat clutter_paint_volume_get_height (const ClutterPaintVolume *pv) { g_return_val_if_fail (pv != NULL, 0.0); if (pv->is_empty) return 0; else if (!pv->is_axis_aligned) { ClutterPaintVolume tmp; float height; _clutter_paint_volume_copy_static (pv, &tmp); _clutter_paint_volume_axis_align (&tmp); height = tmp.vertices[3].y - tmp.vertices[0].y; clutter_paint_volume_free (&tmp); return height; } else return pv->vertices[3].y - pv->vertices[0].y; }
void _clutter_paint_volume_get_stage_paint_box (ClutterPaintVolume *pv, ClutterStage *stage, ClutterActorBox *box) { ClutterPaintVolume projected_pv; CoglMatrix modelview; CoglMatrix projection; float viewport[4]; _clutter_paint_volume_copy_static (pv, &projected_pv); cogl_matrix_init_identity (&modelview); /* If the paint volume isn't already in eye coordinates... */ if (pv->actor) _clutter_actor_apply_relative_transformation_matrix (pv->actor, NULL, &modelview); _clutter_stage_get_projection_matrix (stage, &projection); _clutter_stage_get_viewport (stage, &viewport[0], &viewport[1], &viewport[2], &viewport[3]); _clutter_paint_volume_project (&projected_pv, &modelview, &projection, viewport); _clutter_paint_volume_get_bounding_box (&projected_pv, box); _clutter_actor_box_enlarge_for_effects (box); clutter_paint_volume_free (&projected_pv); }
/** * clutter_paint_volume_union: * @pv: The first #ClutterPaintVolume and destination for resulting * union * @another_pv: A second #ClutterPaintVolume to union with @pv * * Updates the geometry of @pv to encompass @pv and @another_pv. * * There are no guarantees about how precisely the two volumes * will be unioned. * * Since: 1.6 */ void clutter_paint_volume_union (ClutterPaintVolume *pv, const ClutterPaintVolume *another_pv) { ClutterPaintVolume aligned_pv; g_return_if_fail (pv != NULL); g_return_if_fail (another_pv != NULL); /* Both volumes have to belong to the same local coordinate space */ g_return_if_fail (pv->actor == another_pv->actor); /* NB: we only have to update vertices 0, 1, 3 and 4 * (See the ClutterPaintVolume typedef for more details) */ /* We special case empty volumes because otherwise we'd end up * calculating a bounding box that would enclose the origin of * the empty volume which isn't desired. */ if (another_pv->is_empty) return; if (pv->is_empty) { _clutter_paint_volume_set_from_volume (pv, another_pv); goto done; } if (!pv->is_axis_aligned) _clutter_paint_volume_axis_align (pv); if (!another_pv->is_axis_aligned) { _clutter_paint_volume_copy_static (another_pv, &aligned_pv); _clutter_paint_volume_axis_align (&aligned_pv); another_pv = &aligned_pv; } /* grow left*/ /* left vertices 0, 3, 4, 7 */ if (another_pv->vertices[0].x < pv->vertices[0].x) { int min_x = another_pv->vertices[0].x; pv->vertices[0].x = min_x; pv->vertices[3].x = min_x; pv->vertices[4].x = min_x; /* pv->vertices[7].x = min_x; */ } /* grow right */ /* right vertices 1, 2, 5, 6 */ if (another_pv->vertices[1].x > pv->vertices[1].x) { int max_x = another_pv->vertices[1].x; pv->vertices[1].x = max_x; /* pv->vertices[2].x = max_x; */ /* pv->vertices[5].x = max_x; */ /* pv->vertices[6].x = max_x; */ } /* grow up */ /* top vertices 0, 1, 4, 5 */ if (another_pv->vertices[0].y < pv->vertices[0].y) { int min_y = another_pv->vertices[0].y; pv->vertices[0].y = min_y; pv->vertices[1].y = min_y; pv->vertices[4].y = min_y; /* pv->vertices[5].y = min_y; */ } /* grow down */ /* bottom vertices 2, 3, 6, 7 */ if (another_pv->vertices[3].y > pv->vertices[3].y) { int may_y = another_pv->vertices[3].y; /* pv->vertices[2].y = may_y; */ pv->vertices[3].y = may_y; /* pv->vertices[6].y = may_y; */ /* pv->vertices[7].y = may_y; */ } /* grow forward */ /* front vertices 0, 1, 2, 3 */ if (another_pv->vertices[0].z < pv->vertices[0].z) { int min_z = another_pv->vertices[0].z; pv->vertices[0].z = min_z; pv->vertices[1].z = min_z; /* pv->vertices[2].z = min_z; */ pv->vertices[3].z = min_z; } /* grow backward */ /* back vertices 4, 5, 6, 7 */ if (another_pv->vertices[4].z > pv->vertices[4].z) { int maz_z = another_pv->vertices[4].z; pv->vertices[4].z = maz_z; /* pv->vertices[5].z = maz_z; */ /* pv->vertices[6].z = maz_z; */ /* pv->vertices[7].z = maz_z; */ } if (pv->vertices[4].z == pv->vertices[0].z) pv->is_2d = TRUE; else pv->is_2d = FALSE; done: pv->is_empty = FALSE; pv->is_complete = FALSE; }
void _clutter_paint_volume_get_stage_paint_box (ClutterPaintVolume *pv, ClutterStage *stage, ClutterActorBox *box) { ClutterPaintVolume projected_pv; CoglMatrix modelview; CoglMatrix projection; float viewport[4]; float width; float height; _clutter_paint_volume_copy_static (pv, &projected_pv); cogl_matrix_init_identity (&modelview); /* If the paint volume isn't already in eye coordinates... */ if (pv->actor) _clutter_actor_apply_relative_transformation_matrix (pv->actor, NULL, &modelview); _clutter_stage_get_projection_matrix (stage, &projection); _clutter_stage_get_viewport (stage, &viewport[0], &viewport[1], &viewport[2], &viewport[3]); _clutter_paint_volume_project (&projected_pv, &modelview, &projection, viewport); _clutter_paint_volume_get_bounding_box (&projected_pv, box); /* The aim here is that for a given rectangle defined with floating point * coordinates we want to determine a stable quantized size in pixels * that doesn't vary due to the original box's sub-pixel position. * * The reason this is important is because effects will use this * API to determine the size of offscreen framebuffers and so for * a fixed-size object that may be animated accross the screen we * want to make sure that the stage paint-box has an equally stable * size so that effects aren't made to continuously re-allocate * a corresponding fbo. * * The other thing we consider is that the calculation of this box is * subject to floating point precision issues that might be slightly * different to the precision issues involved with actually painting the * actor, which might result in painting slightly leaking outside the * user's calculated paint-volume. For this we simply aim to pad out the * paint-volume by at least half a pixel all the way around. */ width = box->x2 - box->x1; height = box->y2 - box->y1; width = CLUTTER_NEARBYINT (width); height = CLUTTER_NEARBYINT (height); /* XXX: NB the width/height may now be up to 0.5px too small so we * must also pad by 0.25px all around to account for this. In total we * must padd by at least 0.75px around all sides. */ /* XXX: The furthest that we can overshoot the bottom right corner by * here is 1.75px in total if you consider that the 0.75 padding could * just cross an integer boundary and so ceil will effectively add 1. */ box->x2 = ceilf (box->x2 + 0.75); box->y2 = ceilf (box->y2 + 0.75); /* Now we redefine the top-left relative to the bottom right based on the * rounded width/height determined above + a constant so that the overall * size of the box will be stable and not dependant on the box's * position. * * Adding 3px to the width/height will ensure we cover the maximum of * 1.75px padding on the bottom/right and still ensure we have > 0.75px * padding on the top/left. */ box->x1 = box->x2 - width - 3; box->y1 = box->y2 - height - 3; clutter_paint_volume_free (&projected_pv); }