Compare commits
10 Commits
58eb3695f1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 92c69f3e57 | |||
| 62be1dc854 | |||
| d21460b8e4 | |||
| 51a0a6a2eb | |||
| d04c04f028 | |||
| 33285bbf1c | |||
| 83a6640b2e | |||
| 7de923d0b6 | |||
| f48bc757ea | |||
| 494686a203 |
BIN
wayland/docs/uml/diagram-activity-animation.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
51
wayland/docs/uml/diagram-activity-animation.puml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
@startuml
|
||||||
|
title Цикл анимации фигуры (aux_thread)
|
||||||
|
|
||||||
|
start
|
||||||
|
|
||||||
|
:aux_thread запущен;
|
||||||
|
|
||||||
|
while (окно не закрыто?) is (да)
|
||||||
|
|
||||||
|
:Залочить figure_mutex;
|
||||||
|
|
||||||
|
:figure_animation_step(draw_info);
|
||||||
|
|
||||||
|
partition "figure_animation_step (ASM)" {
|
||||||
|
:Обработка коллизий;
|
||||||
|
note right
|
||||||
|
figure_handle_collision():
|
||||||
|
- Расчёт точек фигуры на окружности
|
||||||
|
- Проверка выхода за границы
|
||||||
|
- Инверсия velocity при коллизии
|
||||||
|
- Обновление angular_velocity
|
||||||
|
end note
|
||||||
|
|
||||||
|
:Обновить позицию;
|
||||||
|
note right
|
||||||
|
position += (velocity * speed) / height
|
||||||
|
end note
|
||||||
|
|
||||||
|
:Обновить угол поворота;
|
||||||
|
note right
|
||||||
|
angle += angular_velocity * speed
|
||||||
|
end note
|
||||||
|
|
||||||
|
:Применить трение к вращению;
|
||||||
|
note right
|
||||||
|
angular_velocity *= 0.95
|
||||||
|
end note
|
||||||
|
}
|
||||||
|
|
||||||
|
:Разлочить figure_mutex;
|
||||||
|
|
||||||
|
:usleep(33 ms);
|
||||||
|
note right: ~30 FPS обновление физики
|
||||||
|
|
||||||
|
endwhile (нет)
|
||||||
|
|
||||||
|
:Завершение потока;
|
||||||
|
|
||||||
|
stop
|
||||||
|
|
||||||
|
@enduml
|
||||||
BIN
wayland/docs/uml/diagram-activity-render.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
76
wayland/docs/uml/diagram-activity-render.puml
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
@startuml
|
||||||
|
title Цикл отрисовки окна (window_thread)
|
||||||
|
|
||||||
|
start
|
||||||
|
|
||||||
|
:window_thread запущен;
|
||||||
|
|
||||||
|
:Создать event queue;
|
||||||
|
:window_init();
|
||||||
|
:Запустить aux_thread для анимации;
|
||||||
|
|
||||||
|
while (окно не закрыто?) is (да)
|
||||||
|
|
||||||
|
:wl_display_dispatch_queue();
|
||||||
|
note right: Ожидание событий Wayland
|
||||||
|
|
||||||
|
if (событие произошло?) then (да)
|
||||||
|
|
||||||
|
if (xdg_surface_configure?) then (да)
|
||||||
|
:xdg_surface_ack_configure();
|
||||||
|
if (буфер не создан?) then (да)
|
||||||
|
:resize_canvas();
|
||||||
|
endif
|
||||||
|
:draw();
|
||||||
|
endif
|
||||||
|
|
||||||
|
if (xdg_toplevel_configure?) then (да)
|
||||||
|
if (размер изменился?) then (да)
|
||||||
|
:resize_new(w, h);
|
||||||
|
note right
|
||||||
|
- Освободить старый буфер
|
||||||
|
- Создать новый буфер
|
||||||
|
- Обновить размеры draw_info
|
||||||
|
end note
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if (xdg_toplevel_close?) then (да)
|
||||||
|
:Установить need_close = 1;
|
||||||
|
endif
|
||||||
|
|
||||||
|
if (frame_callback?) then (да)
|
||||||
|
:Уничтожить старый callback;
|
||||||
|
:Создать новый callback;
|
||||||
|
|
||||||
|
partition "draw()" {
|
||||||
|
:Залочить figure_mutex;
|
||||||
|
|
||||||
|
:Очистить фон (черный);
|
||||||
|
|
||||||
|
:figure_draw();
|
||||||
|
note right
|
||||||
|
- Получить текущую фигуру
|
||||||
|
- Нарисовать границу и заливку
|
||||||
|
- Цвет зависит от типа фигуры
|
||||||
|
end note
|
||||||
|
|
||||||
|
:Разлочить figure_mutex;
|
||||||
|
|
||||||
|
:wl_surface_attach(buffer);
|
||||||
|
:wl_surface_damage_buffer();
|
||||||
|
:wl_surface_commit();
|
||||||
|
}
|
||||||
|
endif
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
endwhile (нет)
|
||||||
|
|
||||||
|
:window_destroy();
|
||||||
|
:Уничтожить event queue;
|
||||||
|
:signal_thread_exit();
|
||||||
|
|
||||||
|
stop
|
||||||
|
|
||||||
|
@enduml
|
||||||
BIN
wayland/docs/uml/diagram-class.png
Normal file
|
After Width: | Height: | Size: 82 KiB |
127
wayland/docs/uml/diagram-class.puml
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
@startuml
|
||||||
|
title Структура классов проекта Wayland
|
||||||
|
|
||||||
|
class wayland_runtime {
|
||||||
|
+ init_wayland() : int32_t
|
||||||
|
+ run_window() : int32_t
|
||||||
|
+ wait_for_windows() : void
|
||||||
|
+ destroy_wayland() : void
|
||||||
|
+ get_window_by_surface(surf) : wayland_window*
|
||||||
|
--
|
||||||
|
- g_display : wl_display*
|
||||||
|
- g_slots[MAX_WINDOW_THREADS] : window_thread_slot
|
||||||
|
- g_thread_lock : pthread_mutex_t
|
||||||
|
- g_active_threads : atomic_int
|
||||||
|
- g_shutdown : atomic_bool
|
||||||
|
}
|
||||||
|
|
||||||
|
class window_thread_slot {
|
||||||
|
+ thread : pthread_t
|
||||||
|
+ aux_thread : pthread_t
|
||||||
|
+ active : int
|
||||||
|
+ queue : wl_event_queue*
|
||||||
|
+ window : wayland_window
|
||||||
|
}
|
||||||
|
|
||||||
|
class wayland_window {
|
||||||
|
+ id : int
|
||||||
|
+ wl_surface : wl_surface*
|
||||||
|
+ xdg_surface : xdg_surface*
|
||||||
|
+ xdg_toplevel : xdg_toplevel*
|
||||||
|
+ buffer : wl_buffer*
|
||||||
|
+ frame_callback : wl_callback*
|
||||||
|
+ queue : wl_event_queue*
|
||||||
|
+ need_close : int
|
||||||
|
+ draw_info : window_draw_info
|
||||||
|
--
|
||||||
|
+ window_init(display, queue) : int
|
||||||
|
+ window_destroy() : void
|
||||||
|
+ window_should_close() : int
|
||||||
|
}
|
||||||
|
|
||||||
|
class window_draw_info {
|
||||||
|
+ width : uint32_t
|
||||||
|
+ height : uint32_t
|
||||||
|
+ data : void*
|
||||||
|
+ figure : figure_animation_info
|
||||||
|
+ figure_mutex : pthread_mutex_t
|
||||||
|
}
|
||||||
|
|
||||||
|
class figure_animation_info {
|
||||||
|
+ type : figure_type
|
||||||
|
+ position : vec2
|
||||||
|
+ velocity : vec2
|
||||||
|
+ angle : float
|
||||||
|
+ angular_velocity : float
|
||||||
|
+ speed : float
|
||||||
|
+ radius : float
|
||||||
|
}
|
||||||
|
|
||||||
|
enum figure_type {
|
||||||
|
FIGURE_CIRCLE = 0
|
||||||
|
FIGURE_TRIANGLE = 1
|
||||||
|
FIGURE_SQUARE = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
class registry {
|
||||||
|
+ registry_global_bind(display) : int
|
||||||
|
+ registry_global_unbind() : void
|
||||||
|
+ registry_get_compositor() : wl_compositor*
|
||||||
|
+ registry_get_shm() : wl_shm*
|
||||||
|
+ registry_get_xdg_wm_base() : xdg_wm_base*
|
||||||
|
--
|
||||||
|
- global_compositor : wl_compositor*
|
||||||
|
- global_shm : wl_shm*
|
||||||
|
- global_wm_base : xdg_wm_base*
|
||||||
|
- global_registry : wl_registry*
|
||||||
|
- global_thread : pthread_t
|
||||||
|
- global_thread_running : atomic_int
|
||||||
|
}
|
||||||
|
|
||||||
|
class input {
|
||||||
|
+ input_register_seat(seat) : void
|
||||||
|
+ input_cleanup() : void
|
||||||
|
--
|
||||||
|
- seat : wl_seat*
|
||||||
|
- keyboard : wl_keyboard*
|
||||||
|
- xkb_ctx : xkb_context*
|
||||||
|
- xkb_keymap : xkb_keymap*
|
||||||
|
- xkb_state : xkb_state*
|
||||||
|
- focused_window : wayland_window*
|
||||||
|
}
|
||||||
|
|
||||||
|
class input_handle {
|
||||||
|
+ keyboard_key_handle(kc, ks, state, window) : void
|
||||||
|
}
|
||||||
|
|
||||||
|
class figure_animate <<ASM>> {
|
||||||
|
+ figure_animation_step(draw_info) : void
|
||||||
|
+ place_points_on_circle(...) : void
|
||||||
|
--
|
||||||
|
- figure_handle_collision(draw_info) : void
|
||||||
|
- check_collision_mask(...) : uint64_t
|
||||||
|
- sincos_f32_rbp(angle) : (sin, cos)
|
||||||
|
}
|
||||||
|
|
||||||
|
class figure_draw {
|
||||||
|
+ figure_draw(draw_info, thickness, border_color, fill_color) : void
|
||||||
|
}
|
||||||
|
|
||||||
|
wayland_runtime "1" *-- "0..128" window_thread_slot
|
||||||
|
window_thread_slot "1" *-- "1" wayland_window
|
||||||
|
wayland_window "1" *-- "1" window_draw_info
|
||||||
|
window_draw_info "1" *-- "1" figure_animation_info
|
||||||
|
figure_animation_info --> figure_type
|
||||||
|
|
||||||
|
wayland_runtime ..> registry : uses
|
||||||
|
wayland_runtime ..> input : uses
|
||||||
|
wayland_window ..> registry : uses
|
||||||
|
wayland_window ..> figure_draw : uses
|
||||||
|
|
||||||
|
input ..> input_handle : uses
|
||||||
|
input --> wayland_window : focuses
|
||||||
|
|
||||||
|
window_thread_slot ..> figure_animate : uses (aux_thread)
|
||||||
|
figure_draw ..> figure_animate : uses
|
||||||
|
|
||||||
|
@enduml
|
||||||
BIN
wayland/docs/uml/diagram-component.png
Normal file
|
After Width: | Height: | Size: 70 KiB |
74
wayland/docs/uml/diagram-component.puml
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
@startuml
|
||||||
|
title Компоненты проекта Wayland
|
||||||
|
|
||||||
|
package "Wayland Application" {
|
||||||
|
|
||||||
|
[wayland-runtime] as Runtime
|
||||||
|
[registry] as Registry
|
||||||
|
[input] as Input
|
||||||
|
[input-handle] as InputHandle
|
||||||
|
[window] as Window
|
||||||
|
|
||||||
|
package "Rendering & Animation" {
|
||||||
|
[figure-draw] as FigureDraw
|
||||||
|
[figure-animate (ASM)] as FigureAnimate
|
||||||
|
}
|
||||||
|
|
||||||
|
Runtime --> Registry : использует глобальные объекты
|
||||||
|
Runtime --> Input : инициализирует
|
||||||
|
Runtime --> Window : создаёт и управляет
|
||||||
|
|
||||||
|
Input --> InputHandle : делегирует обработку
|
||||||
|
InputHandle --> Runtime : вызывает run_window()
|
||||||
|
InputHandle --> Window : изменяет параметры фигуры
|
||||||
|
|
||||||
|
Window --> Registry : получает compositor, shm, wm_base
|
||||||
|
Window --> FigureDraw : отрисовка фигуры
|
||||||
|
Window --> FigureAnimate : aux_thread для анимации
|
||||||
|
|
||||||
|
FigureDraw --> FigureAnimate : использует place_points_on_circle
|
||||||
|
}
|
||||||
|
|
||||||
|
package "System Libraries" {
|
||||||
|
[wayland-client] as WaylandLib
|
||||||
|
[xdg-shell-protocol] as XDGShell
|
||||||
|
[xkbcommon] as XKB
|
||||||
|
}
|
||||||
|
|
||||||
|
Registry --> WaylandLib
|
||||||
|
Registry --> XDGShell
|
||||||
|
Window --> WaylandLib
|
||||||
|
Window --> XDGShell
|
||||||
|
Input --> WaylandLib
|
||||||
|
Input --> XKB
|
||||||
|
|
||||||
|
cloud "Wayland Compositor" as Compositor
|
||||||
|
|
||||||
|
Runtime --> Compositor : wl_display_connect()
|
||||||
|
Registry --> Compositor : получение глобальных объектов
|
||||||
|
Window --> Compositor : создание окон и буферов
|
||||||
|
Input --> Compositor : получение событий клавиатуры
|
||||||
|
|
||||||
|
note right of Runtime
|
||||||
|
Центральный компонент:
|
||||||
|
- Управление жизненным циклом
|
||||||
|
- Многопоточность (окна + анимация)
|
||||||
|
- Синхронизация через mutex
|
||||||
|
end note
|
||||||
|
|
||||||
|
note right of FigureAnimate
|
||||||
|
Реализация на NASM:
|
||||||
|
- Физика движения
|
||||||
|
- Обработка коллизий
|
||||||
|
- Математика (sin/cos)
|
||||||
|
- SSE инструкции
|
||||||
|
end note
|
||||||
|
|
||||||
|
note right of Window
|
||||||
|
Каждое окно в отдельном потоке:
|
||||||
|
- window_thread: отрисовка
|
||||||
|
- aux_thread: анимация
|
||||||
|
- Event queue для изоляции событий
|
||||||
|
end note
|
||||||
|
|
||||||
|
@enduml
|
||||||
BIN
wayland/docs/uml/diagram-sequence-init.png
Normal file
|
After Width: | Height: | Size: 57 KiB |
78
wayland/docs/uml/diagram-sequence-init.puml
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
@startuml
|
||||||
|
title Последовательность инициализации Wayland приложения
|
||||||
|
|
||||||
|
actor Main
|
||||||
|
participant "wayland-runtime" as Runtime
|
||||||
|
participant "registry" as Registry
|
||||||
|
participant "input" as Input
|
||||||
|
participant "window" as Window
|
||||||
|
|
||||||
|
Main -> Runtime: init_wayland()
|
||||||
|
activate Runtime
|
||||||
|
|
||||||
|
Runtime -> Runtime: wl_display_connect()
|
||||||
|
note right: Подключение к Wayland серверу
|
||||||
|
|
||||||
|
Runtime -> Registry: registry_global_bind(display)
|
||||||
|
activate Registry
|
||||||
|
|
||||||
|
Registry -> Registry: wl_display_get_registry()
|
||||||
|
Registry -> Registry: wl_registry_add_listener()
|
||||||
|
Registry -> Registry: wl_display_roundtrip()
|
||||||
|
note right: Получение глобальных объектов:\n- wl_compositor\n- wl_shm\n- xdg_wm_base\n- wl_seat
|
||||||
|
|
||||||
|
Registry -> Input: input_register_seat(seat)
|
||||||
|
activate Input
|
||||||
|
Input -> Input: wl_seat_add_listener()
|
||||||
|
Input -> Input: wl_seat_get_keyboard()
|
||||||
|
Input -> Input: xkb_context_new()
|
||||||
|
note right: Инициализация обработки клавиатуры
|
||||||
|
deactivate Input
|
||||||
|
|
||||||
|
Registry -> Registry: pthread_create(global_thread)
|
||||||
|
note right: Запуск потока обработки\nглобальных событий
|
||||||
|
|
||||||
|
deactivate Registry
|
||||||
|
|
||||||
|
Runtime -> Runtime: Инициализация слотов окон
|
||||||
|
Runtime -> Runtime: atomic_store(g_shutdown, 0)
|
||||||
|
|
||||||
|
deactivate Runtime
|
||||||
|
|
||||||
|
Main -> Runtime: run_window()
|
||||||
|
activate Runtime
|
||||||
|
|
||||||
|
Runtime -> Runtime: Найти свободный слот
|
||||||
|
Runtime -> Runtime: pthread_create(window_thread)
|
||||||
|
note right: Создание потока окна
|
||||||
|
|
||||||
|
Runtime --> Main: slot_index
|
||||||
|
|
||||||
|
== Поток окна ==
|
||||||
|
|
||||||
|
Runtime -> Runtime: wl_display_create_queue()
|
||||||
|
Runtime -> Window: window_init(display, queue)
|
||||||
|
activate Window
|
||||||
|
|
||||||
|
Window -> Registry: registry_get_compositor()
|
||||||
|
Window -> Registry: registry_get_shm()
|
||||||
|
Window -> Registry: registry_get_xdg_wm_base()
|
||||||
|
|
||||||
|
Window -> Window: wl_compositor_create_surface()
|
||||||
|
Window -> Window: xdg_wm_base_get_xdg_surface()
|
||||||
|
Window -> Window: xdg_surface_get_toplevel()
|
||||||
|
Window -> Window: Инициализация listeners
|
||||||
|
Window -> Window: Инициализация figure_animation_info
|
||||||
|
note right: Параметры анимации:\n- position, velocity\n- angle, angular_velocity\n- speed, radius
|
||||||
|
|
||||||
|
deactivate Window
|
||||||
|
|
||||||
|
Runtime -> Runtime: pthread_create(aux_thread)
|
||||||
|
note right: Вспомогательный поток\nдля анимации
|
||||||
|
|
||||||
|
Runtime -> Runtime: wl_display_dispatch_queue()
|
||||||
|
note right: Цикл обработки событий окна
|
||||||
|
|
||||||
|
deactivate Runtime
|
||||||
|
|
||||||
|
@enduml
|
||||||
BIN
wayland/docs/uml/diagram-sequence-keyboard.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
61
wayland/docs/uml/diagram-sequence-keyboard.puml
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
@startuml
|
||||||
|
title Обработка клавиатурного ввода
|
||||||
|
|
||||||
|
actor User
|
||||||
|
participant "Wayland Server" as Server
|
||||||
|
participant "input" as Input
|
||||||
|
participant "input-handle" as Handler
|
||||||
|
participant "wayland-runtime" as Runtime
|
||||||
|
participant "window" as Window
|
||||||
|
|
||||||
|
User -> Server: Нажатие клавиши
|
||||||
|
Server -> Input: keyboard_key(key, state)
|
||||||
|
activate Input
|
||||||
|
|
||||||
|
Input -> Input: xkb_state_key_get_one_sym()
|
||||||
|
note right: Преобразование keycode в keysym
|
||||||
|
|
||||||
|
Input -> Handler: keyboard_key_handle(kc, ks, state, window)
|
||||||
|
activate Handler
|
||||||
|
|
||||||
|
alt Клавиша Enter
|
||||||
|
Handler -> Runtime: run_window()
|
||||||
|
note right: Создание нового окна
|
||||||
|
else Клавиша '1'
|
||||||
|
Handler -> Window: figure.type = CIRCLE
|
||||||
|
else Клавиша '2'
|
||||||
|
Handler -> Window: figure.type = TRIANGLE
|
||||||
|
else Клавиша '3'
|
||||||
|
Handler -> Window: figure.type = SQUARE
|
||||||
|
else Клавиша '-'
|
||||||
|
Handler -> Handler: pthread_mutex_lock()
|
||||||
|
Handler -> Window: figure.speed -= 0.5
|
||||||
|
Handler -> Handler: Ограничить [1, 30]
|
||||||
|
Handler -> Handler: pthread_mutex_unlock()
|
||||||
|
else Клавиша '+' или '='
|
||||||
|
Handler -> Handler: pthread_mutex_lock()
|
||||||
|
Handler -> Window: figure.speed += 0.5
|
||||||
|
Handler -> Handler: Ограничить [1, 30]
|
||||||
|
Handler -> Handler: pthread_mutex_unlock()
|
||||||
|
else Клавиша Up
|
||||||
|
Handler -> Handler: pthread_mutex_lock()
|
||||||
|
Handler -> Window: figure.radius += 2.0
|
||||||
|
Handler -> Handler: Ограничить [1, max]
|
||||||
|
Handler -> Handler: pthread_mutex_unlock()
|
||||||
|
else Клавиша Down
|
||||||
|
Handler -> Handler: pthread_mutex_lock()
|
||||||
|
Handler -> Window: figure.radius -= 2.0
|
||||||
|
Handler -> Handler: Ограничить [1, max]
|
||||||
|
Handler -> Handler: pthread_mutex_unlock()
|
||||||
|
end
|
||||||
|
|
||||||
|
deactivate Handler
|
||||||
|
deactivate Input
|
||||||
|
|
||||||
|
note over Window
|
||||||
|
Изменения параметров фигуры
|
||||||
|
влияют на следующий frame
|
||||||
|
анимации и отрисовки
|
||||||
|
end note
|
||||||
|
|
||||||
|
@enduml
|
||||||
BIN
wayland/docs/uml/diagram-state-figure.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
62
wayland/docs/uml/diagram-state-figure.puml
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
@startuml
|
||||||
|
title Диаграмма состояний фигуры
|
||||||
|
|
||||||
|
[*] --> Circle : init (по умолчанию)
|
||||||
|
|
||||||
|
Circle : Красный цвет (0xFFFF0000)
|
||||||
|
Circle : radius точек = 16
|
||||||
|
Triangle : Зелёный цвет (0xFF00FF00)
|
||||||
|
Triangle : radius точек = 3
|
||||||
|
Square : Синий цвет (0xFF0000FF)
|
||||||
|
Square : radius точек = 4
|
||||||
|
|
||||||
|
Circle --> Triangle : Клавиша '2'
|
||||||
|
Circle --> Square : Клавиша '3'
|
||||||
|
|
||||||
|
Triangle --> Circle : Клавиша '1'
|
||||||
|
Triangle --> Square : Клавиша '3'
|
||||||
|
|
||||||
|
Square --> Circle : Клавиша '1'
|
||||||
|
Square --> Triangle : Клавиша '2'
|
||||||
|
|
||||||
|
Circle : velocity движет позицию
|
||||||
|
Circle : angular_velocity вращает
|
||||||
|
Triangle : velocity движет позицию
|
||||||
|
Triangle : angular_velocity вращает
|
||||||
|
Square : velocity движет позицию
|
||||||
|
Square : angular_velocity вращает
|
||||||
|
|
||||||
|
note right of Circle
|
||||||
|
Общие свойства для всех состояний:
|
||||||
|
- position (x, y)
|
||||||
|
- velocity (vx, vy)
|
||||||
|
- angle (угол поворота)
|
||||||
|
- angular_velocity (скорость вращения)
|
||||||
|
- speed (множитель скорости: 1-30)
|
||||||
|
- radius (радиус в пикселях)
|
||||||
|
|
||||||
|
Управление:
|
||||||
|
- '+'/'-': изменение speed
|
||||||
|
- Up/Down: изменение radius
|
||||||
|
- Enter: создать новое окно
|
||||||
|
end note
|
||||||
|
|
||||||
|
state "Коллизия с границей" as Collision {
|
||||||
|
[*] --> CheckCollision
|
||||||
|
CheckCollision --> InvertVelocity : точка вышла за границу
|
||||||
|
InvertVelocity --> UpdateAngularVel : инверсия компоненты velocity
|
||||||
|
UpdateAngularVel --> CheckCollision : обновление angular_velocity
|
||||||
|
|
||||||
|
CheckCollision : проверка всех точек фигуры
|
||||||
|
InvertVelocity : vel = -vel (по оси коллизии)
|
||||||
|
UpdateAngularVel : зависит от направления движения
|
||||||
|
}
|
||||||
|
|
||||||
|
Circle --> Collision : каждый frame
|
||||||
|
Triangle --> Collision : каждый frame
|
||||||
|
Square --> Collision : каждый frame
|
||||||
|
Collision --> Circle
|
||||||
|
Collision --> Triangle
|
||||||
|
Collision --> Square
|
||||||
|
|
||||||
|
@enduml
|
||||||
2564
wayland/docs/wayland-report.md
Normal file
@@ -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,616 @@
|
|||||||
|
; Макрос для локальных переменных
|
||||||
|
%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
|
||||||
|
ABS_MASK: dd 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff
|
||||||
|
ANG_COLLIDE_COEF: dd 0.2
|
||||||
|
ANG_BOOST_FACTOR: dd 0.01
|
||||||
|
; Скорость углового обновления (можно регулировать независимо от FIG_SPEED)
|
||||||
|
ANG_SPEED: dd 15.0
|
||||||
|
ANG_MAX: dd 0.03
|
||||||
|
ANG_SWITCH_FACTOR: dd 0.2
|
||||||
|
ANG_MAX_DELTA: dd 0.006
|
||||||
|
ANG_FRICTION: dd 0.94
|
||||||
|
|
||||||
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 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:
|
|
||||||
|
|
||||||
|
; Отработка коллизий
|
||||||
|
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
|
||||||
|
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
|
||||||
|
|
||||||
|
; 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
|
||||||
|
|
||||||
|
; Обновить угол: angle += angular_velocity * ANG_SPEED (локальная константа)
|
||||||
|
movss xmm0, [rdi + WDI_FIGURE + FIG_ANG_VEL]
|
||||||
|
mulss xmm0, [rel ANG_SPEED]
|
||||||
|
addss xmm0, [rdi + WDI_FIGURE + FIG_ANGLE]
|
||||||
|
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
|
||||||
|
ret
|
||||||
|
|
||||||
|
; Функция для обработки коллизии, изменяет velocity при обнаружении коллизии с границами
|
||||||
|
; Параметры:
|
||||||
|
; rdi - указатель на struct window_draw_info
|
||||||
|
%assign __local_offset 0
|
||||||
|
figure_handle_collision:
|
||||||
|
enter 128,0
|
||||||
|
|
||||||
|
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, [r12 + WDI_FIGURE + FIG_POSITION]
|
||||||
|
movss xmm1, [r12 + WDI_FIGURE + FIG_POSITION + 4]
|
||||||
|
movss xmm2, [r12 + WDI_FIGURE + FIG_ANGLE] ; смещение угла = 0
|
||||||
|
mulss xmm2, [rel NEG_ONE_CONST]
|
||||||
|
|
||||||
|
; Установка правильного количества точек
|
||||||
|
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
|
||||||
|
.figure_points_done:
|
||||||
|
|
||||||
|
lea rdi, [rbp + point_buffer]
|
||||||
|
call place_points_on_circle
|
||||||
|
|
||||||
|
; Вычислить 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
|
||||||
|
|
||||||
|
; -----------------------
|
||||||
|
; Обновить угловую скорость при коллизии
|
||||||
|
; Формула: 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
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
; 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
|
||||||
|
.loop:
|
||||||
|
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 .loop
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
|
; Функция проверки выхода за границы с маской
|
||||||
|
; Вход:
|
||||||
|
; 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
|
||||||
|
|||||||
@@ -1,110 +1,239 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include "figure-draw.h"
|
#include "figure-draw.h"
|
||||||
|
|
||||||
/* C implementation of the drawing routine. The .asm file simply forwards to this
|
#ifndef M_PI
|
||||||
* function so we keep the symbol present in an assembly file. */
|
#define M_PI 3.14159265358979323846
|
||||||
void figure_draw(struct window_draw_info* draw_info, float border_thickness, uint32_t border_color, uint32_t fill_color)
|
#endif
|
||||||
|
|
||||||
|
/* Вспомогательная функция для установки пикселя */
|
||||||
|
static inline void set_pixel(uint8_t *data, int32_t width, int32_t height, int x, int y, uint32_t color)
|
||||||
{
|
{
|
||||||
if (!draw_info || !draw_info->data)
|
if (x < 0 || x >= width || y < 0 || y >= height)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
uint32_t *pixel = (uint32_t *)(data + (y * width + x) * 4);
|
||||||
|
*pixel = color;
|
||||||
|
}
|
||||||
|
|
||||||
int w = draw_info->width;
|
/* Проверка, находится ли точка внутри треугольника (барицентрические координаты) */
|
||||||
int h = draw_info->height;
|
static int point_in_triangle(float px, float py, float x1, float y1, float x2, float y2, float x3, float y3)
|
||||||
uint32_t *pixels = (uint32_t *)draw_info->data;
|
{
|
||||||
|
float d1 = (px - x2) * (y1 - y2) - (x1 - x2) * (py - y2);
|
||||||
|
float d2 = (px - x3) * (y2 - y3) - (x2 - x3) * (py - y3);
|
||||||
|
float d3 = (px - x1) * (y3 - y1) - (x3 - x1) * (py - y1);
|
||||||
|
|
||||||
|
int has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0);
|
||||||
|
int has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0);
|
||||||
|
|
||||||
|
return !(has_neg && has_pos);
|
||||||
|
}
|
||||||
|
|
||||||
struct figure_animation_info fig = draw_info->figure;
|
/* Расстояние от точки до отрезка */
|
||||||
|
static float point_to_segment_distance(float px, float py, float x1, float y1, float x2, float y2)
|
||||||
|
{
|
||||||
|
float dx = x2 - x1;
|
||||||
|
float dy = y2 - y1;
|
||||||
|
float len_sq = dx * dx + dy * dy;
|
||||||
|
|
||||||
|
if (len_sq < 0.0001f) {
|
||||||
|
dx = px - x1;
|
||||||
|
dy = py - y1;
|
||||||
|
return sqrtf(dx * dx + dy * dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
float t = ((px - x1) * dx + (py - y1) * dy) / len_sq;
|
||||||
|
t = fmaxf(0.0f, fminf(1.0f, t));
|
||||||
|
|
||||||
|
float proj_x = x1 + t * dx;
|
||||||
|
float proj_y = y1 + t * dy;
|
||||||
|
|
||||||
|
dx = px - proj_x;
|
||||||
|
dy = py - proj_y;
|
||||||
|
|
||||||
|
return sqrtf(dx * dx + dy * dy);
|
||||||
|
}
|
||||||
|
|
||||||
/* center in pixels */
|
/* Рисование круга */
|
||||||
float cx = fig.position.x * (float)w;
|
static void draw_circle(struct window_draw_info* draw_info, float cx, float cy, float radius,
|
||||||
float cy = fig.position.y * (float)h;
|
float border_thickness, uint32_t border_color, uint32_t fill_color)
|
||||||
/* `fig.radius` is in pixels now; use it directly. */
|
{
|
||||||
float r = fig.radius;
|
int x_min = (int)fmaxf(0, cx - radius - border_thickness);
|
||||||
float r2 = r * r;
|
int x_max = (int)fminf(draw_info->width - 1, cx + radius + border_thickness);
|
||||||
float border = border_thickness;
|
int y_min = (int)fmaxf(0, cy - radius - border_thickness);
|
||||||
if (border < 0.0f) border = 0.0f;
|
int y_max = (int)fminf(draw_info->height - 1, cy + radius + border_thickness);
|
||||||
|
|
||||||
/* bounding box */
|
for (int y = y_min; y <= y_max; y++) {
|
||||||
int minx = (int)floorf(cx - r);
|
for (int x = x_min; x <= x_max; x++) {
|
||||||
int maxx = (int)ceilf(cx + r);
|
float dx = x - cx;
|
||||||
int miny = (int)floorf(cy - r);
|
float dy = y - cy;
|
||||||
int maxy = (int)ceilf(cy + r);
|
float dist = sqrtf(dx * dx + dy * dy);
|
||||||
/* make sure we don't go out of bounds */
|
|
||||||
if (miny < 0) miny = 0;
|
if (dist <= radius) {
|
||||||
if (minx < 0) minx = 0;
|
set_pixel(draw_info->data, draw_info->width, draw_info->height, x, y, fill_color);
|
||||||
if (maxy >= h) maxy = h - 1;
|
} else if (dist <= radius + border_thickness) {
|
||||||
if (maxx >= w) maxx = w - 1;
|
set_pixel(draw_info->data, draw_info->width, draw_info->height, x, y, border_color);
|
||||||
|
|
||||||
/* We'll compute pixel centers at (x + 0.5f, y + 0.5f) */
|
|
||||||
for (int y = miny; y <= maxy; ++y)
|
|
||||||
{
|
|
||||||
float py = (float)y + 0.5f;
|
|
||||||
for (int x = minx; x <= maxx; ++x)
|
|
||||||
{
|
|
||||||
float px = (float)x + 0.5f;
|
|
||||||
int draw = 0;
|
|
||||||
int border_pixel = 0;
|
|
||||||
switch (fig.type)
|
|
||||||
{
|
|
||||||
case FIGURE_CIRCLE:
|
|
||||||
{
|
|
||||||
float dx = px - cx;
|
|
||||||
float dy = py - cy;
|
|
||||||
float d2 = dx*dx + dy*dy;
|
|
||||||
if (d2 <= r2)
|
|
||||||
{
|
|
||||||
draw = 1;
|
|
||||||
if (d2 >= (r - border)*(r - border))
|
|
||||||
border_pixel = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FIGURE_SQUARE:
|
|
||||||
{
|
|
||||||
float dx = fabsf(px - cx);
|
|
||||||
float dy = fabsf(py - cy);
|
|
||||||
if (dx <= r && dy <= r)
|
|
||||||
{
|
|
||||||
draw = 1;
|
|
||||||
if (fmaxf(dx, dy) >= r - border)
|
|
||||||
border_pixel = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FIGURE_TRIANGLE:
|
|
||||||
{
|
|
||||||
/* Equilateral triangle centered at cx,cy. Apex up. *
|
|
||||||
* Vertices: A=(cx, cy - r), B=(cx + r*0.866, cy + r*0.5), C=(cx - r*0.866, cy + r*0.5) */
|
|
||||||
float v1x = r * 0.8660254037844386f;
|
|
||||||
float v1y = r * 0.5f;
|
|
||||||
float ax = cx; float ay = cy - r;
|
|
||||||
float bx = cx + v1x; float by = cy + v1y;
|
|
||||||
float cx2 = cx - v1x; float cy2 = by;
|
|
||||||
|
|
||||||
/* barycentric tests: point inside triangle if all cross products have same sign */
|
|
||||||
float s1 = (px - bx)*(ay - by) - (ax - bx)*(py - by);
|
|
||||||
float s2 = (px - cx2)*(by - cy2) - (bx - cx2)*(py - cy2);
|
|
||||||
float s3 = (px - ax)*(cy2 - ay) - (cx2 - ax)*(py - ay);
|
|
||||||
int neg = (s1 < 0) + (s2 < 0) + (s3 < 0);
|
|
||||||
int pos = (s1 > 0) + (s2 > 0) + (s3 > 0);
|
|
||||||
if (neg == 0 || pos == 0)
|
|
||||||
{
|
|
||||||
draw = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (draw)
|
|
||||||
{
|
|
||||||
uint32_t col = border_pixel ? border_color : fill_color;
|
|
||||||
pixels[y * w + x] = col;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* C symbol exported to be called by minimal assembly wrapper */
|
/* Рисование треугольника */
|
||||||
|
static void draw_triangle(struct window_draw_info* draw_info, float cx, float cy, float radius, float angle,
|
||||||
|
float border_thickness, uint32_t border_color, uint32_t fill_color)
|
||||||
|
{
|
||||||
|
/* Вычисляем координаты вершин равностороннего треугольника */
|
||||||
|
/* Угол 0 означает, что одна вершина справа от центра */
|
||||||
|
float vertices[3][2];
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
float vertex_angle = angle + i * (2.0f * M_PI / 3.0f);
|
||||||
|
vertices[i][0] = cx + radius * cosf(vertex_angle);
|
||||||
|
vertices[i][1] = cy - radius * sinf(vertex_angle); /* Инвертируем Y для экранных координат */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Находим ограничивающий прямоугольник */
|
||||||
|
float min_x = fminf(vertices[0][0], fminf(vertices[1][0], vertices[2][0])) - border_thickness;
|
||||||
|
float max_x = fmaxf(vertices[0][0], fmaxf(vertices[1][0], vertices[2][0])) + border_thickness;
|
||||||
|
float min_y = fminf(vertices[0][1], fminf(vertices[1][1], vertices[2][1])) - border_thickness;
|
||||||
|
float max_y = fmaxf(vertices[0][1], fmaxf(vertices[1][1], vertices[2][1])) + border_thickness;
|
||||||
|
|
||||||
|
int x_min = (int)fmaxf(0, min_x);
|
||||||
|
int x_max = (int)fminf(draw_info->width - 1, max_x);
|
||||||
|
int y_min = (int)fmaxf(0, min_y);
|
||||||
|
int y_max = (int)fminf(draw_info->height - 1, max_y);
|
||||||
|
|
||||||
|
/* Рисуем треугольник */
|
||||||
|
for (int y = y_min; y <= y_max; y++) {
|
||||||
|
for (int x = x_min; x <= x_max; x++) {
|
||||||
|
int inside = point_in_triangle((float)x, (float)y,
|
||||||
|
vertices[0][0], vertices[0][1],
|
||||||
|
vertices[1][0], vertices[1][1],
|
||||||
|
vertices[2][0], vertices[2][1]);
|
||||||
|
|
||||||
|
if (inside) {
|
||||||
|
set_pixel(draw_info->data, draw_info->width, draw_info->height, x, y, fill_color);
|
||||||
|
} else {
|
||||||
|
/* Проверяем расстояние до границ */
|
||||||
|
float dist1 = point_to_segment_distance((float)x, (float)y,
|
||||||
|
vertices[0][0], vertices[0][1],
|
||||||
|
vertices[1][0], vertices[1][1]);
|
||||||
|
float dist2 = point_to_segment_distance((float)x, (float)y,
|
||||||
|
vertices[1][0], vertices[1][1],
|
||||||
|
vertices[2][0], vertices[2][1]);
|
||||||
|
float dist3 = point_to_segment_distance((float)x, (float)y,
|
||||||
|
vertices[2][0], vertices[2][1],
|
||||||
|
vertices[0][0], vertices[0][1]);
|
||||||
|
|
||||||
|
float min_dist = fminf(dist1, fminf(dist2, dist3));
|
||||||
|
if (min_dist <= border_thickness) {
|
||||||
|
set_pixel(draw_info->data, draw_info->width, draw_info->height, x, y, border_color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Рисование квадрата */
|
||||||
|
static void draw_square(struct window_draw_info* draw_info, float cx, float cy, float radius, float angle,
|
||||||
|
float border_thickness, uint32_t border_color, uint32_t fill_color)
|
||||||
|
{
|
||||||
|
/* Вычисляем координаты вершин квадрата */
|
||||||
|
/* Угол 0 означает, что одна вершина справа от центра */
|
||||||
|
float vertices[4][2];
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
float vertex_angle = angle + i * (M_PI / 2.0f);
|
||||||
|
vertices[i][0] = cx + radius * cosf(vertex_angle);
|
||||||
|
vertices[i][1] = cy - radius * sinf(vertex_angle); /* Инвертируем Y для экранных координат */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Находим ограничивающий прямоугольник */
|
||||||
|
float min_x = vertices[0][0], max_x = vertices[0][0];
|
||||||
|
float min_y = vertices[0][1], max_y = vertices[0][1];
|
||||||
|
for (int i = 1; i < 4; i++) {
|
||||||
|
min_x = fminf(min_x, vertices[i][0]);
|
||||||
|
max_x = fmaxf(max_x, vertices[i][0]);
|
||||||
|
min_y = fminf(min_y, vertices[i][1]);
|
||||||
|
max_y = fmaxf(max_y, vertices[i][1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
min_x -= border_thickness;
|
||||||
|
max_x += border_thickness;
|
||||||
|
min_y -= border_thickness;
|
||||||
|
max_y += border_thickness;
|
||||||
|
|
||||||
|
int x_min = (int)fmaxf(0, min_x);
|
||||||
|
int x_max = (int)fminf(draw_info->width - 1, max_x);
|
||||||
|
int y_min = (int)fmaxf(0, min_y);
|
||||||
|
int y_max = (int)fminf(draw_info->height - 1, max_y);
|
||||||
|
|
||||||
|
/* Рисуем квадрат */
|
||||||
|
for (int y = y_min; y <= y_max; y++) {
|
||||||
|
for (int x = x_min; x <= x_max; x++) {
|
||||||
|
float px = (float)x;
|
||||||
|
float py = (float)y;
|
||||||
|
|
||||||
|
/* Проверяем, находится ли точка внутри квадрата */
|
||||||
|
/* Используем два треугольника */
|
||||||
|
int inside = point_in_triangle(px, py,
|
||||||
|
vertices[0][0], vertices[0][1],
|
||||||
|
vertices[1][0], vertices[1][1],
|
||||||
|
vertices[2][0], vertices[2][1]) ||
|
||||||
|
point_in_triangle(px, py,
|
||||||
|
vertices[0][0], vertices[0][1],
|
||||||
|
vertices[2][0], vertices[2][1],
|
||||||
|
vertices[3][0], vertices[3][1]);
|
||||||
|
|
||||||
|
if (inside) {
|
||||||
|
set_pixel(draw_info->data, draw_info->width, draw_info->height, x, y, fill_color);
|
||||||
|
} else {
|
||||||
|
/* Проверяем расстояние до границ */
|
||||||
|
float min_dist = INFINITY;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
int next = (i + 1) % 4;
|
||||||
|
float dist = point_to_segment_distance(px, py,
|
||||||
|
vertices[i][0], vertices[i][1],
|
||||||
|
vertices[next][0], vertices[next][1]);
|
||||||
|
min_dist = fminf(min_dist, dist);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (min_dist <= border_thickness) {
|
||||||
|
set_pixel(draw_info->data, draw_info->width, draw_info->height, x, y, border_color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void figure_draw(struct window_draw_info* draw_info, float border_thickness, uint32_t border_color, uint32_t fill_color)
|
||||||
|
{
|
||||||
|
if (!draw_info || !draw_info->data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Координаты приходят в относительных единицах
|
||||||
|
* Y: [0..1] -> умножаем на высоту
|
||||||
|
* X: нормализован относительно высоты -> умножаем на высоту же
|
||||||
|
*/
|
||||||
|
float cx = draw_info->figure.position.x * draw_info->height;
|
||||||
|
float cy = draw_info->figure.position.y * draw_info->height;
|
||||||
|
float radius = draw_info->figure.radius;
|
||||||
|
float angle = draw_info->figure.angle;
|
||||||
|
enum figure_type type = draw_info->figure.type;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case FIGURE_CIRCLE:
|
||||||
|
draw_circle(draw_info, cx, cy, radius, border_thickness, border_color, fill_color);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FIGURE_TRIANGLE:
|
||||||
|
draw_triangle(draw_info, cx, cy, radius, angle, border_thickness, border_color, fill_color);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FIGURE_SQUARE:
|
||||||
|
draw_square(draw_info, cx, cy, radius, angle, border_thickness, border_color, fill_color);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "input-handle.h"
|
#include "input-handle.h"
|
||||||
#include "wayland-runtime.h"
|
#include "wayland-runtime.h"
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
void keyboard_key_handle(xkb_keycode_t kc, xkb_keysym_t ks, enum keyboard_key_state state, struct wayland_window *window)
|
void keyboard_key_handle(xkb_keycode_t kc, xkb_keysym_t ks, enum keyboard_key_state state, struct wayland_window *window)
|
||||||
{
|
{
|
||||||
@@ -8,12 +9,12 @@ void keyboard_key_handle(xkb_keycode_t kc, xkb_keysym_t ks, enum keyboard_key_st
|
|||||||
char buf[64];
|
char buf[64];
|
||||||
int n = xkb_keysym_to_utf8(ks, buf, sizeof(buf));
|
int n = xkb_keysym_to_utf8(ks, buf, sizeof(buf));
|
||||||
|
|
||||||
if (n > 0)
|
// if (n > 0)
|
||||||
printf("keyboard: symbol '%s' (keysym 0x%x) on surface:%p\n", buf, ks, window);
|
// printf("keyboard: symbol '%s' (keysym 0x%x) on surface:%p\n", buf, ks, window);
|
||||||
else
|
// else
|
||||||
printf("keyboard: keysym 0x%x (no UTF-8 representation)\n", ks);
|
// printf("keyboard: keysym 0x%x (no UTF-8 representation)\n", ks);
|
||||||
|
|
||||||
if(state == KEYBOARD_KEY_STATE_PRESSED)
|
if(state != KEYBOARD_KEY_STATE_RELEASED)
|
||||||
{
|
{
|
||||||
switch (ks)
|
switch (ks)
|
||||||
{
|
{
|
||||||
@@ -30,6 +31,48 @@ void keyboard_key_handle(xkb_keycode_t kc, xkb_keysym_t ks, enum keyboard_key_st
|
|||||||
case '3':
|
case '3':
|
||||||
window->draw_info.figure.type = FIGURE_SQUARE;
|
window->draw_info.figure.type = FIGURE_SQUARE;
|
||||||
break;
|
break;
|
||||||
|
case '-':
|
||||||
|
/* decrease animation speed (multiplicative delta, clamped) */
|
||||||
|
pthread_mutex_lock(&window->draw_info.figure_mutex);
|
||||||
|
window->draw_info.figure.speed -= 1;
|
||||||
|
if (window->draw_info.figure.speed < 1)
|
||||||
|
window->draw_info.figure.speed = 1;
|
||||||
|
printf("keyboard: speed decreased to %.2f\n", window->draw_info.figure.speed);
|
||||||
|
pthread_mutex_unlock(&window->draw_info.figure_mutex);
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
case '=': /* some layouts may emit '=' for unshifted, handle + via keysym */
|
||||||
|
/* increase animation speed (multiplicative delta, clamped) */
|
||||||
|
pthread_mutex_lock(&window->draw_info.figure_mutex);
|
||||||
|
window->draw_info.figure.speed += 1;
|
||||||
|
if (window->draw_info.figure.speed > 50.0f)
|
||||||
|
window->draw_info.figure.speed = 50.0f;
|
||||||
|
printf("keyboard: speed increased to %.2f\n", window->draw_info.figure.speed);
|
||||||
|
pthread_mutex_unlock(&window->draw_info.figure_mutex);
|
||||||
|
break;
|
||||||
|
case XKB_KEY_Up:
|
||||||
|
/* increase figure radius */
|
||||||
|
pthread_mutex_lock(&window->draw_info.figure_mutex);
|
||||||
|
{
|
||||||
|
float maxr = fminf(window->draw_info.width, window->draw_info.height) / 2.0f - 1.0f;
|
||||||
|
window->draw_info.figure.radius += 2.0f;
|
||||||
|
if (window->draw_info.figure.radius > maxr)
|
||||||
|
window->draw_info.figure.radius = maxr;
|
||||||
|
}
|
||||||
|
printf("keyboard: radius increased to %.2f\n", window->draw_info.figure.radius);
|
||||||
|
pthread_mutex_unlock(&window->draw_info.figure_mutex);
|
||||||
|
break;
|
||||||
|
case XKB_KEY_Down:
|
||||||
|
/* decrease figure radius */
|
||||||
|
pthread_mutex_lock(&window->draw_info.figure_mutex);
|
||||||
|
{
|
||||||
|
window->draw_info.figure.radius -= 2.0f;
|
||||||
|
if (window->draw_info.figure.radius < 1.0f)
|
||||||
|
window->draw_info.figure.radius = 1.0f;
|
||||||
|
}
|
||||||
|
printf("keyboard: radius decreased to %.2f\n", window->draw_info.figure.radius);
|
||||||
|
pthread_mutex_unlock(&window->draw_info.figure_mutex);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,14 +70,12 @@ static void keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t f
|
|||||||
|
|
||||||
static void keyboard_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys)
|
static void keyboard_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys)
|
||||||
{
|
{
|
||||||
printf("keyboard: enter serial=%u surface=%p\n", serial, surface);
|
|
||||||
/* Сохраняем поверхность, которая получила фокус клавиатуры */
|
/* Сохраняем поверхность, которая получила фокус клавиатуры */
|
||||||
focused_window = get_window_by_surface(surface);
|
focused_window = get_window_by_surface(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void keyboard_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface)
|
static void keyboard_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface)
|
||||||
{
|
{
|
||||||
printf("keyboard: leave serial=%u surface=%p\n", serial, surface);
|
|
||||||
/* Если уходим с фокусной поверхности — сбросить фокус */
|
/* Если уходим с фокусной поверхности — сбросить фокус */
|
||||||
if (focused_window && focused_window->wl_surface == surface)
|
if (focused_window && focused_window->wl_surface == surface)
|
||||||
focused_window = NULL;
|
focused_window = NULL;
|
||||||
@@ -100,7 +98,6 @@ static void keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t seri
|
|||||||
|
|
||||||
static void keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
|
static void keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
|
||||||
{
|
{
|
||||||
printf("keyboard: modifiers serial=%u depressed=%u latched=%u locked=%u group=%u\n", serial, mods_depressed, mods_latched, mods_locked, group);
|
|
||||||
if (xkb_state)
|
if (xkb_state)
|
||||||
{
|
{
|
||||||
xkb_state_update_mask(xkb_state, mods_depressed, mods_latched, mods_locked, group, 0, 0);
|
xkb_state_update_mask(xkb_state, mods_depressed, mods_latched, mods_locked, group, 0, 0);
|
||||||
@@ -109,7 +106,6 @@ static void keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_
|
|||||||
|
|
||||||
static void keyboard_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay)
|
static void keyboard_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay)
|
||||||
{
|
{
|
||||||
printf("keyboard: repeat rate=%d delay=%d\n", rate, delay);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_keyboard_listener keyboard_listener = {
|
static const struct wl_keyboard_listener keyboard_listener = {
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -50,9 +70,38 @@ 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(15 * 1000);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -129,6 +178,20 @@ int32_t init_wayland(void)
|
|||||||
atomic_store(&g_shutdown, 0);
|
atomic_store(&g_shutdown, 0);
|
||||||
atomic_store(&g_active_threads, 0);
|
atomic_store(&g_active_threads, 0);
|
||||||
g_initialized = 1;
|
g_initialized = 1;
|
||||||
|
|
||||||
|
/* Print keyboard help to the console so users know available shortcuts and
|
||||||
|
* behaviors. This mirrors the handling implemented in
|
||||||
|
* `input-handle.c` and acts as a quick usage hint. */
|
||||||
|
printf("\nKeyboard shortcuts and behavior:\n");
|
||||||
|
printf(" - Enter: open a new window\n");
|
||||||
|
printf(" - 1: switch to circle figure\n");
|
||||||
|
printf(" - 2: switch to triangle figure\n");
|
||||||
|
printf(" - 3: switch to square figure\n");
|
||||||
|
printf(" - - : decrease animation speed (clamped, multiplicative)\n");
|
||||||
|
printf(" - + or = : increase animation speed (clamped, multiplicative)\n");
|
||||||
|
printf(" - Up arrow: increase figure radius (clamped to window bounds)\n");
|
||||||
|
printf(" - Down arrow: decrease figure radius (minimum 1.0)\n");
|
||||||
|
printf(" Note: actions are triggered on key press (not on release).\n\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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, 0xFF000000, 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 = 0.01; /* radians per frame */
|
||||||
draw_info->figure.speed = 100.0f; /* pixels per second */
|
draw_info->figure.speed = 10; /* 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;
|
||||||
|
|||||||