Размер не зависит от ширины

This commit is contained in:
2025-11-17 16:13:47 +03:00
parent 2c383b20e9
commit 58eb3695f1
5 changed files with 85 additions and 34 deletions

View File

@@ -13,15 +13,24 @@ enum figure_type
struct figure_animation_info { struct figure_animation_info {
enum figure_type type; enum figure_type type;
struct vec2 position; 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; struct vec2 velocity;
float angle; float angle;
float angular_velocity; 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; 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 * 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; float radius;
}; };

View File

@@ -15,25 +15,60 @@ figure_animation_step:
mov rax, rdi mov rax, rdi
add rax, WDI_FIGURE 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 ; using SSE for float math
movss xmm0, dword [rax + FIG_SPEED] ; xmm0 = speed movss xmm0, dword [rax + FIG_SPEED] ; xmm0 = speed (pixels/sec)
mulss xmm0, [rel SCALE_FACTOR] ; xmm0 = speed * (dt / BASE_SIZE) movss xmm9, [rel DT] ; xmm9 = dt
mulss xmm0, xmm9 ; xmm0 = speed * dt (pixels)
; dx = velocity.x * scale ; load width/height
movss xmm1, dword [rax + FIG_VELOCITY] ; velocity.x mov ebx, dword [rdi + WDI_WIDTH]
mulss xmm1, xmm0 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 movss xmm2, dword [rax + FIG_POSITION] ; position.x
addss xmm2, xmm1 addss xmm2, xmm1
movss dword [rax + FIG_POSITION], xmm2 movss dword [rax + FIG_POSITION], xmm2
; dy = velocity.y * scale ; dy = vel.y * scalar
movss xmm1, dword [rax + FIG_VELOCITY + 4] movss xmm1, dword [rax + FIG_VELOCITY + 4]
mulss xmm1, xmm0 mulss xmm1, xmm4
movss xmm2, dword [rax + FIG_POSITION + 4] movss xmm2, dword [rax + FIG_POSITION + 4]
addss xmm2, xmm1 addss xmm2, xmm1
movss dword [rax + FIG_POSITION + 4], xmm2 movss dword [rax + FIG_POSITION + 4], xmm2
.skip_move:
; rotate: angle += angular_velocity * dt ; rotate: angle += angular_velocity * dt
movss xmm3, dword [rax + FIG_ANG_VEL] movss xmm3, dword [rax + FIG_ANG_VEL]
mulss xmm3, [rel DT] mulss xmm3, [rel DT]
@@ -73,24 +108,30 @@ figure_check_collision_circle:
movss xmm4, dword [rax + FIG_ANG_VEL] ; angvel movss xmm4, dword [rax + FIG_ANG_VEL] ; angvel
; radius is stored in figure as normalized relative to window width ; radius is stored in figure as pixel count (float)
movss xmm5, dword [rax + FIG_RADIUS] ; 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 ; load width/height from window_draw_info
mov ebx, dword [rdi + WDI_WIDTH] mov ebx, dword [rdi + WDI_WIDTH]
cvtsi2ss xmm10, ebx cvtsi2ss xmm10, ebx ; xmm10 = width
mov ebx, dword [rdi + WDI_HEIGHT] mov ebx, dword [rdi + WDI_HEIGHT]
cvtsi2ss xmm11, ebx cvtsi2ss xmm11, ebx ; xmm11 = height
divss xmm10, xmm11 ; xmm10 = width/height
movss xmm12, xmm5
mulss xmm12, xmm10 ; xmm12 = radius_y
; left edge: pos.x < radius ? ; compute r_x = radius / width
ucomiss xmm0, xmm5 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 jae .check_right
; pos.x = radius ; pos.x = radius
movss dword [rax + FIG_POSITION], xmm5 movss dword [rax + FIG_POSITION], xmm12
; vel.x = -vel.x ; vel.x = -vel.x
movss xmm6, xmm2 movss xmm6, xmm2
mulss xmm6, [rel NEG_ONE] mulss xmm6, [rel NEG_ONE]
@@ -104,11 +145,11 @@ figure_check_collision_circle:
.check_right: .check_right:
; pos.x + radius > 1 ? ; pos.x + radius > 1 ?
movss xmm8, [rel ONE_CONST] 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 ; Actually want pos.x + radius > 1 <=> pos.x > 1 - radius
; compute bound = 1 - radius ; compute bound = 1 - r_x
movss xmm9, [rel ONE_CONST] movss xmm9, [rel ONE_CONST]
subss xmm9, xmm5 subss xmm9, xmm12
ucomiss xmm0, xmm9 ucomiss xmm0, xmm9
jbe .done_x jbe .done_x
; pos.x = 1 - radius ; pos.x = 1 - radius
@@ -124,10 +165,10 @@ figure_check_collision_circle:
.done_x: .done_x:
; check bottom / top boundaries for y ; check bottom / top boundaries for y
; bottom: pos.y < radius ; bottom: pos.y < r_y
ucomiss xmm1, xmm12 ucomiss xmm1, xmm13
jae .check_top2 jae .check_top2
movss dword [rax + FIG_POSITION + 4], xmm12 movss dword [rax + FIG_POSITION + 4], xmm13
movss xmm6, xmm3 movss xmm6, xmm3
mulss xmm6, [rel NEG_ONE] mulss xmm6, [rel NEG_ONE]
movss dword [rax + FIG_VELOCITY + 4], xmm6 movss dword [rax + FIG_VELOCITY + 4], xmm6
@@ -138,9 +179,9 @@ figure_check_collision_circle:
jmp .done_y jmp .done_y
.check_top2: .check_top2:
; top: pos.y > 1 - radius ; top: pos.y > 1 - r_y
movss xmm9, [rel ONE_CONST] movss xmm9, [rel ONE_CONST]
subss xmm9, xmm5 subss xmm9, xmm13
ucomiss xmm1, xmm9 ucomiss xmm1, xmm9
jbe .done_y jbe .done_y
movss dword [rax + FIG_POSITION + 4], xmm9 movss dword [rax + FIG_POSITION + 4], xmm9
@@ -156,7 +197,7 @@ figure_check_collision_circle:
ret ret
section .rodata section .rodata
SCALE_FACTOR: dd 0.001
DT: dd 0.1 DT: dd 0.1
NEG_ONE: dd -1.0 NEG_ONE: dd -1.0
ONE_CONST: dd 1.0 ONE_CONST: dd 1.0
ZERO_CONST: dd 0.0

