Compare commits

...

6 Commits

8 changed files with 937 additions and 306 deletions

View File

@@ -13,24 +13,13 @@ 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 in pixels (float)
* This field is used by animation code to check collisions
* 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

@@ -1,203 +1,613 @@
; Макрос для локальных переменных
%macro local 2
%assign __local_offset __local_offset - %2
%define %1 (__local_offset)
%endmacro
; Подключаем автоматически сгенерированные offsets из C структур ; Подключаем автоматически сгенерированные offsets из C структур
%include "offsets.inc" %include "offsets.inc"
section .rodata
PI: dd 3.1415926
TWO_PI: dd 6.2831852
NEG_ONE_CONST: dd -1.0
ONE_CONST: dd 1.0
ZERO_CONST: dd 0.0
ABS_MASK: dd 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff
ANG_COLLIDE_COEF: dd 0.55
ANG_BOOST_FACTOR: dd 0.02
ANG_MAX: dd 0.04
ANG_SWITCH_FACTOR: dd 0.1
ANG_MAX_DELTA: dd 0.5
ANG_FRICTION: dd 0.95
section .text section .text
; void animation_step(struct window_draw_info* draw_info); ; void figure_animation_step(struct window_draw_info* draw_info);
; Параметры: ; Параметры:
; rdi - указатель на struct window_draw_info ; rdi - указатель на struct window_draw_info
%assign __local_offset 0
global figure_animation_step global figure_animation_step
figure_animation_step: figure_animation_step:
; Создаём локальную область на стеке и будем туда копировать поля структуры
enter 0, 0 enter 0, 0
; rdi - pointer to struct window_draw_info
; figure is embedded at offset WDI_FIGURE
mov rax, rdi
add rax, WDI_FIGURE
; --- compute movement increments so that `speed` means pixels/second ; Отработка коллизий
; Convert velocity to pixel-space (vx = vel.x * width, vy = vel.y * height), push rdi
; normalize that vector and apply `speed*dt` so movement in pixel units equals speed. call figure_handle_collision
; using SSE for float math pop rdi
movss xmm0, dword [rax + FIG_SPEED] ; xmm0 = speed (pixels/sec)
movss xmm9, [rel DT] ; xmm9 = dt
mulss xmm0, xmm9 ; xmm0 = speed * dt (pixels)
; load width/height ; Вычислить нормализующий коэффициент: 1.0 / height_pixels
mov ebx, dword [rdi + WDI_WIDTH] cvtsi2ss xmm4, dword [rdi + WDI_HEIGHT]
cvtsi2ss xmm10, ebx ; xmm10 = width movss xmm5, [rel ONE_CONST]
mov ebx, dword [rdi + WDI_HEIGHT] divss xmm5, xmm4 ; xmm5 = 1.0 / height
cvtsi2ss xmm11, ebx ; xmm11 = height
; vx_pixels = vel.x * width ; Обновить позицию: position += (velocity * speed) / height_pixels
movss xmm1, dword [rax + FIG_VELOCITY] ; vel.x ; pos_x += (vel_x * speed) / height
mulss xmm1, xmm10 ; xmm1 = vx_pixels movss xmm0, [rdi + WDI_FIGURE + FIG_VELOCITY]
mulss xmm0, [rdi + WDI_FIGURE + FIG_SPEED]
mulss xmm0, xmm5 ; нормализовать скорость
addss xmm0, [rdi + WDI_FIGURE + FIG_POSITION]
movss [rdi + WDI_FIGURE + FIG_POSITION], xmm0
; vy_pixels = vel.y * height ; pos_y += (vel_y * speed) / height
movss xmm2, dword [rax + FIG_VELOCITY + 4] movss xmm0, [rdi + WDI_FIGURE + FIG_VELOCITY + 4]
mulss xmm2, xmm11 ; xmm2 = vy_pixels mulss xmm0, [rdi + WDI_FIGURE + FIG_SPEED]
mulss xmm0, xmm5 ; нормализовать скорость
addss xmm0, [rdi + WDI_FIGURE + FIG_POSITION + 4]
movss [rdi + WDI_FIGURE + FIG_POSITION + 4], xmm0
; length = sqrt(vx^2 + vy^2) ; Обновить угол: angle += angular_velocity * speed
movss xmm3, xmm1 movss xmm0, [rdi + WDI_FIGURE + FIG_ANG_VEL]
mulss xmm3, xmm1 ; xmm3 = vx^2 mulss xmm0, [rdi + WDI_FIGURE + FIG_SPEED]
movss xmm4, xmm2 addss xmm0, [rdi + WDI_FIGURE + FIG_ANGLE]
mulss xmm4, xmm4 ; xmm4 = vy^2 movss [rdi + WDI_FIGURE + FIG_ANGLE], xmm0
addss xmm3, xmm4 ; xmm3 = vx^2 + vy^2
sqrtss xmm3, xmm3 ; xmm3 = length (pixels)
; if length == 0 -> skip movement ; Apply angular friction to slow down rotation over time
ucomiss xmm3, [rel ZERO_CONST] movss xmm0, [rdi + WDI_FIGURE + FIG_ANG_VEL]
je .skip_move mulss xmm0, [rel ANG_FRICTION]
movss [rdi + WDI_FIGURE + FIG_ANG_VEL], xmm0
; scalar = (speed * dt) / length leave
movss xmm4, xmm0 ; xmm4 = speed*dt ret
divss xmm4, xmm3 ; xmm4 = scalar
; dx = vel.x * scalar ; Функция для обработки коллизии, изменяет velocity при обнаружении коллизии с границами
movss xmm1, dword [rax + FIG_VELOCITY] ; Параметры:
; rdi - указатель на struct window_draw_info
%assign __local_offset 0
figure_handle_collision:
enter 128,0
local point_buffer, 128
; Сохранить регистры
push r12
push r13
push r14
push r15
mov r12, rdi
; Нормализовать радиус: radius_normalized = radius_pixels / height_pixels
movss xmm3, [r12 + WDI_FIGURE + FIG_RADIUS]
cvtsi2ss xmm4, dword [r12 + WDI_HEIGHT]
divss xmm3, xmm4
; Вызов place_points_on_circle
movss xmm0, [r12 + WDI_FIGURE + FIG_POSITION]
movss xmm1, [r12 + WDI_FIGURE + FIG_POSITION + 4]
movss xmm2, [r12 + WDI_FIGURE + FIG_ANGLE] ; смещение угла = 0
mulss xmm2, [rel NEG_ONE_CONST]
; Установка правильного количества точек
mov eax, dword [r12 + WDI_FIGURE + FIG_TYPE]
cmp eax, 1 ; FIGURE_TRIANGLE
je .figure_triangle
cmp eax, 2 ; FIGURE_SQUARE
je .figure_square
; default (FIGURE_CIRCLE and others): 16 points
mov rsi, 16
jmp .figure_points_done
.figure_triangle:
mov rsi, 3
jmp .figure_points_done
.figure_square:
mov rsi, 4
.figure_points_done:
lea rdi, [rbp + point_buffer]
call place_points_on_circle
; Вычислить canvas_width = width_pixels / height_pixels
cvtsi2ss xmm0, dword [r12 + WDI_WIDTH]
cvtsi2ss xmm1, dword [r12 + WDI_HEIGHT]
divss xmm0, xmm1
movss xmm14, xmm0 ; сохраняем canvas_width в xmm14
movss xmm13, [rel ONE_CONST] ; canvas_height = 1.0 в xmm13
; Инициализация: r14 = маска коллизий (OR всех точек), r15 = указатель на текущую точку
xor r14, r14
lea r15, [rbp + point_buffer]
mov rcx, rsi
.point_check:
; Загрузить координаты точки
movss xmm2, [r15] ; x
movss xmm3, [r15 + 4] ; y
; Вызвать check_collision_mask(canvas_width, canvas_height, x, y)
movss xmm0, xmm14 ; width
movss xmm1, xmm13 ; height = 1.0
push rcx
call check_collision_mask
pop rcx
; Объединить маску коллизий
or r14, rax
; Перейти к следующей точке
add r15, 8
loop .point_check
; Проверить, были ли коллизии
test r14, r14
jz .no_collision
; -----------------------
; Обновить угловую скорость при коллизии
; Формула: delta = |relevant_velocity| * speed * ANG_COLLIDE_COEF
; Знак delta зависит от границы и направления движения.
; Если итоговое направление совпадает с текущим - даём небольшой буст.
; -----------------------
; Сохраняем старую угловую скорость и обнуляем суммарный эффект
movss xmm6, [r12 + WDI_FIGURE + FIG_ANG_VEL] ; old ang vel
xorps xmm7, xmm7 ; total delta
; LEFT (bit 0): use vertical motion (vel_y)
test r14, 0x1
jz .skip_left_ang
movss xmm0, [r12 + WDI_FIGURE + FIG_VELOCITY + 4] ; vel_y
movss xmm1, xmm0
; Broadcast ABS_MASK (0x7fffffff) into xmm2 and AND to get abs
mov eax, dword [rel ABS_MASK]
movd xmm2, eax
pshufd xmm2, xmm2, 0x0
andps xmm1, xmm2 ; abs(vel_y)
mulss xmm1, [r12 + WDI_FIGURE + FIG_SPEED]
mulss xmm1, [rel ANG_COLLIDE_COEF]
ucomiss xmm0, [rel ZERO_CONST]
jb .left_up_ang ; vel_y < 0 -> moving UP
; moving DOWN -> clockwise (+)
addss xmm7, xmm1
jmp .skip_left_ang
.left_up_ang:
; moving UP -> anticlockwise (-)
movss xmm2, [rel NEG_ONE_CONST]
mulss xmm1, xmm2
addss xmm7, xmm1
.skip_left_ang:
; RIGHT (bit 2): use vertical motion (vel_y)
test r14, 0x4
jz .skip_right_ang
movss xmm0, [r12 + WDI_FIGURE + FIG_VELOCITY + 4] ; vel_y
movss xmm1, xmm0
mov eax, dword [rel ABS_MASK]
movd xmm2, eax
pshufd xmm2, xmm2, 0x0
andps xmm1, xmm2
mulss xmm1, [r12 + WDI_FIGURE + FIG_SPEED]
mulss xmm1, [rel ANG_COLLIDE_COEF]
ucomiss xmm0, [rel ZERO_CONST]
jb .right_up_ang ; vel_y < 0 -> moving UP
; moving DOWN -> anticlockwise (-)
movss xmm2, [rel NEG_ONE_CONST]
mulss xmm1, xmm2
addss xmm7, xmm1
jmp .skip_right_ang
.right_up_ang:
; moving UP -> clockwise (+)
addss xmm7, xmm1
.skip_right_ang:
; TOP (bit 1): use horizontal motion (vel_x)
test r14, 0x2
jz .skip_top_ang
movss xmm0, [r12 + WDI_FIGURE + FIG_VELOCITY] ; vel_x
movss xmm1, xmm0
mov eax, dword [rel ABS_MASK]
movd xmm2, eax
pshufd xmm2, xmm2, 0x0
andps xmm1, xmm2
mulss xmm1, [r12 + WDI_FIGURE + FIG_SPEED]
mulss xmm1, [rel ANG_COLLIDE_COEF]
ucomiss xmm0, [rel ZERO_CONST]
ja .top_right_ang ; vel_x > 0 -> moving RIGHT
; moving LEFT -> clockwise (+)
addss xmm7, xmm1
jmp .skip_top_ang
.top_right_ang:
; moving RIGHT -> anticlockwise (-)
movss xmm2, [rel NEG_ONE_CONST]
mulss xmm1, xmm2
addss xmm7, xmm1
.skip_top_ang:
; BOTTOM (bit 3): use horizontal motion (vel_x)
test r14, 0x8
jz .skip_bottom_ang
movss xmm0, [r12 + WDI_FIGURE + FIG_VELOCITY] ; vel_x
movss xmm1, xmm0
mov eax, dword [rel ABS_MASK]
movd xmm2, eax
pshufd xmm2, xmm2, 0x0
andps xmm1, xmm2
mulss xmm1, [r12 + WDI_FIGURE + FIG_SPEED]
mulss xmm1, [rel ANG_COLLIDE_COEF]
ucomiss xmm0, [rel ZERO_CONST]
ja .bottom_right_ang ; vel_x > 0 -> moving RIGHT
; moving LEFT -> anticlockwise (-)
movss xmm2, [rel NEG_ONE_CONST]
mulss xmm1, xmm2
addss xmm7, xmm1
jmp .skip_bottom_ang
.bottom_right_ang:
; moving RIGHT -> clockwise (+)
addss xmm7, xmm1
.skip_bottom_ang:
; Если суммарный эффект нулевой - ничего не делаем
ucomiss xmm7, [rel ZERO_CONST]
je .ang_no_change
; Invert direction rules to match drawing coordinate system
; (User requested flip — so we reverse sign of computed delta)
movss xmm0, [rel NEG_ONE_CONST]
mulss xmm7, xmm0
; Decide: same direction or switch sign
ucomiss xmm6, [rel ZERO_CONST]
jb .old_neg_dir
; old >= 0
ucomiss xmm7, [rel ZERO_CONST]
jae .same_dir
jmp .switch_dir
.old_neg_dir:
; old < 0
ucomiss xmm7, [rel ZERO_CONST]
jb .same_dir
jmp .switch_dir
; If same direction -> boost and add
.same_dir:
mulss xmm7, [rel ANG_BOOST_FACTOR]
; Clamp delta magnitude to ANG_MAX_DELTA
movss xmm0, xmm7
movss xmm1, xmm0
mov eax, dword [rel ABS_MASK]
movd xmm2, eax
pshufd xmm2, xmm2, 0x0
andps xmm1, xmm2 ; xmm1 = abs(delta)
movss xmm3, [rel ANG_MAX_DELTA]
ucomiss xmm1, xmm3
ja .cap_delta_same
jmp .after_cap_same
.cap_delta_same:
; Set abs(delta) = ANG_MAX_DELTA, preserve sign
movss xmm1, [rel ANG_MAX_DELTA]
ucomiss xmm0, [rel ZERO_CONST]
jae .cap_delta_same_pos
movss xmm4, [rel NEG_ONE_CONST]
mulss xmm1, xmm4 mulss xmm1, xmm4
movss xmm2, dword [rax + FIG_POSITION] ; position.x .cap_delta_same_pos:
addss xmm2, xmm1 movss xmm7, xmm1
movss dword [rax + FIG_POSITION], xmm2 .after_cap_same:
addss xmm6, xmm7
jmp .finish_dir_logic
; dy = vel.y * scalar ; Switch sign -> compute new magnitude using old magnitude and delta
movss xmm1, dword [rax + FIG_VELOCITY + 4] .switch_dir:
mulss xmm1, xmm4 ; xmm6 = old, xmm7 = delta
movss xmm2, dword [rax + FIG_POSITION + 4] ; abs_old = abs(xmm6)
addss xmm2, xmm1 movss xmm0, xmm6
movss dword [rax + FIG_POSITION + 4], xmm2 movss xmm1, xmm0
mov eax, dword [rel ABS_MASK]
movd xmm2, eax
pshufd xmm2, xmm2, 0x0
andps xmm1, xmm2 ; xmm1 = abs_old
.skip_move: ; abs_delta = abs(xmm7)
movss xmm3, xmm7
movss xmm4, xmm3
andps xmm4, xmm2 ; xmm4 = abs_delta
; Clamp abs_delta
movss xmm5, [rel ANG_MAX_DELTA]
ucomiss xmm4, xmm5
ja .cap_delta_switch
jmp .delta_not_capped
.cap_delta_switch:
movss xmm4, xmm5
.delta_not_capped:
; rotate: angle += angular_velocity * dt ; abs_old *= ANG_SWITCH_FACTOR
movss xmm3, dword [rax + FIG_ANG_VEL] movss xmm5, [rel ANG_SWITCH_FACTOR]
mulss xmm3, [rel DT] mulss xmm1, xmm5
movss xmm4, dword [rax + FIG_ANGLE]
addss xmm4, xmm3
movss dword [rax + FIG_ANGLE], xmm4
; If circle -> call collision check helper ; new_mag = abs_old + abs_delta
mov ecx, dword [rax + FIG_TYPE] addss xmm1, xmm4
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: ; apply sign of delta (xmm7)
ucomiss xmm7, [rel ZERO_CONST]
jae .switch_positive
; negative
movss xmm5, [rel NEG_ONE_CONST]
mulss xmm1, xmm5
movss xmm6, xmm1
jmp .finish_dir_logic
.switch_positive:
movss xmm6, xmm1
.finish_dir_logic:
; Clamp angular velocity: |xmm6| <= ANG_MAX
movss xmm0, xmm6
movss xmm1, xmm0
mov eax, dword [rel ABS_MASK]
movd xmm2, eax
pshufd xmm2, xmm2, 0x0
andps xmm1, xmm2 ; xmm1 = abs(xmm0)
movss xmm2, [rel ANG_MAX]
ucomiss xmm1, xmm2
ja .ang_clamp_needed
movss [r12 + WDI_FIGURE + FIG_ANG_VEL], xmm6
jmp .ang_no_change2
.ang_clamp_needed:
; If xmm0 >= 0 -> set +ANG_MAX else set -ANG_MAX
ucomiss xmm0, [rel ZERO_CONST]
jae .ang_positive_clamp
; negative
movss xmm3, [rel ANG_MAX]
movss xmm4, [rel NEG_ONE_CONST]
mulss xmm3, xmm4
movss xmm6, xmm3
movss [r12 + WDI_FIGURE + FIG_ANG_VEL], xmm6
jmp .ang_no_change2
.ang_positive_clamp:
movss xmm3, [rel ANG_MAX]
movss xmm6, xmm3
movss [r12 + WDI_FIGURE + FIG_ANG_VEL], xmm6
.ang_no_change2:
.ang_no_change:
; Обработка коллизий: инвертировать velocity только если движемся к границе
; Проверка left (bit 0): инвертировать velocity.x только если vel.x < 0
test r14, 0x1
jz .check_right
movss xmm0, [r12 + WDI_FIGURE + FIG_VELOCITY]
movss xmm1, [rel ZERO_CONST]
ucomiss xmm0, xmm1
jae .check_right ; если vel.x >= 0, пропускаем
; vel.x < 0, инвертируем
movss xmm1, [rel NEG_ONE_CONST]
mulss xmm0, xmm1
movss [r12 + WDI_FIGURE + FIG_VELOCITY], xmm0
.check_right:
; Проверка right (bit 2): инвертировать velocity.x только если vel.x > 0
test r14, 0x4
jz .check_top
movss xmm0, [r12 + WDI_FIGURE + FIG_VELOCITY]
movss xmm1, [rel ZERO_CONST]
ucomiss xmm0, xmm1
jbe .check_top ; если vel.x <= 0, пропускаем
; vel.x > 0, инвертируем
movss xmm1, [rel NEG_ONE_CONST]
mulss xmm0, xmm1
movss [r12 + WDI_FIGURE + FIG_VELOCITY], xmm0
.check_top:
; Проверка top (bit 1): инвертировать velocity.y только если vel.y < 0
test r14, 0x2
jz .check_bottom
movss xmm0, [r12 + WDI_FIGURE + FIG_VELOCITY + 4]
movss xmm1, [rel ZERO_CONST]
ucomiss xmm0, xmm1
jae .check_bottom ; если vel.y >= 0, пропускаем
; vel.y < 0, инвертируем
movss xmm1, [rel NEG_ONE_CONST]
mulss xmm0, xmm1
movss [r12 + WDI_FIGURE + FIG_VELOCITY + 4], xmm0
.check_bottom:
; Проверка bottom (bit 3): инвертировать velocity.y только если vel.y > 0
test r14, 0x8
jz .no_collision
movss xmm0, [r12 + WDI_FIGURE + FIG_VELOCITY + 4]
movss xmm1, [rel ZERO_CONST]
ucomiss xmm0, xmm1
jbe .no_collision ; если vel.y <= 0, пропускаем
; vel.y > 0, инвертируем
movss xmm1, [rel NEG_ONE_CONST]
mulss xmm0, xmm1
movss [r12 + WDI_FIGURE + FIG_VELOCITY + 4], xmm0
.no_collision:
; Костыль: если центр фигуры вышел за границу, вернуть его на границу
; Проверка pos_x < 0
movss xmm0, [r12 + WDI_FIGURE + FIG_POSITION]
movss xmm1, [rel ZERO_CONST]
ucomiss xmm0, xmm1
jae .check_pos_x_max
movss [r12 + WDI_FIGURE + FIG_POSITION], xmm1 ; pos_x = 0
.check_pos_x_max:
; Проверка pos_x > canvas_width
movss xmm0, [r12 + WDI_FIGURE + FIG_POSITION]
ucomiss xmm0, xmm14
jbe .check_pos_y_min
movss [r12 + WDI_FIGURE + FIG_POSITION], xmm14 ; pos_x = canvas_width
.check_pos_y_min:
; Проверка pos_y < 0
movss xmm0, [r12 + WDI_FIGURE + FIG_POSITION + 4]
movss xmm1, [rel ZERO_CONST]
ucomiss xmm0, xmm1
jae .check_pos_y_max
movss [r12 + WDI_FIGURE + FIG_POSITION + 4], xmm1 ; pos_y = 0
.check_pos_y_max:
; Проверка pos_y > canvas_height (1.0)
movss xmm0, [r12 + WDI_FIGURE + FIG_POSITION + 4]
ucomiss xmm0, xmm13
jbe .position_clamped
movss [r12 + WDI_FIGURE + FIG_POSITION + 4], xmm13 ; pos_y = 1.0
.position_clamped:
; Восстановить регистры
pop r15
pop r14
pop r13
pop r12
leave leave
ret ret
; helper: check collision for circle and reflect velocity & angular velocity ; Функция для расположения точек на окружности
; rdi - pointer to struct window_draw_info ; Вход:
global figure_check_collision_circle ; xmm0 - pos_x
figure_check_collision_circle: ; xmm1 - pos_y
push rbx ; xmm2 - смещение точек на окружности в радианах
; rdi -> window_draw_info ; xmm3 - радиус
; rax -> figure_animation_info ; rdi - адрес буфера для точек
mov rax, rdi ; rsi - количество точек
add rax, WDI_FIGURE ; Уничтожает: rax, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7
global place_points_on_circle
place_points_on_circle:
enter 0, 0
movss xmm0, dword [rax + FIG_POSITION] ; pos.x ; Сохранить координаты центра
movss xmm1, dword [rax + FIG_POSITION + 4] ; pos.y movss xmm6, xmm0
movss xmm7, xmm1
movss xmm2, dword [rax + FIG_VELOCITY] ; vel.x ; Рассчитать TWO_PI / rsi и сохранить в xmm4
movss xmm3, dword [rax + FIG_VELOCITY + 4] ; vel.y movss xmm4, [rel TWO_PI]
cvtsi2ss xmm5, rsi
divss xmm4, xmm5
movss xmm4, dword [rax + FIG_ANG_VEL] ; angvel movss xmm5, [rel ZERO_CONST] ; счётчик
mov rcx, rsi
.loop:
movss xmm0, xmm5
; radius is stored in figure as pixel count (float) mulss xmm0, xmm4 ; Счётчик*шаг
; we keep positions normalized (0..1) so convert radius to normalized addss xmm0, xmm2 ; Прибавить смещение
; coordinates for x and y: r_x = radius / width, r_y = radius / height call sincos_f32_rbp ; Посчитать sincos
movss xmm5, dword [rax + FIG_RADIUS] ; xmm5 = radius_pixels mulss xmm0, xmm3 ; sin *= radius
mulss xmm1, xmm3 ; cos *= radius
; load width/height from window_draw_info addss xmm1, xmm6 ; x = center_x + cos*radius
mov ebx, dword [rdi + WDI_WIDTH] addss xmm0, xmm7 ; y = center_y + sin*radius
cvtsi2ss xmm10, ebx ; xmm10 = width
mov ebx, dword [rdi + WDI_HEIGHT]
cvtsi2ss xmm11, ebx ; xmm11 = height
; compute r_x = radius / width movss [rdi], xmm1
movss xmm12, xmm5 movss [rdi + 4], xmm0
divss xmm12, xmm10 ; xmm12 = r_x add rdi, 8
; compute r_y = radius / height
movss xmm13, xmm5
divss xmm13, xmm11 ; xmm13 = r_y
; left edge: pos.x < r_x ? addss xmm5, [rel ONE_CONST]
ucomiss xmm0, xmm12 loop .loop
jae .check_right
; pos.x = radius
movss dword [rax + FIG_POSITION], xmm12
; 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: leave
; pos.x + radius > 1 ?
movss xmm8, [rel ONE_CONST]
addss xmm8, xmm12 ; xmm8 = 1 + r_x
; Actually want pos.x + radius > 1 <=> pos.x > 1 - radius
; compute bound = 1 - r_x
movss xmm9, [rel ONE_CONST]
subss xmm9, xmm12
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 < r_y
ucomiss xmm1, xmm13
jae .check_top2
movss dword [rax + FIG_POSITION + 4], xmm13
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 - r_y
movss xmm9, [rel ONE_CONST]
subss xmm9, xmm13
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 ret
section .rodata
DT: dd 0.1 ; Функция для рассчёта sin и cos
NEG_ONE: dd -1.0 ; Вход:
ONE_CONST: dd 1.0 ; xmm0 - угол в радианах (float)
ZERO_CONST: dd 0.0 ; Выход:
; xmm0 - sin(angle)
; xmm1 - cos(angle)
; Уничтожает: rax, flags
sincos_f32_rbp:
enter 24, 0 ; 24 байта локального места:
; [rbp-8] — временно угол (для fld)
; [rbp-16] — sin
; [rbp-24] — cos
; (выравнивание по 16 будет соблюдено за счёт enter)
; Сохраняем входной угол как float32 в стек для загрузки в x87
movss [rbp-8], xmm0
fld dword [rbp-8] ; ST(0) = angle (в extended precision)
fsincos ; ST(0) = cos, ST(1) = sin
; Сохраняем результаты обратно в память как float32
fstp dword [rbp-24] ; pop cos → [rbp-24]
fstp dword [rbp-16] ; pop sin → [rbp-16]
; Загружаем результаты в xmm0 и xmm1
movss xmm0, [rbp-16] ; xmm0 = sin
movss xmm1, [rbp-24] ; xmm1 = cos
leave ; эквивалент: mov rsp, rbp / pop rbp
ret
; Функция проверки выхода за границы с маской
; Вход:
; xmm0 - width
; xmm1 - height
; xmm2 - x
; xmm3 - y
; Выход:
; rax - битовая маска границ (left=1, top=2, right=4, bottom=8)
check_collision_mask:
xor rax, rax ; очистим rax (маска)
movss xmm4, [rel ZERO_CONST]
; left: x < 0
ucomiss xmm2, xmm4
jb .set_left
.next_left:
; right: x > width
ucomiss xmm2, xmm0
ja .set_right
.next_right:
; top: y < 0
ucomiss xmm3, xmm4
jb .set_top
.next_top:
; bottom: y > height
ucomiss xmm3, xmm1
ja .set_bottom
ret
.set_left:
or rax, 1
jmp .next_left
.set_top:
or rax, 2
jmp .next_top
.set_right:
or rax, 4
jmp .next_right
.set_bottom:
or rax, 8
ret

