Commit: 7c13a4869eaea10cd138ab616c873b0226a5ff7f
Parent: a38a0df3f85e0c437de3a28cf1627bcae68ef4ff
Author: zvezdochiot
Date:   Wed,  7 Aug 2019 10:23:02 +0300
fix #9: 1.5: Approximation of the redshift table (no limits)
Diffstat:
5 files changed, 108 insertions(+), 60 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
@@ -1,5 +1,11 @@
 PROJECT: https://github.com/faf0/sct
 
+1.5: zvezdochiot on 07 Aug 2019
+* Approximation of the `redshift` table (no limits)
+
+1.4: zvezdochiot on 04 Aug 2019
+* Read current temperature
+
 1.3: zvezdochiot on 02 Jan 2019
 * Rename utilites for X11
 * Add -h option to print usage information
diff --git a/Makefile b/Makefile
@@ -1,7 +1,7 @@
 PROG = xsct
 CC = gcc
 CFLAGS = -Wall -std=c99 -O2 -I /usr/X11R6/include
-LDFLAGS = -L /usr/X11R6/lib -lX11 -lXrandr
+LDFLAGS = -L /usr/X11R6/lib -lX11 -lXrandr -lm
 SRCS = sct.c
 PREFIX = /usr
 BIN = $(PREFIX)/bin
diff --git a/README.md b/README.md
@@ -20,7 +20,7 @@ Minor modifications were made in order to get sct to:
 Compile the code using the following command:
 
 ~~~
-cc -std=c99 -O2 -I /usr/X11R6/include sct.c -o xsct -L /usr/X11R6/lib -lX11 -lXrandr
+gcc -Wall -std=c99 -O2 -I /usr/X11R6/include sct.c -o xsct -L /usr/X11R6/lib -lX11 -lXrandr -lm -s
 ~~~
 
 Execute sct using the following command:
@@ -34,6 +34,12 @@ between `1000` and `10000`.
 If `xsct` is called with parameter 0, the color temperature is set to `6500`.  
 If `xsct` is called without parameters, the current display temperature is estimated.
 
+Test sct using the following command:
+
+~~~
+./xsct 3700 && ./xsct
+~~~
+
 ---
 
 https://github.com/faf0/sct/
diff --git a/sct.c b/sct.c
@@ -16,6 +16,9 @@
  * - return EXIT_SUCCESS
  *
  * Public domain, do as you wish.
+ * 
+ * gcc -Wall -std=c99 -O2 -I /usr/X11R6/include sct.c -o xsct -L /usr/X11R6/lib -lX11 -lXrandr -lm -s
+ * 
  */
 
 #include <X11/Xatom.h>
@@ -26,6 +29,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <math.h>
 
 static void usage()
 {
@@ -36,83 +40,115 @@ static void usage()
         "If -h or --help is passed xsct will display this usage information\n");
 }
 
-/* cribbed from redshift, but truncated with 500K steps */
-static const struct { float r; float g; float b; } whitepoints[] = {
-    { 1.00000000,  0.18172716,  0.00000000, }, /* 1000K */
-    { 1.00000000,  0.42322816,  0.00000000, },
-    { 1.00000000,  0.54360078,  0.08679949, },
-    { 1.00000000,  0.64373109,  0.28819679, },
-    { 1.00000000,  0.71976951,  0.42860152, },
-    { 1.00000000,  0.77987699,  0.54642268, },
-    { 1.00000000,  0.82854786,  0.64816570, },
-    { 1.00000000,  0.86860704,  0.73688797, },
-    { 1.00000000,  0.90198230,  0.81465502, },
-    { 1.00000000,  0.93853986,  0.88130458, },
-    { 1.00000000,  0.97107439,  0.94305985, },
-    { 1.00000000,  1.00000000,  1.00000000, }, /* 6500K */
-    { 0.95160805,  0.96983355,  1.00000000, },
-    { 0.91194747,  0.94470005,  1.00000000, },
-    { 0.87906581,  0.92357340,  1.00000000, },
-    { 0.85139976,  0.90559011,  1.00000000, },
-    { 0.82782969,  0.89011714,  1.00000000, },
-    { 0.80753191,  0.87667891,  1.00000000, },
-    { 0.78988728,  0.86491137,  1.00000000, }, /* 10000K */
-    { 0.77442176,  0.85453121,  1.00000000, },
-};
-#define TEMPERATURE_DEFAULT 6500
-#define TEMPERATURE_MIN     1000
-#define TEMPERATURE_MAX     10000
-#define TEMPERATURE_STEP    500
+#define TEMPERATURE_NORM    6500
+#define TEMPERATURE_ZERO    700
 #define GAMMA_MULT          65535.0
