Это самый простой способ создания программ для Р-ФОН.

Традиционно программы для мобильных телефонов собираются в специализированных средах разработки, включающих эмуляторы.

Уникальность телефона Р-ФОН заключается в том, что на нём можно сразу запускать программы, работающие на компьютерах с процессорами ARM и операционными системами «РОСА Фреш» и «РОСА Хром». Это существенно облегчает разработку. И написание, и запуск, и отладку, и работу в программе можно сначала обкатать на компьютере, и лишь на последнем этапе скопировать программу на телефон и протестировать уже на нём.

Естественно, для работы со специфическими для телефона компонентами, такими как GPS-приёмник и GSM-модем, требуется отдельный подход. Но для создания пользовательского интерфейса и, например, кода для работы по сети - компьютер более чем удобен.

Какой же компьютер с архитектурой процессора ARM подойдёт? Неплох компьютер на процессоре Байкал-М, но он дороговат, и его ещё нужно поискать. А вот компьютер на основе Raspberry Pi можно назвать народным. Подойдёт 64-разрядный, то есть, начиная с версии Raspberry Pi 4. Мне достался Pi 400, и всё описанное ниже было опробовано именно на нём.

Ниже описан мой опыт написания простых тестовых программ для Р-ФОН, использующих различные графические инструментарии (Qt, PyQt, GTK3, GTK4, SDL2).

Содержание

1 Запись образа ОС «РОСА Фреш» для Raspberry Pi

2 Дополнительные шаги после запуска ОС

3 Как собрать образ для Raspberry Pi самостоятельно

4 Общие замечания к написанию программ

5 Программы, использующие Qt

6 Программы, использующие PyQt

7 Программы, использующие GTK 3

8 Программы, использующие GTK 4

9 Программы, использующие SDL2

10 Заключение

1. Запись образа ОС «РОСА Фреш» для Raspberry Pi

 Для начала запишем на SD-карту образ диска с операционной системой РОСА Фреш 12.5.1 для Raspberry Pi.

Почему именно версия 12.5.1, когда уже доступна версия 13?

Версия 12.5.1 имеет репозитарий 2021.1, совместимый с репозитарием Р-ФОН (информация на декабрь 2025 года).

Готовые образы я выложил вот сюда:

сборка с графическим интерфейсом Plasma5:
https://disk.360.yandex.ru/d/SxXqB1TYiqsphQ

минимальная сборка:
https://disk.360.yandex.ru/d/-OZE4QknLDEs7g

На моей Raspberry Pi с 4Гб оперативной памяти отлично работает сборка с графическим интерфейсом. Впрочем, тяжелые задачи я на ней не запускал, только сборку небольших тестовых программ.

Я записывал образы на SD-карту командой dd (под Linux). Устройство для чтения SD-карт у меня виделось как /dev/mmcblk0:

$ unxz rosapi-12.5.1-plasma5.raw.xz

$ sudo dd if=rosapi-12.5.1-plasma5.raw of=/dev/mmcblk0 bs=1M status=progress

$ sync

2. дополнительные шаги после запуска ОС

После запуска образа на Raspberry Pi следует выполнить дополнительные шаги
( пароль пользователя root: root ):

2.1. Для работы WiFi на Raspberry Pi 400, нужно скопировать в каталог /lib/firmware/brcm установленного образа операционной системы файлы:

  • brcmfmac43456-sdio.raspberrypi,400.bin

  • brcmfmac43456-sdio.raspberrypi,400.clm_blob

  • brcmfmac43456-sdio.raspberrypi,400.txt

Файлы качать вот отсюда:

https://github.com/bsdkurt/brcm-supplemental

 

2.2. Отключить засыпание (Suspend). Ибо заснувший Raspberry Pi разбудить невозможно. По крайней мере, мне это не удавалось. Пришлось для оживления отключать/включать питание.

2.3. Добавить обычного пользователя, внести его в группу wheel, чтобы он смог выполнять команду “sudo” . Также браузер и регулировка громкости звука не работали у меня в сессии пользователя root.

 # useradd user

# passwd user

# usermod -aG wheel user

2.4. Поменять пароль у пользователя root

# passwd root

2.5. При входе в графическую оболочку выбрать Wayland вместо X11

2.6. Увеличить корневую файловую систему (сборка для версии 13 сама расширят файловую систему при первом запуске, но в 12.5.1 я это до ума не довёл, поэтому – руками). Пример ниже:

