From 58eb3695f10e6755da84e7a09eb000615faf866a Mon Sep 17 00:00:00 2001 From: Roman Pytkov Date: Mon, 17 Nov 2025 16:13:47 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B0=D0=B7=D0=BC=D0=B5=D1=80=20=D0=BD?= =?UTF-8?q?=D0=B5=20=D0=B7=D0=B0=D0=B2=D0=B8=D1=81=D0=B8=D1=82=20=D0=BE?= =?UTF-8?q?=D1=82=20=D1=88=D0=B8=D1=80=D0=B8=D0=BD=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wayland/include/figure.h | 13 ++++- wayland/src/figure-animate.asm | 97 ++++++++++++++++++++++++---------- wayland/src/figure-draw.c | 3 +- wayland/src/wayland-runtime.c | 2 +- wayland/src/window.c | 4 +- 5 files changed, 85 insertions(+), 34 deletions(-) diff --git a/wayland/include/figure.h b/wayland/include/figure.h index 0a4b19c..e23c168 100644 --- a/wayland/include/figure.h +++ b/wayland/include/figure.h @@ -13,15 +13,24 @@ enum figure_type struct figure_animation_info { enum figure_type type; struct vec2 position; + /* Direction vector; its components are not in pixels. Anim code converts + * them to pixel-space and normalizes them so that `speed` is applied as + * pixels/sec uniformly in both axes (aspect ratio is accounted for). */ struct vec2 velocity; float angle; float angular_velocity; + /* Speed in pixels per second. This value is applied uniformly to both + * axes (X and Y); the animation code converts this pixel speed to + * normalized increments for position updates taking window aspect ratio + * into account. */ float speed; - /* Radius of the figure normalized for window width (0..1) + /* Radius of the figure in pixels (float) * This field is used by animation code to check collisions - * with the left/right/top/bottom borders. */ + * with the left/right/top/bottom borders. The animation code + * will convert this pixel radius to normalized coordinates for + * collision checks against normalized positions. */ float radius; }; diff --git a/wayland/src/figure-animate.asm b/wayland/src/figure-animate.asm index e18ccb9..d77c064 100644 --- a/wayland/src/figure-animate.asm +++ b/wayland/src/figure-animate.asm @@ -15,25 +15,60 @@ figure_animation_step: mov rax, rdi add rax, WDI_FIGURE - ; --- compute movement scale: scale = speed * (dt / BASE_SIZE) + ; --- compute movement increments so that `speed` means pixels/second + ; Convert velocity to pixel-space (vx = vel.x * width, vy = vel.y * height), + ; normalize that vector and apply `speed*dt` so movement in pixel units equals speed. ; using SSE for float math - movss xmm0, dword [rax + FIG_SPEED] ; xmm0 = speed - mulss xmm0, [rel SCALE_FACTOR] ; xmm0 = speed * (dt / BASE_SIZE) + movss xmm0, dword [rax + FIG_SPEED] ; xmm0 = speed (pixels/sec) + movss xmm9, [rel DT] ; xmm9 = dt + mulss xmm0, xmm9 ; xmm0 = speed * dt (pixels) - ; dx = velocity.x * scale - movss xmm1, dword [rax + FIG_VELOCITY] ; velocity.x - mulss xmm1, xmm0 + ; load width/height + mov ebx, dword [rdi + WDI_WIDTH] + cvtsi2ss xmm10, ebx ; xmm10 = width + mov ebx, dword [rdi + WDI_HEIGHT] + cvtsi2ss xmm11, ebx ; xmm11 = height + + ; vx_pixels = vel.x * width + movss xmm1, dword [rax + FIG_VELOCITY] ; vel.x + mulss xmm1, xmm10 ; xmm1 = vx_pixels + + ; vy_pixels = vel.y * height + movss xmm2, dword [rax + FIG_VELOCITY + 4] + mulss xmm2, xmm11 ; xmm2 = vy_pixels + + ; length = sqrt(vx^2 + vy^2) + movss xmm3, xmm1 + mulss xmm3, xmm1 ; xmm3 = vx^2 + movss xmm4, xmm2 + mulss xmm4, xmm4 ; xmm4 = vy^2 + addss xmm3, xmm4 ; xmm3 = vx^2 + vy^2 + sqrtss xmm3, xmm3 ; xmm3 = length (pixels) + + ; if length == 0 -> skip movement + ucomiss xmm3, [rel ZERO_CONST] + je .skip_move + + ; scalar = (speed * dt) / length + movss xmm4, xmm0 ; xmm4 = speed*dt + divss xmm4, xmm3 ; xmm4 = scalar + + ; dx = vel.x * scalar + movss xmm1, dword [rax + FIG_VELOCITY] + mulss xmm1, xmm4 movss xmm2, dword [rax + FIG_POSITION] ; position.x addss xmm2, xmm1 movss dword [rax + FIG_POSITION], xmm2 - ; dy = velocity.y * scale + ; dy = vel.y * scalar movss xmm1, dword [rax + FIG_VELOCITY + 4] - mulss xmm1, xmm0 + mulss xmm1, xmm4 movss xmm2, dword [rax + FIG_POSITION + 4] addss xmm2, xmm1 movss dword [rax + FIG_POSITION + 4], xmm2 +.skip_move: + ; rotate: angle += angular_velocity * dt movss xmm3, dword [rax + FIG_ANG_VEL] mulss xmm3, [rel DT] @@ -73,24 +108,30 @@ figure_check_collision_circle: movss xmm4, dword [rax + FIG_ANG_VEL] ; angvel - ; radius is stored in figure as normalized relative to window width - movss xmm5, dword [rax + FIG_RADIUS] + ; radius is stored in figure as pixel count (float) + ; we keep positions normalized (0..1) so convert radius to normalized + ; coordinates for x and y: r_x = radius / width, r_y = radius / height + movss xmm5, dword [rax + FIG_RADIUS] ; xmm5 = radius_pixels - ; compute normalized radius for Y: r_y = radius * (width / height) ; load width/height from window_draw_info mov ebx, dword [rdi + WDI_WIDTH] - cvtsi2ss xmm10, ebx + cvtsi2ss xmm10, ebx ; xmm10 = width mov ebx, dword [rdi + WDI_HEIGHT] - cvtsi2ss xmm11, ebx - divss xmm10, xmm11 ; xmm10 = width/height - movss xmm12, xmm5 - mulss xmm12, xmm10 ; xmm12 = radius_y + cvtsi2ss xmm11, ebx ; xmm11 = height - ; left edge: pos.x < radius ? - ucomiss xmm0, xmm5 + ; compute r_x = radius / width + movss xmm12, xmm5 + divss xmm12, xmm10 ; xmm12 = r_x + + ; compute r_y = radius / height + movss xmm13, xmm5 + divss xmm13, xmm11 ; xmm13 = r_y + + ; left edge: pos.x < r_x ? + ucomiss xmm0, xmm12 jae .check_right ; pos.x = radius - movss dword [rax + FIG_POSITION], xmm5 + movss dword [rax + FIG_POSITION], xmm12 ; vel.x = -vel.x movss xmm6, xmm2 mulss xmm6, [rel NEG_ONE] @@ -104,11 +145,11 @@ figure_check_collision_circle: .check_right: ; pos.x + radius > 1 ? movss xmm8, [rel ONE_CONST] - addss xmm8, xmm5 ; xmm8 = 1 + radius + addss xmm8, xmm12 ; xmm8 = 1 + r_x ; Actually want pos.x + radius > 1 <=> pos.x > 1 - radius - ; compute bound = 1 - radius + ; compute bound = 1 - r_x movss xmm9, [rel ONE_CONST] - subss xmm9, xmm5 + subss xmm9, xmm12 ucomiss xmm0, xmm9 jbe .done_x ; pos.x = 1 - radius @@ -124,10 +165,10 @@ figure_check_collision_circle: .done_x: ; check bottom / top boundaries for y - ; bottom: pos.y < radius - ucomiss xmm1, xmm12 + ; bottom: pos.y < r_y + ucomiss xmm1, xmm13 jae .check_top2 - movss dword [rax + FIG_POSITION + 4], xmm12 + movss dword [rax + FIG_POSITION + 4], xmm13 movss xmm6, xmm3 mulss xmm6, [rel NEG_ONE] movss dword [rax + FIG_VELOCITY + 4], xmm6 @@ -138,9 +179,9 @@ figure_check_collision_circle: jmp .done_y .check_top2: - ; top: pos.y > 1 - radius + ; top: pos.y > 1 - r_y movss xmm9, [rel ONE_CONST] - subss xmm9, xmm5 + subss xmm9, xmm13 ucomiss xmm1, xmm9 jbe .done_y movss dword [rax + FIG_POSITION + 4], xmm9 @@ -156,7 +197,7 @@ figure_check_collision_circle: ret section .rodata -SCALE_FACTOR: dd 0.001 DT: dd 0.1 NEG_ONE: dd -1.0 ONE_CONST: dd 1.0 +ZERO_CONST: dd 0.0 diff --git a/wayland/src/figure-draw.c b/wayland/src/figure-draw.c index 0122258..fd8ba5d 100644 --- a/wayland/src/figure-draw.c +++ b/wayland/src/figure-draw.c @@ -19,7 +19,8 @@ void figure_draw(struct window_draw_info* draw_info, float border_thickness, uin /* center in pixels */ float cx = fig.position.x * (float)w; float cy = fig.position.y * (float)h; - float r = fig.radius * (float)w; /* normalized to width */ + /* `fig.radius` is in pixels now; use it directly. */ + float r = fig.radius; float r2 = r * r; float border = border_thickness; if (border < 0.0f) border = 0.0f; diff --git a/wayland/src/wayland-runtime.c b/wayland/src/wayland-runtime.c index 8d537b5..1c1cd93 100644 --- a/wayland/src/wayland-runtime.c +++ b/wayland/src/wayland-runtime.c @@ -52,7 +52,7 @@ static void *window_aux_loop(void *arg) figure_animation_step(draw_info); pthread_mutex_unlock(&draw_info->figure_mutex); - usleep(100 * 1000); + usleep(30 * 1000); } return NULL; } diff --git a/wayland/src/window.c b/wayland/src/window.c index 8fc9b9f..1e4594f 100644 --- a/wayland/src/window.c +++ b/wayland/src/window.c @@ -255,8 +255,8 @@ int window_init(struct wl_display *display, struct wl_event_queue *queue, struct draw_info->figure.velocity.y = 0.3f; draw_info->figure.angle = 0.0f; draw_info->figure.angular_velocity = 1.0f; /* radians per second */ - draw_info->figure.speed = 30.0f; /* pixels per second baseline (norm by width) */ - draw_info->figure.radius = 0.05f; /* normalized relative to width: 5% */ + draw_info->figure.speed = 100.0f; /* pixels per second */ + draw_info->figure.radius = 20.0f; /* radius in pixels */ win->buffer = NULL; win->frame_callback = NULL;