#include "TextureSheet.h" namespace New3D { TextureSheet::TextureSheet() { m_temp.resize(1024 * 1024 * 4); // temporay buffer for textures } int TextureSheet::ToIndex(int x, int y) { return (y * 2048) + x; } std::shared_ptr TextureSheet::BindTexture(const UINT16* src, int format, bool mirrorU, bool mirrorV, int x, int y, int width, int height) { //======== int index; //======== x &= 2047; y &= 2047; if ((x + width) > 2048 || (y + height) > 2048) { return nullptr; } if (width > 1024 || height > 1024) { // sanity checking return nullptr; } index = ToIndex(x, y); auto range = m_texMap[format].equal_range(index); if (range.first == range.second) { // nothing found so create a new texture std::shared_ptr t(new Texture()); m_texMap[format].insert(std::pair>(index, t)); t->UploadTexture(src, m_temp.data(), format, mirrorU, mirrorV, x, y, width, height); return t; } else { // iterate to try and find a match for (auto it = range.first; it != range.second; ++it) { int x2, y2, width2, height2, format2; it->second->GetDetails(x2, y2, width2, height2, format2); if (width == width2 && height == height2) { return it->second; } } // nothing found so create a new entry std::shared_ptr t(new Texture()); m_texMap[format].insert(std::pair>(index, t)); t->UploadTexture(src, m_temp.data(), format, mirrorU, mirrorV, x, y, width, height); return t; } } void TextureSheet::Release() { for (int i = 0; i < 12; i++) { m_texMap[i].clear(); } } void TextureSheet::Invalidate(int x, int y, int width, int height) { //============ int newX; int newY; int newWidth; int newHeight; int count; int sWidth; // sample width int sHeight; // sample height //============ if (width <= 512) { newX = (x + width) - 512; newWidth = 512; } else { newX = x; newWidth = width; } if (height <= 512) { newY = (y + height) - 512; newHeight = 512; } else { newY = y; newHeight = height; } CropTile(x, y, newX, newY, newWidth, newHeight); sWidth = newWidth / 32; sHeight = newHeight / 32; count = sWidth * sHeight; for (int i = 0; i < count; i++) { int posX = newX + ((i%sWidth) * 32); int posY = newY + ((i / sWidth) * 32); int index = ToIndex(posX, posY); if (posX >= x && posY >= y) { // invalidate this area of memory for (int j = 0; j < 12; j++) { m_texMap[j].erase(index); } } else { // check for overlapping data tiles and invalidate as necessary for (int j = 0; j < 12; j++) { auto range = m_texMap[j].equal_range(index); for (auto it = range.first; it != range.second; ++it) { if (it->second->CheckMapPos(x, x + width, y, y + height)) { m_texMap[j].erase(index); break; } } } } } } void TextureSheet::CropTile(int oldX, int oldY, int &newX, int &newY, int &newWidth, int &newHeight) { if (newX < 0) { newWidth += newX; newX = 0; } if (newY < 0) { newHeight += newY; newY = 0; } if (oldY >= 1024 && newY < 1024) { // gone into next memory page, limitation of our flat model newHeight -= 1024 - newY; newY = 1024; } } int TextureSheet::GetTexFormat(int originalFormat, bool contour) { if (!contour) { return originalFormat; // the same } switch (originalFormat) { case 1: case 2: case 3: case 4: return originalFormat + 7; // these formats are identical to 1-4, except they lose the 4 bit alpha part when contour is enabled default: return originalFormat; } } void TextureSheet::GetMicrotexPos(int basePage, int id, int& x, int& y) { int xCoords[8] = { 0, 0, 128, 128, 0, 0, 128, 128 }; int yCoords[8] = { 0, 128, 0, 128, 256, 384, 256, 384 }; // i'm assuming .. the micro texture map is always on the other memory bank to the base texture // this logic works for all our current games // the microtextures are always on the top left of each texture sheet basePage = (basePage + 1) & 1; // wrap around base page x = xCoords[id]; y = yCoords[id] + (basePage * 1024); } } // New3D