Пример увеличения корневой файловой системы

[mikhail@raspberrypi ~]$ sudo parted /dev/mmcblk0

[sudo] password for mikhail:

GNU Parted 3.5

Using /dev/mmcblk0

Welcome to GNU Parted! Type 'help' to view a list of commands.

(parted) print

Warning: Not all of the space available to /dev/mmcblk0 appears to be used, you can fix the GPT to use all of the space

(an extra 17208928 blocks) or continue with the current setting?

Fix/Ignore? f

Model: SD SC16G (sd/mmc)

Disk /dev/mmcblk0: 15.9GB

Sector size (logical/physical): 512B/512B

Partition Table: gpt

Disk Flags:

 

Number  Start   End     Size    File system  Name    Flags

 1      1049kB  269MB   268MB   fat32        bootfs  boot, esp

 2      269MB   7121MB  6851MB  ext4         rootfs

 

(parted) resizepart 2 15000

Warning: Partition /dev/mmcblk0p2 is being used. Are you sure you want to continue?

Yes/No? Y

(parted) q

Information: You may need to update /etc/fstab.

 

[mikhail@raspberrypi ~]$ sudo resize2fs /dev/mmcblk0p2

resize2fs 1.46.6 (1-Feb-2023)

Filesystem at /dev/mmcblk0p2 is mounted on /; on-line resizing required

old_desc_blocks = 1, new_desc_blocks = 2

The filesystem on /dev/mmcblk0p2 is now 3596317 (4k) blocks long.

3. Как собрать образ для Raspberry Pi самостоятельно

Для тех, кто хочет собрать образ самостоятельно, под катом привожу инструкцию по сборке.

Инструкция по сборке образа операционной системы РОСА Фреш 12.5.1 для Raspberry Pi

3.1 Установите на компьютер ( x86 ) операционную систему РОСА Фреш 13. Дистрибутивы лежат вот здесь: https://rosa.ru/rosa-linux-download-links/

Я использовал сборку с графическим интерфейсом Plasma 6, но вы можете выбрать другой интерфейс по своему вкусу.

При разбиении диска убедитесь, что после установки у вас останется по 20 Гбайт свободного места в корневой файловой системе, в «/home» и в «/var/tmp».

Сразу после установки обновите систему.

3.2 Установите набор файлов конфигурации для создания образов операционной системы для различных платформ «image-builder». Качается вот отсюда, там же есть инструкция по установке необходимых ему пакетов:

https://github.com/rosalinux/image-builder

 3.3 Скопируйте файл /etc/pki/rpm-gpg/RPM-GPG-KEY-ROSA в каталог /usr/share/distribution-gpg-keys/

sudo cp /etc/pki/rpm-gpg/RPM-GPG-KEY-ROSA /usr/share/distribution-gpg-keys/

3.4 Перейдите в каталог image-builder-main/device/raspberry/rpi5

Для создания образа диска с установленной минимальной операционной системой версии 12.5.1 подставьте файл mkosi.conf вот отсюда: https://disk.360.yandex.ru/d/uj_4IyvKpfOxkQ

Для создания образа диска с установленной операционной системы версии 12.5.1 и графической оболочкой Plasma5 (впрочем, минимально наполненной) подставьте файл mkosi.conf вот отсюда: https://disk.360.yandex.ru/d/cPfQHdNrZpX82g

3.5 Запустите команду:

$ sudo mkosi --force

Во время сборки могут появляться отдельные незначительные ошибки, связанные с тем, что собирается предыдущая версия операционной системы, на которую скрипт не был изначально рассчитан. Но по окончании сборки образа вы должны увидеть сообщение вида:

‣  /home/mikhail/image-builder-main/device/raspberry/rpi5/rce.raw size is 6.5G, consumes 6.4G.

3.6. Необходимо отключить в свойствах файловой системы образа функцию orphan_file (она же FEATURE_C12).

Примонтируйте образ (файл raw) как устройство:

$ sudo losetup -P /dev/loop0 rosapi.raw

Убедитесь, что появились устройства для обоих разделов на образе диска:

$ lsblk

NAME      MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS

loop0       7:0    0     1G  0 loop

├─loop0p1 259:0    0   256M  0 part

└─loop0p2 259:1    0 815,9M  0 part

 

