Программирование: SFML - Рисуем в 2D

Читай на DevTribe.ru!

» Раздел: C++

Оригинал статьи - официальный туториал
Автор перевода - Nerevar

Рисуем в 2D

Введение

Как было сказано в предыдущих статьях, модуль SFML, отвечающий за окна, предоставляет простой способ создания окна с OpenGL-контекстом и управления его событиями, но не помогает нам что-либо нарисовать. Он дает единственную возможность, но довольно-таки мощную - рисование с помощью OpenGL API напрямую.
К счастью, SFML предоставляет графический модуль, который вам поможет нарисовать различные 2D объекты более простым способом, чем если бы вы использовали OpenGL.

Окно рисования

Для рисования разных вещей нам предоставляется графический модуль, вместе с которым вам нужно использовать специальный класс окна sf::RenderWindow. Этот класс получен от класса sf::Window и содержит все его функции. Все, что вы уже знаете об sf::Window (создание, управление событиями, управление частотой кадров, использование OpenGL), также применимо и к sf::RenderWindow.
В добавок к этому, sf::RenderWindow дает высоко-уровневые функции, которые помогут вам очень просто рисовать разные вещи. В этой статье мы остановимся на двух из этих функций : очищении и рисовании. Они напрямую соответствуют своим названиям : функция очистки экрана очищает всё окно и заливает заданным цветом, а функция рисования рисует любой переданный ей объект.
Ниже представлен типичный главный цикл с окном рисования:
#include <SFML/Graphics.hpp>

int main()
{
    // создаем окно
    sf::RenderWindow window(sf::VideoMode(800, 600), "My window");

    // приложение будет работать, пока окно открыто
    while (window.isOpen())
    {
        // проверяем все события окна, которые были запущены с предыдущей итерации цикла
        sf::Event event;
        while (window.pollEvent(event))
        {
            // сработало событие закрытия окна - закроем его
            if (event.type == sf::Event::Closed)
                window.close();
        }

        // очищаем окно и заливаем черным цветом
        window.clear(sf::Color::Black);

        // рисуем что-нибудь здесь
        // window.draw(...);

        // конец текущего кадра - отображаем
        window.display();
    }

    return 0;
}
Вызов очистки перед рисование чего-либо является обязательным, иначе то, что было отображено предыдущим кадром будет нарисовано позади нового кадра и смешается. Исключением является, если вы перерисовываете окно полностью так, что ни один пиксель из предыдущего кадра не будет показан. В этом случае вы можете не вызывать функцию очистки (хотя это и не будет иметь большого влияния на производительность).
Вызов функции рисования также обязателен, он принимает то, что нужно рисовать и отображает это в окне. На самом деле оно не отображается напрямую сразу в окно, а сохраняется в скрытом буфере. Затем этот буфер отображается на экран, когда вы вызываете функцию отображения окна - это называется Двойной буферизацией.
Этот цикл очистки\рисования\отображения - единственный хороший способ рисования различных вещей. Не используйте другую стратегию отрисовки, такие, как сохранение пикселей из предыдущего кадра, перебора пикселей, или одиночного вызова рисования и множественного вызова отображения. Вы получите странные результаты, благодаря двойной буферизации.
Современное графическое оборудование и API создано для постоянных циклов очистки\рисования\отображения, в которых всё полностью очищается на каждой итерации главного цикла. Не бойтесь рисовать 1000 спрайтов 60 раз в секунду, это все равно намного меньше рисования миллионов треугольников, которые ваш компьютер может обработать.

Что мы теперь можем нарисовать?

Сейчас, когда главный цикл готов для рисования, давайте посмотрим что и как мы можем в нем нарисовать.
SFML дает возможность рисования 4 разных объектов : 3 из них готовы для рисования (спрайты, текст и фигуры), последний - это всего-лишь блок для строительства ваших собственных объектов (буфер вершин).
Хотя они имеют некоторые общие свойства, каждый из этих объектов поставляются с собственными нюансами, которые описаны в специальных учебных пособиях, которые постепенно будут мной переводиться и ссылки буду даны ниже.

Рисование вне окна

SFML также предоставляет способ рисования в текстуру или в окно. Для этого используйте класс sf::RenderTexture, вместо sf::RenderWindow. Он имеет такие же функции для рисования, наследованные от общего класса sf::RenderTarget.
// создаем render-texture размерами 500х500 пикселей
sf::RenderTexture renderTexture;
if (!renderTexture.create(500, 500))
{
    // ошибка при создании
}

// все тот же цикл рисования
renderTexture.clear();
renderTexture.draw(sprite); // or any other drawable
renderTexture.display();

// получаем текстуру, в которую все было отрисовано
const sf::Texture& texture = renderTexture.getTexture();

// и рисуем её в окне
sf::Sprite sprite(texture);
window.draw(sprite);
Функция getTexture возвращает текстуру "только для чтения", это значит, что вы можете только использовать её, не изменяя. Если вы хотите её изменить, перед использованием, вы можете скопировать её в собственную sf::Texture и изменять её.
Класс sf::RenderTexture также имеет такие же функции, как и sf::RenderWindow для управления видом и OpenGL. Если вы используете OpenGL для рисования в render-texture, вы можете запросить создания буфера глубины с помощью передачи третьего параметра в функцию создания текстуры.
renderTexture.create(500, 500, true); // включаем буфер глубины

Рисуем из потоков

SFML поддерживает рисование из нескольких потоков, и вам не потребуется никаких дополнительных усилий, чтобы это работало. Единственная вещь, которую вам следует запомнить - это необходимость деактивировать окно перед использованием в другом потоке. Причиной этой необходимости является то, что окно (благодаря контексту OpenGL) не может быть активно в более, чем одном потоке, в один момент времени.
void renderingThread(sf::RenderWindow* window)
{
    // цикл отрисовки
    while (window->isOpen())
    {
        // рисуем

        // конец текущего кадра
        window->display();
    }
}

int main()
{
    // создаем окно
    sf::RenderWindow window(sf::VideoMode(800, 600), "OpenGL");

    // деактивируем контекст OpenGL
    window.setActive(false);

    // запускаем поток
    sf::Thread thread(&renderingThread, &window);
    thread.launch();

    // обрабатываем события,логику и всё, что угодно, в этом цикле
    while (window.isOpen())
    {
        ...
    }

    return 0;
}
Как вы можете видеть, вам не требуется возиться с активацией окна в потоке рисования, SFML делает это за вас автоматически, когда это требуется.

Просмотров: 3 919

leongrand #1 - 3 года назад 2
а вы можете показать что из этого получится ?
Nerevar #2 - 3 года назад 2
а вы можете показать что из этого получится ?
Из чего именно? Просто цикла рисования? Или рисования в текстуру, с последующим натягиванием на спрайт?
Kozinaka #3 - 3 года назад 2
А что с полноэкранным режимом и ресайзом окна?
Nerevar #4 - 3 года назад (отредактировано ) 2
специальный класс окна sf::RenderWindow. Этот класс получен от класса sf::Window и содержит все его функции. Все, что вы уже знаете об sf::Window (создание, управление событиями, управление частотой кадров, использование OpenGL), также применимо и к sf::RenderWindow.
Kozinaka,
Вот отрисовка обычная
И рендер в текстуру 250х250,затем в спрайт,а спрайт красим в зеленый и рисуем
прикреплены файлы