Окно для рисования
Для рисования объектов с помощью графического модуля, вам необходимо использовать специальный класс окна: sf::RenderWindow. Этот класс является наследником класса sf::Window и обладает всем методами класса родителя. Всё что вы изучили о sf::Window (создание, обработка событий, настройка частоты кадров, смешанное использование с OpenGL и т.д.), применимо и к sf::RenderWindow.
Помимо этого, sf::RenderWindow имеет методы облегчающие задачу рисования объектов. В этом уроке мы сосредоточимся на двух таких методах: clear() и draw(). Они просты как и их названия: clear() очищает окно выбранным цветом, а draw() рисует любой переданный ему объект.
Так выглядит типичный главный цикл с окном визуализации (render window):
#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; }
Вызов clear(), перед рисованием чего-либо, является обязательным, поскольку иначе, пиксели с предыдущего кадра наложатся на текущий. Единственное исключение, это когда вы перерисовываете абсолютно все пиксели в окне.
Вызов display() так же обязателен, он берёт всё объекты отданные на отрисовку (методом draw()) с последнего вызова display(), и отображает их в окне. На самом деле объекты рисуются не сразу в окно, а предварительно в скрытый буфер. Этот буфер затем копируется в окно вызовом display() — это называется двойной буферизацией.
Цикл clear()/draw()/display() это единственный хороший способ для рисования объектов. Не пытайтесь использовать другие стратегии, такие как сохранение пикселей с предыдущего кадра, «стирание» отдельных пикселей и т.п. В этих случаях вы можете получить странные результаты из-за двойной буферизации. Современные видеокарты и их API заточены под повторяющиеся циклы clear()/draw()/display(). Не бойтесь рисовать 1000 спрайтов по 60 раз в секунду, это намного меньше миллионов треугольников которые ваш компьютер способен обработать.
Что я теперь могу нарисовать?
Теперь у вас есть главный цикл готовый к рисованию, давайте же рассмотрим что и как вы можете в нём нарисовать.
SFML поддерживает четыре типа объектов которые можно нарисовать: три из них сразу готовы к использованию (спрайты (sprites), тексты (texts) и фигуры (shapes)), а четвёртый является строительным блоком для создания ваших собственных объектов (массивы вершин (vertex arrays)).
Не смотря на то, что у них есть общие свойства, каждый из этих типов объектов заслуживает отдельных уроков:
- (Как только переведу их тут будут ссылки..наберитесь терпения)
Рисование за кадром
SFML так же обеспечивает способ рисования в текстуру, вместо рисования в окне. Для этого, следует использовать sf::RenderTexture вместо sf::RenderWindow. Этот класс имеет такие же методы для рисования, унаследованные от их общего предка sf::RenderTarget.
// создаём текстуру 500x500 на которой будем рисовать sf::RenderTexture renderTexture; if (!renderTexture.create(500, 500)) { // ошибка... } // для рисования используются те же функции renderTexture.clear(); renderTexture.draw(sprite); // или что то другое что можно нарисовать renderTexture.display(); // получаем текстуру (на которой был нарисован объект) sf::Texture& texture = renderTexture.getTexture(); // рисуем её в окне sf::Sprite sprite(texture); window.draw(sprite);
Метод getTexture() возвращает текстуру, доступную только для чтения, т.е. вы можете использовать её, но не изменять. Если вам необходимо её изменить перед тем как использовать, то скопируйте её в другой объект класса sf::Texture.
Кроме того, sf::RenderTexture имеет те же самые методы что и sf::RenderWindow для управления видами и OpenGL (см. соответствующие уроки). Если вы используете OpenGL для рисования на текстуре, вы можете в конструкторе указать третий параметр, который отвечает за использование буфера глубины (depth buffer).
renderTexture.create(500, 500, true); // включаем depth buffer
Рисование из потока
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 делает это автоматически за вас когда это необходимо.
Главное помните что создавать окно и обрабатывать его события необходимо в главном потоке (см. в уроке Открытие и управление окном SFML).
Рисовать то легко примитивами, а как указать координаты для рисования и задать размеры фигуры? Просто не понимаю как мне нарисовать квадрат в нужном месте…
И есть ли нормальные примеры не для детей. Просто на Линукс я смотрю фиг что найдешь, вот ваши уроки это всё что есть, но тут так сыро. Много текста, мало информации, однотипно и выше основ нет материала. Может что напишете интереснее или поделитесь ссылкой на любые другие источники кроми хабров и киберфорумов. Заранее спасибо.
Эти статьи про SFML не являются уроками, это перевод (и то незавершённый) документации с оф.сайта. По поводу примеров посложнее, я даже и не знаю.. Если вы пишите прям под линукс то берите движок Unity, я вообще жалею немного что тратил время на SFML при создании первой игры, а не делал её сразу на Unity, но это тоже был полезный опыт. :)