Подсистема вывода графики движка MagicEngine.
Изначально вывод графики в движке был ориентирован на строго одну платформу и несоклько раз полностью переписывался. Со временем возник интерес сделать систему с подключаемыми модулями(драйверами) вывода видео — что и используется в данный момент.
Исторически использовалось несколько подходов к отрисовке 2д графики в движке:
1. Прямой доступ к видео памяти/экранному буферу: данный метод использовался во времена DOS(защищенный режим), Windows98 (DirectDraw) огромным минусом такого подхода является необходимость написания довольно большого объема кода для управления выводом графики и  достаточно низкая производительность. Все данные хранятся в оперативной памяти и посылаются на отрисовку по готовности — а значит для разрешения 1024*768 отсылается 3 мегабайта данных на каждый кадр, что весьма сильно ограничивает скорость. К томуже все операции со спрайтами производятся на ЦПУ, который выполняет и другие задачи.
2. С переходом в ОС Linux данный метод был ликвидирован и ему на смену пришел кросплатформенный SDL в котором я также столкнулся с проблемами скорости, да и сама библиотека оказалась слишком монструозной.
В данный момент я остановился на модульной системе вывода графики и в качестве основного драйвера — использование OpenGL для отрисовки спрайтов. Конечно спрайты отрисованные таким образом могут получить некоторые дефекты — но с другой стороны можно получить гораздо большую скорость.

Структура видео подсистемы.
В видео подсистемы входит видео интерфейс, интерфейс загрузчиков и сами драйвера.
Видео интерфейс предоставляет унифицырованный доступ к функциям драйвера — добавление спрайтов на отрисовку, инициализация, деинициализация, получение событий и т.д.
Интерфейс загрузчиков — абстрагирует пользователя от загрузки различных форматов файлов, предоставляя для этого одинаковый интерфейс

Драйвер GLFW.
Последней и единственной развивающейся версией драйвера на данный момент — является драйвер GLFW.
GLFW — это свободно распространяемая кросплатформенная библиотека для работы с окнами и пользовательскими событиями.
Данный драйвер использует также несколько вспомогательных библиотек — например GLEW которая позволяет достаточно простым способом работать с расширениями OpenGL

Цикл работы драйвера.
В целом в типичном приложении работа с видео драйвером выглядит примерно так:
Video::_init();
Video::_create_sprite(…);
Video::_add_sprite(..);
Video::_draw();

Устройство видео драйвера.
Видео драйвер умеет оперировать со следующими объектами:
1. Поверхность — битмап в формате RGBA в котором хранится некая картинка. (на самом деле это текстура, хранящаяся в видео памяти)
2. Спрайт — объект, содержащий в себе поверхность. Несколько спрайтов могут иметь одинаковую поверхность. Представляется в виде квада (GL_QUAD)
3. Частицы — набор частиц, имеют всегда общую поверхность.
4. Событие — объект содержащий информацию о событиях произошедших с приложением (нажатия кнопок, закрытие окна и т.д.)

При добавлении некоторого объекта на отрисовку (add_srite, add_particles) они добавляются в массив объектов которые надо рисовать. Все объекты хранятся внутри видео драйвера, поэтому добавляется только указатель на этот объект и при вызове _draw() по данному вектору происходит построение картинки на экране.

Отрисовка спрайтов.
Как уже было сказано — список спрайтов которые требуется нарисовать лежит в векторе и поидее можно просто идти последовательно по этому списку и делать
glBindTexture(sprite_surface);
glBegin(GL_QUADS);
… рисуем
glEnd();
Однако при использовании такого подхода (а он использовался) мы получим сильное падение производительности, потомучто BindTexture — достаточно медленная операция.
Поэтому в данный момент отрисовка происходит так:
С начала делается glBindTexture для текущего спрайта. Потом ищутся все спрайты, которые используют этуже текстуру и находятся в списке отрисовки. Это дает огромный прирост проивзодительности.

Отрисовка частиц.
Наверное отрисовка частиц — самое геморойная часть видео драйвера. Была главная задача — получить максимальную скорость.
Классическое решение — PointSprites. PointSprite — это большая точка на которую натянута текстура и которая для особой радости окрашена в какойнить цвет.
Однако с ними возникает проблема — не все видеокарты их умеют обрабатывать, а на некоторых АТИ картах с ними имеются крупные проблемы.
Второй вариант — использование квадов — в 4 раза медленней но надежно.
Я решил использовать оба этих варианта — если возможно — PointSprites если нет — GL_QUAD.

Дополнительная оптимизация.
Даже с учетом всех этих рекомендаций скорость всеравно оставляет желать много лучшего. Так на GF8800 GTS получается в районе 300fps при примерно 4000 спрайтов и частиц
Здесь на помощь приходит VBO. Суть его в том, чтобы хранить на видеокарте не только текстуры, но и все координаты и цвета. Так для каждой частицы создаются буферы для хранения их координат и цветов, а в некоторых случаях (если не используется PointSprites) и координат текстур.
Использование VBO повысило скорость работы на старой видеокарте в 5 раз. Разумеется это повышает системные требования, поэтому данная возможность (как и точечные спрайты) является опциональной.

События.
Обработка событий сделана в виде callback функций в библиотеке glfw. В нутри драйвера есть некая очередь в которую складываются все приходящие события. При запросе событий — отдается первое в очереди.

Tags:

This entry was posted on Понедельник, Ноябрь 10th, 2008 at 13:38 and is filed under MagicEngine, Новости. You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings are currently closed.

Comments are closed at this time.