From d2944d5def6e8b30ddab2239b7307a7ada307886 Mon Sep 17 00:00:00 2001 From: David Capello Date: Sat, 22 Mar 2008 21:44:03 +0000 Subject: [PATCH] Added raster/palette.[ch] (duh) --- src/raster/palette.c | 418 +++++++++++++++++++++++++++++++++++++++++++ src/raster/palette.h | 65 +++++++ 2 files changed, 483 insertions(+) create mode 100644 src/raster/palette.c create mode 100644 src/raster/palette.h diff --git a/src/raster/palette.c b/src/raster/palette.c new file mode 100644 index 000000000..851ecc252 --- /dev/null +++ b/src/raster/palette.c @@ -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 +#include + +#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; ccolor[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; icolor[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; ccolor[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; ccolor[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; ccolor[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; icolor[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; icolor[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; ycolor[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; icolor[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; icolor[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 (icolor[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; +} diff --git a/src/raster/palette.h b/src/raster/palette.h new file mode 100644 index 000000000..cecd376a3 --- /dev/null +++ b/src/raster/palette.h @@ -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 + +#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 */