6c4b897d74
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>
200 lines
5.7 KiB
C
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);
|
|
}
|