1
0
Fork 0

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:
Robert Bragg 2010-09-07 13:10:55 +01:00
parent ab008948cf
commit f5f066df9c
10 changed files with 592 additions and 618 deletions

View file

@ -588,8 +588,6 @@ static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
static void clutter_animatable_iface_init (ClutterAnimatableIface *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,
gboolean repeat);
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 void _clutter_actor_get_relative_modelview (ClutterActor *self,
ClutterActor *ancestor,
CoglMatrix *matrix);
/* Helper macro which translates by the anchor coord, applies the
given transformation and then translates back */
#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);
}
/* 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:
* @self: A #ClutterActor
@ -2056,34 +1890,119 @@ clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
const ClutterVertex *point,
ClutterVertex *vertex)
{
gfloat x, y, z, w;
full_vertex_t tmp;
gfloat v[4];
gfloat w;
CoglMatrix matrix;
g_return_if_fail (CLUTTER_IS_ACTOR (self));
g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
g_return_if_fail (point != NULL);
g_return_if_fail (vertex != NULL);
x = point->x;
y = point->y;
z = point->z;
*vertex = *point;
w = 1.0;
/* First we tranform the point using the OpenGL modelview matrix */
clutter_actor_transform_point_relative (self, ancestor, &x, &y, &z, &w);
if (ancestor == NULL)
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
* we would have to divide the original verts with it.
*/
tmp.x = (x + 0.5) * v[2];
tmp.y = (0.5 - y) * v[3];
tmp.z = (z + 0.5) * v[2];
tmp.w = 0;
_clutter_actor_get_relative_modelview (self, ancestor, &matrix);
cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
}
full_vertex_to_units (&tmp, vertex);
/* Help macros to scale from OpenGL <-1,1> coordinates system to
* window coordinates ranging [0,window-size]
*/
#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)))
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,
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 (vertex != NULL);
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_fully_transform_vertices (self, point, vertex, 1);
}
/* _clutter_actor_get_relative_modelview:
*
* Retrives the modelview transformation relative to some ancestor actor, or
* the stage if NULL is given for the ancestor.
* Retrieves the modelview transformation relative to some 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
* actor itself */
/* TODO: Replace all other occurrences of this code pattern in clutter-actor.c:
* 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
static void
_clutter_actor_get_relative_modelview (ClutterActor *self,
ClutterActor *ancestor,
CoglMatrix *matrix)
{
ClutterActor *stage;
gfloat width, height;
CoglMatrix tmp_matrix;
gfloat z_camera;
ClutterPerspective perspective;
g_return_if_fail (ancestor != NULL);
_clutter_actor_ensure_stage_current (self);
cogl_matrix_init_identity (matrix);
cogl_push_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_apply_modelview_transform_recursive (self, ancestor, matrix);
}
/* _clutter_actor_get_projection_and_viewport
*
* Retrieves the projection matrix and viewport for the actors corresponding
* 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
/* Project the given @box into stage window coordinates, writing the
* transformed vertices to @verts[]. */
gboolean
_clutter_actor_transform_and_project_box (ClutterActor *self,
const ClutterActorBox *box,
ClutterVertex verts[])
{
CoglMatrix mtx;
CoglMatrix mtx_p;
float v[4];
full_vertex_t vertices[4];
ClutterVertex box_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]);
full_vertex_transform (&mtx, box->x2, box->y1, 0, 1.0, &vertices[1]);
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]);
return
_clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
}
/**
* clutter_actor_get_allocation_vertices:
* @self: A #ClutterActor
* @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
* 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[])
{
ClutterActorPrivate *priv;
ClutterActor *stage;
gfloat v[4];
full_vertex_t vertices[4];
full_vertex_t tmp = { 0, };
ClutterActorBox box;
ClutterVertex vertices[4];
CoglMatrix modelview;
float w;
g_return_if_fail (CLUTTER_IS_ACTOR (self));
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;
/* 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
* clutter_actor_transform_vertices_relative() will have valid values
* to use in the transformations
*/
* we will have valid values to use in the transformations */
if (priv->needs_allocation)
_clutter_stage_maybe_relayout (stage);
{
ClutterActor *stage = _clutter_actor_get_stage_internal (self);
if (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;
* 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]);
_clutter_actor_get_relative_modelview (self, ancestor, &modelview);
tmp.x = ((vertices[1].x + 0.5) * v[2]);
tmp.y = ((0.5 - vertices[1].y) * v[3]);
tmp.z = ((vertices[1].z + 0.5) * v[2]);
full_vertex_to_units (&tmp, &verts[1]);
tmp.x = ((vertices[2].x + 0.5) * v[2]);
tmp.y = ((0.5 - vertices[2].y) * v[3]);
tmp.z = ((vertices[2].z + 0.5) * v[2]);
full_vertex_to_units (&tmp, &verts[2]);
tmp.x = ((vertices[3].x + 0.5) * v[2]);
tmp.y = ((0.5 - vertices[3].y) * v[3]);
tmp.z = ((vertices[3].z + 0.5) * v[2]);
full_vertex_to_units (&tmp, &verts[3]);
w = 1;
cogl_matrix_transform_point (&modelview,
&vertices[0].x, &vertices[0].y, &vertices[0].z,
&w);
cogl_matrix_transform_point (&modelview,
&vertices[1].x, &vertices[1].y, &vertices[1].z,
&w);
cogl_matrix_transform_point (&modelview,
&vertices[2].x, &vertices[2].y, &vertices[2].z,
&w);
cogl_matrix_transform_point (&modelview,
&vertices[3].x, &vertices[3].y, &vertices[3].z,
&w);
}
/**
@ -2455,12 +2219,9 @@ clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
if (priv->needs_allocation)
{
ClutterActor *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 ();
/* There's nothing meaningful we can do now */
if (!stage)
return;
_clutter_stage_maybe_relayout (stage);
}
@ -2481,15 +2242,11 @@ clutter_actor_real_apply_transform (ClutterActor *self,
CoglMatrix *matrix)
{
ClutterActorPrivate *priv = self->priv;
gboolean is_stage = CLUTTER_IS_STAGE (self);
if (!is_stage)
{
cogl_matrix_translate (matrix,
priv->allocation.x1,
priv->allocation.y1,
0.0);
}
cogl_matrix_translate (matrix,
priv->allocation.x1,
priv->allocation.y1,
0.0);
if (priv->z)
cogl_matrix_translate (matrix, 0, 0, priv->z);
@ -2531,7 +2288,7 @@ clutter_actor_real_apply_transform (ClutterActor *self,
priv->rxang,
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;
@ -2540,26 +2297,13 @@ clutter_actor_real_apply_transform (ClutterActor *self,
}
}
/* Applies the transforms associated with this actor to the
* OpenGL modelview matrix.
*
* This function does not push/pop matrix; it is the responsibility
* of the caller to do so as appropriate
*/
static void
_clutter_actor_apply_modelview_transform (ClutterActor *self)
/* Applies the transforms associated with this actor to the given
* matrix. */
void
_clutter_actor_apply_modelview_transform (ClutterActor *self,
CoglMatrix *matrix)
{
CoglMatrix matrix, cur, new;
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);
CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
}
static gboolean
@ -2597,42 +2341,30 @@ _clutter_actor_effects_post_paint (ClutterActor *self)
}
/* 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.
*
* This function does not push/pop matrix; it is the responsibility
* of the caller to do so as appropriate
*/
void
_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);
/*
* If we reached the ancestor, quit
* NB: NULL ancestor means the stage, and this will not trigger
* (as it should not)
*/
/* 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
* value to represent the fake parent of the stage. */
if (self == ancestor)
return;
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 ();
parent = clutter_actor_get_parent (self);
if (parent != NULL)
_clutter_actor_apply_modelview_transform_recursive (parent, ancestor);
else if (self != stage)
_clutter_actor_apply_modelview_transform (stage);
_clutter_actor_apply_modelview_transform_recursive (parent, ancestor,
matrix);
_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();
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)
{
@ -5071,27 +4811,6 @@ _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
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)
{
_clutter_actor_get_allocation_clip (self, &allocation_clip);
@ -10657,7 +10376,8 @@ clutter_actor_unset_flags (ClutterActor *self,
* @self: a #ClutterActor
* @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
*/
@ -10669,7 +10389,7 @@ clutter_actor_get_transformation_matrix (ClutterActor *self,
cogl_matrix_init_identity (matrix);
CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
_clutter_actor_apply_modelview_transform (self, matrix);
}
/**

View file

@ -421,6 +421,17 @@ _clutter_backend_ensure_context (ClutterBackend *backend,
clutter_actor_get_size (CLUTTER_ACTOR (stage), &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
@ -429,17 +440,6 @@ _clutter_backend_ensure_context (ClutterBackend *backend,
* potential issue of GL calls with no context)
*/
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
CLUTTER_NOTE (MULTISTAGE, "Stage is the same");

View file

@ -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
_clutter_do_redraw (ClutterStage *stage)
{

View file

@ -75,25 +75,20 @@ typedef enum {
CLUTTER_IS_TOPLEVEL = 1 << 1,
CLUTTER_IN_REPARENT = 1 << 2,
/* Used by the stage to indicate GL viewport / perspective etc needs
* (re)setting.
*/
CLUTTER_SYNC_MATRICES = 1 << 3,
/* Used to avoid recursion */
CLUTTER_IN_PAINT = 1 << 3,
/* Used to avoid recursion */
CLUTTER_IN_PAINT = 1 << 4,
/* Used to avoid recursion */
CLUTTER_IN_RELAYOUT = 1 << 5,
CLUTTER_IN_RELAYOUT = 1 << 4,
/* Used by the stage if resizing is an asynchronous operation (like on
* X11) to delay queueing relayouts until we got a notification from the
* event handling
*/
CLUTTER_IN_RESIZE = 1 << 6,
CLUTTER_IN_RESIZE = 1 << 5,
/* a flag for internal children of Containers */
CLUTTER_INTERNAL_CHILD = 1 << 7
CLUTTER_INTERNAL_CHILD = 1 << 6
} ClutterPrivateFlags;
struct _ClutterInputDevice
@ -251,6 +246,23 @@ void _clutter_stage_set_window (ClutterStage *sta
ClutterStageWindow *stage_window);
ClutterStageWindow *_clutter_stage_get_window (ClutterStage *stage);
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_relayout (ClutterActor *stage);
gboolean _clutter_stage_needs_update (ClutterStage *stage);
@ -330,8 +342,12 @@ gboolean _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint,
gpointer dummy);
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,
ClutterActor *ancestor);
ClutterActor *ancestor,
CoglMatrix *matrix);
void _clutter_actor_rerealize (ClutterActor *self,
ClutterCallback callback,
@ -349,9 +365,9 @@ void _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
void _clutter_actor_set_has_pointer (ClutterActor *self,
gboolean has_pointer);
void _clutter_actor_transform_and_project_box (ClutterActor *self,
const ClutterActorBox *box,
ClutterVertex verts[]);
gboolean _clutter_actor_transform_and_project_box (ClutterActor *self,
const ClutterActorBox *box,
ClutterVertex verts[]);
void _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
ClutterRedrawFlags flags,

View file

@ -105,6 +105,8 @@ struct _ClutterStagePrivate
ClutterColor color;
ClutterPerspective perspective;
CoglMatrix projection;
int viewport[4];
ClutterFog fog;
gchar *title;
@ -122,6 +124,8 @@ struct _ClutterStagePrivate
guint throttle_motion_events : 1;
guint use_alpha : 1;
guint min_size_changed : 1;
guint dirty_viewport : 1;
guint dirty_projection : 1;
};
enum
@ -291,6 +295,15 @@ clutter_stage_allocate (ClutterActor *self,
klass = CLUTTER_ACTOR_CLASS (clutter_stage_parent_class);
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
@ -376,7 +389,8 @@ clutter_stage_realize (ClutterActor *self)
* first paint (which will likely occur before the ConfigureNotify
* is received)
*/
CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_SYNC_MATRICES);
priv->dirty_viewport = TRUE;
priv->dirty_projection = TRUE;
g_assert (priv->impl != NULL);
is_realized = _clutter_stage_window_realize (priv->impl);
@ -794,6 +808,72 @@ clutter_stage_real_delete_event (ClutterStage *stage,
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
clutter_stage_set_property (GObject *object,
guint prop_id,
@ -1003,6 +1083,7 @@ clutter_stage_class_init (ClutterStageClass *klass)
actor_class->show = clutter_stage_show;
actor_class->hide = clutter_stage_hide;
actor_class->queue_redraw = clutter_stage_real_queue_redraw;
actor_class->apply_transform = clutter_stage_real_apply_transform;
/**
* ClutterStage:fullscreen:
@ -1313,6 +1394,7 @@ clutter_stage_init (ClutterStage *self)
{
ClutterStagePrivate *priv;
ClutterBackend *backend;
ClutterGeometry geom;
/* a stage is a top-level object */
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_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 */
priv->fog.z_near = 1.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_signal_connect (self, "notify::min-height",
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;
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;
/* this will cause the viewport to be reset; see
* clutter_maybe_setup_viewport() inside clutter-main.c
*/
CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_SYNC_MATRICES);
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);
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;
}
/*
* 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:
* @stage: a #ClutterStage
@ -1534,6 +1779,15 @@ clutter_stage_set_fullscreen (ClutterStage *stage,
if (iface->set_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));
CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_SYNC_MATRICES);
_clutter_stage_dirty_viewport (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:
* @stage: a #ClutterStage

View file

@ -509,8 +509,22 @@ update_fbo (ClutterActor *self)
/* Reapply the source's parent transformations */
if ((source_parent = clutter_actor_get_parent (priv->fbo_source)))
_clutter_actor_apply_modelview_transform_recursive (source_parent,
NULL);
{
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,
NULL,
&modelview);
cogl_set_modelview_matrix (&modelview);
}
}

