mirror of
https://github.com/brl/mutter.git
synced 2024-11-21 23:50:41 -05:00
clutter/stage: Replace _cogl_util_get_eye_planes_for_screen_poly()
_cogl_util_get_eye_planes_for_screen_poly() is quite a complicated beast. Ever since Clutter became a compositor toolkit, and specially after we switched to graphene_frustum_t on paint volumes, we can brutally simplify this function. The new code assumes camera is at (0, 0, 0) at world coordinates (i.e. before applying the projection). We also consider that the redraw clip are at stage coordinates. That means that converting the clip rectangle to world rectangle is simply a matter of projecting the corresponding vertices using the "view" matrix. Furthermore, we only need to project the top-left, and bottom-right vertices, since top-right and bottom-left can be derived from those two. The frustum setup still uses triplets of vertices to setup the planes, except now the first vertex is always the camera (hardcoded to 0, 0, 0), and the other two vertices are the projected clip rectangle vertices. https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1489
This commit is contained in:
parent
f7d0461768
commit
bc41a88c92
@ -653,107 +653,58 @@ clutter_stage_allocate (ClutterActor *self,
|
||||
clutter_stage_set_viewport (CLUTTER_STAGE (self), new_width, new_height);
|
||||
}
|
||||
|
||||
typedef struct _Vector4
|
||||
{
|
||||
float x, y, z, w;
|
||||
} Vector4;
|
||||
|
||||
static void
|
||||
_cogl_util_get_eye_planes_for_screen_poly (float *polygon,
|
||||
int n_vertices,
|
||||
float *viewport,
|
||||
const graphene_matrix_t *projection,
|
||||
const graphene_matrix_t *inverse_project,
|
||||
const ClutterPerspective *perspective,
|
||||
setup_clip_frustum (ClutterStage *stage,
|
||||
const cairo_rectangle_int_t *clip,
|
||||
graphene_frustum_t *frustum)
|
||||
{
|
||||
ClutterStagePrivate *priv = stage->priv;
|
||||
cairo_rectangle_int_t geom;
|
||||
graphene_point3d_t camera_position;
|
||||
graphene_point3d_t p[4];
|
||||
graphene_plane_t planes[6];
|
||||
graphene_vec4_t v;
|
||||
float Wc;
|
||||
Vector4 *tmp_poly;
|
||||
int i;
|
||||
Vector4 *poly;
|
||||
float zw, ww;
|
||||
|
||||
tmp_poly = g_alloca (sizeof (Vector4) * n_vertices * 2);
|
||||
_clutter_stage_window_get_geometry (priv->impl, &geom);
|
||||
|
||||
#define DEPTH -50
|
||||
CLUTTER_NOTE (CLIPPING, "Creating stage clip frustum for "
|
||||
"x=%d, y=%d, width=%d, height=%d",
|
||||
clip->x, clip->y, clip->width, clip->height);
|
||||
|
||||
/* Determine W in clip-space (Wc) for a point (0, 0, DEPTH, 1)
|
||||
*
|
||||
* Note: the depth could be anything except 0.
|
||||
*
|
||||
* We will transform the polygon into clip coordinates using this
|
||||
* depth and then into eye coordinates. Our clip planes will be
|
||||
* defined by triangles that extend between points of the polygon at
|
||||
* DEPTH and corresponding points of the same polygon at DEPTH * 2.
|
||||
*
|
||||
* NB: Wc defines the position of the clip planes in clip
|
||||
* coordinates. Given a screen aligned cross section through the
|
||||
* frustum; coordinates range from [-Wc,Wc] left to right on the
|
||||
* x-axis and [Wc,-Wc] top to bottom on the y-axis.
|
||||
*/
|
||||
zw = graphene_matrix_get_value (projection, 2, 3);
|
||||
ww = graphene_matrix_get_value (projection, 3, 3);
|
||||
Wc = DEPTH * zw + ww;
|
||||
camera_position = GRAPHENE_POINT3D_INIT_ZERO;
|
||||
|
||||
#define CLIP_X(X) ((((float)X - viewport[0]) * (2.0 / viewport[2])) - 1) * Wc
|
||||
#define CLIP_Y(Y) ((((float)Y - viewport[1]) * (2.0 / viewport[3])) - 1) * -Wc
|
||||
p[0] = GRAPHENE_POINT3D_INIT (MAX (clip->x, 0), MAX (clip->y, 0), 0.f);
|
||||
p[2] = GRAPHENE_POINT3D_INIT (MIN (clip->x + clip->width, geom.width),
|
||||
MIN (clip->y + clip->height, geom.height),
|
||||
0.f);
|
||||
|
||||
for (i = 0; i < n_vertices; i++)
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
tmp_poly[i].x = CLIP_X (polygon[i * 2]);
|
||||
tmp_poly[i].y = CLIP_Y (polygon[i * 2 + 1]);
|
||||
tmp_poly[i].z = DEPTH;
|
||||
tmp_poly[i].w = Wc;
|
||||
float w = 1.0;
|
||||
cogl_graphene_matrix_project_point (&priv->view,
|
||||
&p[2 * i].x,
|
||||
&p[2 * i].y,
|
||||
&p[2 * i].z,
|
||||
&w);
|
||||
}
|
||||
|
||||
Wc = DEPTH * 2 * zw + ww;
|
||||
graphene_point3d_init (&p[1], p[2].x, p[0].y, p[0].z);
|
||||
graphene_point3d_init (&p[3], p[0].x, p[2].y, p[0].z);
|
||||
|
||||
/* FIXME: technically we don't need to project all of the points
|
||||
* twice, it would be enough project every other point since
|
||||
* we can share points in this set to define the plane vectors. */
|
||||
for (i = 0; i < n_vertices; i++)
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
tmp_poly[n_vertices + i].x = CLIP_X (polygon[i * 2]);
|
||||
tmp_poly[n_vertices + i].y = CLIP_Y (polygon[i * 2 + 1]);
|
||||
tmp_poly[n_vertices + i].z = DEPTH * 2;
|
||||
tmp_poly[n_vertices + i].w = Wc;
|
||||
graphene_plane_init_from_points (&planes[i],
|
||||
&camera_position,
|
||||
&p[i],
|
||||
&p[(i + 1) % 4]);
|
||||
}
|
||||
|
||||
#undef CLIP_X
|
||||
#undef CLIP_Y
|
||||
graphene_vec4_init (&v, 0.f, 0.f, -1.f, priv->perspective.z_near);
|
||||
graphene_plane_init_from_vec4 (&planes[4], &v);
|
||||
|
||||
cogl_graphene_matrix_project_points (inverse_project,
|
||||
4,
|
||||
sizeof (Vector4),
|
||||
tmp_poly,
|
||||
sizeof (Vector4),
|
||||
tmp_poly,
|
||||
n_vertices * 2);
|
||||
|
||||
for (i = 0; i < n_vertices; i++)
|
||||
{
|
||||
graphene_point3d_t p[3];
|
||||
|
||||
poly = &tmp_poly[i];
|
||||
graphene_point3d_init (&p[0], poly->x, poly->y, poly->z);
|
||||
|
||||
poly = &tmp_poly[n_vertices + i];
|
||||
graphene_point3d_init (&p[1], poly->x, poly->y, poly->z);
|
||||
|
||||
poly = &tmp_poly[n_vertices + ((i + 1) % n_vertices)];
|
||||
graphene_point3d_init (&p[2], poly->x, poly->y, poly->z);
|
||||
|
||||
graphene_plane_init_from_points (&planes[i], &p[0], &p[1], &p[2]);
|
||||
}
|
||||
|
||||
graphene_plane_init_from_vec4 (&planes[4],
|
||||
graphene_vec4_init (&v, 0.f, 0.f, -1.f,
|
||||
perspective->z_near));
|
||||
graphene_plane_init_from_vec4 (&planes[5],
|
||||
graphene_vec4_init (&v, 0.f, 0.f, 1.f,
|
||||
perspective->z_far));
|
||||
graphene_vec4_init (&v, 0.f, 0.f, 1.f, priv->perspective.z_far);
|
||||
graphene_plane_init_from_vec4 (&planes[5], &v);
|
||||
|
||||
graphene_frustum_init (frustum,
|
||||
&planes[0], &planes[1],
|
||||
@ -761,55 +712,6 @@ _cogl_util_get_eye_planes_for_screen_poly (float *polygon,
|
||||
&planes[4], &planes[5]);
|
||||
}
|
||||
|
||||
/* XXX: Instead of having a toplevel 2D clip region, it might be
|
||||
* better to have a clip volume within the view frustum. This could
|
||||
* allow us to avoid projecting actors into window coordinates to
|
||||
* be able to cull them.
|
||||
*/
|
||||
static void
|
||||
setup_view_for_paint (ClutterStage *stage,
|
||||
const cairo_rectangle_int_t *clip,
|
||||
graphene_frustum_t *out_frustum)
|
||||
{
|
||||
ClutterStagePrivate *priv = stage->priv;
|
||||
float clip_poly[8];
|
||||
float viewport[4];
|
||||
cairo_rectangle_int_t geom;
|
||||
|
||||
_clutter_stage_window_get_geometry (priv->impl, &geom);
|
||||
|
||||
viewport[0] = priv->viewport[0];
|
||||
viewport[1] = priv->viewport[1];
|
||||
viewport[2] = priv->viewport[2];
|
||||
viewport[3] = priv->viewport[3];
|
||||
|
||||
clip_poly[0] = MAX (clip->x, 0);
|
||||
clip_poly[1] = MAX (clip->y, 0);
|
||||
|
||||
clip_poly[2] = MIN (clip->x + clip->width, geom.width);
|
||||
clip_poly[3] = clip_poly[1];
|
||||
|
||||
clip_poly[4] = clip_poly[2];
|
||||
clip_poly[5] = MIN (clip->y + clip->height, geom.height);
|
||||
|
||||
clip_poly[6] = clip_poly[0];
|
||||
clip_poly[7] = clip_poly[5];
|
||||
|
||||
CLUTTER_NOTE (CLIPPING, "Setting stage clip too: "
|
||||
"x=%f, y=%f, width=%f, height=%f",
|
||||
clip_poly[0], clip_poly[1],
|
||||
clip_poly[2] - clip_poly[0],
|
||||
clip_poly[5] - clip_poly[1]);
|
||||
|
||||
_cogl_util_get_eye_planes_for_screen_poly (clip_poly,
|
||||
4,
|
||||
viewport,
|
||||
&priv->projection,
|
||||
&priv->inverse_projection,
|
||||
&priv->perspective,
|
||||
out_frustum);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_do_paint_view (ClutterStage *stage,
|
||||
ClutterStageView *view,
|
||||
@ -840,7 +742,7 @@ clutter_stage_do_paint_view (ClutterStage *stage,
|
||||
for (i = 0; i < n_rectangles; i++)
|
||||
{
|
||||
cairo_region_get_rectangle (redraw_clip, i, &clip_rect);
|
||||
setup_view_for_paint (stage, &clip_rect, &clip_frustum);
|
||||
setup_clip_frustum (stage, &clip_rect, &clip_frustum);
|
||||
g_array_append_val (clip_frusta, clip_frustum);
|
||||
}
|
||||
}
|
||||
@ -854,7 +756,7 @@ clutter_stage_do_paint_view (ClutterStage *stage,
|
||||
else
|
||||
clutter_stage_view_get_layout (view, &clip_rect);
|
||||
|
||||
setup_view_for_paint (stage, &clip_rect, &clip_frustum);
|
||||
setup_clip_frustum (stage, &clip_rect, &clip_frustum);
|
||||
g_array_append_val (clip_frusta, clip_frustum);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user