summaryrefslogtreecommitdiffstats
path: root/kernel/kls_ttf/ftview/gblender.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kls_ttf/ftview/gblender.cpp')
-rw-r--r--kernel/kls_ttf/ftview/gblender.cpp381
1 files changed, 381 insertions, 0 deletions
diff --git a/kernel/kls_ttf/ftview/gblender.cpp b/kernel/kls_ttf/ftview/gblender.cpp
new file mode 100644
index 0000000..a0f204d
--- /dev/null
+++ b/kernel/kls_ttf/ftview/gblender.cpp
@@ -0,0 +1,381 @@
+#include "gblender.h"
+#include <stdlib.h>
+#include <math.h>
+
+static void
+gblender_set_gamma_table( double gamma_value,
+ unsigned short* gamma_ramp,
+ unsigned char* gamma_ramp_inv )
+{
+ int gmax = (256 << GBLENDER_GAMMA_SHIFT)-1;
+
+ if ( gamma_value <= 0 ) /* special case for sRGB */
+ {
+ int ii;
+
+ for ( ii = 0; ii < 256; ii++ )
+ {
+ double x = (double)ii / 255.0;
+
+ if ( x <= 0.03926 )
+ x = x/12.92;
+ else
+ x = pow( (x+0.055)/ 1.055, 2.4 );
+
+ gamma_ramp[ii] = (unsigned short)(gmax*x);
+ }
+
+ for ( ii = 0; ii < gmax; ii++ )
+ {
+ double x = (double)ii / gmax;
+
+ if ( x <= 0.00304 )
+ x = 12.92*x;
+ else
+ x = 1.055*pow(x,1/2.4) - 0.055;
+
+ gamma_ramp_inv[ii] = (unsigned char)(255*x);
+ }
+ }
+ else
+ {
+ int ii;
+ double gamma_inv = 1.0f / gamma_value;
+
+ /* voltage to linear */
+ for ( ii = 0; ii < 256; ii++ )
+ gamma_ramp[ii] = (unsigned short)( pow( (double)ii/255.0f, gamma_value )*gmax );
+
+ /* linear to voltage */
+ for ( ii = 0; ii < gmax; ii++ )
+ gamma_ramp_inv[ii] = (unsigned char)( pow( (double)ii/gmax, gamma_inv ) * 255.0f );
+ }
+}
+
+
+/* clear the cache
+ */
+static void
+gblender_clear( GBlender blender )
+{
+ int nn;
+ GBlenderKey keys = blender->keys;
+
+ if ( blender->channels )
+ {
+ GBlenderChanKey chan_keys = (GBlenderChanKey) blender->keys;
+
+ for ( nn = 0; nn < GBLENDER_KEY_COUNT; nn++ )
+ chan_keys[nn].index = -1;
+ }
+ else
+ {
+ for ( nn = 0; nn < GBLENDER_KEY_COUNT; nn++ )
+ keys[nn].cells = NULL;
+ }
+}
+
+GBLENDER_APIDEF( void )
+gblender_reset( GBlender blender )
+{
+ gblender_clear( blender );
+
+ blender->cache_r_back = -1;
+ blender->cache_r_fore = -1;
+ blender->cache_r_cells = 0;
+
+ blender->cache_r_back = -1;
+ blender->cache_r_fore = -1;
+ blender->cache_r_cells = 0;
+
+ blender->cache_back = 0;
+ blender->cache_fore = 0xFFFFFF;
+ blender->cache_cells = gblender_lookup( blender,
+ blender->cache_back,
+ blender->cache_fore );
+
+#ifdef GBLENDER_STATS
+ blender->stat_hits = 0;
+ blender->stat_lookups = 0;
+ blender->stat_keys = 0;
+ blender->stat_clears = 0;
+#endif
+}
+
+GBLENDER_APIDEF( void )
+gblender_init( GBlender blender,
+ double gamma_value )
+{
+ blender->channels = 0;
+
+ gblender_set_gamma_table ( gamma_value,
+ blender->gamma_ramp,
+ blender->gamma_ramp_inv );
+
+ gblender_reset( blender );
+}
+
+/* recompute the grade levels of a given key
+ */
+static void
+gblender_reset_key( GBlender blender,
+ GBlenderKey key )
+{
+ GBlenderPixel back = key->background;
+ GBlenderPixel fore = key->foreground;
+ GBlenderCell* gr = key->cells;
+ int nn;
+ int gmax = (256 << GBLENDER_GAMMA_SHIFT)-1;
+
+ const unsigned char* gamma_ramp_inv = blender->gamma_ramp_inv;
+ const unsigned short* gamma_ramp = blender->gamma_ramp;
+
+ int r1,g1,b1,r2,g2,b2;
+
+ r1 = ( back >> 16 ) & 255;
+ g1 = ( back >> 8 ) & 255;
+ b1 = ( back ) & 255;
+
+ r2 = ( fore >> 16 ) & 255;
+ g2 = ( fore >> 8 ) & 255;
+ b2 = ( fore ) & 255;
+
+#ifdef GBLENDER_STORE_BYTES
+ gr[0] = (unsigned char)r1;
+ gr[1] = (unsigned char)g1;
+ gr[2] = (unsigned char)b1;
+ gr += 3;
+#else
+ gr[0] = back;
+ gr += 1;
+#endif
+
+ r1 = gamma_ramp[r1];
+ g1 = gamma_ramp[g1];
+ b1 = gamma_ramp[b1];
+
+ r2 = gamma_ramp[r2];
+ g2 = gamma_ramp[g2];
+ b2 = gamma_ramp[b2];
+
+ for ( nn = 1; nn < GBLENDER_SHADE_COUNT; nn++ )
+ {
+ int a = (nn << GBLENDER_SHADE_BITS);
+ int r = ((r2-r1)*a + 128);
+ int g = ((g2-g1)*a + 128);
+ int b = ((g2-g1)*a + 128);
+
+ r = (r + (r >> 8)) >> 8;
+ g = (g + (g >> 8)) >> 8;
+ b = (b + (b >> 8)) >> 8;
+
+ r += r1;
+ g += g1;
+ b += b1;
+
+#if 0
+ r = ( r | -(r >> 8) ) & 255;
+ g = ( g | -(g >> 8) ) & 255;
+ b = ( b | -(b >> 8) ) & 255;
+#else
+ if ( r < 0 ) r = 0; else if ( r > gmax ) r = gmax;
+ if ( g < 0 ) g = 0; else if ( g > gmax ) g = gmax;
+ if ( b < 0 ) b = 0; else if ( b > gmax ) b = gmax;
+#endif
+
+ r = gamma_ramp_inv[r];
+ g = gamma_ramp_inv[g];
+ b = gamma_ramp_inv[b];
+
+#ifdef GBLENDER_STORE_BYTES
+ gr[0] = (unsigned char)r;
+ gr[1] = (unsigned char)g;
+ gr[2] = (unsigned char)b;
+ gr += 3;
+#else
+ gr[0] = (( r & 255 ) << 16) |
+ (( g & 255 ) << 8 ) |
+ (( b & 255 ) ) ;
+ gr ++;
+#endif
+ }
+}
+
+ /* lookup the grades of a given (background,foreground) couple
+ */
+GBLENDER_APIDEF( GBlenderCell* )
+gblender_lookup( GBlender blender,
+ GBlenderPixel background,
+ GBlenderPixel foreground )
+{
+ int idx, idx0;
+ GBlenderKey key;
+
+#ifdef GBLENDER_STATS
+ blender->stat_hits--;
+ blender->stat_lookups++;
+#endif
+
+ if ( blender->channels )
+ {
+ /* set to normal mode */
+ blender->channels = 0;
+ gblender_reset( blender );
+ }
+
+ idx0 = ( background + foreground*63 ) % GBLENDER_KEY_COUNT;
+ idx = idx0;
+ do
+ {
+ key = blender->keys + idx;
+
+ if ( key->cells == NULL )
+ goto NewNode;
+
+ if ( key->background == background &&
+ key->foreground == foreground )
+ goto Exit;
+
+ idx = (idx+1) % GBLENDER_KEY_COUNT;
+ }
+ while ( idx != idx0 );
+
+ /* the cache is full, clear it completely
+ */
+#ifdef GBLENDER_STATS
+ blender->stat_clears++;
+ gblender_clear( blender );
+#endif
+
+NewNode:
+ key->background = background;
+ key->foreground = foreground;
+ key->cells = blender->cells + \
+ idx0*(GBLENDER_SHADE_COUNT*GBLENDER_CELL_SIZE);
+
+ gblender_reset_key( blender, key );
+
+#ifdef GBLENDER_STATS
+ blender->stat_keys++;
+#endif
+
+Exit:
+ return key->cells;
+}
+
+
+static void
+gblender_reset_channel_key( GBlender blender,
+ GBlenderChanKey key )
+{
+ int back = key->backfore & 255;
+ int fore = (key->backfore >> 8) & 255;
+ unsigned char* gr = (unsigned char*)blender->cells + key->index;
+ int nn;
+
+ const unsigned char* gamma_ramp_inv = blender->gamma_ramp_inv;
+ const unsigned short* gamma_ramp = blender->gamma_ramp;
+
+ int r1,r2;
+ int gmax = (256 << GBLENDER_GAMMA_SHIFT)-1;
+
+ r1 = back;
+ r2 = fore;
+
+ gr[0] = r1;
+ gr++;
+
+
+ r1 = gamma_ramp[r1];
+ r2 = gamma_ramp[r2];
+
+ for ( nn = 1; nn < GBLENDER_SHADE_COUNT; nn++ )
+ {
+ int a = (nn << GBLENDER_SHADE_BITS);
+ int r = ((r2-r1)*a + 128);
+
+ r = (r + (r >> 8)) >> 8;
+ r += r1;
+ if ( r < 0 ) r = 0; else if ( r > gmax ) r = gmax;
+ r = gamma_ramp_inv[r];
+
+ gr[0] = (unsigned char)r;
+ gr++;
+ }
+}
+
+
+GBLENDER_APIDEF( unsigned char* )
+gblender_lookup_channel( GBlender blender,
+ int background,
+ int foreground )
+{
+ int idx, idx0;
+ unsigned short backfore = (unsigned short)((foreground << 8) | background);
+ GBlenderChanKey key;
+
+#ifdef GBLENDER_STATS
+ blender->stat_hits--;
+ blender->stat_lookups++;
+#endif
+
+ if ( !blender->channels )
+ {
+ /* set to normal mode */
+ blender->channels = 1;
+ gblender_reset( blender );
+ }
+
+ idx0 = ( background + foreground*63 ) % (2*GBLENDER_KEY_COUNT);
+ idx = idx0;
+ do
+ {
+ key = (GBlenderChanKey)blender->keys + idx;
+
+ if ( key->index < 0 )
+ goto NewNode;
+
+ if ( key->backfore == backfore )
+ goto Exit;
+
+ idx = (idx+1) % (2*GBLENDER_KEY_COUNT);
+ }
+ while ( idx != idx0 );
+
+ /* the cache is full, clear it completely
+ */
+#ifdef GBLENDER_STATS
+ blender->stat_clears++;
+ gblender_clear( blender );
+#endif
+
+NewNode:
+ key->backfore = backfore;
+ key->index = (signed short)( idx0 * GBLENDER_SHADE_COUNT );
+
+ gblender_reset_channel_key( blender, key );
+
+#ifdef GBLENDER_STATS
+ blender->stat_keys++;
+#endif
+
+Exit:
+ return (unsigned char*)blender->cells + key->index;
+}
+
+
+
+#ifdef GBLENDER_STATS
+#include <stdio.h>
+GBLENDER_APIDEF( void )
+gblender_dump_stats( GBlender blender )
+{
+ printf( "hits = %ld, miss1 = %ld, miss2 = %ld, rate1=%.2f%%, rate2=%.2f%%\n",
+ blender->stat_hits,
+ blender->stat_lookups,
+ blender->stat_keys,
+ (100.0*blender->stat_hits) / (double)(blender->stat_hits + blender->stat_lookups),
+ (100.0*blender->stat_lookups) / (double)( blender->stat_lookups + blender->stat_keys)
+ );
+}
+#endif