GLTexture* MapTextureManager::getSprite(string name, string translation, string palette) { // Don't bother looking for nameless sprites if (name.IsEmpty()) return NULL; // Get sprite matching name string hashname = name.Upper(); if (!translation.IsEmpty()) hashname += translation.Lower(); if (!palette.IsEmpty()) hashname += palette.Upper(); map_tex_t& mtex = sprites[hashname]; // Get desired filter type int filter = 1; if (map_tex_filter == 0) filter = GLTexture::NEAREST_LINEAR_MIN; else if (map_tex_filter == 1) filter = GLTexture::LINEAR; else if (map_tex_filter == 2) filter = GLTexture::LINEAR; else if (map_tex_filter == 3) filter = GLTexture::NEAREST_MIPMAP; // If the texture is loaded if (mtex.texture) { // If the texture filter matches the desired one, return it if (mtex.texture->getFilter() == filter) return mtex.texture; else { // Otherwise, reload the texture delete mtex.texture; mtex.texture = NULL; } } // Sprite not found, look for it bool found = false; bool mirror = false; SImage image; Palette8bit* pal = getResourcePalette(); ArchiveEntry* entry = theResourceManager->getPatchEntry(name, "sprites", archive); if (!entry) entry = theResourceManager->getPatchEntry(name, "", archive); if (!entry && name.length() == 8) { string newname = name; newname[4] = name[6]; newname[5] = name[7]; newname[6] = name[4]; newname[7] = name[5]; entry = theResourceManager->getPatchEntry(newname, "sprites", archive); if (entry) mirror = true; } if (entry) { found = true; Misc::loadImageFromEntry(&image, entry); } else // Try composite textures then { CTexture* ctex = theResourceManager->getTexture(name, archive); if (ctex && ctex->toImage(image, archive, pal)) found = true; } // We have a valid image either from an entry or a composite texture. if (found) { // Apply translation if (!translation.IsEmpty()) image.applyTranslation(translation, pal); // Apply palette override if (!palette.IsEmpty()) { ArchiveEntry* newpal = theResourceManager->getPaletteEntry(palette, archive); if (newpal && newpal->getSize() == 768) { // Why is this needed? // Copying data in pal->loadMem shouldn't // change it in the original entry... // We shouldn't need to copy the data in a temporary place first. pal = image.getPalette(); MemChunk mc; mc.importMem(newpal->getData(), newpal->getSize()); pal->loadMem(mc); } } // Apply mirroring if (mirror) image.mirror(false); // Turn into GL texture mtex.texture = new GLTexture(false); mtex.texture->setFilter(filter); mtex.texture->setTiling(false); mtex.texture->loadImage(&image, pal); return mtex.texture; } else if (name.EndsWith("?")) { name.RemoveLast(1); GLTexture* sprite = getSprite(name + '0', translation, palette); if (!sprite) sprite = getSprite(name + '1', translation, palette); if (sprite) return sprite; if (!sprite && name.length() == 5) { for (char chr = 'A'; chr <= ']'; ++chr) { sprite = getSprite(name + '0' + chr + '0', translation, palette); if (sprite) return sprite; sprite = getSprite(name + '1' + chr + '1', translation, palette); if (sprite) return sprite; } } } return NULL; }
// ----------------------------------------------------------------------------- // Returns the sprite matching [name], loading it from resources if necessary. // Sprite name also supports wildcards (?) // ----------------------------------------------------------------------------- const MapTextureManager::Texture& MapTextureManager::sprite( std::string_view name, std::string_view translation, std::string_view palette) { // Don't bother looking for nameless sprites if (name.empty()) return tex_invalid; // Get sprite matching name /*auto hashname = StrUtil::upper(name); if (!translation.empty()) hashname += StrUtil::lower(translation); if (!palette.empty()) hashname += StrUtil::upper(palette);*/ auto hashname = fmt::format("{}{}{}", name, translation, palette); StrUtil::upperIP(hashname); auto& mtex = sprites_[hashname]; // Get desired filter type auto filter = OpenGL::TexFilter::Linear; if (map_tex_filter == 0) filter = OpenGL::TexFilter::NearestLinearMin; else if (map_tex_filter == 1) filter = OpenGL::TexFilter::Linear; else if (map_tex_filter == 2) filter = OpenGL::TexFilter::Linear; else if (map_tex_filter == 3) filter = OpenGL::TexFilter::NearestMipmap; // If the texture is loaded if (mtex.gl_id) { // If the texture filter matches the desired one, return it auto& tex_info = OpenGL::Texture::info(mtex.gl_id); if (tex_info.filter == filter) return mtex; else { // Otherwise, reload the texture OpenGL::Texture::clear(mtex.gl_id); mtex.gl_id = 0; } } // Sprite not found, look for it bool found = false; bool mirror = false; SImage image; // Palette8bit* pal = getResourcePalette(); auto entry = App::resources().getPatchEntry(name, "sprites", archive_); if (!entry) entry = App::resources().getPatchEntry(name, "", archive_); if (!entry && name.length() == 8) { std::string newname{ name }; newname[4] = name[6]; newname[5] = name[7]; newname[6] = name[4]; newname[7] = name[5]; entry = App::resources().getPatchEntry(newname, "sprites", archive_); if (entry) mirror = true; } if (entry) { found = true; Misc::loadImageFromEntry(&image, entry); } else // Try composite textures then { auto ctex = App::resources().getTexture(name, archive_); if (ctex && ctex->toImage(image, archive_, palette_.get(), true)) found = true; } // We have a valid image either from an entry or a composite texture. if (found) { auto pal = palette_.get(); // Apply translation if (!translation.empty()) image.applyTranslation(translation, pal, true); // Apply palette override if (!palette.empty()) { auto newpal = App::resources().getPaletteEntry(palette, archive_); if (newpal && newpal->size() == 768) { pal = image.palette(); pal->loadMem(newpal->data()); } } // Apply mirroring if (mirror) image.mirror(false); // Turn into GL texture mtex.gl_id = OpenGL::Texture::createFromImage(image, pal, filter, false); return mtex; } else if (name.back() == '?') { name.remove_suffix(1); auto stex = &sprite(fmt::format("{}0", name), translation, palette); if (!stex->gl_id) stex = &sprite(fmt::format("{}1", name), translation, palette); if (stex->gl_id) return *stex; if (!stex->gl_id && name.length() == 5) { for (char chr = 'A'; chr <= ']'; ++chr) { stex = &sprite(fmt::format("{}0{}0", name, chr), translation, palette); if (stex->gl_id) return *stex; stex = &sprite(fmt::format("{}1{}1", name, chr), translation, palette); if (stex->gl_id) return *stex; } } } return tex_invalid; }