Рабочий прототип

This commit is contained in:
2025-11-17 22:46:36 +03:00
parent 494686a203
commit f48bc757ea
4 changed files with 299 additions and 109 deletions

View File

@@ -22,66 +22,38 @@ section .text
%assign __local_offset 0 %assign __local_offset 0
global figure_animation_step global figure_animation_step
figure_animation_step: figure_animation_step:
; Создаём локальную область на стеке и будем туда копировать поля структуры enter 0, 0
enter 48, 0
; Отработка коллизий ; Отработка коллизий
call figure_handle_collision; push rdi
call figure_handle_collision
pop rdi
; Сохранить регистры ; Вычислить нормализующий коэффициент: 1.0 / height_pixels
cvtsi2ss xmm4, dword [rdi + WDI_HEIGHT]
movss xmm5, [rel ONE_CONST]
divss xmm5, xmm4 ; xmm5 = 1.0 / height
; Сдвиги переменных ; Обновить позицию: position += (velocity * speed) / height_pixels
; Аргументы ; pos_x += (vel_x * speed) / height
local width, 4 movss xmm0, [rdi + WDI_FIGURE + FIG_VELOCITY]
local height, 4 mulss xmm0, [rdi + WDI_FIGURE + FIG_SPEED]
local fig_type, 4 mulss xmm0, xmm5 ; нормализовать скорость
local pos_x, 4 addss xmm0, [rdi + WDI_FIGURE + FIG_POSITION]
local pos_y, 4 movss [rdi + WDI_FIGURE + FIG_POSITION], xmm0
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] ; pos_y += (vel_y * speed) / height
mov [rbp - height], eax movss xmm0, [rdi + WDI_FIGURE + FIG_VELOCITY + 4]
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
mov eax, dword [rdi + WDI_FIGURE + FIG_TYPE] ; Обновить угол: angle += angular_velocity * speed
mov [rbp - fig_type], eax movss xmm0, [rdi + WDI_FIGURE + FIG_ANG_VEL]
mulss xmm0, [rdi + WDI_FIGURE + FIG_SPEED]
mov eax, dword [rdi + WDI_FIGURE + FIG_POSITION] addss xmm0, [rdi + WDI_FIGURE + FIG_ANGLE]
mov [rbp - pos_x], eax movss [rdi + WDI_FIGURE + FIG_ANGLE], xmm0
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 leave
ret ret
@@ -95,17 +67,177 @@ figure_handle_collision:
local point_buffer, 128 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 ; Вызов place_points_on_circle
movss xmm0, [rdi + WDI_FIGURE + FIG_POSITION] movss xmm0, [r12 + WDI_FIGURE + FIG_POSITION]
movss xmm1, [rdi + WDI_FIGURE + FIG_POSITION + 4] movss xmm1, [r12 + WDI_FIGURE + FIG_POSITION + 4]
movss xmm2, [rel ZERO_CONST] ; смещение угла = 0
; Установка правильного количества точек
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 mov rsi, 4
mov rdx, 0 .figure_points_done:
push rdi
mov rdi, rbp lea rdi, [rbp + point_buffer]
add rdi, point_buffer
call place_points_on_circle call place_points_on_circle
pop rdi
; Вычислить 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
; Обработка коллизий: инвертировать 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
@@ -113,12 +245,12 @@ figure_handle_collision:
; Функция для расположения точек на окружности ; Функция для расположения точек на окружности
; Вход: ; Вход:
; xmm0 - pos_x ; xmm0 - pos_x
; xmm1 - pos_y ; xmm1 - pos_y
; xmm2 - смещение точек на окружности в радианах ; xmm2 - смещение точек на окружности в радианах
; xmm3 - радиус ; xmm3 - радиус
; rdi - адрес буфера для точек ; rdi - адрес буфера для точек
; rsi - количество точек ; rsi - количество точек
; Уничтожает: rax, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 ; Уничтожает: rax, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7
global place_points_on_circle global place_points_on_circle
place_points_on_circle: place_points_on_circle:
@@ -135,7 +267,7 @@ place_points_on_circle:
movss xmm5, [rel ZERO_CONST] ; счётчик movss xmm5, [rel ZERO_CONST] ; счётчик
mov rcx, rsi mov rcx, rsi
.cycle: .loop:
movss xmm0, xmm5 movss xmm0, xmm5
mulss xmm0, xmm4 ; Счётчик*шаг mulss xmm0, xmm4 ; Счётчик*шаг
@@ -153,7 +285,7 @@ place_points_on_circle:
addss xmm5, [rel ONE_CONST] addss xmm5, [rel ONE_CONST]
loop .cycle loop .loop
leave leave
ret ret
@@ -188,4 +320,55 @@ sincos_f32_rbp:
movss xmm1, [rbp-24] ; xmm1 = cos movss xmm1, [rbp-24] ; xmm1 = cos
leave ; эквивалент: mov rsp, rbp / pop rbp leave ; эквивалент: mov rsp, rbp / pop rbp
ret 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

@@ -16,9 +16,15 @@ void figure_draw(struct window_draw_info* draw_info, float border_thickness, uin
struct figure_animation_info fig = draw_info->figure; struct figure_animation_info fig = draw_info->figure;
/* center in pixels */ /* Calculate aspect ratio: width is proportional, height is always 1.0 */
float cx = fig.position.x * (float)w; float aspect_ratio = (float)w / (float)h;
float cy = fig.position.y * (float)h;
/* center in pixels:
* x coordinates are in range [0, aspect_ratio]
* y coordinates are in range [0, 1.0]
*/
float cx = fig.position.x * (float)h; /* scale x by height to maintain aspect */
float cy = fig.position.y * (float)h; /* scale y by height */
/* `fig.radius` is in pixels now; use it directly. */ /* `fig.radius` is in pixels now; use it directly. */
float r = fig.radius; float r = fig.radius;
float r2 = r * r; float r2 = r * r;

View File

@@ -69,36 +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; // const size_t n = 8;
struct vec2 *pts = malloc(sizeof(struct vec2) * n); // struct vec2 *pts = malloc(sizeof(struct vec2) * n);
if (!pts) // if (!pts)
{ // {
printf("malloc failed\n"); // printf("malloc failed\n");
} // }
float center_x = 0.0f; // float center_x = 0.0f;
float center_y = 0.0f; // float center_y = 0.0f;
float offset = 0.78f; // float offset = 0.78f;
float radius = 1.0f; // float radius = 1.0f;
// Вызов ASM-функции // // Вызов ASM-функции
place_points_on_circle( // place_points_on_circle(
center_x, // center_x,
center_y, // center_y,
offset, // offset,
radius, // radius,
(float *)pts, // адрес выходного массива // (float *)pts, // адрес выходного массива
n); // n);
// Вывод для проверки (и удобной точки останова) // // Вывод для проверки (и удобной точки останова)
for (size_t i = 0; i < n; i++) // for (size_t i = 0; i < n; i++)
{ // {
printf("%zu: x = %f, y = %f\n", i, pts[i].x, pts[i].y); // printf("%zu: x = %f, y = %f\n", i, pts[i].x, pts[i].y);
} // }
free(pts); // free(pts);
pthread_mutex_unlock(&draw_info->figure_mutex); pthread_mutex_unlock(&draw_info->figure_mutex);
usleep(30 * 1000); usleep(30 * 1000);

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, 0xFFFFFFFF, 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 = 1; /* radians per frame */
draw_info->figure.speed = 100.0f; /* pixels per second */ draw_info->figure.speed = 20; /* 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;