Compare commits
10 Commits
908d539abe
...
58eb3695f1
| Author | SHA1 | Date | |
|---|---|---|---|
| 58eb3695f1 | |||
| 2c383b20e9 | |||
| 92f4632803 | |||
| 5ac43bb236 | |||
| 743b8336a3 | |||
| 8dd2aa19ad | |||
| de18bd8252 | |||
| c21df94757 | |||
| b8ebf31762 | |||
| bc5bf92fee |
@@ -16,7 +16,16 @@
|
|||||||
"editor.codeLens": false,
|
"editor.codeLens": false,
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
"flake.lock": "json",
|
"flake.lock": "json",
|
||||||
"ios": "c"
|
"ios": "c",
|
||||||
|
"cstdint": "c",
|
||||||
|
"array": "c",
|
||||||
|
"string": "c",
|
||||||
|
"string_view": "c",
|
||||||
|
"ranges": "c",
|
||||||
|
"span": "c",
|
||||||
|
"vector": "c",
|
||||||
|
"regex": "c",
|
||||||
|
"__node_handle": "c"
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
wayland/.ignore
Normal file
2
wayland/.ignore
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
**/build/
|
||||||
|
**/out/
|
||||||
@@ -4,7 +4,7 @@ project(wayland)
|
|||||||
|
|
||||||
enable_language(ASM_NASM)
|
enable_language(ASM_NASM)
|
||||||
|
|
||||||
set(CMAKE_ASM_NASM_FLAGS "-f elf64")
|
set(CMAKE_ASM_NASM_FLAGS "-f elf64 -I${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
set(CMAKE_ASM_NASM_FLAGS_DEBUG "-gdwarf")
|
set(CMAKE_ASM_NASM_FLAGS_DEBUG "-gdwarf")
|
||||||
|
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
@@ -39,6 +39,19 @@ add_custom_command(
|
|||||||
# Цель для генерации протокола
|
# Цель для генерации протокола
|
||||||
add_custom_target(generate-xdg-shell DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-client-protocol.h ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-client-protocol.c)
|
add_custom_target(generate-xdg-shell DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-client-protocol.h ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-client-protocol.c)
|
||||||
|
|
||||||
|
# Генерируем offsets.inc
|
||||||
|
add_executable(generate-offsets ${CMAKE_CURRENT_SOURCE_DIR}/generate-offsets.c)
|
||||||
|
target_include_directories(generate-offsets PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/offsets.inc
|
||||||
|
COMMAND generate-offsets > ${CMAKE_CURRENT_BINARY_DIR}/offsets.inc
|
||||||
|
DEPENDS generate-offsets
|
||||||
|
COMMENT "Generating offsets.inc"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(generate-offsets-file DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/offsets.inc)
|
||||||
|
|
||||||
# Создаем исполняемый файл из ассемблерного, C и сгенерированного кода
|
# Создаем исполняемый файл из ассемблерного, C и сгенерированного кода
|
||||||
file(GLOB_RECURSE WAYLAND_SOURCES CONFIGURE_DEPENDS
|
file(GLOB_RECURSE WAYLAND_SOURCES CONFIGURE_DEPENDS
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.c"
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.c"
|
||||||
@@ -53,7 +66,7 @@ list(APPEND WAYLAND_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-client-protoco
|
|||||||
add_executable(wayland ${WAYLAND_SOURCES})
|
add_executable(wayland ${WAYLAND_SOURCES})
|
||||||
|
|
||||||
# Ensure generated files are produced before building the target
|
# Ensure generated files are produced before building the target
|
||||||
add_dependencies(wayland generate-xdg-shell)
|
add_dependencies(wayland generate-xdg-shell generate-offsets-file)
|
||||||
|
|
||||||
# Include headers and binary dir where generated headers are written
|
# Include headers and binary dir where generated headers are written
|
||||||
target_include_directories(wayland PRIVATE
|
target_include_directories(wayland PRIVATE
|
||||||
|
|||||||
30
wayland/generate-offsets.c
Normal file
30
wayland/generate-offsets.c
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/* generate-offsets.c
|
||||||
|
* Генерирует offsets.inc с смещениями полей структур
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "window.h"
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
printf("; offsets.inc — generated automatically\n");
|
||||||
|
|
||||||
|
// window_draw_info offsets
|
||||||
|
printf("WDI_DATA equ %zu\n", offsetof(struct window_draw_info, data));
|
||||||
|
printf("WDI_WIDTH equ %zu\n", offsetof(struct window_draw_info, width));
|
||||||
|
printf("WDI_HEIGHT equ %zu\n", offsetof(struct window_draw_info, height));
|
||||||
|
printf("WDI_FIGURE equ %zu\n", offsetof(struct window_draw_info, figure));
|
||||||
|
printf("WDI_FIGURE_MUTEX equ %zu\n", offsetof(struct window_draw_info, figure_mutex));
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
// figure_animation_info offsets
|
||||||
|
printf("FIG_TYPE equ %zu\n", offsetof(struct figure_animation_info, type));
|
||||||
|
printf("FIG_POSITION equ %zu\n", offsetof(struct figure_animation_info, position));
|
||||||
|
printf("FIG_VELOCITY equ %zu\n", offsetof(struct figure_animation_info, velocity));
|
||||||
|
printf("FIG_ANGLE equ %zu\n", offsetof(struct figure_animation_info, angle));
|
||||||
|
printf("FIG_ANG_VEL equ %zu\n", offsetof(struct figure_animation_info, angular_velocity));
|
||||||
|
printf("FIG_SPEED equ %zu\n", offsetof(struct figure_animation_info, speed));
|
||||||
|
printf("FIG_RADIUS equ %zu\n", offsetof(struct figure_animation_info, radius));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
9
wayland/include/figure-animate.h
Normal file
9
wayland/include/figure-animate.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef FIGURE_ANIMATE_H
|
||||||
|
#define FIGURE_ANIMATE_H
|
||||||
|
|
||||||
|
#include "window.h"
|
||||||
|
|
||||||
|
/* Провести один шаг анимации на окне */
|
||||||
|
void figure_animation_step(struct window_draw_info* draw_info);
|
||||||
|
|
||||||
|
#endif
|
||||||
9
wayland/include/figure-draw.h
Normal file
9
wayland/include/figure-draw.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef FIGURE_DRAW_H
|
||||||
|
#define FIGURE_DRAW_H
|
||||||
|
|
||||||
|
#include "window.h"
|
||||||
|
|
||||||
|
/* Нарисовать фигуру на холсте */
|
||||||
|
void figure_draw(struct window_draw_info* draw_info, float border_thikness, uint32_t border_color, uint32_t fill_color);
|
||||||
|
|
||||||
|
#endif
|
||||||
37
wayland/include/figure.h
Normal file
37
wayland/include/figure.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#ifndef FIGURE_H
|
||||||
|
#define FIGURE_H
|
||||||
|
|
||||||
|
#include "geomerty.h"
|
||||||
|
|
||||||
|
enum figure_type
|
||||||
|
{
|
||||||
|
FIGURE_CIRCLE = 0,
|
||||||
|
FIGURE_TRIANGLE = 1,
|
||||||
|
FIGURE_SQUARE = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
struct figure_animation_info {
|
||||||
|
enum figure_type type;
|
||||||
|
struct vec2 position;
|
||||||
|
/* Direction vector; its components are not in pixels. Anim code converts
|
||||||
|
* them to pixel-space and normalizes them so that `speed` is applied as
|
||||||
|
* pixels/sec uniformly in both axes (aspect ratio is accounted for). */
|
||||||
|
struct vec2 velocity;
|
||||||
|
|
||||||
|
float angle;
|
||||||
|
float angular_velocity;
|
||||||
|
|
||||||
|
/* Speed in pixels per second. This value is applied uniformly to both
|
||||||
|
* axes (X and Y); the animation code converts this pixel speed to
|
||||||
|
* normalized increments for position updates taking window aspect ratio
|
||||||
|
* into account. */
|
||||||
|
float speed;
|
||||||
|
/* Radius of the figure in pixels (float)
|
||||||
|
* This field is used by animation code to check collisions
|
||||||
|
* with the left/right/top/bottom borders. The animation code
|
||||||
|
* will convert this pixel radius to normalized coordinates for
|
||||||
|
* collision checks against normalized positions. */
|
||||||
|
float radius;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
9
wayland/include/geomerty.h
Normal file
9
wayland/include/geomerty.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef GEOMETRY_H
|
||||||
|
#define GEOMETRY_H
|
||||||
|
|
||||||
|
struct vec2 {
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
10
wayland/include/input-handle.h
Normal file
10
wayland/include/input-handle.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef INPUT_HANDLE_H
|
||||||
|
#define INPUT_HANDLE_H
|
||||||
|
|
||||||
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
#include "window.h"
|
||||||
|
#include "input.h"
|
||||||
|
|
||||||
|
void keyboard_key_handle(xkb_keycode_t kc, xkb_keysym_t ks, enum keyboard_key_state state, struct wayland_window* window);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -8,7 +8,19 @@ void input_register_seat(struct wl_seat *seat);
|
|||||||
/* Очистка input (разрушить keyboard и xkb state) */
|
/* Очистка input (разрушить keyboard и xkb state) */
|
||||||
void input_cleanup(void);
|
void input_cleanup(void);
|
||||||
|
|
||||||
/* Возвращает wl_surface, имеющую фокус клавиатуры или NULL */
|
enum keyboard_key_state {
|
||||||
struct wl_surface *input_get_keyboard_focus(void);
|
/**
|
||||||
|
* key is not pressed
|
||||||
|
*/
|
||||||
|
KEYBOARD_KEY_STATE_RELEASED = 0,
|
||||||
|
/**
|
||||||
|
* key is pressed
|
||||||
|
*/
|
||||||
|
KEYBOARD_KEY_STATE_PRESSED = 1,
|
||||||
|
/**
|
||||||
|
* key was repeated
|
||||||
|
*/
|
||||||
|
KEYBOARD_KEY_STATE_REPEATED = 2,
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -15,4 +15,7 @@ void wait_for_windows(void);
|
|||||||
/* Остановить оконные потоки, очистить input и закрыть соединение Wayland */
|
/* Остановить оконные потоки, очистить input и закрыть соединение Wayland */
|
||||||
void destroy_wayland(void);
|
void destroy_wayland(void);
|
||||||
|
|
||||||
|
/* Поиск окна по wl_surface */
|
||||||
|
struct wayland_window* get_window_by_surface(struct wl_surface* surf);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,7 +1,17 @@
|
|||||||
#ifndef WAYLAND_WINDOW_H
|
#ifndef WAYLAND_WINDOW_H
|
||||||
#define WAYLAND_WINDOW_H
|
#define WAYLAND_WINDOW_H
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
#include <wayland-client.h>
|
#include <wayland-client.h>
|
||||||
|
#include "figure.h"
|
||||||
|
|
||||||
|
struct window_draw_info {
|
||||||
|
uint8_t *data;
|
||||||
|
int32_t width;
|
||||||
|
int32_t height;
|
||||||
|
struct figure_animation_info figure;
|
||||||
|
pthread_mutex_t figure_mutex;
|
||||||
|
};
|
||||||
|
|
||||||
/* Данные одного Wayland-окна (одна поверхность) */
|
/* Данные одного Wayland-окна (одна поверхность) */
|
||||||
struct wayland_window {
|
struct wayland_window {
|
||||||
@@ -12,13 +22,11 @@ struct wayland_window {
|
|||||||
struct xdg_surface *xdg_surface;
|
struct xdg_surface *xdg_surface;
|
||||||
struct xdg_toplevel *xdg_toplevel;
|
struct xdg_toplevel *xdg_toplevel;
|
||||||
struct wl_event_queue *queue; /* очередь событий для окна */
|
struct wl_event_queue *queue; /* очередь событий для окна */
|
||||||
uint8_t *data;
|
struct window_draw_info draw_info;
|
||||||
int32_t width;
|
|
||||||
int32_t height;
|
|
||||||
int need_close;
|
int need_close;
|
||||||
uint8_t color;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Инициализация окна; структура предоставляется вызывающим */
|
/* Инициализация окна; структура предоставляется вызывающим */
|
||||||
int window_init(struct wl_display *display, struct wl_event_queue *queue, struct wayland_window *win);
|
int window_init(struct wl_display *display, struct wl_event_queue *queue, struct wayland_window *win);
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ main:
|
|||||||
|
|
||||||
; Launch the first window thread (duplicate calls for more windows)
|
; Launch the first window thread (duplicate calls for more windows)
|
||||||
call run_window
|
call run_window
|
||||||
call run_window
|
|
||||||
call run_window
|
|
||||||
|
|
||||||
call wait_for_windows
|
call wait_for_windows
|
||||||
|
|
||||||
|
|||||||
203
wayland/src/figure-animate.asm
Normal file
203
wayland/src/figure-animate.asm
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
; Подключаем автоматически сгенерированные offsets из C структур
|
||||||
|
%include "offsets.inc"
|
||||||
|
|
||||||
|
section .text
|
||||||
|
|
||||||
|
; void animation_step(struct window_draw_info* draw_info);
|
||||||
|
; Параметры:
|
||||||
|
; rdi - указатель на struct window_draw_info
|
||||||
|
global figure_animation_step
|
||||||
|
figure_animation_step:
|
||||||
|
; Создаём локальную область на стеке и будем туда копировать поля структуры
|
||||||
|
enter 0, 0
|
||||||
|
; rdi - pointer to struct window_draw_info
|
||||||
|
; figure is embedded at offset WDI_FIGURE
|
||||||
|
mov rax, rdi
|
||||||
|
add rax, WDI_FIGURE
|
||||||
|
|
||||||
|
; --- compute movement increments so that `speed` means pixels/second
|
||||||
|
; Convert velocity to pixel-space (vx = vel.x * width, vy = vel.y * height),
|
||||||
|
; normalize that vector and apply `speed*dt` so movement in pixel units equals speed.
|
||||||
|
; using SSE for float math
|
||||||
|
movss xmm0, dword [rax + FIG_SPEED] ; xmm0 = speed (pixels/sec)
|
||||||
|
movss xmm9, [rel DT] ; xmm9 = dt
|
||||||
|
mulss xmm0, xmm9 ; xmm0 = speed * dt (pixels)
|
||||||
|
|
||||||
|
; load width/height
|
||||||
|
mov ebx, dword [rdi + WDI_WIDTH]
|
||||||
|
cvtsi2ss xmm10, ebx ; xmm10 = width
|
||||||
|
mov ebx, dword [rdi + WDI_HEIGHT]
|
||||||
|
cvtsi2ss xmm11, ebx ; xmm11 = height
|
||||||
|
|
||||||
|
; vx_pixels = vel.x * width
|
||||||
|
movss xmm1, dword [rax + FIG_VELOCITY] ; vel.x
|
||||||
|
mulss xmm1, xmm10 ; xmm1 = vx_pixels
|
||||||
|
|
||||||
|
; vy_pixels = vel.y * height
|
||||||
|
movss xmm2, dword [rax + FIG_VELOCITY + 4]
|
||||||
|
mulss xmm2, xmm11 ; xmm2 = vy_pixels
|
||||||
|
|
||||||
|
; length = sqrt(vx^2 + vy^2)
|
||||||
|
movss xmm3, xmm1
|
||||||
|
mulss xmm3, xmm1 ; xmm3 = vx^2
|
||||||
|
movss xmm4, xmm2
|
||||||
|
mulss xmm4, xmm4 ; xmm4 = vy^2
|
||||||
|
addss xmm3, xmm4 ; xmm3 = vx^2 + vy^2
|
||||||
|
sqrtss xmm3, xmm3 ; xmm3 = length (pixels)
|
||||||
|
|
||||||
|
; if length == 0 -> skip movement
|
||||||
|
ucomiss xmm3, [rel ZERO_CONST]
|
||||||
|
je .skip_move
|
||||||
|
|
||||||
|
; scalar = (speed * dt) / length
|
||||||
|
movss xmm4, xmm0 ; xmm4 = speed*dt
|
||||||
|
divss xmm4, xmm3 ; xmm4 = scalar
|
||||||
|
|
||||||
|
; dx = vel.x * scalar
|
||||||
|
movss xmm1, dword [rax + FIG_VELOCITY]
|
||||||
|
mulss xmm1, xmm4
|
||||||
|
movss xmm2, dword [rax + FIG_POSITION] ; position.x
|
||||||
|
addss xmm2, xmm1
|
||||||
|
movss dword [rax + FIG_POSITION], xmm2
|
||||||
|
|
||||||
|
; dy = vel.y * scalar
|
||||||
|
movss xmm1, dword [rax + FIG_VELOCITY + 4]
|
||||||
|
mulss xmm1, xmm4
|
||||||
|
movss xmm2, dword [rax + FIG_POSITION + 4]
|
||||||
|
addss xmm2, xmm1
|
||||||
|
movss dword [rax + FIG_POSITION + 4], xmm2
|
||||||
|
|
||||||
|
.skip_move:
|
||||||
|
|
||||||
|
; rotate: angle += angular_velocity * dt
|
||||||
|
movss xmm3, dword [rax + FIG_ANG_VEL]
|
||||||
|
mulss xmm3, [rel DT]
|
||||||
|
movss xmm4, dword [rax + FIG_ANGLE]
|
||||||
|
addss xmm4, xmm3
|
||||||
|
movss dword [rax + FIG_ANGLE], xmm4
|
||||||
|
|
||||||
|
; If circle -> call collision check helper
|
||||||
|
mov ecx, dword [rax + FIG_TYPE]
|
||||||
|
cmp ecx, 0
|
||||||
|
jne .no_collision_check
|
||||||
|
; pass pointer to window_draw_info (original rdi) in rdi
|
||||||
|
; rdi already has draw_info pointer
|
||||||
|
call figure_check_collision_circle
|
||||||
|
|
||||||
|
.no_collision_check:
|
||||||
|
|
||||||
|
leave
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
; helper: check collision for circle and reflect velocity & angular velocity
|
||||||
|
; rdi - pointer to struct window_draw_info
|
||||||
|
global figure_check_collision_circle
|
||||||
|
figure_check_collision_circle:
|
||||||
|
push rbx
|
||||||
|
; rdi -> window_draw_info
|
||||||
|
; rax -> figure_animation_info
|
||||||
|
mov rax, rdi
|
||||||
|
add rax, WDI_FIGURE
|
||||||
|
|
||||||
|
movss xmm0, dword [rax + FIG_POSITION] ; pos.x
|
||||||
|
movss xmm1, dword [rax + FIG_POSITION + 4] ; pos.y
|
||||||
|
|
||||||
|
movss xmm2, dword [rax + FIG_VELOCITY] ; vel.x
|
||||||
|
movss xmm3, dword [rax + FIG_VELOCITY + 4] ; vel.y
|
||||||
|
|
||||||
|
movss xmm4, dword [rax + FIG_ANG_VEL] ; angvel
|
||||||
|
|
||||||
|
; radius is stored in figure as pixel count (float)
|
||||||
|
; we keep positions normalized (0..1) so convert radius to normalized
|
||||||
|
; coordinates for x and y: r_x = radius / width, r_y = radius / height
|
||||||
|
movss xmm5, dword [rax + FIG_RADIUS] ; xmm5 = radius_pixels
|
||||||
|
|
||||||
|
; load width/height from window_draw_info
|
||||||
|
mov ebx, dword [rdi + WDI_WIDTH]
|
||||||
|
cvtsi2ss xmm10, ebx ; xmm10 = width
|
||||||
|
mov ebx, dword [rdi + WDI_HEIGHT]
|
||||||
|
cvtsi2ss xmm11, ebx ; xmm11 = height
|
||||||
|
|
||||||
|
; compute r_x = radius / width
|
||||||
|
movss xmm12, xmm5
|
||||||
|
divss xmm12, xmm10 ; xmm12 = r_x
|
||||||
|
|
||||||
|
; compute r_y = radius / height
|
||||||
|
movss xmm13, xmm5
|
||||||
|
divss xmm13, xmm11 ; xmm13 = r_y
|
||||||
|
|
||||||
|
; left edge: pos.x < r_x ?
|
||||||
|
ucomiss xmm0, xmm12
|
||||||
|
jae .check_right
|
||||||
|
; pos.x = radius
|
||||||
|
movss dword [rax + FIG_POSITION], xmm12
|
||||||
|
; vel.x = -vel.x
|
||||||
|
movss xmm6, xmm2
|
||||||
|
mulss xmm6, [rel NEG_ONE]
|
||||||
|
movss dword [rax + FIG_VELOCITY], xmm6
|
||||||
|
; invert angular velocity
|
||||||
|
movss xmm7, xmm4
|
||||||
|
mulss xmm7, [rel NEG_ONE]
|
||||||
|
movss dword [rax + FIG_ANG_VEL], xmm7
|
||||||
|
jmp .done_x
|
||||||
|
|
||||||
|
.check_right:
|
||||||
|
; pos.x + radius > 1 ?
|
||||||
|
movss xmm8, [rel ONE_CONST]
|
||||||
|
addss xmm8, xmm12 ; xmm8 = 1 + r_x
|
||||||
|
; Actually want pos.x + radius > 1 <=> pos.x > 1 - radius
|
||||||
|
; compute bound = 1 - r_x
|
||||||
|
movss xmm9, [rel ONE_CONST]
|
||||||
|
subss xmm9, xmm12
|
||||||
|
ucomiss xmm0, xmm9
|
||||||
|
jbe .done_x
|
||||||
|
; pos.x = 1 - radius
|
||||||
|
movss dword [rax + FIG_POSITION], xmm9
|
||||||
|
; vel.x = -vel.x
|
||||||
|
movss xmm6, xmm2
|
||||||
|
mulss xmm6, [rel NEG_ONE]
|
||||||
|
movss dword [rax + FIG_VELOCITY], xmm6
|
||||||
|
; invert angular velocity
|
||||||
|
movss xmm7, xmm4
|
||||||
|
mulss xmm7, [rel NEG_ONE]
|
||||||
|
movss dword [rax + FIG_ANG_VEL], xmm7
|
||||||
|
|
||||||
|
.done_x:
|
||||||
|
; check bottom / top boundaries for y
|
||||||
|
; bottom: pos.y < r_y
|
||||||
|
ucomiss xmm1, xmm13
|
||||||
|
jae .check_top2
|
||||||
|
movss dword [rax + FIG_POSITION + 4], xmm13
|
||||||
|
movss xmm6, xmm3
|
||||||
|
mulss xmm6, [rel NEG_ONE]
|
||||||
|
movss dword [rax + FIG_VELOCITY + 4], xmm6
|
||||||
|
; invert angular
|
||||||
|
movss xmm7, xmm4
|
||||||
|
mulss xmm7, [rel NEG_ONE]
|
||||||
|
movss dword [rax + FIG_ANG_VEL], xmm7
|
||||||
|
jmp .done_y
|
||||||
|
|
||||||
|
.check_top2:
|
||||||
|
; top: pos.y > 1 - r_y
|
||||||
|
movss xmm9, [rel ONE_CONST]
|
||||||
|
subss xmm9, xmm13
|
||||||
|
ucomiss xmm1, xmm9
|
||||||
|
jbe .done_y
|
||||||
|
movss dword [rax + FIG_POSITION + 4], xmm9
|
||||||
|
movss xmm6, xmm3
|
||||||
|
mulss xmm6, [rel NEG_ONE]
|
||||||
|
movss dword [rax + FIG_VELOCITY + 4], xmm6
|
||||||
|
movss xmm7, xmm4
|
||||||
|
mulss xmm7, [rel NEG_ONE]
|
||||||
|
movss dword [rax + FIG_ANG_VEL], xmm7
|
||||||
|
|
||||||
|
.done_y:
|
||||||
|
pop rbx
|
||||||
|
ret
|
||||||
|
|
||||||
|
section .rodata
|
||||||
|
DT: dd 0.1
|
||||||
|
NEG_ONE: dd -1.0
|
||||||
|
ONE_CONST: dd 1.0
|
||||||
|
ZERO_CONST: dd 0.0
|
||||||
0
wayland/src/figure-draw.asm
Normal file
0
wayland/src/figure-draw.asm
Normal file
110
wayland/src/figure-draw.c
Normal file
110
wayland/src/figure-draw.c
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
#include <math.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "figure-draw.h"
|
||||||
|
|
||||||
|
/* C implementation of the drawing routine. The .asm file simply forwards to this
|
||||||
|
* function so we keep the symbol present in an assembly file. */
|
||||||
|
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;
|
||||||
|
|
||||||
|
int w = draw_info->width;
|
||||||
|
int h = draw_info->height;
|
||||||
|
uint32_t *pixels = (uint32_t *)draw_info->data;
|
||||||
|
|
||||||
|
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;
|
||||||
|
/* `fig.radius` is in pixels now; use it directly. */
|
||||||
|
float r = fig.radius;
|
||||||
|
float r2 = r * r;
|
||||||
|
float border = border_thickness;
|
||||||
|
if (border < 0.0f) border = 0.0f;
|
||||||
|
|
||||||
|
/* bounding box */
|
||||||
|
int minx = (int)floorf(cx - r);
|
||||||
|
int maxx = (int)ceilf(cx + r);
|
||||||
|
int miny = (int)floorf(cy - r);
|
||||||
|
int maxy = (int)ceilf(cy + r);
|
||||||
|
/* make sure we don't go out of bounds */
|
||||||
|
if (miny < 0) miny = 0;
|
||||||
|
if (minx < 0) minx = 0;
|
||||||
|
if (maxy >= h) maxy = h - 1;
|
||||||
|
if (maxx >= w) maxx = w - 1;
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
38
wayland/src/input-handle.c
Normal file
38
wayland/src/input-handle.c
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#include "input-handle.h"
|
||||||
|
#include "wayland-runtime.h"
|
||||||
|
|
||||||
|
void keyboard_key_handle(xkb_keycode_t kc, xkb_keysym_t ks, enum keyboard_key_state state, struct wayland_window *window)
|
||||||
|
{
|
||||||
|
if (ks != XKB_KEY_NoSymbol)
|
||||||
|
{
|
||||||
|
char buf[64];
|
||||||
|
int n = xkb_keysym_to_utf8(ks, buf, sizeof(buf));
|
||||||
|
|
||||||
|
if (n > 0)
|
||||||
|
printf("keyboard: symbol '%s' (keysym 0x%x) on surface:%p\n", buf, ks, window);
|
||||||
|
else
|
||||||
|
printf("keyboard: keysym 0x%x (no UTF-8 representation)\n", ks);
|
||||||
|
|
||||||
|
if(state == KEYBOARD_KEY_STATE_PRESSED)
|
||||||
|
{
|
||||||
|
switch (ks)
|
||||||
|
{
|
||||||
|
case XKB_KEY_Return:
|
||||||
|
run_window();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '1':
|
||||||
|
window->draw_info.figure.type = FIGURE_CIRCLE;
|
||||||
|
break;
|
||||||
|
case '2':
|
||||||
|
window->draw_info.figure.type = FIGURE_TRIANGLE;
|
||||||
|
break;
|
||||||
|
case '3':
|
||||||
|
window->draw_info.figure.type = FIGURE_SQUARE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
#include "input.h"
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
#include <wayland-client.h>
|
#include <wayland-client.h>
|
||||||
@@ -7,12 +6,17 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "input.h"
|
||||||
|
#include "input-handle.h"
|
||||||
|
#include "wayland-runtime.h"
|
||||||
|
#include "window.h"
|
||||||
|
|
||||||
static struct wl_seat *seat = NULL;
|
static struct wl_seat *seat = NULL;
|
||||||
static struct wl_keyboard *keyboard = NULL;
|
static struct wl_keyboard *keyboard = NULL;
|
||||||
static struct xkb_context *xkb_ctx = NULL;
|
static struct xkb_context *xkb_ctx = NULL;
|
||||||
static struct xkb_keymap *xkb_keymap = NULL;
|
static struct xkb_keymap *xkb_keymap = NULL;
|
||||||
static struct xkb_state *xkb_state = NULL;
|
static struct xkb_state *xkb_state = NULL;
|
||||||
static struct wl_surface *keyboard_focus = NULL;
|
static struct wayland_window* focused_window = NULL;
|
||||||
|
|
||||||
/* Обработчики клавиатуры */
|
/* Обработчики клавиатуры */
|
||||||
static void keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size)
|
static void keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size)
|
||||||
@@ -68,40 +72,29 @@ static void keyboard_enter(void *data, struct wl_keyboard *keyboard, uint32_t se
|
|||||||
{
|
{
|
||||||
printf("keyboard: enter serial=%u surface=%p\n", serial, surface);
|
printf("keyboard: enter serial=%u surface=%p\n", serial, surface);
|
||||||
/* Сохраняем поверхность, которая получила фокус клавиатуры */
|
/* Сохраняем поверхность, которая получила фокус клавиатуры */
|
||||||
keyboard_focus = 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);
|
printf("keyboard: leave serial=%u surface=%p\n", serial, surface);
|
||||||
/* Если уходим с фокусной поверхности — сбросить фокус */
|
/* Если уходим с фокусной поверхности — сбросить фокус */
|
||||||
if (keyboard_focus == surface)
|
if (focused_window && focused_window->wl_surface == surface)
|
||||||
keyboard_focus = NULL;
|
focused_window = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
|
static void keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
|
||||||
{
|
{
|
||||||
const char *s = (state == WL_KEYBOARD_KEY_STATE_PRESSED) ? "PRESSED"
|
enum keyboard_key_state key_state = (state == WL_KEYBOARD_KEY_STATE_PRESSED) ? KEYBOARD_KEY_STATE_PRESSED
|
||||||
: (state == WL_KEYBOARD_KEY_STATE_RELEASED) ? "RELEASED"
|
: (state == WL_KEYBOARD_KEY_STATE_REPEATED) ? KEYBOARD_KEY_STATE_REPEATED
|
||||||
: (state == WL_KEYBOARD_KEY_STATE_REPEATED) ? "REPEATED"
|
: KEYBOARD_KEY_STATE_RELEASED;
|
||||||
: "Unknown";
|
|
||||||
/* Отладочный вывод удалён */
|
|
||||||
|
|
||||||
if (xkb_state && keyboard_focus)
|
if (xkb_state && focused_window)
|
||||||
{
|
{
|
||||||
xkb_keycode_t kc = (xkb_keycode_t)key + 8;
|
xkb_keycode_t kc = (xkb_keycode_t)key + 8;
|
||||||
xkb_keysym_t ks = xkb_state_key_get_one_sym(xkb_state, kc);
|
xkb_keysym_t ks = xkb_state_key_get_one_sym(xkb_state, kc);
|
||||||
if (ks != XKB_KEY_NoSymbol)
|
|
||||||
{
|
keyboard_key_handle(kc, ks, key_state, focused_window);
|
||||||
char buf[64];
|
|
||||||
int n = xkb_keysym_to_utf8(ks, buf, sizeof(buf));
|
|
||||||
if (ks == XKB_KEY_Return)
|
|
||||||
sprintf(buf, "Return");
|
|
||||||
if (n > 0)
|
|
||||||
printf("keyboard: symbol '%s' (keysym 0x%x) on surface:%p\n", buf, ks, keyboard_focus);
|
|
||||||
else
|
|
||||||
printf("keyboard: keysym 0x%x (no UTF-8 representation)\n", ks);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,10 +200,5 @@ void input_cleanup(void)
|
|||||||
xkb_context_unref(xkb_ctx);
|
xkb_context_unref(xkb_ctx);
|
||||||
xkb_ctx = NULL;
|
xkb_ctx = NULL;
|
||||||
}
|
}
|
||||||
keyboard_focus = NULL;
|
focused_window = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
struct wl_surface *input_get_keyboard_focus(void)
|
|
||||||
{
|
|
||||||
return keyboard_focus;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,3 +218,4 @@ struct xdg_wm_base *registry_get_xdg_wm_base(void)
|
|||||||
{
|
{
|
||||||
return global_wm_base;
|
return global_wm_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,17 +5,20 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <wayland-client.h>
|
#include <wayland-client.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "registry.h"
|
#include "registry.h"
|
||||||
#include "wayland_runtime.h"
|
#include "wayland-runtime.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
|
#include "figure-animate.h"
|
||||||
|
|
||||||
#define MAX_WINDOW_THREADS 128
|
#define MAX_WINDOW_THREADS 128
|
||||||
|
|
||||||
struct window_thread_slot
|
struct window_thread_slot
|
||||||
{
|
{
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
|
pthread_t aux_thread;
|
||||||
int active;
|
int active;
|
||||||
struct wl_event_queue *queue;
|
struct wl_event_queue *queue;
|
||||||
struct wayland_window window;
|
struct wayland_window window;
|
||||||
@@ -38,6 +41,22 @@ static void signal_thread_exit(struct window_thread_slot *slot)
|
|||||||
pthread_mutex_unlock(&g_thread_lock);
|
pthread_mutex_unlock(&g_thread_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void *window_aux_loop(void *arg)
|
||||||
|
{
|
||||||
|
struct window_thread_slot *slot = arg;
|
||||||
|
struct window_draw_info *draw_info = &slot->window.draw_info;
|
||||||
|
while (!atomic_load(&g_shutdown) && !window_should_close(&slot->window))
|
||||||
|
{
|
||||||
|
/* На время обновления позиции фигуры локаем мутекс */
|
||||||
|
pthread_mutex_lock(&draw_info->figure_mutex);
|
||||||
|
figure_animation_step(draw_info);
|
||||||
|
pthread_mutex_unlock(&draw_info->figure_mutex);
|
||||||
|
|
||||||
|
usleep(30 * 1000);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void *window_thread_main(void *arg)
|
static void *window_thread_main(void *arg)
|
||||||
{
|
{
|
||||||
struct window_thread_slot *slot = arg;
|
struct window_thread_slot *slot = arg;
|
||||||
@@ -50,16 +69,20 @@ static void *window_thread_main(void *arg)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (window_init(g_display, slot->queue, &slot->window) < 0)
|
if (window_init(g_display, slot->queue, &slot->window) < 0)
|
||||||
{
|
{
|
||||||
input_cleanup();
|
|
||||||
wl_event_queue_destroy(slot->queue);
|
wl_event_queue_destroy(slot->queue);
|
||||||
slot->queue = NULL;
|
slot->queue = NULL;
|
||||||
signal_thread_exit(slot);
|
signal_thread_exit(slot);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Запуск вспомогательного потока, который пока просто крутится с паузой 100 ms.
|
||||||
|
* Поток завершится, как только окно будет помечено как закрыто. */
|
||||||
|
int aux_res = pthread_create(&slot->aux_thread, NULL, window_aux_loop, slot);
|
||||||
|
if (aux_res == 0)
|
||||||
|
pthread_detach(slot->aux_thread);
|
||||||
|
|
||||||
while (!atomic_load(&g_shutdown) && !window_should_close(&slot->window))
|
while (!atomic_load(&g_shutdown) && !window_should_close(&slot->window))
|
||||||
{
|
{
|
||||||
int dispatch = wl_display_dispatch_queue(g_display, slot->queue);
|
int dispatch = wl_display_dispatch_queue(g_display, slot->queue);
|
||||||
@@ -73,7 +96,6 @@ static void *window_thread_main(void *arg)
|
|||||||
}
|
}
|
||||||
printf("Window #%d closed\n", slot->window.id);
|
printf("Window #%d closed\n", slot->window.id);
|
||||||
|
|
||||||
input_cleanup();
|
|
||||||
window_destroy(&slot->window);
|
window_destroy(&slot->window);
|
||||||
|
|
||||||
if (slot->queue)
|
if (slot->queue)
|
||||||
@@ -177,3 +199,11 @@ void destroy_wayland(void)
|
|||||||
g_initialized = 0;
|
g_initialized = 0;
|
||||||
atomic_store(&g_shutdown, 0);
|
atomic_store(&g_shutdown, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct wayland_window *get_window_by_surface(struct wl_surface *surf)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_WINDOW_THREADS; i++)
|
||||||
|
if (g_slots[i].window.wl_surface == surf)
|
||||||
|
return &g_slots[i].window;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "registry.h"
|
#include "registry.h"
|
||||||
|
#include "figure-draw.h"
|
||||||
#include "xdg-shell-client-protocol.h"
|
#include "xdg-shell-client-protocol.h"
|
||||||
#include <wayland-client.h>
|
#include <wayland-client.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@@ -44,8 +45,9 @@ static void destroy_frame_callback(struct wayland_window *win)
|
|||||||
|
|
||||||
static void resize_canvas(struct wayland_window *win)
|
static void resize_canvas(struct wayland_window *win)
|
||||||
{
|
{
|
||||||
size_t stride = win->width * 4;
|
struct window_draw_info *draw_info = &win->draw_info;
|
||||||
size_t size = stride * win->height;
|
size_t stride = draw_info->width * 4;
|
||||||
|
size_t size = stride * draw_info->height;
|
||||||
int32_t fd = alloc_shm(size);
|
int32_t fd = alloc_shm(size);
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
return;
|
return;
|
||||||
@@ -64,42 +66,77 @@ static void resize_canvas(struct wayland_window *win)
|
|||||||
}
|
}
|
||||||
struct wl_shm *shm = registry_get_shm();
|
struct wl_shm *shm = registry_get_shm();
|
||||||
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size);
|
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size);
|
||||||
win->buffer = wl_shm_pool_create_buffer(pool, 0, win->width, win->height, stride, WL_SHM_FORMAT_ARGB8888);
|
win->buffer = wl_shm_pool_create_buffer(pool, 0, draw_info->width, draw_info->height, stride, WL_SHM_FORMAT_ARGB8888);
|
||||||
wl_shm_pool_destroy(pool);
|
wl_shm_pool_destroy(pool);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
win->data = map;
|
draw_info->data = map;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void resize_new(struct wayland_window *win, int32_t w, int32_t h)
|
static void resize_new(struct wayland_window *win, int32_t w, int32_t h)
|
||||||
{
|
{
|
||||||
if (!w || !h)
|
if (!w || !h)
|
||||||
return;
|
return;
|
||||||
if (win->width != w || win->height != h)
|
struct window_draw_info *draw_info = &win->draw_info;
|
||||||
|
|
||||||
|
if (draw_info->width != w || draw_info->height != h)
|
||||||
{
|
{
|
||||||
if (win->data)
|
if (draw_info->data)
|
||||||
{
|
{
|
||||||
munmap(win->data, win->width * win->height * 4);
|
munmap(draw_info->data, draw_info->width * draw_info->height * 4);
|
||||||
win->data = NULL;
|
draw_info->data = NULL;
|
||||||
}
|
}
|
||||||
win->width = w;
|
draw_info->width = w;
|
||||||
win->height = h;
|
draw_info->height = h;
|
||||||
resize_canvas(win);
|
resize_canvas(win);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw(struct wayland_window *win)
|
static void draw(struct wayland_window *win)
|
||||||
{
|
{
|
||||||
size_t stride = win->width * 4;
|
struct window_draw_info *draw_info = &win->draw_info;
|
||||||
size_t size = stride * win->height;
|
|
||||||
|
|
||||||
if (!win->data || !win->buffer)
|
size_t stride = draw_info->width * 4;
|
||||||
|
size_t size = stride * draw_info->height;
|
||||||
|
|
||||||
|
if (!draw_info->data || !win->buffer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memset(win->data, win->color++, size);
|
// Залочиться, чтобы операции обновления позиции фигуры происходили атомарно
|
||||||
|
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:
|
||||||
|
color = 0xFF00FF00;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *bytes = (uint8_t *)draw_info->data;
|
||||||
|
for (int32_t y = 0; y < (int32_t)draw_info->height; ++y)
|
||||||
|
{
|
||||||
|
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 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw figure into buffer. border thickness in pixels = 3.0f */
|
||||||
|
figure_draw(&win->draw_info, 3.0f, 0xFFFFFFFF, color);
|
||||||
|
|
||||||
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, win->width, win->height);
|
wl_surface_damage_buffer(win->wl_surface, 0, 0, draw_info->width, draw_info->height);
|
||||||
wl_surface_commit(win->wl_surface);
|
wl_surface_commit(win->wl_surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +144,7 @@ static void xdg_surface_conf(void *data, struct xdg_surface *xdg_surface_local,
|
|||||||
{
|
{
|
||||||
xdg_surface_ack_configure(xdg_surface_local, serial);
|
xdg_surface_ack_configure(xdg_surface_local, serial);
|
||||||
struct wayland_window *win = data;
|
struct wayland_window *win = data;
|
||||||
if (!win->data)
|
if (!win->draw_info.data)
|
||||||
resize_canvas(win);
|
resize_canvas(win);
|
||||||
|
|
||||||
draw(win);
|
draw(win);
|
||||||
@@ -129,12 +166,17 @@ static void xdg_toplevel_cls(void *data, struct xdg_toplevel *xdg_top)
|
|||||||
|
|
||||||
static void xdg_toplevel_bounds(void *data, struct xdg_toplevel *xdg_top, int32_t w, int32_t h)
|
static void xdg_toplevel_bounds(void *data, struct xdg_toplevel *xdg_top, int32_t w, int32_t h)
|
||||||
{
|
{
|
||||||
(void)data; (void)xdg_top; (void)w; (void)h;
|
(void)data;
|
||||||
|
(void)xdg_top;
|
||||||
|
(void)w;
|
||||||
|
(void)h;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xdg_toplevel_wm_caps(void *data, struct xdg_toplevel *xdg_top, struct wl_array *caps)
|
static void xdg_toplevel_wm_caps(void *data, struct xdg_toplevel *xdg_top, struct wl_array *caps)
|
||||||
{
|
{
|
||||||
(void)data; (void)xdg_top; (void)caps;
|
(void)data;
|
||||||
|
(void)xdg_top;
|
||||||
|
(void)caps;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct wl_callback_listener callback_listener;
|
static struct wl_callback_listener callback_listener;
|
||||||
@@ -157,19 +199,15 @@ static void frame_new(void *data, struct wl_callback *cb, uint32_t _)
|
|||||||
draw(win);
|
draw(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct wl_callback_listener callback_listener = {
|
static struct wl_callback_listener callback_listener = {
|
||||||
.done = frame_new
|
.done = frame_new};
|
||||||
};
|
|
||||||
static struct xdg_surface_listener surface_listener = {
|
static struct xdg_surface_listener surface_listener = {
|
||||||
.configure = xdg_surface_conf
|
.configure = xdg_surface_conf};
|
||||||
};
|
|
||||||
static struct xdg_toplevel_listener top_listener = {
|
static struct xdg_toplevel_listener top_listener = {
|
||||||
.configure = xdg_toplevel_conf,
|
.configure = xdg_toplevel_conf,
|
||||||
.close = xdg_toplevel_cls,
|
.close = xdg_toplevel_cls,
|
||||||
.configure_bounds = xdg_toplevel_bounds,
|
.configure_bounds = xdg_toplevel_bounds,
|
||||||
.wm_capabilities = xdg_toplevel_wm_caps
|
.wm_capabilities = xdg_toplevel_wm_caps};
|
||||||
};
|
|
||||||
|
|
||||||
int window_init(struct wl_display *display, struct wl_event_queue *queue, struct wayland_window *win)
|
int window_init(struct wl_display *display, struct wl_event_queue *queue, struct wayland_window *win)
|
||||||
{
|
{
|
||||||
@@ -197,22 +235,39 @@ int window_init(struct wl_display *display, struct wl_event_queue *queue, struct
|
|||||||
if (win->xdg_toplevel && queue)
|
if (win->xdg_toplevel && queue)
|
||||||
wl_proxy_set_queue((struct wl_proxy *)win->xdg_toplevel, queue);
|
wl_proxy_set_queue((struct wl_proxy *)win->xdg_toplevel, queue);
|
||||||
|
|
||||||
|
|
||||||
xdg_toplevel_add_listener(win->xdg_toplevel, &top_listener, win);
|
xdg_toplevel_add_listener(win->xdg_toplevel, &top_listener, win);
|
||||||
|
|
||||||
wl_surface_commit(win->wl_surface);
|
wl_surface_commit(win->wl_surface);
|
||||||
|
|
||||||
/* wm_base — глобальный объект, listener в registry */
|
struct window_draw_info *draw_info = &win->draw_info;
|
||||||
|
|
||||||
/* Инициализация состояния */
|
/* Инициализация состояния */
|
||||||
win->id = id++;
|
win->id = id++;
|
||||||
win->width = 400;
|
draw_info->width = 400;
|
||||||
win->height = 250;
|
draw_info->height = 250;
|
||||||
win->data = NULL;
|
draw_info->data = NULL;
|
||||||
|
|
||||||
|
/* Default animation state */
|
||||||
|
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.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 */
|
||||||
|
|
||||||
win->buffer = NULL;
|
win->buffer = NULL;
|
||||||
win->frame_callback = NULL;
|
win->frame_callback = NULL;
|
||||||
win->need_close = 0;
|
win->need_close = 0;
|
||||||
win->color = 0;
|
/* Мьютекс нужен для атомарного обращения к структуре фигуры */
|
||||||
|
if (pthread_mutex_init(&win->draw_info.figure_mutex, NULL) != 0)
|
||||||
|
{
|
||||||
|
/* if mutex init failed — cleanup and return error */
|
||||||
|
window_destroy(win);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
xdg_toplevel_set_app_id(win->xdg_toplevel, "my-wayland-window");
|
xdg_toplevel_set_app_id(win->xdg_toplevel, "my-wayland-window");
|
||||||
xdg_toplevel_set_title(win->xdg_toplevel, "Custom Title");
|
xdg_toplevel_set_title(win->xdg_toplevel, "Custom Title");
|
||||||
@@ -236,6 +291,8 @@ void window_destroy(struct wayland_window *win)
|
|||||||
xdg_surface_destroy(win->xdg_surface);
|
xdg_surface_destroy(win->xdg_surface);
|
||||||
if (win->wl_surface)
|
if (win->wl_surface)
|
||||||
wl_surface_destroy(win->wl_surface);
|
wl_surface_destroy(win->wl_surface);
|
||||||
if (win->data)
|
if (win->draw_info.data)
|
||||||
munmap(win->data, win->width * win->height * 4);
|
munmap(win->draw_info.data, win->draw_info.width * win->draw_info.height * 4);
|
||||||
|
/* destroy mutex if initialized */
|
||||||
|
pthread_mutex_destroy(&win->draw_info.figure_mutex);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user