Added raster/palette.[ch] (duh)

This commit is contained in:
David Capello 2008-03-22 21:44:03 +00:00
parent bec33706bf
commit d2944d5def
2 changed files with 483 additions and 0 deletions

418
src/raster/palette.c Normal file
View File

@ -0,0 +1,418 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2008 David A. Capello
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <assert.h>
#include <allegro.h>
#include "raster/image.h"
#include "raster/palette.h"
#include "util/col_file.h"
Palette *palette_new(int frame, int ncolors)
{
Palette *pal;
int c;
assert(ncolors >= 1 && ncolors <= MAX_PALETTE_COLORS);
pal = (Palette *)gfxobj_new(GFXOBJ_PALETTE, sizeof(Palette));
if (!pal)
return NULL;
pal->frame = frame;
pal->ncolors = ncolors;
for (c=0; c<MAX_PALETTE_COLORS; ++c)
pal->color[c] = _rgba(0, 0, 0, 255);
return pal;
}
Palette *palette_new_copy(const Palette *pal)
{
Palette *palcopy;
int i;
palcopy = palette_new(pal->frame, pal->ncolors);
if (palcopy == NULL)
return NULL;
for (i=0; i<MAX_PALETTE_COLORS; ++i)
palcopy->color[i] = pal->color[i];
return palcopy;
}
void palette_free(Palette *palette)
{
gfxobj_free((GfxObj *)palette);
}
void palette_black(Palette *pal)
{
int c;
for (c=0; c<MAX_PALETTE_COLORS; ++c)
pal->color[c] = 0;
}
/**
* Copies the color of both palettes.
*/
void palette_copy_colors(Palette *pal, const Palette *src)
{
int c;
/* don't copy the frame property "pal->frame = src->frame;" !... */
/* just copy the colors */
pal->ncolors = src->ncolors;
for (c=0; c<MAX_PALETTE_COLORS; ++c)
pal->color[c] = src->color[c];
}
int palette_count_diff(const Palette *p1, const Palette *p2, int *from, int *to)
{
register int c, diff = 0;
int min = MIN(p1->ncolors, p2->ncolors);
int max = MAX(p1->ncolors, p2->ncolors);
if (from) *from = -1;
if (to) *to = -1;
/* compare palettes */
for (c=0; c<min; ++c) {
if (p1->color[c] != p2->color[c]) {
if (from && *from < 0) *from = c;
if (to) *to = c;
++diff;
}
}
if (max != min) {
diff += max - min;
if (to) *to = max;
}
return diff;
}
void palette_set_ncolors(Palette *pal, int ncolors)
{
int i;
assert(pal != NULL);
assert(ncolors >= 1 && ncolors <= MAX_PALETTE_COLORS);
if (pal->ncolors != ncolors) {
if (pal->ncolors > ncolors) {
for (i=pal->ncolors-1; i>=ncolors; --i) {
pal->color[i] = _rgba(0, 0, 0, 255);
}
}
else {
for (i=pal->ncolors; i<ncolors; ++i) {
pal->color[i] = _rgba(0, 0, 0, 255);
}
}
pal->ncolors = ncolors;
}
}
void palette_set_frame(Palette *pal, int frame)
{
assert(pal != NULL);
assert(frame >= 0);
pal->frame = frame;
}
ase_uint32 palette_get_entry(const Palette *pal, int i)
{
assert(pal != NULL);
assert(i >= 0 && i < MAX_PALETTE_COLORS);
return pal->color[i];
}
void palette_set_entry(Palette *pal, int i, ase_uint32 color)
{
assert(pal != NULL);
assert(i >= 0 && i < pal->ncolors);
assert(_rgba_geta(color) == 255);
pal->color[i] = color;
}
/* creates a linear ramp in the palette */
void palette_make_horz_ramp(Palette *p, int from, int to)
{
int r, g, b;
int r1, g1, b1;
int r2, g2, b2;
int i, n;
assert(from >= 0 && from <= 255);
assert(to >= 0 && to <= 255);
if (from > to) {
i = from;
from = to;
to = i;
}
n = to - from;
if (n < 2)
return;
r1 = _rgba_getr(p->color[from]);
g1 = _rgba_getg(p->color[from]);
b1 = _rgba_getb(p->color[from]);
r2 = _rgba_getr(p->color[to]);
g2 = _rgba_getg(p->color[to]);
b2 = _rgba_getb(p->color[to]);
for (i=from+1; i<to; ++i) {
r = r1 + (r2-r1) * (i-from) / n;
g = g1 + (g2-g1) * (i-from) / n;
b = b1 + (b2-b1) * (i-from) / n;
p->color[i] = _rgba(r, g, b, 255);
}
}
void palette_make_vert_ramp(Palette *p, int from, int to, int columns)
{
int r, g, b;
int r1, g1, b1;
int r2, g2, b2;
int y, ybeg, yend, n;
int offset;
assert(from >= 0 && from <= 255);
assert(to >= 0 && to <= 255);
assert(columns >= 1 && columns <= 256);
/* both indices have to be in the same column */
assert((from % columns) == (to % columns));
if (from > to) {
y = from;
from = to;
to = y;
}
ybeg = from/columns;
yend = to/columns;
n = yend - ybeg;
if (n < 2)
return;
r1 = _rgba_getr(p->color[from]);
g1 = _rgba_getg(p->color[from]);
b1 = _rgba_getb(p->color[from]);
r2 = _rgba_getr(p->color[to]);
g2 = _rgba_getg(p->color[to]);
b2 = _rgba_getb(p->color[to]);
offset = from % columns;
for (y=ybeg+1; y<yend; ++y) {
r = r1 + (r2-r1) * (y-ybeg) / n;
g = g1 + (g2-g1) * (y-ybeg) / n;
b = b1 + (b2-b1) * (y-ybeg) / n;
p->color[y*columns+offset] = _rgba(r, g, b, 255);
}
}
/* creates a rectangular ramp in the palette */
void palette_make_rect_ramp(Palette *p, int from, int to, int columns)
{
int x1, y1, x2, y2, y;
assert(from >= 0 && from <= 255);
assert(to >= 0 && to <= 255);
assert(columns >= 1 && columns <= 256);
x1 = from % columns;
y1 = from / columns;
x2 = to % columns;
y2 = to / columns;
palette_make_vert_ramp(p, from, y2*columns+x1, columns);
if (x1 < x2) {
palette_make_vert_ramp(p, y1*columns+x2, to, columns);
if (x2 - x1 >= 2)
for (y=y1; y<=y2; ++y)
palette_make_horz_ramp(p, y*columns+x1, y*columns+x2);
}
}
/**
* @param pal The ASE color palette to copy.
* @param rgb An Allegro's PALETTE.
*
* @return The same @a rgb pointer specified in the parameters.
*/
RGB *palette_to_allegro(const Palette *pal, RGB *rgb)
{
int i;
for (i=0; i<MAX_PALETTE_COLORS; ++i) {
rgb[i].r = _rgba_getr(pal->color[i]) / 4;
rgb[i].g = _rgba_getg(pal->color[i]) / 4;
rgb[i].b = _rgba_getb(pal->color[i]) / 4;
}
return rgb;
}
Palette *palette_from_allegro(Palette *pal, const struct RGB *rgb)
{
int i;
pal->ncolors = MAX_PALETTE_COLORS;
for (i=0; i<MAX_PALETTE_COLORS; ++i) {
pal->color[i] = _rgba(_rgb_scale_6[rgb[i].r],
_rgb_scale_6[rgb[i].g],
_rgb_scale_6[rgb[i].b], 255);
}
return pal;
}
Palette *palette_load(const char *filename)
{
Palette *pal = NULL;
char ext[64];
ustrcpy(ext, get_extension(filename));
if ((ustricmp(ext, "pcx") == 0) ||
(ustricmp(ext, "bmp") == 0) ||
(ustricmp(ext, "tga") == 0) ||
(ustricmp(ext, "lbm") == 0)) {
PALETTE rgbpal;
BITMAP *bmp;
bmp = load_bitmap(filename, rgbpal);
if (bmp) {
destroy_bitmap(bmp);
pal = palette_new(0, MAX_PALETTE_COLORS);
palette_from_allegro(pal, rgbpal);
}
}
else if (ustricmp(ext, "col") == 0) {
pal = load_col_file(filename);
}
return pal;
}
bool palette_save(Palette *pal, const char *filename)
{
bool ret = FALSE;
char ext[64];
ustrcpy(ext, get_extension(filename));
if ((ustricmp(ext, "pcx") == 0) ||
(ustricmp(ext, "bmp") == 0) ||
(ustricmp(ext, "tga") == 0)) {
PALETTE rgbpal;
BITMAP *bmp;
int c, x, y;
bmp = create_bitmap_ex(8, 16, 16);
for (y=c=0; y<16; y++)
for (x=0; x<16; x++)
putpixel(bmp, x, y, c++);
palette_to_allegro(pal, rgbpal);
ret = save_bitmap(filename, bmp, rgbpal);
destroy_bitmap(bmp);
}
else if (ustricmp(ext, "col") == 0) {
ret = save_col_file(pal, filename);
}
return ret;
}
/**********************************************************************/
/* Based on Allegro's bestfit_color */
static unsigned int col_diff[3*128];
static void bestfit_init(void)
{
register int i, k;
for (i=1; i<64; i++) {
k = i * i;
col_diff[0 +i] = col_diff[0 +128-i] = k * (59 * 59);
col_diff[128+i] = col_diff[128+128-i] = k * (30 * 30);
col_diff[256+i] = col_diff[256+128-i] = k * (11 * 11);
}
}
int palette_find_bestfit(const Palette *pal, int r, int g, int b)
{
#ifdef __GNUC__
register int bestfit asm("%eax");
#else
register int bestfit;
#endif
int i, coldiff, lowest;
assert(r >= 0 && r <= 255);
assert(g >= 0 && g <= 255);
assert(b >= 0 && b <= 255);
if (col_diff[1] == 0)
bestfit_init();
bestfit = 0;
lowest = INT_MAX;
r >>= 3;
g >>= 3;
b >>= 3;
i = 1;
while (i<PAL_SIZE) {
ase_uint32 rgb = pal->color[i];
coldiff = (col_diff + 0) [ ((_rgba_getg(rgb)>>3) - g) & 0x7F ];
if (coldiff < lowest) {
coldiff += (col_diff + 128) [ ((_rgba_getr(rgb)>>3) - r) & 0x7F ];
if (coldiff < lowest) {
coldiff += (col_diff + 256) [ ((_rgba_getb(rgb)>>3) - b) & 0x7F ];
if (coldiff < lowest) {
bestfit = i;
if (coldiff == 0)
return bestfit;
lowest = coldiff;
}
}
}
i++;
}
return bestfit;
}