View file

@ -170,8 +170,6 @@ clutter_stage_osx_get_wrapper (ClutterStageWindow *stage_window);
stage_osx->requisition_height = [self bounds].size.height;
clutter_actor_set_size (CLUTTER_ACTOR (self->stage_osx->wrapper),
(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. */
@ -300,8 +298,6 @@ clutter_stage_osx_realize (ClutterStageWindow *stage_window)
initWithView: self->view
UTF8Title: clutter_stage_get_title (CLUTTER_STAGE (self->wrapper))
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) */
[self->window center];
@ -422,9 +418,6 @@ clutter_stage_osx_resize (ClutterStageWindow *stage_window,
[self->window setContentSize: size];
CLUTTER_OSX_POOL_RELEASE ();
/* make sure that the viewport is updated */
CLUTTER_SET_PRIVATE_FLAGS (self->wrapper, CLUTTER_SYNC_MATRICES);
}
/*************************************************************************/

View file

@ -63,7 +63,6 @@ clutter_stage_win32_show (ClutterStageWindow *stage_window,
{
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));
}
}
@ -190,9 +189,6 @@ clutter_stage_win32_resize (ClutterStageWindow *stage_window,
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,
SWP_NOZORDER | SWP_NOMOVE);
}
CLUTTER_SET_PRIVATE_FLAGS (stage_win32->wrapper,
CLUTTER_SYNC_MATRICES);
}
/* Report the state change */

