Урок 4. Вывод текста в SDL

      Комментарии к записи Урок 4. Вывод текста в SDL отключены

Помечено: , ,

В этой теме 0 ответов, 1 участник, последнее обновление  Васильев Владимир Сергеевич 3 мес., 2 нед. назад.

  • Автор
    Сообщения
  • #3145
    Дополнение к уроку 3 Содержание Урок 5

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

    lesson4_1 lesson4_2

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

    Осталось сделать механизм, который будет переводить строку char * в последовательность из спрайтов. Можно сделать последовательность символов в исходном рисунке в соответствии со стандартной кодовой таблицей (например ASCII или KOI8-R): номер кадра с символом равен соответствующему коду этого символа. Это самый простой пример создания своего механизма печати. Я пересмотрел несколько подобных механизмов, некоторые были гораздо изощреннее и богаче по возможностям. Возможно этот метод пригодится, когда нужно использовать уникальный шрифт в какой-нибудь игре. Теперь давайте попробуем сделать простую функцию для вывода текста с помощью растрового шрифта, т.е. шрифт, который находится в файле изображении.

    Для начала познакомимся с библиотекой SDL_image. Достать ее можно на официальном сайте. Установка чрезвычайно проста. Для работы с этой библиотекой нам нужно подключить файл заголовков #include "SDL_image.h" и при линковке указать библиотеку: -lSDL_image. Эта библиотека очень простая в использовании. Справки с ней не прилагается, но в файле заголовков очень понятные комментарии.

    Как я уже упоминал в предыдущих уроках, штатными средствами SDL мы можем загружать только файлы BMP. Но при помощи SDL_image мы можем работать с практически любым форматом изображения. Файл нашего растрового шрифта имеет формат PNG (Portable Network Graphics). Чтобы загрузить такой файл мы используем функцию IMG_Load из библиотеки SDL_image. Вот ее прототип: SDL_Surface* IMG_Load(const char* file);
    И все! Таким нехитрым способом можно загрузить на поверхность SDL_Surface любую графику. И давайте посмотрим на функцию загрузки шрифта:

    SDL_Surface* LoadFont(char* BitmapFont){
      SDL_Surface* temp;
      
      temp = IMG_Load(BitmapFont);
      if(temp == NULL){
      	printf("Can't load image %s\n",BitmapFont);
    	return NULL;
      }
      
      SDL_SetColorKey(temp,SDL_SRCCOLORKEY,SDL_MapRGB(temp->format,255,255,255));
      
      return temp;
    }

    Функция очень простая. Она просто загружает изображение на поверхность и устанавливает прозрачность. Устанавливать прозрачность (Color Keying) мы уже умеем. Следует только добавить, что здесь у нас используется белый цвет в качестве прозрачного (триплет 255,255,255). Теперь об ограничениях нашего шрифта. Буквы могут быть только английские и только в верхнем регистре. Собственно, диапазон шрифта от A до Z. Цифр и других символов нет. Теперь немного теории о кодировках.

    Как вы уже заметили, буквы в нашем шрифте идут по алфавитному порядку. И вот почему. В большинстве кодовых таблиц первые 128 символов занимают латинские буквы и стандартные и управляющие символы. Остальные 128 используются для локализации, то есть содержат символы других языков. Вот кусок из кодовой таблицы KOI8-R:

    . . . . . . ! " # $ % & ' (
    ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; <
    = > ? @ A B C D E F G H I J K L M N O P
    Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d
    e f g h i j k l m n o p q r s t u v w x
    y z { | } ~ . . . . .
    . . . . . .© ю а б ц д е ф г х
    и й к л м н о п я р с т у ж в ь ы з ш э
    щ ч ъ Ю А Б Ц Д Е Ф Г Х И Й К Л М Н О П
    Я Р С Т У Ж В Ь Ы З Ш Э Щ Ч Ъ

    Нетрудно заметить, что латинские буквы построены по алфавиту, а вот русские нет. Это небольшая проблема для адаптации нашего примера для русского шрифта, хотя создать версию KOI8-R шрифта несложно. Поэтому мы рассмотрим только латинские буквы в верхнем регистре.

    Далее код функции для рисования текста. Посмотрите на него внимательно, попытайтесь понять что происходит, а ниже мы разберем ее подробно:

    void DrawText(SDL_Surface* sFont, int x, int y, char * str) {
      int i;
      SDL_Rect src, dest;
      
      for (i = 0; i < strlen(str); i++) {
         if (str[i] >= 'A' && str[i] <= 'Z') {
    	src.x = (str[i] - 'A') * 32;
            src.y = 0;
    	src.w = 32;
    	src.h = 32;
    	  
    	dest.x = x + (i * 32);
    	dest.y = y;
    	dest.w = 32;
    	dest.h = 32;
    	  
    	SDL_BlitSurface(sFont, &src, screen, &dest);
          }
      }
      SDL_Flip(screen);
    }

    В качестве аргументов передаем поверхность с загруженным изображением, координаты куда выводить текст и сам текст. Далее в цикле выводим по порядку каждый символ строки:
    for (i = 0; i < strlen(str); i++)

    Обязательно проверяем чтобы символ был в диапазоне A-Z:
    if (str[i] >= 'A' && str[i] <= 'Z')

    Далее рассчитываем координату х в исходном изображении (откуда вырезать). У нас размеры буквы заведомо 32х32.
    Выражение (str[i] -'A') * 32; вычисляет эту координату. Допустим у нас символ B (код 66), тогда получаем: (66-65)*32 = 32. То есть начинаем вырезать букву B в координатах x=32, y=0. Для выходных координат ( в которые выводить текст) рассчитываем позицию каждого следующего символа: x + (i * 32); и поскольку индекс i самого первого символа равен нулю, то первый символ будет выведен в тех координатах, что поступают как аргументы.

    И наконец, как же это добро использовать. Вот кусок кода, использующий наши функции:

     SDL_Surface* sFont;
     sFont = LoadFont("font.png");
     DrawText(sFont, 20, 150, "BITMAP FONT EXAMPLE");

    Все чрезвычайно просто. Вы можете доработать эту функцию, расширив диапазон символов в шрифте. Например, можно создать шрифт на 256 символов, а вместо служебных и непечатных символов оставить пустое место. Код получается абсолютно несложным. Вы можете создавать шрифты любых форм, гарнитур и размеров. Посмотрите исходный код программы bmf.cxx (Bitmap Font) и попробуйте разобраться в нем. А теперь рассмотрим следующий способ.

    Нет ничего лучше как использовать разнообразные и красивые TrueType шрифты, коих очень много можно найти в интернете и причем совершенно бесплатно. В системах Unix для этого существует библиотека FreeType, которая является бесплатной реализацией библиотеки для работы со шрифтами TrueType. В Win32 этот формат вообще является родным для системы. Но работа с библиотекой FreeType очень сложна. Разработчик библиотеки SDL Sam Lantinga был очень любезен и создал надстройку (wrapper) для библиотеки FreeType чтобы мы могли использовать ее в своих программах. Новая библиотека называется SDL_ttf. Найти ее можно все на том же официальном сайте SDL, который уже наверно стал местом вашего паломничества. Устанавливается эта библиотека чрезвычайно просто для любой платформы, под которую есть реализация SDL. Единственный заголовочный файл SDL_ttf.h помещается вместе с другими заголовочными файлами SDL. То же самое и для файла библиотеки (libSDL_ttf.a и libSDL_ttf.so или SDL_ttf.lib и SDL_ttf.dll в Win32). Для работы с этой библиотекой вам нужно просто добавить заголовок: #include "SDL_ttf.h" и указать библиотеку для линковки: -lSDL_ttf. Вот и все подготовительные процедуры. Ну что ж, давайте попробуем наваять небольшой пример, чтобы убедиться, какая же простая эта библиотека.
    Для начала необходимо инициализировать библиотеку SDL_ttf, наподобии того, как мы инициализируем SDL:

     TTF_Init();
     atexit(TTF_Quit);

    Также указываем вызывать функцию TTF_Quit() перед выходом из программы. Теперь посмотрите на код функции для вывода текста. Это очень просто.

    void print_ttf(SDL_Surface *sDest, char* message, char* font, int size, SDL_Color color, SDL_Rect dest){
     TTF_Font *fnt = TTF_OpenFont(font, size);
     SDL_Surface *sText = TTF_RenderText_Blended( fnt, message, color);
     SDL_BlitSurface( sText,NULL, sDest,&dest );
     SDL_FreeSurface( sText );
     TTF_CloseFont( fnt );
    }

    Аргументы:

    • SDL_Surface *sDest – поверхность, на которую будет скопирован текст;
    • char* message – текст сообщения;
    • char* font – имя файла TrueType шрифта (например arial.ttf);
    • int size – размер шрифта; SDL_Color color – структура, содержащяя цвет шрифта, вот ее прототип:
      typedef struct{
        Uint8 r;
        Uint8 g;
        Uint8 b;
        Uint8 unused;
      } SDL_Color;

    Параметр Uint8 unused не используется. И, наконец, SDL_Rect dest – содержит координаты, куда следует вывести текст (в этой структуре не используются элементы w и h). Чтобы вывести текст, мы загружаем шрифт:
    TTF_Font *fnt = TTF_OpenFont(font, size);

    Далее создаем поверхность, на которую отображаем текст при помощи загруженного шрифта:
    SDL_Surface *sText = TTF_RenderText_Blended( fnt, message, color);

    Функция TTF_RenderText_Blended() отображает сглаженный шрифт. Если вам нужно использовать шрифт без сглаживания, то используйте TTF_RenderText_Solid() с теми же самыми параметрами. Наконец, копируем надпись на поверхность, которую задали в аргументах (можно задать к примеру screen), удаляем временную поверхность sText, чтобы очистить память и закрываем шрифт.

    Из main() вызываем функцию для отображения текста:

     SDL_Color clr = {255,50,40,0};
     SDL_Rect dest = {80, 120,0,0};
     print_ttf(screen, "SDL_ttf example", "courier.ttf", 46, clr, dest);
    
     clr.r = 255;
     clr.g = 255;
     clr.b = 0;
     dest.x = 80;
     dest.y = 250;
     print_ttf(screen, "Пример SDL_ttf", "courier.ttf", 46, clr, dest);
     
     SDL_Flip(screen);

    Сначала создаем структуры цвета и координат и заполняем их значениями, а затем выводим надпись на английском и на русском. Заметьте, что на русском можно писать, если только у вас шрифт в соответствующей кодировке. Прилагаемый с исходниками шрифт Courier в кодировке KOI8-R.
    Рекомендую загрузить исходники для этого урока и внимательно их изучить.

    Дополнение к уроку 3 Содержание Урок 5

Для ответа в этой теме необходимо авторизоваться.