65
src/raster/palette.h Normal file
View File

@ -0,0 +1,65 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2008 David A. Capello
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef RASTER_PALETTE_H
#define RASTER_PALETTE_H
#include "jinete/jbase.h"
#include "raster/gfxobj.h"
#include <allegro/color.h>
#define MAX_PALETTE_COLORS 256
typedef struct Palette Palette;
struct Palette
{
GfxObj gfxobj;
int frame;
int ncolors;
ase_uint32 color[MAX_PALETTE_COLORS];
};
Palette *palette_new(int frame, int ncolors);
Palette *palette_new_copy(const Palette *pal);
void palette_free(Palette *pal);
void palette_black(Palette *pal);
void palette_copy_colors(Palette *pal, const Palette *src);
int palette_count_diff(const Palette *p1, const Palette *p2, int *from, int *to);
void palette_set_ncolors(Palette *pal, int ncolors);
void palette_set_frame(Palette *pal, int frame);
ase_uint32 palette_get_entry(const Palette *pal, int i);
void palette_set_entry(Palette *pal, int i, ase_uint32 color);
void palette_make_horz_ramp(Palette *palette, int from, int to);
void palette_make_vert_ramp(Palette *palette, int from, int to, int columns);
void palette_make_rect_ramp(Palette *palette, int from, int to, int columns);
struct RGB *palette_to_allegro(const Palette *pal, struct RGB *rgb);
Palette *palette_from_allegro(Palette *pal, const struct RGB *rgb);
Palette *palette_load(const char *filename);
bool palette_save(Palette *palette, const char *filename);
int palette_find_bestfit(const Palette *pal, int r, int g, int b);
#endif /* RASTER_PALETTE_H */