View File

@@ -1,110 +1,239 @@
#include <math.h> #include <math.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "figure-draw.h" #include "figure-draw.h"
/* C implementation of the drawing routine. The .asm file simply forwards to this #ifndef M_PI
* function so we keep the symbol present in an assembly file. */ #define M_PI 3.14159265358979323846
void figure_draw(struct window_draw_info* draw_info, float border_thickness, uint32_t border_color, uint32_t fill_color) #endif
/* Вспомогательная функция для установки пикселя */
static inline void set_pixel(uint8_t *data, int32_t width, int32_t height, int x, int y, uint32_t color)
{ {
if (!draw_info || !draw_info->data) if (x < 0 || x >= width || y < 0 || y >= height)
return; return;
int w = draw_info->width; uint32_t *pixel = (uint32_t *)(data + (y * width + x) * 4);
int h = draw_info->height; *pixel = color;
uint32_t *pixels = (uint32_t *)draw_info->data; }
struct figure_animation_info fig = draw_info->figure; /* Проверка, находится ли точка внутри треугольника (барицентрические координаты) */
static int point_in_triangle(float px, float py, float x1, float y1, float x2, float y2, float x3, float y3)
{
float d1 = (px - x2) * (y1 - y2) - (x1 - x2) * (py - y2);
float d2 = (px - x3) * (y2 - y3) - (x2 - x3) * (py - y3);
float d3 = (px - x1) * (y3 - y1) - (x3 - x1) * (py - y1);
/* center in pixels */ int has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0);
float cx = fig.position.x * (float)w; int has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0);
float cy = fig.position.y * (float)h;
/* `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;
/* bounding box */ return !(has_neg && has_pos);
int minx = (int)floorf(cx - r); }
int maxx = (int)ceilf(cx + r);
int miny = (int)floorf(cy - r);
int maxy = (int)ceilf(cy + r);
/* make sure we don't go out of bounds */
if (miny < 0) miny = 0;
if (minx < 0) minx = 0;
if (maxy >= h) maxy = h - 1;
if (maxx >= w) maxx = w - 1;
/* We'll compute pixel centers at (x + 0.5f, y + 0.5f) */ /* Расстояние от точки до отрезка */
for (int y = miny; y <= maxy; ++y) static float point_to_segment_distance(float px, float py, float x1, float y1, float x2, float y2)
{ {
float py = (float)y + 0.5f; float dx = x2 - x1;
for (int x = minx; x <= maxx; ++x) float dy = y2 - y1;
{ float len_sq = dx * dx + dy * dy;
float px = (float)x + 0.5f;
int draw = 0;
int border_pixel = 0;
switch (fig.type)
{
case FIGURE_CIRCLE:
{
float dx = px - cx;
float dy = py - cy;
float d2 = dx*dx + dy*dy;
if (d2 <= r2)
{
draw = 1;
if (d2 >= (r - border)*(r - border))
border_pixel = 1;
}
break;
}
case FIGURE_SQUARE:
{
float dx = fabsf(px - cx);
float dy = fabsf(py - cy);
if (dx <= r && dy <= r)
{
draw = 1;
if (fmaxf(dx, dy) >= r - border)
border_pixel = 1;
}
break;
}
case FIGURE_TRIANGLE:
{
/* Equilateral triangle centered at cx,cy. Apex up. *
* Vertices: A=(cx, cy - r), B=(cx + r*0.866, cy + r*0.5), C=(cx - r*0.866, cy + r*0.5) */
float v1x = r * 0.8660254037844386f;
float v1y = r * 0.5f;
float ax = cx; float ay = cy - r;
float bx = cx + v1x; float by = cy + v1y;
float cx2 = cx - v1x; float cy2 = by;
/* barycentric tests: point inside triangle if all cross products have same sign */ if (len_sq < 0.0001f) {
float s1 = (px - bx)*(ay - by) - (ax - bx)*(py - by); dx = px - x1;
float s2 = (px - cx2)*(by - cy2) - (bx - cx2)*(py - cy2); dy = py - y1;
float s3 = (px - ax)*(cy2 - ay) - (cx2 - ax)*(py - ay); return sqrtf(dx * dx + dy * dy);
int neg = (s1 < 0) + (s2 < 0) + (s3 < 0);
int pos = (s1 > 0) + (s2 > 0) + (s3 > 0);
if (neg == 0 || pos == 0)
{
draw = 1;
}
break;
}
default:
break;
} }
if (draw) float t = ((px - x1) * dx + (py - y1) * dy) / len_sq;
{ t = fmaxf(0.0f, fminf(1.0f, t));
uint32_t col = border_pixel ? border_color : fill_color;
pixels[y * w + x] = col; float proj_x = x1 + t * dx;
float proj_y = y1 + t * dy;
dx = px - proj_x;
dy = py - proj_y;
return sqrtf(dx * dx + dy * dy);
}
/* Рисование круга */
static void draw_circle(struct window_draw_info* draw_info, float cx, float cy, float radius,
float border_thickness, uint32_t border_color, uint32_t fill_color)
{
int x_min = (int)fmaxf(0, cx - radius - border_thickness);
int x_max = (int)fminf(draw_info->width - 1, cx + radius + border_thickness);
int y_min = (int)fmaxf(0, cy - radius - border_thickness);
int y_max = (int)fminf(draw_info->height - 1, cy + radius + border_thickness);
for (int y = y_min; y <= y_max; y++) {
for (int x = x_min; x <= x_max; x++) {
float dx = x - cx;
float dy = y - cy;
float dist = sqrtf(dx * dx + dy * dy);
if (dist <= radius) {
set_pixel(draw_info->data, draw_info->width, draw_info->height, x, y, fill_color);
} else if (dist <= radius + border_thickness) {
set_pixel(draw_info->data, draw_info->width, draw_info->height, x, y, border_color);
} }
} }
} }
} }
/* C symbol exported to be called by minimal assembly wrapper */ /* Рисование треугольника */
static void draw_triangle(struct window_draw_info* draw_info, float cx, float cy, float radius, float angle,
float border_thickness, uint32_t border_color, uint32_t fill_color)
{
/* Вычисляем координаты вершин равностороннего треугольника */
/* Угол 0 означает, что одна вершина справа от центра */
float vertices[3][2];
for (int i = 0; i < 3; i++) {
float vertex_angle = angle + i * (2.0f * M_PI / 3.0f);
vertices[i][0] = cx + radius * cosf(vertex_angle);
vertices[i][1] = cy - radius * sinf(vertex_angle); /* Инвертируем Y для экранных координат */
}
/* Находим ограничивающий прямоугольник */
float min_x = fminf(vertices[0][0], fminf(vertices[1][0], vertices[2][0])) - border_thickness;
float max_x = fmaxf(vertices[0][0], fmaxf(vertices[1][0], vertices[2][0])) + border_thickness;
float min_y = fminf(vertices[0][1], fminf(vertices[1][1], vertices[2][1])) - border_thickness;
float max_y = fmaxf(vertices[0][1], fmaxf(vertices[1][1], vertices[2][1])) + border_thickness;
int x_min = (int)fmaxf(0, min_x);
int x_max = (int)fminf(draw_info->width - 1, max_x);
int y_min = (int)fmaxf(0, min_y);
int y_max = (int)fminf(draw_info->height - 1, max_y);
/* Рисуем треугольник */
for (int y = y_min; y <= y_max; y++) {
for (int x = x_min; x <= x_max; x++) {
int inside = point_in_triangle((float)x, (float)y,
vertices[0][0], vertices[0][1],
vertices[1][0], vertices[1][1],
vertices[2][0], vertices[2][1]);
if (inside) {
set_pixel(draw_info->data, draw_info->width, draw_info->height, x, y, fill_color);
} else {
/* Проверяем расстояние до границ */
float dist1 = point_to_segment_distance((float)x, (float)y,
vertices[0][0], vertices[0][1],
vertices[1][0], vertices[1][1]);
float dist2 = point_to_segment_distance((float)x, (float)y,
vertices[1][0], vertices[1][1],
vertices[2][0], vertices[2][1]);
float dist3 = point_to_segment_distance((float)x, (float)y,
vertices[2][0], vertices[2][1],
vertices[0][0], vertices[0][1]);
float min_dist = fminf(dist1, fminf(dist2, dist3));
if (min_dist <= border_thickness) {
set_pixel(draw_info->data, draw_info->width, draw_info->height, x, y, border_color);
}
}
}
}
}
/* Рисование квадрата */
static void draw_square(struct window_draw_info* draw_info, float cx, float cy, float radius, float angle,
float border_thickness, uint32_t border_color, uint32_t fill_color)
{
/* Вычисляем координаты вершин квадрата */
/* Угол 0 означает, что одна вершина справа от центра */
float vertices[4][2];
for (int i = 0; i < 4; i++) {
float vertex_angle = angle + i * (M_PI / 2.0f);
vertices[i][0] = cx + radius * cosf(vertex_angle);
vertices[i][1] = cy - radius * sinf(vertex_angle); /* Инвертируем Y для экранных координат */
}
/* Находим ограничивающий прямоугольник */
float min_x = vertices[0][0], max_x = vertices[0][0];
float min_y = vertices[0][1], max_y = vertices[0][1];
for (int i = 1; i < 4; i++) {
min_x = fminf(min_x, vertices[i][0]);
max_x = fmaxf(max_x, vertices[i][0]);
min_y = fminf(min_y, vertices[i][1]);
max_y = fmaxf(max_y, vertices[i][1]);
}
min_x -= border_thickness;
max_x += border_thickness;
min_y -= border_thickness;
max_y += border_thickness;
int x_min = (int)fmaxf(0, min_x);
int x_max = (int)fminf(draw_info->width - 1, max_x);
int y_min = (int)fmaxf(0, min_y);
int y_max = (int)fminf(draw_info->height - 1, max_y);
/* Рисуем квадрат */
for (int y = y_min; y <= y_max; y++) {
for (int x = x_min; x <= x_max; x++) {
float px = (float)x;
float py = (float)y;
/* Проверяем, находится ли точка внутри квадрата */
/* Используем два треугольника */
int inside = point_in_triangle(px, py,
vertices[0][0], vertices[0][1],
vertices[1][0], vertices[1][1],
vertices[2][0], vertices[2][1]) ||
point_in_triangle(px, py,
vertices[0][0], vertices[0][1],
vertices[2][0], vertices[2][1],
vertices[3][0], vertices[3][1]);
if (inside) {
set_pixel(draw_info->data, draw_info->width, draw_info->height, x, y, fill_color);
} else {
/* Проверяем расстояние до границ */
float min_dist = INFINITY;
for (int i = 0; i < 4; i++) {
int next = (i + 1) % 4;
float dist = point_to_segment_distance(px, py,
vertices[i][0], vertices[i][1],
vertices[next][0], vertices[next][1]);
min_dist = fminf(min_dist, dist);
}
if (min_dist <= border_thickness) {
set_pixel(draw_info->data, draw_info->width, draw_info->height, x, y, border_color);
}
}
}
}
}
void figure_draw(struct window_draw_info* draw_info, float border_thickness, uint32_t border_color, uint32_t fill_color)
{
if (!draw_info || !draw_info->data)
return;
/* Координаты приходят в относительных единицах
* Y: [0..1] -> умножаем на высоту
* X: нормализован относительно высоты -> умножаем на высоту же
*/
float cx = draw_info->figure.position.x * draw_info->height;
float cy = draw_info->figure.position.y * draw_info->height;
float radius = draw_info->figure.radius;
float angle = draw_info->figure.angle;
enum figure_type type = draw_info->figure.type;
switch (type) {
case FIGURE_CIRCLE:
draw_circle(draw_info, cx, cy, radius, border_thickness, border_color, fill_color);
break;
case FIGURE_TRIANGLE:
draw_triangle(draw_info, cx, cy, radius, angle, border_thickness, border_color, fill_color);
break;
case FIGURE_SQUARE:
draw_square(draw_info, cx, cy, radius, angle, border_thickness, border_color, fill_color);
break;
}
}

