Создайте простой движок 2D спрайтов с кроссплатформенным абстрагированным API
■ Демо должно быть полностью кроссплатформенным и не иметь заголовков для конкретной платформы
■ Кроссплатформенный код полностью изолирован от кода, зависящего от платформы, в том смысле, что в файлах, не зависящих от платформы, нет никаких следов включения заголовков для конкретной платформы.
У меня есть это задание, но я ужасно смущен тем, как я могу сделать что-то кроссплатформенное. У меня уже есть движок, способный делать то, что должен, но мне нужно, чтобы он был кроссплатформенным. Мне больше всего интересно, что я могу включить (или, Как я узнаю, что что-то использует код, специфичный для платформы), и если я не могу включить вещи, потому что они зависят от платформы, я не знаю, как я могу использовать эту функциональность без включая это. Решение лежит где-то в абстракции и Pimpl, по словам однокурсника, но я не могу его найти.
Помимо простого создания своего 2d-движка поверх многоплатформенной библиотеки, как предлагает @ddriver, вы можете выделить большой буфер для цветов пикселей и написать код для рендеринга всех ваших примитивов (отдельных пикселей, линий, прямоугольников, кругов, эллипсов, дуг). , текстуры / растровые изображения / изображения, текстовые символы) в него. После того как вы завершили рендеринг кадра в этом буфере, вы можете вызвать любую библиотеку, чтобы отобразить этот буфер в виде изображения на экране или в окне. Или, если ваш код работает на голом оборудовании без каких-либо вспомогательных библиотек, вы можете просто скопировать этот буфер в видеобуфер видеокарты.
Ваш API может выглядеть примерно так:
typedef struct
{
unsigned BitsPerPixel; // 8,16,32
unsigned ColorScheme; // something that tells the order of the R, G and B components and how many bits are in each or if there's a palette used instead of RGB
unsigned Width; // in pixels
unsigned Height; // in pixels
size_t Size; // buffer size in bytes
void* Buf; // pointer to the beginning of the buffer itself
// extra info
} tBuffer;
int BufferInit(tBuffer* Buf, unsigned BitsPerPixel, unsigned ColorScheme, unsigned Width, unsigned Height)
{
Buf->BitsPerPixel = BitsPerPixel;
Buf->ColorScheme = ColorScheme;
Buf->Width = Width;
Buf->Height = Height;
Buf->Size = Buf->Width * Buf->Height * Buf->BitsPerPixel / 8;
Buf->Buf = malloc(Buf->Size);
if (Buf->Buf != NULL)
{
memset(Buf->Buf, 0, Buf->Size);
return 1;
}
return 0;
}
void BufferDone(tBuffer* Buf)
{
free(Buf->Buf);
Buf->Buf = NULL;
}
unsigned FindClosest8BitPaletteIndex(unsigned R, unsigned G, unsigned B)
{
// find the palette element that's closest to the given R, G and B
// and return its index
}
unsigned BufferRgbToColor(tBuffer* Buf, unsigned R, unsigned G, unsigned B)
{
switch (Buf->BitsPerPixel)
{
case 8:
return FindClosest8BitPaletteIndex(R, G, B);
case 16:
return ((R & 0x1F) << 11) | ((G & 0x3F) << 6) | (B & 0x1F); // 5-6-5
case 32:
return ((R & 0xFF) << 16) | ((G & 0xFF) << 8) | (B & 0xFF); // (8)-8-8-8
default:
return 0; // error
}
}
void BufferSetPixel(tBuffer* Buf, unsigned X, unsigned Y, unsigned Color)
{
switch (Buf->BitsPerPixel)
{
case 8:
*((unsigned char*)Buf->Buf + Buf->Width * Y + X) = Color;
break;
case 16:
*((unsigned short*)Buf->Buf + Buf->Width * Y + X) = Color;
break;
case 32:
*((unsigned*)Buf->Buf + Buf->Width * Y + X) = Color;
break;
}
}
И тогда вы можете использовать это так:
tBuffer buf;
if (BufferInit(&buf, 32, 0, 1024, 768))
{
BufferSetPixel(&buf, 512, 384, BufferRgbToColor(&buf, 0xFF, 0xFF, 0xFF));
// make the contents of buf.Buf visible in some way
BufferDone(&buf);
}
Это должно дать вам несколько идей.
Что ж, если вам нужен независимый от платформы движок, тогда вам нужна переносимая библиотека.
Прежде всего, есть Qt, который сам по себе предлагает абстракцию для создания графики OpenGL (простое открытие контекста OpenGL на нескольких различных платформах может быть серьезной проблемой в нижней части, но Qt делает его переносимым, гибким и занимает всего несколько строк). кода). Он также имеет QML, который является декларативным языком, с которым намного быстрее развиваться. Есть несколько 2D и 3D движков, построенных вокруг Qt (посмотрите V-Play). С QtQuick2 у вас есть аппаратно ускоренная графика. Вы даже можете напечатать фрагментный и векторный шейдеры на ваших 2D объектах во время выполнения.
Кроме того, есть библиотеки, такие как Allegro и SDL — они довольно портативны, хотя поддержка мобильных платформ находится на довольно сырой стадии. Сами библиотеки гораздо более простые, чем Qt. Оба поддерживают OpenGL, но их собственные графические возможности незначительны.
Существует также JUCE, который предлагает некоторые графические возможности, хотя вам в значительной степени придется полагаться на сырой OpenGL, здесь нет абстракции высокого уровня.
Кроме того, существуют библиотеки, такие как MoSync или Marmalade, которые ориентированы на мобильную платформу, и поддержка настольных систем, по-видимому, отсутствует, так что, возможно, это не лучший выбор.
Причина, по которой я начал с Qt, заключается в том, что он, безусловно, является самым мощным, гибким и независимым от всех платформ. Не говоря уже о том, что есть много книг, множество учебников, отличная подробная документация и значительное сообщество. Это то, что я использую и часто рекомендую. Вы даже можете бесплатно разрабатывать коммерческие приложения с ним, единственное условие — это динамическая связь.