You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
PDCursesMod/common/pdccolor.c

220 lines
6.2 KiB
C

/* PDCurses */
/* Palette management code used by VT, WinGUI, SDL1/2, and X11 for
'full color' (24-bit). It may eventually be used by DOSVGA, WinCon,
and/or the Plan9 platform, all of which have full color capability.
It will presumably never be useful for the DOS or OS/2 platforms.
See 'pdccolor.txt' for a rationale of how this works. */
#include <stdlib.h>
#include <assert.h>
#define PACKED_RGB uint32_t
#ifndef PACK_RGB
#define PACK_RGB( red, green, blue) ((red) | ((green)<<8) | ((PACKED_RGB)(blue) << 16))
#endif
#include <curspriv.h>
#include "pdccolor.h"
int PDC_blink_state = 0;
static PACKED_RGB *rgbs; /* the 'standard' 256-color palette, plus any allocated */
static int _palette_size;
PACKED_RGB PDC_default_color( int idx)
{
PACKED_RGB rval;
assert( idx >= 0);
if( idx < 16)
{
if( idx == 8)
rval = PACK_RGB( 0x80, 0x80, 0x80);
else
{
const int intensity = ((idx & 8) ? 0xff : 0xc0);
rval = PACK_RGB( ((idx & COLOR_RED) ? intensity : 0),
((idx & COLOR_GREEN) ? intensity : 0),
((idx & COLOR_BLUE) ? intensity : 0));
}
}
else if( idx < 216 + 16)
{ /* colors 16-231 are a 6x6x6 color cube */
int r, g, b;
idx -= 16;
r = idx / 36;
g = (idx / 6) % 6;
b = idx % 6;
rval = PACK_RGB( r ? r * 40 + 55 : 0,
g ? g * 40 + 55 : 0,
b ? b * 40 + 55 : 0);
}
else if( idx < 256) /* colors 232-255 are 24 shades of gray */
{
const int intensity = (idx - 232) * 10 + 8;
rval = PACK_RGB( intensity, intensity, intensity);
}
else /* colors 256 to 256+2^24 are RGB values */
rval = idx - 256;
return( rval);
}
int PDC_init_palette( void)
{
return( 0);
}
void PDC_free_palette( void)
{
if( rgbs)
free( rgbs);
rgbs = NULL;
}
PACKED_RGB PDC_get_palette_entry( const int idx)
{
PACKED_RGB rval;
if( idx < _palette_size)
{
assert( idx >= 0);
rval = rgbs[idx];
}
else
rval = PDC_default_color( idx);
return( rval);
}
/* Return value is -1 if no palette could be allocated, 0 if the color
didn't change (new RGB matched the old one), and 1 if the color changed. */
int PDC_set_palette_entry( const int idx, const PACKED_RGB rgb)
{
int rval, i;
if( idx >= _palette_size)
{
int new_size = _palette_size;
const int initial_palette_size = 8;
if( !new_size)
new_size = initial_palette_size;
while( new_size <= idx)
new_size *= 2;
rgbs = (PACKED_RGB *)realloc( rgbs, new_size * sizeof( PACKED_RGB));
assert( rgbs);
if( !rgbs)
return( -1);
for( i = _palette_size; i < new_size; i++)
rgbs[i] = PDC_default_color( i);
_palette_size = new_size;
}
rval = (rgbs[idx] == rgb ? 1 : 0);
rgbs[idx] = rgb;
return( rval);
}
/* This function 'intensifies' a color by shifting it toward white. */
/* It used to average the input color with white. Then it did a */
/* weighted average: 2/3 of the input color, 1/3 white, for a */
/* lower "intensification" level. */
/* Then Mark Hessling suggested that the output level should */
/* remap zero to 85 (= 255 / 3, so one-third intensity), and input */
/* of 192 or greater should be remapped to 255 (full intensity). */
/* Assuming we want a linear response between zero and 192, that */
/* leads to output = 85 + input * (255-85)/192. */
/* This should lead to proper handling of bold text in legacy */
/* apps, where "bold" means "high intensity". */
static PACKED_RGB intensified_color( PACKED_RGB ival)
{
int rgb, i;
PACKED_RGB oval = 0;
for( i = 0; i < 3; i++, ival >>= 8)
{
rgb = (int)( ival & 0xff);
if( rgb >= 192)
rgb = 255;
else
rgb = 85 + rgb * (255 - 85) / 192;
oval |= ((PACKED_RGB)rgb << (i * 8));
}
return( oval);
}
/* For use in adjusting colors for A_DIMmed characters. Just */
/* knocks down the intensity of R, G, and B by 1/3. */
static PACKED_RGB dimmed_color( PACKED_RGB ival)
{
unsigned i;
PACKED_RGB oval = 0;
for( i = 0; i < 3; i++, ival >>= 8)
{
unsigned rgb = (unsigned)( ival & 0xff);
rgb -= (rgb / 3);
oval |= ((PACKED_RGB)rgb << (i * 8));
}
return( oval);
}
void PDC_get_rgb_values( const chtype srcp,
PACKED_RGB *foreground_rgb, PACKED_RGB *background_rgb)
{
const int color = (int)(( srcp & A_COLOR) >> PDC_COLOR_SHIFT);
bool reverse_colors = ((srcp & A_REVERSE) ? TRUE : FALSE);
bool intensify_backgnd = FALSE;
bool default_foreground = FALSE, default_background = FALSE;
int foreground_index, background_index;
extended_pair_content( color, &foreground_index, &background_index);
if( foreground_index < 0 && SP->orig_attr)
default_foreground = TRUE;
else
*foreground_rgb = PDC_get_palette_entry( foreground_index);
if( background_index < 0 && SP->orig_attr)
default_background = TRUE;
else
*background_rgb = PDC_get_palette_entry( background_index);
if( srcp & A_BLINK)
{
if( !(SP->termattrs & A_BLINK)) /* convert 'blinking' to 'bold' */
intensify_backgnd = TRUE;
else if( PDC_blink_state)
reverse_colors ^= 1;
}
if( default_foreground)
*foreground_rgb = (PACKED_RGB)-1;
else if( srcp & A_BOLD & ~SP->termattrs)
*foreground_rgb = intensified_color( *foreground_rgb);
if( default_background)
*background_rgb = (PACKED_RGB)-1;
else if( intensify_backgnd)
*background_rgb = intensified_color( *background_rgb);
if( srcp & A_DIM)
{
if( !default_foreground)
*foreground_rgb = dimmed_color( *foreground_rgb);
if( !default_background)
*background_rgb = dimmed_color( *background_rgb);
}
if( reverse_colors)
{
const PACKED_RGB temp = *foreground_rgb;
*foreground_rgb = *background_rgb;
*background_rgb = temp;
}
}