/* TextureXPanel::newTextureFromPatch * Creates a new texture called [name] from [patch]. The new texture * will be set to the dimensions of the patch, with the patch added * at 0,0 *******************************************************************/ CTexture* TextureXPanel::newTextureFromPatch(string name, string patch) { // Create new texture CTexture* tex = new CTexture(); tex->setName(name); tex->setState(2); // Setup texture scale if (texturex.getFormat() == TXF_TEXTURES) { tex->setScale(1, 1); tex->setExtended(true); } else tex->setScale(0, 0); // Add patch tex->addPatch(patch, 0, 0); // Load patch image (to determine dimensions) SImage image; tex->loadPatchImage(0, image); // Set dimensions tex->setWidth(image.getWidth()); tex->setHeight(image.getHeight()); // Update variables modified = true; // Return the new texture return tex; }
/* TextureXList::readTEXTUREXData * Reads in a doom-format TEXTUREx entry. Returns true on success, * false otherwise *******************************************************************/ bool TextureXList::readTEXTUREXData(ArchiveEntry* texturex, PatchTable& patch_table, bool add) { // Check entries were actually given if (!texturex) return false; // Clear current textures if needed if (!add) clear(); // Update palette theMainWindow->getPaletteChooser()->setGlobalFromArchive(texturex->getParent()); // Read TEXTUREx // Read header texturex->seek(0, SEEK_SET); int32_t n_tex = 0; int32_t* offsets = NULL; // Number of textures if (!texturex->read(&n_tex, 4)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't read texture count)"); return false; } n_tex = wxINT32_SWAP_ON_BE(n_tex); // If it's an empty TEXTUREx entry, stop here if (n_tex == 0) return true; // Texture definition offsets offsets = new int32_t[n_tex]; if (!texturex->read(offsets, n_tex * 4)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't read first offset)"); return false; } // Read the first texture definition to try to identify the format if (!texturex->seek(wxINT32_SWAP_ON_BE(offsets[0]), SEEK_SET)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't read first definition)"); return false; } // Look at the name field. Is it present or not? char tempname[8]; if (!texturex->read(&tempname, 8)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't read first name)"); return false; } // Let's pretend it is and see what happens. txformat = TXF_NORMAL; // Only the characters A-Z (uppercase), 0-9, and [ ] - _ should be used in texture names. for (uint8_t a = 0; a < 8; ++a) { if (a > 0 && tempname[a] == 0) // We found a null-terminator for the string, so we can assume it's okay. break; if (tempname[a] >= 'a' && tempname[a] <= 'z') { txformat = TXF_JAGUAR; //wxLogMessage("Jaguar texture"); break; } else if (!((tempname[a] >= 'A' && tempname[a] <= '[') || (tempname[a] >= '0' && tempname[a] <= '9') || tempname[a] == ']' || tempname[a] == '-' || tempname[a] == '_')) // We're out of character range, so this is probably not a texture name. { txformat = TXF_NAMELESS; //wxLogMessage("Nameless texture"); break; } } // Now let's see if it is the abridged Strife format or not. if (txformat == TXF_NORMAL) { // No need to test this again since it was already tested before. texturex->seek(offsets[0], SEEK_SET); ftdef_t temp; if (!texturex->read(&temp, 22)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't test definition)"); return false; } // Test condition adapted from ZDoom; apparently the first two bytes of columndir // may be set to garbage values by some editors and are therefore unreliable. if (wxINT16_SWAP_ON_BE(temp.patchcount <= 0) || (temp.columndir[1] != 0)) txformat = TXF_STRIFE11; } // Read all texture definitions for (int32_t a = 0; a < n_tex; a++) { // Skip to texture definition if (!texturex->seek(offsets[a], SEEK_SET)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't find definition)"); return false; } // Read definition tdef_t tdef; if (txformat == TXF_NAMELESS) { nltdef_t nameless; // Auto-naming mechanism taken from DeuTex if (a > 99999) { wxLogMessage("Error: More than 100000 nameless textures"); return false; } char temp[9] = ""; sprintf (temp, "TEX%05d", a); memcpy(tdef.name, temp, 8); // Read texture info if (!texturex->read(&nameless, 8)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't read nameless definition #%d)", a); return false; } // Copy data to permanent structure tdef.flags = nameless.flags; tdef.scale[0] = nameless.scale[0]; tdef.scale[1] = nameless.scale[1]; tdef.width = nameless.width; tdef.height = nameless.height; } else if (!texturex->read(&tdef, 16)) { wxLogMessage("Error: TEXTUREx entry is corrupt, (can't read texture definition #%d)", a); return false; } // Skip unused if (txformat != TXF_STRIFE11) { if (!texturex->seek(4, SEEK_CUR)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't skip dummy data past #%d)", a); return false; } } // Create texture CTexture* tex = new CTexture(); tex->name = wxString::FromAscii(tdef.name, 8); tex->width = wxINT16_SWAP_ON_BE(tdef.width); tex->height = wxINT16_SWAP_ON_BE(tdef.height); tex->scale_x = tdef.scale[0]/8.0; tex->scale_y = tdef.scale[1]/8.0; // Set flags if (tdef.flags & TX_WORLDPANNING) tex->world_panning = true; // Read patches int16_t n_patches = 0; if (!texturex->read(&n_patches, 2)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't read patchcount #%d)", a); return false; } //wxLogMessage("Texture #%d: %d patch%s", a, n_patches, n_patches == 1 ? "" : "es"); for (uint16_t p = 0; p < n_patches; p++) { // Read patch definition tx_patch_t pdef; if (!texturex->read(&pdef, 6)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't read patch definition #%d:%d)", a, p); wxLogMessage("Lump size %d, offset %d", texturex->getSize(), texturex->currentPos()); return false; } // Skip unused if (txformat != TXF_STRIFE11) { if (!texturex->seek(4, SEEK_CUR)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't skip dummy data past #%d:%d)", a, p); return false; } } // Add it to the texture string patch; if (txformat == TXF_JAGUAR) { patch = tex->name.Upper(); } else { patch = patch_table.patchName(pdef.patch); } if (patch.IsEmpty()) { //wxLogMessage("Warning: Texture %s contains patch %d which is invalid - may be incorrect PNAMES entry", CHR(tex->getName()), pdef.patch); patch = S_FMT("INVPATCH%04d", pdef.patch); } tex->addPatch(patch, pdef.left, pdef.top); } // Add texture to list addTexture(tex); } // Clean up delete[] offsets; return true; }
/* 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; }