Давным-давно, в далёкой-далёкой галактике Художники подумали и решили, что слишком много времени они тратят на сборку текстурных атласов. А раз есть у них Программист, то пускай он мучается с этой проблемой. Почесал Программист репу и начал думать. Первой мыслью было использовать программы для автоматической генерации атласов. Мысль вроде хорошая, но Художники народ ленивый, не станут они марать свои творческие руки о прах бытия. Так что Программист решил ввести функцию сборки атласов в движок, дабы С++ отдувался и за него, и за художников :) Что для этого потребовалось: 1. Всего-лишь библиотека FreeLib и немного размышлений. Для начала, нам нужно загрузить PNG текстуру в оперативную память
void C_Texture_Loader::Add(std::wstring Name, std::wstring Path, int Width, int Height){
FIBITMAP *dib = FreeImage_LoadU(FIF_PNG, (wchar_t*)Path.c_str(), PNG_DEFAULT);
DraftTextures[Name].dib = dib;
DraftTextures[Name].Width = FreeImage_GetWidth(dib);
DraftTextures[Name].Height = FreeImage_GetHeight(dib);
DraftTextures[Name].Pitch = FreeImage_GetPitch(dib);
}
Тут в принципе всё должно быть понятно. В переменную dib загоняем указатель на текстуру, а в ассоциативный массив (std::map) загоняем данные, необходимые для дальнейшего построения атласа.
void C_Texture_Loader::GenerateTextureAtlases()
{
if (DraftTextures.size() == 0)return;
NextX=0;
NextY=0;
CurrentTexture=0;
MaxY=0;
std::wstring CurrentTextureS;
CurrentTextureS = L"t"+IntToWString(CurrentTexture);
TA_Count++; //Количество текстур
//Создаём текстуру 1024*1024
D3DXCreateTexture(DirectX_Device->Device,1024,1024,1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED,&texture[CurrentTextureS].Texture);
D3DLOCKED_RECT RectLock;
RECT r;
r.left = r.top = 0;
r.right = 1024;
r.bottom = 1024;
//Лочим текстру
texture[CurrentTextureS].Texture->LockRect(0,&RectLock,&r,0);
BYTE* PixelMap = (BYTE *)RectLock.pBits;
DraftTextures_Iter = DraftTextures.begin();
for (int i=0; i<DraftTextures.size(); i++)
{
//Проверка, что текущая текстура выходит за пределы атласа
//Если выходит - тогда создаём новый атлас
if (DraftTextures_Iter->second.Height > MaxY)
{
MaxY = DraftTextures_Iter->second.Height;
}
if (NextX+DraftTextures_Iter->second.Width > 1024 || NextY+DraftTextures_Iter->second.Height > 1024)
{
NextX=0;
NextY+=MaxY+1;
MaxY=0;
if (NextY>1024||NextY+DraftTextures_Iter->second.Height >= 1024)
{
NextY=0;
MaxY = DraftTextures_Iter->second.Height;
texture[CurrentTextureS].Texture->UnlockRect(0);
TA_Count++;
CurrentTexture++;
CurrentTextureS = L"t"+IntToWString(CurrentTexture);
D3DXCreateTexture(DirectX_Device->Device,1024,1024,1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED,&texture[CurrentTextureS].Texture);
texture[CurrentTextureS].Texture->LockRect(0,&RectLock,&r,0);
PixelMap = (BYTE *)RectLock.pBits;
}
}
//BitsOffset - Количество байтов в строке изображения
int BitsOffset = DraftTextures_Iter->second.Pitch/DraftTextures_Iter->second.Width;
BYTE * bits = FreeImage_GetBits(DraftTextures_Iter->second.dib);
//Переход к последнему байту изображения
//Считываем изображение задом наперёд, потому что
//оно хранится в памяти перевёрнутым
bits+=DraftTextures_Iter->second.Pitch*DraftTextures_Iter->second.Height-DraftTextures_Iter->second.Pitch;
for (int y=NextY; y<NextY+DraftTextures_Iter->second.Height; y++)
{
BYTE * pixel = (BYTE*)bits;
//Попиксельный проход
for (int x=NextX; x<NextX+DraftTextures_Iter->second.Width; x++)
{
PixelMap[x*4+(RectLock.Pitch*(y))] = pixel[0];//blue
PixelMap[x*4+(RectLock.Pitch*(y))+1] = pixel[1];//green
PixelMap[x*4+(RectLock.Pitch*(y))+2] = pixel[2];//red
//BitsOffset равняется 4 тогда, когда у изображения есть альфа канал
if (BitsOffset == 4)
PixelMap[x*4+(RectLock.Pitch*(y))+3] = pixel[3];//alpha
else
PixelMap[x*4+(RectLock.Pitch*(y))+3] = 255;
pixel+=BitsOffset;
}
bits-=DraftTextures_Iter->second.Pitch;
}
NextX+=DraftTextures_Iter->second.Width+1;
DraftTextures_Iter++;
}
texture[CurrentTextureS].Texture->UnlockRect(0);
}
Комментариев нет:
Отправить комментарий