~sircmpwn/casa

a31ea89f0b99a4808035ca703d232db2b9ccec5b — Gy├Ârgy Kurucz 6 months ago e8a71dc
Change everything to use float, add vec2 functions.
7 files changed, 108 insertions(+), 55 deletions(-)

M include/casa.h
M include/matrix.h
M include/surface.h
M src/input.c
M src/matrix.c
M src/render.c
M src/surface.c
M include/casa.h => include/casa.h +5 -4
@@ 12,16 12,17 @@
struct casa_touchpoint {
	int32_t id;
	struct casa_surface *surface;
	int init_x, init_y;

	float init[2];
	int32_t init_time;

	int cur_x, cur_y;
	float cur[2];
	int32_t cur_time;

	int last_x, last_y;
	float last[2];
	int32_t last_time;

	double vel_x, vel_y; // moving average of velocity (pixel / msec)
	float vel[2]; // moving average of velocity (pixel / msec)
};

struct casa_state {

M include/matrix.h => include/matrix.h +8 -0
@@ 16,4 16,12 @@ void matrix_projection(float mat[static 9], int width, int height);
void matrix_project_box(float mat[static 9], const struct box *box,
		float rotation, const float projection[static 9]);

void vec2_zero(float vec[static 2]);
void vec2_add(float vec[static 2],
		const float a[static 2], const float b[static 2]);
void vec2_sub(float vec[static 2],
		const float a[static 2], const float b[static 2]);
void vec2_mul(float vec[static 2], const float a[static 2], float b);
float vec2_dot(const float a[static 2], const float b[static 2]);

#endif

M include/surface.h => include/surface.h +10 -9
@@ 30,7 30,7 @@ enum casa_surface_state {

struct casa_drag_integrator {
	uint32_t touchpoints;
	double int_x, int_y;
	float integ[2];
};

enum casa_animation_kind {


@@ 44,13 44,13 @@ struct casa_animation {
	enum casa_animation_kind kind;
	union {
		struct {
			double s_0, s_1;
			float s_0, s_1;
		} linear;
		struct {
			// s(t) = s_0 + v_0*t + (1/2)*a*t^2
			double s_0; // pixel
			double v_0; // pixel / msec
			double a; // pixel / msec^2
			float s_0; // pixel
			float v_0; // pixel / msec
			float a; // pixel / msec^2
		} quadratic;
	};
};


@@ 71,8 71,8 @@ struct casa_surface {
	struct wl_list outputs; // casa_surface_output::link

	enum casa_surface_state state;
	double idle_offset;
	double scroll_offset; // (-infinity, idle_offset]
	float idle_offset;
	float scroll_offset; // (-infinity, idle_offset]
	struct casa_drag_integrator drag_integrator;
	struct casa_animation scroll_offset_anim;
};


@@ 88,9 88,10 @@ struct casa_surface *casa_surface_create(
void casa_surface_schedule_frame(struct casa_surface *surf);

void casa_surface_state_progress(struct casa_surface *surf, int32_t time,
		double *progress, double *y_offs);
		float *progress, float *y_offs);

void casa_surface_touch_down(struct casa_surface *surf, int32_t time);
void casa_surface_touch_up(struct casa_surface *surf, int32_t time, double vel_y);
void casa_surface_touch_up(struct casa_surface *surf, int32_t time,
		const float vel[static 2]);

#endif

M src/input.c => src/input.c +18 -14
@@ 1,6 1,7 @@
#include <stdio.h>
#include <wayland-client.h>
#include "casa.h"
#include "matrix.h"
#include "surface.h"
#include "render.h"



@@ 43,12 44,12 @@ wl_touch_down(void *data, struct wl_touch *wl_touch,
	}
	tp->id = id;
	tp->surface = surf;
	tp->last_x = tp->cur_x = tp->init_x =
	tp->last[0] = tp->cur[0] = tp->init[0] =
		(int)(wl_fixed_to_double(x) * surf->scale);
	tp->last_y = tp->cur_y = tp->init_y =
	tp->last[1] = tp->cur[1] = tp->init[1] =
		(int)(wl_fixed_to_double(y) * surf->scale);
	tp->last_time = tp->cur_time = tp->init_time = time;
	tp->vel_x = tp->vel_y = 0;
	vec2_zero(tp->vel);

	surf->drag_integrator.touchpoints++;



@@ 70,12 71,13 @@ wl_touch_up(void *data, struct wl_touch *wl_touch,
	tp->id = -1;

	struct casa_drag_integrator *di = &surf->drag_integrator;
	di->int_x += tp->cur_x - tp->init_x;
	di->int_y += tp->cur_y - tp->init_y;
	float delta[2];
	vec2_sub(delta, tp->cur, tp->init);
	vec2_add(di->integ, di->integ, delta);

	if (--di->touchpoints == 0) {
		// last touchpoint gone from this surface
		casa_surface_touch_up(surf, time, tp->vel_y);
		casa_surface_touch_up(surf, time, tp->vel);
	}
}



@@ 89,19 91,21 @@ wl_touch_motion(void *data, struct wl_touch *wl_touch,
		return;
	}
	struct casa_surface *surf = tp->surface;
	tp->last_x = tp->cur_x, tp->last_y = tp->cur_y;
	tp->last[0] = tp->cur[0], tp->last[1] = tp->cur[1];
	tp->last_time = tp->cur_time, tp->last_time = tp->cur_time;
	tp->cur_x = (int)(wl_fixed_to_double(x) * surf->scale);
	tp->cur_y = (int)(wl_fixed_to_double(y) * surf->scale);
	tp->cur[0] = (int)(wl_fixed_to_double(x) * surf->scale);
	tp->cur[1] = (int)(wl_fixed_to_double(y) * surf->scale);
	tp->cur_time = time;

	double dt = tp->cur_time - tp->last_time;
	double vel_x = (tp->cur_x - tp->last_x) / dt;
	double vel_y = (tp->cur_y - tp->last_y) / dt;
	float dt = tp->cur_time - tp->last_time;
	float vel[2];
	vec2_sub(vel, tp->cur, tp->last);
	vec2_mul(vel, vel, 1/dt);

	// moving average filter
	tp->vel_x = 0.7 * tp->vel_x + 0.3 * vel_x;
	tp->vel_y = 0.7 * tp->vel_y + 0.3 * vel_y;
	vec2_mul(tp->vel, tp->vel, 0.7);
	vec2_mul(vel, vel, 0.3);
	vec2_add(tp->vel, tp->vel, vel);

	casa_surface_schedule_frame(surf);
}

M src/matrix.c => src/matrix.c +37 -0
@@ 112,3 112,40 @@ void matrix_project_box(float mat[static 9], const struct box *box,
	matrix_scale(mat, width, height);
	matrix_multiply(mat, projection, mat);
}

void vec2_zero(float vec[static 2])
{
	vec[0] = 0;
	vec[1] = 0;
}

void vec2_add(float vec[static 2],
		const float a[static 2], const float b[static 2])
{
	float sum[2];
	sum[0] = a[0] + b[0];
	sum[1] = a[1] + b[1];
	memcpy(vec, sum, sizeof(sum));
}

void vec2_sub(float vec[static 2],
		const float a[static 2], const float b[static 2])
{
	float sum[2];
	sum[0] = a[0] - b[0];
	sum[1] = a[1] - b[1];
	memcpy(vec, sum, sizeof(sum));
}

void vec2_mul(float vec[static 2], const float a[static 2], float b)
{
	float product[2];
	product[0] = a[0] * b;
	product[1] = a[1] * b;
	memcpy(vec, product, sizeof(product));
}

float vec2_dot(const float a[static 2], const float b[static 2])
{
	return a[0] * b[0] + a[1] * b[1];
}

M src/render.c => src/render.c +2 -2
@@ 15,7 15,7 @@
 */
static void
render_icons(struct casa_surface *surface,
		struct casa_buffer *buffer, double progress, int y_offs)
		struct casa_buffer *buffer, float progress, int y_offs)
{
	const int width = 128, height = 128;
	const int nrows = 16, ncols = 4;


@@ 87,7 87,7 @@ casa_render(struct casa_surface *surface, uint32_t time)
			surface->height * surface->scale);
	assert(buffer);

