Advertisement
Guest User

pallete.h

a guest
Oct 1st, 2013
167
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.44 KB | None | 0 0
  1. /*
  2.  * Copyright 2012 Michael Drake <tlsa@netsurf-browser.org>
  3.  *
  4.  * This file is part of libnsfb, http://www.netsurf-browser.org/
  5.  * Licenced under the MIT License,
  6.  *                http://www.opensource.org/licenses/mit-license.php
  7.  *
  8.  * This is the *internal* interface for the cursor.
  9.  */
  10.  
  11. #ifndef PALETTE_H
  12. #define PALETTE_H 1
  13.  
  14. #include <stdint.h>
  15. #include <limits.h>
  16.  
  17. #include "libnsfb.h"
  18. #include "libnsfb_plot.h"
  19.  
  20. uint8_t Bpp;
  21.  
  22. enum nsfb_palette_type_e {
  23.     NSFB_PALETTE_EMPTY,     /**< empty palette object */
  24.     NSFB_PALETTE_NSFB_8BPP, /**< libnsfb's own 8bpp palette */
  25.     NSFB_PALETTE_OTHER      /**< any other palette  */
  26. };
  27.  
  28. struct nsfb_palette_s {
  29.     enum nsfb_palette_type_e type; /**< Palette type */
  30.     uint8_t last; /**< Last used palette index */
  31.     nsfb_colour_t data[256]; /**< Palette for index modes */
  32.  
  33.     bool dither; /**< Whether to use error diffusion */
  34.     struct {
  35.         int width; /**< Length of error value buffer ring*/
  36.         int current; /**< Current pos in ring buffer*/
  37.         int *data; /**< Ring buffer error values */
  38.         int data_len; /**< Max size of ring */
  39.     } dither_ctx;
  40. };
  41.  
  42.  
  43. /** Create an empty palette object. */
  44. bool nsfb_palette_new(struct nsfb_palette_s **palette, int width);
  45.  
  46. /** Free a palette object. */
  47. void nsfb_palette_free(struct nsfb_palette_s *palette);
  48.  
  49. /** Init error diffusion for a plot. */
  50. void nsfb_palette_dither_init(struct nsfb_palette_s *palette, int width);
  51.  
  52. /** Finalise error diffusion after a plot. */
  53. void nsfb_palette_dither_fini(struct nsfb_palette_s *palette);
  54.  
  55. /** Generate libnsfb 8bpp default palette. */
  56. void nsfb_palette_generate_nsfb_8bpp(struct nsfb_palette_s *palette);
  57.  
  58. /** Find best palette match for given colour. */
  59. static inline uint8_t nsfb_palette_best_match(struct nsfb_palette_s *palette,
  60.         nsfb_colour_t c, int *r_error, int *g_error, int *b_error)
  61. {
  62.     uint8_t best_col = 0;
  63.  
  64.     nsfb_colour_t palent;
  65.     int col;
  66.     int dr, dg, db; /* delta red, green blue values */
  67.  
  68.     int cur_distance;
  69.     int best_distance = INT_MAX;
  70.  
  71.     switch (palette->type) {
  72.     case NSFB_PALETTE_NSFB_8BPP:
  73.         /* Index into colour cube part */
  74.         dr = ((( c        & 0xFF) * 5) + 128) / 256;
  75.         dg = ((((c >>  8) & 0xFF) * 7) + 128) / 256;
  76.         db = ((((c >> 16) & 0xFF) * 4) + 128) / 256;
  77.         col = 40 * dr + 5 * dg + db;
  78.  
  79.         palent = palette->data[col];
  80.         dr = ( c        & 0xFF) - ( palent        & 0xFF);
  81.         dg = ((c >>  8) & 0xFF) - ((palent >> 8 ) & 0xFF);
  82.         db = ((c >> 16) & 0xFF) - ((palent >> 16) & 0xFF);
  83.         cur_distance = (dr * dr) + (dg * dg) + (db * db);
  84.  
  85.         best_col = col;
  86.         best_distance = cur_distance;
  87.         *r_error = dr;
  88.         *g_error = dg;
  89.         *b_error = db;
  90.  
  91.         /* Index into grayscale part */
  92.         col = (( c        & 0xFF) +
  93.                ((c >>  8) & 0xFF) +
  94.                ((c >> 16) & 0xFF) + (45 / 2)) / (15 * 3) - 1 + 240;
  95.         palent = palette->data[col];
  96.  
  97.         dr = ( c        & 0xFF) - ( palent        & 0xFF);
  98.         dg = ((c >>  8) & 0xFF) - ((palent >>  8) & 0xFF);
  99.         db = ((c >> 16) & 0xFF) - ((palent >> 16) & 0xFF);
  100.         cur_distance = (dr * dr) + (dg * dg) + (db * db);
  101.         if (cur_distance < best_distance) {
  102.             best_distance = cur_distance;
  103.             best_col = col;
  104.             *r_error = dr;
  105.             *g_error = dg;
  106.             *b_error = db;
  107.         }
  108.         break;
  109.  
  110.     case NSFB_PALETTE_OTHER:
  111.         /* Try all colours in palette */
  112.         for (col = 0; col <= palette->last; col++) {
  113.             palent = palette->data[col];
  114.  
  115.             dr = ( c        & 0xFF) - ( palent        & 0xFF);
  116.             dg = ((c >>  8) & 0xFF) - ((palent >>  8) & 0xFF);
  117.             db = ((c >> 16) & 0xFF) - ((palent >> 16) & 0xFF);
  118.             cur_distance = (dr * dr) + (dg * dg) + (db * db);
  119.             if (cur_distance < best_distance) {
  120.                 best_distance = cur_distance;
  121.                 best_col = col;
  122.                 *r_error = dr;
  123.                 *g_error = dg;
  124.                 *b_error = db;
  125.             }
  126.         }
  127.         break;
  128.  
  129.     default:
  130.         break;
  131.     }
  132.  
  133.         return best_col;
  134. }
  135.  
  136. /** Find best palette match for given colour, with error diffusion. */
  137. static inline uint8_t nsfb_palette_best_match_dither(
  138.         struct nsfb_palette_s *palette, nsfb_colour_t c)
  139. {
  140.     int r, g, b;
  141.     int current;
  142.     int error;
  143.     int width = palette->dither_ctx.width;
  144.     uint8_t best_col_index;
  145.  
  146.     if (palette == NULL)
  147.         return 0;
  148.  
  149.     if (palette->dither == false)
  150.         return nsfb_palette_best_match(palette, c, &r, &g, &b);
  151.  
  152.     current = palette->dither_ctx.current;
  153.  
  154.     /* Get RGB components of colour, and apply error */
  155.     r = ( c        & 0xFF) + palette->dither_ctx.data[current    ];
  156.     g = ((c >>  8) & 0xFF) + palette->dither_ctx.data[current + 1];
  157.     b = ((c >> 16) & 0xFF) + palette->dither_ctx.data[current + 2];
  158.  
  159.     /* Clamp new RGB components to range */
  160.     if (r <   0) r =   0;
  161.     if (r > 255) r = 255;
  162.     if (g <   0) g =   0;
  163.     if (g > 255) g = 255;
  164.     if (b <   0) b =   0;
  165.     if (b > 255) b = 255;
  166.  
  167.     /* Reset error diffusion slots to 0 */
  168.     palette->dither_ctx.data[current    ] = 0;
  169.     palette->dither_ctx.data[current + 1] = 0;
  170.     palette->dither_ctx.data[current + 2] = 0;
  171.  
  172.     /* Rebuild colour from modified components */
  173.     c = r + (g << 8) + (b << 16);
  174.  
  175.     /* Get best match for pixel, and find errors for each component */
  176.     best_col_index = nsfb_palette_best_match(palette, c, &r, &g, &b);
  177.  
  178.     /* Advance one set of error diffusion slots */
  179.     current += 3;
  180.     if (current >= width)
  181.         current = 0;
  182.     palette->dither_ctx.current = current;
  183.  
  184.     /* Save errors
  185.      *
  186.      *       [*]-[N]
  187.      *      / | \
  188.      *   [l]-[m]-[r]
  189.      */
  190.     error = current;
  191.  
  192.     /* Error for [N] (next) */
  193.     if (error != 0) {
  194.         /* The pixel exists */
  195.         palette->dither_ctx.data[error    ] += r * 7 / 16;
  196.         palette->dither_ctx.data[error + 1] += g * 7 / 16;
  197.         palette->dither_ctx.data[error + 2] += b * 7 / 16;
  198.     }
  199.  
  200.     error += width - 2 * 3;
  201.     if (error >= width)
  202.         error -= width;
  203.     /* Error for [l] (below, left) */
  204.     if (error >= 0 && error != 3) {
  205.         /* The pixel exists */
  206.         palette->dither_ctx.data[error    ] += r * 3 / 16;
  207.         palette->dither_ctx.data[error + 1] += g * 3 / 16;
  208.         palette->dither_ctx.data[error + 2] += b * 3 / 16;
  209.     }
  210.  
  211.     error += 3;
  212.     if (error >= width)
  213.         error -= width;
  214.     /* Error for [m] (below, middle) */
  215.     palette->dither_ctx.data[error    ] += r * 5 / 16;
  216.     palette->dither_ctx.data[error + 1] += g * 5 / 16;
  217.     palette->dither_ctx.data[error + 2] += b * 5 / 16;
  218.  
  219.     error += 3;
  220.     if (error >= width)
  221.         error -= width;
  222.     /* Error for [r] (below, right) */
  223.     if (error != 0) {
  224.         /* The pixel exists */
  225.         palette->dither_ctx.data[error    ] += r / 16;
  226.         palette->dither_ctx.data[error + 1] += g / 16;
  227.         palette->dither_ctx.data[error + 2] += b / 16;
  228.     }
  229.  
  230.     return best_col_index;
  231. }
  232.  
  233. #endif /* PALETTE_H */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement