Skip to content

Commit

Permalink
Merge pull request #74 from ndsl7109256/path
Browse files Browse the repository at this point in the history
Support path function to fulfill TinyVG rendering
  • Loading branch information
jserv authored Dec 5, 2024
2 parents 1d990a9 + ff4847d commit 16f7f9e
Show file tree
Hide file tree
Showing 8 changed files with 545 additions and 45 deletions.
52 changes: 52 additions & 0 deletions apps/multi.c
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,57 @@ static void apps_jelly_start(twin_screen_t *screen, int x, int y, int w, int h)
twin_window_show(window);
}

static void draw_flower(twin_path_t *path,
twin_fixed_t radius,
int number_of_petals)
{
const twin_angle_t angle_shift = TWIN_ANGLE_360 / number_of_petals;
const twin_angle_t angle_start = angle_shift / 2;
twin_fixed_t s, c;
twin_sincos(-angle_start, &s, &c);
twin_fixed_t p_x = twin_fixed_mul(radius, c);
twin_fixed_t p_y = twin_fixed_mul(radius, s);
twin_path_move(path, p_x, p_y);

for (twin_angle_t a = angle_start; a <= TWIN_ANGLE_360; a += angle_shift) {
twin_sincos(a, &s, &c);
twin_fixed_t c_x = twin_fixed_mul(radius, c);
twin_fixed_t c_y = twin_fixed_mul(radius, s);
twin_fixed_t rx = radius;
twin_fixed_t ry = radius * 3;
twin_path_arc_ellipse(path, 1, 1, rx, ry, p_x, p_y, c_x, c_y,
a - angle_start);
p_x = c_x;
p_y = c_y;
}

twin_path_close(path);
}

static void apps_flower_start(twin_screen_t *screen, int x, int y, int w, int h)
{
twin_window_t *window = twin_window_create(
screen, TWIN_ARGB32, TwinWindowApplication, x, y, w, h);
twin_pixmap_t *pixmap = window->pixmap;
twin_path_t *stroke = twin_path_create();
twin_path_t *path = twin_path_create();
twin_path_translate(path, D(200), D(200));
twin_path_scale(path, D(10), D(10));
twin_path_translate(stroke, D(200), D(200));
twin_fill(pixmap, 0xffffffff, TWIN_SOURCE, 0, 0, w, h);
twin_window_set_name(window, "Flower");
twin_path_move(stroke, D(-200), D(0));
twin_path_draw(stroke, D(200), D(0));
twin_path_move(stroke, D(0), D(200));
twin_path_draw(stroke, D(0), D(-200));
twin_path_set_cap_style(stroke, TwinCapProjecting);
twin_paint_stroke(pixmap, 0xffcc9999, stroke, D(10));
draw_flower(path, D(3), 5);
twin_paint_path(pixmap, 0xffe2d2d2, path);
twin_path_destroy(stroke);
twin_window_show(window);
}

