// ----------------------------------------------------------------------------- // Detects offset hacks such as that used by the wall torch thing in Heretic. // If the Y offset is noticeably larger than the sprite height, that means the // thing is supposed to be rendered above its real position. // ----------------------------------------------------------------------------- int MapTextureManager::verticalOffset(std::string_view name) const { // Don't bother looking for nameless sprites if (name.empty()) return 0; // Get sprite matching name auto entry = App::resources().getPatchEntry(name, "sprites", archive_); if (!entry) entry = App::resources().getPatchEntry(name, "", archive_); if (entry) { SImage image; Misc::loadImageFromEntry(&image, entry); int h = image.height(); int o = image.offset().y; if (o > h) return o - h; else return 0; } return 0; }
// ----------------------------------------------------------------------------- // 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; }