View File

@@ -19,7 +19,8 @@ void figure_draw(struct window_draw_info* draw_info, float border_thickness, uin
/* center in pixels */ /* center in pixels */
float cx = fig.position.x * (float)w; float cx = fig.position.x * (float)w;
float cy = fig.position.y * (float)h; 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 r2 = r * r;
float border = border_thickness; float border = border_thickness;
if (border < 0.0f) border = 0.0f; if (border < 0.0f) border = 0.0f;

View File

@@ -52,7 +52,7 @@ static void *window_aux_loop(void *arg)
figure_animation_step(draw_info); figure_animation_step(draw_info);
pthread_mutex_unlock(&draw_info->figure_mutex); pthread_mutex_unlock(&draw_info->figure_mutex);
usleep(100 * 1000); usleep(30 * 1000);
} }
return NULL; return NULL;
} }

View File

@@ -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.velocity.y = 0.3f;
draw_info->figure.angle = 0.0f; draw_info->figure.angle = 0.0f;
draw_info->figure.angular_velocity = 1.0f; /* radians per second */ 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.speed = 100.0f; /* pixels per second */
draw_info->figure.radius = 0.05f; /* normalized relative to width: 5% */ draw_info->figure.radius = 20.0f; /* radius in pixels */
win->buffer = NULL; win->buffer = NULL;
win->frame_callback = NULL; win->frame_callback = NULL;