void apps_multi_start(twin_screen_t *screen,
const char *name,
int x,
Expand All @@ -233,4 +284,5 @@ void apps_multi_start(twin_screen_t *screen,
apps_quickbrown_start(screen, x += 20, y += 20, w, h);
apps_ascii_start(screen, x += 20, y += 20, w, h);
apps_jelly_start(screen, x += 20, y += 20, w / 2, h);
apps_flower_start(screen, x += 20, y += 20, w, h);
}
149 changes: 110 additions & 39 deletions apps/spline.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,45 +15,86 @@

#define _apps_spline_pixmap(spline) ((spline)->widget.window->pixmap)

#define NPT 4

typedef struct _apps_spline {
twin_widget_t widget;
twin_point_t points[NPT];
int n_points;
twin_point_t *points;
int which;
twin_fixed_t line_width;
twin_cap_t cap_style;
twin_matrix_t transition;
twin_matrix_t inverse_transition;
} apps_spline_t;

static void _init_control_point(apps_spline_t *spline)
{
const int init_point_quad[3][2] = {
{100, 100},
{200, 100},
{300, 100},
};
const int init_point_cubic[4][2] = {
{100, 100},
{300, 300},
{100, 300},
{300, 100},
};
const int(*init_point)[2];
if (spline->n_points == 4) {
init_point = init_point_cubic;
} else if (spline->n_points == 3) {
init_point = init_point_quad;
}
for (int i = 0; i < spline->n_points; i++) {
spline->points[i].x = twin_int_to_fixed(init_point[i][0]);
spline->points[i].y = twin_int_to_fixed(init_point[i][1]);
}
}

static void _draw_aux_line(twin_path_t *path,
apps_spline_t *spline,
int idx1,
int idx2)
{
twin_path_move(path, spline->points[idx1].x, spline->points[idx1].y);
twin_path_draw(path, spline->points[idx2].x, spline->points[idx2].y);
twin_paint_stroke(_apps_spline_pixmap(spline), 0xc08000c0, path,
twin_int_to_fixed(2));
twin_path_empty(path);
}

static void _apps_spline_paint(apps_spline_t *spline)
{
twin_path_t *path;
int i;

path = twin_path_create();
twin_path_set_cap_style(path, spline->cap_style);
twin_path_set_matrix(path, spline->transition);

twin_path_move(path, spline->points[0].x, spline->points[0].y);
twin_path_curve(path, spline->points[1].x, spline->points[1].y,
spline->points[2].x, spline->points[2].y,
spline->points[3].x, spline->points[3].y);
if (spline->n_points == 4) {
twin_path_curve(path, spline->points[1].x, spline->points[1].y,
spline->points[2].x, spline->points[2].y,
spline->points[3].x, spline->points[3].y);
} else if (spline->n_points == 3) {
twin_path_quadratic_curve(path, spline->points[1].x,
spline->points[1].y, spline->points[2].x,
spline->points[2].y);
}
twin_paint_stroke(_apps_spline_pixmap(spline), 0xff404040, path,
spline->line_width);
twin_path_set_cap_style(path, TwinCapButt);
twin_paint_stroke(_apps_spline_pixmap(spline), 0xffffff00, path,
twin_int_to_fixed(2));

twin_path_empty(path);
twin_path_move(path, spline->points[0].x, spline->points[0].y);
twin_path_draw(path, spline->points[1].x, spline->points[1].y);
twin_paint_stroke(_apps_spline_pixmap(spline), 0xc08000c0, path,
twin_int_to_fixed(2));
twin_path_empty(path);
twin_path_move(path, spline->points[3].x, spline->points[3].y);
twin_path_draw(path, spline->points[2].x, spline->points[2].y);
twin_paint_stroke(_apps_spline_pixmap(spline), 0xc08000c0, path,
twin_int_to_fixed(2));
twin_path_empty(path);
for (i = 0; i < NPT; i++) {
if (spline->n_points == 4) {
_draw_aux_line(path, spline, 0, 1);
_draw_aux_line(path, spline, 3, 2);
} else if (spline->n_points == 3) {
_draw_aux_line(path, spline, 0, 1);
_draw_aux_line(path, spline, 1, 2);
}

for (int i = 0; i < spline->n_points; i++) {
twin_path_empty(path);
twin_path_circle(path, spline->points[i].x, spline->points[i].y,
twin_int_to_fixed(10));
Expand All @@ -62,13 +103,31 @@ static void _apps_spline_paint(apps_spline_t *spline)
twin_path_destroy(path);
}

static void _apps_spline_button_signal(maybe_unused twin_button_t *button,
twin_button_signal_t signal,
void *closure)
{
if (signal != TwinButtonSignalDown)
return;

apps_spline_t *spline = closure;
spline->n_points = (spline->n_points == 3) ? 4 : 3;
_init_control_point(spline);
_twin_widget_queue_paint(&spline->widget);
}

static twin_dispatch_result_t _apps_spline_update_pos(apps_spline_t *spline,
twin_event_t *event)
{
if (spline->which < 0)
return TwinDispatchContinue;
spline->points[spline->which].x = twin_int_to_fixed(event->u.pointer.x);
spline->points[spline->which].y = twin_int_to_fixed(event->u.pointer.y);
twin_fixed_t x = twin_int_to_fixed(event->u.pointer.x);
twin_fixed_t y = twin_int_to_fixed(event->u.pointer.y);

spline->points[spline->which].x = twin_sfixed_to_fixed(
_twin_matrix_x(&(spline->inverse_transition), x, y));
spline->points[spline->which].y = twin_sfixed_to_fixed(
_twin_matrix_y(&(spline->inverse_transition), x, y));
_twin_widget_queue_paint(&spline->widget);
return TwinDispatchDone;
}
Expand All @@ -80,11 +139,15 @@ static int _apps_spline_hit(apps_spline_t *spline,
twin_fixed_t y)
{
int i;

for (i = 0; i < NPT; i++)
if (twin_fixed_abs(x - spline->points[i].x) < spline->line_width / 2 &&
twin_fixed_abs(y - spline->points[i].y) < spline->line_width / 2)
for (i = 0; i < spline->n_points; i++) {
twin_fixed_t px = twin_sfixed_to_fixed(_twin_matrix_x(
&(spline->transition), spline->points[i].x, spline->points[i].y));
twin_fixed_t py = twin_sfixed_to_fixed(_twin_matrix_y(
&(spline->transition), spline->points[i].x, spline->points[i].y));
if (twin_fixed_abs(x - px) < spline->line_width / 2 &&
twin_fixed_abs(y - py) < spline->line_width / 2)
return i;
}
return -1;
}

Expand Down Expand Up @@ -123,28 +186,36 @@ static twin_dispatch_result_t _apps_spline_dispatch(twin_widget_t *widget,

static void _apps_spline_init(apps_spline_t *spline,
twin_box_t *parent,
twin_dispatch_proc_t dispatch)
twin_dispatch_proc_t dispatch,
int n_points)
{
static const twin_widget_layout_t preferred = {0, 0, 1, 1};
static twin_widget_layout_t preferred = {0, 0, 1, 1};
preferred.height = parent->widget.window->screen->height * 2 / 3;
_twin_widget_init(&spline->widget, parent, 0, preferred, dispatch);
twin_widget_set(&spline->widget, 0xffffffff);
spline->line_width = twin_int_to_fixed(100);
spline->cap_style = TwinCapRound;
spline->points[0].x = twin_int_to_fixed(100);
spline->points[0].y = twin_int_to_fixed(100);
spline->points[1].x = twin_int_to_fixed(300);
spline->points[1].y = twin_int_to_fixed(300);
spline->points[2].x = twin_int_to_fixed(100);
spline->points[2].y = twin_int_to_fixed(300);
spline->points[3].x = twin_int_to_fixed(300);
spline->points[3].y = twin_int_to_fixed(100);
twin_matrix_identity(&spline->transition);
twin_matrix_rotate(&spline->transition, TWIN_ANGLE_11_25);
twin_matrix_identity(&spline->inverse_transition);
twin_matrix_rotate(&spline->inverse_transition, -TWIN_ANGLE_11_25);
spline->points = calloc(n_points, sizeof(twin_point_t));
spline->n_points = n_points;
_init_control_point(spline);
twin_button_t *button =
twin_button_create(parent, "SwitchCurve", 0xffae0000, D(10),
TwinStyleBold | TwinStyleOblique);
twin_widget_set(&button->label.widget, 0xc0808080);
button->signal = _apps_spline_button_signal;
button->closure = spline;
button->label.widget.shape = TwinShapeRectangle;
}

static apps_spline_t *apps_spline_create(twin_box_t *parent)
static apps_spline_t *apps_spline_create(twin_box_t *parent, int n_points)
{
apps_spline_t *spline = malloc(sizeof(apps_spline_t));

_apps_spline_init(spline, parent, _apps_spline_dispatch);
_apps_spline_init(spline, parent, _apps_spline_dispatch, n_points);
return spline;
}

Expand All @@ -157,7 +228,7 @@ void apps_spline_start(twin_screen_t *screen,
{
twin_toplevel_t *toplevel = twin_toplevel_create(
screen, TWIN_ARGB32, TwinWindowApplication, x, y, w, h, name);
apps_spline_t *spline = apps_spline_create(&toplevel->box);
apps_spline_t *spline = apps_spline_create(&toplevel->box, 4);
(void) spline;
twin_toplevel_show(toplevel);
}
33 changes: 32 additions & 1 deletion include/twin.h
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ void twin_event_enqueue(const twin_event_t *event);
*/

#define twin_fixed_mul(a, b) ((twin_fixed_t) (((int64_t) (a) * (b)) >> 16))
#define twin_fixed_div(a, b) ((twin_fixed_t) ((((int64_t) (a)) << 16) / b))
#define twin_fixed_div(a, b) ((twin_fixed_t) ((((int64_t) (a)) << 16) / (b)))

twin_fixed_t twin_fixed_sqrt(twin_fixed_t a);

Expand Down Expand Up @@ -789,6 +789,7 @@ void twin_path_ellipse(twin_path_t *path,
twin_fixed_t y,
twin_fixed_t x_radius,
twin_fixed_t y_radius);

void twin_path_arc(twin_path_t *path,
twin_fixed_t x,
twin_fixed_t y,
Expand All @@ -797,6 +798,26 @@ void twin_path_arc(twin_path_t *path,
twin_angle_t start,
twin_angle_t extent);

void twin_path_arc_ellipse(twin_path_t *path,
bool large_arc,
bool sweep,
twin_fixed_t radius_x,
twin_fixed_t radius_y,
twin_fixed_t cur_x,
twin_fixed_t cur_y,
twin_fixed_t target_x,
twin_fixed_t target_y,
twin_angle_t rotation);

void twin_path_arc_circle(twin_path_t *path,
bool large_arc,
bool sweep,
twin_fixed_t radius,
twin_fixed_t cur_x,
twin_fixed_t cur_y,
twin_fixed_t target_x,
twin_fixed_t target_y);

void twin_path_rectangle(twin_path_t *path,
twin_fixed_t x,
twin_fixed_t y,
Expand Down Expand Up @@ -1050,6 +1071,12 @@ void twin_path_curve(twin_path_t *path,
twin_fixed_t x3,
twin_fixed_t y3);

void twin_path_quadratic_curve(twin_path_t *path,
twin_fixed_t x1,
twin_fixed_t y1,
twin_fixed_t x2,
twin_fixed_t y2);

/*
* timeout.c
*/
Expand Down Expand Up @@ -1087,6 +1114,10 @@ twin_fixed_t twin_tan(twin_angle_t a);

void twin_sincos(twin_angle_t a, twin_fixed_t *sin, twin_fixed_t *cos);

twin_angle_t twin_atan2(twin_fixed_t y, twin_fixed_t x);

twin_angle_t twin_acos(twin_fixed_t x);

/*
* widget.c
*/
Expand Down
Loading

0 comments on commit 16f7f9e

Please sign in to comment.