/* 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; }
/* TextureXPanel::removeTexture * Removes any selected textures *******************************************************************/ void TextureXPanel::removeTexture() { // Get selected textures vector<long> selection = list_textures->getSelection(); // Begin recording undo level undo_manager->beginRecord("Remove Texture(s)"); // Go through selection backwards for (int a = selection.size() - 1; a >= 0; a--) { // Remove texture from patch table entries CTexture* tex = texturex.getTexture(selection[a]); for (unsigned p = 0; p < tex->nPatches(); p++) tx_editor->patchTable().patch(tex->getPatch(p)->getName()).removeTextureUsage(tex->getName()); // Record undo step undo_manager->recordUndoStep(new TextureCreateDeleteUS(this, tex, false)); // Remove texture from list texturex.removeTexture(selection[a]); } // End recording undo level undo_manager->endRecord(true); // Clear selection & refresh list_textures->clearSelection(); list_textures->updateList(); texture_editor->clearTexture(); // Update variables modified = true; }
TextureModificationUS(TextureXPanel* tx_panel, CTexture* texture) : tx_panel(tx_panel) { tex_copy = new CTexture(); tex_copy->copyTexture(texture); tex_copy->setState(texture->getState()); index = tx_panel->txList().textureIndex(tex_copy->getName()); }
/* TextureXPanel::openTEXTUREX * Loads a TEXTUREx or TEXTURES format texture list into the editor *******************************************************************/ bool TextureXPanel::openTEXTUREX(ArchiveEntry* entry) { // Open texture list (check format) if (entry->getType()->getFormat() == "texturex") { // TEXTURE1/2 format if (!texturex.readTEXTUREXData(entry, tx_editor->patchTable())) return false; // Create default texture editor texture_editor = new TextureEditorPanel(this, tx_editor); // Update patch table usage info for (size_t a = 0; a < texturex.nTextures(); a++) { CTexture* tex = texturex.getTexture(a); // Go through texture's patches for (size_t p = 0; p < tex->nPatches(); p++) tx_editor->patchTable().patch(tex->getPatch(p)->getName()).used_in.push_back(tex->getName()); } } else { // TEXTURES format if (!texturex.readTEXTURESData(entry)) return false; // Create extended texture editor texture_editor = new ZTextureEditorPanel(this, tx_editor); // Add 'type' column list_textures->InsertColumn(2, "Type"); } tx_entry = entry; // Add texture editor area GetSizer()->Add(texture_editor, 1, wxEXPAND|wxALL, 4); texture_editor->setupLayout(); // Update format label label_tx_format->SetLabel("Format: " + texturex.getTextureXFormatString()); // Update texture list list_textures->updateList(); return true; }
/* TextureXListView::getItemText * Returns the string for [item] at [column] *******************************************************************/ string TextureXListView::getItemText(long item, long column, long index) const { // Check texture list exists if (!texturex) return "INVALID INDEX"; // Check index is ok if (index < 0 || (unsigned)index > texturex->nTextures()) return "INVALID INDEX"; // Get associated texture CTexture* tex = texturex->getTexture(index); if (column == 0) // Name column return tex->getName(); else if (column == 1) // Size column return S_FMT("%dx%d", tex->getWidth(), tex->getHeight()); else if (column == 2) // Type column return tex->getType(); else return "INVALID COLUMN"; }
/* 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; }
/* MapTextureManager::buildTexInfoList * (Re)builds lists with information about all currently available * resource textures and flats *******************************************************************/ void MapTextureManager::buildTexInfoList() { // Clear tex_info.clear(); flat_info.clear(); // --- Textures --- // Composite textures vector<TextureResource::tex_res_t> textures; theResourceManager->getAllTextures(textures, NULL); for (unsigned a = 0; a < textures.size(); a++) { CTexture * tex = textures[a].tex; Archive* parent = textures[a].parent; if (tex->isExtended()) { if (S_CMPNOCASE(tex->getType(), "texture") || S_CMPNOCASE(tex->getType(), "walltexture")) tex_info.push_back(map_texinfo_t(tex->getName(), TC_TEXTURES, parent)); else if (S_CMPNOCASE(tex->getType(), "define")) tex_info.push_back(map_texinfo_t(tex->getName(), TC_HIRES, parent)); else if (S_CMPNOCASE(tex->getType(), "flat")) flat_info.push_back(map_texinfo_t(tex->getName(), TC_TEXTURES, parent)); // Ignore graphics, patches and sprites } else tex_info.push_back(map_texinfo_t(tex->getName(), TC_TEXTUREX, parent, "", tex->getIndex() + 1)); } // Texture namespace patches (TX_) if (theGameConfiguration->txTextures()) { vector<ArchiveEntry*> patches; theResourceManager->getAllPatchEntries(patches, NULL); for (unsigned a = 0; a < patches.size(); a++) { if (patches[a]->isInNamespace("textures") || patches[a]->isInNamespace("hires")) { // Determine texture path if it's in a pk3 string path = patches[a]->getPath(); if (path.StartsWith("/textures/")) path.Remove(0, 9); else if (path.StartsWith("/hires/")) path.Remove(0, 6); else path = ""; tex_info.push_back(map_texinfo_t(patches[a]->getName(true), TC_TX, patches[a]->getParent(), path)); } } } // Flats vector<ArchiveEntry*> flats; theResourceManager->getAllFlatEntries(flats, NULL); for (unsigned a = 0; a < flats.size(); a++) { ArchiveEntry* entry = flats[a]; // Determine flat path if it's in a pk3 string path = entry->getPath(); if (path.StartsWith("/flats/") || path.StartsWith("/hires/")) path.Remove(0, 6); else path = ""; flat_info.push_back(map_texinfo_t(entry->getName(true), TC_NONE, flats[a]->getParent(), path)); } }
CFont::CFont(CXMLTreeNode& fontNode, CGUI* gui) : CNamed(fontNode) , m_glyphs( MAX_GLYPHS_BATCH ) , m_gui(gui) , m_textAlign(Rectf::Alignment::TOP_LEFT) { auto mm = CEngine::GetSingleton().getMaterialManager(); auto tm = CEngine::GetSingleton().getTextureManager(); std::string fontFile = fontNode.GetPszProperty("path", "", false); std::string fontName = fontNode.GetPszProperty("name", "", false); DEBUG_ASSERT(fontFile.size() != 0 && fontName.size() != 0); if (fontFile.size() == 0 || fontName.size() == 0) { return; } for (int i = 0; i < fontNode.GetNumChildren(); ++i) { auto matNode = fontNode(i); if (matNode.GetName() == std::string("material")) { std::string matName = "font-material-" + fontName; CMaterial *mat = new CMaterial(matNode); mat->setName(matName); mm->add(matName, mat); m_material = mat; break; } } std::string fontPath; size_t pathEnd = fontFile.find_last_of('\\'); if (pathEnd == fontFile.npos) { pathEnd = fontFile.find_last_of('/'); } if (pathEnd != fontFile.npos) { fontPath = fontFile.substr(0, pathEnd+1); } CXMLTreeNode ff; if (!ff.LoadFile(fontFile.c_str())) { DEBUG_ASSERT(false); return; } CXMLTreeNode font = ff["font"]; CXMLTreeNode common = font["common"]; CXMLTreeNode info = font["info"]; Vect2f pageSize(common.GetFloatProperty("scaleW", 0, false), common.GetFloatProperty("scaleH", 0, false)); m_fontSize = info.GetFloatProperty( "size", 0, false ); DEBUG_ASSERT( m_fontSize != 0); m_lineHeight = common.GetFloatProperty( "lineHeight", m_fontSize, false ); m_base = common.GetFloatProperty( "base", m_fontSize, false ); CXMLTreeNode pages = font["pages"]; for (int i = 0; i < pages.GetNumChildren(); ++i) { auto page = pages(i); if (page.GetName() == std::string("page")) { std::string texFile = page.GetPszProperty("file", "", false); DEBUG_ASSERT(texFile.size() > 0); texFile = fontPath + texFile; CTexture *tex = new CTexture(); tex->load(texFile, false); tm->add(tex->getName(), tex); m_pages.push_back(tex); } } auto chars = font["chars"]; for (int i = 0; i < chars.GetNumChildren(); ++i) { auto ch = chars(i); if (ch.GetName() != std::string("char")) { continue; } uchar chId = ch.GetIntProperty("id"); CharDesc_t cdesc; cdesc.offset = Vect2f(ch.GetFloatProperty("xoffset", 0, false), ch.GetFloatProperty("yoffset", 0, false)); cdesc.page = ch.GetIntProperty("page"); cdesc.size = Vect2f(ch.GetFloatProperty("width", 0, false), ch.GetFloatProperty("height", 0, false)); cdesc.xAdvance = ch.GetFloatProperty("xadvance", 0, false); cdesc.uvRect.position = Vect2f(ch.GetFloatProperty("x", 0, false), ch.GetFloatProperty("y", 0, false)); cdesc.uvRect.position = Vect2f(cdesc.uvRect.position.x / pageSize.x, cdesc.uvRect.position.y / pageSize.y); cdesc.uvRect.size = Vect2f(cdesc.size.x / pageSize.x, cdesc.size.y / pageSize.y); m_chars[chId] = cdesc; } auto kerns = font["kernings"]; if (kerns.Exists()) { for (int i = 0; i < kerns.GetNumChildren(); ++i) { auto k = kerns(i); uchar f = k.GetIntProperty("first", 0, false); uchar s = k.GetIntProperty("second", 0, false); uchar a = k.GetIntProperty("amount", 0, false); m_kernings[std::make_pair(f, s)] = a; } } m_glyphsVtxs = new CPointsListRenderableVertexs<GUI_TEXT_VERTEX>(m_glyphs.data(), MAX_GLYPHS_BATCH, MAX_GLYPHS_BATCH, true); }