/* CTexture::loadPatchImage * Loads the image for the patch at [pindex] into [image]. Can deal * with textures-as-patches *******************************************************************/ bool CTexture::loadPatchImage(unsigned pindex, SImage& image, Archive* parent, Palette8bit* pal) { // Check patch index if (pindex >= patches.size()) return false; CTPatch* patch = patches[pindex]; // If the texture is extended, search for textures-as-patches first // (as long as the patch name is different from this texture's name) if (extended && !(S_CMPNOCASE(patch->getName(), name))) { // Search the texture list we're in first if (in_list) { for (unsigned a = 0; a < in_list->nTextures(); a++) { CTexture* tex = in_list->getTexture(a); // Don't look past this texture in the list if (tex->getName() == name) break; // Check for name match if (S_CMPNOCASE(tex->getName(), patch->getName())) { // Load texture to image return tex->toImage(image, parent, pal); } } } // Otherwise, try the resource manager // TODO: Something has to be ignored here. The entire archive or just the current list? CTexture* tex = theResourceManager->getTexture(patch->getName(), parent); if (tex) return tex->toImage(image, parent, pal); } // Get patch entry ArchiveEntry* entry = patch->getPatchEntry(parent); // Load entry to image if valid if (entry) return Misc::loadImageFromEntry(&image, entry); else return false; }
/* CTexture::copyTexture * Copies the texture [tex] to this texture. If keep_type is true, * the current texture type (extended/regular) will be kept, * otherwise it will be converted to the type of [tex] *******************************************************************/ void CTexture::copyTexture(CTexture* tex, bool keep_type) { // Check texture was given if (!tex) return; // Clear current texture clear(); // Copy texture info this->name = tex->name; this->width = tex->width; this->height = tex->height; this->scale_x = tex->scale_x; this->scale_y = tex->scale_y; this->world_panning = tex->world_panning; if (!keep_type) this->extended = tex->extended; this->optional = tex->optional; this->no_decals = tex->no_decals; this->null_texture = tex->null_texture; this->offset_x = tex->offset_x; this->offset_y = tex->offset_y; this->type = tex->type; // Copy patches for (unsigned a = 0; a < tex->nPatches(); a++) { CTPatch* patch = tex->getPatch(a); if (extended) { if (tex->extended) patches.push_back(new CTPatchEx((CTPatchEx*)patch)); else patches.push_back(new CTPatchEx(patch)); } else addPatch(patch->getName(), patch->xOffset(), patch->yOffset()); } }
/* TextureXPanel::paste * Pastes any textures on the clipboard after the last selected * texture *******************************************************************/ void TextureXPanel::paste() { // Check there is anything on the clipboard if (theClipboard->nItems() == 0) return; // Get last selected index int selected = list_textures->getLastSelected(); if (selected == -1) selected = texturex.nTextures() - 1; // Add to end of the list if nothing selected // Begin recording undo level undo_manager->beginRecord("Paste Texture(s)"); // Go through clipboard items for (unsigned a = 0; a < theClipboard->nItems(); a++) { // Skip if not a texture clipboard item if (theClipboard->getItem(a)->getType() != CLIPBOARD_COMPOSITE_TEXTURE) continue; // Get texture item TextureClipboardItem* item = (TextureClipboardItem*)(theClipboard->getItem(a)); // Add new texture after last selected item CTexture* ntex = new CTexture((texturex.getFormat() == TXF_TEXTURES)); ntex->copyTexture(item->getTexture(), true); ntex->setState(2); texturex.addTexture(ntex, ++selected); // Record undo step undo_manager->recordUndoStep(new TextureCreateDeleteUS(this, ntex, true)); // Deal with patches for (unsigned p = 0; p < ntex->nPatches(); p++) { CTPatch* patch = ntex->getPatch(p); // Update patch table if necessary if (texturex.getFormat() != TXF_TEXTURES) tx_editor->patchTable().addPatch(patch->getName()); // Get the entry for this patch ArchiveEntry* entry = patch->getPatchEntry(tx_editor->getArchive()); // If the entry wasn't found in any open archive, try copying it from the clipboard // (the user may have closed the archive the original patch was in) if (!entry) { entry = item->getPatchEntry(patch->getName()); // Copy the copied patch entry over to this archive if (entry) tx_editor->getArchive()->addEntry(entry, "patches", true); } // If the entry exists in the base resource archive or this archive, do nothing else if (entry->getParent() == theArchiveManager->baseResourceArchive() || entry->getParent() == tx_editor->getArchive()) continue; // Otherwise, copy the entry over to this archive else tx_editor->getArchive()->addEntry(entry, "patches", true); } } // End recording undo level undo_manager->endRecord(true); // Refresh list_textures->updateList(); // Update variables modified = true; }
/* TextureXList::writeTEXTUREXData * Writes the texture list in TEXTUREX format to [texturex], using * [patch_table] for patch information. Returns true on success, * false otherwise *******************************************************************/ bool TextureXList::writeTEXTUREXData(ArchiveEntry* texturex, PatchTable& patch_table) { // Check entry was given if (!texturex) return false; if (texturex->isLocked()) return false; wxLogMessage("Writing " + getTextureXFormatString() + " format TEXTUREx entry"); /* Total size of a TEXTUREx lump, in bytes: Header: 4 + (4 * numtextures) Textures: 22 * numtextures (normal format) 14 * numtextures (nameless format) 18 * numtextures (Strife 1.1 format) Patches: 10 * sum of patchcounts (normal and nameless formats) 6 * sum of patchcounts (Strife 1.1 format) */ size_t numpatchrefs = 0; size_t numtextures = textures.size(); for (size_t i = 0; i < numtextures; ++i) { numpatchrefs += textures[i]->nPatches(); } wxLogMessage("%i patch references in %i textures", numpatchrefs, numtextures); size_t datasize = 0; size_t headersize = 4 + (4 * numtextures); switch (txformat) { case TXF_NORMAL: datasize = 4 + (26 * numtextures) + (10 * numpatchrefs); break; case TXF_NAMELESS: datasize = 4 + (18 * numtextures) + (10 * numpatchrefs); break; case TXF_STRIFE11: datasize = 4 + (22 * numtextures) + ( 6 * numpatchrefs); break; // Some compilers insist on having default cases. default: return false; } MemChunk txdata(datasize); int32_t* offsets = new int32_t[numtextures]; int32_t foo = wxINT32_SWAP_ON_BE((signed) numtextures); // Write header txdata.seek(0, SEEK_SET); SAFEFUNC(txdata.write(&foo, 4)); // Go to beginning of texture definitions SAFEFUNC(txdata.seek(4 + (numtextures*4), SEEK_SET)); // Write texture entries for (size_t i = 0; i < numtextures; ++i) { // Get texture to write CTexture* tex = textures[i]; // Set offset offsets[i] = (signed)txdata.currentPos(); // Write texture entry switch (txformat) { case TXF_NORMAL: { // Create 'normal' doom format texture definition ftdef_t txdef; memset(txdef.name, 0, 8); // Set texture name to all 0's (to ensure compatibility with XWE) strncpy(txdef.name, CHR(tex->getName().Upper()), tex->getName().Len()); txdef.flags = 0; txdef.scale[0] = (tex->getScaleX()*8); txdef.scale[1] = (tex->getScaleY()*8); txdef.width = tex->getWidth(); txdef.height = tex->getHeight(); txdef.columndir[0] = 0; txdef.columndir[1] = 0; txdef.patchcount = tex->nPatches(); // Check for WorldPanning flag if (tex->world_panning) txdef.flags |= TX_WORLDPANNING; // Write texture definition SAFEFUNC(txdata.write(&txdef, 22)); break; } case TXF_NAMELESS: { // Create nameless texture definition nltdef_t txdef; txdef.flags = 0; txdef.scale[0] = (tex->getScaleX()*8); txdef.scale[1] = (tex->getScaleY()*8); txdef.width = tex->getWidth(); txdef.height = tex->getHeight(); txdef.columndir[0] = 0; txdef.columndir[1] = 0; txdef.patchcount = tex->nPatches(); // Write texture definition SAFEFUNC(txdata.write(&txdef, 8)); break; } case TXF_STRIFE11: { // Create strife format texture definition stdef_t txdef; memset(txdef.name, 0, 8); // Set texture name to all 0's (to ensure compatibility with XWE) strncpy(txdef.name, CHR(tex->getName().Upper()), tex->getName().Len()); txdef.flags = 0; txdef.scale[0] = (tex->getScaleX()*8); txdef.scale[1] = (tex->getScaleY()*8); txdef.width = tex->getWidth(); txdef.height = tex->getHeight(); txdef.patchcount = tex->nPatches(); // Check for WorldPanning flag if (tex->world_panning) txdef.flags |= TX_WORLDPANNING; // Write texture definition SAFEFUNC(txdata.write(&txdef, 18)); break; } default: return false; } // Write patch references for (size_t k = 0; k < tex->nPatches(); ++k) { // Get patch to write CTPatch* patch = tex->getPatch(k); // Create patch definition tx_patch_t pdef; pdef.left = patch->xOffset(); pdef.top = patch->yOffset(); // Check for 'invalid' patch if (patch->getName().StartsWith("INVPATCH")) { // Get raw patch index from name string number = patch->getName(); number.Replace("INVPATCH", ""); long index; number.ToLong(&index); pdef.patch = index; } else pdef.patch = patch_table.patchIndex(patch->getName()); // Note this will be -1 if the patch doesn't exist in the patch table. This should never happen with the texture editor, though. // Write common data SAFEFUNC(txdata.write(&pdef, 6)); // In non-Strife formats, there's some added rubbish if (txformat != TXF_STRIFE11) { foo = 0; SAFEFUNC(txdata.write(&foo, 4)); } } } // Write offsets SAFEFUNC(txdata.seek(4, SEEK_SET)); SAFEFUNC(txdata.write(offsets, 4*numtextures)); // Write data to the TEXTUREx entry texturex->importMemChunk(txdata); // Update entry type EntryType::detectEntryType(texturex); // Clean up delete[] offsets; return true; }