mirror of
https://github.com/brl/mutter.git
synced 2024-11-29 19:40:43 -05:00
Try to clean up how we handle actor transformations
When building actor relative transforms, instead of using the matrix stack to combine transformations and making assumptions about what is currently on the stack we now just explicitly initialize an identity matrix and apply transforms to that. This removes the full_vertex_t typedef for internal transformation code and we just use ClutterVertex. ClutterStage now implements apply_transform like any other actor now and the code we had in _cogl_setup_viewport has been moved to the stage's apply_transform instead. ClutterStage now tracks an explicit projection matrix and viewport geometry. The projection matrix is derived from the perspective whenever that changes, and the viewport is updated when the stage gets a new allocation. The SYNC_MATRICES mechanism has been removed in favour of _clutter_stage_dirty_viewport/projection() APIs that get used when switching between multiple stages to ensure cogl has the latest information about the onscreen framebuffer.
This commit is contained in:
parent
ab008948cf
commit
f5f066df9c
@ -588,8 +588,6 @@ static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
|
|||||||
static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
|
static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
|
||||||
static void atk_implementor_iface_init (AtkImplementorIface *iface);
|
static void atk_implementor_iface_init (AtkImplementorIface *iface);
|
||||||
|
|
||||||
static void _clutter_actor_apply_modelview_transform (ClutterActor *self);
|
|
||||||
|
|
||||||
static void clutter_actor_shader_pre_paint (ClutterActor *actor,
|
static void clutter_actor_shader_pre_paint (ClutterActor *actor,
|
||||||
gboolean repeat);
|
gboolean repeat);
|
||||||
static void clutter_actor_shader_post_paint (ClutterActor *actor);
|
static void clutter_actor_shader_post_paint (ClutterActor *actor);
|
||||||
@ -637,6 +635,10 @@ static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
|
|||||||
|
|
||||||
static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
|
static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
|
||||||
|
|
||||||
|
static void _clutter_actor_get_relative_modelview (ClutterActor *self,
|
||||||
|
ClutterActor *ancestor,
|
||||||
|
CoglMatrix *matrix);
|
||||||
|
|
||||||
/* Helper macro which translates by the anchor coord, applies the
|
/* Helper macro which translates by the anchor coord, applies the
|
||||||
given transformation and then translates back */
|
given transformation and then translates back */
|
||||||
#define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
|
#define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
|
||||||
@ -1863,174 +1865,6 @@ clutter_actor_real_queue_relayout (ClutterActor *self)
|
|||||||
clutter_actor_queue_relayout (priv->parent_actor);
|
clutter_actor_queue_relayout (priv->parent_actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* like ClutterVertex, but with a w component */
|
|
||||||
typedef struct {
|
|
||||||
gfloat x;
|
|
||||||
gfloat y;
|
|
||||||
gfloat z;
|
|
||||||
gfloat w;
|
|
||||||
} full_vertex_t;
|
|
||||||
|
|
||||||
/* copies a fixed vertex into a ClutterVertex */
|
|
||||||
static inline void
|
|
||||||
full_vertex_to_units (const full_vertex_t *f,
|
|
||||||
ClutterVertex *u)
|
|
||||||
{
|
|
||||||
u->x = f->x;
|
|
||||||
u->y = f->y;
|
|
||||||
u->z = f->z;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* transforms a 4-tuple of coordinates using @matrix and
|
|
||||||
* places the result into a @vertex
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
full_vertex_transform (const CoglMatrix *matrix,
|
|
||||||
gfloat x,
|
|
||||||
gfloat y,
|
|
||||||
gfloat z,
|
|
||||||
gfloat w,
|
|
||||||
full_vertex_t *vertex)
|
|
||||||
{
|
|
||||||
cogl_matrix_transform_point (matrix, &x, &y, &z, &w);
|
|
||||||
|
|
||||||
vertex->x = x;
|
|
||||||
vertex->y = y;
|
|
||||||
vertex->z = z;
|
|
||||||
vertex->w = w;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Help macros to scale from OpenGL <-1,1> coordinates system to our
|
|
||||||
* X-window based <0,window-size> coordinates
|
|
||||||
*/
|
|
||||||
#define MTX_GL_SCALE_X(x,w,v1,v2) ((((((x) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2))
|
|
||||||
#define MTX_GL_SCALE_Y(y,w,v1,v2) ((v1) - (((((y) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2))
|
|
||||||
#define MTX_GL_SCALE_Z(z,w,v1,v2) (MTX_GL_SCALE_X ((z), (w), (v1), (v2)))
|
|
||||||
|
|
||||||
/* scales a fixed @vertex using @matrix and @viewport, and
|
|
||||||
* transforms the result into a ClutterVertex, filling @vertex_p
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
full_vertex_scale (const CoglMatrix *matrix,
|
|
||||||
const full_vertex_t *vertex,
|
|
||||||
const gfloat viewport[],
|
|
||||||
ClutterVertex *vertex_p)
|
|
||||||
{
|
|
||||||
gfloat v_x, v_y, v_width, v_height;
|
|
||||||
full_vertex_t tmp;
|
|
||||||
|
|
||||||
tmp = *vertex;
|
|
||||||
|
|
||||||
cogl_matrix_transform_point (matrix, &tmp.x, &tmp.y, &tmp.z, &tmp.w);
|
|
||||||
|
|
||||||
v_x = viewport[0];
|
|
||||||
v_y = viewport[1];
|
|
||||||
v_width = viewport[2];
|
|
||||||
v_height = viewport[3];
|
|
||||||
|
|
||||||
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.w = 0;
|
|
||||||
|
|
||||||
full_vertex_to_units (&tmp, vertex_p);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Applies the transforms associated with this actor and its ancestors,
|
|
||||||
* retrieves the resulting OpenGL modelview matrix, and uses the matrix
|
|
||||||
* to transform the supplied point
|
|
||||||
*
|
|
||||||
* The point coordinates are in-out parameters
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
clutter_actor_transform_point_relative (ClutterActor *actor,
|
|
||||||
ClutterActor *ancestor,
|
|
||||||
gfloat *x,
|
|
||||||
gfloat *y,
|
|
||||||
gfloat *z,
|
|
||||||
gfloat *w)
|
|
||||||
{
|
|
||||||
full_vertex_t vertex;
|
|
||||||
CoglMatrix matrix;
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
_clutter_actor_apply_modelview_transform_recursive (actor, ancestor);
|
|
||||||
|
|
||||||
cogl_get_modelview_matrix (&matrix);
|
|
||||||
cogl_matrix_transform_point (&matrix,
|
|
||||||
&vertex.x,
|
|
||||||
&vertex.y,
|
|
||||||
&vertex.z,
|
|
||||||
&vertex.w);
|
|
||||||
|
|
||||||
|
|
||||||
cogl_pop_matrix();
|
|
||||||
|
|
||||||
if (x)
|
|
||||||
*x = vertex.x;
|
|
||||||
|
|
||||||
if (y)
|
|
||||||
*y = vertex.y;
|
|
||||||
|
|
||||||
if (z)
|
|
||||||
*z = vertex.z;
|
|
||||||
|
|
||||||
if (w)
|
|
||||||
*w = vertex.w;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Applies the transforms associated with this actor and its ancestors,
|
|
||||||
* retrieves the resulting OpenGL modelview matrix, and uses the matrix
|
|
||||||
* to transform the supplied point
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
clutter_actor_transform_point (ClutterActor *actor,
|
|
||||||
gfloat *x,
|
|
||||||
gfloat *y,
|
|
||||||
gfloat *z,
|
|
||||||
gfloat *w)
|
|
||||||
{
|
|
||||||
full_vertex_t vertex;
|
|
||||||
CoglMatrix matrix;
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
_clutter_actor_apply_modelview_transform_recursive (actor, NULL);
|
|
||||||
|
|
||||||
cogl_get_modelview_matrix (&matrix);
|
|
||||||
cogl_matrix_transform_point (&matrix,
|
|
||||||
&vertex.x,
|
|
||||||
&vertex.y,
|
|
||||||
&vertex.z,
|
|
||||||
&vertex.w);
|
|
||||||
|
|
||||||
|
|
||||||
cogl_pop_matrix();
|
|
||||||
|
|
||||||
if (x)
|
|
||||||
*x = vertex.x;
|
|
||||||
|
|
||||||
if (y)
|
|
||||||
*y = vertex.y;
|
|
||||||
|
|
||||||
if (z)
|
|
||||||
*z = vertex.z;
|
|
||||||
|
|
||||||
if (w)
|
|
||||||
*w = vertex.w;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clutter_actor_apply_relative_transform_to_point:
|
* clutter_actor_apply_relative_transform_to_point:
|
||||||
* @self: A #ClutterActor
|
* @self: A #ClutterActor
|
||||||
@ -2056,34 +1890,119 @@ clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
|
|||||||
const ClutterVertex *point,
|
const ClutterVertex *point,
|
||||||
ClutterVertex *vertex)
|
ClutterVertex *vertex)
|
||||||
{
|
{
|
||||||
gfloat x, y, z, w;
|
gfloat w;
|
||||||
full_vertex_t tmp;
|
CoglMatrix matrix;
|
||||||
gfloat v[4];
|
|
||||||
|
|
||||||
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
||||||
g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
|
g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
|
||||||
g_return_if_fail (point != NULL);
|
g_return_if_fail (point != NULL);
|
||||||
g_return_if_fail (vertex != NULL);
|
g_return_if_fail (vertex != NULL);
|
||||||
|
|
||||||
x = point->x;
|
*vertex = *point;
|
||||||
y = point->y;
|
|
||||||
z = point->z;
|
|
||||||
w = 1.0;
|
w = 1.0;
|
||||||
|
|
||||||
/* First we tranform the point using the OpenGL modelview matrix */
|
if (ancestor == NULL)
|
||||||
clutter_actor_transform_point_relative (self, ancestor, &x, &y, &z, &w);
|
ancestor = _clutter_actor_get_stage_internal (self);
|
||||||
|
|
||||||
cogl_get_viewport (v);
|
if (ancestor == NULL)
|
||||||
|
{
|
||||||
|
*vertex = *point;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* The w[3] parameter should always be 1.0 here, so we ignore it; otherwise
|
_clutter_actor_get_relative_modelview (self, ancestor, &matrix);
|
||||||
* we would have to divide the original verts with it.
|
cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Help macros to scale from OpenGL <-1,1> coordinates system to
|
||||||
|
* window coordinates ranging [0,window-size]
|
||||||
*/
|
*/
|
||||||
tmp.x = (x + 0.5) * v[2];
|
#define MTX_GL_SCALE_X(x,w,v1,v2) ((((((x) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2))
|
||||||
tmp.y = (0.5 - y) * v[3];
|
#define MTX_GL_SCALE_Y(y,w,v1,v2) ((v1) - (((((y) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2))
|
||||||
tmp.z = (z + 0.5) * v[2];
|
#define MTX_GL_SCALE_Z(z,w,v1,v2) (MTX_GL_SCALE_X ((z), (w), (v1), (v2)))
|
||||||
tmp.w = 0;
|
|
||||||
|
|
||||||
full_vertex_to_units (&tmp, vertex);
|
static void
|
||||||
|
_fully_transform_vertices (const CoglMatrix *modelview,
|
||||||
|
const CoglMatrix *projection,
|
||||||
|
const int *viewport,
|
||||||
|
const ClutterVertex *vertices_in,
|
||||||
|
ClutterVertex *vertices_out,
|
||||||
|
int n_vertices)
|
||||||
|
{
|
||||||
|
CoglMatrix modelview_projection;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* XXX: we should find a way to cache this per actor */
|
||||||
|
cogl_matrix_multiply (&modelview_projection,
|
||||||
|
projection,
|
||||||
|
modelview);
|
||||||
|
|
||||||
|
for (i = 0; i < n_vertices; i++)
|
||||||
|
{
|
||||||
|
const ClutterVertex *vertex_in = &vertices_in[i];
|
||||||
|
ClutterVertex *vertex_out = &vertices_out[i];
|
||||||
|
gfloat x, y, z, w;
|
||||||
|
|
||||||
|
x = vertex_in->x;
|
||||||
|
y = vertex_in->y;
|
||||||
|
z = vertex_in->z;
|
||||||
|
w = 1.0;
|
||||||
|
|
||||||
|
/* Transform the point using the modelview matrix */
|
||||||
|
cogl_matrix_transform_point (&modelview_projection, &x, &y, &z, &w);
|
||||||
|
|
||||||
|
/* Finally translate from OpenGL coords to window coords */
|
||||||
|
vertex_out->x = MTX_GL_SCALE_X (x, w, viewport[2], viewport[0]);
|
||||||
|
vertex_out->y = MTX_GL_SCALE_Y (y, w, viewport[3], viewport[1]);
|
||||||
|
vertex_out->z = MTX_GL_SCALE_Z (z, w, viewport[2], viewport[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_clutter_actor_fully_transform_vertices (ClutterActor *self,
|
||||||
|
const ClutterVertex *vertices_in,
|
||||||
|
ClutterVertex *vertices_out,
|
||||||
|
int n_vertices)
|
||||||
|
{
|
||||||
|
ClutterActor *stage;
|
||||||
|
CoglMatrix modelview;
|
||||||
|
CoglMatrix projection;
|
||||||
|
int viewport[4];
|
||||||
|
|
||||||
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
|
||||||
|
|
||||||
|
/* NB: _clutter_actor_apply_modelview_transform_recursive will never
|
||||||
|
* include the transformation between stage coordinates and OpenGL
|
||||||
|
* window coordinates, we have to explicitly use the
|
||||||
|
* stage->apply_transform to get that... */
|
||||||
|
stage = _clutter_actor_get_stage_internal (self);
|
||||||
|
|
||||||
|
/* We really can't do anything meaningful in this case so don't try
|
||||||
|
* to do any transform */
|
||||||
|
if (stage == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Setup the modelview */
|
||||||
|
cogl_matrix_init_identity (&modelview);
|
||||||
|
_clutter_actor_apply_modelview_transform (stage, &modelview);
|
||||||
|
_clutter_actor_apply_modelview_transform_recursive (self, stage, &modelview);
|
||||||
|
|
||||||
|
/* Fetch the projection and viewport */
|
||||||
|
_clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
|
||||||
|
_clutter_stage_get_viewport (CLUTTER_STAGE (stage),
|
||||||
|
&viewport[0],
|
||||||
|
&viewport[1],
|
||||||
|
&viewport[2],
|
||||||
|
&viewport[3]);
|
||||||
|
|
||||||
|
_fully_transform_vertices (&modelview,
|
||||||
|
&projection,
|
||||||
|
viewport,
|
||||||
|
vertices_in,
|
||||||
|
vertices_out,
|
||||||
|
n_vertices);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2103,233 +2022,75 @@ clutter_actor_apply_transform_to_point (ClutterActor *self,
|
|||||||
const ClutterVertex *point,
|
const ClutterVertex *point,
|
||||||
ClutterVertex *vertex)
|
ClutterVertex *vertex)
|
||||||
{
|
{
|
||||||
full_vertex_t tmp = { 0, };
|
|
||||||
gfloat x, y, z, w;
|
|
||||||
CoglMatrix matrix_p;
|
|
||||||
gfloat v[4];
|
|
||||||
|
|
||||||
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
||||||
g_return_if_fail (point != NULL);
|
g_return_if_fail (point != NULL);
|
||||||
g_return_if_fail (vertex != NULL);
|
g_return_if_fail (vertex != NULL);
|
||||||
|
_clutter_actor_fully_transform_vertices (self, point, vertex, 1);
|
||||||
x = point->x;
|
|
||||||
y = point->y;
|
|
||||||
z = point->z;
|
|
||||||
w = 1.0;
|
|
||||||
|
|
||||||
/* First we tranform the point using the OpenGL modelview matrix */
|
|
||||||
clutter_actor_transform_point (self, &x, &y, &z, &w);
|
|
||||||
|
|
||||||
tmp.x = x;
|
|
||||||
tmp.y = y;
|
|
||||||
tmp.z = z;
|
|
||||||
tmp.w = w;
|
|
||||||
|
|
||||||
cogl_get_projection_matrix (&matrix_p);
|
|
||||||
cogl_get_viewport (v);
|
|
||||||
|
|
||||||
/* Now, transform it again with the projection matrix */
|
|
||||||
cogl_matrix_transform_point (&matrix_p,
|
|
||||||
&tmp.x,
|
|
||||||
&tmp.y,
|
|
||||||
&tmp.z,
|
|
||||||
&tmp.w);
|
|
||||||
|
|
||||||
|
|
||||||
/* Finaly translate from OpenGL coords to window coords */
|
|
||||||
vertex->x = MTX_GL_SCALE_X (tmp.x, tmp.w, v[2], v[0]);
|
|
||||||
vertex->y = MTX_GL_SCALE_Y (tmp.y, tmp.w, v[3], v[1]);
|
|
||||||
vertex->z = MTX_GL_SCALE_Z (tmp.z, tmp.w, v[2], v[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Recursively tranform supplied vertices with the tranform for the current
|
|
||||||
* actor and up to the ancestor (like clutter_actor_transform_point() but
|
|
||||||
* for all the vertices in one go).
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
clutter_actor_transform_vertices_relative (ClutterActor *self,
|
|
||||||
ClutterActor *ancestor,
|
|
||||||
full_vertex_t vertices[])
|
|
||||||
{
|
|
||||||
ClutterActorPrivate *priv = self->priv;
|
|
||||||
gfloat width, height;
|
|
||||||
CoglMatrix mtx;
|
|
||||||
|
|
||||||
width = priv->allocation.x2 - priv->allocation.x1;
|
|
||||||
height = priv->allocation.y2 - priv->allocation.y1;
|
|
||||||
|
|
||||||
cogl_push_matrix();
|
|
||||||
|
|
||||||
_clutter_actor_apply_modelview_transform_recursive (self, ancestor);
|
|
||||||
|
|
||||||
cogl_get_modelview_matrix (&mtx);
|
|
||||||
|
|
||||||
full_vertex_transform (&mtx, 0, 0, 0, 1.0, &vertices[0]);
|
|
||||||
full_vertex_transform (&mtx, width, 0, 0, 1.0, &vertices[1]);
|
|
||||||
full_vertex_transform (&mtx, 0, height, 0, 1.0, &vertices[2]);
|
|
||||||
full_vertex_transform (&mtx, width, height, 0, 1.0, &vertices[3]);
|
|
||||||
|
|
||||||
cogl_pop_matrix();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* _clutter_actor_ensure_stage_current
|
|
||||||
*
|
|
||||||
* Ensures that the actors corresponding stage is made current so we
|
|
||||||
* have a valid viewport, projection matrix and modelview matrix stack.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
_clutter_actor_ensure_stage_current (ClutterActor *self)
|
|
||||||
{
|
|
||||||
ClutterActor *stage;
|
|
||||||
|
|
||||||
/* 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
|
|
||||||
* haven't yet rendered anything.
|
|
||||||
*
|
|
||||||
* Simply duping code for now in wait for Cogl cleanup that can hopefully
|
|
||||||
* address this in a nicer way.
|
|
||||||
*/
|
|
||||||
stage = _clutter_actor_get_stage_internal (self);
|
|
||||||
|
|
||||||
/* FIXME: if were not yet added to a stage, its probably unsafe to
|
|
||||||
* return default - ideally the func should fail
|
|
||||||
*/
|
|
||||||
if (stage == NULL)
|
|
||||||
stage = clutter_stage_get_default ();
|
|
||||||
|
|
||||||
clutter_stage_ensure_current (CLUTTER_STAGE (stage));
|
|
||||||
_clutter_stage_maybe_setup_viewport (CLUTTER_STAGE (stage));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* _clutter_actor_get_relative_modelview:
|
/* _clutter_actor_get_relative_modelview:
|
||||||
*
|
*
|
||||||
* Retrives the modelview transformation relative to some ancestor actor, or
|
* Retrieves the modelview transformation relative to some ancestor
|
||||||
* the stage if NULL is given for the ancestor.
|
* actor, or the stage if NULL is given for the ancestor.
|
||||||
*
|
*
|
||||||
* It assumes you currently have an empty matrix stack.
|
* Note: This will never include the transformations from
|
||||||
|
* stage::apply_transform since that would give you a modelview
|
||||||
|
* transform relative to the OpenGL window coordinate space that the
|
||||||
|
* stage lies within.
|
||||||
|
*
|
||||||
|
* If you need to do a full modelview + projective transform and get
|
||||||
|
* to window coordinates then you should explicitly apply the stage
|
||||||
|
* transform to an identity matrix and use
|
||||||
|
* _clutter_actor_apply_modelview_transform like:
|
||||||
|
*
|
||||||
|
* cogl_matrix_init_identity (&mtx);
|
||||||
|
* stage = _clutter_actor_get_stage_internal (self);
|
||||||
|
* _clutter_actor_apply_modelview_transform (stage, &mtx);
|
||||||
*/
|
*/
|
||||||
/* FIXME: We should be caching the stage relative modelview along with the
|
/* FIXME: We should be caching the stage relative modelview along with the
|
||||||
* actor itself */
|
* actor itself */
|
||||||
/* TODO: Replace all other occurrences of this code pattern in clutter-actor.c:
|
static void
|
||||||
* cogl_push_matrix();
|
|
||||||
* _clutter_actor_apply_modelview_transform_recursive (self, ancestor)
|
|
||||||
* cogl_get_modelview_matrix()
|
|
||||||
* cogl_pop_matrix();
|
|
||||||
* with a call to this function:
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
_clutter_actor_get_relative_modelview (ClutterActor *self,
|
_clutter_actor_get_relative_modelview (ClutterActor *self,
|
||||||
ClutterActor *ancestor,
|
ClutterActor *ancestor,
|
||||||
CoglMatrix *matrix)
|
CoglMatrix *matrix)
|
||||||
{
|
{
|
||||||
ClutterActor *stage;
|
g_return_if_fail (ancestor != NULL);
|
||||||
gfloat width, height;
|
|
||||||
CoglMatrix tmp_matrix;
|
|
||||||
gfloat z_camera;
|
|
||||||
ClutterPerspective perspective;
|
|
||||||
|
|
||||||
_clutter_actor_ensure_stage_current (self);
|
cogl_matrix_init_identity (matrix);
|
||||||
|
|
||||||
cogl_push_matrix ();
|
_clutter_actor_apply_modelview_transform_recursive (self, ancestor, matrix);
|
||||||
|
|
||||||
if (ancestor == NULL)
|
|
||||||
{
|
|
||||||
stage = _clutter_actor_get_stage_internal (self);
|
|
||||||
|
|
||||||
clutter_stage_get_perspective (CLUTTER_STAGE (stage), &perspective);
|
|
||||||
cogl_perspective (perspective.fovy,
|
|
||||||
perspective.aspect,
|
|
||||||
perspective.z_near,
|
|
||||||
perspective.z_far);
|
|
||||||
|
|
||||||
cogl_get_projection_matrix (&tmp_matrix);
|
|
||||||
z_camera = 0.5f * tmp_matrix.xx;
|
|
||||||
|
|
||||||
clutter_actor_get_size (stage, &width, &height);
|
|
||||||
|
|
||||||
/* obliterate the current modelview matrix and reset it to be
|
|
||||||
* the same as the stage's at the beginning of a paint run; this
|
|
||||||
* is done to paint the target material in screen coordinates at
|
|
||||||
* the same place as the actor would have been
|
|
||||||
*/
|
|
||||||
cogl_matrix_init_identity (&tmp_matrix);
|
|
||||||
cogl_matrix_translate (&tmp_matrix, -0.5f, -0.5f, -z_camera);
|
|
||||||
cogl_matrix_scale (&tmp_matrix, 1.0f / width, -1.0f / height, 1.0f / width);
|
|
||||||
cogl_matrix_translate (&tmp_matrix, 0.0f, -1.0f * height, 0.0f);
|
|
||||||
cogl_set_modelview_matrix (&tmp_matrix);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
static CoglMatrix identity;
|
|
||||||
static gboolean initialized_identity = FALSE;
|
|
||||||
|
|
||||||
if (!initialized_identity)
|
|
||||||
{
|
|
||||||
cogl_matrix_init_identity (&identity);
|
|
||||||
initialized_identity = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
cogl_set_modelview_matrix (&identity);
|
|
||||||
}
|
|
||||||
|
|
||||||
_clutter_actor_apply_modelview_transform_recursive (self, ancestor);
|
|
||||||
|
|
||||||
cogl_get_modelview_matrix (matrix);
|
|
||||||
|
|
||||||
cogl_pop_matrix ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* _clutter_actor_get_projection_and_viewport
|
/* Project the given @box into stage window coordinates, writing the
|
||||||
*
|
* transformed vertices to @verts[]. */
|
||||||
* Retrieves the projection matrix and viewport for the actors corresponding
|
gboolean
|
||||||
* stage.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
_clutter_actor_get_projection_and_viewport (ClutterActor *self,
|
|
||||||
CoglMatrix *matrix,
|
|
||||||
float *viewport)
|
|
||||||
{
|
|
||||||
_clutter_actor_ensure_stage_current (self);
|
|
||||||
|
|
||||||
cogl_get_projection_matrix (matrix);
|
|
||||||
cogl_get_viewport (viewport);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Recursively transform supplied box with the transform for the current
|
|
||||||
* actor and all its ancestors (like clutter_actor_transform_point()
|
|
||||||
* but for all the vertices in one go) and project it into screen
|
|
||||||
* coordinates
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
_clutter_actor_transform_and_project_box (ClutterActor *self,
|
_clutter_actor_transform_and_project_box (ClutterActor *self,
|
||||||
const ClutterActorBox *box,
|
const ClutterActorBox *box,
|
||||||
ClutterVertex verts[])
|
ClutterVertex verts[])
|
||||||
{
|
{
|
||||||
CoglMatrix mtx;
|
ClutterVertex box_vertices[4];
|
||||||
CoglMatrix mtx_p;
|
|
||||||
float v[4];
|
|
||||||
full_vertex_t vertices[4];
|
|
||||||
|
|
||||||
_clutter_actor_get_relative_modelview (self, NULL, &mtx);
|
box_vertices[0].x = box->x1;
|
||||||
|
box_vertices[0].y = box->y1;
|
||||||
|
box_vertices[0].z = 0;
|
||||||
|
box_vertices[1].x = box->x2;
|
||||||
|
box_vertices[1].y = box->y1;
|
||||||
|
box_vertices[1].z = 0;
|
||||||
|
box_vertices[2].x = box->x1;
|
||||||
|
box_vertices[2].y = box->y2;
|
||||||
|
box_vertices[2].z = 0;
|
||||||
|
box_vertices[3].x = box->x2;
|
||||||
|
box_vertices[3].y = box->y2;
|
||||||
|
box_vertices[3].z = 0;
|
||||||
|
|
||||||
full_vertex_transform (&mtx, box->x1, box->y1, 0, 1.0, &vertices[0]);
|
return
|
||||||
full_vertex_transform (&mtx, box->x2, box->y1, 0, 1.0, &vertices[1]);
|
_clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
|
||||||
full_vertex_transform (&mtx, box->x1, box->y2, 0, 1.0, &vertices[2]);
|
|
||||||
full_vertex_transform (&mtx, box->x2, box->y2, 0, 1.0, &vertices[3]);
|
|
||||||
|
|
||||||
_clutter_actor_get_projection_and_viewport (self, &mtx_p, v);
|
|
||||||
|
|
||||||
full_vertex_scale (&mtx_p, &vertices[0], v, &verts[0]);
|
|
||||||
full_vertex_scale (&mtx_p, &vertices[1], v, &verts[1]);
|
|
||||||
full_vertex_scale (&mtx_p, &vertices[2], v, &verts[2]);
|
|
||||||
full_vertex_scale (&mtx_p, &vertices[3], v, &verts[3]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clutter_actor_get_allocation_vertices:
|
* clutter_actor_get_allocation_vertices:
|
||||||
* @self: A #ClutterActor
|
* @self: A #ClutterActor
|
||||||
* @ancestor: (allow-none): A #ClutterActor to calculate the vertices
|
* @ancestor: (allow-none): A #ClutterActor to calculate the vertices
|
||||||
* against, or %NULL to use the default #ClutterStage
|
* against, or %NULL to use the #ClutterStage
|
||||||
* @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
|
* @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
|
||||||
* location for an array of 4 #ClutterVertex in which to store the result
|
* location for an array of 4 #ClutterVertex in which to store the result
|
||||||
*
|
*
|
||||||
@ -2356,67 +2117,70 @@ clutter_actor_get_allocation_vertices (ClutterActor *self,
|
|||||||
ClutterVertex verts[])
|
ClutterVertex verts[])
|
||||||
{
|
{
|
||||||
ClutterActorPrivate *priv;
|
ClutterActorPrivate *priv;
|
||||||
ClutterActor *stage;
|
ClutterActorBox box;
|
||||||
gfloat v[4];
|
ClutterVertex vertices[4];
|
||||||
full_vertex_t vertices[4];
|
CoglMatrix modelview;
|
||||||
full_vertex_t tmp = { 0, };
|
float w;
|
||||||
|
|
||||||
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
||||||
g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
|
g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
|
||||||
|
|
||||||
|
if (ancestor == NULL)
|
||||||
|
ancestor = _clutter_actor_get_stage_internal (self);
|
||||||
|
|
||||||
|
/* Fallback to a NOP transform if the actor isn't parented under a
|
||||||
|
* stage. */
|
||||||
|
if (ancestor == NULL)
|
||||||
|
ancestor = self;
|
||||||
|
|
||||||
priv = self->priv;
|
priv = self->priv;
|
||||||
|
|
||||||
/* 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
|
|
||||||
* havn't yet rendered anything.
|
|
||||||
*
|
|
||||||
* Simply duping code for now in wait for Cogl cleanup that can hopefully
|
|
||||||
* address this in a nicer way.
|
|
||||||
*/
|
|
||||||
stage = _clutter_actor_get_stage_internal (self);
|
|
||||||
|
|
||||||
/* FIXME: if were not yet added to a stage, its probably unsafe to
|
|
||||||
* return default - idealy the func should fail
|
|
||||||
*/
|
|
||||||
if (stage == NULL)
|
|
||||||
stage = clutter_stage_get_default ();
|
|
||||||
|
|
||||||
clutter_stage_ensure_current (CLUTTER_STAGE (stage));
|
|
||||||
_clutter_stage_maybe_setup_viewport (CLUTTER_STAGE (stage));
|
|
||||||
|
|
||||||
/* if the actor needs to be allocated we force a relayout, so that
|
/* if the actor needs to be allocated we force a relayout, so that
|
||||||
* clutter_actor_transform_vertices_relative() will have valid values
|
* we will have valid values to use in the transformations */
|
||||||
* to use in the transformations
|
|
||||||
*/
|
|
||||||
if (priv->needs_allocation)
|
if (priv->needs_allocation)
|
||||||
|
{
|
||||||
|
ClutterActor *stage = _clutter_actor_get_stage_internal (self);
|
||||||
|
if (stage)
|
||||||
_clutter_stage_maybe_relayout (stage);
|
_clutter_stage_maybe_relayout (stage);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
box.x1 = box.y1 = 0;
|
||||||
|
/* The result isn't really meaningful in this case but at
|
||||||
|
* least try to do something *vaguely* reasonable... */
|
||||||
|
clutter_actor_get_size (self, &box.x2, &box.y2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
clutter_actor_transform_vertices_relative (self, ancestor, vertices);
|
clutter_actor_get_allocation_box (self, &box);
|
||||||
|
|
||||||
cogl_get_viewport (v);
|
vertices[0].x = box.x1;
|
||||||
|
vertices[0].y = box.y1;
|
||||||
|
vertices[0].z = 0;
|
||||||
|
vertices[1].x = box.x2;
|
||||||
|
vertices[1].y = box.y1;
|
||||||
|
vertices[1].z = 0;
|
||||||
|
vertices[2].x = box.x1;
|
||||||
|
vertices[2].y = box.y2;
|
||||||
|
vertices[2].z = 0;
|
||||||
|
vertices[3].x = box.x2;
|
||||||
|
vertices[3].y = box.y2;
|
||||||
|
vertices[3].z = 0;
|
||||||
|
|
||||||
/* The w[3] parameter should always be 1.0 here, so we ignore it;
|
_clutter_actor_get_relative_modelview (self, ancestor, &modelview);
|
||||||
* otherwise we would have to divide the original verts with it.
|
|
||||||
*/
|
|
||||||
tmp.x = ((vertices[0].x + 0.5) * v[2]);
|
|
||||||
tmp.y = ((0.5 - vertices[0].y) * v[3]);
|
|
||||||
tmp.z = ((vertices[0].z + 0.5) * v[2]);
|
|
||||||
full_vertex_to_units (&tmp, &verts[0]);
|
|
||||||
|
|
||||||
tmp.x = ((vertices[1].x + 0.5) * v[2]);
|
w = 1;
|
||||||
tmp.y = ((0.5 - vertices[1].y) * v[3]);
|
cogl_matrix_transform_point (&modelview,
|
||||||
tmp.z = ((vertices[1].z + 0.5) * v[2]);
|
&vertices[0].x, &vertices[0].y, &vertices[0].z,
|
||||||
full_vertex_to_units (&tmp, &verts[1]);
|
&w);
|
||||||
|
cogl_matrix_transform_point (&modelview,
|
||||||
tmp.x = ((vertices[2].x + 0.5) * v[2]);
|
&vertices[1].x, &vertices[1].y, &vertices[1].z,
|
||||||
tmp.y = ((0.5 - vertices[2].y) * v[3]);
|
&w);
|
||||||
tmp.z = ((vertices[2].z + 0.5) * v[2]);
|
cogl_matrix_transform_point (&modelview,
|
||||||
full_vertex_to_units (&tmp, &verts[2]);
|
&vertices[2].x, &vertices[2].y, &vertices[2].z,
|
||||||
|
&w);
|
||||||
tmp.x = ((vertices[3].x + 0.5) * v[2]);
|
cogl_matrix_transform_point (&modelview,
|
||||||
tmp.y = ((0.5 - vertices[3].y) * v[3]);
|
&vertices[3].x, &vertices[3].y, &vertices[3].z,
|
||||||
tmp.z = ((vertices[3].z + 0.5) * v[2]);
|
&w);
|
||||||
full_vertex_to_units (&tmp, &verts[3]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2455,12 +2219,9 @@ clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
|
|||||||
if (priv->needs_allocation)
|
if (priv->needs_allocation)
|
||||||
{
|
{
|
||||||
ClutterActor *stage = _clutter_actor_get_stage_internal (self);
|
ClutterActor *stage = _clutter_actor_get_stage_internal (self);
|
||||||
|
/* There's nothing meaningful we can do now */
|
||||||
/* FIXME: if were not yet added to a stage, its probably unsafe to
|
if (!stage)
|
||||||
* return default - idealy the func should fail
|
return;
|
||||||
*/
|
|
||||||
if (stage == NULL)
|
|
||||||
stage = clutter_stage_get_default ();
|
|
||||||
|
|
||||||
_clutter_stage_maybe_relayout (stage);
|
_clutter_stage_maybe_relayout (stage);
|
||||||
}
|
}
|
||||||
@ -2481,15 +2242,11 @@ clutter_actor_real_apply_transform (ClutterActor *self,
|
|||||||
CoglMatrix *matrix)
|
CoglMatrix *matrix)
|
||||||
{
|
{
|
||||||
ClutterActorPrivate *priv = self->priv;
|
ClutterActorPrivate *priv = self->priv;
|
||||||
gboolean is_stage = CLUTTER_IS_STAGE (self);
|
|
||||||
|
|
||||||
if (!is_stage)
|
|
||||||
{
|
|
||||||
cogl_matrix_translate (matrix,
|
cogl_matrix_translate (matrix,
|
||||||
priv->allocation.x1,
|
priv->allocation.x1,
|
||||||
priv->allocation.y1,
|
priv->allocation.y1,
|
||||||
0.0);
|
0.0);
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->z)
|
if (priv->z)
|
||||||
cogl_matrix_translate (matrix, 0, 0, priv->z);
|
cogl_matrix_translate (matrix, 0, 0, priv->z);
|
||||||
@ -2531,7 +2288,7 @@ clutter_actor_real_apply_transform (ClutterActor *self,
|
|||||||
priv->rxang,
|
priv->rxang,
|
||||||
1.0, 0, 0));
|
1.0, 0, 0));
|
||||||
|
|
||||||
if (!is_stage && !clutter_anchor_coord_is_zero (&priv->anchor))
|
if (!clutter_anchor_coord_is_zero (&priv->anchor))
|
||||||
{
|
{
|
||||||
gfloat x, y, z;
|
gfloat x, y, z;
|
||||||
|
|
||||||
@ -2540,26 +2297,13 @@ clutter_actor_real_apply_transform (ClutterActor *self,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Applies the transforms associated with this actor to the
|
/* Applies the transforms associated with this actor to the given
|
||||||
* OpenGL modelview matrix.
|
* matrix. */
|
||||||
*
|
void
|
||||||
* This function does not push/pop matrix; it is the responsibility
|
_clutter_actor_apply_modelview_transform (ClutterActor *self,
|
||||||
* of the caller to do so as appropriate
|
CoglMatrix *matrix)
|
||||||
*/
|
|
||||||
static void
|
|
||||||
_clutter_actor_apply_modelview_transform (ClutterActor *self)
|
|
||||||
{
|
{
|
||||||
CoglMatrix matrix, cur, new;
|
CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
|
||||||
|
|
||||||
cogl_matrix_init_identity (&matrix);
|
|
||||||
|
|
||||||
clutter_actor_get_transformation_matrix (self, &matrix);
|
|
||||||
|
|
||||||
cogl_get_modelview_matrix (&cur);
|
|
||||||
|
|
||||||
cogl_matrix_multiply (&new, &cur, &matrix);
|
|
||||||
|
|
||||||
cogl_set_modelview_matrix (&new);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -2597,42 +2341,30 @@ _clutter_actor_effects_post_paint (ClutterActor *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Recursively applies the transforms associated with this actor and
|
/* Recursively applies the transforms associated with this actor and
|
||||||
* its ancestors to the OpenGL modelview matrix. Use NULL if you want this
|
* its ancestors to the given matrix. Use NULL if you want this
|
||||||
* to go all the way down to the stage.
|
* to go all the way down to the stage.
|
||||||
*
|
|
||||||
* This function does not push/pop matrix; it is the responsibility
|
|
||||||
* of the caller to do so as appropriate
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
_clutter_actor_apply_modelview_transform_recursive (ClutterActor *self,
|
_clutter_actor_apply_modelview_transform_recursive (ClutterActor *self,
|
||||||
ClutterActor *ancestor)
|
ClutterActor *ancestor,
|
||||||
|
CoglMatrix *matrix)
|
||||||
{
|
{
|
||||||
ClutterActor *parent, *stage;
|
ClutterActor *parent;
|
||||||
|
|
||||||
parent = clutter_actor_get_parent (self);
|
/* Note we terminate before ever calling stage->apply_transform()
|
||||||
|
* since that would conceptually be relative to the underlying
|
||||||
/*
|
* window OpenGL coordinates so we'd need a special @ancestor
|
||||||
* If we reached the ancestor, quit
|
* value to represent the fake parent of the stage. */
|
||||||
* NB: NULL ancestor means the stage, and this will not trigger
|
|
||||||
* (as it should not)
|
|
||||||
*/
|
|
||||||
if (self == ancestor)
|
if (self == ancestor)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
stage = _clutter_actor_get_stage_internal (self);
|
parent = clutter_actor_get_parent (self);
|
||||||
|
|
||||||
/* FIXME: if were not yet added to a stage, its probably unsafe to
|
|
||||||
* return default - idealy the func should fail
|
|
||||||
*/
|
|
||||||
if (stage == NULL)
|
|
||||||
stage = clutter_stage_get_default ();
|
|
||||||
|
|
||||||
if (parent != NULL)
|
if (parent != NULL)
|
||||||
_clutter_actor_apply_modelview_transform_recursive (parent, ancestor);
|
_clutter_actor_apply_modelview_transform_recursive (parent, ancestor,
|
||||||
else if (self != stage)
|
matrix);
|
||||||
_clutter_actor_apply_modelview_transform (stage);
|
|
||||||
|
|
||||||
_clutter_actor_apply_modelview_transform (self);
|
_clutter_actor_apply_modelview_transform (self, matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2703,7 +2435,15 @@ clutter_actor_paint (ClutterActor *self)
|
|||||||
cogl_push_matrix();
|
cogl_push_matrix();
|
||||||
|
|
||||||
if (priv->enable_model_view_transform)
|
if (priv->enable_model_view_transform)
|
||||||
_clutter_actor_apply_modelview_transform (self);
|
{
|
||||||
|
CoglMatrix matrix;
|
||||||
|
/* XXX: It could be better to cache the modelview with the actor
|
||||||
|
* instead of progressively building up the transformations on
|
||||||
|
* the matrix stack every time we paint. */
|
||||||
|
cogl_get_modelview_matrix (&matrix);
|
||||||
|
_clutter_actor_apply_modelview_transform (self, &matrix);
|
||||||
|
cogl_set_modelview_matrix (&matrix);
|
||||||
|
}
|
||||||
|
|
||||||
if (priv->has_clip)
|
if (priv->has_clip)
|
||||||
{
|
{
|
||||||
@ -5071,27 +4811,6 @@ _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SYNC_MATRICES is a flag for the stage, which means that we just
|
|
||||||
* got resized and we need to re-setup the viewport.
|
|
||||||
* IN_RESIZE is used on X11 where the resize is asynchronous, so we
|
|
||||||
* don't ask for a viewport change before we have the final size.
|
|
||||||
*
|
|
||||||
* If either of these flags are set then we won't be able to
|
|
||||||
* transform the given clip rectangle into valid stage coordinates,
|
|
||||||
* so we instead queue a full stage redraw.
|
|
||||||
*
|
|
||||||
* (Note: to some extent this is redundant because these flags
|
|
||||||
* should imply a full stage redraw will be queued, but we at least
|
|
||||||
* avoid needlessly traversing the actors ancestors to derive an
|
|
||||||
* incorrect modelview matrix.)
|
|
||||||
*/
|
|
||||||
if ((CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_SYNC_MATRICES) &&
|
|
||||||
!CLUTTER_STAGE_IN_RESIZE (self))
|
|
||||||
{
|
|
||||||
clutter_actor_queue_redraw (self);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
|
if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
|
||||||
{
|
{
|
||||||
_clutter_actor_get_allocation_clip (self, &allocation_clip);
|
_clutter_actor_get_allocation_clip (self, &allocation_clip);
|
||||||
@ -10657,7 +10376,8 @@ clutter_actor_unset_flags (ClutterActor *self,
|
|||||||
* @self: a #ClutterActor
|
* @self: a #ClutterActor
|
||||||
* @matrix: (out): the return location for a #CoglMatrix
|
* @matrix: (out): the return location for a #CoglMatrix
|
||||||
*
|
*
|
||||||
* Retrieves the transformations applied to @self
|
* Retrieves the transformations applied to @self relative to its
|
||||||
|
* parent.
|
||||||
*
|
*
|
||||||
* Since: 1.0
|
* Since: 1.0
|
||||||
*/
|
*/
|
||||||
@ -10669,7 +10389,7 @@ clutter_actor_get_transformation_matrix (ClutterActor *self,
|
|||||||
|
|
||||||
cogl_matrix_init_identity (matrix);
|
cogl_matrix_init_identity (matrix);
|
||||||
|
|
||||||
CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
|
_clutter_actor_apply_modelview_transform (self, matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -421,6 +421,17 @@ _clutter_backend_ensure_context (ClutterBackend *backend,
|
|||||||
clutter_actor_get_size (CLUTTER_ACTOR (stage), &width, &height);
|
clutter_actor_get_size (CLUTTER_ACTOR (stage), &width, &height);
|
||||||
|
|
||||||
_cogl_onscreen_clutter_backend_set_size (width, height);
|
_cogl_onscreen_clutter_backend_set_size (width, height);
|
||||||
|
|
||||||
|
/* Eventually we will have a separate CoglFramebuffer for
|
||||||
|
* each stage and each one will track private projection
|
||||||
|
* matrix and viewport state, but until then we need to make
|
||||||
|
* sure we update the projection and viewport whenever we
|
||||||
|
* switch between stages.
|
||||||
|
*
|
||||||
|
* This dirty mechanism will ensure they are asserted before
|
||||||
|
* the next paint... */
|
||||||
|
_clutter_stage_dirty_viewport (stage);
|
||||||
|
_clutter_stage_dirty_projection (stage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: With a NULL stage and thus no active context it may make more
|
/* FIXME: With a NULL stage and thus no active context it may make more
|
||||||
@ -429,17 +440,6 @@ _clutter_backend_ensure_context (ClutterBackend *backend,
|
|||||||
* potential issue of GL calls with no context)
|
* potential issue of GL calls with no context)
|
||||||
*/
|
*/
|
||||||
current_context_stage = new_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
|
|
||||||
* SYNC_MATRICES flag and letting the next redraw cycle take care
|
|
||||||
* of calling glViewport()
|
|
||||||
*/
|
|
||||||
if (current_context_stage)
|
|
||||||
{
|
|
||||||
CLUTTER_SET_PRIVATE_FLAGS (current_context_stage,
|
|
||||||
CLUTTER_SYNC_MATRICES);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
CLUTTER_NOTE (MULTISTAGE, "Stage is the same");
|
CLUTTER_NOTE (MULTISTAGE, "Stage is the same");
|
||||||
|
@ -265,34 +265,6 @@ _clutter_stage_maybe_relayout (ClutterActor *stage)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
_clutter_stage_maybe_setup_viewport (ClutterStage *stage)
|
|
||||||
{
|
|
||||||
if ((CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_SYNC_MATRICES) &&
|
|
||||||
!CLUTTER_STAGE_IN_RESIZE (stage))
|
|
||||||
{
|
|
||||||
ClutterPerspective perspective;
|
|
||||||
gfloat width, height;
|
|
||||||
|
|
||||||
clutter_actor_get_preferred_size (CLUTTER_ACTOR (stage),
|
|
||||||
NULL, NULL,
|
|
||||||
&width, &height);
|
|
||||||
clutter_stage_get_perspective (stage, &perspective);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_SYNC_MATRICES);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
_clutter_do_redraw (ClutterStage *stage)
|
_clutter_do_redraw (ClutterStage *stage)
|
||||||
{
|
{
|
||||||
|
@ -75,25 +75,20 @@ typedef enum {
|
|||||||
CLUTTER_IS_TOPLEVEL = 1 << 1,
|
CLUTTER_IS_TOPLEVEL = 1 << 1,
|
||||||
CLUTTER_IN_REPARENT = 1 << 2,
|
CLUTTER_IN_REPARENT = 1 << 2,
|
||||||
|
|
||||||
/* Used by the stage to indicate GL viewport / perspective etc needs
|
/* Used to avoid recursion */
|
||||||
* (re)setting.
|
CLUTTER_IN_PAINT = 1 << 3,
|
||||||
*/
|
|
||||||
CLUTTER_SYNC_MATRICES = 1 << 3,
|
|
||||||
|
|
||||||
/* Used to avoid recursion */
|
/* Used to avoid recursion */
|
||||||
CLUTTER_IN_PAINT = 1 << 4,
|
CLUTTER_IN_RELAYOUT = 1 << 4,
|
||||||
|
|
||||||
/* Used to avoid recursion */
|
|
||||||
CLUTTER_IN_RELAYOUT = 1 << 5,
|
|
||||||
|
|
||||||
/* Used by the stage if resizing is an asynchronous operation (like on
|
/* Used by the stage if resizing is an asynchronous operation (like on
|
||||||
* X11) to delay queueing relayouts until we got a notification from the
|
* X11) to delay queueing relayouts until we got a notification from the
|
||||||
* event handling
|
* event handling
|
||||||
*/
|
*/
|
||||||
CLUTTER_IN_RESIZE = 1 << 6,
|
CLUTTER_IN_RESIZE = 1 << 5,
|
||||||
|
|
||||||
/* a flag for internal children of Containers */
|
/* a flag for internal children of Containers */
|
||||||
CLUTTER_INTERNAL_CHILD = 1 << 7
|
CLUTTER_INTERNAL_CHILD = 1 << 6
|
||||||
} ClutterPrivateFlags;
|
} ClutterPrivateFlags;
|
||||||
|
|
||||||
struct _ClutterInputDevice
|
struct _ClutterInputDevice
|
||||||
@ -251,6 +246,23 @@ void _clutter_stage_set_window (ClutterStage *sta
|
|||||||
ClutterStageWindow *stage_window);
|
ClutterStageWindow *stage_window);
|
||||||
ClutterStageWindow *_clutter_stage_get_window (ClutterStage *stage);
|
ClutterStageWindow *_clutter_stage_get_window (ClutterStage *stage);
|
||||||
ClutterStageWindow *_clutter_stage_get_default_window (void);
|
ClutterStageWindow *_clutter_stage_get_default_window (void);
|
||||||
|
void _clutter_stage_get_projection_matrix (ClutterStage *stage,
|
||||||
|
CoglMatrix *projection);
|
||||||
|
|
||||||
|
void _clutter_stage_dirty_projection (ClutterStage *stage);
|
||||||
|
void _clutter_stage_set_viewport (ClutterStage *stage,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
int width,
|
||||||
|
int height);
|
||||||
|
void _clutter_stage_get_viewport (ClutterStage *stage,
|
||||||
|
int *x,
|
||||||
|
int *y,
|
||||||
|
int *width,
|
||||||
|
int *height);
|
||||||
|
void _clutter_stage_dirty_viewport (ClutterStage *stage);
|
||||||
|
|
||||||
|
|
||||||
void _clutter_stage_maybe_setup_viewport (ClutterStage *stage);
|
void _clutter_stage_maybe_setup_viewport (ClutterStage *stage);
|
||||||
void _clutter_stage_maybe_relayout (ClutterActor *stage);
|
void _clutter_stage_maybe_relayout (ClutterActor *stage);
|
||||||
gboolean _clutter_stage_needs_update (ClutterStage *stage);
|
gboolean _clutter_stage_needs_update (ClutterStage *stage);
|
||||||
@ -330,8 +342,12 @@ gboolean _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint,
|
|||||||
gpointer dummy);
|
gpointer dummy);
|
||||||
|
|
||||||
ClutterActor *_clutter_actor_get_stage_internal (ClutterActor *actor);
|
ClutterActor *_clutter_actor_get_stage_internal (ClutterActor *actor);
|
||||||
|
|
||||||
|
void _clutter_actor_apply_modelview_transform (ClutterActor *self,
|
||||||
|
CoglMatrix *matrix);
|
||||||
void _clutter_actor_apply_modelview_transform_recursive (ClutterActor *self,
|
void _clutter_actor_apply_modelview_transform_recursive (ClutterActor *self,
|
||||||
ClutterActor *ancestor);
|
ClutterActor *ancestor,
|
||||||
|
CoglMatrix *matrix);
|
||||||
|
|
||||||
void _clutter_actor_rerealize (ClutterActor *self,
|
void _clutter_actor_rerealize (ClutterActor *self,
|
||||||
ClutterCallback callback,
|
ClutterCallback callback,
|
||||||
@ -349,7 +365,7 @@ void _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
|
|||||||
void _clutter_actor_set_has_pointer (ClutterActor *self,
|
void _clutter_actor_set_has_pointer (ClutterActor *self,
|
||||||
gboolean has_pointer);
|
gboolean has_pointer);
|
||||||
|
|
||||||
void _clutter_actor_transform_and_project_box (ClutterActor *self,
|
gboolean _clutter_actor_transform_and_project_box (ClutterActor *self,
|
||||||
const ClutterActorBox *box,
|
const ClutterActorBox *box,
|
||||||
ClutterVertex verts[]);
|
ClutterVertex verts[]);
|
||||||
|
|
||||||
|
@ -105,6 +105,8 @@ struct _ClutterStagePrivate
|
|||||||
|
|
||||||
ClutterColor color;
|
ClutterColor color;
|
||||||
ClutterPerspective perspective;
|
ClutterPerspective perspective;
|
||||||
|
CoglMatrix projection;
|
||||||
|
int viewport[4];
|
||||||
ClutterFog fog;
|
ClutterFog fog;
|
||||||
|
|
||||||
gchar *title;
|
gchar *title;
|
||||||
@ -122,6 +124,8 @@ struct _ClutterStagePrivate
|
|||||||
guint throttle_motion_events : 1;
|
guint throttle_motion_events : 1;
|
||||||
guint use_alpha : 1;
|
guint use_alpha : 1;
|
||||||
guint min_size_changed : 1;
|
guint min_size_changed : 1;
|
||||||
|
guint dirty_viewport : 1;
|
||||||
|
guint dirty_projection : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@ -291,6 +295,15 @@ clutter_stage_allocate (ClutterActor *self,
|
|||||||
klass = CLUTTER_ACTOR_CLASS (clutter_stage_parent_class);
|
klass = CLUTTER_ACTOR_CLASS (clutter_stage_parent_class);
|
||||||
klass->allocate (self, &override, flags);
|
klass->allocate (self, &override, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clutter_actor_get_allocation_geometry (self, &geom);
|
||||||
|
_clutter_stage_set_viewport (CLUTTER_STAGE (self),
|
||||||
|
0, 0, geom.width, geom.height);
|
||||||
|
|
||||||
|
/* Note: we don't assume that set_viewport will queue a full redraw
|
||||||
|
* since it may bail-out early if something preemptively set the
|
||||||
|
* viewport before the stage was really allocated its new size. */
|
||||||
|
clutter_actor_queue_redraw (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -376,7 +389,8 @@ clutter_stage_realize (ClutterActor *self)
|
|||||||
* first paint (which will likely occur before the ConfigureNotify
|
* first paint (which will likely occur before the ConfigureNotify
|
||||||
* is received)
|
* is received)
|
||||||
*/
|
*/
|
||||||
CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_SYNC_MATRICES);
|
priv->dirty_viewport = TRUE;
|
||||||
|
priv->dirty_projection = TRUE;
|
||||||
|
|
||||||
g_assert (priv->impl != NULL);
|
g_assert (priv->impl != NULL);
|
||||||
is_realized = _clutter_stage_window_realize (priv->impl);
|
is_realized = _clutter_stage_window_realize (priv->impl);
|
||||||
@ -794,6 +808,72 @@ clutter_stage_real_delete_event (ClutterStage *stage,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clutter_stage_real_apply_transform (ClutterActor *stage,
|
||||||
|
CoglMatrix *matrix)
|
||||||
|
{
|
||||||
|
ClutterStagePrivate *priv = CLUTTER_STAGE (stage)->priv;
|
||||||
|
CoglMatrix perspective;
|
||||||
|
gfloat z_camera;
|
||||||
|
gfloat width, height;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In theory, we can compute the camera distance from screen as:
|
||||||
|
*
|
||||||
|
* 0.5 * tan (FOV)
|
||||||
|
*
|
||||||
|
* However, it's better to compute the z_camera from our projection
|
||||||
|
* matrix so that we get a 1:1 mapping at the screen distance. Consider
|
||||||
|
* the upper-left corner of the screen. It has object coordinates
|
||||||
|
* (0,0,0), so by the transform below, ends up with eye coordinate
|
||||||
|
*
|
||||||
|
* x_eye = x_object / width - 0.5 = - 0.5
|
||||||
|
* y_eye = (height - y_object) / width - 0.5 = 0.5
|
||||||
|
* z_eye = z_object / width - z_camera = - z_camera
|
||||||
|
*
|
||||||
|
* From cogl_perspective(), we know that the projection matrix has
|
||||||
|
* the form:
|
||||||
|
*
|
||||||
|
* (x, 0, 0, 0)
|
||||||
|
* (0, y, 0, 0)
|
||||||
|
* (0, 0, c, d)
|
||||||
|
* (0, 0, -1, 0)
|
||||||
|
*
|
||||||
|
* Applied to the above, we get clip coordinates of
|
||||||
|
*
|
||||||
|
* x_clip = x * (- 0.5)
|
||||||
|
* y_clip = y * 0.5
|
||||||
|
* w_clip = - 1 * (- z_camera) = z_camera
|
||||||
|
*
|
||||||
|
* Dividing through by w to get normalized device coordinates, we
|
||||||
|
* have, x_nd = x * 0.5 / z_camera, y_nd = - y * 0.5 / z_camera.
|
||||||
|
* The upper left corner of the screen has normalized device coordinates,
|
||||||
|
* (-1, 1), so to have the correct 1:1 mapping, we have to have:
|
||||||
|
*
|
||||||
|
* z_camera = 0.5 * x = 0.5 * y
|
||||||
|
*
|
||||||
|
* If x != y, then we have a non-uniform aspect ration, and a 1:1 mapping
|
||||||
|
* doesn't make sense.
|
||||||
|
*/
|
||||||
|
|
||||||
|
cogl_matrix_init_identity (&perspective);
|
||||||
|
cogl_matrix_perspective (&perspective,
|
||||||
|
priv->perspective.fovy,
|
||||||
|
priv->perspective.aspect,
|
||||||
|
priv->perspective.z_near,
|
||||||
|
priv->perspective.z_far);
|
||||||
|
|
||||||
|
z_camera = 0.5f * perspective.xx;
|
||||||
|
|
||||||
|
clutter_actor_get_size (stage, &width, &height);
|
||||||
|
|
||||||
|
cogl_matrix_init_identity (matrix);
|
||||||
|
cogl_matrix_translate (matrix, -0.5f, -0.5f, -z_camera);
|
||||||
|
cogl_matrix_scale (matrix,
|
||||||
|
1.0f / width, -1.0f / height, 1.0f / width);
|
||||||
|
cogl_matrix_translate (matrix, 0.0f, -1.0f * height, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clutter_stage_set_property (GObject *object,
|
clutter_stage_set_property (GObject *object,
|
||||||
guint prop_id,
|
guint prop_id,
|
||||||
@ -1003,6 +1083,7 @@ clutter_stage_class_init (ClutterStageClass *klass)
|
|||||||
actor_class->show = clutter_stage_show;
|
actor_class->show = clutter_stage_show;
|
||||||
actor_class->hide = clutter_stage_hide;
|
actor_class->hide = clutter_stage_hide;
|
||||||
actor_class->queue_redraw = clutter_stage_real_queue_redraw;
|
actor_class->queue_redraw = clutter_stage_real_queue_redraw;
|
||||||
|
actor_class->apply_transform = clutter_stage_real_apply_transform;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ClutterStage:fullscreen:
|
* ClutterStage:fullscreen:
|
||||||
@ -1313,6 +1394,7 @@ clutter_stage_init (ClutterStage *self)
|
|||||||
{
|
{
|
||||||
ClutterStagePrivate *priv;
|
ClutterStagePrivate *priv;
|
||||||
ClutterBackend *backend;
|
ClutterBackend *backend;
|
||||||
|
ClutterGeometry geom;
|
||||||
|
|
||||||
/* a stage is a top-level object */
|
/* a stage is a top-level object */
|
||||||
CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IS_TOPLEVEL);
|
CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IS_TOPLEVEL);
|
||||||
@ -1348,6 +1430,13 @@ clutter_stage_init (ClutterStage *self)
|
|||||||
priv->perspective.z_near = 0.1;
|
priv->perspective.z_near = 0.1;
|
||||||
priv->perspective.z_far = 100.0;
|
priv->perspective.z_far = 100.0;
|
||||||
|
|
||||||
|
cogl_matrix_init_identity (&priv->projection);
|
||||||
|
cogl_matrix_perspective (&priv->projection,
|
||||||
|
priv->perspective.fovy,
|
||||||
|
priv->perspective.aspect,
|
||||||
|
priv->perspective.z_near,
|
||||||
|
priv->perspective.z_far);
|
||||||
|
|
||||||
/* depth cueing */
|
/* depth cueing */
|
||||||
priv->fog.z_near = 1.0;
|
priv->fog.z_near = 1.0;
|
||||||
priv->fog.z_far = 2.0;
|
priv->fog.z_far = 2.0;
|
||||||
@ -1360,6 +1449,9 @@ clutter_stage_init (ClutterStage *self)
|
|||||||
G_CALLBACK (clutter_stage_notify_min_size), NULL);
|
G_CALLBACK (clutter_stage_notify_min_size), NULL);
|
||||||
g_signal_connect (self, "notify::min-height",
|
g_signal_connect (self, "notify::min-height",
|
||||||
G_CALLBACK (clutter_stage_notify_min_size), NULL);
|
G_CALLBACK (clutter_stage_notify_min_size), NULL);
|
||||||
|
|
||||||
|
_clutter_stage_window_get_geometry (priv->impl, &geom);
|
||||||
|
_clutter_stage_set_viewport (self, 0, 0, geom.width, geom.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1463,12 +1555,23 @@ clutter_stage_set_perspective (ClutterStage *stage,
|
|||||||
|
|
||||||
priv = stage->priv;
|
priv = stage->priv;
|
||||||
|
|
||||||
|
if (priv->perspective.fovy == perspective->fovy &&
|
||||||
|
priv->perspective.aspect == perspective->aspect &&
|
||||||
|
priv->perspective.z_near == perspective->z_near &&
|
||||||
|
priv->perspective.z_far == perspective->z_far)
|
||||||
|
return;
|
||||||
|
|
||||||
priv->perspective = *perspective;
|
priv->perspective = *perspective;
|
||||||
|
|
||||||
/* this will cause the viewport to be reset; see
|
cogl_matrix_init_identity (&priv->projection);
|
||||||
* clutter_maybe_setup_viewport() inside clutter-main.c
|
cogl_matrix_perspective (&priv->projection,
|
||||||
*/
|
priv->perspective.fovy,
|
||||||
CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_SYNC_MATRICES);
|
priv->perspective.aspect,
|
||||||
|
priv->perspective.z_near,
|
||||||
|
priv->perspective.z_far);
|
||||||
|
|
||||||
|
priv->dirty_projection = TRUE;
|
||||||
|
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1489,6 +1592,148 @@ clutter_stage_get_perspective (ClutterStage *stage,
|
|||||||
*perspective = stage->priv->perspective;
|
*perspective = stage->priv->perspective;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* clutter_stage_get_projection_matrix:
|
||||||
|
* @stage: A #ClutterStage
|
||||||
|
* @projection: return location for a #CoglMatrix representing the
|
||||||
|
* perspective projection applied to actors on the given
|
||||||
|
* @stage.
|
||||||
|
*
|
||||||
|
* Retrieves the @stage's projection matrix. This is derived from the
|
||||||
|
* current perspective set using clutter_stage_set_perspective().
|
||||||
|
*
|
||||||
|
* Since: 1.6
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
_clutter_stage_get_projection_matrix (ClutterStage *stage,
|
||||||
|
CoglMatrix *projection)
|
||||||
|
{
|
||||||
|
g_return_if_fail (CLUTTER_IS_STAGE (stage));
|
||||||
|
g_return_if_fail (projection != NULL);
|
||||||
|
|
||||||
|
*projection = stage->priv->projection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This simply provides a simple mechanism for us to ensure that
|
||||||
|
* the projection matrix gets re-asserted before painting.
|
||||||
|
*
|
||||||
|
* This is used when switching between multiple stages */
|
||||||
|
void
|
||||||
|
_clutter_stage_dirty_projection (ClutterStage *stage)
|
||||||
|
{
|
||||||
|
stage->priv->dirty_projection = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* clutter_stage_set_viewport:
|
||||||
|
* @stage: A #ClutterStage
|
||||||
|
* @x: The X postition to render the stage at, in window coordinates
|
||||||
|
* @y: The Y position to render the stage at, in window coordinates
|
||||||
|
* @width: The width to render the stage at, in window coordinates
|
||||||
|
* @height: The height to render the stage at, in window coordinates
|
||||||
|
*
|
||||||
|
* Sets the stage viewport. The viewport defines a final scale and
|
||||||
|
* translation of your rendered stage and actors. This lets you render
|
||||||
|
* your stage into a subregion of the stage window or you could use it to
|
||||||
|
* pan a subregion of the stage if your stage window is smaller then
|
||||||
|
* the stage. (XXX: currently this isn't possible)
|
||||||
|
*
|
||||||
|
* Unlike a scale and translation done using the modelview matrix this
|
||||||
|
* is done after everything has had perspective projection applied, so
|
||||||
|
* for example if you were to pan across a subregion of the stage using
|
||||||
|
* the viewport then you would not see a change in perspective for the
|
||||||
|
* actors on the stage.
|
||||||
|
*
|
||||||
|
* Normally the stage viewport will automatically track the size of the
|
||||||
|
* stage window with no offset so the stage will fill your window. This
|
||||||
|
* behaviour can be changed with the "viewport-mimics-window" property
|
||||||
|
* which will automatically be set to FALSE if you use this API. If
|
||||||
|
* you want to revert to the original behaviour then you should set
|
||||||
|
* this property back to %TRUE using
|
||||||
|
* clutter_stage_set_viewport_mimics_window().
|
||||||
|
* (XXX: If we were to make this API public then we might want to do
|
||||||
|
* add that property.)
|
||||||
|
*
|
||||||
|
* Since: 1.6
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
_clutter_stage_set_viewport (ClutterStage *stage,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
int width,
|
||||||
|
int height)
|
||||||
|
{
|
||||||
|
ClutterStagePrivate *priv;
|
||||||
|
|
||||||
|
g_return_if_fail (CLUTTER_IS_STAGE (stage));
|
||||||
|
|
||||||
|
priv = stage->priv;
|
||||||
|
|
||||||
|
|
||||||
|
if (x == priv->viewport[0] &&
|
||||||
|
y == priv->viewport[1] &&
|
||||||
|
width == priv->viewport[2] &&
|
||||||
|
height == priv->viewport[3])
|
||||||
|
return;
|
||||||
|
|
||||||
|
priv->viewport[0] = x;
|
||||||
|
priv->viewport[1] = y;
|
||||||
|
priv->viewport[2] = width;
|
||||||
|
priv->viewport[3] = height;
|
||||||
|
|
||||||
|
priv->dirty_viewport = TRUE;
|
||||||
|
|
||||||
|
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This simply provides a simple mechanism for us to ensure that
|
||||||
|
* the viewport gets re-asserted before next painting.
|
||||||
|
*
|
||||||
|
* This is used when switching between multiple stages */
|
||||||
|
void
|
||||||
|
_clutter_stage_dirty_viewport (ClutterStage *stage)
|
||||||
|
{
|
||||||
|
stage->priv->dirty_viewport = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* clutter_stage_get_viewport:
|
||||||
|
* @stage: A #ClutterStage
|
||||||
|
* @x: A location for the X position where the stage is rendered,
|
||||||
|
* in window coordinates.
|
||||||
|
* @y: A location for the Y position where the stage is rendered,
|
||||||
|
* in window coordinates.
|
||||||
|
* @width: A location for the width the stage is rendered at,
|
||||||
|
* in window coordinates.
|
||||||
|
* @height: A location for the height the stage is rendered at,
|
||||||
|
* in window coordinates.
|
||||||
|
*
|
||||||
|
* Returns the viewport offset and size set using
|
||||||
|
* clutter_stage_set_viewport() or if the "viewport-mimics-window" property
|
||||||
|
* is TRUE then @x and @y will be set to 0 and @width and @height will equal
|
||||||
|
* the width if the stage window.
|
||||||
|
*
|
||||||
|
* Since: 1.6
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
_clutter_stage_get_viewport (ClutterStage *stage,
|
||||||
|
int *x,
|
||||||
|
int *y,
|
||||||
|
int *width,
|
||||||
|
int *height)
|
||||||
|
{
|
||||||
|
ClutterStagePrivate *priv;
|
||||||
|
|
||||||
|
g_return_if_fail (CLUTTER_IS_STAGE (stage));
|
||||||
|
|
||||||
|
priv = stage->priv;
|
||||||
|
|
||||||
|
*x = priv->viewport[0];
|
||||||
|
*y = priv->viewport[1];
|
||||||
|
*width = priv->viewport[2];
|
||||||
|
*height = priv->viewport[3];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clutter_stage_set_fullscreen:
|
* clutter_stage_set_fullscreen:
|
||||||
* @stage: a #ClutterStage
|
* @stage: a #ClutterStage
|
||||||
@ -1534,6 +1779,15 @@ clutter_stage_set_fullscreen (ClutterStage *stage,
|
|||||||
if (iface->set_fullscreen)
|
if (iface->set_fullscreen)
|
||||||
iface->set_fullscreen (impl, fullscreen);
|
iface->set_fullscreen (impl, fullscreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the backend did fullscreen the stage window then we need to resize
|
||||||
|
* the stage and update its viewport so we queue a relayout. Note: if the
|
||||||
|
* fullscreen request is handled asynchronously we can't rely on this
|
||||||
|
* queue_relayout to update the viewport, but for example the X backend
|
||||||
|
* will recieve a ConfigureNotify after a successful resize which is how
|
||||||
|
* we ensure the viewport is updated on X.
|
||||||
|
*/
|
||||||
|
clutter_actor_queue_relayout (CLUTTER_ACTOR (stage));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2279,11 +2533,33 @@ clutter_stage_ensure_viewport (ClutterStage *stage)
|
|||||||
{
|
{
|
||||||
g_return_if_fail (CLUTTER_IS_STAGE (stage));
|
g_return_if_fail (CLUTTER_IS_STAGE (stage));
|
||||||
|
|
||||||
CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_SYNC_MATRICES);
|
_clutter_stage_dirty_viewport (stage);
|
||||||
|
|
||||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
|
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_clutter_stage_maybe_setup_viewport (ClutterStage *stage)
|
||||||
|
{
|
||||||
|
ClutterStagePrivate *priv = stage->priv;
|
||||||
|
|
||||||
|
if (priv->dirty_viewport)
|
||||||
|
{
|
||||||
|
CLUTTER_NOTE (PAINT,
|
||||||
|
"Setting up the viewport { w:%d, h:%d }",
|
||||||
|
priv->viewport[2], priv->viewport[3]);
|
||||||
|
|
||||||
|
cogl_set_viewport (priv->viewport[0],
|
||||||
|
priv->viewport[1],
|
||||||
|
priv->viewport[2],
|
||||||
|
priv->viewport[3]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->dirty_projection)
|
||||||
|
cogl_set_projection_matrix (&priv->projection);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clutter_stage_ensure_redraw:
|
* clutter_stage_ensure_redraw:
|
||||||
* @stage: a #ClutterStage
|
* @stage: a #ClutterStage
|
||||||
|
@ -509,8 +509,22 @@ update_fbo (ClutterActor *self)
|
|||||||
|
|
||||||
/* Reapply the source's parent transformations */
|
/* Reapply the source's parent transformations */
|
||||||
if ((source_parent = clutter_actor_get_parent (priv->fbo_source)))
|
if ((source_parent = clutter_actor_get_parent (priv->fbo_source)))
|
||||||
|
{
|
||||||
|
CoglMatrix modelview;
|
||||||
|
|
||||||
|
/* NB: _clutter_actor_apply_modelview_transform_recursive
|
||||||
|
* will never include the transformation between stage
|
||||||
|
* coordinates and OpenGL window coordinates, we have to
|
||||||
|
* explicitly use the stage->apply_transform to get that...
|
||||||
|
*/
|
||||||
|
|
||||||
|
cogl_matrix_init_identity (&modelview);
|
||||||
|
_clutter_actor_apply_modelview_transform (stage, &modelview);
|
||||||
_clutter_actor_apply_modelview_transform_recursive (source_parent,
|
_clutter_actor_apply_modelview_transform_recursive (source_parent,
|
||||||
NULL);
|
NULL,
|
||||||
|
&modelview);
|
||||||
|
cogl_set_modelview_matrix (&modelview);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -170,8 +170,6 @@ clutter_stage_osx_get_wrapper (ClutterStageWindow *stage_window);
|
|||||||
stage_osx->requisition_height = [self bounds].size.height;
|
stage_osx->requisition_height = [self bounds].size.height;
|
||||||
clutter_actor_set_size (CLUTTER_ACTOR (self->stage_osx->wrapper),
|
clutter_actor_set_size (CLUTTER_ACTOR (self->stage_osx->wrapper),
|
||||||
(int)[self bounds].size.width, (int)[self bounds].size.height);
|
(int)[self bounds].size.width, (int)[self bounds].size.height);
|
||||||
/* make sure that the viewport is updated */
|
|
||||||
CLUTTER_SET_PRIVATE_FLAGS (self->stage_osx->wrapper, CLUTTER_SYNC_MATRICES);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Simply forward all events that reach our view to clutter. */
|
/* Simply forward all events that reach our view to clutter. */
|
||||||
@ -300,8 +298,6 @@ clutter_stage_osx_realize (ClutterStageWindow *stage_window)
|
|||||||
initWithView: self->view
|
initWithView: self->view
|
||||||
UTF8Title: clutter_stage_get_title (CLUTTER_STAGE (self->wrapper))
|
UTF8Title: clutter_stage_get_title (CLUTTER_STAGE (self->wrapper))
|
||||||
stage: self];
|
stage: self];
|
||||||
/* all next operations will cause draw operation and viewport should be setup now */
|
|
||||||
_clutter_stage_maybe_setup_viewport(self->wrapper);
|
|
||||||
/* looks better than positioning to 0,0 (bottom right) */
|
/* looks better than positioning to 0,0 (bottom right) */
|
||||||
[self->window center];
|
[self->window center];
|
||||||
|
|
||||||
@ -422,9 +418,6 @@ clutter_stage_osx_resize (ClutterStageWindow *stage_window,
|
|||||||
[self->window setContentSize: size];
|
[self->window setContentSize: size];
|
||||||
|
|
||||||
CLUTTER_OSX_POOL_RELEASE ();
|
CLUTTER_OSX_POOL_RELEASE ();
|
||||||
|
|
||||||
/* make sure that the viewport is updated */
|
|
||||||
CLUTTER_SET_PRIVATE_FLAGS (self->wrapper, CLUTTER_SYNC_MATRICES);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
@ -63,7 +63,6 @@ clutter_stage_win32_show (ClutterStageWindow *stage_window,
|
|||||||
{
|
{
|
||||||
ShowWindow (stage_win32->hwnd, do_raise ? SW_SHOW : SW_SHOWNA);
|
ShowWindow (stage_win32->hwnd, do_raise ? SW_SHOW : SW_SHOWNA);
|
||||||
|
|
||||||
clutter_stage_ensure_viewport (CLUTTER_STAGE (stage_win32->wrapper));
|
|
||||||
clutter_actor_map (CLUTTER_ACTOR (stage_win32->wrapper));
|
clutter_actor_map (CLUTTER_ACTOR (stage_win32->wrapper));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -190,9 +189,6 @@ clutter_stage_win32_resize (ClutterStageWindow *stage_window,
|
|||||||
SWP_NOZORDER | SWP_NOMOVE);
|
SWP_NOZORDER | SWP_NOMOVE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CLUTTER_SET_PRIVATE_FLAGS (stage_win32->wrapper,
|
|
||||||
CLUTTER_SYNC_MATRICES);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,9 +343,6 @@ clutter_stage_win32_set_fullscreen (ClutterStageWindow *stage_window,
|
|||||||
full_width, full_height,
|
full_width, full_height,
|
||||||
SWP_NOZORDER | SWP_NOMOVE);
|
SWP_NOZORDER | SWP_NOMOVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
CLUTTER_SET_PRIVATE_FLAGS (stage_win32->wrapper,
|
|
||||||
CLUTTER_SYNC_MATRICES);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Report the state change */
|
/* Report the state change */
|
||||||
|
@ -225,7 +225,6 @@ clutter_stage_x11_resize (ClutterStageWindow *stage_window,
|
|||||||
ClutterBackend *backend = clutter_get_default_backend ();
|
ClutterBackend *backend = clutter_get_default_backend ();
|
||||||
ClutterBackendX11 *backend_x11;
|
ClutterBackendX11 *backend_x11;
|
||||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
|
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
|
||||||
ClutterStage *stage = stage_x11->wrapper;
|
|
||||||
gboolean resize;
|
gboolean resize;
|
||||||
|
|
||||||
if (stage_x11->is_foreign_xwin)
|
if (stage_x11->is_foreign_xwin)
|
||||||
@ -277,26 +276,14 @@ clutter_stage_x11_resize (ClutterStageWindow *stage_window,
|
|||||||
CLUTTER_SET_PRIVATE_FLAGS (stage_x11->wrapper,
|
CLUTTER_SET_PRIVATE_FLAGS (stage_x11->wrapper,
|
||||||
CLUTTER_IN_RESIZE);
|
CLUTTER_IN_RESIZE);
|
||||||
|
|
||||||
|
/* XXX: in this case we can rely on a subsequent
|
||||||
|
* ConfigureNotify that will result in the stage
|
||||||
|
* being reallocated so we don't actively do anything
|
||||||
|
* to affect the stage allocation here. */
|
||||||
XResizeWindow (backend_x11->xdpy,
|
XResizeWindow (backend_x11->xdpy,
|
||||||
stage_x11->xwin,
|
stage_x11->xwin,
|
||||||
width,
|
width,
|
||||||
height);
|
height);
|
||||||
|
|
||||||
/* If the viewport hasn't previously been initialized then even
|
|
||||||
* though we can't guarantee that the server will honour our request
|
|
||||||
* we need to ensure a valid viewport is set before our first paint.
|
|
||||||
*/
|
|
||||||
if (G_UNLIKELY (!stage_x11->viewport_initialized))
|
|
||||||
{
|
|
||||||
ClutterPerspective perspective;
|
|
||||||
clutter_stage_get_perspective (stage, &perspective);
|
|
||||||
_cogl_setup_viewport (width,
|
|
||||||
height,
|
|
||||||
perspective.fovy,
|
|
||||||
perspective.aspect,
|
|
||||||
perspective.z_near,
|
|
||||||
perspective.z_far);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -436,8 +423,6 @@ clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window,
|
|||||||
|
|
||||||
CLUTTER_NOTE (BACKEND, "%ssetting fullscreen", is_fullscreen ? "" : "un");
|
CLUTTER_NOTE (BACKEND, "%ssetting fullscreen", is_fullscreen ? "" : "un");
|
||||||
|
|
||||||
CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_SYNC_MATRICES);
|
|
||||||
|
|
||||||
if (is_fullscreen)
|
if (is_fullscreen)
|
||||||
{
|
{
|
||||||
int width, height;
|
int width, height;
|
||||||
@ -516,8 +501,10 @@ clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clutter_stage_ensure_viewport (CLUTTER_STAGE (stage_x11->wrapper));
|
/* XXX: Note we rely on the ConfigureNotify mechanism as the common
|
||||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (stage_x11->wrapper));
|
* mechanism to handle notifications of new X window sizes from the
|
||||||
|
* X server so we don't actively change the stage viewport here or
|
||||||
|
* queue a relayout etc. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -706,7 +693,6 @@ clutter_stage_x11_init (ClutterStageX11 *stage)
|
|||||||
stage->is_foreign_xwin = FALSE;
|
stage->is_foreign_xwin = FALSE;
|
||||||
stage->fullscreening = FALSE;
|
stage->fullscreening = FALSE;
|
||||||
stage->is_cursor_visible = TRUE;
|
stage->is_cursor_visible = TRUE;
|
||||||
stage->viewport_initialized = FALSE;
|
|
||||||
|
|
||||||
stage->title = NULL;
|
stage->title = NULL;
|
||||||
|
|
||||||
@ -949,7 +935,16 @@ clutter_x11_set_stage_foreign (ClutterStage *stage,
|
|||||||
set_foreign_window_callback,
|
set_foreign_window_callback,
|
||||||
&fwd);
|
&fwd);
|
||||||
|
|
||||||
clutter_stage_ensure_viewport (stage);
|
/* Queue a relayout - so the stage will be allocated the new
|
||||||
|
* window size.
|
||||||
|
*
|
||||||
|
* Note also that when the stage gets allocated the new
|
||||||
|
* window size that will result in the stage's
|
||||||
|
* priv->viewport being changed, which will in turn result
|
||||||
|
* in the Cogl viewport changing when _clutter_do_redraw
|
||||||
|
* calls _clutter_stage_maybe_setup_viewport().
|
||||||
|
*/
|
||||||
|
clutter_actor_queue_relayout (CLUTTER_ACTOR (stage));
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -115,11 +115,6 @@ CLUTTER_ACTOR_ABOUT_TO_UNPARENT
|
|||||||
actor is removed from the stage, so unrealize implementations
|
actor is removed from the stage, so unrealize implementations
|
||||||
can use clutter_actor_get_stage().
|
can use clutter_actor_get_stage().
|
||||||
|
|
||||||
CLUTTER_ACTOR_SYNC_MATRICES
|
|
||||||
Set internally by ClutterStage implementations
|
|
||||||
Means: the size of the stage changed and the viewport must be
|
|
||||||
synchronized to the new size
|
|
||||||
|
|
||||||
CLUTTER_ACTOR_IN_PAINT:
|
CLUTTER_ACTOR_IN_PAINT:
|
||||||
Set internally by clutter_actor_paint()
|
Set internally by clutter_actor_paint()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user