Отключите функцию orphan_file на большем (втором) разделе:

$ sudo tune2fs -O ^orphan_file /dev/loop0p2

tune2fs 1.47.2 (1-Jan-2025)

 

( tune2fs сделает работу молча, только напишет свою версию, да код возврата укажет на то, что она всё сделала успешно)

Размонтируйте образ диска:

$ sudo losetup -d /dev/loop0


4. Общие замечания к написанию программ.

4.1 Несовпадение разрешений экрана

Разрешение экрана, подключенного к Raspberry Pi и дисплея Р-ФОН, скорее всего, у вас будут существенно различаться.

У Р-Фон стандартное разрешение: 1080 x 2412

Некоторые графические инструментарии (например, Qt), сами подстраиваются под разрешение дисплея, и можно использовать один и тот же код как для компьютера, так и для телефона.

 Другие же (например, GTK) не масштабируют самостоятельно элементы интерфейса, и нужно менять ход исполнения программы в зависимости от того, с каким разрешением она будет работать.

 Разрешение экрана иногда лучше знать до того, как инициализируется графический инструментарий. Для этого можно воспользоваться библиотекой libdrm.

Пример кода программы, добывающей разрешение дисплея
// позаимствовано из https://twosixtech.com/blog/learning-libdrm/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <drm.h>
#include <drm_mode.h>
#include <xf86drm.h>
#include <xf86drmMode.h>

char *device_path="/dev/dri/card0";

int main()
{
	int result=0;
	
	int fd = open(device_path, O_RDONLY);
    	if (fd < 0) 
	{
		printf ("Не удалось открыть файл %s на чтение\n", device_path);
        	return -1;
    	}

	drmModeRes *device = drmModeGetResources(fd);
    	if (!device) 
	{
		printf ("Не удался вызов drmModeGetResources\n");
        	result=-1;
        	goto close;
    	}
	// uint32_t
	printf ("Максимальные размеры: %lu %lu\n", device->max_width, device->max_height);



    // find first available connector
    printf("Checking for first available plugged-in connector.\n");
    drmModeConnector *first_available_connector;
    bool found_connector = false;
    for (int i = 0; i < device->count_connectors; i++) {
        first_available_connector = drmModeGetConnector(fd, device->connectors[i]);
        printf("%d\n", i);
        if (first_available_connector->connection == DRM_MODE_CONNECTED) {
            found_connector = true;
            break;
        } else {
            drmModeFreeConnector(first_available_connector);
        }
    }
    if(!found_connector) {
        fprintf(stderr, "Couldn't find plugged-in connector!\n");
        result=-1;
	goto close;
    }
    // find first available CRTC
    printf("Finding first available crtc\n");
    if(!device->count_crtcs) {
            fprintf(stderr, "No available CRTCs on first connector!");
            result=-1;
	    goto close;
        }
    // find first available mode
    printf("Checking for preferred mode.\n");
    drmModeModeInfo *mode;
    if(!first_available_connector->count_modes) {
            fprintf(stderr, "No available modes on first connector!");
            result=-1;
	    goto close;
        }
    bool found_preferred_mode = false;
    for (int i = 0; i < first_available_connector->count_modes; i++) {
        mode = &first_available_connector->modes[i];
        if (mode->type & DRM_MODE_TYPE_PREFERRED) {
            found_preferred_mode = true;
            break;
        }
    }
    if (!found_preferred_mode) {
        printf("Did not find preferred mode!\n");
	result=-1;
	goto close;
    }

	printf ("Предпочтительное разрешение: %u %u\n", mode->hdisplay, mode->vdisplay);
	

	
close:
	close(fd);
	return result;
}

 Для сборки используйте командную строку:

gcc drm.c -o drm -I/usr/include/drm -ldrm

 Программа, естественно, работает как на Raspberry PI, так и на Р-Фон. Предлагаю использовать куски кода из этой программы в своём приложении для определения, с каким разрешением экрана оно будет работать.

4.2 Поворот экрана

В текущей прошивке (декабрь 2025 года) при повороте экрана менеджер окон поворачивает только два приложения: галерею и браузер.

Для того, чтобы ваше приложение также поворачивалось, сегодня есть только один способ: имя исполняемого файла должно были либо «koko» (как у Галереи), либо «angelfish», как у браузера.

