mutter/clutter/clutter/clutter-pick-context.c
Georges Basile Stavracas Neto 6c4b897d74 clutter/actor: Cull out when picking
Testing points and rays against boxes is substantially cheaper - in
fact, almost trivial - compared to triangles. Check if the actor's
paint volume doesn't intersect with the current pick point / ray,
and skip recursing altogether in those cases.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1520>
2020-11-25 16:34:29 +00:00

200 lines
5.7 KiB
C

/*
* Copyright (C) 2019 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "clutter-build-config.h"
#include "clutter-backend.h"
#include "clutter-pick-context-private.h"
struct _ClutterPickContext
{
grefcount ref_count;
ClutterPickMode mode;
ClutterPickStack *pick_stack;
graphene_ray_t ray;
graphene_point3d_t point;
};
G_DEFINE_BOXED_TYPE (ClutterPickContext, clutter_pick_context,
clutter_pick_context_ref,
clutter_pick_context_unref)
ClutterPickContext *
clutter_pick_context_new_for_view (ClutterStageView *view,
ClutterPickMode mode,
const graphene_point3d_t *point,
const graphene_ray_t *ray)
{
ClutterPickContext *pick_context;
CoglContext *context;
pick_context = g_new0 (ClutterPickContext, 1);
g_ref_count_init (&pick_context->ref_count);
pick_context->mode = mode;
graphene_ray_init_from_ray (&pick_context->ray, ray);
graphene_point3d_init_from_point (&pick_context->point, point);
context = clutter_backend_get_cogl_context (clutter_get_default_backend ());
pick_context->pick_stack = clutter_pick_stack_new (context);
return pick_context;
}
ClutterPickContext *
clutter_pick_context_ref (ClutterPickContext *pick_context)
{
g_ref_count_inc (&pick_context->ref_count);
return pick_context;
}
static void
clutter_pick_context_dispose (ClutterPickContext *pick_context)
{
g_clear_pointer (&pick_context->pick_stack, clutter_pick_stack_unref);
}
void
clutter_pick_context_unref (ClutterPickContext *pick_context)
{
if (g_ref_count_dec (&pick_context->ref_count))
{
clutter_pick_context_dispose (pick_context);
g_free (pick_context);
}
}
void
clutter_pick_context_destroy (ClutterPickContext *pick_context)
{
clutter_pick_context_dispose (pick_context);
clutter_pick_context_unref (pick_context);
}
/**
* clutter_pick_context_get_mode: (skip)
*/
ClutterPickMode
clutter_pick_context_get_mode (ClutterPickContext *pick_context)
{
return pick_context->mode;
}
ClutterPickStack *
clutter_pick_context_steal_stack (ClutterPickContext *pick_context)
{
clutter_pick_stack_seal (pick_context->pick_stack);
return g_steal_pointer (&pick_context->pick_stack);
}
/**
* clutter_pick_context_log_pick:
* @pick_context: a #ClutterPickContext
* @box: a #ClutterActorBox
* @actor: a #ClutterActor
*
* Logs a pick rectangle into the pick stack.
*/
void
clutter_pick_context_log_pick (ClutterPickContext *pick_context,
const ClutterActorBox *box,
ClutterActor *actor)
{
clutter_pick_stack_log_pick (pick_context->pick_stack, box, actor);
}
/**
* clutter_pick_context_push_clip:
* @pick_context: a #ClutterPickContext
* @box: a #ClutterActorBox
*
* Pushes a clip rectangle defined by @box into the pick stack. Pop with
* clutter_pick_context_pop_clip() when done.
*/
void
clutter_pick_context_push_clip (ClutterPickContext *pick_context,
const ClutterActorBox *box)
{
clutter_pick_stack_push_clip (pick_context->pick_stack, box);
}
/**
* clutter_pick_context_pop_clip:
* @pick_context: a #ClutterPickContext
*
* Pops the current clip rectangle from the clip stack. It is a programming
* error to call this without a corresponding clutter_pick_context_push_clip()
* call first.
*/
void
clutter_pick_context_pop_clip (ClutterPickContext *pick_context)
{
clutter_pick_stack_pop_clip (pick_context->pick_stack);
}
/**
* clutter_pick_context_push_transform:
* @pick_context: a #ClutterPickContext
* @transform: a #graphene_matrix_t
*
* Pushes @transform into the pick stack. Pop with
* clutter_pick_context_pop_transform() when done.
*/
void
clutter_pick_context_push_transform (ClutterPickContext *pick_context,
const graphene_matrix_t *transform)
{
clutter_pick_stack_push_transform (pick_context->pick_stack, transform);
}
/**
* clutter_pick_context_get_transform:
* @pick_context: a #ClutterPickContext
* @out_matrix: (out): a #graphene_matrix_t
*
* Retrieves the current transform of the pick stack.
*/
void
clutter_pick_context_get_transform (ClutterPickContext *pick_context,
graphene_matrix_t *out_transform)
{
clutter_pick_stack_get_transform (pick_context->pick_stack, out_transform);
}
/**
* clutter_pick_context_pop_transform:
* @pick_context: a #ClutterPickContext
*
* Pops the current transform from the clip stack. It is a programming error
* to call this without a corresponding clutter_pick_context_push_transform()
* call first.
*/
void
clutter_pick_context_pop_transform (ClutterPickContext *pick_context)
{
clutter_pick_stack_pop_transform (pick_context->pick_stack);
}
gboolean
clutter_pick_context_intersects_box (ClutterPickContext *pick_context,
const graphene_box_t *box)
{
return graphene_box_contains_point (box, &pick_context->point) ||
graphene_ray_intersects_box (&pick_context->ray, box);
}