Initial Commit
This commit is contained in:
131
source/lib/atlas.cpp
Normal file
131
source/lib/atlas.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
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
|
||||
Reference in New Issue
Block a user