diff --git a/wayland/generate-offsets.c b/wayland/generate-offsets.c index 565e698..96f5133 100644 --- a/wayland/generate-offsets.c +++ b/wayland/generate-offsets.c @@ -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; } diff --git a/wayland/include/figure-draw.h b/wayland/include/figure-draw.h new file mode 100644 index 0000000..a9aef1b --- /dev/null +++ b/wayland/include/figure-draw.h @@ -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 diff --git a/wayland/include/figure.h b/wayland/include/figure.h index 33f81d4..0a4b19c 100644 --- a/wayland/include/figure.h +++ b/wayland/include/figure.h @@ -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 diff --git a/wayland/src/figure-animate.asm b/wayland/src/figure-animate.asm index 6591c31..e18ccb9 100644 --- a/wayland/src/figure-animate.asm +++ b/wayland/src/figure-animate.asm @@ -8,32 +8,155 @@ section .text ; rdi - указатель на struct window_draw_info global figure_animation_step figure_animation_step: + ; Создаём локальную область на стеке и будем туда копировать поля структуры enter 0, 0 - - ; Сохранение регистров (если будут использоваться) - ; push rbx - ; push r12 - ; push r13 - - ; 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] ; скорость - - ; --- Здесь будет логика анимации --- - - - ; Восстановление регистров - ; pop r13 - ; pop r12 - ; pop rbx + ; rdi - pointer to struct window_draw_info + ; figure is embedded at offset WDI_FIGURE + mov rax, rdi + add rax, WDI_FIGURE + + ; --- 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) + + ; 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 + + ; 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 diff --git a/wayland/src/window.c b/wayland/src/window.c index b17f1ef..5d2d604 100644 --- a/wayland/src/window.c +++ b/wayland/src/window.c @@ -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;