mirror of
https://github.com/aseprite/aseprite.git
synced 2024-12-29 18:20:44 +00:00
Added raster/palette.[ch] (duh)
This commit is contained in:
parent
bec33706bf
commit
d2944d5def
418
src/raster/palette.c
Normal file
418
src/raster/palette.c
Normal 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
65
src/raster/palette.h
Normal 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 */
|
Loading…
Reference in New Issue
Block a user