#include "stereokit.h"
#include <string.h>
#include <math.h>
#include "sk_math.h"
#include "sk_memory.h"
namespace sk {
struct _gradient_t {
gradient_key_t *keys;
int32_t count;
int32_t capacity;
};
color128 color_hsv(float hue, float saturation, float value, float transparency) {
const vec4 K = vec4{ 1.0f, 2.0f / 3.0f, 1.0f / 3.0f, 3.0f };
vec3 p = {
fabsf(((hue + K.x) - floorf(hue + K.x)) * 6.0f - K.w),
fabsf(((hue + K.y) - floorf(hue + K.y)) * 6.0f - K.w),
fabsf(((hue + K.z) - floorf(hue + K.z)) * 6.0f - K.w) };
return {
math_lerp(K.x, fmaxf(0,fminf(p.x - K.x, 1.0f)), saturation) * value,
math_lerp(K.x, fmaxf(0,fminf(p.y - K.x, 1.0f)), saturation) * value,
math_lerp(K.x, fmaxf(0,fminf(p.z - K.x, 1.0f)), saturation) * value,
transparency };
}
vec3 color_to_hsv(const color128 &col) {
const vec4 K = vec4{ 0.0f, -1.0f / 3.0f, 2.0f / 3.0f, -1.0f };
vec4 p = col.g < col.b ? vec4{ col.b, col.g, K.w, K.z } : vec4{ col.g, col.b, K.x, K.y };
vec4 q = col.r < p.x ? vec4{ p.x, p.y, p.w, col.r } : vec4{ col.r, p.y, p.z, p.x };
float d = q.x - fminf(q.w, q.y);
float e = 1.0e-10f;
return vec3{ fabsf(q.z + (q.w - q.y) / (6.0f * d + e)), d / (q.x + e), q.x };
}
color128 color_lab(float l, float a, float b, float transparency) {
l = l * 100;
a = a * 400 - 200;
b = b * 400 - 200;
float
y = (l + 16.f) / 116.f,
x = (a / 500.f) + y,
z = y - (b / 200.f);
color128 col = { 0,0,0,transparency };
x = 0.95047f * ((x * x * x > 0.008856f) ? x * x * x : (x - 16/116.f) / 7.787f);
y = 1.00000f * ((y * y * y > 0.008856f) ? y * y * y : (y - 16/116.f) / 7.787f);
z = 1.08883f * ((z * z * z > 0.008856f) ? z * z * z : (z - 16/116.f) / 7.787f);
col.r = x * 3.2406f + y * -1.5372f + z * -0.4986f;
col.g = x * -0.9689f + y * 1.8758f + z * 0.0415f;
col.b = x * 0.0557f + y * -0.2040f + z * 1.0570f;
col.r = (col.r > 0.0031308f) ? (1.055f * powf(col.r, 1/2.4f) - 0.055f) : 12.92f * col.r;
col.g = (col.g > 0.0031308f) ? (1.055f * powf(col.g, 1/2.4f) - 0.055f) : 12.92f * col.g;
col.b = (col.b > 0.0031308f) ? (1.055f * powf(col.b, 1/2.4f) - 0.055f) : 12.92f * col.b;
return {
fmaxf(0, fminf(1, col.r)),
fmaxf(0, fminf(1, col.g)),
fmaxf(0, fminf(1, col.b)), transparency };
}
vec3 color_to_lab(const color128 &color) {
vec3 lab;
color128 col = color;
col.r = (col.r > 0.04045f) ? powf((col.r + 0.055f) / 1.055f, 2.4f) : col.r / 12.92f;
col.g = (col.g > 0.04045f) ? powf((col.g + 0.055f) / 1.055f, 2.4f) : col.g / 12.92f;
col.b = (col.b > 0.04045f) ? powf((col.b + 0.055f) / 1.055f, 2.4f) : col.b / 12.92f;
lab.x = (col.r * 0.4124f + col.g * 0.3576f + col.b * 0.1805f) / 0.95047f;
lab.y = (col.r * 0.2126f + col.g * 0.7152f + col.b * 0.0722f) / 1.00000f;
lab.z = (col.r * 0.0193f + col.g * 0.1192f + col.b * 0.9505f) / 1.08883f;
lab.x = (lab.x > 0.008856f) ? powf(lab.x, 1/3.f) : (7.787f * lab.x) + 16/116.f;
lab.y = (lab.y > 0.008856f) ? powf(lab.y, 1/3.f) : (7.787f * lab.y) + 16/116.f;
lab.z = (lab.z > 0.008856f) ? powf(lab.z, 1/3.f) : (7.787f * lab.z) + 16/116.f;
return {
(1.16f * lab.y) - .16f,
1.25f * (lab.x - lab.y) + 0.5f,
0.5f * (lab.y - lab.z) + 0.5f};
}
color128 color_to_linear(color128 srgb_gamma_correct) {
return {
powf(srgb_gamma_correct.r, 2.2f),
powf(srgb_gamma_correct.g, 2.2f),
powf(srgb_gamma_correct.b, 2.2f),
srgb_gamma_correct.a };
}
color128 color_to_gamma(color128 srgb_linear) {
return {
powf(srgb_linear.r, 1/2.2f),
powf(srgb_linear.g, 1/2.2f),
powf(srgb_linear.b, 1/2.2f),
srgb_linear.a };
}
gradient_t gradient_create() {
gradient_t result = sk_malloc_t(_gradient_t, 1);
*result = {};
return result;
}
gradient_t gradient_create_keys(const gradient_key_t *keys, int32_t count) {
gradient_t result = gradient_create();
result->capacity = count;
result->keys = sk_malloc_t(gradient_key_t, count);
for (int32_t i = 0; i < count; i++) {
gradient_add(result, keys[i].color, keys[i].position);
}
return result;
}
void gradient_add(gradient_t gradient, color128 color, float position) {
if (gradient->count + 1 >= gradient->capacity) {
gradient->capacity += 1;
gradient->keys = sk_realloc_t(gradient_key_t, gradient->keys, gradient->capacity);
}
int index = gradient->count;
for (int32_t i = 0; i < gradient->count; i++) {
if (gradient->keys[i].position > position) {
index = i;
break;
}
}
for (int32_t i = gradient->count; i > index; i--) {
gradient->keys[i] = gradient->keys[i - 1];
}
gradient->keys[index] = { color,position };
gradient->count += 1;
}
void gradient_set(gradient_t gradient, int32_t index, color128 color, float position) {
gradient->keys[index] = { color, position };
}
void gradient_remove(gradient_t gradient, int32_t index) {
memmove(&gradient->keys[index], &gradient->keys[index + 1], sizeof(gradient_key_t) * (gradient->count - (index + 1)));
gradient->capacity -= 1;
}
int32_t gradient_count(gradient_t gradient) {
return gradient->count;
}
color128 gradient_get(gradient_t gradient, float at) {
if (gradient->count == 0)
return { 1,0,0,1 };
if (at < gradient->keys[0].position)
return gradient->keys[0].color;
if (at >= gradient->keys[gradient->count - 1].position)
return gradient->keys[gradient->count - 1].color;
for (int32_t i = 1; i < gradient->count; i++) {
if (gradient->keys[i].position >= at) {
float pct = (at - gradient->keys[i-1].position) / (gradient->keys[i].position - gradient->keys[i-1].position);
return color_lerp(gradient->keys[i-1].color, gradient->keys[i].color, pct);
}
}
return { 1,0,0,1 };
}
color32 gradient_get32(gradient_t gradient, float at) {
color128 result = gradient_get(gradient, at);
return {
(uint8_t)(result.r * 255.f),
(uint8_t)(result.g * 255.f),
(uint8_t)(result.b * 255.f),
(uint8_t)(result.a * 255.f) };
}
void gradient_destroy(gradient_t gradient) {
sk_free(gradient->keys);
*gradient = {};
sk_free(gradient);
}
}