	double y_offs, progress;
	float y_offs, progress;
	casa_surface_state_progress(surface, time, &progress, &y_offs);

	glClearColor(0.0f, 0.0f, 0.0f, progress * 0.75);

M src/surface.c => src/surface.c +28 -26
@@ 4,6 4,7 @@
#include <wayland-client.h>
#include "buffers.h"
#include "casa.h"
#include "matrix.h"
#include "output.h"
#include "render.h"
#include "surface.h"


@@ 11,22 12,23 @@
/* TODO: Move animation/state into its own file */
/* The minimum number of milliseconds an animation will complete in */
const int32_t anim_target_duration = 200;
const double gesture_completion_threshold = 0.25;
const double kinetic_scrolling_friction = 0.01; // pixel / msec^2
const double kinetic_scrolling_max_v = 5.0; // pixel / msec
const float gesture_completion_threshold = 0.25;
const float kinetic_scrolling_friction = 0.01; // pixel / msec^2
const float kinetic_scrolling_max_v = 5.0; // pixel / msec

static void
casa_surface_drag_get(const struct casa_surface *surf, double *x, double *y)
casa_surface_drag_get(const struct casa_surface *surf, float off[static 2])
{
	const struct casa_state *state = surf->casa;
	*x = surf->drag_integrator.int_x;
	*y = surf->drag_integrator.int_y;
	off[0] = surf->drag_integrator.integ[0];
	off[1] = surf->drag_integrator.integ[1];
	for (size_t i = 0;
			i < sizeof(state->touchpoints) / sizeof(state->touchpoints[0]); ++i) {
		const struct casa_touchpoint *point = &state->touchpoints[i];
		if (point->id != -1 && point->surface == surf) {
			*x += point->cur_x - point->init_x;
			*y += point->cur_y - point->init_y;
			float delta[2];
			vec2_sub(delta, point->cur, point->init);
			vec2_add(off, off, delta);
		}
	}
}


@@ 145,7 147,7 @@ casa_surface_create(struct casa_state *state, struct wl_output *output)
	surf->scroll_offset = surf->idle_offset;
	surf->state = CASA_SURFACE_IDLE;
	surf->drag_integrator = (struct casa_drag_integrator){
		.touchpoints = 0, .int_x = 0, .int_y = 0 };
		.touchpoints = 0, .integ = { 0, 0 } };
	surf->scroll_offset_anim.time_end = -1;

	surf->surface = wl_compositor_create_surface(state->compositor);


