Added --createMultipleDisplays option and some usage instructions.
[OpenColorIO-Configs.git] / aces_1.0.0 / python / aces_ocio / aces_config.py
index a63acf7..16f91d5 100755 (executable)
@@ -21,6 +21,7 @@ from aces_ocio.colorspaces import red
 from aces_ocio.colorspaces import sony
 from aces_ocio.process import Process
 
+from aces_ocio.utilities import replace
 
 __author__ = 'ACES Developers'
 __copyright__ = 'Copyright (C) 2014 - 2015 - ACES Developers'
@@ -55,7 +56,9 @@ def set_config_default_roles(config,
                              matte_paint='',
                              reference='',
                              scene_linear='',
-                             texture_paint=''):
+                             texture_paint='',
+                             rendering='',
+                             compositing_linear=''):
     """
     Sets given *OCIO* configuration default roles.
 
@@ -102,11 +105,22 @@ def set_config_default_roles(config,
         config.setRole(ocio.Constants.ROLE_MATTE_PAINT, matte_paint)
     if reference:
         config.setRole(ocio.Constants.ROLE_REFERENCE, reference)
-    if scene_linear:
-        config.setRole(ocio.Constants.ROLE_SCENE_LINEAR, scene_linear)
     if texture_paint:
         config.setRole(ocio.Constants.ROLE_TEXTURE_PAINT, texture_paint)
 
+    # 'rendering' and 'compositing_linear' roles default to the 'scene_linear'
+    # value if not set explicitly
+    if rendering:
+        config.setRole("rendering", rendering)
+    if compositing_linear:
+        config.setRole("compositing_linear", compositing_linear)
+    if scene_linear:
+        config.setRole(ocio.Constants.ROLE_SCENE_LINEAR, scene_linear)
+        if not rendering:
+            config.setRole("rendering", scene_linear)
+        if not compositing_linear:
+            config.setRole("compositing_linear", scene_linear)
+
     return True
 
 
@@ -246,7 +260,9 @@ def add_colorspace_alias(config,
     """
 
     for alias_name in colorspace_alias_names:
