Расстановка точек на окружности
This commit is contained in:
@@ -13,24 +13,13 @@ enum figure_type
|
||||
struct figure_animation_info {
|
||||
enum figure_type type;
|
||||
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;
|
||||
|
||||
float angle;
|
||||
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;
|
||||
/* 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;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,203 +1,191 @@
|
||||
; Макрос для локальных переменных
|
||||
%macro local 2
|
||||
%assign __local_offset __local_offset - %2
|
||||
%define %1 (__local_offset)
|
||||
%endmacro
|
||||
|
||||
; Подключаем автоматически сгенерированные offsets из C структур
|
||||
%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
|
||||
|
||||
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
|
||||
%assign __local_offset 0
|
||||
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
|
||||
|
||||
; --- compute movement increments so that `speed` means pixels/second
|
||||
; Convert velocity to pixel-space (vx = vel.x * width, vy = vel.y * height),
|
||||
; normalize that vector and apply `speed*dt` so movement in pixel units equals speed.
|
||||
; using SSE for float math
|
||||
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
|
||||
mov ebx, dword [rdi + WDI_WIDTH]
|
||||
cvtsi2ss xmm10, ebx ; xmm10 = width
|
||||
mov ebx, dword [rdi + WDI_HEIGHT]
|
||||
cvtsi2ss xmm11, ebx ; xmm11 = height
|
||||
|
||||
; vx_pixels = vel.x * width
|
||||
movss xmm1, dword [rax + FIG_VELOCITY] ; vel.x
|
||||
mulss xmm1, xmm10 ; xmm1 = vx_pixels
|
||||
|
||||
; vy_pixels = vel.y * height
|
||||
movss xmm2, dword [rax + FIG_VELOCITY + 4]
|
||||
mulss xmm2, xmm11 ; xmm2 = vy_pixels
|
||||
|
||||
; length = sqrt(vx^2 + vy^2)
|
||||
movss xmm3, xmm1
|
||||
mulss xmm3, xmm1 ; xmm3 = vx^2
|
||||
movss xmm4, xmm2
|
||||
mulss xmm4, xmm4 ; xmm4 = vy^2
|
||||
addss xmm3, xmm4 ; xmm3 = vx^2 + vy^2
|
||||
sqrtss xmm3, xmm3 ; xmm3 = length (pixels)
|
||||
|
||||
; if length == 0 -> skip movement
|
||||
ucomiss xmm3, [rel ZERO_CONST]
|
||||
je .skip_move
|
||||
|
||||
; scalar = (speed * dt) / length
|
||||
movss xmm4, xmm0 ; xmm4 = speed*dt
|
||||
divss xmm4, xmm3 ; xmm4 = scalar
|
||||
|
||||
; dx = vel.x * scalar
|
||||
movss xmm1, dword [rax + FIG_VELOCITY]
|
||||
mulss xmm1, xmm4
|
||||
movss xmm2, dword [rax + FIG_POSITION] ; position.x
|
||||
addss xmm2, xmm1
|
||||
movss dword [rax + FIG_POSITION], xmm2
|
||||
|
||||
; dy = vel.y * scalar
|
||||
movss xmm1, dword [rax + FIG_VELOCITY + 4]
|
||||
mulss xmm1, xmm4
|
||||
movss xmm2, dword [rax + FIG_POSITION + 4]
|
||||
addss xmm2, xmm1
|
||||
movss dword [rax + FIG_POSITION + 4], xmm2
|
||||
|
||||
.skip_move:
|
||||
|
||||
; 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:
|
||||
enter 48, 0
|
||||
|
||||
; Отработка коллизий
|
||||
call figure_handle_collision;
|
||||
|
||||
; Сохранить регистры
|
||||
|
||||
; Сдвиги переменных
|
||||
; Аргументы
|
||||
local width, 4
|
||||
local height, 4
|
||||
local fig_type, 4
|
||||
local pos_x, 4
|
||||
local pos_y, 4
|
||||
local vel_x, 4
|
||||
local vel_y, 4
|
||||
local angle, 4
|
||||
local angular_vel, 4
|
||||
local speed, 4
|
||||
local radius, 4
|
||||
|
||||
; Чтение аргументов
|
||||
mov eax, dword [rdi + WDI_WIDTH]
|
||||
mov [rbp - width], eax
|
||||
|
||||
mov eax, dword [rdi + WDI_HEIGHT]
|
||||
mov [rbp - height], eax
|
||||
|
||||
mov eax, dword [rdi + WDI_FIGURE + FIG_TYPE]
|
||||
mov [rbp - fig_type], eax
|
||||
|
||||
mov eax, dword [rdi + WDI_FIGURE + FIG_POSITION]
|
||||
mov [rbp - pos_x], eax
|
||||
|
||||
mov eax, dword [rdi + WDI_FIGURE + FIG_POSITION + 4]
|
||||
mov [rbp - pos_x], eax
|
||||
|
||||
mov eax, dword [rdi + WDI_FIGURE + FIG_VELOCITY]
|
||||
mov [rbp - vel_x], eax
|
||||
|
||||
mov eax, dword [rdi + WDI_FIGURE + FIG_VELOCITY + 4]
|
||||
mov [rbp - vel_y], eax
|
||||
|
||||
mov eax, dword [rdi + WDI_FIGURE + FIG_ANGLE]
|
||||
mov [rbp - angle], eax
|
||||
|
||||
mov eax, dword [rdi + WDI_FIGURE + FIG_ANG_VEL]
|
||||
mov [rbp - angular_vel], eax
|
||||
|
||||
mov eax, dword [rdi + WDI_FIGURE + FIG_SPEED]
|
||||
mov [rbp - speed], eax
|
||||
|
||||
mov eax, dword [rdi + WDI_FIGURE + FIG_RADIUS]
|
||||
mov [rbp - radius], eax
|
||||
|
||||
|
||||
|
||||
|
||||
; Восстановить регистры
|
||||
|
||||
leave
|
||||
ret
|
||||
|
||||
; Функция для обработки коллизии, изменяет velocity при обнаружении коллизии с границами
|
||||
; Параметры:
|
||||
; rdi - указатель на struct window_draw_info
|
||||
%assign __local_offset 0
|
||||
figure_handle_collision:
|
||||
enter 128,0
|
||||
|
||||
local point_buffer, 128
|
||||
|
||||
|
||||
; Вызов place_points_on_circle
|
||||
movss xmm0, [rdi + WDI_FIGURE + FIG_POSITION]
|
||||
movss xmm1, [rdi + WDI_FIGURE + FIG_POSITION + 4]
|
||||
mov rsi, 4
|
||||
mov rdx, 0
|
||||
push rdi
|
||||
mov rdi, rbp
|
||||
add rdi, point_buffer
|
||||
call place_points_on_circle
|
||||
pop rdi
|
||||
|
||||
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
|
||||
; Функция для расположения точек на окружности
|
||||
; Вход:
|
||||
; xmm0 - pos_x
|
||||
; xmm1 - pos_y
|
||||
; xmm2 - смещение точек на окружности в радианах
|
||||
; xmm3 - радиус
|
||||
; rdi - адрес буфера для точек
|
||||
; rsi - количество точек
|
||||
; Уничтожает: 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
|
||||
movss xmm3, dword [rax + FIG_VELOCITY + 4] ; vel.y
|
||||
; Рассчитать TWO_PI / rsi и сохранить в xmm4
|
||||
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
|
||||
.cycle:
|
||||
movss xmm0, xmm5
|
||||
|
||||
; radius is stored in figure as pixel count (float)
|
||||
; we keep positions normalized (0..1) so convert radius to normalized
|
||||
; coordinates for x and y: r_x = radius / width, r_y = radius / height
|
||||
movss xmm5, dword [rax + FIG_RADIUS] ; xmm5 = radius_pixels
|
||||
mulss xmm0, xmm4 ; Счётчик*шаг
|
||||
addss xmm0, xmm2 ; Прибавить смещение
|
||||
call sincos_f32_rbp ; Посчитать sincos
|
||||
mulss xmm0, xmm3 ; sin *= radius
|
||||
mulss xmm1, xmm3 ; cos *= radius
|
||||
|
||||
; load width/height from window_draw_info
|
||||
mov ebx, dword [rdi + WDI_WIDTH]
|
||||
cvtsi2ss xmm10, ebx ; xmm10 = width
|
||||
mov ebx, dword [rdi + WDI_HEIGHT]
|
||||
cvtsi2ss xmm11, ebx ; xmm11 = height
|
||||
addss xmm1, xmm6 ; x = center_x + cos*radius
|
||||
addss xmm0, xmm7 ; y = center_y + sin*radius
|
||||
|
||||
; compute r_x = radius / width
|
||||
movss xmm12, xmm5
|
||||
divss xmm12, xmm10 ; xmm12 = r_x
|
||||
movss [rdi], xmm1
|
||||
movss [rdi + 4], xmm0
|
||||
add rdi, 8
|
||||
|
||||
; compute r_y = radius / height
|
||||
movss xmm13, xmm5
|
||||
divss xmm13, xmm11 ; xmm13 = r_y
|
||||
|
||||
; left edge: pos.x < r_x ?
|
||||
ucomiss xmm0, xmm12
|
||||
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
|
||||
addss xmm5, [rel ONE_CONST]
|
||||
loop .cycle
|
||||
|
||||
.check_right:
|
||||
; 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
|
||||
leave
|
||||
ret
|
||||
|
||||
section .rodata
|
||||
DT: dd 0.1
|
||||
NEG_ONE: dd -1.0
|
||||
ONE_CONST: dd 1.0
|
||||
ZERO_CONST: dd 0.0
|
||||
|
||||
; Функция для рассчёта sin и cos
|
||||
; Вход:
|
||||
; xmm0 - угол в радианах (float)
|
||||
; Выход:
|
||||
; 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
|
||||
@@ -41,6 +41,26 @@ static void signal_thread_exit(struct window_thread_slot *slot)
|
||||
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)
|
||||
{
|
||||
struct window_thread_slot *slot = arg;
|
||||
@@ -49,7 +69,36 @@ static void *window_aux_loop(void *arg)
|
||||
{
|
||||
/* На время обновления позиции фигуры локаем мутекс */
|
||||
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);
|
||||
|
||||
usleep(30 * 1000);
|
||||
|
||||
Reference in New Issue
Block a user