-#define AVG(c,temp,ratio) whitepoints[(temp) / TEMPERATURE_STEP].c * (1 - (ratio)) + whitepoints[(temp) / TEMPERATURE_STEP + 1].c * (ratio)
+#define GAMMA_K0GR          -1.47751309139817
+#define GAMMA_K1GR          0.28590164772055
+#define GAMMA_K0BR          -4.38321650114872
+#define GAMMA_K1BR          0.6212158769447
+#define GAMMA_K0RB          1.75390204039018
+#define GAMMA_K1RB          -0.1150805671482
+#define GAMMA_K0GB          1.49221604915144
+#define GAMMA_K1GB          -0.07513509588921
+
+static double DoubleTrim(double x, double a, double b)
+{
+    double buff[3] = {a, x, b};
+    return buff[ (x > a) + (x > b) ];
+}
 
 static int get_sct_for_screen(Display *dpy, int screen)
 {
     Window root = RootWindow(dpy, screen);
     XRRScreenResources *res = XRRGetScreenResourcesCurrent(dpy, root);
 
-    int temp = 0;
-    double t, ts;
-    double gammar, gammag, gammab;
+    int temp = 0, n, c;
+    double t = 0.0;
+    double gammar = 0.0, gammag = 0.0, gammab = 0.0, gammam = 1.0, gammad = 0.0;
 
-    int n = res->ncrtc;
-    ts = 0.0;
-    for (int c = 0; c < n; c++)
+    n = res->ncrtc;
+    for (c = 0; c < n; c++)
     {
         int crtcxid = res->crtcs[c];
         XRRCrtcGamma *crtc_gamma = XRRGetCrtcGamma(dpy, crtcxid);
         int size = crtc_gamma->size;
+        gammar += (crtc_gamma->red[size - 1]);
+        gammag += (crtc_gamma->green[size - 1]);
+        gammab += (crtc_gamma->blue[size - 1]);
 
-        if (size > 0)
+        XFree(crtc_gamma);
+    }
+    XFree(res);
+    gammam = (gammar > gammag) ? gammar : gammag;
+    gammam = (gammab > gammam) ? gammab : gammam;
+    if (gammam > 0.0)
+    {
+        gammar /= gammam;
+        gammag /= gammam;
+        gammab /= gammam;
+        gammad = gammab - gammar;
+        if (gammad < 0.0)
         {
-            double g_inv = (size + 1) / size / GAMMA_MULT;
-            gammar = crtc_gamma->red[size - 1] * g_inv;
-            gammag = crtc_gamma->green[size - 1] * g_inv;
-            gammab = crtc_gamma->blue[size - 1] * g_inv;
-            t = (64465 - 109049 * gammar + 46013 * gammar * gammar -
-                 4322 * gammag + 10708 * gammag * gammag -
-                 2662 * gammab + 1355 * gammab * gammab);
-            ts += t;
+            if (gammab == 0.0)
+            {
+                if (gammag == 0.0)
+                {
+                    t = TEMPERATURE_ZERO;
+                } else {
+                    t = gammag;
+                    t -= GAMMA_K0GR;
+                    t /= GAMMA_K1GR;
+                    t = exp(t);
+                    t += TEMPERATURE_ZERO;
+                }
+            } else {
+                t = gammag + gammad + 1.0;
+                t -= (GAMMA_K0GR + GAMMA_K0BR);
+                t /= (GAMMA_K1GR + GAMMA_K1BR);
+                t = exp(t);
+                t += TEMPERATURE_ZERO;
+            }
+        } else {
+            t = gammag + 1.0 - gammad;
+            t -= (GAMMA_K0GB + GAMMA_K0RB);
+            t /= (GAMMA_K1GB + GAMMA_K1RB);
+            t = exp(t);
+            t += (TEMPERATURE_NORM - TEMPERATURE_ZERO);
         }
-
-        XFree(crtc_gamma);
     }
-    temp = (int)(ts / (double)n);
 
-    XFree(res);
+    temp = (int)(t + 0.5);
+
     return temp;
 }
 
 static void sct_for_screen(Display *dpy, int screen, int temp)
 {
+    double t = 0.0, g = 0.0, gammar, gammag, gammab;
     Window root = RootWindow(dpy, screen);
     XRRScreenResources *res = XRRGetScreenResourcesCurrent(dpy, root);
 
-    temp -= TEMPERATURE_MIN;
-    double ratio = temp % TEMPERATURE_STEP / TEMPERATURE_STEP;
-    double gammar = AVG(r, temp, ratio);
-    double gammag = AVG(g, temp, ratio);
-    double gammab = AVG(b, temp, ratio);
+    t = (double)temp;
+    if (temp < TEMPERATURE_NORM)
+    {
+        gammar = 1.0;
+        if (temp < TEMPERATURE_ZERO)
+        {
+            gammag = 0.0;
+            gammab = 0.0;
+        } else {
+            g = log(t - TEMPERATURE_ZERO);
+            gammag = DoubleTrim(GAMMA_K0GR + GAMMA_K1GR * g, 0.0, 1.0);
+            gammab = DoubleTrim(GAMMA_K0BR + GAMMA_K1BR * g, 0.0, 1.0);         
+        }
+    } else {
+        g = log(t - (TEMPERATURE_NORM - TEMPERATURE_ZERO));
+        gammar = DoubleTrim(GAMMA_K0RB + GAMMA_K1RB * g, 0.0, 1.0);
+        gammag = DoubleTrim(GAMMA_K0GB + GAMMA_K1GB * g, 0.0, 1.0);
+        gammab = 1.0;
+        
+    }
 
     int n = res->ncrtc;
     for (int c = 0; c < n; c++)
@@ -124,7 +160,7 @@ static void sct_for_screen(Display *dpy, int screen, int temp)
 
         for (int i = 0; i < size; i++)
         {
-            double g = GAMMA_MULT * i / size;
+            g = GAMMA_MULT * (double)i / (double)size;
             crtc_gamma->red[i] = g * gammar;
             crtc_gamma->green[i] = g * gammag;
             crtc_gamma->blue[i] = g * gammab;
@@ -147,7 +183,7 @@ int main(int argc, char **argv)
     }
     int screens = XScreenCount(dpy);
 
-    int temp = TEMPERATURE_DEFAULT;
+    int temp = TEMPERATURE_NORM;
     if (argc > 1)
     {
         if (!strcmp(argv[1],"-h") || !strcmp(argv[1],"--help"))
@@ -155,8 +191,8 @@ int main(int argc, char **argv)
             usage();
         } else {
             temp = atoi(argv[1]);
-            if (temp < TEMPERATURE_MIN || temp > TEMPERATURE_MAX)
-                temp = TEMPERATURE_DEFAULT;
+            if (temp <= 0)
+                temp = TEMPERATURE_NORM;
 
             for (int screen = 0; screen < screens; screen++)
                 sct_for_screen(dpy, screen, temp);
diff --git a/xsct.1 b/xsct.1
@@ -1,4 +1,4 @@
-.TH xsct 1 "Aug 2019" "1.4" "User Manual"
+.TH xsct 1 "Aug 2019" "1.5" "User Manual"
 .SH NAME
 xsct \- X11 set screen color temperature
 .SH SYNOPSIS
@@ -13,7 +13,7 @@ or
 
 .SH DESCRIPTION
 .B xsct
-sets the screen's color temperature in a range from 1000 to 10000
+sets the screen's color temperature.
 
 .SH OPTIONS
 .IP temperature