В будущих прошивках ожидается более гибкий механизм.

 4.3. Пакеты, необходимые для всех инструментариев

Практически для всех приведённых ниже примеров необходимо установить компиляторы С, С++ и программу make:

sudo dnf install gcc gcc-c++ make

 4.4. X11 и Wayland

На сегодняшний день телефон поддерживает только Wayland, не пытайтесь запускать классические X11-приложения.

 

5. Программы, использующие Qt

Здесь всё просто. Если вы явно не задаёте размеры шрифтов или элементов управления, то программа будет отображаться единообразно на компьютере и на телефоне.

В примере ниже явно задан размер шрифта для надписи «Привет!», поэтому на экране телефона, имеющего большее разрешение, эта надпись выглядит уменьшенной.

Так выглядит приложение, запущенное на компьютере

Так выглядит то же приложение, запущенное на телефоне

Исходный код программы состоит из двух файлов: hello.pro и main.cpp

hello.pro
QT += core gui widgets
TARGET = hello
TEMPLATE = app
SOURCES += main.cpp
main.cpp
#include <QApplication>
#include <QDialog>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QDialog dialog;
    dialog.setWindowTitle("Miha");

    
    QLabel *logoLabel = new QLabel("Привет!");
    logoLabel->setAlignment(Qt::AlignCenter);
    logoLabel->setStyleSheet("font-size: 32px; font-weight: bold; color: #2c3e50;");

    
    QLabel *messageLabel = new QLabel("<font color=red>Hello, World!</font>");
    messageLabel->setAlignment(Qt::AlignCenter);

    
    QPushButton *okButton = new QPushButton("OK");
    QObject::connect(okButton, &QPushButton::clicked, &dialog, &QDialog::accept);

    
    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(logoLabel);
    layout->addWidget(messageLabel);
    layout->addWidget(okButton);
    layout->setAlignment(Qt::AlignCenter);

    dialog.setLayout(layout);
    dialog.resize(250, 150);

    dialog.show();
    return app.exec();
}

 Для сборки программы вам проще всего установить пакет qt-creator, который подтянет все другие необходимые пакеты.

 sudo dnf install qt-creator

 Сборку осуществляйте последовательным выполнением команд:

qmake5

make

 На выходе получите исполняемый файл «hello», который, как и во всех остальных примерах, можете запускать как на Raspberry Pi, так и на Р-Фон.

6. Программы, использующие PyQt

Для примера я взял программу из статьи на Хабре: https://habr.com/ru/companies/skillfactory/articles/599599/

Перепечатывать здесь код программы не буду, единственное внесённое мною изменение – заменил цифру 6 на цифру 5, сделав из PyQt6 PyQt5.

Вам необходимо установить модуль python3-qt5

 sudo dnf install python3-qt5

Одна и та же программа выглядит на RaspberryPi и на телефоне вот так:

Так выглядит приложение, запущенное на компьютере

Так выглядит то же приложение, запущенное на телефоне

7. Программы, использующие GTK 3

Если выставить переменную окружения GDK_SCALE=2 или GDK_DPI_SCALE=2, то программа при выполнении увеличит элементы интерфейса в 2 раза.

Благодаря этому свойству GTK 3 мне удалось запустить на телефоне ( в относительно удобоваримом виде) программу audacity, скачанную прямо из репозитария. Естественно, пользоваться ей на телефоне в таком виде сложно, но проиллюстрировать масштабирование это позволило.

Вы можете менять эту переменную окружения в самом начале программы (перед вызовом g_application_run ) функцией:

 g_setenv("GDK_SCALE", "2", TRUE);

 Ниже приведён пример программы, которую вы можете собрать сами.

Окно программы выглядит вот так:

Так выглядит приложение, запущенное на компьютере

Так выглядит то же приложение, запущенное на телефоне

Для сборки потребуются пакет  gtk+3-devel :

 sudo dnf install gtk+3-devel

 Собрать программу можно командной строкой:

 gcc 2.c -o 2 -I/usr/include/gtk-3.0 -I/usr/include/glib-2.0 -I//usr/lib64/glib-2.0/include -I/usr/include/pango-1.0/ -I/usr/include/harfbuzz/ -I/usr/include/cairo/ -I/usr/include/gdk-pixbuf-2.0/ -I/usr/include/atk-1.0/ -lgtk-3 -lgdk-3 -lglib-2.0 -lgobject-2.0

 Исходный код программы, файл «2.с» :
