Add color manipulation utilities
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -77,3 +77,7 @@ _deps
|
|||||||
*.html
|
*.html
|
||||||
*.3
|
*.3
|
||||||
*.zip
|
*.zip
|
||||||
|
|
||||||
|
# Exclude temporary and backup files
|
||||||
|
*.tmp
|
||||||
|
*.bak
|
||||||
@@ -82,6 +82,7 @@ set(BH_SOURCE
|
|||||||
src/Args.c
|
src/Args.c
|
||||||
src/Buffer.c
|
src/Buffer.c
|
||||||
src/Bytes.c
|
src/Bytes.c
|
||||||
|
src/Color.c
|
||||||
src/Hashmap.c
|
src/Hashmap.c
|
||||||
src/IO.c
|
src/IO.c
|
||||||
src/Math/Box2f.c
|
src/Math/Box2f.c
|
||||||
@@ -110,6 +111,7 @@ set(BH_SOURCE
|
|||||||
set(BH_HEADER
|
set(BH_HEADER
|
||||||
include/BH/Algo.h
|
include/BH/Algo.h
|
||||||
include/BH/Args.h
|
include/BH/Args.h
|
||||||
|
include/BH/Color.h
|
||||||
include/BH/Common.h
|
include/BH/Common.h
|
||||||
include/BH/Hashmap.h
|
include/BH/Hashmap.h
|
||||||
include/BH/IO.h
|
include/BH/IO.h
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ SRCS = src/Algo.c \
|
|||||||
src/Args.c \
|
src/Args.c \
|
||||||
src/Buffer.c \
|
src/Buffer.c \
|
||||||
src/Bytes.c \
|
src/Bytes.c \
|
||||||
|
src/Color.c \
|
||||||
src/Hashmap.c \
|
src/Hashmap.c \
|
||||||
src/IO.c \
|
src/IO.c \
|
||||||
src/Math/Box2f.c \
|
src/Math/Box2f.c \
|
||||||
|
|||||||
314
doc/Manual/en/BH_Color.pod
Normal file
314
doc/Manual/en/BH_Color.pod
Normal file
@@ -0,0 +1,314 @@
|
|||||||
|
=encoding UTF-8
|
||||||
|
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
BH_Color - color manipulation utility
|
||||||
|
|
||||||
|
|
||||||
|
=head1 SYNTAX
|
||||||
|
|
||||||
|
#include <BH/Math/Box3f.h>
|
||||||
|
|
||||||
|
cc prog.c -o prog -lbh
|
||||||
|
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
The BH_Color module provides mechanism for color representation and translation
|
||||||
|
between different color spaces color spaces (RGB, HSL and HSV). Additionally,
|
||||||
|
this module provides mechanism for blending two colors.
|
||||||
|
|
||||||
|
|
||||||
|
=head1 NOTES
|
||||||
|
|
||||||
|
Internally, color is stored in four 16-bit integers.
|
||||||
|
|
||||||
|
When converting between RGB and HSV/HSL there is ~0.009% error. While this is
|
||||||
|
not an issue, if you are using 8-bit RGB value, this may become a problem for
|
||||||
|
the 16-bit RGB values (not every RGB value can be represented in unique HSV/HSL
|
||||||
|
value). If you need this kind of precision, then this module is not for you.
|
||||||
|
|
||||||
|
Almost all color blending modes work like in other software packages. The
|
||||||
|
exception is I<BH_COLOR_MODE_SOFT_LIGHT>. This library opted-in for the Pegtop's
|
||||||
|
version of the formula (which might yield different results). This might be an
|
||||||
|
issue if you are trying to implement standard complient SVG or PDF renderer.
|
||||||
|
|
||||||
|
The I<BH_COLOR_MODE_HUE>, I<BH_COLOR_MODE_SATURATION>, I<BH_COLOR_MODE_COLOR>
|
||||||
|
and I<BH_COLOR_MODE_LUMINOSITY> are implemented in HSL color space.
|
||||||
|
|
||||||
|
|
||||||
|
=head1 API CALLS
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorRGBA8
|
||||||
|
|
||||||
|
void BH_ColorRGBA8(const BH_Color *color,
|
||||||
|
uint8_t *r,
|
||||||
|
uint8_t *g,
|
||||||
|
uint8_t *b,
|
||||||
|
uint8_t *a);
|
||||||
|
|
||||||
|
Gets 8-bit RGBA representation of the I<color>.
|
||||||
|
|
||||||
|
Parameters I<r>, I<g>, I<b>, I<a> represent color components in RGB color space.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorRGBA16
|
||||||
|
|
||||||
|
void BH_ColorRGBA16(const BH_Color *color,
|
||||||
|
uint16_t *r,
|
||||||
|
uint16_t *g,
|
||||||
|
uint16_t *b,
|
||||||
|
uint16_t *a);
|
||||||
|
|
||||||
|
Gets 16-bit RGBA representation of the I<color>.
|
||||||
|
|
||||||
|
Parameters I<r>, I<g>, I<b>, I<a> represent color components in RGB color space.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorRGBAf
|
||||||
|
|
||||||
|
void BH_ColorRGBAf(const BH_Color *color,
|
||||||
|
float *r,
|
||||||
|
float *g,
|
||||||
|
float *b,
|
||||||
|
float *a);
|
||||||
|
|
||||||
|
Gets floating-point RGBA representation of the I<color>.
|
||||||
|
|
||||||
|
Parameters I<r>, I<g>, I<b>, I<a> represent color components in RGB color space.
|
||||||
|
|
||||||
|
=head2 BH_ColorSetRGBA8
|
||||||
|
|
||||||
|
void BH_ColorSetRGBA8(BH_Color *color,
|
||||||
|
uint8_t r,
|
||||||
|
uint8_t g,
|
||||||
|
uint8_t b,
|
||||||
|
uint8_t a);
|
||||||
|
|
||||||
|
Sets 8-bit I<r>, I<g>, I<b>, I<a> components of the color.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorSetRGBA16
|
||||||
|
|
||||||
|
void BH_ColorSetRGBA16(BH_Color *color,
|
||||||
|
uint16_t r,
|
||||||
|
uint16_t g,
|
||||||
|
uint16_t b,
|
||||||
|
uint16_t a);
|
||||||
|
|
||||||
|
Sets 16-bit I<r>, I<g>, I<b>, I<a> components of the color.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorSetRGBAf
|
||||||
|
|
||||||
|
void BH_ColorSetRGBAf(BH_Color *color,
|
||||||
|
float r,
|
||||||
|
float g,
|
||||||
|
float b,
|
||||||
|
float a);
|
||||||
|
|
||||||
|
Sets floating-point I<r>, I<g>, I<b>, I<a> components of the color.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorHSVAf
|
||||||
|
|
||||||
|
void BH_ColorHSVAf(const BH_Color *color,
|
||||||
|
float *h,
|
||||||
|
float *s,
|
||||||
|
float *v,
|
||||||
|
float *a);
|
||||||
|
|
||||||
|
Gets floating-point HSV representation of the I<color>.
|
||||||
|
|
||||||
|
Parameters I<h>, I<s>, I<v>, I<a> represent color components in HSV color space.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorSetHSVAf
|
||||||
|
|
||||||
|
void BH_ColorSetHSVAf(BH_Color *color,
|
||||||
|
float h,
|
||||||
|
float s,
|
||||||
|
float v,
|
||||||
|
float a);
|
||||||
|
|
||||||
|
Sets floating-point I<h>, I<s>, I<v>, I<a> components of the color.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorHSLAf
|
||||||
|
|
||||||
|
void BH_ColorHSLAf(const BH_Color *color,
|
||||||
|
float *h,
|
||||||
|
float *s,
|
||||||
|
float *l,
|
||||||
|
float *a);
|
||||||
|
|
||||||
|
Gets floating-point HSL representation of the I<color>.
|
||||||
|
|
||||||
|
Parameters I<h>, I<s>, I<l>, I<a> represent color components in HSV color space.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorSetHSLAf
|
||||||
|
|
||||||
|
void BH_ColorSetHSLAf(BH_Color *color,
|
||||||
|
float h,
|
||||||
|
float s,
|
||||||
|
float l,
|
||||||
|
float a);
|
||||||
|
|
||||||
|
Sets floating-point I<h>, I<s>, I<l>, I<a> components of the color.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorToRGBA
|
||||||
|
|
||||||
|
void BH_ColorToRGBA(const BH_Color *color,
|
||||||
|
BH_Color *out);
|
||||||
|
|
||||||
|
Converts I<color> to RGB color space.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorToHSVA
|
||||||
|
|
||||||
|
void BH_ColorToHSVA(const BH_Color *color,
|
||||||
|
BH_Color *out);
|
||||||
|
|
||||||
|
Converts I<color> to HSV color space.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorToHSLA
|
||||||
|
|
||||||
|
void BH_ColorToHSLA(const BH_Color *color,
|
||||||
|
BH_Color *out);
|
||||||
|
|
||||||
|
Converts I<color> to HSL color space.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorBlend
|
||||||
|
|
||||||
|
void BH_ColorBlend(const BH_Color *foreground,
|
||||||
|
const BH_Color *background,
|
||||||
|
int mode,
|
||||||
|
BH_Color *dest);
|
||||||
|
|
||||||
|
Blends I<foreground> and I<background> color, using specified blending I<mode>.
|
||||||
|
|
||||||
|
The following modes can be used:
|
||||||
|
|
||||||
|
=over
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_NORMAL>
|
||||||
|
|
||||||
|
r = f
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_MULTIPLY>
|
||||||
|
|
||||||
|
r = f * b
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_SCREEN>
|
||||||
|
|
||||||
|
r = 1 - (1 - f) * (1 - b)
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_OVERLAY>
|
||||||
|
|
||||||
|
r = HardLight(b, f)
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_DARKEN>
|
||||||
|
|
||||||
|
r = min(f, b)
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_LIGHTEN>
|
||||||
|
|
||||||
|
r = max(f, b)
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_COLOR_DODGE>
|
||||||
|
|
||||||
|
r = min(1, b / (1 - f))
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_COLOR_BURN>
|
||||||
|
|
||||||
|
r = 1 - min(1, (1 - b) / f)
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_LINEAR_DODGE>
|
||||||
|
|
||||||
|
r = f + b
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_LINEAR_BURN>
|
||||||
|
|
||||||
|
r = f + b - 1
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_HARD_LIGHT>
|
||||||
|
|
||||||
|
if (f < 0.5)
|
||||||
|
r = Multipy(2 * f, b)
|
||||||
|
else
|
||||||
|
r = Screen(2 * f - 1, b)
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_SOFT_LIGHT>
|
||||||
|
|
||||||
|
r = (1 - 2 * f) * b^2 + 2 * f * b
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_DIFFERENCE>
|
||||||
|
|
||||||
|
r = abs(f - b)
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_EXCLUSION>
|
||||||
|
|
||||||
|
r = f + b - (2 * f * b)
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_HUE>
|
||||||
|
|
||||||
|
r = HSL(H(f), S(b), L(b))
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_SATURATION>
|
||||||
|
|
||||||
|
r = HSL(H(b), S(f), L(b))
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_COLOR>
|
||||||
|
|
||||||
|
r = HSL(H(f), S(f), L(b))
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_LUMINOSITY>
|
||||||
|
|
||||||
|
r = HSL(H(b), S(b), L(f))
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
|
||||||
|
=head1 STRUCTURES
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_Color
|
||||||
|
|
||||||
|
typedef struct BH_Color
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint16_t r;
|
||||||
|
uint16_t g;
|
||||||
|
uint16_t b;
|
||||||
|
uint16_t a;
|
||||||
|
} rgba;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint16_t h;
|
||||||
|
uint16_t s;
|
||||||
|
uint16_t v;
|
||||||
|
uint16_t a;
|
||||||
|
} hsva;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint16_t h;
|
||||||
|
uint16_t s;
|
||||||
|
uint16_t l;
|
||||||
|
uint16_t a;
|
||||||
|
} hsla;
|
||||||
|
} data;
|
||||||
|
} BH_Color;
|
||||||
|
|
||||||
|
=head1 SEE ALSO
|
||||||
|
|
||||||
|
L<BH>
|
||||||
@@ -5,6 +5,7 @@ HTMLS = BH_Algo.html \
|
|||||||
BH_Args.html \
|
BH_Args.html \
|
||||||
BH_Box2f.html \
|
BH_Box2f.html \
|
||||||
BH_Box3f.html \
|
BH_Box3f.html \
|
||||||
|
BH_Color.html \
|
||||||
BH_Hashmap.html \
|
BH_Hashmap.html \
|
||||||
BH_IO.html \
|
BH_IO.html \
|
||||||
BH_Line.html \
|
BH_Line.html \
|
||||||
@@ -31,6 +32,7 @@ MANS = BH_Algo.3 \
|
|||||||
BH_Args.3 \
|
BH_Args.3 \
|
||||||
BH_Box2f.3 \
|
BH_Box2f.3 \
|
||||||
BH_Box3f.3 \
|
BH_Box3f.3 \
|
||||||
|
BH_Color.3 \
|
||||||
BH_Hashmap.3 \
|
BH_Hashmap.3 \
|
||||||
BH_IO.3 \
|
BH_IO.3 \
|
||||||
BH_Line.3 \
|
BH_Line.3 \
|
||||||
|
|||||||
319
doc/Manual/ru/BH_Color.pod
Normal file
319
doc/Manual/ru/BH_Color.pod
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
=encoding UTF-8
|
||||||
|
|
||||||
|
|
||||||
|
=head1 НАИМЕНОВАНИЕ
|
||||||
|
|
||||||
|
BH_Color - утилиты для работы с цветом
|
||||||
|
|
||||||
|
|
||||||
|
=head1 СИНТАКСИС
|
||||||
|
|
||||||
|
#include <BH/Math/Box3f.h>
|
||||||
|
|
||||||
|
cc prog.c -o prog -lbh
|
||||||
|
|
||||||
|
|
||||||
|
=head1 ОПИСАНИЕ
|
||||||
|
|
||||||
|
Модуль BH_Color предоставляет механизм для представления цвета и трансляции
|
||||||
|
между различными цветовыми пространствами (RGB, HSL и HSV). Кроме того, этот
|
||||||
|
модуль предоставляет механизм для смешивания двух цветов.
|
||||||
|
|
||||||
|
|
||||||
|
=head1 ЗАМЕТКИ
|
||||||
|
|
||||||
|
Внутренне, цвет хранится в четырех 16-разрядных целых числах.
|
||||||
|
|
||||||
|
При преобразовании между RGB и HSV/HSL возникает ошибка ~0,009%. Это не является
|
||||||
|
проблемой, если вы используете 8-битные RGB значения. Это может стать проблемой
|
||||||
|
если вы используете 16-битные значения RGB (не каждое значение RGB сможет быть
|
||||||
|
представлено в уникальном значении HSV/HSL). Если вам нужна такая точность, то
|
||||||
|
этот модуль не для вас.
|
||||||
|
|
||||||
|
Почти все режимы смешивания цветов работают так же, как и в других программных
|
||||||
|
пакетах. Исключением является I<BH_COLOR_MODE_SOFT_LIGHT>. Эта библиотека
|
||||||
|
использует Pegtop весию формулы (которая может привести к другому результату).
|
||||||
|
Это может быть проблемой, если вы пытаетесь реализовать стандартный рендеринг
|
||||||
|
для форматов SVG или PDF.
|
||||||
|
|
||||||
|
I<BH_COLOR_MODE_HUE>, I<BH_COLOR_MODE_SATURATION>, I<BH_COLOR_MODE_COLOR>
|
||||||
|
и I<BH_COLOR_MODE_LUMINOSITY> реализованы в цветовом пространстве HSL.
|
||||||
|
|
||||||
|
|
||||||
|
=head1 API ВЫЗОВЫ
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorRGBA8
|
||||||
|
|
||||||
|
void BH_ColorRGBA8(const BH_Color *color,
|
||||||
|
uint8_t *r,
|
||||||
|
uint8_t *g,
|
||||||
|
uint8_t *b,
|
||||||
|
uint8_t *a);
|
||||||
|
|
||||||
|
Возвращает 8-битное RGB представление цвета I<color>.
|
||||||
|
|
||||||
|
Параметры I<r>, I<g>, I<b>, I<a> представляю компоненты цвета в RGB.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorRGBA16
|
||||||
|
|
||||||
|
void BH_ColorRGBA16(const BH_Color *color,
|
||||||
|
uint16_t *r,
|
||||||
|
uint16_t *g,
|
||||||
|
uint16_t *b,
|
||||||
|
uint16_t *a);
|
||||||
|
|
||||||
|
Возвращает 16-битное RGB представление цвета I<color>.
|
||||||
|
|
||||||
|
Параметры I<r>, I<g>, I<b>, I<a> представляют компоненты цвета в RGB.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorRGBAf
|
||||||
|
|
||||||
|
void BH_ColorRGBAf(const BH_Color *color,
|
||||||
|
float *r,
|
||||||
|
float *g,
|
||||||
|
float *b,
|
||||||
|
float *a);
|
||||||
|
|
||||||
|
Возвращает вещественное RGB представление цвета I<color>.
|
||||||
|
|
||||||
|
Параметры I<r>, I<g>, I<b>, I<a> представляют компоненты цвета в RGB.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorSetRGBA8
|
||||||
|
|
||||||
|
void BH_ColorSetRGBA8(BH_Color *color,
|
||||||
|
uint8_t r,
|
||||||
|
uint8_t g,
|
||||||
|
uint8_t b,
|
||||||
|
uint8_t a);
|
||||||
|
|
||||||
|
Устанавливает 8-битные компонеты I<r>, I<g>, I<b>, I<a> цвета.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorSetRGBA16
|
||||||
|
|
||||||
|
void BH_ColorSetRGBA16(BH_Color *color,
|
||||||
|
uint16_t r,
|
||||||
|
uint16_t g,
|
||||||
|
uint16_t b,
|
||||||
|
uint16_t a);
|
||||||
|
|
||||||
|
Устанавливает 16-битные компонеты I<r>, I<g>, I<b>, I<a> цвета.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorSetRGBAf
|
||||||
|
|
||||||
|
void BH_ColorSetRGBAf(BH_Color *color,
|
||||||
|
float r,
|
||||||
|
float g,
|
||||||
|
float b,
|
||||||
|
float a);
|
||||||
|
|
||||||
|
Устанавливает вещественные компонеты I<r>, I<g>, I<b>, I<a> цвета.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorHSVAf
|
||||||
|
|
||||||
|
void BH_ColorHSVAf(const BH_Color *color,
|
||||||
|
float *h,
|
||||||
|
float *s,
|
||||||
|
float *v,
|
||||||
|
float *a);
|
||||||
|
|
||||||
|
Возвращает вещественное HSV представление цвета I<color>.
|
||||||
|
|
||||||
|
Параметры I<h>, I<s>, I<v>, I<a> представляют компоненты цвета в RGB.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorSetHSVAf
|
||||||
|
|
||||||
|
void BH_ColorSetHSVAf(BH_Color *color,
|
||||||
|
float h,
|
||||||
|
float s,
|
||||||
|
float v,
|
||||||
|
float a);
|
||||||
|
|
||||||
|
Устанавливает вещественные компонеты I<h>, I<s>, I<v>, I<a> цвета.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorHSLAf
|
||||||
|
|
||||||
|
void BH_ColorHSLAf(const BH_Color *color,
|
||||||
|
float *h,
|
||||||
|
float *s,
|
||||||
|
float *l,
|
||||||
|
float *a);
|
||||||
|
|
||||||
|
Возвращает вещественное HSL представление цвета I<color>.
|
||||||
|
|
||||||
|
Параметры I<h>, I<s>, I<l>, I<a> представляют компоненты цвета в RGB.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorSetHSLAf
|
||||||
|
|
||||||
|
void BH_ColorSetHSLAf(BH_Color *color,
|
||||||
|
float h,
|
||||||
|
float s,
|
||||||
|
float l,
|
||||||
|
float a);
|
||||||
|
|
||||||
|
Устанавливает вещественные компонеты I<h>, I<s>, I<l>, I<a> цвета.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorToRGBA
|
||||||
|
|
||||||
|
void BH_ColorToRGBA(const BH_Color *color,
|
||||||
|
BH_Color *out);
|
||||||
|
|
||||||
|
Преобразует цвет I<color> в цветовое представление RGB.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorToHSVA
|
||||||
|
|
||||||
|
void BH_ColorToHSVA(const BH_Color *color,
|
||||||
|
BH_Color *out);
|
||||||
|
|
||||||
|
Преобразует цвет I<color> в цветовое представление HSV.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorToHSLA
|
||||||
|
|
||||||
|
void BH_ColorToHSLA(const BH_Color *color,
|
||||||
|
BH_Color *out);
|
||||||
|
|
||||||
|
Преобразует цвет I<color> в цветовое представление HSL.
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_ColorBlend
|
||||||
|
|
||||||
|
void BH_ColorBlend(const BH_Color *foreground,
|
||||||
|
const BH_Color *background,
|
||||||
|
int mode,
|
||||||
|
BH_Color *dest);
|
||||||
|
|
||||||
|
Смешивает цвета I<foreground> и I<background>, используя указанный режим
|
||||||
|
смешивания I<mode>.
|
||||||
|
|
||||||
|
Могут использоваться следующие режимы:
|
||||||
|
|
||||||
|
=over
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_NORMAL>
|
||||||
|
|
||||||
|
r = f
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_MULTIPLY>
|
||||||
|
|
||||||
|
r = f * b
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_SCREEN>
|
||||||
|
|
||||||
|
r = 1 - (1 - f) * (1 - b)
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_OVERLAY>
|
||||||
|
|
||||||
|
r = HardLight(b, f)
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_DARKEN>
|
||||||
|
|
||||||
|
r = min(f, b)
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_LIGHTEN>
|
||||||
|
|
||||||
|
r = max(f, b)
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_COLOR_DODGE>
|
||||||
|
|
||||||
|
r = min(1, b / (1 - f))
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_COLOR_BURN>
|
||||||
|
|
||||||
|
r = 1 - min(1, (1 - b) / f)
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_LINEAR_DODGE>
|
||||||
|
|
||||||
|
r = f + b
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_LINEAR_BURN>
|
||||||
|
|
||||||
|
r = f + b - 1
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_HARD_LIGHT>
|
||||||
|
|
||||||
|
if (f < 0.5)
|
||||||
|
r = Multipy(2 * f, b)
|
||||||
|
else
|
||||||
|
r = Screen(2 * f - 1, b)
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_SOFT_LIGHT>
|
||||||
|
|
||||||
|
r = (1 - 2 * f) * b^2 + 2 * f * b
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_DIFFERENCE>
|
||||||
|
|
||||||
|
r = abs(f - b)
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_EXCLUSION>
|
||||||
|
|
||||||
|
r = f + b - (2 * f * b)
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_HUE>
|
||||||
|
|
||||||
|
r = HSL(H(f), S(b), L(b))
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_SATURATION>
|
||||||
|
|
||||||
|
r = HSL(H(b), S(f), L(b))
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_COLOR>
|
||||||
|
|
||||||
|
r = HSL(H(f), S(f), L(b))
|
||||||
|
|
||||||
|
=item B<BH_COLOR_MODE_LUMINOSITY>
|
||||||
|
|
||||||
|
r = HSL(H(b), S(b), L(f))
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
|
||||||
|
=head1 СТРУКТУРЫ
|
||||||
|
|
||||||
|
|
||||||
|
=head2 BH_Color
|
||||||
|
|
||||||
|
typedef struct BH_Color
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint16_t r;
|
||||||
|
uint16_t g;
|
||||||
|
uint16_t b;
|
||||||
|
uint16_t a;
|
||||||
|
} rgba;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint16_t h;
|
||||||
|
uint16_t s;
|
||||||
|
uint16_t v;
|
||||||
|
uint16_t a;
|
||||||
|
} hsva;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint16_t h;
|
||||||
|
uint16_t s;
|
||||||
|
uint16_t l;
|
||||||
|
uint16_t a;
|
||||||
|
} hsla;
|
||||||
|
} data;
|
||||||
|
} BH_Color;
|
||||||
|
|
||||||
|
=head1 СМ. ТАКЖЕ
|
||||||
|
|
||||||
|
L<BH>
|
||||||
@@ -5,6 +5,7 @@ HTMLS = BH_Algo.html \
|
|||||||
BH_Args.html \
|
BH_Args.html \
|
||||||
BH_Box2f.html \
|
BH_Box2f.html \
|
||||||
BH_Box3f.html \
|
BH_Box3f.html \
|
||||||
|
BH_Color.html \
|
||||||
BH_Hashmap.html \
|
BH_Hashmap.html \
|
||||||
BH_IO.html \
|
BH_IO.html \
|
||||||
BH_Line.html \
|
BH_Line.html \
|
||||||
@@ -31,6 +32,7 @@ MANS = BH_Algo.3 \
|
|||||||
BH_Args.3 \
|
BH_Args.3 \
|
||||||
BH_Box2f.3 \
|
BH_Box2f.3 \
|
||||||
BH_Box3f.3 \
|
BH_Box3f.3 \
|
||||||
|
BH_Color.3 \
|
||||||
BH_Hashmap.3 \
|
BH_Hashmap.3 \
|
||||||
BH_IO.3 \
|
BH_IO.3 \
|
||||||
BH_Line.3 \
|
BH_Line.3 \
|
||||||
|
|||||||
151
include/BH/Color.h
Normal file
151
include/BH/Color.h
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
#ifndef BH_COLOR_H
|
||||||
|
#define BH_COLOR_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define BH_COLOR_TYPE_RGBA 0x0000
|
||||||
|
#define BH_COLOR_TYPE_HSVA 0x0001
|
||||||
|
#define BH_COLOR_TYPE_HSLA 0x0002
|
||||||
|
|
||||||
|
|
||||||
|
#define BH_COLOR_MODE_NORMAL 0x0000
|
||||||
|
#define BH_COLOR_MODE_MULTIPLY 0x0001
|
||||||
|
#define BH_COLOR_MODE_SCREEN 0x0002
|
||||||
|
#define BH_COLOR_MODE_OVERLAY 0x0003
|
||||||
|
#define BH_COLOR_MODE_DARKEN 0x0004
|
||||||
|
#define BH_COLOR_MODE_LIGHTEN 0x0005
|
||||||
|
#define BH_COLOR_MODE_COLOR_DODGE 0x0006
|
||||||
|
#define BH_COLOR_MODE_COLOR_BURN 0x0007
|
||||||
|
#define BH_COLOR_MODE_LINEAR_DODGE 0x0008
|
||||||
|
#define BH_COLOR_MODE_LINEAR_BURN 0x0009
|
||||||
|
#define BH_COLOR_MODE_HARD_LIGHT 0x000A
|
||||||
|
#define BH_COLOR_MODE_SOFT_LIGHT 0x000B
|
||||||
|
#define BH_COLOR_MODE_DIFFERENCE 0x000C
|
||||||
|
#define BH_COLOR_MODE_EXCLUSION 0x000D
|
||||||
|
#define BH_COLOR_MODE_HUE 0x000E
|
||||||
|
#define BH_COLOR_MODE_SATURATION 0x000F
|
||||||
|
#define BH_COLOR_MODE_COLOR 0x0010
|
||||||
|
#define BH_COLOR_MODE_LUMINOSITY 0x0011
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct BH_Color
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint16_t r;
|
||||||
|
uint16_t g;
|
||||||
|
uint16_t b;
|
||||||
|
uint16_t a;
|
||||||
|
} rgba;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint16_t h;
|
||||||
|
uint16_t s;
|
||||||
|
uint16_t v;
|
||||||
|
uint16_t a;
|
||||||
|
} hsva;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint16_t h;
|
||||||
|
uint16_t s;
|
||||||
|
uint16_t l;
|
||||||
|
uint16_t a;
|
||||||
|
} hsla;
|
||||||
|
} data;
|
||||||
|
} BH_Color;
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorRGBA8(const BH_Color *color,
|
||||||
|
uint8_t *r,
|
||||||
|
uint8_t *g,
|
||||||
|
uint8_t *b,
|
||||||
|
uint8_t *a);
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorRGBA16(const BH_Color *color,
|
||||||
|
uint16_t *r,
|
||||||
|
uint16_t *g,
|
||||||
|
uint16_t *b,
|
||||||
|
uint16_t *a);
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorRGBAf(const BH_Color *color,
|
||||||
|
float *r,
|
||||||
|
float *g,
|
||||||
|
float *b,
|
||||||
|
float *a);
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorSetRGBA8(BH_Color *color,
|
||||||
|
uint8_t r,
|
||||||
|
uint8_t g,
|
||||||
|
uint8_t b,
|
||||||
|
uint8_t a);
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorSetRGBA16(BH_Color *color,
|
||||||
|
uint16_t r,
|
||||||
|
uint16_t g,
|
||||||
|
uint16_t b,
|
||||||
|
uint16_t a);
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorSetRGBAf(BH_Color *color,
|
||||||
|
float r,
|
||||||
|
float g,
|
||||||
|
float b,
|
||||||
|
float a);
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorHSVAf(const BH_Color *color,
|
||||||
|
float *h,
|
||||||
|
float *s,
|
||||||
|
float *v,
|
||||||
|
float *a);
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorSetHSVAf(BH_Color *color,
|
||||||
|
float h,
|
||||||
|
float s,
|
||||||
|
float v,
|
||||||
|
float a);
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorHSLAf(const BH_Color *color,
|
||||||
|
float *h,
|
||||||
|
float *s,
|
||||||
|
float *l,
|
||||||
|
float *a);
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorSetHSLAf(BH_Color *color,
|
||||||
|
float h,
|
||||||
|
float s,
|
||||||
|
float l,
|
||||||
|
float a);
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorToRGBA(const BH_Color *color,
|
||||||
|
BH_Color *out);
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorToHSVA(const BH_Color *color,
|
||||||
|
BH_Color *out);
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorToHSLA(const BH_Color *color,
|
||||||
|
BH_Color *out);
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorBlend(const BH_Color *foreground,
|
||||||
|
const BH_Color *background,
|
||||||
|
int mode,
|
||||||
|
BH_Color *dest);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* BH_COLOR_H */
|
||||||
618
src/Color.c
Normal file
618
src/Color.c
Normal file
@@ -0,0 +1,618 @@
|
|||||||
|
#include "BH/Common.h"
|
||||||
|
#include <BH/Color.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||||
|
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||||
|
|
||||||
|
|
||||||
|
/* Conversion between RGB <-> HSL/HSV has error of around ~ 0.009% */
|
||||||
|
#define DEGREE_MULT 1.8204444e02f
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorRGBA8(const BH_Color *color,
|
||||||
|
uint8_t *r,
|
||||||
|
uint8_t *g,
|
||||||
|
uint8_t *b,
|
||||||
|
uint8_t *a)
|
||||||
|
{
|
||||||
|
BH_Color tmp;
|
||||||
|
|
||||||
|
BH_ColorToRGBA(color, &tmp);
|
||||||
|
*r = tmp.data.rgba.r >> 8;
|
||||||
|
*g = tmp.data.rgba.g >> 8;
|
||||||
|
*b = tmp.data.rgba.b >> 8;
|
||||||
|
*a = tmp.data.rgba.a >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BH_ColorRGBA16(const BH_Color *color,
|
||||||
|
uint16_t *r,
|
||||||
|
uint16_t *g,
|
||||||
|
uint16_t *b,
|
||||||
|
uint16_t *a)
|
||||||
|
{
|
||||||
|
BH_Color tmp;
|
||||||
|
|
||||||
|
BH_ColorToRGBA(color, &tmp);
|
||||||
|
*r = tmp.data.rgba.r;
|
||||||
|
*g = tmp.data.rgba.g;
|
||||||
|
*b = tmp.data.rgba.b;
|
||||||
|
*a = tmp.data.rgba.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorRGBAf(const BH_Color *color,
|
||||||
|
float *r,
|
||||||
|
float *g,
|
||||||
|
float *b,
|
||||||
|
float *a)
|
||||||
|
{
|
||||||
|
BH_Color tmp;
|
||||||
|
|
||||||
|
BH_ColorToRGBA(color, &tmp);
|
||||||
|
*r = tmp.data.rgba.r / 65535.0f;
|
||||||
|
*g = tmp.data.rgba.g / 65535.0f;
|
||||||
|
*b = tmp.data.rgba.b / 65535.0f;
|
||||||
|
*a = tmp.data.rgba.a / 65535.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorSetRGBA8(BH_Color *color,
|
||||||
|
uint8_t r,
|
||||||
|
uint8_t g,
|
||||||
|
uint8_t b,
|
||||||
|
uint8_t a)
|
||||||
|
{
|
||||||
|
color->type = BH_COLOR_TYPE_RGBA;
|
||||||
|
color->data.rgba.r = (uint16_t)r * 0x0101;
|
||||||
|
color->data.rgba.g = (uint16_t)g * 0x0101;
|
||||||
|
color->data.rgba.b = (uint16_t)b * 0x0101;
|
||||||
|
color->data.rgba.a = (uint16_t)a * 0x0101;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorSetRGBA16(BH_Color *color,
|
||||||
|
uint16_t r,
|
||||||
|
uint16_t g,
|
||||||
|
uint16_t b,
|
||||||
|
uint16_t a)
|
||||||
|
{
|
||||||
|
color->type = BH_COLOR_TYPE_RGBA;
|
||||||
|
color->data.rgba.r = r;
|
||||||
|
color->data.rgba.g = g;
|
||||||
|
color->data.rgba.b = b;
|
||||||
|
color->data.rgba.a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorSetRGBAf(BH_Color *color,
|
||||||
|
float r,
|
||||||
|
float g,
|
||||||
|
float b,
|
||||||
|
float a)
|
||||||
|
{
|
||||||
|
r = MAX(MIN(1.0f, r), 0.0f);
|
||||||
|
g = MAX(MIN(1.0f, g), 0.0f);
|
||||||
|
b = MAX(MIN(1.0f, b), 0.0f);
|
||||||
|
a = MAX(MIN(1.0f, a), 0.0f);
|
||||||
|
|
||||||
|
color->type = BH_COLOR_TYPE_RGBA;
|
||||||
|
color->data.rgba.r = r * 65535.0f;
|
||||||
|
color->data.rgba.g = g * 65535.0f;
|
||||||
|
color->data.rgba.b = b * 65535.0f;
|
||||||
|
color->data.rgba.a = a * 65535.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorHSVAf(const BH_Color *color,
|
||||||
|
float *h,
|
||||||
|
float *s,
|
||||||
|
float *v,
|
||||||
|
float *a)
|
||||||
|
{
|
||||||
|
BH_Color tmp;
|
||||||
|
|
||||||
|
BH_ColorToHSVA(color, &tmp);
|
||||||
|
*h = tmp.data.hsva.h / DEGREE_MULT;
|
||||||
|
*s = tmp.data.hsva.s / 65535.0f;
|
||||||
|
*v = tmp.data.hsva.v / 65535.0f;
|
||||||
|
*a = tmp.data.hsva.a / 65535.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorSetHSVAf(BH_Color *color,
|
||||||
|
float h,
|
||||||
|
float s,
|
||||||
|
float v,
|
||||||
|
float a)
|
||||||
|
{
|
||||||
|
while (h >= 360.0f)
|
||||||
|
h -= 360.0f;
|
||||||
|
while (h < 0.0f)
|
||||||
|
h += 360.0f;
|
||||||
|
|
||||||
|
s = MAX(MIN(1.0f, s), 0.0f);
|
||||||
|
v = MAX(MIN(1.0f, v), 0.0f);
|
||||||
|
|
||||||
|
color->type = BH_COLOR_TYPE_HSVA;
|
||||||
|
color->data.hsva.h = h * DEGREE_MULT;
|
||||||
|
color->data.hsva.s = s * 65535.0f;
|
||||||
|
color->data.hsva.v = v * 65535.0f;
|
||||||
|
color->data.hsva.a = a * 65535.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorHSLAf(const BH_Color *color,
|
||||||
|
float *h,
|
||||||
|
float *s,
|
||||||
|
float *l,
|
||||||
|
float *a)
|
||||||
|
{
|
||||||
|
BH_Color tmp;
|
||||||
|
|
||||||
|
BH_ColorToHSLA(color, &tmp);
|
||||||
|
*h = tmp.data.hsla.h / DEGREE_MULT;
|
||||||
|
*s = tmp.data.hsla.s / 65535.0f;
|
||||||
|
*l = tmp.data.hsla.l / 65535.0f;
|
||||||
|
*a = tmp.data.hsla.a / 65535.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorSetHSLAf(BH_Color *color,
|
||||||
|
float h,
|
||||||
|
float s,
|
||||||
|
float l,
|
||||||
|
float a)
|
||||||
|
{
|
||||||
|
while (h >= 360.0f)
|
||||||
|
h -= 360.0f;
|
||||||
|
while (h < 0.0f)
|
||||||
|
h += 360.0f;
|
||||||
|
|
||||||
|
s = MAX(MIN(1.0f, s), 0.0f);
|
||||||
|
l = MAX(MIN(1.0f, l), 0.0f);
|
||||||
|
|
||||||
|
color->type = BH_COLOR_TYPE_HSLA;
|
||||||
|
color->data.hsla.h = h * DEGREE_MULT;
|
||||||
|
color->data.hsla.s = s * 65535;
|
||||||
|
color->data.hsla.l = l * 65535;
|
||||||
|
color->data.hsla.a = a * 65535;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Transformations between color models are based on:
|
||||||
|
* Computer Graphics and Geometric Modeling by Max K. Agoston
|
||||||
|
*/
|
||||||
|
static void rgbToHsv(const BH_Color *color,
|
||||||
|
BH_Color *out)
|
||||||
|
{
|
||||||
|
float min, max, d, r, g, b, a, h, s, v;
|
||||||
|
|
||||||
|
BH_ColorRGBAf(color, &r, &g, &b, &a);
|
||||||
|
max = MAX(MAX(r, g), b);
|
||||||
|
min = MIN(MIN(r, g), b);
|
||||||
|
|
||||||
|
v = max;
|
||||||
|
s = 0.0f;
|
||||||
|
h = 0.0f;
|
||||||
|
d = max - min;
|
||||||
|
|
||||||
|
if (max)
|
||||||
|
s = d / max;
|
||||||
|
|
||||||
|
if (s)
|
||||||
|
{
|
||||||
|
if (r == max)
|
||||||
|
h = (g - b) / d;
|
||||||
|
else if (g == max)
|
||||||
|
h = 2 + (b - r) / d;
|
||||||
|
else
|
||||||
|
h = 4 + (r - g) / d;
|
||||||
|
}
|
||||||
|
|
||||||
|
BH_ColorSetHSVAf(out, h * 60.0f, s, v, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hsvToRgb(const BH_Color *color,
|
||||||
|
BH_Color *out)
|
||||||
|
{
|
||||||
|
float h, s, v, a, r, g, b, fract, p, q, t;
|
||||||
|
int sextant;
|
||||||
|
BH_ColorHSVAf(color, &h, &s, &v, &a);
|
||||||
|
|
||||||
|
r = v;
|
||||||
|
g = v;
|
||||||
|
b = v;
|
||||||
|
|
||||||
|
if (s)
|
||||||
|
{
|
||||||
|
h /= 60.0f;
|
||||||
|
sextant = (int)h;
|
||||||
|
fract = h - sextant;
|
||||||
|
|
||||||
|
p = v * (1 - s);
|
||||||
|
q = v * (1 - (s * fract));
|
||||||
|
t = v * (1 - (s * (1 - fract)));
|
||||||
|
|
||||||
|
switch (sextant)
|
||||||
|
{
|
||||||
|
case 0: r = v; g = t; b = p; break;
|
||||||
|
case 1: r = q; g = v; b = p; break;
|
||||||
|
case 2: r = p; g = v; b = t; break;
|
||||||
|
case 3: r = p; g = q; b = v; break;
|
||||||
|
case 4: r = t; g = p; b = v; break;
|
||||||
|
case 5: r = v; g = p; b = q; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BH_ColorSetRGBAf(out, r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void rgbToHsl(const BH_Color *color,
|
||||||
|
BH_Color *out)
|
||||||
|
{
|
||||||
|
float min, max, d, r, g, b, a, h, s, l;
|
||||||
|
|
||||||
|
BH_ColorRGBAf(color, &r, &g, &b, &a);
|
||||||
|
max = MAX(MAX(r, g), b);
|
||||||
|
min = MIN(MIN(r, g), b);
|
||||||
|
|
||||||
|
l = (max + min) / 2.0;
|
||||||
|
s = 0.0f;
|
||||||
|
h = 0.0f;
|
||||||
|
d = max - min;
|
||||||
|
|
||||||
|
if (max != min)
|
||||||
|
{
|
||||||
|
if (l <= 0.5f)
|
||||||
|
s = d / (max + min);
|
||||||
|
else
|
||||||
|
s = d / (2.0f - max - min);
|
||||||
|
|
||||||
|
if (r == max)
|
||||||
|
h = (g - b) / d;
|
||||||
|
else if (g == max)
|
||||||
|
h = 2 + (b - r) / d;
|
||||||
|
else
|
||||||
|
h = 4 + (r - g) / d;
|
||||||
|
}
|
||||||
|
|
||||||
|
BH_ColorSetHSLAf(out, h * 60.0f, s, l, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hslToHsv(const BH_Color *color,
|
||||||
|
BH_Color *out)
|
||||||
|
{
|
||||||
|
float h, s, l, v, a;
|
||||||
|
|
||||||
|
BH_ColorHSLAf(color, &h, &s, &l, &a);
|
||||||
|
v = s * MIN(l, 1.0f - l) + l;
|
||||||
|
s = (v) ? (2.0f - 2.0f * l / v) : (0.0f);
|
||||||
|
|
||||||
|
BH_ColorSetHSVAf(out, h, s, v, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hsvToHsl(const BH_Color *color,
|
||||||
|
BH_Color *out)
|
||||||
|
{
|
||||||
|
float h, s, v, l, a, m;
|
||||||
|
|
||||||
|
BH_ColorHSVAf(color, &h, &s, &v, &a);
|
||||||
|
l = v - v * s / 2.0f;
|
||||||
|
m = MIN(l, 1.0f - l);
|
||||||
|
s = (m) ? ((v - l) / m) : (0);
|
||||||
|
BH_ColorSetHSLAf(out, h, s, l, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorToRGBA(const BH_Color *color,
|
||||||
|
BH_Color *out)
|
||||||
|
{
|
||||||
|
switch (color->type)
|
||||||
|
{
|
||||||
|
case BH_COLOR_TYPE_RGBA:
|
||||||
|
*out = *color;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_TYPE_HSVA:
|
||||||
|
hsvToRgb(color, out);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_TYPE_HSLA:
|
||||||
|
hslToHsv(color, out);
|
||||||
|
hsvToRgb(out, out);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorToHSVA(const BH_Color *color,
|
||||||
|
BH_Color *out)
|
||||||
|
{
|
||||||
|
switch (color->type)
|
||||||
|
{
|
||||||
|
case BH_COLOR_TYPE_RGBA:
|
||||||
|
rgbToHsv(color, out);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_TYPE_HSVA:
|
||||||
|
*out = *color;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_TYPE_HSLA:
|
||||||
|
hslToHsv(color, out);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorToHSLA(const BH_Color *color,
|
||||||
|
BH_Color *out)
|
||||||
|
{
|
||||||
|
switch (color->type)
|
||||||
|
{
|
||||||
|
case BH_COLOR_TYPE_RGBA:
|
||||||
|
rgbToHsl(color, out);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_TYPE_HSVA:
|
||||||
|
hsvToHsl(color, out);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_TYPE_HSLA:
|
||||||
|
*out = *color;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float blendNormal(float foreground,
|
||||||
|
float background)
|
||||||
|
{
|
||||||
|
BH_UNUSED(background);
|
||||||
|
return foreground;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float blendMultiply(float foreground,
|
||||||
|
float background)
|
||||||
|
{
|
||||||
|
return foreground * background;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float blendScreen(float foreground,
|
||||||
|
float background)
|
||||||
|
{
|
||||||
|
return foreground + background - (foreground * background);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float blendDarken(float foreground,
|
||||||
|
float background)
|
||||||
|
{
|
||||||
|
return MIN(foreground, background);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float blendLighten(float foreground,
|
||||||
|
float background)
|
||||||
|
{
|
||||||
|
return MAX(foreground, background);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float blendColorDodge(float foreground,
|
||||||
|
float background)
|
||||||
|
{
|
||||||
|
if (foreground != 1.0f)
|
||||||
|
return MIN(1.0f, background / (1.0f - foreground));
|
||||||
|
return foreground;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float blendColorBurn(float foreground,
|
||||||
|
float background)
|
||||||
|
{
|
||||||
|
if (foreground != 0.0f)
|
||||||
|
return 1.0f - MIN(1.0f, (1.0f - background) / foreground);
|
||||||
|
return foreground;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float blendLinearDodge(float foreground,
|
||||||
|
float background)
|
||||||
|
{
|
||||||
|
return foreground + background;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float blendLinearBurn(float foreground,
|
||||||
|
float background)
|
||||||
|
{
|
||||||
|
return foreground + background - 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float blendDifference(float foreground,
|
||||||
|
float background)
|
||||||
|
{
|
||||||
|
return fabsf(background - foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float blendExclusion(float foreground,
|
||||||
|
float background)
|
||||||
|
{
|
||||||
|
return foreground + background - (2.0f * foreground * background);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float blendHardLight(float foreground,
|
||||||
|
float background)
|
||||||
|
{
|
||||||
|
if (foreground <= 0.5f)
|
||||||
|
return blendMultiply(2.0f * foreground, background);
|
||||||
|
else
|
||||||
|
return blendScreen(2.0f * foreground - 1.0f, background);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float blendSoftLight(float foreground,
|
||||||
|
float background)
|
||||||
|
{
|
||||||
|
return (1.0f - 2.0f * foreground) * background * background + 2.0f * foreground * background;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float blendOverlay(float foreground,
|
||||||
|
float background)
|
||||||
|
{
|
||||||
|
return blendHardLight(background, foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ColorBlend(const BH_Color *foreground,
|
||||||
|
const BH_Color *background,
|
||||||
|
int mode,
|
||||||
|
BH_Color *dest)
|
||||||
|
{
|
||||||
|
float br, bg, bb, ba;
|
||||||
|
float fr, fg, fb, fa;
|
||||||
|
|
||||||
|
if (mode == BH_COLOR_MODE_HUE || mode == BH_COLOR_MODE_SATURATION ||
|
||||||
|
mode == BH_COLOR_MODE_COLOR || mode == BH_COLOR_MODE_LUMINOSITY)
|
||||||
|
{
|
||||||
|
BH_ColorHSLAf(foreground, &fr, &fg, &fb, &fa);
|
||||||
|
BH_ColorHSLAf(background, &br, &bg, &bb, &ba);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BH_ColorRGBAf(foreground, &fr, &fg, &fb, &fa);
|
||||||
|
BH_ColorRGBAf(background, &br, &bg, &bb, &ba);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case BH_COLOR_MODE_NORMAL:
|
||||||
|
fr = blendNormal(fr, br);
|
||||||
|
fg = blendNormal(fg, bg);
|
||||||
|
fb = blendNormal(fb, bb);
|
||||||
|
BH_ColorSetRGBAf(dest, fr, fg, fb, fa);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_MODE_MULTIPLY:
|
||||||
|
fr = blendMultiply(fr, br);
|
||||||
|
fg = blendMultiply(fg, bg);
|
||||||
|
fb = blendMultiply(fb, bb);
|
||||||
|
BH_ColorSetRGBAf(dest, fr, fg, fb, fa);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_MODE_SCREEN:
|
||||||
|
fr = blendScreen(fr, br);
|
||||||
|
fg = blendScreen(fg, bg);
|
||||||
|
fb = blendScreen(fb, bb);
|
||||||
|
BH_ColorSetRGBAf(dest, fr, fg, fb, fa);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_MODE_OVERLAY:
|
||||||
|
fr = blendOverlay(fr, br);
|
||||||
|
fg = blendOverlay(fg, bg);
|
||||||
|
fb = blendOverlay(fb, bb);
|
||||||
|
BH_ColorSetRGBAf(dest, fr, fg, fb, fa);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_MODE_DARKEN:
|
||||||
|
fr = blendDarken(fr, br);
|
||||||
|
fg = blendDarken(fg, bg);
|
||||||
|
fb = blendDarken(fb, bb);
|
||||||
|
BH_ColorSetRGBAf(dest, fr, fg, fb, fa);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_MODE_LIGHTEN:
|
||||||
|
fr = blendLighten(fr, br);
|
||||||
|
fg = blendLighten(fg, bg);
|
||||||
|
fb = blendLighten(fb, bb);
|
||||||
|
BH_ColorSetRGBAf(dest, fr, fg, fb, fa);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_MODE_COLOR_DODGE:
|
||||||
|
fr = blendColorDodge(fr, br);
|
||||||
|
fg = blendColorDodge(fg, bg);
|
||||||
|
fb = blendColorDodge(fb, bb);
|
||||||
|
BH_ColorSetRGBAf(dest, fr, fg, fb, fa);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_MODE_COLOR_BURN:
|
||||||
|
fr = blendColorBurn(fr, br);
|
||||||
|
fg = blendColorBurn(fg, bg);
|
||||||
|
fb = blendColorBurn(fb, bb);
|
||||||
|
BH_ColorSetRGBAf(dest, fr, fg, fb, fa);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_MODE_LINEAR_DODGE:
|
||||||
|
fr = blendLinearDodge(fr, br);
|
||||||
|
fg = blendLinearDodge(fg, bg);
|
||||||
|
fb = blendLinearDodge(fb, bb);
|
||||||
|
BH_ColorSetRGBAf(dest, fr, fg, fb, fa);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_MODE_LINEAR_BURN:
|
||||||
|
fr = blendLinearBurn(fr, br);
|
||||||
|
fg = blendLinearBurn(fg, bg);
|
||||||
|
fb = blendLinearBurn(fb, bb);
|
||||||
|
BH_ColorSetRGBAf(dest, fr, fg, fb, fa);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_MODE_HARD_LIGHT:
|
||||||
|
fr = blendHardLight(fr, br);
|
||||||
|
fg = blendHardLight(fg, bg);
|
||||||
|
fb = blendHardLight(fb, bb);
|
||||||
|
BH_ColorSetRGBAf(dest, fr, fg, fb, fa);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_MODE_SOFT_LIGHT:
|
||||||
|
fr = blendSoftLight(fr, br);
|
||||||
|
fg = blendSoftLight(fg, bg);
|
||||||
|
fb = blendSoftLight(fb, bb);
|
||||||
|
BH_ColorSetRGBAf(dest, fr, fg, fb, fa);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_MODE_DIFFERENCE:
|
||||||
|
fr = blendDifference(fr, br);
|
||||||
|
fg = blendDifference(fg, bg);
|
||||||
|
fb = blendDifference(fb, bb);
|
||||||
|
BH_ColorSetRGBAf(dest, fr, fg, fb, fa);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_MODE_EXCLUSION:
|
||||||
|
fr = blendExclusion(fr, br);
|
||||||
|
fg = blendExclusion(fg, bg);
|
||||||
|
fb = blendExclusion(fb, bb);
|
||||||
|
BH_ColorSetRGBAf(dest, fr, fg, fb, fa);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_MODE_HUE:
|
||||||
|
BH_ColorSetHSLAf(dest, fr, bg, bb, fa);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_MODE_SATURATION:
|
||||||
|
BH_ColorSetHSLAf(dest, br, fg, bb, fa);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_MODE_COLOR:
|
||||||
|
BH_ColorSetHSLAf(dest, fr, fg, bb, fa);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BH_COLOR_MODE_LUMINOSITY:
|
||||||
|
BH_ColorSetHSLAf(dest, br, bg, fb, fa);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user