Первый движок анимации

This commit is contained in:
2025-11-17 15:43:33 +03:00
parent 5ac43bb236
commit 92f4632803
5 changed files with 174 additions and 25 deletions

View File

@@ -24,6 +24,7 @@ int main(void) {
printf("FIG_ANGLE equ %zu\n", offsetof(struct figure_animation_info, angle));
printf("FIG_ANG_VEL equ %zu\n", offsetof(struct figure_animation_info, angular_velocity));
printf("FIG_SPEED equ %zu\n", offsetof(struct figure_animation_info, speed));
printf("FIG_RADIUS equ %zu\n", offsetof(struct figure_animation_info, radius));
return 0;
}

View File

@@ -0,0 +1,9 @@
#ifndef FIGURE_DRAW_H
#define FIGURE_ANFIGURE_DRAW_HIMATE_H
#include "window.h"
/* Нарисовать фигуру на холсте */
void figure_draw(struct window_draw_info* draw_info, float border_thikness, uint32_t border_color, uint32_t fill_color);
#endif

View File

@@ -19,6 +19,10 @@ struct figure_animation_info {
float angular_velocity;
float speed;
/* Radius of the figure normalized for window width (0..1)
* This field is used by animation code to check collisions
* with the left/right/top/bottom borders. */
float radius;
};
#endif

View File