#include <gtk/gtk.h>

gint count = 0;
char buf[5];

void increase(GtkWidget *widget, gpointer label)
{
  count++;
  
  sprintf(buf, "%d", count);
  gtk_label_set_text(GTK_LABEL(label), buf);
}

void decrease(GtkWidget *widget, gpointer label)
{
  count--;
  
  sprintf(buf, "%d", count);
  gtk_label_set_text(GTK_LABEL(label), buf);
}

int main(int argc, char** argv) {

  setenv("GDK_DPI_SCALE","5",0);
  
  GtkWidget *label;
  GtkWidget *window;
  GtkWidget *plus;
  GtkWidget *minus;
  
  GtkWidget *grid;
  
  gtk_init(&argc, &argv);
  
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 250, 500);
  gtk_window_set_title(GTK_WINDOW(window), "+-");
  

  grid = gtk_grid_new();



  plus = gtk_button_new_with_label("+");
  gtk_grid_attach(GTK_GRID(grid), plus, 0, 0, 1, 1); 
  gtk_widget_set_valign(window,GTK_ALIGN_FILL);



  minus = gtk_button_new_with_label("-");
  gtk_grid_attach(GTK_GRID(grid), minus, 0, 3, 1, 1); 

  label = gtk_label_new("0");
  gtk_grid_attach(GTK_GRID(grid), label, 2, 2, 1, 1); 

  gtk_container_add( GTK_CONTAINER(window), grid);

  gtk_widget_show_all(window);
  
  g_signal_connect(window, "destroy",
		   G_CALLBACK (gtk_main_quit), NULL);
  
  g_signal_connect(plus, "clicked", 
		   G_CALLBACK(increase), label);
  
  g_signal_connect(minus, "clicked", 
		   G_CALLBACK(decrease), label);

  
  gtk_main();
  
  return 0;
}

8. Программы, использующие GTK 4

Программы на GTK 4 не реагируют на переменные окружения, которыми мы управляли масштабом отображения в GTK 3.

Поэтому воспользуемся стилем CSS для получения нужного размера элементов отображения.

Окно программы выглядит вот так:

Так выглядит приложение, запущенное на компьютере

Так выглядит то же приложение, запущенное на телефоне

Для сборки потребуются пакет lib64gtk4.0-devel:

 sudo dnf install lib64gtk4.0-devel

 Собрать программу можно командной строкой (если не ошибаюсь):

 gcc $( pkg-config --cflags gtk4 ) -o 4 4.c $( pkg-config --libs gtk4 )

 Код программы 4.с

Код программы 4.с
#include <gtk/gtk.h>

static void activate(GtkApplication *app, gpointer user_data) {

    // Добавлено в функцию activate():
GtkCssProvider *provider = gtk_css_provider_new();
const char *css = "button { min-height: 60px; min-width: 200px; font-size: 48px; }";
gtk_css_provider_load_from_data(provider, css, -1);
gtk_style_context_add_provider_for_display(
    gdk_display_get_default(),
    GTK_STYLE_PROVIDER(provider),
    GTK_STYLE_PROVIDER_PRIORITY_APPLICATION
);

    // Создаем главное окно
    GtkWidget *window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "GTK4 Mobile App");
    
    
    // Создаем вертикальный контейнер
    GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
    gtk_widget_set_margin_top(box, 20);
    gtk_widget_set_margin_bottom(box, 20);
    gtk_widget_set_margin_start(box, 20);
    gtk_widget_set_margin_end(box, 20);
    
    // Создаем кнопки с увеличенными размерами
    GtkWidget *button1 = gtk_button_new_with_label("Кнопка 1");
    GtkWidget *button2 = gtk_button_new_with_label("Кнопка 2");
    
    // Устанавливаем минимальные размеры кнопок
    gtk_widget_set_size_request(button1, 200, 110);
    gtk_widget_set_size_request(button2, 200, 110);
    
    // Добавляем кнопки в контейнер
    gtk_box_append(GTK_BOX(box), button1);
    gtk_box_append(GTK_BOX(box), button2);
    
    // Добавляем контейнер в окно
    gtk_window_set_child(GTK_WINDOW(window), box);
    
    gtk_widget_show(window);
}

