Browse Source

Pack repeatable textures first, followed by other textures in the remaining space. This is actually producing more efficient textures atlases. The hell.

master
Nico de Poel 3 years ago
parent
commit
eb3de1b624
  1. 40
      texture.cpp

40
texture.cpp

@ -253,12 +253,11 @@ bool process_textures(const world_t* world, TextureList& outTextures)
outTim.clutYoffs = 0; outTim.clutYoffs = 0;
generate_clut(palette, &outTim); generate_clut(palette, &outTim);
const auto max_bin = rectpack2D::rect_wh(1024, 256); // 8-bit textures take up half the horizontal space so this is 512x256 in practice, or a quarter of the PS1's VRAM allocation.
auto max_bin = rectpack2D::rect_wh(1024, 256); // 8-bit textures take up half the horizontal space so this is 512x256 in practice, or a quarter of the PS1's VRAM allocation.
printf("Finding best texture packing...\n"); printf("Finding best texture packing...\n");
std::map<int, miptex_t*> textures;
std::vector<rect_type> rectangles;
std::map<int, miptex_t*> textures, repeatables;
// Try some texture packing and see if we fit inside the PS1's VRAM // Try some texture packing and see if we fit inside the PS1's VRAM
for (int texNum = 0; texNum < world->mipheader.numtex; ++texNum) for (int texNum = 0; texNum < world->mipheader.numtex; ++texNum)
@ -269,10 +268,41 @@ bool process_textures(const world_t* world, TextureList& outTextures)
//printf("Texture %d (%dx%d): %.16s\n", texNum, miptex->width, miptex->height, miptex->name); //printf("Texture %d (%dx%d): %.16s\n", texNum, miptex->width, miptex->height, miptex->name);
if (texture_isRepeatable(miptex))
repeatables[texNum] = miptex;
else
textures[texNum] = miptex; textures[texNum] = miptex;
} }
const auto result_size = pack_textures(textures, max_bin, rectangles);
// Pack the repeatable textures first, so that they get placed at predictable locations
// rectpack2D is set up to pack larger textures first, so this actually works out with power-of-two textures
std::vector<rect_type> rRects;
const auto rSize = pack_textures(repeatables, max_bin, rRects);
max_bin.w -= rSize.w;
// Pack the remaining textures into the remaining space
std::vector<rect_type> tRects;
const auto tSize = pack_textures(textures, max_bin, tRects);
auto result_size = rectpack2D::rect_wh(rSize.w + tSize.w, max(rSize.h, tSize.h));
// Collect all of the texture rectangles back into a single in-order list again
std::vector<rect_type> rectangles;
auto rIter = rRects.begin();
auto tIter = tRects.begin();
for (int texNum = 0; texNum < world->mipheader.numtex; ++texNum)
{
if (repeatables.find(texNum) != repeatables.end())
{
rectangles.push_back(*rIter++);
continue;
}
auto rect = *tIter++;
rect.x += rSize.w;
rectangles.push_back(rect);
}
printf("%d textures. Packed texture atlas size: %d x %d\n", world->mipheader.numtex, result_size.w, result_size.h); printf("%d textures. Packed texture atlas size: %d x %d\n", world->mipheader.numtex, result_size.w, result_size.h);
@ -320,7 +350,7 @@ bool process_textures(const world_t* world, TextureList& outTextures)
tex.ps1tex.tpage = getTPage(outTim.format, 0, x, y); tex.ps1tex.tpage = getTPage(outTim.format, 0, x, y);
tex.uoffs = (u_char)((x % 64) << (2 - outTim.format)); tex.uoffs = (u_char)((x % 64) << (2 - outTim.format));
tex.voffs = (u_char)(y & 0xFF); tex.voffs = (u_char)(y & 0xFF);
tex.ps1tex.twin = getTexWindow(tex.uoffs, tex.voffs, tex.w, tex.h); // TODO: figure out the right offsets that are multiples of w and h
tex.ps1tex.twin = getTexWindow(tex.uoffs, tex.voffs, tex.w, tex.h); // TODO: figure out the right offsets that are multiples of w and h; NOTE: if uoffs has to >> 1, then w probably has to as well
} }
} }

Loading…
Cancel
Save