diff options
author | Michael Drake <tlsa@netsurf-browser.org> | 2014-07-19 09:20:45 +0100 |
---|---|---|
committer | Michael Drake <tlsa@netsurf-browser.org> | 2014-07-19 09:20:45 +0100 |
commit | 7ebff5169afecd39fcc9161761d88e792b703d82 (patch) | |
tree | e6725b9bab785792f6e2c357b8f99d053fefaaf2 /src/palette.h | |
parent | 2b22da8d169401917bbd06614b4d3ec8c8856547 (diff) | |
download | libnsfb-7ebff5169afecd39fcc9161761d88e792b703d82.tar.gz libnsfb-7ebff5169afecd39fcc9161761d88e792b703d82.tar.bz2 |
Move private headers out of include/ and into src/
To match our other libraries.
Diffstat (limited to 'src/palette.h')
-rw-r--r-- | src/palette.h | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/src/palette.h b/src/palette.h new file mode 100644 index 0000000..a853254 --- /dev/null +++ b/src/palette.h @@ -0,0 +1,238 @@ +/* + * Copyright 2012 Michael Drake <tlsa@netsurf-browser.org> + * + * This file is part of libnsfb, http://www.netsurf-browser.org/ + * Licenced under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * + * This is the *internal* interface for the cursor. + */ + +#ifndef PALETTE_H +#define PALETTE_H 1 + +#include <stdint.h> +#include <limits.h> + +#include "libnsfb.h" +#include "libnsfb_plot.h" + +enum nsfb_palette_type_e { + NSFB_PALETTE_EMPTY, /**< empty palette object */ + NSFB_PALETTE_NSFB_8BPP, /**< libnsfb's own 8bpp palette */ + NSFB_PALETTE_OTHER /**< any other palette */ +}; + +struct nsfb_palette_s { + enum nsfb_palette_type_e type; /**< Palette type */ + uint8_t last; /**< Last used palette index */ + nsfb_colour_t data[256]; /**< Palette for index modes */ + + bool dither; /**< Whether error diffusion was requested */ + struct { + int width; /**< Length of error value buffer ring*/ + int current; /**< Current pos in ring buffer*/ + int *data; /**< Ring buffer error values */ + int data_len; /**< Max size of ring */ + } dither_ctx; +}; + + +/** Create an empty palette object. */ +bool nsfb_palette_new(struct nsfb_palette_s **palette, int width); + +/** Free a palette object. */ +void nsfb_palette_free(struct nsfb_palette_s *palette); + +/** Init error diffusion for a plot. */ +void nsfb_palette_dither_init(struct nsfb_palette_s *palette, int width); + +/** Finalise error diffusion after a plot. */ +void nsfb_palette_dither_fini(struct nsfb_palette_s *palette); + +/** Generate libnsfb 8bpp default palette. */ +void nsfb_palette_generate_nsfb_8bpp(struct nsfb_palette_s *palette); + +static inline bool nsfb_palette_dithering_on(struct nsfb_palette_s *palette) +{ + return palette->dither; +} + +/** Find best palette match for given colour. */ +static inline uint8_t nsfb_palette_best_match(struct nsfb_palette_s *palette, + nsfb_colour_t c, int *r_error, int *g_error, int *b_error) +{ + uint8_t best_col = 0; + + nsfb_colour_t palent; + int col; + int dr, dg, db; /* delta red, green blue values */ + + int cur_distance; + int best_distance = INT_MAX; + + int r = ( c & 0xFF); + int g = ((c >> 8) & 0xFF); + int b = ((c >> 16) & 0xFF); + + switch (palette->type) { + case NSFB_PALETTE_NSFB_8BPP: + /* Index into colour cube part */ + dr = ((r * 5) + 128) / 256; + dg = ((g * 7) + 128) / 256; + db = ((b * 4) + 128) / 256; + col = 40 * dr + 5 * dg + db; + + palent = palette->data[col]; + dr = r - ( palent & 0xFF); + dg = g - ((palent >> 8) & 0xFF); + db = b - ((palent >> 16) & 0xFF); + cur_distance = (dr * dr) + (dg * dg) + (db * db); + + best_col = col; + best_distance = cur_distance; + *r_error = dr; + *g_error = dg; + *b_error = db; + + /* Index into grayscale part */ + col = (r + g + b + (45 / 2)) / (15 * 3) - 1 + 240; + palent = palette->data[col]; + + dr = r - (palent & 0xFF); + dg = g - (palent & 0xFF); + db = b - (palent & 0xFF); + cur_distance = (dr * dr) + (dg * dg) + (db * db); + if (cur_distance < best_distance) { + best_col = col; + *r_error = dr; + *g_error = dg; + *b_error = db; + } + break; + + case NSFB_PALETTE_OTHER: + /* Try all colours in palette */ + for (col = 0; col <= palette->last; col++) { + palent = palette->data[col]; + + dr = r - ( palent & 0xFF); + dg = g - ((palent >> 8) & 0xFF); + db = b - ((palent >> 16) & 0xFF); + cur_distance = (dr * dr) + (dg * dg) + (db * db); + if (cur_distance < best_distance) { + best_distance = cur_distance; + best_col = col; + *r_error = dr; + *g_error = dg; + *b_error = db; + } + } + break; + + default: + break; + } + + return best_col; +} + +/** Find best palette match for given colour, with error diffusion. */ +static inline uint8_t nsfb_palette_best_match_dither( + struct nsfb_palette_s *palette, nsfb_colour_t c) +{ + int r, g, b; + int current; + int error; + int width = palette->dither_ctx.width; + int *data = palette->dither_ctx.data; + uint8_t best_col_index; + + if (palette == NULL) + return 0; + + if (palette->dither == false) + return nsfb_palette_best_match(palette, c, &r, &g, &b); + + current = palette->dither_ctx.current; + + /* Get RGB components of colour, and apply error */ + r = ( c & 0xFF) + data[current ]; + g = ((c >> 8) & 0xFF) + data[current + 1]; + b = ((c >> 16) & 0xFF) + data[current + 2]; + + /* Clamp new RGB components to range */ + if (r < 0) r = 0; + if (r > 255) r = 255; + if (g < 0) g = 0; + if (g > 255) g = 255; + if (b < 0) b = 0; + if (b > 255) b = 255; + + /* Reset error diffusion slots to 0 */ + data[current ] = 0; + data[current + 1] = 0; + data[current + 2] = 0; + + /* Rebuild colour from modified components */ + c = r + (g << 8) + (b << 16); + + /* Get best match for pixel, and find errors for each component */ + best_col_index = nsfb_palette_best_match(palette, c, &r, &g, &b); + + /* Advance one set of error diffusion slots */ + current += 3; + if (current >= width) + current = 0; + palette->dither_ctx.current = current; + + /* Save errors + * + * [*]-[N] + * / | \ + * [l]-[m]-[r] + */ + error = current; + + /* Error for [N] (next) */ + if (error != 0) { + /* The pixel exists */ + data[error ] += r * 7 / 16; + data[error + 1] += g * 7 / 16; + data[error + 2] += b * 7 / 16; + } + + error += width - 2 * 3; + if (error >= width) + error -= width; + /* Error for [l] (below, left) */ + if (error >= 0 && error != 3) { + /* The pixel exists */ + data[error ] += r * 3 / 16; + data[error + 1] += g * 3 / 16; + data[error + 2] += b * 3 / 16; + } + + error += 3; + if (error >= width) + error -= width; + /* Error for [m] (below, middle) */ + data[error ] += r * 5 / 16; + data[error + 1] += g * 5 / 16; + data[error + 2] += b * 5 / 16; + + error += 3; + if (error >= width) + error -= width; + /* Error for [r] (below, right) */ + if (error != 0) { + /* The pixel exists */ + data[error ] += r / 16; + data[error + 1] += g / 16; + data[error + 2] += b / 16; + } + + return best_col_index; +} + +#endif /* PALETTE_H */ |