@@ -8,32 +8,155 @@ section .text
; rdi - указатель на struct window_draw_info
global figure_animation_step
figure_animation_step:
; Создаём локальную область на стеке и будем туда копировать поля структуры
enter 0, 0
; rdi - pointer to struct window_draw_info
; figure is embedded at offset WDI_FIGURE
mov rax, rdi
add rax, WDI_FIGURE
; Сохранение регистров (если будут использоваться)
; push rbx
; push r12
; push r13
; --- compute movement scale: scale = speed * (dt / BASE_SIZE)
; using SSE for float math
movss xmm0, dword [rax + FIG_SPEED] ; xmm0 = speed
mulss xmm0, [rel SCALE_FACTOR] ; xmm0 = speed * (dt / BASE_SIZE)
; rdi содержит указатель на window_draw_info
; Доступ к полям через константы из offsets.inc:
mov rax, WDI_FIGURE ; указатель на данные
; mov edx, [rdi + WD_WIDTH] ; ширина окна
; mov ecx, [rdi + WD_HEIGHT] ; высота окна
; lea rsi, [rdi + WD_FIGURE] ; указатель на figure_animation_info
;
; Доступ к полям figure_animation_info (относительно rsi):
; mov eax, [rsi + FIG_TYPE] ; тип фигуры
; movss xmm0, [rsi + FIG_ANGLE] ; угол поворота
; movss xmm1, [rsi + FIG_SPEED] ; скорость
; dx = velocity.x * scale
movss xmm1, dword [rax + FIG_VELOCITY] ; velocity.x
mulss xmm1, xmm0
movss xmm2, dword [rax + FIG_POSITION] ; position.x
addss xmm2, xmm1
movss dword [rax + FIG_POSITION], xmm2
; --- Здесь будет логика анимации ---
; dy = velocity.y * scale
movss xmm1, dword [rax + FIG_VELOCITY + 4]
mulss xmm1, xmm0
movss xmm2, dword [rax + FIG_POSITION + 4]
addss xmm2, xmm1
movss dword [rax + FIG_POSITION + 4], xmm2
; rotate: angle += angular_velocity * dt
movss xmm3, dword [rax + FIG_ANG_VEL]
mulss xmm3, [rel DT]
movss xmm4, dword [rax + FIG_ANGLE]
addss xmm4, xmm3
movss dword [rax + FIG_ANGLE], xmm4
; Восстановление регистров
; pop r13
; pop r12
; pop rbx
; If circle -> call collision check helper
mov ecx, dword [rax + FIG_TYPE]
cmp ecx, 0
jne .no_collision_check
; pass pointer to window_draw_info (original rdi) in rdi
; rdi already has draw_info pointer
call figure_check_collision_circle
.no_collision_check:
leave
ret
; helper: check collision for circle and reflect velocity & angular velocity
; rdi - pointer to struct window_draw_info
global figure_check_collision_circle
figure_check_collision_circle:
push rbx
; rdi -> window_draw_info
; rax -> figure_animation_info
mov rax, rdi
add rax, WDI_FIGURE
movss xmm0, dword [rax + FIG_POSITION] ; pos.x
movss xmm1, dword [rax + FIG_POSITION + 4] ; pos.y
movss xmm2, dword [rax + FIG_VELOCITY] ; vel.x
movss xmm3, dword [rax + FIG_VELOCITY + 4] ; vel.y
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]
; 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
mov ebx, dword [rdi + WDI_HEIGHT]
cvtsi2ss xmm11, ebx
divss xmm10, xmm11 ; xmm10 = width/height
movss xmm12, xmm5
mulss xmm12, xmm10 ; xmm12 = radius_y
; left edge: pos.x < radius ?
ucomiss xmm0, xmm5
jae .check_right
; pos.x = radius
movss dword [rax + FIG_POSITION], xmm5
; vel.x = -vel.x
movss xmm6, xmm2
mulss xmm6, [rel NEG_ONE]
movss dword [rax + FIG_VELOCITY], xmm6
; invert angular velocity
movss xmm7, xmm4
mulss xmm7, [rel NEG_ONE]
movss dword [rax + FIG_ANG_VEL], xmm7
jmp .done_x
.check_right:
; pos.x + radius > 1 ?
movss xmm8, [rel ONE_CONST]
addss xmm8, xmm5 ; xmm8 = 1 + radius
; Actually want pos.x + radius > 1 <=> pos.x > 1 - radius
; compute bound = 1 - radius
movss xmm9, [rel ONE_CONST]
subss xmm9, xmm5
ucomiss xmm0, xmm9
jbe .done_x
; pos.x = 1 - radius
movss dword [rax + FIG_POSITION], xmm9
; vel.x = -vel.x
movss xmm6, xmm2
mulss xmm6, [rel NEG_ONE]
movss dword [rax + FIG_VELOCITY], xmm6
; invert angular velocity
movss xmm7, xmm4
mulss xmm7, [rel NEG_ONE]
movss dword [rax + FIG_ANG_VEL], xmm7
.done_x:
; check bottom / top boundaries for y
; bottom: pos.y < radius
ucomiss xmm1, xmm12
jae .check_top2
movss dword [rax + FIG_POSITION + 4], xmm12
movss xmm6, xmm3
mulss xmm6, [rel NEG_ONE]
movss dword [rax + FIG_VELOCITY + 4], xmm6
; invert angular
movss xmm7, xmm4
mulss xmm7, [rel NEG_ONE]
movss dword [rax + FIG_ANG_VEL], xmm7
jmp .done_y
.check_top2:
; top: pos.y > 1 - radius
movss xmm9, [rel ONE_CONST]
subss xmm9, xmm5
ucomiss xmm1, xmm9
jbe .done_y
movss dword [rax + FIG_POSITION + 4], xmm9
movss xmm6, xmm3
mulss xmm6, [rel NEG_ONE]
movss dword [rax + FIG_VELOCITY + 4], xmm6
movss xmm7, xmm4
mulss xmm7, [rel NEG_ONE]
movss dword [rax + FIG_ANG_VEL], xmm7
.done_y:
pop rbx
ret
section .rodata
SCALE_FACTOR: dd 0.001
DT: dd 0.1
NEG_ONE: dd -1.0
ONE_CONST: dd 1.0

View File

@@ -242,6 +242,18 @@ int window_init(struct wl_display *display, struct wl_event_queue *queue, struct
draw_info->width = 400;
draw_info->height = 250;
draw_info->data = NULL;
/* Default animation state */
draw_info->figure.type = FIGURE_CIRCLE;
draw_info->figure.position.x = 0.5f;
draw_info->figure.position.y = 0.5f;
draw_info->figure.velocity.x = 0.6f;
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% */
win->buffer = NULL;
win->frame_callback = NULL;
win->need_close = 0;