@@ 196,18 198,18 @@ casa_surface_schedule_frame(struct casa_surface *surf)
}

static void
casa_surface_set_scroll_offset(struct casa_surface *surf, double offs) {
casa_surface_set_scroll_offset(struct casa_surface *surf, float offs) {
	offs = fmin(offs, surf->idle_offset);
	surf->scroll_offset = offs;
}

double
static float
casa_animation_val(const struct casa_animation *anim, int32_t time)
{
	double t, val;
	float t, val;
	switch (anim->kind) {
	case CASA_ANIMATION_LINEAR:
		t = (time - anim->time_start) / (double)(anim->time_end - anim->time_start);
		t = (time - anim->time_start) / (float)(anim->time_end - anim->time_start);
		val = (1.0 - t) * anim->linear.s_0 + t * anim->linear.s_1;
		break;
	case CASA_ANIMATION_QUADRATIC:


@@ 222,14 224,14 @@ casa_animation_val(const struct casa_animation *anim, int32_t time)

void
casa_surface_state_progress(struct casa_surface *surf, int32_t time,
		double *progress, double *y_offs)
		float *progress, float *y_offs)
{
	struct casa_animation *anim = &surf->scroll_offset_anim;

	if (surf->drag_integrator.touchpoints > 0) {
		double off_x, off_y;
		casa_surface_drag_get(surf, &off_x, &off_y);
		*y_offs = fmin(surf->scroll_offset + off_y, surf->idle_offset);
		float off[2];
		casa_surface_drag_get(surf, off);
		*y_offs = fmin(surf->scroll_offset + off[1], surf->idle_offset);
	} else if (anim->kind != CASA_ANIMATION_NONE) {
		if (anim->time_end > time) {
			*y_offs = casa_animation_val(anim, time);


@@ 267,16 269,16 @@ casa_surface_touch_down(struct casa_surface *surf, int32_t time)
}

void
casa_surface_touch_up(struct casa_surface *surf, int32_t time, double vel_y)
casa_surface_touch_up(struct casa_surface *surf, int32_t time,
		const float vel[static 2])
{
	surf->scroll_offset += surf->drag_integrator.int_y;
	surf->scroll_offset += surf->drag_integrator.integ[1];
	surf->scroll_offset = fmin(surf->scroll_offset, surf->idle_offset);

	// reset integrator
	surf->drag_integrator.int_x = 0;
	surf->drag_integrator.int_y = 0;
	vec2_zero(surf->drag_integrator.integ);

	double progress = 1.0 - surf->scroll_offset / surf->idle_offset;
	float progress = 1.0 - surf->scroll_offset / surf->idle_offset;

	enum casa_surface_state next_state = surf->state;
	switch (surf->state) {


@@ 299,17 301,17 @@ casa_surface_touch_up(struct casa_surface *surf, int32_t time, double vel_y)
		anim->linear.s_0 = surf->scroll_offset;
		anim->linear.s_1 = next_state == CASA_SURFACE_BROWSE
				? 0.0 : surf->idle_offset;
		double diff = fabs(anim->linear.s_1 - anim->linear.s_0);
		float diff = fabs(anim->linear.s_1 - anim->linear.s_0);
		anim->time_end = anim->time_start +
				(int32_t)(anim_target_duration * (diff / surf->idle_offset));
	} else if (progress >= 1.0) {
		anim->kind = CASA_ANIMATION_QUADRATIC;
		anim->time_start = time;
		anim->quadratic.s_0 = surf->scroll_offset;
		if (fabs(vel_y) > kinetic_scrolling_max_v) {
			anim->quadratic.v_0 = copysign(kinetic_scrolling_max_v, vel_y);
		if (fabs(vel[1]) > kinetic_scrolling_max_v) {
			anim->quadratic.v_0 = copysign(kinetic_scrolling_max_v, vel[1]);
		} else {
			anim->quadratic.v_0 = vel_y;
			anim->quadratic.v_0 = vel[1];
		}
		anim->quadratic.a = copysign(kinetic_scrolling_friction, -anim->quadratic.v_0);
		anim->time_end = anim->time_start - anim->quadratic.v_0 / anim->quadratic.a;