bool convertWritable(SImage& image, convert_options_t opt) { // Firstly, make image paletted image.convertPaletted(opt.pal_target, opt.pal_current); // Secondly, remove any alpha information image.fillAlpha(255); // Quick hack for COLORMAP size // TODO: Remove me when a proper COLORMAP editor is implemented if (image.getWidth() == 256 && image.getHeight() >= 32 && image.getHeight() <= 34) return true; // Check for fullscreen/autopage size if (image.getWidth() == 320) return true; // And finally, find a suitable flat size and crop to that size int width = 0; int height = 0; for (unsigned a = 1; a < n_valid_flat_sizes; a++) { // Ignore non-writable flat sizes if (valid_flat_size[a][2] == 0) continue; // Check for exact match (no need to crop) if (image.getWidth() == valid_flat_size[a][0] && image.getHeight() == valid_flat_size[a][1]) return true; // If the flat will fit within this size, crop to the previous size // (this works because flat sizes list is in size-order) if (image.getWidth() <= (int)valid_flat_size[a][0] && image.getHeight() <= (int)valid_flat_size[a][1] && width > 0 && height > 0) { image.crop(0, 0, width, height); return true; } // Save 'previous' valid size width = valid_flat_size[a][0]; height = valid_flat_size[a][1]; } return false; }
/* GfxEntryPanel::detectOffsetType * Detects the offset view type of the current entry *******************************************************************/ int GfxEntryPanel::detectOffsetType() { if (!entry) return GFXVIEW_DEFAULT; if (!entry->getParent()) return GFXVIEW_DEFAULT; // Check what section of the archive the entry is in string section = entry->getParent()->detectNamespace(entry); if (section == "sprites") { SImage* img = getImage(); int left = -img->offset().x; int right = -img->offset().x + img->getWidth(); int top = -img->offset().y; int bottom = -img->offset().y + img->getHeight(); if (top >= 0 && bottom <= 216 && left >= 0 && right <= 336) return GFXVIEW_HUD; else return GFXVIEW_SPRITE; } // Check for png image if (entry->getType()->getFormat() == "img_png") { if (getImage()->offset().x == 0 && getImage()->offset().y == 0) return GFXVIEW_DEFAULT; else { SImage* img = getImage(); int left = -img->offset().x; int right = -img->offset().x + img->getWidth(); int top = -img->offset().y; int bottom = -img->offset().y + img->getHeight(); if (top >= 0 && bottom <= 216 && left >= 0 && right <= 336) return GFXVIEW_HUD; else return GFXVIEW_SPRITE; } } return GFXVIEW_DEFAULT; }
/* 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; }
/* GfxEntryPanel::statusString * Returns a string with extended editing/entry info for the status * bar *******************************************************************/ string GfxEntryPanel::statusString() { // Setup status string SImage* image = getImage(); string status = S_FMT("%dx%d", image->getWidth(), image->getHeight()); // Colour format if (image->getType() == RGBA) status += ", 32bpp"; else status += ", 8bpp"; // PNG stuff if (entry->getType()->getFormat() == "img_png") { // alPh if (EntryOperations::getalPhChunk(entry)) status += ", alPh"; // tRNS if (EntryOperations::gettRNSChunk(entry)) status += ", tRNS"; } return status; }
bool writeImage(SImage& image, MemChunk& data, Palette* pal, int index) { // Can't write if RGBA if (image.getType() == RGBA) return false; // Check size if (!validSize(image.getWidth(), image.getHeight())) return false; // Just dump image data to memchunk data.clear(); data.write(imageData(image), image.getWidth() * image.getHeight()); return true; }
/* CTexture::parseDefine * Parses a HIRESTEX define block *******************************************************************/ bool CTexture::parseDefine(Tokenizer& tz) { this->type = "Define"; this->extended = true; this->defined = true; name = tz.getToken().Upper(); def_width = tz.getInteger(); def_height = tz.getInteger(); width = def_width; height = def_height; ArchiveEntry* entry = theResourceManager->getPatchEntry(name); if (entry) { SImage image; if (image.open(entry->getMCData())) { width = image.getWidth(); height = image.getHeight(); scale_x = (double)width / (double)def_width; scale_y = (double)height / (double)def_height; } } CTPatchEx* patch = new CTPatchEx(name); patches.push_back(patch); return true; }
int canWrite(SImage& image) { // If it's the correct size and colour format, it's writable if (image.getType() == PALMASK && validSize(image.getWidth(), image.getHeight())) return WRITABLE; // Otherwise, it can be converted via palettising and cropping return CONVERTIBLE; }
int canWrite(SImage& image) { // If it's the correct size and colour format, it's writable int width = image.getWidth(); int height = image.getHeight(); // Shouldn't happen but... if (width < 0 || height < 0) return NOTWRITABLE; if (image.getType() == PALMASK && validSize(image.getWidth(), image.getHeight())) return WRITABLE; // Otherwise, check if it can be cropped to a valid size for (unsigned a = 0; a < n_valid_flat_sizes; a++) if (((unsigned)width >= valid_flat_size[a][0] && (unsigned)height >= valid_flat_size[a][1] && valid_flat_size[a][2] == 1) || gfx_extraconv) return CONVERTIBLE; return NOTWRITABLE; }
/* MapTextureManager::getVerticalOffset * Detects offset hacks such as that used by the wall torch thing in * Heretic (type 50). 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::getVerticalOffset(string name) { // Don't bother looking for nameless sprites if (name.IsEmpty()) return 0; // Get sprite matching name ArchiveEntry* entry = theResourceManager->getPatchEntry(name, "sprites", archive); if (!entry) entry = theResourceManager->getPatchEntry(name, "", archive); if (entry) { SImage image; Misc::loadImageFromEntry(&image, entry); int h = image.getHeight(); int o = image.offset().y; if (o > h) return o - h; else return 0; } return 0; }
/* 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; }
/* MapTextureManager::getTexture * Returns the texture matching [name]. Loads it from resources if * necessary. If [mixed] is true, flats are also searched if no * matching texture is found *******************************************************************/ GLTexture* MapTextureManager::getTexture(string name, bool mixed) { // Get texture matching name map_tex_t& mtex = textures[name.Upper()]; // Get desired filter type int filter = 1; if (map_tex_filter == 0) filter = GLTexture::NEAREST_LINEAR_MIN; else if (map_tex_filter == 1) filter = GLTexture::LINEAR; else if (map_tex_filter == 2) filter = GLTexture::LINEAR_MIPMAP; else if (map_tex_filter == 3) filter = GLTexture::NEAREST_MIPMAP; // If the texture is loaded if (mtex.texture) { // If the texture filter matches the desired one, return it if (mtex.texture->getFilter() == filter) return mtex.texture; else { // Otherwise, reload the texture if (mtex.texture != &(GLTexture::missingTex())) delete mtex.texture; mtex.texture = NULL; } } // Texture not found or unloaded, look for it //Palette8bit* pal = getResourcePalette(); // Look for stand-alone textures first ArchiveEntry* etex = theResourceManager->getTextureEntry(name, "hires", archive); int textypefound = TEXTYPE_HIRES; if (etex == NULL) { etex = theResourceManager->getTextureEntry(name, "textures", archive); textypefound = TEXTYPE_TEXTURE; } if (etex) { SImage image; // Get image format hint from type, if any if (Misc::loadImageFromEntry(&image, etex)) { mtex.texture = new GLTexture(false); mtex.texture->setFilter(filter); mtex.texture->loadImage(&image, palette); // Handle hires texture scale if (textypefound == TEXTYPE_HIRES) { ArchiveEntry* ref = theResourceManager->getTextureEntry(name, "textures", archive); if (ref) { SImage imgref; if (Misc::loadImageFromEntry(&imgref, ref)) { int w, h, sw, sh; w = image.getWidth(); h = image.getHeight(); sw = imgref.getWidth(); sh = imgref.getHeight(); mtex.texture->setScale((double)sw/(double)w, (double)sh/(double)h); } } } } } // Try composite textures then CTexture* ctex = theResourceManager->getTexture(name, archive); if (ctex && (!mtex.texture || textypefound == TEXTYPE_FLAT)) { textypefound = TEXTYPE_WALLTEXTURE; SImage image; if (ctex->toImage(image, archive, palette)) { mtex.texture = new GLTexture(false); mtex.texture->setFilter(filter); mtex.texture->loadImage(&image, palette); double sx = ctex->getScaleX(); if (sx == 0) sx = 1.0; double sy = ctex->getScaleY(); if (sy == 0) sy = 1.0; mtex.texture->setScale(1.0/sx, 1.0/sy); } } // Not found if (!mtex.texture) { // Try flats if mixed if (mixed) return getFlat(name, false); // Otherwise use missing texture else mtex.texture = &(GLTexture::missingTex()); } return mtex.texture; }