Merge remote-tracking branch 'pq/transform-v1'
This commit is contained in:
commit
b7674a2a6c
@ -1 +1 @@
|
||||
SUBDIRS = shared src clients data protocol
|
||||
SUBDIRS = shared src clients data protocol tests
|
||||
|
6
clients/.gitignore
vendored
6
clients/.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
clickdot
|
||||
desktop-shell-client-protocol.h
|
||||
desktop-shell-protocol.c
|
||||
dnd
|
||||
@ -12,11 +13,12 @@ screenshooter-protocol.c
|
||||
screenshot
|
||||
simple-egl
|
||||
simple-shm
|
||||
simple-touch
|
||||
smoke
|
||||
tablet-shell-client-protocol.h
|
||||
tablet-shell-protocol.c
|
||||
terminal
|
||||
view
|
||||
wayland-desktop-shell
|
||||
wayland-tablet-shell
|
||||
weston-desktop-shell
|
||||
weston-tablet-shell
|
||||
wscreensaver
|
||||
|
@ -37,6 +37,7 @@ clients_programs = \
|
||||
smoke \
|
||||
resizor \
|
||||
eventdemo \
|
||||
clickdot \
|
||||
$(full_gl_client_programs)
|
||||
|
||||
desktop_shell = weston-desktop-shell
|
||||
@ -83,6 +84,9 @@ resizor_LDADD = $(toolkit_libs)
|
||||
eventdemo_SOURCES = eventdemo.c
|
||||
eventdemo_LDADD = $(toolkit_libs)
|
||||
|
||||
clickdot_SOURCES = clickdot.c
|
||||
clickdot_LDADD = $(toolkit_libs)
|
||||
|
||||
weston_desktop_shell_SOURCES = \
|
||||
desktop-shell.c \
|
||||
desktop-shell-client-protocol.h \
|
||||
|
181
clients/clickdot.c
Normal file
181
clients/clickdot.c
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright © 2010 Intel Corporation
|
||||
* Copyright © 2012 Collabora, Ltd.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cairo.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "window.h"
|
||||
|
||||
#include <X11/keysym.h>
|
||||
|
||||
struct clickdot {
|
||||
struct display *display;
|
||||
struct window *window;
|
||||
struct widget *widget;
|
||||
|
||||
int32_t x, y;
|
||||
};
|
||||
|
||||
static void
|
||||
redraw_handler(struct widget *widget, void *data)
|
||||
{
|
||||
static const double r = 10.0;
|
||||
struct clickdot *clickdot = data;
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
struct rectangle allocation;
|
||||
|
||||
widget_get_allocation(clickdot->widget, &allocation);
|
||||
|
||||
surface = window_get_surface(clickdot->window);
|
||||
|
||||
cr = cairo_create(surface);
|
||||
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_rectangle(cr,
|
||||
allocation.x,
|
||||
allocation.y,
|
||||
allocation.width,
|
||||
allocation.height);
|
||||
cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
|
||||
cairo_fill(cr);
|
||||
|
||||
cairo_translate(cr, clickdot->x + 0.5, clickdot->y + 0.5);
|
||||
cairo_set_line_width(cr, 1.0);
|
||||
cairo_set_source_rgb(cr, 0.1, 0.9, 0.9);
|
||||
cairo_move_to(cr, 0.0, -r);
|
||||
cairo_line_to(cr, 0.0, r);
|
||||
cairo_move_to(cr, -r, 0.0);
|
||||
cairo_line_to(cr, r, 0.0);
|
||||
cairo_arc(cr, 0.0, 0.0, r, 0.0, 2.0 * M_PI);
|
||||
cairo_stroke(cr);
|
||||
|
||||
cairo_destroy(cr);
|
||||
|
||||
cairo_surface_destroy(surface);
|
||||
}
|
||||
|
||||
static void
|
||||
keyboard_focus_handler(struct window *window,
|
||||
struct input *device, void *data)
|
||||
{
|
||||
struct clickdot *clickdot = data;
|
||||
|
||||
window_schedule_redraw(clickdot->window);
|
||||
}
|
||||
|
||||
static void
|
||||
key_handler(struct window *window, struct input *input, uint32_t time,
|
||||
uint32_t key, uint32_t sym, uint32_t state, void *data)
|
||||
{
|
||||
struct clickdot *clickdot = data;
|
||||
|
||||
if (state == 0)
|
||||
return;
|
||||
|
||||
switch (sym) {
|
||||
case XK_Escape:
|
||||
display_exit(clickdot->display);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
button_handler(struct widget *widget,
|
||||
struct input *input, uint32_t time,
|
||||
int button, int state, void *data)
|
||||
{
|
||||
struct clickdot *clickdot = data;
|
||||
|
||||
if (state && button == BTN_LEFT)
|
||||
input_get_position(input, &clickdot->x, &clickdot->y);
|
||||
|
||||
widget_schedule_redraw(widget);
|
||||
}
|
||||
|
||||
static struct clickdot *
|
||||
clickdot_create(struct display *display)
|
||||
{
|
||||
struct clickdot *clickdot;
|
||||
|
||||
clickdot = malloc(sizeof *clickdot);
|
||||
if (clickdot == NULL)
|
||||
return clickdot;
|
||||
memset(clickdot, 0, sizeof *clickdot);
|
||||
|
||||
clickdot->window = window_create(display, 500, 400);
|
||||
clickdot->widget = frame_create(clickdot->window, clickdot);
|
||||
window_set_title(clickdot->window, "Wayland ClickDot");
|
||||
clickdot->display = display;
|
||||
|
||||
window_set_key_handler(clickdot->window, key_handler);
|
||||
window_set_user_data(clickdot->window, clickdot);
|
||||
window_set_keyboard_focus_handler(clickdot->window,
|
||||
keyboard_focus_handler);
|
||||
|
||||
widget_set_redraw_handler(clickdot->widget, redraw_handler);
|
||||
widget_set_button_handler(clickdot->widget, button_handler);
|
||||
|
||||
widget_schedule_resize(clickdot->widget, 500, 400);
|
||||
clickdot->x = 250;
|
||||
clickdot->y = 200;
|
||||
|
||||
return clickdot;
|
||||
}
|
||||
|
||||
static void
|
||||
clickdot_destroy(struct clickdot *clickdot)
|
||||
{
|
||||
widget_destroy(clickdot->widget);
|
||||
window_destroy(clickdot->window);
|
||||
free(clickdot);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct display *display;
|
||||
struct clickdot *clickdot;
|
||||
|
||||
display = display_create(&argc, &argv, NULL);
|
||||
if (display == NULL) {
|
||||
fprintf(stderr, "failed to create display: %m\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
clickdot = clickdot_create(display);
|
||||
|
||||
display_run(display);
|
||||
|
||||
clickdot_destroy(clickdot);
|
||||
display_destroy(display);
|
||||
|
||||
return 0;
|
||||
}
|
@ -148,6 +148,9 @@ AC_ARG_ENABLE(tablet-shell, [ --enable-tablet-shell],,
|
||||
AM_CONDITIONAL(ENABLE_TABLET_SHELL,
|
||||
test x$enable_tablet_shell == xyes)
|
||||
|
||||
AC_ARG_ENABLE(tests, [ --enable-tests],,enable_tests=yes)
|
||||
AM_CONDITIONAL(BUILD_TESTS, test x$enable_tests == xyes)
|
||||
|
||||
if test "x$GCC" = "xyes"; then
|
||||
GCC_CFLAGS="-Wall -g -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden"
|
||||
fi
|
||||
@ -160,7 +163,8 @@ AC_CONFIG_FILES([Makefile
|
||||
src/Makefile
|
||||
clients/Makefile
|
||||
data/Makefile
|
||||
protocol/Makefile])
|
||||
protocol/Makefile
|
||||
tests/Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
if test "x$enable_setuid_install" == xyes; then
|
||||
|
2
src/.gitignore
vendored
2
src/.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
wayland-compositor
|
||||
weston
|
||||
screenshooter-protocol.c
|
||||
screenshooter-server-protocol.h
|
||||
tablet-shell-protocol.c
|
||||
|
@ -20,6 +20,8 @@ weston_SOURCES = \
|
||||
screenshooter-protocol.c \
|
||||
screenshooter-server-protocol.h \
|
||||
util.c \
|
||||
matrix.c \
|
||||
matrix.h \
|
||||
$(xserver_launcher_sources)
|
||||
|
||||
if ENABLE_SETUID_INSTALL
|
||||
|
@ -97,16 +97,18 @@ drm_output_prepare_scanout_surface(struct drm_output *output)
|
||||
struct weston_surface, link);
|
||||
|
||||
if (es->visual != WESTON_RGB_VISUAL ||
|
||||
es->x != output->base.x ||
|
||||
es->y != output->base.y ||
|
||||
es->width != output->base.current->width ||
|
||||
es->height != output->base.current->height ||
|
||||
es->geometry.x != output->base.x ||
|
||||
es->geometry.y != output->base.y ||
|
||||
es->geometry.width != output->base.current->width ||
|
||||
es->geometry.height != output->base.current->height ||
|
||||
es->transform.enabled ||
|
||||
es->image == EGL_NO_IMAGE_KHR)
|
||||
return -1;
|
||||
|
||||
bo = gbm_bo_create_from_egl_image(c->gbm,
|
||||
c->base.display, es->image,
|
||||
es->width, es->height,
|
||||
es->geometry.width,
|
||||
es->geometry.height,
|
||||
GBM_BO_USE_SCANOUT);
|
||||
|
||||
handle = gbm_bo_get_handle(bo).s32;
|
||||
@ -231,8 +233,10 @@ drm_output_set_cursor(struct weston_output *output_base,
|
||||
}
|
||||
|
||||
pixman_region32_init_rect(&cursor_region,
|
||||
eid->sprite->x, eid->sprite->y,
|
||||
eid->sprite->width, eid->sprite->height);
|
||||
eid->sprite->geometry.x,
|
||||
eid->sprite->geometry.y,
|
||||
eid->sprite->geometry.width,
|
||||
eid->sprite->geometry.height);
|
||||
|
||||
pixman_region32_intersect_rect(&cursor_region, &cursor_region,
|
||||
output->base.x, output->base.y,
|
||||
@ -245,7 +249,8 @@ drm_output_set_cursor(struct weston_output *output_base,
|
||||
if (eid->sprite->image == EGL_NO_IMAGE_KHR)
|
||||
goto out;
|
||||
|
||||
if (eid->sprite->width > 64 || eid->sprite->height > 64)
|
||||
if (eid->sprite->geometry.width > 64 ||
|
||||
eid->sprite->geometry.height > 64)
|
||||
goto out;
|
||||
|
||||
bo = gbm_bo_create_from_egl_image(c->gbm,
|
||||
@ -272,8 +277,8 @@ drm_output_set_cursor(struct weston_output *output_base,
|
||||
}
|
||||
|
||||
ret = drmModeMoveCursor(c->drm.fd, output->crtc_id,
|
||||
eid->sprite->x - output->base.x,
|
||||
eid->sprite->y - output->base.y);
|
||||
eid->sprite->geometry.x - output->base.x,
|
||||
eid->sprite->geometry.y - output->base.y);
|
||||
if (ret) {
|
||||
fprintf(stderr, "failed to move cursor: %s\n", strerror(-ret));
|
||||
goto out;
|
||||
|
409
src/compositor.c
409
src/compositor.c
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright © 2010-2011 Intel Corporation
|
||||
* Copyright © 2008-2011 Kristian Høgsberg
|
||||
* Copyright © 2012 Collabora, Ltd.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
@ -189,10 +190,10 @@ weston_surface_create(struct weston_compositor *compositor,
|
||||
surface->compositor = compositor;
|
||||
surface->visual = WESTON_NONE_VISUAL;
|
||||
surface->image = EGL_NO_IMAGE_KHR;
|
||||
surface->x = x;
|
||||
surface->y = y;
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->geometry.x = x;
|
||||
surface->geometry.y = y;
|
||||
surface->geometry.width = width;
|
||||
surface->geometry.height = height;
|
||||
surface->alpha = 255;
|
||||
|
||||
surface->fullscreen_output = NULL;
|
||||
@ -205,7 +206,12 @@ weston_surface_create(struct weston_compositor *compositor,
|
||||
|
||||
surface->buffer_destroy_listener.func = surface_handle_buffer_destroy;
|
||||
|
||||
surface->transform = NULL;
|
||||
wl_list_init(&surface->geometry.transformation_list);
|
||||
wl_list_insert(&surface->geometry.transformation_list,
|
||||
&surface->transform.position.link);
|
||||
weston_matrix_init(&surface->transform.position.matrix);
|
||||
pixman_region32_init(&surface->transform.boundingbox);
|
||||
surface->geometry.dirty = 1;
|
||||
|
||||
return surface;
|
||||
}
|
||||
@ -226,25 +232,189 @@ weston_surface_set_color(struct weston_surface *surface,
|
||||
surface->shader = &surface->compositor->solid_shader;
|
||||
}
|
||||
|
||||
static void
|
||||
surface_compute_bbox(struct weston_surface *surface, int32_t sx, int32_t sy,
|
||||
int32_t width, int32_t height,
|
||||
pixman_region32_t *bbox)
|
||||
{
|
||||
int min_x = INT_MAX, min_y = INT_MAX, max_x = INT_MIN, max_y = INT_MIN;
|
||||
int32_t s[4][2] = {
|
||||
{ sx, sy },
|
||||
{ sx, sy + height },
|
||||
{ sx + width, sy },
|
||||
{ sx + width, sy + height }
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
int32_t x, y;
|
||||
weston_surface_to_global(surface, s[i][0], s[i][1], &x, &y);
|
||||
if (x < min_x)
|
||||
min_x = x;
|
||||
if (x > max_x)
|
||||
max_x = x;
|
||||
if (y < min_y)
|
||||
min_y = y;
|
||||
if (y > max_y)
|
||||
max_y = y;
|
||||
}
|
||||
|
||||
/* weston_surface_to_global rounds with floor(), add the
|
||||
* minimum required safety margin.
|
||||
*/
|
||||
pixman_region32_init_rect(bbox, min_x, min_y,
|
||||
max_x - min_x + 1, max_y - min_y + 1);
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
weston_surface_update_transform(struct weston_surface *surface)
|
||||
{
|
||||
struct weston_matrix *matrix = &surface->transform.matrix;
|
||||
struct weston_matrix *inverse = &surface->transform.inverse;
|
||||
struct weston_transform *tform;
|
||||
|
||||
if (!surface->geometry.dirty)
|
||||
return;
|
||||
|
||||
surface->geometry.dirty = 0;
|
||||
|
||||
pixman_region32_fini(&surface->transform.boundingbox);
|
||||
|
||||
/* transform.position is always in transformation_list */
|
||||
if (surface->geometry.transformation_list.next ==
|
||||
&surface->transform.position.link &&
|
||||
surface->geometry.transformation_list.prev ==
|
||||
&surface->transform.position.link) {
|
||||
surface->transform.enabled = 0;
|
||||
|
||||
pixman_region32_init_rect(&surface->transform.boundingbox,
|
||||
surface->geometry.x,
|
||||
surface->geometry.y,
|
||||
surface->geometry.width,
|
||||
surface->geometry.height);
|
||||
return;
|
||||
}
|
||||
|
||||
surface->transform.enabled = 1;
|
||||
|
||||
surface->transform.position.matrix.d[12] = surface->geometry.x;
|
||||
surface->transform.position.matrix.d[13] = surface->geometry.y;
|
||||
|
||||
weston_matrix_init(matrix);
|
||||
wl_list_for_each(tform, &surface->geometry.transformation_list, link)
|
||||
weston_matrix_multiply(matrix, &tform->matrix);
|
||||
|
||||
if (weston_matrix_invert(inverse, matrix) < 0) {
|
||||
/* Oops, bad total transformation, not invertible */
|
||||
surface->transform.enabled = 0;
|
||||
fprintf(stderr, "error: weston_surface %p"
|
||||
" transformation not invertible.\n", surface);
|
||||
}
|
||||
|
||||
surface_compute_bbox(surface, 0, 0, surface->geometry.width,
|
||||
surface->geometry.height,
|
||||
&surface->transform.boundingbox);
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
weston_surface_to_global(struct weston_surface *surface,
|
||||
int32_t sx, int32_t sy, int32_t *x, int32_t *y)
|
||||
{
|
||||
weston_surface_update_transform(surface);
|
||||
|
||||
if (surface->transform.enabled) {
|
||||
struct weston_vector v = { { sx, sy, 0.0f, 1.0f } };
|
||||
|
||||
weston_matrix_transform(&surface->transform.matrix, &v);
|
||||
|
||||
if (fabsf(v.f[3]) < 1e-6) {
|
||||
fprintf(stderr, "warning: numerical instability in "
|
||||
"weston_surface_to_global(), divisor = %g\n",
|
||||
v.f[3]);
|
||||
*x = 0;
|
||||
*y = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
*x = floorf(v.f[0] / v.f[3]);
|
||||
*y = floorf(v.f[1] / v.f[3]);
|
||||
} else {
|
||||
*x = sx + surface->geometry.x;
|
||||
*y = sy + surface->geometry.y;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
surface_from_global_float(struct weston_surface *surface,
|
||||
int32_t x, int32_t y, GLfloat *sx, GLfloat *sy)
|
||||
{
|
||||
if (surface->transform.enabled) {
|
||||
struct weston_vector v = { { x, y, 0.0f, 1.0f } };
|
||||
|
||||
weston_matrix_transform(&surface->transform.inverse, &v);
|
||||
|
||||
if (fabsf(v.f[3]) < 1e-6) {
|
||||
fprintf(stderr, "warning: numerical instability in "
|
||||
"weston_surface_from_global(), divisor = %g\n",
|
||||
v.f[3]);
|
||||
*sx = 0;
|
||||
*sy = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
*sx = v.f[0] / v.f[3];
|
||||
*sy = v.f[1] / v.f[3];
|
||||
} else {
|
||||
*sx = x - surface->geometry.x;
|
||||
*sy = y - surface->geometry.y;
|
||||
}
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
weston_surface_from_global(struct weston_surface *surface,
|
||||
int32_t x, int32_t y, int32_t *sx, int32_t *sy)
|
||||
{
|
||||
GLfloat sxf, syf;
|
||||
|
||||
weston_surface_update_transform(surface);
|
||||
|
||||
surface_from_global_float(surface, x, y, &sxf, &syf);
|
||||
*sx = floorf(sxf);
|
||||
*sy = floorf(syf);
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
weston_surface_damage_rectangle(struct weston_surface *surface,
|
||||
int32_t x, int32_t y,
|
||||
int32_t width, int32_t height)
|
||||
int32_t sx, int32_t sy,
|
||||
int32_t width, int32_t height)
|
||||
{
|
||||
struct weston_compositor *compositor = surface->compositor;
|
||||
weston_surface_update_transform(surface);
|
||||
|
||||
pixman_region32_union_rect(&surface->damage,
|
||||
&surface->damage,
|
||||
surface->x + x, surface->y + y,
|
||||
width, height);
|
||||
weston_compositor_schedule_repaint(compositor);
|
||||
if (surface->transform.enabled) {
|
||||
pixman_region32_t box;
|
||||
surface_compute_bbox(surface, sx, sy, width, height, &box);
|
||||
pixman_region32_union(&surface->damage, &surface->damage,
|
||||
&box);
|
||||
pixman_region32_fini(&box);
|
||||
} else {
|
||||
int32_t x, y;
|
||||
weston_surface_to_global(surface, sx, sy, &x, &y);
|
||||
pixman_region32_union_rect(&surface->damage, &surface->damage,
|
||||
x, y, width, height);
|
||||
}
|
||||
|
||||
weston_compositor_schedule_repaint(surface->compositor);
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
weston_surface_damage(struct weston_surface *surface)
|
||||
{
|
||||
weston_surface_damage_rectangle(surface, 0, 0,
|
||||
surface->width, surface->height);
|
||||
weston_surface_update_transform(surface);
|
||||
|
||||
pixman_region32_union(&surface->damage, &surface->damage,
|
||||
&surface->transform.boundingbox);
|
||||
|
||||
weston_compositor_schedule_repaint(surface->compositor);
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
@ -260,10 +430,10 @@ weston_surface_damage_below(struct weston_surface *surface)
|
||||
|
||||
below = container_of(surface->link.next, struct weston_surface, link);
|
||||
|
||||
pixman_region32_union_rect(&below->damage,
|
||||
&below->damage,
|
||||
surface->x, surface->y,
|
||||
surface->width, surface->height);
|
||||
weston_surface_update_transform(surface);
|
||||
pixman_region32_union(&below->damage, &below->damage,
|
||||
&surface->transform.boundingbox);
|
||||
|
||||
weston_compositor_schedule_repaint(surface->compositor);
|
||||
}
|
||||
|
||||
@ -288,10 +458,11 @@ weston_surface_configure(struct weston_surface *surface,
|
||||
{
|
||||
weston_surface_damage_below(surface);
|
||||
|
||||
surface->x = x;
|
||||
surface->y = y;
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->geometry.x = x;
|
||||
surface->geometry.y = y;
|
||||
surface->geometry.width = width;
|
||||
surface->geometry.height = height;
|
||||
surface->geometry.dirty = 1;
|
||||
|
||||
weston_surface_assign_output(surface);
|
||||
weston_surface_damage(surface);
|
||||
@ -299,20 +470,14 @@ weston_surface_configure(struct weston_surface *surface,
|
||||
pixman_region32_fini(&surface->opaque);
|
||||
if (surface->visual == WESTON_RGB_VISUAL)
|
||||
pixman_region32_init_rect(&surface->opaque,
|
||||
surface->x, surface->y,
|
||||
surface->width, surface->height);
|
||||
surface->geometry.x,
|
||||
surface->geometry.y,
|
||||
surface->geometry.width,
|
||||
surface->geometry.height);
|
||||
else
|
||||
pixman_region32_init(&surface->opaque);
|
||||
}
|
||||
|
||||
static void
|
||||
weston_surface_transform(struct weston_surface *surface,
|
||||
int32_t x, int32_t y, int32_t *sx, int32_t *sy)
|
||||
{
|
||||
*sx = x - surface->x;
|
||||
*sy = y - surface->y;
|
||||
}
|
||||
|
||||
WL_EXPORT uint32_t
|
||||
weston_compositor_get_time(void)
|
||||
{
|
||||
@ -344,8 +509,8 @@ weston_device_repick(struct wl_input_device *device, uint32_t time)
|
||||
|
||||
focus = (struct weston_surface *) device->grab->focus;
|
||||
if (focus)
|
||||
weston_surface_transform(focus, device->x, device->y,
|
||||
&device->grab->x, &device->grab->y);
|
||||
weston_surface_from_global(focus, device->x, device->y,
|
||||
&device->grab->x, &device->grab->y);
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
@ -387,6 +552,7 @@ destroy_surface(struct wl_resource *resource)
|
||||
|
||||
wl_list_remove(&surface->buffer_link);
|
||||
|
||||
pixman_region32_fini(&surface->transform.boundingbox);
|
||||
pixman_region32_fini(&surface->damage);
|
||||
pixman_region32_fini(&surface->opaque);
|
||||
|
||||
@ -442,7 +608,7 @@ weston_buffer_attach(struct wl_buffer *buffer, struct wl_surface *surface)
|
||||
ec->image_target_texture_2d(GL_TEXTURE_2D, es->image);
|
||||
|
||||
es->visual = WESTON_ARGB_VISUAL;
|
||||
es->pitch = es->width;
|
||||
es->pitch = es->geometry.width;
|
||||
}
|
||||
}
|
||||
|
||||
@ -451,6 +617,7 @@ texture_region(struct weston_surface *es, pixman_region32_t *region)
|
||||
{
|
||||
struct weston_compositor *ec = es->compositor;
|
||||
GLfloat *v, inv_width, inv_height;
|
||||
GLfloat sx, sy;
|
||||
pixman_box32_t *rectangles;
|
||||
unsigned int *p;
|
||||
int i, n;
|
||||
@ -459,28 +626,36 @@ texture_region(struct weston_surface *es, pixman_region32_t *region)
|
||||
v = wl_array_add(&ec->vertices, n * 16 * sizeof *v);
|
||||
p = wl_array_add(&ec->indices, n * 6 * sizeof *p);
|
||||
inv_width = 1.0 / es->pitch;
|
||||
inv_height = 1.0 / es->height;
|
||||
inv_height = 1.0 / es->geometry.height;
|
||||
|
||||
for (i = 0; i < n; i++, v += 16, p += 6) {
|
||||
surface_from_global_float(es, rectangles[i].x1,
|
||||
rectangles[i].y1, &sx, &sy);
|
||||
v[ 0] = rectangles[i].x1;
|
||||
v[ 1] = rectangles[i].y1;
|
||||
v[ 2] = (GLfloat) (rectangles[i].x1 - es->x) * inv_width;
|
||||
v[ 3] = (GLfloat) (rectangles[i].y1 - es->y) * inv_height;
|
||||
v[ 2] = sx * inv_width;
|
||||
v[ 3] = sy * inv_height;
|
||||
|
||||
surface_from_global_float(es, rectangles[i].x1,
|
||||
rectangles[i].y2, &sx, &sy);
|
||||
v[ 4] = rectangles[i].x1;
|
||||
v[ 5] = rectangles[i].y2;
|
||||
v[ 6] = v[ 2];
|
||||
v[ 7] = (GLfloat) (rectangles[i].y2 - es->y) * inv_height;
|
||||
v[ 6] = sx * inv_width;
|
||||
v[ 7] = sy * inv_height;
|
||||
|
||||
surface_from_global_float(es, rectangles[i].x2,
|
||||
rectangles[i].y1, &sx, &sy);
|
||||
v[ 8] = rectangles[i].x2;
|
||||
v[ 9] = rectangles[i].y1;
|
||||
v[10] = (GLfloat) (rectangles[i].x2 - es->x) * inv_width;
|
||||
v[11] = v[ 3];
|
||||
v[10] = sx * inv_width;
|
||||
v[11] = sy * inv_height;
|
||||
|
||||
surface_from_global_float(es, rectangles[i].x2,
|
||||
rectangles[i].y2, &sx, &sy);
|
||||
v[12] = rectangles[i].x2;
|
||||
v[13] = rectangles[i].y2;
|
||||
v[14] = v[10];
|
||||
v[15] = v[ 7];
|
||||
v[14] = sx * inv_width;
|
||||
v[15] = sy * inv_height;
|
||||
|
||||
p[0] = i * 4 + 0;
|
||||
p[1] = i * 4 + 1;
|
||||
@ -493,51 +668,6 @@ texture_region(struct weston_surface *es, pixman_region32_t *region)
|
||||
return n;
|
||||
}
|
||||
|
||||
static void
|
||||
transform_vertex(struct weston_surface *surface,
|
||||
GLfloat x, GLfloat y, GLfloat u, GLfloat v, GLfloat *r)
|
||||
{
|
||||
struct weston_vector t;
|
||||
|
||||
t.f[0] = x;
|
||||
t.f[1] = y;
|
||||
t.f[2] = 0.0;
|
||||
t.f[3] = 1.0;
|
||||
|
||||
weston_matrix_transform(&surface->transform->matrix, &t);
|
||||
|
||||
r[ 0] = t.f[0];
|
||||
r[ 1] = t.f[1];
|
||||
r[ 2] = u;
|
||||
r[ 3] = v;
|
||||
}
|
||||
|
||||
static int
|
||||
texture_transformed_surface(struct weston_surface *es)
|
||||
{
|
||||
struct weston_compositor *ec = es->compositor;
|
||||
GLfloat *v;
|
||||
unsigned int *p;
|
||||
|
||||
v = wl_array_add(&ec->vertices, 16 * sizeof *v);
|
||||
p = wl_array_add(&ec->indices, 6 * sizeof *p);
|
||||
|
||||
transform_vertex(es, es->x, es->y, 0.0, 0.0, &v[0]);
|
||||
transform_vertex(es, es->x, es->y + es->height, 0.0, 1.0, &v[4]);
|
||||
transform_vertex(es, es->x + es->width, es->y, 1.0, 0.0, &v[8]);
|
||||
transform_vertex(es, es->x + es->width, es->y + es->height,
|
||||
1.0, 1.0, &v[12]);
|
||||
|
||||
p[0] = 0;
|
||||
p[1] = 1;
|
||||
p[2] = 2;
|
||||
p[3] = 2;
|
||||
p[4] = 1;
|
||||
p[5] = 3;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
weston_surface_draw(struct weston_surface *es, struct weston_output *output)
|
||||
{
|
||||
@ -547,13 +677,15 @@ weston_surface_draw(struct weston_surface *es, struct weston_output *output)
|
||||
GLint filter;
|
||||
int n;
|
||||
|
||||
pixman_region32_init_rect(&repaint,
|
||||
es->x, es->y, es->width, es->height);
|
||||
pixman_region32_intersect(&repaint, &repaint, &output->region);
|
||||
weston_surface_update_transform(es);
|
||||
|
||||
pixman_region32_init(&repaint);
|
||||
pixman_region32_intersect(&repaint, &es->transform.boundingbox,
|
||||
&output->region);
|
||||
pixman_region32_intersect(&repaint, &repaint, &es->damage);
|
||||
|
||||
if (!pixman_region32_not_empty(&repaint))
|
||||
return;
|
||||
goto out;
|
||||
|
||||
switch (es->visual) {
|
||||
case WESTON_ARGB_VISUAL:
|
||||
@ -584,13 +716,16 @@ weston_surface_draw(struct weston_surface *es, struct weston_output *output)
|
||||
ec->current_alpha = es->alpha;
|
||||
}
|
||||
|
||||
if (es->transform == NULL) {
|
||||
filter = GL_NEAREST;
|
||||
n = texture_region(es, &repaint);
|
||||
} else {
|
||||
if (es->shader->texwidth_uniform != GL_NONE)
|
||||
glUniform1f(es->shader->texwidth_uniform,
|
||||
(GLfloat)es->geometry.width / es->pitch);
|
||||
|
||||
if (es->transform.enabled)
|
||||
filter = GL_LINEAR;
|
||||
n = texture_transformed_surface(es);
|
||||
}
|
||||
else
|
||||
filter = GL_NEAREST;
|
||||
|
||||
n = texture_region(es, &repaint);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, es->texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
|
||||
@ -601,10 +736,16 @@ weston_surface_draw(struct weston_surface *es, struct weston_output *output)
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[2]);
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
glDrawElements(GL_TRIANGLES, n * 6, GL_UNSIGNED_INT, ec->indices.data);
|
||||
|
||||
glDisableVertexAttribArray(1);
|
||||
glDisableVertexAttribArray(0);
|
||||
|
||||
ec->vertices.size = 0;
|
||||
ec->indices.size = 0;
|
||||
|
||||
out:
|
||||
pixman_region32_fini(&repaint);
|
||||
}
|
||||
|
||||
@ -716,12 +857,12 @@ weston_output_set_cursor(struct weston_output *output,
|
||||
if (device->sprite == NULL)
|
||||
return;
|
||||
|
||||
pixman_region32_init_rect(&cursor_region,
|
||||
device->sprite->x, device->sprite->y,
|
||||
device->sprite->width,
|
||||
device->sprite->height);
|
||||
weston_surface_update_transform(device->sprite);
|
||||
|
||||
pixman_region32_intersect(&cursor_region, &cursor_region, &output->region);
|
||||
pixman_region32_init(&cursor_region);
|
||||
pixman_region32_intersect(&cursor_region,
|
||||
&device->sprite->transform.boundingbox,
|
||||
&output->region);
|
||||
|
||||
if (!pixman_region32_not_empty(&cursor_region)) {
|
||||
output->set_hardware_cursor(output, NULL);
|
||||
@ -770,14 +911,15 @@ weston_output_repaint(struct weston_output *output, int msecs)
|
||||
pixman_region32_init(&overlap);
|
||||
|
||||
wl_list_for_each(es, &ec->surface_list, link) {
|
||||
weston_surface_update_transform(es);
|
||||
|
||||
pixman_region32_init(&surface_overlap);
|
||||
pixman_region32_intersect_rect(&surface_overlap,
|
||||
&overlap, es->x, es->y,
|
||||
es->width, es->height);
|
||||
pixman_region32_intersect(&surface_overlap, &overlap,
|
||||
&es->transform.boundingbox);
|
||||
es->overlapped = pixman_region32_not_empty(&surface_overlap);
|
||||
pixman_region32_fini(&surface_overlap);
|
||||
pixman_region32_union_rect(&overlap, &overlap, es->x, es->y,
|
||||
es->width, es->height);
|
||||
pixman_region32_union(&overlap, &overlap,
|
||||
&es->transform.boundingbox);
|
||||
}
|
||||
|
||||
weston_output_set_cursor(output, ec->input_device);
|
||||
@ -903,12 +1045,14 @@ weston_surface_assign_output(struct weston_surface *es)
|
||||
uint32_t max, area;
|
||||
pixman_box32_t *e;
|
||||
|
||||
weston_surface_update_transform(es);
|
||||
|
||||
new_output = NULL;
|
||||
max = 0;
|
||||
pixman_region32_init(®ion);
|
||||
wl_list_for_each(output, &ec->output_list, link) {
|
||||
pixman_region32_init_rect(®ion,
|
||||
es->x, es->y, es->width, es->height);
|
||||
pixman_region32_intersect(®ion, ®ion, &output->region);
|
||||
pixman_region32_intersect(®ion, &es->transform.boundingbox,
|
||||
&output->region);
|
||||
|
||||
e = pixman_region32_extents(®ion);
|
||||
area = (e->x2 - e->x1) * (e->y2 - e->y1);
|
||||
@ -918,6 +1062,7 @@ weston_surface_assign_output(struct weston_surface *es)
|
||||
max = area;
|
||||
}
|
||||
}
|
||||
pixman_region32_fini(®ion);
|
||||
|
||||
es->output = new_output;
|
||||
if (!wl_list_empty(&es->frame_callback_list)) {
|
||||
@ -951,9 +1096,11 @@ surface_attach(struct wl_client *client,
|
||||
if (es->visual == WESTON_NONE_VISUAL) {
|
||||
shell->map(shell, es, buffer->width, buffer->height);
|
||||
} else if (x != 0 || y != 0 ||
|
||||
es->width != buffer->width ||
|
||||
es->height != buffer->height) {
|
||||
shell->configure(shell, es, es->x + x, es->y + y,
|
||||
es->geometry.width != buffer->width ||
|
||||
es->geometry.height != buffer->height) {
|
||||
/* FIXME: the x,y delta should be in surface-local coords */
|
||||
shell->configure(shell, es, es->geometry.x + x,
|
||||
es->geometry.y + y,
|
||||
buffer->width, buffer->height);
|
||||
}
|
||||
|
||||
@ -1052,9 +1199,9 @@ weston_compositor_pick_surface(struct weston_compositor *compositor,
|
||||
wl_list_for_each(surface, &compositor->surface_list, link) {
|
||||
if (surface->surface.resource.client == NULL)
|
||||
continue;
|
||||
weston_surface_transform(surface, x, y, sx, sy);
|
||||
if (0 <= *sx && *sx < surface->width &&
|
||||
0 <= *sy && *sy < surface->height)
|
||||
weston_surface_from_global(surface, x, y, sx, sy);
|
||||
if (0 <= *sx && *sx < surface->geometry.width &&
|
||||
0 <= *sy && *sy < surface->geometry.height)
|
||||
return surface;
|
||||
}
|
||||
|
||||
@ -1163,8 +1310,9 @@ notify_motion(struct wl_input_device *device, uint32_t time, int x, int y)
|
||||
if (wd->sprite) {
|
||||
weston_surface_damage_below(wd->sprite);
|
||||
|
||||
wd->sprite->x = device->x - wd->hotspot_x;
|
||||
wd->sprite->y = device->y - wd->hotspot_y;
|
||||
wd->sprite->geometry.x = device->x - wd->hotspot_x;
|
||||
wd->sprite->geometry.y = device->y - wd->hotspot_y;
|
||||
wd->sprite->geometry.dirty = 1;
|
||||
|
||||
weston_surface_damage(wd->sprite);
|
||||
}
|
||||
@ -1440,7 +1588,7 @@ notify_touch(struct wl_input_device *device, uint32_t time, int touch_id,
|
||||
touch_set_focus(wd, &es->surface, time);
|
||||
} else if (wd->touch_focus) {
|
||||
es = (struct weston_surface *) wd->touch_focus;
|
||||
weston_surface_transform(es, x, y, &sx, &sy);
|
||||
weston_surface_from_global(es, x, y, &sx, &sy);
|
||||
}
|
||||
|
||||
if (wd->touch_focus_resource && wd->touch_focus)
|
||||
@ -1454,7 +1602,7 @@ notify_touch(struct wl_input_device *device, uint32_t time, int touch_id,
|
||||
if (!es)
|
||||
break;
|
||||
|
||||
weston_surface_transform(es, x, y, &sx, &sy);
|
||||
weston_surface_from_global(es, x, y, &sx, &sy);
|
||||
if (wd->touch_focus_resource)
|
||||
wl_resource_post_event(wd->touch_focus_resource,
|
||||
touch_type, time,
|
||||
@ -1515,10 +1663,11 @@ input_device_attach(struct wl_client *client,
|
||||
|
||||
device->hotspot_x = x;
|
||||
device->hotspot_y = y;
|
||||
device->sprite->width = buffer->width;
|
||||
device->sprite->height = buffer->height;
|
||||
device->sprite->x = device->input_device.x - device->hotspot_x;
|
||||
device->sprite->y = device->input_device.y - device->hotspot_y;
|
||||
device->sprite->geometry.width = buffer->width;
|
||||
device->sprite->geometry.height = buffer->height;
|
||||
device->sprite->geometry.x = device->input_device.x - device->hotspot_x;
|
||||
device->sprite->geometry.y = device->input_device.y - device->hotspot_y;
|
||||
device->sprite->geometry.dirty = 1;
|
||||
|
||||
weston_surface_damage(device->sprite);
|
||||
}
|
||||
@ -1624,8 +1773,12 @@ static const char texture_fragment_shader[] =
|
||||
"varying vec2 v_texcoord;\n"
|
||||
"uniform sampler2D tex;\n"
|
||||
"uniform float alpha;\n"
|
||||
"uniform float texwidth;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" if (v_texcoord.x < 0.0 || v_texcoord.x > texwidth ||\n"
|
||||
" v_texcoord.y < 0.0 || v_texcoord.y > 1.0)\n"
|
||||
" discard;\n"
|
||||
" gl_FragColor = texture2D(tex, v_texcoord)\n;"
|
||||
" gl_FragColor = alpha * gl_FragColor;\n"
|
||||
"}\n";
|
||||
@ -1687,6 +1840,8 @@ weston_shader_init(struct weston_shader *shader,
|
||||
shader->proj_uniform = glGetUniformLocation(shader->program, "proj");
|
||||
shader->tex_uniform = glGetUniformLocation(shader->program, "tex");
|
||||
shader->alpha_uniform = glGetUniformLocation(shader->program, "alpha");
|
||||
shader->texwidth_uniform = glGetUniformLocation(shader->program,
|
||||
"texwidth");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright © 2008-2011 Kristian Høgsberg
|
||||
* Copyright © 2012 Collabora, Ltd.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
@ -32,27 +33,11 @@
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
struct weston_matrix {
|
||||
GLfloat d[16];
|
||||
};
|
||||
|
||||
struct weston_vector {
|
||||
GLfloat f[4];
|
||||
};
|
||||
|
||||
void
|
||||
weston_matrix_init(struct weston_matrix *matrix);
|
||||
void
|
||||
weston_matrix_scale(struct weston_matrix *matrix, GLfloat x, GLfloat y, GLfloat z);
|
||||
void
|
||||
weston_matrix_translate(struct weston_matrix *matrix,
|
||||
GLfloat x, GLfloat y, GLfloat z);
|
||||
void
|
||||
weston_matrix_transform(struct weston_matrix *matrix, struct weston_vector *v);
|
||||
#include "matrix.h"
|
||||
|
||||
struct weston_transform {
|
||||
struct weston_matrix matrix;
|
||||
struct weston_matrix inverse;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct weston_surface;
|
||||
@ -118,6 +103,7 @@ struct weston_shader {
|
||||
GLuint tex_uniform;
|
||||
GLuint alpha_uniform;
|
||||
GLuint color_uniform;
|
||||
GLuint texwidth_uniform;
|
||||
};
|
||||
|
||||
struct weston_animation {
|
||||
@ -162,7 +148,6 @@ struct weston_compositor {
|
||||
EGLContext context;
|
||||
EGLConfig config;
|
||||
GLuint fbo;
|
||||
GLuint proj_uniform, tex_uniform, alpha_uniform;
|
||||
uint32_t current_alpha;
|
||||
struct weston_shader texture_shader;
|
||||
struct weston_shader solid_shader;
|
||||
@ -230,17 +215,45 @@ struct weston_surface {
|
||||
GLuint texture;
|
||||
pixman_region32_t damage;
|
||||
pixman_region32_t opaque;
|
||||
int32_t x, y, width, height;
|
||||
int32_t pitch;
|
||||
struct wl_list link;
|
||||
struct wl_list buffer_link;
|
||||
struct weston_transform *transform;
|
||||
struct weston_shader *shader;
|
||||
GLfloat color[4];
|
||||
uint32_t alpha;
|
||||
uint32_t visual;
|
||||
int overlapped;
|
||||
|
||||
/* Surface geometry state, mutable.
|
||||
* If you change anything, set dirty = 1.
|
||||
* That includes the transformations referenced from the list.
|
||||
*/
|
||||
struct {
|
||||
int32_t x, y; /* surface translation on display */
|
||||
int32_t width, height;
|
||||
|
||||
/* struct weston_transform */
|
||||
struct wl_list transformation_list;
|
||||
|
||||
int dirty;
|
||||
} geometry;
|
||||
|
||||
/* State derived from geometry state, read-only.
|
||||
* This is updated by weston_surface_update_transform().
|
||||
*/
|
||||
struct {
|
||||
pixman_region32_t boundingbox;
|
||||
|
||||
/* matrix and inverse are used only if enabled = 1.
|
||||
* If enabled = 0, use x, y, width, height directly.
|
||||
*/
|
||||
int enabled;
|
||||
struct weston_matrix matrix;
|
||||
struct weston_matrix inverse;
|
||||
|
||||
struct weston_transform position; /* matrix from x, y */
|
||||
} transform;
|
||||
|
||||
/*
|
||||
* Which output to vsync this surface to.
|
||||
* Used to determine, whether to send or queue frame events.
|
||||
@ -257,6 +270,17 @@ struct weston_surface {
|
||||
struct wl_listener buffer_destroy_listener;
|
||||
};
|
||||
|
||||
void
|
||||
weston_surface_update_transform(struct weston_surface *surface);
|
||||
|
||||
void
|
||||
weston_surface_to_global(struct weston_surface *surface,
|
||||
int32_t sx, int32_t sy, int32_t *x, int32_t *y);
|
||||
|
||||
void
|
||||
weston_surface_from_global(struct weston_surface *surface,
|
||||
int32_t x, int32_t y, int32_t *sx, int32_t *sy);
|
||||
|
||||
void
|
||||
weston_device_repick(struct wl_input_device *device, uint32_t time);
|
||||
|
||||
|
250
src/matrix.c
Normal file
250
src/matrix.c
Normal file
@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright © 2011 Intel Corporation
|
||||
* Copyright © 2012 Collabora, Ltd.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
* that the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of the copyright holders not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. The copyright holders make
|
||||
* no representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <GLES2/gl2.h>
|
||||
#include <wayland-server.h>
|
||||
|
||||
#include "matrix.h"
|
||||
|
||||
|
||||
/*
|
||||
* Matrices are stored in column-major order, that is the array indices are:
|
||||
* 0 4 8 12
|
||||
* 1 5 9 13
|
||||
* 2 6 10 14
|
||||
* 3 7 11 15
|
||||
*/
|
||||
|
||||
WL_EXPORT void
|
||||
weston_matrix_init(struct weston_matrix *matrix)
|
||||
{
|
||||
static const struct weston_matrix identity = {
|
||||
{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }
|
||||
};
|
||||
|
||||
memcpy(matrix, &identity, sizeof identity);
|
||||
}
|
||||
|
||||
/* m <- n * m, that is, m is multiplied on the LEFT. */
|
||||
WL_EXPORT void
|
||||
weston_matrix_multiply(struct weston_matrix *m, const struct weston_matrix *n)
|
||||
{
|
||||
struct weston_matrix tmp;
|
||||
const GLfloat *row, *column;
|
||||
div_t d;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
tmp.d[i] = 0;
|
||||
d = div(i, 4);
|
||||
row = m->d + d.quot * 4;
|
||||
column = n->d + d.rem;
|
||||
for (j = 0; j < 4; j++)
|
||||
tmp.d[i] += row[j] * column[j * 4];
|
||||
}
|
||||
memcpy(m, &tmp, sizeof tmp);
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
weston_matrix_translate(struct weston_matrix *matrix, GLfloat x, GLfloat y, GLfloat z)
|
||||
{
|
||||
struct weston_matrix translate = {
|
||||
{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1 }
|
||||
};
|
||||
|
||||
weston_matrix_multiply(matrix, &translate);
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
weston_matrix_scale(struct weston_matrix *matrix, GLfloat x, GLfloat y, GLfloat z)
|
||||
{
|
||||
struct weston_matrix scale = {
|
||||
{ x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1 }
|
||||
};
|
||||
|
||||
weston_matrix_multiply(matrix, &scale);
|
||||
}
|
||||
|
||||
/* v <- m * v */
|
||||
WL_EXPORT void
|
||||
weston_matrix_transform(struct weston_matrix *matrix, struct weston_vector *v)
|
||||
{
|
||||
int i, j;
|
||||
struct weston_vector t;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
t.f[i] = 0;
|
||||
for (j = 0; j < 4; j++)
|
||||
t.f[i] += v->f[j] * matrix->d[i + j * 4];
|
||||
}
|
||||
|
||||
*v = t;
|
||||
}
|
||||
|
||||
static inline void
|
||||
swap_rows(double *a, double *b)
|
||||
{
|
||||
unsigned k;
|
||||
double tmp;
|
||||
|
||||
for (k = 0; k < 13; k += 4) {
|
||||
tmp = a[k];
|
||||
a[k] = b[k];
|
||||
b[k] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
swap_unsigned(unsigned *a, unsigned *b)
|
||||
{
|
||||
unsigned tmp;
|
||||
|
||||
tmp = *a;
|
||||
*a = *b;
|
||||
*b = tmp;
|
||||
}
|
||||
|
||||
static inline unsigned
|
||||
find_pivot(double *column, unsigned k)
|
||||
{
|
||||
unsigned p = k;
|
||||
for (++k; k < 4; ++k)
|
||||
if (fabs(column[p]) < fabs(column[k]))
|
||||
p = k;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* reference: Gene H. Golub and Charles F. van Loan. Matrix computations.
|
||||
* 3rd ed. The Johns Hopkins University Press. 1996.
|
||||
* LU decomposition, forward and back substitution: Chapter 3.
|
||||
*/
|
||||
|
||||
MATRIX_TEST_EXPORT inline int
|
||||
matrix_invert(double *A, unsigned *p, const struct weston_matrix *matrix)
|
||||
{
|
||||
unsigned i, j, k;
|
||||
unsigned pivot;
|
||||
double pv;
|
||||
|
||||
for (i = 0; i < 4; ++i)
|
||||
p[i] = i;
|
||||
for (i = 16; i--; )
|
||||
A[i] = matrix->d[i];
|
||||
|
||||
/* LU decomposition with partial pivoting */
|
||||
for (k = 0; k < 4; ++k) {
|
||||
pivot = find_pivot(&A[k * 4], k);
|
||||
if (pivot != k) {
|
||||
swap_unsigned(&p[k], &p[pivot]);
|
||||
swap_rows(&A[k], &A[pivot]);
|
||||
}
|
||||
|
||||
pv = A[k * 4 + k];
|
||||
if (fabs(pv) < 1e-9)
|
||||
return -1; /* zero pivot, not invertible */
|
||||
|
||||
for (i = k + 1; i < 4; ++i) {
|
||||
A[i + k * 4] /= pv;
|
||||
|
||||
for (j = k + 1; j < 4; ++j)
|
||||
A[i + j * 4] -= A[i + k * 4] * A[k + j * 4];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MATRIX_TEST_EXPORT inline void
|
||||
inverse_transform(const double *LU, const unsigned *p, GLfloat *v)
|
||||
{
|
||||
/* Solve A * x = v, when we have P * A = L * U.
|
||||
* P * A * x = P * v => L * U * x = P * v
|
||||
* Let U * x = b, then L * b = P * v.
|
||||
*/
|
||||
double b[4];
|
||||
unsigned j;
|
||||
|
||||
/* Forward substitution, column version, solves L * b = P * v */
|
||||
/* The diagonal of L is all ones, and not explicitly stored. */
|
||||
b[0] = v[p[0]];
|
||||
b[1] = (double)v[p[1]] - b[0] * LU[1 + 0 * 4];
|
||||
b[2] = (double)v[p[2]] - b[0] * LU[2 + 0 * 4];
|
||||
b[3] = (double)v[p[3]] - b[0] * LU[3 + 0 * 4];
|
||||
b[2] -= b[1] * LU[2 + 1 * 4];
|
||||
b[3] -= b[1] * LU[3 + 1 * 4];
|
||||
b[3] -= b[2] * LU[3 + 2 * 4];
|
||||
|
||||
/* backward substitution, column version, solves U * y = b */
|
||||
#if 1
|
||||
/* hand-unrolled, 25% faster for whole function */
|
||||
b[3] /= LU[3 + 3 * 4];
|
||||
b[0] -= b[3] * LU[0 + 3 * 4];
|
||||
b[1] -= b[3] * LU[1 + 3 * 4];
|
||||
b[2] -= b[3] * LU[2 + 3 * 4];
|
||||
|
||||
b[2] /= LU[2 + 2 * 4];
|
||||
b[0] -= b[2] * LU[0 + 2 * 4];
|
||||
b[1] -= b[2] * LU[1 + 2 * 4];
|
||||
|
||||
b[1] /= LU[1 + 1 * 4];
|
||||
b[0] -= b[1] * LU[0 + 1 * 4];
|
||||
|
||||
b[0] /= LU[0 + 0 * 4];
|
||||
#else
|
||||
for (j = 3; j > 0; --j) {
|
||||
unsigned k;
|
||||
b[j] /= LU[j + j * 4];
|
||||
for (k = 0; k < j; ++k)
|
||||
b[k] -= b[j] * LU[k + j * 4];
|
||||
}
|
||||
|
||||
b[0] /= LU[0 + 0 * 4];
|
||||
#endif
|
||||
|
||||
/* the result */
|
||||
for (j = 0; j < 4; ++j)
|
||||
v[j] = b[j];
|
||||
}
|
||||
|
||||
WL_EXPORT int
|
||||
weston_matrix_invert(struct weston_matrix *inverse,
|
||||
const struct weston_matrix *matrix)
|
||||
{
|
||||
double LU[16]; /* column-major */
|
||||
unsigned perm[4]; /* permutation */
|
||||
unsigned c;
|
||||
|
||||
if (matrix_invert(LU, perm, matrix) < 0)
|
||||
return -1;
|
||||
|
||||
weston_matrix_init(inverse);
|
||||
for (c = 0; c < 4; ++c)
|
||||
inverse_transform(LU, perm, &inverse->d[c * 4]);
|
||||
|
||||
return 0;
|
||||
}
|
64
src/matrix.h
Normal file
64
src/matrix.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright © 2008-2011 Kristian Høgsberg
|
||||
* Copyright © 2012 Collabora, Ltd.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
* that the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of the copyright holders not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. The copyright holders make
|
||||
* no representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef WESTON_MATRIX_H
|
||||
#define WESTON_MATRIX_H
|
||||
|
||||
struct weston_matrix {
|
||||
GLfloat d[16];
|
||||
};
|
||||
|
||||
struct weston_vector {
|
||||
GLfloat f[4];
|
||||
};
|
||||
|
||||
void
|
||||
weston_matrix_init(struct weston_matrix *matrix);
|
||||
void
|
||||
weston_matrix_multiply(struct weston_matrix *m, const struct weston_matrix *n);
|
||||
void
|
||||
weston_matrix_scale(struct weston_matrix *matrix, GLfloat x, GLfloat y, GLfloat z);
|
||||
void
|
||||
weston_matrix_translate(struct weston_matrix *matrix,
|
||||
GLfloat x, GLfloat y, GLfloat z);
|
||||
void
|
||||
weston_matrix_transform(struct weston_matrix *matrix, struct weston_vector *v);
|
||||
|
||||
int
|
||||
weston_matrix_invert(struct weston_matrix *inverse,
|
||||
const struct weston_matrix *matrix);
|
||||
|
||||
#ifdef UNIT_TEST
|
||||
# define MATRIX_TEST_EXPORT WL_EXPORT
|
||||
|
||||
int
|
||||
matrix_invert(double *A, unsigned *p, const struct weston_matrix *matrix);
|
||||
|
||||
void
|
||||
inverse_transform(const double *LU, const unsigned *p, GLfloat *v);
|
||||
|
||||
#else
|
||||
# define MATRIX_TEST_EXPORT static
|
||||
#endif
|
||||
|
||||
#endif /* WESTON_MATRIX_H */
|
240
src/shell.c
240
src/shell.c
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright © 2010 Intel Corporation
|
||||
* Copyright © 2011 Collabora, Ltd.
|
||||
* Copyright © 2011-2012 Collabora, Ltd.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
@ -29,6 +29,7 @@
|
||||
#include <linux/input.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <wayland-server.h>
|
||||
#include "compositor.h"
|
||||
@ -93,6 +94,10 @@ struct shell_surface {
|
||||
enum shell_surface_type type;
|
||||
int32_t saved_x, saved_y;
|
||||
|
||||
struct {
|
||||
struct weston_transform transform;
|
||||
} rotation;
|
||||
|
||||
struct {
|
||||
struct wl_grab grab;
|
||||
uint32_t time;
|
||||
@ -110,6 +115,15 @@ struct weston_move_grab {
|
||||
int32_t dx, dy;
|
||||
};
|
||||
|
||||
struct rotate_grab {
|
||||
struct wl_grab grab;
|
||||
struct shell_surface *surface;
|
||||
struct {
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
} center;
|
||||
};
|
||||
|
||||
static void
|
||||
shell_configuration(struct wl_shell *shell)
|
||||
{
|
||||
@ -152,7 +166,7 @@ move_grab_motion(struct wl_grab *grab,
|
||||
weston_surface_configure(es,
|
||||
device->x + move->dx,
|
||||
device->y + move->dy,
|
||||
es->width, es->height);
|
||||
es->geometry.width, es->geometry.height);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -184,8 +198,8 @@ weston_surface_move(struct weston_surface *es,
|
||||
return -1;
|
||||
|
||||
move->grab.interface = &move_grab_interface;
|
||||
move->dx = es->x - wd->input_device.grab_x;
|
||||
move->dy = es->y - wd->input_device.grab_y;
|
||||
move->dx = es->geometry.x - wd->input_device.grab_x;
|
||||
move->dy = es->geometry.y - wd->input_device.grab_y;
|
||||
move->surface = es;
|
||||
|
||||
wl_input_device_start_grab(&wd->input_device, &move->grab, time);
|
||||
@ -282,10 +296,10 @@ weston_surface_resize(struct shell_surface *shsurf,
|
||||
|
||||
resize->grab.interface = &resize_grab_interface;
|
||||
resize->edges = edges;
|
||||
resize->dx = es->x - wd->input_device.grab_x;
|
||||
resize->dy = es->y - wd->input_device.grab_y;
|
||||
resize->width = es->width;
|
||||
resize->height = es->height;
|
||||
resize->dx = es->geometry.x - wd->input_device.grab_x;
|
||||
resize->dy = es->geometry.y - wd->input_device.grab_y;
|
||||
resize->width = es->geometry.width;
|
||||
resize->height = es->geometry.height;
|
||||
resize->shsurf = shsurf;
|
||||
|
||||
if (edges == 0 || edges > 15 ||
|
||||
@ -328,8 +342,9 @@ reset_shell_surface_type(struct shell_surface *surface)
|
||||
{
|
||||
switch (surface->type) {
|
||||
case SHELL_SURFACE_FULLSCREEN:
|
||||
surface->surface->x = surface->saved_x;
|
||||
surface->surface->y = surface->saved_y;
|
||||
surface->surface->geometry.x = surface->saved_x;
|
||||
surface->surface->geometry.y = surface->saved_y;
|
||||
surface->surface->geometry.dirty = 1;
|
||||
surface->surface->fullscreen_output = NULL;
|
||||
break;
|
||||
case SHELL_SURFACE_PANEL:
|
||||
@ -385,8 +400,9 @@ shell_surface_set_transient(struct wl_client *client,
|
||||
/* assign to parents output */
|
||||
es->output = pes->output;
|
||||
|
||||
es->x = pes->x + x;
|
||||
es->y = pes->y + y;
|
||||
es->geometry.x = pes->geometry.x + x;
|
||||
es->geometry.y = pes->geometry.y + y;
|
||||
es->geometry.dirty = 1;
|
||||
|
||||
weston_surface_damage(es);
|
||||
shsurf->type = SHELL_SURFACE_TRANSIENT;
|
||||
@ -416,10 +432,11 @@ shell_surface_set_fullscreen(struct wl_client *client,
|
||||
output = get_default_output(es->compositor);
|
||||
es->output = output;
|
||||
|
||||
shsurf->saved_x = es->x;
|
||||
shsurf->saved_y = es->y;
|
||||
es->x = (output->current->width - es->width) / 2;
|
||||
es->y = (output->current->height - es->height) / 2;
|
||||
shsurf->saved_x = es->geometry.x;
|
||||
shsurf->saved_y = es->geometry.y;
|
||||
es->geometry.x = (output->current->width - es->geometry.width) / 2;
|
||||
es->geometry.y = (output->current->height - es->geometry.height) / 2;
|
||||
es->geometry.dirty = 1;
|
||||
es->fullscreen_output = output;
|
||||
weston_surface_damage(es);
|
||||
shsurf->type = SHELL_SURFACE_FULLSCREEN;
|
||||
@ -501,8 +518,9 @@ shell_map_popup(struct shell_surface *shsurf, uint32_t time)
|
||||
shsurf->popup.grab.interface = &popup_grab_interface;
|
||||
device = es->compositor->input_device;
|
||||
|
||||
es->x = shsurf->parent->surface->x + shsurf->popup.x;
|
||||
es->y = shsurf->parent->surface->y + shsurf->popup.y;
|
||||
es->geometry.x = shsurf->parent->surface->geometry.x + shsurf->popup.x;
|
||||
es->geometry.y = shsurf->parent->surface->geometry.y + shsurf->popup.y;
|
||||
es->geometry.dirty = 1;
|
||||
|
||||
shsurf->popup.grab.input_device = device;
|
||||
shsurf->popup.time = device->grab_time;
|
||||
@ -621,6 +639,9 @@ shell_get_shell_surface(struct wl_client *client,
|
||||
/* init link so its safe to always remove it in destroy_shell_surface */
|
||||
wl_list_init(&shsurf->link);
|
||||
|
||||
/* empty when not in use */
|
||||
wl_list_init(&shsurf->rotation.transform.link);
|
||||
|
||||
shsurf->type = SHELL_SURFACE_NONE;
|
||||
|
||||
wl_client_add_resource(client, &shsurf->resource);
|
||||
@ -673,10 +694,10 @@ show_screensaver(struct wl_shell *shell, struct shell_surface *surface)
|
||||
wl_list_remove(&surface->surface->link);
|
||||
wl_list_insert(list, &surface->surface->link);
|
||||
weston_surface_configure(surface->surface,
|
||||
surface->surface->x,
|
||||
surface->surface->y,
|
||||
surface->surface->width,
|
||||
surface->surface->height);
|
||||
surface->surface->geometry.x,
|
||||
surface->surface->geometry.y,
|
||||
surface->surface->geometry.width,
|
||||
surface->surface->geometry.height);
|
||||
surface->surface->output = surface->output;
|
||||
}
|
||||
|
||||
@ -716,8 +737,9 @@ desktop_shell_set_background(struct wl_client *client,
|
||||
|
||||
wl_list_insert(&shell->backgrounds, &shsurf->link);
|
||||
|
||||
surface->x = shsurf->output->x;
|
||||
surface->y = shsurf->output->y;
|
||||
surface->geometry.x = shsurf->output->x;
|
||||
surface->geometry.y = shsurf->output->y;
|
||||
surface->geometry.dirty = 1;
|
||||
|
||||
wl_resource_post_event(resource,
|
||||
DESKTOP_SHELL_CONFIGURE,
|
||||
@ -754,8 +776,9 @@ desktop_shell_set_panel(struct wl_client *client,
|
||||
|
||||
wl_list_insert(&shell->panels, &shsurf->link);
|
||||
|
||||
surface->x = shsurf->output->x;
|
||||
surface->y = shsurf->output->y;
|
||||
surface->geometry.x = shsurf->output->x;
|
||||
surface->geometry.y = shsurf->output->y;
|
||||
surface->geometry.dirty = 1;
|
||||
|
||||
wl_resource_post_event(resource,
|
||||
DESKTOP_SHELL_CONFIGURE,
|
||||
@ -813,8 +836,10 @@ resume_desktop(struct wl_shell *shell)
|
||||
terminate_screensaver(shell);
|
||||
|
||||
wl_list_for_each(surface, &shell->hidden_surface_list, link)
|
||||
weston_surface_configure(surface, surface->x, surface->y,
|
||||
surface->width, surface->height);
|
||||
weston_surface_configure(surface, surface->geometry.x,
|
||||
surface->geometry.y,
|
||||
surface->geometry.width,
|
||||
surface->geometry.height);
|
||||
|
||||
if (wl_list_empty(&shell->backgrounds)) {
|
||||
list = &shell->compositor->surface_list;
|
||||
@ -915,19 +940,20 @@ resize_binding(struct wl_input_device *device, uint32_t time,
|
||||
break;
|
||||
}
|
||||
|
||||
x = device->grab_x - surface->x;
|
||||
y = device->grab_y - surface->y;
|
||||
/* FIXME: convert properly to surface coordinates */
|
||||
x = device->grab_x - surface->geometry.x;
|
||||
y = device->grab_y - surface->geometry.y;
|
||||
|
||||
if (x < surface->width / 3)
|
||||
if (x < surface->geometry.width / 3)
|
||||
edges |= WL_SHELL_SURFACE_RESIZE_LEFT;
|
||||
else if (x < 2 * surface->width / 3)
|
||||
else if (x < 2 * surface->geometry.width / 3)
|
||||
edges |= 0;
|
||||
else
|
||||
edges |= WL_SHELL_SURFACE_RESIZE_RIGHT;
|
||||
|
||||
if (y < surface->height / 3)
|
||||
if (y < surface->geometry.height / 3)
|
||||
edges |= WL_SHELL_SURFACE_RESIZE_TOP;
|
||||
else if (y < 2 * surface->height / 3)
|
||||
else if (y < 2 * surface->geometry.height / 3)
|
||||
edges |= 0;
|
||||
else
|
||||
edges |= WL_SHELL_SURFACE_RESIZE_BOTTOM;
|
||||
@ -946,6 +972,114 @@ terminate_binding(struct wl_input_device *device, uint32_t time,
|
||||
wl_display_terminate(compositor->wl_display);
|
||||
}
|
||||
|
||||
static void
|
||||
rotate_grab_motion(struct wl_grab *grab,
|
||||
uint32_t time, int32_t x, int32_t y)
|
||||
{
|
||||
struct rotate_grab *rotate =
|
||||
container_of(grab, struct rotate_grab, grab);
|
||||
struct wl_input_device *device = grab->input_device;
|
||||
struct shell_surface *surface = rotate->surface;
|
||||
GLfloat dx, dy;
|
||||
GLfloat r;
|
||||
|
||||
dx = device->x - rotate->center.x;
|
||||
dy = device->y - rotate->center.y;
|
||||
r = sqrtf(dx * dx + dy * dy);
|
||||
|
||||
wl_list_remove(&surface->rotation.transform.link);
|
||||
surface->surface->geometry.dirty = 1;
|
||||
|
||||
if (r > 20.0f) {
|
||||
struct weston_matrix roto;
|
||||
struct weston_matrix *matrix =
|
||||
&surface->rotation.transform.matrix;
|
||||
|
||||
weston_matrix_init(&roto);
|
||||
roto.d[0] = dx / r;
|
||||
roto.d[4] = -dy / r;
|
||||
roto.d[1] = -roto.d[4];
|
||||
roto.d[5] = roto.d[0];
|
||||
|
||||
weston_matrix_init(matrix);
|
||||
weston_matrix_translate(matrix, -rotate->center.x,
|
||||
-rotate->center.y, 0.0f);
|
||||
weston_matrix_multiply(matrix, &roto);
|
||||
weston_matrix_translate(matrix, rotate->center.x,
|
||||
rotate->center.y, 0.0f);
|
||||
|
||||
wl_list_insert(
|
||||
surface->surface->geometry.transformation_list.prev,
|
||||
&surface->rotation.transform.link);
|
||||
} else {
|
||||
wl_list_init(&surface->rotation.transform.link);
|
||||
}
|
||||
|
||||
weston_compositor_damage_all(surface->surface->compositor);
|
||||
}
|
||||
|
||||
static void
|
||||
rotate_grab_button(struct wl_grab *grab,
|
||||
uint32_t time, int32_t button, int32_t state)
|
||||
{
|
||||
struct rotate_grab *rotate =
|
||||
container_of(grab, struct rotate_grab, grab);
|
||||
struct wl_input_device *device = grab->input_device;
|
||||
|
||||
if (device->button_count == 0 && state == 0) {
|
||||
wl_input_device_end_grab(device, time);
|
||||
free(rotate);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wl_grab_interface rotate_grab_interface = {
|
||||
noop_grab_focus,
|
||||
rotate_grab_motion,
|
||||
rotate_grab_button,
|
||||
};
|
||||
|
||||
static void
|
||||
rotate_binding(struct wl_input_device *device, uint32_t time,
|
||||
uint32_t key, uint32_t button, uint32_t state, void *data)
|
||||
{
|
||||
struct weston_surface *base_surface =
|
||||
(struct weston_surface *) device->pointer_focus;
|
||||
struct shell_surface *surface;
|
||||
struct rotate_grab *rotate;
|
||||
|
||||
if (base_surface == NULL)
|
||||
return;
|
||||
|
||||
surface = get_shell_surface(base_surface);
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
switch (surface->type) {
|
||||
case SHELL_SURFACE_PANEL:
|
||||
case SHELL_SURFACE_BACKGROUND:
|
||||
case SHELL_SURFACE_FULLSCREEN:
|
||||
case SHELL_SURFACE_SCREENSAVER:
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
rotate = malloc(sizeof *rotate);
|
||||
if (!rotate)
|
||||
return;
|
||||
|
||||
rotate->grab.interface = &rotate_grab_interface;
|
||||
rotate->surface = surface;
|
||||
|
||||
weston_surface_to_global(surface->surface,
|
||||
surface->surface->geometry.width / 2,
|
||||
surface->surface->geometry.height / 2,
|
||||
&rotate->center.x, &rotate->center.y);
|
||||
|
||||
wl_input_device_start_grab(device, &rotate->grab, time);
|
||||
wl_input_device_set_pointer_focus(device, NULL, time, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
activate(struct weston_shell *base, struct weston_surface *es,
|
||||
struct weston_input_device *device, uint32_t time)
|
||||
@ -1098,8 +1232,11 @@ center_on_output(struct weston_surface *surface, struct weston_output *output)
|
||||
{
|
||||
struct weston_mode *mode = output->current;
|
||||
|
||||
surface->x = output->x + (mode->width - surface->width) / 2;
|
||||
surface->y = output->y + (mode->height - surface->height) / 2;
|
||||
surface->geometry.x =
|
||||
output->x + (mode->width - surface->geometry.width) / 2;
|
||||
surface->geometry.y =
|
||||
output->y + (mode->height - surface->geometry.height) / 2;
|
||||
surface->geometry.dirty = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1125,14 +1262,16 @@ map(struct weston_shell *base,
|
||||
do_configure = 1;
|
||||
}
|
||||
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->geometry.width = width;
|
||||
surface->geometry.height = height;
|
||||
surface->geometry.dirty = 1;
|
||||
|
||||
/* initial positioning, see also configure() */
|
||||
switch (surface_type) {
|
||||
case SHELL_SURFACE_TOPLEVEL:
|
||||
surface->x = 10 + random() % 400;
|
||||
surface->y = 10 + random() % 400;
|
||||
surface->geometry.x = 10 + random() % 400;
|
||||
surface->geometry.y = 10 + random() % 400;
|
||||
surface->geometry.dirty = 1;
|
||||
break;
|
||||
case SHELL_SURFACE_SCREENSAVER:
|
||||
case SHELL_SURFACE_FULLSCREEN:
|
||||
@ -1189,8 +1328,9 @@ map(struct weston_shell *base,
|
||||
|
||||
switch (surface_type) {
|
||||
case SHELL_SURFACE_TOPLEVEL:
|
||||
surface->x = 10 + random() % 400;
|
||||
surface->y = 10 + random() % 400;
|
||||
surface->geometry.x = 10 + random() % 400;
|
||||
surface->geometry.y = 10 + random() % 400;
|
||||
surface->geometry.dirty = 1;
|
||||
break;
|
||||
case SHELL_SURFACE_POPUP:
|
||||
shell_map_popup(shsurf, shsurf->popup.time);
|
||||
@ -1199,10 +1339,12 @@ map(struct weston_shell *base,
|
||||
break;
|
||||
}
|
||||
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->geometry.width = width;
|
||||
surface->geometry.height = height;
|
||||
surface->geometry.dirty = 1;
|
||||
if (do_configure) {
|
||||
weston_surface_configure(surface, surface->x, surface->y,
|
||||
weston_surface_configure(surface, surface->geometry.x,
|
||||
surface->geometry.y,
|
||||
width, height);
|
||||
weston_compositor_repick(compositor);
|
||||
}
|
||||
@ -1238,8 +1380,9 @@ configure(struct weston_shell *base, struct weston_surface *surface,
|
||||
if (shsurf)
|
||||
surface_type = shsurf->type;
|
||||
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->geometry.width = width;
|
||||
surface->geometry.height = height;
|
||||
surface->geometry.dirty = 1;
|
||||
|
||||
switch (surface_type) {
|
||||
case SHELL_SURFACE_SCREENSAVER:
|
||||
@ -1474,6 +1617,9 @@ shell_init(struct weston_compositor *ec)
|
||||
terminate_binding, ec);
|
||||
weston_compositor_add_binding(ec, 0, BTN_LEFT, 0,
|
||||
click_to_activate_binding, ec);
|
||||
weston_compositor_add_binding(ec, 0, BTN_LEFT,
|
||||
MODIFIER_SUPER | MODIFIER_ALT,
|
||||
rotate_binding, NULL);
|
||||
|
||||
ec->shell = &shell->shell;
|
||||
|
||||
|
@ -110,8 +110,9 @@ tablet_shell_map(struct weston_shell *base, struct weston_surface *surface,
|
||||
struct tablet_shell *shell =
|
||||
container_of(base, struct tablet_shell, shell);
|
||||
|
||||
surface->x = 0;
|
||||
surface->y = 0;
|
||||
surface->geometry.x = 0;
|
||||
surface->geometry.y = 0;
|
||||
surface->geometry.dirty = 1;
|
||||
|
||||
if (surface == shell->lockscreen_surface) {
|
||||
/* */
|
||||
@ -133,7 +134,8 @@ tablet_shell_map(struct weston_shell *base, struct weston_surface *surface,
|
||||
}
|
||||
|
||||
wl_list_insert(&shell->compositor->surface_list, &surface->link);
|
||||
weston_surface_configure(surface, surface->x, surface->y, width, height);
|
||||
weston_surface_configure(surface, surface->geometry.x,
|
||||
surface->geometry.y, width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -165,8 +167,9 @@ tablet_shell_set_lockscreen(struct wl_client *client,
|
||||
struct tablet_shell *shell = resource->data;
|
||||
struct weston_surface *es = surface_resource->data;
|
||||
|
||||
es->x = 0;
|
||||
es->y = 0;
|
||||
es->geometry.x = 0;
|
||||
es->geometry.y = 0;
|
||||
es->geometry.dirty = 1;
|
||||
shell->lockscreen_surface = es;
|
||||
shell->lockscreen_listener.func = handle_lockscreen_surface_destroy;
|
||||
wl_list_insert(es->surface.resource.destroy_listener_list.prev,
|
||||
@ -199,8 +202,9 @@ tablet_shell_set_switcher(struct wl_client *client,
|
||||
* layer idea, we should be able to hit the framerate on the
|
||||
* fade/zoom in. */
|
||||
shell->switcher_surface = es;
|
||||
shell->switcher_surface->x = 0;
|
||||
shell->switcher_surface->y = 0;
|
||||
shell->switcher_surface->geometry.x = 0;
|
||||
shell->switcher_surface->geometry.y = 0;
|
||||
shell->switcher_surface->geometry.dirty = 1;
|
||||
|
||||
shell->switcher_listener.func = handle_switcher_surface_destroy;
|
||||
wl_list_insert(es->surface.resource.destroy_listener_list.prev,
|
||||
@ -215,8 +219,9 @@ tablet_shell_set_homescreen(struct wl_client *client,
|
||||
struct tablet_shell *shell = resource->data;
|
||||
|
||||
shell->home_surface = surface_resource->data;
|
||||
shell->home_surface->x = 0;
|
||||
shell->home_surface->y = 0;
|
||||
shell->home_surface->geometry.x = 0;
|
||||
shell->home_surface->geometry.y = 0;
|
||||
shell->home_surface->geometry.dirty = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
|
85
src/util.c
85
src/util.c
@ -27,70 +27,6 @@
|
||||
|
||||
#include "compositor.h"
|
||||
|
||||
WL_EXPORT void
|
||||
weston_matrix_init(struct weston_matrix *matrix)
|
||||
{
|
||||
static const struct weston_matrix identity = {
|
||||
{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }
|
||||
};
|
||||
|
||||
memcpy(matrix, &identity, sizeof identity);
|
||||
}
|
||||
|
||||
static void
|
||||
weston_matrix_multiply(struct weston_matrix *m, const struct weston_matrix *n)
|
||||
{
|
||||
struct weston_matrix tmp;
|
||||
const GLfloat *row, *column;
|
||||
div_t d;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
tmp.d[i] = 0;
|
||||
d = div(i, 4);
|
||||
row = m->d + d.quot * 4;
|
||||
column = n->d + d.rem;
|
||||
for (j = 0; j < 4; j++)
|
||||
tmp.d[i] += row[j] * column[j * 4];
|
||||
}
|
||||
memcpy(m, &tmp, sizeof tmp);
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
weston_matrix_translate(struct weston_matrix *matrix, GLfloat x, GLfloat y, GLfloat z)
|
||||
{
|
||||
struct weston_matrix translate = {
|
||||
{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1 }
|
||||
};
|
||||
|
||||
weston_matrix_multiply(matrix, &translate);
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
weston_matrix_scale(struct weston_matrix *matrix, GLfloat x, GLfloat y, GLfloat z)
|
||||
{
|
||||
struct weston_matrix scale = {
|
||||
{ x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1 }
|
||||
};
|
||||
|
||||
weston_matrix_multiply(matrix, &scale);
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
weston_matrix_transform(struct weston_matrix *matrix, struct weston_vector *v)
|
||||
{
|
||||
int i, j;
|
||||
struct weston_vector t;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
t.f[i] = 0;
|
||||
for (j = 0; j < 4; j++)
|
||||
t.f[i] += v->f[j] * matrix->d[i + j * 4];
|
||||
}
|
||||
|
||||
*v = t;
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
weston_spring_init(struct weston_spring *spring,
|
||||
double k, double current, double target)
|
||||
@ -162,7 +98,8 @@ weston_zoom_destroy(struct weston_zoom *zoom)
|
||||
{
|
||||
wl_list_remove(&zoom->animation.link);
|
||||
wl_list_remove(&zoom->listener.link);
|
||||
zoom->surface->transform = NULL;
|
||||
wl_list_remove(&zoom->transform.link);
|
||||
zoom->surface->geometry.dirty = 1;
|
||||
if (zoom->done)
|
||||
zoom->done(zoom, zoom->data);
|
||||
free(zoom);
|
||||
@ -198,19 +135,18 @@ weston_zoom_frame(struct weston_animation *animation,
|
||||
(zoom->stop - zoom->start) * zoom->spring.current;
|
||||
weston_matrix_init(&zoom->transform.matrix);
|
||||
weston_matrix_translate(&zoom->transform.matrix,
|
||||
-(es->x + es->width / 2.0),
|
||||
-(es->y + es->height / 2.0), 0);
|
||||
-0.5f * es->geometry.width,
|
||||
-0.5f * es->geometry.height, 0);
|
||||
weston_matrix_scale(&zoom->transform.matrix, scale, scale, scale);
|
||||
weston_matrix_translate(&zoom->transform.matrix,
|
||||
es->x + es->width / 2.0,
|
||||
es->y + es->height / 2.0, 0);
|
||||
0.5f * es->geometry.width,
|
||||
0.5f * es->geometry.height, 0);
|
||||
|
||||
es->alpha = zoom->spring.current * 255;
|
||||
if (es->alpha > 255)
|
||||
es->alpha = 255;
|
||||
scale = 1.0 / zoom->spring.current;
|
||||
weston_matrix_init(&zoom->transform.inverse);
|
||||
weston_matrix_scale(&zoom->transform.inverse, scale, scale, scale);
|
||||
|
||||
zoom->surface->geometry.dirty = 1;
|
||||
|
||||
weston_compositor_damage_all(es->compositor);
|
||||
}
|
||||
@ -230,7 +166,8 @@ weston_zoom_run(struct weston_surface *surface, GLfloat start, GLfloat stop,
|
||||
zoom->data = data;
|
||||
zoom->start = start;
|
||||
zoom->stop = stop;
|
||||
surface->transform = &zoom->transform;
|
||||
wl_list_insert(&surface->geometry.transformation_list,
|
||||
&zoom->transform.link);
|
||||
weston_spring_init(&zoom->spring, 200.0, 0.0, 1.0);
|
||||
zoom->spring.friction = 700;
|
||||
zoom->spring.timestamp = weston_compositor_get_time();
|
||||
@ -241,7 +178,7 @@ weston_zoom_run(struct weston_surface *surface, GLfloat start, GLfloat stop,
|
||||
wl_list_insert(surface->surface.resource.destroy_listener_list.prev,
|
||||
&zoom->listener.link);
|
||||
|
||||
wl_list_insert(surface->compositor->animation_list.prev,
|
||||
wl_list_insert(&surface->compositor->animation_list,
|
||||
&zoom->animation.link);
|
||||
|
||||
return zoom;
|
||||
|
2
tests/.gitignore
vendored
Normal file
2
tests/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
matrix-test
|
||||
|
15
tests/Makefile.am
Normal file
15
tests/Makefile.am
Normal file
@ -0,0 +1,15 @@
|
||||
if BUILD_TESTS
|
||||
|
||||
noinst_PROGRAMS = matrix-test
|
||||
|
||||
endif
|
||||
|
||||
|
||||
AM_CFLAGS = $(GCC_CFLAGS)
|
||||
AM_CPPFLAGS = -I../src -DUNIT_TEST
|
||||
|
||||
matrix_test_SOURCES = \
|
||||
matrix-test.c \
|
||||
../src/matrix.c \
|
||||
../src/matrix.h
|
||||
matrix_test_LDADD = -lm -lrt
|
422
tests/matrix-test.c
Normal file
422
tests/matrix-test.c
Normal file
@ -0,0 +1,422 @@
|
||||
/*
|
||||
* Copyright © 2012 Collabora, Ltd.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
* that the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of the copyright holders not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. The copyright holders make
|
||||
* no representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <GLES2/gl2.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "matrix.h"
|
||||
|
||||
struct inverse_matrix {
|
||||
double LU[16]; /* column-major */
|
||||
unsigned perm[4]; /* permutation */
|
||||
};
|
||||
|
||||
static struct timespec begin_time;
|
||||
|
||||
static void
|
||||
reset_timer(void)
|
||||
{
|
||||
clock_gettime(CLOCK_MONOTONIC, &begin_time);
|
||||
}
|
||||
|
||||
static double
|
||||
read_timer(void)
|
||||
{
|
||||
struct timespec t;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &t);
|
||||
return (double)(t.tv_sec - begin_time.tv_sec) +
|
||||
1e-9 * (t.tv_nsec - begin_time.tv_nsec);
|
||||
}
|
||||
|
||||
static double
|
||||
det3x3(const GLfloat *c0, const GLfloat *c1, const GLfloat *c2)
|
||||
{
|
||||
return (double)
|
||||
c0[0] * c1[1] * c2[2] +
|
||||
c1[0] * c2[1] * c0[2] +
|
||||
c2[0] * c0[1] * c1[2] -
|
||||
c0[2] * c1[1] * c2[0] -
|
||||
c1[2] * c2[1] * c0[0] -
|
||||
c2[2] * c0[1] * c1[0];
|
||||
}
|
||||
|
||||
static double
|
||||
determinant(const struct weston_matrix *m)
|
||||
{
|
||||
double det = 0;
|
||||
#if 1
|
||||
/* develop on last row */
|
||||
det -= m->d[3 + 0 * 4] * det3x3(&m->d[4], &m->d[8], &m->d[12]);
|
||||
det += m->d[3 + 1 * 4] * det3x3(&m->d[0], &m->d[8], &m->d[12]);
|
||||
det -= m->d[3 + 2 * 4] * det3x3(&m->d[0], &m->d[4], &m->d[12]);
|
||||
det += m->d[3 + 3 * 4] * det3x3(&m->d[0], &m->d[4], &m->d[8]);
|
||||
#else
|
||||
/* develop on first row */
|
||||
det += m->d[0 + 0 * 4] * det3x3(&m->d[5], &m->d[9], &m->d[13]);
|
||||
det -= m->d[0 + 1 * 4] * det3x3(&m->d[1], &m->d[9], &m->d[13]);
|
||||
det += m->d[0 + 2 * 4] * det3x3(&m->d[1], &m->d[5], &m->d[13]);
|
||||
det -= m->d[0 + 3 * 4] * det3x3(&m->d[1], &m->d[5], &m->d[9]);
|
||||
#endif
|
||||
return det;
|
||||
}
|
||||
|
||||
static void
|
||||
print_permutation_matrix(const struct inverse_matrix *m)
|
||||
{
|
||||
const unsigned *p = m->perm;
|
||||
const char *row[4] = {
|
||||
"1 0 0 0\n",
|
||||
"0 1 0 0\n",
|
||||
"0 0 1 0\n",
|
||||
"0 0 0 1\n"
|
||||
};
|
||||
|
||||
printf(" P =\n%s%s%s%s", row[p[0]], row[p[1]], row[p[2]], row[p[3]]);
|
||||
}
|
||||
|
||||
static void
|
||||
print_LU_decomposition(const struct inverse_matrix *m)
|
||||
{
|
||||
unsigned r, c;
|
||||
|
||||
printf(" L "
|
||||
" U\n");
|
||||
for (r = 0; r < 4; ++r) {
|
||||
double v;
|
||||
|
||||
for (c = 0; c < 4; ++c) {
|
||||
if (c < r)
|
||||
v = m->LU[r + c * 4];
|
||||
else if (c == r)
|
||||
v = 1.0;
|
||||
else
|
||||
v = 0.0;
|
||||
printf(" %12.6f", v);
|
||||
}
|
||||
|
||||
printf(" | ");
|
||||
|
||||
for (c = 0; c < 4; ++c) {
|
||||
if (c >= r)
|
||||
v = m->LU[r + c * 4];
|
||||
else
|
||||
v = 0.0;
|
||||
printf(" %12.6f", v);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_inverse_data_matrix(const struct inverse_matrix *m)
|
||||
{
|
||||
unsigned r, c;
|
||||
|
||||
for (r = 0; r < 4; ++r) {
|
||||
for (c = 0; c < 4; ++c)
|
||||
printf(" %12.6f", m->LU[r + c * 4]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printf("permutation: ");
|
||||
for (r = 0; r < 4; ++r)
|
||||
printf(" %u", m->perm[r]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
print_matrix(const struct weston_matrix *m)
|
||||
{
|
||||
unsigned r, c;
|
||||
|
||||
for (r = 0; r < 4; ++r) {
|
||||
for (c = 0; c < 4; ++c)
|
||||
printf(" %14.6e", m->d[r + c * 4]);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static double
|
||||
frand(void)
|
||||
{
|
||||
double r = random();
|
||||
return r / (double)(RAND_MAX / 2) - 1.0f;
|
||||
}
|
||||
|
||||
static void
|
||||
randomize_matrix(struct weston_matrix *m)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < 16; ++i)
|
||||
#if 1
|
||||
m->d[i] = frand() * exp(10.0 * frand());
|
||||
#else
|
||||
m->d[i] = frand();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Take a matrix, compute inverse, multiply together
|
||||
* and subtract the identity matrix to get the error matrix.
|
||||
* Return the largest absolute value from the error matrix.
|
||||
*/
|
||||
static double
|
||||
test_inverse(struct weston_matrix *m)
|
||||
{
|
||||
unsigned i;
|
||||
struct inverse_matrix q;
|
||||
double errsup = 0.0;
|
||||
|
||||
if (matrix_invert(q.LU, q.perm, m) != 0)
|
||||
return INFINITY;
|
||||
|
||||
for (i = 0; i < 4; ++i)
|
||||
inverse_transform(q.LU, q.perm, &m->d[i * 4]);
|
||||
|
||||
m->d[0] -= 1.0f;
|
||||
m->d[5] -= 1.0f;
|
||||
m->d[10] -= 1.0f;
|
||||
m->d[15] -= 1.0f;
|
||||
|
||||
for (i = 0; i < 16; ++i) {
|
||||
double err = fabs(m->d[i]);
|
||||
if (err > errsup)
|
||||
errsup = err;
|
||||
}
|
||||
|
||||
return errsup;
|
||||
}
|
||||
|
||||
enum {
|
||||
TEST_OK,
|
||||
TEST_NOT_INVERTIBLE_OK,
|
||||
TEST_FAIL,
|
||||
TEST_COUNT
|
||||
};
|
||||
|
||||
static int
|
||||
test(void)
|
||||
{
|
||||
struct weston_matrix m;
|
||||
struct weston_matrix n;
|
||||
double det, errsup;
|
||||
|
||||
randomize_matrix(&m);
|
||||
n = m;
|
||||
det = determinant(&m);
|
||||
|
||||
errsup = test_inverse(&m);
|
||||
if (errsup < 1e-6)
|
||||
return TEST_OK;
|
||||
|
||||
if (fabs(det) < 1e-5 && isinf(errsup))
|
||||
return TEST_NOT_INVERTIBLE_OK;
|
||||
|
||||
printf("test fail, det: %g, error sup: %g\n", det, errsup);
|
||||
/* print_matrix(&n);*/
|
||||
return TEST_FAIL;
|
||||
}
|
||||
|
||||
static int running;
|
||||
static void
|
||||
stopme(int n)
|
||||
{
|
||||
running = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
test_loop_precision(void)
|
||||
{
|
||||
int counts[TEST_COUNT] = { 0 };
|
||||
|
||||
printf("\nRunning a test loop for 10 seconds...\n");
|
||||
running = 1;
|
||||
alarm(10);
|
||||
while (running) {
|
||||
counts[test()]++;
|
||||
}
|
||||
|
||||
printf("tests: %d ok, %d not invertible but ok, %d failed.\n"
|
||||
"Total: %d iterations.\n",
|
||||
counts[TEST_OK], counts[TEST_NOT_INVERTIBLE_OK],
|
||||
counts[TEST_FAIL],
|
||||
counts[TEST_OK] + counts[TEST_NOT_INVERTIBLE_OK] +
|
||||
counts[TEST_FAIL]);
|
||||
}
|
||||
|
||||
static void __attribute__((noinline))
|
||||
test_loop_speed_matrixvector(void)
|
||||
{
|
||||
struct weston_matrix m;
|
||||
struct weston_vector v = { { 0.5, 0.5, 0.5, 1.0 } };
|
||||
unsigned long count = 0;
|
||||
double t;
|
||||
|
||||
printf("\nRunning 3 s test on weston_matrix_transform()...\n");
|
||||
|
||||
weston_matrix_init(&m);
|
||||
|
||||
running = 1;
|
||||
alarm(3);
|
||||
reset_timer();
|
||||
while (running) {
|
||||
weston_matrix_transform(&m, &v);
|
||||
count++;
|
||||
}
|
||||
t = read_timer();
|
||||
|
||||
printf("%lu iterations in %f seconds, avg. %.1f us/iter.\n",
|
||||
count, t, 1e9 * t / count);
|
||||
}
|
||||
|
||||
static void __attribute__((noinline))
|
||||
test_loop_speed_inversetransform(void)
|
||||
{
|
||||
struct weston_matrix m;
|
||||
struct inverse_matrix inv;
|
||||
struct weston_vector v = { { 0.5, 0.5, 0.5, 1.0 } };
|
||||
unsigned long count = 0;
|
||||
double t;
|
||||
|
||||
printf("\nRunning 3 s test on inverse_transform()...\n");
|
||||
|
||||
weston_matrix_init(&m);
|
||||
matrix_invert(inv.LU, inv.perm, &m);
|
||||
|
||||
running = 1;
|
||||
alarm(3);
|
||||
reset_timer();
|
||||
while (running) {
|
||||
inverse_transform(inv.LU, inv.perm, v.f);
|
||||
count++;
|
||||
}
|
||||
t = read_timer();
|
||||
|
||||
printf("%lu iterations in %f seconds, avg. %.1f us/iter.\n",
|
||||
count, t, 1e9 * t / count);
|
||||
}
|
||||
|
||||
static void __attribute__((noinline))
|
||||
test_loop_speed_invert(void)
|
||||
{
|
||||
struct weston_matrix m;
|
||||
struct inverse_matrix inv;
|
||||
unsigned long count = 0;
|
||||
double t;
|
||||
|
||||
printf("\nRunning 3 s test on matrix_invert()...\n");
|
||||
|
||||
weston_matrix_init(&m);
|
||||
|
||||
running = 1;
|
||||
alarm(3);
|
||||
reset_timer();
|
||||
while (running) {
|
||||
matrix_invert(inv.LU, inv.perm, &m);
|
||||
count++;
|
||||
}
|
||||
t = read_timer();
|
||||
|
||||
printf("%lu iterations in %f seconds, avg. %.1f ns/iter.\n",
|
||||
count, t, 1e9 * t / count);
|
||||
}
|
||||
|
||||
static void __attribute__((noinline))
|
||||
test_loop_speed_invert_explicit(void)
|
||||
{
|
||||
struct weston_matrix m;
|
||||
unsigned long count = 0;
|
||||
double t;
|
||||
|
||||
printf("\nRunning 3 s test on weston_matrix_invert()...\n");
|
||||
|
||||
weston_matrix_init(&m);
|
||||
|
||||
running = 1;
|
||||
alarm(3);
|
||||
reset_timer();
|
||||
while (running) {
|
||||
weston_matrix_invert(&m, &m);
|
||||
count++;
|
||||
}
|
||||
t = read_timer();
|
||||
|
||||
printf("%lu iterations in %f seconds, avg. %.1f ns/iter.\n",
|
||||
count, t, 1e9 * t / count);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct sigaction ding;
|
||||
struct weston_matrix M;
|
||||
struct inverse_matrix Q;
|
||||
int ret;
|
||||
double errsup;
|
||||
double det;
|
||||
|
||||
ding.sa_handler = stopme;
|
||||
sigemptyset(&ding.sa_mask);
|
||||
ding.sa_flags = 0;
|
||||
sigaction(SIGALRM, &ding, NULL);
|
||||
|
||||
srandom(13);
|
||||
|
||||
M.d[0] = 3.0; M.d[4] = 17.0; M.d[8] = 10.0; M.d[12] = 0.0;
|
||||
M.d[1] = 2.0; M.d[5] = 4.0; M.d[9] = -2.0; M.d[13] = 0.0;
|
||||
M.d[2] = 6.0; M.d[6] = 18.0; M.d[10] = -12; M.d[14] = 0.0;
|
||||
M.d[3] = 0.0; M.d[7] = 0.0; M.d[11] = 0.0; M.d[15] = 1.0;
|
||||
|
||||
ret = matrix_invert(Q.LU, Q.perm, &M);
|
||||
printf("ret = %d\n", ret);
|
||||
printf("det = %g\n\n", determinant(&M));
|
||||
|
||||
if (ret != 0)
|
||||
return 1;
|
||||
|
||||
print_inverse_data_matrix(&Q);
|
||||
printf("P * A = L * U\n");
|
||||
print_permutation_matrix(&Q);
|
||||
print_LU_decomposition(&Q);
|
||||
|
||||
|
||||
printf("a random matrix:\n");
|
||||
randomize_matrix(&M);
|
||||
det = determinant(&M);
|
||||
print_matrix(&M);
|
||||
errsup = test_inverse(&M);
|
||||
printf("\nThe matrix multiplied by its inverse, error:\n");
|
||||
print_matrix(&M);
|
||||
printf("max abs error: %g, original determinant %g\n", errsup, det);
|
||||
|
||||
test_loop_precision();
|
||||
test_loop_speed_matrixvector();
|
||||
test_loop_speed_inversetransform();
|
||||
test_loop_speed_invert();
|
||||
test_loop_speed_invert_explicit();
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user