|
@@ -117,6 +117,7 @@ const char LA_IMM_FRAGMENT_SHADER[] = "#version 330\n\
|
|
|
uniform sampler2D TexColor;\
|
|
|
uniform sampler2DMS TexColorMS;\
|
|
|
uniform int TextureMode;\n\
|
|
|
+uniform int ColorMode;\n\
|
|
|
uniform int MultiplyColor;\n\
|
|
|
uniform int SampleAmount;\n\
|
|
|
uniform int UseNormal;\n\
|
|
@@ -128,6 +129,7 @@ in vec3 fGPos;\n\
|
|
|
layout(location = 0) out vec4 outColor;\n\
|
|
|
layout(location = 1) out vec3 outNormal;\n\
|
|
|
layout(location = 2) out vec3 outGPos;\n\
|
|
|
+#with TNS_SHADER_COLOR_COMMON\n\
|
|
|
void main(){\n\
|
|
|
vec4 color=vec4(1,0,1,1);\n\
|
|
|
if(TextureMode==0){ color = fColor;}\n\
|
|
@@ -151,6 +153,7 @@ void main(){\n\
|
|
|
vec3 oNormal=fNormal; if(view<0){ oNormal=-fNormal; }\n\
|
|
|
outNormal = oNormal;\n\
|
|
|
}\n\
|
|
|
+ if(ColorMode!=0){ color.rgb=okhsl_to_srgb(color.rgb); }\n\
|
|
|
outColor = color;\n\
|
|
|
outGPos = fGPos;\n\
|
|
|
}";
|
|
@@ -526,7 +529,9 @@ void tnsShaderApplyShadowMatrix(tnsShader *tns, tnsMatrix44d m){
|
|
|
glUniformMatrix4fv(tns->iShadow, 1, 0, mf);
|
|
|
}
|
|
|
|
|
|
-//--------------------Export
|
|
|
+char* tnsEnsureShaderCommoms(char* Content){
|
|
|
+ return strSub(Content,"#with TNS_SHADER_COLOR_COMMON",TNS_SHADER_COLOR_COMMON);
|
|
|
+}
|
|
|
int tnsNewVertexShader(char *Content){
|
|
|
int status = 0;
|
|
|
char error[1024];
|
|
@@ -537,7 +542,8 @@ int tnsNewVertexShader(char *Content){
|
|
|
|
|
|
VertexShaderObject = glCreateShader(GL_VERTEX_SHADER);
|
|
|
|
|
|
- glShaderSource(VertexShaderObject, 1, &Content, 0);
|
|
|
+ char* UseContent=tnsEnsureShaderCommoms(Content);
|
|
|
+ glShaderSource(VertexShaderObject, 1, &UseContent, 0); free(UseContent);
|
|
|
glCompileShader(VertexShaderObject);
|
|
|
glGetShaderiv(VertexShaderObject, GL_COMPILE_STATUS, &status);
|
|
|
if (status == GL_FALSE){
|
|
@@ -559,7 +565,8 @@ int tnsNewFragmentShader(char *Content){
|
|
|
|
|
|
FragmentShaderObject = glCreateShader(GL_FRAGMENT_SHADER);
|
|
|
|
|
|
- glShaderSource(FragmentShaderObject, 1, &Content, 0);
|
|
|
+ char* UseContent=tnsEnsureShaderCommoms(Content);
|
|
|
+ glShaderSource(FragmentShaderObject, 1, &UseContent, 0); free(UseContent);
|
|
|
glCompileShader(FragmentShaderObject);
|
|
|
glGetShaderiv(FragmentShaderObject, GL_COMPILE_STATUS, &status);
|
|
|
if (status == GL_FALSE){
|
|
@@ -581,7 +588,8 @@ int tnsNewGeometryShader(char *Content){
|
|
|
|
|
|
GeometryShaderObject = glCreateShader(GL_GEOMETRY_SHADER);
|
|
|
|
|
|
- glShaderSource(GeometryShaderObject, 1, &Content, 0);
|
|
|
+ char* UseContent=tnsEnsureShaderCommoms(Content);
|
|
|
+ glShaderSource(GeometryShaderObject, 1, &UseContent, 0); free(UseContent);
|
|
|
glCompileShader(GeometryShaderObject);
|
|
|
glGetShaderiv(GeometryShaderObject, GL_COMPILE_STATUS, &status);
|
|
|
if (status == GL_FALSE){
|
|
@@ -1976,6 +1984,9 @@ void tnsUniformUseMultiplyColor(tnsShader* s, int enable){
|
|
|
int mode=enable?1:0;
|
|
|
if(s->StateMultiplyColor != mode){ s->StateMultiplyColor=mode; glUniform1i(s->iMultiplyColor,mode); }
|
|
|
}
|
|
|
+void tnsUniformColorMode(tnsShader* s, int mode){
|
|
|
+ glUniform1i(s->iColorMode,mode);
|
|
|
+}
|
|
|
|
|
|
void tnsDraw2DTextureDirectly(tnsTexture *t, real x, real y, real w, real h){
|
|
|
real Verts[8];
|
|
@@ -2644,7 +2655,7 @@ void tnsDrawToOffscreen(tnsOffscreen *toff, int HowMany, GLuint *AttachmentArray
|
|
|
T->IsOffscreen = 1;
|
|
|
T->BindedShader = 0;
|
|
|
}
|
|
|
-//void tnsDrawToExtraColorAttachment(tnsOffscreen *toff){
|
|
|
+//void tnsDraw_toextraColorAttachment(tnsOffscreen *toff){
|
|
|
// if (!toff) return;
|
|
|
// if (!toff->pColor[1]){
|
|
|
// tnsCreate2DOffscreenMSAttachmentExtraColor(toff);
|
|
@@ -2654,7 +2665,7 @@ void tnsDrawToOffscreen(tnsOffscreen *toff, int HowMany, GLuint *AttachmentArray
|
|
|
// T->IsOffscreen = 1;
|
|
|
// T->BindedShader = 0;
|
|
|
//}
|
|
|
-//void tnsDrawToExtraNormalAttachment(tnsOffscreen *toff){
|
|
|
+//void tnsDraw_toextraNormalAttachment(tnsOffscreen *toff){
|
|
|
// if (!toff) return;
|
|
|
// if (!toff->pColor[2]){
|
|
|
// tnsCreate2DOffscreenMSAttachmentExtraNormal(toff);
|
|
@@ -3811,17 +3822,17 @@ void tnsLinearToLog(real *rgb, real gamma){
|
|
|
if (rgb[0] < 0) rgb[0] = 0;
|
|
|
if (rgb[1] < 0) rgb[1] = 0;
|
|
|
if (rgb[2] < 0) rgb[2] = 0;
|
|
|
- rgb[0] = powf(rgb[0], gamma);
|
|
|
- rgb[1] = powf(rgb[1], gamma);
|
|
|
- rgb[2] = powf(rgb[2], gamma);
|
|
|
+ rgb[0] = pow(rgb[0], gamma);
|
|
|
+ rgb[1] = pow(rgb[1], gamma);
|
|
|
+ rgb[2] = pow(rgb[2], gamma);
|
|
|
}
|
|
|
void tnsLogToLinear(real *rgb, real gamma){
|
|
|
if (rgb[0] < 0) rgb[0] = 0;
|
|
|
if (rgb[1] < 0) rgb[1] = 0;
|
|
|
if (rgb[2] < 0) rgb[2] = 0;
|
|
|
- rgb[0] = powf(rgb[0], 1.0f / gamma);
|
|
|
- rgb[1] = powf(rgb[1], 1.0f / gamma);
|
|
|
- rgb[2] = powf(rgb[2], 1.0f / gamma);
|
|
|
+ rgb[0] = pow(rgb[0], 1.0f / gamma);
|
|
|
+ rgb[1] = pow(rgb[1], 1.0f / gamma);
|
|
|
+ rgb[2] = pow(rgb[2], 1.0f / gamma);
|
|
|
}
|
|
|
void tnsRgbToLuminance(real *rgb){
|
|
|
real l;
|
|
@@ -3832,153 +3843,277 @@ void tnsRgbToLuminance(real *rgb){
|
|
|
rgb[0] = rgb[1] = rgb[2] = l;
|
|
|
}
|
|
|
|
|
|
-static const double LA_LUMA_WEIGHTS[]={ 0.2126, 0.7152, 0.0722 };
|
|
|
-void tnsHCYtoRGB(real *hcy, real *rgb){
|
|
|
- double red, green, blue;
|
|
|
- double Y_peak = 0., H_insec, X, m;
|
|
|
- int H_sec;
|
|
|
+real _srgb_transfer_function(real a){
|
|
|
+ return .0031308f >= a ? 12.92f * a : 1.055f * powf(a, .4166666666666667f) - .055f;
|
|
|
+}
|
|
|
+real _srgb_transfer_function_inv(real a){
|
|
|
+ return .04045f < a ? powf((a + .055f) / 1.055f, 2.4f) : a / 12.92f;
|
|
|
+}
|
|
|
+void tnsRGB2OKLAB(real* rgb, real* oklab){
|
|
|
+ real l = 0.4122214708f * rgb[0] + 0.5363325363f * rgb[1] + 0.0514459929f * rgb[2];
|
|
|
+ real m = 0.2119034982f * rgb[0] + 0.6806995451f * rgb[1] + 0.1073969566f * rgb[2];
|
|
|
+ real s = 0.0883024619f * rgb[0] + 0.2817188376f * rgb[1] + 0.6299787005f * rgb[2];
|
|
|
|
|
|
- double hue = hcy[0];
|
|
|
- double chroma = hcy[1];
|
|
|
- double luma = hcy[2];
|
|
|
- double* weights=LA_LUMA_WEIGHTS;
|
|
|
+ real l_ = cbrt(l); real m_ = cbrt(m); real s_ = cbrt(s);
|
|
|
|
|
|
- if (chroma < DBL_EPSILON){
|
|
|
- red = green = blue = luma;
|
|
|
- }else{
|
|
|
- hue = fmod(hue, 1.0);
|
|
|
- hue += hue < 0.0;
|
|
|
- hue *= 6.0;
|
|
|
-
|
|
|
- H_sec = (int)hue;
|
|
|
-
|
|
|
- switch (H_sec){
|
|
|
- case 0:
|
|
|
- H_insec = hue - H_sec;
|
|
|
- Y_peak = weights[0] + H_insec * weights[1];
|
|
|
- chroma *= luma < Y_peak ? luma / Y_peak : (1. - luma) / (1. - Y_peak);
|
|
|
- X = chroma * H_insec;
|
|
|
- m = luma - (weights[0] * chroma + weights[1] * X);
|
|
|
- red = m + chroma;
|
|
|
- green = m + X;
|
|
|
- blue = m;
|
|
|
- break;
|
|
|
- case 1:
|
|
|
- H_insec = 1. - (hue - H_sec);
|
|
|
- Y_peak = weights[1] + H_insec * weights[0];
|
|
|
- chroma *= luma < Y_peak ? luma / Y_peak : (1. - luma) / (1. - Y_peak);
|
|
|
- X = chroma * H_insec;
|
|
|
- m = luma - (weights[0] * X + weights[1] * chroma);
|
|
|
- red = m + X;
|
|
|
- green = m + chroma;
|
|
|
- blue = m;
|
|
|
- break;
|
|
|
- case 2:
|
|
|
- H_insec = hue - H_sec;
|
|
|
- Y_peak = weights[1] + H_insec * weights[2];
|
|
|
- chroma *= luma < Y_peak ? luma / Y_peak : (1. - luma) / (1. - Y_peak);
|
|
|
- X = chroma * H_insec;
|
|
|
- m = luma - (weights[1] * chroma + weights[2] * X);
|
|
|
- red = m;
|
|
|
- green = m + chroma;
|
|
|
- blue = m + X;
|
|
|
- break;
|
|
|
- case 3:
|
|
|
- H_insec = 1. - (hue - H_sec);
|
|
|
- Y_peak = weights[2] + H_insec * weights[1];
|
|
|
- chroma *= luma < Y_peak ? luma / Y_peak : (1. - luma) / (1. - Y_peak);
|
|
|
- X = chroma * H_insec;
|
|
|
- m = luma - (weights[1] * X + weights[2] * chroma);
|
|
|
- red = m;
|
|
|
- green = m + X;
|
|
|
- blue = m + chroma;
|
|
|
- break;
|
|
|
- case 4:
|
|
|
- H_insec = hue - H_sec;
|
|
|
- Y_peak = weights[2] + H_insec * weights[0];
|
|
|
- chroma *= luma < Y_peak ? luma / Y_peak : (1. - luma) / (1. - Y_peak);
|
|
|
- X = chroma * H_insec;
|
|
|
- m = luma - (weights[0] * X + weights[2] * chroma);
|
|
|
- red = m + X;
|
|
|
- green = m;
|
|
|
- blue = m + chroma;
|
|
|
- break;
|
|
|
- default:
|
|
|
- H_insec = 1. - (hue - H_sec);
|
|
|
- Y_peak = weights[0] + H_insec * weights[2];
|
|
|
- chroma *= luma < Y_peak ? luma / Y_peak : (1. - luma) / (1. - Y_peak);
|
|
|
- X = chroma * H_insec;
|
|
|
- m = luma - (weights[0] * chroma + weights[2] * X);
|
|
|
- red = m + chroma;
|
|
|
- green = m;
|
|
|
- blue = m + X;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
+ oklab[0]=0.2104542553f*l_ + 0.7936177850f*m_ - 0.0040720468f*s_;
|
|
|
+ oklab[1]=1.9779984951f*l_ - 2.4285922050f*m_ + 0.4505937099f*s_;
|
|
|
+ oklab[2]=0.0259040371f*l_ + 0.7827717662f*m_ - 0.8086757660f*s_;
|
|
|
+}
|
|
|
+void tnsOKLAB2RGB(real* oklab, real* rgb){
|
|
|
+ real l_ = oklab[0] + 0.3963377774f * oklab[1] + 0.2158037573f * oklab[2];
|
|
|
+ real m_ = oklab[0] - 0.1055613458f * oklab[1] - 0.0638541728f * oklab[2];
|
|
|
+ real s_ = oklab[0] - 0.0894841775f * oklab[1] - 1.2914855480f * oklab[2];
|
|
|
|
|
|
- rgb[0] =red;
|
|
|
- rgb[1] =green;
|
|
|
- rgb[2] =blue;
|
|
|
-}
|
|
|
-void tnsRGBtoHCY(real *rgb, real *hcy){
|
|
|
- double hue, chroma, luma;
|
|
|
- double X, Y_peak = 0.;
|
|
|
- int H_sec = 4, t = -1;
|
|
|
- double* weights=LA_LUMA_WEIGHTS;
|
|
|
-
|
|
|
- int ix[3] = {0, 1, 2};
|
|
|
-
|
|
|
- if (rgb[0] < rgb[1]){
|
|
|
- if (rgb[1] > rgb[2]){
|
|
|
- if (rgb[0] < rgb[2]){
|
|
|
- ix[1] = 2;
|
|
|
- ix[2] = 1;
|
|
|
- H_sec = 2;
|
|
|
- t = 1;
|
|
|
- }else{
|
|
|
- ix[0] = 2;
|
|
|
- ix[1] = 0;
|
|
|
- ix[2] = 1;
|
|
|
- H_sec = 2;
|
|
|
- }
|
|
|
- }
|
|
|
- }else{
|
|
|
- if (rgb[1] < rgb[2]){
|
|
|
- if (rgb[0] < rgb[2]){
|
|
|
- ix[0] = 1;
|
|
|
- ix[1] = 0;
|
|
|
- H_sec = 4;
|
|
|
- t = 1;
|
|
|
- }else{
|
|
|
- ix[0] = 1;
|
|
|
- ix[1] = 2;
|
|
|
- ix[2] = 0;
|
|
|
- H_sec = 6;
|
|
|
- }
|
|
|
- }else{
|
|
|
- ix[0] = 2;
|
|
|
- ix[2] = 0;
|
|
|
- H_sec = 0;
|
|
|
- t = 1;
|
|
|
- }
|
|
|
- }
|
|
|
+ real l = l_*l_*l_; real m = m_*m_*m_; real s = s_*s_*s_;
|
|
|
+
|
|
|
+ rgb[0]=+4.0767416621f * l - 3.3077115913f * m + 0.2309699292f * s;
|
|
|
+ rgb[1]=-1.2684380046f * l + 2.6097574011f * m - 0.3413193965f * s;
|
|
|
+ rgb[2]=-0.0041960863f * l - 0.7034186147f * m + 1.7076147010f * s;
|
|
|
+}
|
|
|
+real _compute_max_saturation(real a, real b){
|
|
|
+ real k0, k1, k2, k3, k4, wl, wm, ws;
|
|
|
+ if (-1.88170328f * a - 0.80936493f * b > 1){
|
|
|
+ k0 = +1.19086277f; k1 = +1.76576728f; k2 = +0.59662641f; k3 = +0.75515197f; k4 = +0.56771245f;
|
|
|
+ wl = +4.0767416621f; wm = -3.3077115913f; ws = +0.2309699292f;
|
|
|
+ }
|
|
|
+ else if (1.81444104f * a - 1.19445276f * b > 1){
|
|
|
+ k0 = +0.73956515f; k1 = -0.45954404f; k2 = +0.08285427f; k3 = +0.12541070f; k4 = +0.14503204f;
|
|
|
+ wl = -1.2684380046f; wm = +2.6097574011f; ws = -0.3413193965f;
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ k0 = +1.35733652f; k1 = -0.00915799f; k2 = -1.15130210f; k3 = -0.50559606f; k4 = +0.00692167f;
|
|
|
+ wl = -0.0041960863f; wm = -0.7034186147f; ws = +1.7076147010f;
|
|
|
+ }
|
|
|
+ real S = k0 + k1 * a + k2 * b + k3 * a * a + k4 * a * b;
|
|
|
+ real k_l = +0.3963377774f * a + 0.2158037573f * b;
|
|
|
+ real k_m = -0.1055613458f * a - 0.0638541728f * b;
|
|
|
+ real k_s = -0.0894841775f * a - 1.2914855480f * b;
|
|
|
+ {
|
|
|
+ real l_ = 1.f + S * k_l;
|
|
|
+ real m_ = 1.f + S * k_m;
|
|
|
+ real s_ = 1.f + S * k_s;
|
|
|
+
|
|
|
+ real l = l_ * l_ * l_;
|
|
|
+ real m = m_ * m_ * m_;
|
|
|
+ real s = s_ * s_ * s_;
|
|
|
+
|
|
|
+ real l_dS = 3.f * k_l * l_ * l_;
|
|
|
+ real m_dS = 3.f * k_m * m_ * m_;
|
|
|
+ real s_dS = 3.f * k_s * s_ * s_;
|
|
|
+
|
|
|
+ real l_dS2 = 6.f * k_l * k_l * l_;
|
|
|
+ real m_dS2 = 6.f * k_m * k_m * m_;
|
|
|
+ real s_dS2 = 6.f * k_s * k_s * s_;
|
|
|
+
|
|
|
+ real f = wl * l + wm * m + ws * s;
|
|
|
+ real f1 = wl * l_dS + wm * m_dS + ws * s_dS;
|
|
|
+ real f2 = wl * l_dS2 + wm * m_dS2 + ws * s_dS2;
|
|
|
+
|
|
|
+ S = S - f * f1 / (f1 * f1 - 0.5f * f * f2);
|
|
|
+ }
|
|
|
+
|
|
|
+ return S;
|
|
|
+}
|
|
|
+void _find_cusp(real a, real b, real *l, real *c)
|
|
|
+{
|
|
|
+ real S_cusp = _compute_max_saturation(a, b);
|
|
|
+ real oklab[3]={1, S_cusp * a, S_cusp * b}; real rgb_at_max[3];
|
|
|
+ tnsOKLAB2RGB(oklab,rgb_at_max);
|
|
|
+ real L_cusp = cbrt(1.f / TNS_MAX3(rgb_at_max[0], rgb_at_max[1], rgb_at_max[2]));
|
|
|
+ real C_cusp = L_cusp * S_cusp;
|
|
|
+ *l=L_cusp; *c=C_cusp;
|
|
|
+}
|
|
|
+real _find_gamut_intersection(real a, real b, real L1, real C1, real L0, real cusp_L, real cusp_C)
|
|
|
+{
|
|
|
+ real t;
|
|
|
+ if (((L1 - L0) * cusp_C - (cusp_L - L0) * C1) <= 0.f) {
|
|
|
+ t = cusp_C * L0 / (C1 * cusp_L + cusp_C * (L0 - L1));
|
|
|
+ }else{
|
|
|
+ t = cusp_C * (L0 - 1.f) / (C1 * (cusp_L - 1.f) + cusp_C * (L0 - L1));
|
|
|
+ {
|
|
|
+ real dL = L1 - L0; real dC = C1;
|
|
|
+
|
|
|
+ real k_l = +0.3963377774f * a + 0.2158037573f * b;
|
|
|
+ real k_m = -0.1055613458f * a - 0.0638541728f * b;
|
|
|
+ real k_s = -0.0894841775f * a - 1.2914855480f * b;
|
|
|
+
|
|
|
+ real l_dt = dL + dC * k_l;
|
|
|
+ real m_dt = dL + dC * k_m;
|
|
|
+ real s_dt = dL + dC * k_s;
|
|
|
+ {
|
|
|
+ real L = L0 * (1.f - t) + t * L1;
|
|
|
+ real C = t * C1;
|
|
|
+
|
|
|
+ real l_ = L + C * k_l;
|
|
|
+ real m_ = L + C * k_m;
|
|
|
+ real s_ = L + C * k_s;
|
|
|
+
|
|
|
+ real l = l_ * l_ * l_;
|
|
|
+ real m = m_ * m_ * m_;
|
|
|
+ real s = s_ * s_ * s_;
|
|
|
+
|
|
|
+ real ldt = 3 * l_dt * l_ * l_;
|
|
|
+ real mdt = 3 * m_dt * m_ * m_;
|
|
|
+ real sdt = 3 * s_dt * s_ * s_;
|
|
|
+
|
|
|
+ real ldt2 = 6 * l_dt * l_dt * l_;
|
|
|
+ real mdt2 = 6 * m_dt * m_dt * m_;
|
|
|
+ real sdt2 = 6 * s_dt * s_dt * s_;
|
|
|
+
|
|
|
+ real r = 4.0767416621f * l - 3.3077115913f * m + 0.2309699292f * s - 1;
|
|
|
+ real r1 = 4.0767416621f * ldt - 3.3077115913f * mdt + 0.2309699292f * sdt;
|
|
|
+ real r2 = 4.0767416621f * ldt2 - 3.3077115913f * mdt2 + 0.2309699292f * sdt2;
|
|
|
+
|
|
|
+ real u_r = r1 / (r1 * r1 - 0.5f * r * r2);
|
|
|
+ real t_r = -r * u_r;
|
|
|
+
|
|
|
+ real g = -1.2684380046f * l + 2.6097574011f * m - 0.3413193965f * s - 1;
|
|
|
+ real g1 = -1.2684380046f * ldt + 2.6097574011f * mdt - 0.3413193965f * sdt;
|
|
|
+ real g2 = -1.2684380046f * ldt2 + 2.6097574011f * mdt2 - 0.3413193965f * sdt2;
|
|
|
+
|
|
|
+ real u_g = g1 / (g1 * g1 - 0.5f * g * g2);
|
|
|
+ real t_g = -g * u_g;
|
|
|
+
|
|
|
+ real b = -0.0041960863f * l - 0.7034186147f * m + 1.7076147010f * s - 1;
|
|
|
+ real b1 = -0.0041960863f * ldt - 0.7034186147f * mdt + 1.7076147010f * sdt;
|
|
|
+ real b2 = -0.0041960863f * ldt2 - 0.7034186147f * mdt2 + 1.7076147010f * sdt2;
|
|
|
+
|
|
|
+ real u_b = b1 / (b1 * b1 - 0.5f * b * b2);
|
|
|
+ real t_b = -b * u_b;
|
|
|
+
|
|
|
+ t_r = u_r >= 0.f ? t_r : FLT_MAX;
|
|
|
+ t_g = u_g >= 0.f ? t_g : FLT_MAX;
|
|
|
+ t_b = u_b >= 0.f ? t_b : FLT_MAX;
|
|
|
+
|
|
|
+ t += fmin(t_r, fmin(t_g, t_b));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return t;
|
|
|
+}
|
|
|
+real _toe(real x) {
|
|
|
+ const real k_1 = 0.206f; const real k_2 = 0.03f; const real k_3 = (1.f + k_1) / (1.f + k_2);
|
|
|
+ return 0.5f * (k_3 * x - k_1 + sqrt((k_3 * x - k_1) * (k_3 * x - k_1) + 4 * k_2 * k_3 * x));
|
|
|
+}
|
|
|
+real _toe_inv(real x) {
|
|
|
+ const real k_1 = 0.206f; const real k_2 = 0.03f; const real k_3 = (1.f + k_1) / (1.f + k_2);
|
|
|
+ return (x * x + k_1 * x) / (k_3 * (x + k_2));
|
|
|
+}
|
|
|
+void _to_ST(real cusp_L, real cusp_C, real* _s, real* _t) {
|
|
|
+ real L = cusp_L; real C = cusp_C;
|
|
|
+ *_s=C / L; *_t=C / (1 - L);
|
|
|
+}
|
|
|
+void _get_ST_mid(real a_, real b_, real *s,real *t){
|
|
|
+ *s = 0.11516993f + 1.f / (
|
|
|
+ +7.44778970f + 4.15901240f * b_
|
|
|
+ + a_ * (-2.19557347f + 1.75198401f * b_
|
|
|
+ + a_ * (-2.13704948f - 10.02301043f * b_
|
|
|
+ + a_ * (-4.24894561f + 5.38770819f * b_ + 4.69891013f * a_
|
|
|
+ )))
|
|
|
+ );
|
|
|
+ *t = 0.11239642f + 1.f / (
|
|
|
+ +1.61320320f - 0.68124379f * b_
|
|
|
+ + a_ * (+0.40370612f + 0.90148123f * b_
|
|
|
+ + a_ * (-0.27087943f + 0.61223990f * b_
|
|
|
+ + a_ * (+0.00299215f - 0.45399568f * b_ - 0.14661872f * a_
|
|
|
+ )))
|
|
|
+ );
|
|
|
+}
|
|
|
+void _get_Cs(real L, real a_, real b_,real *rC_0, real *rC_mid, real *rC_max){
|
|
|
+ real cusp_L,cusp_C; _find_cusp(a_, b_,&cusp_L,&cusp_C);
|
|
|
+
|
|
|
+ real C_max = _find_gamut_intersection(a_, b_, L, 1, L,cusp_L,cusp_C);
|
|
|
+ real _S,_T; _to_ST(cusp_L,cusp_C,&_S, &_T);
|
|
|
+ real k = C_max / fmin((L * _S), (1 - L) * _T);
|
|
|
+ real C_mid;{
|
|
|
+ real _s, _t; _get_ST_mid(a_, b_,&_s,&_t);
|
|
|
+ real C_a = L * _s; real C_b = (1.f - L) * _t;
|
|
|
+ C_mid = 0.9f * k * sqrt(sqrt(1.f / (1.f / (C_a * C_a * C_a * C_a) + 1.f / (C_b * C_b * C_b * C_b))));
|
|
|
+ }
|
|
|
+
|
|
|
+ real C_0;{
|
|
|
+ real C_a = L * 0.4f;
|
|
|
+ real C_b = (1.f - L) * 0.8f;
|
|
|
+ C_0 = sqrt(1.f / (1.f / (C_a * C_a) + 1.f / (C_b * C_b)));
|
|
|
+ }
|
|
|
|
|
|
- luma = weights[0] * rgb[0] + weights[1] * rgb[1] + weights[2] * rgb[2];
|
|
|
- chroma = rgb[ix[2]] - rgb[ix[0]];
|
|
|
+ *rC_0=C_0; *rC_mid=C_mid; *rC_max=C_max;
|
|
|
+}
|
|
|
+void tnsHCY2RGB(real *hcy, real *rgb){
|
|
|
+ real h = hcy[0]; real s = hcy[1]; real l = hcy[2];
|
|
|
+
|
|
|
+ if (l >= 1.0f){ tnsVectorSet3(rgb,1,1,1); return; }
|
|
|
+ else if (l <= 0.0f){ tnsVectorSet3(rgb,0,0,0); return; }
|
|
|
|
|
|
- if (chroma >= DBL_EPSILON){
|
|
|
- X = (rgb[ix[1]] - rgb[ix[0]]) / chroma;
|
|
|
+ real a_ = cos(2.f * TNS_PI * h);
|
|
|
+ real b_ = sin(2.f * TNS_PI * h);
|
|
|
+ real L = _toe_inv(l);
|
|
|
|
|
|
- Y_peak = weights[ix[2]] + X * weights[ix[1]];
|
|
|
- if (luma != 0. && luma != 1.) chroma /= luma < Y_peak ? luma / Y_peak : (1. - luma) / (1. - Y_peak);
|
|
|
+ real C_0, C_mid, C_max;
|
|
|
+ _get_Cs(L, a_, b_,&C_0,&C_mid,&C_max);
|
|
|
|
|
|
- hue = (H_sec + t * X) / 6.;
|
|
|
- }else
|
|
|
- chroma = hue = 0.0;
|
|
|
+ real mid = 0.8f; real mid_inv = 1.25f;
|
|
|
+ real C, t, k_0, k_1, k_2;
|
|
|
|
|
|
- hcy[0] = hue;
|
|
|
- hcy[1] = chroma;
|
|
|
- hcy[2] = luma;
|
|
|
+ if (s < mid){
|
|
|
+ t = mid_inv * s;
|
|
|
+ k_1 = mid * C_0;
|
|
|
+ k_2 = (1.f - k_1 / C_mid);
|
|
|
+ C = t * k_1 / (1.f - k_2 * t);
|
|
|
+ }else{
|
|
|
+ t = (s - mid)/ (1 - mid);
|
|
|
+ k_0 = C_mid;
|
|
|
+ k_1 = (1.f - mid) * C_mid * C_mid * mid_inv * mid_inv / C_0;
|
|
|
+ k_2 = (1.f - (k_1) / (C_max - C_mid));
|
|
|
+ C = k_0 + t * k_1 / (1.f - k_2 * t);
|
|
|
+ }
|
|
|
+
|
|
|
+ real okl[3]={L, C * a_, C * b_};
|
|
|
+ tnsOKLAB2RGB(okl, rgb);
|
|
|
+ rgb[0]=_srgb_transfer_function(rgb[0]);
|
|
|
+ rgb[1]=_srgb_transfer_function(rgb[1]);
|
|
|
+ rgb[2]=_srgb_transfer_function(rgb[2]);
|
|
|
+}
|
|
|
+void tnsRGB2HCY(real *rgb, real *hcy){
|
|
|
+ real lab[3]; real lrgb[3];
|
|
|
+ lrgb[0]=_srgb_transfer_function_inv(rgb[0]);
|
|
|
+ lrgb[1]=_srgb_transfer_function_inv(rgb[1]);
|
|
|
+ lrgb[2]=_srgb_transfer_function_inv(rgb[2]);
|
|
|
+ tnsRGB2OKLAB(lrgb,lab);
|
|
|
+
|
|
|
+ if(lab[0]>=1.0f-1e-4){ tnsVectorSet3(hcy,0,0,1); return; }
|
|
|
+ if(lab[0]<=1e-4){ tnsVectorSet3(hcy,0,0,0); return; }
|
|
|
+
|
|
|
+ real C = sqrt(lab[1]*lab[1] + lab[2]*lab[2]);
|
|
|
+ real a_ = (!C)?0:(lab[1] / C);
|
|
|
+ real b_ = (!C)?0:(lab[2] / C);
|
|
|
+
|
|
|
+ real L = lab[0];
|
|
|
+ real h = 0.5f + 0.5f * atan2(-lab[2], -lab[1]) / TNS_PI;
|
|
|
+
|
|
|
+ real C_0, C_mid, C_max;
|
|
|
+ _get_Cs(L, a_, b_,&C_0,&C_mid,&C_max);
|
|
|
+
|
|
|
+ real mid = 0.8f; real mid_inv = 1.25f;
|
|
|
+
|
|
|
+ real s;
|
|
|
+ if (C < C_mid){
|
|
|
+ real k_1 = mid * C_0;
|
|
|
+ real k_2 = (1.f - k_1 / C_mid);
|
|
|
+ real t = C / (k_1 + k_2 * C);
|
|
|
+ s = t * mid;
|
|
|
+ }else{
|
|
|
+ real k_0 = C_mid;
|
|
|
+ real k_1 = (1.f - mid) * C_mid * C_mid * mid_inv * mid_inv / C_0;
|
|
|
+ real k_2 = (1.f - (k_1) / (C_max - C_mid));
|
|
|
+ real t = (C - k_0) / (k_1 + k_2 * (C - k_0));
|
|
|
+ s = mid + (1.f - mid) * t;
|
|
|
+ }
|
|
|
+
|
|
|
+ real l = _toe(L);
|
|
|
+ hcy[0]=h; hcy[1]=s; hcy[2]=l;
|
|
|
}
|
|
|
|
|
|
void tnsClearAll(){
|
|
@@ -4070,7 +4205,7 @@ void tnsMakeQuad4d(real *arr, real x1, real y1, real z1, real w1, real x2, real
|
|
|
arr[14] = z4;
|
|
|
arr[15] = w4;
|
|
|
}
|
|
|
-void tnsMakeCircle2d(real *arr, int slices, real ctrX, real ctrY, real r){
|
|
|
+void tnsMakeCircle2d(real *arr, int slices, real ctrX, real ctrY, real r, int jump){
|
|
|
int i;
|
|
|
real radstep = 2 * TNS_PI / (real)slices;
|
|
|
real rd = 0;
|
|
@@ -4078,8 +4213,9 @@ void tnsMakeCircle2d(real *arr, int slices, real ctrX, real ctrY, real r){
|
|
|
for (i = 0; i < slices; i++){
|
|
|
x = ctrX + cos(rd) * r;
|
|
|
y = ctrY + sin(rd) * r;
|
|
|
- arr[2 * i] = x;
|
|
|
- arr[2 * i + 1] = y;
|
|
|
+ int idx=2 * i * (1+jump);
|
|
|
+ arr[idx] = x;
|
|
|
+ arr[idx+1] = y;
|
|
|
rd += radstep;
|
|
|
}
|
|
|
}
|
|
@@ -4113,8 +4249,8 @@ void tnsMakeBridgedIndex(unsigned int *result, int num, int revert, int begin){
|
|
|
}
|
|
|
|
|
|
void tnsMakeRing2d(real *arr, int *index, int slices, real ctrX, real ctrY, real r1, real r2){
|
|
|
- tnsMakeCircle2d(arr, slices, ctrX, ctrY, r1);
|
|
|
- tnsMakeCircle2d(&arr[slices*2], slices, ctrX, ctrY, r2);
|
|
|
+ tnsMakeCircle2d(arr, slices, ctrX, ctrY, r1,0);
|
|
|
+ tnsMakeCircle2d(&arr[slices*2], slices, ctrX, ctrY, r2,0);
|
|
|
tnsMakeBridgedIndex(index, slices, 0, 0);
|
|
|
index[slices*2]=0; index[slices*2+1]=slices;
|
|
|
}
|