/* TextureXPanel::exportTexture * Create standalone image entries of any selected textures *******************************************************************/ void TextureXPanel::exportTexture() { // Get selected textures vector<long> selec_num = list_textures->getSelection(); vector<CTexture*> selection; if (!tx_entry) return; //saveTEXTUREX(); Archive* archive = tx_entry->getParent(); bool force_rgba = texture_editor->getBlendRGBA(); // Go through selection for (unsigned a = 0; a < selec_num.size(); ++a) { selection.push_back(texturex.getTexture(selec_num[a])); } // Create gfx conversion dialog GfxConvDialog gcd(this); // Send selection to the gcd gcd.openTextures(selection, texture_editor->getPalette(), archive, force_rgba); // Run the gcd gcd.ShowModal(); // Show splash window theSplashWindow->show("Writing converted image data...", true); // Write any changes for (unsigned a = 0; a < selection.size(); a++) { // Update splash window theSplashWindow->setProgressMessage(selection[a]->getName()); theSplashWindow->setProgress((float)a / (float)selection.size()); // Skip if the image wasn't converted if (!gcd.itemModified(a)) continue; // Get image and conversion info SImage* image = gcd.getItemImage(a); SIFormat* format = gcd.getItemFormat(a); // Write converted image back to entry MemChunk mc; format->saveImage(*image, mc, force_rgba ? NULL : gcd.getItemPalette(a)); ArchiveEntry* lump = new ArchiveEntry; lump->importMemChunk(mc); lump->rename(selection[a]->getName()); archive->addEntry(lump, "textures"); EntryType::detectEntryType(lump); lump->setExtensionByType(); } // Hide splash window theSplashWindow->hide(); }
void updateEntry() { // Read file MemChunk data; data.importFile(filename); // Read image SImage image; image.open(data, 0, "png"); image.convertPaletted(&palette); // Convert image to entry gfx format SIFormat* format = SIFormat::getFormat(gfx_format); if (format) { MemChunk conv_data; if (format->saveImage(image, conv_data, &palette)) { // Update entry data entry->importMemChunk(conv_data); EntryOperations::setGfxOffsets(entry, offsets.x, offsets.y); } else { LOG_MESSAGE(1, "Unable to convert external png to %s", format->getName()); } } }
/* SImage::open * Detects the format of [data] and, if it's a valid image format, * loads it into this image *******************************************************************/ bool SImage::open(MemChunk& data, int index, string type_hint) { // Check with type hint format first if (!type_hint.IsEmpty()) { SIFormat* format = SIFormat::getFormat(type_hint); if (format != SIFormat::unknownFormat() && format->isThisFormat(data)) return format->loadImage(*this, data, index); } // No type hint given or didn't match, autodetect format with SIFormat system instead return SIFormat::determineFormat(data)->loadImage(*this, data, index); }
/* EntryOperations::gfxConvert * Converts the image [entry] to [target_format], using conversion * options specified in [opt] and converting to [target_colformat] * colour format if possible. Returns false if the conversion failed, * true otherwise *******************************************************************/ bool EntryOperations::gfxConvert(ArchiveEntry* entry, string target_format, SIFormat::convert_options_t opt, int target_colformat) { // Init variables SImage image; // Get target image format SIFormat* fmt = SIFormat::getFormat(target_format); if (fmt == SIFormat::unknownFormat()) return false; // Check format and target colour type are compatible if (target_colformat >= 0 && !fmt->canWriteType((SIType)target_colformat)) { if (target_colformat == RGBA) wxLogMessage("Format \"%s\" cannot be written as RGBA data", fmt->getName()); else if (target_colformat == PALMASK) wxLogMessage("Format \"%s\" cannot be written as paletted data", fmt->getName()); return false; } // Load entry to image Misc::loadImageFromEntry(&image, entry); // Check if we can write the image to the target format int writable = fmt->canWrite(image); if (writable == SIFormat::NOTWRITABLE) { wxLogMessage("Entry \"%s\" could not be converted to target format \"%s\"", entry->getName(), fmt->getName()); return false; } else if (writable == SIFormat::CONVERTIBLE) fmt->convertWritable(image, opt); // Now we apply the target colour format (if any) if (target_colformat == PALMASK) image.convertPaletted(opt.pal_target, opt.pal_current); else if (target_colformat == RGBA) image.convertRGBA(opt.pal_current); // Finally, write new image data back to the entry fmt->saveImage(image, entry->getMCData(), opt.pal_target); return true; }
/* GfxEntryPanel::handleAction * Handles the action [id]. Returns true if the action was handled, * false otherwise *******************************************************************/ bool GfxEntryPanel::handleAction(string id) { // Don't handle actions if hidden if (!isActivePanel()) return false; // We're only interested in "pgfx_" actions if (!id.StartsWith("pgfx_")) return false; // Mirror if (id == "pgfx_mirror") { // Mirror X getImage()->mirror(false); // Update UI gfx_canvas->updateImageTexture(); gfx_canvas->Refresh(); // Update variables image_data_modified = true; setModified(); } // Flip else if (id == "pgfx_flip") { // Mirror Y getImage()->mirror(true); // Update UI gfx_canvas->updateImageTexture(); gfx_canvas->Refresh(); // Update variables image_data_modified = true; setModified(); } // Rotate else if (id == "pgfx_rotate") { // Prompt for rotation angle string angles[] = { "90", "180", "270" }; int choice = wxGetSingleChoiceIndex("Select rotation angle", "Rotate", 3, angles, 0); // Rotate image switch (choice) { case 0: getImage()->rotate(90); break; case 1: getImage()->rotate(180); break; case 2: getImage()->rotate(270); break; default: break; } // Update UI gfx_canvas->updateImageTexture(); gfx_canvas->Refresh(); // Update variables image_data_modified = true; setModified(); } // Translate else if (id == "pgfx_translate") { // Create translation editor dialog Palette8bit* pal = theMainWindow->getPaletteChooser()->getSelectedPalette(); TranslationEditorDialog ted(theMainWindow, pal, " Colour Remap", gfx_canvas->getImage()); // Create translation to edit ted.openTranslation(prev_translation); // Show the dialog if (ted.ShowModal() == wxID_OK) { // Apply translation to image getImage()->applyTranslation(&ted.getTranslation(), pal); // Update UI gfx_canvas->updateImageTexture(); gfx_canvas->Refresh(); // Update variables image_data_modified = true; gfx_canvas->updateImageTexture(); setModified(); prev_translation.copy(ted.getTranslation()); } } // Colourise else if (id == "pgfx_colourise") { Palette8bit* pal = theMainWindow->getPaletteChooser()->getSelectedPalette(); GfxColouriseDialog gcd(theMainWindow, entry, pal); gcd.setColour(last_colour); // Show colourise dialog if (gcd.ShowModal() == wxID_OK) { // Colourise image getImage()->colourise(gcd.getColour(), pal); // Update UI gfx_canvas->updateImageTexture(); gfx_canvas->Refresh(); // Update variables image_data_modified = true; Refresh(); setModified(); } rgba_t gcdcol = gcd.getColour(); last_colour = S_FMT("RGB(%d, %d, %d)", gcdcol.r, gcdcol.g, gcdcol.b); } // Tint else if (id == "pgfx_tint") { Palette8bit* pal = theMainWindow->getPaletteChooser()->getSelectedPalette(); GfxTintDialog gtd(theMainWindow, entry, pal); gtd.setValues(last_tint_colour, last_tint_amount); // Show tint dialog if (gtd.ShowModal() == wxID_OK) { // Tint image getImage()->tint(gtd.getColour(), gtd.getAmount(), pal); // Update UI gfx_canvas->updateImageTexture(); gfx_canvas->Refresh(); // Update variables image_data_modified = true; Refresh(); setModified(); } rgba_t gtdcol = gtd.getColour(); last_tint_colour = S_FMT("RGB(%d, %d, %d)", gtdcol.r, gtdcol.g, gtdcol.b); last_tint_amount = (int)(gtd.getAmount() * 100.0); } // Crop else if (id == "pgfx_crop") { Palette8bit* pal = theMainWindow->getPaletteChooser()->getSelectedPalette(); GfxCropDialog gcd(theMainWindow, entry, pal); // Show crop dialog if (gcd.ShowModal() == wxID_OK) { // stuff } } // alPh/tRNS else if (id == "pgfx_alph" || id == "pgfx_trns") { setModified(); Refresh(); } // Optimize PNG else if (id == "pgfx_pngopt") { // This is a special case. If we set the entry as modified, SLADE will prompt // to save it, rewriting the entry and cancelling the optimization done... if (EntryOperations::optimizePNG(entry)) setModified(false); else wxMessageBox("Warning: Couldn't optimize this image, check console log for info", "Warning", wxOK|wxCENTRE|wxICON_WARNING); Refresh(); } // Extract all else if (id == "pgfx_extract") { extractAll(); } // Convert else if (id == "pgfx_convert") { GfxConvDialog gcd(theMainWindow); gcd.CenterOnParent(); gcd.openEntry(entry); gcd.ShowModal(); if (gcd.itemModified(0)) { // Get image and conversion info SImage* image = gcd.getItemImage(0); SIFormat* format = gcd.getItemFormat(0); // Write converted image back to entry format->saveImage(*image, entry_data, gcd.getItemPalette(0)); // This makes the "save" button (and the setModified stuff) redundant and confusing! // The alternative is to save to entry effectively (uncomment the importMemChunk line) // but remove the setModified and image_data_modified lines, and add a call to refresh // to get the PNG tRNS status back in sync. //entry->importMemChunk(entry_data); image_data_modified = true; setModified(); // Fix tRNS status if we converted to paletted PNG int MENU_GFXEP_PNGOPT = theApp->getAction("pgfx_pngopt")->getWxId(); int MENU_GFXEP_ALPH = theApp->getAction("pgfx_alph")->getWxId(); int MENU_GFXEP_TRNS = theApp->getAction("pgfx_trns")->getWxId(); int MENU_ARCHGFX_EXPORTPNG = theApp->getAction("arch_gfx_exportpng")->getWxId(); if (format->getName() == "PNG") { ArchiveEntry temp; temp.importMemChunk(entry_data); temp.setType(EntryType::getType("png")); menu_custom->Enable(MENU_GFXEP_ALPH, true); menu_custom->Enable(MENU_GFXEP_TRNS, true); menu_custom->Check(MENU_GFXEP_TRNS, EntryOperations::gettRNSChunk(&temp)); menu_custom->Enable(MENU_ARCHGFX_EXPORTPNG, false); menu_custom->Enable(MENU_GFXEP_PNGOPT, true); toolbar->enableGroup("PNG", true); } else { menu_custom->Enable(MENU_GFXEP_ALPH, false); menu_custom->Enable(MENU_GFXEP_TRNS, false); menu_custom->Enable(MENU_ARCHGFX_EXPORTPNG, true); menu_custom->Enable(MENU_GFXEP_PNGOPT, false); toolbar->enableGroup("PNG", false); } // Refresh getImage()->open(entry_data, 0, format->getId()); gfx_canvas->Refresh(); } } // Unknown action else return false; // Action handled return true; }
/* GfxEntryPanel::saveEntry * Saves any changes to the entry *******************************************************************/ bool GfxEntryPanel::saveEntry() { // Write new image data if modified bool ok = true; if (image_data_modified) { SImage* image = getImage(); SIFormat* format = image->getFormat(); string error = ""; ok = false; int writable = format->canWrite(*image); if (format == SIFormat::unknownFormat()) error = "Image is of unknown format"; else if (writable == SIFormat::NOTWRITABLE) error = S_FMT("Writing unsupported for format \"%s\"", format->getName()); else { // Convert image if necessary (using default options) if (writable == SIFormat::CONVERTIBLE) { format->convertWritable(*image, SIFormat::convert_options_t()); wxLogMessage("Image converted for writing"); } if (format->saveImage(*image, entry->getMCData(), gfx_canvas->getPalette())) ok = true; else error = "Error writing image"; } if (ok) { // Set modified entry->setState(1); // Re-detect type EntryType* oldtype = entry->getType(); EntryType::detectEntryType(entry); // Update extension if type changed if (oldtype != entry->getType()) entry->setExtensionByType(); } else wxMessageBox(wxString("Cannot save changes to image: ") + error, "Error", wxICON_ERROR); } // Otherwise just set offsets else EntryOperations::setGfxOffsets(entry, spin_xoffset->GetValue(), spin_yoffset->GetValue()); // Apply alPh/tRNS options if (entry->getType()->getFormat() == "img_png") { bool alph = EntryOperations::getalPhChunk(entry); bool trns = EntryOperations::gettRNSChunk(entry); if (alph != menu_custom->IsChecked(theApp->getAction("pgfx_alph")->getWxId())) EntryOperations::modifyalPhChunk(entry, !alph); if (trns != menu_custom->IsChecked(theApp->getAction("pgfx_trns")->getWxId())) EntryOperations::modifytRNSChunk(entry, !trns); } if (ok) setModified(false); return ok; }