improve animation

This commit is contained in:
hippoz 2023-04-13 18:34:16 +03:00
parent 9aac4865dc
commit 601a0c3f06
Signed by: hippoz
GPG key ID: 56C4E02A85F2FBED
3 changed files with 38 additions and 7 deletions

8
src/defs.h Normal file
View file

@ -0,0 +1,8 @@
#ifndef _UI__DEFS_H
#define _UI__DEFS_H
#ifndef NDEBUG
#define _UI_DEBUG
#endif
#endif // _UI__DEFS_H

View file

@ -43,6 +43,10 @@ double lerp(double a, double b, double t)
return a + (b - a) * t; return a + (b - a) * t;
} }
double easeInOutQuart(double x) {
return x < 0.5 ? 8 * x * x * x * x : 1 - pow(-2 * x + 2, 4) / 2;
}
int app_handle(struct UINode *node, void *data, int event_type, size_t d, void *p) int app_handle(struct UINode *node, void *data, int event_type, size_t d, void *p)
{ {
(void)d; (void)p; (void)d; (void)p;
@ -104,13 +108,13 @@ int app_handle(struct UINode *node, void *data, int event_type, size_t d, void *
state->sidebar_animate_start_w = state->sidebar_node->rect.w; state->sidebar_animate_start_w = state->sidebar_node->rect.w;
state->sidebar_animate_target_w = state->sidebar_node->rect.w == 0 ? 200 : 0; state->sidebar_animate_target_w = state->sidebar_node->rect.w == 0 ? 200 : 0;
state->sidebar_animate_time_ms = 0.0; state->sidebar_animate_time_ms = 0.0;
window_sched_timer(node->window, state->sidebar_node, 8); window_sched_timer(node->window, state->sidebar_node, 10);
break; break;
} }
case SIDEBAR_ANIAMTE: { case SIDEBAR_ANIAMTE: {
int64_t dt = *(int64_t*)p; int64_t dt = *(int64_t*)p;
state->sidebar_animate_time_ms += dt; state->sidebar_animate_time_ms += dt;
state->sidebar_node->rect.w = lerp(state->sidebar_animate_start_w, state->sidebar_animate_target_w, (double)state->sidebar_animate_time_ms / (double)state->sidebar_animate_duration_ms); state->sidebar_node->rect.w = lerp(state->sidebar_animate_start_w, state->sidebar_animate_target_w, easeInOutQuart((double)state->sidebar_animate_time_ms / (double)state->sidebar_animate_duration_ms));
if (state->sidebar_node->rect.w < 0) { if (state->sidebar_node->rect.w < 0) {
state->sidebar_node->rect.w = 0; state->sidebar_node->rect.w = 0;
} }
@ -124,7 +128,7 @@ int app_handle(struct UINode *node, void *data, int event_type, size_t d, void *
return 0; return 0;
} }
window_sched_timer(node->window, state->sidebar_node, 8); window_sched_timer(node->window, state->sidebar_node, 10);
return 1; return 1;
} }
@ -162,7 +166,7 @@ int main(void)
AppState state = {0}; AppState state = {0};
state.font = desc; state.font = desc;
state.sidebar_animate_duration_ms = 3000; state.sidebar_animate_duration_ms = 250;
app_handle(root, &state, APP_SCAFFOLD, 0, NULL); app_handle(root, &state, APP_SCAFFOLD, 0, NULL);
window_turn(window); window_turn(window);

View file

