/* EntryOperations::createTexture * Same as addToPatchTable, but also creates a single-patch texture * from each added patch *******************************************************************/ bool EntryOperations::createTexture(vector<ArchiveEntry*> entries) { // Check any entries were given if (entries.size() == 0) return true; // Get parent archive Archive* parent = entries[0]->getParent(); // Create texture entries if needed if (!TextureXEditor::setupTextureEntries(parent)) return false; // Find texturex entry to add to Archive::search_options_t opt; opt.match_type = EntryType::getType("texturex"); ArchiveEntry* texturex = parent->findFirst(opt); // Check it exists bool zdtextures = false; if (!texturex) { opt.match_type = EntryType::getType("zdtextures"); texturex = parent->findFirst(opt); if (!texturex) return false; else zdtextures = true; } // Find patch table in parent archive ArchiveEntry* pnames = NULL; if (!zdtextures) { opt.match_type = EntryType::getType("pnames"); pnames = parent->findLast(opt); // Check it exists if (!pnames) return false; } // Check entries aren't locked (texture editor open or iwad) if ((pnames && pnames->isLocked()) || texturex->isLocked()) { if (parent->isReadOnly()) wxMessageBox("Cannot perform this action on an IWAD", "Error", wxICON_ERROR); else wxMessageBox("Cannot perform this action because one or more texture related entries is locked. Please close the archive's texture editor if it is open.", "Error", wxICON_ERROR); return false; } TextureXList tx; PatchTable ptable; if (zdtextures) { // Load TEXTURES tx.readTEXTURESData(texturex); } else { // Load patch table ptable.loadPNAMES(pnames); // Load TEXTUREx tx.readTEXTUREXData(texturex, ptable); } // Create textures from entries SImage image; for (unsigned a = 0; a < entries.size(); a++) { // Check entry type if (!(entries[a]->getType()->extraProps().propertyExists("image"))) { wxLogMessage("Entry %s is not a valid image", entries[a]->getName()); continue; } // Check entry name string name = entries[a]->getName(true); if (name.Length() > 8) { wxLogMessage("Entry %s has too long a name to add to the patch table (name must be 8 characters max)", entries[a]->getName()); continue; } // Add to patch table if (!zdtextures) ptable.addPatch(name); // Load patch to temp image Misc::loadImageFromEntry(&image, entries[a]); // Create texture CTexture* ntex = new CTexture(zdtextures); ntex->setName(name); ntex->addPatch(name, 0, 0); ntex->setWidth(image.getWidth()); ntex->setHeight(image.getHeight()); // Setup texture scale if (tx.getFormat() == TXF_TEXTURES) ntex->setScale(1, 1); else ntex->setScale(0, 0); // Add to texture list tx.addTexture(ntex); } if (zdtextures) { // Write texture data back to textures entry tx.writeTEXTURESData(texturex); } else { // Write patch table data back to pnames entry ptable.writePNAMES(pnames); // Write texture data back to texturex entry tx.writeTEXTUREXData(texturex, ptable); } return true; }
// ----------------------------------------------------------------------------- // Static function to check if an archive has sufficient texture related // entries, and if not, prompts the user to either create or import them. // Returns true if the entries exist, false otherwise // ----------------------------------------------------------------------------- bool TextureXEditor::setupTextureEntries(Archive* archive) { using Format = TextureXList::Format; // Check any archive was given if (!archive) return false; // Search archive for any ZDoom TEXTURES entries Archive::SearchOptions options; options.match_type = EntryType::fromId("zdtextures"); auto entry_tx = archive->findFirst(options); // Find any TEXTURES entry // If it's found, we're done if (entry_tx) return true; // Search archive for any texture-related entries options.match_type = EntryType::fromId("texturex"); entry_tx = archive->findFirst(options); // Find any TEXTUREx entry options.match_type = EntryType::fromId("pnames"); auto entry_pnames = archive->findFirst(options); // Find any PNAMES entry // If both exist, we're done if (entry_tx && entry_pnames) return true; // Todo: accept entry_tx without pnames if the textures are in Jaguar mode // If no TEXTUREx entry exists if (!entry_tx) { // No TEXTUREx entries found, so ask if the user wishes to create one wxMessageDialog dlg( nullptr, "The archive does not contain any texture definitions (TEXTURE1/2 or TEXTURES). " "Do you wish to create or import a texture definition list?", "No Texture Definitions Found", wxYES_NO); if (dlg.ShowModal() == wxID_YES) { CreateTextureXDialog ctxd(nullptr); while (true) { // Check if cancelled if (ctxd.ShowModal() == wxID_CANCEL) return false; if (ctxd.createNewSelected()) { // User selected to create a new TEXTUREx list ArchiveEntry* texturex = nullptr; // Doom or Strife TEXTUREx if (ctxd.getSelectedFormat() == Format::Normal || ctxd.getSelectedFormat() == Format::Strife11) { // Create texture list TextureXList txlist; txlist.setFormat(ctxd.getSelectedFormat()); // Create patch table PatchTable ptt; // Create dummy patch auto dpatch = App::archiveManager().programResourceArchive()->entryAtPath("s3dummy.lmp"); archive->addEntry(dpatch, "patches", true); ptt.addPatch("S3DUMMY"); // Create dummy texture auto dummytex = std::make_unique<CTexture>(); dummytex->setName("S3DUMMY"); dummytex->addPatch("S3DUMMY", 0, 0); dummytex->setWidth(128); dummytex->setHeight(128); dummytex->setScale({ 0., 0. }); // Add dummy texture to list // (this serves two purposes - supplies the special 'invalid' texture by default, // and allows the texturex format to be detected) txlist.addTexture(std::move(dummytex)); // Add empty PNAMES entry to archive entry_pnames = archive->addNewEntry("PNAMES"); ptt.writePNAMES(entry_pnames); entry_pnames->setType(EntryType::fromId("pnames")); entry_pnames->setExtensionByType(); // Add empty TEXTURE1 entry to archive texturex = archive->addNewEntry("TEXTURE1"); txlist.writeTEXTUREXData(texturex, ptt); texturex->setType(EntryType::fromId("texturex")); texturex->setExtensionByType(); } else if (ctxd.getSelectedFormat() == Format::Textures) { // Create texture list TextureXList txlist; txlist.setFormat(Format::Textures); // Add empty TEXTURES entry to archive texturex = archive->addNewEntry("TEXTURES"); texturex->setType(EntryType::fromId("zdtextures")); texturex->setExtensionByType(); return false; } if (!texturex) return false; } else { // User selected to import texture definitions from the base resource archive auto bra = App::archiveManager().baseResourceArchive(); if (!bra) { wxMessageBox( "No Base Resource Archive is opened, please select/open one", "Error", wxICON_ERROR); continue; } // Find all relevant entries in the base resource archive Archive::SearchOptions opt; opt.match_type = EntryType::fromId("texturex"); auto import_tx = bra->findAll(opt); // Find all TEXTUREx entries opt.match_type = EntryType::fromId("pnames"); auto import_pnames = bra->findLast(opt); // Find last PNAMES entry // Check enough entries exist if (import_tx.empty() || !import_pnames) { wxMessageBox( "The selected Base Resource Archive does not contain " "sufficient texture definition entries", "Error", wxICON_ERROR); continue; } // Copy TEXTUREx entries over to current archive for (auto& a : import_tx) { auto texturex = archive->addEntry(a, "global", true); texturex->setType(EntryType::fromId("texturex")); texturex->setExtensionByType(); } // Copy PNAMES entry over to current archive entry_pnames = archive->addEntry(import_pnames, "global", true); entry_pnames->setType(EntryType::fromId("pnames")); entry_pnames->setExtensionByType(); } break; } return true; } // 'No' clicked return false; } else // TEXTUREx entry exists { // TODO: Probably a better idea here to get the user to select an archive to import the patch table from // If no PNAMES entry was found, search resource archives if (!entry_pnames) { Archive::SearchOptions opt; opt.match_type = EntryType::fromId("pnames"); entry_pnames = App::archiveManager().findResourceEntry(opt, archive); } // If no PNAMES entry is found at all, show an error and abort // TODO: ask user to select appropriate base resource archive if (!entry_pnames) { wxMessageBox("PNAMES entry not found!", wxMessageBoxCaptionStr, wxICON_ERROR); return false; } return true; } return false; }