1 /* This file is an image processing operation for GEGL
2  *
3  * GEGL is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation; either
6  * version 3 of the License, or (at your option) any later version.
7  *
8  * GEGL is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
15  *
16  * Copyright 2018 Øyvind Kolås <pippin@gimp.org>
17  */
18 
19 #include "config.h"
20 #include <glib/gi18n-lib.h>
21 
22 
23 #ifdef GEGL_PROPERTIES
24 
25    /* no properties */
26 
27 #else
28 
29 #define GEGL_OP_POINT_FILTER
30 #define GEGL_OP_NAME     aces_rrt
31 #define GEGL_OP_C_SOURCE aces-rrt.c
32 
33 #include "gegl-op.h"
34 
aces_rrt(float x)35 static inline float aces_rrt (float x)
36 {
37  /* source of approximation:
38 
39     https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
40     https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl
41   */
42  float a = x * (x + 0.0245786f) - 0.000090537f;
43  float b = x * (0.983729f * x + 0.4329510f) + 0.238081f;
44  return a / b;
45 }
46 
47 #define lerp(a,b,d)   ((a) * (1.0-d) + (b) * ((d)))
48 
aces_rrt_rgb(float rin,float gin,float bin,float * rout,float * gout,float * bout)49 static inline void aces_rrt_rgb (float rin, float gin, float bin, float *rout, float *gout, float *bout)
50 {
51   float r, g, b;
52 
53   r = aces_rrt (rin);
54   g = aces_rrt (gin);
55   b = aces_rrt (bin);
56   r = (rin);
57   g = (gin);
58   b = (bin);
59 
60 #if 0
61    /* this is not the proper glow + desaturate used by ACES RRT,
62       but does something similar
63     */
64 
65 #define THRESHOLD     0.05
66 #define THRESHOLD2    0.4
67 
68 
69   {
70   float gray;
71 
72   gray = (r+g+b) / 3.0;
73   if (gray > 1.0f) gray = 1.0f;
74 
75   if (gray < THRESHOLD)
76   {
77     float saturation = 1.0-(gray)/THRESHOLD;
78     r = lerp (r, gray, saturation);
79     g = lerp (g, gray, saturation);
80     b = lerp (b, gray, saturation);
81   }
82   else if (gray > THRESHOLD2)
83   {
84     float saturation = (gray - THRESHOLD2)/(1.0-THRESHOLD2);
85     r = lerp (r, gray, saturation);
86     g = lerp (g, gray, saturation);
87     b = lerp (b, gray, saturation);
88   }
89   }
90 #endif
91 
92   *rout = r;
93   *gout = g;
94   *bout = b;
95 }
96 
97 static gboolean
process(GeglOperation * op,void * in_buf,void * out_buf,glong samples,const GeglRectangle * roi,gint level)98 process (GeglOperation       *op,
99          void                *in_buf,
100          void                *out_buf,
101          glong                samples,
102          const GeglRectangle *roi,
103          gint                 level)
104 {
105   gfloat *in  = in_buf;
106   gfloat *out = out_buf;
107 
108   while (samples--)
109     {
110       aces_rrt_rgb (in[0], in[1], in[2],
111                   &out[0], &out[1], &out[2]);
112       out[3] = in[3];
113 
114       in += 4;
115       out+= 4;
116     }
117   return TRUE;
118 }
119 
120 static void
gegl_op_class_init(GeglOpClass * klass)121 gegl_op_class_init (GeglOpClass *klass)
122 {
123   GeglOperationClass            *operation_class;
124   GeglOperationPointFilterClass *point_filter_class;
125 
126   operation_class    = GEGL_OPERATION_CLASS (klass);
127   point_filter_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass);
128 
129   point_filter_class->process  = process;
130 
131   gegl_operation_class_set_keys (operation_class,
132     "name",        "gegl:aces-rrt",
133     "title",       _("ACES RRT"),
134     "categories" , "color:tonemapping",
135     "description",
136        _("HDR to SDR proofing filter/mapping curve that is an approximation of the ACES RRT (Reference Rendering Transform). When feeding scene-refereed imagery into this op, the result is suitable for display referred transform to sRGB or output display using regular ICC matric profiles as the ODT. Note that for the time being, this is a luminance only approximation of the ACES RRT; without desaturation of highlights and shadows nor red hue modifications."),
137     NULL);
138 }
139 
140 #endif
141