image

От переводчика:

Это продолжение серии переводов туториалов от Twinklebear, в оригинале доступных тут. Перевод отчасти вольный и может содержать незначительные поправки или дополнения от переводчика. Перевод первых двух уроков — за авторством InvalidPointer, а третьего и четвертого — за k1-801.


Список уроков:


Загружаем шрифты с помощью SDL_ttf


В этом уроке мы узнаем, как отображать шрифты формата True Type font с помощью библиотеки-расширения SDL_ttf. Установка библиотеки идентична установке SDL_image в Уроке 3, но вместо “image” просто пишем “ttf” (пользователям Windows стоит еще скопировать включенный dll freetype). Так что загрузите SDL_ttf, взгляните на документацию и приступайте к уроку!

Первое, что нам нужно для работы с SDL_ttf, — это ttf шрифт. Используя BitFontMaker, автор сделал довольно ужасный шрифт, который вы можете скачать из репозитория, но если у вас уже имеется свой красивый шрифт, то можно использовать его. Этот шрифт предоставляет только простые символы ASCII, так что если вы попробуете отобразить не-ASCII символы, то скорее всего это не получится. Код этого урока будет написан на основе урока 5, как обычно вы можете скачать его с Github. Изображения, нарезанные спрайты и рисунки будут изменены в этом уроке.

Отображаемый текст


SDL_ttf обеспечивает несколько способов отображения шрифтов различной скорости и качества, а также возможность отображения UTF8 и Unicode символов. Документация предоставляет неплохой обзор различных методов отображения, так что стоит почитать и узнать о них больше, когда и какой метод вы хотите использовать в зависимости от ваших требований к качеству и скорости. В этом уроке мы будем использовать TTF_RenderText_Blended, так как у нас нет никаких временных ограничений и хотим, чтобы наш текст был красивым. Различные функции отображения текста принимают цвет в формате RGB SDL_Color, который мы можем использовать, чтобы подобрать цвет текста для отрисовки.

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

Пишем функцию renderText


Чтобы упростить себе жизнь, создадим функцию renderText, которая будет принимать текст, файл, содержащий шрифт TTF, цвет, желаемый размер и рендерер для загрузки окончательной текстуры. Функция открывает шрифт, отображает текст, преобразует его в текстуру и возвращает текстуру. Так как могут возникнуть проблемы, нужно проверить каждый вызов библиотеки на ошибки и правильно их обработать, например, почистить ресурсы, логгировать ошибки и вернуть nullptr, чтобы мы знали, что произошло что-то плохое. SDL_ttf сообщает все свои ошибки через SDL_GetError, так что можно продолжать использовать logSDLError для логгирования ошибок.

Держа в уме эти требования, давайте напишем функцию renderText:

/**
* Отображает текст в текстуру для отрисовки
* @param message Сообщение, которое хотим отобразить
* @param fontFile Шрифт, который хотим использовать
* @param color Цвет, в который хотим окрасить текст
* @param fontSize Размер шрифта
* @param renderer Рендерер, в который нужно загрузить текстуру
* @return SDL_Texture, содержащий отрендеренный текст или nullptr, если что-то пошло не так
*/
SDL_Texture* renderText(const std::string &message, const std::string &fontFile,
        SDL_Color color, int fontSize, SDL_Renderer *renderer)
{
        //Открываем шрифт
        TTF_Font *font = TTF_OpenFont(fontFile.c_str(), fontSize);
        if (font == nullptr){
                logSDLError(std::cout, "TTF_OpenFont");
                return nullptr;
        }       
        //Сначала нужно отобразить на поверхность с помощью TTF_RenderText,
        //затем загрузить поверхность в текстуру
        SDL_Surface *surf = TTF_RenderText_Blended(font, message.c_str(), color);
        if (surf == nullptr){
                TTF_CloseFont(font);
                logSDLError(std::cout, "TTF_RenderText");
                return nullptr;
        }
        SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surf);
        if (texture == nullptr){
                logSDLError(std::cout, "CreateTexture");
        }
        //Очистка поверхности и шрифта
        SDL_FreeSurface(surf);
        TTF_CloseFont(font);
        return texture;
}

Предупреждение о производительности


Очень важно заметить, что каждый раз, когда хотим отобразить текст, заново открываем и закрываем шрифт, что подходит в нашем случае, так как отображаем текст один раз, но если мы захотим отобразить много текста и/или слишком часто, то лучшей идеей будет держать шрифт открытым столько, сколько нам нужно. Наша версия renderText для этого более частого случая будет принимать TTF_Font* вместо названия файла шрифта и не будет открывать и закрывать, так как жизнь файла шрифта будет регулироваться отдельно.

Инициализируем SDL_ttf


Как и с SDL нам нужно инициализировать библиотеку перед тем, как использовать ее. Это делается с помощью TTF_Init, который вернет 0 в случае успеха. Чтобы инициализировать SDL_ttf, мы лишь вызываем эту функцию после инициализации SDL и проверяем вернувшееся значение, чтобы убедиться, что все нормально.

if (TTF_Init() != 0){
        logSDLError(std::cout, "TTF_Init");
        SDL_Quit();
        return 1;
}

Используем renderText


С помощью нашей удобной функции renderText мы можем отображать текст одним простым вызовом. Для этого урока отобразим текст “TTF fonts are cool!” белого цвета, размера 64 шрифтом, который мы скачали до этого. Затем мы можем запросить ширину и высоту так же, как и для любой другой текстуры, и вычислить координаты x/y, чтобы нарисовать сообщение в центре окна.

const std::string resPath = getResourcePath("Lesson6");
//Мы отображаем строку "TTF fonts are cool!"
//Цвет в формате RGBA
SDL_Color color = { 255, 255, 255, 255 };
SDL_Texture *image = renderText("TTF fonts are cool!", resPath + "sample.ttf",
        color, 64, renderer);
if (image == nullptr){
        cleanup(renderer, window);
        TTF_Quit();
        SDL_Quit();
        return 1;
}
//Получим ширину и высоту текстуры, чтобы отобразить ее в центре
int iW, iH;
SDL_QueryTexture(image, NULL, NULL, &iW, &iH);
int x = SCREEN_WIDTH / 2 - iW / 2;
int y = SCREEN_HEIGHT / 2 - iH / 2;

Рисуем текст


В конце концов можем нарисовать текстуру, как мы это делали до этого с помощью функции renderTexture.

//Заметка: Это в основном цикле программы
SDL_RenderClear(renderer);
//Мы можем отрисовать наш текст, как и любую другую текстуру, так как
//он был отрендерен в текстуру
renderTexture(image, renderer, x, y);
SDL_RenderPresent(renderer);

Если все пошло по плану, вы увидите что-то вроде такого:

image

Конец урока 6


Это все, что нужно знать, чтобы начать пользоваться SDL_ttf! Не забудьте посмотреть документацию, чтобы увидеть, на что эта библиотека способна. Как обычно, если у вас возникнут проблемы с уроком, можете писать в комментариях.

Автор стал занят другими проектами и не сможет писать уроки больше, так что это был последний урок из цикла. Вы можете посмотреть уроки от Lazy Foo или почитать примеры и документацию из SDL wiki.