From f48bc757ea9032b1f2cc855ab95a61ee2b37b506 Mon Sep 17 00:00:00 2001 From: Roman Pytkov Date: Mon, 17 Nov 2025 22:46:36 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B0=D0=B1=D0=BE=D1=87=D0=B8=D0=B9=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D1=82=D0=BE=D1=82=D0=B8=D0=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wayland/src/figure-animate.asm | 323 ++++++++++++++++++++++++++------- wayland/src/figure-draw.c | 12 +- wayland/src/wayland-runtime.c | 50 ++--- wayland/src/window.c | 23 +-- 4 files changed, 299 insertions(+), 109 deletions(-) diff --git a/wayland/src/figure-animate.asm b/wayland/src/figure-animate.asm index 08b766c..89fc069 100644 --- a/wayland/src/figure-animate.asm +++ b/wayland/src/figure-animate.asm @@ -22,66 +22,38 @@ section .text %assign __local_offset 0 global figure_animation_step figure_animation_step: - ; Создаём локальную область на стеке и будем туда копировать поля структуры - enter 48, 0 + enter 0, 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 - ; Сдвиги переменных - ; Аргументы - 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 + ; Обновить позицию: position += (velocity * speed) / height_pixels + ; pos_x += (vel_x * speed) / height + movss xmm0, [rdi + WDI_FIGURE + FIG_VELOCITY] + mulss xmm0, [rdi + WDI_FIGURE + FIG_SPEED] + mulss xmm0, xmm5 ; нормализовать скорость + addss xmm0, [rdi + WDI_FIGURE + FIG_POSITION] + movss [rdi + WDI_FIGURE + FIG_POSITION], xmm0 - mov eax, dword [rdi + WDI_HEIGHT] - mov [rbp - height], eax + ; pos_y += (vel_y * speed) / height + 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] - 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 - - - - - ; Восстановить регистры + ; Обновить угол: angle += angular_velocity * speed + movss xmm0, [rdi + WDI_FIGURE + FIG_ANG_VEL] + mulss xmm0, [rdi + WDI_FIGURE + FIG_SPEED] + addss xmm0, [rdi + WDI_FIGURE + FIG_ANGLE] + movss [rdi + WDI_FIGURE + FIG_ANGLE], xmm0 leave ret @@ -95,17 +67,177 @@ figure_handle_collision: 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 - movss xmm0, [rdi + WDI_FIGURE + FIG_POSITION] - movss xmm1, [rdi + WDI_FIGURE + FIG_POSITION + 4] + movss xmm0, [r12 + WDI_FIGURE + FIG_POSITION] + 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 rdx, 0 - push rdi - mov rdi, rbp - add rdi, point_buffer +.figure_points_done: + + lea rdi, [rbp + point_buffer] 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 ret @@ -113,12 +245,12 @@ figure_handle_collision: ; Функция для расположения точек на окружности ; Вход: -; xmm0 - pos_x -; xmm1 - pos_y -; xmm2 - смещение точек на окружности в радианах -; xmm3 - радиус -; rdi - адрес буфера для точек -; rsi - количество точек +; 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: @@ -135,7 +267,7 @@ place_points_on_circle: movss xmm5, [rel ZERO_CONST] ; счётчик mov rcx, rsi -.cycle: +.loop: movss xmm0, xmm5 mulss xmm0, xmm4 ; Счётчик*шаг @@ -153,7 +285,7 @@ place_points_on_circle: addss xmm5, [rel ONE_CONST] - loop .cycle + loop .loop leave ret @@ -188,4 +320,55 @@ sincos_f32_rbp: movss xmm1, [rbp-24] ; xmm1 = cos leave ; эквивалент: mov rsp, rbp / pop rbp - ret \ No newline at end of file + 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 diff --git a/wayland/src/figure-draw.c b/wayland/src/figure-draw.c index fd8ba5d..3b50cad 100644 --- a/wayland/src/figure-draw.c +++ b/wayland/src/figure-draw.c @@ -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; - /* center in pixels */ - float cx = fig.position.x * (float)w; - float cy = fig.position.y * (float)h; + /* Calculate aspect ratio: width is proportional, height is always 1.0 */ + float aspect_ratio = (float)w / (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. */ float r = fig.radius; float r2 = r * r; diff --git a/wayland/src/wayland-runtime.c b/wayland/src/wayland-runtime.c index b3365f6..5d6b91a 100644 --- a/wayland/src/wayland-runtime.c +++ b/wayland/src/wayland-runtime.c @@ -69,36 +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"); - } + // 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; + // 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); + // // Вызов 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); - } + // // Вывод для проверки (и удобной точки останова) + // for (size_t i = 0; i < n; i++) + // { + // 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); usleep(30 * 1000); diff --git a/wayland/src/window.c b/wayland/src/window.c index 1e4594f..67d2c5c 100644 --- a/wayland/src/window.c +++ b/wayland/src/window.c @@ -105,20 +105,19 @@ static void draw(struct wayland_window *win) // Залочиться, чтобы операции обновления позиции фигуры происходили атомарно pthread_mutex_lock(&draw_info->figure_mutex); struct figure_animation_info figure = draw_info->figure; - pthread_mutex_unlock(&draw_info->figure_mutex); uint32_t color; switch (figure.type) { case FIGURE_CIRCLE: - color = 0xFFFFFFFF; - break; - case FIGURE_TRIANGLE: color = 0xFFFF0000; break; - case FIGURE_SQUARE: + case FIGURE_TRIANGLE: color = 0xFF00FF00; break; + case FIGURE_SQUARE: + color = 0xFF0000FF; + break; default: break; @@ -129,11 +128,13 @@ static void draw(struct wayland_window *win) { uint32_t *row = (uint32_t *)(bytes + y * stride); 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 */ 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_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.position.x = 0.5f; draw_info->figure.position.y = 0.5f; - draw_info->figure.velocity.x = 0.6f; - draw_info->figure.velocity.y = 0.3f; + draw_info->figure.velocity.x = 0.5f; + draw_info->figure.velocity.y = 0.5f; draw_info->figure.angle = 0.0f; - draw_info->figure.angular_velocity = 1.0f; /* radians per second */ - draw_info->figure.speed = 100.0f; /* pixels per second */ - draw_info->figure.radius = 20.0f; /* radius in pixels */ + draw_info->figure.angular_velocity = 1; /* radians per frame */ + draw_info->figure.speed = 20; /* speed multiplier */ + draw_info->figure.radius = 25.0f; /* radius in pixels */ win->buffer = NULL; win->frame_callback = NULL;