Давным-давно, в далёкой-далёкой галактике Художники подумали и решили, что слишком много времени они тратят на сборку текстурных атласов. А раз есть у них Программист, то пускай он мучается с этой проблемой. Почесал Программист репу и начал думать. Первой мыслью было использовать программы для автоматической генерации атласов. Мысль вроде хорошая, но Художники народ ленивый, не станут они марать свои творческие руки о прах бытия. Так что Программист решил ввести функцию сборки атласов в движок, дабы С++ отдувался и за него, и за художников :) Что для этого потребовалось: 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); }
Комментариев нет:
Отправить комментарий