From 83a6640b2ece533219dfa6e9f85500858a6e62ad Mon Sep 17 00:00:00 2001 From: Roman Pytkov Date: Mon, 17 Nov 2025 23:51:31 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D0=B0=D0=BB=D0=B4=D0=B5=D0=BD?= =?UTF-8?q?=D0=BD=D0=BE=D0=B5=20=D0=B2=D1=80=D0=B0=D1=89=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wayland/src/figure-animate.asm | 238 +++++++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) diff --git a/wayland/src/figure-animate.asm b/wayland/src/figure-animate.asm index 89fc069..ba2d92a 100644 --- a/wayland/src/figure-animate.asm +++ b/wayland/src/figure-animate.asm @@ -13,6 +13,13 @@ 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 @@ -55,6 +62,11 @@ figure_animation_step: addss xmm0, [rdi + WDI_FIGURE + FIG_ANGLE] movss [rdi + WDI_FIGURE + FIG_ANGLE], xmm0 + ; Apply angular friction to slow down rotation over time + movss xmm0, [rdi + WDI_FIGURE + FIG_ANG_VEL] + mulss xmm0, [rel ANG_FRICTION] + movss [rdi + WDI_FIGURE + FIG_ANG_VEL], xmm0 + leave ret @@ -139,6 +151,232 @@ figure_handle_collision: 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 +.cap_delta_same_pos: + movss xmm7, xmm1 +.after_cap_same: + addss xmm6, xmm7 + jmp .finish_dir_logic + +; Switch sign -> compute new magnitude using old magnitude and delta +.switch_dir: + ; xmm6 = old, xmm7 = delta + ; abs_old = abs(xmm6) + movss xmm0, xmm6 + movss xmm1, xmm0 + mov eax, dword [rel ABS_MASK] + movd xmm2, eax + pshufd xmm2, xmm2, 0x0 + andps xmm1, xmm2 ; xmm1 = abs_old + + ; 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: + + ; abs_old *= ANG_SWITCH_FACTOR + movss xmm5, [rel ANG_SWITCH_FACTOR] + mulss xmm1, xmm5 + + ; new_mag = abs_old + abs_delta + addss xmm1, xmm4 + + ; 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