302 lines
8.5 KiB
C
302 lines
8.5 KiB
C
#include "config.h"
|
|
|
|
#include "gskvulkanclipprivate.h"
|
|
|
|
#include "gskrectprivate.h"
|
|
#include "gskroundedrectprivate.h"
|
|
#include "gsktransform.h"
|
|
|
|
void
|
|
gsk_vulkan_clip_init_empty (GskVulkanClip *clip,
|
|
const graphene_rect_t *rect)
|
|
{
|
|
clip->type = GSK_VULKAN_CLIP_NONE;
|
|
gsk_rounded_rect_init_from_rect (&clip->rect, rect, 0);
|
|
}
|
|
|
|
void
|
|
gsk_vulkan_clip_init_rect (GskVulkanClip *clip,
|
|
const graphene_rect_t *rect)
|
|
{
|
|
clip->type = GSK_VULKAN_CLIP_RECT;
|
|
gsk_rounded_rect_init_from_rect (&clip->rect, rect, 0);
|
|
}
|
|
|
|
void
|
|
gsk_vulkan_clip_init_copy (GskVulkanClip *self,
|
|
const GskVulkanClip *src)
|
|
{
|
|
self->type = src->type;
|
|
gsk_rounded_rect_init_copy (&self->rect, &src->rect);
|
|
}
|
|
|
|
static gboolean
|
|
gsk_vulkan_clip_init_after_intersection (GskVulkanClip *self,
|
|
GskRoundedRectIntersection res)
|
|
{
|
|
if (res == GSK_INTERSECTION_NOT_REPRESENTABLE)
|
|
return FALSE;
|
|
|
|
if (res == GSK_INTERSECTION_EMPTY)
|
|
self->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
|
|
else if (gsk_rounded_rect_is_rectilinear (&self->rect))
|
|
self->type = GSK_VULKAN_CLIP_RECT;
|
|
else
|
|
self->type = GSK_VULKAN_CLIP_ROUNDED;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
gsk_vulkan_clip_intersect_rect (GskVulkanClip *dest,
|
|
const GskVulkanClip *src,
|
|
const graphene_rect_t *rect)
|
|
{
|
|
GskRoundedRectIntersection res;
|
|
|
|
if (graphene_rect_contains_rect (rect, &src->rect.bounds))
|
|
{
|
|
gsk_vulkan_clip_init_copy (dest, src);
|
|
return TRUE;
|
|
}
|
|
if (!gsk_rect_intersects (rect, &src->rect.bounds))
|
|
{
|
|
dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
|
|
return TRUE;
|
|
}
|
|
|
|
switch (src->type)
|
|
{
|
|
case GSK_VULKAN_CLIP_ALL_CLIPPED:
|
|
dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
|
|
break;
|
|
|
|
case GSK_VULKAN_CLIP_NONE:
|
|
gsk_vulkan_clip_init_copy (dest, src);
|
|
if (graphene_rect_intersection (&dest->rect.bounds, rect, &dest->rect.bounds))
|
|
dest->type = GSK_VULKAN_CLIP_RECT;
|
|
else
|
|
dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
|
|
break;
|
|
|
|
case GSK_VULKAN_CLIP_RECT:
|
|
gsk_vulkan_clip_init_copy (dest, src);
|
|
if (!graphene_rect_intersection (&dest->rect.bounds, rect, &dest->rect.bounds))
|
|
dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
|
|
break;
|
|
|
|
case GSK_VULKAN_CLIP_ROUNDED:
|
|
res = gsk_rounded_rect_intersect_with_rect (&src->rect, rect, &dest->rect);
|
|
if (!gsk_vulkan_clip_init_after_intersection (dest, res))
|
|
return FALSE;
|
|
break;
|
|
|
|
default:
|
|
g_assert_not_reached ();
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
gsk_vulkan_clip_intersect_rounded_rect (GskVulkanClip *dest,
|
|
const GskVulkanClip *src,
|
|
const GskRoundedRect *rounded)
|
|
{
|
|
GskRoundedRectIntersection res;
|
|
|
|
if (gsk_rounded_rect_contains_rect (rounded, &src->rect.bounds))
|
|
{
|
|
gsk_vulkan_clip_init_copy (dest, src);
|
|
return TRUE;
|
|
}
|
|
if (!gsk_rect_intersects (&rounded->bounds, &src->rect.bounds))
|
|
{
|
|
dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
|
|
return TRUE;
|
|
}
|
|
|
|
switch (src->type)
|
|
{
|
|
case GSK_VULKAN_CLIP_ALL_CLIPPED:
|
|
dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
|
|
break;
|
|
|
|
case GSK_VULKAN_CLIP_NONE:
|
|
dest->type = GSK_VULKAN_CLIP_ROUNDED;
|
|
gsk_rounded_rect_init_copy (&dest->rect, rounded);
|
|
break;
|
|
|
|
case GSK_VULKAN_CLIP_RECT:
|
|
res = gsk_rounded_rect_intersect_with_rect (rounded, &src->rect.bounds, &dest->rect);
|
|
if (!gsk_vulkan_clip_init_after_intersection (dest, res))
|
|
return FALSE;
|
|
break;
|
|
|
|
case GSK_VULKAN_CLIP_ROUNDED:
|
|
res = gsk_rounded_rect_intersection (&src->rect, rounded, &dest->rect);
|
|
if (!gsk_vulkan_clip_init_after_intersection (dest, res))
|
|
return FALSE;
|
|
break;
|
|
|
|
default:
|
|
g_assert_not_reached ();
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
gsk_vulkan_clip_scale (GskVulkanClip *dest,
|
|
const GskVulkanClip *src,
|
|
float scale_x,
|
|
float scale_y)
|
|
{
|
|
dest->type = src->type;
|
|
gsk_rounded_rect_scale_affine (&dest->rect,
|
|
&src->rect,
|
|
1.0f / scale_x, 1.0f / scale_y,
|
|
0, 0);
|
|
}
|
|
|
|
gboolean
|
|
gsk_vulkan_clip_transform (GskVulkanClip *dest,
|
|
const GskVulkanClip *src,
|
|
GskTransform *transform,
|
|
const graphene_rect_t *viewport)
|
|
{
|
|
switch (src->type)
|
|
{
|
|
default:
|
|
g_assert_not_reached();
|
|
return FALSE;
|
|
|
|
case GSK_VULKAN_CLIP_ALL_CLIPPED:
|
|
gsk_vulkan_clip_init_copy (dest, src);
|
|
return TRUE;
|
|
|
|
case GSK_VULKAN_CLIP_NONE:
|
|
gsk_vulkan_clip_init_empty (dest, viewport);
|
|
return TRUE;
|
|
|
|
case GSK_VULKAN_CLIP_RECT:
|
|
case GSK_VULKAN_CLIP_ROUNDED:
|
|
switch (gsk_transform_get_category (transform))
|
|
{
|
|
case GSK_TRANSFORM_CATEGORY_IDENTITY:
|
|
gsk_vulkan_clip_init_copy (dest, src);
|
|
return TRUE;
|
|
|
|
case GSK_TRANSFORM_CATEGORY_2D_TRANSLATE:
|
|
{
|
|
float dx, dy;
|
|
|
|
gsk_transform_to_translate (transform, &dx, &dy);
|
|
gsk_vulkan_clip_init_copy (dest, src);
|
|
dest->rect.bounds.origin.x -= dx;
|
|
dest->rect.bounds.origin.y -= dy;
|
|
}
|
|
return TRUE;
|
|
|
|
case GSK_TRANSFORM_CATEGORY_2D_AFFINE:
|
|
{
|
|
float dx, dy, scale_x, scale_y;
|
|
|
|
gsk_transform_to_affine (transform, &scale_x, &scale_y, &dx, &dy);
|
|
scale_x = 1. / scale_x;
|
|
scale_y = 1. / scale_y;
|
|
gsk_vulkan_clip_init_copy (dest, src);
|
|
dest->rect.bounds.origin.x = (dest->rect.bounds.origin.x - dx) * scale_x;
|
|
dest->rect.bounds.origin.y = (dest->rect.bounds.origin.y - dy) * scale_y;
|
|
dest->rect.bounds.size.width *= scale_x;
|
|
dest->rect.bounds.size.height *= scale_y;
|
|
if (src->type != GSK_VULKAN_CLIP_RECT)
|
|
{
|
|
dest->rect.corner[0].width *= scale_x;
|
|
dest->rect.corner[0].height *= scale_y;
|
|
dest->rect.corner[1].width *= scale_x;
|
|
dest->rect.corner[1].height *= scale_y;
|
|
dest->rect.corner[2].width *= scale_x;
|
|
dest->rect.corner[2].height *= scale_y;
|
|
dest->rect.corner[3].width *= scale_x;
|
|
dest->rect.corner[3].height *= scale_y;
|
|
}
|
|
}
|
|
return TRUE;
|
|
|
|
case GSK_TRANSFORM_CATEGORY_UNKNOWN:
|
|
case GSK_TRANSFORM_CATEGORY_ANY:
|
|
case GSK_TRANSFORM_CATEGORY_3D:
|
|
case GSK_TRANSFORM_CATEGORY_2D:
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
gboolean
|
|
gsk_vulkan_clip_may_intersect_rect (const GskVulkanClip *self,
|
|
const graphene_point_t *offset,
|
|
const graphene_rect_t *rect)
|
|
{
|
|
graphene_rect_t r = *rect;
|
|
r.origin.x += offset->x;
|
|
r.origin.y += offset->y;
|
|
|
|
switch (self->type)
|
|
{
|
|
default:
|
|
g_assert_not_reached();
|
|
case GSK_VULKAN_CLIP_ALL_CLIPPED:
|
|
return FALSE;
|
|
|
|
case GSK_VULKAN_CLIP_NONE:
|
|
case GSK_VULKAN_CLIP_RECT:
|
|
case GSK_VULKAN_CLIP_ROUNDED:
|
|
return gsk_rect_intersects (&self->rect.bounds, &r);
|
|
}
|
|
}
|
|
|
|
gboolean
|
|
gsk_vulkan_clip_contains_rect (const GskVulkanClip *self,
|
|
const graphene_point_t *offset,
|
|
const graphene_rect_t *rect)
|
|
{
|
|
graphene_rect_t r = *rect;
|
|
r.origin.x += offset->x;
|
|
r.origin.y += offset->y;
|
|
|
|
switch (self->type)
|
|
{
|
|
default:
|
|
g_assert_not_reached();
|
|
case GSK_VULKAN_CLIP_ALL_CLIPPED:
|
|
return FALSE;
|
|
|
|
case GSK_VULKAN_CLIP_NONE:
|
|
return TRUE;
|
|
|
|
case GSK_VULKAN_CLIP_RECT:
|
|
return graphene_rect_contains_rect (&self->rect.bounds, &r);
|
|
|
|
case GSK_VULKAN_CLIP_ROUNDED:
|
|
return gsk_rounded_rect_contains_rect (&self->rect, &r);
|
|
}
|
|
}
|
|
|
|
GskVulkanShaderClip
|
|
gsk_vulkan_clip_get_shader_clip (const GskVulkanClip *self,
|
|
const graphene_point_t *offset,
|
|
const graphene_rect_t *rect)
|
|
{
|
|
if (gsk_vulkan_clip_contains_rect (self, offset, rect))
|
|
return GSK_VULKAN_SHADER_CLIP_NONE;
|
|
else if (self->type == GSK_VULKAN_CLIP_RECT)
|
|
return GSK_VULKAN_SHADER_CLIP_RECT;
|
|
else
|
|
return GSK_VULKAN_SHADER_CLIP_ROUNDED;
|
|
}
|
|
|