mirror of
https://github.com/brl/mutter.git
synced 2024-11-26 18:11:05 -05:00
2007-12-05 Tomas Frydrych <tf@openedhand.com>
* clutter/clutter-actor.c: * clutter/clutter-actor.h: * tests/Makefile.am: * tests/test-unproject: (clutter_actor_transform_stage_point): Added new function for translating stage coordinates into local actor coordinates.
This commit is contained in:
parent
dabe850551
commit
e9d9715dcf
12
ChangeLog
12
ChangeLog
@ -1,3 +1,13 @@
|
||||
2007-12-05 Tomas Frydrych <tf@openedhand.com>
|
||||
|
||||
* clutter/clutter-actor.c:
|
||||
* clutter/clutter-actor.h:
|
||||
* tests/Makefile.am:
|
||||
* tests/test-unproject:
|
||||
(clutter_actor_transform_stage_point):
|
||||
Added new function for translating stage coordinates into local
|
||||
actor coordinates.
|
||||
|
||||
2007-12-04 Emmanuele Bassi <ebassi@openedhand.com>
|
||||
|
||||
* clutter/clutter-score.c: Better document ClutterScore
|
||||
@ -39,7 +49,7 @@
|
||||
(clutter_stage_glx_unrealize): unbind all shaders on stage unrealize.
|
||||
|
||||
* clutter/Makefile.am: added clutter-shader.[ch]
|
||||
* clutter/clutter-actor.[ch]: adding shader capability to
|
||||
* clutter/clutter-actor.[ch]: adding shader capability to
|
||||
actors.
|
||||
* clutter/clutter-feature.h: added CLUTTER_FEATURE_SHADERS_GLSL
|
||||
* clutter/clutter-private.h: added stack of shaders to context.
|
||||
|
@ -928,8 +928,6 @@ clutter_actor_paint (ClutterActor *self)
|
||||
cogl_pop_matrix();
|
||||
}
|
||||
|
||||
#undef M
|
||||
|
||||
static void
|
||||
clutter_actor_real_request_coords (ClutterActor *self,
|
||||
ClutterActorBox *box)
|
||||
@ -3870,7 +3868,7 @@ parse_units (ClutterActor *self,
|
||||
else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
|
||||
{
|
||||
gint val;
|
||||
|
||||
|
||||
if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL)
|
||||
{
|
||||
g_warning ("Unable to set percentage of %s on a top-level "
|
||||
@ -3948,6 +3946,191 @@ clutter_scriptable_iface_init (ClutterScriptableIface *iface)
|
||||
iface->parse_custom_node = clutter_actor_parse_custom_node;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_actor_transform_stage_point
|
||||
* @self: A #ClutterActor
|
||||
* @x: x screen coordiance of point to unproject, in #ClutterUnit
|
||||
* @y: y screen coordiance of point to unproject, in #ClutterUnit
|
||||
* @x: x_out location where to store the unprojected x coordinance, in
|
||||
* #ClutterUnit.
|
||||
* @y: y_out location where to store the unprojected y coordinance, in
|
||||
* #ClutterUnit.
|
||||
*
|
||||
* Return value: TRUE if conversion was successful.
|
||||
*
|
||||
* The function translates point with screen coordinates x,y to coordinates
|
||||
* relative to the actor, i.e., it can be used, to translate screen events
|
||||
* from global screen coordinates into local coordinates.
|
||||
*
|
||||
* The conversion can fail, notably if the transform stack results in the
|
||||
* actor being projected on the screen as a mere line.
|
||||
*
|
||||
* The conversion should not be expected to be pixel-perfect due to the nature
|
||||
* of the operation. In general the error grows when the skewing of the actor
|
||||
* rectangle on screen increases.
|
||||
*
|
||||
* WARNING: This function is fairly computationally intensive.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
gboolean
|
||||
clutter_actor_transform_stage_point (ClutterActor *self,
|
||||
ClutterUnit x,
|
||||
ClutterUnit y,
|
||||
ClutterUnit *x_out,
|
||||
ClutterUnit *y_out)
|
||||
{
|
||||
ClutterVertex v[4];
|
||||
ClutterFixed ST[3][3];
|
||||
ClutterFixed RQ[3][3];
|
||||
int du, dv, xi, yi;
|
||||
ClutterFixed xf, yf, wf, px, py, det;
|
||||
ClutterActorPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
|
||||
|
||||
priv = self->priv;
|
||||
|
||||
/*
|
||||
* This implementation is based on the quad -> quad projection algorithm
|
||||
* described by Paul Heckbert in
|
||||
*
|
||||
* http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
|
||||
*
|
||||
* and the sample implementaion at http://www.cs.cmu.edu/~ph/src/texfund/.
|
||||
*
|
||||
* Our texture is a rectangle with origin [0,0], so we are mapping from quad
|
||||
* to rectangle only, which significantly simplifies things; the function
|
||||
* calls have been unrolled, and most of the math is done in fixed point.
|
||||
*/
|
||||
|
||||
clutter_actor_get_vertices (self, v);
|
||||
|
||||
/*
|
||||
* Keeping these as ints simplifies the multiplication (no significant loss
|
||||
* of precission here).
|
||||
*/
|
||||
du = CLUTTER_UNITS_TO_DEVICE (priv->coords.x2 - priv->coords.x1);
|
||||
dv = CLUTTER_UNITS_TO_DEVICE (priv->coords.y2 - priv->coords.y1);
|
||||
|
||||
if (!du || !dv)
|
||||
return FALSE;
|
||||
|
||||
#define FP2FX CLUTTER_FLOAT_TO_FIXED
|
||||
#define FX2FP CLUTTER_FIXED_TO_DOUBLE
|
||||
#define FP2INT CLUTTER_FLOAT_TO_INT
|
||||
#define DET2X(a,b, c,d) (CFX_QMUL(a,d) - CFX_QMUL(b,c))
|
||||
|
||||
/*
|
||||
* First, find mapping from unit uv square to xy quadrilateral; this
|
||||
* equivalent to the pmap_square_quad() functions in the sample
|
||||
* implementation, which we can simplify, since our target is always
|
||||
* a rectangle.
|
||||
*/
|
||||
px = v[0].x - v[1].x + v[3].x - v[2].x;
|
||||
py = v[0].y - v[1].y + v[3].y - v[2].y;
|
||||
|
||||
if (!px && !py)
|
||||
{ /* affine transform */
|
||||
RQ[0][0] = v[1].x - v[0].x;
|
||||
RQ[1][0] = v[3].x - v[1].x;
|
||||
RQ[2][0] = v[0].x;
|
||||
RQ[0][1] = v[1].y - v[0].y;
|
||||
RQ[1][1] = v[3].y - v[1].y;
|
||||
RQ[2][1] = v[0].y;
|
||||
RQ[0][2] = 0;
|
||||
RQ[1][2] = 0;
|
||||
RQ[2][2] = CFX_ONE;
|
||||
}
|
||||
else
|
||||
{ /* projective transform */
|
||||
ClutterFixed dx1, dx2, dy1, dy2, del;
|
||||
|
||||
dx1 = v[1].x - v[3].x;
|
||||
dx2 = v[2].x - v[3].x;
|
||||
dy1 = v[1].y - v[3].y;
|
||||
dy2 = v[2].y - v[3].y;
|
||||
|
||||
del = DET2X (dx1,dx2, dy1,dy2);
|
||||
|
||||
if (!del)
|
||||
return FALSE;
|
||||
|
||||
/*
|
||||
* The division here needs to be done in floating point for
|
||||
* precisions reasons.
|
||||
*/
|
||||
RQ[0][2] = FP2FX (FX2FP (DET2X (px,dx2, py,dy2) / FX2FP (del)));
|
||||
RQ[1][2] = FP2FX (FX2FP (DET2X (dx1,px, dy1,py) / FX2FP (del)));
|
||||
RQ[1][2] = CFX_DIV (DET2X(dx1,px, dy1,py), del);
|
||||
RQ[2][2] = CFX_ONE;
|
||||
RQ[0][0] = v[1].x - v[0].x + CFX_QMUL (RQ[0][2], v[1].x);
|
||||
RQ[1][0] = v[2].x - v[0].x + CFX_QMUL (RQ[1][2], v[2].x);
|
||||
RQ[2][0] = v[0].x;
|
||||
RQ[0][1] = v[1].y - v[0].y + CFX_QMUL (RQ[0][2], v[1].y);
|
||||
RQ[1][1] = v[2].y - v[0].y + CFX_QMUL (RQ[1][2], v[2].y);
|
||||
RQ[2][1] = v[0].y;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
|
||||
* square. Since our rectangle is based at 0,0 we only need to scale.
|
||||
*/
|
||||
RQ[0][0] /= du;
|
||||
RQ[1][0] /= dv;
|
||||
RQ[0][1] /= du;
|
||||
RQ[1][1] /= dv;
|
||||
RQ[0][2] /= du;
|
||||
RQ[1][2] /= dv;
|
||||
|
||||
/*
|
||||
* Now RQ is transform from uv rectangle to xy quadrilateral; we need an
|
||||
* inverse of that.
|
||||
*/
|
||||
ST[0][0] = DET2X(RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
|
||||
ST[1][0] = DET2X(RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
|
||||
ST[2][0] = DET2X(RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
|
||||
ST[0][1] = DET2X(RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
|
||||
ST[1][1] = DET2X(RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
|
||||
ST[2][1] = DET2X(RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
|
||||
ST[0][2] = DET2X(RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
|
||||
ST[1][2] = DET2X(RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
|
||||
ST[2][2] = DET2X(RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
|
||||
|
||||
/*
|
||||
* Check the resutling martix is OK.
|
||||
*/
|
||||
det = CFX_QMUL (RQ[0][0], ST[0][0]) + CFX_QMUL (RQ[0][1], ST[0][1]) +
|
||||
CFX_QMUL (RQ[0][2], ST[0][2]);
|
||||
|
||||
if (!det)
|
||||
return FALSE;
|
||||
|
||||
/*
|
||||
* Now transform our point with the ST matrix; the notional w coordiance
|
||||
* is 1, hence the last part is simply added.
|
||||
*/
|
||||
xi = CLUTTER_UNITS_TO_DEVICE (x);
|
||||
yi = CLUTTER_UNITS_TO_DEVICE (y);
|
||||
|
||||
xf = xi*ST[0][0] + yi*ST[1][0] + ST[2][0];
|
||||
yf = xi*ST[0][1] + yi*ST[1][1] + ST[2][1];
|
||||
wf = xi*ST[0][2] + yi*ST[1][2] + ST[2][2];
|
||||
|
||||
/*
|
||||
* The division needs to be done in floating point for precission reasons.
|
||||
*/
|
||||
*x_out = CLUTTER_UNITS_FROM_FLOAT (FX2FP (xf) / FX2FP (wf));
|
||||
*y_out = CLUTTER_UNITS_FROM_FLOAT (FX2FP (yf) / FX2FP (wf));
|
||||
|
||||
#undef FP2FX
|
||||
#undef FX2FP
|
||||
#undef FP2INT
|
||||
#undef DET2X
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* ClutterGeometry
|
||||
*/
|
||||
@ -4097,7 +4280,7 @@ gboolean clutter_actor_apply_shader (ClutterActor *self,
|
||||
ShaderData *shader_data;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
|
||||
|
||||
|
||||
actor_priv = self->priv;
|
||||
shader_data = actor_priv->shader_data;
|
||||
|
||||
@ -4143,7 +4326,7 @@ clutter_actor_shader_pre_paint (ClutterActor *actor,
|
||||
ClutterMainContext *context;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
|
||||
|
||||
|
||||
actor_priv = actor->priv;
|
||||
shader_data = actor_priv->shader_data;
|
||||
|
||||
@ -4175,7 +4358,7 @@ clutter_actor_shader_post_paint (ClutterActor *actor)
|
||||
ClutterMainContext *context;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
|
||||
|
||||
|
||||
actor_priv = actor->priv;
|
||||
shader_data = actor_priv->shader_data;
|
||||
|
||||
@ -4211,7 +4394,7 @@ clutter_actor_set_shader_param (ClutterActor *actor,
|
||||
BoxedFloat *box;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
|
||||
|
||||
|
||||
actor_priv = actor->priv;
|
||||
shader_data = actor_priv->shader_data;
|
||||
|
||||
@ -4222,3 +4405,5 @@ clutter_actor_set_shader_param (ClutterActor *actor,
|
||||
box->value = value;
|
||||
g_hash_table_insert (shader_data->float1f_hash, g_strdup (param), box);
|
||||
}
|
||||
|
||||
#undef M
|
||||
|
@ -415,6 +415,12 @@ void clutter_actor_get_anchor_pointu (ClutterActor *se
|
||||
void clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
|
||||
ClutterGravity gravity);
|
||||
|
||||
gboolean clutter_actor_transform_stage_point (ClutterActor *self,
|
||||
ClutterUnit x,
|
||||
ClutterUnit y,
|
||||
ClutterUnit *x_out,
|
||||
ClutterUnit *y_out);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* _HAVE_CLUTTER_ACTOR_H */
|
||||
|
@ -2,12 +2,13 @@ noinst_PROGRAMS = test-textures test-events test-offscreen test-scale \
|
||||
test-actors test-behave test-text test-entry test-project \
|
||||
test-perspective test-rotate test-depth \
|
||||
test-threads test-timeline test-score test-script \
|
||||
test-model test-grab test-effects test-fullscreen test-shader
|
||||
test-model test-grab test-effects test-fullscreen \
|
||||
test-shader test-unproject
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/
|
||||
LDADD = $(top_builddir)/clutter/libclutter-@CLUTTER_FLAVOUR@-@CLUTTER_MAJORMINOR@.la
|
||||
AM_CFLAGS = $(CLUTTER_CFLAGS)
|
||||
AM_LDFLAGS = $(CLUTTER_LIBS)
|
||||
AM_LDFLAGS = $(CLUTTER_LIBS)
|
||||
|
||||
test_textures_SOURCES = test-textures.c
|
||||
test_events_SOURCES = test-events.c
|
||||
@ -15,10 +16,11 @@ test_offscreen_SOURCES = test-offscreen.c
|
||||
test_scale_SOURCES = test-scale.c
|
||||
test_actors_SOURCES = test-actors.c
|
||||
test_grab_SOURCES = test-grab.c
|
||||
test_behave_SOURCES = test-behave.c
|
||||
test_text_SOURCES = test-text.c
|
||||
test_behave_SOURCES = test-behave.c
|
||||
test_text_SOURCES = test-text.c
|
||||
test_entry_SOURCES = test-entry.c
|
||||
test_project_SOURCES = test-project.c
|
||||
test_unproject_SOURCES = test-unproject.c
|
||||
test_perspective_SOURCES = test-perspective.c
|
||||
test_rotate_SOURCES = test-rotate.c
|
||||
test_depth_SOURCES = test-depth.c
|
||||
|
147
tests/test-unproject.c
Normal file
147
tests/test-unproject.c
Normal file
@ -0,0 +1,147 @@
|
||||
#include <clutter/clutter.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
ClutterActor *label;
|
||||
|
||||
#define RECT_L 200
|
||||
#define RECT_T 150
|
||||
#define RECT_W 320
|
||||
#define RECT_H 240
|
||||
|
||||
void
|
||||
on_event (ClutterStage *stage,
|
||||
ClutterEvent *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
static ClutterActor * dragging = NULL;
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case CLUTTER_BUTTON_PRESS:
|
||||
{
|
||||
gint x, y;
|
||||
ClutterActor * actor;
|
||||
ClutterUnit xu2, yu2;
|
||||
|
||||
clutter_event_get_coords (event, &x, &y);
|
||||
|
||||
actor = clutter_stage_get_actor_at_pos (stage, x, y);
|
||||
|
||||
|
||||
if (clutter_actor_transform_stage_point (actor,
|
||||
CLUTTER_UNITS_FROM_DEVICE (x),
|
||||
CLUTTER_UNITS_FROM_DEVICE (y),
|
||||
&xu2, &yu2))
|
||||
{
|
||||
gchar *txt;
|
||||
|
||||
if (actor != stage)
|
||||
txt = g_strdup_printf ("Click on rectangle\n"
|
||||
"Screen coords: [%d, %d]\n"
|
||||
"Local coords : [%d, %d]",
|
||||
x, y,
|
||||
CLUTTER_UNITS_TO_DEVICE (xu2),
|
||||
CLUTTER_UNITS_TO_DEVICE (yu2));
|
||||
else
|
||||
txt = g_strdup_printf ("Click on stage\n"
|
||||
"Screen coords: [%d, %d]\n"
|
||||
"Local coords : [%d, %d]",
|
||||
x, y,
|
||||
CLUTTER_UNITS_TO_DEVICE (xu2),
|
||||
CLUTTER_UNITS_TO_DEVICE (yu2));
|
||||
|
||||
clutter_label_set_text (CLUTTER_LABEL (label), txt);
|
||||
g_free (txt);
|
||||
}
|
||||
else
|
||||
clutter_label_set_text (CLUTTER_LABEL (label),
|
||||
"Unprojection failed.");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
gchar *txt;
|
||||
ClutterActor *rect, *stage, *label0;
|
||||
int i, rotate_x = 0, rotate_y = 60, rotate_z = 0;
|
||||
ClutterColor stage_clr = { 0x0, 0x0, 0x0, 0xff },
|
||||
white = { 0xff, 0xff, 0xff, 0xff },
|
||||
blue = { 0, 0xff, 0xff, 0xff };
|
||||
|
||||
for (i = 0; i < argc; ++i)
|
||||
{
|
||||
if (!strncmp (argv[i], "--rotate-x", 10))
|
||||
{
|
||||
rotate_x = atoi (argv[i] + 11);
|
||||
}
|
||||
else if (!strncmp (argv[i], "--rotate-y", 10))
|
||||
{
|
||||
rotate_y = atoi (argv[i] + 11);
|
||||
}
|
||||
else if (!strncmp (argv[i], "--rotate-z", 10))
|
||||
{
|
||||
rotate_z = atoi (argv[i] + 11);
|
||||
}
|
||||
else if (!strncmp (argv[i], "--help", 6))
|
||||
{
|
||||
printf ("%s [--rotage-x=degrees] [--rotage-y=degrees] "
|
||||
"[--rotage-z=degrees]\n",
|
||||
argv[0]);
|
||||
|
||||
exit (0);
|
||||
}
|
||||
}
|
||||
|
||||
clutter_init (&argc, &argv);
|
||||
|
||||
stage = clutter_stage_get_default ();
|
||||
|
||||
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_clr);
|
||||
clutter_actor_set_size (stage, 640, 480);
|
||||
|
||||
rect = clutter_rectangle_new_with_color (&white);
|
||||
clutter_actor_set_size (rect, RECT_W, RECT_H);
|
||||
clutter_actor_set_position (rect, RECT_L, RECT_T);
|
||||
clutter_actor_set_rotation (rect, CLUTTER_X_AXIS, rotate_x, 0, 0, 0);
|
||||
clutter_actor_set_rotation (rect, CLUTTER_Y_AXIS, rotate_y, 0, 0, 0);
|
||||
clutter_actor_set_rotation (rect, CLUTTER_Z_AXIS, rotate_z, 0, 0, 0);
|
||||
clutter_group_add (CLUTTER_GROUP (stage), rect);
|
||||
|
||||
txt = g_strdup_printf ("Rectangle: L %d, R %d, T %d, B %d\n"
|
||||
"Rotation : x %d, y %d, z %d",
|
||||
RECT_L, RECT_L + RECT_W,
|
||||
RECT_T, RECT_T + RECT_H,
|
||||
rotate_x, rotate_y, rotate_z);
|
||||
|
||||
label0 = clutter_label_new_with_text ("Mono 8pt", txt);
|
||||
clutter_label_set_color (CLUTTER_LABEL (label0), &white);
|
||||
|
||||
clutter_actor_set_position (label0, 10, 10);
|
||||
clutter_group_add (CLUTTER_GROUP (stage), label0);
|
||||
|
||||
g_free (txt);
|
||||
|
||||
label =
|
||||
clutter_label_new_with_text ("Mono 8pt", "Click around!");
|
||||
|
||||
clutter_label_set_color (CLUTTER_LABEL (label), &blue);
|
||||
|
||||
clutter_actor_set_position (label, 10, 50);
|
||||
clutter_group_add (CLUTTER_GROUP (stage), label);
|
||||
|
||||
clutter_actor_show_all (stage);
|
||||
|
||||
g_signal_connect (stage, "event", G_CALLBACK (on_event), NULL);
|
||||
|
||||
clutter_main();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Loading…
Reference in New Issue
Block a user