-        if alias_name == colorspace.name.lower():
+        if alias_name.lower() == colorspace.name.lower():
+            print('Skipping alias creation for %s, alias %s, because lower cased names match' % (
+                colorspace.name, alias_name) )
             return
 
         print('Adding alias colorspace space %s, alias to %s' % (
@@ -264,7 +280,7 @@ def add_colorspace_alias(config,
             allocation=colorspace.allocation_type,
             allocationVars=colorspace.allocation_vars)
 
-        if not colorspace.to_reference_transforms:
+        if colorspace.to_reference_transforms:
             print('Generating To-Reference transforms')
             ocio_transform = generate_OCIO_transform(
                 [{'type': 'colorspace',
@@ -275,7 +291,7 @@ def add_colorspace_alias(config,
                 ocio_transform,
                 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
 
-        if not colorspace.from_reference_transforms:
+        if colorspace.from_reference_transforms:
             print('Generating From-Reference transforms')
             ocio_transform = generate_OCIO_transform(
                 [{'type': 'colorspace',
@@ -288,8 +304,14 @@ def add_colorspace_alias(config,
 
         config.addColorSpace(ocio_colorspace_alias)
 
+def colorspace_prefixed_name(colorspace):
+    prefix = colorspace.family.replace("/", " - ")
+    return "%s - %s" % (prefix, colorspace.name)
 
-def create_config(config_data, nuke=False):
+def create_config(config_data, 
+    aliases=False, 
+    prefix=False,
+    multiple_displays=False):
     """
     Object description.
 
@@ -304,6 +326,9 @@ def create_config(config_data, nuke=False):
          Return value description.
     """
 
+    prefixed_names = {}
+    alias_colorspaces = []
+
     # Creating the *OCIO* configuration.
     config = ocio.Config()
 
@@ -313,6 +338,14 @@ def create_config(config_data, nuke=False):
 
     # Defining the reference colorspace.
     reference_data = config_data['referenceColorSpace']
+
+    # Adding the color space Family into the name
+    # Helps with applications that present colorspaces as one long list
+    if prefix:
+        prefixed_name = colorspace_prefixed_name(reference_data)
+        prefixed_names[reference_data.name] = prefixed_name
+        reference_data.name = prefixed_name
+
     print('Adding the reference color space : %s' % reference_data.name)
 
     reference = ocio.ColorSpace(
@@ -328,15 +361,29 @@ def create_config(config_data, nuke=False):
     config.addColorSpace(reference)
 
     # Add alias
-    if not nuke:
+    if aliases:
         if reference_data.aliases != []:
-            add_colorspace_alias(config, reference_data,
-                                 reference_data, reference_data.aliases)
+            #add_colorspace_alias(config, reference_data,
+            #                     reference_data, reference_data.aliases)
+            # defer adding alias colorspaces until end. Helps with some applications
+            alias_colorspaces.append([reference_data, reference_data, reference_data.aliases])
+
 
     print("")
 
+    #print( "color spaces : %s" % [x.name for x in sorted(config_data['colorSpaces'])])
+
+    print('Adding the regular color spaces')
+
     # Creating the remaining colorspaces.
     for colorspace in sorted(config_data['colorSpaces']):
+        # Adding the color space Family into the name
+        # Helps with applications that present colorspaces as one long list
+        if prefix:
+            prefixed_name = colorspace_prefixed_name(colorspace)
+            prefixed_names[colorspace.name] = prefixed_name
+            colorspace.name = prefixed_name
+
         print('Creating new color space : %s' % colorspace.name)
 
         ocio_colorspace = ocio.ColorSpace(
@@ -370,19 +417,36 @@ def create_config(config_data, nuke=False):
         #
         # Add alias to normal colorspace, using compact name
         #
-        if not nuke:
+        if aliases:
             if colorspace.aliases != []:
-                add_colorspace_alias(config, reference_data,
-                                     colorspace, colorspace.aliases)
+                #add_colorspace_alias(config, reference_data,
+                #                     colorspace, colorspace.aliases)
+                # defer adding alias colorspaces until end. Helps with some applications
+                alias_colorspaces.append([reference_data, colorspace, colorspace.aliases])
 
         print('')
 
+    print("")
+
+    # We add these at the end as some applications use the order of the colorspaces
+    # definitions in the config to order the colorspaces in their selection lists.
+    # Other go alphabetically. This should keep the alias colorspaces out of the way
+    # for the apps that use the order of definition in the config.
+    print('Adding the alias colorspaces')
+    for reference, colorspace, aliases in alias_colorspaces:
+        add_colorspace_alias(config, reference, colorspace, aliases)
+
+    print("")
+
+    print('Adding the diplays and views')
+
     # Defining the *views* and *displays*.
     displays = []
     views = []
 
+
     # Defining a *generic* *display* and *view* setup.
-    if not nuke:
+    if multiple_displays:
         for display, view_list in config_data['displays'].iteritems():
             for view_name, colorspace in view_list.iteritems():
                 config.addDisplay(display, view_name, colorspace.name)
@@ -390,26 +454,39 @@ def create_config(config_data, nuke=False):
                     views.append(view_name)
             displays.append(display)
 
-    # Defining the *Nuke* specific set of *views* and *displays*.
     else:
-        display_name = 'ACES'
+        # Defining the set of *views* and *displays* useful in a *GUI* context.
+        #display_name = 'ACES'
+        display_name = config_data['roles']['scene_linear']
         displays.append(display_name)
 
         display_names = sorted(config_data['displays'])
+
+        # Make sure the default display is first
+        default_display = config_data['defaultDisplay']
+        display_names.insert(0, display_names.pop(display_names.index(default_display)))
+
         for display in display_names:
             view_list = config_data['displays'][display]
             for view_name, colorspace in view_list.iteritems():
                 if view_name == 'Output Transform':
-                    config.addDisplay(display_name, display, colorspace.name)
-                    if not (display in views):
-                        views.append(display)
+                    display_cleaned = replace(display, {')': '', '(': ''})
+                    config.addDisplay(display_name, display_cleaned, colorspace.name)
+                    if not (display_cleaned in views):
+                        views.append(display_cleaned)
 
         # Works with Nuke Studio and Mari, but not Nuke
         # display_name = 'Utility'
         # displays.append(display_name)
 
-        linear_display_space_name = config_data['linearDisplaySpace'].name
-        log_display_space_name = config_data['logDisplaySpace'].name
+        linear_display_space_name = config_data['roles']['scene_linear']
+        log_display_space_name = config_data['roles']['compositing_log']
+
+        # Find the newly-prefixed colorspace names
+        if prefix:
+            #print( prefixed_names )
+            linear_display_space_name = prefixed_names[linear_display_space_name]
+            log_display_space_name = prefixed_names[log_display_space_name]
 
         config.addDisplay(display_name, 'Linear', linear_display_space_name)
         views.append('Linear')
@@ -420,20 +497,54 @@ def create_config(config_data, nuke=False):
     config.setActiveDisplays(','.join(sorted(displays)))
     config.setActiveViews(','.join(views))
 
-    set_config_default_roles(
-        config,
-        color_picking=config_data['roles']['color_picking'],
-        color_timing=config_data['roles']['color_timing'],
-        compositing_log=config_data['roles']['compositing_log'],
-        data=config_data['roles']['data'],
-        default=config_data['roles']['default'],
-        matte_paint=config_data['roles']['matte_paint'],
-        reference=config_data['roles']['reference'],
-        scene_linear=config_data['roles']['scene_linear'],
-        texture_paint=config_data['roles']['texture_paint'])
+    print("")
+
+    print('Setting the roles')
+
+    if prefix:
+        set_config_default_roles(
+            config,
+            color_picking=prefixed_names[config_data['roles']['color_picking']],
+            color_timing=prefixed_names[config_data['roles']['color_timing']],
+            compositing_log=prefixed_names[config_data['roles']['compositing_log']],
+            data=prefixed_names[config_data['roles']['data']],
+            default=prefixed_names[config_data['roles']['default']],
+            matte_paint=prefixed_names[config_data['roles']['matte_paint']],
+            reference=prefixed_names[config_data['roles']['reference']],
+            scene_linear=prefixed_names[config_data['roles']['scene_linear']],
+            texture_paint=prefixed_names[config_data['roles']['texture_paint']])
+    else:
+        set_config_default_roles(
+            config,
+            color_picking=config_data['roles']['color_picking'],
+            color_timing=config_data['roles']['color_timing'],
+            compositing_log=config_data['roles']['compositing_log'],
+            data=config_data['roles']['data'],
+            default=config_data['roles']['default'],
+            matte_paint=config_data['roles']['matte_paint'],
+            reference=config_data['roles']['reference'],
+            scene_linear=config_data['roles']['scene_linear'],
+            texture_paint=config_data['roles']['texture_paint'])
+
+    print("")
 
+    # Make sure we didn't create a bad config
     config.sanityCheck()
 
+    # Reset the colorspace names back to their non-prefixed versions
+    if prefix:
+        # Build the reverse lookup
+        prefixed_names_inverse = {}
+        for original, prefixed in prefixed_names.iteritems():
+            prefixed_names_inverse[prefixed] = original
+
+        # Reet the reference colorspace name
+        reference_data.name = prefixed_names_inverse[reference_data.name]
+
+        # Reset the rest of the colorspace names
+        for colorspace in config_data['colorSpaces']:
+            colorspace.name = prefixed_names_inverse[colorspace.name]
+
     return config
 
 
@@ -476,14 +587,15 @@ def generate_LUTs(odt_info,
      aces_colorspaces,
      aces_displays,
      aces_log_display_space,
-     aces_roles) = aces.create_colorspaces(aces_ctl_directory,
-                                           lut_directory,
-                                           lut_resolution_1d,
-                                           lut_resolution_3d,
-                                           lmt_info,
-                                           odt_info,
-                                           shaper_name,
-                                           cleanup)
+     aces_roles,
+     aces_default_display) = aces.create_colorspaces(aces_ctl_directory,
+                                                     lut_directory,
+                                                     lut_resolution_1d,
+                                                     lut_resolution_3d,
+                                                     lmt_info,
+                                                     odt_info,
+                                                     shaper_name,
+                                                     cleanup)
 
     config_data['referenceColorSpace'] = aces_reference
     config_data['roles'] = aces_roles
@@ -494,6 +606,7 @@ def generate_LUTs(odt_info,
     for name, data in aces_displays.iteritems():
         config_data['displays'][name] = data
 
+    config_data['defaultDisplay'] = aces_default_display
     config_data['linearDisplaySpace'] = aces_reference
     config_data['logDisplaySpace'] = aces_log_display_space
 
@@ -737,6 +850,7 @@ def create_ACES_config(aces_ctl_directory,
                        lut_resolution_1d=4096,
                        lut_resolution_3d=64,
                        bake_secondary_LUTs=True,
+                       multiple_displays=False,
                        cleanup=True):
     """
     Creates the ACES configuration.
@@ -767,20 +881,14 @@ def create_ACES_config(aces_ctl_directory,
                                 lut_resolution_3d,
                                 cleanup)
 
-    print('Creating "generic" config')
-    config = create_config(config_data)
+    print('Creating config - with prefixes, with aliases')
+    config = create_config(config_data, 
+        prefix=True, aliases=True, multiple_displays=multiple_displays)
     print('\n\n\n')
 
     write_config(config,
                  os.path.join(config_directory, 'config.ocio'))
 
-    print('Creating "Nuke" config')
-    nuke_config = create_config(config_data, nuke=True)
-    print('\n\n\n')
-
-    write_config(nuke_config,
-                 os.path.join(config_directory, 'nuke_config.ocio'))
-
     if bake_secondary_LUTs:
         generate_baked_LUTs(odt_info,
                             shaper_name,
@@ -810,18 +918,32 @@ def main():
 
     import optparse
 
-    p = optparse.OptionParser(description='An OCIO config generation script',
-                              prog='createACESConfig',
-                              version='createACESConfig 0.1',
-                              usage='%prog [options]')
+    usage  = '%prog [options]\n'
+    usage += '\n'
+    usage += 'An OCIO config generation script for ACES 1.0\n'
+    usage += '\n'
+    usage += 'Command line examples'
+    usage += '\n'
+    usage += 'Create a GUI-friendly ACES 1.0 config with no secondary, baked LUTs : \n'
+    usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 --dontBakeSecondaryLUTs'
+    usage += '\n'
+    usage += 'Create a traditional ACES 1.0 config with secondary, baked LUTs : \n'
+    usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 --createMultipleDisplays'
+    usage += '\n'
+
+    p = optparse.OptionParser(description='',
+                              prog='create_aces_config',
+                              version='create_aces_config 1.0',
+                              usage=usage)
     p.add_option('--acesCTLDir', '-a', default=os.environ.get(
         ACES_OCIO_CTL_DIRECTORY_ENVIRON, None))
     p.add_option('--configDir', '-c', default=os.environ.get(
         ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON, None))
     p.add_option('--lutResolution1d', default=4096)
     p.add_option('--lutResolution3d', default=64)
-    p.add_option('--dontBakeSecondaryLUTs', action='store_true')
-    p.add_option('--keepTempImages', action='store_true')
+    p.add_option('--dontBakeSecondaryLUTs', action='store_true', default=False)
+    p.add_option('--keepTempImages', action='store_true', default=False)
+    p.add_option('--createMultipleDisplays', action='store_true', default=False)
 
     options, arguments = p.parse_args()
 
@@ -831,6 +953,7 @@ def main():
     lut_resolution_3d = int(options.lutResolution3d)
     bake_secondary_luts = not options.dontBakeSecondaryLUTs
     cleanup_temp_images = not options.keepTempImages
+    multiple_displays = options.createMultipleDisplays
 
     # TODO: Investigate the following statements.
     try:
@@ -857,8 +980,8 @@ def main():
                               lut_resolution_1d,
                               lut_resolution_3d,
                               bake_secondary_luts,
+                              multiple_displays,
                               cleanup_temp_images)
 
-
 if __name__ == '__main__':
     main()