summaryrefslogtreecommitdiff
path: root/src/mari
diff options
context:
space:
mode:
Diffstat (limited to 'src/mari')
-rw-r--r--src/mari/1.4v1/README10
-rwxr-xr-xsrc/mari/1.4v1/_ocio_filter.py127
-rwxr-xr-xsrc/mari/1.4v1/_ocio_toolbar.py1279
-rwxr-xr-xsrc/mari/1.4v1/ocio.py789
-rw-r--r--src/mari/prototype/README3
-rw-r--r--src/mari/prototype/ociodisplay.py242
-rw-r--r--src/mari/prototype/ociofiletransform.py93
7 files changed, 2543 insertions, 0 deletions
diff --git a/src/mari/1.4v1/README b/src/mari/1.4v1/README
new file mode 100644
index 0000000..ecfdf18
--- /dev/null
+++ b/src/mari/1.4v1/README
@@ -0,0 +1,10 @@
+These files ship with Mari, and are *not* required to be manually installed.
+
+They are provided as a reference example of using the OCIO API to create a GPU
+monitor implementation in python.
+
+Media/Scripts/mari/utils/ocio.py
+Media/Scripts/mari/system/_ocio_toolbar.py
+Media/Scripts/mari/system/_ocio_filter.py
+
+All code in these examples is Copyright (c) 2011 The Foundry Visionmongers Ltd.
diff --git a/src/mari/1.4v1/_ocio_filter.py b/src/mari/1.4v1/_ocio_filter.py
new file mode 100755
index 0000000..e3c3bf3
--- /dev/null
+++ b/src/mari/1.4v1/_ocio_filter.py
@@ -0,0 +1,127 @@
+#-------------------------------------------------------------------------------
+# Post processing (color management) related Mari scripts
+# coding: utf-8
+# Copyright (c) 2011 The Foundry Visionmongers Ltd. All Rights Reserved.
+#-------------------------------------------------------------------------------
+
+import mari, time, PythonQt, os, math
+ocio = mari.utils.ocio
+
+##############################################################################################
+
+filter = None
+
+class OcioFilter():
+
+ #-----------------------------------------------------------------------------------------
+
+ def __init__(self):
+ # Default all members...
+ self._config_file_list = mari.FileList(ocio.config_file_list_default)
+ self._config = ocio.config_default
+ self._input_color_space = ocio.color_space_default
+ self._output_color_space = ocio.color_space_default
+ self._filter = mari.gl_render.createQuickApplyGLSL('Color Correction', '', '', 'ColorManager.png')
+ self._filter_cache_id = None
+ self._texture_cache_id = None
+ self._sampler_name = None
+
+ self._filter.setMetadata('ConfigPath', self._config_file_list)
+ self._filter.setMetadataDisplayName('ConfigPath', 'Configuration File')
+ self._filter.setMetadataDefault('ConfigPath', ocio.CONFIG_FILE_LIST_RESET)
+ self._filter.setMetadataFlags('ConfigPath', self._filter.METADATA_VISIBLE | self._filter.METADATA_EDITABLE)
+
+ color_spaces = [color_space.getName() for color_space in self._config.getColorSpaces()]
+
+ color_space_reset = ocio.COLOR_SPACE_RESET
+ if color_spaces.count(color_space_reset) == 0:
+ color_space_reset = color_spaces[0]
+
+ self._filter.setMetadata('InputColorSpace', self._input_color_space)
+ self._filter.setMetadataDisplayName('InputColorSpace', 'Input Color Space')
+ self._filter.setMetadataDefault('InputColorSpace', color_space_reset)
+ self._filter.setMetadataItemList('InputColorSpace', color_spaces)
+ self._filter.setMetadataFlags('InputColorSpace', self._filter.METADATA_VISIBLE | self._filter.METADATA_EDITABLE)
+
+ self._filter.setMetadata('OutputColorSpace', self._output_color_space)
+ self._filter.setMetadataDisplayName('OutputColorSpace', 'Output Color Space')
+ self._filter.setMetadataDefault('OutputColorSpace', color_space_reset)
+ self._filter.setMetadataItemList('OutputColorSpace', color_spaces)
+ self._filter.setMetadataFlags('OutputColorSpace', self._filter.METADATA_VISIBLE | self._filter.METADATA_EDITABLE)
+
+ mari.utils.connect(self._filter.metadataValueChanged, self._metadataValueChanged)
+
+ self._rebuildFilter()
+
+ #-----------------------------------------------------------------------------------------
+
+ def _metadataValueChanged(self, name, value):
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Metadata \'%s\' changed to \'%s\'' % (name, value))
+
+ if name == 'ConfigPath':
+ if value == self._config_file_list:
+ return
+ self._config_file_list = mari.FileList(value)
+ self._config = ocio.loadConfig(self._config_file_list.at(0), False)
+
+ color_spaces = [color_space.getName() for color_space in self._config.getColorSpaces()]
+
+ color_space_reset = ocio.COLOR_SPACE_RESET
+ if color_spaces.count(color_space_reset) == 0:
+ color_space_reset = color_spaces[0]
+
+ if color_spaces.count(self._input_color_space) == 0:
+ self._input_color_space = color_space_reset
+
+ if color_spaces.count(self._output_color_space) == 0:
+ self._output_color_space = color_space_reset
+
+ self._filter.setMetadataItemList('InputColorSpace', color_spaces)
+ self._filter.setMetadataItemList('OutputColorSpace', color_spaces)
+ self._filter.setMetadataDefault('InputColorSpace', color_space_reset)
+ self._filter.setMetadataDefault('OutputColorSpace', color_space_reset)
+ self._filter.setMetadata('InputColorSpace', self._input_color_space )
+ self._filter.setMetadata('OutputColorSpace', self._output_color_space)
+
+ elif name == 'InputColorSpace':
+ if value == self._input_color_space:
+ return
+ self._input_color_space = value
+
+ elif name == 'OutputColorSpace':
+ if value == self._output_color_space:
+ return
+ self._output_color_space = value
+
+ else:
+ return
+
+ self._rebuildFilter()
+
+ #-----------------------------------------------------------------------------------------
+
+ def _rebuildFilter(self):
+ input_color_space = self._config.getColorSpace(self._input_color_space)
+ if input_color_space is not None:
+ output_color_space = self._config.getColorSpace(self._output_color_space)
+ if output_color_space is not None:
+ processor = self._config.getProcessor(input_color_space, output_color_space)
+
+ self._filter_cache_id, self._texture_cache_id, self._sampler_name = ocio.buildProcessorFilter(
+ processor,
+ self._filter,
+ self._filter_cache_id,
+ self._texture_cache_id)
+
+ current_canvas = mari.canvases.current()
+ if current_canvas is not None:
+ current_canvas.repaint()
+
+##############################################################################################
+
+if mari.app.isRunning():
+ if not hasattr(mari.gl_render, 'createQuickApplyGLSL'):
+ printMessage(MessageType.ERROR, 'This version of Mari does not support the mari.gl_render.createQuickApplyGLSL API')
+
+ elif ocio is not None:
+ filter = OcioFilter()
diff --git a/src/mari/1.4v1/_ocio_toolbar.py b/src/mari/1.4v1/_ocio_toolbar.py
new file mode 100755
index 0000000..84afb68
--- /dev/null
+++ b/src/mari/1.4v1/_ocio_toolbar.py
@@ -0,0 +1,1279 @@
+#-------------------------------------------------------------------------------
+# Post processing (color management) related Mari scripts
+# coding: utf-8
+# Copyright (c) 2011 The Foundry Visionmongers Ltd. All Rights Reserved.
+#-------------------------------------------------------------------------------
+
+import mari, time, PythonQt, os, math
+QtGui = PythonQt.QtGui
+QtCore = PythonQt.QtCore
+ocio = mari.utils.ocio
+
+##############################################################################################
+
+GAIN_GROUP_MAX_WIDTH = 312
+FSTOP_MAX_WIDTH = 50
+EXPOSURE_MAX_WIDTH = 102
+GAIN_MAX_WIDTH = 80
+GAMMA_MAX_WIDTH = 200
+TOOLBAR_SPACING = 3
+
+toolbar = None
+
+class OcioToolBar():
+
+ #-----------------------------------------------------------------------------------------
+
+ def __init__(self):
+ # Default all members...
+ self._config_file_list = mari.FileList(ocio.config_file_list_default)
+ self._config = ocio.config_default
+ self._lut_file_list = mari.FileList(ocio.lut_file_list_default)
+ self._lut_extrapolate = ocio.lut_extrapolate_default
+ self._color_space = ocio.color_space_default
+ self._display = ocio.display_default
+ self._view = ocio.view_default
+ self._swizzle = ocio.swizzle_default
+ self._gain = ocio.gain_default
+ self._gamma = ocio.gamma_default
+
+ self._lut_filter = None
+ self._lut_filter_cache_id = None
+ self._lut_texture_cache_id = None
+ self._lut_sampler_name = None
+
+ self._display_filter = None
+ self._display_filter_cache_id = None
+ self._display_texture_cache_id = None
+ self._display_sampler_name = None
+
+ self._lut_extrapolate_widget = None
+ self._color_space_widget = None
+ self._display_widget = None
+ self._view_widget = None
+ self._swizzle_widget = None
+ self._fstop_widget = None
+ self._fstop_decrement_widget = None
+ self._fstop_increment_widget = None
+ self._gain_widget = None
+ self._exposure_widget = None
+ self._gain_reset_widget = None
+ self._gamma_widget = None
+ self._gamma_reset_widget = None
+
+ self._buildWidgets()
+ self._toggle_color_management_action.setEnabled(False)
+ self._enableWidgets(False)
+
+ # Enable/disable color management.
+ mari.gl_render.setPostProcessingEnabled(self.isColorManagementEnabled())
+
+ # *** IMPORTANT *** The post filter collection used to be called 'OpenColorIO' but was renamed to hide the fact
+ # we use OpenColorIO from our users. So as a temporary workaround we need to check for the old filter collection
+ # on startup and remove it if found.
+ delete_filter_collection = mari.gl_render.findPostFilterCollection('OpenColorIO')
+ if delete_filter_collection is not None:
+ mari.gl_render.deletePostFilterCollection(delete_filter_collection)
+
+ # Create the OCIO post filter collection if not present.
+ self._filter_collection = mari.gl_render.findPostFilterCollection('Color Space')
+ if self._filter_collection is None:
+ self._filter_collection = mari.gl_render.createPostFilterCollection('Color Space')
+ else:
+ self._filter_collection.clear()
+ self._filter_collection.setReadOnly(True)
+
+ self._lut_filter = self._filter_collection.createGLSL('LUT Transform')
+ if not self._lut_file_list.isEmpty() and not self._rebuildLUTFilter(self._lut_file_list.at(0)):
+ self._lut_file_list.clear()
+
+ self._display_filter = self._filter_collection.createGLSL('Display Transform')
+ self._rebuildDisplayFilter()
+
+ self._buildMetadata()
+
+ # Set the color management filter stack as the current.
+ mari.gl_render.setPostFilterCollection(self._filter_collection)
+
+ # Attach ourselves to the applications toolbar created signal so we can rebuild the toolbar when it's been
+ # destoyed.
+ mari.utils.connect(mari.app.toolBarsCreated, self._toolBarsCreated)
+
+ # Attach ourselves to the appropriate GL signals so we can enable and disable widgets.
+ mari.utils.connect(mari.gl_render.postProcessingEnabled, self._postProcessingEnabled)
+ mari.utils.connect(mari.gl_render.setCurrentPostFilterCollection, self._setCurrentPostFilterCollection)
+
+ # Attach ourselves to the appropriate project signals so we can load and save settings.
+ mari.utils.connect(mari.projects.openedProject, self._openedProject)
+ mari.utils.connect(mari.projects.aboutToSaveProject, self._aboutToSaveProject)
+ mari.utils.connect(mari.projects.projectClosed, self._closedProject)
+
+ # Update the UI to match the current project, if we have one.
+ current_project = mari.projects.current()
+ if current_project is not None:
+ self._openedProject(current_project)
+
+ #-----------------------------------------------------------------------------------------
+
+ def isColorManagementEnabled(self):
+ return self._toggle_color_management_action.isChecked()
+
+ #-----------------------------------------------------------------------------------------
+
+ def setLUTPath(self, value, update_metadata = True, force_shader_build = False):
+ if (self._lut_file_list.isEmpty() and value != '') or \
+ (not self._lut_file_list.isEmpty() and value == '') or \
+ (not self._lut_file_list.isEmpty() and value != self._lut_file_list.at(0)) \
+ :
+ if self._rebuildLUTFilter(value, force_shader_build):
+ self._lut_file_list.clear()
+ if value != '':
+ self._lut_file_list.append(value)
+ self._lut_file_list.setPickedFile(value)
+
+ self._clear_lut_action.setEnabled(True)
+ self._lut_extrapolate_widget.setEnabled(True)
+ self._lut_filter.setEnabled(True)
+ else:
+ self._clear_lut_action.setEnabled(False)
+ self._lut_extrapolate_widget.setEnabled(False)
+ self._lut_filter.setEnabled(False)
+
+ if update_metadata:
+ mari.utils.disconnect(self._lut_filter.metadataValueChanged, lutMetadataValueChanged)
+ self._lut_filter.setMetadata('File', self._lut_file_list)
+ mari.utils.connect(self._lut_filter.metadataValueChanged, lutMetadataValueChanged)
+
+ else:
+ # If this was a request via the metadata system we will need to put the value back to what it was
+ # before.
+ if not update_metadata:
+ mari.utils.disconnect(self._lut_filter.metadataValueChanged, lutMetadataValueChanged)
+ self._lut_filter.setMetadata('File', self._lut_file_list)
+ mari.utils.connect(self._lut_filter.metadataValueChanged, lutMetadataValueChanged)
+
+ return False
+
+ return True
+
+ #-----------------------------------------------------------------------------------------
+
+ def resetLUT(self):
+ if ocio.lut_file_list_default.isEmpty() or not self.setLUTPath(ocio.lut_file_list_default.at(0)):
+ self.setLUTPath('')
+
+ #-----------------------------------------------------------------------------------------
+
+ def selectLUT(self):
+ lut_path = mari.utils.misc.getOpenFileName(None,
+ 'Select LUT File',
+ '' if self._lut_file_list.isEmpty() else self._lut_file_list.at(0),
+ ocio.lutFileFilter(),
+ None,
+ 0)
+ if os.path.isfile(lut_path):
+ self.setLUTPath(lut_path)
+
+ #-----------------------------------------------------------------------------------------
+
+ def setExtrapolateEnabled(self, value, update_widget = True, update_metadata = True):
+ if value != self._lut_extrapolate:
+ self._lut_extrapolate = value
+
+ if update_widget:
+ block = self._lut_extrapolate_widget.blockSignals(True)
+ self._lut_extrapolate_widget.setChecked(self._lut_extrapolate)
+ self._lut_extrapolate_widget.blockSignals(block)
+
+ if update_metadata:
+ mari.utils.disconnect(self._lut_filter.metadataValueChanged, lutMetadataValueChanged)
+ self._lut_filter.setMetadata('Extrapolate', self._lut_extrapolate)
+ mari.utils.connect(self._lut_filter.metadataValueChanged, lutMetadataValueChanged)
+
+ if not self._rebuildLUTFilter(lut_path = '' if self._lut_file_list.isEmpty() else self._lut_file_list.at(0),
+ force_shader_build = True):
+ self.resetLUT()
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Changed extrapolate to \'%s\'' % self._lut_extrapolate)
+
+ #-----------------------------------------------------------------------------------------
+
+ def setConfigPath(self, value, update_metadata = True):
+ if self._config_file_list.isEmpty() or value != self._config_file_list.at(0):
+ config = ocio.loadConfig(value, True)
+ if config is not None:
+ self._config_file_list.clear()
+ self._config_file_list.append(value)
+ self._config_file_list.setPickedFile(value)
+
+ self._config = config
+
+ self._updateDisplayWidgets()
+ self._updateDisplayMetadata()
+
+ self._rebuildDisplayFilter()
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Changed config to \'%s\'' % self._config_file_list.at(0))
+
+ else:
+ # If this was a request via the metadata system we will need to put the value back to what it was
+ # before.
+ if not update_metadata:
+ mari.utils.disconnect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+ self._display_filter.setMetadata('ConfigPath', self._config_file_list)
+ mari.utils.connect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+
+ return False
+
+ return True
+
+ #-----------------------------------------------------------------------------------------
+
+ def selectConfig(self):
+ config_path = mari.utils.misc.getOpenFileName(None,
+ 'Select Configuration File',
+ '' if self._config_file_list.isEmpty() else self._config_file_list.at(0),
+ ocio.configFileFilter(),
+ None,
+ 0)
+ if os.path.isfile(config_path):
+ self.setConfigPath(config_path)
+
+ #-----------------------------------------------------------------------------------------
+
+ def setColorSpace(self, value, update_widget = True, update_metadata = True):
+ if value != self._color_space:
+ self._color_space = value
+
+ if update_widget:
+ block = self._color_space_widget.blockSignals(True)
+ index = self._color_space_widget.findText(self._color_space)
+ self._color_space_widget.setCurrentIndex(index)
+ self._color_space_widget.blockSignals(block)
+
+ if update_metadata:
+ mari.utils.disconnect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+ self._display_filter.setMetadata('InputColorSpace', self._color_space)
+ mari.utils.connect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+
+ self._rebuildDisplayFilter()
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Changed input color space to \'%s\'' % self._color_space)
+
+ #-----------------------------------------------------------------------------------------
+
+ def setDisplay(self, value, update_widget = True, update_metadata = True):
+ if value != self._display:
+ self._display = value
+
+ if update_widget:
+ block = self._display_widget.blockSignals(True)
+ index = self._display_widget.findText(self._display)
+ self._display_widget.setCurrentIndex(index)
+ self._display_widget.blockSignals(block)
+
+ if update_metadata:
+ mari.utils.disconnect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+ self._display_filter.setMetadata('Display', self._display)
+ mari.utils.connect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+
+ self.setView(self._config.getDefaultView(self._display), update_widget, update_metadata)
+
+ self._rebuildDisplayFilter()
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Changed display to \'%s\'' % self._display)
+
+ #-----------------------------------------------------------------------------------------
+
+ def setView(self, value, update_widget = True, update_metadata = True):
+ if value != self._view:
+ self._view = value
+
+ if update_widget:
+ block = self._view_widget.blockSignals(True)
+ index = self._view_widget.findText(self._view)
+ self._view_widget.setCurrentIndex(index)
+ self._view_widget.blockSignals(block)
+
+ if update_metadata:
+ mari.utils.disconnect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+ self._display_filter.setMetadata('View', self._view)
+ mari.utils.connect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+
+ self._rebuildDisplayFilter()
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Changed view to \'%s\'' % self._view)
+
+ #-----------------------------------------------------------------------------------------
+
+ def setSwizzle(self, value, update_widget = True, update_metadata = True):
+ if value != self._swizzle:
+ self._swizzle = value
+
+ if update_widget:
+ block = self._swizzle_widget.blockSignals(True)
+ index = self._swizzle_widget.findText(self._swizzle)
+ self._swizzle_widget.setCurrentIndex(index)
+ self._swizzle_widget.blockSignals(block)
+
+ if update_metadata:
+ mari.utils.disconnect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+ self._display_filter.setMetadata('Swizzle', self._swizzle)
+ mari.utils.connect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+
+ self._rebuildDisplayFilter()
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Changed swizzle to \'%s\'' % self._swizzle)
+
+ #-----------------------------------------------------------------------------------------
+
+ def setGain(self, value, update_widget = True, update_metadata = True):
+ if value != self._gain:
+ self._gain = value
+
+ if update_widget:
+ self._updateGainWidgets()
+
+ if update_metadata:
+ mari.utils.disconnect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+ self._display_filter.setMetadata('Gain', self._gain)
+ mari.utils.connect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+
+ self._rebuildDisplayFilter()
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Changed gain to \'%s\'' % self._gain)
+
+ #-----------------------------------------------------------------------------------------
+
+ def setGamma(self, value, update_widget = True, update_metadata = True):
+ if value != self._gamma:
+ self._gamma = value
+
+ if update_widget:
+ block = self._gamma_widget.blockSignals(True)
+ self._gamma_widget.setValue(self._gamma)
+ self._gamma_widget.blockSignals(block)
+
+ if update_metadata:
+ mari.utils.disconnect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+ self._display_filter.setMetadata('Gamma', self._gamma)
+ mari.utils.connect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+
+ self._rebuildDisplayFilter()
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Changed gamma to \'%s\'' % self._gamma)
+
+ #-----------------------------------------------------------------------------------------
+
+ def updateLUTSize(self):
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Updating LUT size...')
+
+ # Rebuild the LUT filter.
+ if self._lut_sampler_name is not None:
+ self._lut_filter.deleteTexture(self._lut_sampler_name)
+ self._lut_sampler_name = None
+
+ self._lut_filter_cache_id = None
+ self._lut_texture_cache_id = None
+
+ if not self._rebuildLUTFilter(lut_path = '' if self._lut_file_list.isEmpty() else self._lut_file_list.at(0),
+ force_shader_build = True):
+ self.resetLUT()
+
+ # Rebuild the display filter.
+ if self._display_sampler_name is not None:
+ self._display_filter.deleteTexture(self._display_sampler_name)
+ self._display_sampler_name = None
+
+ self._display_filter_cache_id = None
+ self._display_texture_cache_id = None
+
+ self._rebuildDisplayFilter()
+
+ #-----------------------------------------------------------------------------------------
+
+ def updateFStopCenter(self):
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Updating f-stop center...')
+
+ fstop = ocio.convertGainToFStop(self._gain)
+ self._updateFStopWidgetText(fstop)
+
+ #-----------------------------------------------------------------------------------------
+ # Widgets:
+ #-----------------------------------------------------------------------------------------
+
+ def _buildWidgets(self):
+ action_list = list()
+
+ self._toggle_color_management_action = self._addAction(
+ '/Mari/OpenColorIO/&Toggle Color Management',
+ 'mari.system._ocio_toolbar.toolbar._toggleColorManagement()',
+ 'ColorManager.png',
+ 'Toggle on/off color management',
+ 'Toggle color management')
+ self._toggle_color_management_action.setCheckable(True)
+ self._toggle_color_management_action.setChecked(ocio.enabled_default)
+ action_list.append('/Mari/OpenColorIO/&Toggle Color Management')
+
+ self._select_config_action = self._addAction(
+ '/Mari/OpenColorIO/&Select Config',
+ 'mari.system._ocio_toolbar.toolbar.selectConfig()',
+ 'LoadColorConfig.png',
+ 'Select color space configuration file',
+ 'Select config')
+ action_list.append('/Mari/OpenColorIO/&Select Config')
+
+ self._select_lut_action = self._addAction(
+ '/Mari/OpenColorIO/&Select LUT',
+ 'mari.system._ocio_toolbar.toolbar.selectLUT()',
+ 'LoadLookupTable.png',
+ 'Select LUT file',
+ 'Select LUT')
+ action_list.append('/Mari/OpenColorIO/&Select LUT')
+
+ self._clear_lut_action = self._addAction(
+ '/Mari/OpenColorIO/&Clear LUT',
+ 'mari.system._ocio_toolbar.toolbar._clearLUT()',
+ 'ClearLookupTable.png',
+ 'Clear current LUT',
+ 'Clear LUT')
+ action_list.append('/Mari/OpenColorIO/&Clear LUT')
+
+ mari.app.deleteToolBar('Color Space')
+ self._toolbar = mari.app.createToolBar('Color Space', True)
+ self._toolbar.addActionList(action_list, False)
+ self._toolbar.setLockedSlot(True)
+ self._toolbar.setSpacing(TOOLBAR_SPACING)
+
+ self._toolbar.insertSeparator('/Mari/OpenColorIO/&Select LUT')
+
+ # Extrapolate:
+ self._toolbar.addWidget(QtGui.QLabel('Extrapolate'))
+ self._lut_extrapolate_widget = QtGui.QCheckBox()
+ self._lut_extrapolate_widget.setToolTip('Extrapolate if outside LUT range');
+ self._lut_extrapolate_widget.setChecked(self._lut_extrapolate)
+ self._lut_extrapolate_widget.connect(
+ QtCore.SIGNAL('toggled(bool)'),
+ lambda value: self.setExtrapolateEnabled(value = value, update_widget = False, update_metadata = True))
+ self._toolbar.addWidget(self._lut_extrapolate_widget)
+
+ self._toolbar.addSeparator()
+
+ color_spaces = [color_space.getName() for color_space in self._config.getColorSpaces()]
+
+ # Color-Space:
+ self._color_space_widget = self._addComboBox(
+ 'Input Color Space',
+ color_spaces,
+ self._color_space,
+ ocio.color_space_default,
+ lambda value: self.setColorSpace(value = value, update_widget = False, update_metadata = True))
+ self._color_space = self._color_space_widget.currentText
+
+ # Display:
+ self._display_widget = self._addComboBox(
+ 'Display Device',
+ self._config.getDisplays(),
+ self._display,
+ ocio.display_default,
+ lambda value: self.setDisplay(value = value, update_widget = False, update_metadata = True))
+ self._display = self._display_widget.currentText
+
+ # View:
+ self._view_widget = self._addComboBox(
+ 'View Transform',
+ self._config.getViews(self._display),
+ self._view,
+ ocio.view_default,
+ lambda value: self.setView(value = value, update_widget = False, update_metadata = True))
+ self._view = self._view_widget.currentText
+
+ # Swizzle:
+ self._swizzle_widget = self._addComboBox(
+ 'Component',
+ ocio.SWIZZLE_TYPES,
+ self._swizzle,
+ ocio.swizzle_default,
+ lambda value: self.setSwizzle(value = value, update_widget = False, update_metadata = True))
+ self._swizzle = self._swizzle_widget.currentText
+
+ # Gain Group:
+ group_widget, layout = self._addWidgetGroup()
+ group_widget.setMaximumWidth(GAIN_GROUP_MAX_WIDTH)
+
+ layout.addWidget(QtGui.QLabel('Gain'))
+
+ # F-Stop:
+ subgroup_widget = QtGui.QWidget()
+ layout.addWidget(subgroup_widget)
+
+ sublayout = QtGui.QHBoxLayout()
+ sublayout.setSpacing(0)
+ sublayout.setMargin(0)
+ subgroup_widget.setLayout(sublayout)
+
+ exposure = ocio.convertGainToExposure(self._gain)
+ fstop = ocio.convertExposureToFStop(exposure)
+ scale = (exposure - ocio.EXPOSURE_MIN) / ocio.EXPOSURE_DELTA
+ widget_max = int(math.ceil(ocio.EXPOSURE_DELTA / ocio.FSTOP_STEP_SIZE))
+ widget_value = scale * widget_max
+ self._fstop_widget = mari.LineEdit()
+ self._fstop_widget.setRange(widget_max)
+ self._fstop_widget.setMaximumWidth(FSTOP_MAX_WIDTH)
+ self._fstop_widget.setReadOnly(True)
+ self._updateFStopWidgetText(fstop)
+ self._fstop_widget.setValue(widget_value)
+ mari.utils.connect(self._fstop_widget.movedMouse, self._fstopMovedMouse)
+ self._fstop_widget.addToLayout(sublayout)
+
+ self._fstop_decrement_widget = self._addSmallButtom(
+ sublayout,
+ '-',
+ 'Decrease gain 1/2 stop',
+ lambda: self.setGain(ocio.convertExposureToGain(ocio.convertGainToExposure(self._gain) - 0.5)))
+ self._fstop_increment_widget = self._addSmallButtom(
+ sublayout,
+ '+',
+ 'Increase gain 1/2 stop',
+ lambda: self.setGain(ocio.convertExposureToGain(ocio.convertGainToExposure(self._gain) + 0.5)))
+
+ ocio.registerLUTSizeChanged(self.updateLUTSize)
+ ocio.registerFStopCenterChanged(self.updateFStopCenter)
+
+ # Gain:
+ subgroup_widget = QtGui.QWidget()
+ layout.addWidget(subgroup_widget)
+
+ sublayout = QtGui.QHBoxLayout()
+ sublayout.setSpacing(3)
+ sublayout.setMargin(0)
+ subgroup_widget.setLayout(sublayout)
+
+ widget_max = int(math.ceil(ocio.EXPOSURE_DELTA / ocio.EXPOSURE_STEP_SIZE))
+ widget_value = scale * widget_max
+ self._gain_widget = mari.LineEdit()
+ self._gain_widget.setRange(widget_max)
+ self._gain_widget.addFloatValidator(ocio.GAIN_MIN, ocio.GAIN_MAX, ocio.GAIN_PRECISION)
+ self._gain_widget.setMaximumWidth(GAIN_MAX_WIDTH)
+ self._updateGainWidgetText()
+ self._gain_widget.setValue(widget_value)
+ mari.utils.connect(
+ self._gain_widget.lostFocus,
+ lambda: self.setGain(max(min(float(self._gain_widget.text()), ocio.GAIN_MAX), ocio.GAIN_MIN)))
+ mari.utils.connect(self._gain_widget.movedMouse, self._gainMovedMouse)
+ self._gain_widget.addToLayout(sublayout)
+
+ # Exposure:
+ self._exposure_widget = QtGui.QSlider()
+ self._exposure_widget.orientation = 1
+ self._exposure_widget.setMaximum(widget_max)
+ self._exposure_widget.setValue(widget_value)
+ self._exposure_widget.setMinimumWidth(EXPOSURE_MAX_WIDTH)
+ self._exposure_widget.setMaximumWidth(EXPOSURE_MAX_WIDTH)
+ mari.utils.connect(self._exposure_widget.valueChanged, self._exposureChanged)
+ sublayout.addWidget(self._exposure_widget)
+
+ self._gain_reset_widget = self._addSmallButtom(
+ layout,
+ 'R',
+ 'Reset gain to default',
+ lambda: self.setGain(value = ocio.GAIN_RESET, update_widget = True, update_metadata = True))
+
+ # Gamma:
+ group_widget, layout = self._addWidgetGroup()
+ group_widget.setMaximumWidth(GAMMA_MAX_WIDTH)
+
+ layout.addWidget(QtGui.QLabel('Gamma'))
+
+ self._gamma_widget = mari.FloatSlider()
+ self._gamma_widget.setRange(ocio.GAMMA_MIN, ocio.GAMMA_MAX)
+ self._gamma_widget.setStepSize(ocio.GAMMA_STEP_SIZE)
+ self._gamma_widget.setPrecision(ocio.GAMMA_PRECISION)
+ self._gamma_widget.setValue(self._gamma)
+ mari.utils.connect(
+ self._gamma_widget.valueChanged,
+ lambda value: self.setGamma(value = value, update_widget = False, update_metadata = True))
+ self._gamma_widget.addToLayout(layout)
+
+ self._gamma_reset_widget = self._addSmallButtom(
+ layout,
+ 'R',
+ 'Reset gamma to default',
+ lambda: self.setGamma(value = ocio.GAMMA_RESET, update_widget = True, update_metadata = True))
+
+ #-----------------------------------------------------------------------------------------
+
+ def _updateDisplayWidgets(self):
+ color_spaces = [color_space.getName() for color_space in self._config.getColorSpaces()]
+
+ self._updateComboBox(self._color_space_widget, color_spaces, self._color_space, ocio.color_space_default)
+ self._color_space = self._color_space_widget.currentText
+
+ self._updateComboBox(self._display_widget, self._config.getDisplays(), self._display, ocio.display_default)
+ self._display = self._display_widget.currentText
+
+ self._updateComboBox(self._view_widget, self._config.getViews(self._display), self._view, ocio.view_default)
+ self._view = self._view_widget.currentText
+
+ self._updateComboBox(self._swizzle_widget, ocio.SWIZZLE_TYPES, self._swizzle, ocio.swizzle_default)
+ self._swizzle = self._swizzle_widget.currentText
+
+ self._updateGainWidgets()
+
+ self._gamma_widget.setValue(self._gamma)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _enableWidgets(self, enable):
+ self._select_config_action.setEnabled(enable)
+ self._select_lut_action.setEnabled(enable)
+ lut_enable = enable and not self._lut_file_list.isEmpty()
+ self._clear_lut_action.setEnabled(lut_enable)
+ self._lut_extrapolate_widget.setEnabled(lut_enable)
+
+ self._color_space_widget.setEnabled(enable)
+ self._display_widget.setEnabled(enable)
+ self._view_widget.setEnabled(enable)
+ self._swizzle_widget.setEnabled(enable)
+
+ self._fstop_widget.setEnabled(enable)
+ self._fstop_decrement_widget.setEnabled(enable)
+ self._fstop_increment_widget.setEnabled(enable)
+ self._gain_widget.setEnabled(enable)
+ self._exposure_widget.setEnabled(enable)
+ self._gain_reset_widget.setEnabled(enable)
+
+ self._gamma_widget.setEnabled(enable)
+ self._gamma_reset_widget.setEnabled(enable)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _addAction(self, identifier, command, icon_filename, tip, whats_this):
+ action = mari.actions.find(identifier)
+ if action is None:
+ action = mari.actions.create(identifier, command)
+
+ icon_path = mari.resources.path(mari.resources.ICONS) + '/' + icon_filename
+ action.setIconPath(icon_path)
+
+ action.setStatusTip(tip)
+ action.setToolTip(tip)
+ action.setWhatsThis(whats_this)
+
+ return action
+
+ #-----------------------------------------------------------------------------------------
+
+ def _addWidgetGroup(self):
+ group_widget = QtGui.QWidget()
+ self._toolbar.addWidget(group_widget)
+
+ layout = QtGui.QHBoxLayout()
+ layout.setSpacing(1)
+ layout.setMargin(1)
+ group_widget.setLayout(layout)
+
+ return (group_widget, layout)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _addComboBox(self, label, items, value, default, value_changed, *args):
+ group_widget, layout = self._addWidgetGroup()
+
+ layout.addWidget(QtGui.QLabel(label))
+
+ widget = QtGui.QComboBox()
+ self._updateComboBox(widget, items, value, default)
+ widget.connect(QtCore.SIGNAL('currentIndexChanged(const QString &)'), value_changed)
+ layout.addWidget(widget)
+
+ return widget
+
+ #-----------------------------------------------------------------------------------------
+
+ def _updateComboBox(self, widget, items, value, default):
+ block = widget.blockSignals(True)
+
+ widget.clear()
+ for item in items:
+ widget.addItem(item)
+
+ if items.count(value) != 0:
+ widget.setCurrentIndex(items.index(value))
+ elif items.count(default) != 0:
+ widget.setCurrentIndex(items.index(default))
+
+ widget.blockSignals(block)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _addSmallButtom(self, layout, label, tool_tip, value_changed, *args):
+ widget = QtGui.QPushButton(label);
+ widget.setToolTip(tool_tip);
+ widget.setFixedHeight(16);
+ widget.setFixedWidth(16);
+ widget.connect(QtCore.SIGNAL('released()'), value_changed)
+ layout.addWidget(widget);
+
+ return widget
+
+ #-----------------------------------------------------------------------------------------
+
+ def _convertFStopWidgetValueToGain(self, value):
+ widget_max = int(math.ceil(ocio.EXPOSURE_DELTA / ocio.FSTOP_STEP_SIZE))
+ scale = float(value) / float(widget_max)
+ exposure = ocio.EXPOSURE_MIN + scale * ocio.EXPOSURE_DELTA
+ return ocio.convertExposureToGain(exposure)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _convertExposureWidgetValueToGain(self, value):
+ widget_max = int(math.ceil(ocio.EXPOSURE_DELTA / ocio.EXPOSURE_STEP_SIZE))
+ scale = float(value) / float(widget_max)
+ exposure = ocio.EXPOSURE_MIN + scale * ocio.EXPOSURE_DELTA
+ return ocio.convertExposureToGain(exposure)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _updateFStopWidgetText(self, fstop):
+ block = self._fstop_widget.blockSignals(True)
+ if fstop < 10.0:
+ # Floor the value to one decimal place and only display the decimal point if necessary
+ text = '%f' % fstop
+ index = text.index('.')
+ if text[index + 1] == '0':
+ text = text[:index]
+ else:
+ text = text[:index + 2]
+ self._fstop_widget.setText('f/%s' % text)
+ else:
+ self._fstop_widget.setText('f/%d' % int(fstop))
+ self._fstop_widget.blockSignals(block)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _updateGainWidgetText(self):
+ block = self._gain_widget.blockSignals(True)
+ self._gain_widget.setText(('%.' + ('%d' % ocio.GAIN_PRECISION) + 'f') % self._gain)
+ self._gain_widget.home(False)
+ self._gain_widget.blockSignals(block)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _updateGainWidgets(self):
+ exposure = ocio.convertGainToExposure(self._gain)
+ fstop = ocio.convertExposureToFStop(exposure)
+ self._updateFStopWidgetText(fstop)
+
+ scale = (exposure - ocio.EXPOSURE_MIN) / ocio.EXPOSURE_DELTA
+ widget_max = int(math.ceil(ocio.EXPOSURE_DELTA / ocio.FSTOP_STEP_SIZE))
+ widget_value = int(round(scale * float(widget_max)))
+ block = self._fstop_widget.blockSignals(True)
+ self._fstop_widget.setValue(widget_value)
+ self._fstop_widget.blockSignals(block)
+
+ self._updateGainWidgetText()
+
+ widget_max = int(math.ceil(ocio.EXPOSURE_DELTA / ocio.EXPOSURE_STEP_SIZE))
+ widget_value = int(round(scale * float(widget_max)))
+ block = self._gain_widget.blockSignals(True)
+ self._gain_widget.setValue(widget_value)
+ self._gain_widget.blockSignals(block)
+ block = self._exposure_widget.blockSignals(True)
+ self._exposure_widget.setValue(widget_value)
+ self._exposure_widget.blockSignals(block)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _toggleColorManagement(self):
+ enabled = self.isColorManagementEnabled()
+ mari.gl_render.setPostProcessingEnabled(enabled)
+ self._enableWidgets(enabled)
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Toggled color management to \'%s\'' % ('on' if enabled else 'off'))
+
+ #-----------------------------------------------------------------------------------------
+
+ def _clearLUT(self):
+ self.setLUTPath('')
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Cleared lut')
+
+ #-----------------------------------------------------------------------------------------
+
+ def _fstopMovedMouse(self, value):
+ self.setGain(self._convertFStopWidgetValueToGain(float(value)), False)
+
+ exposure = ocio.convertGainToExposure(self._gain)
+ fstop = ocio.convertExposureToFStop(exposure)
+ self._updateFStopWidgetText(fstop)
+
+ self._updateGainWidgetText()
+
+ widget_max = int(math.ceil(ocio.EXPOSURE_DELTA / ocio.EXPOSURE_STEP_SIZE))
+ scale = (exposure - ocio.EXPOSURE_MIN) / ocio.EXPOSURE_DELTA
+ value = int(round(scale * float(widget_max)))
+ self._gain_widget.setValue(value)
+
+ value = max(min(value, widget_max), 0)
+ self._exposure_widget.setValue(value)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _gainMovedMouse(self, value):
+ self.setGain(self._convertExposureWidgetValueToGain(float(value)), False)
+
+ self._updateGainWidgetText()
+
+ widget_max = int(math.ceil(ocio.EXPOSURE_DELTA / ocio.EXPOSURE_STEP_SIZE))
+ value = max(min(value, widget_max), 0)
+ self._exposure_widget.setValue(value)
+
+ exposure = ocio.convertGainToExposure(self._gain)
+ fstop = ocio.convertExposureToFStop(exposure)
+ self._updateFStopWidgetText(fstop)
+
+ scale = (exposure - ocio.EXPOSURE_MIN) / ocio.EXPOSURE_DELTA
+ widget_max = int(math.ceil(ocio.EXPOSURE_DELTA / ocio.FSTOP_STEP_SIZE))
+ value = int(round(scale * float(widget_max)))
+ self._fstop_widget.setValue(value)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _exposureChanged(self, value):
+ self.setGain(value = self._convertExposureWidgetValueToGain(float(value)),
+ update_widget = False,
+ update_metadata = True)
+
+ self._updateGainWidgetText()
+
+ self._gain_widget.setValue(value)
+
+ exposure = ocio.convertGainToExposure(self._gain)
+ fstop = ocio.convertExposureToFStop(exposure)
+ self._updateFStopWidgetText(fstop)
+
+ scale = (exposure - ocio.EXPOSURE_MIN) / ocio.EXPOSURE_DELTA
+ widget_max = int(math.ceil(ocio.EXPOSURE_DELTA / ocio.FSTOP_STEP_SIZE))
+ value = int(round(scale * float(widget_max)))
+ self._fstop_widget.setValue(value)
+
+ #-----------------------------------------------------------------------------------------
+ # Metadata:
+ #-----------------------------------------------------------------------------------------
+
+ def _buildMetadata(self):
+ # LUT:
+ # ---
+ mari.utils.connect(self._lut_filter.metadataValueChanged, lutMetadataValueChanged)
+ self._updateLUTMetadata()
+
+ flags = self._lut_filter.METADATA_VISIBLE | self._lut_filter.METADATA_EDITABLE
+ self._lut_filter.setMetadataFlags('File', flags)
+
+ self._lut_filter.setMetadataFlags('Extrapolate', flags)
+
+ # Display:
+ # -------
+ mari.utils.connect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+ self._updateDisplayMetadata()
+
+ self._display_filter.setMetadataDisplayName('ConfigPath', 'Configuration File')
+ flags = self._display_filter.METADATA_VISIBLE | self._display_filter.METADATA_EDITABLE
+ self._display_filter.setMetadataFlags('ConfigPath', flags)
+
+ self._display_filter.setMetadataDisplayName('InputColorSpace', 'Input Color Space')
+ self._display_filter.setMetadataFlags('InputColorSpace', flags)
+
+ self._display_filter.setMetadataDisplayName('Display', 'Display Device')
+ self._display_filter.setMetadataFlags('Display', flags)
+
+ self._display_filter.setMetadataDisplayName('View', 'View Transform')
+ self._display_filter.setMetadataFlags('View', flags)
+
+ self._display_filter.setMetadataDisplayName('Swizzle', 'Component')
+ self._display_filter.setMetadataFlags('Swizzle', flags)
+
+ self._display_filter.setMetadataDefault('Gain', ocio.GAIN_RESET)
+ self._display_filter.setMetadataRange('Gain', ocio.GAIN_MIN, ocio.GAIN_MAX)
+ self._display_filter.setMetadataStep('Gain', ocio.GAIN_STEP_SIZE)
+ self._display_filter.setMetadataFlags('Gain', flags)
+
+ self._display_filter.setMetadataDefault('Gamma', ocio.GAMMA_RESET)
+ self._display_filter.setMetadataRange('Gamma', ocio.GAMMA_MIN, ocio.GAMMA_MAX)
+ self._display_filter.setMetadataStep('Gamma', ocio.GAMMA_STEP_SIZE)
+ self._display_filter.setMetadataFlags('Gamma', flags)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _updateLUTMetadata(self):
+ mari.utils.disconnect(self._lut_filter.metadataValueChanged, lutMetadataValueChanged)
+
+ self._lut_filter.setMetadata('File', self._lut_file_list)
+
+ self._lut_filter.setMetadata('Extrapolate', self._lut_extrapolate)
+
+ mari.utils.connect(self._lut_filter.metadataValueChanged, lutMetadataValueChanged)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _updateDisplayMetadata(self):
+ mari.utils.disconnect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+
+ self._display_filter.setMetadata('ConfigPath', self._config_file_list)
+
+ color_spaces = [color_space.getName() for color_space in self._config.getColorSpaces()]
+
+ self._display_filter.setMetadata('InputColorSpace', self._color_space)
+ self._display_filter.setMetadataItemList('InputColorSpace', color_spaces)
+
+ self._display_filter.setMetadata('Display', self._display)
+ self._display_filter.setMetadataItemList('Display', self._config.getDisplays())
+
+ self._display_filter.setMetadata('View', self._view)
+ self._display_filter.setMetadataItemList('View', self._config.getViews(self._display))
+
+ self._display_filter.setMetadata('Swizzle', self._swizzle)
+ self._display_filter.setMetadataItemList('Swizzle', ocio.SWIZZLE_TYPES)
+
+ self._display_filter.setMetadata('Gain', self._gain)
+
+ self._display_filter.setMetadata('Gamma', self._gain)
+
+ mari.utils.connect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+
+
+ #-----------------------------------------------------------------------------------------
+ # External Connections:
+ #-----------------------------------------------------------------------------------------
+
+ def _openedProject(self, project):
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Loading settings for project \'%s\'' % project.name())
+
+ # Load the settings stored as metadata on the project...
+
+ # General:
+ # -------
+
+ self._toggle_color_management_action.setEnabled(True)
+ self._toggle_color_management_action.setChecked(project.metadata('ColorEnabled') if project.hasMetadata('ColorEnabled') else ocio.enabled_default)
+
+ # Enable/disable color management (MUST be done after modifications to 'self._toggle_color_management_action'.
+ mari.gl_render.setPostProcessingEnabled(self.isColorManagementEnabled())
+
+ filter_collection = None
+ if project.hasMetadata('ColorProfile'):
+ # *** IMPORTANT *** The post filter collection used to be called 'OpenColorIO' but was renamed to hide the
+ # fact we use OpenColorIO from our users. So as a temporary workaround we need to check for the old filter
+ # collection correct for it.
+ name = project.metadata('ColorProfile')
+ if name == 'OpenColorIO':
+ name = 'Color Space'
+ filter_collection = mari.gl_render.findPostFilterCollection(name)
+
+ # Default the color management filter stack if the working one doesn't exist.
+ if filter_collection is None:
+ filter_collection = mari.gl_render.findPostFilterCollection(ocio.profile_default)
+
+ mari.gl_render.setPostFilterCollection(filter_collection)
+
+ # LUT:
+ # ---
+
+ lut_extrapolate = project.metadata('OcioLutExtrapolate') if project.hasMetadata('OcioLutExtrapolate') else ocio.lut_extrapolate_default
+ force_shader_build = lut_extrapolate != self._lut_extrapolate
+ self._lut_extrapolate = lut_extrapolate
+ self._lut_extrapolate_widget.setChecked(self._lut_extrapolate)
+
+ if project.hasMetadata('OcioLutPath'):
+ lut_path = ocio.buildLoadPath(project.metadata('OcioLutPath'))
+ if not self.setLUTPath(value = lut_path, update_metadata = True, force_shader_build = force_shader_build):
+ self.resetLUT()
+ else:
+ self.resetLUT()
+
+ # Display:
+ # -------
+
+ self._color_space = project.metadata( 'OcioColorSpace') if project.hasMetadata('OcioColorSpace') else ocio.color_space_default
+ self._display = project.metadata( 'OcioDisplay') if project.hasMetadata( 'OcioDisplay') else ocio.display_default
+ self._view = project.metadata( 'OcioView') if project.hasMetadata( 'OcioView') else ocio.view_default
+ self._swizzle = project.metadata( 'OcioSwizzle') if project.hasMetadata( 'OcioSwizzle') else ocio.swizzle_default
+ self._gain = max(min(project.metadata('OcioGain'),
+ ocio.GAIN_MAX),
+ ocio.GAIN_MIN) if project.hasMetadata( 'OcioGain') else ocio.gain_default
+ self._gamma = project.metadata( 'OcioGamma') if project.hasMetadata( 'OcioGamma') else ocio.gamma_default
+
+ # Attempt to load a configuration file...
+ self._config_file_list.clear()
+ self._config = None
+
+ # 1. Environment variable.
+ config_path = os.getenv('OCIO')
+ if config_path is not None:
+ self.setConfigPath(config_path)
+
+ # 2. Project setting.
+ if self._config is None and project.hasMetadata('OcioConfigPath'):
+ self.setConfigPath(ocio.buildLoadPath(project.metadata('OcioConfigPath')))
+
+ # 3. Use the default if nothing was found.
+ if self._config is None:
+ self._config_file_list = mari.FileList(ocio.config_file_list_default)
+ self._config = ocio.config_default
+
+ self._updateDisplayWidgets()
+ self._rebuildDisplayFilter()
+
+ self._enableWidgets(filter_collection.name() == 'Color Space' and self._toggle_color_management_action.isChecked())
+ self._updateLUTMetadata()
+ self._updateDisplayMetadata()
+
+ self._printLog()
+
+ #-----------------------------------------------------------------------------------------
+
+ def _aboutToSaveProject(self, project):
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Saving settings for project \'%s\'' % project.name())
+
+ # Store the settings as metadata on the project.
+ project.setMetadata( 'ColorEnabled', self.isColorManagementEnabled())
+ filter_collection = mari.gl_render.currentPostFilterCollection()
+ if filter_collection is not None:
+ project.setMetadata( 'ColorProfile', filter_collection.name())
+ project.setMetadata('OcioLutExtrapolate', self._lut_extrapolate)
+ project.setMetadata( 'OcioLutPath', '' if self._lut_file_list.isEmpty() else ocio.buildSavePath(self._lut_file_list.at(0)))
+ if os.getenv('OCIO') is None:
+ project.setMetadata('OcioConfigPath', '' if self._config_file_list.isEmpty() else ocio.buildSavePath(self._config_file_list.at(0)))
+ project.setMetadata( 'OcioColorSpace', self._color_space)
+ project.setMetadata( 'OcioDisplay', self._display)
+ project.setMetadata( 'OcioView', self._view)
+ project.setMetadata( 'OcioSwizzle', self._swizzle)
+ project.setMetadata( 'OcioGain', self._gain)
+ project.setMetadata( 'OcioGamma', self._gamma)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _closedProject(self):
+ self._toggle_color_management_action.setEnabled(False)
+ self._enableWidgets(False)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _toolBarsCreated(self):
+ # Things like deleting Mari's configuration file and reseting the layout to the default will destroy the toolbar
+ # so we need to detect if this is the case and rebuild it!
+ toolbar = mari.app.findToolBar('Color Space')
+ if toolbar is None:
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Rebuilding missing toolbar...')
+ self._buildWidgets()
+
+ #-----------------------------------------------------------------------------------------
+
+ def _postProcessingEnabled(self, enabled):
+ self._toggle_color_management_action.setChecked(enabled)
+
+ # Only enable or disable UI if we have a current project.
+ current_project = mari.projects.current()
+ if current_project is not None:
+ self._enableWidgets(enabled)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _setCurrentPostFilterCollection(self):
+ # Only enable or disable UI if we have a current project.
+ current_project = mari.projects.current()
+ if current_project is not None:
+ filter_collection = mari.gl_render.currentPostFilterCollection()
+ if filter_collection is None or filter_collection.name() != 'Color Space':
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Disabling OpenColorIO')
+ self._enableWidgets(False)
+ else:
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Enabling OpenColorIO')
+ self._enableWidgets(True)
+
+ #-----------------------------------------------------------------------------------------
+ # Filter:
+ #-----------------------------------------------------------------------------------------
+
+ def _rebuildLUTFilter(self, lut_path, force_shader_build = False):
+ if lut_path == '':
+ self._lut_filter.setDefinitionsSnippet('')
+ self._lut_filter.setBodySnippet('')
+
+ if self._lut_sampler_name is not None:
+ self._lut_filter.deleteTexture(self._lut_sampler_name)
+ self._lut_sampler_name = None
+
+ self._lut_filter_cache_id = None
+ self._lut_texture_cache_id = None
+
+ else:
+ # There is a chance this is a bad file so we need to guard against it.
+ try:
+ self._lut_filter_cache_id, self._lut_texture_cache_id, self._lut_sampler_name = ocio.buildLUTFilter(
+ self._config,
+ lut_path,
+ self._lut_filter,
+ self._lut_filter_cache_id,
+ self._lut_texture_cache_id,
+ self._lut_extrapolate,
+ force_shader_build)
+
+ except Exception, e:
+ message = 'Failed to load LUT file \'%s\' due to \'%s\'' % (lut_path, e)
+ ocio.printMessage(ocio.MessageType.ERROR, '%s' % message)
+ if not mari.app.inTerminalMode():
+ mari.utils.misc.message(message, 'Color Space', 1024, 2)
+
+ return False
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Changed LUT to \'%s\'' % lut_path)
+
+ return True
+
+ #-----------------------------------------------------------------------------------------
+
+ def _rebuildDisplayFilter(self):
+ display_transform = ocio.PyOpenColorIO.DisplayTransform()
+ display_transform.setInputColorSpaceName(self._color_space)
+
+ if hasattr(display_transform, 'setDisplay'):
+ # OCIO 1.0+
+ display_transform.setDisplay(self._display)
+ display_transform.setView(self._view)
+ else:
+ # OCIO 0.8.X
+ display_color_space = self._config.getDisplayColorSpaceName(self._display, self._view)
+ display_transform.setDisplayColorSpaceName(display_color_space)
+
+ # Add the channel sizzle.
+ luma_coefs = self._config.getDefaultLumaCoefs()
+ mtx, offset = ocio.PyOpenColorIO.MatrixTransform.View(ocio.SWIZZLE_VALUES[self._swizzle], luma_coefs)
+
+ transform = ocio.PyOpenColorIO.MatrixTransform()
+ transform.setValue(mtx, offset)
+ display_transform.setChannelView(transform)
+
+ # Add the linear gain.
+ transform = ocio.PyOpenColorIO.CDLTransform()
+ transform.setSlope((self._gain, self._gain, self._gain))
+ display_transform.setLinearCC(transform)
+
+ # Add the post-display CC.
+ transform = ocio.PyOpenColorIO.ExponentTransform()
+ transform.setValue([1.0 / max(1e-6, v) for v in (self._gamma, self._gamma, self._gamma, self._gamma)])
+ display_transform.setDisplayCC(transform)
+
+ processor = self._config.getProcessor(display_transform)
+
+ self._display_filter_cache_id, self._display_texture_cache_id, self._display_sampler_name = ocio.buildProcessorFilter(
+ processor,
+ self._display_filter,
+ self._display_filter_cache_id,
+ self._display_texture_cache_id)
+
+ current_canvas = mari.canvases.current()
+ if current_canvas is not None:
+ current_canvas.repaint()
+
+ #-----------------------------------------------------------------------------------------
+ # Debugging:
+ #-----------------------------------------------------------------------------------------
+
+ def _printLog(self):
+ ocio.printMessage( ocio.MessageType.INFO, '==============================================================')
+ ocio.printMessage( ocio.MessageType.INFO, 'Configuration:')
+ ocio.printMessage( ocio.MessageType.INFO, '==============================================================')
+ ocio.printMessage( ocio.MessageType.INFO, ' Enabled: %s; Default: %s' % (mari.gl_render.isPostProcessingEnabled(),
+ ocio.enabled_default))
+ filter_collection = mari.gl_render.currentPostFilterCollection()
+ if filter_collection is not None:
+ ocio.printMessage(ocio.MessageType.INFO, ' Profile: %s; Default: %s' % (filter_collection.name(),
+ ocio.profile_default))
+ else:
+ ocio.printMessage(ocio.MessageType.INFO, ' Profile: None; Default: %s' % (ocio.profile_default))
+ ocio.printMessage( ocio.MessageType.INFO, ' LUT Path: %s; Default: %s' % ('' if self._lut_file_list.isEmpty() else self._lut_file_list.at(0),
+ '' if ocio.lut_file_list_default.isEmpty() else ocio.lut_file_list_default.at(0)))
+ ocio.printMessage( ocio.MessageType.INFO, ' Extrapolate: %s; Default: %s' % (self._lut_extrapolate,
+ ocio.lut_extrapolate_default))
+ ocio.printMessage( ocio.MessageType.INFO, ' Config Path: %s; Default: %s' % ('' if self._config_file_list.isEmpty() else self._config_file_list.at(0),
+ '' if ocio.config_file_list_default.isEmpty() else ocio.config_file_list_default.at(0)))
+ ocio.printMessage( ocio.MessageType.INFO, ' Color Space: %s; Default: %s' % (self._color_space,
+ ocio.color_space_default))
+ ocio.printMessage( ocio.MessageType.INFO, ' Display: %s; Default: %s' % (self._display,
+ ocio.display_default))
+ ocio.printMessage( ocio.MessageType.INFO, ' View: %s; Default: %s' % (self._view,
+ ocio.view_default))
+ ocio.printMessage( ocio.MessageType.INFO, ' Swizzle: %s; Default: %s' % (self._swizzle,
+ ocio.swizzle_default))
+ ocio.printMessage( ocio.MessageType.INFO, ' F-Stop: %f; Default: %f; Center: %f' % (ocio.convertGainToFStop(self._gain),
+ ocio.convertGainToFStop(ocio.gain_default),
+ ocio.fstop_center))
+ ocio.printMessage( ocio.MessageType.INFO, ' Gain: %f; Default: %f' % (self._gain,
+ ocio.gain_default))
+ ocio.printMessage( ocio.MessageType.INFO, ' Gamma: %f; Default: %f' % (self._gamma,
+ ocio.gamma_default))
+ ocio.printMessage( ocio.MessageType.INFO, '==============================================================')
+
+##############################################################################################
+# The following functions CAN'T be part of the toolbar class as a potential bug in PythonQt
+# causes the disconnect function to fail
+
+def lutMetadataValueChanged(name, value):
+ global toolbar
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'LUT metadata \'%s\' changed to \'%s\'' % (name, value))
+
+ if name == 'File':
+ toolbar.setLUTPath(value = '' if value.isEmpty() else value.at(0),
+ update_metadata = False,
+ force_shader_build = False)
+
+ elif name == 'Extrapolate':
+ toolbar.setExtrapolateEnabled(value = value, update_widget = True, update_metadata = False)
+
+#-----------------------------------------------------------------------------------------
+
+def displayMetadataValueChanged(name, value):
+ global toolbar
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Display metadata \'%s\' changed to \'%s\'' % (name, value))
+
+ if name == 'ConfigPath':
+ toolbar.setConfigPath(value = '' if value.isEmpty() else value.at(0), update_metadata = False)
+
+ elif name == 'InputColorSpace':
+ toolbar.setColorSpace(value = value, update_widget = True, update_metadata = False)
+
+ elif name == 'Display':
+ toolbar.setDisplay(value = value, update_widget = True, update_metadata = False)
+
+ elif name == 'View':
+ toolbar.setView(value = value, update_widget = True, update_metadata = False)
+
+ elif name == 'Swizzle':
+ toolbar.setSwizzle(value = value, update_widget = True, update_metadata = False)
+
+ elif name == 'Gain':
+ toolbar.setGain(value = value, update_widget = True, update_metadata = False)
+
+ elif name == 'Gamma':
+ toolbar.setGamma(value = value, update_widget = True, update_metadata = False)
+
+##############################################################################################
+
+if mari.app.isRunning():
+ if not hasattr(mari.gl_render, 'createPostFilterCollection'):
+ ocio.printMessage(ocio.MessageType.ERROR, 'This version of Mari does not support the mari.gl_render.createPostFilterCollection API')
+
+ else:
+ if ocio.config_default is not None:
+ toolbar = OcioToolBar()
+
+ else:
+ # Destroy the OCIO post filter collection if present to prevent the user trying to use it.
+ filter_collection = mari.gl_render.findPostFilterCollection('Color Space')
+ if filter_collection is not None:
+ mari.gl_render.deletePostFilterCollection(filter_collection)
+
+ # Destroy the toolbar to prevent the user trying to use it.
+ mari.app.deleteToolBar('Color Space')
diff --git a/src/mari/1.4v1/ocio.py b/src/mari/1.4v1/ocio.py
new file mode 100755
index 0000000..4f0f61e
--- /dev/null
+++ b/src/mari/1.4v1/ocio.py
@@ -0,0 +1,789 @@
+#-------------------------------------------------------------------------------
+# OpenColorIO (color management) related Mari scripts
+# coding: utf-8
+# Copyright (c) 2011 The Foundry Visionmongers Ltd. All Rights Reserved.
+#-------------------------------------------------------------------------------
+
+import mari, time, PythonQt, os, math
+
+##############################################################################################
+
+# Enable to output extended debugging messages.
+VERBOSE_ENABLED = False
+
+# Message type identifiers.
+class MessageType:
+ DEBUG = 1
+ INFO = 2
+ WARNING = 3
+ ERROR = 4
+
+def printMessage(type, message):
+ if type == MessageType.DEBUG:
+ if VERBOSE_ENABLED:
+ mari.app.log('[ OpenColorIO ] %s' % message)
+ elif type == MessageType.INFO:
+ mari.app.log('[ OpenColorIO ] %s' % message)
+ elif type == MessageType.WARNING:
+ mari.app.log('[ OpenColorIO ] [ WARNING ] %s' % message)
+ elif type == MessageType.ERROR:
+ mari.app.log('[ OpenColorIO ] [ ERROR ] %s' % message)
+
+##############################################################################################
+
+def configFileFilter():
+ return 'OpenColorIO Configuration (*.ocio)'
+
+#---------------------------------------------------------------------------------------------
+
+def lutFileFilter():
+ result = 'All LUT Files (*.3dl *.ccc *.cc *.csp *.cub *.cube *.hdl *.m3d *.mga *.spi1d *.spi3d *.spimtx *.vf);;'
+ result += 'Autodesk LUT (*.3dl);;'
+ result += 'ASC CDL Color Correction Collection LUT (*.ccc);;'
+ result += 'ASC CDL Color Correction LUT (*.cc);;'
+ result += 'Cinespace LUT (*.csp);;'
+ result += 'Truelight LUT (*.cub);;'
+ result += 'Iridas LUT (*.cube);;'
+ result += 'Houdini LUT (*.hdl);;'
+ result += 'Pandora LUT (*.m3d *.mga);;'
+ result += 'Imageworks LUT (*.spi1d *.spi3d *.spimtx);;'
+ result += 'Inventor LUT (*.vf)'
+ return result
+
+##############################################################################################
+
+# Make sure the OpenColorIO python bindings are okay.
+try:
+ import PyOpenColorIO
+ printMessage(MessageType.INFO, 'Loaded Python bindings \'%s\' successfully' % PyOpenColorIO.__file__)
+except ImportError, e:
+ PyOpenColorIO = None
+ printMessage(MessageType.ERROR, 'Failed to load Python bindings \'%s\'' % e)
+
+LUT_FILE_LIST_RESET = mari.FileList(mari.FileList.TYPE_SINGLE_FILE)
+LUT_FILE_LIST_RESET.setAcceptNonExisting(True)
+LUT_FILE_LIST_RESET.setFilter(lutFileFilter())
+
+CONFIG_FILE_LIST_RESET = mari.FileList(mari.FileList.TYPE_SINGLE_FILE)
+if mari.app.isRunning():
+ CONFIG_FILE_LIST_RESET.append(mari.resources.path(mari.resources.COLOR) + '/OpenColorIO/nuke-default/config.ocio')
+else:
+ CONFIG_FILE_LIST_RESET.append('/OpenColorIO/nuke-default/config.ocio')
+CONFIG_FILE_LIST_RESET.setPickedFile(CONFIG_FILE_LIST_RESET.at(0))
+CONFIG_FILE_LIST_RESET.setAcceptNonExisting(True)
+CONFIG_FILE_LIST_RESET.setFilter(configFileFilter())
+
+SQRT_TWO = math.sqrt(2.0)
+LUT_SIZE_TYPES = ['Small', 'Medium', 'Large']
+LUT_SIZE_VALUES = {'Small': 16,
+ 'Medium': 32,
+ 'Large': 64}
+LUT_SIZE_RESET = LUT_SIZE_TYPES[1]
+ENABLED_RESET = True
+PROFILE_RESET = 'Color Space'
+LUT_EXTRAPOLATE_RESET = True
+COLOR_SPACE_RESET = 'sRGB'
+DISPLAY_RESET = 'default'
+VIEW_RESET = 'sRGB'
+SWIZZLE_TYPES = ['Luminance', 'RGB', 'R', 'G', 'B', 'A']
+SWIZZLE_VALUES = {'Luminance': ( True, True, True, False),
+ 'RGB': ( True, True, True, True),
+ 'R': ( True, False, False, False),
+ 'G': (False, True, False, False),
+ 'B': (False, False, True, False),
+ 'A': (False, False, False, True)}
+SWIZZLE_RESET = SWIZZLE_TYPES[1]
+FSTOP_STEP_SIZE = 0.5
+FSTOP_CENTER_MIN = 1.0
+FSTOP_CENTER_MAX = 64.0
+FSTOP_CENTER_STEP_SIZE = 0.001
+FSTOP_CENTER_RESET = 8.0
+EXPOSURE_MIN = -6.0
+EXPOSURE_MAX = +6.0
+EXPOSURE_DELTA = EXPOSURE_MAX - EXPOSURE_MIN
+EXPOSURE_STEP_SIZE = 0.1
+GAIN_RESET = 1.0
+GAIN_MIN = 2.0 ** EXPOSURE_MIN
+GAIN_MAX = 2.0 ** EXPOSURE_MAX
+GAIN_STEP_SIZE = 0.000001
+GAIN_PRECISION = 6
+GAMMA_RESET = 1.0
+GAMMA_MIN = 0.0
+GAMMA_MAX = 4.0
+GAMMA_STEP_SIZE = 0.01
+GAMMA_PRECISION = 2
+
+enabled_default = ENABLED_RESET
+profile_default = PROFILE_RESET
+lut_file_list_default = mari.FileList(LUT_FILE_LIST_RESET)
+lut_extrapolate_default = LUT_EXTRAPOLATE_RESET
+config_file_list_default = mari.FileList(CONFIG_FILE_LIST_RESET)
+color_space_default = COLOR_SPACE_RESET
+display_default = DISPLAY_RESET
+view_default = VIEW_RESET
+swizzle_default = SWIZZLE_RESET
+gain_default = GAIN_RESET
+gamma_default = GAMMA_RESET
+lut_size = LUT_SIZE_RESET
+fstop_center = FSTOP_CENTER_RESET
+
+config_default = None
+
+lut_size_functions = []
+fstop_center_functions = []
+
+##############################################################################################
+
+def registerLUTSizeChanged(function):
+ global lut_size_functions
+ lut_size_functions.append(function)
+
+#---------------------------------------------------------------------------------------------
+
+def registerFStopCenterChanged(function):
+ global fstop_center_functions
+ fstop_center_functions.append(function)
+
+#---------------------------------------------------------------------------------------------
+
+def _enabledDefaultChanged():
+ global enabled_default
+ enabled_default = mari.prefs.get('/Color/Color Management Defaults/colorEnabledDefault')
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _profileDefaultChanged():
+ global profile_default
+ profile_default = mari.prefs.get('/Color/Color Management Defaults/colorProfileDefault')
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _postFilterCollectionAdded(filter_collection):
+ mari.prefs.setItemList('/Color/Color Management Defaults/colorProfileDefault', mari.gl_render.postFilterCollectionNames())
+
+#---------------------------------------------------------------------------------------------
+
+def _postFilterCollectionRemoved(name):
+ collection_names = mari.gl_render.postFilterCollectionNames()
+ mari.prefs.setItemList('/Color/Color Management Defaults/colorProfileDefault', collection_names)
+
+ global PROFILE_RESET
+ if name == PROFILE_RESET:
+ PROFILE_RESET = collection_names[0]
+ mari.prefs.setDefault('/Color/Color Management Defaults/colorProfileDefault', PROFILE_RESET)
+
+ global profile_default
+ if name == profile_default:
+ profile_default = PROFILE_RESET
+ mari.prefs.set('/Color/Color Management Defaults/colorProfileDefault', profile_default)
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _lutPathDefaultChanged():
+ global lut_file_list_default
+ lut_file_list_default = mari.FileList(mari.prefs.get('/Color/LUT Defaults/lutPathDefault'))
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _lutExtrapolateDefaultChanged():
+ global lut_extrapolate_default
+ lut_extrapolate_default = mari.prefs.get('/Color/LUT Defaults/lutExtrapolateDefault')
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _configPathDefaultChanged():
+ global config_file_list_default
+
+ # Only replace the existing configuration file if the new one is valid!
+ config_file_list = mari.FileList(mari.prefs.get('/Color/Display Defaults/displayConfigPathDefault'))
+
+ if not config_file_list.isEmpty():
+ config = loadConfig(config_file_list.at(0), True)
+ if config is not None:
+ config_file_list_default = config_file_list
+
+ global config_default
+ config_default = config
+
+ _updateColorSpaceDefault()
+ _updateDisplayDefault()
+ _updateViewDefault()
+
+ _savePreferences()
+
+ else:
+ # Put back the existing configuration file that works...
+ mari.prefs.set('/Color/Display Defaults/displayConfigPathDefault', config_file_list_default)
+ else:
+ # Put back the existing configuration file that works...
+ mari.prefs.set('/Color/Display Defaults/displayConfigPathDefault', config_file_list_default)
+
+#---------------------------------------------------------------------------------------------
+
+def _colorSpaceDefaultChanged():
+ global color_space_default
+ color_space_default = mari.prefs.get('/Color/Display Defaults/displayColorSpaceDefault')
+ _updateDisplayDefault()
+ _updateViewDefault()
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _displayDefaultChanged():
+ global display_default
+ display_default = mari.prefs.get('/Color/Display Defaults/displayDisplayDefault')
+ _updateViewDefault()
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _viewDefaultChanged():
+ global view_default
+ view_default = mari.prefs.get('/Color/Display Defaults/displayViewDefault')
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _swizzleDefaultChanged():
+ global swizzle_default
+ swizzle_default = mari.prefs.get('/Color/Display Defaults/displaySwizzleDefault')
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _gainDefaultChanged():
+ global gain_default
+ gain_default = mari.prefs.get('/Color/Display Defaults/displayGainDefault')
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _gammaDefaultChanged():
+ global gamma_default
+ gamma_default = mari.prefs.get('/Color/Display Defaults/displayGammaDefault')
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _lutSizeChanged():
+ global lut_size
+ global lut_size_functions
+ lut_size = mari.prefs.get('/Color/Display General/displayLutSize')
+ _savePreferences()
+ for function in lut_size_functions:
+ function()
+
+#---------------------------------------------------------------------------------------------
+
+def _fstopCenterChanged():
+ global fstop_center
+ global fstop_center_functions
+ fstop_center = mari.prefs.get('/Color/Display General/displayFStopCenter')
+ _savePreferences()
+ for function in fstop_center_functions:
+ function()
+
+#---------------------------------------------------------------------------------------------
+
+def _registerPreferences():
+ global enabled_default
+ mari.prefs.set('/Color/Color Management Defaults/colorEnabledDefault', enabled_default)
+ mari.prefs.setChangedScript('/Color/Color Management Defaults/colorEnabledDefault', 'mari.utils.ocio._enabledDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/Color Management Defaults/colorEnabledDefault', 'Enabled')
+ mari.prefs.setDefault('/Color/Color Management Defaults/colorEnabledDefault', ENABLED_RESET)
+
+ global profile_default
+ mari.prefs.set('/Color/Color Management Defaults/colorProfileDefault', profile_default)
+ mari.prefs.setChangedScript('/Color/Color Management Defaults/colorProfileDefault', 'mari.utils.ocio._profileDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/Color Management Defaults/colorProfileDefault', 'Color Profile')
+ mari.prefs.setDefault('/Color/Color Management Defaults/colorProfileDefault', PROFILE_RESET)
+ mari.prefs.setItemList('/Color/Color Management Defaults/colorProfileDefault', mari.gl_render.postFilterCollectionNames())
+
+ global lut_file_list_default
+ if not lut_file_list_default.isEmpty() and not os.path.isfile(lut_file_list_default.at(0)):
+ message = 'LUT file \'%s\' does not exist' % lut_file_list_default.at(0)
+ printMessage(MessageType.ERROR, '%s' % message)
+ lut_file_list_default = mari.FileList(LUT_FILE_LIST_RESET)
+
+ mari.prefs.set('/Color/LUT Defaults/lutPathDefault', lut_file_list_default)
+ mari.prefs.setChangedScript('/Color/LUT Defaults/lutPathDefault', 'mari.utils.ocio._lutPathDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/LUT Defaults/lutPathDefault', 'File')
+ mari.prefs.setDefault('/Color/LUT Defaults/lutPathDefault', LUT_FILE_LIST_RESET)
+
+ global lut_extrapolate_default
+ mari.prefs.set('/Color/LUT Defaults/lutExtrapolateDefault', lut_extrapolate_default)
+ mari.prefs.setChangedScript('/Color/LUT Defaults/lutExtrapolateDefault', 'mari.utils.ocio._lutExtrapolateDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/LUT Defaults/lutExtrapolateDefault', 'Extrapolate')
+ mari.prefs.setDefault('/Color/LUT Defaults/lutExtrapolateDefault', LUT_EXTRAPOLATE_RESET)
+
+ global config_file_list_default
+ global config_default
+ if not config_file_list_default.isEmpty():
+ config = loadConfig(config_file_list_default.at(0), False)
+ if config is not None:
+ config_default = config
+ else:
+ config_file_list_default = mari.FileList(CONFIG_FILE_LIST_RESET)
+ else:
+ config_file_list_default = mari.FileList(CONFIG_FILE_LIST_RESET)
+
+ mari.prefs.set('/Color/Display Defaults/displayConfigPathDefault', config_file_list_default)
+ mari.prefs.setChangedScript('/Color/Display Defaults/displayConfigPathDefault', 'mari.utils.ocio._configPathDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/Display Defaults/displayConfigPathDefault', 'Configuration File')
+ mari.prefs.setDefault('/Color/Display Defaults/displayConfigPathDefault', CONFIG_FILE_LIST_RESET)
+
+ color_spaces = [color_space.getName() for color_space in config_default.getColorSpaces()]
+
+ color_space_reset = COLOR_SPACE_RESET
+ if color_spaces.count(color_space_reset) == 0:
+ color_space_reset = color_spaces[0]
+
+ global color_space_default
+ if color_spaces.count(color_space_default) == 0:
+ color_space_default = color_space_reset
+
+ mari.prefs.set('/Color/Display Defaults/displayColorSpaceDefault', color_space_default)
+ mari.prefs.setChangedScript('/Color/Display Defaults/displayColorSpaceDefault', 'mari.utils.ocio._colorSpaceDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/Display Defaults/displayColorSpaceDefault', 'Input Color Space')
+ mari.prefs.setDefault('/Color/Display Defaults/displayColorSpaceDefault', color_space_reset)
+ mari.prefs.setItemList('/Color/Display Defaults/displayColorSpaceDefault', color_spaces)
+
+ displays = config_default.getDisplays()
+
+ display_reset = DISPLAY_RESET
+ if displays.count(display_reset) == 0:
+ display_reset = config_default.getDefaultDisplay()
+
+ global display_default
+ if displays.count(display_default) == 0:
+ display_default = display_reset
+
+ mari.prefs.set('/Color/Display Defaults/displayDisplayDefault', display_default)
+ mari.prefs.setChangedScript('/Color/Display Defaults/displayDisplayDefault', 'mari.utils.ocio._displayDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/Display Defaults/displayDisplayDefault', 'Display')
+ mari.prefs.setDefault('/Color/Display Defaults/displayDisplayDefault', display_reset)
+ mari.prefs.setItemList('/Color/Display Defaults/displayDisplayDefault', displays)
+
+ views = config_default.getViews(display_default)
+
+ view_reset = VIEW_RESET
+ if views.count(view_reset) == 0:
+ view_reset = config_default.getDefaultView(display_default)
+
+ global view_default
+ if views.count(view_default) == 0:
+ view_default = view_reset
+
+ mari.prefs.set('/Color/Display Defaults/displayViewDefault', view_default)
+ mari.prefs.setChangedScript('/Color/Display Defaults/displayViewDefault', 'mari.utils.ocio._viewDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/Display Defaults/displayViewDefault', 'View')
+ mari.prefs.setDefault('/Color/Display Defaults/displayViewDefault', view_reset)
+ mari.prefs.setItemList('/Color/Display Defaults/displayViewDefault', views)
+
+ global swizzle_default
+ if SWIZZLE_TYPES.count(swizzle_default) == 0:
+ swizzle_default = SWIZZLE_RESET
+
+ mari.prefs.set('/Color/Display Defaults/displaySwizzleDefault', swizzle_default)
+ mari.prefs.setChangedScript('/Color/Display Defaults/displaySwizzleDefault', 'mari.utils.ocio._swizzleDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/Display Defaults/displaySwizzleDefault', 'Component')
+ mari.prefs.setDefault('/Color/Display Defaults/displaySwizzleDefault', SWIZZLE_RESET)
+ mari.prefs.setItemList('/Color/Display Defaults/displaySwizzleDefault', SWIZZLE_TYPES)
+
+ global gain_default
+ mari.prefs.set('/Color/Display Defaults/displayGainDefault', gain_default)
+ mari.prefs.setChangedScript('/Color/Display Defaults/displayGainDefault', 'mari.utils.ocio._gainDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/Display Defaults/displayGainDefault', 'Gain')
+ mari.prefs.setDefault('/Color/Display Defaults/displayGainDefault', GAIN_RESET)
+ mari.prefs.setRange('/Color/Display Defaults/displayGainDefault', GAIN_MIN, GAIN_MAX)
+ mari.prefs.setStep('/Color/Display Defaults/displayGainDefault', GAIN_STEP_SIZE)
+
+ global gamma_default
+ mari.prefs.set('/Color/Display Defaults/displayGammaDefault', gamma_default)
+ mari.prefs.setChangedScript('/Color/Display Defaults/displayGammaDefault', 'mari.utils.ocio._gammaDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/Display Defaults/displayGammaDefault', 'Gamma')
+ mari.prefs.setDefault('/Color/Display Defaults/displayGammaDefault', GAMMA_RESET)
+ mari.prefs.setRange('/Color/Display Defaults/displayGammaDefault', GAMMA_MIN, GAMMA_MAX)
+ mari.prefs.setStep('/Color/Display Defaults/displayGammaDefault', GAMMA_STEP_SIZE)
+
+ global lut_size
+ mari.prefs.set('/Color/Display General/displayLutSize', lut_size)
+ mari.prefs.setChangedScript('/Color/Display General/displayLutSize', 'mari.utils.ocio._lutSizeChanged()')
+ mari.prefs.setDisplayName('/Color/Display General/displayLutSize', 'LUT Size')
+ mari.prefs.setDefault('/Color/Display General/displayLutSize', LUT_SIZE_RESET)
+ mari.prefs.setItemList('/Color/Display General/displayLutSize', LUT_SIZE_TYPES)
+
+ global fstop_center
+ mari.prefs.set('/Color/Display General/displayFStopCenter', fstop_center)
+ mari.prefs.setChangedScript('/Color/Display General/displayFStopCenter', 'mari.utils.ocio._fstopCenterChanged()')
+ mari.prefs.setDisplayName('/Color/Display General/displayFStopCenter', 'Center F-Stop')
+ mari.prefs.setDefault('/Color/Display General/displayFStopCenter', FSTOP_CENTER_RESET)
+ mari.prefs.setRange('/Color/Display General/displayFStopCenter', FSTOP_CENTER_MIN, FSTOP_CENTER_MAX)
+ mari.prefs.setStep('/Color/Display General/displayFStopCenter', FSTOP_CENTER_STEP_SIZE)
+
+ # Attach ourselves to the appropriate project signals so we can update widgets.
+ PythonQt.QtCore.QObject.connect(mari.gl_render.postFilterCollectionAdded.__self__,
+ mari.gl_render.postFilterCollectionAdded.__name__,
+ _postFilterCollectionAdded)
+ PythonQt.QtCore.QObject.connect(mari.gl_render.postFilterCollectionRemoved.__self__,
+ mari.gl_render.postFilterCollectionRemoved.__name__,
+ _postFilterCollectionRemoved)
+
+#---------------------------------------------------------------------------------------------
+
+def _updateColorSpaceDefault():
+ global config_default
+ global color_space_default
+
+ color_spaces = [color_space.getName() for color_space in config_default.getColorSpaces()]
+
+ color_space_reset = COLOR_SPACE_RESET
+ if color_spaces.count(color_space_reset) == 0:
+ color_space_reset = color_spaces[0]
+
+ if color_spaces.count(color_space_default) == 0:
+ color_space_default = color_space_reset
+
+ mari.prefs.setItemList('/Color/Display Defaults/displayColorSpaceDefault', color_spaces)
+ mari.prefs.set('/Color/Display Defaults/displayColorSpaceDefault', color_space_default)
+ mari.prefs.setDefault('/Color/Display Defaults/displayColorSpaceDefault', color_space_reset)
+
+
+#---------------------------------------------------------------------------------------------
+
+def _updateDisplayDefault():
+ global config_default
+ global display_default
+
+ displays = config_default.getDisplays()
+
+ display_reset = DISPLAY_RESET
+ if displays.count(display_reset) == 0:
+ display_reset = config_default.getDefaultDisplay()
+
+ if displays.count(display_default) == 0:
+ display_default = display_reset
+
+ mari.prefs.setItemList('/Color/Display Defaults/displayDisplayDefault', displays)
+ mari.prefs.set('/Color/Display Defaults/displayDisplayDefault', display_default)
+ mari.prefs.setDefault('/Color/Display Defaults/displayDisplayDefault', display_reset)
+
+#---------------------------------------------------------------------------------------------
+
+def _updateViewDefault():
+ global config_default
+ global display_default
+ global view_default
+
+ views = config_default.getViews(display_default)
+
+ view_reset = VIEW_RESET
+ if views.count(view_reset) == 0:
+ view_reset = config_default.getDefaultView(display_default)
+
+ if views.count(view_default) == 0:
+ view_default = view_reset
+
+ mari.prefs.setItemList('/Color/Display Defaults/displayViewDefault', views)
+ mari.prefs.set('/Color/Display Defaults/displayViewDefault', view_default)
+ mari.prefs.setDefault('/Color/Display Defaults/displayViewDefault', view_reset)
+
+#---------------------------------------------------------------------------------------------
+
+def _loadPreferences():
+ settings = mari.Settings()
+ settings.beginGroup('OpenColorIO')
+
+ try:
+ global enabled_default
+ global profile_default
+ global lut_file_list_default
+ global lut_extrapolate_default
+ global config_file_list_default
+ global color_space_default
+ global display_default
+ global view_default
+ global swizzle_default
+ global gain_default
+ global gamma_default
+ global lut_size
+ global fstop_center
+
+ enabled_default = False if int(settings.value('enabledDefault', ENABLED_RESET)) == 0 else True
+ profile_default = str(settings.value('profileDefault', PROFILE_RESET))
+ lut_path = buildLoadPath(str(settings.value('lutPathDefault', '' if LUT_FILE_LIST_RESET.isEmpty() else LUT_FILE_LIST_RESET.at(0))))
+ lut_extrapolate_default = False if int(settings.value('lutExtrapolateDefault', LUT_EXTRAPOLATE_RESET)) == 0 else True
+ config_path = buildLoadPath(str(settings.value('configPathDefault', '' if CONFIG_FILE_LIST_RESET.isEmpty() else CONFIG_FILE_LIST_RESET.at(0))))
+ color_space_default = str(settings.value('colorSpaceDefault', COLOR_SPACE_RESET))
+ display_default = str(settings.value('displayDefault', DISPLAY_RESET))
+ view_default = str(settings.value('viewDefault', VIEW_RESET))
+ swizzle_default = str(settings.value('swizzleDefault', SWIZZLE_RESET))
+ gain_default = max(min(float(settings.value('gainDefault', GAIN_RESET)), GAIN_MAX), GAIN_MIN)
+ gamma_default = max(min(float(settings.value('gammaDefault', GAMMA_RESET)), GAMMA_MAX), GAMMA_MIN)
+ lut_size = str(settings.value('lutSize', LUT_SIZE_RESET))
+ fstop_center = max(min(float(settings.value('fstopCenter', FSTOP_CENTER_RESET)), FSTOP_CENTER_MAX), FSTOP_CENTER_MIN)
+
+ if os.path.isfile(lut_path):
+ lut_file_list_default.clear()
+ lut_file_list_default.append(lut_path)
+ lut_file_list_default.setPickedFile(lut_path)
+
+ if os.path.isfile(config_path):
+ config_file_list_default.clear()
+ config_file_list_default.append(config_path)
+ config_file_list_default.setPickedFile(config_path)
+
+ except ValueError, e:
+ printMessage(MessageType.ERROR, 'Failed to load preferences \'%s\'' % e)
+
+ settings.endGroup()
+
+ _printPreferences(MessageType.DEBUG, 'Loaded Preferences:')
+
+#---------------------------------------------------------------------------------------------
+
+def _savePreferences():
+ settings = mari.Settings()
+ settings.beginGroup('OpenColorIO')
+
+ global enabled_default
+ global profile_default
+ global lut_file_list_default
+ global lut_extrapolate_default
+ global config_file_list_default
+ global color_space_default
+ global display_default
+ global view_default
+ global swizzle_default
+ global gain_default
+ global gamma_default
+ global lut_size
+ global fstop_center
+
+ settings.setValue( 'enabledDefault', 1 if enabled_default else 0)
+ settings.setValue( 'profileDefault', profile_default)
+ settings.setValue( 'lutPathDefault', '' if lut_file_list_default.isEmpty() else buildSavePath(lut_file_list_default.at(0)))
+ settings.setValue('lutExtrapolateDefault', 1 if lut_extrapolate_default else 0)
+ settings.setValue( 'configPathDefault', '' if config_file_list_default.isEmpty() else buildSavePath(config_file_list_default.at(0)))
+ settings.setValue( 'colorSpaceDefault', color_space_default)
+ settings.setValue( 'displayDefault', display_default)
+ settings.setValue( 'viewDefault', view_default)
+ settings.setValue( 'swizzleDefault', swizzle_default)
+ settings.setValue( 'gainDefault', gain_default)
+ settings.setValue( 'gammaDefault', gamma_default)
+ settings.setValue( 'lutSize', lut_size)
+ settings.setValue( 'fstopCenter', fstop_center)
+
+ settings.endGroup()
+
+ _printPreferences(MessageType.DEBUG, 'Saved Preferences:')
+
+#---------------------------------------------------------------------------------------------
+
+def _printPreferences(type, title):
+ global enabled_default
+ global profile_default
+ global lut_file_list_default
+ global lut_extrapolate_default
+ global config_file_list_default
+ global color_space_default
+ global display_default
+ global view_default
+ global swizzle_default
+ global gain_default
+ global fstop_center
+ global lut_size
+ global gamma_default
+
+ printMessage(type, '==============================================================')
+ printMessage(type, title)
+ printMessage(type, '==============================================================')
+ printMessage(type, ' Enabled: %s' % enabled_default)
+ printMessage(type, ' Profile: %s' % profile_default)
+ printMessage(type, ' LUT Path: %s' % '' if lut_file_list_default.isEmpty() else lut_file_list_default.at(0))
+ printMessage(type, ' Extrapolate: %s' % lut_extrapolate_default)
+ printMessage(type, ' Config Path: %s' % '' if config_file_list_default.isEmpty() else config_file_list_default.at(0))
+ printMessage(type, ' Color Space: %s' % color_space_default)
+ printMessage(type, ' Display: %s' % display_default)
+ printMessage(type, ' View: %s' % view_default)
+ printMessage(type, ' Swizzle: %s' % swizzle_default)
+ printMessage(type, ' F-Stop: %f; Center: %f' % (convertGainToFStop(gain_default), fstop_center))
+ printMessage(type, ' Gain: %f' % gain_default)
+ printMessage(type, ' Gamma: %f' % gamma_default)
+ printMessage(type, ' LUT Size: %s' % lut_size)
+ printMessage(type, '==============================================================')
+
+##############################################################################################
+
+def convertExposureToGain(exposure):
+ return 2.0 ** exposure
+
+#---------------------------------------------------------------------------------------------
+
+def convertGainToExposure(gain):
+ return math.log(gain, 2.0)
+
+#---------------------------------------------------------------------------------------------
+
+def convertExposureToFStop(exposure):
+ global fstop_center
+ exposure_center = math.log(fstop_center, SQRT_TWO)
+ return math.pow(SQRT_TWO, exposure_center - exposure)
+
+#---------------------------------------------------------------------------------------------
+
+def convertGainToFStop(gain):
+ exposure = convertGainToExposure(gain)
+ return convertExposureToFStop(exposure)
+
+#---------------------------------------------------------------------------------------------
+
+def buildProcessorFilter(processor, filter, filter_cache_id, texture_cache_id, extrapolate = False, force_shader_build = False):
+ # Create a name, using the filter's name, that can be used in uniquely naming parameters and functions.
+ name = filter.name();
+ name = name.lower()
+ name = name.replace(' ', '_')
+
+ sampler_name = 'ocio_' + name + '_lut_$ID_'
+ function_name = 'ocio_' + name + '_$ID_'
+
+ global lut_size
+ shader_desc = { 'language': PyOpenColorIO.Constants.GPU_LANGUAGE_GLSL_1_3,
+ 'functionName': function_name,
+ 'lut3DEdgeLen': LUT_SIZE_VALUES[lut_size]}
+
+ cache_id = processor.getGpuShaderTextCacheID(shader_desc)
+ if cache_id != filter_cache_id or force_shader_build:
+ filter_cache_id = cache_id
+ printMessage(MessageType.DEBUG, 'Creating new GLSL filter...')
+
+ desc = 'uniform sampler3D ' + sampler_name + ';\n'
+ desc += processor.getGpuShaderText(shader_desc)
+ body = ''
+ if extrapolate:
+ # The following code was taken from Nuke's 'LUT3D::Extrapolate' functionality. It attempts to estimate what
+ # the corresponding color value would be when the incoming color value is outside the normal range of [0-1],
+ # such as the case with HDR images.
+ rcp_lut_edge_length = 1.0 / float(LUT_SIZE_VALUES[lut_size])
+
+ body += '{\n'
+ body += ' if( 1.0 < Out.r || 1.0 < Out.g || 1.0 < Out.b )\n'
+ body += ' {\n'
+ body += ' vec4 closest;\n'
+ body += ' closest.rgb = clamp(Out.rgb, vec3(0.0), vec3(1.0));\n'
+ body += ' closest.a = Out.a;\n'
+ body += '\n'
+ body += ' vec3 offset = Out.rgb - closest.rgb;\n'
+ body += ' float offset_distance = length(offset);\n'
+ body += ' offset = normalize(offset);\n'
+ body += '\n'
+ body += ' vec4 nbr_position;\n'
+ body += ' nbr_position.rgb = closest.rgb - %f * offset;\n' % rcp_lut_edge_length
+ body += ' nbr_position.a = Out.a;\n'
+ body += '\n'
+ body += ' Out = ' + function_name + '(closest, ' + sampler_name + ');\n'
+ body += ' Out.rgb += (Out.rgb - ' + function_name + '(nbr_position, ' + sampler_name + ').rgb) / %f * offset_distance;\n' % rcp_lut_edge_length
+ body += ' }\n'
+ body += ' else\n'
+ body += ' {\n'
+ body += ' Out = ' + function_name + '(Out, ' + sampler_name + ');\n'
+ body += ' }\n'
+ body += '}\n'
+ else:
+ body += '{ Out = ' + function_name + '(Out, ' + sampler_name + '); }\n'
+
+ filter.setDefinitionsSnippet(desc)
+ filter.setBodySnippet(body)
+ else:
+ printMessage(MessageType.DEBUG, 'No GLSL filter update required')
+
+ cache_id = processor.getGpuLut3DCacheID(shader_desc)
+ if cache_id != texture_cache_id:
+ lut = processor.getGpuLut3D(shader_desc)
+
+ printMessage(MessageType.DEBUG, 'Updating LUT...')
+
+ if texture_cache_id is None:
+ filter.setTexture3D(sampler_name,
+ LUT_SIZE_VALUES[lut_size],
+ LUT_SIZE_VALUES[lut_size],
+ LUT_SIZE_VALUES[lut_size],
+ filter.FORMAT_RGB,
+ lut)
+ else:
+ filter.updateTexture3D(sampler_name, lut)
+
+ texture_cache_id = cache_id
+ else:
+ printMessage(MessageType.DEBUG, 'No LUT update required')
+
+ return (filter_cache_id, texture_cache_id, sampler_name)
+
+#---------------------------------------------------------------------------------------------
+
+def buildLUTFilter(config, path, filter, filter_cache_id, texture_cache_id, extrapolate, force_shader_build = False):
+ file_transform = PyOpenColorIO.FileTransform()
+ file_transform.setSrc(path)
+ file_transform.setInterpolation('linear')
+
+ processor = config.getProcessor(file_transform)
+
+ return buildProcessorFilter(processor, filter, filter_cache_id, texture_cache_id, extrapolate, force_shader_build)
+
+#---------------------------------------------------------------------------------------------
+
+def loadConfig(path, display_message_box = True):
+ try:
+ config = PyOpenColorIO.Config.CreateFromFile(path)
+ return config
+
+ except Exception, e:
+ message = 'Failed to load configuration file \'%s\' due to \'%s\'' % (path, e)
+ printMessage(MessageType.ERROR, '%s' % message)
+ if display_message_box and not mari.app.inTerminalMode():
+ mari.utils.misc.message(message, 'Color Space', 1024, 2)
+
+ return None
+
+#---------------------------------------------------------------------------------------------
+
+# This converts a path into a form which can be shared among different platforms and installations.
+def buildSavePath(path):
+ result = path.replace(mari.resources.path(mari.resources.COLOR), '$MARI_COLOR_PATH', 1)
+ return result
+
+#---------------------------------------------------------------------------------------------
+
+# This converts a path saved out to disk back into a form which can used by the application.
+def buildLoadPath(path):
+ result = path.replace('$MARI_COLOR_PATH', mari.resources.path(mari.resources.COLOR), 1)
+ return result
+
+##############################################################################################
+
+if mari.app.isRunning():
+ if PyOpenColorIO is not None:
+ # Attempt to load the default configuration file... without it we can't do nothing!
+ config_file_lists = [config_file_list_default, CONFIG_FILE_LIST_RESET]
+ for config_file_list in config_file_lists:
+ if not config_file_list.isEmpty():
+ config_default = loadConfig(config_file_list.at(0), False)
+ if config_default is not None:
+ config_file_list_default = mari.FileList(config_file_list)
+ break
+
+ if config_default is not None:
+ _loadPreferences()
+ _registerPreferences()
+ _savePreferences()
+
+ else:
+ message = 'Failed to find a working configuration file. OpenColorIO will be disabled!'
+ printMessage(MessageType.ERROR, message)
+ if not mari.app.inTerminalMode():
+ mari.utils.misc.message(message, 'OpenColorIO', 1024, 3)
diff --git a/src/mari/prototype/README b/src/mari/prototype/README
new file mode 100644
index 0000000..514cd65
--- /dev/null
+++ b/src/mari/prototype/README
@@ -0,0 +1,3 @@
+This is a prototype implemetation for a python display integration, which worked
+in early Mari versions. It's provided as a simple example of how to use the
+OCIO python API to query the GPU interface functions.
diff --git a/src/mari/prototype/ociodisplay.py b/src/mari/prototype/ociodisplay.py
new file mode 100644
index 0000000..5b0b949
--- /dev/null
+++ b/src/mari/prototype/ociodisplay.py
@@ -0,0 +1,242 @@
+"""
+This script allows the use of OpenColorIO display transforms (3d luts) in
+the Mari Viewer. Requires Mari 1.3v2+.
+
+This example is not represntative of the final Mari OCIO workflow, merely
+an API demonstration. This code is a work in progress, to demonstrate the
+integration of OpenColorIO and Mari. The APIs this code relies on are subject
+to change at any time, and as such should not be relied on for production use
+(yet).
+
+LINUX testing instructions:
+
+* Build OCIO
+mkdir -p dist_mari
+mkdir -p build_mari && cd build_mari
+cmake -D CMAKE_BUILD_TYPE=Release \
+ -D CMAKE_INSTALL_PREFIX=../dist_mari \
+ -D PYTHON=/usr/bin/python2.6 \
+ -D OCIO_NAMESPACE=OpenColorIO_Mari \
+ ../
+make install -j8
+
+* Set $OCIO color environment
+setenv OCIO setenv OCIO <YOURDIR>/ocio.configs/spi-vfx/config.ocio
+(Profiles available for download from opencolorio.org)
+
+* Run Mari with OpenColorIO added to the LD_LIBRARY_PATH, and Python
+env LD_LIBRARY_PATH=<YOURDIR>/dist_mari/lib/ PYTHONPATH=<YOURDIR>/dist_mari/lib/python2.6 mari
+
+* Source this script in the python console.
+Also - IMPORTANT - you must enable 'Use Color Correction' in the Color Manager.
+
+"""
+
+import mari, time, PythonQt
+QtGui = PythonQt.QtGui
+QtCore = PythonQt.QtCore
+
+try:
+ import PyOpenColorIO as OCIO
+ mari.app.log("OCIODisplay: %s" % OCIO.__file__)
+except Exception,e:
+ OCIO = None
+ mari.app.log("OCIODisplay: Error: Could not import OpenColorIO python bindings.")
+ mari.app.log("OCIODisplay: Please confirm PYTHONPATH has dir containing PyOpenColorIO.so")
+
+__all__ = [ 'OCIO', 'CreateOCIODisplayTransform', 'OCIODisplayUI']
+
+LUT3D_SIZE = 32
+WINDOW_NAME = "OpenColorIO Display Manager"
+CREATE_FLOATING = True
+
+
+class OCIODisplayUI(QtGui.QWidget):
+ def __init__(self):
+ QtGui.QWidget.__init__(self)
+ QtGui.QGridLayout(self)
+ self.setWindowTitle(WINDOW_NAME)
+ self.setMinimumWidth(300)
+
+ config = OCIO.GetCurrentConfig()
+
+ self.__inputColorSpace = OCIO.Constants.ROLE_DEFAULT
+ inputColorSpaces = [ OCIO.Constants.ROLE_TEXTURE_PAINT,
+ 'dt8',
+ OCIO.Constants.ROLE_SCENE_LINEAR ]
+ for cs in inputColorSpaces:
+ if config.getColorSpace(cs) is None: continue
+ self.__inputColorSpace = cs
+ break
+
+ self.__fStopOffset = 0.0
+ self.__viewGamma = 1.0
+ self.__swizzle = (True, True, True, True)
+
+ self.__filter_cacheID = None
+ self.__filter = None
+ self.__texture3d_cacheID = None
+ self.__counter_hack = 0
+
+ self.__buildUI()
+ self.__rebuildFilter()
+
+ def __buildUI(self):
+ config = OCIO.GetCurrentConfig()
+
+ self.layout().addWidget( QtGui.QLabel("Input Color Space", self), 0, 0)
+ csWidget = QtGui.QComboBox(self)
+ self.layout().addWidget( csWidget, 0, 1)
+ csIndex = None
+ for name in (cs.getName() for cs in config.getColorSpaces()):
+ csWidget.addItem(name)
+ if name == self.__inputColorSpace:
+ csIndex = csWidget.count - 1
+ if csIndex is not None:
+ csWidget.setCurrentIndex(csIndex)
+ csWidget.connect( QtCore.SIGNAL('currentIndexChanged(const QString &)'), self.__csChanged)
+
+
+ # This doesnt work until the Horizontal enum is exposed.
+ """
+ self.__fstopWidget_numStops = 3.0
+ self.__fstopWidget_ticksPerStop = 4
+
+ self.layout().addWidget( QtGui.QLabel("FStop", self), 1, 0)
+ fstopWidget = QtGui.QSlider(Horizontal, self)
+ self.layout().addWidget( fstopWidget, 1, 1)
+ fstopWidget.setMinimum(int(-self.__fstopWidget_numStops*self.__fstopWidget_ticksPerStop))
+ fstopWidget.setMaximum(int(self.__fstopWidget_numStops*self.__fstopWidget_ticksPerStop))
+ fstopWidget.setTickInterval(self.__fstopWidget_ticksPerStop)
+ """
+
+
+ def __csChanged(self, text):
+ text = str(text)
+ if text != self.__inputColorSpace:
+ self.__inputColorSpace = text
+ self.__rebuildFilter()
+
+ def __rebuildFilter(self):
+ config = OCIO.GetCurrentConfig()
+ display = config.getDefaultDisplay()
+ view = config.getDefaultView(display)
+ transform = CreateOCIODisplayTransform(config, self.__inputColorSpace,
+ display, view,
+ self.__swizzle,
+ self.__fStopOffset, self.__viewGamma)
+
+ processor = config.getProcessor(transform)
+
+ shaderDesc = dict( [('language', OCIO.Constants.GPU_LANGUAGE_GLSL_1_3),
+ ('functionName', 'display_ocio_$ID_'),
+ ('lut3DEdgeLen', LUT3D_SIZE)] )
+
+ filterCacheID = processor.getGpuShaderTextCacheID(shaderDesc)
+ if filterCacheID != self.__filter_cacheID:
+ self.__filter_cacheID = filterCacheID
+ mari.app.log("OCIODisplay: Creating filter %s" % self.__filter_cacheID)
+
+ desc = "sampler3D lut3d_ocio_$ID_;\n"
+ desc += processor.getGpuShaderText(shaderDesc)
+ body = "{ Out = display_ocio_$ID_(Out, lut3d_ocio_$ID_); }"
+
+ # Clear the existing color managment filter stack and create a new filter
+ # HACK: Increment a counter by 1 each time to force a refresh
+ #self.__counter_hack += 1
+ #name = "OCIO %s %s %s v%d" % (display, view, self.__inputColorSpace, self.__counter_hack)
+ name = "OCIO %s %s %s" % (display, view, self.__inputColorSpace)
+
+ self.__filter = None
+ self.__texture3d_cacheID = None
+
+ mari.gl_render.clearPostFilterStack()
+ self.__filter = mari.gl_render.createPostFilter(name, desc, body)
+ mari.gl_render.appendPostFilter(self.__filter)
+ else:
+ mari.app.log('OCIODisplay: no shader text update required')
+
+ texture3d_cacheID = processor.getGpuLut3DCacheID(shaderDesc)
+ if texture3d_cacheID != self.__texture3d_cacheID:
+ lut3d = processor.getGpuLut3D(shaderDesc)
+
+ mari.app.log("OCIODisplay: Updating 3dlut %s" % texture3d_cacheID)
+
+ if self.__texture3d_cacheID is None:
+ self.__filter.setTexture3D("lut3d_ocio_$ID_",
+ LUT3D_SIZE, LUT3D_SIZE, LUT3D_SIZE,
+ self.__filter.FORMAT_RGB, lut3d)
+ else:
+ self.__filter.updateTexture3D( "lut3d_ocio_$ID_", lut3d)
+
+ self.__texture3d_cacheID = texture3d_cacheID
+ else:
+ mari.app.log("OCIODisplay: No lut3d update required")
+
+
+
+def CreateOCIODisplayTransform(config,
+ inputColorSpace,
+ display, view,
+ swizzle,
+ fstopOffset, viewGamma):
+
+ displayTransform = OCIO.DisplayTransform()
+ displayTransform.setInputColorSpaceName( inputColorSpace )
+
+ displayColorSpace = config.getDisplayColorSpaceName(display, view)
+ displayTransform.setDisplayColorSpaceName( displayColorSpace )
+
+ # Add the channel sizzle
+ lumacoef = config.getDefaultLumaCoefs()
+ mtx, offset = OCIO.MatrixTransform.View(swizzle, lumacoef)
+
+ transform = OCIO.MatrixTransform()
+ transform.setValue(mtx, offset)
+ displayTransform.setChannelView(transform)
+
+ # Add the linear fstop gain
+ gain = 2**fstopOffset
+ mtx, offset = OCIO.MatrixTransform.Scale((gain,gain,gain,gain))
+ transform = OCIO.MatrixTransform()
+ transform.setValue(mtx, offset)
+ displayTransform.setLinearCC(transform)
+
+ # Add the post-display CC
+ transform = OCIO.ExponentTransform()
+ transform.setValue([1.0 / max(1e-6, v) for v in \
+ (viewGamma, viewGamma, viewGamma, viewGamma)])
+ displayTransform.setDisplayCC(transform)
+
+ return displayTransform
+
+"""
+SWIZZLE_COLOR = (True, True, True, True)
+SWIZZLE_RED = (True, False, False, False)
+SWIZZLE_GREEN = (False, True, False, False)
+SWIZZLE_BLUE = (False, False, True, False)
+SWIZZLE_ALPHA = (False, False, False, True)
+SWIZZLE_LUMA = (True, True, True, False)
+
+Timings
+
+OCIO Setup: 0.5 ms
+OCIO 3D Lut creation: 14.7 ms
+Mari Setup: 21.3 ms
+Mari Texture Upload: 44.2 ms
+"""
+
+
+if __name__ == '__main__':
+ if not hasattr(mari.gl_render,"createPostFilter"):
+ mari.app.log("OCIODisplay: Error: This version of Mari does not support the mari.gl_render.createPostFilter API")
+ else:
+ if OCIO is not None:
+ if CREATE_FLOATING:
+ w = OCIODisplayUI()
+ w.show()
+ else:
+ if WINDOW_NAME in mari.app.tabNames():
+ mari.app.removeTab(WINDOW_NAME)
+ w = OCIODisplayUI()
+ mari.app.addTab(WINDOW_NAME, w)
diff --git a/src/mari/prototype/ociofiletransform.py b/src/mari/prototype/ociofiletransform.py
new file mode 100644
index 0000000..318c656
--- /dev/null
+++ b/src/mari/prototype/ociofiletransform.py
@@ -0,0 +1,93 @@
+"""
+This script allows the loading of a specied lut (1d/3d/mtx) in
+the Mari Viewer. Requires Mari 1.3v2+.
+
+This example is not represntative of the final Mari OCIO workflow, merely
+an API demonstration. This code is a work in progress, to demonstrate the
+integration of OpenColorIO and Mari. The APIs this code relies on are subject
+to change at any time, and as such should not be relied on for production use
+(yet).
+
+LINUX testing instructions:
+
+* Build OCIO
+mkdir -p dist_mari
+mkdir -p build_mari && cd build_mari
+cmake -D CMAKE_BUILD_TYPE=Release \
+ -D CMAKE_INSTALL_PREFIX=../dist_mari \
+ -D PYTHON=/usr/bin/python2.6 \
+ -D OCIO_NAMESPACE=OpenColorIO_Mari \
+ ../
+make install -j8
+
+* Edit this file to point to use viewer lut you want to use
+
+* Run Mari with OpenColorIO added to the LD_LIBRARY_PATH, and Python
+env LD_LIBRARY_PATH=<YOURDIR>/dist_mari/lib/ PYTHONPATH=<YOURDIR>/dist_mari/lib/python2.6 mari
+
+* Source this script in the python console.
+Also - IMPORTANT - you must enable 'Use Color Correction' in the Color Manager.
+
+"""
+
+# YOU MUST CHANGE THIS TO MODIFY WHICH LUT TO USE
+LUT_FILENAME = "/shots/spi/home/lib/lut/dev/v29/luts/LC3DL_Kodak2383_Sony_GDM.3dl"
+LUT3D_SIZE = 32
+
+import mari, time, os
+
+try:
+ import PyOpenColorIO as OCIO
+ print OCIO.__file__
+except Exception,e:
+ print "Error: Could not import OpenColorIO python bindings."
+ print "Please confirm PYTHONPATH has dir containing PyOpenColorIO.so"
+
+def RegisterOCIOLut():
+ if not hasattr(mari.gl_render,"createPostFilter"):
+ print "Error: This version of Mari does not support the mari.gl_render.createPostFilter API"
+ return
+
+ config = OCIO.Config()
+ transform = OCIO.FileTransform(src = os.path.realpath(LUT_FILENAME),
+ interpolation = OCIO.Constants.INTERP_LINEAR,
+ direction = OCIO.Constants.TRANSFORM_DIR_FORWARD)
+ processor = config.getProcessor(transform)
+
+ shaderDesc = dict( [('language', OCIO.Constants.GPU_LANGUAGE_GLSL_1_3),
+ ('functionName', 'display_ocio_$ID_'),
+ ('lut3DEdgeLen', LUT3D_SIZE)] )
+ shaderText = processor.getGpuShaderText(shaderDesc)
+
+ lut3d = processor.getGpuLut3D(shaderDesc)
+
+ # Clear the existing color managment filter stack
+ mari.gl_render.clearPostFilterStack()
+
+ # Create variable pre-declarations
+ desc = "sampler3D lut3d_ocio_$ID_;\n"
+ desc += shaderText
+
+ # Set the body of the filter
+ body = "{ Out = display_ocio_$ID_(Out, lut3d_ocio_$ID_); }"
+
+ # HACK: Increment a counter by 1 each time to force a refresh
+ if not hasattr(mari, "ocio_lut_counter_hack"):
+ mari.ocio_lut_counter_hack = 0
+ else:
+ mari.ocio_lut_counter_hack += 1
+ ocio_lut_counter_hack = mari.ocio_lut_counter_hack
+
+ # Create a new filter
+ name = "OCIO %s v%d" % (os.path.basename(LUT_FILENAME), ocio_lut_counter_hack)
+ postfilter = mari.gl_render.createPostFilter(name, desc, body)
+
+ # Set the texture to use for the given sampler on this filter
+ postfilter.setTexture3D("lut3d_ocio_$ID_",
+ LUT3D_SIZE, LUT3D_SIZE, LUT3D_SIZE,
+ postfilter.FORMAT_RGB, lut3d)
+
+ # Append the filter to the end of the current list of filters
+ mari.gl_render.appendPostFilter(postfilter)
+
+RegisterOCIOLut()