mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-27 12:16:59 +00:00
a19c23ab7a
svn-id: r40838
308 lines
7.0 KiB
C++
308 lines
7.0 KiB
C++
/* 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(uint s) {
|
|
_size = s;
|
|
_colors = new PaletteEntry[s];
|
|
_parent = 0;
|
|
_dirty = true;
|
|
_refcount = 1;
|
|
_revision = 0;
|
|
}
|
|
|
|
Palette::Palette(const gfx_pixmap_color_t *colors, uint s) {
|
|
_size = s;
|
|
_colors = new PaletteEntry[s];
|
|
_parent = 0;
|
|
_dirty = true;
|
|
_refcount = 1;
|
|
_revision = 0;
|
|
|
|
for (uint i = 0; i < _size; ++i) {
|
|
_colors[i].r = colors[i].r;
|
|
_colors[i].g = colors[i].g;
|
|
_colors[i].b = colors[i].b;
|
|
_colors[i].refcount = 0;
|
|
_colors[i].parent_index = -1;
|
|
}
|
|
}
|
|
|
|
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(uint s) {
|
|
if (s == _size)
|
|
return;
|
|
|
|
assert(!_parent);
|
|
assert(_refcount == 1);
|
|
assert(s >= _size);
|
|
|
|
PaletteEntry *n = new PaletteEntry[s];
|
|
for (uint 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
|
|
if (_parent->_revision != _revision) {
|
|
#ifdef DEBUG_MERGE
|
|
fprintf(stderr, "NOP (revision mismatch)\n");
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
int count = 0;
|
|
for (uint 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);
|
|
if (_parent->_colors[pi].refcount != PALENTRY_LOCKED)
|
|
_parent->_colors[pi].refcount--;
|
|
if (_parent->_colors[pi].refcount == 0) {
|
|
_parent->_colors[pi].refcount = PALENTRY_FREE;
|
|
count++;
|
|
}
|
|
_colors[i].parent_index = -1;
|
|
}
|
|
#ifdef DEBUG_MERGE
|
|
fprintf(stderr, "Unmerge free %d colors\n", count);
|
|
#endif
|
|
|
|
_parent = 0;
|
|
}
|
|
|
|
void Palette::setColor(uint 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(uint 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;
|
|
}
|
|
|
|
uint 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 (uint 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;
|
|
}
|
|
|
|
bool 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 && parent->_revision == _revision) {
|
|
#ifdef DEBUG_MERGE
|
|
fprintf(stderr, "NOP\n");
|
|
#endif
|
|
return false;
|
|
}
|
|
_parent = parent;
|
|
_revision = parent->_revision;
|
|
|
|
#ifdef DEBUG_MERGE
|
|
bool *used = new bool[_parent->size()];
|
|
for (uint i = 0; i < _parent->size(); ++i)
|
|
used[i] = false;
|
|
int count = 0;
|
|
uint used_min = 1000;
|
|
uint used_max = 0;
|
|
#endif
|
|
|
|
for (uint i = 0; i < _size; ++i) {
|
|
PaletteEntry& entry = _colors[i];
|
|
if (entry.refcount == PALENTRY_FREE)
|
|
continue;
|
|
|
|
uint 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
|
|
return true;
|
|
}
|
|
|
|
void Palette::forceInto(Palette *parent) {
|
|
assert(!_parent || _parent == parent);
|
|
assert(parent != this);
|
|
#ifdef DEBUG_MERGE
|
|
fprintf(stderr, "Merge: force %s into %s (%d colors)\n", name.c_str(), parent->name.c_str(), _size);
|
|
#endif
|
|
|
|
_parent = parent;
|
|
parent->_revision++;
|
|
_revision = parent->_revision;
|
|
|
|
for (unsigned int i = 0; i < _size; ++i) {
|
|
// FIXME: PALENTRY_LOCKED doesn't work well with forceInto...
|
|
if (_colors[i].refcount != PALENTRY_FREE) {
|
|
_parent->_colors[i] = _colors[i];
|
|
_parent->_colors[i].parent_index = -1;
|
|
_colors[i].parent_index = i;
|
|
if (_parent->_colors[i].refcount != PALENTRY_LOCKED)
|
|
_parent->_colors[i].refcount = 1;
|
|
} else {
|
|
_parent->_colors[i].refcount = 0;
|
|
}
|
|
}
|
|
_parent->_dirty = true;
|
|
}
|
|
|
|
Palette *Palette::copy() {
|
|
assert(!_parent);
|
|
Palette* p = new Palette(_size);
|
|
p->name = "copy of " + name;
|
|
|
|
for (uint i = 0; i < _size; ++i) {
|
|
p->_colors[i] = _colors[i];
|
|
if (p->_colors[i].refcount >= 0)
|
|
p->_colors[i].refcount = 0;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
|
|
} // End of namespace Sci
|