diff options
Diffstat (limited to 'engines/sci/gfx/palette.cpp')
-rw-r--r-- | engines/sci/gfx/palette.cpp | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/engines/sci/gfx/palette.cpp b/engines/sci/gfx/palette.cpp new file mode 100644 index 0000000000..f7beb3f474 --- /dev/null +++ b/engines/sci/gfx/palette.cpp @@ -0,0 +1,265 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "sci/gfx/palette.h" +#include "sci/gfx/gfx_system.h" + +// #define DEBUG_MERGE + +namespace Sci { + +Palette::Palette(unsigned int s) { + _size = s; + _colors = new PaletteEntry[s]; + _parent = 0; + _dirty = true; + _refcount = 1; +} + +Palette::Palette(gfx_pixmap_color_t* colors, unsigned int s) +{ + _size = s; + _colors = new PaletteEntry[s]; + _parent = 0; + _dirty = true; + _refcount = 1; + + for (unsigned int i = 0; i < _size; ++i) + setColor(i, colors[i].r, colors[i].g, colors[i].b); +} + +Palette::~Palette() { + if (_parent) + unmerge(); + + delete[] _colors; + _colors = 0; +} + +Palette* Palette::getref() { + _refcount++; + return this; +} + +void Palette::free() { + assert(_refcount > 0); + _refcount--; + + if (_refcount == 0) + delete this; +} + +void Palette::resize(unsigned int s) { + if (s == _size) return; + assert(!_parent); + assert(_refcount == 1); + assert(s >= _size); + + PaletteEntry *n = new PaletteEntry[s]; + for (unsigned int i = 0; i < _size; ++i) + n[i] = _colors[i]; + + delete[] _colors; + _colors = n; + _size = s; +} + +void Palette::unmerge() { + assert(_parent); +#ifdef DEBUG_MERGE + fprintf(stderr, "Unmerge %s from %s (%d colors)\n", name.c_str(), _parent->name.c_str(), _size); +#endif + + int count = 0; + for (unsigned int i = 0; i < _size; ++i) { + if (_colors[i].refcount == PALENTRY_FREE) continue; + int pi = _colors[i].parent_index; + assert(pi >= 0); + assert(pi < (int)_parent->_size); + assert(_parent->_colors[pi].refcount != 0); + assert(_parent->_colors[pi].refcount != PALENTRY_FREE); + int old = _parent->_colors[pi].refcount; + if (_parent->_colors[pi].refcount != PALENTRY_LOCKED) + _parent->_colors[pi].refcount--; + if (_parent->_colors[pi].refcount == 0) { + _parent->_colors[pi].refcount = PALENTRY_FREE; + count++; + } +#ifdef DEBUG_MERGE + fprintf(stderr, "%d: %d -> %d\n", pi, old, _parent->_colors[pi].refcount); +#endif + _colors[i].parent_index = -1; + } +#ifdef DEBUG_MERGE + fprintf(stderr, "Unmerge free %d colors\n", count); +#endif + + _parent = 0; +} + +void Palette::setColor(unsigned int index, byte r, byte g, byte b) { + assert(index < _size); + assert(!_parent); + +// FIXME: We may want to have this assert. This will require changing the +// way loops sharing a single view's palette works. +// assert(_refcount == 1); + + PaletteEntry& entry = _colors[index]; + + assert(entry.refcount == PALENTRY_FREE || entry.refcount == 0); + entry.refcount = 0; + entry.r = r; + entry.g = g; + entry.b = b; + entry.parent_index = -1; + + _dirty = true; +} + +void Palette::makeSystemColor(unsigned int index, const PaletteEntry& color) { + assert(index < _size); + PaletteEntry& entry = _colors[index]; + entry.r = color.r; + entry.g = color.g; + entry.b = color.b; + entry.refcount = PALENTRY_LOCKED; +} + +unsigned int Palette::findNearbyColor(byte r, byte g, byte b, bool lock) { + int bestdelta = 1 + ((0x100 * 0x100) * 3); + int bestcolor = -1; + int firstfree = -1; + + assert(_size != 0); + + for (unsigned int i = 0; i < _size; ++i) { + PaletteEntry& entry = _colors[i]; + + if (entry.refcount != PALENTRY_FREE) { + int dr = abs(entry.r - r); + int dg = abs(entry.g - g); + int db = abs(entry.b - b); + + if (dr == 0 && dg == 0 && db == 0) { + // Exact match + //exact = true; + if (lock && entry.refcount != PALENTRY_LOCKED) + entry.refcount++; + return i; + } + + int delta = (dr * dr) + (dg * dg) + (db * db); + if (delta < bestdelta) { + bestdelta = delta; + bestcolor = i; + } + } else { + if (firstfree == -1) + firstfree = i; + } + } + + if (firstfree != -1) { + // TODO: mark palette as dirty + setColor(firstfree, r, g, b); + //exact = true; + if (lock) + _colors[firstfree].refcount++; + return firstfree; + } + + //exact = false; + if (lock && _colors[bestcolor].refcount != PALENTRY_LOCKED) { +#if 0 + _colors[bestcolor].r = r; + _colors[bestcolor].g = g; + _colors[bestcolor].b = b; + _dirty = true; +#endif + _colors[bestcolor].refcount++; + } + return bestcolor; +} + +void Palette::mergeInto(Palette *parent) { + assert(!_parent || _parent == parent); + assert(parent != this); +#ifdef DEBUG_MERGE + fprintf(stderr, "Merge: %s into %s (%d colors)\n", name.c_str(), parent->name.c_str(), _size); +#endif + + if (_parent == parent) { +#ifdef DEBUG_MERGE + fprintf(stderr, "NOP\n"); +#endif + return; + } + _parent = parent; + +#ifdef DEBUG_MERGE + bool *used = new bool[_parent->size()]; + for (unsigned int i = 0; i < _parent->size(); ++i) + used[i] = false; + int count = 0; + int used_min = 1000; + int used_max = 0; +#endif + + for (unsigned int i = 0; i < _size; ++i) { + PaletteEntry& entry = _colors[i]; + if (entry.refcount == PALENTRY_FREE) continue; + + unsigned int pi = _parent->findNearbyColor(entry.r, entry.g, entry.b); +#ifdef DEBUG_MERGE + if (!used[pi]) count++; + used[pi] = true; + if (pi > used_max) used_max = pi; + if (pi < used_min) used_min = pi; +#endif + entry.parent_index = pi; + if (_parent->_colors[pi].refcount != PALENTRY_LOCKED) + _parent->_colors[pi].refcount++; + } +#ifdef DEBUG_MERGE + fprintf(stderr, "Merge used %d colours in [%d..%d]\n", count, used_min, used_max); + delete[] used; +#endif +} + +Palette* Palette::copy() { + assert(!_parent); + Palette* p = new Palette(_size); + p->name = "copy of " + name; + + for (unsigned int i = 0; i < _size; ++i) { + p->_colors[i] = _colors[i]; + p->_colors[i].refcount = 0; + } + return p; +} + + +} // End of namespace Sci |