Added the ability to write out 1D and 3D LUTs as CTL code
authorHaarm-Pieter Duiker <hpd1@duikerresearch.com>
Wed, 29 Apr 2015 17:40:29 +0000 (10:40 -0700)
committerHaarm-Pieter Duiker <hpd1@duikerresearch.com>
Wed, 29 Apr 2015 17:40:29 +0000 (10:40 -0700)
aces_1.0.0/python/aces_ocio/generate_lut.py

index 3debe06..66a0d6e 100755 (executable)
@@ -181,6 +181,92 @@ def write_CSP_1d(filename,
               fp.write('%s\n' % entry)
         fp.write('\n')
 
+def write_CTL_1d(filename, 
+                 from_min, 
+                 from_max, 
+                 data, 
+                 entries, 
+                 channels, 
+                 components=3):
+    """
+    Object description.
+
+    Parameters
+    ----------
+    parameter : type
+        Parameter description.
+
+    Returns
+    -------
+    type
+         Return value description.
+    """
+
+    # May want to use fewer components than there are channels in the data
+    # Most commonly used for single channel LUTs
+    components = min(3, components, channels)
+
+    with open(filename, 'w') as fp:
+        fp.write('// %d x %d LUT generated by "generate_lut"\n' % (
+          entries, components))
+        fp.write('\n')
+        fp.write('const float min1d = %3.9f;\n' % from_min)
+        fp.write('const float max1d = %3.9f;\n' % from_max)
+        fp.write('\n')
+
+        # Write LUT
+        if components == 1:
+          fp.write('const float lut[] = {\n')
+          for i in range(0, entries):
+              fp.write('%s' % data[i * channels])
+              if i != (entries-1):
+                fp.write(',')
+              fp.write('\n')
+          fp.write('};\n')
+          fp.write('\n')
+        else:
+          for j in range(components):
+            fp.write('const float lut%d[] = {\n' % j)
+            for i in range(0, entries):
+                fp.write('%s' % data[i * channels])
+                if i != (entries-1):
+                  fp.write(',')
+                fp.write('\n')
+            fp.write('};\n')
+            fp.write('\n')
+
+        fp.write('void main\n')
+        fp.write('(\n')
+        fp.write('  input varying float rIn,\n')
+        fp.write('  input varying float gIn,\n')
+        fp.write('  input varying float bIn,\n')
+        fp.write('  input varying float aIn,\n')
+        fp.write('  output varying float rOut,\n')
+        fp.write('  output varying float gOut,\n')
+        fp.write('  output varying float bOut,\n')
+        fp.write('  output varying float aOut\n')
+        fp.write(')\n')
+        fp.write('{\n')
+        fp.write('  float r = rIn;\n')
+        fp.write('  float g = gIn;\n')
+        fp.write('  float b = bIn;\n')
+        fp.write('\n')
+        fp.write('  // Apply LUT\n')
+        if components == 1:
+          fp.write('  r = lookup1D(lut, min1d, max1d, r);\n')
+          fp.write('  g = lookup1D(lut, min1d, max1d, g);\n')
+          fp.write('  b = lookup1D(lut, min1d, max1d, b);\n')
+        elif components == 3:
+          fp.write('  r = lookup1D(lut0, min1d, max1d, r);\n')
+          fp.write('  g = lookup1D(lut1, min1d, max1d, g);\n')
+          fp.write('  b = lookup1D(lut2, min1d, max1d, b);\n')          
+        fp.write('\n')
+        fp.write('  rOut = r;\n')
+        fp.write('  gOut = g;\n')
+        fp.write('  bOut = b;\n')
+        fp.write('  aOut = aIn;\n')
+        fp.write('}\n')
+
 def write_1d(filename, 
              from_min, 
              from_max, 
@@ -207,7 +293,8 @@ def write_1d(filename,
                                'flame'     : '3dl',
                                'icc'       : 'icc',
                                'houdini'   : 'lut',
-                               'lustre'    : '3dl'}
+                               'lustre'    : '3dl',
+                               'ctl'       : 'ctl'}
 
     if format in ocioFormatsToExtensions:
       if ocioFormatsToExtensions[format] == 'csp':
@@ -218,6 +305,14 @@ def write_1d(filename,
                      data_entries,
                      data_channels,
                      lut_components)
+      elif ocioFormatsToExtensions[format] == 'ctl':
+        write_CTL_1d(filename,
+                     from_min,
+                     from_max,
+                     data,
+                     data_entries,
+                     data_channels,
+                     lut_components)
     else:
       write_SPI_1d(filename,
                    from_min,