Расстановка точек на окружности
This commit is contained in:
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,203 +1,191 @@
|
|||||||
|
; Макрос для локальных переменных
|
||||||
|
%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
|
||||||
|
|
||||||
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 48, 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:
|
|
||||||
|
|
||||||
|
; Отработка коллизий
|
||||||
|
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
|
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
|
||||||
|
.cycle:
|
||||||
|
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 .cycle
|
||||||
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
|
||||||
@@ -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;
|
||||||
@@ -49,7 +69,36 @@ 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(30 * 1000);
|
||||||
|
|||||||
Reference in New Issue
Block a user