/* PaletteEntryPanel::loadEntry * Reads all palettes in the PLAYPAL entry and shows the first one *******************************************************************/ bool PaletteEntryPanel::loadEntry(ArchiveEntry* entry) { // Clear any existing palettes for (size_t a = 0; a < palettes.size(); a++) delete palettes[a]; palettes.clear(); // Determine how many palettes are in the entry int n_palettes = entry->getSize() / 768; // Load each palette entry->seek(0, SEEK_SET); uint8_t pal_data[768]; for (int a = 0; a < n_palettes; a++) { // Read palette data entry->read(&pal_data, 768); // Create palette Palette8bit* pal = new Palette8bit(); pal->loadMem(pal_data, 768); // Add palette palettes.push_back(pal); } // Show first palette cur_palette = 0; showPalette(0); setModified(false); return true; }
/* PaletteEntryPanel::move * Shifts the current palette's position in the list *******************************************************************/ bool PaletteEntryPanel::move(bool infront) { // Avoid invalid moves if (palettes.size() == 1) return false; uint32_t newpos = cur_palette; if (infront) { if (newpos == 0) newpos = palettes.size() - 1; else --newpos; } else /* behind*/ { if (newpos + 1 == palettes.size()) newpos = 0; else ++newpos; } Palette8bit* tmp = palettes[cur_palette]; palettes[cur_palette] = palettes[newpos]; palettes[newpos] = tmp; // Refresh the display to show the updated amount of palettes cur_palette = newpos; showPalette(newpos); setModified(); return true; }
/* PaletteEntryPanel::clearOne * Deletes all palettes except the current one from the list *******************************************************************/ bool PaletteEntryPanel::clearOthers() { // Nothing to do if there's already only one if (palettes.size() == 1) return true; // Keeping a pointer to the palette we keep Palette8bit* pal = palettes[cur_palette]; // Swap current palette with the first one if needed if (cur_palette != 0) { palettes[cur_palette] = palettes[0]; palettes[0] = pal; } // Delete all palettes after the first for (size_t i = 1; i < palettes.size(); ++i) { delete palettes[i]; } // Empty the palette list and add back the single palette palettes.clear(); palettes.push_back(pal); // Display the only remaining palette cur_palette = 0; showPalette(0); setModified(); return true; }
/* PaletteEntryPanel::generatePalettes * Generates the full complement of palettes needed by the game *******************************************************************/ bool PaletteEntryPanel::generatePalettes() { GeneratePalettesDialog gpd(theMainWindow); if (gpd.ShowModal() == wxID_OK) { // Get choice int choice = gpd.getChoice(); if (choice == 0) return false; // Make sure the current palette is the only one clearOthers(); // The first thirteen palettes are common // Generate the eight REDPALS for (int a = 1; a < 9; ++a) generatePalette(255, 0, 0, a, 9); // Then the four BONUSPALS for (int a = 1; a < 5; ++a) generatePalette(215, 186, 69, a, 8); // And here we are at the crossroad if (choice == 1) { // Write the Doom/Heretic/Strife palettes, that is to say: // Write RADIATIONPAL with its oversaturated green generatePalette(0, 256, 0, 1, 8); } else { // Write all the Hexen palettes // Starting with the eight POISONPALS for (int a = 1; a < 9; ++a) generatePalette(44, 92, 36, a, 10); // Then the ICEPAL generatePalette(0, 0, 224, 1, 2); // The three HOLYPALS generatePalette(130, 130, 130, 1, 2); generatePalette(100, 100, 100, 1, 2); generatePalette(70, 70, 70, 1, 2); // And lastly the three SCOURGEPAL generatePalette(150, 110, 0, 1, 2); generatePalette(125, 92, 0, 1, 2); generatePalette(100, 73, 0, 1, 2); } // Refresh view to show changed amount of palettes cur_palette = 0; showPalette(0); setModified(); } return true; }
/* PaletteEntryPanel::toolbarButtonClick * Called when a (EntryPanel) toolbar button is clicked *******************************************************************/ void PaletteEntryPanel::toolbarButtonClick(string action_id) { // Prev. palette if (action_id == "pal_prev") { if (cur_palette == 0) cur_palette = palettes.size(); if (showPalette(cur_palette - 1)) cur_palette--; } // Next palette else if (action_id == "pal_next") { if (cur_palette + 1 == palettes.size()) cur_palette = -1; if (showPalette(cur_palette + 1)) cur_palette++; } }
/* PaletteEntryPanel::refreshPanel * Redraws the panel *******************************************************************/ void PaletteEntryPanel::refreshPanel() { if (entry) { uint32_t our_palette = cur_palette; //loadEntry(entry); if (our_palette > 0 && our_palette < palettes.size()) showPalette(our_palette); } Update(); Refresh(); }
/* PaletteEntryPanel::duplicate * Make a copy of the current palette and add it to the list *******************************************************************/ bool PaletteEntryPanel::duplicate() { Palette8bit* newpalette = new Palette8bit; if (!newpalette) return false; newpalette->copyPalette(palettes[cur_palette]); palettes.push_back(newpalette); // Refresh the display to show the updated amount of palettes showPalette(cur_palette); setModified(); return true; }
/* PaletteEntryPanel::tweak * Tweaks the colours of the current palette *******************************************************************/ bool PaletteEntryPanel::tweak() { Palette8bit* pal = new Palette8bit; if (pal == NULL) return false; pal->copyPalette(palettes[cur_palette]); PaletteColourTweakDialog pctd(theMainWindow, pal); if (pctd.ShowModal() == wxID_OK) { palettes[cur_palette]->copyPalette(pctd.getFinalPalette()); showPalette(cur_palette); setModified(); } delete pal; return true; }
PaletteBoxButton::PaletteBoxButton(Palette* p, QWidget* parent) : QToolButton(parent) { palette = p; editAction = 0; setCheckable(true); setFocusPolicy(Qt::NoFocus); connect(this, SIGNAL(clicked(bool)), this, SLOT(showPalette(bool))); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); setText(qApp->translate("Palette", palette->name().toUtf8())); setToolButtonStyle(Qt::ToolButtonTextBesideIcon); setArrowType(Qt::RightArrow); showPalette(false); }
/* PaletteEntryPanel::importFrom * Imports the selected file in the current palette *******************************************************************/ bool PaletteEntryPanel::importFrom() { bool ret = false; // Run open file dialog SFileDialog::fd_info_t info; string extensions = "Raw Palette (*.pal)|*.pal|PNG File (*.png)|*.png|CSV Palette (*.csv)|*.csv|JASC Palette (*.pal)|*.pal|GIMP Palette (*.gpl)|*.gpl"; if (SFileDialog::openFile(info, "Import Palette As", extensions, this)) { // Load palette ret = palettes[cur_palette]->loadFile(info.filenames[0], info.ext_index); if (ret) { setModified(); showPalette(cur_palette); } } return ret; }
/* PaletteEntryPanel::clearOne * Deletes the current palette from the list *******************************************************************/ bool PaletteEntryPanel::clearOne() { // Always keep at least one palette if (cur_palette == 0 && palettes.size() == 1) { wxLogMessage("Palette cannot be removed, no other palette in this entry."); return false; } // Erase palette delete palettes[cur_palette]; palettes.erase(palettes.begin() + cur_palette); // Display the next, or previous, palette instead if (cur_palette >= palettes.size()) --cur_palette; showPalette(cur_palette); setModified(); return true; }
void PaletteEntryPanel::analysePalettes() { if (palettes.size() < PALETTECHECK + 1) return; #ifdef GPALCOMPANALYSIS int devR, devG, devB; int minR, minG, minB; int maxR, maxG, maxB; int wrongcount; #else unsigned int reds[256]; unsigned int greens[256]; unsigned int blues[256]; #endif string report = "\n"; #ifdef GPALCOMPANALYSIS int i = PALETTECHECK; if (i) { report += S_FMT("Deviation between palettes 0 and %i:\n\n", i); devR = devG = devB = 0; maxR = maxG = maxB = -1; minR = minG = minB = 256; wrongcount = 0; #else report += S_FMT("Changes between %u palettes compared to the first:\n\n", palettes.size()); for (size_t i = 1; i < palettes.size(); ++i) { for (int j = 0; j < 256; ++j) reds[j] = blues[j] = greens[j] = 999; #endif report += S_FMT("\n==============\n= Palette %02u =\n==============\n", i); for (size_t c = 0; c < 256; ++c) { rgba_t ref1 = palettes[0]->colour(c); rgba_t cmp1 = palettes[i]->colour(c); hsl_t ref2 = Misc::rgbToHsl(ref1); hsl_t cmp2 = Misc::rgbToHsl(cmp1); #ifdef GPALCOMPANALYSIS int r, g, b; double h, s, l; r = cmp1.r - ref1.r; g = cmp1.g - ref1.g; b = cmp1.b - ref1.b; h = cmp2.h - ref2.h; s = cmp2.s - ref2.s; l = cmp2.l - ref2.l; devR += r; devG += g; devB += b; if (r > maxR) maxR = r; if (r < minR) minR = r; if (g > maxG) maxG = g; if (g < minG) minG = g; if (b > maxB) maxB = b; if (b < minB) minB = b; if (r | g | b) { ++wrongcount; report += S_FMT("Index %003u: [%003i %003i %003i | %1.3f %1.3f %1.3f]->[%003i %003i %003i | %1.3f %1.3f %1.3f]\t\tR %+003i\tG %+003i\tB %+003i\t\t\tH %+1.3f\tS %+1.3f\tL %+1.3f\n", c, ref1.r, ref1.g, ref1.b, ref2.h, ref2.s, ref2.l, cmp1.r, cmp1.g, cmp1.b, cmp2.h, cmp2.s, cmp2.l, r, g, b, h, s, l); } #else if (reds[ref1.r] != cmp1.r && reds[ref1.r] != 999) DPrintf("Discrepency for red channel at index %i, value %i: %d vs. %d set before", c, ref1.r, cmp1.r, reds[ref1.r]); if (greens[ref1.g] != cmp1.g && greens[ref1.g] != 999) DPrintf("Discrepency for green channel at index %i, value %i: %d vs. %d set before", c, ref1.g, cmp1.g, greens[ref1.g]); if (blues[ref1.b] != cmp1.b && blues[ref1.b] != 999) DPrintf("Discrepency for blue channel at index %i, value %i: %d vs. %d set before", c, ref1.b, cmp1.b, blues[ref1.b]); reds[ref1.r] = cmp1.r; greens[ref1.g] = cmp1.g; blues[ref1.b] = cmp1.b; #endif } #ifdef GPALCOMPANALYSIS report += S_FMT("Deviation sigma: R %+003i G %+003i B %+003i\t%s\n", devR, devG, devB, entry->getName(true)); report += S_FMT("Min R %+003i Min G %+003i Min B %+003i Max R %+003i Max G %+003i Max B %+003i \nError count: %i\n", minR, minG, minB, maxR, maxG, maxB, wrongcount); #else report += "Shift table for existing channel values:\n| I | R | G | B |\n"; for (size_t i = 0; i < 256; ++i) { if (reds[i] < 999 || greens[i] < 999 || blues[i] < 999) report += S_FMT("| %003d | %003d | %003d | %003d |\n", i, reds[i], greens[i], blues[i]); } report.Replace("999", " "); #endif } wxLogMessage(report); } /******************************************************************* * PALETTEENTRYPANEL CLASS EVENTS *******************************************************************/ /* PaletteEntryPanel::onPalCanvasMouseEvent * Called when a mouse event happens within the palette canvas (eg. * button clicked, pointer moved, etc) *******************************************************************/ void PaletteEntryPanel::onPalCanvasMouseEvent(wxMouseEvent& e) { // Update colour info label with selected colour (if any) if (e.LeftDown()) { // Send to palette canvas pal_canvas->onMouseLeftDown(e); // Update status bar updateStatus(); } else if (e.RightDown()) { // Would this be better if the colour picking was handled by // the canvas' onMouseRightDown() function? The problem here // being that the canvas processes its events after the panel. // So for the left click we can afford to call it from there // first and let it harmlessly process it again, but for the // right click it would result in the colour box being shown // twice to the user, the second time being ignored. So it is // preferrable to handle all this on this side rather than try // to make the canvas do the work. // Pretend there was a left click to get the selected colour. pal_canvas->onMouseLeftDown(e); int sel = pal_canvas->getSelectionStart(); // There actually was a colour selected if (sel > -1) { rgba_t col = pal_canvas->getSelectedColour(); // Open a colour dialog wxColour cd = wxGetColourFromUser(GetParent(), WXCOL(col)); if (cd.Ok()) { col.r = cd.Red(); col.g = cd.Green(); col.b = cd.Blue(); palettes[cur_palette]->setColour(sel, col); setModified(); showPalette(cur_palette); } } } }