131 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			131 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | /*
 | ||
|  | MIT License | ||
|  | 
 | ||
|  | Copyright (c) 2025 tobid7 | ||
|  | 
 | ||
|  | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
|  | of this software and associated documentation files (the "Software"), to deal | ||
|  | in the Software without restriction, including without limitation the rights | ||
|  | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
|  | copies of the Software, and to permit persons to whom the Software is | ||
|  | furnished to do so, subject to the following conditions: | ||
|  | 
 | ||
|  | The above copyright notice and this permission notice shall be included in all | ||
|  | copies or substantial portions of the Software. | ||
|  | 
 | ||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
|  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
|  | SOFTWARE. | ||
|  | */ | ||
|  | 
 | ||
|  | #include <d7rc/atlas.hpp>
 | ||
|  | 
 | ||
|  | namespace D7RC { | ||
|  | Atlas::Atlas(int size) { | ||
|  |   Size = PD::ivec2(size, size); | ||
|  |   Space.push_back(PD::ivec4(0, 0, size, size)); | ||
|  | } | ||
|  | 
 | ||
|  | bool Atlas::AppendImage(PD::Image::Ref img, const std::string& name) { | ||
|  |   for (size_t i = 0; i < Space.size(); i++) { | ||
|  |     auto& it = Space[i]; | ||
|  |     PD::ivec2 size = PD::ivec2(it.z, it.w); | ||
|  |     if (img->Width() <= size.x && img->Height() <= size.y) { | ||
|  |       Entry e; | ||
|  |       e.Name = name; | ||
|  |       e.iImg = img; | ||
|  |       e.iPos = PD::ivec2(it.x, it.y); | ||
|  |       e.Size = PD::ivec2(img->Width(), img->Height()); | ||
|  |       e.UV = PD::fvec4((float)it.x / (float)Size.x, (float)it.y / (float)Size.y, | ||
|  |                        (float)(it.x + img->Width()) / (float)Size.x, | ||
|  |                        (float)(it.x + img->Height()) / (float)Size.y); | ||
|  |       Entries.push_back(e); | ||
|  | #ifdef DEBUG
 | ||
|  |       std::cout << std::format("Created Image {} ({})\n", name, | ||
|  |                                PD::ivec4(e.iPos, e.Size)); | ||
|  | #endif
 | ||
|  |       if (e.iPos.x + e.Size.x > Max.x) { | ||
|  |         Max.x = e.iPos.x + e.Size.x; | ||
|  |       } | ||
|  |       if (e.iPos.y + e.Size.y > Max.y) { | ||
|  |         Max.y = e.iPos.y + e.Size.y; | ||
|  |       } | ||
|  |       pSplit(i, PD::ivec4(it.x, it.y, img->Width(), img->Height())); | ||
|  |       return true; | ||
|  |     } | ||
|  |   } | ||
|  |   return false; | ||
|  | } | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * TODO: Need a smarter splitting algo | ||
|  |  * Does not really find free spaces yet | ||
|  |  */ | ||
|  | void Atlas::pSplit(int i, PD::ivec4 area) { | ||
|  |   auto s = Space[i]; | ||
|  |   Space.erase(Space.begin() + i); | ||
|  | 
 | ||
|  |   if (area.x + area.z < s.x + s.z) | ||
|  |     Space.emplace_back(area.x + area.z, s.y, (s.x + s.z) - (area.x + area.z), | ||
|  |                        area.w); | ||
|  |   if (area.y + area.w < s.y + s.w) | ||
|  |     Space.emplace_back(s.x, area.y + area.w, s.z, | ||
|  |                        (s.y + s.w) - (area.y + area.w)); | ||
|  |   std::sort(Space.begin(), Space.end(), | ||
|  |             [](PD::ivec4& a, PD::ivec4& b) { return a.y < b.y && a.x < b.x; }); | ||
|  | } | ||
|  | 
 | ||
|  | void Atlas::Pack() { | ||
|  |   if (!PD::BitUtil::IsSingleBit(Max.x)) { | ||
|  |     Size.x = PD::BitUtil::GetPow2(Max.x); | ||
|  |   } | ||
|  |   if (!PD::BitUtil::IsSingleBit(Max.y)) { | ||
|  |     Size.y = PD::BitUtil::GetPow2(Max.y); | ||
|  |   } | ||
|  |   Img.resize(Size.x * Size.y * 4); | ||
|  |   for (auto& it : Entries) { | ||
|  |     for (int i = 0; i < it.Size.x; i++) { | ||
|  |       for (int j = 0; j < it.Size.y; j++) { | ||
|  |         Img[((j + it.iPos.y) * Size.x + (it.iPos.x + i)) * 4] = | ||
|  |             it.iImg->pBuffer[(j * it.iImg->pWidth + i) * 4]; | ||
|  |         Img[((j + it.iPos.y) * Size.x + (it.iPos.x + i)) * 4 + 1] = | ||
|  |             it.iImg->pBuffer[(j * it.iImg->pWidth + i) * 4 + 1]; | ||
|  |         Img[((j + it.iPos.y) * Size.x + (it.iPos.x + i)) * 4 + 2] = | ||
|  |             it.iImg->pBuffer[(j * it.iImg->pWidth + i) * 4 + 2]; | ||
|  |         Img[((j + it.iPos.y) * Size.x + (it.iPos.x + i)) * 4 + 3] = | ||
|  |             it.iImg->pBuffer[(j * it.iImg->pWidth + i) * 4 + 3]; | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  | #ifdef DEBUG
 | ||
|  |   std::cout << std::format("Created Texture ({})\n", Size); | ||
|  | #endif
 | ||
|  | } | ||
|  | 
 | ||
|  | void Atlas::LoadTextures() { | ||
|  |   pTex = PD::Gfx::LoadTex(Img, Size.x, Size.y); | ||
|  |   for (auto& it : Entries) { | ||
|  |     it.iTex = PD::Li::Texture::New(); | ||
|  |     it.iTex->Address = pTex->Address; | ||
|  |     it.iTex->Size = it.Size; | ||
|  |     it.iTex->UV = it.UV; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | PD::Li::Texture::Ref Atlas::Get(const std::string& name) { | ||
|  |   if (!pTex) { | ||
|  |     return nullptr; | ||
|  |   } | ||
|  |   for (auto& it : Entries) { | ||
|  |     if (it.Name == name) { | ||
|  |       return it.iTex; | ||
|  |     } | ||
|  |   } | ||
|  |   return nullptr; | ||
|  | } | ||
|  | }  // namespace D7RC
 |