View File

@@ -1,5 +1,6 @@
#include "input-handle.h" #include "input-handle.h"
#include "wayland-runtime.h" #include "wayland-runtime.h"
#include <math.h>
void keyboard_key_handle(xkb_keycode_t kc, xkb_keysym_t ks, enum keyboard_key_state state, struct wayland_window *window) void keyboard_key_handle(xkb_keycode_t kc, xkb_keysym_t ks, enum keyboard_key_state state, struct wayland_window *window)
{ {
@@ -8,12 +9,12 @@ void keyboard_key_handle(xkb_keycode_t kc, xkb_keysym_t ks, enum keyboard_key_st
char buf[64]; char buf[64];
int n = xkb_keysym_to_utf8(ks, buf, sizeof(buf)); int n = xkb_keysym_to_utf8(ks, buf, sizeof(buf));
if (n > 0) // if (n > 0)
printf("keyboard: symbol '%s' (keysym 0x%x) on surface:%p\n", buf, ks, window); // printf("keyboard: symbol '%s' (keysym 0x%x) on surface:%p\n", buf, ks, window);
else // else
printf("keyboard: keysym 0x%x (no UTF-8 representation)\n", ks); // printf("keyboard: keysym 0x%x (no UTF-8 representation)\n", ks);
if(state == KEYBOARD_KEY_STATE_PRESSED) if(state != KEYBOARD_KEY_STATE_RELEASED)
{ {
switch (ks) switch (ks)
{ {
@@ -30,6 +31,48 @@ void keyboard_key_handle(xkb_keycode_t kc, xkb_keysym_t ks, enum keyboard_key_st
case '3': case '3':
window->draw_info.figure.type = FIGURE_SQUARE; window->draw_info.figure.type = FIGURE_SQUARE;
break; break;
case '-':
/* decrease animation speed (multiplicative delta, clamped) */
pthread_mutex_lock(&window->draw_info.figure_mutex);
window->draw_info.figure.speed -= 0.5f;
if (window->draw_info.figure.speed < 1)
window->draw_info.figure.speed = 1;
printf("keyboard: speed decreased to %.2f\n", window->draw_info.figure.speed);
pthread_mutex_unlock(&window->draw_info.figure_mutex);
break;
case '+':
case '=': /* some layouts may emit '=' for unshifted, handle + via keysym */
/* increase animation speed (multiplicative delta, clamped) */
pthread_mutex_lock(&window->draw_info.figure_mutex);
window->draw_info.figure.speed += 0.5f;
if (window->draw_info.figure.speed > 30.0f)
window->draw_info.figure.speed = 30.0f;
printf("keyboard: speed increased to %.2f\n", window->draw_info.figure.speed);
pthread_mutex_unlock(&window->draw_info.figure_mutex);
break;
case XKB_KEY_Up:
/* increase figure radius */
pthread_mutex_lock(&window->draw_info.figure_mutex);
{
float maxr = fminf(window->draw_info.width, window->draw_info.height) / 2.0f - 1.0f;
window->draw_info.figure.radius += 2.0f;
if (window->draw_info.figure.radius > maxr)
window->draw_info.figure.radius = maxr;
}
printf("keyboard: radius increased to %.2f\n", window->draw_info.figure.radius);
pthread_mutex_unlock(&window->draw_info.figure_mutex);
break;
case XKB_KEY_Down:
/* decrease figure radius */
pthread_mutex_lock(&window->draw_info.figure_mutex);
{
window->draw_info.figure.radius -= 2.0f;
if (window->draw_info.figure.radius < 1.0f)
window->draw_info.figure.radius = 1.0f;
}
printf("keyboard: radius decreased to %.2f\n", window->draw_info.figure.radius);
pthread_mutex_unlock(&window->draw_info.figure_mutex);
break;
default: default:
break; break;
} }

View File

@@ -70,14 +70,12 @@ static void keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t f
static void keyboard_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) static void keyboard_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys)
{ {
printf("keyboard: enter serial=%u surface=%p\n", serial, surface);
/* Сохраняем поверхность, которая получила фокус клавиатуры */ /* Сохраняем поверхность, которая получила фокус клавиатуры */
focused_window = get_window_by_surface(surface); focused_window = get_window_by_surface(surface);
} }
static void keyboard_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) static void keyboard_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface)
{ {
printf("keyboard: leave serial=%u surface=%p\n", serial, surface);
/* Если уходим с фокусной поверхности — сбросить фокус */ /* Если уходим с фокусной поверхности — сбросить фокус */
if (focused_window && focused_window->wl_surface == surface) if (focused_window && focused_window->wl_surface == surface)
focused_window = NULL; focused_window = NULL;
@@ -100,7 +98,6 @@ static void keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t seri
static void keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) static void keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
{ {
printf("keyboard: modifiers serial=%u depressed=%u latched=%u locked=%u group=%u\n", serial, mods_depressed, mods_latched, mods_locked, group);
if (xkb_state) if (xkb_state)
{ {
xkb_state_update_mask(xkb_state, mods_depressed, mods_latched, mods_locked, group, 0, 0); xkb_state_update_mask(xkb_state, mods_depressed, mods_latched, mods_locked, group, 0, 0);
@@ -109,7 +106,6 @@ static void keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_
static void keyboard_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay) static void keyboard_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay)
{ {
printf("keyboard: repeat rate=%d delay=%d\n", rate, delay);
} }
static const struct wl_keyboard_listener keyboard_listener = { static const struct wl_keyboard_listener keyboard_listener = {

View File

@@ -41,6 +41,26 @@ static void signal_thread_exit(struct window_thread_slot *slot)
pthread_mutex_unlock(&g_thread_lock); pthread_mutex_unlock(&g_thread_lock);
} }
#include <stdio.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
// Прототип ASM-функции
void place_points_on_circle(
float pos_x,
float pos_y,
float offset_rad,
float radius,
float *points,
size_t count);
struct Point
{
float x;
float y;
};
static void *window_aux_loop(void *arg) static void *window_aux_loop(void *arg)
{ {
struct window_thread_slot *slot = arg; struct window_thread_slot *slot = arg;
@@ -50,9 +70,38 @@ static void *window_aux_loop(void *arg)
/* На время обновления позиции фигуры локаем мутекс */ /* На время обновления позиции фигуры локаем мутекс */
pthread_mutex_lock(&draw_info->figure_mutex); pthread_mutex_lock(&draw_info->figure_mutex);
figure_animation_step(draw_info); figure_animation_step(draw_info);
// const size_t n = 8;
// struct vec2 *pts = malloc(sizeof(struct vec2) * n);
// if (!pts)
// {
// printf("malloc failed\n");
// }
// float center_x = 0.0f;
// float center_y = 0.0f;
// float offset = 0.78f;
// float radius = 1.0f;
// // Вызов ASM-функции
// place_points_on_circle(
// center_x,
// center_y,
// offset,
// radius,
// (float *)pts, // адрес выходного массива
// n);
// // Вывод для проверки (и удобной точки останова)
// for (size_t i = 0; i < n; i++)
// {
// printf("%zu: x = %f, y = %f\n", i, pts[i].x, pts[i].y);
// }
// free(pts);
pthread_mutex_unlock(&draw_info->figure_mutex); pthread_mutex_unlock(&draw_info->figure_mutex);
usleep(30 * 1000); usleep(33 * 1000);
} }
return NULL; return NULL;
} }
@@ -129,6 +178,20 @@ int32_t init_wayland(void)
atomic_store(&g_shutdown, 0); atomic_store(&g_shutdown, 0);
atomic_store(&g_active_threads, 0); atomic_store(&g_active_threads, 0);
g_initialized = 1; g_initialized = 1;
/* Print keyboard help to the console so users know available shortcuts and
* behaviors. This mirrors the handling implemented in
* `input-handle.c` and acts as a quick usage hint. */
printf("\nKeyboard shortcuts and behavior:\n");
printf(" - Enter: open a new window\n");
printf(" - 1: switch to circle figure\n");
printf(" - 2: switch to triangle figure\n");
printf(" - 3: switch to square figure\n");
printf(" - - : decrease animation speed (clamped, multiplicative)\n");
printf(" - + or = : increase animation speed (clamped, multiplicative)\n");
printf(" - Up arrow: increase figure radius (clamped to window bounds)\n");
printf(" - Down arrow: decrease figure radius (minimum 1.0)\n");
printf(" Note: actions are triggered on key press (not on release).\n\n");
return 0; return 0;
} }

View File

@@ -105,20 +105,19 @@ static void draw(struct wayland_window *win)
// Залочиться, чтобы операции обновления позиции фигуры происходили атомарно // Залочиться, чтобы операции обновления позиции фигуры происходили атомарно
pthread_mutex_lock(&draw_info->figure_mutex); pthread_mutex_lock(&draw_info->figure_mutex);
struct figure_animation_info figure = draw_info->figure; struct figure_animation_info figure = draw_info->figure;
pthread_mutex_unlock(&draw_info->figure_mutex);
uint32_t color; uint32_t color;
switch (figure.type) switch (figure.type)
{ {
case FIGURE_CIRCLE: case FIGURE_CIRCLE:
color = 0xFFFFFFFF;
break;
case FIGURE_TRIANGLE:
color = 0xFFFF0000; color = 0xFFFF0000;
break; break;
case FIGURE_SQUARE: case FIGURE_TRIANGLE:
color = 0xFF00FF00; color = 0xFF00FF00;
break; break;
case FIGURE_SQUARE:
color = 0xFF0000FF;
break;
default: default:
break; break;
@@ -129,11 +128,13 @@ static void draw(struct wayland_window *win)
{ {
uint32_t *row = (uint32_t *)(bytes + y * stride); uint32_t *row = (uint32_t *)(bytes + y * stride);
for (int32_t x = 0; x < (int32_t)draw_info->width; ++x) for (int32_t x = 0; x < (int32_t)draw_info->width; ++x)
row[x] = 0xFF000000; /* background black */ row[x] = 0xAA5F5F5F; /* background black */
} }
/* Draw figure into buffer. border thickness in pixels = 3.0f */ /* Draw figure into buffer. border thickness in pixels = 3.0f */
figure_draw(&win->draw_info, 3.0f, 0xFFFFFFFF, color); figure_draw(&win->draw_info, 3.0f, 0xFF000000, color);
pthread_mutex_unlock(&draw_info->figure_mutex);
wl_surface_attach(win->wl_surface, win->buffer, 0, 0); wl_surface_attach(win->wl_surface, win->buffer, 0, 0);
wl_surface_damage_buffer(win->wl_surface, 0, 0, draw_info->width, draw_info->height); wl_surface_damage_buffer(win->wl_surface, 0, 0, draw_info->width, draw_info->height);
@@ -251,12 +252,12 @@ int window_init(struct wl_display *display, struct wl_event_queue *queue, struct
draw_info->figure.type = FIGURE_CIRCLE; draw_info->figure.type = FIGURE_CIRCLE;
draw_info->figure.position.x = 0.5f; draw_info->figure.position.x = 0.5f;
draw_info->figure.position.y = 0.5f; draw_info->figure.position.y = 0.5f;
draw_info->figure.velocity.x = 0.6f; draw_info->figure.velocity.x = 0.5f;
draw_info->figure.velocity.y = 0.3f; draw_info->figure.velocity.y = 0.5f;
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 = 0.01; /* radians per frame */
draw_info->figure.speed = 100.0f; /* pixels per second */ draw_info->figure.speed = 10; /* speed multiplier */
draw_info->figure.radius = 20.0f; /* radius in pixels */ draw_info->figure.radius = 25.0f; /* radius in pixels */
win->buffer = NULL; win->buffer = NULL;
win->frame_callback = NULL; win->frame_callback = NULL;