Обалденное вращение

This commit is contained in:
2025-11-17 23:51:31 +03:00
parent 7de923d0b6
commit 83a6640b2e

View File

@@ -13,6 +13,13 @@ TWO_PI: dd 6.2831852
NEG_ONE_CONST: dd -1.0 NEG_ONE_CONST: dd -1.0
ONE_CONST: dd 1.0 ONE_CONST: dd 1.0
ZERO_CONST: dd 0.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
@@ -55,6 +62,11 @@ figure_animation_step:
addss xmm0, [rdi + WDI_FIGURE + FIG_ANGLE] addss xmm0, [rdi + WDI_FIGURE + FIG_ANGLE]
movss [rdi + WDI_FIGURE + FIG_ANGLE], xmm0 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 leave
ret ret
@@ -139,6 +151,232 @@ figure_handle_collision:
test r14, r14 test r14, r14
jz .no_collision 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 только если движемся к границе ; Обработка коллизий: инвертировать velocity только если движемся к границе
; Проверка left (bit 0): инвертировать velocity.x только если vel.x < 0 ; Проверка left (bit 0): инвертировать velocity.x только если vel.x < 0