View file

@ -225,7 +225,6 @@ clutter_stage_x11_resize (ClutterStageWindow *stage_window,
ClutterBackend *backend = clutter_get_default_backend ();
ClutterBackendX11 *backend_x11;
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
ClutterStage *stage = stage_x11->wrapper;
gboolean resize;
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_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,
stage_x11->xwin,
width,
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_SET_PRIVATE_FLAGS (stage, CLUTTER_SYNC_MATRICES);
if (is_fullscreen)
{
int width, height;
@ -516,8 +501,10 @@ clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window,
}
}
clutter_stage_ensure_viewport (CLUTTER_STAGE (stage_x11->wrapper));
clutter_actor_queue_relayout (CLUTTER_ACTOR (stage_x11->wrapper));
/* XXX: Note we rely on the ConfigureNotify mechanism as the common
* 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
@ -706,7 +693,6 @@ clutter_stage_x11_init (ClutterStageX11 *stage)
stage->is_foreign_xwin = FALSE;
stage->fullscreening = FALSE;
stage->is_cursor_visible = TRUE;
stage->viewport_initialized = FALSE;
stage->title = NULL;
@ -949,7 +935,16 @@ clutter_x11_set_stage_foreign (ClutterStage *stage,
set_foreign_window_callback,
&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;
}

View file

@ -115,11 +115,6 @@ CLUTTER_ACTOR_ABOUT_TO_UNPARENT
actor is removed from the stage, so unrealize implementations
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:
Set internally by clutter_actor_paint()