int main(int argc, char **argv) {
    // Создаем приложение
    GtkApplication *app = gtk_application_new("com.example.gtkapp", 
    //    G_APPLICATION_DEFAULT_FLAGS);
        0);
    
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    
   
    int status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);
    
    return status;
}

9. Программы, использующие SDL2

Тестовая программа составлена путём комбинирования обучающих материалов с сайта LazyFoo’ Productions ( https://lazyfoo.net/tutorials/SDL/index.php )

В одном куске кода проверялся:

  • рендеринг текстуры

  • реакция на нажатие мыши (или пальца в случае с телефоном)

  • проигрывание звука

Всё это сработало и на Raspberry Pi, и на Р-Фон.

В Raspberry Pi может не быть встроенного выхода звука, тогда можно проверить звук на HDMI-мониторе или же вонзить простейшую USB звуковую карту, как это сделал я. В моём случае – карта на чипе PCM2902.

Окно программы выглядит вот так:

Так выглядит приложение, запущенное на компьютере

Так выглядит то же приложение, запущенное на телефоне

Основные моменты, на которые следует обратить внимание:

1. В начале программы следует выставить переменную окружения, которая укажет на то, что нам нужен именно Wayland, а не X11

 setenv("SDL_VIDEODRIVER","wayland",0);

 2. Если нам не нужна экранная клавиатура, то сразу после SDL_Init вызываем:

 SDL_StopTextInput();

 Для сборки нам потребуются пакеты: SDL2-devel, SDL2_mixer-devel, SDL2_image-devel

 sudo dnf install SDL2-devel SDL2_mixer-devel SDL2_image-devel

 Сборка выполняется запуском в командной строке:

 gcc 07.cpp -o 07 -I/usr/include/SDL2 -lSDL2 -lSDL2_image -lSDL2_mixer -lstdc++

 Архив со всеми файлами (включая исходный код программы, звуковой файл и файл с текстурой) доступен для скачивания вот здесь:

 https://disk.360.yandex.ru/d/4C20EML3ZdM-Iw

Исходный код программы 07.cpp
/*This source code copyrighted by Lazy Foo' Productions 2004-2024
and may not be redistributed without written permission.*/

//Using SDL, SDL_image, standard IO, and strings
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_mixer.h>
#include <stdio.h>
#include <string>

//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

//Starts up SDL and creates window
bool init();

//Loads media
bool loadMedia();

//Frees media and shuts down SDL
void close();

//Loads individual image as texture
SDL_Texture* loadTexture( std::string path );

//The window we'll be rendering to
SDL_Window* gWindow = NULL;

//The sound effects that will be used
Mix_Chunk* gScratch = NULL;

//The window renderer
SDL_Renderer* gRenderer = NULL;

//Current displayed texture
SDL_Texture* gTexture = NULL;

bool init()
{
	//Initialization flag
	bool success = true;

	// Пробуем установить переменную окружения
	setenv("SDL_VIDEODRIVER","wayland",0);

	//Initialize SDL
	if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
	{
		printf( "SDL could not initialize! SDL Error: %s\n", SDL_GetError() );
		success = false;
	}
	else
	{
			// Попробуем запретить текстовый ввод
			SDL_StopTextInput();

		//Set texture filtering to linear
		if( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" ) )
		{
			printf( "Warning: Linear texture filtering not enabled!" );
		}

		//Create window
		gWindow = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
		if( gWindow == NULL )
		{
			printf( "Window could not be created! SDL Error: %s\n", SDL_GetError() );
			success = false;
		}
		else
		{

			//Create renderer for window
			gRenderer = SDL_CreateRenderer( gWindow, -1, SDL_RENDERER_ACCELERATED );
			if( gRenderer == NULL )
			{
				printf( "Renderer could not be created! SDL Error: %s\n", SDL_GetError() );
				success = false;
			}
			else
			{
				//Initialize renderer color
				SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );

				//Initialize PNG loading
				int imgFlags = IMG_INIT_PNG;
				if( !( IMG_Init( imgFlags ) & imgFlags ) )
				{
					printf( "SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError() );
					success = false;
				}

                		 //Initialize SDL_mixer
                		if( Mix_OpenAudio( 44100, MIX_DEFAULT_FORMAT, 2, 2048 ) < 0 )
                		{
                    			printf( "SDL_mixer could not initialize! SDL_mixer Error: %s\n", Mix_GetError() );
                   			 success = false;
                		}
			}
		}
	}

	return success;
}

bool loadMedia()
{
	//Loading success flag
	bool success = true;

	//Load PNG texture
	gTexture = loadTexture( "texture.png" );
	if( gTexture == NULL )
	{
		printf( "Failed to load texture image!\n" );
		success = false;
	}

	//Load sound effects
    	gScratch = Mix_LoadWAV( "scratch.wav" );
    	if( gScratch == NULL )
    	{
    	    printf( "Failed to load scratch sound effect! SDL_mixer Error: %s\n", Mix_GetError() );
    	    success = false;
    	}

	return success;
}

void close()
{
	//Free loaded image
	SDL_DestroyTexture( gTexture );
	gTexture = NULL;

    	//Free the sound effects
    	Mix_FreeChunk( gScratch );
    	gScratch = NULL;
    
	//Destroy window	
	SDL_DestroyRenderer( gRenderer );
	SDL_DestroyWindow( gWindow );
	gWindow = NULL;
	gRenderer = NULL;

	//Quit SDL subsystems
	IMG_Quit();
	SDL_Quit();
}

SDL_Texture* loadTexture( std::string path )
{
	//The final texture
	SDL_Texture* newTexture = NULL;

	//Load image at specified path
	SDL_Surface* loadedSurface = IMG_Load( path.c_str() );
	if( loadedSurface == NULL )
	{
		printf( "Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError() );
	}
	else
	{
		//Create texture from surface pixels
        newTexture = SDL_CreateTextureFromSurface( gRenderer, loadedSurface );
		if( newTexture == NULL )
		{
			printf( "Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError() );
		}

		//Get rid of old loaded surface
		SDL_FreeSurface( loadedSurface );
	}

	return newTexture;
}

int main( int argc, char* args[] )
{
	//Start up SDL and create window
	if( !init() )
	{
		printf( "Failed to initialize!\n" );
	}
	else
	{
		//Load media
		if( !loadMedia() )
		{
			printf( "Failed to load media!\n" );
		}
		else
		{	
			//Main loop flag
			bool quit = false;

			//Event handler
			SDL_Event e;

			//While application is running
			while( !quit )
			{
				//Handle events on queue
				while( SDL_PollEvent( &e ) != 0 )
				{
					//User requests quit
					switch (e.type)
					{
					case  SDL_MOUSEBUTTONDOWN:
						Mix_PlayChannel( -1, gScratch, 0 );
						break;

					case SDL_QUIT:
						quit = true;
						break;
					}
				}

				//Clear screen
				SDL_RenderClear( gRenderer );

				//Render texture to screen
				SDL_RenderCopy( gRenderer, gTexture, NULL, NULL );

				//Update screen
				SDL_RenderPresent( gRenderer );
			}
		}
	}

	//Free resources and close SDL
	close();

	return 0;
}

10. Заключение

Лично мне оказалось удобнее сначала писать и отлаживать программу на x86 версии Роса Фреш. Просто потому, что я привык работать на ноутбуке, который можно легко переносить с места на место. Если же вы всегда работаете на одном рабочем месте, то первый шаг с архитектурой x86 для вас будет излишним.

Лирическое отступление

Интересно, что работая на x86 и на ARM (она же aarch) версиях РОСА Хром, я не почувствовал никакой разницы. Даже странным показалось. Если раньше пересаживался, например, с PA-RISC на IBM Power, то приходилось переключаться на особенности их операционных систем. А здесь - ну прямо одно и то же.

  Неоценимую помощь при написании статьи мне оказали сотрудники «НТЦ ИТ РОСА» Михаил Новосёлов и Олег Воробьёв.

Комментарии (3)


  1. NutsUnderline
    15.12.2025 05:28

    Вероятно ноут у автора довольно тормозной что ему малинка 4 показалась эквивалентом . Кроскомпиляцию как таковую сделать несложно, к тому же тут вообще все в командной строке , больше волнения вызывает вопрос версий библиотек и заголовочных файлов. Но с этим риск есть и при переносе с малины.


  1. technomancer
    15.12.2025 05:28

    "Во-первых, это просто шикарная презентация!" (Грань будущего)
    "Во-первых, это просто шикарная презентация!" (Грань будущего)


    1. MastaLomaster Автор
      15.12.2025 05:28