/* Try to push a rectangle given in object coordinates as a rectangle in window * coordinates instead of object coordinates */ gboolean try_pushing_rect_as_window_rect (float x_1, float y_1, float x_2, float y_2) { CoglMatrix matrix; CoglMatrix matrix_p; float v[4]; cogl_get_modelview_matrix (&matrix); /* If the modelview meets these constraints then a transformed rectangle * should still be a rectangle when it reaches screen coordinates. * * FIXME: we are are making certain assumptions about the projection * matrix a.t.m and should really be looking at the combined modelview * and projection matrix. * FIXME: we don't consider rotations that are a multiple of 90 degrees * which could be quite common. */ if (matrix.xy != 0 || matrix.xz != 0 || matrix.yx != 0 || matrix.yz != 0 || matrix.zx != 0 || matrix.zy != 0) return FALSE; cogl_get_projection_matrix (&matrix_p); cogl_get_viewport (v); transform_point (&matrix, &matrix_p, v, &x_1, &y_1); transform_point (&matrix, &matrix_p, v, &x_2, &y_2); /* Consider that the modelview matrix may flip the rectangle * along the x or y axis... */ #define SWAP(A,B) do { float tmp = B; B = A; A = tmp; } while (0) if (x_1 > x_2) SWAP (x_1, x_2); if (y_1 > y_2) SWAP (y_1, y_2); #undef SWAP cogl_clip_push_window_rectangle (COGL_UTIL_NEARBYINT (x_1), COGL_UTIL_NEARBYINT (y_1), COGL_UTIL_NEARBYINT (x_2 - x_1), COGL_UTIL_NEARBYINT (y_2 - y_1)); return TRUE; }
CoglClipStack * _cogl_clip_stack_push_rectangle (CoglClipStack *stack, float x_1, float y_1, float x_2, float y_2, CoglMatrixEntry *modelview_entry, CoglMatrixEntry *projection_entry, const float *viewport) { CoglClipStackRect *entry; CoglMatrix modelview; CoglMatrix projection; CoglMatrix modelview_projection; /* Corners of the given rectangle in an clockwise order: * (0, 1) (2, 3) * * * * (6, 7) (4, 5) */ float rect[] = { x_1, y_1, x_2, y_1, x_2, y_2, x_1, y_2 }; /* Make a new entry */ entry = _cogl_clip_stack_push_entry (stack, sizeof (CoglClipStackRect), COGL_CLIP_STACK_RECT); entry->x0 = x_1; entry->y0 = y_1; entry->x1 = x_2; entry->y1 = y_2; entry->matrix_entry = cogl_matrix_entry_ref (modelview_entry); cogl_matrix_entry_get (modelview_entry, &modelview); cogl_matrix_entry_get (projection_entry, &projection); cogl_matrix_multiply (&modelview_projection, &projection, &modelview); /* Technically we could avoid the viewport transform at this point * if we want to make this a bit faster. */ _cogl_transform_point (&modelview, &projection, viewport, &rect[0], &rect[1]); _cogl_transform_point (&modelview, &projection, viewport, &rect[2], &rect[3]); _cogl_transform_point (&modelview, &projection, viewport, &rect[4], &rect[5]); _cogl_transform_point (&modelview, &projection, viewport, &rect[6], &rect[7]); /* If the fully transformed rectangle isn't still axis aligned we * can't handle it using a scissor. * * We don't use an epsilon here since we only really aim to catch * simple cases where the transform doesn't leave the rectangle screen * aligned and don't mind some false positives. */ if (rect[0] != rect[6] || rect[1] != rect[3] || rect[2] != rect[4] || rect[7] != rect[5]) { entry->can_be_scissor = FALSE; _cogl_clip_stack_entry_set_bounds ((CoglClipStack *) entry, rect); } else { CoglClipStack *base_entry = (CoglClipStack *) entry; x_1 = rect[0]; y_1 = rect[1]; x_2 = rect[4]; y_2 = rect[5]; /* Consider that the modelview matrix may flip the rectangle * along the x or y axis... */ #define SWAP(A,B) do { float tmp = B; B = A; A = tmp; } while (0) if (x_1 > x_2) SWAP (x_1, x_2); if (y_1 > y_2) SWAP (y_1, y_2); #undef SWAP base_entry->bounds_x0 = COGL_UTIL_NEARBYINT (x_1); base_entry->bounds_y0 = COGL_UTIL_NEARBYINT (y_1); base_entry->bounds_x1 = COGL_UTIL_NEARBYINT (x_2); base_entry->bounds_y1 = COGL_UTIL_NEARBYINT (y_2); entry->can_be_scissor = TRUE; } return (CoglClipStack *) entry; }