- PVSM.RU - https://www.pvsm.ru -
Вот решил поведать о библиотеке, которую написал недавно. Возможно кому-то и пригодится.
Это 2D framework на языке Rust для рендеринга непосредственно в Linux Frame Buffer /dev/fb0.
Задача была — на Raspberry Pi выводить на экран / телевизор простые 2D сцены. Raspberry Pi работает под управление собранного при помощи YoctoProject custom headless Linux. Window Managers отсутствуют, так же, как и OpenGL. Остается только Frame Buffer.
В случае с Frame Buffer обрабатывать приходится каждый пиксель. Так как я для Raspberry Pi пишу в основном на GoLang, то решил написать библиотеку на Go. Очень быстро понял что Go не подходит мне по производительности. Массивные операции с памятью он не смог выполнить за разумное время.
Тогда я обратил внимание на Rust, который выполнял похожие тесты намного быстрее.
Итак, библиотека разработана на Rust. Так как, это мой первый проект на Rust, сильно не пинайте, но комментарии приветствуется.
Как в любой 2D библиотеке, здесь есть две главные сущности: сцены и ноды.
Сцена — это контейнер для визуальных объектов. Нод — это виртуальный объект, наделенный определенными свойствами, такими как местоположение, размер и т.д. Ноды могут быть вложенными.
Каждый нод содержит визуальный объект, так называемый спрайт. Спрайты бывают нескольких видов. Сейчас поддерживаются спрайты типа RectSprite, TextureSprite, TextSprite.
RectSprite — прямоугольник определенного цвета. RectSprite без цвета обычно используется для группировки других дочерних нодов. RectSprite соответствует XML тегу <box>
TextureSprite — объект для рендеринга картинки. На данный момент поддерживается только PNG (RGBA). TextureSprite соответствует XML тегу <image>
ТехтSprite — объект для рендеринга одной строки текста выбранным шрифтом и размером. Есть автоматическая поддержка RTL. ТехтSprite соответствует XML тегу <text>
В дополнении к атрибутам местоположения и размера каждый нод имеет атрибуты gravity и anchor. Это помогает точно расположить объект внутри другого объекта. Все атрибуты связанные с размером и местоположением задаются в процентах относительно родительского нода. Такой подход позволяет достичь наилучшего масштабирования на экранах разного размера и пропорций.
Создать сцену возможно, как программным способом, так и создать описывающий сцену xml файл.
Программный способ создания и запуска сцены.
let mut fb = fb2d::screen_writer_for_framebuffer("/dev/fb0")?;
fb2d::set_graphics_mode();
let mut scene = fb2d::scene::Scene::new();
let background_sprite = RectSprite::new();
let background_node = Node::new_rect_node(FLOAT_RECT_FULL, background_sprite);
let sprite1 = RectSprite::new();
let mut node1 = Node::new_rect_node(
FloatRect {
pos: FLOAT_POS_ZERO,
size: FLOAT_SIZE_HALF,
},
sprite1,
);
node1.anchor_point = ANCHOR_POINT_TOP_LEFT;
let sprite2 = TextureSprite::new_for_texture("image.png");
let mut node2 = Node::new_texture_node(
FloatRect {
pos: FLOAT_POS_ZERO,
size: FloatSize {
width: 0.7,
height: 0.7,
},
},
sprite2,
);
node2.anchor_point = ANCHOR_POINT_CENTER;
let mut sprite3 = TextSprite::new();
sprite3.text = String::from("Hello, World !!!");
sprite3.gravity = GRAVITY_CENTER;
sprite3.height = 0.2;
let node3 = Node::new_text_node(
FloatRect {
pos: FLOAT_POS_ZERO,
size: FLOAT_SIZE_FULL,
},
sprite3,
);
scene.add_node(node2, node1.key);
scene.add_node(node1, background_node.key);
scene.add_node(node3, background_node.key);
scene.set_root_node(background_node);
scene.writer = Some(Box::new(fb));
scene.run();
<scene color="#ffa500">
<box pos="0" size="95% 95%" anchor-point="0.5 0" color="#F0C0C0C0">
<text pos="0 -40%" size="100% 10%" anchor-point="0.5 0" height="100%" text="שלום Hello Привет" font="Times New Roman.ttf" color="red"/>
</box>
<box pos="0%" size="25% 25%" anchor-point="0 1" color="olive" alpha="0.5">
<image pos="0" size="100% 100%" anchor-point="0 1" image="image1.png" />
</box>
</scene>
Сцена создается указанием на каталог или zip файл, содержащий scene.xml. Зависимые файлы картинок и шрифтов должны находится в этом каталоге или zip файле.
match fb2d::scene::Scene::new_from_bundle("assets/scene1") {
Ok(mut scene) => {
let mut fb = fb2d::screen_writer_for_framebuffer("/dev/fb0")?;
fb2d::set_graphics_mode();
scene.writer = Some(Box::new(fb));
scene.run();
}
Err(e) => eprintln!("Error: {:?}", e),
}
Любая помощь (Contribution) приветствуется. Есть много работы по оптимизации рендеринга, и добавлению новых возможностей, таких как анимация.
Автор: mark2b
Источник [2]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/linux/290814
Ссылки в тексте:
[1] GitHub репозиторий.: https://github.com/mark2b/fb2d
[2] Источник: https://habr.com/post/421707/?utm_campaign=421707
Нажмите здесь для печати.