// ----------------------------------------------------------------------------- // Search for errors in texture list, return true if any are found // ----------------------------------------------------------------------------- bool TextureXList::findErrors() { bool ret = false; // Texture errors: // 1. A texture without any patch // 2. A texture with missing patches // 3. A texture with columns not covered by a patch for (unsigned a = 0; a < textures_.size(); a++) { if (textures_[a]->nPatches() == 0) { ret = true; Log::warning("Texture {}: {} does not have any patch", a, textures_[a]->name()); } else { vector<uint8_t> columns(textures_[a]->width()); memset(columns.data(), 0, textures_[a]->width()); for (size_t i = 0; i < textures_[a]->nPatches(); ++i) { auto patch = textures_[a]->patches_[i]->patchEntry(); if (patch == nullptr) { ret = true; Log::warning( "Texture {}: {}: patch {} cannot be found in any open archive", a, textures_[a]->name(), textures_[a]->patches_[i]->name()); // Don't list missing columns when we don't know the size of the patch memset(columns.data(), 1, textures_[a]->width()); } else { SImage img; img.open(patch->data()); size_t start = std::max<size_t>(0, textures_[a]->patches_[i]->xOffset()); size_t end = std::min<size_t>(textures_[a]->width(), img.width() + start); for (size_t c = start; c < end; ++c) columns[c] = 1; } } for (size_t c = 0; c < textures_[a]->width(); ++c) { if (columns[c] == 0) { ret = true; Log::warning("Texture {}: {}: column {} without a patch", a, textures_[a]->name(), c); break; } } } } return ret; }
// ----------------------------------------------------------------------------- // Returns the texture matching [name], loading it from resources if necessary. // If [mixed] is true, flats are also searched if no matching texture is found // ----------------------------------------------------------------------------- const MapTextureManager::Texture& MapTextureManager::texture(std::string_view name, bool mixed) { // Get texture matching name auto& mtex = textures_[StrUtil::upper(name)]; // 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::LinearMipmap; 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; } } // Texture not found or unloaded, look for it // Look for stand-alone textures first auto etex = App::resources().getTextureEntry(name, "hires", archive_); auto textypefound = CTexture::Type::HiRes; if (etex == nullptr) { etex = App::resources().getTextureEntry(name, "textures", archive_); textypefound = CTexture::Type::Texture; } if (etex) { SImage image; // Get image format hint from type, if any if (Misc::loadImageFromEntry(&image, etex)) { mtex.gl_id = OpenGL::Texture::createFromImage(image, palette_.get(), filter); // Handle hires texture scale if (textypefound == CTexture::Type::HiRes) { auto ref = App::resources().getTextureEntry(name, "textures", archive_); if (ref) { SImage imgref; if (Misc::loadImageFromEntry(&imgref, ref)) { int w, h, sw, sh; w = image.width(); h = image.height(); sw = imgref.width(); sh = imgref.height(); mtex.world_panning = true; mtex.scale = { (double)sw / (double)w, (double)sh / (double)h }; } } } } } // Try composite textures then auto ctex = App::resources().getTexture(name, archive_); if (ctex) // Composite textures take precedence over the textures directory { textypefound = CTexture::Type::WallTexture; SImage image; if (ctex->toImage(image, archive_, palette_.get(), true)) { mtex.gl_id = OpenGL::Texture::createFromImage(image, palette_.get(), filter); double sx = ctex->scaleX(); if (sx == 0) sx = 1.0; double sy = ctex->scaleY(); if (sy == 0) sy = 1.0; mtex.world_panning = ctex->worldPanning(); mtex.scale = { 1.0 / sx, 1.0 / sy }; } } // Not found if (!mtex.gl_id) { // Try flats if mixed if (mixed) return flat(name, false); // Otherwise use missing texture mtex.gl_id = OpenGL::Texture::missingTexture(); } return mtex; }