Вероятно, существуют некоторые библиотеки для создания атласов текстур (оптимальная упаковка - нетривиальная задача) и преобразования старых координат текстуры в новые.
Однако, если вы хотите сделать это самостоятельно, вы, вероятно, сделаете что-то вроде этого:
- Загрузка всех текстур с диска (ваш «исходный PNG») и получение буфера необработанных пикселей,
- При необходимости, преобразовать все исходные текстуры в один и тот же формат пикселей,
- Создайте новую текстуру, достаточно большую, чтобы вместить все существующие текстуры, вместе с соответствующим буфером для хранения данных пикселей
- «Blit» данных пикселей из исходных изображений в новый буфер с заданным смещением (см. Ниже)
- Создать текстуру как обычно, используя данные нового буфера.
- При этом определите отображение из «старых» координат текстуры в «новые» координаты текстуры (должно быть просто записать смещения для каждого элемента атласа текстуры и выполнить быстрое преобразование). Вероятно, было бы также довольно легко сделать это внутри пиксельного шейдера, но некоторое профилирование потребовалось бы, чтобы посмотреть, стоит ли это накладных расходов на передачу дополнительных параметров.
Очевидно, что вы также хотите проверить, чтобы убедиться, что вы не делаете глупостей, например, дважды загружаете одну и ту же текстуру в атлас, но это не относится к этой процедуре.
Чтобы «скопировать» (скопировать) исходное изображение на целевое, вы должны сделать что-то вроде этого (при условии, что вы копируете текстуру 128x128 в текстуру атласа 512x512, начиная с (128, 0) на цели ):
unsigned char* source = new unsigned char[ 128 * 128 * 4 ]; // in reality, comes from your texture loader
unsigned char* target = new unsigned char[ 512 * 512 * 4 ];
int targetX = 128;
int targetY = 0;
for(int sourceY = 0; sourceY < 128; ++sourceY) {
for(int sourceX = 0; sourceX < 128; ++sourceX) {
int from = (sourceY * 128 * 4) + (sourceX * 4); // 4 bytes per pixel (assuming RGBA)
int to = ((targetY + sourceY) * 512 * 4) + ((targetX + sourceX) * 4); // same format as source
for(int channel = 0; channel < 4; ++channel) {
target[to + channel] = source[from + channel];
}
}
}
Это очень простая реализация грубой силы: есть гораздо более быстрые, краткие и более умные способы копирования массива, но идея заключается в том, что вы в основном копируете содержимое исходной текстуры в целевую текстуру с заданной X и Y смещены. В конце концов, вы создадите новую текстуру, которая содержит старые текстуры.
Если математика индексирования не имеет для вас смысла, подумайте , как двумерный массив на самом деле индексируется в одномерном пространстве (например, в памяти компьютера).
Пожалуйста, прости любые ошибки. Это не рабочий код, а то, что я написал, не проверяя, компилируется ли он или запускается.
Поскольку вы используете SDL, я должен упомянуть, что у него есть хорошая функция, которая может вам помочь: SDL_BlitSurface
. Вы можете создать SDL_Surface
полностью в SDL и просто использовать SDL_BlitSurface
, чтобы скопировать в него исходные поверхности, а затем преобразовать поверхность атласа в текстуру GL .
Он позаботится обо всей математике, а также может сделать преобразование формата для вас на лету.