Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * 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"
- uint8_t Bpp;
- 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 to use error diffusion */
- 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);
- /** 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;
- switch (palette->type) {
- case NSFB_PALETTE_NSFB_8BPP:
- /* Index into colour cube part */
- dr = ((( c & 0xFF) * 5) + 128) / 256;
- dg = ((((c >> 8) & 0xFF) * 7) + 128) / 256;
- db = ((((c >> 16) & 0xFF) * 4) + 128) / 256;
- col = 40 * dr + 5 * dg + db;
- palent = palette->data[col];
- dr = ( c & 0xFF) - ( palent & 0xFF);
- dg = ((c >> 8) & 0xFF) - ((palent >> 8 ) & 0xFF);
- db = ((c >> 16) & 0xFF) - ((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 = (( c & 0xFF) +
- ((c >> 8) & 0xFF) +
- ((c >> 16) & 0xFF) + (45 / 2)) / (15 * 3) - 1 + 240;
- palent = palette->data[col];
- dr = ( c & 0xFF) - ( palent & 0xFF);
- dg = ((c >> 8) & 0xFF) - ((palent >> 8) & 0xFF);
- db = ((c >> 16) & 0xFF) - ((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;
- case NSFB_PALETTE_OTHER:
- /* Try all colours in palette */
- for (col = 0; col <= palette->last; col++) {
- palent = palette->data[col];
- dr = ( c & 0xFF) - ( palent & 0xFF);
- dg = ((c >> 8) & 0xFF) - ((palent >> 8) & 0xFF);
- db = ((c >> 16) & 0xFF) - ((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;
- 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) + palette->dither_ctx.data[current ];
- g = ((c >> 8) & 0xFF) + palette->dither_ctx.data[current + 1];
- b = ((c >> 16) & 0xFF) + palette->dither_ctx.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 */
- palette->dither_ctx.data[current ] = 0;
- palette->dither_ctx.data[current + 1] = 0;
- palette->dither_ctx.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 */
- palette->dither_ctx.data[error ] += r * 7 / 16;
- palette->dither_ctx.data[error + 1] += g * 7 / 16;
- palette->dither_ctx.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 */
- palette->dither_ctx.data[error ] += r * 3 / 16;
- palette->dither_ctx.data[error + 1] += g * 3 / 16;
- palette->dither_ctx.data[error + 2] += b * 3 / 16;
- }
- error += 3;
- if (error >= width)
- error -= width;
- /* Error for [m] (below, middle) */
- palette->dither_ctx.data[error ] += r * 5 / 16;
- palette->dither_ctx.data[error + 1] += g * 5 / 16;
- palette->dither_ctx.data[error + 2] += b * 5 / 16;
- error += 3;
- if (error >= width)
- error -= width;
- /* Error for [r] (below, right) */
- if (error != 0) {
- /* The pixel exists */
- palette->dither_ctx.data[error ] += r / 16;
- palette->dither_ctx.data[error + 1] += g / 16;
- palette->dither_ctx.data[error + 2] += b / 16;
- }
- return best_col_index;
- }
- #endif /* PALETTE_H */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement