#include #include #include #include #include bool TextureLoader::loadFromFile(std::string filename, GTAData* gameData) { std::ifstream dfile(filename); if ( ! dfile.is_open()) { std::cerr << "Error opening file " << filename << std::endl; return false; } dfile.seekg(0, std::ios_base::end); size_t length = dfile.tellg(); dfile.seekg(0); char *data = new char[length]; dfile.read(data, length); return loadFromMemory(data, gameData); } GLuint gErrorTextureData[] = { 0x00FF00FF, 0x00FFFFFF, 0x00FFFFFF, 0x00FF00FF }; bool TextureLoader::loadFromMemory(char *data, GTAData *gameData) { RW::BinaryStreamSection root(data); auto texDict = root.readStructure(); size_t rootI = 0; while (root.hasMoreData(rootI)) { auto rootSection = root.getNextChildSection(rootI); if (rootSection.header.id != RW::SID_TextureNative) continue; RW::BSTextureNative texNative = rootSection.readStructure(); /// Short circuit for things we dont support. if(texNative.platform != 8) { std::cerr << "Unsupported texture platform " << std::dec << texNative.platform << std::endl; continue; } bool isPal8 = (texNative.rasterformat & RW::BSTextureNative::FORMAT_EXT_PAL8) == RW::BSTextureNative::FORMAT_EXT_PAL8; bool isFulc = texNative.rasterformat == RW::BSTextureNative::FORMAT_1555 || texNative.rasterformat == RW::BSTextureNative::FORMAT_8888 || texNative.rasterformat == RW::BSTextureNative::FORMAT_888; if(! (isPal8 || isFulc)) { std::cerr << "Unsuported raster format " << std::dec << texNative.rasterformat << std::endl; continue; } TextureAtlas* atlas; glm::vec4 texRect; size_t ai = 0; size_t texW = texNative.width, texH = texNative.height; do { atlas = gameData->getAtlas(ai++); } while(! atlas->canPack(&texW, &texH, 1)); if(isPal8) { uint32_t fullColor[texNative.width * texNative.height]; size_t paletteSize = sizeof(uint32_t) * 256; uint8_t* coldata = reinterpret_cast(rootSection.raw() + sizeof(RW::BSSectionHeader) + sizeof(RW::BSTextureNative) + paletteSize); if((texNative.rasterformat & RW::BSTextureNative::FORMAT_8888) == RW::BSTextureNative::FORMAT_8888) { uint32_t* palette = reinterpret_cast(rootSection.raw() + sizeof(RW::BSSectionHeader) + sizeof(RW::BSTextureNative) - 4); for(size_t j = 0, iTex = 0, iPal = 0; j < texNative.width * texNative.height; ++j) { iTex = j; iPal = coldata[j]; fullColor[iTex] = palette[iPal]; } } else { uint32_t* palette = reinterpret_cast(rootSection.raw() + sizeof(RW::BSSectionHeader) + sizeof(RW::BSTextureNative) - 4); for(size_t j = 0, iTex = 0, iPal = 0; j < texNative.width * texNative.height; ++j) { iTex = j; iPal = coldata[j]; fullColor[iTex] = 0xFF000000 | palette[iPal]; } } atlas->packTextureFormat( fullColor, GL_RGBA, GL_UNSIGNED_BYTE, texNative.width, texNative.height, texRect.x, texRect.y, texRect.z, texRect.w); } else if(isFulc) { auto coldata = rootSection.raw() + sizeof(RW::BSTextureNative); coldata += sizeof(uint32_t); GLenum type, format; switch(texNative.rasterformat) { case RW::BSTextureNative::FORMAT_1555: format = GL_RGBA; type = GL_UNSIGNED_SHORT_1_5_5_5_REV; break; case RW::BSTextureNative::FORMAT_8888: format = GL_BGRA; type = GL_UNSIGNED_INT_8_8_8_8_REV; break; case RW::BSTextureNative::FORMAT_888: format = GL_BGR; type = GL_UNSIGNED_BYTE; break; } atlas->packTextureFormat( coldata, format, type, texNative.width, texNative.height, texRect.x, texRect.y, texRect.z, texRect.w); } // todo: not completely ignore everything the TXD says. /*glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); glGenerateMipmap(GL_TEXTURE_2D);*/ std::string name = std::string(texNative.diffuseName); gameData->textures.insert({name, {atlas, texRect}}); } return true; }