Cliptest is for controlled testing of the calculate_edges() function in compositor.c. The function is copied verbatim into cliptest.c. Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>dev
parent
84ec19a758
commit
8c492b1293
@ -0,0 +1,833 @@ |
||||
/*
|
||||
* Copyright © 2012 Collabora, Ltd. |
||||
* Copyright © 2012 Rob Clark |
||||
* |
||||
* 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. |
||||
*/ |
||||
|
||||
/* cliptest: for debugging calculate_edges() function, which is copied
|
||||
* from compositor.c. |
||||
* controls: |
||||
* clip box position: mouse left drag, keys: w a s d |
||||
* clip box size: mouse right drag, keys: i j k l |
||||
* surface orientation: mouse wheel, keys: n m |
||||
* surface transform disable key: r |
||||
*/ |
||||
|
||||
#include <stdint.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <fcntl.h> |
||||
#include <libgen.h> |
||||
#include <unistd.h> |
||||
#include <math.h> |
||||
#include <time.h> |
||||
#include <pixman.h> |
||||
#include <cairo.h> |
||||
#include <float.h> |
||||
#include <assert.h> |
||||
|
||||
#include <linux/input.h> |
||||
#include <wayland-client.h> |
||||
|
||||
#include "window.h" |
||||
|
||||
typedef float GLfloat; |
||||
|
||||
struct geometry { |
||||
pixman_box32_t clip; |
||||
|
||||
pixman_box32_t surf; |
||||
float s; /* sin phi */ |
||||
float c; /* cos phi */ |
||||
float phi; |
||||
}; |
||||
|
||||
struct weston_surface { |
||||
struct { |
||||
int enabled; |
||||
} transform; |
||||
|
||||
struct geometry *geometry; |
||||
}; |
||||
|
||||
static void |
||||
weston_surface_to_global_float(struct weston_surface *surface, |
||||
GLfloat sx, GLfloat sy, GLfloat *x, GLfloat *y) |
||||
{ |
||||
struct geometry *g = surface->geometry; |
||||
|
||||
/* pure rotation around origin by sine and cosine */ |
||||
*x = g->c * sx + g->s * sy; |
||||
*y = -g->s * sx + g->c * sy; |
||||
} |
||||
|
||||
/* ---------------------- copied begins -----------------------*/ |
||||
|
||||
#define max(a, b) (((a) > (b)) ? (a) : (b)) |
||||
#define min(a, b) (((a) > (b)) ? (b) : (a)) |
||||
#define clip(x, a, b) min(max(x, a), b) |
||||
#define sign(x) ((x) >= 0) |
||||
|
||||
static int |
||||
calculate_edges(struct weston_surface *es, pixman_box32_t *rect, |
||||
pixman_box32_t *surf_rect, GLfloat *ex, GLfloat *ey) |
||||
{ |
||||
int i, n = 0; |
||||
GLfloat min_x, max_x, min_y, max_y; |
||||
GLfloat x[4] = { |
||||
surf_rect->x1, surf_rect->x2, surf_rect->x2, surf_rect->x1, |
||||
}; |
||||
GLfloat y[4] = { |
||||
surf_rect->y1, surf_rect->y1, surf_rect->y2, surf_rect->y2, |
||||
}; |
||||
GLfloat cx1 = rect->x1; |
||||
GLfloat cx2 = rect->x2; |
||||
GLfloat cy1 = rect->y1; |
||||
GLfloat cy2 = rect->y2; |
||||
|
||||
GLfloat dist_squared(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) |
||||
{ |
||||
GLfloat dx = (x1 - x2); |
||||
GLfloat dy = (y1 - y2); |
||||
return dx * dx + dy * dy; |
||||
} |
||||
|
||||
void append_vertex(GLfloat x, GLfloat y) |
||||
{ |
||||
/* don't emit duplicate vertices: */ |
||||
if ((n > 0) && (ex[n-1] == x) && (ey[n-1] == y)) |
||||
return; |
||||
ex[n] = x; |
||||
ey[n] = y; |
||||
n++; |
||||
} |
||||
|
||||
/* transform surface to screen space: */ |
||||
for (i = 0; i < 4; i++) |
||||
weston_surface_to_global_float(es, x[i], y[i], &x[i], &y[i]); |
||||
|
||||
/* find bounding box: */ |
||||
min_x = max_x = x[0]; |
||||
min_y = max_y = y[0]; |
||||
|
||||
for (i = 1; i < 4; i++) { |
||||
min_x = min(min_x, x[i]); |
||||
max_x = max(max_x, x[i]); |
||||
min_y = min(min_y, y[i]); |
||||
max_y = max(max_y, y[i]); |
||||
} |
||||
|
||||
/* First, simple bounding box check to discard early transformed
|
||||
* surface rects that do not intersect with the clip region: |
||||
*/ |
||||
if ((min_x > cx2) || (max_x < cx1) || |
||||
(min_y > cy2) || (max_y < cy1)) |
||||
return 0; |
||||
|
||||
/* Simple case, bounding box edges are parallel to surface edges,
|
||||
* there will be only four edges. We just need to clip the surface |
||||
* vertices to the clip rect bounds: |
||||
*/ |
||||
if (!es->transform.enabled) { |
||||
for (i = 0; i < 4; i++) { |
||||
ex[n] = clip(x[i], cx1, cx2); |
||||
ey[n] = clip(y[i], cy1, cy2); |
||||
n++; |
||||
} |
||||
return 4; |
||||
} |
||||
|
||||
/* Hard case, transformation applied. We need to find the vertices
|
||||
* of the shape that is the intersection of the clip rect and |
||||
* transformed surface. This can be anything from 3 to 8 sides. |
||||
* |
||||
* Observation: all the resulting vertices will be the intersection |
||||
* points of the transformed surface and the clip rect, plus the |
||||
* vertices of the clip rect which are enclosed by the transformed |
||||
* surface and the vertices of the transformed surface which are |
||||
* enclosed by the clip rect. |
||||
* |
||||
* Observation: there will be zero, one, or two resulting vertices |
||||
* for each edge of the src rect. |
||||
* |
||||
* Loop over four edges of the transformed rect: |
||||
*/ |
||||
for (i = 0; i < 4; i++) { |
||||
GLfloat x1, y1, x2, y2; |
||||
int last_n = n; |
||||
|
||||
x1 = x[i]; |
||||
y1 = y[i]; |
||||
|
||||
/* if this vertex is contained in the clip rect, use it as-is: */ |
||||
if ((cx1 <= x1) && (x1 <= cx2) && |
||||
(cy1 <= y1) && (y1 <= cy2)) |
||||
append_vertex(x1, y1); |
||||
|
||||
/* for remaining, we consider the point as part of a line: */ |
||||
x2 = x[(i+1) % 4]; |
||||
y2 = y[(i+1) % 4]; |
||||
|
||||
if (x1 == x2) { |
||||
append_vertex(clip(x1, cx1, cx2), clip(y1, cy1, cy2)); |
||||
append_vertex(clip(x2, cx1, cx2), clip(y2, cy1, cy2)); |
||||
} else if (y1 == y2) { |
||||
append_vertex(clip(x1, cx1, cx2), clip(y1, cy1, cy2)); |
||||
append_vertex(clip(x2, cx1, cx2), clip(y2, cy1, cy2)); |
||||
} else { |
||||
GLfloat m, c, p; |
||||
GLfloat tx[2], ty[2]; |
||||
int tn = 0; |
||||
|
||||
int intersect_horiz(GLfloat y, GLfloat *p) |
||||
{ |
||||
GLfloat x; |
||||
|
||||
/* if y does not lie between y1 and y2, no
|
||||
* intersection possible |
||||
*/ |
||||
if (sign(y-y1) == sign(y-y2)) |
||||
return 0; |
||||
|
||||
x = (y - c) / m; |
||||
|
||||
/* if x does not lie between cx1 and cx2, no
|
||||
* intersection: |
||||
*/ |
||||
if (sign(x-cx1) == sign(x-cx2)) |
||||
return 0; |
||||
|
||||
*p = x; |
||||
return 1; |
||||
} |
||||
|
||||
int intersect_vert(GLfloat x, GLfloat *p) |
||||
{ |
||||
GLfloat y; |
||||
|
||||
if (sign(x-x1) == sign(x-x2)) |
||||
return 0; |
||||
|
||||
y = m * x + c; |
||||
|
||||
if (sign(y-cy1) == sign(y-cy2)) |
||||
return 0; |
||||
|
||||
*p = y; |
||||
return 1; |
||||
} |
||||
|
||||
/* y = mx + c */ |
||||
m = (y2 - y1) / (x2 - x1); |
||||
c = y1 - m * x1; |
||||
|
||||
/* check for up to two intersections with the four edges
|
||||
* of the clip rect. Note that we don't know the orientation |
||||
* of the transformed surface wrt. the clip rect. So if when |
||||
* there are two intersection points, we need to put the one |
||||
* closest to x1,y1 first: |
||||
*/ |
||||
|
||||
/* check top clip rect edge: */ |
||||
if (intersect_horiz(cy1, &p)) { |
||||
ty[tn] = cy1; |
||||
tx[tn] = p; |
||||
tn++; |
||||
} |
||||
|
||||
/* check right clip rect edge: */ |
||||
if (intersect_vert(cx2, &p)) { |
||||
ty[tn] = p; |
||||
tx[tn] = cx2; |
||||
tn++; |
||||
if (tn == 2) |
||||
goto edge_check_done; |
||||
} |
||||
|
||||
/* check bottom clip rect edge: */ |
||||
if (intersect_horiz(cy2, &p)) { |
||||
ty[tn] = cy2; |
||||
tx[tn] = p; |
||||
tn++; |
||||
if (tn == 2) |
||||
goto edge_check_done; |
||||
} |
||||
|
||||
/* check left clip rect edge: */ |
||||
if (intersect_vert(cx1, &p)) { |
||||
ty[tn] = p; |
||||
tx[tn] = cx1; |
||||
tn++; |
||||
} |
||||
|
||||
edge_check_done: |
||||
if (tn == 1) { |
||||
append_vertex(tx[0], ty[0]); |
||||
} else if (tn == 2) { |
||||
if (dist_squared(x1, y1, tx[0], ty[0]) < |
||||
dist_squared(x1, y1, tx[1], ty[1])) { |
||||
append_vertex(tx[0], ty[0]); |
||||
append_vertex(tx[1], ty[1]); |
||||
} else { |
||||
append_vertex(tx[1], ty[1]); |
||||
append_vertex(tx[0], ty[0]); |
||||
} |
||||
} |
||||
|
||||
if (n == last_n) { |
||||
GLfloat best_x=0, best_y=0; |
||||
uint32_t d, best_d = (unsigned int)-1; /* distance squared */ |
||||
uint32_t max_d = dist_squared(x2, y2, |
||||
x[(i+2) % 4], y[(i+2) % 4]); |
||||
|
||||
/* if there are no vertices on this line, it could be that
|
||||
* there is a vertex of the clip rect that is enclosed by |
||||
* the transformed surface. Find the vertex of the clip |
||||
* rect that is reached by the shortest line perpendicular |
||||
* to the current edge, if any. |
||||
* |
||||
* slope of perpendicular is 1/m, so |
||||
* |
||||
* cy = -cx/m + c2 |
||||
* c2 = cy + cx/m |
||||
* |
||||
*/ |
||||
|
||||
int perp_intersect(GLfloat cx, GLfloat cy, uint32_t *d) |
||||
{ |
||||
GLfloat c2 = cy + cx/m; |
||||
GLfloat x = (c2 - c) / (m + 1/m); |
||||
|
||||
/* if the x position of the intersection of the
|
||||
* perpendicular with the transformed edge does |
||||
* not lie within the bounds of the edge, then |
||||
* no intersection: |
||||
*/ |
||||
if (sign(x-x1) == sign(x-x2)) |
||||
return 0; |
||||
|
||||
*d = dist_squared(cx, cy, x, (m * x) + c); |
||||
|
||||
/* if intersection distance is further away than
|
||||
* opposite edge of surface region, it is invalid: |
||||
*/ |
||||
if (*d > max_d) |
||||
return 0; |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
if (perp_intersect(cx1, cy1, &d)) { |
||||
best_x = cx1; |
||||
best_y = cy1; |
||||
best_d = d; |
||||
} |
||||
|
||||
if (perp_intersect(cx1, cy2, &d) && (d < best_d)) { |
||||
best_x = cx1; |
||||
best_y = cy2; |
||||
best_d = d; |
||||
} |
||||
|
||||
if (perp_intersect(cx2, cy2, &d) && (d < best_d)) { |
||||
best_x = cx2; |
||||
best_y = cy2; |
||||
best_d = d; |
||||
} |
||||
|
||||
if (perp_intersect(cx2, cy1, &d) && (d < best_d)) { |
||||
best_x = cx2; |
||||
best_y = cy1; |
||||
best_d = d; |
||||
} |
||||
|
||||
if (best_d != (unsigned int)-1) // XXX can this happen?
|
||||
append_vertex(best_x, best_y); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
return n; |
||||
} |
||||
|
||||
/* ---------------------- copied ends -----------------------*/ |
||||
|
||||
static void |
||||
geometry_set_phi(struct geometry *g, float phi) |
||||
{ |
||||
g->phi = phi; |
||||
g->s = sin(phi); |
||||
g->c = cos(phi); |
||||
} |
||||
|
||||
static void |
||||
geometry_init(struct geometry *g) |
||||
{ |
||||
g->clip.x1 = -50; |
||||
g->clip.y1 = -50; |
||||
g->clip.x2 = -10; |
||||
g->clip.y2 = -10; |
||||
|
||||
g->surf.x1 = -20; |
||||
g->surf.y1 = -20; |
||||
g->surf.x2 = 20; |
||||
g->surf.y2 = 20; |
||||
|
||||
geometry_set_phi(g, 0.0); |
||||
} |
||||
|
||||
struct ui_state { |
||||
uint32_t button; |
||||
int down; |
||||
|
||||
int down_pos[2]; |
||||
struct geometry geometry; |
||||
}; |
||||
|
||||
struct cliptest { |
||||
struct window *window; |
||||
struct widget *widget; |
||||
struct display *display; |
||||
int fullscreen; |
||||
|
||||
struct ui_state ui; |
||||
|
||||
struct geometry geometry; |
||||
struct weston_surface surface; |
||||
}; |
||||
|
||||
static void |
||||
draw_polygon_closed(cairo_t *cr, GLfloat *x, GLfloat *y, int n) |
||||
{ |
||||
int i; |
||||
|
||||
cairo_move_to(cr, x[0], y[0]); |
||||
for (i = 1; i < n; i++) |
||||
cairo_line_to(cr, x[i], y[i]); |
||||
cairo_line_to(cr, x[0], y[0]); |
||||
} |
||||
|
||||
static void |
||||
draw_polygon_labels(cairo_t *cr, GLfloat *x, GLfloat *y, int n) |
||||
{ |
||||
char str[16]; |
||||
int i; |
||||
|
||||
for (i = 0; i < n; i++) { |
||||
snprintf(str, 16, "%d", i); |
||||
cairo_move_to(cr, x[i], y[i]); |
||||
cairo_show_text(cr, str); |
||||
} |
||||
} |
||||
|
||||
static void |
||||
draw_coordinates(cairo_t *cr, double ox, double oy, GLfloat *x, GLfloat *y, int n) |
||||
{ |
||||
char str[64]; |
||||
int i; |
||||
cairo_font_extents_t ext; |
||||
|
||||
cairo_font_extents(cr, &ext); |
||||
for (i = 0; i < n; i++) { |
||||
snprintf(str, 64, "%d: %14.9f, %14.9f", i, x[i], y[i]); |
||||
cairo_move_to(cr, ox, oy + ext.height * (i + 1)); |
||||
cairo_show_text(cr, str); |
||||
} |
||||
} |
||||
|
||||
static void |
||||
draw_box(cairo_t *cr, pixman_box32_t *box, struct weston_surface *surface) |
||||
{ |
||||
GLfloat x[4], y[4]; |
||||
|
||||
if (surface) { |
||||
weston_surface_to_global_float(surface, box->x1, box->y1, &x[0], &y[0]); |
||||
weston_surface_to_global_float(surface, box->x2, box->y1, &x[1], &y[1]); |
||||
weston_surface_to_global_float(surface, box->x2, box->y2, &x[2], &y[2]); |
||||
weston_surface_to_global_float(surface, box->x1, box->y2, &x[3], &y[3]); |
||||
} else { |
||||
x[0] = box->x1; y[0] = box->y1; |
||||
x[1] = box->x2; y[1] = box->y1; |
||||
x[2] = box->x2; y[2] = box->y2; |
||||
x[3] = box->x1; y[3] = box->y2; |
||||
} |
||||
|
||||
draw_polygon_closed(cr, x, y, 4); |
||||
} |
||||
|
||||
static void |
||||
draw_geometry(cairo_t *cr, struct weston_surface *surface, |
||||
GLfloat *ex, GLfloat *ey, int n) |
||||
{ |
||||
struct geometry *g = surface->geometry; |
||||
GLfloat cx, cy; |
||||
|
||||
draw_box(cr, &g->surf, surface); |
||||
cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.4); |
||||
cairo_fill(cr); |
||||
weston_surface_to_global_float(surface, g->surf.x1 - 4, g->surf.y1 - 4, &cx, &cy); |
||||
cairo_arc(cr, cx, cy, 1.5, 0.0, 2.0 * M_PI); |
||||
if (surface->transform.enabled == 0) |
||||
cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.8); |
||||
cairo_fill(cr); |
||||
|
||||
draw_box(cr, &g->clip, NULL); |
||||
cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 0.4); |
||||
cairo_fill(cr); |
||||
|
||||
draw_polygon_closed(cr, ex, ey, n); |
||||
cairo_set_source_rgb(cr, 0.0, 1.0, 0.0); |
||||
cairo_stroke(cr); |
||||
|
||||
cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 0.5); |
||||
draw_polygon_labels(cr, ex, ey, n); |
||||
} |
||||
|
||||
static void |
||||
redraw_handler(struct widget *widget, void *data) |
||||
{ |
||||
struct cliptest *cliptest = data; |
||||
struct geometry *g = cliptest->surface.geometry; |
||||
struct rectangle allocation; |
||||
cairo_t *cr; |
||||
cairo_surface_t *surface; |
||||
GLfloat ex[8]; |
||||
GLfloat ey[8]; |
||||
int n; |
||||
|
||||
n = calculate_edges(&cliptest->surface, &g->clip, &g->surf, ex, ey); |
||||
|
||||
widget_get_allocation(cliptest->widget, &allocation); |
||||
|
||||
surface = window_get_surface(cliptest->window); |
||||
cr = cairo_create(surface); |
||||
widget_get_allocation(cliptest->widget, &allocation); |
||||
cairo_rectangle(cr, allocation.x, allocation.y, |
||||
allocation.width, allocation.height); |
||||
cairo_clip(cr); |
||||
|
||||
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); |
||||
cairo_set_source_rgba(cr, 0, 0, 0, 1); |
||||
cairo_paint(cr); |
||||
|
||||
cairo_translate(cr, allocation.x, allocation.y); |
||||
cairo_set_line_width(cr, 1.0); |
||||
cairo_move_to(cr, allocation.width / 2.0, 0.0); |
||||
cairo_line_to(cr, allocation.width / 2.0, allocation.height); |
||||
cairo_move_to(cr, 0.0, allocation.height / 2.0); |
||||
cairo_line_to(cr, allocation.width, allocation.height / 2.0); |
||||
cairo_set_source_rgba(cr, 0.5, 0.5, 0.5, 1.0); |
||||
cairo_stroke(cr); |
||||
|
||||
cairo_set_operator(cr, CAIRO_OPERATOR_OVER); |
||||
cairo_push_group(cr); |
||||
cairo_translate(cr, allocation.width / 2.0, |
||||
allocation.height / 2.0); |
||||
cairo_scale(cr, 4.0, 4.0); |
||||
cairo_set_line_width(cr, 0.5); |
||||
cairo_set_line_join(cr, CAIRO_LINE_JOIN_BEVEL); |
||||
cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, |
||||
CAIRO_FONT_WEIGHT_BOLD); |
||||
cairo_set_font_size(cr, 5.0); |
||||
draw_geometry(cr, &cliptest->surface, ex, ey, n); |
||||
cairo_pop_group_to_source(cr); |
||||
cairo_paint(cr); |
||||
|
||||
cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 1.0); |
||||
cairo_select_font_face(cr, "monospace", CAIRO_FONT_SLANT_NORMAL, |
||||
CAIRO_FONT_WEIGHT_NORMAL); |
||||
cairo_set_font_size(cr, 12.0); |
||||
draw_coordinates(cr, 10.0, 10.0, ex, ey, n); |
||||
|
||||
cairo_destroy(cr); |
||||
|
||||
cairo_surface_destroy(surface); |
||||
} |
||||
|
||||
static int |
||||
motion_handler(struct widget *widget, struct input *input, |
||||
uint32_t time, float x, float y, void *data) |
||||
{ |
||||
struct cliptest *cliptest = data; |
||||
struct ui_state *ui = &cliptest->ui; |
||||
struct geometry *ref = &ui->geometry; |
||||
struct geometry *geom = &cliptest->geometry; |
||||
float dx, dy; |
||||
|
||||
if (!ui->down) |
||||
return CURSOR_LEFT_PTR; |
||||
|
||||
dx = (x - ui->down_pos[0]) * 0.25; |
||||
dy = (y - ui->down_pos[1]) * 0.25; |
||||
|
||||
switch (ui->button) { |
||||
case BTN_LEFT: |
||||
geom->clip.x1 = ref->clip.x1 + dx; |
||||
geom->clip.y1 = ref->clip.y1 + dy; |
||||
/* fall through */ |
||||
case BTN_RIGHT: |
||||
geom->clip.x2 = ref->clip.x2 + dx; |
||||
geom->clip.y2 = ref->clip.y2 + dy; |
||||
break; |
||||
default: |
||||
return CURSOR_LEFT_PTR; |
||||
} |
||||
|
||||
widget_schedule_redraw(cliptest->widget); |
||||
return CURSOR_BLANK; |
||||
} |
||||
|
||||
static void |
||||
button_handler(struct widget *widget, struct input *input, |
||||
uint32_t time, uint32_t button, |
||||
enum wl_pointer_button_state state, void *data) |
||||
{ |
||||
struct cliptest *cliptest = data; |
||||
struct ui_state *ui = &cliptest->ui; |
||||
|
||||
ui->button = button; |
||||
|
||||
if (state == WL_POINTER_BUTTON_STATE_PRESSED) { |
||||
ui->down = 1; |
||||
input_get_position(input, &ui->down_pos[0], &ui->down_pos[1]); |
||||
} else { |
||||
ui->down = 0; |
||||
ui->geometry = cliptest->geometry; |
||||
} |
||||
} |
||||
|
||||
static void |
||||
axis_handler(struct widget *widget, struct input *input, uint32_t time, |
||||
uint32_t axis, wl_fixed_t value, void *data) |
||||
{ |
||||
struct cliptest *cliptest = data; |
||||
struct geometry *geom = &cliptest->geometry; |
||||
|
||||
if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL) |
||||
return; |
||||
|
||||
geometry_set_phi(geom, geom->phi + |
||||
(M_PI / 12.0) * wl_fixed_to_double(value)); |
||||
cliptest->surface.transform.enabled = 1; |
||||
|
||||
widget_schedule_redraw(cliptest->widget); |
||||
} |
||||
|
||||
static void |
||||
key_handler(struct window *window, struct input *input, uint32_t time, |
||||
uint32_t key, uint32_t sym, |
||||
enum wl_keyboard_key_state state, void *data) |
||||
{ |
||||
struct cliptest *cliptest = data; |
||||
struct geometry *g = &cliptest->geometry; |
||||
|
||||
if (state == WL_KEYBOARD_KEY_STATE_RELEASED) |
||||
return; |
||||
|
||||
switch (sym) { |
||||
case XKB_KEY_Escape: |
||||
display_exit(cliptest->display); |
||||
return; |
||||
case XKB_KEY_w: |
||||
g->clip.y1 -= 1; |
||||
g->clip.y2 -= 1; |
||||
break; |
||||
case XKB_KEY_a: |
||||
g->clip.x1 -= 1; |
||||
g->clip.x2 -= 1; |
||||
break; |
||||
case XKB_KEY_s: |
||||
g->clip.y1 += 1; |
||||
g->clip.y2 += 1; |
||||
break; |
||||
case XKB_KEY_d: |
||||
g->clip.x1 += 1; |
||||
g->clip.x2 += 1; |
||||
break; |
||||
case XKB_KEY_i: |
||||
g->clip.y2 -= 1; |
||||
break; |
||||
case XKB_KEY_j: |
||||
g->clip.x2 -= 1; |
||||
break; |
||||
case XKB_KEY_k: |
||||
g->clip.y2 += 1; |
||||
break; |
||||
case XKB_KEY_l: |
||||
g->clip.x2 += 1; |
||||
break; |
||||
case XKB_KEY_n: |
||||
geometry_set_phi(g, g->phi + (M_PI / 24.0)); |
||||
cliptest->surface.transform.enabled = 1; |
||||
break; |
||||
case XKB_KEY_m: |
||||
geometry_set_phi(g, g->phi - (M_PI / 24.0)); |
||||
cliptest->surface.transform.enabled = 1; |
||||
break; |
||||
case XKB_KEY_r: |
||||
geometry_set_phi(g, 0.0); |
||||
cliptest->surface.transform.enabled = 0; |
||||
break; |
||||
default: |
||||
return; |
||||
} |
||||
|
||||
widget_schedule_redraw(cliptest->widget); |
||||
} |
||||
|
||||
static void |
||||
keyboard_focus_handler(struct window *window, |
||||
struct input *device, void *data) |
||||
{ |
||||
struct cliptest *cliptest = data; |
||||
|
||||
window_schedule_redraw(cliptest->window); |
||||
} |
||||
|
||||
static void |
||||
fullscreen_handler(struct window *window, void *data) |
||||
{ |
||||
struct cliptest *cliptest = data; |
||||
|
||||
cliptest->fullscreen ^= 1; |
||||
window_set_fullscreen(window, cliptest->fullscreen); |
||||
} |
||||
|
||||
static struct cliptest * |
||||
cliptest_create(struct display *display) |
||||
{ |
||||
struct cliptest *cliptest; |
||||
|
||||
cliptest = malloc(sizeof *cliptest); |
||||
if (cliptest == NULL) |
||||
return cliptest; |
||||
memset(cliptest, 0, sizeof *cliptest); |
||||
|
||||
cliptest->surface.geometry = &cliptest->geometry; |
||||
cliptest->surface.transform.enabled = 0; |
||||
geometry_init(&cliptest->geometry); |
||||
geometry_init(&cliptest->ui.geometry); |
||||
|
||||
cliptest->window = window_create(display); |
||||
cliptest->widget = frame_create(cliptest->window, cliptest); |
||||
window_set_title(cliptest->window, "cliptest"); |
||||
cliptest->display = display; |
||||
|
||||
window_set_user_data(cliptest->window, cliptest); |
||||
widget_set_redraw_handler(cliptest->widget, redraw_handler); |
||||
widget_set_button_handler(cliptest->widget, button_handler); |
||||
widget_set_motion_handler(cliptest->widget, motion_handler); |
||||
widget_set_axis_handler(cliptest->widget, axis_handler); |
||||
|
||||
window_set_keyboard_focus_handler(cliptest->window, |
||||
keyboard_focus_handler); |
||||
window_set_key_handler(cliptest->window, key_handler); |
||||
window_set_fullscreen_handler(cliptest->window, fullscreen_handler); |
||||
|
||||
/* set minimum size */ |
||||
widget_schedule_resize(cliptest->widget, 200, 100); |
||||
|
||||
/* set current size */ |
||||
widget_schedule_resize(cliptest->widget, 500, 400); |
||||
|
||||
return cliptest; |
||||
} |
||||
|
||||
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 int |
||||
benchmark(void) |
||||
{ |
||||
struct weston_surface surface; |
||||
struct geometry geom; |
||||
GLfloat ex[8], ey[8]; |
||||
int i; |
||||
double t; |
||||
const int N = 1000000; |
||||
|
||||
geom.clip.x1 = -19; |
||||
geom.clip.y1 = -19; |
||||
geom.clip.x2 = 19; |
||||
geom.clip.y2 = 19; |
||||
|
||||
geom.surf.x1 = -20; |
||||
geom.surf.y1 = -20; |
||||
geom.surf.x2 = 20; |
||||
geom.surf.y2 = 20; |
||||
|
||||
geometry_set_phi(&geom, 0.0); |
||||
|
||||
surface.transform.enabled = 1; |
||||
surface.geometry = &geom; |
||||
|
||||
reset_timer(); |
||||
for (i = 0; i < N; i++) { |
||||
geometry_set_phi(&geom, (float)i / 360.0f); |
||||
calculate_edges(&surface, &geom.clip, &geom.surf, ex, ey); |
||||
} |
||||
t = read_timer(); |
||||
|
||||
printf("%d calls took %g s, average %g us/call\n", N, t, t / N * 1e6); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
main(int argc, char *argv[]) |
||||
{ |
||||
struct display *d; |
||||
struct cliptest *cliptest; |
||||
|
||||
if (argc > 1) |
||||
return benchmark(); |
||||
|
||||
d = display_create(argc, argv); |
||||
if (d == NULL) { |
||||
fprintf(stderr, "failed to create display: %m\n"); |
||||
return -1; |
||||
} |
||||
|
||||
cliptest = cliptest_create(d); |
||||
display_run(d); |
||||
|
||||
widget_destroy(cliptest->widget); |
||||
window_destroy(cliptest->window); |
||||
free(cliptest); |
||||
|
||||
return 0; |
||||
} |
Loading…
Reference in new issue