@ -3,7 +3,10 @@
#include "timeutil.h" #include "timeutil.h"
#include "window.h" #include "window.h"
#include "node.h" #include "node.h"
#include "defs.h"
#ifdef _UI_DEBUG
#define PROF #define PROF
#endif
#include "prof.c" #include "prof.c"
#include "time.h" #include "time.h"
#include <stdint.h> #include <stdint.h>
@ -141,12 +144,16 @@ bool window_flush_invalidated(UIWindow *window)
if (ui_rect_null(&window->invalid_region)) { if (ui_rect_null(&window->invalid_region)) {
return false; return false;
} }
begin_clock("Flush invalidated widgets");
cairo_push_group(window->drw); cairo_push_group(window->drw);
node_repaint(window->root, &window->invalid_region, true, 0, 0); node_repaint(window->root, &window->invalid_region, true, 0, 0);
window->invalid_region = (UIRect){ 0, 0, 0, 0 }; window->invalid_region = (UIRect){ 0, 0, 0, 0 };
cairo_pop_group_to_source(window->drw); cairo_pop_group_to_source(window->drw);
cairo_paint(window->drw); cairo_paint(window->drw);
cairo_surface_flush(window->_cairo_surface); cairo_surface_flush(window->_cairo_surface);
end_clock();
return true; return true;
} }
@ -190,7 +197,9 @@ void _window_process_xcb_event(UIWindow *window, xcb_generic_event_t *event)
window->root->rect.w = ev->width; window->root->rect.w = ev->width;
window->root->rect.h = ev->height; window->root->rect.h = ev->height;
node_dispatch(window->root, UI_EVENT_RELAYOUT, 0, NULL); node_dispatch(window->root, UI_EVENT_RELAYOUT, 0, NULL);
#ifdef _UI_DEBUG
node_dump(window->root, 0); node_dump(window->root, 0);
#endif
} }
end_clock(); end_clock();
break; break;
@ -320,6 +329,9 @@ int window_turn(UIWindow *window)
} }
} }
} }
if (lowest < 0) {
lowest = 0;
}
poll_timeout = has_timer ? lowest : -1; poll_timeout = has_timer ? lowest : -1;
if (!has_looped_once) { if (!has_looped_once) {
@ -370,7 +382,10 @@ int window_turn(UIWindow *window)
int64_t now = time_current_ms(); int64_t now = time_current_ms();
int64_t distance = (timer->started_at_ms + timer->duration_ms) - now; int64_t distance = (timer->started_at_ms + timer->duration_ms) - now;
if (distance <= 0) { if (distance <= 0) {
int64_t dt = time_current_ms() - timer->started_at_ms; int64_t dt = now - timer->started_at_ms;
#ifdef _UI_DEBUG
printf("timer jitter: %ld\n", dt - timer->duration_ms);
#endif
UINode *target = timer->target; UINode *target = timer->target;
timer->present = false; timer->present = false;
timer->started_at_ms = 0; timer->started_at_ms = 0;
@ -384,16 +399,15 @@ int window_turn(UIWindow *window)
} }
} }
begin_clock("Flush invalidated widgets");
if (window_flush_invalidated(window)) { if (window_flush_invalidated(window)) {
begin_clock("Flush painting results to XCB"); begin_clock("Flush painting results to XCB");
xcb_flush(window->_xcb_connection); xcb_flush(window->_xcb_connection);
end_clock(); end_clock();
} }
end_clock();
has_looped_once = true; has_looped_once = true;
#ifdef _UI_DEBUG
int64_t frame_end_ms = time_current_ms(); int64_t frame_end_ms = time_current_ms();
int64_t frame_delta_ms = frame_end_ms - frame_start_ms; int64_t frame_delta_ms = frame_end_ms - frame_start_ms;
if (frame_delta_ms > frame_peak_ms || frame_end_ms - frame_peak_last_measurement_ms >= 3000) { if (frame_delta_ms > frame_peak_ms || frame_end_ms - frame_peak_last_measurement_ms >= 3000) {
@ -401,6 +415,11 @@ int window_turn(UIWindow *window)
frame_peak_ms = frame_delta_ms; frame_peak_ms = frame_delta_ms;
printf("peak frametime: %ldms\n", frame_peak_ms); printf("peak frametime: %ldms\n", frame_peak_ms);
} }
#else
(void)frame_peak_last_measurement_ms;
(void)frame_start_ms;
(void)frame_peak_ms;
#endif
end_clock(); end_clock();