From 033cbbdf52653d7f841ed93bf673d2a314ce9d87 Mon Sep 17 00:00:00 2001 From: Doug Walker Date: Mon, 8 Apr 2024 01:42:40 -0400 Subject: [PATCH 01/14] Config merge rewrite, part 1 Signed-off-by: Doug Walker (cherry picked from commit 08a3adf15308ee1a629a29ce8ff94b53f9e7de70) Signed-off-by: Doug Walker --- include/OpenColorIO/OpenColorAppHelpers.h | 274 + include/OpenColorIO/OpenColorIO.h | 49 +- include/OpenColorIO/OpenColorTypes.h | 45 + src/OpenColorIO/CMakeLists.txt | 3 + src/OpenColorIO/ColorSpaceSet.cpp | 25 +- src/OpenColorIO/Config.cpp | 102 +- src/OpenColorIO/ConfigUtils.cpp | 319 + src/OpenColorIO/ConfigUtils.h | 18 + src/OpenColorIO/CustomKeys.h | 24 +- src/OpenColorIO/Exception.cpp | 38 + .../mergeconfigs/MergeConfigsHelpers.cpp | 695 ++ .../mergeconfigs/MergeConfigsHelpers.h | 204 + .../apphelpers/mergeconfigs/OCIOMYaml.cpp | 625 ++ .../apphelpers/mergeconfigs/OCIOMYaml.h | 71 + .../apphelpers/mergeconfigs/SectionMerger.cpp | 3999 +++++++++++ .../apphelpers/mergeconfigs/SectionMerger.h | 443 ++ src/apps/CMakeLists.txt | 1 + src/apps/ociomergeconfigs/CMakeLists.txt | 30 + src/apps/ociomergeconfigs/main.cpp | 198 + tests/cpu/CMakeLists.txt | 4 + tests/cpu/ConfigUtils_tests.cpp | 584 ++ tests/cpu/Config_tests.cpp | 2 +- tests/cpu/UnitTestLogUtils.cpp | 21 +- tests/cpu/UnitTestLogUtils.h | 6 +- .../apphelpers/MergeConfigsHelpers_tests.cpp | 6069 +++++++++++++++++ .../mergeconfigs/base_colorspaces_config.yaml | 57 + .../configs/mergeconfigs/base_config.yaml | 170 + .../mergeconfigs/default_strategy.ociom | 25 + .../input_colorspaces_config.yaml | 63 + .../configs/mergeconfigs/input_config.yaml | 192 + .../configs/mergeconfigs/merged1/base1.ocio | 55 + .../configs/mergeconfigs/merged1/input1.ocio | 67 + .../mergeconfigs/merged1/merged1.ociom | 23 + .../configs/mergeconfigs/merged2/base.ocio | 52 + .../configs/mergeconfigs/merged2/input.ocio | 64 + .../configs/mergeconfigs/merged2/merged.ociom | 43 + .../configs/mergeconfigs/merged3/base.ocio | 27 + .../configs/mergeconfigs/merged3/input.ocio | 38 + .../configs/mergeconfigs/merged3/looks.cdl | 42 + .../configs/mergeconfigs/merged3/lut1.clf | 10 + .../configs/mergeconfigs/merged3/merged.ociom | 25 + .../mergeconfigs/merged3/shot1/lut1.clf | 10 + .../mergeconfigs/merged3/shot2/lut1.clf | 10 + .../mergeconfigs/merged3/shot4/lut1.clf | 10 + .../configs/mergeconfigs/merged4/base1.ocio | 52 + .../configs/mergeconfigs/merged4/merged.ociom | 23 + .../configs/mergeconfigs/parser_test.ociom | 47 + .../parser_test_no_overrides.ociom | 47 + tests/utils/StringUtils_tests.cpp | 6 + 49 files changed, 14971 insertions(+), 36 deletions(-) create mode 100644 src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp create mode 100644 src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h create mode 100644 src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp create mode 100644 src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.h create mode 100644 src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp create mode 100644 src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.h create mode 100644 src/apps/ociomergeconfigs/CMakeLists.txt create mode 100644 src/apps/ociomergeconfigs/main.cpp create mode 100644 tests/cpu/ConfigUtils_tests.cpp create mode 100644 tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp create mode 100644 tests/data/files/configs/mergeconfigs/base_colorspaces_config.yaml create mode 100644 tests/data/files/configs/mergeconfigs/base_config.yaml create mode 100644 tests/data/files/configs/mergeconfigs/default_strategy.ociom create mode 100644 tests/data/files/configs/mergeconfigs/input_colorspaces_config.yaml create mode 100644 tests/data/files/configs/mergeconfigs/input_config.yaml create mode 100644 tests/data/files/configs/mergeconfigs/merged1/base1.ocio create mode 100644 tests/data/files/configs/mergeconfigs/merged1/input1.ocio create mode 100644 tests/data/files/configs/mergeconfigs/merged1/merged1.ociom create mode 100644 tests/data/files/configs/mergeconfigs/merged2/base.ocio create mode 100644 tests/data/files/configs/mergeconfigs/merged2/input.ocio create mode 100644 tests/data/files/configs/mergeconfigs/merged2/merged.ociom create mode 100644 tests/data/files/configs/mergeconfigs/merged3/base.ocio create mode 100644 tests/data/files/configs/mergeconfigs/merged3/input.ocio create mode 100644 tests/data/files/configs/mergeconfigs/merged3/looks.cdl create mode 100644 tests/data/files/configs/mergeconfigs/merged3/lut1.clf create mode 100644 tests/data/files/configs/mergeconfigs/merged3/merged.ociom create mode 100644 tests/data/files/configs/mergeconfigs/merged3/shot1/lut1.clf create mode 100644 tests/data/files/configs/mergeconfigs/merged3/shot2/lut1.clf create mode 100644 tests/data/files/configs/mergeconfigs/merged3/shot4/lut1.clf create mode 100644 tests/data/files/configs/mergeconfigs/merged4/base1.ocio create mode 100644 tests/data/files/configs/mergeconfigs/merged4/merged.ociom create mode 100644 tests/data/files/configs/mergeconfigs/parser_test.ociom create mode 100644 tests/data/files/configs/mergeconfigs/parser_test_no_overrides.ociom diff --git a/include/OpenColorIO/OpenColorAppHelpers.h b/include/OpenColorIO/OpenColorAppHelpers.h index e461d1d474..3e5a466ca8 100644 --- a/include/OpenColorIO/OpenColorAppHelpers.h +++ b/include/OpenColorIO/OpenColorAppHelpers.h @@ -521,6 +521,280 @@ class OCIOEXPORT MixingColorSpaceManager extern OCIOEXPORT std::ostream & operator<<(std::ostream &, const MixingColorSpaceManager &); +/** + * The ConfigMergingParameters class represent all the options that a merge can have. + * + * In terms of OCIOM file, it represent one of the merges in a OCIOM file. + * + * Let's take the following OCIOM structure: + * + * ociom_version: 2.1 + * search_path: + * - . + * - subfolder + * merge: + * Merge_ADD_THIS: + * [...] + * Merge_ADD_THAT: + * [...] + * + * In the OCIOM above, there would be two instances of ConfigMergingParameters. + * One for the merge "Merge_ADD_THIS" and one for the merge "Merge_ADD_THAT". + * + * Where the [...] have the following structure: + * Merge1: + * base: base1.ocio + * input: base1.ocio + * options: + * input_family_prefix: "" + * base_family_prefix: "" + * input_first: true + * error_on_conflict: false + * default_strategy: PreferInput + * avoid_duplicates: true + * assume_common_reference_space: false + * overrides: + * name: "" + * description: "" + * search_path: "" + * environment: {} + * active_displays: [] + * active_views: [] + * inactive_colorspaces: [] + * params: + * roles: + * strategy: PreferInput + * [...] + * + */ +class OCIOEXPORT ConfigMergingParameters +{ +public: + + enum MergeStrategies + { + // Merge, pieces from the input config replace those from the base config. + // On conflict, take from input. + STRATEGY_PREFER_INPUT = 0, + // Merge, pieces from the input config are ignored. + // On conflict, take from base. + STRATEGY_PREFER_BASE, + // Don't merge, replace the base content with the content of the input config. + STRATEGY_INPUT_ONLY, + // Don't merge, just keep the base content. + STRATEGY_BASE_ONLY, + // Pieces from the input config are removed from the base config. The prefixes are + // not used in this case. If the names match, the item is removed, even if the content + // is not identical. + STRATEGY_REMOVE, + STRATEGY_UNSET + }; + + // Default object + static ConfigMergingParametersRcPtr Create(); + + ConfigMergingParametersRcPtr createEditableCopy() const; + + void setBaseConfigName(const char * baseConfig); + const char * getBaseConfigName() const; + + void setInputConfigName(const char * inputConfig); + const char * getInputConfigName() const; + + void setOutputName(const char * outputName); + const char * getOutputName() const; + + // Options + void setDefaultStrategy(const ConfigMergingParameters::MergeStrategies strategy); + ConfigMergingParameters::MergeStrategies getDefaultStrategy() const; + + /** + * @brief Set the Input Family Prefix object + * + * The default separator '/' must be used here. + * It will be replaced by the right separator based on the merged parameters. + * + * @param prefix Prefix + */ + void setInputFamilyPrefix(const char * prefix); + const char * getInputFamilyPrefix() const; + + /** + * @brief Set the Base Family Prefix object + * + * The default separator '/' must be used here. + * It will be replaced by the right separator based on the merged parameters. + * + * @param prefix Prefix + */ + void setBaseFamilyPrefix(const char * prefix); + const char * getBaseFamilyPrefix() const; + + void setInputFirst(bool enabled); + bool isInputFirst() const; + + void setErrorOnConflict(bool enabled); + bool isErrorOnConflict() const; + + void setAvoidDuplicates(bool enabled); + bool isAvoidDuplicates() const; + + void setAssumeCommonReferenceSpace(bool enabled); + bool isAssumeCommonReferenceSpace() const; + + // Overrides + void setName(const char * mergedConfigName); + const char * getName() const; + + void setDescription(const char * mergedConfigDesc); + const char * getDescription() const; + + void addEnvironmentVar(const char * name, const char * defaultValue); + int getNumEnvironmentVars() const; + const char * getEnvironmentVar(int index) const; + const char * getEnvironmentVarValue(int index) const; + + void setSearchPath(const char * path); + void addSearchPath(const char * path); + const char * getSearchPath() const; + + void setActiveDisplays(const char * displays); + const char * getActiveDisplays() const; + + void setActiveViews(const char * views); + const char * getActiveViews() const; + + void setInactiveColorspaces(const char * colorspaces); + const char * getInactiveColorSpaces() const; + + //////////// + + // roles + void setRoles(MergeStrategies strategy); + MergeStrategies getRoles() const; + + // file_rules + void setFileRules(MergeStrategies strategy); + MergeStrategies getFileRules() const; + + // Includes shared_views, displays, view_transforms, viewing_rules, virtual_display, + // active_display, active_views and default_view_transform. + void setDisplayViews(MergeStrategies strategy); + MergeStrategies getDisplayViews() const; + + // looks + void setLooks(MergeStrategies strategy); + MergeStrategies getLooks() const; + + // Includes colorspaces, display_colorspaces, environment, + // search_path, family_separator and inactive_colorspaces. + void setColorspaces(MergeStrategies strategy); + MergeStrategies getColorspaces() const; + + // named_transforms + void setNamedTransforms(MergeStrategies strategy); + MergeStrategies getNamedTransforms() const; + + ConfigMergingParameters(const ConfigMergingParameters &) = delete; + ConfigMergingParameters& operator= (const ConfigMergingParameters &) = delete; + + /// Do not use (needed only for pybind11). + ~ConfigMergingParameters(); + +private: + ConfigMergingParameters(); + + static void deleter(ConfigMergingParameters * c); + + class Impl; + Impl * m_impl; + Impl * getImpl() { return m_impl; } + const Impl * getImpl() const { return m_impl; } +}; + +//TODO Not implemented. +extern OCIOEXPORT std::ostream & operator<<(std::ostream &, const ConfigMergingParameters &); + +/** + * The ConfigMerger class is the controller for the merging process. + * + * It is controlling the ociom_version, the search_path to find the base and input config, + * and the merges. + * + * It contains an instance of ConfigMergingParameters for each merges present under the "merge" + * section. + * + */ +class OCIOEXPORT ConfigMerger +{ +public: + static ConfigMergerRcPtr Create(); + + // Create based on the ociom file. + static ConstConfigMergerRcPtr CreateFromFile(const char * filepath); + + ConfigMergerRcPtr createEditableCopy() const; + + void setSearchPath(const char * path); + void addSearchPath(const char * path); + int getNumSearchPaths() const; + const char * getSearchPath(int index) const; + + void setWorkingDir(const char * dirname); + const char * getWorkingDir() const; + + ConfigMergingParametersRcPtr getParams(int index) const; + int getNumOfConfigMergingParameters() const; + void addParams(ConfigMergingParametersRcPtr params); + + void addMergedConfig(ConstConfigRcPtr cfg); + + ConstConfigRcPtr getMergedConfig() const; + ConstConfigRcPtr getMergedConfig(int index) const; + + void serialize(std::ostream& os) const; + + void setMajorVersion(unsigned int major); + void setMinorVersion(unsigned int minor); + void setVersion(unsigned int major, unsigned int minor); + + unsigned int getMajorVersion() const; + unsigned int getMinorVersion() const; + + ConfigMerger(const ConfigMerger &) = delete; + ConfigMerger & operator=(const ConfigMerger &) = delete; + + /// Do not use (needed only for pybind11). + ~ConfigMerger(); + +private: + ConfigMerger(); + + static void deleter(ConfigMerger * c); + + class Impl; + Impl * m_impl; + Impl * getImpl() { return m_impl; } + const Impl * getImpl() const { return m_impl; } +}; + +extern OCIOEXPORT std::ostream & operator<<(std::ostream &, const ColorSpaceMenuHelper &); + +namespace ConfigMergingHelpers +{ +/** + * \brief Execute the merge(s) based on the merger object. + * + * Execute the merge(s) based on the merger object that was previously populated by using + * ConfigMerger::CreateFromFile or created from scratch by using ConfigMerger::Create() and + * programmatically configuring it. + * + * \param merger Merger object + * \return OCIOEXPORT + */ +extern OCIOEXPORT ConstConfigMergerRcPtr MergeConfigs(const ConstConfigMergerRcPtr & merger); +} // ConfigMergingHelpers + } // namespace OCIO_NAMESPACE #endif // INCLUDED_OCIO_OPENCOLORAPPHELPERS_H diff --git a/include/OpenColorIO/OpenColorIO.h b/include/OpenColorIO/OpenColorIO.h index d97a376365..2159a06b94 100644 --- a/include/OpenColorIO/OpenColorIO.h +++ b/include/OpenColorIO/OpenColorIO.h @@ -108,6 +108,48 @@ class OCIOEXPORT ExceptionMissingFile : public Exception ~ExceptionMissingFile(); }; +/** + * \brief An exception class for errors detected while adding a colorspace to a config object. + */ +class OCIOEXPORT ExceptionAddColorspace : public Exception +{ +public: + ExceptionAddColorspace() = delete; + /// Constructor that takes a string as the exception message. + explicit ExceptionAddColorspace(const char *, AddColorspaceError errorCode); + /// Constructor that takes an existing exception. + ExceptionAddColorspace(const ExceptionAddColorspace &); + ExceptionAddColorspace & operator= (const ExceptionAddColorspace &) = delete; + + AddColorspaceError getErrorCode() const noexcept; + + ~ExceptionAddColorspace(); + +private: + AddColorspaceError m_errorCode; +}; + +/** + * \brief An exception class for errors detected while adding a named transform to a config object. + */ +class OCIOEXPORT ExceptionAddNamedTransform: public Exception +{ +public: + ExceptionAddNamedTransform() = delete; + /// Constructor that takes a string as the exception message. + explicit ExceptionAddNamedTransform(const char *, AddNamedTransformError errorCode); + /// Constructor that takes an existing exception. + ExceptionAddNamedTransform(const ExceptionAddNamedTransform &); + ExceptionAddNamedTransform & operator= (const ExceptionAddNamedTransform &) = delete; + + AddNamedTransformError getErrorCode() const noexcept; + + ~ExceptionAddNamedTransform(); + +private: + AddNamedTransformError m_errorCode; +}; + // Restore default warning behaviour for Visual Studio. #ifdef _MSC_VER #pragma warning( pop ) @@ -1279,6 +1321,11 @@ class OCIOEXPORT Config */ void addNamedTransform(const ConstNamedTransformRcPtr & namedTransform); + /** + * \brief Remove a named transform. (Does nothing if name is not found.) + */ + void removeNamedTransform(const char * name); + /// Clear all named transforms. void clearNamedTransforms(); @@ -1690,7 +1737,7 @@ class OCIOEXPORT FileRules /// Does include default rule. Result will be at least 1. size_t getNumEntries() const noexcept; - /// Get the index from the rule name. + /// Get the index from the rule name. Throws if the rule is not found. size_t getIndexForRule(const char * ruleName) const; /// Get name of the rule. diff --git a/include/OpenColorIO/OpenColorTypes.h b/include/OpenColorIO/OpenColorTypes.h index 21243eb363..9cf7fc7343 100644 --- a/include/OpenColorIO/OpenColorTypes.h +++ b/include/OpenColorIO/OpenColorTypes.h @@ -254,6 +254,13 @@ class LegacyViewingPipeline; typedef OCIO_SHARED_PTR LegacyViewingPipelineRcPtr; typedef OCIO_SHARED_PTR ConstLegacyViewingPipelineRcPtr; +class ConfigMergingParameters; +typedef OCIO_SHARED_PTR ConfigMergingParametersRcPtr; +typedef OCIO_SHARED_PTR ConstConfigMergingParametersRcPtr; + +class ConfigMerger; +typedef OCIO_SHARED_PTR ConfigMergerRcPtr; +typedef OCIO_SHARED_PTR ConstConfigMergerRcPtr; template inline OCIO_SHARED_PTR DynamicPtrCast(OCIO_SHARED_PTR const & ptr) @@ -685,6 +692,44 @@ enum ProcessorCacheFlags : unsigned int PROCESSOR_CACHE_DEFAULT = (PROCESSOR_CACHE_ENABLED | PROCESSOR_CACHE_SHARE_DYN_PROPERTIES) }; +// Provides codes for errors if there is any problem when a colorspace is added to a config. +enum AddColorspaceError +{ + ADD_CS_ERROR_NONE = 0, + + ADD_CS_ERROR_EMPTY, + ADD_CS_ERROR_NAME_IDENTICAL_TO_A_ROLE_NAME, + ADD_CS_ERROR_NAME_IDENTICAL_TO_NT_NAME_OR_ALIAS, + ADD_CS_ERROR_NAME_CONTAIN_CTX_VAR_TOKEN, + ADD_CS_ERROR_NAME_IDENTICAL_TO_EXISTING_COLORSPACE_ALIAS, + + ADD_CS_ERROR_ALIAS_IDENTICAL_TO_A_ROLE_NAME, + ADD_CS_ERROR_ALIAS_IDENTICAL_TO_NT_NAME_OR_ALIAS, + ADD_CS_ERROR_ALIAS_CONTAIN_CTX_VAR_TOKEN, + ADD_CS_ERROR_ALIAS_IDENTICAL_TO_EXISTING_COLORSPACE_NAME, + ADD_CS_ERROR_ALIAS_IDENTICAL_TO_EXISTING_COLORSPACE_ALIAS, +}; + +// Provides codes for errors if there is any problem when a named transform is added to a config. +enum AddNamedTransformError +{ + ADD_NT_ERROR_NONE = 0, + + ADD_NT_ERROR_NULL, + ADD_NT_ERROR_EMPTY, + ADD_NT_ERROR_AT_LEAST_ONE_TRANSFORM, + + ADD_NT_ERROR_NAME_IDENTICAL_TO_A_ROLE_NAME, + ADD_NT_ERROR_NAME_IDENTICAL_TO_COLORSPACE_OR_ALIAS, + ADD_NT_ERROR_NAME_CONTAIN_CTX_VAR_TOKEN, + ADD_NT_ERROR_NAME_IDENTICAL_TO_EXISTING_NT_ALIAS, + + ADD_NT_ERROR_ALIAS_IDENTICAL_TO_A_ROLE_NAME, + ADD_NT_ERROR_ALIAS_IDENTICAL_TO_COLORSPACE_OR_ALIAS, + ADD_NT_ERROR_ALIAS_CONTAIN_CTX_VAR_TOKEN, + ADD_NT_ERROR_ALIAS_IDENTICAL_TO_EXISTING_NT_ALIAS +}; + // Conversion extern OCIOEXPORT const char * BoolToString(bool val); diff --git a/src/OpenColorIO/CMakeLists.txt b/src/OpenColorIO/CMakeLists.txt index 7d2894da6b..a5823a46c4 100755 --- a/src/OpenColorIO/CMakeLists.txt +++ b/src/OpenColorIO/CMakeLists.txt @@ -6,6 +6,9 @@ set(SOURCES apphelpers/ColorSpaceHelpers.cpp apphelpers/DisplayViewHelpers.cpp apphelpers/LegacyViewingPipeline.cpp + apphelpers/mergeconfigs/MergeConfigsHelpers.cpp + apphelpers/mergeconfigs/OCIOMYaml.cpp + apphelpers/mergeconfigs/SectionMerger.cpp apphelpers/MixingHelpers.cpp Baker.cpp BakingUtils.cpp diff --git a/src/OpenColorIO/ColorSpaceSet.cpp b/src/OpenColorIO/ColorSpaceSet.cpp index 99c659a61b..cdb30b32b0 100644 --- a/src/OpenColorIO/ColorSpaceSet.cpp +++ b/src/OpenColorIO/ColorSpaceSet.cpp @@ -122,7 +122,8 @@ class ColorSpaceSet::Impl const char * csName = cs->getName(); if (!*csName) { - throw Exception("Cannot add a color space with an empty name."); + throw ExceptionAddColorspace("Cannot add a color space with an empty name.", + ADD_CS_ERROR_EMPTY); } auto entryIdx = getIndex(csName); @@ -137,7 +138,8 @@ class ColorSpaceSet::Impl std::ostringstream os; os << "Cannot add '" << csName << "' color space, existing color space, '"; os << m_colorSpaces[entryIdx]->getName() << "' is using this name as an alias."; - throw Exception(os.str().c_str()); + throw ExceptionAddColorspace(os.str().c_str(), + ADD_CS_ERROR_NAME_IDENTICAL_TO_EXISTING_COLORSPACE_ALIAS); } // There is a color space with the same name that will be replaced (if new color space // can be used). @@ -148,6 +150,7 @@ class ColorSpaceSet::Impl for (size_t aidx = 0; aidx < numAliases; ++aidx) { const char * alias = cs->getAlias(aidx); + // Note that getIndex return the index to either a colorspace or an alias. entryIdx = getIndex(alias); // Is an alias of the color space already used by a color space? // Skip existing colorspace that might be replaced. @@ -156,8 +159,22 @@ class ColorSpaceSet::Impl std::ostringstream os; os << "Cannot add '" << csName << "' color space, it has '" << alias; os << "' alias and existing color space, '"; - os << m_colorSpaces[entryIdx]->getName() << "' is using the same alias."; - throw Exception(os.str().c_str()); + + // Check if entryIdx is a colorspace. + if (entryIdx < size() && StringUtils::Compare(get(entryIdx)->getName(), alias)) + { + // conflict with a colorspace name + os << m_colorSpaces[entryIdx]->getName() << "' has the same name."; + throw ExceptionAddColorspace(os.str().c_str(), + ADD_CS_ERROR_ALIAS_IDENTICAL_TO_EXISTING_COLORSPACE_NAME); + } + else + { + // Conflict with a colorspace alias. + os << m_colorSpaces[entryIdx]->getName() << "' is using the same alias."; + throw ExceptionAddColorspace(os.str().c_str(), + ADD_CS_ERROR_ALIAS_IDENTICAL_TO_EXISTING_COLORSPACE_ALIAS); + } } } if (replaceIdx != (size_t)-1) diff --git a/src/OpenColorIO/Config.cpp b/src/OpenColorIO/Config.cpp index 727d434e9f..11c4dca0c8 100644 --- a/src/OpenColorIO/Config.cpp +++ b/src/OpenColorIO/Config.cpp @@ -1179,8 +1179,8 @@ ConstConfigRcPtr Config::CreateFromFile(const char * filename) throw Exception (os.str().c_str()); } - char magicNumber[2] = { 0 }; - if (ifstream.read(magicNumber, 2)) + char magicNumber[5] = { 0 }; + if (ifstream.read(magicNumber, 5)) { // Check if it is an OCIOZ archive. if (magicNumber[0] == 'P' && magicNumber[1] == 'K') @@ -1197,9 +1197,33 @@ ConstConfigRcPtr Config::CreateFromFile(const char * filename) ciop->buildEntries(); return CreateFromConfigIOProxy(ciop); } + else + { + // *IMPORTANT NOTE* + // It not the most robust method. Comments at the top of the files would break this. + + // Check for "ociom" at the start of the file. (ociom_profile) + if (magicNumber[0] == 'o' && magicNumber[1] == 'c' && + magicNumber[2] == 'i' && magicNumber[3] == 'o' && magicNumber[4] == 'm' ) + { + try + { + ifstream.close(); + + ConstConfigMergerRcPtr merger = ConfigMerger::CreateFromFile(filename); + ConstConfigMergerRcPtr newMerger = ConfigMergingHelpers::MergeConfigs(merger); + // return final merged config. + return newMerger->getMergedConfig(); + } + catch(const Exception & e) + { + throw e; + } + } + } } - // Not an OCIOZ archive. Continue as usual. + // Not an OCIOZ archive or OCIOM file. Continue as usual. ifstream.clear(); ifstream.seekg(0); return Config::Impl::Read(ifstream, filename); @@ -2561,7 +2585,8 @@ void Config::addColorSpace(const ConstColorSpaceRcPtr & original) const std::string name(original->getName()); if (name.empty()) { - throw Exception("Color space must have a non-empty name."); + throw ExceptionAddColorspace("Color space must have a non-empty name.", + ADD_CS_ERROR_EMPTY); } // Check this is not an existing role or named transform. @@ -2570,7 +2595,7 @@ void Config::addColorSpace(const ConstColorSpaceRcPtr & original) std::ostringstream os; os << "Cannot add '" << name << "' color space, there is already a role with this " "name."; - throw Exception(os.str().c_str()); + throw ExceptionAddColorspace(os.str().c_str(), ADD_CS_ERROR_NAME_IDENTICAL_TO_A_ROLE_NAME); } auto nt = getNamedTransform(name.c_str()); if (nt) @@ -2578,7 +2603,8 @@ void Config::addColorSpace(const ConstColorSpaceRcPtr & original) std::ostringstream os; os << "Cannot add '" << name << "' color space, there is already a named transform using " "this name as a name or as an alias: '" << nt->getName() << "'."; - throw Exception(os.str().c_str()); + throw ExceptionAddColorspace(os.str().c_str(), + ADD_CS_ERROR_NAME_IDENTICAL_TO_NT_NAME_OR_ALIAS); } if (getMajorVersion() >= 2 && ContainsContextVariableToken(name)) @@ -2587,7 +2613,8 @@ void Config::addColorSpace(const ConstColorSpaceRcPtr & original) oss << "A color space name '" << name << "' cannot contain a context variable reserved token i.e. % or $."; - throw Exception(oss.str().c_str()); + throw ExceptionAddColorspace(oss.str().c_str(), + ADD_CS_ERROR_NAME_CONTAIN_CTX_VAR_TOKEN); } const size_t numAliases = original->getNumAliases(); @@ -2600,7 +2627,8 @@ void Config::addColorSpace(const ConstColorSpaceRcPtr & original) std::ostringstream os; os << "Cannot add '" << name << "' color space, it has an alias '" << alias << "' and there is already a role with this name."; - throw Exception(os.str().c_str()); + throw ExceptionAddColorspace(os.str().c_str(), + ADD_CS_ERROR_ALIAS_IDENTICAL_TO_A_ROLE_NAME); } auto nt = getNamedTransform(alias); if (nt) @@ -2609,7 +2637,8 @@ void Config::addColorSpace(const ConstColorSpaceRcPtr & original) os << "Cannot add '" << name << "' color space, it has an alias '" << alias << "' and there is already a named transform using this name as a name or as " "an alias: '" << nt->getName() << "'."; - throw Exception(os.str().c_str()); + throw ExceptionAddColorspace(os.str().c_str(), + ADD_CS_ERROR_ALIAS_IDENTICAL_TO_NT_NAME_OR_ALIAS); } if (ContainsContextVariableToken(alias)) { @@ -2617,7 +2646,8 @@ void Config::addColorSpace(const ConstColorSpaceRcPtr & original) os << "Cannot add '" << name << "' color space, it has an alias '" << alias << "' that cannot contain a context variable reserved token i.e. % or $."; - throw Exception(os.str().c_str()); + throw ExceptionAddColorspace(os.str().c_str(), + ADD_CS_ERROR_ALIAS_CONTAIN_CTX_VAR_TOKEN); } } @@ -3152,17 +3182,19 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) { if (!nt) { - throw Exception("Named transform is null."); + throw ExceptionAddNamedTransform("Named transform is null.", ADD_NT_ERROR_NULL); } const std::string name(nt->getName()); if (name.empty()) { - throw Exception("Named transform must have a non-empty name."); + throw ExceptionAddNamedTransform("Named transform must have a non-empty name.", + ADD_NT_ERROR_EMPTY); } if (!nt->getTransform(TRANSFORM_DIR_FORWARD) && !nt->getTransform(TRANSFORM_DIR_INVERSE)) { - throw Exception("Named transform must define at least one transform."); + throw ExceptionAddNamedTransform("Named transform must define at least one transform.", + ADD_NT_ERROR_AT_LEAST_ONE_TRANSFORM); } if (hasRole(name.c_str())) @@ -3170,7 +3202,7 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) std::ostringstream os; os << "Cannot add '" << name << "' named transform, there is already a role with this " "name."; - throw Exception(os.str().c_str()); + throw ExceptionAddNamedTransform(os.str().c_str(), ADD_NT_ERROR_NAME_IDENTICAL_TO_A_ROLE_NAME); } auto cs = getColorSpace(name.c_str()); if (cs) @@ -3178,7 +3210,8 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) std::ostringstream os; os << "Cannot add '" << name << "' named transform, there is already a color space using " "this name as a name or as an alias: '" << cs->getName() << "'."; - throw Exception(os.str().c_str()); + throw ExceptionAddNamedTransform(os.str().c_str(), + ADD_NT_ERROR_NAME_IDENTICAL_TO_COLORSPACE_OR_ALIAS); } if (ContainsContextVariableToken(name)) @@ -3187,7 +3220,7 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) oss << "A named transform name '" << name << "' cannot contain a context variable reserved token i.e. % or $."; - throw Exception(oss.str().c_str()); + throw ExceptionAddNamedTransform(oss.str().c_str(), ADD_NT_ERROR_NAME_CONTAIN_CTX_VAR_TOKEN); } size_t existing = getImpl()->getNamedTransformIndex(name.c_str()); @@ -3202,7 +3235,8 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) std::ostringstream os; os << "Cannot add '" << name << "' named transform, existing named transform, '"; os << existingName << "' is using this name as an alias."; - throw Exception(os.str().c_str()); + throw ExceptionAddNamedTransform(os.str().c_str(), + ADD_NT_ERROR_NAME_IDENTICAL_TO_EXISTING_NT_ALIAS); } // There is a named transform with the same name that will be replaced (if new named // transform can be used). @@ -3219,7 +3253,8 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) std::ostringstream os; os << "Cannot add '" << name << "' named transform, it has an alias '" << alias << "' and there is already a role with this name."; - throw Exception(os.str().c_str()); + throw ExceptionAddNamedTransform(os.str().c_str(), + ADD_NT_ERROR_ALIAS_IDENTICAL_TO_A_ROLE_NAME); } auto cs = getColorSpace(alias); if (cs) @@ -3228,7 +3263,8 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) os << "Cannot add '" << name << "' named transform, it has an alias '" << alias << "' and there is already a color space using this name as a name or as " "an alias: '" << cs->getName() << "'."; - throw Exception(os.str().c_str()); + throw ExceptionAddNamedTransform(os.str().c_str(), + ADD_NT_ERROR_ALIAS_IDENTICAL_TO_COLORSPACE_OR_ALIAS); } if (ContainsContextVariableToken(alias)) { @@ -3236,7 +3272,8 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) oss << "Cannot add '" << name << "' named transform, it has an alias '" << alias << "' that cannot contain a context variable reserved token i.e. % or $."; - throw Exception(oss.str().c_str()); + throw ExceptionAddNamedTransform(oss.str().c_str(), + ADD_NT_ERROR_ALIAS_CONTAIN_CTX_VAR_TOKEN); } existing = getImpl()->getNamedTransformIndex(alias); @@ -3249,7 +3286,8 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) os << "Cannot add '" << name << "' named transform, it has '" << alias; os << "' alias and existing named transform, '"; os << existingName << "' is using the same alias."; - throw Exception(os.str().c_str()); + throw ExceptionAddNamedTransform(os.str().c_str(), + ADD_NT_ERROR_ALIAS_IDENTICAL_TO_EXISTING_NT_ALIAS); } } @@ -3261,7 +3299,8 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) std::ostringstream os; os << "Cannot add '" << name << "' named transform, existing named transform, '"; os << existingName << "' is using this name as an alias."; - throw Exception(os.str().c_str()); + throw ExceptionAddNamedTransform(os.str().c_str(), + ADD_NT_ERROR_ALIAS_IDENTICAL_TO_EXISTING_NT_ALIAS); } NamedTransformRcPtr copy = nt->createEditableCopy(); ConstNamedTransformRcPtr namedTransformCopy = copy; @@ -3279,6 +3318,25 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) getImpl()->refreshActiveColorSpaces(); } +void Config::removeNamedTransform(const char * name) +{ + const std::string nameToSearch = StringUtils::Lower(name); + if (nameToSearch.empty()) return; + + for (auto itr = getImpl()->m_allNamedTransforms.begin(); itr != getImpl()->m_allNamedTransforms.end(); ++itr) + { + if (StringUtils::Lower((*itr)->getName()) == nameToSearch) + { + getImpl()->m_allNamedTransforms.erase(itr); + return; + } + } + + AutoMutex lock(getImpl()->m_cacheidMutex); + getImpl()->resetCacheIDs(); + getImpl()->refreshActiveColorSpaces(); +} + void Config::clearNamedTransforms() { getImpl()->m_allNamedTransforms.clear(); diff --git a/src/OpenColorIO/ConfigUtils.cpp b/src/OpenColorIO/ConfigUtils.cpp index 0b45b04de8..85b7ef14dd 100644 --- a/src/OpenColorIO/ConfigUtils.cpp +++ b/src/OpenColorIO/ConfigUtils.cpp @@ -836,6 +836,325 @@ const char * IdentifyBuiltinColorSpace(const ConstConfigRcPtr & srcConfig, throw Exception(os.str().c_str()); } + +// Simplify a transform by removing nested group transforms and identities. +// +ConstTransformRcPtr simplifyTransform(const ConstGroupTransformRcPtr & gt) +{ + ConstConfigRcPtr config = Config::CreateRaw(); + ConstProcessorRcPtr p = config->getProcessor(gt); + ConstProcessorRcPtr opt = p->getOptimizedProcessor(OPTIMIZATION_DEFAULT); + GroupTransformRcPtr finalGt = opt->createGroupTransform(); + if (finalGt->getNumTransforms() == 1) + { + return finalGt->getTransform(0); + } + return finalGt; +} + +ConstTransformRcPtr invertTransform(const ConstTransformRcPtr & t) +{ + TransformRcPtr eT = t->createEditableCopy(); + eT->setDirection(TRANSFORM_DIR_INVERSE); + return eT; +} + +// Return a transform in either the to_ref or from_ref direction for this color space. +// Return an identity matrix, if the color space has no transforms. +// +ConstTransformRcPtr getTransformForDir(const ConstColorSpaceRcPtr & cs, ColorSpaceDirection dir) +{ + ColorSpaceDirection otherDir = COLORSPACE_DIR_TO_REFERENCE; + if (dir == COLORSPACE_DIR_TO_REFERENCE) + { + otherDir = COLORSPACE_DIR_FROM_REFERENCE; + } + + ConstTransformRcPtr t = cs->getTransform(dir); + if (t) + { + return t; + } + + ConstTransformRcPtr tOther = cs->getTransform(otherDir); + if (tOther) + { + return invertTransform(tOther); + } + + // If it's the reference space, it won't have a transform, so return an identity matrix. + double m44[16]; + double offset4[4]; + MatrixTransform::Identity(m44, offset4); + MatrixTransformRcPtr p = MatrixTransform::Create(); + p->setMatrix(m44); + p->setOffset(offset4); + + return p; +} + +// Get a transform to convert from the source config reference space to the +// destination config reference space. The ref_space_type specifies whether +// to work with the scene-referred or display-referred reference space. +// +ConstTransformRcPtr getRefSpaceConverter(const ConstConfigRcPtr & srcConfig, + const ConstConfigRcPtr & dstConfig, + ReferenceSpaceType refSpaceType) +{ + ConstConfigRcPtr builtinConfig = Config::CreateFromFile("ocio://cg-config-latest"); + + auto getColorspaceOfRefType = [](const ConstConfigRcPtr & config, + ReferenceSpaceType refType) -> const char * + { + // Just return the first one, doesn't matter if it's inactive or a data space. + // All that matters is the reference space type. + // Casting to SearchReferenceSpaceType since they have the same values. + SearchReferenceSpaceType searchRefType = static_cast(refType); + for (int i = 0; i < config->getNumColorSpaces(searchRefType, COLORSPACE_ALL); i++) + { + const char * name = config->getColorSpaceNameByIndex(searchRefType, COLORSPACE_ALL, i); + ConstColorSpaceRcPtr cs = config->getColorSpace(name); + return cs->getName(); + } + + throw Exception("Config is lacking any color spaces of the requested reference space type."); + }; + + // Identify an interchange space for the src config. + // Note that the interchange space will always be a linear color space. + // TODO: IdentifyInterchangeSpace currently fails if the config does not have + // a color space for the reference space. + // TODO: IdentifyInterchangeSpace will fail in the display-referred case if the + // config does not have the cie_xyz_d65_interchange role. + const char * srcInterchange = nullptr; + const char * srcBuiltinInterchange = nullptr; + Config::IdentifyInterchangeSpace(&srcInterchange, + &srcBuiltinInterchange, + srcConfig, + getColorspaceOfRefType(srcConfig, refSpaceType), + builtinConfig, + getColorspaceOfRefType(builtinConfig, refSpaceType)); + + // Identify an interchange space for the dst config. + // Note that the interchange space will always be a linear color space. + const char * dstInterchange = nullptr; + const char * dstBuiltinInterchange = nullptr; + Config::IdentifyInterchangeSpace(&dstInterchange, + &dstBuiltinInterchange, + dstConfig, + getColorspaceOfRefType(dstConfig, refSpaceType), + builtinConfig, + getColorspaceOfRefType(builtinConfig, refSpaceType)); + + // Get the from_ref transform from the srcInterchange space. + ConstTransformRcPtr srcFromRef = getTransformForDir(srcConfig->getColorSpace(srcInterchange), + COLORSPACE_DIR_FROM_REFERENCE); + + // Get a conversion from one builtin interchange to another + ColorSpaceTransformRcPtr cst = ColorSpaceTransform::Create(); + GroupTransformRcPtr srcBuiltinToDstBuiltin; + if (srcBuiltinInterchange && *srcBuiltinInterchange && + dstBuiltinInterchange && *dstBuiltinInterchange) + { + // srcBuiltinInterchange and dstBuiltinInterchange are not empty. + cst->setSrc(srcBuiltinInterchange); + cst->setDst(dstBuiltinInterchange); + + srcBuiltinToDstBuiltin = builtinConfig->getProcessor(cst)->createGroupTransform(); + } + + // Append to_ref transform from the dstInterchange space. + ConstTransformRcPtr dstToRef = getTransformForDir(dstConfig->getColorSpace(dstInterchange), + COLORSPACE_DIR_TO_REFERENCE); + + // Combine into a group transform. + // Note: Some of these pieces may be identities but the whole thing needs to get + // simplified/optimized after being combined with the existing transform anyway + // since one of these pieces may be the inverse of a color space's existing transform. + GroupTransformRcPtr gt = GroupTransform::Create(); + gt->appendTransform(srcFromRef->createEditableCopy()); + gt->appendTransform(srcBuiltinToDstBuiltin); + gt->appendTransform(dstToRef->createEditableCopy()); + + // TODO: Need to ensure that gt would never contain a file transform. + // for (size_t t = 0; t < gt->getNumTransforms(); t++) + // { + // if (gt->getTransform(t)->getTransformType() == TRANSFORM_TYPE_FILE) + // { + // throw Exception("Cannot contain FileTransform."); + // } + // } + return simplifyTransform(gt); +} + +// Update the reference space used by a color space's transforms. +// The argument is a group transform that converts from the current to the new ref. space. +// +void updateReferenceColorspace(ColorSpaceRcPtr & cs, + const ConstTransformRcPtr & toNewReferenceTransform) +{ + if (!toNewReferenceTransform || !cs) + { + std::ostringstream os; + os << "Could not update reference space, converter transform was not initialized."; + throw Exception(os.str().c_str()); + } + + ConstTransformRcPtr transformTo = cs->getTransform(COLORSPACE_DIR_TO_REFERENCE); + if (transformTo) + { + GroupTransformRcPtr gt = GroupTransform::Create(); + gt->appendTransform(transformTo->createEditableCopy()); + gt->appendTransform(toNewReferenceTransform->createEditableCopy()); + + // NB: Don't want to call simplify_transforms on gt since it would do things like + // expand built-in or file transforms. But as a result, there could be transforms that + // appear more complex than necessary. In some cases there could be color spaces + // with transforms present that would actually simplify into an identity. In other + // words there could be color spaces that are effectively the reference space that + // have from_ref or to_ref transforms. + cs->setTransform(gt, COLORSPACE_DIR_TO_REFERENCE); + } + + ConstTransformRcPtr transformFrom = cs->getTransform(COLORSPACE_DIR_FROM_REFERENCE); + if (transformFrom) + { + ConstTransformRcPtr inv = invertTransform(toNewReferenceTransform); + GroupTransformRcPtr gt = GroupTransform::Create(); + gt->appendTransform(inv->createEditableCopy()); + gt->appendTransform(transformFrom->createEditableCopy()); + cs->setTransform(gt, COLORSPACE_DIR_FROM_REFERENCE); + } + + if (transformTo == nullptr && transformFrom == nullptr && !cs->isData()) + { + GroupTransformRcPtr gt = GroupTransform::Create(); + gt->appendTransform(toNewReferenceTransform->createEditableCopy()); + cs->setTransform(gt, COLORSPACE_DIR_TO_REFERENCE); + } +} + +// Update the transforms in a view transform to adapt the reference spaces. +// Note that the from_ref transform converts from the scene-referred reference space to +// the display-referred reference space. +// +void updateReferenceView(ViewTransformRcPtr & vt, + const ConstTransformRcPtr & toNewSceneReferenceTransform, + const ConstTransformRcPtr & toNewDisplayReferenceTransform) +{ + ConstTransformRcPtr transformTo = vt->getTransform(VIEWTRANSFORM_DIR_TO_REFERENCE); + if (transformTo) + { + ConstTransformRcPtr inv = invertTransform(toNewSceneReferenceTransform); + GroupTransformRcPtr gt = GroupTransform::Create(); + gt->appendTransform(inv->createEditableCopy()); + gt->appendTransform(transformTo->createEditableCopy()); + gt->appendTransform(toNewDisplayReferenceTransform->createEditableCopy()); + vt->setTransform(gt, VIEWTRANSFORM_DIR_TO_REFERENCE); + } + + ConstTransformRcPtr transformFrom = vt->getTransform(VIEWTRANSFORM_DIR_FROM_REFERENCE); + if (transformFrom) + { + ConstTransformRcPtr inv = invertTransform(toNewDisplayReferenceTransform); + GroupTransformRcPtr gt = GroupTransform::Create(); + gt->appendTransform(inv->createEditableCopy()); + gt->appendTransform(transformFrom->createEditableCopy()); + gt->appendTransform(toNewSceneReferenceTransform->createEditableCopy()); + vt->setTransform(gt, VIEWTRANSFORM_DIR_FROM_REFERENCE); + } + + // Note that Config::addViewTransform prevents creating a view transform that + // has no transforms, so we may be sure at least one direction will be present. +} + +// If config contains a color space equivalent to new_cs, return its name. +// Return an empty string if no equivalent color space is found (within the tolerance). +// The ref_space_type specifies the type of new_cs and determines which part of the +// config is searched. Note: Normally the refType should be set by simply calling +// newCS->getReferenceSpaceType(). Not sure the extra flexibility to search the +// other ref space type is needed (perhaps drop the option if this gets added to +// the public API). +// +const char * findEquivalentColorspace(const ConstConfigRcPtr & config, + const ConstColorSpaceRcPtr & newCS, + ReferenceSpaceType refType) +{ + // NB: This assumes that new_cs uses the same reference space as config. + // In general, this means that update_color_reference_space must be called on new_cs + // before calling this function. + + if (newCS->isData()) + { + for (int i = 0; i < config->getNumColorSpaces(SEARCH_REFERENCE_SPACE_SCENE, COLORSPACE_ALL); ++i) + { + const char * name = config->getColorSpaceNameByIndex(SEARCH_REFERENCE_SPACE_SCENE, COLORSPACE_ALL, i); + ConstColorSpaceRcPtr cs = config->getColorSpace(name); + if (cs->isData()) + { + return cs->getName(); + } + + } + return ""; + } + + // The heuristics need to create a lot of Processors and send RGB values through + // them to try and identify a known color space. Turn off the Processor cache in + // the configs to avoid polluting the cache with transforms that won't be reused + // and avoid the overhead of maintaining the cache. + SuspendCacheGuard srcGuard(config); + + ConstTransformRcPtr fromRef = getTransformForDir(newCS, COLORSPACE_DIR_FROM_REFERENCE); + + + +// FIXME: Before looping over all color spaces, check to see if there's one with the same name. + + SearchReferenceSpaceType searchRefType = static_cast(refType); + for (int i = 0; i < config->getNumColorSpaces(searchRefType, COLORSPACE_ALL); ++i) + { + const char * name = config->getColorSpaceNameByIndex(searchRefType, COLORSPACE_ALL, i); + ConstColorSpaceRcPtr cs = config->getColorSpace(name); + +// TODO: Need to add isdata check to other heuristics too. + + if (!cs->isData()) + { + ConstTransformRcPtr toRef = getTransformForDir(cs, COLORSPACE_DIR_TO_REFERENCE); + GroupTransformRcPtr gt = GroupTransform::Create(); + gt->appendTransform(toRef->createEditableCopy()); + gt->appendTransform(fromRef->createEditableCopy()); + + auto p = config->getProcessor(gt); + + // Define a set of (somewhat arbitrary) RGB values to test whether the combined transform is + // enough of an identity. + // TODO: Should we check values outside [0,1]? + std::vector vals = { 0.7f, 0.4f, 0.02f, 0.f, + 0.02f, 0.6f, 0.2f, 0.f, + 0.3f, 0.02f, 0.5f, 0.f, + 0.f, 0.f, 0.f, 0.f, + 1.f, 1.f, 1.f, 0.f }; + +// FIXME: THIS BREAKS THE TESTS + +// std::vector vals = { 0.7f, 0.4f, 0.02f, 0.f, +// 0.02f, 0.6f, -0.2f, 0.f, +// 0.3f, 0.02f, 1.5f, 0.f, +// 0.f, 0.f, 0.f, 0.f, +// 1.f, 1.f, 1.f, 0.f }; + + if (isIdentityTransform(p, vals, 1e-3f)) + { + return cs->getName(); + } + } + } + + return ""; +} + } // namespace ConfigUtils } // namespace OCIO_NAMESPACE diff --git a/src/OpenColorIO/ConfigUtils.h b/src/OpenColorIO/ConfigUtils.h index 3d7d00701b..921d9fabf5 100644 --- a/src/OpenColorIO/ConfigUtils.h +++ b/src/OpenColorIO/ConfigUtils.h @@ -31,6 +31,24 @@ const char * IdentifyBuiltinColorSpace(const ConstConfigRcPtr & srcConfig, const ConstConfigRcPtr & builtinConfig, const char * builtinColorSpaceName); +ConstTransformRcPtr simplifyTransform(const ConstGroupTransformRcPtr & gt); +ConstTransformRcPtr invertTransform(const ConstTransformRcPtr & t); +ConstTransformRcPtr getTransformDir(const ConstColorSpaceRcPtr & cs, ColorSpaceDirection dir); + +ConstTransformRcPtr getRefSpaceConverter(const ConstConfigRcPtr & srcConfig, + const ConstConfigRcPtr & dstConfig, + ReferenceSpaceType refSpaceType); + +void updateReferenceColorspace(ColorSpaceRcPtr & cs, + const ConstTransformRcPtr & toNewReferenceTransform); +void updateReferenceView(ViewTransformRcPtr & vt, + const ConstTransformRcPtr & toNewSceneReferenceTransform, + const ConstTransformRcPtr & toNewDisplayReferenceTransform); + +const char * findEquivalentColorspace(const ConstConfigRcPtr & config, + const ConstColorSpaceRcPtr & newCs, + ReferenceSpaceType refType); + // Temporarily deactivate the Processor cache on a Config object. // Currently, this also clears the cache. // diff --git a/src/OpenColorIO/CustomKeys.h b/src/OpenColorIO/CustomKeys.h index 6b93a74d2e..b41b9714ce 100644 --- a/src/OpenColorIO/CustomKeys.h +++ b/src/OpenColorIO/CustomKeys.h @@ -29,17 +29,17 @@ class CustomKeysContainer return m_customKeys.size(); } - const char * getName(size_t key) const + const char * getName(size_t idx) const { - validateIndex(key); - auto cust = std::next(m_customKeys.begin(), key); + validateIndex(idx); + auto cust = std::next(m_customKeys.begin(), idx); return (*cust).first.c_str(); } - const char * getValue(size_t key) const + const char * getValue(size_t idx) const { - validateIndex(key); - auto cust = std::next(m_customKeys.begin(), key); + validateIndex(idx); + auto cust = std::next(m_customKeys.begin(), idx); return (*cust).second.c_str(); } @@ -59,6 +59,18 @@ class CustomKeysContainer } } + bool hasKey(const char * key) + { + std::string s = key; + return m_customKeys.count(s) > 0; + } + + const char * getValueForKey(const char * key) + { + // NB: Will throw if the map doesn't have the key. + return m_customKeys[key].c_str(); + } + private: void validateIndex(size_t key) const { diff --git a/src/OpenColorIO/Exception.cpp b/src/OpenColorIO/Exception.cpp index 061324e138..6c5dbc165b 100644 --- a/src/OpenColorIO/Exception.cpp +++ b/src/OpenColorIO/Exception.cpp @@ -35,5 +35,43 @@ ExceptionMissingFile::~ExceptionMissingFile() { } +ExceptionAddColorspace::ExceptionAddColorspace(const char * msg, AddColorspaceError errorCode) + : Exception(msg), m_errorCode(errorCode) +{ +} + +ExceptionAddColorspace::ExceptionAddColorspace(const ExceptionAddColorspace & e) + : Exception(e) +{ +} + +AddColorspaceError ExceptionAddColorspace::getErrorCode() const noexcept +{ + return m_errorCode; +} + +ExceptionAddColorspace::~ExceptionAddColorspace() +{ +} + +ExceptionAddNamedTransform::ExceptionAddNamedTransform(const char * msg, AddNamedTransformError errorCode) + : Exception(msg), m_errorCode(errorCode) +{ +} + +ExceptionAddNamedTransform::ExceptionAddNamedTransform(const ExceptionAddNamedTransform & e) + : Exception(e) +{ +} + +AddNamedTransformError ExceptionAddNamedTransform::getErrorCode() const noexcept +{ + return m_errorCode; +} + +ExceptionAddNamedTransform::~ExceptionAddNamedTransform() +{ +} + } // namespace OCIO_NAMESPACE diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp new file mode 100644 index 0000000000..643dd913a5 --- /dev/null +++ b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp @@ -0,0 +1,695 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "MergeConfigsHelpers.h" +#include "Logging.h" +#include "ParseUtils.h" +#include "Platform.h" +#include "OCIOMYaml.h" +#include "utils/StringUtils.h" + +namespace OCIO_NAMESPACE +{ + +// +// Config merging feature +// + +/// Private implementation section + +// ... + +/// Public implementation section + +ConfigMergingParameters::ConfigMergingParameters() : m_impl(new ConfigMergingParameters::Impl()) +{ + +} + +ConfigMergingParameters::~ConfigMergingParameters() +{ + delete m_impl; + m_impl = nullptr; +} + +ConfigMergingParametersRcPtr ConfigMergingParameters::Create() +{ + return ConfigMergingParametersRcPtr(new ConfigMergingParameters(), &deleter); +} + +void ConfigMergingParameters::deleter(ConfigMergingParameters * c) +{ + delete c; +} + +//TODO Not implemented +std::ostream & operator<<(std::ostream & os, const ConfigMergingParameters & ms) +{ + (void)ms; + return os; +} + +ConfigMergingParametersRcPtr ConfigMergingParameters::createEditableCopy() const +{ + ConfigMergingParametersRcPtr params = ConfigMergingParameters::Create(); + *params->m_impl = *m_impl; + return params; +} + +void ConfigMergingParameters::setBaseConfigName(const char * baseConfig) +{ + getImpl()->m_baseConfig = baseConfig; +} + +const char * ConfigMergingParameters::getBaseConfigName() const +{ + return getImpl()->m_baseConfig.c_str(); +} + +void ConfigMergingParameters::setInputConfigName(const char * inputConfig) +{ + getImpl()->m_inputConfig = inputConfig; +} + +const char * ConfigMergingParameters::getInputConfigName() const +{ + return getImpl()->m_inputConfig.c_str(); +} + +void ConfigMergingParameters::setName(const char * mergedConfigName) +{ + getImpl()->m_name = mergedConfigName; +} + +const char * ConfigMergingParameters::getName() const +{ + return getImpl()->m_name.c_str(); +} + +const char * ConfigMergingParameters::getDescription() const +{ + return getImpl()->m_description.c_str(); +} + +void ConfigMergingParameters::setDescription(const char * mergedConfigDesc) +{ + getImpl()->m_description = mergedConfigDesc; +} + +void ConfigMergingParameters::addEnvironmentVar(const char * name, const char * defaultValue) +{ + getImpl()->m_overrideCfg->addEnvironmentVar(name, defaultValue); +} + +int ConfigMergingParameters::getNumEnvironmentVars() const +{ + return getImpl()->m_overrideCfg->getNumEnvironmentVars(); +} + +const char * ConfigMergingParameters::getEnvironmentVar(int index) const +{ + return getImpl()->m_overrideCfg->getEnvironmentVarNameByIndex(index); +} + +const char * ConfigMergingParameters::getEnvironmentVarValue(int index) const +{ + const char * name = getImpl()->m_overrideCfg->getEnvironmentVarNameByIndex(index); + return getImpl()->m_overrideCfg->getEnvironmentVarDefault(name); +} + +void ConfigMergingParameters::setSearchPath(const char * path) +{ + getImpl()->m_overrideCfg->setSearchPath(path); +} + +void ConfigMergingParameters::addSearchPath(const char * path) +{ + getImpl()->m_overrideCfg->addSearchPath(path); +} + +const char * ConfigMergingParameters::getSearchPath() const +{ + return getImpl()->m_overrideCfg->getSearchPath(); +} + +void ConfigMergingParameters::setActiveDisplays(const char * displays) +{ + getImpl()->m_overrideCfg->setActiveDisplays(displays); +} + +const char * ConfigMergingParameters::getActiveDisplays() const +{ + return getImpl()->m_overrideCfg->getActiveDisplays(); +} + +void ConfigMergingParameters::setActiveViews(const char * views) +{ + getImpl()->m_overrideCfg->setActiveViews(views); +} + +const char * ConfigMergingParameters::getActiveViews() const +{ + return getImpl()->m_overrideCfg->getActiveViews(); +} + +void ConfigMergingParameters::setInactiveColorspaces(const char * colorspaces) +{ + getImpl()->m_overrideCfg->setInactiveColorSpaces(colorspaces); +} + +const char * ConfigMergingParameters::getInactiveColorSpaces() const +{ + return getImpl()->m_overrideCfg->getInactiveColorSpaces(); +} + +void ConfigMergingParameters::setOutputName(const char * outputName) +{ + getImpl()->m_outputName = outputName; +} + +const char * ConfigMergingParameters::getOutputName() const +{ + return getImpl()->m_outputName.c_str(); +} + +void ConfigMergingParameters::setDefaultStrategy(const MergeStrategies strategy) +{ + getImpl()->m_defaultStrategy = strategy; +} + +ConfigMergingParameters::MergeStrategies ConfigMergingParameters::getDefaultStrategy() const +{ + return getImpl()->m_defaultStrategy; +} + +void ConfigMergingParameters::setInputFamilyPrefix(const char * prefix) +{ + getImpl()->m_inputFamilyPrefix = prefix; +} + +const char * ConfigMergingParameters::getInputFamilyPrefix() const +{ + return getImpl()->m_inputFamilyPrefix.c_str(); +} + +void ConfigMergingParameters::setBaseFamilyPrefix(const char * prefix) +{ + getImpl()->m_baseFamilyPrefix = prefix; +} + +const char * ConfigMergingParameters::getBaseFamilyPrefix() const +{ + return getImpl()->m_baseFamilyPrefix.c_str(); +} + +void ConfigMergingParameters::setInputFirst(bool enabled) +{ + getImpl()->m_inputFirst = enabled; +} + +bool ConfigMergingParameters::isInputFirst() const +{ + return getImpl()->m_inputFirst; +} + +void ConfigMergingParameters::setErrorOnConflict(bool enabled) +{ + getImpl()->m_errorOnConflict = enabled; +} + +bool ConfigMergingParameters::isErrorOnConflict() const +{ + return getImpl()->m_errorOnConflict; +} + +void ConfigMergingParameters::setAvoidDuplicates(bool enabled) +{ + getImpl()->m_avoidDuplicates = enabled; +} + +bool ConfigMergingParameters::isAvoidDuplicates() const +{ + return getImpl()->m_avoidDuplicates; +} + +void ConfigMergingParameters::setAssumeCommonReferenceSpace(bool enabled) +{ + getImpl()->m_assumeCommonReferenceSpace = enabled; +} + +bool ConfigMergingParameters::isAssumeCommonReferenceSpace() const +{ + return getImpl()->m_assumeCommonReferenceSpace; +} + +void ConfigMergingParameters::setRoles(MergeStrategies strategy) +{ + getImpl()->m_roles = strategy; +} + +ConfigMergingParameters::MergeStrategies ConfigMergingParameters::getRoles() const +{ + if (getImpl()->m_roles == MergeStrategies::STRATEGY_UNSET) + { + return getDefaultStrategy(); + } + return getImpl()->m_roles; +} + +void ConfigMergingParameters::setFileRules(MergeStrategies strategy) +{ + getImpl()->m_fileRules = strategy; +} + +ConfigMergingParameters::MergeStrategies ConfigMergingParameters::getFileRules() const +{ + if (getImpl()->m_fileRules == MergeStrategies::STRATEGY_UNSET) + { + return getDefaultStrategy(); + } + return getImpl()->m_fileRules; +} + +void ConfigMergingParameters::setDisplayViews(MergeStrategies strategy) +{ + getImpl()->m_displayViews = strategy; +} + +ConfigMergingParameters::MergeStrategies ConfigMergingParameters::getDisplayViews() const +{ + if (getImpl()->m_displayViews == MergeStrategies::STRATEGY_UNSET) + { + return getDefaultStrategy(); + } + return getImpl()->m_displayViews; +} + +void ConfigMergingParameters::setLooks(MergeStrategies strategy) +{ + getImpl()->m_looks = strategy; +} + +ConfigMergingParameters::MergeStrategies ConfigMergingParameters::getLooks() const +{ + if (getImpl()->m_looks == MergeStrategies::STRATEGY_UNSET) + { + return getDefaultStrategy(); + } + return getImpl()->m_looks; +} + +void ConfigMergingParameters::setColorspaces(MergeStrategies strategy) +{ + getImpl()->m_colorspaces = strategy; +} + +ConfigMergingParameters::MergeStrategies ConfigMergingParameters::getColorspaces() const +{ + if (getImpl()->m_colorspaces == MergeStrategies::STRATEGY_UNSET) + { + return getDefaultStrategy(); + } + return getImpl()->m_colorspaces; +} + +void ConfigMergingParameters::setNamedTransforms(MergeStrategies strategy) +{ + getImpl()->m_namedTransforms = strategy; +} + +ConfigMergingParameters::MergeStrategies ConfigMergingParameters::getNamedTransforms() const +{ + if (getImpl()->m_namedTransforms == MergeStrategies::STRATEGY_UNSET) + { + return getDefaultStrategy(); + } + return getImpl()->m_namedTransforms; +} + +///////////////////////////////////////// +// Implementation ConfigMerger +///////////////////////////////////////// + +// Private + +ConstConfigMergerRcPtr ConfigMerger::Impl::Read(std::istream & istream, const char * filepath) +{ + OCIOMYaml ociomParser; + ConfigMergerRcPtr merger; + + try + { + YAML::Node node = YAML::Load(istream); + int numOfMerges = ociomParser.countMerges(node); + + merger = ConfigMerger::Create(); + + // Create the number of ConfigMergingParametersRcPtr needed. + for (int i = 0; i < numOfMerges; i++) + { + ConfigMergingParametersRcPtr params = ConfigMergingParameters::Create(); + merger->getImpl()->mergesParams.push_back(params); + } + + ociomParser.load(node, merger, filepath); + + // Look at each set of Params and check if there are any 'Unset' sections. + // If so, initialize them to the default strategy. + // If there are no default, use PreferInput. + } + catch(const std::exception & e) + { + std::ostringstream os; + os << "Error: Loading the OCIOM Merge parameters "; + os << "'" << filepath << "' failed. " << e.what(); + throw Exception(os.str().c_str()); + } + + return merger; +} + +ConstConfigRcPtr ConfigMerger::Impl::loadConfig(const char * value) const +{ + try + { + // Try to load the provided config name as a file. + return Config::CreateFromFile(value); + } + catch(...) { /* don't capture the exception */ } + + // Try to load the provided base config name as a built-in config. + try + { + // Check if the base config name is a built-in config. + return Config::CreateFromBuiltinConfig(value); + } + catch(...) { /* don't capture the exception */ } + + // Must be a reference to a config from a previous merge. + for (int i = 0; i < getNumOfConfigMergingParameters(); i++) + { + if (Platform::Strcasecmp(getParams(i)->getOutputName(), value) == 0) + { + // Use the config from the index. + if (i < mergedConfigs.size()) + { + return mergedConfigs.at(i); + } + } + } + + return nullptr; +} + +// Public + +ConfigMerger::ConfigMerger() : m_impl(new ConfigMerger::Impl()) +{ + +} + +ConfigMerger::~ConfigMerger() +{ + delete m_impl; + m_impl = nullptr; +} + +ConfigMergerRcPtr ConfigMerger::Create() +{ + return ConfigMergerRcPtr(new ConfigMerger(), &deleter); +} + +ConstConfigMergerRcPtr ConfigMerger::CreateFromFile(const char * filepath) +{ + if (!filepath || !*filepath) + { + throw ExceptionMissingFile ("The merge options filepath is missing."); + } + + std::ifstream ifstream = Platform::CreateInputFileStream( + filepath, + std::ios_base::in | std::ios_base::binary + ); + + if (ifstream.fail()) + { + std::ostringstream os; + os << "Error could not read '" << filepath; + os << "' merge options."; + throw Exception (os.str().c_str()); + } + + return ConfigMerger::Impl::Read(ifstream, filepath); +} + +ConfigMergerRcPtr ConfigMerger::createEditableCopy() const +{ + ConfigMergerRcPtr merger = ConfigMerger::Create(); + *merger->m_impl = *m_impl; + return merger; +} + +void ConfigMerger::deleter(ConfigMerger * c) +{ + delete c; +} + +int ConfigMerger::getNumSearchPaths() const +{ + return (int)getImpl()->m_searchPaths.size(); +} + +const char * ConfigMerger::getSearchPath(int index) const +{ + if (index < 0 || index >= (int)getImpl()->m_searchPaths.size()) return ""; + return getImpl()->m_searchPaths[index].c_str(); +} + +void ConfigMerger::setSearchPath(const char * path) +{ + getImpl()->m_searchPaths = StringUtils::Split(path ? path : "", ':'); +} + +void ConfigMerger::addSearchPath(const char * path) +{ + if (path && *path) + { + getImpl()->m_searchPaths.emplace_back(path ? path : ""); + } +} + +void ConfigMerger::setWorkingDir(const char * dirname) +{ + getImpl()->m_workingDir = dirname; +} + +const char * ConfigMerger::getWorkingDir() const +{ + return getImpl()->m_workingDir.c_str(); +} + +ConfigMergingParametersRcPtr ConfigMerger::getParams(int index) const +{ + if (index < static_cast(getImpl()->mergesParams.size())) + { + return getImpl()->mergesParams.at(index); + } + return nullptr; +} + +int ConfigMerger::getNumOfConfigMergingParameters() const +{ + return static_cast(getImpl()->mergesParams.size()); +} + +void ConfigMerger::addParams(ConfigMergingParametersRcPtr params) +{ + getImpl()->mergesParams.push_back(params); +} + +void ConfigMerger::serialize(std::ostream& os) const +{ + try + { + OCIOMYaml ociom; + ociom.write(os, *this); + } + catch (const std::exception & e) + { + std::ostringstream error; + error << "Error building YAML: " << e.what(); + throw Exception(error.str().c_str()); + } +} + +unsigned int ConfigMerger::getMajorVersion() const +{ + return getImpl()->m_majorVersion; +} + +void ConfigMerger::setMajorVersion(unsigned int version) +{ + getImpl()->m_majorVersion = version; +} + +unsigned int ConfigMerger::getMinorVersion() const +{ + return getImpl()->m_minorVersion; +} + +void ConfigMerger::setMinorVersion(unsigned int version) +{ + getImpl()->m_minorVersion = version; +} + +void ConfigMerger::setVersion(unsigned int major, unsigned int minor) +{ + setMajorVersion(major); + setMinorVersion(minor); +} + +void ConfigMerger::addMergedConfig(ConstConfigRcPtr cfg) +{ + getImpl()->mergedConfigs.push_back(cfg); +} + +ConstConfigRcPtr ConfigMerger::getMergedConfig() const +{ + return getMergedConfig(static_cast(getImpl()->mergedConfigs.size() - 1)); +} + +ConstConfigRcPtr ConfigMerger::getMergedConfig(int index) const +{ + if (index < static_cast(getImpl()->mergedConfigs.size())) + { + return getImpl()->mergedConfigs.at(index); + } + return nullptr; +} + +namespace ConfigMergingHelpers +{ + +ConstConfigRcPtr loadConfig(const ConfigMergerRcPtr merger, + const char * value) +{ + // Get the absolute path. + StringUtils::StringVec searchpaths; + + if (merger->getNumSearchPaths() == 0) + { + merger->addSearchPath(merger->getWorkingDir()); + } + + for (int i = 0; i < merger->getNumSearchPaths(); ++i) + { + // Resolve variables in case the expansion adds slashes. + const std::string path = merger->getSearchPath(i); + + // Remove trailing "/", and spaces. + std::string dirname = StringUtils::RightTrim(StringUtils::Trim(path), '/'); + + if (!pystring::os::path::isabs(dirname)) + { + dirname = pystring::os::path::join(merger->getWorkingDir(), dirname); + } + + searchpaths.push_back(pystring::os::path::normpath(dirname)); + } + + for (size_t i = 0; i < searchpaths.size(); ++i) + { + try + { + // Try to load the provided config using the searchpaths. + // Return as soon as they a valid path. + const std::string resolvedfullpath = pystring::os::path::join(searchpaths[i], + value); + return Config::CreateFromFile(resolvedfullpath.c_str()); + } + catch(...) { /* don't capture the exception */ } + } + + // Try to load the provided base config name as a built-in config. + try + { + // Check if the base config name is a built-in config. + return Config::CreateFromBuiltinConfig(value); + } + catch(...) { /* don't capture the exception */ } + + // Must be a reference to a config from a previous merge. + for (int i = 0; i < merger->getNumOfConfigMergingParameters(); i++) + { + if (Platform::Strcasecmp(merger->getParams(i)->getOutputName(), value) == 0) + { + // Use the config from the index. + return merger->getMergedConfig(i); + } + } + + return nullptr; +} + +ConstConfigMergerRcPtr MergeConfigs(const ConstConfigMergerRcPtr & merger) +{ + ConfigMergerRcPtr editableMerger = merger->createEditableCopy(); + + for (int i = 0; i < merger->getNumOfConfigMergingParameters(); i++) + { + ConstConfigMergingParametersRcPtr params = merger->getParams(i); + + // Load base config. + ConstConfigRcPtr baseCfg = loadConfig(editableMerger, params->getBaseConfigName()); + + // Load input config. + ConstConfigRcPtr inputCfg = loadConfig(editableMerger, params->getInputConfigName()); + + if (baseCfg && inputCfg) + { + // Create a copy of the base config. + ConfigRcPtr mergedConfig = baseCfg->createEditableCopy(); + + // Process merge. + try + { + MergeHandlerOptions options = { baseCfg, inputCfg, merger->getParams(i), mergedConfig }; + GeneralMerger(options).merge(); + RolesMerger(options).merge(); + FileRulesMerger(options).merge(); + DisplayViewMerger(options).merge(); + LooksMerger(options).merge(); + ColorspacesMerger(options).merge(); + NamedTransformsMerger(options).merge(); + } + catch(const Exception & e) + { + throw(e); + } + + // Add new config object to mergedConfigs so they can be used for following merges. + editableMerger->addMergedConfig(mergedConfig); + } + else + { + throw(Exception("Could not load the base or the input config")); + } + } + + return editableMerger; +} + +} // ConfigMergingHelpers + +} // namespace OCIO_NAMESPACE diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h new file mode 100644 index 0000000000..4e2d54af17 --- /dev/null +++ b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + + +#ifndef INCLUDED_OCIO_MERGE_CONFIG_HELPERS_H +#define INCLUDED_OCIO_MERGE_CONFIG_HELPERS_H + +#include +#include +#include + +#include + +#include "SectionMerger.h" +#include "utils/StringUtils.h" +#include "Logging.h" + +namespace OCIO_NAMESPACE +{ + +class ConfigMergingParameters::Impl +{ +public: + std::string m_baseConfig; + std::string m_inputConfig; + std::string m_outputName; + + // overrides + std::string m_name; + std::string m_description; + std::vector m_searchPaths; + StringUtils::StringVec m_activeDisplays; + StringUtils::StringVec m_activeViews; + StringUtils::StringVec m_inactiveColorspaces; + mutable std::string m_activeDisplaysStr; + mutable std::string m_activeViewsStr; + mutable std::string m_inactiveColorSpaceStr; + + // Used to store the overrides for the following sections: + // search_path, active_displays, active_views and inactive_colorspace. + ConfigRcPtr m_overrideCfg; + + // Options + std::string m_inputFamilyPrefix; + std::string m_baseFamilyPrefix; + bool m_inputFirst; + bool m_errorOnConflict; + bool m_avoidDuplicates; + bool m_assumeCommonReferenceSpace; + + // Strategies + MergeStrategies m_defaultStrategy; + MergeStrategies m_roles; + MergeStrategies m_fileRules; + // Includes shared_views, displays, view_transforms, viewing_rules, virtual_display, + // active_display, active_views and default_view_transform. + MergeStrategies m_displayViews; + MergeStrategies m_looks; + // colorspace, environment, search_path, family_separator and inactive_colorspaces + MergeStrategies m_colorspaces; + MergeStrategies m_namedTransforms; + + Impl() + { + m_baseConfig = ""; + m_inputConfig = ""; + m_outputName = "merged"; + + // Overrides + m_name = ""; + m_description = ""; + m_overrideCfg = Config::Create(); + m_overrideCfg->clearEnvironmentVars(); + + // Options + m_defaultStrategy = STRATEGY_PREFER_INPUT; + m_inputFamilyPrefix = ""; + m_baseFamilyPrefix = ""; + m_inputFirst = true; + m_errorOnConflict = false; + m_avoidDuplicates = true; + m_assumeCommonReferenceSpace = false; + + m_roles = STRATEGY_UNSET; + m_fileRules = STRATEGY_UNSET; + m_displayViews = STRATEGY_UNSET; + m_looks = STRATEGY_UNSET; + m_colorspaces = STRATEGY_UNSET; + m_namedTransforms = STRATEGY_UNSET; + } + + ~Impl() = default; + Impl(const Impl&) = delete; + + Impl& operator= (const Impl & rhs) + { + if(this!=&rhs) + { + m_baseConfig = rhs.m_baseConfig; + m_inputConfig = rhs.m_inputConfig; + m_outputName = rhs.m_outputName; + + // Overrides + m_name = rhs.m_name; + m_description = rhs.m_description; + m_searchPaths = rhs.m_searchPaths; + + // Options + m_defaultStrategy = rhs.m_defaultStrategy; + m_inputFamilyPrefix = rhs.m_inputFamilyPrefix; + m_baseFamilyPrefix = rhs.m_baseFamilyPrefix; + m_inputFirst = rhs.m_inputFirst; + m_errorOnConflict = rhs.m_errorOnConflict; + m_avoidDuplicates = rhs.m_avoidDuplicates; + m_assumeCommonReferenceSpace = rhs.m_assumeCommonReferenceSpace; + + m_roles = rhs.m_roles; + m_fileRules = rhs.m_fileRules; + m_displayViews = rhs.m_displayViews; + m_looks = rhs.m_looks; + m_colorspaces = rhs.m_colorspaces; + m_namedTransforms = rhs.m_namedTransforms; + } + return *this; + } +}; + +class ConfigMerger::Impl +{ +public: + StringUtils::StringVec m_searchPaths; + std::string m_workingDir; + + unsigned int m_majorVersion; + unsigned int m_minorVersion; + + std::vector mergesParams; + std::vector mergedConfigs; + + Impl() + { + + } + + ~Impl() = default; + Impl(const Impl&) = delete; + + Impl& operator= (const Impl & rhs) + { + if(this != &rhs) + { + m_searchPaths = rhs.m_searchPaths; + m_workingDir = rhs.m_workingDir; + m_majorVersion = rhs.m_majorVersion; + m_minorVersion = rhs.m_minorVersion; + + mergesParams.clear(); + mergesParams.reserve(rhs.mergesParams.size()); + for (const auto & param : rhs.mergesParams) + { + mergesParams.push_back(param->createEditableCopy()); + } + + mergedConfigs.clear(); + mergedConfigs.reserve(rhs.mergedConfigs.size()); + for (const auto & config : rhs.mergedConfigs) + { + mergedConfigs.push_back(config->createEditableCopy()); + } + } + return *this; + } + + static ConstConfigMergerRcPtr Read(std::istream & istream, const char * filepath); + + /** + * \brief Load the config based on the name/filepath specified. + * + * Here's the steps: + * 1 - Try to find the config name/filepath using the search_paths. + * 2 - If not found, try to use the name as a built-in config's name. + * 3 - If not found, try to use the name as the output of a previous merge. + * 4 - If still not found, return an empty config object. + */ + ConstConfigRcPtr loadConfig(const char * value) const; + + ConfigMergingParametersRcPtr getParams(int index) const + { + if (index >= 0 && index < static_cast(mergesParams.size())) + { + return nullptr; + } + return mergesParams.at(index); + } + + int getNumOfConfigMergingParameters() const + { + return static_cast(mergesParams.size()); + } +}; + +} // namespace OCIO_NAMESPACE + +#endif // INCLUDED_OCIO_MERGE_CONFIG_HELPERS_H diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp new file mode 100644 index 0000000000..4baee5d175 --- /dev/null +++ b/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp @@ -0,0 +1,625 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + +#include +#include +#include + +#include + +#include + +#include "Logging.h" +#include "OCIOMYaml.h" +#include "ParseUtils.h" +#include "PathUtils.h" +#include "utils/StringUtils.h" +#include "yaml-cpp/yaml.h" + +namespace OCIO_NAMESPACE +{ + +OCIOMYaml::OCIOMYaml() +{ + m_mergeStrategiesMap["PreferInput"] = ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT; + m_mergeStrategiesMap["PreferBase"] = ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_BASE; + m_mergeStrategiesMap["InputOnly"] = ConfigMergingParameters::MergeStrategies::STRATEGY_INPUT_ONLY; + m_mergeStrategiesMap["BaseOnly"] = ConfigMergingParameters::MergeStrategies::STRATEGY_BASE_ONLY; + m_mergeStrategiesMap["Remove"] = ConfigMergingParameters::MergeStrategies::STRATEGY_REMOVE; +} + +inline void OCIOMYaml::load(const YAML::Node & node, std::string & x) +{ + try + { + x = node.as(); + } + catch (const std::exception & e) + { + std::ostringstream os; + os << "At line " << (node.Mark().line + 1) + << ", '" << node.Tag() << "' parsing string failed " + << "with: " << e.what(); + throw Exception(os.str().c_str()); + } +} + +inline void OCIOMYaml::load(const YAML::Node & node, std::vector & x) +{ + try + { + x = node.as>(); + } + catch (const std::exception & e) + { + std::ostringstream os; + os << "At line " << (node.Mark().line + 1) + << ", '" << node.Tag() << "' parsing StringVec failed " + << "with: " << e.what(); + throw Exception(os.str().c_str()); + } +} + +inline void OCIOMYaml::throwValueError(const std::string & nodeName, + const YAML::Node & key, + const std::string & msg) +{ + std::string keyName; + load(key, keyName); + + std::ostringstream os; + os << "At line " << (key.Mark().line + 1) + << ", the value parsing of the property '" << keyName + << "' from '" << nodeName << "' failed: " << msg; + + throw Exception(os.str().c_str()); +} + +inline void OCIOMYaml::CheckDuplicates(const YAML::Node & node) +{ + std::unordered_set keyset; + + for (YAML::const_iterator iter = node.begin(); iter != node.end(); ++iter) + { + const std::string & key = iter->first.as(); + if (keyset.find(key) == keyset.end()) + { + keyset.insert(key); + } + else + { + std::ostringstream os; + os << "Key-value pair with key '" << key; + os << "' specified more than once. "; + throwValueError(node.Tag(), iter->first, os.str()); + } + } +} +ConfigMergingParameters::MergeStrategies OCIOMYaml::strategyToEnum(const char * enumStr) const +{ + auto it = m_mergeStrategiesMap.find(enumStr); + if (it != m_mergeStrategiesMap.end()) + { + return it->second; + } + + return ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET; +} + + +ConfigMergingParameters::MergeStrategies OCIOMYaml::genericStrategyHandler(const YAML::Node & pnode, const YAML::Node & node) +{ + if(node.Type() != YAML::NodeType::Map) + { + throwValueError(node.Tag(), pnode, + "The value type of a property 'strategy' needs to be a map."); + } + + std::string strategy; + for (YAML::const_iterator it = node.begin(); it != node.end(); ++it) + { + const std::string & prop = it->first.as(); + const std::string & value = it->second.as(); + + if (prop == "strategy") + { + strategy = value; + } + } + + auto srategyEnum = strategyToEnum(strategy.c_str()); + if (srategyEnum == ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET) + { + std::ostringstream os; + os << "The value '" << strategy; + os << "' is not recognized. "; + throwValueError(node.Tag(), pnode, os.str()); + } + return srategyEnum; +} + +void OCIOMYaml::loadOptions(const YAML::Node & node, ConfigMergingParametersRcPtr & params) +{ + CheckDuplicates(node); + + for (YAML::const_iterator it = node.begin(); it != node.end(); ++it) + { + const std::string & key = it->first.as(); + if (key == "input_family_prefix") + { + params->setInputFamilyPrefix(it->second.as().c_str()); + } + else if (key == "base_family_prefix") + { + params->setBaseFamilyPrefix(it->second.as().c_str()); + } + else if (key == "input_first") + { + params->setInputFirst(it->second.as()); + } + else if (key == "error_on_conflict") + { + params->setErrorOnConflict(it->second.as()); + } + else if (key == "avoid_duplicates") + { + params->setAvoidDuplicates(it->second.as()); + } + else if (key == "assume_common_reference_space") + { + params->setAssumeCommonReferenceSpace(it->second.as()); + } + else if (key == "default_strategy") + { + const std::string & strategy = it->second.as(); + auto srategyEnum = strategyToEnum(strategy.c_str()); + if (srategyEnum == ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET) + { + std::ostringstream os; + os << "The value '" << strategy; + os << "' is not recognized. "; + throwValueError(node.Tag(), it->first, os.str()); + } + params->setDefaultStrategy(srategyEnum); + } + } +} + +void OCIOMYaml::loadOverrides(const YAML::Node & node, ConfigMergingParametersRcPtr & params) +{ + CheckDuplicates(node); + + std::string stringval; + + for (YAML::const_iterator it = node.begin(); it != node.end(); ++it) + { + const std::string & key = it->first.as(); + + if (it->second.IsNull() || !it->second.IsDefined()) continue; + + if (key == "name") + { + load(it->second, stringval); + params->setName(stringval.c_str()); + } + else if (key == "description") + { + load(it->second, stringval); + params->setDescription(stringval.c_str()); + } + else if (key == "search_path") + { + if (it->second.size() == 0) + { + load(it->second, stringval); + params->setSearchPath(stringval.c_str()); + } + else + { + std::vector paths; + load(it->second, paths); + for (const auto & path : paths) + { + params->addSearchPath(path.c_str()); + } + } + } + else if (key == "environment") + { + if(it->second.Type() != YAML::NodeType::Map) + { + throwValueError(node.Tag(), it->first, + "The value type of key 'environment' needs to be a map."); + } + for (YAML::const_iterator itEnv = it->second.begin(); itEnv != it->second.end(); ++itEnv) + { + const std::string & k = itEnv->first.as(); + const std::string & v = itEnv->second.as(); + params->addEnvironmentVar(k.c_str(), v.c_str()); + } + } + else if (key == "active_displays") + { + std::vector display; + load(it->second, display); + std::string displays = StringUtils::Join(display, ','); + params->setActiveDisplays(displays.c_str()); + } + else if (key == "active_views") + { + std::vector view; + load(it->second, view); + std::string views = StringUtils::Join(view, ','); + params->setActiveViews(views.c_str()); + } + else if (key == "inactive_colorspaces") + { + std::vector inactiveCSs; + load(it->second, inactiveCSs); + const std::string inactivecCSsStr = StringUtils::Join(inactiveCSs, ','); + params->setInactiveColorspaces(inactivecCSsStr.c_str()); + } + } +} + +void OCIOMYaml::loadParams(const YAML::Node & node, ConfigMergingParametersRcPtr & params) +{ + // Check for duplicates in params. + CheckDuplicates(node); + + for (YAML::const_iterator it = node.begin(); it != node.end(); ++it) + { + const std::string & key = it->first.as(); + if (key == "roles") + { + params->setRoles(genericStrategyHandler(it->first, it->second)); + } + else if (key == "file_rules") + { + params->setFileRules(genericStrategyHandler(it->first, it->second)); + } + else if (key == "display-views") + { + params->setDisplayViews(genericStrategyHandler(it->first, it->second)); + } + else if (key == "looks") + { + params->setLooks(genericStrategyHandler(it->first, it->second)); + } + else if (key == "colorspaces") + { + params->setColorspaces(genericStrategyHandler(it->first, it->second)); + } + else if (key == "named_transform") + { + params->setNamedTransforms(genericStrategyHandler(it->first, it->second)); + } + else + { + // Handle unsupported property or use default handler. + std::cout << "Unsupported property : " << key << std::endl; + } + } +} + +void OCIOMYaml::load(const YAML::Node& node, ConfigMergerRcPtr & merger, const char * filename) +{ + CheckDuplicates(node); + + // Parse all properties. + for (YAML::const_iterator it = node.begin(); it != node.end(); ++it) + { + const std::string & key = it->first.as(); + + if (it->second.IsNull() || !it->second.IsDefined()) continue; + + if (key == "ociom_version") + { + std::string version; + std::vector results; + + load(node["ociom_version"], version); + results = StringUtils::Split(version, '.'); + + if(results.size() == 1) + { + merger->setMajorVersion(std::stoi(results[0].c_str())); + } + else if(results.size() == 2) + { + merger->setMajorVersion(std::stoi(results[0].c_str())); + merger->setMinorVersion(std::stoi(results[1].c_str())); + } + } + else if (key == "search_path") + { + if (it->second.size() == 0) + { + std::string stringval; + load(it->second, stringval); + merger->setSearchPath(stringval.c_str()); + } + else + { + StringUtils::StringVec paths; + load(it->second, paths); + for (const auto & path : paths) + { + merger->addSearchPath(path.c_str()); + } + } + } + else if (key == "merge") + { + if(it->second.Type() != YAML::NodeType::Map) + { + throwValueError(it->second.Tag(), it->first, + "The value type of the key 'merge' needs to be a map."); + } + + int mergesCounter = 0; + for (YAML::const_iterator mergeIt = it->second.begin(); mergeIt != it->second.end(); ++mergeIt) + { + const std::string & mergedConfigName = mergeIt->first.as(); + ConfigMergingParametersRcPtr params = merger->getParams(mergesCounter); + params->setOutputName(mergedConfigName.c_str()); + + for (YAML::const_iterator paramsIt = mergeIt->second.begin(); paramsIt != mergeIt->second.end(); ++paramsIt) + { + const std::string & key = paramsIt->first.as(); + + if (key == "base") + { + params->setBaseConfigName(paramsIt->second.as().c_str()); + } + else if (key == "input") + { + params->setInputConfigName(paramsIt->second.as().c_str()); + } + else if (key == "options") + { + loadOptions(paramsIt->second, params); + } + else if (key == "overrides") + { + loadOverrides(paramsIt->second, params); + } + else if (key == "params") + { + loadParams(paramsIt->second, params); + } + } + mergesCounter++; + } + } + + if (filename && filename[0]) + { + // Working directory defaults to the directory of the OCIOM file. + std::string realfilename = AbsPath(filename); + std::string configrootdir = pystring::os::path::dirname(realfilename); + merger->setWorkingDir(configrootdir.c_str()); + } + } +} + +int OCIOMYaml::countMerges(const YAML::Node& node) +{ + int numOfMerges = 0; + + CheckDuplicates(node); + + // Parse all properties. + for (YAML::const_iterator it = node.begin(); it != node.end(); ++it) + { + const std::string & key = it->first.as(); + + if (it->second.IsNull() || !it->second.IsDefined()) continue; + + if (key == "merge") + { + if(it->second.Type() != YAML::NodeType::Map) + { + throwValueError(it->second.Tag(), it->first, + "The value type of the key 'merge' needs to be a map."); + } + + CheckDuplicates(it->second); + + for (YAML::const_iterator mergeIt = it->second.begin(); mergeIt != it->second.end(); ++mergeIt) + { + numOfMerges++; + } + } + } + + return numOfMerges; +} + +void OCIOMYaml::read(std::istream & istream, ConfigMergerRcPtr & merger, const char * filepath) +{ + try + { + YAML::Node node = YAML::Load(istream); + load(node, merger, filepath); + } + catch(const std::exception & e) + { + std::ostringstream os; + os << "Error: Loading the OCIOM Merge parameters "; + os << "'" << filepath << "' failed. " << e.what(); + throw Exception(os.str().c_str()); + } +} + +const char * stategyEnumToString(ConfigMergingParameters::MergeStrategies strategy) +{ + switch (strategy) + { + case ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT: + return "PreferInput"; + break; + case ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_BASE: + return "PreferBase"; + break; + case ConfigMergingParameters::MergeStrategies::STRATEGY_INPUT_ONLY: + return "InputOnly"; + break; + case ConfigMergingParameters::MergeStrategies::STRATEGY_BASE_ONLY: + return "BaseOnly"; + break; + case ConfigMergingParameters::MergeStrategies::STRATEGY_REMOVE: + return "Remove"; + break; + case ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET: + return "Unset"; + break; + default: + return "Unknown"; + break; + } +} + +inline void save(YAML::Emitter & out, const ConfigMerger & merger) +{ + std::stringstream ss; + const unsigned parserMajorVersion = merger.getMajorVersion(); + ss << parserMajorVersion; + if (merger.getMinorVersion() != 0) + { + ss << "." << merger.getMinorVersion(); + } + + out << YAML::Block; + out << YAML::BeginMap; + out << YAML::Key << "ociom_version" << YAML::Value << ss.str(); + out << YAML::Key << "search_path"; + out << YAML::Value << YAML::BeginSeq; + for (int i = 0; i < merger.getNumSearchPaths(); i++) + { + out << YAML::Value << merger.getSearchPath(i); + } + out << YAML::EndSeq; + out << YAML::Newline; + + out << YAML::Key << "merge"; + out << YAML::Value << YAML::BeginMap; + + for (int mp = 0; mp < merger.getNumOfConfigMergingParameters(); mp++) + { + // Serialized every merge section. + ConfigMergingParametersRcPtr p = merger.getParams(mp); + out << YAML::Key << p->getOutputName(); + out << YAML::Value << YAML::BeginMap; + + out << YAML::Key << "base" << YAML::Value << p->getBaseConfigName(); + out << YAML::Key << "input" << YAML::Value << p->getBaseConfigName(); + out << YAML::Newline; + + out << YAML::Key << "options"; + out << YAML::Value << YAML::BeginMap; + out << YAML::Key << "input_family_prefix" << YAML::Value << p->getInputFamilyPrefix(); + out << YAML::Key << "base_family_prefix" << YAML::Value << p->getBaseFamilyPrefix(); + out << YAML::Key << "input_first" << YAML::Value << p->isInputFirst(); + out << YAML::Key << "error_on_conflict" << YAML::Value << p->isErrorOnConflict(); + out << YAML::Key << "default_strategy" << YAML::Value << stategyEnumToString(p->getDefaultStrategy()); + out << YAML::Key << "avoid_duplicates" << YAML::Value << p->isAvoidDuplicates(); + out << YAML::Key << "assume_common_reference_space" << YAML::Value << p->isAssumeCommonReferenceSpace(); + // End of options section. + out << YAML::EndMap; + out << YAML::Newline; + + out << YAML::Key << "overrides"; + out << YAML::Value << YAML::BeginMap; + out << YAML::Key << "name" << YAML::Value << p->getName(); + out << YAML::Key << "description" << YAML::Value << p->getDescription(); + out << YAML::Key << "search_path" << YAML::Value << p->getSearchPath(); + + out << YAML::Key << "environment"; + out << YAML::Value << YAML::BeginMap; + for(int i = 0; i < p->getNumEnvironmentVars(); ++i) + { + const char* name = p->getEnvironmentVar(i); + out << YAML::Key << name; + out << YAML::Value << p->getEnvironmentVarValue(i); + } + out << YAML::EndMap; + out << YAML::Newline; + + out << YAML::Key << "active_displays"; + StringUtils::StringVec active_displays; + if (p->getActiveDisplays() != NULL && strlen(p->getActiveDisplays()) > 0) + active_displays = SplitStringEnvStyle(p->getActiveDisplays()); + out << YAML::Value << YAML::Flow << active_displays; + out << YAML::Newline; + + out << YAML::Key << "active_views"; + StringUtils::StringVec active_views; + if (p->getActiveViews() != NULL && strlen(p->getActiveViews()) > 0) + active_views = SplitStringEnvStyle(p->getActiveViews()); + out << YAML::Value << YAML::Flow << active_views; + + out << YAML::Key << "inactive_colorspaces"; + StringUtils::StringVec inactive_colorspaces; + if (p->getInactiveColorSpaces() != NULL && strlen(p->getInactiveColorSpaces()) > 0) + inactive_colorspaces = SplitStringEnvStyle(p->getInactiveColorSpaces()); + out << YAML::Value << YAML::Flow << inactive_colorspaces; + + // End of overrides section. + out << YAML::EndMap; + out << YAML::Newline; + + out << YAML::Key << "params"; + out << YAML::Value << YAML::BeginMap; + + out << YAML::Key << "roles"; + out << YAML::Value << YAML::BeginMap; + out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getRoles()); + out << YAML::EndMap; + + out << YAML::Key << "file_rules"; + out << YAML::Value << YAML::BeginMap; + out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getRoles()); + out << YAML::EndMap; + + out << YAML::Key << "display-views"; + out << YAML::Value << YAML::BeginMap; + out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getRoles()); + out << YAML::EndMap; + + out << YAML::Key << "looks"; + out << YAML::Value << YAML::BeginMap; + out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getRoles()); + out << YAML::EndMap; + + out << YAML::Key << "colorspaces"; + out << YAML::Value << YAML::BeginMap; + out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getRoles()); + out << YAML::EndMap; + + out << YAML::Key << "named_transform"; + out << YAML::Value << YAML::BeginMap; + out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getRoles()); + out << YAML::EndMap; + + // End of params section. + out << YAML::EndMap; + + // End of the current merge section. + out << YAML::EndMap; + } + + // End of the merges. + out << YAML::EndMap; + + out << YAML::EndMap; +} + +void OCIOMYaml::write(std::ostream & ostream, const ConfigMerger & merger) +{ + YAML::Emitter out; + save(out, merger); + ostream << out.c_str(); +} + +} // namespace OCIO_NAMESPACE diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.h b/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.h new file mode 100644 index 0000000000..d7f3ae4014 --- /dev/null +++ b/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.h @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + +#include +#include + +#include +#include "yaml-cpp/yaml.h" + +#ifndef INCLUDED_OCIOM_YAML_H +#define INCLUDED_OCIOM_YAML_H + +namespace OCIO_NAMESPACE +{ + +// Handles the OCIOM file parsing. +class OCIOMYaml +{ +public: + OCIOMYaml(); + ~OCIOMYaml() = default; + + void throwValueError(const std::string & nodeName, + const YAML::Node & key, + const std::string & msg); + void CheckDuplicates(const YAML::Node & node); + + /** + * \brief Load the options section. + */ + void loadOptions(const YAML::Node & node, ConfigMergingParametersRcPtr & params); + /** + * \brief Load the overrides section. + */ + void loadOverrides(const YAML::Node & node, ConfigMergingParametersRcPtr & params); + /** + * \brief Load the params section. + */ + void loadParams(const YAML::Node & node, ConfigMergingParametersRcPtr & params); + + ConfigMergingParameters::MergeStrategies genericStrategyHandler(const YAML::Node & pnode, const YAML::Node & node); + + /** + * \brief Converts a string into a ConfigMergingParameters::MergeStrategies enum. + */ + ConfigMergingParameters::MergeStrategies strategyToEnum(const char * enumStr) const; + + void read(std::istream & istream, ConfigMergerRcPtr & merger, const char * filepath); + void write(std::ostream & ostream, const ConfigMerger & merger); + + void load(const YAML::Node & node, std::string & x); + void load(const YAML::Node & node, std::vector & x); + + /** + * \brief Load a OCIOM file. + */ + void load(const YAML::Node& node, ConfigMergerRcPtr & merger, const char * filename); + + /** + * \brief Counts the number of merges in an OCIOM file to calculate the right number of + * objects to create. + */ + int countMerges(const YAML::Node& node); + +private: + std::unordered_map m_mergeStrategiesMap; +}; + +} // namespace OCIO_NAMESPACE + +#endif // INCLUDED_OCIOM_YAML_H diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp new file mode 100644 index 0000000000..dab1a1f17b --- /dev/null +++ b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp @@ -0,0 +1,3999 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "ConfigUtils.h" +#include "CustomKeys.h" +#include "Logging.h" +#include "OCIOMYaml.h" +#include "ParseUtils.h" +#include "Platform.h" +#include "SectionMerger.h" +#include "TokensManager.h" +#include "utils/StringUtils.h" + +namespace OCIO_NAMESPACE +{ + +namespace +{ + +// void printStrVec(const StringUtils::StringVec str) +// { +// for (int i=0; i (baseMajor * 100 + baseMinor)) + { + major = inputMajor; + minor = inputMinor; + } + + // A merge always produces at least a v2 config. + const unsigned int minMajor = 2u; + const unsigned int minMinor = 0u; + + if ((minMajor * 100 + minMinor) > (major * 100 + minor)) + { + major = minMajor; + minor = minMinor; + } + + config->setVersion(major, minor); +} + +} // anon. + + +void GeneralMerger::handlePreferInput() +{ + // Set the config Name. + const char * name = m_params->getName(); + if (name && *name) + { + // Use name from override. + m_mergedConfig->setName(name); + } + else + { + // TODO: If empty, take it from the other config? + m_mergedConfig->setName(m_inputConfig->getName()); + } + + // Set the config description. + const char * desc = m_params->getDescription(); + if (desc && *desc) + { + // Use description from override. + m_mergedConfig->setDescription(desc); + } + else + { + // TODO: If empty, take it from the other config? + m_mergedConfig->setDescription(m_inputConfig->getDescription()); + } + + // Use the higher value for ocio_profile_version. + setMergedConfigVersion(m_mergedConfig, + m_inputConfig->getMajorVersion(), + m_inputConfig->getMinorVersion(), + m_baseConfig->getMajorVersion(), + m_baseConfig->getMinorVersion()); + + double rgb[3]; + m_inputConfig->getDefaultLumaCoefs(rgb); + m_mergedConfig->setDefaultLumaCoefs(rgb); +} + +void GeneralMerger::handlePreferBase() +{ + // Set the config Name. + const char * name = m_params->getName(); + if (name && *name) + { + // Use name from override. + m_mergedConfig->setName(name); + } + else + { + // TODO: If empty, take it from the other config? + m_mergedConfig->setName(m_baseConfig->getName()); + } + + // Set the config description. + const char * desc = m_params->getDescription(); + if (desc && *desc) + { + // Use description from override. + m_mergedConfig->setDescription(desc); + } + else + { + // TODO: If empty, take it from the other config? + m_mergedConfig->setDescription(m_baseConfig->getDescription()); + } + + // Use the higher value for ocio_profile_version. + setMergedConfigVersion(m_mergedConfig, + m_inputConfig->getMajorVersion(), + m_inputConfig->getMinorVersion(), + m_baseConfig->getMajorVersion(), + m_baseConfig->getMinorVersion()); + + double rgb[3]; + m_baseConfig->getDefaultLumaCoefs(rgb); + m_mergedConfig->setDefaultLumaCoefs(rgb); +} + +void GeneralMerger::handleInputOnly() +{ + // Set the config Name. + const char * name = m_params->getName(); + if (name && *name) + { + // Use name from override. + m_mergedConfig->setName(name); + } + else + { + m_mergedConfig->setName(m_inputConfig->getName()); + } + + // Set the config description. + const char * desc = m_params->getDescription(); + if (desc && *desc) + { + // Use description from override. + m_mergedConfig->setDescription(desc); + } + else + { + m_mergedConfig->setDescription(m_inputConfig->getDescription()); + } + + setMergedConfigVersion(m_mergedConfig, + m_inputConfig->getMajorVersion(), + m_inputConfig->getMinorVersion(), + 0u, // ignore base + 0u); + + double rgb[3]; + m_inputConfig->getDefaultLumaCoefs(rgb); + m_mergedConfig->setDefaultLumaCoefs(rgb); +} + +void GeneralMerger::handleBaseOnly() +{ + // Set the config Name. + const char * name = m_params->getName(); + if (name && *name) + { + // Use name from override. + m_mergedConfig->setName(name); + } + else + { + m_mergedConfig->setName(m_baseConfig->getName()); + } + + // Set the config description. + const char * desc = m_params->getDescription(); + if (desc && *desc) + { + // Use description from override. + m_mergedConfig->setDescription(desc); + } + else + { + m_mergedConfig->setDescription(m_baseConfig->getDescription()); + } + + setMergedConfigVersion(m_mergedConfig, + 0u, // ignore input + 0u, + m_baseConfig->getMajorVersion(), + m_baseConfig->getMinorVersion()); + + double rgb[3]; + m_baseConfig->getDefaultLumaCoefs(rgb); + m_mergedConfig->setDefaultLumaCoefs(rgb); +} + +////////////////////////////////// GeneralMerger end ///////////////////////////////////// + +bool hasAlias(const ConstColorSpaceRcPtr & cs, const char * aliasName) +{ + if (cs) + { + for (size_t i = 0; i < cs->getNumAliases(); i++) + { + if (Platform::Strcasecmp(cs->getAlias(i), aliasName) == 0) + return true; + } + } + return false; +} + +bool hasAlias(const ConstNamedTransformRcPtr & nt, const char * aliasName) +{ + if (nt) + { + for (size_t i = 0; i < nt->getNumAliases(); i++) + { + if (Platform::Strcasecmp(nt->getAlias(i), aliasName) == 0) + return true; + } + } + return false; +} + +////////////////////////////////////////// RolesMerger /////////////////////////////////// + +void RolesMerger::mergeInputRoles() +{ + // Insert roles from input config. + for (int i = 0; i < m_inputConfig->getNumRoles(); i++) + { + const char * name = m_inputConfig->getRoleName(i); + const char * roleColorSpaceName = m_inputConfig->getRoleColorSpace(name); + + if (m_mergedConfig->hasRole(name)) + { + // The base config already has this role. + const char * baseRoleColorSpaceName = m_mergedConfig->getRoleColorSpace(name); + + const ConfigMergingParameters::MergeStrategies strategy = m_params->getRoles(); + if (Platform::Strcasecmp(roleColorSpaceName, baseRoleColorSpaceName) != 0) + { + // The color spaces are different. Replace based on the strategy. + if (strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT + || strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_INPUT_ONLY) + { + + m_mergedConfig->setRole(name, roleColorSpaceName); + } + + std::ostringstream os; + os << "The Input config contains a role that would override Base config role '"; + os << name << "'."; + notify(os.str(), m_params->isErrorOnConflict()); + } + continue; + } + + // Check for any conflicts. Not allowing input roles to override color spaces + // or named transforms in the base config. The merge strategy only applies to + // overriding base config roles. + + ConstColorSpaceRcPtr existingCS = m_mergedConfig->getColorSpace(name); + if (existingCS) + { + // There is a conflict, figure out what it is. + + std::ostringstream os; + if (Platform::Strcasecmp(existingCS->getName(), name) == 0) + { + os << "The Input config contains a role '" << name << "' that would override Base config color space '"; + os << existingCS->getName() << "'."; + } + else if (hasAlias(existingCS, name)) + { + os << "The Input config contains a role '" << name << "' that would override an alias of Base config color space '"; + os << existingCS->getName() << "'."; + } + else // (Should never happen.) + { + std::ostringstream os; + os << "Problem merging role: '" << name << "' due to color space conflict."; + throw Exception(os.str().c_str()); + } + + notify(os.str(), m_params->isErrorOnConflict()); + continue; + } + + ConstNamedTransformRcPtr existingNT = m_mergedConfig->getNamedTransform(name); + if (existingNT) + { + // There is a conflict, figure out what it is. + + std::ostringstream os; + if (Platform::Strcasecmp(existingNT->getName(), name) == 0) + { + os << "The Input config contains a role '" << name << "' that would override Base config named transform: '"; + os << existingNT->getName() << "'."; + } + else if (hasAlias(existingNT, name)) + { + os << "The Input config contains a role '" << name << "' that would override an alias of Base config named transform: '"; + os << existingNT->getName() << "'."; + } + else // (Should never happen.) + { + std::ostringstream os; + os << "Problem merging role: '" << name << "'."; + throw Exception(os.str().c_str()); + } + + notify(os.str(), m_params->isErrorOnConflict()); + continue; + } + + // No conflicts, go ahead and merge it. + m_mergedConfig->setRole(name, roleColorSpaceName); + } +} + +void RolesMerger::handlePreferInput() +{ + mergeInputRoles(); +} + +void RolesMerger::handlePreferBase() +{ + mergeInputRoles(); +} + +void RolesMerger::handleInputOnly() +{ + // Remove the roles from base and take the roles from input. + for (int i = 0; i < m_baseConfig->getNumRoles(); i++) + { + // Unset role from base config. + m_mergedConfig->setRole(m_baseConfig->getRoleName(i), nullptr); + } + + // Insert roles from input config. + mergeInputRoles(); +} + +void RolesMerger::handleBaseOnly() +{ + // Nothing to do, since the merged config is initialized from the base config. +} + +void RolesMerger::handleRemove() +{ + for (int i = 0; i < m_inputConfig->getNumRoles(); i++) + { + if (m_mergedConfig->hasRole(m_inputConfig->getRoleName(i))) + { + // Remove the role. + m_mergedConfig->setRole(m_inputConfig->getRoleName(i), nullptr); + } + } +} + +////////////////////////////////////// RolesMerger end /////////////////////////////////// + +//////////////////////////////////////// FileRulesMerger ///////////////////////////////// + +bool fileRulesAreEqual(const ConstFileRulesRcPtr & f1, + size_t f1Idx, + const ConstFileRulesRcPtr & f2, + size_t f2Idx) +{ + // NB: No need to compare the name of the rules, that should be done in the caller. + + // Compare color space name, pattern, extension, and regex strings. + + if (Platform::Strcasecmp(f1->getColorSpace(f1Idx), f2->getColorSpace(f2Idx)) != 0 || + Platform::Strcasecmp(f1->getPattern(f1Idx), f2->getPattern(f2Idx)) != 0 || + Platform::Strcasecmp(f1->getRegex(f1Idx), f2->getRegex(f2Idx)) != 0 || + Platform::Strcasecmp(f1->getExtension(f1Idx), f2->getExtension(f2Idx)) != 0) + { + return false; + } + + // Compare the custom keys, handling the case where they may be in a different order. + + if (f1->getNumCustomKeys(f1Idx) != f2->getNumCustomKeys(f2Idx)) + { + return false; + } + + CustomKeysContainer f1CustomKeys; + for (size_t m = 0; m < f1->getNumCustomKeys(f1Idx); m++) + { + f1CustomKeys.set(f1->getCustomKeyName(f1Idx, m), f1->getCustomKeyValue(f1Idx, m)); + } + + for (size_t m = 0; m < f2->getNumCustomKeys(f2Idx); m++) + { + if (!f1CustomKeys.hasKey(f2->getCustomKeyName(f2Idx, m))) + { + return false; + } + else + { + if (Platform::Strcasecmp(f1CustomKeys.getValueForKey(f2->getCustomKeyName(f2Idx, m)), + f2->getCustomKeyValue(f2Idx, m)) != 0) + { + return false; + } + } + } + + return true; +} + +void copyRule(const ConstFileRulesRcPtr & input, // rule source + size_t inputRuleIdx, // rule source index + FileRulesRcPtr & merged, // rule dest + size_t mergedRuleIdx) // rule dest index +{ + // Handle case where the rule is ColorSpaceNamePathSearch. + + const char * name = input->getName(inputRuleIdx); + if (Platform::Strcasecmp(name, FileRules::FilePathSearchRuleName) == 0) + { + merged->insertPathSearchRule(mergedRuleIdx); + return; + } + + // Normal rule case. + + const char * regex = input->getRegex(inputRuleIdx); + if (!regex || !*regex) + { + // The regex is empty --> handle it as a pattern & extension type rule. + const char * pattern = input->getPattern(inputRuleIdx); + const char * extension = input->getExtension(inputRuleIdx); + merged->insertRule(mergedRuleIdx, + name, + input->getColorSpace(inputRuleIdx), + (!pattern || !*pattern) ? "*" : pattern, + (!extension || !*extension) ? "*" : extension); + } + else + { + // Handle it as a regex type rule. + merged->insertRule(mergedRuleIdx, + name, + input->getColorSpace(inputRuleIdx), + regex); + } + + // Copy over any custom keys. + + for (size_t k = 0; k < input->getNumCustomKeys(inputRuleIdx); k++) + { + merged->setCustomKey(mergedRuleIdx, + input->getCustomKeyName(inputRuleIdx, k), + input->getCustomKeyValue(inputRuleIdx, k)); + } +} + +void FileRulesMerger::addRulesIfNotPresent(const ConstFileRulesRcPtr & input, + FileRulesRcPtr & merged) const +{ + for (size_t inputRuleIdx = 0; inputRuleIdx < input->getNumEntries(); inputRuleIdx++) + { + bool hasConflict = false; + + try + { + // Check if the rule is already present. + const char * name = input->getName(inputRuleIdx); + + // This will throw if the merged rules don't contain this name. + size_t mergedRuleIdx = merged->getIndexForRule(name); + + // Based on the name, this file rule exists in the merged config. + + // If the rules are not identical, need to report conflict. + if (!fileRulesAreEqual(merged, mergedRuleIdx, input, inputRuleIdx)) + { + hasConflict = true; + + std::ostringstream os; + os << "The Input config contains a value that would override "; + os << "the Base config: file_rules: " << name; + throw Exception(os.str().c_str()); + } + } + catch(const Exception & e) + { + if (hasConflict) + { + // Log or throw an exception describing the conflict. + notify(e.what(), m_params->isErrorOnConflict()); + } + else + { + // File rule does not exist, add it in the penultimate positon, before the default. + // (Note that a default rule is always present, so will never get here in that case.) + copyRule(input, inputRuleIdx, merged, merged->getNumEntries() - 1); + } + } + } +} + +void FileRulesMerger::addRulesAndOverwrite(const ConstFileRulesRcPtr & input, + FileRulesRcPtr & merged) const +{ + for (size_t inputRuleIdx = 0; inputRuleIdx < input->getNumEntries(); inputRuleIdx++) + { + bool hasConflict = false; + + const char * name = input->getName(inputRuleIdx); + try + { + // Check if the rule is already present, throw if it is not. + size_t mergedRuleIdx = merged->getIndexForRule(name); + + if (!fileRulesAreEqual(merged, mergedRuleIdx, input, inputRuleIdx)) + { + hasConflict = true; + + // Overwrite the existing rule. + if (Platform::Strcasecmp(name, FileRules::DefaultRuleName) != 0) + { + merged->removeRule(mergedRuleIdx); + copyRule(input, inputRuleIdx, merged, mergedRuleIdx); + } + else + { + merged->setDefaultRuleColorSpace(input->getColorSpace(inputRuleIdx)); + } + + std::ostringstream os; + os << "The Input config contains a value that would override "; + os << "the Base config: file_rules: " << name; + throw Exception(os.str().c_str()); + } + } + catch(const Exception & e) + { + if (hasConflict) + { + notify(e.what(), m_params->isErrorOnConflict()); + } + else + { + // File rule does not exist, add it in the penultimate positon, before the default. + // (Note that a default rule is always present, so will never get here in that case.) + copyRule(input, inputRuleIdx, merged, merged->getNumEntries() - 1); + } + } + } +} + +void FileRulesMerger::handlePreferInput() +{ + ConstFileRulesRcPtr baseFr = m_baseConfig->getFileRules(); + ConstFileRulesRcPtr inputFr = m_inputConfig->getFileRules(); + + // Handle strictparsing. + m_mergedConfig->setStrictParsingEnabled(m_inputConfig->isStrictParsingEnabled()); + + // Technique depends on whether the input rules should go first or not. + if (m_params->isInputFirst()) + { + // Copying file rules from input config. + FileRulesRcPtr mergedFileRules = inputFr->createEditableCopy(); + // Insert file rules from base config, if not present. + // If it doesn't exist, add it right before the default rule. + addRulesIfNotPresent(baseFr, mergedFileRules); + m_mergedConfig->setFileRules(mergedFileRules); + } + else + { + // Copying file rules from base config. + FileRulesRcPtr mergedFileRules = baseFr->createEditableCopy(); + // Insert file rules from input config. + // If the rule already exists, overwrite it. + // If it doesn't exist, add it right before the default rule. + addRulesAndOverwrite(inputFr, mergedFileRules); + m_mergedConfig->setFileRules(mergedFileRules); + } +} + +void FileRulesMerger::handlePreferBase() +{ + ConstFileRulesRcPtr baseFr = m_baseConfig->getFileRules(); + ConstFileRulesRcPtr inputFr = m_inputConfig->getFileRules(); + + // Handle strictparsing. + // Nothing to do. Keep the base config value. + + // Technique depends on whether the input rules should go first or not. + if (m_params->isInputFirst()) + { + // Copying file rules from input config. + FileRulesRcPtr mergedFileRules = inputFr->createEditableCopy(); + // Insert file rules from base config. + // If the rule already exists, overwrite it. + // If it doesn't exist, add it right before the default rule. + addRulesAndOverwrite(baseFr, mergedFileRules); + m_mergedConfig->setFileRules(mergedFileRules); + } + else + { + // Copying file rules from base config. + FileRulesRcPtr mergedFileRules = baseFr->createEditableCopy(); + // Insert file rules from input config, if not present. + // If it doesn't exist, add it right before the default rule. + addRulesIfNotPresent(inputFr, mergedFileRules); + m_mergedConfig->setFileRules(mergedFileRules); + } +} + +void FileRulesMerger::handleInputOnly() +{ + // Handle strictparsing. + m_mergedConfig->setStrictParsingEnabled(m_inputConfig->isStrictParsingEnabled()); + + // Simply take the rules from the input config. + m_mergedConfig->setFileRules(m_inputConfig->getFileRules()->createEditableCopy()); +} + +void FileRulesMerger::handleBaseOnly() +{ + // Supported, but nothing to do. +} + +void FileRulesMerger::handleRemove() +{ + ConstFileRulesRcPtr inputFr = m_inputConfig->getFileRules(); + FileRulesRcPtr mergedFileRules = m_baseConfig->getFileRules()->createEditableCopy(); + + for (size_t f = 0; f < inputFr->getNumEntries(); f++) + { + const char * name = inputFr->getName(f); + + // Never remove the Default rule. + if (Platform::Strcasecmp(name, FileRules::DefaultRuleName) == 0) + { + continue; + } + + // Check if the input rule name is present in the base config. + try + { + // Will throw if the name is not present. + size_t idx = mergedFileRules->getIndexForRule(name); + + // Remove the rule (regardless of whether the content matches the base config). + mergedFileRules->removeRule(idx); + } + catch(...) + { + // Do nothing if it is not present. + } + } + m_mergedConfig->setFileRules(mergedFileRules); +} + +//////////////////////////////////// FileRulesMerger end ///////////////////////////////// + +/////////////////////////////////////// DisplayViewMerger //////////////////////////////// + +namespace +{ + +bool displayHasView(const ConstConfigRcPtr & cfg, const char * dispName, const char * viewName) +{ + // This returns null if either the display or view doesn't exist. + // It works regardless of whether the display or view are active, + // and it works regardless of whether the view is display-defined + // or if the display has this as a shared view. + // + // It will only check config level shared views if dispName is null. + // It will not check config level shared views if dispName is not null. + const char * cs = cfg->getDisplayViewColorSpaceName(dispName, viewName); + + // All views must have a color space, so if it's not empty, the view exists. + return (cs && *cs); +} + +bool hasVirtualView(const ConstConfigRcPtr & cfg, const char * viewName) +{ + const char * cs = cfg->getVirtualDisplayViewColorSpaceName(viewName); + + // All views must have a color space, so if it's not empty, the view exists. + return (cs && *cs); +} + +void clearSharedViews(ConfigRcPtr & cfg) +{ + int numViews = cfg->getNumViews(VIEW_SHARED, nullptr); + for (int v = numViews - 1; v >= 0; v--) + { + const char * sharedViewName = cfg->getView(VIEW_SHARED, nullptr, v); + if (sharedViewName && *sharedViewName) + { + cfg->removeSharedView(sharedViewName); + } + } +} + +bool viewIsShared(const ConstConfigRcPtr & cfg, + const char * dispName, + const char * viewName) +{ + // Check if a view within a given display is a display-defined view or is referencing + // one of the config's shared views. + + for (int v = 0; v < cfg->getNumViews(VIEW_SHARED, dispName); v++) + { + const char * sharedViewName = cfg->getView(VIEW_SHARED, dispName, v); + if (sharedViewName && *sharedViewName && Platform::Strcasecmp(sharedViewName, viewName) == 0) + { + return true; + } + } + + return false; +} + +bool virtualViewIsShared(const ConstConfigRcPtr & cfg, + const char * viewName) +{ + for (int v = 0; v < cfg->getVirtualDisplayNumViews(VIEW_SHARED); v++) + { + const char * sharedViewName = cfg->getVirtualDisplayView(VIEW_SHARED, v); + if (sharedViewName && *sharedViewName && Platform::Strcasecmp(sharedViewName, viewName) == 0) + { + return true; + } + } + + return false; +} + +bool viewsAreEqual(const ConstConfigRcPtr & first, + const ConstConfigRcPtr & second, + const char * dispName, // may be empty or nullptr for shared views + const char * viewName) +{ + // It's ok to call this even for displays/views that don't exist, it will simply return false. + + // Note that this will return true even if the view is display-defined in one config and a reference + // to a shared view in the other config (both within the same display), as long as the contents match. + + // These calls return null if either the display or view doesn't exist (regardless if it's active). + const char * cs1 = first->getDisplayViewColorSpaceName(dispName, viewName); + const char * cs2 = second->getDisplayViewColorSpaceName(dispName, viewName); + + // If the color space is not null, the display and view exist. + if (cs1 && *cs1 && cs2 && *cs2) + { + // Both configs have a display and view by this name, now check the contents. + if (Platform::Strcasecmp(cs1, cs2) == 0) + { + // Note the remaining strings may be empty in a valid view. + // Intentionally not checking the description since it is not a functional difference. + if ( (Platform::Strcasecmp(first->getDisplayViewLooks(dispName, viewName), + second->getDisplayViewLooks(dispName, viewName)) == 0) && + (Platform::Strcasecmp(first->getDisplayViewTransformName(dispName, viewName), + second->getDisplayViewTransformName(dispName, viewName)) == 0) && + (Platform::Strcasecmp(first->getDisplayViewRule(dispName, viewName), + second->getDisplayViewRule(dispName, viewName)) == 0) ) + { + return true; + } + } + } + return false; +} + +bool virtualViewsAreEqual(const ConstConfigRcPtr & first, + const ConstConfigRcPtr & second, + const char * viewName) +{ + const char * cs1 = first->getVirtualDisplayViewColorSpaceName(viewName); + const char * cs2 = second->getVirtualDisplayViewColorSpaceName(viewName); + + // If the color space is not null, the display and view exist. + if (cs1 && *cs1 && cs2 && *cs2) + { + if (Platform::Strcasecmp(cs1, cs2) == 0) + { + // Note the remaining strings may be empty in a valid view. + // Intentionally not checking the description since it is not a functional difference. + if ( (Platform::Strcasecmp(first->getVirtualDisplayViewLooks(viewName), + second->getVirtualDisplayViewLooks(viewName)) == 0) && + (Platform::Strcasecmp(first->getVirtualDisplayViewTransformName(viewName), + second->getVirtualDisplayViewTransformName(viewName)) == 0) && + (Platform::Strcasecmp(first->getVirtualDisplayViewRule(viewName), + second->getVirtualDisplayViewRule(viewName)) == 0) ) + { + return true; + } + } + } + return false; +} + +bool viewTransformsAreEqual(const ConstConfigRcPtr & first, + const ConstConfigRcPtr & second, + const char * name) +{ + ConstViewTransformRcPtr vt1 = first->getViewTransform(name); + ConstViewTransformRcPtr vt2 = second->getViewTransform(name); + if (vt1 && vt2) + { + // Both configs have a view transform by this name, now check the parts. + // Note: Not checking family or description since it is not a functional difference. + + // FIXME: Check categories. + + if (vt1->getReferenceSpaceType() != vt2->getReferenceSpaceType()) + { + return false; + } + + ConstTransformRcPtr t1_to = vt1->getTransform(VIEWTRANSFORM_DIR_TO_REFERENCE); + ConstTransformRcPtr t2_to = vt2->getTransform(VIEWTRANSFORM_DIR_TO_REFERENCE); + if (t1_to || t2_to) + { + if (!t1_to || !t2_to) // one of them has a transform but the other does not + { + return false; + } + + // FIXME: Compare transforms. + } + + ConstTransformRcPtr t1_from = vt1->getTransform(VIEWTRANSFORM_DIR_FROM_REFERENCE); + ConstTransformRcPtr t2_from = vt2->getTransform(VIEWTRANSFORM_DIR_FROM_REFERENCE); + if (t1_from || t2_from) + { + if (!t1_from || !t2_from) // one of them has a transform but the other does not + { + return false; + } + + // FIXME: Compare transforms. + } + + return true; + } + return false; +} + +bool viewingRulesAreEqual(const ConstViewingRulesRcPtr & r1, + size_t r1Idx, + const ConstViewingRulesRcPtr & r2, + size_t r2Idx) +{ + // NB: No need to compare the name of the rules, that should be done in the caller. + + // Compare color space tokens, handling the case where they may be in a different order. + + if (r1->getNumColorSpaces(r1Idx) != r2->getNumColorSpaces(r2Idx)) + { + return false; + } + + TokensManager r1ColorSpaces; + for (size_t m = 0; m < r1->getNumColorSpaces(r1Idx); m++) + { + r1ColorSpaces.addToken(r1->getColorSpace(r1Idx, m)); + } + + for (size_t m = 0; m < r2->getNumColorSpaces(r2Idx); m++) + { + if (!r1ColorSpaces.hasToken(r2->getColorSpace(r2Idx, m))) + { + return false; + } + } + + // Compare encoding tokens, handling the case where they may be in a different order. + + if (r1->getNumEncodings(r1Idx) != r2->getNumEncodings(r2Idx)) + { + return false; + } + + TokensManager r1Encodings; + for (size_t m = 0; m < r1->getNumEncodings(r1Idx); m++) + { + r1Encodings.addToken(r1->getEncoding(r1Idx, m)); + } + + for (size_t m = 0; m < r2->getNumEncodings(r2Idx); m++) + { + if(!r1Encodings.hasToken(r2->getEncoding(r2Idx, m))) + { + return false; + } + } + + // Compare the custom keys, handling the case where they may be in a different order. + + if (r1->getNumCustomKeys(r1Idx) != r2->getNumCustomKeys(r2Idx)) + { + return false; + } + + CustomKeysContainer r1CustomKeys; + for (size_t m = 0; m < r1->getNumCustomKeys(r1Idx); m++) + { + r1CustomKeys.set(r1->getCustomKeyName(r1Idx, m), r1->getCustomKeyValue(r1Idx, m)); + } + + for (size_t m = 0; m < r2->getNumCustomKeys(r2Idx); m++) + { + if (!r1CustomKeys.hasKey(r2->getCustomKeyName(r2Idx, m))) + { + return false; + } + else + { + if (Platform::Strcasecmp(r1CustomKeys.getValueForKey(r2->getCustomKeyName(r2Idx, m)), + r2->getCustomKeyValue(r2Idx, m)) != 0) + { + return false; + } + } + } + + return true; +} + +void copyViewingRule(const ConstViewingRulesRcPtr & src, + size_t srcIdx, + size_t dstIdx, + ViewingRulesRcPtr & rules) +{ + try + { + rules->insertRule(dstIdx, src->getName(srcIdx)); + + for (int j = 0; j < static_cast(src->getNumColorSpaces(srcIdx)); j++) + { + rules->addColorSpace(dstIdx, src->getColorSpace(srcIdx, j)); + } + + for (int k = 0; k < static_cast(src->getNumEncodings(srcIdx)); k++) + { + rules->addEncoding(dstIdx, src->getEncoding(srcIdx, k)); + } + + for (int l = 0; l < static_cast(src->getNumCustomKeys(srcIdx)); l++) + { + rules->setCustomKey(dstIdx, src->getCustomKeyName(srcIdx, l), src->getCustomKeyValue(srcIdx, l)); + } + } + catch(...) + { + // Don't add it if any errors. + // Continue. + } +} + +void addUniqueViewingRules(const ConstViewingRulesRcPtr & rules, + ViewingRulesRcPtr & mergedRules) +{ + for (size_t i = 0; i < rules->getNumEntries(); i++) + { + const char * name = rules->getName(i); + // Take the rule from the first config if it does not exist. + try + { + mergedRules->getIndexForRule(name); + } + catch(...) + { + // Rule does not exist in merged rules. + // Add it. + copyViewingRule(rules, i, mergedRules->getNumEntries(), mergedRules); + } + } +} + +} // anon. + +void DisplayViewMerger::addUniqueDisplays(const ConstConfigRcPtr & cfg) +{ + // For each display, add any views from cfg that are not already in the merged config. + + for (int i = 0; i < cfg->getNumDisplaysAll(); i++) + { + const char * dispName = cfg->getDisplayAll(i); + + // Display defined views. + for (int v = 0; v < cfg->getNumViews(VIEW_DISPLAY_DEFINED, dispName); v++) + { + const char * displayDefinedView = cfg->getView(VIEW_DISPLAY_DEFINED, dispName, v); + + // This will return true if the display contains either a display-defined or + // shared view with this name. + const bool dispDefinedExists = displayHasView(m_mergedConfig, dispName, displayDefinedView); + + if (displayDefinedView && *displayDefinedView && !dispDefinedExists) + { + // (Note this works for either the new or old style of view.) + m_mergedConfig->addDisplayView(dispName, + displayDefinedView, + cfg->getDisplayViewTransformName(dispName, displayDefinedView), + cfg->getDisplayViewColorSpaceName(dispName, displayDefinedView), + cfg->getDisplayViewLooks(dispName, displayDefinedView), + cfg->getDisplayViewRule(dispName, displayDefinedView), + cfg->getDisplayViewDescription(dispName, displayDefinedView)); + } + } + + // Shared views. + for (int v = 0; v < cfg->getNumViews(VIEW_SHARED, dispName); v++) + { + const char * sharedViewName = cfg->getView(VIEW_SHARED, dispName, v); + + const bool sharedViewExists = displayHasView(m_mergedConfig, dispName, sharedViewName); + + if (sharedViewName && *sharedViewName && !sharedViewExists) + { + m_mergedConfig->addDisplaySharedView(dispName, sharedViewName); + } + } + } +} + +void DisplayViewMerger::addUniqueVirtualViews(const ConstConfigRcPtr & cfg) +{ + // Display defined views. + for (int v = 0; v < cfg->getVirtualDisplayNumViews(VIEW_DISPLAY_DEFINED); v++) + { + const char * displayDefinedView = cfg->getVirtualDisplayView(VIEW_DISPLAY_DEFINED, v); + const bool dispDefinedExists = hasVirtualView(m_mergedConfig, displayDefinedView); + if (displayDefinedView && *displayDefinedView && !dispDefinedExists) + { + m_mergedConfig->addVirtualDisplayView(displayDefinedView, + cfg->getVirtualDisplayViewTransformName(displayDefinedView), + cfg->getVirtualDisplayViewColorSpaceName(displayDefinedView), + cfg->getVirtualDisplayViewLooks(displayDefinedView), + cfg->getVirtualDisplayViewRule(displayDefinedView), + cfg->getVirtualDisplayViewDescription(displayDefinedView)); + } + } + + // Shared views. + for (int v = 0; v < cfg->getVirtualDisplayNumViews(VIEW_SHARED); v++) + { + const char * sharedViewName = cfg->getVirtualDisplayView(VIEW_SHARED, v); + const bool sharedViewExists = hasVirtualView(m_mergedConfig, sharedViewName); + if (sharedViewName && *sharedViewName && !sharedViewExists) + { + m_mergedConfig->addVirtualDisplaySharedView(sharedViewName); + } + } +} + +void DisplayViewMerger::processDisplays(const ConstConfigRcPtr & first, + const ConstConfigRcPtr & second, + bool preferSecond) +{ + // Iterate over the first config's displays. + + for (int i = 0; i < first->getNumDisplaysAll(); i++) + { + const char * dispName = first->getDisplayAll(i); + + // Iterate over this display's display-defined views. + + for (int v = 0; v < first->getNumViews(VIEW_DISPLAY_DEFINED, dispName); v++) + { + const char * displayDefinedView = first->getView(VIEW_DISPLAY_DEFINED, dispName, v); + + if (displayDefinedView && *displayDefinedView) + { + // One case to be aware of is where both configs have the same display with the same + // view name, but it's a display-defined view in one and a shared view in the other. + // This check will return true if it exists in either form. + const bool existsInSecond = displayHasView(second, dispName, displayDefinedView); + + if (existsInSecond && !viewsAreEqual(first, second, dispName, displayDefinedView)) + { + // Throw or log on conflict. + std::ostringstream os; + os << "The Input config contains a value that would override "; + os << "the Base config: display: " << dispName << ", view: " << displayDefinedView; + notify(os.str(), m_params->isErrorOnConflict()); + } + + // Display defined views. + if (existsInSecond && preferSecond) + { + // Take the view from the second config. + + // This was a display-defined view in the first config but it may not be in + // the second config. Want to add it as the same type of view. + if (viewIsShared(second, dispName, displayDefinedView)) + { + m_mergedConfig->addDisplaySharedView(dispName, displayDefinedView); + } + else + { + m_mergedConfig->addDisplayView(dispName, + displayDefinedView, + second->getDisplayViewTransformName(dispName, displayDefinedView), + second->getDisplayViewColorSpaceName(dispName, displayDefinedView), + second->getDisplayViewLooks(dispName, displayDefinedView), + second->getDisplayViewRule(dispName, displayDefinedView), + second->getDisplayViewDescription(dispName, displayDefinedView)); + } + } + else + { + // Take the view from the first config (where it is display-defined). + // (Note this works for either the new or old style of view.) + m_mergedConfig->addDisplayView(dispName, + displayDefinedView, + first->getDisplayViewTransformName(dispName, displayDefinedView), + first->getDisplayViewColorSpaceName(dispName, displayDefinedView), + first->getDisplayViewLooks(dispName, displayDefinedView), + first->getDisplayViewRule(dispName, displayDefinedView), + first->getDisplayViewDescription(dispName, displayDefinedView)); + } + } + } + + // Iterate over this display's shared views. + + for (int v = 0; v < first->getNumViews(VIEW_SHARED, dispName); v++) + { + const char * sharedViewName = first->getView(VIEW_SHARED, dispName, v); + + if (sharedViewName && *sharedViewName) + { + const bool existsInSecond = displayHasView(second, dispName, sharedViewName); + + if (existsInSecond && preferSecond) + { + // This was a shared view in the first config but it may not be in + // the second config. Want to add it as the same type of view. + if (viewIsShared(second, dispName, sharedViewName)) + { + m_mergedConfig->addDisplaySharedView(dispName, sharedViewName); + } + else + { + if (!viewsAreEqual(first, second, dispName, sharedViewName)) + { + // Throw or log on conflict. + std::ostringstream os; + os << "The Input config contains a value that would override "; + os << "the Base config: display: " << dispName << ", view: " << sharedViewName; + notify(os.str(), m_params->isErrorOnConflict()); + } + m_mergedConfig->addDisplayView(dispName, + sharedViewName, + second->getDisplayViewTransformName(dispName, sharedViewName), + second->getDisplayViewColorSpaceName(dispName, sharedViewName), + second->getDisplayViewLooks(dispName, sharedViewName), + second->getDisplayViewRule(dispName, sharedViewName), + second->getDisplayViewDescription(dispName, sharedViewName)); + } + } + else + { + // Note: The error-on-conflict check happens in processSharedViews, + // this is just adding the reference, so it's not checked again here. + m_mergedConfig->addDisplaySharedView(dispName, sharedViewName); + } + } + } + } + + // Add the remaining views for all displays from the second config. (This only adds views + // that are not already present.) + + addUniqueDisplays(second); +} + +void DisplayViewMerger::processVirtualDisplay(const ConstConfigRcPtr & first, + const ConstConfigRcPtr & second, + bool preferSecond) +{ + for (int v = 0; v < first->getVirtualDisplayNumViews(VIEW_DISPLAY_DEFINED); v++) + { + const char * displayDefinedView = first->getVirtualDisplayView(VIEW_DISPLAY_DEFINED, v); + + if (displayDefinedView && *displayDefinedView) + { + // Check if it displays shared view exists in second config. + const bool existsInSecond = hasVirtualView(second, displayDefinedView); + + if (existsInSecond && !virtualViewsAreEqual(first, second, displayDefinedView)) + { + // Throw or log on conflict. + std::ostringstream os; + os << "The Input config contains a value that would override "; + os << "the Base config: virtual_display: " << displayDefinedView; + notify(os.str(), m_params->isErrorOnConflict()); + } + + // Display defined views. + if (existsInSecond && preferSecond) + { + // Take the view from the second config. + + // This was a display-defined view in the first config but it may not be in + // the second config. Want to add it as the same type of view. + if (virtualViewIsShared(second, displayDefinedView)) + { + m_mergedConfig->addVirtualDisplaySharedView(displayDefinedView); + } + else + { + m_mergedConfig->addVirtualDisplayView(displayDefinedView, + second->getVirtualDisplayViewTransformName(displayDefinedView), + second->getVirtualDisplayViewColorSpaceName(displayDefinedView), + second->getVirtualDisplayViewLooks(displayDefinedView), + second->getVirtualDisplayViewRule(displayDefinedView), + second->getVirtualDisplayViewDescription(displayDefinedView)); + } + } + else + { + // Take the view from the first config (where it is display-defined). + // (Note this works for either the new or old style of view.) + m_mergedConfig->addVirtualDisplayView(displayDefinedView, + first->getVirtualDisplayViewTransformName(displayDefinedView), + first->getVirtualDisplayViewColorSpaceName(displayDefinedView), + first->getVirtualDisplayViewLooks(displayDefinedView), + first->getVirtualDisplayViewRule(displayDefinedView), + first->getVirtualDisplayViewDescription(displayDefinedView)); + } + } + } + + // Iterate over this display's shared views. + + for (int v = 0; v < first->getVirtualDisplayNumViews(VIEW_SHARED); v++) + { + const char * sharedViewName = first->getVirtualDisplayView(VIEW_SHARED, v); + + if (sharedViewName && *sharedViewName) + { + const bool existsInSecond = hasVirtualView(second, sharedViewName); + + if (existsInSecond && preferSecond) + { + // This was a shared view in the first config but it may not be in + // the second config. Want to add it as the same type of view. + if (virtualViewIsShared(second, sharedViewName)) + { + m_mergedConfig->addVirtualDisplaySharedView(sharedViewName); + } + else + { + if (!virtualViewsAreEqual(first, second, sharedViewName)) + { + // Throw or log on conflict. + std::ostringstream os; + os << "The Input config contains a value that would override "; + os << "the Base config: virtual_display: " << sharedViewName; + notify(os.str(), m_params->isErrorOnConflict()); + } + m_mergedConfig->addVirtualDisplayView(sharedViewName, + second->getVirtualDisplayViewTransformName(sharedViewName), + second->getVirtualDisplayViewColorSpaceName(sharedViewName), + second->getVirtualDisplayViewLooks(sharedViewName), + second->getVirtualDisplayViewRule(sharedViewName), + second->getVirtualDisplayViewDescription(sharedViewName)); + } + } + else + { + // Note: The error-on-conflict check happens in processSharedViews, + // this is just adding the reference, so it's not checked again here. + m_mergedConfig->addVirtualDisplaySharedView(sharedViewName); + } + } + } + + // Add the remaining views from the second config. + + addUniqueVirtualViews(second); +} + +void DisplayViewMerger::addUniqueSharedViews(const ConstConfigRcPtr & cfg) +{ + // Add any shared views that are not already in the merged config. + + for (int v = 0; v < cfg->getNumViews(VIEW_SHARED, nullptr); v++) + { + const char * sharedViewName = cfg->getView(VIEW_SHARED, nullptr, v); + + // Check if shared view exists in merged config. + bool sharedViewExists = displayHasView(m_mergedConfig, nullptr, sharedViewName); + + if (sharedViewName && *sharedViewName && !sharedViewExists) + { + m_mergedConfig->addSharedView(sharedViewName, + cfg->getDisplayViewTransformName(nullptr, sharedViewName), + cfg->getDisplayViewColorSpaceName(nullptr, sharedViewName), + cfg->getDisplayViewLooks(nullptr, sharedViewName), + cfg->getDisplayViewRule(nullptr, sharedViewName), + cfg->getDisplayViewDescription(nullptr, sharedViewName)); + } + } +} + +void DisplayViewMerger::processSharedViews(const ConstConfigRcPtr & first, + const ConstConfigRcPtr & second, + bool preferSecond) +{ + // Iterate over all shared views in the first config. + for (int v = 0; v < first->getNumViews(VIEW_SHARED, nullptr); v++) + { + const char * sharedViewName = first->getView(VIEW_SHARED, nullptr, v); + + if (sharedViewName && *sharedViewName) + { + // Check if shared view exists in second config. + bool existsInSecond = displayHasView(second, nullptr, sharedViewName); + + if (existsInSecond && !viewsAreEqual(first, second, nullptr, sharedViewName)) + { + // Throw or log on conflict. + std::ostringstream os; + os << "The Input config contains a value that would override "; + os << "the Base config: shared_views: " << sharedViewName; + notify(os.str(), m_params->isErrorOnConflict()); + } + + if (existsInSecond && preferSecond) + { + // Take the shared view from the second config. + // (Note this works for either the new or old style of view.) + m_mergedConfig->addSharedView(sharedViewName, + second->getDisplayViewTransformName(nullptr, sharedViewName), + second->getDisplayViewColorSpaceName(nullptr, sharedViewName), + second->getDisplayViewLooks(nullptr, sharedViewName), + second->getDisplayViewRule(nullptr, sharedViewName), + second->getDisplayViewDescription(nullptr, sharedViewName)); + } + else + { + // Take the shared view from the first config. + m_mergedConfig->addSharedView(sharedViewName, + first->getDisplayViewTransformName(nullptr, sharedViewName), + first->getDisplayViewColorSpaceName(nullptr, sharedViewName), + first->getDisplayViewLooks(nullptr, sharedViewName), + first->getDisplayViewRule(nullptr, sharedViewName), + first->getDisplayViewDescription(nullptr, sharedViewName)); + } + } + } + + // Add the remaining shared views that are only in the second config. + + addUniqueSharedViews(second); +} + +void DisplayViewMerger::processActiveLists() +{ + // Merge active_displays. + const char * activeDisplays = m_params->getActiveDisplays(); + if (activeDisplays && *activeDisplays) + { + // Take active_displays from overrides. + m_mergedConfig->setActiveDisplays(activeDisplays); + } + else + { + // Take active_displays from config. + + StringUtils::StringVec mergedActiveDisplays; + if (m_params->isInputFirst()) + { + StringUtils::StringVec baseActiveDisplays; + splitActiveList(m_baseConfig->getActiveDisplays(), baseActiveDisplays); + splitActiveList(m_inputConfig->getActiveDisplays(), mergedActiveDisplays); + + mergeStringsWithoutDuplicates(baseActiveDisplays, mergedActiveDisplays); + } + else + { + StringUtils::StringVec inputActiveDisplays; + splitActiveList(m_inputConfig->getActiveDisplays(), inputActiveDisplays); + splitActiveList(m_baseConfig->getActiveDisplays(), mergedActiveDisplays); + + mergeStringsWithoutDuplicates(inputActiveDisplays, mergedActiveDisplays); + } + + // NB: StringUtils::Join adds a space after the comma. + m_mergedConfig->setActiveDisplays(StringUtils::Join(mergedActiveDisplays, ',').c_str()); + } + + // Merge active_views. + const char * activeViews = m_params->getActiveViews(); + if (activeViews && *activeViews) + { + // Take active_views from overrides. + m_mergedConfig->setActiveViews(activeViews); + } + else + { + // Take active_views from config. + + StringUtils::StringVec mergedActiveViews; + if (m_params->isInputFirst()) + { + StringUtils::StringVec baseActiveViews; + splitActiveList(m_baseConfig->getActiveViews(), baseActiveViews); + splitActiveList(m_inputConfig->getActiveViews(), mergedActiveViews); + + mergeStringsWithoutDuplicates(baseActiveViews, mergedActiveViews); + } + else + { + StringUtils::StringVec inputActiveViews; + splitActiveList(m_inputConfig->getActiveViews(), inputActiveViews); + splitActiveList(m_baseConfig->getActiveViews(), mergedActiveViews); + + mergeStringsWithoutDuplicates(inputActiveViews, mergedActiveViews); + } + + m_mergedConfig->setActiveViews(StringUtils::Join(mergedActiveViews, ',').c_str()); + } +} + +void DisplayViewMerger::addUniqueViewTransforms(const ConstConfigRcPtr & cfg) +{ + for (int i = 0; i < cfg->getNumViewTransforms(); i++) + { + const char * name = cfg->getViewTransformNameByIndex(i); + // Take the view from the config if it does not exist in merged config. + if (m_mergedConfig->getViewTransform(name) == nullptr) + { + m_mergedConfig->addViewTransform(cfg->getViewTransform(name)); + } + } +} + +void DisplayViewMerger::processViewTransforms(const ConstConfigRcPtr & first, + const ConstConfigRcPtr & second, + bool preferSecond) +{ + for (int i = 0; i < first->getNumViewTransforms(); i++) + { + const char * name = first->getViewTransformNameByIndex(i); + if (name && *name) + { + ConstViewTransformRcPtr vt2 = second->getViewTransform(name); + if (vt2 && !viewTransformsAreEqual(first, second, name)) + { + std::ostringstream os; + os << "The Input config contains a value that would override "; + os << "the Base config: view_transforms: " << name; + notify(os.str(), m_params->isErrorOnConflict()); + } + + if (vt2 && preferSecond) + { + m_mergedConfig->addViewTransform(second->getViewTransform(name)); + } + else + { + m_mergedConfig->addViewTransform(first->getViewTransform(name)); + } + } + } + + // Add the remaining unique views transform. + + addUniqueViewTransforms(second); +} + +void DisplayViewMerger::processViewingRules(const ConstConfigRcPtr & first, + const ConstConfigRcPtr & second, + bool preferSecond) const +{ + ViewingRulesRcPtr mergedRules = ViewingRules::Create(); + + ConstViewingRulesRcPtr firstRules = first->getViewingRules(); + ConstViewingRulesRcPtr secondRules = second->getViewingRules(); + + for (size_t i = 0; i < firstRules->getNumEntries(); i++) + { + bool hasConflict = false; + + const char * name = firstRules->getName(i); + try + { + // Check if it exists in second rules, will throw if not. + size_t idx = secondRules->getIndexForRule(name); + + if (!viewingRulesAreEqual(firstRules, i, secondRules, idx)) + { + hasConflict = true; + + if (preferSecond) + { + // Take rule from the second config. + copyViewingRule(secondRules, idx, mergedRules->getNumEntries(), mergedRules); + } + else + { + // Found, but not overriding. Take rule from the first config. + copyViewingRule(firstRules, i, mergedRules->getNumEntries(), mergedRules); + } + + std::ostringstream os; + os << "The Input config contains a value that would override "; + os << "the Base config: viewing_rules: " << name; + throw Exception(os.str().c_str()); + } + + } + catch(const Exception & e) + { + if (hasConflict) + { + notify(e.what(), m_params->isErrorOnConflict()); + } + else + { + // Not found in second rules. Take rule from the first config. + copyViewingRule(firstRules, i, mergedRules->getNumEntries(), mergedRules); + } + } + } + + // Add the remaining rules. + addUniqueViewingRules(secondRules, mergedRules); + + m_mergedConfig->setViewingRules(mergedRules); +} + +void DisplayViewMerger::handlePreferInput() +{ + // The error_on_conflict option implies to shared_views, displays/views, virtual_display, + // view_transforms, default_view_transform, and viewing_rules. + + // Clear displays and shared_views from merged config. + m_mergedConfig->clearDisplays(); + clearSharedViews(m_mergedConfig); + + // Merge displays and views. + // The order is important: shared_views, and then displays. + if (m_params->isInputFirst()) + { + processSharedViews(m_inputConfig, m_baseConfig, false); + processDisplays(m_inputConfig, m_baseConfig, false); + } + else + { + processSharedViews(m_baseConfig, m_inputConfig, true); + processDisplays(m_baseConfig, m_inputConfig, true); + } + + // Merge virtual_display. + m_mergedConfig->clearVirtualDisplay(); + if (m_params->isInputFirst()) + { + processVirtualDisplay(m_inputConfig, m_baseConfig, false); + } + else + { + processVirtualDisplay(m_baseConfig, m_inputConfig, true); + } + + // Merge active_displays and active_views. + processActiveLists(); + + // Merge view_transforms. + m_mergedConfig->clearViewTransforms(); + if (m_params->isInputFirst()) + { + processViewTransforms(m_inputConfig, m_baseConfig, false); + } + else + { + processViewTransforms(m_baseConfig, m_inputConfig, true); + } + + // Merge default_view_transform. + const char * baseName = m_baseConfig->getDefaultViewTransformName(); + const char * inputName = m_inputConfig->getDefaultViewTransformName(); + if (!(Platform::Strcasecmp(baseName, inputName) == 0)) + { + notify("The Input config contains a value that would override the Base config: "\ + "default_view_transform: " + std::string(inputName), m_params->isErrorOnConflict()); + } + // If the input config does not specify a default, keep the one from the base. + if (inputName && *inputName) + { + m_mergedConfig->setDefaultViewTransformName(inputName); + } + + // Merge viewing_rules. + if (m_params->isInputFirst()) + { + processViewingRules(m_inputConfig, m_baseConfig, false); + } + else + { + processViewingRules(m_baseConfig, m_inputConfig, true); + } +} + +void DisplayViewMerger::handlePreferBase() +{ + // Clear displays and shared_views from merged config. + m_mergedConfig->clearDisplays(); + clearSharedViews(m_mergedConfig); + + // Merge displays and views. + // The order is important: shared_views, and then displays. + if (m_params->isInputFirst()) + { + processSharedViews(m_inputConfig, m_baseConfig, true); + processDisplays(m_inputConfig, m_baseConfig, true); + } + else + { + processSharedViews(m_baseConfig, m_inputConfig, false); + processDisplays(m_baseConfig, m_inputConfig, false); + } + + // Merge virtual_display. + m_mergedConfig->clearVirtualDisplay(); + if (m_params->isInputFirst()) + { + processVirtualDisplay(m_inputConfig, m_baseConfig, true); + } + else + { + processVirtualDisplay(m_baseConfig, m_inputConfig, false); + } + + // Merge active_displays and active_views. + processActiveLists(); + + // Merge view_transforms. + m_mergedConfig->clearViewTransforms(); + if (m_params->isInputFirst()) + { + processViewTransforms(m_inputConfig, m_baseConfig, true); + } + else + { + processViewTransforms(m_baseConfig, m_inputConfig, false); + } + + // Merge default_view_transform. + const char * baseName = m_baseConfig->getDefaultViewTransformName(); + const char * inputName = m_inputConfig->getDefaultViewTransformName(); + if (!(Platform::Strcasecmp(baseName, inputName) == 0)) + { + notify("The Input config contains a value that would override the Base config: "\ + "default_view_transform: " + std::string(inputName), m_params->isErrorOnConflict()); + } + // Only use the input if the base is missing. + if (!baseName || !*baseName) + { + m_mergedConfig->setDefaultViewTransformName(inputName); + } + + // Merge viewing_rules. + if (m_params->isInputFirst()) + { + processViewingRules(m_inputConfig, m_baseConfig, true); + } + else + { + processViewingRules(m_baseConfig, m_inputConfig, false); + } +} + +void DisplayViewMerger::handleInputOnly() +{ + // Clear displays and shared_views from merged config. + m_mergedConfig->clearDisplays(); + clearSharedViews(m_mergedConfig); + + // Merge displays and views. + addUniqueSharedViews(m_inputConfig); + addUniqueDisplays(m_inputConfig); + + // Merge virtual_display. + m_mergedConfig->clearVirtualDisplay(); + addUniqueVirtualViews(m_inputConfig); + + // Merge active_displays. + const char * activeDisplays = m_params->getActiveDisplays(); + if (activeDisplays && *activeDisplays) + { + // Take active_displays from overrides. + m_mergedConfig->setActiveDisplays(activeDisplays); + } + else + { + // Take active_displays from config. + m_mergedConfig->setActiveDisplays(m_inputConfig->getActiveDisplays()); + } + + // Merge active_views. + const char * activeViews = m_params->getActiveViews(); + if (activeViews && *activeViews) + { + // Take active_views from overrides. + m_mergedConfig->setActiveViews(activeViews); + } + else + { + // Take active_views from config. + m_mergedConfig->setActiveViews(m_inputConfig->getActiveViews()); + } + + // Merge view_transforms. + m_mergedConfig->clearViewTransforms(); + addUniqueViewTransforms(m_inputConfig); + + // Merge default_view_transform. + m_mergedConfig->setDefaultViewTransformName(m_inputConfig->getDefaultViewTransformName()); + + // Merge viewing_rules. + m_mergedConfig->setViewingRules(m_inputConfig->getViewingRules()); +} + +void DisplayViewMerger::handleBaseOnly() +{ + // Process the overrides only since the merged config is initialized to + // the base config. + + const char * activeDisplays = m_params->getActiveDisplays(); + if (activeDisplays && *activeDisplays) + { + // Take active_displays from overrides. + m_mergedConfig->setActiveDisplays(activeDisplays); + } + + const char * activeViews = m_params->getActiveViews(); + if (activeViews && *activeViews) + { + // Take active_views from overrides. + m_mergedConfig->setActiveViews(activeViews); + } +} + +void DisplayViewMerger::handleRemove() +{ + // Remove shared_views. + + clearSharedViews(m_mergedConfig); + + for (int v = 0; v < m_baseConfig->getNumViews(VIEW_SHARED, nullptr); v++) + { + // Add shared views that are present in the base config and NOT present in the input config. + const char * sharedViewName = m_baseConfig->getView(VIEW_SHARED, nullptr, v); + if (sharedViewName && *sharedViewName + && !displayHasView(m_inputConfig, nullptr, sharedViewName)) + { + m_mergedConfig->addSharedView(sharedViewName, + m_baseConfig->getDisplayViewTransformName(nullptr, sharedViewName), + m_baseConfig->getDisplayViewColorSpaceName(nullptr, sharedViewName), + m_baseConfig->getDisplayViewLooks(nullptr, sharedViewName), + m_baseConfig->getDisplayViewRule(nullptr, sharedViewName), + m_baseConfig->getDisplayViewDescription(nullptr, sharedViewName)); + } + } + + // Remove views from displays. + + m_mergedConfig->clearDisplays(); + + for (int i = 0; i < m_baseConfig->getNumDisplaysAll(); i++) + { + // Add views that are present in the base config and NOT present in the input config. + + // Display-defined views. + const char * dispName = m_baseConfig->getDisplayAll(i); + for (int v = 0; v < m_baseConfig->getNumViews(VIEW_DISPLAY_DEFINED, dispName); v++) + { + const char * displayDefinedView = m_baseConfig->getView(VIEW_DISPLAY_DEFINED, dispName, v); + // Check if the view is not present in the input config. + if (displayDefinedView && *displayDefinedView + && !displayHasView(m_inputConfig, dispName, displayDefinedView)) + { + m_mergedConfig->addDisplayView(dispName, + displayDefinedView, + m_baseConfig->getDisplayViewTransformName(dispName, displayDefinedView), + m_baseConfig->getDisplayViewColorSpaceName(dispName, displayDefinedView), + m_baseConfig->getDisplayViewLooks(dispName, displayDefinedView), + m_baseConfig->getDisplayViewRule(dispName, displayDefinedView), + m_baseConfig->getDisplayViewDescription(dispName, displayDefinedView)); + } + } + + // Shared views. + for (int v = 0; v < m_baseConfig->getNumViews(VIEW_SHARED, dispName); v++) + { + const char * sharedViewName = m_baseConfig->getView(VIEW_SHARED, dispName, v); + // Check if the view is not present in the input config. + if (sharedViewName && *sharedViewName + && !displayHasView(m_inputConfig, dispName, sharedViewName)) + { + m_mergedConfig->addDisplaySharedView(dispName, sharedViewName); + } + } + } + + // Remove views from virtual_display. + + m_mergedConfig->clearVirtualDisplay(); + + { + // Add virtual views that are present in the base config and NOT present in the input config. + + // Display-defined views. + for (int v = 0; v < m_baseConfig->getVirtualDisplayNumViews(VIEW_DISPLAY_DEFINED); v++) + { + const char * displayDefinedView = m_baseConfig->getVirtualDisplayView(VIEW_DISPLAY_DEFINED, v); + // Check if the view is not present in the input config. + if (displayDefinedView && *displayDefinedView + && !hasVirtualView(m_inputConfig, displayDefinedView)) + { + // Add the display defined view + m_mergedConfig->addVirtualDisplayView(displayDefinedView, + m_baseConfig->getVirtualDisplayViewTransformName(displayDefinedView), + m_baseConfig->getVirtualDisplayViewColorSpaceName(displayDefinedView), + m_baseConfig->getVirtualDisplayViewLooks(displayDefinedView), + m_baseConfig->getVirtualDisplayViewRule(displayDefinedView), + m_baseConfig->getVirtualDisplayViewDescription(displayDefinedView)); + } + } + + // Shared views. + for (int v = 0; v < m_baseConfig->getVirtualDisplayNumViews(VIEW_SHARED); v++) + { + const char * sharedViewName = m_baseConfig->getVirtualDisplayView(VIEW_SHARED, v); + // Check if the view is not present in the input config. + if (sharedViewName && *sharedViewName + && !hasVirtualView(m_inputConfig, sharedViewName)) + { + // Add the shared view + m_mergedConfig->addVirtualDisplaySharedView(sharedViewName); + } + } + } + + // Remove from active_displays. + + StringUtils::StringVec inputActiveDisplays, mergedActiveDisplays; + splitActiveList(m_inputConfig->getActiveDisplays(), inputActiveDisplays); + splitActiveList(m_baseConfig->getActiveDisplays(), mergedActiveDisplays); + + for (const auto & disp : inputActiveDisplays) + { + StringUtils::Remove(mergedActiveDisplays, disp); + } + m_mergedConfig->setActiveDisplays(StringUtils::Join(mergedActiveDisplays, ',').c_str()); + + // Remove from active_views. + + StringUtils::StringVec inputActiveViews, mergedActiveViews; + splitActiveList(m_inputConfig->getActiveViews(), inputActiveViews); + splitActiveList(m_baseConfig->getActiveViews(), mergedActiveViews); + + for (const auto & view : inputActiveViews) + { + StringUtils::Remove(mergedActiveViews, view); + } + m_mergedConfig->setActiveViews(StringUtils::Join(mergedActiveViews, ',').c_str()); + + // Remove from view_transforms. + m_mergedConfig->clearViewTransforms(); + // Add view transforms that are present in the base config and NOT present in the input config. + for (int i = 0; i < m_baseConfig->getNumViewTransforms(); i++) + { + const char * name = m_baseConfig->getViewTransformNameByIndex(i); + if (m_inputConfig->getViewTransform(name) == nullptr) + { + m_mergedConfig->addViewTransform(m_baseConfig->getViewTransform(name)); + } + } + + // Handle default_view_transform. + // Leave the base alone unless it identified a view transform that was removed. + const char * baseName = m_baseConfig->getDefaultViewTransformName(); + if (m_mergedConfig->getViewTransform(baseName) == nullptr) + { + // Set to empty string, the first view transform will be used by default. + m_mergedConfig->setDefaultViewTransformName(""); + } + + // Handle viewing_rules. + + ViewingRulesRcPtr mergedRules = ViewingRules::Create(); + ConstViewingRulesRcPtr inputRules = m_inputConfig->getViewingRules(); + ConstViewingRulesRcPtr baseRules = m_baseConfig->getViewingRules(); + + for (size_t i = 0; i < baseRules->getNumEntries(); i++) + { + const char * name = baseRules->getName(i); + try + { + // Throws if the input doesn't have the base rule. + inputRules->getIndexForRule(name); + } + catch(...) + { + // Keep any base rules that aren't in the input. + copyViewingRule(baseRules, i, mergedRules->getNumEntries(), mergedRules); + } + } + + m_mergedConfig->setViewingRules(mergedRules); +} + +/////////////////////////////////// DisplayViewMerger end //////////////////////////////// + + +////////////////////////////////////////// LooksMerger //////////////////////////////////////////// +void LooksMerger::handlePreferInput() +{ + m_mergedConfig->clearLooks(); + + if (m_params->isInputFirst()) + { + // Add the Looks from the input config. + for(int i = 0; i < m_inputConfig->getNumLooks(); ++i) + { + m_mergedConfig->addLook(m_inputConfig->getLook(m_inputConfig->getLookNameByIndex(i))); + } + + // Add the Looks from the base config if it does not exist in the merged config. + for(int i = 0; i < m_baseConfig->getNumLooks(); ++i) + { + if (m_mergedConfig->getLook(m_baseConfig->getLookNameByIndex(i)) == nullptr) + { + m_mergedConfig->addLook(m_baseConfig->getLook(m_baseConfig->getLookNameByIndex(i))); + } + } + } + else + { + // PreferInput, InputFirst = false + // Add the looks from the base config. + for(int i = 0; i < m_baseConfig->getNumLooks(); ++i) + { + m_mergedConfig->addLook(m_baseConfig->getLook(m_baseConfig->getLookNameByIndex(i))); + } + + // Add the Looks from the input config and overwrite look if the name is the same. + for(int i = 0; i < m_inputConfig->getNumLooks(); ++i) + { + m_mergedConfig->addLook(m_inputConfig->getLook(m_inputConfig->getLookNameByIndex(i))); + } + } +} + +void LooksMerger::handlePreferBase() +{ + m_mergedConfig->clearLooks(); + + if (m_params->isInputFirst()) + { + // Add the Looks from the input config. + for(int i = 0; i < m_inputConfig->getNumLooks(); ++i) + { + m_mergedConfig->addLook(m_inputConfig->getLook(m_inputConfig->getLookNameByIndex(i))); + } + + // Add the Looks from the input config and overwrite look if the name is the same. + for(int i = 0; i < m_baseConfig->getNumLooks(); ++i) + { + m_mergedConfig->addLook(m_baseConfig->getLook(m_baseConfig->getLookNameByIndex(i))); + } + } + else + { + // PreferBase, InputFirst = false + // Add the looks from the base config. + for(int i = 0; i < m_baseConfig->getNumLooks(); ++i) + { + m_mergedConfig->addLook(m_baseConfig->getLook(m_baseConfig->getLookNameByIndex(i))); + } + + // Add the Looks from the input config if it does not exist in the merged config. + for(int i = 0; i < m_inputConfig->getNumLooks(); ++i) + { + if (m_mergedConfig->getLook(m_inputConfig->getLookNameByIndex(i)) == nullptr) + { + m_mergedConfig->addLook(m_inputConfig->getLook(m_inputConfig->getLookNameByIndex(i))); + } + } + } +} + +void LooksMerger::handleInputOnly() +{ + m_mergedConfig->clearLooks(); + // Add the Looks from the input config. + for(int i = 0; i < m_inputConfig->getNumLooks(); ++i) + { + m_mergedConfig->addLook(m_inputConfig->getLook(m_inputConfig->getLookNameByIndex(i))); + } +} + +void LooksMerger::handleBaseOnly() +{ + // Supported, but nothing to do. +} + +void LooksMerger::handleRemove() +{ + m_mergedConfig->clearLooks(); + // Add the looks from the base config if they do not exist in the INPUT config. + for(int i = 0; i < m_baseConfig->getNumLooks(); ++i) + { + const char * baseName = m_baseConfig->getLookNameByIndex(i); + if (m_inputConfig->getLook(baseName) == nullptr) + { + m_mergedConfig->addLook(m_baseConfig->getLook(baseName)); + } + } +} + +////////////////////////////////////// LooksMerger end //////////////////////////////////////////// + + +/////////////////////////////////////// ColorspacesMerger ///////////////////////////////////////// + +/* +void ColorspacesMerger::handleErrorCodes(ColorSpaceRcPtr & eColorspace) +{ + switch (errorCode) + { + case ADD_CS_ERROR_NAME_IDENTICAL_TO_A_ROLE_NAME: + skipCurrentColorspace = handleAddCsErrorNameIdenticalToARoleName(eColorspace); + break; + + case ADD_CS_ERROR_NAME_IDENTICAL_TO_NT_NAME_OR_ALIAS: + skipCurrentColorspace = handleAddCsErrorNameIdenticalToNTNameOrAlias(eColorspace); + break; + + case ADD_CS_ERROR_NAME_CONTAIN_CTX_VAR_TOKEN: + // Not handled as it can't happen in this context. + // The config will error out while loading the config (before the merge process). + break; + + case ADD_CS_ERROR_NAME_IDENTICAL_TO_EXISTING_COLORSPACE_ALIAS: + skipCurrentColorspace = handleAddCsErrorNameIdenticalToExistingColorspaceAlias(eColorspace); + break; + + case ADD_CS_ERROR_ALIAS_IDENTICAL_TO_A_ROLE_NAME: + skipCurrentColorspace = handleAddCsErrorAliasIdenticalToARoleName(eColorspace); + break; + + case ADD_CS_ERROR_ALIAS_IDENTICAL_TO_NT_NAME_OR_ALIAS: + skipCurrentColorspace = handleAddCsErrorAliasIdenticalToNTNameOrAlias(eColorspace); + break; + + case ADD_CS_ERROR_ALIAS_CONTAIN_CTX_VAR_TOKEN: + // Not handled as it can't happen in this context. + // The config will error out while loading the config (before the merge process). + break; + + case ADD_CS_ERROR_ALIAS_IDENTICAL_TO_EXISTING_COLORSPACE_NAME: + skipCurrentColorspace = handleAddCsErrorAliasIdenticalToExistingColorspaceName(eColorspace); + break; + + case ADD_CS_ERROR_ALIAS_IDENTICAL_TO_EXISTING_COLORSPACE_ALIAS: + skipCurrentColorspace = handleAddCsErrorAliasIdenticalToExistingColorspaceAlias(eColorspace); + break; + + case ADD_CS_ERROR_NONE: + allErrorsResolved = true; + break; + + case ADD_CS_ERROR_EMPTY: + // Nothing to do. + break; + + default: + break; + } +} +*/ + +//TODO We need to decide if we want to do this or it is the responsibility of the person +// doing the merge. +/* +void ColorspacesMerger::handleMarkedToBeDeletedColorspaces() +{ + // Go through the marked colorspaces, remove them and replace their name. + // colorspace %duplicate% should be deleted and the named replaced everywhere it is used. + + + if (m_colorspaceMarkedToBeDeleted.size() > 0) + { + // A color space name may appear in the following places: + // ColorSpaceTransforms (src, dst) + // DisplayViewTransforms (src) + // Look (process_space) + // View (colorspace, display_colorspace) + // inactive_colorspaces, + // file_rules (colorspace), + // viewing_rules (colorspaces list) + + // roles + // for (int r = 0; r < m_mergedConfig->getNumRoles(); r++) + // { + // auto csName = m_mergedConfig->getRoleColorSpace(r); + // for (int i = 0; i < m_colorspaceMarkedToBeDeleted.size(); i++) + // { + // if (Platform::Strcasecmp(csName, m_colorspaceMarkedToBeDeleted[i].c_str()) == 0) + // { + // // Replace the name with the colorspace that we kept earlier. + // m_mergedConfig->setRole(m_mergedConfig->getRoleName(r), + // m_colorspaceReplacingMarkedCs[i].c_str()); + // } + // } + // } + + // // environment + // for (int e = 0; e < m_mergedConfig->getNumEnvironmentVars(); e++) + // { + // const char * name = m_mergedConfig->getEnvironmentVarNameByIndex(e); + // const char * value = m_mergedConfig->getEnvironmentVarDefault(name); + // for (int i = 0; i < m_colorspaceMarkedToBeDeleted.size(); i++) + // { + // if (Platform::Strcasecmp(value, m_colorspaceMarkedToBeDeleted[i].c_str()) == 0) + // { + // // Replace the name with the colorspace that we kept earlier. + // m_mergedConfig->addEnvironmentVar(name, m_colorspaceReplacingMarkedCs[i].c_str()); + // } + // } + // } + + m_colorspaceMarkedToBeDeleted.clear(); + m_colorspaceReplacingMarkedCs.clear(); + } +} + +void ColorspacesMerger::replaceFamilySeparatorInFamily(ColorSpaceRcPtr & incomingCs) +{ + std::string family = incomingCs->getFamily(); + if (!family.empty()) + { + char separator = '/'; + std::string updatedFamily = ""; + + if (m_params->getColorspaces() == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT) + { + // Incoming colorspaces are from the base config. + separator = m_baseConfig->getFamilySeparator(); + } + else if (m_params->getColorspaces() == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_BASE) + { + // Incoming colorspaces are from the input config. + separator = m_inputConfig->getFamilySeparator(); + } + + std::string separatorStr(1, separator); + std::string mergedSeparatorStr(1, m_mergedConfig->getFamilySeparator()); + updatedFamily = StringUtils::Replace(incomingCs->getFamily(), separatorStr, mergedSeparatorStr); + incomingCs->setFamily(updatedFamily.c_str()); + } + // Do nothing if family is empty +} +*/ + +bool hasSearchPath(const ConstConfigRcPtr & cfg, const char * path) +{ + for (int i = 0; i < cfg->getNumSearchPaths(); i++) + { + if (Platform::Strcasecmp(cfg->getSearchPath(i), path) == 0) + { + return true; + } + } + return false; +} + +void ColorspacesMerger::processSearchPaths() const +{ + const char * searchPaths = m_params->getSearchPath(); + if (searchPaths && *searchPaths) + { + // Use the override. + m_mergedConfig->setSearchPath(searchPaths); + return; + } + + if (m_params->isInputFirst()) + { + m_mergedConfig->clearSearchPaths(); + // Add all from input config. + for (int i = 0; i < m_inputConfig->getNumSearchPaths(); i++) + { + m_mergedConfig->addSearchPath(m_inputConfig->getSearchPath(i)); + } + + // Only add the new ones from the base config. + for (int i = 0; i < m_baseConfig->getNumSearchPaths(); i++) + { + if (!hasSearchPath(m_inputConfig, m_baseConfig->getSearchPath(i))) + { + m_mergedConfig->addSearchPath(m_baseConfig->getSearchPath(i)); + } + } + } + else + { + // NB: The m_mergecConfig is initialized with the contents of the m_baseConfig. + + for (int i = 0; i < m_inputConfig->getNumSearchPaths(); i++) + { + if (!hasSearchPath(m_baseConfig, m_inputConfig->getSearchPath(i))) + { + m_mergedConfig->addSearchPath(m_inputConfig->getSearchPath(i)); + } + } + } +} + +void cleanUpInactiveList(ConfigRcPtr & mergeConfig) +{ + StringUtils::StringVec originalList, validList; + splitActiveList(mergeConfig->getInactiveColorSpaces(), originalList); + for (auto & item : originalList) + { + const std::string name = StringUtils::Trim(item); + ConstColorSpaceRcPtr existingCS = mergeConfig->getColorSpace(name.c_str()); + ConstNamedTransformRcPtr existingNT = mergeConfig->getNamedTransform(name.c_str()); + + if (existingCS) + { + // Don't want aliases in the inactive list. + if (Platform::Strcasecmp(existingCS->getName(), name.c_str()) == 0) + { + validList.push_back(name); + } + } + else if (existingNT) + { + if (Platform::Strcasecmp(existingNT->getName(), name.c_str()) == 0) + { + validList.push_back(name); + } + } + } + mergeConfig->setInactiveColorSpaces(StringUtils::Join(validList, ',').c_str()); +} + +std::string replaceSeparator(std::string str, char inSep, char outSep) +{ + std::string defaultSeparatorStr(1, inSep); + std::string mergedSeparatorStr(1, outSep); + std::string updatedStr = StringUtils::Replace(str, defaultSeparatorStr, mergedSeparatorStr); + return updatedStr; +} + +void ColorspacesMerger::updateFamily(std::string & family, bool fromBase) const +{ + // Note that if a prefix is present, it is always added, even if the CS did not have a family. + + std::string updatedPrefix = ""; + if (m_params->getColorspaces() == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT) + { + if (fromBase) + { + // If the color space is from the base config, need to update its family separator. + if (!family.empty()) + { + family = replaceSeparator(family, m_baseConfig->getFamilySeparator(), m_mergedConfig->getFamilySeparator()); + } + // Note: The family prefix argument must always use the default slash separator. + // TODO: Should do this just once in the initializer. + updatedPrefix = replaceSeparator(m_params->getBaseFamilyPrefix(), '/', m_mergedConfig->getFamilySeparator()); + } + else + { + updatedPrefix = replaceSeparator(m_params->getInputFamilyPrefix(), '/', m_mergedConfig->getFamilySeparator()); + } + } + else if (m_params->getColorspaces() == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_BASE) + { + if (fromBase) + { + // TODO: Should do this just once in the initializer. + updatedPrefix = replaceSeparator(m_params->getBaseFamilyPrefix(), '/', m_mergedConfig->getFamilySeparator()); + } + else + { + // If the color space is from the input config, need to update its family separator. + if (!family.empty()) + { + family = replaceSeparator(family, m_inputConfig->getFamilySeparator(), m_mergedConfig->getFamilySeparator()); + } + updatedPrefix = replaceSeparator(m_params->getInputFamilyPrefix(), '/', m_mergedConfig->getFamilySeparator()); + } + } + // Append the prefix to the family. + // Note that the prefix should end with a separator, if desired. Not adding one here. + family = updatedPrefix + family; +} + +bool hasColorSpaceRefType(const ConstConfigRcPtr & config, ReferenceSpaceType refType) +{ + SearchReferenceSpaceType searchRefType = static_cast(refType); + int n = config->getNumColorSpaces(searchRefType, COLORSPACE_ALL); + return n > 0; +} + +void ColorspacesMerger::initializeRefSpaceConverters(ConstTransformRcPtr & inputToBaseGtScene, + ConstTransformRcPtr & inputToBaseGtDisplay) +{ + // Note: The base config reference space is always used, regardless of strategy. + + if (!m_params->isAssumeCommonReferenceSpace()) + { + if (hasColorSpaceRefType(m_inputConfig, REFERENCE_SPACE_SCENE)) + { + try + { + inputToBaseGtScene = ConfigUtils::getRefSpaceConverter( + m_inputConfig, + m_baseConfig, + REFERENCE_SPACE_SCENE + ); + } + catch(const Exception & e) + { + LogError(e.what()); + } + } + + // Only attempt to build the converter if the input config has this type of + // reference space. Using the input config for this determination since it is + // only input config color spaces whose reference space is converted. + if (hasColorSpaceRefType(m_inputConfig, REFERENCE_SPACE_DISPLAY)) + { + try + { + inputToBaseGtDisplay = ConfigUtils::getRefSpaceConverter( + m_inputConfig, + m_baseConfig, + REFERENCE_SPACE_DISPLAY + ); + } + catch(const Exception & e) + { + LogError(e.what()); + } + } + } +} + +// TODO: Make this a functional inside where it's called from. +void ColorspacesMerger::attemptToAddAlias(const ConstConfigRcPtr & mergeConfig, + ColorSpaceRcPtr & dupeCS, + const ConstColorSpaceRcPtr & inputCS, + const char * aliasName) +{ + // It is assumed that the base and input configs start out in a legal state, + // however, when adding anything from one config to another, must always + // check that it doesn't conflict with anything. + + // It is assumed that the strategy is prefer_base when this function is called. + + // It's OK if aliasName used in the duplicate color space itself. + if ((Platform::Strcasecmp(dupeCS->getName(), aliasName) == 0) + || hasAlias(dupeCS, aliasName)) + { + // It's already present, no need to add anything. + return; + } + + // Check if aliasName is already a name that is used in the config. + + ConstColorSpaceRcPtr conflictingCS = mergeConfig->getColorSpace(aliasName); + if (conflictingCS) + { + // The conflict could be the name of a color space, an alias, or a role. + // But it doesn't matter, the strategy is prefer base so don't want to + // remove this conflict from the base config to accomodate adding an + // alias from the input config. + std::ostringstream os; + os << "Input color space '" << inputCS->getName() << "'"; + os << " is a duplicate of base color space '"; + os << dupeCS->getName() << "' but was unable to add alias '"; + os << aliasName << "' since it conflicts with base color space '"; + os << conflictingCS->getName() << "'."; + notify(os.str(), m_params->isErrorOnConflict()); + + return; + } + + // No conflicts encountered, it's ok to update the alias and add it to the config. + + dupeCS->addAlias(aliasName); +} + +bool ColorspacesMerger::handleAvoidDuplicatesOption(ConfigRcPtr & eBase, ColorSpaceRcPtr & inputCS) +{ + bool notDuplicate = true; + + if (!m_params->isAvoidDuplicates()) + { + return notDuplicate; + } + + // Note: The search for duplicate color spaces only searches for color spaces with + // the same reference space type (i.e., scene or display), so it won't remove spaces + // that are otherwise equivalent (e.g., an sRGB transform). + // + // However, some configs may intentionally have duplicate color spaces (e.g., aliases + // from v1 configs). Since this search is only done using spaces from the input config, + // those duplicates in the base won't be removed. But if the input config contains + // duplicates, those will be condensed into one space containing aliases for all of + // names of the duplicates. + const char * duplicateInBase = ConfigUtils::findEquivalentColorspace( + eBase, + inputCS, + inputCS->getReferenceSpaceType() + ); + + const ConfigMergingParameters::MergeStrategies strategy = m_params->getColorspaces(); + if (duplicateInBase && *duplicateInBase) + { + if (strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT) + { +// m_colorspaceMarkedToBeDeleted.push_back(duplicateInBase); +// m_colorspaceReplacingMarkedCs.push_back(inputCS->getName()); + + // Add the name and aliases from the duplicate colorspace to the input colorspace. + // + // Note that the aliases added here should not have conflicts with the base config + // (since that's where they originated), but may cause conflicts with other color + // spaces in the input config, but these will be handled as the spaces get added + // to the merged config by the calling function. + + ConstColorSpaceRcPtr dupeCS = eBase->getColorSpace(duplicateInBase); + if (dupeCS) + { + // Note that addAlias will check the argument and won't add it if it matches + // the name of the color space or one of the existing aliases. + inputCS->addAlias(dupeCS->getName()); + + for (size_t i = 0; i < dupeCS->getNumAliases(); i++) + { + inputCS->addAlias(dupeCS->getAlias(i)); + } + + eBase->removeColorSpace(duplicateInBase); + } + } + else if (strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_BASE) + { + // Don't add the input color space, but add it's name and alias to the duplicate. + // Need to be more careful of conflicts, since the modified color space is + // receiving aliases from the input config and yet is not going through the + // mergeColorSpace checking below. + + ConstColorSpaceRcPtr cs = eBase->getColorSpace(duplicateInBase); + if (cs) + { + ColorSpaceRcPtr eCS = cs->createEditableCopy(); + + attemptToAddAlias(eBase, eCS, inputCS, inputCS->getName()); + + for (size_t i = 0; i < inputCS->getNumAliases(); i++) + { + attemptToAddAlias(eBase, eCS, inputCS, inputCS->getAlias(i)); + } + + // Replace the color space in the merge config. (This preserves its + // order in the color space list.) + eBase->addColorSpace(eCS); + + notDuplicate = false; + } + } + } + return notDuplicate; +} + + +bool ColorspacesMerger::colorSpaceMayBeMerged(const ConstConfigRcPtr & mergeConfig, + const ConstColorSpaceRcPtr & inputCS) const +{ + // This should only be called on color spaces from the input config. + + // NB: This routine assumes all NamedTransforms have been removed from the mergeConfig. + // Not trying to handle name conflicts with NamedTransforms, color spaces have precedence. + + if (!inputCS) + { + return false; + } + + const char * name = inputCS->getName(); + + // This will compare the name against roles, color space names, and aliases. + ConstColorSpaceRcPtr existingCS = mergeConfig->getColorSpace(name); + + if (!existingCS) + { + // No name conflicts, go ahead and add it. + return true; + } + + // OK, something has this name, figure out what it is. + + // Does it have the same name as a role? + if (mergeConfig->hasRole(name)) + { + // Don't merge it if it would override a role. + + std::ostringstream os; + os << "Color space '" << name << "' was not merged as it's identical to a role name."; + notify(os.str(), m_params->isErrorOnConflict()); + + return false; + } + + const ConfigMergingParameters::MergeStrategies strategy = m_params->getColorspaces(); + + // Does it have the same name as another color space? + if (Platform::Strcasecmp(existingCS->getName(), name) == 0) + { + // The name matches a color space name in the mergeConfig. + // Whether to allow the merge is based on the merge strategy. + + if (strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT + || strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_INPUT_ONLY) + { + // Allow the merger. + + std::ostringstream os; + os << "Color space '" << name << "' will replace a color space in the base config."; + notify(os.str(), m_params->isErrorOnConflict()); + + return true; + } + else + { + // Don't merge since it would replace a color space from the base config. + + std::ostringstream os; + os << "Color space '" << name << "' was not merged as it's already present in the base config."; + notify(os.str(), m_params->isErrorOnConflict()); + + return false; + } + } + else + { + // The name conflicts with an alias of another color space. + // Whether to allow the merge is based on the merge strategy. + + if (strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT + || strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_INPUT_ONLY) + { + // Allow the merger. + + std::ostringstream os; + os << "The name of merged color space '" << name << "'"; + os << " has a conflict with an alias in color space '"; + os << existingCS->getName() << "'."; + notify(os.str(), m_params->isErrorOnConflict()); + + return true; + } + else + { + // Don't merge it if it would replace an alias from the base config. + + std::ostringstream os; + os << "Color space '" << name << "' was not merged as it conflicts with an alias "; + os << "in color space '" << existingCS->getName() << "'."; + notify(os.str(), m_params->isErrorOnConflict()); + + return false; + } + } +} + +void ColorspacesMerger::mergeColorSpace(ConfigRcPtr & mergeConfig, + ColorSpaceRcPtr & eInputCS, + std::vector & addedInputColorSpaces) +{ + // NB: This routine assumes all NamedTransforms have been removed from the mergeConfig. + // Not trying to handle name conflicts with NamedTransforms, color spaces have precedence. + + // Check if mergeConfig already has a color space with the same name as the input CS. + + const char * name = eInputCS->getName(); + ConstColorSpaceRcPtr originalCS = mergeConfig->getColorSpace(name); + + if (originalCS) + { + // Note that the color space which gets discarded and the color space being added below may not + // have the same reference space type (i.e., scene vs. display). This is currently allowed + // but log a warning. + if (eInputCS->getReferenceSpaceType() != originalCS->getReferenceSpaceType()) + { + std::ostringstream os; + os << "Merged color space '" << name << "' has a different reference "; + os << "space type than the color space it's replacing."; + notify(os.str(), false); + } + + // If there is a color space with this name in the existing config, + // remove it (and any aliases it may contain). This is the case when + // the strategy calls for replacing an existing color space. + // + // If the eInputCS name matched an alias rather than a color space name, + // this does nothing (and the alias is handled below). + // + // The notification is handled in colorSpaceMayBeMerged to avoid having to determine + // again whether the conflict is with the name or alias of originalCS. + + mergeConfig->removeColorSpace(name); + } + + // Handle conflicts of the eInputCS name with aliases of other color spaces. + + ConstColorSpaceRcPtr existingCS = mergeConfig->getColorSpace(name); + if (existingCS) + { + // Get the name of the color space that contains the alias. + + // Verify that the name is actually an alias rather than some other conflict. + // (Should never happen.) + if (!hasAlias(existingCS, name)) + { + std::ostringstream os; + os << "Problem merging color space: '" << name << "'."; + throw Exception(os.str().c_str()); + } + + // Remove the alias from that existing color space. + // Note that this conflict was detected and allowed in colorSpaceMayBeMerged + // based on the merge strategy, so the decision has already been made to remove + // this alias from a color space in the base config. + + auto eExistingCS = existingCS->createEditableCopy(); + eExistingCS->removeAlias(name); + // Edit the colorspace in the copy of the merged config. + mergeConfig->addColorSpace(eExistingCS); + + // The notification is handled in colorSpaceMayBeMerged to avoid having to determine + // again whether the conflict is with the name or alias of originalCS. + } + + const ConfigMergingParameters::MergeStrategies strategy = m_params->getColorspaces(); + + // Handle conflicts of the eInputCS aliases with other color spaces or aliases. + + for (size_t i = 0; i < eInputCS->getNumAliases(); i++) + { + const char * aliasName = eInputCS->getAlias(i); + + std::ostringstream os; + + ConstColorSpaceRcPtr conflictingCS = mergeConfig->getColorSpace(aliasName); + if (conflictingCS) + { + if (Platform::Strcasecmp(conflictingCS->getName(), aliasName) == 0) + { + // The alias conflicts with the name of an existing color space. + + os << "Merged color space '" << name << "'"; + os << " has an alias '"; + os << aliasName << "' that conflicts with color space '"; + os << conflictingCS->getName() << "'."; + + if (strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT + || strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_INPUT_ONLY) + { + // Remove that base color space. + mergeConfig->removeColorSpace(conflictingCS->getName()); + } + else + { + // Remove the alias from the input color space. + eInputCS->removeAlias(aliasName); + } + } + else if (hasAlias(conflictingCS, aliasName)) + { + // The alias conflicts with an alias of the conflicting color space. + + os << "Merged color space '" << name << "'"; + os << " has a conflict with alias '"; + os << aliasName << "' in color space '"; + os << conflictingCS->getName() << "'."; + + if (strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT + || strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_INPUT_ONLY) + { + // Remove the alias from that base color space. + auto eConflictingCS = conflictingCS->createEditableCopy(); + eConflictingCS->removeAlias(aliasName); + + // Replace the colorspace in the copy of the merged config. + mergeConfig->addColorSpace(eConflictingCS); + } + else + { + // Remove the alias from the input color space. + eInputCS->removeAlias(aliasName); + } + } + else if (mergeConfig->hasRole(aliasName)) + { + os << "Merged color space '" << name << "'"; + os << " has an alias '"; + os << aliasName << "' that conflicts with a role."; + + // Remove the alias from the input color space. + eInputCS->removeAlias(aliasName); + } + else // (Should never happen.) + { + std::ostringstream os; + os << "Problem merging color space: '" << name << "' due to its aliases."; + throw Exception(os.str().c_str()); + } + + notify(os.str(), m_params->isErrorOnConflict()); + } + } + + // Add the color space. This will throw if a problem is found. + // (But all name conflicts should have been handled already.) + mergeConfig->addColorSpace(eInputCS); + + // Keep a record that this input color space was added to allow reordering later. + addedInputColorSpaces.push_back(name); + + // TODO: Is it ever possible that a CS added to the list would be removed as another is merged? + + // TODO: When color spaces or aliases are removed above, it's possible it could break + // some other part of the config that referenced them. This would include elements such as: + // environment, views, inactive_colorspaces, ColorSpaceTransforms, or DisplayViewTransforms. +} + +void ColorspacesMerger::addColorSpaces() +{ + // Delete all the NamedTransforms, color spaces take precedence, so don't want them + // interfering with merges by causing name conflicts. + + // NB: This is only intended to be called for the prefer_input and prefer_base strategies. + + m_mergedConfig->clearNamedTransforms(); + + // Make a temp copy to merge the input color spaces into (will reorder them later). + ConfigRcPtr mergeConfig = m_mergedConfig->createEditableCopy(); + + mergeConfig->clearNamedTransforms(); + + ConstTransformRcPtr inputToBaseGtScene, inputToBaseGtDisplay; + initializeRefSpaceConverters(inputToBaseGtScene, inputToBaseGtDisplay); + + // Loop over all active and inactive color spaces of all reference types in the input config. + // Merge them into the temp config (which already contains the base color spaces). + std::vector addedInputColorSpaces; + + for (int i = 0; i < m_inputConfig->getNumColorSpaces(SEARCH_REFERENCE_SPACE_ALL, COLORSPACE_ALL); ++i) + { + const char * name = m_inputConfig->getColorSpaceNameByIndex(SEARCH_REFERENCE_SPACE_ALL, + COLORSPACE_ALL, + i); + ConstColorSpaceRcPtr cs = m_inputConfig->getColorSpace(name); + if (!cs) + continue; + ColorSpaceRcPtr eCS = cs->createEditableCopy(); + + if (!m_params->isAssumeCommonReferenceSpace()) + { + if (eCS->getReferenceSpaceType() == REFERENCE_SPACE_DISPLAY) + ConfigUtils::updateReferenceColorspace(eCS, inputToBaseGtDisplay); + else + ConfigUtils::updateReferenceColorspace(eCS, inputToBaseGtScene); + } + + // Doing this against the mergedConfig rather than the base config so that the most + // recent state of any aliases that get added or color spaces that are removed are + // considered by the duplicate consolidation process. + const bool notDuplicate = handleAvoidDuplicatesOption(mergeConfig, eCS); + + if (notDuplicate && colorSpaceMayBeMerged(mergeConfig, eCS)) + { + // NB: This may make changes to existing color spaces in mergeConfig + // to resolve name conflicts. + mergeColorSpace(mergeConfig, eCS, addedInputColorSpaces); + } + } + + m_mergedConfig->clearColorSpaces(); + + // Add the color spaces to the real merged config. + + if (m_params->isInputFirst()) + { + // Add color spaces from the input config. + for (auto & name : addedInputColorSpaces) + { + ConstColorSpaceRcPtr inputCS = mergeConfig->getColorSpace(name.c_str()); + if (inputCS) + { + ColorSpaceRcPtr eInputCS = inputCS->createEditableCopy(); + + // Add family prefix. + const bool fromBase = false; + std::string family = eInputCS->getFamily(); + updateFamily(family, fromBase); + eInputCS->setFamily(family.c_str()); + + m_mergedConfig->addColorSpace(eInputCS); + + mergeConfig->removeColorSpace(name.c_str()); + } + } + + // Add color spaces from the base config. + for (int i = 0; i < mergeConfig->getNumColorSpaces(SEARCH_REFERENCE_SPACE_ALL, COLORSPACE_ALL); ++i) + { + // Note that during the merge process, some of the color spaces from the base config may + // be replaced if their aliases are edited. This should not change their order in the config, + // but may want to account for this, if that ever changes and they get moved to the end. + const char * name = mergeConfig->getColorSpaceNameByIndex(SEARCH_REFERENCE_SPACE_ALL, + COLORSPACE_ALL, + i); + ConstColorSpaceRcPtr baseCS = mergeConfig->getColorSpace(name); + if (baseCS) + { + auto eBaseCS = baseCS->createEditableCopy(); + + // Add family prefix. + const bool fromBase = true; + std::string family = eBaseCS->getFamily(); + updateFamily(family, fromBase); + eBaseCS->setFamily(family.c_str()); + + m_mergedConfig->addColorSpace(eBaseCS); + } + } + } + else + { + // The color spaces should already be in the correct order. + // Copy them into the real merged config and add family prefix. + for (int i = 0; i < mergeConfig->getNumColorSpaces(SEARCH_REFERENCE_SPACE_ALL, COLORSPACE_ALL); ++i) + { + const char * name = mergeConfig->getColorSpaceNameByIndex(SEARCH_REFERENCE_SPACE_ALL, + COLORSPACE_ALL, + i); + ConstColorSpaceRcPtr cs = mergeConfig->getColorSpace(name); + if (cs) + { + auto eCS = cs->createEditableCopy(); + bool fromBase = true; + + // Add family prefix. + if (std::find(addedInputColorSpaces.begin(), addedInputColorSpaces.end(), name) + != addedInputColorSpaces.end()) + { + fromBase = false; + } + std::string family = eCS->getFamily(); + updateFamily(family, fromBase); + eCS->setFamily(family.c_str()); + + m_mergedConfig->addColorSpace(eCS); + } + } + } + + // (Not cleaning up the inactive list here, it would remove named transforms, wait until after NT.) + + // TODO: What if the environment contains a color space that was removed? +} + + +void ColorspacesMerger::handlePreferInput() +{ + // Set environment. + // Since the environment variables are stored inside a std::map, the key are ordered + // alphabetically. Therefore, there is no point to look at the option "InputFirst". + if (m_params->getNumEnvironmentVars() > 0) + { + // Take environment variables from overrides. + m_mergedConfig->clearEnvironmentVars(); + for (int i = 0; i < m_params->getNumEnvironmentVars(); i++) + { + m_mergedConfig->addEnvironmentVar(m_params->getEnvironmentVar(i), + m_params->getEnvironmentVarValue(i)); + } + } + else + { + // Add environment variables from input config to base config. + for (int i = 0; i < m_inputConfig->getNumEnvironmentVars(); i++) + { + const std::string & name = m_inputConfig->getEnvironmentVarNameByIndex(i); + // Overwrite any existing env. variable with the same name. + m_mergedConfig->addEnvironmentVar(name.c_str(), + m_inputConfig->getEnvironmentVarDefault(name.c_str())); + } + } + + // Set search_path. + processSearchPaths(); + + // Set inactive_colorspaces. + const char * inactiveCS = m_params->getInactiveColorSpaces(); + if (inactiveCS && *inactiveCS) + { + // Take inactive colorspaces from overrides. + m_mergedConfig->setInactiveColorSpaces(inactiveCS); + } + else + { + // Add inactive colorspaces from input config to base config. + + StringUtils::StringVec mergedInactiveCS; + if (m_params->isInputFirst()) + { + StringUtils::StringVec baseInactiveCS; + splitActiveList(m_baseConfig->getInactiveColorSpaces(), baseInactiveCS); + splitActiveList(m_inputConfig->getInactiveColorSpaces(), mergedInactiveCS); + + mergeStringsWithoutDuplicates(baseInactiveCS, mergedInactiveCS); + } + else + { + StringUtils::StringVec inputInactiveCS; + splitActiveList(m_inputConfig->getInactiveColorSpaces(), inputInactiveCS); + splitActiveList(m_mergedConfig->getInactiveColorSpaces(), mergedInactiveCS); + + mergeStringsWithoutDuplicates(inputInactiveCS, mergedInactiveCS); + } + m_mergedConfig->setInactiveColorSpaces(StringUtils::Join(mergedInactiveCS, ',').c_str()); + } + + // Set family_separator. + m_mergedConfig->setFamilySeparator(m_inputConfig->getFamilySeparator()); + + // Merge the color spaces. + addColorSpaces(); +} + +void ColorspacesMerger::handlePreferBase() +{ + // Set environment. + // Since the environment variables are stored inside a std::map, the key are ordered + // alphabetically. Therefore, there is no point to look at the option "InputFirst". + if (m_params->getNumEnvironmentVars() > 0) + { + // Take environment variables from overrides. + m_mergedConfig->clearEnvironmentVars(); + for (int i = 0; i < m_params->getNumEnvironmentVars(); i++) + { + m_mergedConfig->addEnvironmentVar(m_params->getEnvironmentVar(i), + m_params->getEnvironmentVarValue(i)); + } + } + else + { + // Take environment variables from config. + for (int i = 0; i < m_inputConfig->getNumEnvironmentVars(); i++) + { + const std::string & name = m_inputConfig->getEnvironmentVarNameByIndex(i); + // If the var's default value is empty, it doesn't exist, so nothing to overwrite. + const bool varDoesNotExist = std::string(m_mergedConfig->getEnvironmentVarDefault(name.c_str())).empty(); + if (varDoesNotExist) + { + m_mergedConfig->addEnvironmentVar(name.c_str(), + m_inputConfig->getEnvironmentVarDefault(name.c_str())); + } + } + } + + // Set search_path. + processSearchPaths(); + + // Set inactive_colorspaces. + const char * inactiveCS = m_params->getInactiveColorSpaces(); + if (inactiveCS && *inactiveCS) + { + // Take inactive colorspaces from overrides. + m_mergedConfig->setInactiveColorSpaces(inactiveCS); + } + else + { + // Add inactive colorspaces from input config to base config. + + StringUtils::StringVec mergedInactiveCS; + if (m_params->isInputFirst()) + { + StringUtils::StringVec baseInactiveCS; + splitActiveList(m_baseConfig->getInactiveColorSpaces(), baseInactiveCS); + splitActiveList(m_inputConfig->getInactiveColorSpaces(), mergedInactiveCS); + + mergeStringsWithoutDuplicates(baseInactiveCS, mergedInactiveCS); + } + else + { + StringUtils::StringVec inputInactiveCS; + splitActiveList(m_inputConfig->getInactiveColorSpaces(), inputInactiveCS); + splitActiveList(m_mergedConfig->getInactiveColorSpaces(), mergedInactiveCS); + + mergeStringsWithoutDuplicates(inputInactiveCS, mergedInactiveCS); + } + m_mergedConfig->setInactiveColorSpaces(StringUtils::Join(mergedInactiveCS, ',').c_str()); + } + + // Set family_separator. + m_mergedConfig->setFamilySeparator(m_baseConfig->getFamilySeparator()); + + // Merge the color spaces. + addColorSpaces(); +} + +void ColorspacesMerger::handleInputOnly() +{ + // Set environment. + if (m_params->getNumEnvironmentVars() > 0) + { + // Take environment variables from overrides. + m_mergedConfig->clearEnvironmentVars(); + for (int i = 0; i < m_params->getNumEnvironmentVars(); i++) + { + m_mergedConfig->addEnvironmentVar(m_params->getEnvironmentVar(i), + m_params->getEnvironmentVarValue(i)); + } + } + else + { + // Take environment variables from config. + m_mergedConfig->clearEnvironmentVars(); + for (int i = 0; i < m_inputConfig->getNumEnvironmentVars(); i++) + { + const std::string & name = m_inputConfig->getEnvironmentVarNameByIndex(i); + m_mergedConfig->addEnvironmentVar(name.c_str(), + m_inputConfig->getEnvironmentVarDefault(name.c_str())); + } + } + + // Set search_path. + const char * searchPaths = m_params->getSearchPath(); + if (searchPaths && *searchPaths) + { + // Use the override. + m_mergedConfig->setSearchPath(searchPaths); + } + else + { + m_mergedConfig->setSearchPath(m_inputConfig->getSearchPath()); + } + + // Set inactive_colorspaces. + const char * inactiveCS = m_params->getInactiveColorSpaces(); + if (inactiveCS && *inactiveCS) + { + // Take inactive color spaces from overrides. + m_mergedConfig->setInactiveColorSpaces(inactiveCS); + } + else + { + // Take inactive color spaces from config. + m_mergedConfig->setInactiveColorSpaces(m_inputConfig->getInactiveColorSpaces()); + } + + // Set family_separator. + m_mergedConfig->setFamilySeparator(m_inputConfig->getFamilySeparator()); + + // Remove all color spaces from base config. + m_mergedConfig->clearColorSpaces(); + + // Take color spaces from input config. + // No error expected as it only adds the color spaces from the input config. + + // Avoid any conflicts with named transforms from the base config. + m_mergedConfig->clearNamedTransforms(); + + // Merge the color spaces. + const size_t numCS = m_inputConfig->getNumColorSpaces(SEARCH_REFERENCE_SPACE_ALL, COLORSPACE_ALL); + for (unsigned long i = 0; i < numCS; ++i) + { + const char * name = m_inputConfig->getColorSpaceNameByIndex(SEARCH_REFERENCE_SPACE_ALL, + COLORSPACE_ALL, + i); + ConstColorSpaceRcPtr cs = m_inputConfig->getColorSpace(name); + m_mergedConfig->addColorSpace(cs); + } +} + +void ColorspacesMerger::handleBaseOnly() +{ + // Process the overrides only since the merged config is initialized to + // the base config. + + // Do search_path override. + const char * searchPaths = m_params->getSearchPath(); + if (searchPaths && *searchPaths) + { + // Use the override. + m_mergedConfig->setSearchPath(searchPaths); + } + + // Do environment override. + if (m_params->getNumEnvironmentVars() > 0) + { + // Take environment variables from overrides. + m_mergedConfig->clearEnvironmentVars(); + for (int i = 0; i < m_params->getNumEnvironmentVars(); i++) + { + m_mergedConfig->addEnvironmentVar(m_params->getEnvironmentVar(i), + m_params->getEnvironmentVarValue(i)); + } + } + + // Do inactive_colorspaces override. + const char * inactiveCS = m_params->getInactiveColorSpaces(); + if (inactiveCS && *inactiveCS) + { + m_mergedConfig->setInactiveColorSpaces(inactiveCS); + } + + // Nothing to do for display_colorspaces and colorspaces as the merged config + // is initialized to the base config. + + // TODO: Avoid conflicts if roles are added from input config? +} + +void ColorspacesMerger::handleRemove() +{ + // Handle environment. + // If an environment variable is used somewhere and got removed, validating the config + // will return an error. + for (int i = 0; i < m_inputConfig->getNumEnvironmentVars(); i++) + { + const std::string & name = m_inputConfig->getEnvironmentVarNameByIndex(i); + bool exists = !std::string(m_mergedConfig->getEnvironmentVarDefault(name.c_str())).empty(); + if (exists) + { + m_mergedConfig->addEnvironmentVar(name.c_str(), NULL); + } + } + + // Handle search_path. + m_mergedConfig->clearSearchPaths(); + for (int i = 0; i < m_baseConfig->getNumSearchPaths(); i++) + { + size_t found = StringUtils::Find(m_inputConfig->getSearchPath(), m_baseConfig->getSearchPath(i)); + if (found == std::string::npos) + { + m_mergedConfig->addSearchPath(m_baseConfig->getSearchPath(i)); + } + } + + // Handle inactive_colorspaces. + StringUtils::StringVec baseInactiveCS, inputInactiveCS, mergedInactiveCS; + splitActiveList(m_baseConfig->getInactiveColorSpaces(), baseInactiveCS); + splitActiveList(m_inputConfig->getInactiveColorSpaces(), inputInactiveCS); + StringUtils::Trim(inputInactiveCS); + for (const auto & name : baseInactiveCS) + { + const std::string trimmedName = StringUtils::Trim(name); + if (!trimmedName.empty()) + { + if (!StringUtils::Contain(inputInactiveCS, trimmedName)) + { + mergedInactiveCS.push_back(trimmedName); + } + } + } + m_mergedConfig->setInactiveColorSpaces(StringUtils::Join(mergedInactiveCS, ',').c_str()); + + // The family_separator never gets removed. + + // Handle display_colorspaces and colorspaces. + // This could obviously break any other part of the base config that references the + // removed color space, so it is up to the user to know what they are doing. + + const size_t numCS = m_inputConfig->getNumColorSpaces(SEARCH_REFERENCE_SPACE_ALL, COLORSPACE_ALL); + for (unsigned long i = 0; i < numCS; ++i) + { + const char * name = m_inputConfig->getColorSpaceNameByIndex(SEARCH_REFERENCE_SPACE_ALL, + COLORSPACE_ALL, + i); + // Note: The remove does nothing if the color space is not present. + m_mergedConfig->removeColorSpace(name); + } +} + +/////////////////////////////////// ColorspacesMerger end ///////////////////////////////////////// + + +///////////////////////////////////// NamedTransformsMerger /////////////////////////////////////// + +void NamedTransformsMerger::updateFamily(std::string & family, bool fromBase) const +{ + // Note that if a prefix is present, it is always added, even if the CS did not have a family. + + std::string updatedPrefix = ""; + if (m_params->getColorspaces() == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT) + { + if (fromBase) + { + // If the color space is from the base config, need to update its family separator. + if (!family.empty()) + { + family = replaceSeparator(family, m_baseConfig->getFamilySeparator(), m_mergedConfig->getFamilySeparator()); + } + // Note: The family prefix argument must always use the default slash separator. + // TODO: Should do this just once in the initializer. + updatedPrefix = replaceSeparator(m_params->getBaseFamilyPrefix(), '/', m_mergedConfig->getFamilySeparator()); + } + else + { + updatedPrefix = replaceSeparator(m_params->getInputFamilyPrefix(), '/', m_mergedConfig->getFamilySeparator()); + } + } + else if (m_params->getColorspaces() == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_BASE) + { + if (fromBase) + { + // TODO: Should do this just once in the initializer. + updatedPrefix = replaceSeparator(m_params->getBaseFamilyPrefix(), '/', m_mergedConfig->getFamilySeparator()); + } + else + { + // If the color space is from the input config, need to update its family separator. + if (!family.empty()) + { + family = replaceSeparator(family, m_inputConfig->getFamilySeparator(), m_mergedConfig->getFamilySeparator()); + } + updatedPrefix = replaceSeparator(m_params->getInputFamilyPrefix(), '/', m_mergedConfig->getFamilySeparator()); + } + } + // Append the prefix to the family. + // Note that the prefix should end with a separator, if desired. Not adding one here. + family = updatedPrefix + family; +} + +bool NamedTransformsMerger::namedTransformMayBeMerged(const ConstConfigRcPtr & mergeConfig, + const ConstNamedTransformRcPtr & nt, + bool fromBase) const +{ + if (!nt) + { + return false; + } + + const char * name = nt->getName(); + + // This will compare the name against roles, color space names, and aliases. + // (Note that if the role refers to a named transform, this will return null, + // but it's illegal for a role to point to a named transform.) + ConstColorSpaceRcPtr existingCS = mergeConfig->getColorSpace(name); + + ConstNamedTransformRcPtr existingNT = mergeConfig->getNamedTransform(name); + + if (!existingCS && !existingNT) + { + // No name conflicts, go ahead and add it. + return true; + } + + // OK, something has this name, figure out what it is. + + // Does it have the same name as a role? + if (mergeConfig->hasRole(name)) + { + // Don't merge it if it would override a role. + + std::ostringstream os; + os << "Named transform '" << name << "' was not merged as it's identical to a role name."; + notify(os.str(), m_params->isErrorOnConflict()); + + return false; + } + + if (existingCS) + { + // Does it have the same name as another color space? + if (Platform::Strcasecmp(existingCS->getName(), name) == 0) + { + // The name matches a color space name in the mergeConfig. + // Don't merge it, color spaces always have precedence. + std::ostringstream os; + os << "Named transform '" << name << "' was not merged as there's a color space with that name."; + notify(os.str(), m_params->isErrorOnConflict()); + + return false; + } + else + { + // The name conflicts with an alias of a color space. + // Don't merge it, color spaces always have precedence. + std::ostringstream os; + os << "Named transform '" << name << "' was not merged as there's a color space alias with that name."; + notify(os.str(), m_params->isErrorOnConflict()); + + return false; + } + } + + if (existingNT) + { + if (fromBase) + { + // Should not happen if the base config was legal. + std::ostringstream os; + os << "Named transform '" << name << "' was not merged as there's more than one with that name in the base config."; + notify(os.str(), m_params->isErrorOnConflict()); + + return false; + } + + const ConfigMergingParameters::MergeStrategies strategy = m_params->getNamedTransforms(); + + // At this point, only dealing with transforms from the input config. + + if (Platform::Strcasecmp(existingNT->getName(), name) == 0) + { + // The name matches a named transform name in the mergeConfig. + // Whether to allow the merge is based on the merge strategy. + + if (strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT + || strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_INPUT_ONLY) + { + // Allow the merger. + + std::ostringstream os; + os << "Named transform '" << name << "' will replace a named transform in the base config."; + notify(os.str(), m_params->isErrorOnConflict()); + + return true; + } + else + { + // Don't merge it if it would replace a named transform from the base config. + + std::ostringstream os; + os << "Named transform '" << name << "' was not merged as it's already present in the base config."; + notify(os.str(), m_params->isErrorOnConflict()); + + return false; + } + } + else + { + // The name conflicts with an alias of another named transform. + // Whether to allow the merge is based on the merge strategy. + + if (strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT + || strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_INPUT_ONLY) + { + // Allow the merger. + + std::ostringstream os; + os << "The name of merged named transform '" << name << "'"; + os << " has a conflict with an alias in named transform '"; + os << existingNT->getName() << "'."; + notify(os.str(), m_params->isErrorOnConflict()); + + return true; + } + else + { + // Don't merge it if it would replace an alias from the base config. + + std::ostringstream os; + os << "Named transform '" << name << "' was not merged as it conflicts with an alias "; + os << "in named transform '" << existingNT->getName() << "'."; + notify(os.str(), m_params->isErrorOnConflict()); + + return false; + } + } + } + return false; +} + +void NamedTransformsMerger::mergeNamedTransform(ConfigRcPtr & mergeConfig, + NamedTransformRcPtr & eNT, + bool fromBase, + std::vector & addedInputNamedTransforms) +{ + // NB: This routine assumes all NamedTransforms have been removed from the mergeConfig. + // Not trying to handle name conflicts with NamedTransforms, color spaces have precedence. + + // Check if mergeConfig already has a color space with the same name as the input CS. + + const char * name = eNT->getName(); + ConstNamedTransformRcPtr originalNT = mergeConfig->getNamedTransform(name); + + if (originalNT) + { + // If there is a named transform with this name in the existing config, + // remove it (and any aliases it may contain). This is the case when + // the strategy calls for replacing an existing transform. + // + // If the eNT name matched an alias rather than a named transform name, + // this does nothing (and the alias is handled below). + // + // The notification is handled in namedTransformMayBeMerged to avoid having to determine + // again whether the conflict is with the name or alias of originalNT. + + mergeConfig->removeNamedTransform(name); + } + + // Handle conflicts of the eNT name with aliases of other named transforms. + // NB: Would not be here if there is a name conflict with anything other than + // named transforms since the decision would have been not to merge it. + + ConstNamedTransformRcPtr existingNT = mergeConfig->getNamedTransform(name); + if (existingNT) + { + // Get the name of the named transform that contains the alias. + + // Verify that the name is actually an alias rather than some other conflict. + // (Should never happen.) + if (!hasAlias(existingNT, name)) + { + std::ostringstream os; + os << "Problem merging named transform: '" << name << "'."; + throw Exception(os.str().c_str()); + } + + // Remove the alias from that existing named transform. + // Note that this conflict was detected and allowed in namedTransformMayBeMerged + // based on the merge strategy, so the decision has already been made to remove + // this alias from a named transform in the base config. + + auto eExistingNT = existingNT->createEditableCopy(); + eExistingNT->removeAlias(name); + // Edit the named transform in the copy of the merged config. + mergeConfig->addNamedTransform(eExistingNT); + + // The notification is handled in namedTransformMayBeMerged to avoid having to determine + // again whether the conflict is with the name or alias of originalNT. + } + + ConfigMergingParameters::MergeStrategies strategy = m_params->getNamedTransforms(); + if (fromBase) + { + strategy = ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_BASE; + } + + // Handle conflicts of the eNT aliases with other color spaces, named transforms, and etc. + + for (size_t i = 0; i < eNT->getNumAliases(); i++) + { + const char * aliasName = eNT->getAlias(i); + + // Conflicts with color spaces or roles. (Always remove this alias.) + + std::ostringstream os; + + const char * source = fromBase ? "Base" : "Input"; + + ConstColorSpaceRcPtr conflictingCS = mergeConfig->getColorSpace(aliasName); + if (conflictingCS) + { + if (Platform::Strcasecmp(conflictingCS->getName(), aliasName) == 0) + { + // The alias conflicts with the name of the conflicting color space. + + os << "Merged " << source << " named transform '" << name << "'"; + os << " has an alias '"; + os << aliasName << "' that conflicts with color space '"; + os << conflictingCS->getName() << "'."; + + // Remove the alias from the named transform. + eNT->removeAlias(aliasName); + } + else if (hasAlias(conflictingCS, aliasName)) + { + // The alias conflicts with an alias of the conflicting color space. + + os << "Merged " << source << " named transform '" << name << "'"; + os << " has a conflict with alias '"; + os << aliasName << "' in color space '"; + os << conflictingCS->getName() << "'."; + + // Remove the alias from the named transform. + eNT->removeAlias(aliasName); + } + else if (mergeConfig->hasRole(aliasName)) + { + os << "Merged " << source << " named transform '" << name << "'"; + os << " has an alias '"; + os << aliasName << "' that conflicts with a role."; + + // Remove the alias from the named transform. + eNT->removeAlias(aliasName); + } + else // (Should never happen.) + { + std::ostringstream os; + os << "Problem merging named transform: '" << name << "' due to its aliases."; + throw Exception(os.str().c_str()); + } + + // Throw if requested, otherwise log a warning. + notify(os.str(), m_params->isErrorOnConflict()); + } + + // Conflicts of the alias with other named transforms. + + ConstNamedTransformRcPtr conflictingNT = mergeConfig->getNamedTransform(aliasName); + if (conflictingNT) + { + if (Platform::Strcasecmp(conflictingNT->getName(), aliasName) == 0) + { + // The alias conflicts with the name of an existing named transform. + + os << "Merged " << source << " named transform '" << name << "'"; + os << " has an alias '"; + os << aliasName << "' that conflicts with named transform '"; + os << conflictingNT->getName() << "'."; + + if (strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT + || strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_INPUT_ONLY) + { + // Remove that base named transform. + mergeConfig->removeNamedTransform(conflictingNT->getName()); + } + else + { + // Remove the alias from the input named transform. + eNT->removeAlias(aliasName); + } + } + else if (hasAlias(conflictingNT, aliasName)) + { + // The alias conflicts with an alias of the conflicting named transform. + + os << "Merged " << source << " named transform '" << name << "'"; + os << " has a conflict with alias '"; + os << aliasName << "' in named transform '"; + os << conflictingNT->getName() << "'."; + + if (strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT + || strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_INPUT_ONLY) + { + // Remove the alias from that base named transform. + auto eConflictingNT = conflictingNT->createEditableCopy(); + eConflictingNT->removeAlias(aliasName); + + // Replace the colorspace in the copy of the merged config. + mergeConfig->addNamedTransform(eConflictingNT); + } + else + { + // Remove the alias from the input named transform. + eNT->removeAlias(aliasName); + } + } + else // (Should never happen.) + { + std::ostringstream os; + os << "Problem merging named transform: '" << name << "' due to its aliases."; + throw Exception(os.str().c_str()); + } + + notify(os.str(), m_params->isErrorOnConflict()); + } + } + + // Add the named transform. This will throw if a problem is found. + // (But all name conflicts should have been handled already.) + mergeConfig->addNamedTransform(eNT); + + // Keep a record that this input color space was added to allow reordering later. + if (!fromBase) + { + addedInputNamedTransforms.push_back(name); + } + + // TODO: Is it ever possible that a CS added to the list would be removed as another is merged? + + // TODO: When color spaces or aliases are removed above, it's possible it could break + // some other part of the config that referenced them. This would include elements such as: + // environment, views, inactive_colorspaces, ColorSpaceTransforms, or DisplayViewTransforms. +} + +void NamedTransformsMerger::addNamedTransforms() +{ + // Delete all the NamedTransforms, color spaces take precedence, so don't want them + // interfering with merges by causing name conflicts. + + // NB: This is only intended to be called for the prefer_input and prefer_base strategies. + + // Need to add even the base to ensure there are not conflicts with the merged color spaces. + + m_mergedConfig->clearNamedTransforms(); + + // Make a temp copy to merge the input color spaces into (will reorder them later). + ConfigRcPtr mergeConfig = m_mergedConfig->createEditableCopy(); + + std::vector addedInputNamedTransforms; + + // Loop over all active and inactive color spaces of all reference types in the input config. + // Merge them into the temp config (which already contains the base color spaces). + + // Merge from Base config. + + for (int i = 0; i < m_baseConfig->getNumNamedTransforms(NAMEDTRANSFORM_ALL); ++i) + { + const char * name = m_baseConfig->getNamedTransformNameByIndex(NAMEDTRANSFORM_ALL, i); + + ConstNamedTransformRcPtr nt = m_baseConfig->getNamedTransform(name); + if (!nt) + { + continue; + } + + NamedTransformRcPtr eNT = nt->createEditableCopy(); + + const bool fromBase = true; + if (namedTransformMayBeMerged(mergeConfig, eNT, fromBase)) + { + // NB: This may make changes to existing color spaces in mergeConfig + // to resolve name conflicts. + mergeNamedTransform(mergeConfig, eNT, fromBase, addedInputNamedTransforms); + } + } + + // Merge from Input config. + + for (int i = 0; i < m_inputConfig->getNumNamedTransforms(NAMEDTRANSFORM_ALL); ++i) + { + const char * name = m_inputConfig->getNamedTransformNameByIndex(NAMEDTRANSFORM_ALL, i); + + ConstNamedTransformRcPtr nt = m_inputConfig->getNamedTransform(name); + if (!nt) + { + continue; + } + + NamedTransformRcPtr eNT = nt->createEditableCopy(); + + // Doing this against the mergedConfig rather than the base config so that the most + // recent state of any aliases that get added or color spaces that are removed are + // considered by the duplicate consolidation process. + +// FIXME: Handle duplicate named transforms. +// const bool notDuplicate = handleAvoidDuplicatesOption(mergeConfig, eCS); + + const bool fromBase = false; + if (namedTransformMayBeMerged(mergeConfig, eNT, fromBase)) + { + // NB: This may make changes to existing color spaces in mergeConfig + // to resolve name conflicts. + mergeNamedTransform(mergeConfig, eNT, fromBase, addedInputNamedTransforms); + } + } + + m_mergedConfig->clearNamedTransforms(); + + // Add the named transforms to the real merged config. + + if (m_params->isInputFirst()) + { + // Add color spaces from the input config. + for (auto & name : addedInputNamedTransforms) + { + ConstNamedTransformRcPtr inputNT = mergeConfig->getNamedTransform(name.c_str()); + if (inputNT) + { + NamedTransformRcPtr eInputNT = inputNT->createEditableCopy(); + + // Add family prefix. + const bool fromBase = false; + std::string family = eInputNT->getFamily(); + updateFamily(family, fromBase); + eInputNT->setFamily(family.c_str()); + + m_mergedConfig->addNamedTransform(eInputNT); + + mergeConfig->removeNamedTransform(name.c_str()); + } + } + + // Add color spaces from the base config. + for (int i = 0; i < mergeConfig->getNumNamedTransforms(NAMEDTRANSFORM_ALL); ++i) + { + // Note that during the merge process, some of the color spaces from the base config may + // be replaced if their aliases are edited. This should not change their order in the config, + // but may want to account for this, if that ever changes and they get moved to the end. + const char * name = mergeConfig->getNamedTransformNameByIndex(NAMEDTRANSFORM_ALL, i); + + ConstNamedTransformRcPtr baseNT = mergeConfig->getNamedTransform(name); + if (baseNT) + { + auto eBaseNT = baseNT->createEditableCopy(); + + // Add family prefix. + const bool fromBase = true; + std::string family = eBaseNT->getFamily(); + updateFamily(family, fromBase); + eBaseNT->setFamily(family.c_str()); + + m_mergedConfig->addNamedTransform(eBaseNT); + } + } + } + else + { + // The color spaces should already be in the correct order. + // Copy them into the real merged config and add family prefix. + for (int i = 0; i < mergeConfig->getNumNamedTransforms(NAMEDTRANSFORM_ALL); ++i) + { + const char * name = mergeConfig->getNamedTransformNameByIndex(NAMEDTRANSFORM_ALL, i); + + ConstNamedTransformRcPtr nt = mergeConfig->getNamedTransform(name); + if (nt) + { + auto eNT = nt->createEditableCopy(); + bool fromBase = true; + + // Add family prefix. + if (std::find(addedInputNamedTransforms.begin(), addedInputNamedTransforms.end(), name) + != addedInputNamedTransforms.end()) + { + fromBase = false; + } + std::string family = eNT->getFamily(); + updateFamily(family, fromBase); + eNT->setFamily(family.c_str()); + + m_mergedConfig->addNamedTransform(eNT); + } + } + } + + // Ensure the inactive_colorspaces doesn't contain anything that was removed. + // TODO: Should move this to a higher level? + cleanUpInactiveList(m_mergedConfig); + + // TODO: What if the environment contains a color space that was removed? +} + +/* +void NamedTransformsMerger::handleErrorCodes(NamedTransformRcPtr & eNamedTransform) +{ + switch (errorCode) + { + case ADD_NT_ERROR_NONE: + allErrorsResolved = true; + break; + case ADD_NT_ERROR_NULL: + // Should not happen. + break; + case ADD_NT_ERROR_EMPTY: + // Should not happen. + break; + + case ADD_NT_ERROR_AT_LEAST_ONE_TRANSFORM: + skipCurrentNamedTransform = handleAddNtErrorNeedAtLeastOneTransform(eNamedTransform); + break; + + case ADD_NT_ERROR_NAME_IDENTICAL_TO_A_ROLE_NAME: + skipCurrentNamedTransform = handleAddNtErrorNameIdenticalToARoleName(eNamedTransform); + break; + + case ADD_NT_ERROR_NAME_IDENTICAL_TO_COLORSPACE_OR_ALIAS: + skipCurrentNamedTransform = handleAddNtErrorNameIdenticalToColorspaceNameOrAlias(eNamedTransform); + break; + + case ADD_NT_ERROR_NAME_CONTAIN_CTX_VAR_TOKEN: + // Should not happen. It will error out before the merge process. + break; + + case ADD_NT_ERROR_NAME_IDENTICAL_TO_EXISTING_NT_ALIAS: + skipCurrentNamedTransform = handleAddNtErrorNameIdenticalToExistingNtAlias(eNamedTransform); + break; + + case ADD_NT_ERROR_ALIAS_IDENTICAL_TO_A_ROLE_NAME: + skipCurrentNamedTransform = handleAddNtErrorAliasIdenticalToARoleName(eNamedTransform); + break; + + case ADD_NT_ERROR_ALIAS_IDENTICAL_TO_COLORSPACE_OR_ALIAS: + skipCurrentNamedTransform = handleAddNtErrorAliasIdenticalToColorspaceNameOrAlias(eNamedTransform); + break; + + case ADD_NT_ERROR_ALIAS_CONTAIN_CTX_VAR_TOKEN: + // Should not happen. It will error out before the merge process. + break; + + case ADD_NT_ERROR_ALIAS_IDENTICAL_TO_EXISTING_NT_ALIAS: + skipCurrentNamedTransform = handleAddNtErrorAliasIdenticalToExistingNtAlias(eNamedTransform); + break; + + default: + break; + } +} +*/ + +void NamedTransformsMerger::handlePreferInput() +{ + addNamedTransforms(); +} + +void NamedTransformsMerger::handlePreferBase() +{ + addNamedTransforms(); +} + +void NamedTransformsMerger::handleInputOnly() +{ + m_mergedConfig->clearNamedTransforms(); + + // Add the NamedTransforms from the input config. + for(int i = 0; i < m_inputConfig->getNumNamedTransforms(NAMEDTRANSFORM_ALL); ++i) + { + const char * name = m_inputConfig->getNamedTransformNameByIndex(NAMEDTRANSFORM_ALL, i); + + ConstNamedTransformRcPtr nt = m_inputConfig->getNamedTransform(name); + if (!nt) + { + continue; + } + + NamedTransformRcPtr eNT = nt->createEditableCopy(); + + const bool fromBase = false; + std::vector addedInputNamedTransforms; + if (namedTransformMayBeMerged(m_mergedConfig, eNT, fromBase)) + { + // NB: This may make changes to existing color spaces in mergeConfig + // to resolve name conflicts. + mergeNamedTransform(m_mergedConfig, eNT, fromBase, addedInputNamedTransforms); + } + } + + // Ensure the inactive_colorspaces doesn't contain anything that was removed. + cleanUpInactiveList(m_mergedConfig); +} + +void NamedTransformsMerger::handleBaseOnly() +{ + m_mergedConfig->clearNamedTransforms(); + + // Add the NamedTransforms from the base config. + for (int i = 0; i < m_baseConfig->getNumNamedTransforms(NAMEDTRANSFORM_ALL); ++i) + { + const char * name = m_baseConfig->getNamedTransformNameByIndex(NAMEDTRANSFORM_ALL, i); + + ConstNamedTransformRcPtr nt = m_baseConfig->getNamedTransform(name); + if (!nt) + { + continue; + } + + NamedTransformRcPtr eNT = nt->createEditableCopy(); + + const bool fromBase = true; + std::vector addedInputNamedTransforms; + if (namedTransformMayBeMerged(m_mergedConfig, eNT, fromBase)) + { + // NB: This may make changes to existing color spaces in mergeConfig + // to resolve name conflicts. + mergeNamedTransform(m_mergedConfig, eNT, fromBase, addedInputNamedTransforms); + } + } + + // Ensure the inactive_colorspaces doesn't contain anything that was removed. + cleanUpInactiveList(m_mergedConfig); +} + +void NamedTransformsMerger::handleRemove() +{ + m_mergedConfig->clearNamedTransforms(); + // Add the NamedTransforms from the base config if they do not exist in the INPUT config. + for(int i = 0; i < m_baseConfig->getNumNamedTransforms(NAMEDTRANSFORM_ALL); ++i) + { + const char * name = m_baseConfig->getNamedTransformNameByIndex(NAMEDTRANSFORM_ALL, i); + if (m_inputConfig->getNamedTransform(name) == nullptr) + { + ConstNamedTransformRcPtr nt = m_baseConfig->getNamedTransform(name); + if (!nt) + { + continue; + } + + NamedTransformRcPtr eNT = nt->createEditableCopy(); + + const bool fromBase = true; + std::vector addedInputNamedTransforms; + if (namedTransformMayBeMerged(m_mergedConfig, eNT, fromBase)) + { + // NB: This may make changes to existing color spaces in mergeConfig + // to resolve name conflicts. + mergeNamedTransform(m_mergedConfig, eNT, fromBase, addedInputNamedTransforms); + } + } + } + + // Ensure the inactive_colorspaces doesn't contain anything that was removed. + cleanUpInactiveList(m_mergedConfig); +} + +///////////////////////////////// NamedTransformsMerger end /////////////////////////////////////// + +} // namespace OCIO_NAMESPACE \ No newline at end of file diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.h b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.h new file mode 100644 index 0000000000..ab40566785 --- /dev/null +++ b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.h @@ -0,0 +1,443 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + + +#ifndef INCLUDED_OCIO_MERGE_CONFIG_SECTION_MERGER_H +#define INCLUDED_OCIO_MERGE_CONFIG_SECTION_MERGER_H + +#include +#include +#include + +#include + +#include "utils/StringUtils.h" +#include "Logging.h" + + +namespace OCIO_NAMESPACE +{ + +struct MergeHandlerOptions +{ + const ConstConfigRcPtr & baseConfig; + const ConstConfigRcPtr & inputConfig; + const ConfigMergingParametersRcPtr & params; + ConfigRcPtr & mergedConfig; +}; + +class SectionMerger +{ +public: + + enum MergerFlag + { + MERGERSTATE_NOFLAG, + MERGERSTATE_ADD_INITIAL_CONFIG, + }; + + SectionMerger(MergeHandlerOptions options) + : m_baseConfig(options.baseConfig), m_inputConfig(options.inputConfig), + m_mergedConfig(options.mergedConfig), m_params(options.params) + { + m_strategy = options.params->getDefaultStrategy(); + m_params->setDefaultStrategy(options.params->getDefaultStrategy()); + } + + void merge() + { + switch (m_strategy) + { + case ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT: + handlePreferInput(); + break; + case ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_BASE: + handlePreferBase(); + break; + case ConfigMergingParameters::MergeStrategies::STRATEGY_INPUT_ONLY: + handleInputOnly(); + break; + case ConfigMergingParameters::MergeStrategies::STRATEGY_BASE_ONLY: + handleBaseOnly(); + break; + case ConfigMergingParameters::MergeStrategies::STRATEGY_REMOVE: + handleRemove(); + break; + case ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET: + // nothing to do. + break; + default: + break; + } + } + + void notify(std::string s, bool mustThrow) const; + +private: + virtual void handlePreferInput() + { + LogWarning(getName() + std::string(" section does not supported strategy 'PreferInput'")); + } + + virtual void handlePreferBase() + { + LogWarning(getName() + std::string(" section does not supported strategy 'PreferBase'")); + } + + virtual void handleInputOnly() + { + LogWarning(getName() + std::string(" section does not supported strategy 'InputOnly'")); + } + + virtual void handleBaseOnly() + { + LogWarning(getName() + std::string(" section does not supported strategy 'BaseOnly'")); + } + + virtual void handleRemove() + { + LogWarning(getName() + std::string(" section does not supported strategy 'Remove'")); + } + +protected: + const ConstConfigRcPtr & m_baseConfig; + const ConstConfigRcPtr & m_inputConfig; + ConfigRcPtr & m_mergedConfig; + + const ConfigMergingParametersRcPtr & m_params; + ConfigMergingParameters::MergeStrategies m_strategy; + + void mergeStringVecWithoutDuplicate(StringUtils::StringVec & input, + StringUtils::StringVec & mergedVec) const; + void inputFirstMergeStringVec(StringUtils::StringVec & input, + StringUtils::StringVec & base, + StringUtils::StringVec & mergedVec) const; + +private: + virtual const std::string getName() const = 0; +}; + +class GeneralMerger : public SectionMerger +{ +public: + GeneralMerger(MergeHandlerOptions options) : SectionMerger(options) + { + // This merger always use the default strategy as this is for properties + // that are not linked to a specific section. + m_strategy = options.params->getDefaultStrategy(); + } + +private: + const std::string getName() const { return "Miscellaneous"; } + + void handlePreferInput(); + void handlePreferBase(); + void handleInputOnly(); + void handleBaseOnly(); +}; + +class RolesMerger : public SectionMerger +{ +public: + RolesMerger(MergeHandlerOptions options) : SectionMerger(options) + { + ConfigMergingParameters::MergeStrategies strat = options.params->getRoles(); + if (strat != ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET) + { + m_strategy = strat; + } + else + { + m_strategy = options.params->getDefaultStrategy(); + } + } + +private: + const std::string getName() const { return "Roles"; } + + void mergeInputRoles(); + void handlePreferInput(); + void handlePreferBase(); + void handleInputOnly(); + void handleBaseOnly(); + void handleRemove(); +}; + +class FileRulesMerger : public SectionMerger +{ +public: + FileRulesMerger(MergeHandlerOptions options) : SectionMerger(options) + { + ConfigMergingParameters::MergeStrategies strat = options.params->getFileRules(); + if (strat != ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET) + { + m_strategy = strat; + } + else + { + m_strategy = options.params->getDefaultStrategy(); + } + } + +private: + const std::string getName() const { return "FileRules"; } + + void addRulesIfNotPresent(const ConstFileRulesRcPtr & input, + FileRulesRcPtr & merged) const; + void addRulesAndOverwrite(const ConstFileRulesRcPtr & input, FileRulesRcPtr & merged) const; + + void handlePreferInput(); + void handlePreferBase(); + void handleInputOnly(); + void handleBaseOnly(); + void handleRemove(); +}; + +class DisplayViewMerger : public SectionMerger +{ +public: + DisplayViewMerger(MergeHandlerOptions options) : SectionMerger(options) + { + ConfigMergingParameters::MergeStrategies strat = options.params->getDisplayViews(); + if (strat != ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET) + { + m_strategy = strat; + } + else + { + m_strategy = options.params->getDefaultStrategy(); + } + } + +private: + const std::string getName() const { return "Display/Views"; } + + void addUniqueDisplays(const ConstConfigRcPtr & cfg); + void processDisplays(const ConstConfigRcPtr & first, + const ConstConfigRcPtr & second, + bool preferSecond); + + void addUniqueVirtualViews(const ConstConfigRcPtr & cfg); + void processVirtualDisplay(const ConstConfigRcPtr & first, + const ConstConfigRcPtr & second, + bool preferSecond); + + void addUniqueSharedViews(const ConstConfigRcPtr & cfg); + void processSharedViews(const ConstConfigRcPtr & first, + const ConstConfigRcPtr & second, + bool preferSecond); + + void processActiveLists(); + + void addUniqueViewTransforms(const ConstConfigRcPtr & cfg); + void processViewTransforms(const ConstConfigRcPtr & first, + const ConstConfigRcPtr & second, + bool preferSecond); + + void processViewingRules(const ConstConfigRcPtr & first, + const ConstConfigRcPtr & second, + bool preferSecond) const; + + void handlePreferInput(); + void handlePreferBase(); + void handleInputOnly(); + void handleBaseOnly(); + void handleRemove(); +}; + +class LooksMerger : public SectionMerger +{ +public: + LooksMerger(MergeHandlerOptions options) : SectionMerger(options) + { + ConfigMergingParameters::MergeStrategies strat = options.params->getLooks(); + if (strat != ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET) + { + m_strategy = strat; + } + else + { + m_strategy = options.params->getDefaultStrategy(); + } + } + +private: + const std::string getName() const { return "Looks"; } + + void handlePreferInput(); + void handlePreferBase(); + void handleInputOnly(); + void handleBaseOnly(); + void handleRemove(); +}; + +class ColorspacesMerger : public SectionMerger +{ +public: + ColorspacesMerger(MergeHandlerOptions options) : SectionMerger(options) + { + ConfigMergingParameters::MergeStrategies strat = options.params->getColorspaces(); + if (strat != ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET) + { + m_strategy = strat; + } + else + { + m_strategy = options.params->getDefaultStrategy(); + } + + m_state = MERGERSTATE_NOFLAG; + } + + struct ColorspaceNameConflict + { + bool csInColorspaces = false; + bool csInNameTransforms = false; + bool csInAliases = false; + + // Alias to alias conflict + bool aliasInAliaes = false; + }; + +private: + // Attributes + MergerFlag m_state; + + std::vector m_colorspaceMarkedToBeDeleted; + std::vector m_colorspaceReplacingMarkedCs; + + // Methods + const std::string getName() const { return "Colorspaces"; } + + void processSearchPaths() const; + + void iterateOverColorSpaces(ConstConfigRcPtr cfg, + std::function cb) const; + + void detectSpecificIndirectConflicts(const char * name, ColorspaceNameConflict & nc) const; + + void nameConflictWithColorspaceName(const ConstColorSpaceRcPtr & srcCs, + ConfigRcPtr & dstCfg) const; + + void nameConflictWithNameTransformsName(const ConstColorSpaceRcPtr & srcCs, + ConfigRcPtr & dstCfg) const; + + void nameConflictWithColorspaceAliases(const ConstColorSpaceRcPtr & srcCs, + ConfigRcPtr & dstCfg) const; + void aliasConflictWithColorspaceAliases(const ConstColorSpaceRcPtr & srcCs, + ConfigRcPtr & dstCfg) const; + + void resolveConflict(const ConstConfigRcPtr & source, + ConfigRcPtr & destination) const; + + void resolveConflict(ConfigRcPtr & first, + ConfigRcPtr & second) const; + + + void attemptToAddAlias(const ConstConfigRcPtr & mergeConfig, + ColorSpaceRcPtr & dupeCS, + const ConstColorSpaceRcPtr & inputCS, + const char * aliasName); + +// void updateFamily(ColorSpaceRcPtr & incomingCs, bool fromBase) const; + void updateFamily(std::string & family, bool fromBase) const; + bool colorSpaceMayBeMerged(const ConstConfigRcPtr & mergeConfig, + const ConstColorSpaceRcPtr & inputCS) const; + void mergeColorSpace(ConfigRcPtr & mergeConfig, + ColorSpaceRcPtr & eInputCS, + std::vector & addedInputColorSpaces); + void initializeRefSpaceConverters(ConstTransformRcPtr & inputToBaseGtScene, + ConstTransformRcPtr & inputToBaseGtDisplay); + void addColorSpaces(); + + + + bool handleAddCsErrorNameIdenticalToARoleName(ColorSpaceRcPtr & incomingCs) const; + bool handleAddCsErrorNameIdenticalToNTNameOrAlias(ColorSpaceRcPtr & incomingCs) const; + bool handleAddCsErrorNameContainCtxVarToken(ColorSpaceRcPtr & incomingCs) const; + bool handleAddCsErrorNameIdenticalToExistingColorspaceAlias(ColorSpaceRcPtr & incomingCs) const;; + bool handleAddCsErrorAliasIdenticalToARoleName(ColorSpaceRcPtr & incomingCs) const; + bool handleAddCsErrorAliasIdenticalToNTNameOrAlias(ColorSpaceRcPtr & incomingCs) const; + bool handleAddCsErrorAliasContainCtxVarToken(ColorSpaceRcPtr & incomingCs) const; + bool handleAddCsErrorAliasIdenticalToExistingColorspaceName(ColorSpaceRcPtr & incomingCs) const; + bool handleAddCsErrorAliasIdenticalToExistingColorspaceAlias(ColorSpaceRcPtr & incomingCs) const; + + void handleErrorCodeWhenAddingInputFirst(ColorSpaceRcPtr & eColorspace); + void handleErrorCodes(ColorSpaceRcPtr & eColorspace); + + bool handleAvoidDuplicatesOption(ConfigRcPtr & eBase, ColorSpaceRcPtr & eColorspace); + void handleAssumeCommonReferenceOption(ColorSpaceRcPtr & eColorspace); + + void handleMarkedToBeDeletedColorspaces(); + bool isColorspaceMarked(const ConstColorSpaceRcPtr & cs); + + void addFamilyPrefix(ColorSpaceRcPtr & incomingCs, std::string prefix) const; + void replaceFamilySeparatorInFamily(ColorSpaceRcPtr & incomingCs); + + void handlePreferInput(); + void handlePreferBase(); + void handleInputOnly(); + void handleBaseOnly(); + void handleRemove(); +}; + +class NamedTransformsMerger : public SectionMerger +{ +public: + NamedTransformsMerger(MergeHandlerOptions options) : SectionMerger(options) + { + ConfigMergingParameters::MergeStrategies strat = options.params->getNamedTransforms(); + if (strat != ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET) + { + m_strategy = strat; + } + else + { + m_strategy = options.params->getDefaultStrategy(); + } + + m_state = MERGERSTATE_NOFLAG; + } + +private: + // Attributes + MergerFlag m_state; + + // Methods + const std::string getName() const { return "Named Transforms"; } + + void updateFamily(std::string & family, bool fromBase) const; + bool namedTransformMayBeMerged(const ConstConfigRcPtr & mergeConfig, + const ConstNamedTransformRcPtr & nt, + bool fromBase) const; + void mergeNamedTransform(ConfigRcPtr & mergeConfig, + NamedTransformRcPtr & eNT, + bool fromBase, + std::vector & addedInputNamedTransforms); + void addNamedTransforms(); + + void iterateOverColorSpaces(ConstConfigRcPtr cfg, std::function cb) const; + + bool handleAddNtErrorNeedAtLeastOneTransform(NamedTransformRcPtr & incomingNt) const; + bool handleAddNtErrorNameIdenticalToARoleName(NamedTransformRcPtr & incomingNt) const; + bool handleAddNtErrorNameIdenticalToColorspaceNameOrAlias(NamedTransformRcPtr & incomingNt) const; + bool handleAddNtErrorNameContainCtxVarToken(NamedTransformRcPtr & incomingNt) const; + bool handleAddNtErrorNameIdenticalToExistingNtAlias(NamedTransformRcPtr & incomingNt) const; + bool handleAddNtErrorAliasIdenticalToARoleName(NamedTransformRcPtr & incomingNt) const; + bool handleAddNtErrorAliasIdenticalToColorspaceNameOrAlias(NamedTransformRcPtr & incomingNt) const; + bool handleAddNtErrorAliasContainCtxVarToken(NamedTransformRcPtr & incomingNt) const; + bool handleAddNtErrorAliasIdenticalToExistingNtAlias(NamedTransformRcPtr & incomingNt) const; + + void handleErrorCodeWhenAddingInputFirst(NamedTransformRcPtr & eNamedTransform); + void handleErrorCodes(NamedTransformRcPtr & eColorspace); + + void handlePreferInput(); + void handlePreferBase(); + void handleInputOnly(); + void handleBaseOnly(); + void handleRemove(); +}; + +} // namespace OCIO_NAMESPACE + +#endif // INCLUDED_OCIO_MERGE_CONFIG_SECTION_MERGER_H diff --git a/src/apps/CMakeLists.txt b/src/apps/CMakeLists.txt index decb56d50a..bc52d695ae 100755 --- a/src/apps/CMakeLists.txt +++ b/src/apps/CMakeLists.txt @@ -9,6 +9,7 @@ if(OCIO_BUILD_APPS) add_subdirectory(ociocpuinfo) add_subdirectory(ociomakeclf) add_subdirectory(ocioperf) + add_subdirectory(ociomergeconfigs) add_subdirectory(ociowrite) if(TARGET OpenColorIO::ImageIOBackend) diff --git a/src/apps/ociomergeconfigs/CMakeLists.txt b/src/apps/ociomergeconfigs/CMakeLists.txt new file mode 100644 index 0000000000..9d88aa4e75 --- /dev/null +++ b/src/apps/ociomergeconfigs/CMakeLists.txt @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright Contributors to the OpenColorIO Project. + +set(SOURCES + main.cpp +) + +add_executable(ociomergeconfigs ${SOURCES}) + +set_target_properties(ociomergeconfigs PROPERTIES + COMPILE_OPTIONS "${PLATFORM_COMPILE_OPTIONS}" + LINK_OPTIONS "${PLATFORM_LINK_OPTIONS}" +) + +target_include_directories(ociomergeconfigs + PUBLIC + "$" +) + +target_link_libraries(ociomergeconfigs + PRIVATE + apputils + pystring::pystring + OpenColorIO + MINIZIP::minizip-ng +) + +install(TARGETS ociomergeconfigs + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/src/apps/ociomergeconfigs/main.cpp b/src/apps/ociomergeconfigs/main.cpp new file mode 100644 index 0000000000..6240b97eb9 --- /dev/null +++ b/src/apps/ociomergeconfigs/main.cpp @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + +#include +#include +#include + +#include + +#include +#include "utils/StringUtils.h" + +namespace OCIO = OCIO_NAMESPACE; + +#include "apputils/argparse.h" +#include "apputils/logGuard.h" + +#if !defined(_WIN32) +#include +#include +#else +#include +#define MAXPATHLEN 4096 +#endif + +std::string GetCwd() +{ +#ifdef _WIN32 + char path[MAXPATHLEN]; + _getcwd(path, MAXPATHLEN); + return path; +#else + std::vector current_dir; +#ifdef PATH_MAX + current_dir.resize(PATH_MAX); +#else + current_dir.resize(1024); +#endif + while (::getcwd(¤t_dir[0], current_dir.size()) == NULL && errno == ERANGE) { + current_dir.resize(current_dir.size() + 1024); + } + + return std::string(¤t_dir[0]); +#endif +} + +std::string AbsPath(const std::string & path) +{ + std::string p = path; + if(!pystring::os::path::isabs(p)) p = pystring::os::path::join(GetCwd(), p); + return pystring::os::path::normpath(p); +} + +// Array of non OpenColorIO arguments. +static std::vector args; + +// Fill 'args' array with OpenColorIO arguments. +static int +parse_end_args(int argc, const char *argv[]) +{ + while (argc>0) + { + args.push_back(argv[0]); + argc--; + argv++; + } + + return 0; +} + +int main(int argc, const char **argv) +{ + ArgParse ap; + std::string errorMsg = ""; + + // Options + std::string baseConfigName; + std::string inputConfigName; + std::string mergeParameters; + std::string outputFile; + bool displayConfig = false; + bool displayAllConfig = false; + bool displayParams = false; + bool validate = false; + bool help = false; + + OCIO::ConstConfigRcPtr baseCfg; + OCIO::ConstConfigRcPtr inputCfg; + OCIO::ConstConfigMergingParametersRcPtr params; + OCIO::ConstConfigMergerRcPtr merger; + + ap.options("ociomergeconfigs -- Merge two configs\n\n" + "Usage:\n" + " ociomergeconfigs [options] -b config.ocio -i extra.ocio \n\n", + "%*", parse_end_args, "", + "", "Options:", + "--validate", &validate, "Validate the final merged config", + "--merge %s", &mergeParameters, "Path to merge parameters file (.ociom)", + "--out %s", &outputFile, "Filepath to save the merged config", + "--show-last", &displayConfig, "Display the last merged config to screen", + "--show-all", &displayAllConfig, "Display ALL merged config to screen", + "--show-params", &displayParams, "Display merger options (OCIOM)", + "--help", &help, "Display the help and exit", + "-h", &help, "Display the help and exit", + NULL + ); + + if (ap.parse(argc, argv) < 0) + { + std::cerr << ap.geterror() << std::endl; + exit(1); + } + + if (help) + { + ap.usage(); + return 0; + } + + // Load the options from the ociom file. + // Otherwise, return object with default behaviors. + try + { + merger = OCIO::ConfigMerger::CreateFromFile(mergeParameters.c_str()); + } + catch (OCIO::Exception & e) + { + std::cout << e.what() << std::endl; + } + + try + { + OCIO::ConstConfigMergerRcPtr newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); + if (validate) + { + try + { + LogGuard logGuard; + newMerger->getMergedConfig()->validate(); + } + catch(OCIO::Exception & exception) + { + std::cout << exception.what() << std::endl; + exit(1); + } + } + + if (displayParams) + { + std::cout << "********************" << std::endl; + std::cout << "Merger options" << std::endl; + std::cout << "********************" << std::endl; + std::ostringstream os; + newMerger->serialize(os); + std::cout << os.str() << std::endl; + std::cout << std::endl; + } + + // "Show-all" option take priority over the "show" option. + if (displayAllConfig) + { + for (int i = 0; i < merger->getNumOfConfigMergingParameters(); i++) + { + std::cout << "*********************" << std::endl; + std::cout << "Merged Config " << i << std::endl; + std::cout << "*********************" << std::endl; + std::ostringstream os; + newMerger->getMergedConfig(i)->serialize(os); + std::cout << os.str() << std::endl; + } + } + + if (displayConfig && !displayAllConfig) + { + std::cout << "********************" << std::endl; + std::cout << "Last Merged Config" << std::endl; + std::cout << "********************" << std::endl; + std::ostringstream os; + newMerger->getMergedConfig()->serialize(os); + std::cout << os.str() << std::endl; + } + + if (!outputFile.empty()) + { + std::ofstream mergedCfg; + mergedCfg.open(AbsPath(outputFile)); + + std::ostringstream os; + newMerger->getMergedConfig()->serialize(mergedCfg); + mergedCfg.close(); + } + } + catch(const std::exception& e) + { + std::cerr << e.what(); + exit(1); + } +} diff --git a/tests/cpu/CMakeLists.txt b/tests/cpu/CMakeLists.txt index 66c32cb8a7..321d73dcd3 100755 --- a/tests/cpu/CMakeLists.txt +++ b/tests/cpu/CMakeLists.txt @@ -123,6 +123,8 @@ endfunction(add_ocio_test) # but for now, we will maintain the status quo and copy all from the # OpenColorIO target set(SOURCES + apphelpers/mergeconfigs/OCIOMYaml.cpp + apphelpers/mergeconfigs/SectionMerger.cpp builtinconfigs/CGConfig.cpp builtinconfigs/StudioConfig.cpp ConfigUtils.cpp @@ -187,6 +189,7 @@ set(TESTS apphelpers/ColorSpaceHelpers_tests.cpp apphelpers/DisplayViewHelpers_tests.cpp apphelpers/LegacyViewingPipeline_tests.cpp + apphelpers/MergeConfigsHelpers_tests.cpp apphelpers/MixingHelpers_tests.cpp Baker_tests.cpp BitDepthUtils_tests.cpp @@ -195,6 +198,7 @@ set(TESTS ColorSpace_tests.cpp ColorSpaceSet_tests.cpp Config_tests.cpp + ConfigUtils_tests.cpp Context_tests.cpp ContextVariableUtils_tests.cpp CPUProcessor_tests.cpp diff --git a/tests/cpu/ConfigUtils_tests.cpp b/tests/cpu/ConfigUtils_tests.cpp new file mode 100644 index 0000000000..fc04a56c42 --- /dev/null +++ b/tests/cpu/ConfigUtils_tests.cpp @@ -0,0 +1,584 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + +#include + +#include "UnitTestUtils.h" + +#include "ConfigUtils.h" +#include "testutils/UnitTest.h" +#include "UnitTestLogUtils.h" + +namespace OCIO = OCIO_NAMESPACE; + +OCIO_ADD_TEST(MergeConfigs, config_utils_update_reference) +{ + std::istringstream bss; + std::istringstream iss; + + constexpr const char * BASE { +R"(ocio_profile_version: 2.1 +name: base +environment: + TEXTURE_SPACE: sRGB - Texture + SHOT: 001a + +search_path: + - luts + - . + +roles: + aces_interchange: ap0 + cie_xyz_d65_interchange: CIE-XYZ-D65 + +file_rules: + - ! {name: Default, colorspace: ACEScg} + +#inactive_colorspaces: [sRGB - Texture, ACEScg] + +display_colorspaces: # reference space = cie xyz d65 + - ! + name: sRGB - Display + aliases: [srgb_display] + family: Display-Basic + description: from base + from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_sRGB} + + - ! + name: CIE-XYZ-D65 + aliases: [cie_xyz_d65] + description: The \"CIE XYZ (D65)\" display connection colorspace. + isdata: false + +colorspaces: # reference space = aces2065-1 + - ! + name: ACEScg + aliases: [aces] + family: ACES-Linear + description: from base + to_scene_reference: ! {style: ACEScg_to_ACES2065-1} + + - ! + name: ap0 + family: ACES-Linear + description: from base + + - ! + name: sRGB - Texture + family: Texture + aliases: [srgb, srgb_tx] + description: from base + from_scene_reference: ! + children: + - ! {matrix: [2.52168618674388, -1.13413098823972, -0.387555198504164, 0, -0.276479914229922, 1.37271908766826, -0.096239173438334, 0, -0.0153780649660342, -0.152975335867399, 1.16835340083343, 0, 0, 0, 0, 1]} + - ! {gamma: 2.4, offset: 0.055, direction: inverse} + + - ! + name: look + aliases: + family: + description: from base + from_scene_reference: ! {src: ACEScg, dst: sRGB - Texture} +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2.1 +name: input +search_path: lut_dir +inactive_colorspaces: [ACES2065-1] + +roles: + aces_interchange: ACES2065-1 + cie_xyz_d65_interchange: CIE-XYZ-D65 + +file_rules: + - ! {name: Default, colorspace: sRGB} + +displays: + sRGB - Display: + - ! {name: Raw, colorspace: raw} + - ! {name: ACES 1.0 - SDR Video, view_transform: ACES 1.0 - SDR Video, display_colorspace: sRGB - Display} + +view_transforms: + - ! + name: ACES 1.0 - SDR Video + from_scene_reference: ! + children: + # Matrix from rec.709 to aces2065-1 + - ! {matrix: [ 0.439632981919, 0.382988698152, 0.177378319929, 0, 0.089776442959, 0.813439428749, 0.096784128292, 0, 0.017541170383, 0.111546553302, 0.870912276314, 0, 0, 0, 0, 1 ]} + # Built-in transform from aces2065-1 to cie-xyz + - ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO_1.0} + # Matrix from cie-xyz to linear rec.709 + - ! {matrix: [ 3.240969941905, -1.537383177570, -0.498610760293, 0, -0.969243636281, 1.875967501508, 0.041555057407, 0, 0.055630079697, -0.203976958889, 1.056971514243, 0, 0, 0, 0, 1 ]} + +display_colorspaces: # reference space = linear rec 709 + - ! + name: sRGB - Display + aliases: [srgb_display] + family: Display~Standard + description: from input + from_display_reference: ! {gamma: 2.4, offset: 0.055, direction: inverse} + + - ! + name: CIE-XYZ-D65 + aliases: [cie_xyz_d65] + description: The \"CIE XYZ (D65)\" display connection colorspace. + isdata: false + from_display_reference: ! {matrix: [ 0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.950532152250, 0, 0, 0, 0, 1 ]} + +colorspaces: # reference space = linear rec 709 + - ! + name: ACES2065-1 + aliases: [aces] + family: ACES~Linear + description: from input + to_scene_reference: ! {matrix: [ 2.521686186744, -1.134130988240, -0.387555198504, 0, -0.276479914230, 1.372719087668, -0.096239173438, 0, -0.015378064966, -0.152975335867, 1.168353400833, 0, 0, 0, 0, 1 ]} + + - ! + name: sRGB +# aliases: [srgb_display] + family: Texture~ + description: from input + to_scene_reference: ! {gamma: 2.4, offset: 0.055} + + - ! + name: rec709 + description: from input + + - ! + name: raw + description: from base + isdata: true +)" }; + + bss.str(BASE); + iss.str(INPUT); + + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + + // scene-referred reference space + + // Get the transform to convert the scene-referred reference space. + auto inputToBaseGtScene = OCIO::ConfigUtils::getRefSpaceConverter(inputConfig, + baseConfig, + OCIO::REFERENCE_SPACE_SCENE); + { + // Convert each one of the scene-referred color spaces and check the result. + std::vector colorspaces; + for (int i = 0; i < inputConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_SCENE, OCIO::COLORSPACE_ALL); ++i) + { + const char * name = inputConfig->getColorSpaceNameByIndex(OCIO::SEARCH_REFERENCE_SPACE_SCENE, + OCIO::COLORSPACE_ALL, + i); + OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace(name); + // scene-referred colorspace + colorspaces.push_back(cs); + } + OCIO_CHECK_EQUAL(colorspaces.size(), 4); + + // ACES2065-1 no longer needs transforms, it is now the reference space. + // But transforms are not simplified, for clarity in what was done. + { + OCIO::ColorSpaceRcPtr cs = colorspaces.at(0)->createEditableCopy(); + OCIO::ConfigUtils::updateReferenceColorspace(cs, inputToBaseGtScene); + OCIO::ConstTransformRcPtr t = cs->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_GROUP); + + auto gtx = OCIO::DynamicPtrCast(t); + OCIO_REQUIRE_ASSERT(gtx); + OCIO_CHECK_EQUAL(gtx->getNumTransforms(), 2); + + { + std::vector m44(16, 0.0); + auto mtx0 = OCIO::DynamicPtrCast(gtx->getTransform(0)); + OCIO_REQUIRE_ASSERT(mtx0); + mtx0->getMatrix(m44.data()); + OCIO_CHECK_CLOSE(m44[0], 2.521686186744, 1e-5f); + } + + { + std::vector m44(16, 0.0); + auto mtx1 = OCIO::DynamicPtrCast(gtx->getTransform(1)); + OCIO_REQUIRE_ASSERT(mtx1); + mtx1->getMatrix(m44.data()); + OCIO_CHECK_CLOSE(m44[0], 0.4396329819194919, 1e-5f); + } + + OCIO_REQUIRE_ASSERT(!cs->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); + } + + // sRGB now needs a Rec.709 to ACES2065-1 matrix after the exponent. + { + OCIO::ColorSpaceRcPtr cs = colorspaces.at(1)->createEditableCopy(); + OCIO::ConfigUtils::updateReferenceColorspace(cs, inputToBaseGtScene); + OCIO::ConstTransformRcPtr t = cs->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_GROUP); + + auto gtx = OCIO::DynamicPtrCast(t); + OCIO_REQUIRE_ASSERT(gtx); + OCIO_CHECK_EQUAL(gtx->getNumTransforms(), 2); + + std::vector m44(16, 0.0); + auto mtx0 = OCIO::DynamicPtrCast(gtx->getTransform(1)); + OCIO_REQUIRE_ASSERT(mtx0); + mtx0->getMatrix(m44.data()); + OCIO_CHECK_CLOSE(m44[0], 0.4396329819194919, 1e-5f); + OCIO_CHECK_CLOSE(m44[1], 0.3829886981515535, 1e-5f); + + OCIO_REQUIRE_ASSERT(!cs->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); + } + + // rec709 had no transforms but now needs the same matrix. + { + OCIO::ColorSpaceRcPtr cs = colorspaces.at(2)->createEditableCopy(); + OCIO::ConfigUtils::updateReferenceColorspace(cs, inputToBaseGtScene); + OCIO::ConstTransformRcPtr t = cs->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); + OCIO_REQUIRE_ASSERT(t); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_GROUP); + auto gtx = OCIO::DynamicPtrCast(t); + OCIO_REQUIRE_ASSERT(gtx); + OCIO_CHECK_EQUAL(gtx->getNumTransforms(), 1); + + std::vector m44(16, 0.0); + auto mtx0 = OCIO::DynamicPtrCast(gtx->getTransform(0)); + OCIO_REQUIRE_ASSERT(mtx0); + mtx0->getMatrix(m44.data()); + OCIO_CHECK_CLOSE(m44[0], 0.4396329819194919, 1e-5f); + OCIO_CHECK_CLOSE(m44[1], 0.3829886981515535, 1e-5f); + + OCIO_REQUIRE_ASSERT(!cs->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); + } + + // raw had no transforms and none are added since isdata is true. + { + OCIO::ColorSpaceRcPtr cs = colorspaces.at(3)->createEditableCopy(); + OCIO::ConfigUtils::updateReferenceColorspace(cs, inputToBaseGtScene); + OCIO_CHECK_EQUAL(cs->isData(), true); + OCIO_REQUIRE_ASSERT(!cs->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE)) + OCIO_REQUIRE_ASSERT(!cs->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)) + } + } + + + // display-referred reference space + + // Get the transform to convert the display-referred reference space. + auto inputToBaseGtDisplay = OCIO::ConfigUtils::getRefSpaceConverter(inputConfig, + baseConfig, + OCIO::REFERENCE_SPACE_DISPLAY); + { + // Convert each one of the display-referred color spaces and check the result. + std::vector colorspaces; + for (int i = 0; i < inputConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, OCIO::COLORSPACE_ALL); ++i) + { + const char * name = inputConfig->getColorSpaceNameByIndex(OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, + OCIO::COLORSPACE_ALL, + i); + OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace(name); + // display-referred colorspace + colorspaces.push_back(cs); + } + OCIO_CHECK_EQUAL(colorspaces.size(), 2); + + // sRGB - Display needs a CIE-XYZ to Rec.709 matrix before the exponent. + { + OCIO::ColorSpaceRcPtr cs = colorspaces.at(0)->createEditableCopy(); + OCIO::ConfigUtils::updateReferenceColorspace(cs, inputToBaseGtDisplay); + OCIO_REQUIRE_ASSERT(!cs->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE)); + + OCIO::ConstTransformRcPtr t = cs->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_GROUP); + auto gtx = OCIO::DynamicPtrCast(t); + OCIO_REQUIRE_ASSERT(gtx); + OCIO_CHECK_EQUAL(gtx->getNumTransforms(), 2); + + OCIO_CHECK_EQUAL(gtx->getTransform(0)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); + std::vector m44(16, 0.0); + auto mtx0 = OCIO::DynamicPtrCast(gtx->getTransform(0)); + OCIO_REQUIRE_ASSERT(mtx0); + mtx0->getMatrix(m44.data()); + //OCIO_CHECK_CLOSE(m44[0], 3.240969941907037, 1e-5f); + //OCIO_CHECK_CLOSE(m44[1], -1.537383177571058, 1e-5f); + + OCIO_CHECK_EQUAL(gtx->getTransform(1)->getTransformType(), OCIO::TRANSFORM_TYPE_EXPONENT_WITH_LINEAR); + } + + // CIE-XYZ-D65 had a matrix but no longer needs transforms, it's now the reference space. + { + OCIO::ColorSpaceRcPtr cs = colorspaces.at(1)->createEditableCopy(); + OCIO::ConfigUtils::updateReferenceColorspace(cs, inputToBaseGtDisplay); + OCIO_REQUIRE_ASSERT(!cs->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE)); + + OCIO::ConstTransformRcPtr t = cs->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_GROUP); + auto gtx = OCIO::DynamicPtrCast(t); + OCIO_REQUIRE_ASSERT(gtx); + OCIO_CHECK_EQUAL(gtx->getNumTransforms(), 2); + + { + OCIO_CHECK_EQUAL(gtx->getTransform(0)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); + std::vector m44(16, 0.0); + auto mtx0 = OCIO::DynamicPtrCast(gtx->getTransform(0)); + OCIO_REQUIRE_ASSERT(mtx0); + mtx0->getMatrix(m44.data()); + //OCIO_CHECK_CLOSE(m44[0], 3.240969941907, 1e-5f); + } + + { + OCIO_CHECK_EQUAL(gtx->getTransform(1)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); + std::vector m44(16, 0.0); + auto mtx0 = OCIO::DynamicPtrCast(gtx->getTransform(1)); + OCIO_REQUIRE_ASSERT(mtx0); + mtx0->getMatrix(m44.data()); + OCIO_CHECK_CLOSE(m44[0], 0.412390799266, 1e-5f); + } + } + } + + { + // Convert each one of the view transforms and check the result. + // The view transform of the input config goes from linear rec.709 to linear rec.709. + // This needs to be adapted to the base config that goes from cie-xyz to aces2065-1. + std::vector viewTransforms; + for (int v = 0; v < inputConfig->getNumViewTransforms(); v++) + { + const char * name = inputConfig->getViewTransformNameByIndex(v); + viewTransforms.push_back(inputConfig->getViewTransform(name)); + } + + OCIO::ViewTransformRcPtr vt = viewTransforms[0]->createEditableCopy(); + OCIO::ConfigUtils::updateReferenceView(vt, inputToBaseGtScene, inputToBaseGtDisplay); + OCIO_REQUIRE_ASSERT(!vt->getTransform(OCIO::VIEWTRANSFORM_DIR_TO_REFERENCE)) + + OCIO::ConstTransformRcPtr t = vt->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_GROUP); + auto gtx = OCIO::DynamicPtrCast(t); + OCIO_REQUIRE_ASSERT(gtx); + OCIO_CHECK_EQUAL(gtx->getNumTransforms(), 3); + + // Matrix from cie-xyz to rec.709. + { + OCIO_CHECK_EQUAL(gtx->getTransform(0)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); + std::vector m44(16, 0.0); + auto mtx0 = OCIO::DynamicPtrCast(gtx->getTransform(0)); + OCIO_REQUIRE_ASSERT(mtx0); + mtx0->getMatrix(m44.data()); + //OCIO_CHECK_CLOSE(m44[0], 3.240969941907, 1e-5f); + } + + // The original group transform from the input config. + { + OCIO_CHECK_EQUAL(gtx->getTransform(1)->getTransformType(), OCIO::TRANSFORM_TYPE_GROUP); + auto gtxA = OCIO::DynamicPtrCast(gtx->getTransform(1)); + OCIO_REQUIRE_ASSERT(gtxA); + OCIO_CHECK_EQUAL(gtxA->getNumTransforms(), 3); + + { + std::vector m44(16, 0.0); + auto mtx0 = OCIO::DynamicPtrCast(gtxA->getTransform(0)); + OCIO_REQUIRE_ASSERT(mtx0); + mtx0->getMatrix(m44.data()); + OCIO_CHECK_CLOSE(m44[0], 0.439632981919, 1e-5f); + } + + OCIO_CHECK_EQUAL(gtxA->getTransform(1)->getTransformType(), OCIO::TRANSFORM_TYPE_BUILTIN); + + { + std::vector m44(16, 0.0); + auto mtx2 = OCIO::DynamicPtrCast(gtxA->getTransform(2)); + OCIO_REQUIRE_ASSERT(mtx2); + mtx2->getMatrix(m44.data()); + OCIO_CHECK_CLOSE(m44[0], 3.240969941905, 1e-5f); + } + } + + // Matrix from rec.709 to aces2065-1. + { + std::vector m44(16, 0.0); + auto mtx2 = OCIO::DynamicPtrCast(gtx->getTransform(2)); + OCIO_REQUIRE_ASSERT(mtx2); + mtx2->getMatrix(m44.data()); + OCIO_CHECK_CLOSE(m44[0], 0.439632981919, 1e-5f); + } + } +} + +OCIO_ADD_TEST(MergeConfigs, config_utils_find_equivalent_colorspace) +{ + std::istringstream iss; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2.1 +environment: + {} +search_path: "" + +file_rules: + - ! {name: Default, colorspace: ref_space} + +inactive_colorspaces: [] + +colorspaces: + - ! + name: ref_space + description: The reference space, but with a different name. + isdata: false + + - ! + name: Unknown + description: Raw but with a different name. + isdata: true + + - ! + name: standard RGB + isdata: false + description: sRGB - Texture + from_scene_reference: ! + children: + - ! {matrix: [2.52168618674388, -1.13413098823972, -0.387555198504164, 0, -0.276479914229922, 1.37271908766826, -0.096239173438334, 0, -0.0153780649660342, -0.152975335867399, 1.16835340083343, 0, 0, 0, 0, 1]} + - ! {gamma: 2.4, offset: 0.055, direction: inverse} + + - ! + name: approx. standard RGB + isdata: false + description: sRGB - Texture with truncated matrix values + from_scene_reference: ! + children: + - ! {matrix: [2.521686, -1.134131, -0.387555, 0, -0.2764799, 1.372719, -0.09623917, 0, -0.01537806, -0.152975, 1.168353, 0, 0, 0, 0, 1]} + - ! {gamma: 2.4, offset: 0.055, direction: inverse} + + - ! + name: very approx. standard RGB + isdata: false + description: sRGB - Texture with truncated matrix values and different gamma + from_scene_reference: ! + children: + - ! {matrix: [2.521686, -1.134131, -0.387555, 0, -0.2764799, 1.372719, -0.09623917, 0, -0.01537806, -0.152975, 1.168353, 0, 0, 0, 0, 1]} + - ! {gamma: 2.42, offset: 0.055, direction: inverse} + + - ! + name: ACES cct + isdata: false + description: ACEScct + to_scene_reference: ! {style: ACEScct_to_ACES2065-1} + + - ! + name: ACES cg + isdata: false + description: ACEScg but with a Matrix rather than Builtin Transform. + to_reference: ! {matrix: [ 0.695452241357, 0.140678696470, 0.163869062172, 0, 0.044794563372, 0.859671118456, 0.095534318172, 0, -0.005525882558, 0.004025210306, 1.001500672252, 0, 0, 0, 0, 1 ]} + + - ! + name: pq display + isdata: false + description: Rec.2100-PQ - Display + from_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_REC.2100-PQ} +)" }; + + iss.str(INPUT); + + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromFile("ocio://cg-config-v1.0.0_aces-v1.3_ocio-v2.1"); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + + std::vector colorspaces; + OCIO::SearchReferenceSpaceType refType = OCIO::SEARCH_REFERENCE_SPACE_SCENE; + for (int i = 0; i < inputConfig->getNumColorSpaces(refType, OCIO::COLORSPACE_ALL); ++i) + { + const char * name = inputConfig->getColorSpaceNameByIndex(refType, OCIO::COLORSPACE_ALL, i); + OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace(name); + colorspaces.push_back(cs); + } + + // Check 'ref_space' + { +// OCIO::ConstColorSpaceRcPtr cs = colorspaces[0]; +// TODO: could omit the vector of color spaces to make this easier to read. + OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("ref_space"); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(baseConfig, + cs, + OCIO::REFERENCE_SPACE_SCENE); + OCIO_CHECK_EQUAL(name, std::string("ACES2065-1")); + } + + // Check 'Unknown' + { + OCIO::ConstColorSpaceRcPtr cs = colorspaces[1]; + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(baseConfig, + cs, + OCIO::REFERENCE_SPACE_SCENE); + OCIO_CHECK_EQUAL(name, std::string("Raw")); + } + + // Check 'standard RGB' + { + OCIO::ConstColorSpaceRcPtr cs = colorspaces[2]; + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(baseConfig, + cs, + OCIO::REFERENCE_SPACE_SCENE); + OCIO_CHECK_EQUAL(name, std::string("sRGB - Texture")); + } + + // Check 'approx. standard RGB'. Matrix values are different but within tolerance + { + OCIO::ConstColorSpaceRcPtr cs = colorspaces[3]; + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(baseConfig, + cs, + OCIO::REFERENCE_SPACE_SCENE); + OCIO_CHECK_EQUAL(name, std::string("sRGB - Texture")); + } + + // Check 'very approx. standard RGB'. Gamma value is outside tolerance -- no match. + { + OCIO::ConstColorSpaceRcPtr cs = colorspaces[4]; + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(baseConfig, + cs, + OCIO::REFERENCE_SPACE_SCENE); + OCIO_CHECK_EQUAL(name, std::string("")); + } + + // Check 'ACES cct'. + { + OCIO::ConstColorSpaceRcPtr cs = colorspaces[5]; + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(baseConfig, + cs, + OCIO::REFERENCE_SPACE_SCENE); + OCIO_CHECK_EQUAL(name, std::string("ACEScct")); + } + + // Check 'ACES cg' + { + OCIO::ConstColorSpaceRcPtr cs = colorspaces[6]; + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(baseConfig, + cs, + OCIO::REFERENCE_SPACE_SCENE); + OCIO_CHECK_EQUAL(name, std::string("ACEScg")); + } + + // Check 'ACES cg' but with the wrong ref space type -- no match. + { + OCIO::ConstColorSpaceRcPtr cs = colorspaces[6]; + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(baseConfig, + cs, + OCIO::REFERENCE_SPACE_DISPLAY); + OCIO_CHECK_EQUAL(name, std::string("")); + } + + // Check 'pq display'. + { + OCIO::ConstColorSpaceRcPtr cs = colorspaces[7]; + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(baseConfig, + cs, + OCIO::REFERENCE_SPACE_DISPLAY); + OCIO_CHECK_EQUAL(name, std::string("Rec.2100-PQ - Display")); + } + + // Check 'pq display' but with wrong ref space type -- no match. + { + OCIO::ConstColorSpaceRcPtr cs = colorspaces[7]; + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(baseConfig, + cs, + OCIO::REFERENCE_SPACE_SCENE); + OCIO_CHECK_EQUAL(name, std::string("")); + } +} \ No newline at end of file diff --git a/tests/cpu/Config_tests.cpp b/tests/cpu/Config_tests.cpp index 6a310aae04..599dc29cf7 100644 --- a/tests/cpu/Config_tests.cpp +++ b/tests/cpu/Config_tests.cpp @@ -9125,7 +9125,7 @@ OCIO_ADD_TEST(Config, alias_validation) cs->addAlias("colorspace1"); OCIO_CHECK_THROW_WHAT(cfg->addColorSpace(cs), OCIO::Exception, "Cannot add 'colorspace3' " "color space, it has 'colorspace1' alias and existing color space, " - "'colorspace1' is using the same alias"); + "'colorspace1' has the same name"); cs->removeAlias("colorspace1"); OCIO_CHECK_NO_THROW(cfg->setRole("alias", "colorspace2")); diff --git a/tests/cpu/UnitTestLogUtils.cpp b/tests/cpu/UnitTestLogUtils.cpp index 6fd3896561..f55dbc11d3 100644 --- a/tests/cpu/UnitTestLogUtils.cpp +++ b/tests/cpu/UnitTestLogUtils.cpp @@ -37,6 +37,13 @@ LogGuard::LogGuard() SetLoggingFunction(&CustomLoggingFunction); } +LogGuard::LogGuard(LoggingLevel level) + : m_logLevel(GetLoggingLevel()) +{ + SetLoggingLevel(level); + SetLoggingFunction(&CustomLoggingFunction); +} + LogGuard::~LogGuard() { ResetToDefaultLoggingFunction(); @@ -148,9 +155,21 @@ bool checkAndMuteDisplayInterchangeRoleError(LogGuard & logGuard) void muteInactiveColorspaceInfo(LogGuard & logGuard) { const std::string str = "- Display' is neither a color space nor a named transform."; - const std::string pattern = R"(^\[OpenColorIO Info\]: Inactive.*)" + str + R"([\r\n]+)"; + const std::string pattern = R"(\[OpenColorIO Info\]: Inactive.*)" + str + R"([\r\n]+)"; logGuard.findAllAndRemove(pattern); } +bool checkAndMuteWarning(LogGuard & logGuard, const std::string str) +{ + const std::string pattern = R"(\[OpenColorIO Warning\]: )" + str + R"([\.\r\n]+)"; + return logGuard.findAllAndRemove(pattern); +} + +bool checkAndMuteError(LogGuard & logGuard, const std::string str) +{ + const std::string pattern = R"(\[OpenColorIO Error\]: )" + str + R"([\r\n]+)"; + return logGuard.findAllAndRemove(pattern); +} + } // namespace OCIO_NAMESPACE diff --git a/tests/cpu/UnitTestLogUtils.h b/tests/cpu/UnitTestLogUtils.h index ba05ecf1f6..2a24436b11 100644 --- a/tests/cpu/UnitTestLogUtils.h +++ b/tests/cpu/UnitTestLogUtils.h @@ -14,7 +14,8 @@ namespace OCIO_NAMESPACE class LogGuard { public: - LogGuard(); + LogGuard(); // Temporarily sets the level to LOGGING_LEVEL_DEBUG + LogGuard(LoggingLevel level); LogGuard(const LogGuard &) = delete; LogGuard & operator=(const LogGuard &) = delete; ~LogGuard(); @@ -48,6 +49,9 @@ bool checkAndMuteDisplayInterchangeRoleError(LogGuard & logGuard); void muteInactiveColorspaceInfo(LogGuard & logGuard); +bool checkAndMuteWarning(LogGuard & logGuard, const std::string str); +bool checkAndMuteError(LogGuard & logGuard, const std::string str); + } // namespace OCIO_NAMESPACE #endif // INCLUDED_OCIO_UNITTEST_LOGUTILS_H diff --git a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp new file mode 100644 index 0000000000..f8243fbe38 --- /dev/null +++ b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp @@ -0,0 +1,6069 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + +#include + +#include "apphelpers/mergeconfigs/MergeConfigsHelpers.cpp" + +#include "UnitTestUtils.h" + +#include "ConfigUtils.h" +#include "testutils/UnitTest.h" +#include "UnitTestLogUtils.h" + +namespace OCIO = OCIO_NAMESPACE; + +using MergeStrategy = OCIO::ConfigMergingParameters::MergeStrategies; + +OCIO::ConstConfigRcPtr getBaseConfig() +{ + std::vector basePaths = { + std::string(OCIO::GetTestFilesDir()), + std::string("configs"), + std::string("mergeconfigs"), + std::string("base_config.yaml") + }; + const std::string baseCfgPath = pystring::os::path::normpath(pystring::os::path::join(basePaths)); + return OCIO::Config::CreateFromFile(baseCfgPath.c_str()); +} + +OCIO::ConstConfigRcPtr getInputConfig() +{ + std::vector inputPaths = { + std::string(OCIO::GetTestFilesDir()), + std::string("configs"), + std::string("mergeconfigs"), + std::string("input_config.yaml") + }; + const std::string inputCfgPath = pystring::os::path::normpath(pystring::os::path::join(inputPaths)); + return OCIO::Config::CreateFromFile(inputCfgPath.c_str()); +} + +OCIO::ConstConfigRcPtr getConfig(std::string filename) +{ + std::vector inputPaths = { + std::string(OCIO::GetTestFilesDir()), + std::string("configs"), + std::string("mergeconfigs"), + std::string(filename) + }; + const std::string inputCfgPath = pystring::os::path::normpath(pystring::os::path::join(inputPaths)); + return OCIO::Config::CreateFromFile(inputCfgPath.c_str()); +} + +void compareEnvironmentVar(const OCIO::ConfigRcPtr & mergedConfig, + const std::vector & expectedNames, + const std::vector & expectedValues, + int line) +{ + for (int i = 0; i < mergedConfig->getNumEnvironmentVars(); i++) + { + std::string name = mergedConfig->getEnvironmentVarNameByIndex(i); + OCIO_CHECK_EQUAL_FROM(name, expectedNames.at(i), line); + OCIO_CHECK_EQUAL_FROM(std::string(mergedConfig->getEnvironmentVarDefault(name.c_str())), + expectedValues.at(i), + line); + } +} + +OCIO::ConstColorSpaceRcPtr checkColorSpace(const OCIO::ConstConfigRcPtr mergedConfig, + const char * refName, + const int index, + OCIO::SearchReferenceSpaceType refType, + int line) +{ + const char * name = mergedConfig->getColorSpaceNameByIndex(refType, + OCIO::COLORSPACE_ALL, + index); + OCIO_CHECK_EQUAL_FROM(std::string(name), std::string(refName), line); + OCIO::ConstColorSpaceRcPtr cs = mergedConfig->getColorSpace(refName); + OCIO_REQUIRE_ASSERT_FROM(cs, line); + return cs; +} + +OCIO::ConstNamedTransformRcPtr checkNamedTransform(const OCIO::ConstConfigRcPtr mergedConfig, + const char * refName, + const int index, + int line) +{ + const char * name = mergedConfig->getNamedTransformNameByIndex(OCIO::NAMEDTRANSFORM_ALL, index); + OCIO_CHECK_EQUAL_FROM(std::string(name), std::string(refName), line); + OCIO::ConstNamedTransformRcPtr nt = mergedConfig->getNamedTransform(refName); + OCIO_REQUIRE_ASSERT_FROM(nt, line); + return nt; +} + +// FIXME: REMOVE +static constexpr char PREFIX[] { "The Input config contains a value that would override the Base config: " }; + +template +void loadStringsHelper(std::vector& strings, Arg arg) +{ + strings.push_back(arg); +} + +template +void loadStringsHelper(std::vector& strings, Arg arg, Args... args) { + strings.push_back(arg); + loadStringsHelper(strings, args...); +} + +enum LogType +{ + LOG_TYPE_INFO, + LOG_TYPE_WARNING, + LOG_TYPE_ERROR, +}; + +template +void checkForLogOrException(LogType type, int line, std::function setup, Args... args) +{ + std::vector strings; + strings.reserve(sizeof...(args)); + loadStringsHelper(strings, args...); + + // Use INFO rather than DEBUG for the guard to avoid a lot of OpOptimizers.cpp output. + OCIO::LogGuard logGuard(OCIO::LOGGING_LEVEL_INFO); + try + { + setup(); + + for(const auto & s : strings) + { + if (type == LOG_TYPE_ERROR) + { +// OCIO_CHECK_ASSERT_FROM(OCIO::checkAndMuteError(logGuard, s), line); + + const bool errorFound = OCIO::checkAndMuteError(logGuard, s); + if (!errorFound) + { + std::cout << "This error was not found: " << s.c_str() << "\n"; + } + OCIO_CHECK_ASSERT_FROM(errorFound, line); + } + else if (type == LOG_TYPE_WARNING) + { + const bool warningFound = OCIO::checkAndMuteWarning(logGuard, s); + if (!warningFound) + { + std::cout << "This warning was not found: " << s.c_str() << "\n"; + } + OCIO_CHECK_ASSERT_FROM(warningFound, line); + } + } + + // If all messages have not been removed from the log at this point, it's unexpected. + if (!logGuard.empty()) + { + std::cout << "The following unexpected messages were encountered:\n"; + logGuard.print(); + } + OCIO_CHECK_ASSERT_FROM(logGuard.empty(), line); + } + catch(const OCIO::Exception & e) + { + // Only checking the first string because only the first Exception gets out. + OCIO_CHECK_EQUAL_FROM(std::string(e.what()), strings.at(0), line); + } +} + +OCIO_ADD_TEST(MergeConfigs, ociom_parser) +{ + std::vector paths = { + std::string(OCIO::GetTestFilesDir()), + std::string("configs"), + std::string("mergeconfigs"), + std::string("parser_test.ociom") + }; + const std::string ociomPath = pystring::os::path::normpath(pystring::os::path::join(paths)); + + OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); + + // The parser_test.ociom contains only one merge. + OCIO::ConstConfigMergingParametersRcPtr p = merger->getParams(0); + + // Test that the all the options are loaded correctly. + // Note that is does not test all possibilities. + // e.g. it does not test all the strategies for all sections. + + OCIO_CHECK_EQUAL(std::string(p->getBaseConfigName()), std::string("base0.ocio")); + OCIO_CHECK_EQUAL(std::string(p->getInputConfigName()), std::string("input0.ocio")); + + OCIO_CHECK_EQUAL(std::string(p->getInputFamilyPrefix()), std::string("abc")); + OCIO_CHECK_EQUAL(std::string(p->getBaseFamilyPrefix()), std::string("def")); + OCIO_CHECK_EQUAL(p->isInputFirst(), true); + OCIO_CHECK_EQUAL(p->isErrorOnConflict(), false); + // PreferInput + OCIO_CHECK_EQUAL(p->getDefaultStrategy(), MergeStrategy::STRATEGY_INPUT_ONLY); + OCIO_CHECK_EQUAL(p->isAvoidDuplicates(), true); + OCIO_CHECK_EQUAL(p->isAssumeCommonReferenceSpace(), false); + + OCIO_CHECK_EQUAL(std::string(p->getName()), std::string("my merge")); + OCIO_CHECK_EQUAL(std::string(p->getDescription()), std::string("my desc")); + OCIO_CHECK_EQUAL(std::string(p->getSearchPath()), std::string("abc")); + + // Expecting two environment variables. + OCIO_CHECK_EQUAL(p->getNumEnvironmentVars(), 2); + OCIO_CHECK_EQUAL(std::string(p->getEnvironmentVar(0)), "test"); + OCIO_CHECK_EQUAL(std::string(p->getEnvironmentVarValue(0)), "valueOther"); + OCIO_CHECK_EQUAL(std::string(p->getEnvironmentVar(1)), "test1"); + OCIO_CHECK_EQUAL(std::string(p->getEnvironmentVarValue(1)), "value123"); + + OCIO_CHECK_EQUAL(std::string(p->getActiveDisplays()), std::string("D1, D2")); + OCIO_CHECK_EQUAL(std::string(p->getActiveViews()), std::string("V1, V2")); + OCIO_CHECK_EQUAL(std::string(p->getInactiveColorSpaces()), std::string("I1, I2")); + + // PreferInput + OCIO_CHECK_EQUAL(p->getRoles(), MergeStrategy::STRATEGY_PREFER_INPUT); + // PreferBase + OCIO_CHECK_EQUAL(p->getFileRules(), MergeStrategy::STRATEGY_PREFER_BASE); + // InputOnly + OCIO_CHECK_EQUAL(p->getDisplayViews(), MergeStrategy::STRATEGY_INPUT_ONLY); + // BaseOnly + OCIO_CHECK_EQUAL(p->getLooks(), MergeStrategy::STRATEGY_BASE_ONLY); + // Remove + OCIO_CHECK_EQUAL(p->getColorspaces(), MergeStrategy::STRATEGY_REMOVE); + // PreferBase + OCIO_CHECK_EQUAL(p->getNamedTransforms(), MergeStrategy::STRATEGY_PREFER_BASE); +} + +//TODOCED Add test for OCIOM writer + +OCIO_ADD_TEST(MergeConfigs, ociom_parser_no_overrides) +{ + std::vector paths = { + std::string(OCIO::GetTestFilesDir()), + std::string("configs"), + std::string("mergeconfigs"), + std::string("parser_test_no_overrides.ociom") + }; + const std::string ociomPath = pystring::os::path::normpath(pystring::os::path::join(paths)); + + OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); + + // The parser_test.ociom contains only one merge. + OCIO::ConstConfigMergingParametersRcPtr p = merger->getParams(0); + + // Test that the all the options are loaded correctly. + // Note that is does not test all possibilities. + // e.g. it does not test all the strategies for all sections. + + OCIO_CHECK_EQUAL(std::string(p->getBaseConfigName()), std::string("input0.ocio")); + OCIO_CHECK_EQUAL(std::string(p->getInputConfigName()), std::string("input2.ocio")); + + OCIO_CHECK_EQUAL(std::string(p->getInputFamilyPrefix()), std::string("abc")); + OCIO_CHECK_EQUAL(std::string(p->getBaseFamilyPrefix()), std::string("def")); + OCIO_CHECK_EQUAL(p->isInputFirst(), true); + OCIO_CHECK_EQUAL(p->isErrorOnConflict(), false); + // PreferInput + OCIO_CHECK_EQUAL(p->getDefaultStrategy(), MergeStrategy::STRATEGY_INPUT_ONLY); + OCIO_CHECK_EQUAL(p->isAvoidDuplicates(), true); + OCIO_CHECK_EQUAL(p->isAssumeCommonReferenceSpace(), false); + + OCIO_CHECK_EQUAL(std::string(p->getName()), std::string("")); + OCIO_CHECK_EQUAL(std::string(p->getDescription()), std::string("")); + OCIO_CHECK_EQUAL(std::string(p->getSearchPath()), std::string("")); + + // Expecting 0 environment variables. + OCIO_CHECK_EQUAL(p->getNumEnvironmentVars(), 0); + + OCIO_CHECK_EQUAL(std::string(p->getActiveDisplays()), std::string("")); + OCIO_CHECK_EQUAL(std::string(p->getActiveViews()), std::string("")); + OCIO_CHECK_EQUAL(std::string(p->getInactiveColorSpaces()), std::string("")); + + // PreferInput + OCIO_CHECK_EQUAL(p->getRoles(), MergeStrategy::STRATEGY_PREFER_INPUT); + // PreferBase + OCIO_CHECK_EQUAL(p->getFileRules(), MergeStrategy::STRATEGY_PREFER_BASE); + // InputOnly + OCIO_CHECK_EQUAL(p->getDisplayViews(), MergeStrategy::STRATEGY_INPUT_ONLY); + // BaseOnly + OCIO_CHECK_EQUAL(p->getLooks(), MergeStrategy::STRATEGY_BASE_ONLY); + // Remove + OCIO_CHECK_EQUAL(p->getColorspaces(), MergeStrategy::STRATEGY_REMOVE); + // PreferBase + OCIO_CHECK_EQUAL(p->getNamedTransforms(), MergeStrategy::STRATEGY_PREFER_BASE); +} + +OCIO_ADD_TEST(MergeConfigs, overrides) +{ + OCIO::ConstConfigRcPtr baseConfig; + OCIO_CHECK_NO_THROW(baseConfig = getBaseConfig()); + + OCIO::ConstConfigRcPtr inputConfig; + OCIO_CHECK_NO_THROW(inputConfig = getInputConfig()); + + auto setup = [&baseConfig, &inputConfig] + (OCIO::ConfigMergerRcPtr & merger, + OCIO::ConfigRcPtr mergedConfig, + MergeStrategy strategy, + std::function cb) + { + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + merger->addParams(params); + merger->getParams(0)->setDisplayViews(strategy); + merger->getParams(0)->setColorspaces(strategy); + // Not looking for duplicates as this test does not test that. + merger->getParams(0)->setAvoidDuplicates(false); + + if (cb) + { + cb(merger); + } + + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + // Merge name and description. + OCIO::GeneralMerger(options).merge(); + // Merge active_display, active_views. + OCIO::DisplayViewMerger(options).merge(); + // Merge inactive_colorspaces, environment and search_path. + OCIO::ColorspacesMerger(options).merge(); + }; + + // Test that the overrides options are taken into account in the merging process. + + auto testAllStrategies = [&baseConfig, &setup] + (MergeStrategy strategy, + int line) + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + setup(merger, + mergedConfig, + strategy, + [](OCIO::ConfigMergerRcPtr & merger) + { + // overrides + merger->getParams(0)->setName("OVR Name"); + merger->getParams(0)->setDescription("OVR Desc"); + merger->getParams(0)->setSearchPath("OVR1,OVR2"); + merger->getParams(0)->addEnvironmentVar("OVR1", "VALUE1"); + merger->getParams(0)->addEnvironmentVar("OVR2", "VALUE2"); + merger->getParams(0)->setActiveDisplays("OVR DISP 1,OVR DISP 2"); + merger->getParams(0)->setActiveViews("OVR VIEW 1,OVR VIEW 2"); + merger->getParams(0)->setInactiveColorspaces("view_1, ACES2065-1"); + }); + + OCIO_CHECK_EQUAL_FROM(std::string(mergedConfig->getName()), std::string("OVR Name"), line); + OCIO_CHECK_EQUAL_FROM(std::string(mergedConfig->getDescription()), std::string("OVR Desc"), line); + + OCIO_CHECK_EQUAL_FROM(std::string(mergedConfig->getSearchPath()), std::string("OVR1,OVR2"), line); + + std::vector expectedNames = { "OVR1", "OVR2" }; + std::vector expectedValues = { "VALUE1", "VALUE2" }; + OCIO_CHECK_EQUAL_FROM(mergedConfig->getNumEnvironmentVars(), 2, line); + compareEnvironmentVar(mergedConfig, expectedNames, expectedValues, line); + + OCIO_CHECK_EQUAL_FROM(std::string(mergedConfig->getActiveDisplays()), "OVR DISP 1, OVR DISP 2", line); + OCIO_CHECK_EQUAL_FROM(std::string(mergedConfig->getActiveViews()), + "OVR VIEW 1, OVR VIEW 2", line); + + OCIO_CHECK_EQUAL_FROM(std::string(mergedConfig->getInactiveColorSpaces()), "view_1, ACES2065-1", line); + }; + + // Test sections with strategy = PreferInput + testAllStrategies(MergeStrategy::STRATEGY_PREFER_INPUT, __LINE__); + + // Test sections with strategy = PreferBase. + testAllStrategies(MergeStrategy::STRATEGY_PREFER_BASE, __LINE__); + + // Test sections with strategy = InputOnly. + testAllStrategies(MergeStrategy::STRATEGY_INPUT_ONLY, __LINE__); + + // Test sections with strategy = BaseOnly. + testAllStrategies(MergeStrategy::STRATEGY_BASE_ONLY, __LINE__); + + // Strategy Remove is not tested as the overrides do not affect that strategy. +} + +OCIO_ADD_TEST(MergeConfigs, general_section) +{ + OCIO::ConstConfigRcPtr baseConfig; + OCIO_CHECK_NO_THROW(baseConfig = getBaseConfig()); + + OCIO::ConstConfigRcPtr inputConfig; + OCIO_CHECK_NO_THROW(inputConfig = getInputConfig()); + +// auto setupGeneral = [&baseConfig, &inputConfig]( +// OCIO::ConfigMergerRcPtr & merger, +// OCIO::ConfigRcPtr mergedConfig, +// std::function cb) +// { +// OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); +// merger->addParams(params); +// +// if (cb) +// { +// cb(merger); +// } +// +// OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; +// OCIO::GeneralMerger(options).merge(); +// }; + +/// FIXME InputFirst has no impact on general. Should test name, desc, profile version. + + // Test general merger (uses default strategy) with options InputFirst = true. +// { +// OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); +// OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); +// setupGeneral(merger, +// mergedConfig, +// { +// merger->getParams(0)->setInputFirst(true); +// }); +// +// +// OCIO_CHECK_EQUAL(std::string(mergedConfig->getName()), std::string("input0")); +// OCIO_CHECK_EQUAL(std::string(mergedConfig->getDescription()), std::string("My description 2")); +// } +// +// // Test general merger (uses default strategy) with options InputFirst = false. +// { +// OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); +// OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); +// setupGeneral(merger, +// mergedConfig, +// [](OCIO::ConfigMergerRcPtr & merger) +// { +// merger->getParams(0)->setInputFirst(false); +// }); +// +// OCIO_CHECK_EQUAL(std::string(mergedConfig->getName()), std::string("input0")); +// OCIO_CHECK_EQUAL(std::string(mergedConfig->getDescription()), std::string("My description 2")); +// } +} + +OCIO_ADD_TEST(MergeConfigs, roles_section) +{ + // Allowed strategies: PreferInput, PreferBase, InputOnly, BaseOnly, Remove + // Allowed merge options: ErrorOnConflict. + + OCIO::ConstConfigRcPtr baseConfig; + OCIO_CHECK_NO_THROW(baseConfig = getBaseConfig()); + + OCIO::ConstConfigRcPtr inputConfig; + OCIO_CHECK_NO_THROW(inputConfig = getInputConfig()); + + auto setupBasics = [](OCIO::ConfigMergerRcPtr & merger, MergeStrategy strategy) -> OCIO::ConfigMergingParametersRcPtr + { + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + merger->addParams(params); + merger->getParams(0)->setRoles(strategy); + merger->getParams(0)->setDefaultStrategy(strategy); + return params; + }; + + // Test that the default strategy is used as a fallback if the section strategy was not defined. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + // Using STRATEGY_UNSET as this simulates that the section + // is missing from the OCIOM file. + auto params = setupBasics(merger, MergeStrategy::STRATEGY_UNSET); + // Simulate settings from OCIOM file. + merger->getParams(0)->setDefaultStrategy(MergeStrategy::STRATEGY_INPUT_ONLY); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'g22_ap1_tx' that would override an alias of Base config color space 'Gamma 2.2 AP1 - Texture'", + "The Input config contains a role 'nt_base' that would override Base config named transform: 'nt_base'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("aces_interchange")), + std::string("ACES2065-1")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("texture_paint")), + std::string("ACEScct - SomeOtherName")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("matte_paint")), + std::string("sRGB - Texture")); + } + + // Test Roles section with strategy = PreferInput + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'g22_ap1_tx' that would override an alias of Base config color space 'Gamma 2.2 AP1 - Texture'", + "The Input config contains a role that would override Base config role 'texture_paint'.", + "The Input config contains a role 'nt_base' that would override Base config named transform: 'nt_base'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 4); + + // Following three roles were overwritten by input config. + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("aces_interchange")), + std::string("ACES2065-1")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("texture_paint")), + std::string("ACEScct - SomeOtherName")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("matte_paint")), + std::string("sRGB - Texture")); + + // Following role come from base config. + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("data")), + std::string("Raw")); + } + + // Test Roles section with strategy = PreferBase + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'g22_ap1_tx' that would override an alias of Base config color space 'Gamma 2.2 AP1 - Texture'", + "The Input config contains a role that would override Base config role 'texture_paint'.", + "The Input config contains a role 'nt_base' that would override Base config named transform: 'nt_base'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 4); + + // Following three roles comes form the base config. + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("aces_interchange")), + std::string("ACES2065-1")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("texture_paint")), + std::string("ACEScct")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("data")), + std::string("Raw")); + + // Following role come from input config. + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("matte_paint")), + std::string("sRGB - Texture")); + } + + // Test Roles section with strategy = InputOnly. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_INPUT_ONLY); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'g22_ap1_tx' that would override an alias of Base config color space 'Gamma 2.2 AP1 - Texture'", + "The Input config contains a role 'nt_base' that would override Base config named transform: 'nt_base'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 3); + + // Following three roles comes form the input config. + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("aces_interchange")), + std::string("ACES2065-1")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("texture_paint")), + std::string("ACEScct - SomeOtherName")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("matte_paint")), + std::string("sRGB - Texture")); + } + + // Test Roles section with strategy = BaseOnly. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_BASE_ONLY); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::RolesMerger(options).merge(); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 3); + + // Following three roles comes form the base config. + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("aces_interchange")), + std::string("ACES2065-1")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("texture_paint")), + std::string("ACEScct")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("data")), + std::string("Raw")); + } + + // Test Roles section with strategy = Remove + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_REMOVE); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::RolesMerger(options).merge(); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 1); + + // This is the only role in base that is not in input. + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("data")), + std::string("Raw")); + } + + // Test Roles section with strategy = PreferInput and option ErrorOnConflict = true. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setErrorOnConflict(true); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_ERROR, __LINE__, + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'g22_ap1_tx' that would override an alias of Base config color space 'Gamma 2.2 AP1 - Texture'."); + } +} + +OCIO_ADD_TEST(MergeConfigs, file_rules_section) +{ + OCIO::ConstConfigRcPtr baseConfig; + OCIO_CHECK_NO_THROW(baseConfig = getBaseConfig()); + + OCIO::ConstConfigRcPtr inputConfig; + OCIO_CHECK_NO_THROW(inputConfig = getInputConfig()); + + auto setupFileRules = [&baseConfig, &inputConfig] + (OCIO::ConfigMergerRcPtr & merger, + OCIO::ConfigRcPtr mergedConfig, + MergeStrategy strategy, + std::function cb) + { + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + merger->addParams(params); + merger->getParams(0)->setFileRules(strategy); + + if (cb) + { + cb(merger); + } + + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::FileRulesMerger(options).merge(); + }; + + // Allowed strategies: All + // Allowed merge options: All + + // Test that the default strategy is used as a fallback if the section strategy was not defined. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + setupFileRules(merger, + mergedConfig, + // Using STRATEGY_UNSET as this simulate that the section + // is missing from the OCIOM file. + MergeStrategy::STRATEGY_UNSET, + [](OCIO::ConfigMergerRcPtr & merger) + { + // Simulate settings from OCIOM file. + merger->getParams(0)->setDefaultStrategy(MergeStrategy::STRATEGY_INPUT_ONLY); + }); + + OCIO_CHECK_EQUAL(mergedConfig->isStrictParsingEnabled(), false); + + OCIO::ConstFileRulesRcPtr fr = mergedConfig->getFileRules(); + + OCIO_CHECK_EQUAL(fr->getNumEntries(), 5); + + OCIO_CHECK_EQUAL(std::string(fr->getName(0)), "LogC"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(0)), "ACES2065-1"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(1)), "TIFF"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(1)), "sRGB - Texture"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(2)), "JPEG"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(2)), "Linear Rec.2020"); + OCIO_CHECK_EQUAL(std::string(fr->getRegex(2)), ".*\\.jpeg$"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(3)), "ColorSpaceNamePathSearch"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(4)), "Default"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(4)), "ACEScct - SomeOtherName"); + } + + // Test FileRules section with strategy = PreferInput. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + + setupFileRules(merger, + mergedConfig, + MergeStrategy::STRATEGY_PREFER_INPUT, + nullptr); + + OCIO::ConstFileRulesRcPtr fr = mergedConfig->getFileRules(); + + OCIO_CHECK_EQUAL(fr->getNumEntries(), 6); + + OCIO_CHECK_EQUAL(std::string(fr->getName(0)), "LogC"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(0)), "ACES2065-1"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(1)), "TIFF"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(1)), "sRGB - Texture"); + OCIO_CHECK_EQUAL(std::string(fr->getRegex(1)), ".*\\.TIF?F$"); + // Verify that the custom keys are merged. + OCIO_CHECK_EQUAL(std::string(fr->getCustomKeyName(1, 0)), "key1"); + OCIO_CHECK_EQUAL(std::string(fr->getCustomKeyValue(1, 0)), "value1"); + OCIO_CHECK_EQUAL(std::string(fr->getCustomKeyName(1, 1)), "key2"); + OCIO_CHECK_EQUAL(std::string(fr->getCustomKeyValue(1, 1)), "value2"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(2)), "JPEG"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(2)), "Linear Rec.2020"); + OCIO_CHECK_EQUAL(std::string(fr->getRegex(2)), ".*\\.jpeg$"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(3)), "ColorSpaceNamePathSearch"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(4)), "OpenEXR"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(4)), "ACEScct"); + OCIO_CHECK_EQUAL(std::string(fr->getPattern(4)), "*"); + OCIO_CHECK_EQUAL(std::string(fr->getExtension(4)), "exr"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(5)), "Default"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(5)), "ACEScct - SomeOtherName"); + } + + // Test FileRules section with strategy = PreferInput, options InputFirst = false. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + setupFileRules(merger, + mergedConfig, + MergeStrategy::STRATEGY_PREFER_INPUT, + [](OCIO::ConfigMergerRcPtr & merger) + { + merger->getParams(0)->setInputFirst(false); + }); + + OCIO_CHECK_EQUAL(mergedConfig->isStrictParsingEnabled(), false); + + OCIO::ConstFileRulesRcPtr fr = mergedConfig->getFileRules(); + + OCIO_CHECK_EQUAL(fr->getNumEntries(), 6); + + OCIO_CHECK_EQUAL(std::string(fr->getName(0)), "LogC"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(0)), "ACES2065-1"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(1)), "TIFF"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(1)), "sRGB - Texture"); + // Verify that the custom keys are merged. + OCIO_CHECK_EQUAL(std::string(fr->getCustomKeyName(1, 0)), "key1"); + OCIO_CHECK_EQUAL(std::string(fr->getCustomKeyValue(1, 0)), "value1"); + OCIO_CHECK_EQUAL(std::string(fr->getCustomKeyName(1, 1)), "key2"); + OCIO_CHECK_EQUAL(std::string(fr->getCustomKeyValue(1, 1)), "value2"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(2)), "OpenEXR"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(2)), "ACEScct"); + OCIO_CHECK_EQUAL(std::string(fr->getPattern(2)), "*"); + OCIO_CHECK_EQUAL(std::string(fr->getExtension(2)), "exr"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(3)), "ColorSpaceNamePathSearch"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(4)), "JPEG"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(4)), "Linear Rec.2020"); + OCIO_CHECK_EQUAL(std::string(fr->getRegex(4)), ".*\\.jpeg$"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(5)), "Default"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(5)), "ACEScct - SomeOtherName"); + } + + // Test FileRules section with strategy = PreferBase. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + + setupFileRules(merger, + mergedConfig, + MergeStrategy::STRATEGY_PREFER_BASE, + [](OCIO::ConfigMergerRcPtr & merger) + { + merger->getParams(0)->setInputFirst(true); + }); + + OCIO_CHECK_EQUAL(mergedConfig->isStrictParsingEnabled(), true); + + OCIO::ConstFileRulesRcPtr fr = mergedConfig->getFileRules(); + + OCIO_CHECK_EQUAL(fr->getNumEntries(), 6); + + OCIO_CHECK_EQUAL(std::string(fr->getName(0)), "LogC"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(0)), "ACES2065-1"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(1)), "TIFF"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(1)), "Gamma 2.2 AP1 - Texture"); + OCIO_CHECK_EQUAL(fr->getNumCustomKeys(1), 0); + + OCIO_CHECK_EQUAL(std::string(fr->getName(2)), "JPEG"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(2)), "Linear Rec.2020"); + OCIO_CHECK_EQUAL(std::string(fr->getRegex(2)), ".*\\.jpeg$"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(3)), "ColorSpaceNamePathSearch"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(4)), "OpenEXR"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(4)), "ACEScct"); + OCIO_CHECK_EQUAL(std::string(fr->getPattern(4)), "*"); + OCIO_CHECK_EQUAL(std::string(fr->getExtension(4)), "exr"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(5)), "Default"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(5)), "Raw"); + } + + // Test FileRules section with strategy = PreferBase, options InputFirst = false. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + setupFileRules(merger, + mergedConfig, + MergeStrategy::STRATEGY_PREFER_BASE, + [](OCIO::ConfigMergerRcPtr & merger) + { + merger->getParams(0)->setInputFirst(false); + }); + OCIO_CHECK_EQUAL(mergedConfig->isStrictParsingEnabled(), true); + + OCIO::ConstFileRulesRcPtr fr = mergedConfig->getFileRules(); + + OCIO_CHECK_EQUAL(fr->getNumEntries(), 6); + + OCIO_CHECK_EQUAL(std::string(fr->getName(0)), "LogC"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(0)), "ACES2065-1"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(1)), "TIFF"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(1)), "Gamma 2.2 AP1 - Texture"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(2)), "OpenEXR"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(2)), "ACEScct"); + OCIO_CHECK_EQUAL(std::string(fr->getPattern(2)), "*"); + OCIO_CHECK_EQUAL(std::string(fr->getExtension(2)), "exr"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(3)), "ColorSpaceNamePathSearch"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(4)), "JPEG"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(4)), "Linear Rec.2020"); + OCIO_CHECK_EQUAL(std::string(fr->getRegex(4)), ".*\\.jpeg$"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(5)), "Default"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(5)), "Raw"); + } + + // Test FileRules section with strategy = InputOnly. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + + setupFileRules(merger, + mergedConfig, + MergeStrategy::STRATEGY_INPUT_ONLY, + nullptr); + + OCIO_CHECK_EQUAL(mergedConfig->isStrictParsingEnabled(), false); + + OCIO::ConstFileRulesRcPtr fr = mergedConfig->getFileRules(); + + OCIO_CHECK_EQUAL(fr->getNumEntries(), 5); + + OCIO_CHECK_EQUAL(std::string(fr->getName(0)), "LogC"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(0)), "ACES2065-1"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(1)), "TIFF"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(1)), "sRGB - Texture"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(2)), "JPEG"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(2)), "Linear Rec.2020"); + OCIO_CHECK_EQUAL(std::string(fr->getRegex(2)), ".*\\.jpeg$"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(3)), "ColorSpaceNamePathSearch"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(4)), "Default"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(4)), "ACEScct - SomeOtherName"); + } + + // Test FileRules section with strategy = BaseOnly. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + + setupFileRules(merger, + mergedConfig, + MergeStrategy::STRATEGY_BASE_ONLY, + nullptr); + OCIO_CHECK_EQUAL(mergedConfig->isStrictParsingEnabled(), true); + + OCIO::ConstFileRulesRcPtr fr = mergedConfig->getFileRules(); + + OCIO_CHECK_EQUAL(std::string(fr->getName(0)), "LogC"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(0)), "ACES2065-1"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(1)), "TIFF"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(1)), "Gamma 2.2 AP1 - Texture"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(2)), "OpenEXR"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(2)), "ACEScct"); + OCIO_CHECK_EQUAL(std::string(fr->getPattern(2)), "*"); + OCIO_CHECK_EQUAL(std::string(fr->getExtension(2)), "exr"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(3)), "ColorSpaceNamePathSearch"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(4)), "Default"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(4)), "Raw"); + } + + // Test FileRules section with strategy = Remove. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + + setupFileRules(merger, + mergedConfig, + MergeStrategy::STRATEGY_REMOVE, + nullptr); + OCIO_CHECK_EQUAL(mergedConfig->isStrictParsingEnabled(), true); + + OCIO::ConstFileRulesRcPtr fr = mergedConfig->getFileRules(); + + OCIO_CHECK_EQUAL(fr->getNumEntries(), 2); + + OCIO_CHECK_EQUAL(std::string(fr->getName(0)), "OpenEXR"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(0)), "ACEScct"); + OCIO_CHECK_EQUAL(std::string(fr->getPattern(0)), "*"); + OCIO_CHECK_EQUAL(std::string(fr->getExtension(0)), "exr"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(1)), "Default"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(1)), "Raw"); + } + + // Test FileRules section with strategy = PreferInput and copying ColorSpaceNamePathSearch. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + merger->addParams(params); + merger->getParams(0)->setFileRules(MergeStrategy::STRATEGY_PREFER_INPUT); + + { + OCIO::ConfigRcPtr editableInputConfig = inputConfig->createEditableCopy(); + OCIO::FileRulesRcPtr inputFr = editableInputConfig->getFileRules()->createEditableCopy(); + // Delete ColorSpaceNamePathSearch, so it is only in the base and must be copied over. + inputFr->removeRule(3); + editableInputConfig->setFileRules(inputFr); + + OCIO::MergeHandlerOptions options = { baseConfig, editableInputConfig, + params, mergedConfig }; + OCIO_CHECK_NO_THROW(OCIO::FileRulesMerger(options).merge()); + + OCIO::ConstFileRulesRcPtr fr = mergedConfig->getFileRules(); + + OCIO_CHECK_EQUAL(fr->getNumEntries(), 6); + + OCIO_CHECK_EQUAL(std::string(fr->getName(0)), "LogC"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(0)), "ACES2065-1"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(1)), "TIFF"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(1)), "sRGB - Texture"); + OCIO_CHECK_EQUAL(std::string(fr->getRegex(1)), ".*\\.TIF?F$"); + // Verify that the custom keys are merged. + OCIO_CHECK_EQUAL(std::string(fr->getCustomKeyName(1, 0)), "key1"); + OCIO_CHECK_EQUAL(std::string(fr->getCustomKeyValue(1, 0)), "value1"); + OCIO_CHECK_EQUAL(std::string(fr->getCustomKeyName(1, 1)), "key2"); + OCIO_CHECK_EQUAL(std::string(fr->getCustomKeyValue(1, 1)), "value2"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(2)), "JPEG"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(2)), "Linear Rec.2020"); + OCIO_CHECK_EQUAL(std::string(fr->getRegex(2)), ".*\\.jpeg$"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(3)), "OpenEXR"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(3)), "ACEScct"); + OCIO_CHECK_EQUAL(std::string(fr->getPattern(3)), "*"); + OCIO_CHECK_EQUAL(std::string(fr->getExtension(3)), "exr"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(4)), "ColorSpaceNamePathSearch"); + + OCIO_CHECK_EQUAL(std::string(fr->getName(5)), "Default"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(5)), "ACEScct - SomeOtherName"); + } + } + + // Test that error_on_conflicts is processed correctly. + // strategy = PreferInput, InputFirst = true + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + merger->addParams(params); + merger->getParams(0)->setFileRules(MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setErrorOnConflict(true); + merger->getParams(0)->setDefaultStrategy(MergeStrategy::STRATEGY_PREFER_INPUT); + + // Test that an error is thrown when the input config's COLORSPACE is different. + { + OCIO::ConfigRcPtr editableBaseConfig = baseConfig->createEditableCopy(); + OCIO::FileRulesRcPtr baseFr = OCIO::FileRules::Create(); + baseFr->insertRule(0, "ruleTestColorspace", "colorspace1", "*abc*", "*"); + editableBaseConfig->setFileRules(baseFr); + + OCIO::ConfigRcPtr editableInputConfig = inputConfig->createEditableCopy(); + OCIO::FileRulesRcPtr inputFr = OCIO::FileRules::Create(); + inputFr->insertRule(0, "ruleTestColorspace", "colorspace2", "*abc*", "*"); + editableInputConfig->setFileRules(inputFr); + + OCIO::MergeHandlerOptions options = { editableBaseConfig, editableInputConfig, + params, mergedConfig }; + checkForLogOrException(LOG_TYPE_ERROR, __LINE__, + [&options]() { OCIO::FileRulesMerger(options).merge(); }, + std::string(PREFIX) + std::string("file_rules: ruleTestColorspace")); + } + + // Test that an error is thrown when the input config's REGEX is different. + { + OCIO::ConfigRcPtr editableBaseConfig = baseConfig->createEditableCopy(); + OCIO::FileRulesRcPtr baseFr = OCIO::FileRules::Create(); + baseFr->insertRule(0, "ruleTestColorspace", "colorspace1", ".*\\.TIF?F$"); + editableBaseConfig->setFileRules(baseFr); + + OCIO::ConfigRcPtr editableInputConfig = inputConfig->createEditableCopy(); + OCIO::FileRulesRcPtr inputFr = OCIO::FileRules::Create(); + inputFr->insertRule(0, "ruleTestColorspace", "colorspace1", ".*\\.TIF?F"); + editableInputConfig->setFileRules(inputFr); + + OCIO::MergeHandlerOptions options = { editableBaseConfig, editableInputConfig, + params, mergedConfig }; + checkForLogOrException(LOG_TYPE_ERROR, __LINE__, + [&options]() { OCIO::FileRulesMerger(options).merge(); }, + std::string(PREFIX) + std::string("file_rules: ruleTestColorspace")); + } + + // Test that an error is thrown when the input config's PATTERN is different. + { + OCIO::ConfigRcPtr editableBaseConfig = baseConfig->createEditableCopy(); + OCIO::FileRulesRcPtr baseFr = OCIO::FileRules::Create(); + baseFr->insertRule(0, "ruleTestPattern", "colorspace1", "*abc*", "*"); + editableBaseConfig->setFileRules(baseFr); + + OCIO::ConfigRcPtr editableInputConfig = inputConfig->createEditableCopy(); + OCIO::FileRulesRcPtr inputFr = OCIO::FileRules::Create(); + inputFr->insertRule(0, "ruleTestPattern", "colorspace1", "*abcd*", "*"); + editableInputConfig->setFileRules(inputFr); + + OCIO::MergeHandlerOptions options = { editableBaseConfig, editableInputConfig, + params, mergedConfig }; + checkForLogOrException(LOG_TYPE_ERROR, __LINE__, + [&options]() { OCIO::FileRulesMerger(options).merge(); }, + std::string(PREFIX) + std::string("file_rules: ruleTestPattern")); + } + + // Test that an error is thrown when the input config's EXTENSION is different. + { + OCIO::ConfigRcPtr editableBaseConfig = baseConfig->createEditableCopy(); + OCIO::FileRulesRcPtr baseFr = OCIO::FileRules::Create(); + baseFr->insertRule(0, "ruleTestExtension", "colorspace1", "*abc*", "*"); + editableBaseConfig->setFileRules(baseFr); + + OCIO::ConfigRcPtr editableInputConfig = inputConfig->createEditableCopy(); + OCIO::FileRulesRcPtr inputFr = OCIO::FileRules::Create(); + inputFr->insertRule(0, "ruleTestExtension", "colorspace1", "*abc*", "*a"); + editableInputConfig->setFileRules(inputFr); + + OCIO::MergeHandlerOptions options = { editableBaseConfig, editableInputConfig, + params, mergedConfig }; + checkForLogOrException(LOG_TYPE_ERROR, __LINE__, + [&options]() { OCIO::FileRulesMerger(options).merge(); }, + std::string(PREFIX) + std::string("file_rules: ruleTestExtension")); + } + + // Test that an error is thrown when the input config's CUSTOM KEYS are different. + { + OCIO::ConfigRcPtr editableBaseConfig = baseConfig->createEditableCopy(); + OCIO::FileRulesRcPtr baseFr = OCIO::FileRules::Create(); + baseFr->insertRule(0, "ruleTestCustomKeys", "colorspace1", "*abc*", "*"); + baseFr->setCustomKey(0, "key1", "value1"); + baseFr->setCustomKey(0, "key2", "value2"); + editableBaseConfig->setFileRules(baseFr); + + OCIO::ConfigRcPtr editableInputConfig = inputConfig->createEditableCopy(); + OCIO::FileRulesRcPtr inputFr = OCIO::FileRules::Create(); + inputFr->insertRule(0, "ruleTestCustomKeys", "colorspace1", "*abc*", "*"); + inputFr->setCustomKey(0, "key1", "value1"); + inputFr->setCustomKey(0, "key2", "value22"); + editableInputConfig->setFileRules(inputFr); + + OCIO::MergeHandlerOptions options = { editableBaseConfig, editableInputConfig, + params, mergedConfig }; + checkForLogOrException(LOG_TYPE_ERROR, __LINE__, + [&options]() { OCIO::FileRulesMerger(options).merge(); }, + std::string(PREFIX) + std::string("file_rules: ruleTestCustomKeys")); + } + + // Test that no error is thrown when the input config's CUSTOM KEYS are the same. + { + OCIO::ConfigRcPtr editableBaseConfig = baseConfig->createEditableCopy(); + OCIO::FileRulesRcPtr baseFr = OCIO::FileRules::Create(); + baseFr->insertRule(0, "ruleTestCustomKeys", "colorspace1", "*abc*", "*"); + baseFr->setCustomKey(0, "key1", "value1"); + baseFr->setCustomKey(0, "key2", "value2"); + editableBaseConfig->setFileRules(baseFr); + + OCIO::ConfigRcPtr editableInputConfig = inputConfig->createEditableCopy(); + OCIO::FileRulesRcPtr inputFr = OCIO::FileRules::Create(); + inputFr->insertRule(0, "ruleTestCustomKeys", "colorspace1", "*abc*", "*"); + inputFr->setCustomKey(0, "key2", "value2"); + inputFr->setCustomKey(0, "key1", "value1"); // must be equal even in a different order + editableInputConfig->setFileRules(inputFr); + + OCIO::MergeHandlerOptions options = { editableBaseConfig, editableInputConfig, + params, mergedConfig }; + OCIO_CHECK_NO_THROW(OCIO::FileRulesMerger(options).merge()); + } + } +} + +OCIO_ADD_TEST(MergeConfigs, displays_views_section) +{ + OCIO::ConstConfigRcPtr baseConfig; + OCIO_CHECK_NO_THROW(baseConfig = getBaseConfig()); + + OCIO::ConstConfigRcPtr inputConfig; + OCIO_CHECK_NO_THROW(inputConfig = getInputConfig()); + + auto setupDisplaysViews = [&baseConfig, &inputConfig] + (OCIO::ConfigMergerRcPtr & merger, + OCIO::ConfigRcPtr mergedConfig, + MergeStrategy strategy, + std::function cb) + { + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + merger->addParams(params); + merger->getParams(0)->setDisplayViews(strategy); + + if (cb) + { + cb(merger); + } + + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::DisplayViewMerger(options).merge(); + }; + + // Allowed strategies: All + // Allowed merge options: All + + // Test that the default strategy is used as a fallback if the section strategy was not defined. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + setupDisplaysViews(merger, + mergedConfig, + // Using STRATEGY_UNSET as this simulate that the section + // is missing from the OCIOM file. + MergeStrategy::STRATEGY_UNSET, + [](OCIO::ConfigMergerRcPtr & merger) + { + // Simulate settings from OCIOM file. + merger->getParams(0)->setDefaultStrategy(MergeStrategy::STRATEGY_INPUT_ONLY); + merger->getParams(0)->setInputFirst(true); + }); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_1, DISP_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), + "SHARED_1, SHARED_3, VIEW_1, VIEW_3"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "Un-tone-mapped-2"); + + // Validate shared_views + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, nullptr), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 0)), "SHARED_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 1)), "SHARED_3"); + + // Validate displays + OCIO_CHECK_EQUAL(mergedConfig->getNumDisplaysAll(), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplay(0)), "DISP_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplay(1)), "DISP_3"); + + // Validate display/views + + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "DISP_1"), 1); + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, "DISP_1"), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED,"DISP_1", 0)), "VIEW_1"); + // Make sure this is the right VIEW_1 by checking the colorspace. + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "VIEW_1")), "view_1B"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED,"DISP_1", 0)), "SHARED_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "SHARED_3")), "log_3"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED,"DISP_1", 1)), "SHARED_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "SHARED_1")), "lin_3"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3"), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3", 0)), "VIEW_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3", 1)), "VIEW_3"); + + // Validate view_transforms + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped-2"); + + // Validate viewing_rules + OCIO::ConstViewingRulesRcPtr rules = mergedConfig->getViewingRules(); + + OCIO_CHECK_EQUAL(rules->getNumEntries(), 2); + + OCIO_CHECK_EQUAL(std::string(rules->getName(0)), "RULE_1"); + OCIO_CHECK_EQUAL(rules->getNumColorSpaces(0), 1); + OCIO_CHECK_EQUAL(std::string(rules->getColorSpace(0, 0)), "sRGB - Texture"); + + OCIO_CHECK_EQUAL(std::string(rules->getName(1)), "RULE_3"); + OCIO_CHECK_EQUAL(rules->getNumColorSpaces(1), 2); + OCIO_CHECK_EQUAL(std::string(rules->getColorSpace(1, 0)), "Linear Rec.2020"); + OCIO_CHECK_EQUAL(std::string(rules->getColorSpace(1, 1)), "ACEScct - SomeOtherName"); + + // Validate virtual_display + OCIO_CHECK_EQUAL(mergedConfig->getVirtualDisplayNumViews(OCIO::VIEW_DISPLAY_DEFINED), 2); + OCIO_CHECK_EQUAL(mergedConfig->getVirtualDisplayNumViews(OCIO::VIEW_SHARED), 1); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_DISPLAY_DEFINED, 0)), "ACES"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_DISPLAY_DEFINED, 1)), "Lin"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_SHARED, 0)), "SHARED_3"); + } + + // Test display/views with strategy = PreferInput, options InputFirst = true. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + + setupDisplaysViews(merger, + mergedConfig, + MergeStrategy::STRATEGY_PREFER_INPUT, + [](OCIO::ConfigMergerRcPtr & merger) + { + merger->getParams(0)->setInputFirst(true); + }); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_1, DISP_3, DISP_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), + "SHARED_1, SHARED_3, VIEW_1, VIEW_3, SHARED_2, VIEW_2"); + + // Validate default_view_transform + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "Un-tone-mapped-2"); + + // Validate shared_views + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, nullptr), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 0)), "SHARED_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 1)), "SHARED_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 2)), "SHARED_2"); + + // Validate displays + OCIO_CHECK_EQUAL(mergedConfig->getNumDisplaysAll(), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplay(0)), "DISP_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplay(1)), "DISP_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplay(2)), "DISP_2"); + + // Validate display/views + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "DISP_1"), 1); + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, "DISP_1"), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED,"DISP_1", 0)), "VIEW_1"); + // Make sure this is the right VIEW_1 by checking the colorspace. + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "VIEW_1")), "view_1B"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewRule("DISP_1", "VIEW_1")), "RULE_3"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED,"DISP_1", 0)), "SHARED_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "SHARED_3")), "log_3"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED,"DISP_1", 1)), "SHARED_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "SHARED_1")), "lin_3"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED,"DISP_1", 2)), "SHARED_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "SHARED_2")), ""); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewTransformName("DISP_1", "SHARED_2")), "SDR Video"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3"), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3", 0)), "VIEW_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3", 1)), "VIEW_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewLooks("DISP_3", "VIEW_3")), "look_input"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2"), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2", 0)), "VIEW_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2", 1)), "VIEW_2"); + + // Validate view_transforms + + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); + OCIO::ConstTransformRcPtr tf; + OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") + ->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE)); + auto bi = OCIO_DYNAMIC_POINTER_CAST(tf); + OCIO_REQUIRE_ASSERT(bi); + OCIO_CHECK_EQUAL(std::string(bi->getStyle()), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped-2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), "Un-tone-mapped"); + + // Validate viewing_rules + OCIO::ConstViewingRulesRcPtr rules = mergedConfig->getViewingRules(); + + OCIO_CHECK_EQUAL(rules->getNumEntries(), 3); + + OCIO_CHECK_EQUAL(std::string(rules->getName(0)), "RULE_1"); + OCIO_CHECK_EQUAL(rules->getNumColorSpaces(0), 1); + OCIO_CHECK_EQUAL(std::string(rules->getColorSpace(0, 0)), "sRGB - Texture"); + + OCIO_CHECK_EQUAL(std::string(rules->getName(1)), "RULE_3"); + OCIO_CHECK_EQUAL(rules->getNumColorSpaces(1), 2); + OCIO_CHECK_EQUAL(std::string(rules->getColorSpace(1, 0)), "Linear Rec.2020"); + OCIO_CHECK_EQUAL(std::string(rules->getColorSpace(1, 1)), "ACEScct - SomeOtherName"); + + OCIO_CHECK_EQUAL(std::string(rules->getName(2)), "RULE_2"); + OCIO_CHECK_EQUAL(rules->getNumEncodings(2), 1); + OCIO_CHECK_EQUAL(std::string(rules->getEncoding(2, 0)), "scene-linear"); + + // Validate virtual_display + OCIO_CHECK_EQUAL(mergedConfig->getVirtualDisplayNumViews(OCIO::VIEW_DISPLAY_DEFINED), 3); + OCIO_CHECK_EQUAL(mergedConfig->getVirtualDisplayNumViews(OCIO::VIEW_SHARED), 2); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_DISPLAY_DEFINED, 0)), "ACES"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_DISPLAY_DEFINED, 1)), "Lin"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_DISPLAY_DEFINED, 2)), "Log"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_SHARED, 0)), "SHARED_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_SHARED, 1)), "SHARED_1"); + } + + // Test display/views with strategy=PreferInput, options InputFirst = false. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + setupDisplaysViews(merger, + mergedConfig, + MergeStrategy::STRATEGY_PREFER_INPUT, + [](OCIO::ConfigMergerRcPtr & merger) + { + merger->getParams(0)->setInputFirst(false); + }); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_1, DISP_2, DISP_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), + "SHARED_1, SHARED_2, VIEW_1, VIEW_2, SHARED_3, VIEW_3"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "Un-tone-mapped-2"); + + // Validate shared_views + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, nullptr), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 0)), "SHARED_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 1)), "SHARED_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 2)), "SHARED_3"); + + // Validate displays + OCIO_CHECK_EQUAL(mergedConfig->getNumDisplaysAll(), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplay(0)), "DISP_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplay(1)), "DISP_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplay(2)), "DISP_3"); + + // Validate display/views + + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "DISP_1"), 1); + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, "DISP_1"), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED,"DISP_1", 0)), "VIEW_1"); + // Make sure this is the right VIEW_1 by checking the colorspace. + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "VIEW_1")), "view_1B"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewRule("DISP_1", "VIEW_1")), "RULE_3"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED,"DISP_1", 0)), "SHARED_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "SHARED_1")), "lin_3"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED,"DISP_1", 1)), "SHARED_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "SHARED_2")), ""); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewTransformName("DISP_1", "SHARED_2")), "SDR Video"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED,"DISP_1", 2)), "SHARED_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "SHARED_3")), "log_3"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2"), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2", 0)), "VIEW_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2", 1)), "VIEW_2"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3"), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3", 0)), "VIEW_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3", 1)), "VIEW_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewLooks("DISP_3", "VIEW_3")), "look_input"); + + // Validate view_transforms + + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), std::string("SDR Video")); + OCIO::ConstTransformRcPtr tf; + OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") + ->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE)); + auto bi = OCIO_DYNAMIC_POINTER_CAST(tf); + OCIO_REQUIRE_ASSERT(bi); + OCIO_CHECK_EQUAL(std::string(bi->getStyle()), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), std::string("Un-tone-mapped")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), std::string("Un-tone-mapped-2")); + + // Validate viewing_rules + OCIO::ConstViewingRulesRcPtr rules = mergedConfig->getViewingRules(); + + OCIO_CHECK_EQUAL(rules->getNumEntries(), 3); + + OCIO_CHECK_EQUAL(std::string(rules->getName(0)), "RULE_1"); + OCIO_CHECK_EQUAL(rules->getNumColorSpaces(0), 1); + OCIO_CHECK_EQUAL(std::string(rules->getColorSpace(0, 0)), "sRGB - Texture"); + + OCIO_CHECK_EQUAL(std::string(rules->getName(1)), "RULE_2"); + OCIO_CHECK_EQUAL(rules->getNumEncodings(1), 1); + OCIO_CHECK_EQUAL(std::string(rules->getEncoding(1, 0)), "scene-linear"); + + OCIO_CHECK_EQUAL(std::string(rules->getName(2)), "RULE_3"); + OCIO_CHECK_EQUAL(rules->getNumColorSpaces(2), 2); + OCIO_CHECK_EQUAL(std::string(rules->getColorSpace(2, 0)), "Linear Rec.2020"); + OCIO_CHECK_EQUAL(std::string(rules->getColorSpace(2, 1)), "ACEScct - SomeOtherName"); + + // Validate virtual_display + OCIO_CHECK_EQUAL(mergedConfig->getVirtualDisplayNumViews(OCIO::VIEW_DISPLAY_DEFINED), 3); + OCIO_CHECK_EQUAL(mergedConfig->getVirtualDisplayNumViews(OCIO::VIEW_SHARED), 2); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_DISPLAY_DEFINED, 0)), "ACES"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_DISPLAY_DEFINED, 1)), "Log"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_DISPLAY_DEFINED, 2)), "Lin"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_SHARED, 0)), "SHARED_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_SHARED, 1)), "SHARED_3"); + } + + // Test display/views with strategy = PreferBase, options InputFirst = true. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + setupDisplaysViews(merger, + mergedConfig, + MergeStrategy::STRATEGY_PREFER_BASE, + [](OCIO::ConfigMergerRcPtr & merger) + { + merger->getParams(0)->setInputFirst(true); + }); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_1, DISP_3, DISP_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), + "SHARED_1, SHARED_3, VIEW_1, VIEW_3, SHARED_2, VIEW_2"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "SDR Video"); + + // Validate shared_views + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, nullptr), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 0)), "SHARED_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 1)), "SHARED_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 2)), "SHARED_2"); + + // Validate displays + OCIO_CHECK_EQUAL(mergedConfig->getNumDisplaysAll(), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplay(0)), "DISP_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplay(1)), "DISP_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplay(2)), "DISP_2"); + + // Validate display/views + + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "DISP_1"), 1); + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, "DISP_1"), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED,"DISP_1", 0)), "VIEW_1"); + // Make sure this is the right VIEW_1 by checking the colorspace. + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "VIEW_1")), "view_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewRule("DISP_1", "VIEW_1")), "RULE_1"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED,"DISP_1", 0)), "SHARED_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "SHARED_3")), "log_3"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED,"DISP_1", 1)), "SHARED_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "SHARED_1")), "lin_1"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED,"DISP_1", 2)), "SHARED_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "SHARED_2")), ""); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewTransformName("DISP_1", "SHARED_2")), "SDR Video"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3"), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3", 0)), "VIEW_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3", 1)), "VIEW_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewLooks("DISP_3", "VIEW_3")), "look_input"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2"), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2", 0)), "VIEW_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewRule("DISP_2", "VIEW_1")), "RULE_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2", 1)), "VIEW_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewLooks("DISP_2", "VIEW_2")), "look_base"); + + // Validate view_transforms + + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); + OCIO::ConstTransformRcPtr tf; + OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") + ->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE)); + auto bi = OCIO_DYNAMIC_POINTER_CAST(tf); + OCIO_REQUIRE_ASSERT(bi); + OCIO_CHECK_EQUAL(std::string(bi->getStyle()), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO_1.0"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped-2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), "Un-tone-mapped"); + + // Validate viewing_rules + OCIO::ConstViewingRulesRcPtr rules = mergedConfig->getViewingRules(); + + OCIO_CHECK_EQUAL(rules->getNumEntries(), 3); + + OCIO_CHECK_EQUAL(std::string(rules->getName(0)), "RULE_1"); + OCIO_CHECK_EQUAL(rules->getNumColorSpaces(0), 1); + OCIO_CHECK_EQUAL(std::string(rules->getColorSpace(0, 0)), "Gamma 2.2 AP1 - Texture"); + + OCIO_CHECK_EQUAL(std::string(rules->getName(1)), "RULE_3"); + OCIO_CHECK_EQUAL(rules->getNumColorSpaces(1), 2); + OCIO_CHECK_EQUAL(std::string(rules->getColorSpace(1, 0)), "Linear Rec.2020"); + OCIO_CHECK_EQUAL(std::string(rules->getColorSpace(1, 1)), "ACEScct - SomeOtherName"); + + OCIO_CHECK_EQUAL(std::string(rules->getName(2)), "RULE_2"); + OCIO_CHECK_EQUAL(rules->getNumEncodings(2), 1); + OCIO_CHECK_EQUAL(std::string(rules->getEncoding(2, 0)), "scene-linear"); + + // Validate virtual_display + OCIO_CHECK_EQUAL(mergedConfig->getVirtualDisplayNumViews(OCIO::VIEW_DISPLAY_DEFINED), 3); + OCIO_CHECK_EQUAL(mergedConfig->getVirtualDisplayNumViews(OCIO::VIEW_SHARED), 2); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_DISPLAY_DEFINED, 0)), "ACES"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_DISPLAY_DEFINED, 1)), "Lin"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_DISPLAY_DEFINED, 2)), "Log"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_SHARED, 0)), "SHARED_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_SHARED, 1)), "SHARED_1"); + } + + // Test display/views with strategy = PreferBase, options InputFirst = false. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + setupDisplaysViews(merger, + mergedConfig, + MergeStrategy::STRATEGY_PREFER_BASE, + [](OCIO::ConfigMergerRcPtr & merger) + { + merger->getParams(0)->setInputFirst(false); + }); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_1, DISP_2, DISP_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), + "SHARED_1, SHARED_2, VIEW_1, VIEW_2, SHARED_3, VIEW_3"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "SDR Video"); + + // Validate shared_views + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, nullptr), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 0)), "SHARED_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 1)), "SHARED_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 2)), "SHARED_3"); + + // Validate displays + OCIO_CHECK_EQUAL(mergedConfig->getNumDisplaysAll(), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplay(0)), "DISP_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplay(1)), "DISP_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplay(2)), "DISP_3"); + + // Validate display/views + + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "DISP_1"), 1); + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, "DISP_1"), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED,"DISP_1", 0)), "VIEW_1"); + // Make sure this is the right VIEW_1 by checking the colorspace. + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "VIEW_1")), "view_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewRule("DISP_1", "VIEW_1")), "RULE_1"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED,"DISP_1", 0)), "SHARED_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "SHARED_1")), "lin_1"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED,"DISP_1", 1)), "SHARED_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "SHARED_2")), ""); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewTransformName("DISP_1", "SHARED_2")), "SDR Video"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED,"DISP_1", 2)), "SHARED_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "SHARED_3")), "log_3"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2"), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2", 0)), "VIEW_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewRule("DISP_2", "VIEW_1")), "RULE_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2", 1)), "VIEW_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewLooks("DISP_2", "VIEW_2")), "look_base"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3"), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3", 0)), "VIEW_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3", 1)), "VIEW_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewLooks("DISP_3", "VIEW_3")), "look_input"); + + // Validate view_transforms + + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); + OCIO::ConstTransformRcPtr tf; + OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") + ->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE)); + auto bi = OCIO_DYNAMIC_POINTER_CAST(tf); + OCIO_REQUIRE_ASSERT(bi); + OCIO_CHECK_EQUAL(std::string(bi->getStyle()), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO_1.0"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), "Un-tone-mapped-2"); + + // Validate viewing_rules + OCIO::ConstViewingRulesRcPtr rules = mergedConfig->getViewingRules(); + + OCIO_CHECK_EQUAL(rules->getNumEntries(), 3); + + OCIO_CHECK_EQUAL(std::string(rules->getName(0)), "RULE_1"); + OCIO_CHECK_EQUAL(rules->getNumColorSpaces(0), 1); + OCIO_CHECK_EQUAL(std::string(rules->getColorSpace(0, 0)), "Gamma 2.2 AP1 - Texture"); + + OCIO_CHECK_EQUAL(std::string(rules->getName(1)), "RULE_2"); + OCIO_CHECK_EQUAL(rules->getNumEncodings(1), 1); + OCIO_CHECK_EQUAL(std::string(rules->getEncoding(1, 0)), "scene-linear"); + + OCIO_CHECK_EQUAL(std::string(rules->getName(2)), "RULE_3"); + OCIO_CHECK_EQUAL(rules->getNumColorSpaces(2), 2); + OCIO_CHECK_EQUAL(std::string(rules->getColorSpace(2, 0)), "Linear Rec.2020"); + OCIO_CHECK_EQUAL(std::string(rules->getColorSpace(2, 1)), "ACEScct - SomeOtherName"); + + // Validate virtual_display + OCIO_CHECK_EQUAL(mergedConfig->getVirtualDisplayNumViews(OCIO::VIEW_DISPLAY_DEFINED), 3); + OCIO_CHECK_EQUAL(mergedConfig->getVirtualDisplayNumViews(OCIO::VIEW_SHARED), 2); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_DISPLAY_DEFINED, 0)), "ACES"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_DISPLAY_DEFINED, 1)), "Log"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_DISPLAY_DEFINED, 2)), "Lin"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_SHARED, 0)), "SHARED_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_SHARED, 1)), "SHARED_3"); + } + + // Test display/views with strategy = BaseOnly. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + setupDisplaysViews(merger, + mergedConfig, + MergeStrategy::STRATEGY_BASE_ONLY, + nullptr); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_1, DISP_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), + "SHARED_1, SHARED_2, VIEW_1, VIEW_2"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "SDR Video"); + + // Validate shared_views + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, nullptr), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 0)), "SHARED_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 1)), "SHARED_2"); + + // Validate displays + OCIO_CHECK_EQUAL(mergedConfig->getNumDisplaysAll(), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplay(0)), "DISP_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplay(1)), "DISP_2"); + + // Validate display/views + + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "DISP_1"), 1); + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, "DISP_1"), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED,"DISP_1", 0)), "VIEW_1"); + // Make sure this is the right VIEW_1 by checking the colorspace. + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "VIEW_1")), "view_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewRule("DISP_1", "VIEW_1")), "RULE_1"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED,"DISP_1", 0)), "SHARED_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "SHARED_1")), "lin_1"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED,"DISP_1", 1)), "SHARED_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "SHARED_2")), ""); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewTransformName("DISP_1", "SHARED_2")), "SDR Video"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2"), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2", 0)), "VIEW_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewRule("DISP_2", "VIEW_1")), "RULE_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2", 1)), "VIEW_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewLooks("DISP_2", "VIEW_2")), "look_base"); + + // Validate view_transforms + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped"); + + // Validate viewing_rules + OCIO::ConstViewingRulesRcPtr rules = mergedConfig->getViewingRules(); + + OCIO_CHECK_EQUAL(rules->getNumEntries(), 2); + + OCIO_CHECK_EQUAL(std::string(rules->getName(0)), "RULE_1"); + OCIO_CHECK_EQUAL(rules->getNumColorSpaces(0), 1); + OCIO_CHECK_EQUAL(std::string(rules->getColorSpace(0, 0)), "Gamma 2.2 AP1 - Texture"); + + OCIO_CHECK_EQUAL(std::string(rules->getName(1)), std::string("RULE_2")); + OCIO_CHECK_EQUAL(rules->getNumEncodings(1), 1); + OCIO_CHECK_EQUAL(std::string(rules->getEncoding(1, 0)), "scene-linear"); + + // Validate virtual_display + OCIO_CHECK_EQUAL(mergedConfig->getVirtualDisplayNumViews(OCIO::VIEW_DISPLAY_DEFINED), 2); + OCIO_CHECK_EQUAL(mergedConfig->getVirtualDisplayNumViews(OCIO::VIEW_SHARED), 1); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_DISPLAY_DEFINED, 0)), "ACES"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_DISPLAY_DEFINED, 1)), "Log"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_SHARED, 0)), "SHARED_1"); + } + + // Test display/views with strategy = InputOnly. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + setupDisplaysViews(merger, + mergedConfig, + MergeStrategy::STRATEGY_INPUT_ONLY, + nullptr); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_1, DISP_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), + "SHARED_1, SHARED_3, VIEW_1, VIEW_3"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "Un-tone-mapped-2"); + + // Validate shared_views + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, nullptr), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 0)), "SHARED_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 1)), "SHARED_3"); + + // Validate displays + OCIO_CHECK_EQUAL(mergedConfig->getNumDisplaysAll(), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplay(0)), "DISP_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplay(1)), "DISP_3"); + + // Validate display/views + + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "DISP_1"), 1); + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, "DISP_1"), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED,"DISP_1", 0)), "VIEW_1"); + // Make sure this is the right VIEW_1 by checking the colorspace. + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "VIEW_1")), "view_1B"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewRule("DISP_1", "VIEW_1")), "RULE_3"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED,"DISP_1", 0)), "SHARED_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "SHARED_3")), "log_3"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED,"DISP_1", 1)), "SHARED_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "SHARED_1")), "lin_3"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3"), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3", 0)), "VIEW_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3", 1)), "VIEW_3"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewLooks("DISP_3", "VIEW_3")), "look_input"); + + // Validate view_transforms + + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); + OCIO::ConstTransformRcPtr tf; + OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") + ->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE)); + auto bi = OCIO_DYNAMIC_POINTER_CAST(tf); + OCIO_REQUIRE_ASSERT(bi); + OCIO_CHECK_EQUAL(std::string(bi->getStyle()), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped-2"); + + // Validate viewing_rules + OCIO::ConstViewingRulesRcPtr rules = mergedConfig->getViewingRules(); + + OCIO_CHECK_EQUAL(rules->getNumEntries(), 2); + + OCIO_CHECK_EQUAL(std::string(rules->getName(0)), "RULE_1"); + OCIO_CHECK_EQUAL(rules->getNumColorSpaces(0), 1); + OCIO_CHECK_EQUAL(std::string(rules->getColorSpace(0, 0)), "sRGB - Texture"); + + OCIO_CHECK_EQUAL(std::string(rules->getName(1)), "RULE_3"); + OCIO_CHECK_EQUAL(rules->getNumColorSpaces(1), 2); + OCIO_CHECK_EQUAL(std::string(rules->getColorSpace(1, 0)), "Linear Rec.2020"); + OCIO_CHECK_EQUAL(std::string(rules->getColorSpace(1, 1)), "ACEScct - SomeOtherName"); + + // Validate virtual_display + OCIO_CHECK_EQUAL(mergedConfig->getVirtualDisplayNumViews(OCIO::VIEW_DISPLAY_DEFINED), 2); + OCIO_CHECK_EQUAL(mergedConfig->getVirtualDisplayNumViews(OCIO::VIEW_SHARED), 1); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_DISPLAY_DEFINED, 0)), "ACES"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_DISPLAY_DEFINED, 1)), "Lin"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getVirtualDisplayView(OCIO::VIEW_SHARED, 0)), "SHARED_3"); + } + + // Test display/views with strategy = Remove + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + setupDisplaysViews(merger, + mergedConfig, + MergeStrategy::STRATEGY_REMOVE, + nullptr); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), "SHARED_2, VIEW_2"); + + // Note that the "SDR Video" view transform was removed, so the "SDR Video" value + // of the default view transform was reset to empty (will use the first one by default). + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), ""); + + // Validate shared_views + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, nullptr), 1); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 0)), "SHARED_2"); + + // Validate displays + OCIO_CHECK_EQUAL(mergedConfig->getNumDisplaysAll(), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayAll(0)), "DISP_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayAll(1)), "DISP_2"); + + // Validate display/views + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "DISP_1"), 0); + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, "DISP_1"), 1); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED,"DISP_1", 0)), "SHARED_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewColorSpaceName("DISP_1", "SHARED_2")), ""); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewTransformName("DISP_1", "SHARED_2")), "SDR Video"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2"), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2", 0)), "VIEW_1"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewRule("DISP_2", "VIEW_1")), "RULE_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2", 1)), "VIEW_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewLooks("DISP_2", "VIEW_2")), "look_base"); + + // Validate view_transforms + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 1); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), std::string("Un-tone-mapped")); + + // Validate viewing_rules + OCIO::ConstViewingRulesRcPtr rules = mergedConfig->getViewingRules(); + OCIO_CHECK_EQUAL(rules->getNumEntries(), 1); + OCIO_CHECK_EQUAL(std::string(rules->getName(0)), std::string("RULE_2")); + OCIO_CHECK_EQUAL(rules->getNumEncodings(0), 1); + OCIO_CHECK_EQUAL(std::string(rules->getEncoding(0, 0)), "scene-linear"); + + // Validate virtual_display + OCIO_CHECK_EQUAL(mergedConfig->getVirtualDisplayNumViews(OCIO::VIEW_DISPLAY_DEFINED), 1); + OCIO_CHECK_EQUAL(mergedConfig->getVirtualDisplayNumViews(OCIO::VIEW_SHARED), 1); + + OCIO_CHECK_EQUAL(mergedConfig->getVirtualDisplayView(OCIO::VIEW_DISPLAY_DEFINED, 0), std::string("Log")); + OCIO_CHECK_EQUAL(mergedConfig->getVirtualDisplayView(OCIO::VIEW_SHARED, 0), std::string("SHARED_1")); + } + + // Test that error_on_conflicts is processed correctly. + // strategy = PreferInput, InputFirst = false + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + merger->addParams(params); + merger->getParams(0)->setDisplayViews(MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + merger->getParams(0)->setErrorOnConflict(true); + + // Test that an error is thrown when the input config's COLORSPACE is different + { + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_ERROR, __LINE__, + [&options]() { OCIO::DisplayViewMerger(options).merge(); }, + std::string(PREFIX) + std::string("shared_views: SHARED_1"), + std::string(PREFIX) + std::string("display: DISP_1, views: VIEW_1"), + std::string(PREFIX) + std::string("default_view_transform: SDR Video"), + std::string(PREFIX) + std::string("view_transforms: SDR Video"), + std::string(PREFIX) + std::string("viewing_rules: RULE_1"), + std::string(PREFIX) + std::string("virtual_display: ACES")); + } + } +} + +OCIO_ADD_TEST(MergeConfigs, colorspaces_section) +{ + OCIO::ConstConfigRcPtr baseConfig; + OCIO_CHECK_NO_THROW(baseConfig = getConfig("base_colorspaces_config.yaml")); + + OCIO::ConstConfigRcPtr inputConfig; + OCIO_CHECK_NO_THROW(inputConfig = getConfig("input_colorspaces_config.yaml")); + + auto setupBasics = [](OCIO::ConfigMergerRcPtr & merger, MergeStrategy strategy) -> OCIO::ConfigMergingParametersRcPtr + { + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + merger->addParams(params); + merger->getParams(0)->setColorspaces(strategy); + merger->getParams(0)->setDefaultStrategy(strategy); + + merger->getParams(0)->setInputFamilyPrefix("Input/"); + merger->getParams(0)->setBaseFamilyPrefix("Base/"); + + merger->getParams(0)->setAssumeCommonReferenceSpace(true); + merger->getParams(0)->setAvoidDuplicates(false); + + return params; + }; + + // Test that the default strategy is used as a fallback if the section strategy was not defined. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + + // Using STRATEGY_UNSET as this simulates that the section is missing from the OCIOM file. + auto params = setupBasics(merger, MergeStrategy::STRATEGY_UNSET); + // Simulate settings from OCIOM file. + merger->getParams(0)->setDefaultStrategy(MergeStrategy::STRATEGY_INPUT_ONLY); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + + OCIO_CHECK_EQUAL(mergedConfig->getFamilySeparator(), '~'); + + std::vector expectedNames = { "test", "test3" }; + std::vector expectedValues = { "differentValue", "value3" }; + compareEnvironmentVar(mergedConfig, expectedNames, expectedValues, __LINE__); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getSearchPath()), std::string(".:def")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getInactiveColorSpaces()), "ACES2065-1, sRGB - Display"); + } + + // Test Colorspaces with strategy = PreferInput, options InputFirst = true. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Color space 'sRGB - Display' will replace a color space in the base config", + "Color space 'look' will replace a color space in the base config", + "Merged color space 'look' has a different reference space type than the color space it's replacing", + "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", + "The name of merged color space 'sRGB' has a conflict with an alias in color space 'sRGB - Texture'"); + + OCIO_CHECK_EQUAL(mergedConfig->getFamilySeparator(), '~'); + + // Note that the environment vars are always written in alphabetical order, + // so the InputFirst directive doesn't apply to this specific element. + std::vector expectedNames = { "test", "test1", "test3" }; + std::vector expectedValues = { "differentValue", "value1", "value3" }; + compareEnvironmentVar(mergedConfig, expectedNames, expectedValues, __LINE__); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getSearchPath()), std::string(".:def:abc")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getInactiveColorSpaces()), "ACES2065-1, sRGB - Display, sRGB - Texture, ACEScg"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 6); + OCIO::ConstColorSpaceRcPtr cs = nullptr; + + // Display colorspaces. + + cs = checkColorSpace(mergedConfig, "sRGB - Display", 0, OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("srgb_display")); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Input~Display~Standard")); + OCIO_CHECK_EQUAL(cs->getDescription(), std::string("from input")); + + cs = checkColorSpace(mergedConfig, "look", 1, OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("look1")); + OCIO_CHECK_EQUAL(cs->getDescription(), std::string("from input")); + + // Scene colorspaces. + + cs = checkColorSpace(mergedConfig, "ACES2065-1", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("aces")); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Input~ACES~Linear")); + + cs = checkColorSpace(mergedConfig, "sRGB", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("my_srgb")); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Input~Texture~")); + + cs = checkColorSpace(mergedConfig, "ACEScg", 2, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 0); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Base~ACES~Linear")); + + cs = checkColorSpace(mergedConfig, "sRGB - Texture", 3, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + // Note "srgb" is removed as an alias since it is a color space name in the input config. + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("srgb_tx")); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Base~Texture")); + OCIO_CHECK_EQUAL(cs->getDescription(), std::string("from base")); + + // Note that the "look" scene color space is not merged since there is already a display color space + // with that name. + } + + // Test Colorspaces with strategy=PreferInput, options InputFirst = false. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Color space 'sRGB - Display' will replace a color space in the base config", + "Color space 'look' will replace a color space in the base config", + "Merged color space 'look' has a different reference space type than the color space it's replacing", + "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", + "The name of merged color space 'sRGB' has a conflict with an alias in color space 'sRGB - Texture'"); + + OCIO_CHECK_EQUAL(mergedConfig->getFamilySeparator(), '~'); + + std::vector expectedNames = { "test", "test1", "test3" }; + std::vector expectedValues = { "differentValue", "value1", "value3" }; + compareEnvironmentVar(mergedConfig, expectedNames, expectedValues, __LINE__); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getSearchPath()), std::string(".:abc:def")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getInactiveColorSpaces()), "sRGB - Texture, sRGB - Display, ACEScg, ACES2065-1"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 6); + OCIO::ConstColorSpaceRcPtr cs = nullptr; + + // Display colorspaces. + + cs = checkColorSpace(mergedConfig, "sRGB - Display", 0, OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, __LINE__); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("srgb_display")); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Input~Display~Standard")); + OCIO_CHECK_EQUAL(cs->getDescription(), std::string("from input")); + + cs = checkColorSpace(mergedConfig, "look", 1, OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, __LINE__); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("look1")); + OCIO_CHECK_EQUAL(cs->getDescription(), std::string("from input")); + + // Scene colorspaces. + + cs = checkColorSpace(mergedConfig, "ACEScg", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 0); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Base~ACES~Linear")); + + cs = checkColorSpace(mergedConfig, "sRGB - Texture", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("srgb_tx")); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Base~Texture")); + OCIO_CHECK_EQUAL(cs->getDescription(), std::string("from base")); + + cs = checkColorSpace(mergedConfig, "ACES2065-1", 2, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("aces")); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Input~ACES~Linear")); + + cs = checkColorSpace(mergedConfig, "sRGB", 3, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("my_srgb")); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Input~Texture~")); + } + + // Test Colorspaces with strategy = PreferBase, options InputFirst = true. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Color space 'sRGB - Display' was not merged as it's already present in the base config", + "Color space 'look' was not merged as it's already present in the base config", + "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", + "Color space 'sRGB' was not merged as it conflicts with an alias in color space 'sRGB - Texture'"); + + OCIO_CHECK_EQUAL(mergedConfig->getFamilySeparator(), '#'); + + std::vector expectedNames = { "test", "test1", "test3" }; + std::vector expectedValues = { "value", "value1", "value3" }; + compareEnvironmentVar(mergedConfig, expectedNames, expectedValues, __LINE__); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getSearchPath()), std::string(".:def:abc")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getInactiveColorSpaces()), "ACES2065-1, sRGB - Display, sRGB - Texture, ACEScg"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 5); + OCIO::ConstColorSpaceRcPtr cs = nullptr; + + // Display colorspaces. + + cs = checkColorSpace(mergedConfig, "sRGB - Display", 0, OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, __LINE__); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("srgb_display")); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Base#Display#Basic")); + OCIO_CHECK_EQUAL(cs->getDescription(), std::string("from base")); + + // Scene colorspaces. + + cs = checkColorSpace(mergedConfig, "ACES2065-1", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 0); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Input#ACES#Linear")); + OCIO_CHECK_EQUAL(cs->getDescription(), std::string("from input")); + + cs = checkColorSpace(mergedConfig, "ACEScg", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("aces")); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Base#ACES#Linear")); + + cs = checkColorSpace(mergedConfig, "sRGB - Texture", 2, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 2); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("srgb")); + OCIO_CHECK_EQUAL(cs->getAlias(1), std::string("srgb_tx")); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Base#Texture")); + OCIO_CHECK_EQUAL(cs->getDescription(), std::string("from base")); + + cs = checkColorSpace(mergedConfig, "look", 3, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 0); + OCIO_CHECK_EQUAL(cs->getDescription(), std::string("from base")); + } + + // Test Colorspaces with strategy = PreferBase, options InputFirst = false. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Color space 'sRGB - Display' was not merged as it's already present in the base config", + "Color space 'look' was not merged as it's already present in the base config", + "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", + "Color space 'sRGB' was not merged as it conflicts with an alias in color space 'sRGB - Texture'"); + + OCIO_CHECK_EQUAL(mergedConfig->getFamilySeparator(), '#'); + + std::vector expectedNames = { "test", "test1", "test3" }; + std::vector expectedValues = { "value", "value1", "value3" }; + compareEnvironmentVar(mergedConfig, expectedNames, expectedValues, __LINE__); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getSearchPath()), std::string(".:abc:def")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getInactiveColorSpaces()), "sRGB - Texture, sRGB - Display, ACEScg, ACES2065-1"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 5); + OCIO::ConstColorSpaceRcPtr cs = nullptr; + + // Display colorspaces. + + cs = checkColorSpace(mergedConfig, "sRGB - Display", 0, OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, __LINE__); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("srgb_display")); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Base#Display#Basic")); + OCIO_CHECK_EQUAL(cs->getDescription(), std::string("from base")); + + // Scene colorspaces. + + cs = checkColorSpace(mergedConfig, "ACEScg", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("aces")); + + cs = checkColorSpace(mergedConfig, "sRGB - Texture", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 2); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("srgb")); + OCIO_CHECK_EQUAL(cs->getAlias(1), std::string("srgb_tx")); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Base#Texture")); + + cs = checkColorSpace(mergedConfig, "look", 2, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 0); + OCIO_CHECK_EQUAL(cs->getDescription(), std::string("from base")); + + cs = checkColorSpace(mergedConfig, "ACES2065-1", 3, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 0); + } + + // Test Colorspaces with strategy = BaseOnly. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_BASE_ONLY); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + + OCIO_CHECK_EQUAL(mergedConfig->getFamilySeparator(), '#'); + + std::vector expectedNames = { "test", "test1" }; + std::vector expectedValues = { "value", "value1" }; + compareEnvironmentVar(mergedConfig, expectedNames, expectedValues, __LINE__); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getSearchPath()), std::string(".:abc")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getInactiveColorSpaces()), "sRGB - Texture, sRGB - Display, ACEScg"); + + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, + OCIO::COLORSPACE_ALL), 4); + OCIO::ConstColorSpaceRcPtr cs = nullptr; + + cs = checkColorSpace(mergedConfig, "sRGB - Display", 0, OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, __LINE__); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Display#Basic")); + + cs = checkColorSpace(mergedConfig, "ACEScg", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("ACES#Linear")); + + cs = checkColorSpace(mergedConfig, "sRGB - Texture", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Texture")); + + cs = checkColorSpace(mergedConfig, "look", 2, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("")); + } + + // Test Colorspaces with strategy = InputOnly. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_INPUT_ONLY); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + + OCIO_CHECK_EQUAL(mergedConfig->getFamilySeparator(), '~'); + + std::vector expectedNames = { "test", "test3" }; + std::vector expectedValues = { "differentValue", "value3" }; + compareEnvironmentVar(mergedConfig, expectedNames, expectedValues, __LINE__); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getSearchPath()), std::string(".:def")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getInactiveColorSpaces()), "ACES2065-1, sRGB - Display"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, + OCIO::COLORSPACE_ALL), 4); + OCIO::ConstColorSpaceRcPtr cs = nullptr; + + cs = checkColorSpace(mergedConfig, "sRGB - Display", 0, OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, __LINE__); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Display~Standard")); + + cs = checkColorSpace(mergedConfig, "look", 1, OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, __LINE__); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Display~Standard")); + + cs = checkColorSpace(mergedConfig, "ACES2065-1", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("ACES~Linear")); + + cs = checkColorSpace(mergedConfig, "sRGB", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Texture~")); + } + + // Test Colorspaces with strategy = Remove + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_REMOVE); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + + OCIO_CHECK_EQUAL(mergedConfig->getFamilySeparator(), '#'); + + std::vector expectedNames = { "test1" }; + std::vector expectedValues = { "value1" }; + compareEnvironmentVar(mergedConfig, expectedNames, expectedValues, __LINE__); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getSearchPath()), std::string("abc")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getInactiveColorSpaces()), "sRGB - Texture, ACEScg"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, + OCIO::COLORSPACE_ALL), 2); + OCIO::ConstColorSpaceRcPtr cs = nullptr; + + cs = checkColorSpace(mergedConfig, "ACEScg", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("ACES#Linear")); + + cs = checkColorSpace(mergedConfig, "sRGB - Texture", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Texture")); + } +} + +OCIO_ADD_TEST(MergeConfigs, colorspaces_section_common_reference_and_duplicates) +{ + // Base config display ref space: CIE-XYZ-D65, scene ref space: ACES2065-1. + // Input config display ref space: linear Rec.709, scene ref space: linear Rec.709 + // + // Both configs have the role: cie_xyz_d65_interchange: CIE-XYZ-D65 + // but not the aces_interchange role, so heuristics will be used for that. + // + // The merged configs will contain color spaces from the input config where + // the reference space has been converted to that of the base config. + // + // Duplicates are removed, even though they use different reference spaces. + + std::vector pathsBase = { + std::string(OCIO::GetTestFilesDir()), + std::string("configs"), + std::string("mergeconfigs"), + std::string("merged1"), + std::string("base1.ocio") + }; + const std::string basePath = pystring::os::path::normpath(pystring::os::path::join(pathsBase)); + + std::vector pathsInput = { + std::string(OCIO::GetTestFilesDir()), + std::string("configs"), + std::string("mergeconfigs"), + std::string("merged1"), + std::string("input1.ocio") + }; + const std::string inputPath = pystring::os::path::normpath(pystring::os::path::join(pathsInput)); + + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromFile(basePath.c_str()); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromFile(inputPath.c_str()); + + auto setupBasics = [](OCIO::ConfigMergerRcPtr & merger, MergeStrategy strategy) -> OCIO::ConfigMergingParametersRcPtr + { + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + merger->addParams(params); + merger->getParams(0)->setColorspaces(strategy); + merger->getParams(0)->setDefaultStrategy(strategy); + + merger->getParams(0)->setInputFamilyPrefix("Input/"); + merger->getParams(0)->setBaseFamilyPrefix("Base/"); + + merger->getParams(0)->setAssumeCommonReferenceSpace(false); + merger->getParams(0)->setAvoidDuplicates(true); + + return params; + }; + + // PreferInput, Input first. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(true); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, + OCIO::COLORSPACE_ALL), 7); + + // Display-referred spaces. + { + auto cs = checkColorSpace(mergedConfig, "sRGB - Display", 0, OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + // Check for alias srgb_display (added from base config). + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("srgb_display")); + OCIO_CHECK_EQUAL(cs->getDescription(), std::string("from input")); + + auto cs1 = checkColorSpace(mergedConfig, "CIE-XYZ-D65", 1, OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, __LINE__); + OCIO_CHECK_EQUAL(cs1->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs1->getAlias(0), std::string("cie_xyz_d65")); + } + + // Scene-referred spaces. + { + auto cs = checkColorSpace(mergedConfig, "ACES2065-1", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 2); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("aces")); + // Check for alias ap0 (added from base config). + OCIO_CHECK_EQUAL(cs->getAlias(1), std::string("ap0")); + + auto cs1 = checkColorSpace(mergedConfig, "sRGB", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs1->getNumAliases(), 2); + // Check for alias sRGB - Texture (added from base config colorspace name). + OCIO_CHECK_EQUAL(cs1->getAlias(0), std::string("sRGB - Texture")); + // Check for alias srgb_tx (added from base config). + OCIO_CHECK_EQUAL(cs1->getAlias(1), std::string("srgb_tx")); + + auto cs2 = checkColorSpace(mergedConfig, "rec709", 2, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + + auto cs3 = checkColorSpace(mergedConfig, "Raw", 3, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs3->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs3->getAlias(0), std::string("Utility - Raw")); + + auto cs4 = checkColorSpace(mergedConfig, "ACEScg", 4, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs4->getNumAliases(), 0); + } + +// FIXME: Remove the below string and improve the tests above. + + constexpr const char * RESULT { +R"(ocio_profile_version: 2.1 + +environment: + SHOT: 001a + TEXTURE_SPACE: sRGB - Texture +search_path: + - lut_dir + - luts + - . +strictparsing: true +family_separator: "~" +luma: [0.2126, 0.7152, 0.0722] +name: base + +roles: + cie_xyz_d65_interchange: CIE-XYZ-D65 + +file_rules: + - ! {name: Default, colorspace: ACEScg} + +displays: + {} + +active_displays: [] +active_views: [] +inactive_colorspaces: [ACES2065-1] + +display_colorspaces: + - ! + name: sRGB - Display + aliases: [srgb_display] + family: Input~Display~Standard + equalitygroup: "" + bitdepth: unknown + description: from input + isdata: false + allocation: uniform + from_display_reference: ! + children: + - ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1], direction: inverse} + - ! {gamma: 2.4, offset: 0.055, direction: inverse} + + - ! + name: CIE-XYZ-D65 + aliases: [cie_xyz_d65] + family: "Input~" + equalitygroup: "" + bitdepth: unknown + description: The \"CIE XYZ (D65)\" display connection colorspace. + isdata: false + allocation: uniform + from_display_reference: ! + children: + - ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1], direction: inverse} + - ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1]} + +colorspaces: + - ! + name: ACES2065-1 + aliases: [aces, ap0] + family: Input~ACES~Linear + equalitygroup: "" + bitdepth: unknown + description: from input + isdata: false + allocation: uniform + to_scene_reference: ! + children: + - ! {matrix: [2.521686186744, -1.13413098824, -0.387555198504, 0, -0.27647991423, 1.372719087668, -0.096239173438, 0, -0.015378064966, -0.152975335867, 1.168353400833, 0, 0, 0, 0, 1]} + - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} + + - ! + name: sRGB + aliases: [sRGB - Texture, srgb_tx] + family: Input~Texture~ + equalitygroup: "" + bitdepth: unknown + description: from input + isdata: false + allocation: uniform + to_scene_reference: ! + children: + - ! {gamma: 2.4, offset: 0.055} + - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} + + - ! + name: rec709 + family: "Input~" + equalitygroup: "" + bitdepth: unknown + description: from input + isdata: false + allocation: uniform + to_scene_reference: ! + children: + - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} + + - ! + name: Raw + aliases: [Utility - Raw] + family: Input~Utility + equalitygroup: "" + bitdepth: 32f + description: The utility "Raw" colorspace. + isdata: true + categories: [file-io] + allocation: uniform + + - ! + name: ACEScg + family: Base~ACES~Linear + equalitygroup: "" + bitdepth: unknown + description: from base + isdata: false + allocation: uniform + to_scene_reference: ! {style: ACEScg_to_ACES2065-1} +)" }; + + // Test the entire contents of each config. + + std::ostringstream oss; + mergedConfig->serialize(oss); + + std::istringstream resultIss; + resultIss.str(RESULT); + OCIO::ConstConfigRcPtr resultConfig = OCIO::Config::CreateFromStream(resultIss); + std::ostringstream ossResult; + resultConfig->serialize(ossResult); + +// OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); + } + + // PreferInput, Base first. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'"); + +// FIXME: Remove the below string and improve the tests above. + + constexpr const char * RESULT { +R"(ocio_profile_version: 2.1 + +environment: + SHOT: 001a + TEXTURE_SPACE: sRGB - Texture +search_path: + - luts + - . + - lut_dir +strictparsing: true +family_separator: "~" +luma: [0.2126, 0.7152, 0.0722] +name: base +roles: + cie_xyz_d65_interchange: CIE-XYZ-D65 +file_rules: + - ! {name: Default, colorspace: ACEScg} +displays: + {} +active_displays: [] +active_views: [] +inactive_colorspaces: [ACES2065-1] + +display_colorspaces: + - ! + name: sRGB - Display + aliases: [srgb_display] + family: Input~Display~Standard + equalitygroup: "" + bitdepth: unknown + description: from input + isdata: false + allocation: uniform + from_display_reference: ! + children: + - ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1], direction: inverse} + - ! {gamma: 2.4, offset: 0.055, direction: inverse} + + - ! + name: CIE-XYZ-D65 + aliases: [cie_xyz_d65] + family: "Input~" + equalitygroup: "" + bitdepth: unknown + description: The \"CIE XYZ (D65)\" display connection colorspace. + isdata: false + allocation: uniform + from_display_reference: ! + children: + - ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1], direction: inverse} + - ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1]} + +colorspaces: + - ! + name: ACEScg + family: Base~ACES~Linear + equalitygroup: "" + bitdepth: unknown + description: from base + isdata: false + allocation: uniform + to_scene_reference: ! {style: ACEScg_to_ACES2065-1} + + # The ap0 colorspace is added as an alias because it is equivalent to the ACES2065-1 colorspace + # in this config. + - ! + name: ACES2065-1 + aliases: [aces, ap0] + family: Input~ACES~Linear + equalitygroup: "" + bitdepth: unknown + description: from input + isdata: false + allocation: uniform + to_scene_reference: ! + children: + - ! {matrix: [2.521686186744, -1.13413098824, -0.387555198504, 0, -0.27647991423, 1.372719087668, -0.096239173438, 0, -0.015378064966, -0.152975335867, 1.168353400833, 0, 0, 0, 0, 1]} + - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} + + # The sRGB - Texture colorspace is added as an alias because it is equivalent to the sRGB + # colorspace in this config. + - ! + name: sRGB + aliases: [sRGB - Texture, srgb_tx] + family: Input~Texture~ + equalitygroup: "" + bitdepth: unknown + description: from input + isdata: false + allocation: uniform + to_scene_reference: ! + children: + - ! {gamma: 2.4, offset: 0.055} + - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} + + - ! + name: rec709 + family: "Input~" + equalitygroup: "" + bitdepth: unknown + description: from input + isdata: false + allocation: uniform + to_scene_reference: ! + children: + - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} + + - ! + name: Raw + aliases: [Utility - Raw] + family: Input~Utility + equalitygroup: "" + bitdepth: 32f + description: The utility "Raw" colorspace. + isdata: true + categories: [file-io] + allocation: uniform +)" }; + + // Test the entire contents of each config. + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getInactiveColorSpaces()), "ACES2065-1"); + + std::ostringstream oss; + mergedConfig->serialize(oss); + + std::istringstream resultIss; + resultIss.str(RESULT); + OCIO::ConstConfigRcPtr resultConfig = OCIO::Config::CreateFromStream(resultIss); + std::ostringstream ossResult; + resultConfig->serialize(ossResult); + +// OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); + } + + // PreferBase, Input first. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(true); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Input color space 'ACES2065-1' is a duplicate of base color space 'ap0' but was unable to add alias 'aces' since it conflicts with base color space 'ACEScg'"); + +// FIXME: Remove the below string and improve the tests above. + + constexpr const char * RESULT { +R"(ocio_profile_version: 2.1 + +environment: + SHOT: 001a + TEXTURE_SPACE: sRGB - Texture +search_path: + - lut_dir + - luts + - . +strictparsing: true +family_separator: "-" +luma: [0.2126, 0.7152, 0.0722] +name: base +roles: + cie_xyz_d65_interchange: CIE-XYZ-D65 +file_rules: + - ! {name: Default, colorspace: ACEScg} +displays: + {} +active_displays: [] +active_views: [] +inactive_colorspaces: [ACES2065-1] + +display_colorspaces: + - ! + name: sRGB - Display + aliases: [srgb_display] + family: Base-Display-Basic + equalitygroup: "" + bitdepth: unknown + description: from base + isdata: false + allocation: uniform + from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_sRGB} + + - ! + name: CIE-XYZ-D65 + aliases: [cie_xyz_d65] + family: "Base-" + equalitygroup: "" + bitdepth: unknown + description: The \"CIE XYZ (D65)\" display connection colorspace. + isdata: false + allocation: uniform + +colorspaces: + - ! + name: rec709 + family: "Input-" + equalitygroup: "" + bitdepth: unknown + description: from input + isdata: false + allocation: uniform + to_scene_reference: ! + children: + - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} + + - ! + name: Raw + aliases: [Utility - Raw] + family: Input-Utility + equalitygroup: "" + bitdepth: 32f + description: The utility "Raw" colorspace. + isdata: true + categories: [file-io] + allocation: uniform + + - ! + name: ACEScg + aliases: [aces] + family: Base-ACES-Linear + equalitygroup: "" + bitdepth: unknown + description: from base + isdata: false + allocation: uniform + to_scene_reference: ! {style: ACEScg_to_ACES2065-1} + + - ! + name: ap0 + aliases: [ACES2065-1] + family: Base-ACES-Linear + equalitygroup: "" + bitdepth: unknown + description: from base + isdata: false + allocation: uniform + + - ! + name: sRGB - Texture + aliases: [srgb, srgb_tx] + family: Base-Texture + equalitygroup: "" + bitdepth: unknown + description: from base + isdata: false + allocation: uniform + from_scene_reference: ! + children: + - ! {matrix: [2.52168618674388, -1.13413098823972, -0.387555198504164, 0, -0.276479914229922, 1.37271908766826, -0.096239173438334, 0, -0.0153780649660342, -0.152975335867399, 1.16835340083343, 0, 0, 0, 0, 1]} + - ! {gamma: 2.4, offset: 0.055, direction: inverse} +)" }; + + // Test the entire contents of each config. + + std::ostringstream oss; + mergedConfig->serialize(oss); + + std::istringstream resultIss; + resultIss.str(RESULT); + OCIO::ConstConfigRcPtr resultConfig = OCIO::Config::CreateFromStream(resultIss); + std::ostringstream ossResult; + resultConfig->serialize(ossResult); + +// OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); + } + + // PreferBase, Base first. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Input color space 'ACES2065-1' is a duplicate of base color space 'ap0' but was unable to add alias 'aces' since it conflicts with base color space 'ACEScg'"); + +// FIXME: Remove the below string and improve the tests above. + + constexpr const char * RESULT { +R"(ocio_profile_version: 2.1 + +environment: + SHOT: 001a + TEXTURE_SPACE: sRGB - Texture +search_path: + - luts + - . + - lut_dir +strictparsing: true +family_separator: "-" +luma: [0.2126, 0.7152, 0.0722] +name: base +roles: + cie_xyz_d65_interchange: CIE-XYZ-D65 +file_rules: + - ! {name: Default, colorspace: ACEScg} +displays: + {} +active_displays: [] +active_views: [] +inactive_colorspaces: [ACES2065-1] + +display_colorspaces: + - ! + name: sRGB - Display + aliases: [srgb_display] + family: Base-Display-Basic + equalitygroup: "" + bitdepth: unknown + description: from base + isdata: false + allocation: uniform + from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_sRGB} + + - ! + name: CIE-XYZ-D65 + aliases: [cie_xyz_d65] + family: "Base-" + equalitygroup: "" + bitdepth: unknown + description: The \"CIE XYZ (D65)\" display connection colorspace. + isdata: false + allocation: uniform + +colorspaces: + - ! + name: ACEScg + aliases: [aces] + family: Base-ACES-Linear + equalitygroup: "" + bitdepth: unknown + description: from base + isdata: false + allocation: uniform + to_scene_reference: ! {style: ACEScg_to_ACES2065-1} + + - ! + name: ap0 + aliases: [ACES2065-1] + family: Base-ACES-Linear + equalitygroup: "" + bitdepth: unknown + description: from base + isdata: false + allocation: uniform + + - ! + name: sRGB - Texture + aliases: [srgb, srgb_tx] + family: Base-Texture + equalitygroup: "" + bitdepth: unknown + description: from base + isdata: false + allocation: uniform + from_scene_reference: ! + children: + - ! {matrix: [2.52168618674388, -1.13413098823972, -0.387555198504164, 0, -0.276479914229922, 1.37271908766826, -0.096239173438334, 0, -0.0153780649660342, -0.152975335867399, 1.16835340083343, 0, 0, 0, 0, 1]} + - ! {gamma: 2.4, offset: 0.055, direction: inverse} + + - ! + name: rec709 + family: "Input-" + equalitygroup: "" + bitdepth: unknown + description: from input + isdata: false + allocation: uniform + to_scene_reference: ! + children: + - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} + + - ! + name: Raw + aliases: [Utility - Raw] + family: Input-Utility + equalitygroup: "" + bitdepth: 32f + description: The utility "Raw" colorspace. + isdata: true + categories: [file-io] + allocation: uniform +)" }; + + // Test the entire contents of each config. + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getInactiveColorSpaces()), "ACES2065-1"); + + std::ostringstream oss; + mergedConfig->serialize(oss); + + std::istringstream resultIss; + resultIss.str(RESULT); + OCIO::ConstConfigRcPtr resultConfig = OCIO::Config::CreateFromStream(resultIss); + std::ostringstream ossResult; + resultConfig->serialize(ossResult); + +// OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); + } + + // Nothing special to test for Input only and Base only. +} + +OCIO_ADD_TEST(MergeConfigs, colorspaces_section_errors) +{ + auto setupBasics = [](OCIO::ConfigMergerRcPtr & merger, MergeStrategy strategy) -> OCIO::ConfigMergingParametersRcPtr + { + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + merger->addParams(params); + // Note that these tests run several of the mergers. + merger->getParams(0)->setRoles(strategy); + merger->getParams(0)->setColorspaces(strategy); + merger->getParams(0)->setNamedTransforms(strategy); + merger->getParams(0)->setDefaultStrategy(strategy); + + merger->getParams(0)->setInputFamilyPrefix("Input/"); + merger->getParams(0)->setBaseFamilyPrefix("Base/"); + + merger->getParams(0)->setAssumeCommonReferenceSpace(true); + merger->getParams(0)->setAvoidDuplicates(false); + + return params; + }; + + // Test ADD_CS_ERROR_NAME_IDENTICAL_TO_A_ROLE_NAME + { + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: A} + +roles: + b: colorspace_a + +colorspaces: +- ! + name: colorspace_a +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: B} + +colorspaces: +- ! + name: B +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + + // The role takes priority over the inbound colorspace. + // The conflicting color space should not be added to the merged config (skipped). + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::RolesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Color space 'B' was not merged as it's identical to a role name"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 1); + OCIO_CHECK_EQUAL(mergedConfig->getRoleName(0), std::string("b")); + + // Colorspace A should not be added to the merged config (skipped) + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 1); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(0), std::string("colorspace_a")); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(true); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::RolesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Color space 'B' was not merged as it's identical to a role name"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 1); + OCIO_CHECK_EQUAL(mergedConfig->getRoleName(0), std::string("b")); + + // Colorspace A should not be added to the merged config (skipped) + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 1); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(0), std::string("colorspace_a")); + } + // Testing the error message when Error on conflict is enabled. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + merger->getParams(0)->setErrorOnConflict(true); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::RolesMerger(options).merge(); + OCIO_CHECK_THROW_WHAT(OCIO::ColorspacesMerger(options).merge(), + OCIO::Exception, + "Color space 'B' was not merged as it's identical to a role name"); + } + } + + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: A} + +colorspaces: +- ! + name: A +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: B} + +roles: + A: colorspace_b + +colorspaces: +- ! + name: colorspace_b +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'a' that would override Base config color space 'A'"); + OCIO::ColorspacesMerger(options).merge(); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(0), std::string("colorspace_b")); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(1), std::string("A")); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'a' that would override Base config color space 'A'"); + OCIO::ColorspacesMerger(options).merge(); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(0), std::string("colorspace_b")); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(1), std::string("A")); + } + } + } + + // test ADD_CS_ERROR_NAME_IDENTICAL_TO_NT_NAME_OR_ALIAS + { + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: +- ! {name: Default, colorspace: cs_base} + +named_transforms: +- ! + name: nt_base + encoding: log + inverse_transform: ! {name: inverse, offset: [-0.2, -0.1, -0.1, 0]} +- ! + name: nt_base_extra + aliases: [nt_base2] + encoding: log + inverse_transform: ! {name: inverse, offset: [-0.2, -0.1, -0.1, 0]} + +colorspaces: +- ! + name: cs_base +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: +- ! {name: Default, colorspace: nt_base} + +colorspaces: +- ! + name: nt_base +- ! + name: nt_base2 +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'nt_base' was not merged as there's a color space with that name", + "Merged Base named transform 'nt_base_extra' has an alias 'nt_base2' that conflicts with color space 'nt_base2'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); + OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "nt_base_extra", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 3); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(0), std::string("cs_base")); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(1), std::string("nt_base")); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(2), std::string("nt_base2")); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(false); + + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'nt_base' was not merged as there's a color space with that name", + "Merged Base named transform 'nt_base_extra' has an alias 'nt_base2' that conflicts with color space 'nt_base2'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); + OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "nt_base_extra", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 3); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(0), std::string("cs_base")); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(1), std::string("nt_base")); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(2), std::string("nt_base2")); + } + // Testing the error message when Error on conflict is enabled. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + merger->getParams(0)->setErrorOnConflict(true); + + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), + OCIO::Exception, + "Named transform 'nt_base' was not merged as there's a color space with that name"); + } + } + + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: nt_input} + +colorspaces: +- ! + name: nt_input +- ! + name: nt_input2 +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: cs_input} + +named_transforms: + - ! + name: nt_input + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} + + - ! + name: nt_input_extra + aliases: [nt_input2] + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} + +colorspaces: +- ! + name: cs_input +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(true); + + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'nt_input' was not merged as there's a color space with that name", + "Merged Input named transform 'nt_input_extra' has an alias 'nt_input2' that conflicts with color space 'nt_input2'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); + OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "nt_input_extra", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 3); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(0), std::string("cs_input")); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(1), std::string("nt_input")); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(2), std::string("nt_input2")); + } + + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(false); + + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'nt_input' was not merged as there's a color space with that name", + "Merged Input named transform 'nt_input_extra' has an alias 'nt_input2' that conflicts with color space 'nt_input2'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); + OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "nt_input_extra", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 3); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(0), std::string("nt_input")); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(1), std::string("nt_input2")); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(2), std::string("cs_input")); + } + } + } + + // test ADD_CS_ERROR_NAME_CONTAIN_CTX_VAR_TOKEN + // Not handled as it can't happen in this context. + // The config will error out while loading the config (before the merge process). + + // test ADD_CS_ERROR_ALIAS_IDENTICAL_TO_A_ROLE_NAME + { + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: csBase} + +roles: + role_base: csBase + +colorspaces: +- ! + name: csBase + +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: csInput} + +colorspaces: +- ! + name: csInput + aliases: [role_base] +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::RolesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'csInput' has an alias 'role_base' that conflicts with a role"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 1); + OCIO_CHECK_EQUAL(mergedConfig->getRoleName(0), std::string("role_base")); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(0), std::string("csBase")); + const char * name = mergedConfig->getColorSpaceNameByIndex(1); + OCIO_CHECK_EQUAL(std::string(name), std::string("csInput")); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpace(name)->getNumAliases(), 0); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::RolesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'csInput' has an alias 'role_base' that conflicts with a role"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 1); + OCIO_CHECK_EQUAL(mergedConfig->getRoleName(0), std::string("role_base")); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(0), std::string("csBase")); + const char * name = mergedConfig->getColorSpaceNameByIndex(1); + OCIO_CHECK_EQUAL(std::string(name), std::string("csInput")); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpace(name)->getNumAliases(), 0); + } + // Testing the error message when Error on conflict is enabled. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setErrorOnConflict(true); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::RolesMerger(options).merge(); + OCIO_CHECK_THROW_WHAT(OCIO::ColorspacesMerger(options).merge(), + OCIO::Exception, + "Merged color space 'csInput' has an alias 'role_base' that conflicts with a role"); + } + } + + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: csBase} + +colorspaces: +- ! + name: csBase + aliases: [role_input] +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: csInput} + +roles: + role_input: csInput + +colorspaces: +- ! + name: csInput +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'role_input' that would override an alias of Base config color space 'csBase'"); + OCIO::ColorspacesMerger(options).merge(); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(0), std::string("csInput")); + const char * name = mergedConfig->getColorSpaceNameByIndex(1); + OCIO_CHECK_EQUAL(std::string(name), std::string("csBase")); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpace(name)->getNumAliases(), 1); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpace(name)->getAlias(0), std::string("role_input")); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'role_input' that would override an alias of Base config color space 'csBase'"); + OCIO::ColorspacesMerger(options).merge(); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpaceNameByIndex(0), std::string("csInput")); + const char * name = mergedConfig->getColorSpaceNameByIndex(1); + OCIO_CHECK_EQUAL(std::string(name), std::string("csBase")); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpace(name)->getNumAliases(), 1); + OCIO_CHECK_EQUAL(mergedConfig->getColorSpace(name)->getAlias(0), std::string("role_input")); + } + } + } + + // test ADD_CS_ERROR_ALIAS_IDENTICAL_TO_NT_NAME_OR_ALIAS + { + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: A} + +named_transforms: + - ! + name: nt_base + encoding: log + inverse_transform: ! {name: inverse, offset: [-0.2, -0.1, -0.1, 0]} + + - ! + name: nt_base_extra + aliases: [nt_base2] + encoding: log + inverse_transform: ! {name: inverse, offset: [-0.2, -0.1, -0.1, 0]} +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: cs_input} + +colorspaces: +- ! + name: cs_input + aliases: [nt_base] +- ! + name: cs_input2 + aliases: [nt_base2] +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'nt_base' was not merged as there's a color space alias with that name", + "Merged Base named transform 'nt_base_extra' has a conflict with alias 'nt_base2' in color space 'cs_input2'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); + OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "nt_base_extra", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "cs_input", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("nt_base")); + + cs = checkColorSpace(mergedConfig, "cs_input2", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("nt_base2")); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'nt_base' was not merged as there's a color space alias with that name", + "Merged Base named transform 'nt_base_extra' has a conflict with alias 'nt_base2' in color space 'cs_input2'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); + OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "nt_base_extra", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "cs_input", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("nt_base")); + + cs = checkColorSpace(mergedConfig, "cs_input2", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("nt_base2")); + } + // Testing the error message when Error on conflict is enabled. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setErrorOnConflict(true); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), + OCIO::Exception, + "Named transform 'nt_base' was not merged as there's a color space alias with that name"); + } + } + + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: cs_base} + +colorspaces: +- ! + name: cs_base + aliases: [nt_input] +- ! + name: cs_base2 + aliases: [nt_input2] +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: B} + +named_transforms: + - ! + name: nt_input + encoding: log + inverse_transform: ! {name: inverse, offset: [-0.2, -0.1, -0.1, 0]} + - ! + name: nt_input_extra + aliases: [nt_input2] + encoding: log + inverse_transform: ! {name: inverse, offset: [-0.2, -0.1, -0.1, 0]} +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'nt_input' was not merged as there's a color space alias with that name", + "Merged Input named transform 'nt_input_extra' has a conflict with alias 'nt_input2' in color space 'cs_base2'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); + OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "nt_input_extra", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "cs_base", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("nt_input")); + + cs = checkColorSpace(mergedConfig, "cs_base2", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("nt_input2")); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'nt_input' was not merged as there's a color space alias with that name", + "Merged Input named transform 'nt_input_extra' has a conflict with alias 'nt_input2' in color space 'cs_base2'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); + OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "nt_input_extra", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "cs_base", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("nt_input")); + + cs = checkColorSpace(mergedConfig, "cs_base2", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("nt_input2")); + } + } + } + + // test ADD_CS_ERROR_ALIAS_CONTAIN_CTX_VAR_TOKEN + // Not handled as it can't happen in this context. + // The config will error out while loading the config (before the merge process). + + // test ADD_CS_ERROR_ALIAS_IDENTICAL_TO_EXISTING_COLORSPACE_ALIAS + { + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: cs_base} + +colorspaces: +- ! + name: cs_base + aliases: [my_colorspace] +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: cs_input} + +colorspaces: +- ! + name: cs_input + aliases: [my_colorspace] +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'cs_input' has a conflict with alias 'my_colorspace' in color space 'cs_base'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "cs_base", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 0); + + cs = checkColorSpace(mergedConfig, "cs_input", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("my_colorspace")); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'cs_input' has a conflict with alias 'my_colorspace' in color space 'cs_base'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "cs_base", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("my_colorspace")); + + cs = checkColorSpace(mergedConfig, "cs_input", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 0); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'cs_input' has a conflict with alias 'my_colorspace' in color space 'cs_base'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "cs_input", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("my_colorspace")); + + cs = checkColorSpace(mergedConfig, "cs_base", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 0); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'cs_input' has a conflict with alias 'my_colorspace' in color space 'cs_base'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "cs_input", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 0); + + cs = checkColorSpace(mergedConfig, "cs_base", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("my_colorspace")); + } + // Testing the error message when Error on conflict is enabled. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setErrorOnConflict(true); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO_CHECK_THROW_WHAT(OCIO::ColorspacesMerger(options).merge(), + OCIO::Exception, + "Merged color space 'cs_input' has a conflict with alias 'my_colorspace' in color space 'cs_base'"); + } + } + } + + // Test ADD_CS_ERROR_NAME_IDENTICAL_TO_EXISTING_COLORSPACE_ALIAS + { + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: A} + +colorspaces: +- ! + name: A + aliases: [B] +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: B} + +colorspaces: +- ! + name: B +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "The name of merged color space 'B' has a conflict with an alias in color space 'A'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "A", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 0); + + cs = checkColorSpace(mergedConfig, "B", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 0); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Color space 'B' was not merged as it conflicts with an alias in color space 'A'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 1); + + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "A", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("B")); + } + // Testing the error message when Error on conflict is enabled. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setErrorOnConflict(true); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO_CHECK_THROW_WHAT(OCIO::ColorspacesMerger(options).merge(), + OCIO::Exception, + "The name of merged color space 'B' has a conflict with an alias in color space 'A'"); + } + } + + // ADD_CS_ERROR_ALIAS_IDENTICAL_TO_EXISTING_COLORSPACE_NAME + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: A} + +colorspaces: +- ! + name: A +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: B} + +colorspaces: +- ! + name: B + aliases: [A] +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'B' has an alias 'A' that conflicts with color space 'A'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 1); + + OCIO::ConstColorSpaceRcPtr cs = checkColorSpace(mergedConfig, "B", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("A")); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'B' has an alias 'A' that conflicts with color space 'A'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 1); + + OCIO::ConstColorSpaceRcPtr cs = checkColorSpace(mergedConfig, "B", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("A")); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'B' has an alias 'A' that conflicts with color space 'A'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "B", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 0); + + cs = checkColorSpace(mergedConfig, "A", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 0); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'B' has an alias 'A' that conflicts with color space 'A'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "A", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 0); + + cs = checkColorSpace(mergedConfig, "B", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 0); + } + // Testing the error message when Error on conflict is enabled. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setErrorOnConflict(true); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO_CHECK_THROW_WHAT(OCIO::ColorspacesMerger(options).merge(), + OCIO::Exception, + "Merged color space 'B' has an alias 'A' that conflicts with color space 'A'"); + } + } + } +} + +OCIO_ADD_TEST(MergeConfigs, looks_section) +{ + OCIO::ConstConfigRcPtr baseConfig; + OCIO_CHECK_NO_THROW(baseConfig = getBaseConfig()); + + OCIO::ConstConfigRcPtr inputConfig; + OCIO_CHECK_NO_THROW(inputConfig = getInputConfig()); + + auto setupLooks = [] + (OCIO::ConstConfigRcPtr baseConfig, + OCIO::ConstConfigRcPtr inputConfig, + OCIO::ConfigMergerRcPtr & merger, + OCIO::ConfigRcPtr mergedConfig, + MergeStrategy strategy, + std::function cb) + { + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + merger->addParams(params); + merger->getParams(0)->setLooks(strategy); + + merger->getParams(0)->setInputFamilyPrefix("Input/"); + merger->getParams(0)->setBaseFamilyPrefix("Base/"); + + if (cb) + { + cb(merger); + } + + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::LooksMerger(options).merge(); + }; + + + // Test that the default strategy is used as a fallback if the section strategy was not defined. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + setupLooks(baseConfig, inputConfig, merger, + mergedConfig, + // Using STRATEGY_UNSET as this simulate that the section + // is missing from the OCIOM file. + MergeStrategy::STRATEGY_UNSET, + [](OCIO::ConfigMergerRcPtr & merger) + { + // Simulate settings from OCIOM file. + merger->getParams(0)->setDefaultStrategy(MergeStrategy::STRATEGY_INPUT_ONLY); + }); + + OCIO_CHECK_EQUAL(mergedConfig->getNumLooks(), 2); + OCIO_CHECK_EQUAL(mergedConfig->getLookNameByIndex(0), std::string("look_both")); + OCIO_CHECK_EQUAL(mergedConfig->getLookNameByIndex(1), std::string("look_input")); + + OCIO_CHECK_EQUAL(mergedConfig->getLook(mergedConfig->getLookNameByIndex(0))->getProcessSpace(), + std::string("ACEScct - SomeOtherName")); + OCIO_CHECK_EQUAL(mergedConfig->getLook(mergedConfig->getLookNameByIndex(1))->getProcessSpace(), + std::string("log_3")); + } + + // Test Looks with strategy = PreferInput, options InputFirst = true. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + + setupLooks(baseConfig, inputConfig, merger, + mergedConfig, + MergeStrategy::STRATEGY_PREFER_INPUT, + [](OCIO::ConfigMergerRcPtr & merger) + { + merger->getParams(0)->setAssumeCommonReferenceSpace(true); + }); + + OCIO_CHECK_EQUAL(mergedConfig->getNumLooks(), 3); + OCIO_CHECK_EQUAL(mergedConfig->getLookNameByIndex(0), std::string("look_both")); + OCIO_CHECK_EQUAL(mergedConfig->getLookNameByIndex(1), std::string("look_input")); + OCIO_CHECK_EQUAL(mergedConfig->getLookNameByIndex(2), std::string("look_base")); + + OCIO_CHECK_EQUAL(mergedConfig->getLook(mergedConfig->getLookNameByIndex(0))->getProcessSpace(), + std::string("ACEScct - SomeOtherName")); + OCIO_CHECK_EQUAL(mergedConfig->getLook(mergedConfig->getLookNameByIndex(1))->getProcessSpace(), + std::string("log_3")); + OCIO_CHECK_EQUAL(mergedConfig->getLook(mergedConfig->getLookNameByIndex(2))->getProcessSpace(), + std::string("log_1")); + } + + // Test Looks with strategy=PreferInput, options InputFirst = false. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + + setupLooks(baseConfig, inputConfig, merger, + mergedConfig, + MergeStrategy::STRATEGY_PREFER_INPUT, + [](OCIO::ConfigMergerRcPtr & merger) + { + merger->getParams(0)->setInputFirst(false); + merger->getParams(0)->setAssumeCommonReferenceSpace(true); + }); + + OCIO_CHECK_EQUAL(mergedConfig->getNumLooks(), 3); + OCIO_CHECK_EQUAL(mergedConfig->getLookNameByIndex(0), std::string("look_both")); + OCIO_CHECK_EQUAL(mergedConfig->getLookNameByIndex(1), std::string("look_base")); + OCIO_CHECK_EQUAL(mergedConfig->getLookNameByIndex(2), std::string("look_input")); + + OCIO_CHECK_EQUAL(mergedConfig->getLook(mergedConfig->getLookNameByIndex(0))->getProcessSpace(), + std::string("ACEScct - SomeOtherName")); + OCIO_CHECK_EQUAL(mergedConfig->getLook(mergedConfig->getLookNameByIndex(1))->getProcessSpace(), + std::string("log_1")); + OCIO_CHECK_EQUAL(mergedConfig->getLook(mergedConfig->getLookNameByIndex(2))->getProcessSpace(), + std::string("log_3")); + } + + // Test Looks with strategy = PreferBase, options InputFirst = true. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + setupLooks(baseConfig, inputConfig, merger, + mergedConfig, + MergeStrategy::STRATEGY_PREFER_BASE, + [](OCIO::ConfigMergerRcPtr & merger) + { + merger->getParams(0)->setInputFirst(true); + merger->getParams(0)->setAssumeCommonReferenceSpace(true); + }); + + OCIO_CHECK_EQUAL(mergedConfig->getNumLooks(), 3); + OCIO_CHECK_EQUAL(mergedConfig->getLookNameByIndex(0), std::string("look_both")); + OCIO_CHECK_EQUAL(mergedConfig->getLookNameByIndex(1), std::string("look_input")); + OCIO_CHECK_EQUAL(mergedConfig->getLookNameByIndex(2), std::string("look_base")); + + OCIO_CHECK_EQUAL(mergedConfig->getLook(mergedConfig->getLookNameByIndex(0))->getProcessSpace(), + std::string("ACES2065-1")); + OCIO_CHECK_EQUAL(mergedConfig->getLook(mergedConfig->getLookNameByIndex(1))->getProcessSpace(), + std::string("log_3")); + OCIO_CHECK_EQUAL(mergedConfig->getLook(mergedConfig->getLookNameByIndex(2))->getProcessSpace(), + std::string("log_1")); + } + + // Test Looks with strategy = PreferBase, options InputFirst = false. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + setupLooks(baseConfig, inputConfig, merger, + mergedConfig, + MergeStrategy::STRATEGY_PREFER_BASE, + [](OCIO::ConfigMergerRcPtr & merger) + { + merger->getParams(0)->setInputFirst(false); + merger->getParams(0)->setAssumeCommonReferenceSpace(true); + }); + + OCIO_CHECK_EQUAL(mergedConfig->getNumLooks(), 3); + OCIO_CHECK_EQUAL(mergedConfig->getLookNameByIndex(0), std::string("look_both")); + OCIO_CHECK_EQUAL(mergedConfig->getLookNameByIndex(1), std::string("look_base")); + OCIO_CHECK_EQUAL(mergedConfig->getLookNameByIndex(2), std::string("look_input")); + + OCIO_CHECK_EQUAL(mergedConfig->getLook(mergedConfig->getLookNameByIndex(0))->getProcessSpace(), + std::string("ACES2065-1")); + OCIO_CHECK_EQUAL(mergedConfig->getLook(mergedConfig->getLookNameByIndex(1))->getProcessSpace(), + std::string("log_1")); + OCIO_CHECK_EQUAL(mergedConfig->getLook(mergedConfig->getLookNameByIndex(2))->getProcessSpace(), + std::string("log_3")); + } + + // Test Looks with strategy = BaseOnly. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + setupLooks(baseConfig, inputConfig, merger, + mergedConfig, + MergeStrategy::STRATEGY_BASE_ONLY, + nullptr); + + OCIO_CHECK_EQUAL(mergedConfig->getNumLooks(), 2); + OCIO_CHECK_EQUAL(mergedConfig->getLookNameByIndex(0), std::string("look_both")); + OCIO_CHECK_EQUAL(mergedConfig->getLookNameByIndex(1), std::string("look_base")); + + OCIO_CHECK_EQUAL(mergedConfig->getLook(mergedConfig->getLookNameByIndex(0))->getProcessSpace(), + std::string("ACES2065-1")); + OCIO_CHECK_EQUAL(mergedConfig->getLook(mergedConfig->getLookNameByIndex(1))->getProcessSpace(), + std::string("log_1")); + } + + // Test Looks with strategy = InputOnly. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + setupLooks(baseConfig, inputConfig, merger, + mergedConfig, + MergeStrategy::STRATEGY_INPUT_ONLY, + nullptr); + + OCIO_CHECK_EQUAL(mergedConfig->getNumLooks(), 2); + OCIO_CHECK_EQUAL(mergedConfig->getLookNameByIndex(0), std::string("look_both")); + OCIO_CHECK_EQUAL(mergedConfig->getLookNameByIndex(1), std::string("look_input")); + + OCIO_CHECK_EQUAL(mergedConfig->getLook(mergedConfig->getLookNameByIndex(0))->getProcessSpace(), + std::string("ACEScct - SomeOtherName")); + OCIO_CHECK_EQUAL(mergedConfig->getLook(mergedConfig->getLookNameByIndex(1))->getProcessSpace(), + std::string("log_3")); + } + + // Test Looks with strategy = Remove + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + setupLooks(baseConfig, inputConfig, merger, + mergedConfig, + MergeStrategy::STRATEGY_REMOVE, + nullptr); + + OCIO_CHECK_EQUAL(mergedConfig->getNumLooks(), 1); + OCIO_CHECK_EQUAL(mergedConfig->getLookNameByIndex(0), std::string("look_base")); + OCIO_CHECK_EQUAL(mergedConfig->getLook(mergedConfig->getLookNameByIndex(0))->getProcessSpace(), + std::string("log_1")); + } +} + +OCIO_ADD_TEST(MergeConfigs, named_transform_section) +{ + OCIO::ConstConfigRcPtr baseConfig; + OCIO_CHECK_NO_THROW(baseConfig = getBaseConfig()); + + OCIO::ConstConfigRcPtr inputConfig; + OCIO_CHECK_NO_THROW(inputConfig = getInputConfig()); + + auto setupBasics = [](OCIO::ConfigMergerRcPtr & merger, MergeStrategy strategy) -> OCIO::ConfigMergingParametersRcPtr + { + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + merger->addParams(params); + // Note that these tests run several of the mergers. + // Need to run the color space merger too, since that affects how the named transform + // merger will work (in terms of avoiding conflicts with color space names). + merger->getParams(0)->setRoles(strategy); + merger->getParams(0)->setColorspaces(strategy); + merger->getParams(0)->setNamedTransforms(strategy); + merger->getParams(0)->setDefaultStrategy(strategy); + + merger->getParams(0)->setInputFamilyPrefix("Input/"); + merger->getParams(0)->setBaseFamilyPrefix("Base/"); + + merger->getParams(0)->setAssumeCommonReferenceSpace(true); + merger->getParams(0)->setAvoidDuplicates(true); + merger->getParams(0)->setInputFirst(true); + + return params; + }; + + // Test that the default strategy is used as a fallback if the section strategy was not defined. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + // Using STRATEGY_UNSET as this simulate that the section + // is missing from the OCIOM file. + auto params = setupBasics(merger, MergeStrategy::STRATEGY_UNSET); + // Simulate settings from OCIOM file. + merger->getParams(0)->setDefaultStrategy(MergeStrategy::STRATEGY_INPUT_ONLY); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + OCIO::NamedTransformsMerger(options).merge(); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 3); + + OCIO::ConstNamedTransformRcPtr nt = nullptr; + nt = checkNamedTransform(mergedConfig, "nt_both", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 2); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("Utility - Raw")); + OCIO_CHECK_EQUAL(nt->getAlias(1), std::string("nametr")); + OCIO_CHECK_EQUAL(nt->getFamily(), std::string("")); + OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from input")); + + nt = checkNamedTransform(mergedConfig, "nt_input", 1, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 2); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("Raw")); + OCIO_CHECK_EQUAL(nt->getAlias(1), std::string("in nt")); + OCIO_CHECK_EQUAL(nt->getFamily(), std::string("Raw")); + OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from input")); + + nt = checkNamedTransform(mergedConfig, "view_2", 2, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 1); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("g22_ap1")); + OCIO_CHECK_EQUAL(nt->getFamily(), std::string("Raw")); + OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from input")); + } + + // Test NamedTransform with strategy = PreferInput, options InputFirst = true. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Color space 'view_1' will replace a color space in the base config"); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'nt_both' will replace a named transform in the base config", + "Merged Base named transform 'nt_both' has a conflict with alias 'srgb_tx' in color space 'sRGB - Texture'", + "Merged Base named transform 'nt_base' has an alias 'view_3' that conflicts with color space 'view_3'", + "Merged Input named transform 'nt_both' has a conflict with alias 'Utility - Raw' in color space 'Raw'", + "The name of merged named transform 'nt_input' has a conflict with an alias in named transform 'nt_base'", + "Merged Input named transform 'nt_input' has an alias 'Raw' that conflicts with color space 'Raw'", + "Named transform 'view_2' was not merged as there's a color space with that name"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 3); + + OCIO::ConstNamedTransformRcPtr nt = nullptr; + nt = checkNamedTransform(mergedConfig, "nt_both", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 1); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("nametr")); + OCIO_CHECK_EQUAL(nt->getFamily(), std::string("Input@")); + OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from input")); + + nt = checkNamedTransform(mergedConfig, "nt_input", 1, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 1); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("in nt")); + OCIO_CHECK_EQUAL(nt->getFamily(), std::string("Input@Raw")); + OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from input")); + + nt = checkNamedTransform(mergedConfig, "nt_base", 2, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 0); + OCIO_CHECK_EQUAL(nt->getFamily(), std::string("Base@nt")); + OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from base")); + } + + // Test NamedTransform with strategy=PreferInput, options InputFirst = false. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Color space 'view_1' will replace a color space in the base config"); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'nt_both' will replace a named transform in the base config", + "Merged Base named transform 'nt_both' has a conflict with alias 'srgb_tx' in color space 'sRGB - Texture'", + "Merged Base named transform 'nt_base' has an alias 'view_3' that conflicts with color space 'view_3'", + "Merged Input named transform 'nt_both' has a conflict with alias 'Utility - Raw' in color space 'Raw'", + "The name of merged named transform 'nt_input' has a conflict with an alias in named transform 'nt_base'", + "Merged Input named transform 'nt_input' has an alias 'Raw' that conflicts with color space 'Raw'", + "Named transform 'view_2' was not merged as there's a color space with that name"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 3); + + OCIO::ConstNamedTransformRcPtr nt = nullptr; + nt = checkNamedTransform(mergedConfig, "nt_base", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 0); + OCIO_CHECK_EQUAL(nt->getFamily(), std::string("Base@nt")); + OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from base")); + + nt = checkNamedTransform(mergedConfig, "nt_both", 1, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 1); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("nametr")); + OCIO_CHECK_EQUAL(nt->getFamily(), std::string("Input@")); + OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from input")); + + nt = checkNamedTransform(mergedConfig, "nt_input", 2, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 1); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("in nt")); + OCIO_CHECK_EQUAL(nt->getFamily(), std::string("Input@Raw")); + OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from input")); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getInactiveColorSpaces()), "Gamma 2.2 AP1 - Texture, Linear Rec.2020, nt_both, nt_input, view_2"); + } + + // Test NamedTransform with strategy = PreferBase, options InputFirst = true. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Color space 'view_1' was not merged as it's already present in the base config"); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Merged Base named transform 'nt_both' has a conflict with alias 'srgb_tx' in color space 'sRGB - Texture'", + "Merged Base named transform 'nt_base' has an alias 'view_3' that conflicts with color space 'view_3'", + "Named transform 'nt_both' was not merged as it's already present in the base config", + "Named transform 'nt_input' was not merged as it conflicts with an alias in named transform 'nt_base'", + "Named transform 'view_2' was not merged as there's a color space with that name"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 2); + + OCIO::ConstNamedTransformRcPtr nt = nullptr; + nt = checkNamedTransform(mergedConfig, "nt_both", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 1); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("namet2")); + OCIO_CHECK_EQUAL(nt->getFamily(), std::string("Base#")); + OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from base")); + + nt = checkNamedTransform(mergedConfig, "nt_base", 1, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 1); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("nt_input")); + OCIO_CHECK_EQUAL(nt->getFamily(), std::string("Base#nt")); + OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from base")); + + // NB: The nt_input is included referring to the alias in the base config, not the input config. + OCIO_CHECK_EQUAL(std::string(mergedConfig->getInactiveColorSpaces()), "Linear Rec.2020, nt_both, view_2, Gamma 2.2 AP1 - Texture"); + } + + // Test NamedTransform with strategy = PreferBase, options InputFirst = false. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Color space 'view_1' was not merged as it's already present in the base config"); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Merged Base named transform 'nt_both' has a conflict with alias 'srgb_tx' in color space 'sRGB - Texture'", + "Merged Base named transform 'nt_base' has an alias 'view_3' that conflicts with color space 'view_3'", + "Named transform 'nt_both' was not merged as it's already present in the base config", + "Named transform 'nt_input' was not merged as it conflicts with an alias in named transform 'nt_base'", + "Named transform 'view_2' was not merged as there's a color space with that name"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 2); + + OCIO::ConstNamedTransformRcPtr nt = nullptr; + nt = checkNamedTransform(mergedConfig, "nt_both", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 1); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("namet2")); + OCIO_CHECK_EQUAL(nt->getFamily(), std::string("Base#")); + OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from base")); + + nt = checkNamedTransform(mergedConfig, "nt_base", 1, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 1); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("nt_input")); + OCIO_CHECK_EQUAL(nt->getFamily(), std::string("Base#nt")); + OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from base")); + } + + // Test NamedTransform with strategy = BaseOnly. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_BASE_ONLY); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + OCIO::NamedTransformsMerger(options).merge(); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 2); + + OCIO::ConstNamedTransformRcPtr nt = nullptr; + nt = checkNamedTransform(mergedConfig, "nt_both", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 2); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("srgb_tx")); + OCIO_CHECK_EQUAL(nt->getAlias(1), std::string("namet2")); + OCIO_CHECK_EQUAL(nt->getFamily(), std::string("")); + OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from base")); + + nt = checkNamedTransform(mergedConfig, "nt_base", 1, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 2); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("view_3")); + OCIO_CHECK_EQUAL(nt->getAlias(1), std::string("nt_input")); + OCIO_CHECK_EQUAL(nt->getFamily(), std::string("nt")); + OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from base")); + } + + // Test NamedTransform with strategy = InputOnly. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_INPUT_ONLY); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + OCIO::NamedTransformsMerger(options).merge(); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 3); + + OCIO::ConstNamedTransformRcPtr nt = nullptr; + nt = checkNamedTransform(mergedConfig, "nt_both", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 2); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("Utility - Raw")); + OCIO_CHECK_EQUAL(nt->getAlias(1), std::string("nametr")); + OCIO_CHECK_EQUAL(nt->getFamily(), std::string("")); + OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from input")); + + nt = checkNamedTransform(mergedConfig, "nt_input", 1, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 2); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("Raw")); + OCIO_CHECK_EQUAL(nt->getAlias(1), std::string("in nt")); + OCIO_CHECK_EQUAL(nt->getFamily(), std::string("Raw")); + OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from input")); + + nt = checkNamedTransform(mergedConfig, "view_2", 2, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 1); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("g22_ap1")); + OCIO_CHECK_EQUAL(nt->getFamily(), std::string("Raw")); + OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from input")); + } + + // Test NamedTransform with strategy = Remove + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_REMOVE); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + OCIO::NamedTransformsMerger(options).merge(); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); + + OCIO::ConstNamedTransformRcPtr nt = nullptr; + nt = checkNamedTransform(mergedConfig, "nt_base", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 2); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("view_3")); + OCIO_CHECK_EQUAL(nt->getAlias(1), std::string("nt_input")); + OCIO_CHECK_EQUAL(nt->getFamily(), std::string("nt")); + OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from base")); + } +} + +OCIO_ADD_TEST(MergeConfigs, named_transform_section_errors) +{ + auto setupBasics = [](OCIO::ConfigMergerRcPtr & merger, MergeStrategy strategy) -> OCIO::ConfigMergingParametersRcPtr + { + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + merger->addParams(params); + // Note that these tests run several of the mergers. + merger->getParams(0)->setRoles(strategy); + merger->getParams(0)->setColorspaces(strategy); + merger->getParams(0)->setNamedTransforms(strategy); + merger->getParams(0)->setDefaultStrategy(strategy); + + merger->getParams(0)->setInputFamilyPrefix("Input/"); + merger->getParams(0)->setBaseFamilyPrefix("Base/"); + + merger->getParams(0)->setAssumeCommonReferenceSpace(true); + merger->getParams(0)->setAvoidDuplicates(false); + + return params; + }; + + // Test ADD_NT_ERROR_AT_LEAST_ONE_TRANSFORM, + { + + } + + // Test ADD_NT_ERROR_NAME_IDENTICAL_TO_A_ROLE_NAME, + { + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: A} + +roles: + b: Raw + +colorspaces: +- ! + name: Raw + +named_transforms: + - ! + name: A + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: B} + +named_transforms: + - ! + name: B + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + + // The role takes priority. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::RolesMerger(options).merge(); + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'B' was not merged as it's identical to a role name"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 1); + OCIO_CHECK_EQUAL(mergedConfig->getRoleName(0), std::string("b")); + + // NamedTransform B should not be added to the merged config (skipped). + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); + OCIO_CHECK_EQUAL(mergedConfig->getNamedTransformNameByIndex(0), std::string("A")); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::RolesMerger(options).merge(); + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'B' was not merged as it's identical to a role name"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 1); + OCIO_CHECK_EQUAL(mergedConfig->getRoleName(0), std::string("b")); + + // NamedTransform B should not be added to the merged config (skipped) + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); + OCIO_CHECK_EQUAL(mergedConfig->getNamedTransformNameByIndex(0), std::string("A")); + } + // Testing the error message when Error on conflict is enabled. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setErrorOnConflict(true); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), + OCIO::Exception, + "Named transform 'B' was not merged as it's identical to a role name"); + } + } + + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: A} + +named_transforms: + - ! + name: A + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: B} + +roles: + a: B + +colorspaces: +- ! + name: B +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'a' that would override Base config named transform: 'A'"); + OCIO::ColorspacesMerger(options).merge(); + OCIO::NamedTransformsMerger(options).merge(); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); + OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "A", 0, __LINE__); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'a' that would override Base config named transform: 'A'"); + OCIO::ColorspacesMerger(options).merge(); + OCIO::NamedTransformsMerger(options).merge(); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); + OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "A", 0, __LINE__); + } + } + } + + // Test ADD_NT_ERROR_NAME_IDENTICAL_TO_COLORSPACE_OR_ALIAS, + { + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: B} + +colorspaces: +- ! + name: B +- ! + name: myB + aliases: [B1] +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: csB} + +colorspaces: +- ! + name: csB + +named_transforms: + - ! + name: B + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} + + - ! + name: B1 + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + + // The role take priority over the inbound colorspace. + // The conflicting colorspace should not be added to the merged config (skipped). + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'B' was not merged as there's a color space with that name", + "Named transform 'B1' was not merged as there's a color space alias with that name"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 3); + + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "B", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + cs = checkColorSpace(mergedConfig, "myB", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("B1")); + cs = checkColorSpace(mergedConfig, "csB", 2, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'B' was not merged as there's a color space with that name", + "Named transform 'B1' was not merged as there's a color space alias with that name"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 3); + + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "B", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + + cs = checkColorSpace(mergedConfig, "myB", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("B1")); + + cs = checkColorSpace(mergedConfig, "csB", 2, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + } + // Testing the error message when Error on conflict is enabled. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setErrorOnConflict(true); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), + OCIO::Exception, + "Named transform 'B' was not merged as there's a color space with that name"); + } + } + + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: csA} + +colorspaces: +- ! + name: csA + +named_transforms: + - ! + name: A + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} + + - ! + name: A1 + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: A} + +colorspaces: +- ! + name: A +- ! + name: myA + aliases: [A1] +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'A' was not merged as there's a color space with that name", + "Named transform 'A1' was not merged as there's a color space alias with that name"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 3); + + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "A", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + cs = checkColorSpace(mergedConfig, "myA", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("A1")); + cs = checkColorSpace(mergedConfig, "csA", 2, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'A' was not merged as there's a color space with that name", + "Named transform 'A1' was not merged as there's a color space alias with that name"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 3); + + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "A", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + cs = checkColorSpace(mergedConfig, "myA", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("A1")); + cs = checkColorSpace(mergedConfig, "csA", 2, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + } + } + } + + // Test ADD_NT_ERROR_NAME_CONTAIN_CTX_VAR_TOKEN, + // Not handled as it can't happen in this context. + // The config will error out while loading the config (before the merge process). + + // Test ADD_NT_ERROR_NAME_IDENTICAL_TO_EXISTING_NT_ALIAS, + { + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: csA} + +colorspaces: +- ! + name: csA + +named_transforms: + - ! + name: A + aliases: [B] + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: csB} + +colorspaces: +- ! + name: csB + +named_transforms: + - ! + name: B + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "The name of merged named transform 'B' has a conflict with an alias in named transform 'A'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 2); + + OCIO::ConstNamedTransformRcPtr nt = nullptr; + nt = checkNamedTransform(mergedConfig, "A", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 0); + nt = checkNamedTransform(mergedConfig, "B", 1, __LINE__); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "The name of merged named transform 'B' has a conflict with an alias in named transform 'A'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 2); + + OCIO::ConstNamedTransformRcPtr nt = nullptr; + nt = checkNamedTransform(mergedConfig, "A", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 0); + nt = checkNamedTransform(mergedConfig, "B", 1, __LINE__); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setErrorOnConflict(true); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), + OCIO::Exception, + "The name of merged named transform 'B' has a conflict with an alias in named transform 'A'"); + } + } + + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: csA} + +colorspaces: +- ! + name: csA + +named_transforms: + - ! + name: A + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: B} + +colorspaces: +- ! + name: csB + +named_transforms: + - ! + name: B + aliases: [A] + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Merged Input named transform 'B' has an alias 'A' that conflicts with named transform 'A'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); + + OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "B", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 1); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("A")); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Merged Input named transform 'B' has an alias 'A' that conflicts with named transform 'A'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 2); + + OCIO::ConstNamedTransformRcPtr nt = nullptr; + nt = checkNamedTransform(mergedConfig, "B", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 0); + nt = checkNamedTransform(mergedConfig, "A", 1, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 0); + } + } + } + + // Test ADD_NT_ERROR_ALIAS_IDENTICAL_TO_A_ROLE_NAME, + { + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: csA} + +roles: + b1: csA + +colorspaces: +- ! + name: csA +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: csB} + +colorspaces: +- ! + name: csB + +named_transforms: + - ! + name: B + aliases: [B1] + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::RolesMerger(options).merge(); + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Merged Input named transform 'B' has an alias 'B1' that conflicts with a role"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 1); + OCIO_CHECK_EQUAL(mergedConfig->getRoleName(0), std::string("b1")); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); + + OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "B", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 0); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::RolesMerger(options).merge(); + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Merged Input named transform 'B' has an alias 'B1' that conflicts with a role"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 1); + OCIO_CHECK_EQUAL(mergedConfig->getRoleName(0), std::string("b1")); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); + + OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "B", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 0); + } + // Testing the error message when Error on conflict is enabled. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setErrorOnConflict(true); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::RolesMerger(options).merge(); + OCIO::ColorspacesMerger(options).merge(); + OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), + OCIO::Exception, + "Merged Input named transform 'B' has an alias 'B1' that conflicts with a role"); + } + } + + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: csA} + +colorspaces: +- ! + name: csA + +named_transforms: + - ! + name: B + aliases: [A1] + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: csB} + +roles: + a1: csB + +colorspaces: +- ! + name: csB +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'a1' that would override an alias of Base config named transform: 'B'"); + OCIO::ColorspacesMerger(options).merge(); + OCIO::NamedTransformsMerger(options).merge(); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); + + OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "B", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 1); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("A1")); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'a1' that would override an alias of Base config named transform: 'B'"); + OCIO::ColorspacesMerger(options).merge(); + OCIO::NamedTransformsMerger(options).merge(); + + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); + + OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "B", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 1); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("A1")); + } + } + } + + // Test ADD_NT_ERROR_ALIAS_IDENTICAL_TO_COLORSPACE_OR_ALIAS, + { + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: csA} + +colorspaces: +- ! + name: csA +- ! + name: B +- ! + name: myB + aliases: [B1] +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: csB} + +colorspaces: +- ! + name: csB + +named_transforms: + - ! + name: B + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} + + - ! + name: B1 + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'B' was not merged as there's a color space with that name", + "Named transform 'B1' was not merged as there's a color space alias with that name"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 4); + + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "csA", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + cs = checkColorSpace(mergedConfig, "B", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + cs = checkColorSpace(mergedConfig, "myB", 2, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("B1")); + cs = checkColorSpace(mergedConfig, "csB", 3, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'B' was not merged as there's a color space with that name", + "Named transform 'B1' was not merged as there's a color space alias with that name"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 4); + + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "csA", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + cs = checkColorSpace(mergedConfig, "B", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + cs = checkColorSpace(mergedConfig, "myB", 2, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("B1")); + cs = checkColorSpace(mergedConfig, "csB", 3, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + } + // Testing the error message when Error on conflict is enabled. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setErrorOnConflict(true); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), + OCIO::Exception, + "Named transform 'B' was not merged as there's a color space with that name"); + } + } + + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: csA} + +colorspaces: +- ! + name: csA + +named_transforms: + - ! + name: A + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} + + - ! + name: A1 + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: csB} + +colorspaces: +- ! + name: csB +- ! + name: A +- ! + name: myA + aliases: [A1] +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'A' was not merged as there's a color space with that name", + "Named transform 'A1' was not merged as there's a color space alias with that name"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 4); + + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "csA", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + cs = checkColorSpace(mergedConfig, "csB", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + cs = checkColorSpace(mergedConfig, "A", 2, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + cs = checkColorSpace(mergedConfig, "myA", 3, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("A1")); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'A' was not merged as there's a color space with that name", + "Named transform 'A1' was not merged as there's a color space alias with that name"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 0); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 4); + + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "csA", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + cs = checkColorSpace(mergedConfig, "csB", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + cs = checkColorSpace(mergedConfig, "A", 2, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + cs = checkColorSpace(mergedConfig, "myA", 3, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("A1")); + } + } + } + + // Test ADD_NT_ERROR_ALIAS_CONTAIN_CTX_VAR_TOKEN, + // Not handled as it can't happen in this context. + // The config will error out while loading the config (before the merge process). + + // Test ADD_NT_ERROR_ALIAS_IDENTICAL_TO_EXISTING_NT_ALIAS + { + { + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: csA} + +colorspaces: +- ! + name: csA + +named_transforms: + - ! + name: A + aliases: [my_colorspace] + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: csB} + +colorspaces: +- ! + name: csB + +named_transforms: + - ! + name: B + aliases: [my_colorspace] + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardBase, offset: [0.1, 0.2, 0.3, 0.4]} +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Merged Input named transform 'B' has a conflict with alias 'my_colorspace' in named transform 'A'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 2); + + OCIO::ConstNamedTransformRcPtr nt = nullptr; + nt = checkNamedTransform(mergedConfig, "A", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 0); + nt = checkNamedTransform(mergedConfig, "B", 1, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 1); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("my_colorspace")); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Merged Input named transform 'B' has a conflict with alias 'my_colorspace' in named transform 'A'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 2); + + OCIO::ConstNamedTransformRcPtr nt = nullptr; + nt = checkNamedTransform(mergedConfig, "B", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 1); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("my_colorspace")); + nt = checkNamedTransform(mergedConfig, "A", 1, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 0); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(false); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Merged Input named transform 'B' has a conflict with alias 'my_colorspace' in named transform 'A'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 2); + + OCIO::ConstNamedTransformRcPtr nt = nullptr; + nt = checkNamedTransform(mergedConfig, "A", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 1); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("my_colorspace")); + nt = checkNamedTransform(mergedConfig, "B", 1, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 0); + } + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Merged Input named transform 'B' has a conflict with alias 'my_colorspace' in named transform 'A'"); + + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); + + OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 2); + + OCIO::ConstNamedTransformRcPtr nt = nullptr; + nt = checkNamedTransform(mergedConfig, "B", 0, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 0); + nt = checkNamedTransform(mergedConfig, "A", 1, __LINE__); + OCIO_CHECK_EQUAL(nt->getNumAliases(), 1); + OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("my_colorspace")); + } + // Testing the error message when Error on conflict is enabled. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setErrorOnConflict(true); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ColorspacesMerger(options).merge(); + OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), + OCIO::Exception, + "Merged Input named transform 'B' has a conflict with alias 'my_colorspace' in named transform 'A'"); + } + } + } +} + +OCIO_ADD_TEST(MergeConfigs, merges_with_ociom_file) +{ + { + std::vector paths = { + std::string(OCIO::GetTestFilesDir()), + std::string("configs"), + std::string("mergeconfigs"), + std::string("merged1"), + std::string("merged1.ociom") + }; + const std::string ociomPath = pystring::os::path::normpath(pystring::os::path::join(paths)); + + // PreferInput, Input first + { + OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); + OCIO::ConstConfigMergerRcPtr newMerger; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&newMerger, &merger]() { newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); }, + "The Input config contains a value that would override the Base config: file_rules: Default", + "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", +// TODO: Last one should not be necessary. + "The Input config contains a role that would override Base config role 'aces_interchange'"); + OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); + std::ostringstream oss; + mergedConfig->serialize(oss); + + constexpr const char * RESULT { +R"(ocio_profile_version: 2.1 + +environment: + SHOT: 001a + TEXTURE_SPACE: sRGB - Texture +search_path: + - lut_dir + - luts + - . +strictparsing: true +family_separator: "~" +luma: [0.2126, 0.7152, 0.0722] +name: Merged1 +description: Basic merge with default strategy + +roles: + cie_xyz_d65_interchange: CIE-XYZ-D65 + +file_rules: + - ! {name: Default, colorspace: sRGB} + +displays: + sRGB - Display: + - ! {name: Raw, colorspace: raw} + - ! {name: ACES 1.0 - SDR Video, view_transform: SDR Video, display_colorspace: sRGB - Display} + +active_displays: [] +active_views: [] +inactive_colorspaces: [ACES2065-1] + +view_transforms: + - ! + name: SDR Video + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1} + +display_colorspaces: + - ! + name: sRGB - Display + aliases: [srgb_display] + family: Display~Standard + equalitygroup: "" + bitdepth: unknown + description: from input + isdata: false + allocation: uniform + from_display_reference: ! + children: + - ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1], direction: inverse} + - ! {gamma: 2.4, offset: 0.055, direction: inverse} + + - ! + name: CIE-XYZ-D65 + aliases: [cie_xyz_d65] + family: "" + equalitygroup: "" + bitdepth: unknown + description: The \"CIE XYZ (D65)\" display connection colorspace. + isdata: false + allocation: uniform + from_display_reference: ! + children: + - ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1], direction: inverse} + - ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1]} + +colorspaces: + - ! + name: ACES2065-1 + aliases: [aces, ap0] + family: ACES~Linear + equalitygroup: "" + bitdepth: unknown + description: from input + isdata: false + allocation: uniform + to_scene_reference: ! + children: + - ! {matrix: [2.521686186744, -1.13413098824, -0.387555198504, 0, -0.27647991423, 1.372719087668, -0.096239173438, 0, -0.015378064966, -0.152975335867, 1.168353400833, 0, 0, 0, 0, 1]} + - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} + + - ! + name: sRGB + aliases: [sRGB - Texture, srgb_tx] + family: Texture~ + equalitygroup: "" + bitdepth: unknown + description: from input + isdata: false + allocation: uniform + to_scene_reference: ! + children: + - ! {gamma: 2.4, offset: 0.055} + - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} + + - ! + name: rec709 + family: "" + equalitygroup: "" + bitdepth: unknown + description: from input + isdata: false + allocation: uniform + to_scene_reference: ! + children: + - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} + + - ! + name: Raw + aliases: [Utility - Raw] + family: Utility + equalitygroup: "" + bitdepth: 32f + description: The utility "Raw" colorspace. + isdata: true + categories: [file-io] + allocation: uniform + + - ! + name: ACEScg + family: ACES~Linear + equalitygroup: "" + bitdepth: unknown + description: from base + isdata: false + allocation: uniform + to_scene_reference: ! {style: ACEScg_to_ACES2065-1} + )" }; + + std::istringstream resultIss; + resultIss.str(RESULT); + OCIO::ConstConfigRcPtr resultConfig = OCIO::Config::CreateFromStream(resultIss); + std::ostringstream ossResult; + resultConfig->serialize(ossResult); + + //Testing the string of each config +// OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); + } + } +/* + // Test is very similar as the previous one but it has two merges in + // the OCIOM file and it is using the output of the first merged config + // as the input for the second merge. + { + std::vector paths = { + std::string(OCIO::GetTestFilesDir()), + std::string("configs"), + std::string("mergeconfigs"), + std::string("merged2"), + std::string("merged.ociom") + }; + const std::string ociomPath = pystring::os::path::normpath(pystring::os::path::join(paths)); + + // PreferInput, Input first + { + OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); + OCIO::ConstConfigMergerRcPtr newMerger; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&newMerger, &merger]() { newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); }, + "The Input config contains a value that would override the Base config: file_rules: Default", + "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'"); + OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); + std::ostringstream oss; + mergedConfig->serialize(oss); + + constexpr const char * RESULT { +R"(ocio_profile_version: 2.1 + +environment: + {} +search_path: lut_dir +strictparsing: true +luma: [0.2126, 0.7152, 0.0722] +name: Merged2 +description: Same as the input + +roles: + cie_xyz_d65_interchange: CIE-XYZ-D65 + +file_rules: + - ! {name: Default, colorspace: sRGB} + +displays: + sRGB - Display: + - ! {name: Raw, colorspace: raw} + - ! {name: ACES 1.0 - SDR Video, view_transform: SDR Video, display_colorspace: sRGB - Display} + +active_displays: [] +active_views: [] +inactive_colorspaces: [ACES2065-1] + +view_transforms: + - ! + name: SDR Video + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1} + +display_colorspaces: + - ! + name: sRGB - Display + aliases: [srgb_display] + family: Display~Standard + equalitygroup: "" + bitdepth: unknown + description: from input + isdata: false + allocation: uniform + from_display_reference: ! {gamma: 2.4, offset: 0.055, direction: inverse} + + - ! + name: CIE-XYZ-D65 + aliases: [cie_xyz_d65] + family: "" + equalitygroup: "" + bitdepth: unknown + description: The \"CIE XYZ (D65)\" display connection colorspace. + isdata: false + allocation: uniform + from_display_reference: ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1]} + +colorspaces: + - ! + name: ACES2065-1 + aliases: [aces] + family: ACES~Linear + equalitygroup: "" + bitdepth: unknown + description: from input + isdata: false + allocation: uniform + to_scene_reference: ! {matrix: [2.521686186744, -1.13413098824, -0.387555198504, 0, -0.27647991423, 1.372719087668, -0.096239173438, 0, -0.015378064966, -0.152975335867, 1.168353400833, 0, 0, 0, 0, 1]} + + - ! + name: sRGB + family: Texture~ + equalitygroup: "" + bitdepth: unknown + description: from input + isdata: false + allocation: uniform + to_scene_reference: ! {gamma: 2.4, offset: 0.055} + + - ! + name: rec709 + family: "" + equalitygroup: "" + bitdepth: unknown + description: from input + isdata: false + allocation: uniform + + - ! + name: Raw + aliases: [Utility - Raw] + family: Utility + equalitygroup: "" + bitdepth: 32f + description: The utility "Raw" colorspace. + isdata: true + categories: [file-io] + allocation: uniform + )" }; + + std::istringstream resultIss; + resultIss.str(RESULT); + OCIO::ConstConfigRcPtr resultConfig = OCIO::Config::CreateFromStream(resultIss); + std::ostringstream ossResult; + resultConfig->serialize(ossResult); + + //Testing the string of each config +// OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); + } + } +*/ + // Test with external LUT files. + { + std::vector paths = { + std::string(OCIO::GetTestFilesDir()), + std::string("configs"), + std::string("mergeconfigs"), + std::string("merged3"), + std::string("merged.ociom") + }; + const std::string ociomPath = pystring::os::path::normpath(pystring::os::path::join(paths)); + + // PreferInput, Input first + { + OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); + merger->getParams(0)->setAssumeCommonReferenceSpace(true); + OCIO::ConstConfigMergerRcPtr newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); + OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); + std::ostringstream oss; + mergedConfig->serialize(oss); + OCIO_CHECK_NO_THROW(mergedConfig->validate()); + + { + OCIO_CHECK_EQUAL(mergedConfig->getSearchPath(), std::string("./$SHOT:./shot1:shot2:.")); + auto cs = mergedConfig->getColorSpace("shot1_lut1_cs"); + auto tf = cs->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); + auto ftf = OCIO::DynamicPtrCast(tf); + OCIO_REQUIRE_ASSERT(ftf); + OCIO_CHECK_EQUAL(ftf->getSrc(), std::string("lut1.clf")); + OCIO_CHECK_NO_THROW(mergedConfig->getProcessor(ftf)) + } + { + auto look = mergedConfig->getLook("shot_look"); + auto ltf = look->getTransform(); + OCIO_CHECK_NO_THROW(mergedConfig->getProcessor(ltf)); + } + } + } + + // Test that a merge could go wrong if the search_paths are merged with a different strategy + // than the other sections. + { + std::vector paths = { + std::string(OCIO::GetTestFilesDir()), + std::string("configs"), + std::string("mergeconfigs"), + std::string("merged3"), + std::string("merged.ociom") + }; + const std::string ociomPath = pystring::os::path::normpath(pystring::os::path::join(paths)); + + { + OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); + // Changing the strategy for colorspace merger to BASE ONLY. + // This will break the looks "shot_look" (from input) as it needs the search paths + // from the input config. (search_paths are managed by the colorspace merger). + merger->getParams(0)->setColorspaces(OCIO::ConfigMergingParameters::STRATEGY_INPUT_ONLY); + // The rest of the merges uses PreferInput strategy. + + OCIO::ConstConfigMergerRcPtr newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); + OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); + auto look = mergedConfig->getLook("shot_look"); + auto ltf = look->getTransform(); + + // Expected to throw as the search_paths were merged following the InputOnly strategy + // and the looks were merged following the PreferInput (see OCIOM file default strategy). + // Therefore, the look's FileTransform can not find "look.cdl" and throws an exception. + OCIO_CHECK_THROW(mergedConfig->getProcessor(ltf), OCIO::Exception); + + // It can happens with any section that uses the search_paths such as looks, + // named_transforms and colorspaces. + } + } + + // Test with a built-in config. + { + std::vector paths = { + std::string(OCIO::GetTestFilesDir()), + std::string("configs"), + std::string("mergeconfigs"), + std::string("merged4"), + std::string("merged.ociom") + }; + const std::string ociomPath = pystring::os::path::normpath(pystring::os::path::join(paths)); + + // InputOnly + { + OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); + OCIO::ConstConfigMergerRcPtr newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); + OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); + std::ostringstream oss; + mergedConfig->serialize(oss); + + // Test that the merged config is the same of the built-in config used as input. + auto bConfig = OCIO::Config::CreateFromBuiltinConfig("cg-config-v1.0.0_aces-v1.3_ocio-v2.1"); +// OCIO_CHECK_EQUAL(std::string(mergedConfig->getCacheID()), std::string(bConfig->getCacheID())); + } + } + + // Test with an OCIOZ archive + // { + // std::vector paths = { + // std::string(OCIO::GetTestFilesDir()), + // std::string("configs"), + // std::string("mergeconfigs"), + // std::string("merged4"), + // std::string("merged.ociom") + // }; + // const std::string ociomPath = pystring::os::path::normpath(pystring::os::path::join(paths)); + + // // InputOnly + // { + // OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); + // // Update the merge to point to the OCIOZ archive as the input. + // merger->getParams(0)->setInputConfigName(""); + + // OCIO::ConstConfigMergerRcPtr newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); + // OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); + // std::ostringstream oss; + // mergedConfig->serialize(oss); + // OCIO_CHECK_NO_THROW(mergedConfig->validate()); + // } + //} +} diff --git a/tests/data/files/configs/mergeconfigs/base_colorspaces_config.yaml b/tests/data/files/configs/mergeconfigs/base_colorspaces_config.yaml new file mode 100644 index 0000000000..f9c581e994 --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/base_colorspaces_config.yaml @@ -0,0 +1,57 @@ +ocio_profile_version: 2 + +environment: + test: value + test1: value1 + +search_path: + - . + - abc + +family_separator: "#" +inactive_colorspaces: [sRGB - Texture, sRGB - Display, ACEScg] + +file_rules: + - ! {name: Default, colorspace: ACEScg} + +displays: + MyDisplay: + - ! {name: MyDisplayView, view_transform: MyViewTransform, display_colorspace: sRGB - Display} + +view_transforms: + - ! + name: MyViewTransform + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO_1.0} + +display_colorspaces: + - ! + name: sRGB - Display + aliases: [srgb_display] + family: Display#Basic + description: from base + from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_sRGB} + +colorspaces: + - ! + name: ACEScg + aliases: [aces] + family: ACES#Linear + description: from base + to_scene_reference: ! {style: ACEScg_to_ACES2065-1} + + - ! + name: sRGB - Texture + family: Texture + aliases: [srgb, srgb_tx] + description: from base + from_scene_reference: ! + children: + - ! {matrix: [2.52168618674388, -1.13413098823972, -0.387555198504164, 0, -0.276479914229922, 1.37271908766826, -0.096239173438334, 0, -0.0153780649660342, -0.152975335867399, 1.16835340083343, 0, 0, 0, 0, 1]} + - ! {gamma: 2.4, offset: 0.055, direction: inverse} + + - ! + name: look + aliases: + family: + description: from base + from_scene_reference: ! {src: ACEScg, dst: sRGB - Texture} diff --git a/tests/data/files/configs/mergeconfigs/base_config.yaml b/tests/data/files/configs/mergeconfigs/base_config.yaml new file mode 100644 index 0000000000..cf4a881358 --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/base_config.yaml @@ -0,0 +1,170 @@ +ocio_profile_version: 2 + +environment: + test: value + test1: value1 + +search_path: + - . + - abc + +name: base0 +description: | + My description 1 + +family_separator: '#' +strictparsing: true + +roles: + aces_interchange: ACES2065-1 + texture_paint: ACEScct + data: Raw + +file_rules: + - ! {name: LogC, colorspace: ACES2065-1, pattern: "*LogC*", extension: "*"} + - ! {name: TIFF, colorspace: Gamma 2.2 AP1 - Texture, regex: ".*\\.TIF?F$"} + - ! {name: OpenEXR, colorspace: ACEScct, extension: "exr", pattern: "*"} + - ! {name: ColorSpaceNamePathSearch} + - ! {name: Default, colorspace: Raw} + +shared_views: + - ! {name: SHARED_1, colorspace: lin_1} + - ! {name: SHARED_2, view_transform: SDR Video, display_colorspace: } + +viewing_rules: + - ! {name: RULE_1, colorspaces: [Gamma 2.2 AP1 - Texture]} + - ! {name: RULE_2, encodings: [scene-linear]} + +displays: + DISP_1: + - ! {name: VIEW_1, colorspace: view_1, rule: RULE_1} + - ! [ SHARED_1, SHARED_2 ] + DISP_2: + - ! {name: VIEW_1, colorspace: view_1, rule: RULE_2} + - ! {name: VIEW_2, colorspace: view_2, looks: look_base} + +virtual_display: + - ! {name: ACES, view_transform: SDR Video, display_colorspace: } + - ! {name: Log, colorspace: log_1} + - ! [ SHARED_1 ] + +looks: + - ! + name: look_both + process_space: ACES2065-1 + transform: ! {slope: [1, 2, 1]} + + - ! + name: look_base + process_space: log_1 + transform: ! {slope: [1, 2, 1]} + +active_displays: [DISP_1, DISP_2] +active_views: [ SHARED_1 , SHARED_2, VIEW_1 , VIEW_2, ] +inactive_colorspaces: [Gamma 2.2 AP1 - Texture] +default_view_transform: SDR Video + +view_transforms: + - ! + name: SDR Video + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO_1.0} + - ! + name: Un-tone-mapped + from_scene_reference: ! {style: UTILITY - ACES-AP0_to_CIE-XYZ-D65_BFD} + +named_transforms: + - ! + name: nt_both + aliases: [srgb_tx, namet2] + description: from base + family: + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {style: UTILITY - ACES-AP0_to_CIE-XYZ-D65_BFD} + + - ! + name: nt_base + aliases: [view_3, nt_input] + description: from base + family: nt + encoding: log + inverse_transform: ! {name: inverse, offset: [-0.2, -0.1, -0.1, 0]} + +colorspaces: + - ! + name: ACES2065-1 + aliases: [aces2065_1, ACES - ACES2065-1, lin_ap0] + family: ACES + equalitygroup: "" + bitdepth: 32f + description: The "Academy Color Encoding System" reference colorspace. + isdata: false + categories: [file-io] + encoding: scene-linear + allocation: uniform + + - ! + name: ACEScct + aliases: [ACES - ACEScct, acescct_ap1] + family: ACES + equalitygroup: "" + bitdepth: 32f + description: | + Convert ACEScct to ACES2065-1 + + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACEScct_to_ACES.a1.0.3 + isdata: false + categories: [file-io, working-space] + encoding: log + allocation: uniform + to_scene_reference: ! {style: ACEScct_to_ACES2065-1} + + - ! + name: Raw + aliases: [Utility - Raw] + family: Utility + equalitygroup: "" + bitdepth: 32f + description: The utility "Raw" colorspace. + isdata: true + categories: [file-io] + allocation: uniform + + - ! + name: Gamma 2.2 AP1 - Texture + aliases: [g22_ap1_tx, g22_ap1] + family: Utility + equalitygroup: "" + bitdepth: 32f + description: | + Convert ACES2065-1 to 2.2 gamma-corrected AP1 primaries, D60 white point + + CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_Gamma2.2_AP1-Texture:1.0 + isdata: false + categories: [file-io] + encoding: sdr-video + allocation: uniform + from_scene_reference: ! + name: AP0 to Gamma 2.2 AP1 - Texture + children: + - ! {matrix: [1.45143931614567, -0.23651074689374, -0.214928569251925, 0, -0.0765537733960206, 1.17622969983357, -0.0996759264375522, 0, 0.00831614842569772, -0.00603244979102102, 0.997716301365323, 0, 0, 0, 0, 1]} + - ! {value: 2.2, style: pass_thru, direction: inverse} + + - ! + name: view_1 + from_reference: ! {value: [2.6, 2.6, 2.6, 1], direction: inverse} + + - ! + name: view_2 + from_reference: ! {value: [2.4, 2.4, 2.4, 1], direction: inverse} + + - ! + name: log_1 + categories: [ working-space ] + encoding: log + to_reference: ! {base: 2, direction: inverse} + + - ! + name: lin_1 + categories: [ working-space ] + encoding: scene-linear \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/default_strategy.ociom b/tests/data/files/configs/mergeconfigs/default_strategy.ociom new file mode 100644 index 0000000000..03b949e21f --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/default_strategy.ociom @@ -0,0 +1,25 @@ +ociom_version: 1.0 +search_path: "." + +merge: + Merge1: + base: input0.ocio + input: input2.ocio + options: + input_family_prefix: "" + base_family_prefix: "" + input_first: true + error_on_conflict: false + default_strategy: InputOnly + avoid_duplicates: true + assume_common_reference_space: false + overrides: + name: my merge + description: my desc + search_path: "abc" + environment: + test: valueOther + test1: value123 + active_displays: ["D1", "D2"] + active_views: ["V1", "V2"] + inactive_colorspaces: ["I1", "I2"] \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/input_colorspaces_config.yaml b/tests/data/files/configs/mergeconfigs/input_colorspaces_config.yaml new file mode 100644 index 0000000000..808d8649e1 --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/input_colorspaces_config.yaml @@ -0,0 +1,63 @@ +ocio_profile_version: 2 + +environment: + test: differentValue + test3: value3 + +search_path: + - . + - def + +name: input config +description: The input test config. + +roles: + default: ACES2065-1 + +family_separator: "~" +inactive_colorspaces: [ACES2065-1, sRGB - Display] + +file_rules: + - ! {name: Default, colorspace: default} + +displays: + MyDisplay: + - ! {name: MyDisplayView, view_transform: MyViewTransform, display_colorspace: sRGB - Display} + +view_transforms: + - ! + name: MyViewTransform + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO_1.0} + +active_displays: [MyDisplay] +active_views: [MyDisplayView] + +display_colorspaces: + - ! + name: sRGB - Display + aliases: [srgb_display] + family: Display~Standard + description: from input + from_display_reference: ! {gamma: 2.4, offset: 0.055, direction: inverse} + + - ! + name: look + aliases: [look1] + family: Display~Standard + description: from input + from_display_reference: ! {gamma: 2.4, offset: 0.055, direction: inverse} + +colorspaces: + - ! + name: ACES2065-1 + aliases: [aces] + family: ACES~Linear + description: from input + to_scene_reference: ! {matrix: [ 2.521686186744, -1.134130988240, -0.387555198504, 0, -0.276479914230, 1.372719087668, -0.096239173438, 0, -0.015378064966, -0.152975335867, 1.168353400833, 0, 0, 0, 0, 1 ]} + + - ! + name: sRGB + aliases: [my_srgb] + family: Texture~ + description: from input + to_scene_reference: ! {gamma: 2.4, offset: 0.055} \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/input_config.yaml b/tests/data/files/configs/mergeconfigs/input_config.yaml new file mode 100644 index 0000000000..159bd3e841 --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/input_config.yaml @@ -0,0 +1,192 @@ +ocio_profile_version: 2 + +environment: + test: differentValue + test3: value3 + +search_path: + - . + - def + +name: input0 +description: | + My description 2 + +family_separator: '@' +strictparsing: false + +roles: + aces_interchange: ACES2065-1 + texture_paint: ACEScct - SomeOtherName + matte_paint: sRGB - Texture + g22_ap1_tx: view_3 + nt_base: log_3 + +file_rules: + - ! {name: LogC, colorspace: ACES2065-1, pattern: "*LogC*", extension: "*"} + - ! {name: TIFF, colorspace: sRGB - Texture, regex: ".*\\.TIF?F$", custom: {key1: value1, key2: value2}} + - ! {name: JPEG, colorspace: Linear Rec.2020, regex: ".*\\.jpeg$"} + - ! {name: ColorSpaceNamePathSearch} + - ! {name: Default, colorspace: ACEScct - SomeOtherName} + +shared_views: + - ! {name: SHARED_1, colorspace: lin_3} + - ! {name: SHARED_3, colorspace: log_3} + +viewing_rules: + - ! {name: RULE_1, colorspaces: [sRGB - Texture]} + - ! {name: RULE_3, colorspaces: [Linear Rec.2020, ACEScct - SomeOtherName]} + +displays: + DISP_1: + - ! {name: VIEW_1, colorspace: view_1B, rule: RULE_3} + - ! [ SHARED_3, SHARED_1 ] + DISP_3: + - ! {name: VIEW_1, colorspace: view_1} + - ! {name: VIEW_3, colorspace: view_3, looks: look_input} + +virtual_display: + - ! {name: ACES, view_transform: SDR Video, display_colorspace: } + - ! {name: Lin, colorspace: lin_3} + - ! [ SHARED_3 ] + +looks: + - ! + name: look_both + process_space: ACEScct - SomeOtherName + transform: ! {slope: [1, 2, 1]} + + - ! + name: look_input + process_space: log_3 + transform: ! {slope: [1, 2, 1]} + +active_displays: [DISP_1,DISP_3] +active_views: [SHARED_1,SHARED_3,VIEW_1,VIEW_3,] +inactive_colorspaces: [Linear Rec.2020, nt_both, nt_input, view_2] +default_view_transform: Un-tone-mapped-2 + +view_transforms: + - ! + name: SDR Video + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1} + - ! + name: Un-tone-mapped-2 + from_scene_reference: ! {style: UTILITY - ACES-AP0_to_CIE-XYZ-D65_BFD} + +named_transforms: + - ! + name: nt_both + aliases: [Utility - Raw, nametr] + description: from input + family: + categories: [ working-space, basic-3d, advanced-2d ] + encoding: sdr-video + transform: ! {name: forwardInput, offset: [0.1, 0.2, 0.3, 0.4]} + + - ! + name: nt_input + aliases: [Raw, in nt] + description: from input + categories: [ file-io, basic-2d ] + encoding: sdr-video + family: Raw + transform: ! {name: forward, offset: [0.1, 0.2, 0.3, 0.4]} + inverse_transform: ! {name: inverse, offset: [-0.2, -0.1, -0.1, 0]} + + - ! + name: view_2 + aliases: [g22_ap1] + description: from input + family: Raw + transform: ! {name: forward, offset: [0.1, 0.2, 0.3, 0.4]} + +colorspaces: + - ! + name: ACES2065-1 + aliases: [aces2065_1, ACES - ACES2065-1, lin_ap0] + family: ACES + equalitygroup: "" + bitdepth: 32f + description: The "Academy Color Encoding System" reference colorspace. 456 + isdata: false + categories: [file-io] + encoding: scene-linear + allocation: uniform + + - ! + name: ACEScct - SomeOtherName + aliases: [ACES - ACEScct123, acescct_ap1123] + family: ACES + equalitygroup: "" + bitdepth: 32f + description: | + Convert ACEScct to ACES2065-1 + + ACEStransformID: urn:ampas:aces:transformId:v1.5:ACEScsc.Academy.ACEScct_to_ACES.a1.0.3 + isdata: false + categories: [file-io, working-space] + encoding: log + allocation: uniform + to_scene_reference: ! {style: ACEScct_to_ACES2065-1} + + - ! + name: sRGB - Texture + aliases: [srgb_tx, Utility - sRGB - Texture, srgb_texture, Input - Generic - sRGB - Texture] + family: Utility + equalitygroup: "" + bitdepth: 32f + description: | + Convert ACES2065-1 to sRGB + + CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_sRGB-Texture:1.0 + isdata: false + categories: [file-io] + allocation: uniform + from_scene_reference: ! + name: AP0 to sRGB Rec.709 + children: + - ! {matrix: [2.52168618674388, -1.13413098823972, -0.387555198504164, 0, -0.276479914229922, 1.37271908766826, -0.096239173438334, 0, -0.0153780649660342, -0.152975335867399, 1.16835340083343, 0, 0, 0, 0, 1]} + - ! {gamma: 2.4, offset: 0.055, direction: inverse} + + - ! + name: Linear Rec.2020 + aliases: [lin_rec2020, Utility - Linear - Rec.2020] + family: Utility + equalitygroup: "" + bitdepth: 32f + description: | + Convert ACES2065-1 to linear Rec.2020 primaries, D65 white point + + CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_Linear_Rec2020:1.0 + isdata: false + categories: [file-io] + encoding: scene-linear + allocation: uniform + from_scene_reference: ! + name: AP0 to Linear Rec.2020 + children: + - ! {matrix: [1.49040952054172, -0.26617091926613, -0.224238601275593, 0, -0.0801674998722558, 1.18216712109757, -0.10199962122531, 0, 0.00322763119162216, -0.0347764757450576, 1.03154884455344, 0, 0, 0, 0, 1]} + + - ! + name: view_1 + from_reference: ! {value: [2.6, 2.6, 2.6, 1], direction: inverse} + + - ! + name: view_1B + from_reference: ! {value: [2.6, 2.6, 2.6, 1], direction: inverse} + + - ! + name: view_3 + from_reference: ! {value: [2.4, 2.4, 2.4, 1], direction: inverse} + + - ! + name: log_3 + categories: [ working-space ] + encoding: log + to_reference: ! {base: 2, direction: inverse} + + - ! + name: lin_3 + categories: [ working-space ] + encoding: scene-linear \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/merged1/base1.ocio b/tests/data/files/configs/mergeconfigs/merged1/base1.ocio new file mode 100644 index 0000000000..7ec6f6f3c4 --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/merged1/base1.ocio @@ -0,0 +1,55 @@ +ocio_profile_version: 2.1 +name: base +environment: + TEXTURE_SPACE: sRGB - Texture + SHOT: 001a + +search_path: + - luts + - . + +family_separator: "-" + +roles: + aces_interchange: ap0 + cie_xyz_d65_interchange: CIE-XYZ-D65 + +file_rules: + - ! {name: Default, colorspace: ACEScg} + +display_colorspaces: # reference space = cie xyz d65 + - ! + name: sRGB - Display + aliases: [srgb_display] + family: Display-Basic + description: from base + from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_sRGB} + + - ! + name: CIE-XYZ-D65 + aliases: [] + description: The \"CIE XYZ (D65)\" display connection colorspace. + isdata: false + +colorspaces: # reference space = aces2065-1 + - ! + name: ACEScg + aliases: [aces] + family: ACES-Linear + description: from base + to_scene_reference: ! {style: ACEScg_to_ACES2065-1} + + - ! + name: ap0 + family: ACES-Linear + description: from base + + - ! + name: sRGB - Texture + family: Texture + aliases: [srgb, srgb_tx] + description: from base + from_scene_reference: ! + children: + - ! {matrix: [2.52168618674388, -1.13413098823972, -0.387555198504164, 0, -0.276479914229922, 1.37271908766826, -0.096239173438334, 0, -0.0153780649660342, -0.152975335867399, 1.16835340083343, 0, 0, 0, 0, 1]} + - ! {gamma: 2.4, offset: 0.055, direction: inverse} \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/merged1/input1.ocio b/tests/data/files/configs/mergeconfigs/merged1/input1.ocio new file mode 100644 index 0000000000..b5c789f141 --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/merged1/input1.ocio @@ -0,0 +1,67 @@ +ocio_profile_version: 2.1 +name: input +search_path: lut_dir +inactive_colorspaces: [ACES2065-1] + +family_separator: "~" + +roles: + aces_interchange: ACES2065-1 + cie_xyz_d65_interchange: CIE-XYZ-D65 + +file_rules: + - ! {name: Default, colorspace: sRGB} + +displays: + sRGB - Display: + - ! {name: Raw, colorspace: raw} + - ! {name: ACES 1.0 - SDR Video, view_transform: SDR Video, display_colorspace: sRGB - Display} + +view_transforms: + - ! + name: SDR Video + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1} + +display_colorspaces: # reference space = linear rec 709 + - ! + name: sRGB - Display + aliases: [] + family: Display~Standard + description: from input + from_display_reference: ! {gamma: 2.4, offset: 0.055, direction: inverse} + + - ! + name: CIE-XYZ-D65 + aliases: [cie_xyz_d65] + description: The \"CIE XYZ (D65)\" display connection colorspace. + isdata: false + from_display_reference: ! {matrix: [ 0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.950532152250, 0, 0, 0, 0, 1 ]} + +colorspaces: # reference space = linear rec 709 + - ! + name: ACES2065-1 + aliases: [aces] + family: ACES~Linear + description: from input + to_scene_reference: ! {matrix: [ 2.521686186744, -1.134130988240, -0.387555198504, 0, -0.276479914230, 1.372719087668, -0.096239173438, 0, -0.015378064966, -0.152975335867, 1.168353400833, 0, 0, 0, 0, 1 ]} + + - ! + name: sRGB + family: Texture~ + description: from input + to_scene_reference: ! {gamma: 2.4, offset: 0.055} + + - ! + name: rec709 + description: from input + + - ! + name: Raw + aliases: [Utility - Raw] + family: Utility + equalitygroup: "" + bitdepth: 32f + description: The utility "Raw" colorspace. + isdata: true + categories: [file-io] + allocation: uniform \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/merged1/merged1.ociom b/tests/data/files/configs/mergeconfigs/merged1/merged1.ociom new file mode 100644 index 0000000000..9ca3d0d483 --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/merged1/merged1.ociom @@ -0,0 +1,23 @@ +ociom_version: 2.1 +search_path: "." + +merge: + Merge1: + base: base1.ocio + input: input1.ocio + options: + input_family_prefix: "" + base_family_prefix: "" + input_first: true + error_on_conflict: false + default_strategy: PreferInput + avoid_duplicates: true + assume_common_reference_space: false + overrides: + name: Merged1 + description: Basic merge with default strategy + search_path: "" + environment: {} + active_displays: [] + active_views: [] + inactive_colorspaces: [] \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/merged2/base.ocio b/tests/data/files/configs/mergeconfigs/merged2/base.ocio new file mode 100644 index 0000000000..acbfa4eede --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/merged2/base.ocio @@ -0,0 +1,52 @@ +ocio_profile_version: 2.1 +name: base +environment: + TEXTURE_SPACE: sRGB - Texture + SHOT: 001a + +search_path: + - luts + - . + +roles: + cie_xyz_d65_interchange: CIE-XYZ-D65 + +file_rules: + - ! {name: Default, colorspace: ACEScg} + +display_colorspaces: # reference space = cie xyz d65 + - ! + name: sRGB - Display + aliases: [srgb_display] + family: Display-Basic + description: from base + from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_sRGB} + + - ! + name: CIE-XYZ-D65 + aliases: [cie_xyz_d65] + description: The \"CIE XYZ (D65)\" display connection colorspace. + isdata: false + +colorspaces: # reference space = aces2065-1 + - ! + name: ACEScg + aliases: [aces] + family: ACES-Linear + description: from base + to_scene_reference: ! {style: ACEScg_to_ACES2065-1} + + - ! + name: ap0 + family: ACES-Linear + description: from base + + - ! + name: sRGB - Texture + family: Texture + aliases: [srgb, srgb_tx] + description: from base + from_scene_reference: ! + children: + - ! {matrix: [2.52168618674388, -1.13413098823972, -0.387555198504164, 0, -0.276479914229922, 1.37271908766826, -0.096239173438334, 0, -0.0153780649660342, -0.152975335867399, 1.16835340083343, 0, 0, 0, 0, 1]} + - ! {gamma: 2.4, offset: 0.055, direction: inverse} \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/merged2/input.ocio b/tests/data/files/configs/mergeconfigs/merged2/input.ocio new file mode 100644 index 0000000000..379b8241b0 --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/merged2/input.ocio @@ -0,0 +1,64 @@ +ocio_profile_version: 2.1 +name: input +search_path: lut_dir +inactive_colorspaces: [ACES2065-1] + +roles: + cie_xyz_d65_interchange: CIE-XYZ-D65 + +file_rules: + - ! {name: Default, colorspace: sRGB} + +displays: + sRGB - Display: + - ! {name: Raw, colorspace: raw} + - ! {name: ACES 1.0 - SDR Video, view_transform: SDR Video, display_colorspace: sRGB - Display} + +view_transforms: + - ! + name: SDR Video + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1} + +display_colorspaces: # reference space = linear rec 709 + - ! + name: sRGB - Display + aliases: [srgb_display] + family: Display~Standard + description: from input + from_display_reference: ! {gamma: 2.4, offset: 0.055, direction: inverse} + + - ! + name: CIE-XYZ-D65 + aliases: [cie_xyz_d65] + description: The \"CIE XYZ (D65)\" display connection colorspace. + isdata: false + from_display_reference: ! {matrix: [ 0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.950532152250, 0, 0, 0, 0, 1 ]} + +colorspaces: # reference space = linear rec 709 + - ! + name: ACES2065-1 + aliases: [aces] + family: ACES~Linear + description: from input + to_scene_reference: ! {matrix: [ 2.521686186744, -1.134130988240, -0.387555198504, 0, -0.276479914230, 1.372719087668, -0.096239173438, 0, -0.015378064966, -0.152975335867, 1.168353400833, 0, 0, 0, 0, 1 ]} + + - ! + name: sRGB + family: Texture~ + description: from input + to_scene_reference: ! {gamma: 2.4, offset: 0.055} + + - ! + name: rec709 + description: from input + + - ! + name: Raw + aliases: [Utility - Raw] + family: Utility + equalitygroup: "" + bitdepth: 32f + description: The utility "Raw" colorspace. + isdata: true + categories: [file-io] + allocation: uniform \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/merged2/merged.ociom b/tests/data/files/configs/mergeconfigs/merged2/merged.ociom new file mode 100644 index 0000000000..b0db1537e6 --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/merged2/merged.ociom @@ -0,0 +1,43 @@ +ociom_version: 2.1 +search_path: "." + +# This OCIOM file is used to test multiple merges. +merge: + Merge1: + base: base.ocio + input: input.ocio + options: + input_family_prefix: "" + base_family_prefix: "" + input_first: true + error_on_conflict: false + default_strategy: PreferInput + avoid_duplicates: true + assume_common_reference_space: false + overrides: + name: Merged1 + description: Basic merge with default strategy + search_path: "" + environment: {} + active_displays: [] + active_views: [] + inactive_colorspaces: [] + Merge2: + base: Merge1 + input: input.ocio + options: + input_family_prefix: "" + base_family_prefix: "" + input_first: true + error_on_conflict: false + default_strategy: InputOnly + avoid_duplicates: true + assume_common_reference_space: false + overrides: + name: Merged2 + description: Same as the input + search_path: "" + environment: {} + active_displays: [] + active_views: [] + inactive_colorspaces: [] \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/merged3/base.ocio b/tests/data/files/configs/mergeconfigs/merged3/base.ocio new file mode 100644 index 0000000000..cbf1e63f20 --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/merged3/base.ocio @@ -0,0 +1,27 @@ +ocio_profile_version: 2.1 + +environment: + SHOT: shot1 + +search_path: + - ./$SHOT + - shot2 + - . + +roles: + default: raw + +displays: + sRGB: + - ! {name: Raw, colorspace: raw} + +looks: + - ! + name: shot_look + process_space: reference + transform: ! {src: "looks.cdl", cccid: $CCCID} + +colorspaces: + - ! + name: raw + isdata: true \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/merged3/input.ocio b/tests/data/files/configs/mergeconfigs/merged3/input.ocio new file mode 100644 index 0000000000..6c6b14dec2 --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/merged3/input.ocio @@ -0,0 +1,38 @@ +ocio_profile_version: 2.1 + +environment: + SHOT: shot4 + LUT_PATH: shot3/lut1.clf + CCCID: look-02 + +search_path: + - ./$SHOT + - ./shot1 + +roles: + default: raw + scene_linear: reference + +displays: + sRGB: + - ! {name: Raw, colorspace: raw} + +looks: + - ! + name: shot_look + process_space: reference + transform: ! {src: "looks.cdl", cccid: $CCCID} + +colorspaces: + + - ! + name: reference + isdata: false + + - ! + name: raw + isdata: true + + - ! + name: shot1_lut1_cs + to_reference: ! {src: lut1.clf} \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/merged3/looks.cdl b/tests/data/files/configs/mergeconfigs/merged3/looks.cdl new file mode 100644 index 0000000000..e14d42bb91 --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/merged3/looks.cdl @@ -0,0 +1,42 @@ + + + + + + 1.1 1.0 0.9 + -.03 -2e-2 0 + 1.25 1 1e0 + + + 1.700000 + + + + + + + + 0.9000 0.700 0.6000 + 0.100 0.100 0.100 + 0.9 0.9 0.9 + + + 0.7 + + + + + + + + 1.2000 1.1000 1.0000 + 0.000 0.0000 0.0000 + 0.9 1.0 1.2 + + + 1.000000 + + + + + diff --git a/tests/data/files/configs/mergeconfigs/merged3/lut1.clf b/tests/data/files/configs/mergeconfigs/merged3/lut1.clf new file mode 100644 index 0000000000..d948a1e5dd --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/merged3/lut1.clf @@ -0,0 +1,10 @@ + + + + +5 0 0 +0 5 0 +0 0 5 + + + \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/merged3/merged.ociom b/tests/data/files/configs/mergeconfigs/merged3/merged.ociom new file mode 100644 index 0000000000..bca325cfe8 --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/merged3/merged.ociom @@ -0,0 +1,25 @@ +ociom_version: 2.1 +search_path: "." + +# This OCIOM file is used to test that FileTransform's +# paths are still valid after a merge. +merge: + MergeExternalLutFiles: + base: base.ocio + input: input.ocio + options: + input_family_prefix: "" + base_family_prefix: "" + input_first: true + error_on_conflict: false + default_strategy: PreferInput + avoid_duplicates: true + assume_common_reference_space: false + overrides: + name: Merged1 + description: Basic merge with default strategy + search_path: "" + environment: {} + active_displays: [] + active_views: [] + inactive_colorspaces: [] \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/merged3/shot1/lut1.clf b/tests/data/files/configs/mergeconfigs/merged3/shot1/lut1.clf new file mode 100644 index 0000000000..4750b14b38 --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/merged3/shot1/lut1.clf @@ -0,0 +1,10 @@ + + + + +10 0 0 +0 10 0 +0 0 10 + + + \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/merged3/shot2/lut1.clf b/tests/data/files/configs/mergeconfigs/merged3/shot2/lut1.clf new file mode 100644 index 0000000000..14826c0f96 --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/merged3/shot2/lut1.clf @@ -0,0 +1,10 @@ + + + + +20 0 0 +0 20 0 +0 0 20 + + + \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/merged3/shot4/lut1.clf b/tests/data/files/configs/mergeconfigs/merged3/shot4/lut1.clf new file mode 100644 index 0000000000..14826c0f96 --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/merged3/shot4/lut1.clf @@ -0,0 +1,10 @@ + + + + +20 0 0 +0 20 0 +0 0 20 + + + \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/merged4/base1.ocio b/tests/data/files/configs/mergeconfigs/merged4/base1.ocio new file mode 100644 index 0000000000..acbfa4eede --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/merged4/base1.ocio @@ -0,0 +1,52 @@ +ocio_profile_version: 2.1 +name: base +environment: + TEXTURE_SPACE: sRGB - Texture + SHOT: 001a + +search_path: + - luts + - . + +roles: + cie_xyz_d65_interchange: CIE-XYZ-D65 + +file_rules: + - ! {name: Default, colorspace: ACEScg} + +display_colorspaces: # reference space = cie xyz d65 + - ! + name: sRGB - Display + aliases: [srgb_display] + family: Display-Basic + description: from base + from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_sRGB} + + - ! + name: CIE-XYZ-D65 + aliases: [cie_xyz_d65] + description: The \"CIE XYZ (D65)\" display connection colorspace. + isdata: false + +colorspaces: # reference space = aces2065-1 + - ! + name: ACEScg + aliases: [aces] + family: ACES-Linear + description: from base + to_scene_reference: ! {style: ACEScg_to_ACES2065-1} + + - ! + name: ap0 + family: ACES-Linear + description: from base + + - ! + name: sRGB - Texture + family: Texture + aliases: [srgb, srgb_tx] + description: from base + from_scene_reference: ! + children: + - ! {matrix: [2.52168618674388, -1.13413098823972, -0.387555198504164, 0, -0.276479914229922, 1.37271908766826, -0.096239173438334, 0, -0.0153780649660342, -0.152975335867399, 1.16835340083343, 0, 0, 0, 0, 1]} + - ! {gamma: 2.4, offset: 0.055, direction: inverse} \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/merged4/merged.ociom b/tests/data/files/configs/mergeconfigs/merged4/merged.ociom new file mode 100644 index 0000000000..e8e27a07e2 --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/merged4/merged.ociom @@ -0,0 +1,23 @@ +ociom_version: 2.1 +search_path: "." + +merge: + Merge1: + base: base1.ocio + input: cg-config-v1.0.0_aces-v1.3_ocio-v2.1 + options: + input_family_prefix: "" + base_family_prefix: "" + input_first: true + error_on_conflict: false + default_strategy: InputOnly + avoid_duplicates: true + assume_common_reference_space: false + overrides: + name: "" + description: "" + search_path: "" + environment: {} + active_displays: [] + active_views: [] + inactive_colorspaces: [] \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/parser_test.ociom b/tests/data/files/configs/mergeconfigs/parser_test.ociom new file mode 100644 index 0000000000..bbdcbee8e4 --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/parser_test.ociom @@ -0,0 +1,47 @@ +ociom_version: 1.0 +search_path: "." + +merge: + Merge1: + base: base0.ocio + input: input0.ocio + options: + input_family_prefix: "abc" + base_family_prefix: "def" + input_first: true + error_on_conflict: false + default_strategy: InputOnly + avoid_duplicates: true + assume_common_reference_space: false + overrides: + name: my merge + description: my desc + search_path: "abc" + environment: + test: valueOther + test1: value123 + active_displays: ["D1", "D2"] + active_views: ["V1", "V2"] + inactive_colorspaces: ["I1", "I2"] + params: + roles: + strategy: PreferInput + + file_rules: + strategy: PreferBase + + display-views: + # Includes shared_views, displays, view_transforms, viewing_rules, virtual_display, + # active_display, active_views and default_view_transform. + strategy: InputOnly + + looks: + strategy: BaseOnly + + colorspaces: + # Includes colorspaces, display_colorspaces, environment, + # search_path, family_separator and inactive_colorspaces. + strategy: Remove + + named_transform: + strategy: PreferBase \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/parser_test_no_overrides.ociom b/tests/data/files/configs/mergeconfigs/parser_test_no_overrides.ociom new file mode 100644 index 0000000000..93ffbcc65d --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/parser_test_no_overrides.ociom @@ -0,0 +1,47 @@ +ociom_version: 1.0 +search_path: "." + +merge: + Merge1: + base: input0.ocio + input: input2.ocio + options: + input_family_prefix: "abc" + base_family_prefix: "def" + input_first: true + error_on_conflict: false + default_strategy: InputOnly + avoid_duplicates: true + assume_common_reference_space: false + # If no overrides are needed, the overrides can be + # removed from the file or initialized as follows: + # overrides: + # name: "" + # description: "" + # search_path: "" + # environment: {} + # active_displays: [] + # active_views: [] + # inactive_colorspaces: [] + params: + roles: + strategy: PreferInput + + file_rules: + strategy: PreferBase + + display-views: + # Includes shared_views, displays, view_transforms, viewing_rules, virtual_display, + # active_display, active_views and default_view_transform. + strategy: InputOnly + + looks: + strategy: BaseOnly + + colorspaces: + # Includes colorspaces, display_colorspaces, environment, + # search_path, family_separator and inactive_colorspaces. + strategy: Remove + + named_transform: + strategy: PreferBase \ No newline at end of file diff --git a/tests/utils/StringUtils_tests.cpp b/tests/utils/StringUtils_tests.cpp index e258832b17..ccf15c7f4f 100644 --- a/tests/utils/StringUtils_tests.cpp +++ b/tests/utils/StringUtils_tests.cpp @@ -218,4 +218,10 @@ OCIO_ADD_TEST(StringUtils, remove_contain) OCIO_CHECK_EQUAL(res.size(), 5); OCIO_CHECK_ASSERT(!StringUtils::Contain(res, "3")); } + { + // Validate that Contain requires a full-match, not just a partial match. + static const StringUtils::StringVec values{"2 ", " 2 ", " 2", "2,", "2\n"}; + OCIO_CHECK_ASSERT(StringUtils::Contain(values, " 2 ")); + OCIO_CHECK_ASSERT(!StringUtils::Contain(values, "2")); + } } From ce3e1557a86e2656a30b1448e13e2f712662a6b4 Mon Sep 17 00:00:00 2001 From: Doug Walker Date: Wed, 10 Apr 2024 00:24:02 -0400 Subject: [PATCH 02/14] Add API for config and colorspace merge Signed-off-by: Doug Walker (cherry picked from commit fadef86510ecbf10d991c61983c91e860358f78f) Signed-off-by: Doug Walker --- include/OpenColorIO/OpenColorAppHelpers.h | 30 +++++ .../mergeconfigs/MergeConfigsHelpers.cpp | 97 +++++++++++++--- .../mergeconfigs/MergeConfigsHelpers.h | 65 ++++++----- .../apphelpers/mergeconfigs/OCIOMYaml.cpp | 12 +- .../apphelpers/mergeconfigs/OCIOMYaml.h | 5 +- .../apphelpers/mergeconfigs/SectionMerger.h | 36 +++--- .../apphelpers/MergeConfigsHelpers_tests.cpp | 106 +++++++++++++++++- 7 files changed, 279 insertions(+), 72 deletions(-) diff --git a/include/OpenColorIO/OpenColorAppHelpers.h b/include/OpenColorIO/OpenColorAppHelpers.h index 3e5a466ca8..75bd78d1e7 100644 --- a/include/OpenColorIO/OpenColorAppHelpers.h +++ b/include/OpenColorIO/OpenColorAppHelpers.h @@ -782,6 +782,7 @@ extern OCIOEXPORT std::ostream & operator<<(std::ostream &, const ColorSpaceMenu namespace ConfigMergingHelpers { + /** * \brief Execute the merge(s) based on the merger object. * @@ -793,6 +794,35 @@ namespace ConfigMergingHelpers * \return OCIOEXPORT */ extern OCIOEXPORT ConstConfigMergerRcPtr MergeConfigs(const ConstConfigMergerRcPtr & merger); + +/** + * \brief Merge the input into the base config, using the supplied merge parameters. + * + * \param params ConfigMergingParameters controlling the merger. + * \param params The base config. + * \param params The input config to merge. + * \return The merged config object. + */ +extern OCIOEXPORT ConfigRcPtr MergeConfigs(const ConfigMergingParametersRcPtr & params, + const ConstConfigRcPtr & baseConfig, + const ConstConfigRcPtr & inputConfig); + +/** + * \brief Merge a single color space into the base config, using the supplied merge parameters. + * + * Note that the assumeCommonReferenceSpace merge parameter will be ignored and set to true. + * To use automatice reference space conversion, add the color space to an input config that + * has the necessary interchange role set. + * + * \param params ConfigMergingParameters controlling the merger. + * \param params The base config. + * \param params The input color space to merge. + * \return The merged config object. + */ +extern OCIOEXPORT ConfigRcPtr MergeColorSpace(const ConfigMergingParametersRcPtr & params, + const ConstConfigRcPtr & baseConfig, + const ConstColorSpaceRcPtr & colorspace); + } // ConfigMergingHelpers } // namespace OCIO_NAMESPACE diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp index 643dd913a5..0e5f770f04 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp +++ b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp @@ -359,7 +359,7 @@ ConstConfigMergerRcPtr ConfigMerger::Impl::Read(std::istream & istream, const ch for (int i = 0; i < numOfMerges; i++) { ConfigMergingParametersRcPtr params = ConfigMergingParameters::Create(); - merger->getImpl()->mergesParams.push_back(params); + merger->getImpl()->m_mergeParams.push_back(params); } ociomParser.load(node, merger, filepath); @@ -402,9 +402,9 @@ ConstConfigRcPtr ConfigMerger::Impl::loadConfig(const char * value) const if (Platform::Strcasecmp(getParams(i)->getOutputName(), value) == 0) { // Use the config from the index. - if (i < mergedConfigs.size()) + if (i < (int) m_mergedConfigs.size()) { - return mergedConfigs.at(i); + return m_mergedConfigs.at(i); } } } @@ -501,21 +501,21 @@ const char * ConfigMerger::getWorkingDir() const ConfigMergingParametersRcPtr ConfigMerger::getParams(int index) const { - if (index < static_cast(getImpl()->mergesParams.size())) + if (index < static_cast(getImpl()->m_mergeParams.size())) { - return getImpl()->mergesParams.at(index); + return getImpl()->m_mergeParams.at(index); } return nullptr; } int ConfigMerger::getNumOfConfigMergingParameters() const { - return static_cast(getImpl()->mergesParams.size()); + return static_cast(getImpl()->m_mergeParams.size()); } void ConfigMerger::addParams(ConfigMergingParametersRcPtr params) { - getImpl()->mergesParams.push_back(params); + getImpl()->m_mergeParams.push_back(params); } void ConfigMerger::serialize(std::ostream& os) const @@ -561,19 +561,19 @@ void ConfigMerger::setVersion(unsigned int major, unsigned int minor) void ConfigMerger::addMergedConfig(ConstConfigRcPtr cfg) { - getImpl()->mergedConfigs.push_back(cfg); + getImpl()->m_mergedConfigs.push_back(cfg); } ConstConfigRcPtr ConfigMerger::getMergedConfig() const { - return getMergedConfig(static_cast(getImpl()->mergedConfigs.size() - 1)); + return getMergedConfig(static_cast(getImpl()->m_mergedConfigs.size() - 1)); } ConstConfigRcPtr ConfigMerger::getMergedConfig(int index) const { - if (index < static_cast(getImpl()->mergedConfigs.size())) + if (index < static_cast(getImpl()->m_mergedConfigs.size())) { - return getImpl()->mergedConfigs.at(index); + return getImpl()->m_mergedConfigs.at(index); } return nullptr; } @@ -612,8 +612,8 @@ ConstConfigRcPtr loadConfig(const ConfigMergerRcPtr merger, { try { - // Try to load the provided config using the searchpaths. - // Return as soon as they a valid path. + // Try to load the provided config using the search paths. + // Return as soon as they find a valid path. const std::string resolvedfullpath = pystring::os::path::join(searchpaths[i], value); return Config::CreateFromFile(resolvedfullpath.c_str()); @@ -658,7 +658,7 @@ ConstConfigMergerRcPtr MergeConfigs(const ConstConfigMergerRcPtr & merger) if (baseCfg && inputCfg) { - // Create a copy of the base config. + // The merged config must be initialized with a copy of the base config. ConfigRcPtr mergedConfig = baseCfg->createEditableCopy(); // Process merge. @@ -678,7 +678,7 @@ ConstConfigMergerRcPtr MergeConfigs(const ConstConfigMergerRcPtr & merger) throw(e); } - // Add new config object to mergedConfigs so they can be used for following merges. + // Add new config object to m_mergedConfigs so they can be used for following merges. editableMerger->addMergedConfig(mergedConfig); } else @@ -690,6 +690,73 @@ ConstConfigMergerRcPtr MergeConfigs(const ConstConfigMergerRcPtr & merger) return editableMerger; } +ConfigRcPtr MergeConfigs(const ConfigMergingParametersRcPtr & params, + const ConstConfigRcPtr & baseConfig, + const ConstConfigRcPtr & inputConfig) +{ + if (!baseConfig || !inputConfig) + { + throw(Exception("The input or base config was not set.")); + } + + // The merged config must be initialized with a copy of the base config. + ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + + // Process the merge. + try + { + MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + GeneralMerger(options).merge(); + RolesMerger(options).merge(); + FileRulesMerger(options).merge(); + DisplayViewMerger(options).merge(); + LooksMerger(options).merge(); + ColorspacesMerger(options).merge(); + NamedTransformsMerger(options).merge(); + } + catch(const Exception & e) + { + throw(e); + } + + return mergedConfig; +} + +ConfigRcPtr MergeColorSpace(const ConfigMergingParametersRcPtr & params, + const ConstConfigRcPtr & baseConfig, + const ConstColorSpaceRcPtr & colorspace) +{ + if (!baseConfig || !colorspace) + { + throw(Exception("The base config or color space object was not set.")); + } + + // Create an input config and add the color space. + ConfigRcPtr inputConfig = Config::Create(); + inputConfig->addColorSpace(colorspace); + + // The merged config must be initialized with a copy of the base config. + ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + + // With only the color space, the reference space is unknown, so turn off + // automatic reference space conversion to the reference space of the base config. + ConfigMergingParametersRcPtr eParams = params->createEditableCopy(); + eParams->setAssumeCommonReferenceSpace(true); + + // Process the merge. + try + { + MergeHandlerOptions options = { baseConfig, inputConfig, eParams, mergedConfig }; + ColorspacesMerger(options).merge(); + } + catch(const Exception & e) + { + throw(e); + } + + return mergedConfig; +} + } // ConfigMergingHelpers } // namespace OCIO_NAMESPACE diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h index 4e2d54af17..b69a31e9a1 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h +++ b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h @@ -21,26 +21,29 @@ namespace OCIO_NAMESPACE class ConfigMergingParameters::Impl { public: + // Names or paths for identifying the base and input configs. std::string m_baseConfig; std::string m_inputConfig; + + // Name for the output config (may be used as the input or base config for a subsequent merger). std::string m_outputName; - // overrides + // Overrides used to replace various parameters of a merged config. std::string m_name; std::string m_description; - std::vector m_searchPaths; - StringUtils::StringVec m_activeDisplays; - StringUtils::StringVec m_activeViews; - StringUtils::StringVec m_inactiveColorspaces; - mutable std::string m_activeDisplaysStr; - mutable std::string m_activeViewsStr; - mutable std::string m_inactiveColorSpaceStr; +// std::vector m_searchPaths; +// StringUtils::StringVec m_activeDisplays; +// StringUtils::StringVec m_activeViews; +// StringUtils::StringVec m_inactiveColorspaces; +// mutable std::string m_activeDisplaysStr; +// mutable std::string m_activeViewsStr; +// mutable std::string m_inactiveColorSpaceStr; // Used to store the overrides for the following sections: // search_path, active_displays, active_views and inactive_colorspace. ConfigRcPtr m_overrideCfg; - // Options + // Options for the merger. std::string m_inputFamilyPrefix; std::string m_baseFamilyPrefix; bool m_inputFirst; @@ -48,15 +51,17 @@ class ConfigMergingParameters::Impl bool m_avoidDuplicates; bool m_assumeCommonReferenceSpace; - // Strategies + // Merge strategy for each section of the config. + + // The default strategy is used for any sections where a strategy was not specified. MergeStrategies m_defaultStrategy; MergeStrategies m_roles; MergeStrategies m_fileRules; // Includes shared_views, displays, view_transforms, viewing_rules, virtual_display, - // active_display, active_views and default_view_transform. + // active_display, active_views, and default_view_transform. MergeStrategies m_displayViews; MergeStrategies m_looks; - // colorspace, environment, search_path, family_separator and inactive_colorspaces + // Includes colorspaces, environment, search_path, family_separator, and inactive_colorspaces. MergeStrategies m_colorspaces; MergeStrategies m_namedTransforms; @@ -103,7 +108,7 @@ class ConfigMergingParameters::Impl // Overrides m_name = rhs.m_name; m_description = rhs.m_description; - m_searchPaths = rhs.m_searchPaths; +// m_searchPaths = rhs.m_searchPaths; // Options m_defaultStrategy = rhs.m_defaultStrategy; @@ -128,14 +133,22 @@ class ConfigMergingParameters::Impl class ConfigMerger::Impl { public: + // This is the set of search paths for the config files that will be merged. + // (Each of the configs has its own search path for its LUTs.) StringUtils::StringVec m_searchPaths; + + // std::string m_workingDir; + // Version for the .ociom file format. unsigned int m_majorVersion; unsigned int m_minorVersion; - std::vector mergesParams; - std::vector mergedConfigs; + // Vector of merge parameter objects, each one corresponding to one merge. + std::vector m_mergeParams; + + // Vector of config objects, the output of each merge. + std::vector m_mergedConfigs; Impl() { @@ -154,18 +167,18 @@ class ConfigMerger::Impl m_majorVersion = rhs.m_majorVersion; m_minorVersion = rhs.m_minorVersion; - mergesParams.clear(); - mergesParams.reserve(rhs.mergesParams.size()); - for (const auto & param : rhs.mergesParams) + m_mergeParams.clear(); + m_mergeParams.reserve(rhs.m_mergeParams.size()); + for (const auto & param : rhs.m_mergeParams) { - mergesParams.push_back(param->createEditableCopy()); + m_mergeParams.push_back(param->createEditableCopy()); } - mergedConfigs.clear(); - mergedConfigs.reserve(rhs.mergedConfigs.size()); - for (const auto & config : rhs.mergedConfigs) + m_mergedConfigs.clear(); + m_mergedConfigs.reserve(rhs.m_mergedConfigs.size()); + for (const auto & config : rhs.m_mergedConfigs) { - mergedConfigs.push_back(config->createEditableCopy()); + m_mergedConfigs.push_back(config->createEditableCopy()); } } return *this; @@ -186,16 +199,16 @@ class ConfigMerger::Impl ConfigMergingParametersRcPtr getParams(int index) const { - if (index >= 0 && index < static_cast(mergesParams.size())) + if (index >= 0 && index < static_cast(m_mergeParams.size())) { return nullptr; } - return mergesParams.at(index); + return m_mergeParams.at(index); } int getNumOfConfigMergingParameters() const { - return static_cast(mergesParams.size()); + return static_cast(m_mergeParams.size()); } }; diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp index 4baee5d175..76b0e3be74 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp +++ b/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp @@ -513,7 +513,7 @@ inline void save(YAML::Emitter & out, const ConfigMerger & merger) out << YAML::Value << YAML::BeginMap; out << YAML::Key << "base" << YAML::Value << p->getBaseConfigName(); - out << YAML::Key << "input" << YAML::Value << p->getBaseConfigName(); + out << YAML::Key << "input" << YAML::Value << p->getInputConfigName(); out << YAML::Newline; out << YAML::Key << "options"; @@ -579,27 +579,27 @@ inline void save(YAML::Emitter & out, const ConfigMerger & merger) out << YAML::Key << "file_rules"; out << YAML::Value << YAML::BeginMap; - out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getRoles()); + out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getFileRules()); out << YAML::EndMap; out << YAML::Key << "display-views"; out << YAML::Value << YAML::BeginMap; - out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getRoles()); + out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getDisplayViews()); out << YAML::EndMap; out << YAML::Key << "looks"; out << YAML::Value << YAML::BeginMap; - out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getRoles()); + out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getLooks()); out << YAML::EndMap; out << YAML::Key << "colorspaces"; out << YAML::Value << YAML::BeginMap; - out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getRoles()); + out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getColorspaces()); out << YAML::EndMap; out << YAML::Key << "named_transform"; out << YAML::Value << YAML::BeginMap; - out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getRoles()); + out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getNamedTransforms()); out << YAML::EndMap; // End of params section. diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.h b/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.h index d7f3ae4014..9bbbda0536 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.h +++ b/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.h @@ -13,7 +13,8 @@ namespace OCIO_NAMESPACE { -// Handles the OCIOM file parsing. +// Handles the OCIOM file format parsing. + class OCIOMYaml { public: @@ -52,7 +53,7 @@ class OCIOMYaml void load(const YAML::Node & node, std::vector & x); /** - * \brief Load a OCIOM file. + * \brief Load an OCIOM file. */ void load(const YAML::Node& node, ConfigMergerRcPtr & merger, const char * filename); diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.h b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.h index ab40566785..8e44efcce8 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.h +++ b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.h @@ -30,18 +30,16 @@ class SectionMerger { public: - enum MergerFlag - { - MERGERSTATE_NOFLAG, - MERGERSTATE_ADD_INITIAL_CONFIG, - }; - SectionMerger(MergeHandlerOptions options) : m_baseConfig(options.baseConfig), m_inputConfig(options.inputConfig), m_mergedConfig(options.mergedConfig), m_params(options.params) { - m_strategy = options.params->getDefaultStrategy(); - m_params->setDefaultStrategy(options.params->getDefaultStrategy()); + if (!options.baseConfig || !options.inputConfig || !options.mergedConfig || !options.params) + { + throw Exception("SectionMerger arguments were not initialized."); + } +// m_strategy = options.params->getDefaultStrategy(); +// m_params->setDefaultStrategy(options.params->getDefaultStrategy()); } void merge() @@ -64,7 +62,7 @@ class SectionMerger handleRemove(); break; case ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET: - // nothing to do. + // Nothing to do. break; default: break; @@ -76,27 +74,27 @@ class SectionMerger private: virtual void handlePreferInput() { - LogWarning(getName() + std::string(" section does not supported strategy 'PreferInput'")); + LogWarning(getName() + std::string(" section does not support strategy 'PreferInput'")); } virtual void handlePreferBase() { - LogWarning(getName() + std::string(" section does not supported strategy 'PreferBase'")); + LogWarning(getName() + std::string(" section does not support strategy 'PreferBase'")); } virtual void handleInputOnly() { - LogWarning(getName() + std::string(" section does not supported strategy 'InputOnly'")); + LogWarning(getName() + std::string(" section does not support strategy 'InputOnly'")); } virtual void handleBaseOnly() { - LogWarning(getName() + std::string(" section does not supported strategy 'BaseOnly'")); + LogWarning(getName() + std::string(" section does not support strategy 'BaseOnly'")); } virtual void handleRemove() { - LogWarning(getName() + std::string(" section does not supported strategy 'Remove'")); + LogWarning(getName() + std::string(" section does not support strategy 'Remove'")); } protected: @@ -128,7 +126,7 @@ class GeneralMerger : public SectionMerger } private: - const std::string getName() const { return "Miscellaneous"; } + const std::string getName() const { return "General"; } void handlePreferInput(); void handlePreferBase(); @@ -285,8 +283,6 @@ class ColorspacesMerger : public SectionMerger { m_strategy = options.params->getDefaultStrategy(); } - - m_state = MERGERSTATE_NOFLAG; } struct ColorspaceNameConflict @@ -301,13 +297,12 @@ class ColorspacesMerger : public SectionMerger private: // Attributes - MergerFlag m_state; std::vector m_colorspaceMarkedToBeDeleted; std::vector m_colorspaceReplacingMarkedCs; // Methods - const std::string getName() const { return "Colorspaces"; } + const std::string getName() const { return "Color Spaces"; } void processSearchPaths() const; @@ -395,13 +390,10 @@ class NamedTransformsMerger : public SectionMerger { m_strategy = options.params->getDefaultStrategy(); } - - m_state = MERGERSTATE_NOFLAG; } private: // Attributes - MergerFlag m_state; // Methods const std::string getName() const { return "Named Transforms"; } diff --git a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp index f8243fbe38..cc3d7351b4 100644 --- a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp +++ b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp @@ -6041,7 +6041,7 @@ inactive_colorspaces: [ACES2065-1] // OCIO_CHECK_EQUAL(std::string(mergedConfig->getCacheID()), std::string(bConfig->getCacheID())); } } - +} // Test with an OCIOZ archive // { // std::vector paths = { @@ -6066,4 +6066,108 @@ inactive_colorspaces: [ACES2065-1] // OCIO_CHECK_NO_THROW(mergedConfig->validate()); // } //} + +OCIO_ADD_TEST(MergeConfigs, merge_in_memory_configs) +{ + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: A} + +roles: + a: colorspace_a + +colorspaces: +- ! + name: colorspace_a + family: utility +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: B} + +colorspaces: +- ! + name: B + family: aces +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + params->setInputFirst(false); + MergeStrategy strategy = MergeStrategy::STRATEGY_PREFER_INPUT; + params->setRoles(strategy); + params->setColorspaces(strategy); + params->setNamedTransforms(strategy); + params->setDefaultStrategy(strategy); + params->setInputFamilyPrefix("Input/"); + params->setBaseFamilyPrefix("Base/"); + params->setAssumeCommonReferenceSpace(true); + params->setAvoidDuplicates(false); + + OCIO::ConfigRcPtr mergedConfig = OCIO::ConfigMergingHelpers::MergeConfigs(params, baseConfig, inputConfig); + + std::ostringstream ossResult; + mergedConfig->serialize(ossResult); + std::cout << ossResult.str() << "\n"; +} + +OCIO_ADD_TEST(MergeConfigs, merge_single_colorspace) +{ + constexpr const char * BASE { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: A} + +roles: + a: colorspace_a + +colorspaces: +- ! + name: colorspace_a + family: utility +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2 + +file_rules: + - ! {name: Default, colorspace: B} + +colorspaces: +- ! + name: B + family: aces +)" }; + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + OCIO::ConstColorSpaceRcPtr colorspace = inputConfig->getColorSpace("B"); + + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + params->setInputFirst(false); + MergeStrategy strategy = MergeStrategy::STRATEGY_PREFER_INPUT; + params->setRoles(strategy); + params->setColorspaces(strategy); + params->setNamedTransforms(strategy); + params->setDefaultStrategy(strategy); + params->setInputFamilyPrefix("Input/"); + params->setBaseFamilyPrefix("Base/"); + params->setAssumeCommonReferenceSpace(true); + params->setAvoidDuplicates(false); + + OCIO::ConfigRcPtr mergedConfig = OCIO::ConfigMergingHelpers::MergeColorSpace(params, baseConfig, colorspace); + + std::ostringstream ossResult; + mergedConfig->serialize(ossResult); + std::cout << ossResult.str() << "\n"; } From 3470cfaff14e6203ea7dc5dd25ca31e73d4e2840 Mon Sep 17 00:00:00 2001 From: Doug Walker Date: Thu, 23 Jan 2025 23:26:27 -0500 Subject: [PATCH 03/14] Prototype of merge avoid duplicates feature Signed-off-by: Doug Walker (cherry picked from commit 008ad27467f3a02411a89082ec4e3477286c0a2c) Signed-off-by: Doug Walker --- src/OpenColorIO/ConfigUtils.cpp | 460 +++++- src/OpenColorIO/ConfigUtils.h | 30 +- .../apphelpers/mergeconfigs/SectionMerger.cpp | 281 +++- .../apphelpers/mergeconfigs/SectionMerger.h | 109 +- tests/cpu/ConfigUtils_tests.cpp | 378 +++-- .../apphelpers/MergeConfigsHelpers_tests.cpp | 1411 ++++++++--------- .../configs/mergeconfigs/merged1/base1.ocio | 13 +- .../configs/mergeconfigs/merged1/input1.ocio | 5 +- 8 files changed, 1663 insertions(+), 1024 deletions(-) diff --git a/src/OpenColorIO/ConfigUtils.cpp b/src/OpenColorIO/ConfigUtils.cpp index 85b7ef14dd..ca42455f06 100644 --- a/src/OpenColorIO/ConfigUtils.cpp +++ b/src/OpenColorIO/ConfigUtils.cpp @@ -6,6 +6,7 @@ #include "ConfigUtils.h" #include "MathUtils.h" #include "utils/StringUtils.h" +#include "Logging.h" namespace OCIO_NAMESPACE { @@ -934,6 +935,7 @@ ConstTransformRcPtr getRefSpaceConverter(const ConstConfigRcPtr & srcConfig, getColorspaceOfRefType(srcConfig, refSpaceType), builtinConfig, getColorspaceOfRefType(builtinConfig, refSpaceType)); +// std::cout << "srcInterchange: " << srcInterchange << "\n"; // Identify an interchange space for the dst config. // Note that the interchange space will always be a linear color space. @@ -945,6 +947,7 @@ ConstTransformRcPtr getRefSpaceConverter(const ConstConfigRcPtr & srcConfig, getColorspaceOfRefType(dstConfig, refSpaceType), builtinConfig, getColorspaceOfRefType(builtinConfig, refSpaceType)); +// std::cout << "dstInterchange: " << dstInterchange << "\n"; // Get the from_ref transform from the srcInterchange space. ConstTransformRcPtr srcFromRef = getTransformForDir(srcConfig->getColorSpace(srcInterchange), @@ -975,6 +978,10 @@ ConstTransformRcPtr getRefSpaceConverter(const ConstConfigRcPtr & srcConfig, gt->appendTransform(srcFromRef->createEditableCopy()); gt->appendTransform(srcBuiltinToDstBuiltin); gt->appendTransform(dstToRef->createEditableCopy()); +// std::cout << "srcFromRef: " << *srcFromRef << "\n"; +// std::cout << "srcToDstBuiltin: " << *srcBuiltinToDstBuiltin << "\n"; +// std::cout << "dstToRef: " << *dstToRef << "\n"; +// std::cout << "simplified: " << *simplifyTransform(gt) << "\n\n"; // TODO: Need to ensure that gt would never contain a file transform. // for (size_t t = 0; t < gt->getNumTransforms(); t++) @@ -987,6 +994,19 @@ ConstTransformRcPtr getRefSpaceConverter(const ConstConfigRcPtr & srcConfig, return simplifyTransform(gt); } +bool transformIsEmpty(const ConstTransformRcPtr & tr) +{ + if (tr->getTransformType() == TRANSFORM_TYPE_GROUP) + { + ConstGroupTransformRcPtr gt = DynamicPtrCast(tr); + if (gt->getNumTransforms() == 0) + { + return true; + } + } + return false; +} + // Update the reference space used by a color space's transforms. // The argument is a group transform that converts from the current to the new ref. space. // @@ -1000,6 +1020,11 @@ void updateReferenceColorspace(ColorSpaceRcPtr & cs, throw Exception(os.str().c_str()); } + if (transformIsEmpty(toNewReferenceTransform)) + { + return; + } + ConstTransformRcPtr transformTo = cs->getTransform(COLORSPACE_DIR_TO_REFERENCE); if (transformTo) { @@ -1042,119 +1067,422 @@ void updateReferenceView(ViewTransformRcPtr & vt, const ConstTransformRcPtr & toNewSceneReferenceTransform, const ConstTransformRcPtr & toNewDisplayReferenceTransform) { + if (!toNewSceneReferenceTransform || !toNewDisplayReferenceTransform || !vt) + { + std::ostringstream os; + os << "Could not update view transform reference spaces, converter transforms were not initialized."; + throw Exception(os.str().c_str()); + } + + // FIXME: Is any more error checking needed? + + const bool emptySceneSide = transformIsEmpty(toNewSceneReferenceTransform); + const bool emptyDisplaySide = transformIsEmpty(toNewDisplayReferenceTransform); + + if (emptySceneSide && emptyDisplaySide) return; + ConstTransformRcPtr transformTo = vt->getTransform(VIEWTRANSFORM_DIR_TO_REFERENCE); if (transformTo) { - ConstTransformRcPtr inv = invertTransform(toNewSceneReferenceTransform); GroupTransformRcPtr gt = GroupTransform::Create(); - gt->appendTransform(inv->createEditableCopy()); + if (!emptyDisplaySide) + { + ConstTransformRcPtr inv = invertTransform(toNewDisplayReferenceTransform); + gt->appendTransform(inv->createEditableCopy()); + } + gt->appendTransform(transformTo->createEditableCopy()); - gt->appendTransform(toNewDisplayReferenceTransform->createEditableCopy()); + + if (vt->getReferenceSpaceType() == REFERENCE_SPACE_DISPLAY) + { + // Use the converter to display reference on both sides. + if (!emptyDisplaySide) + { + gt->appendTransform(toNewDisplayReferenceTransform->createEditableCopy()); + } + } + else + { + if (!emptySceneSide) + { + gt->appendTransform(toNewSceneReferenceTransform->createEditableCopy()); + } + } vt->setTransform(gt, VIEWTRANSFORM_DIR_TO_REFERENCE); } ConstTransformRcPtr transformFrom = vt->getTransform(VIEWTRANSFORM_DIR_FROM_REFERENCE); if (transformFrom) { - ConstTransformRcPtr inv = invertTransform(toNewDisplayReferenceTransform); GroupTransformRcPtr gt = GroupTransform::Create(); - gt->appendTransform(inv->createEditableCopy()); + + if (vt->getReferenceSpaceType() == REFERENCE_SPACE_DISPLAY) + { + // Use the converter to display reference on both sides. + if (!emptyDisplaySide) + { + ConstTransformRcPtr inv = invertTransform(toNewDisplayReferenceTransform); + gt->appendTransform(inv->createEditableCopy()); + } + } + else + { + if (!emptySceneSide) + { + ConstTransformRcPtr inv = invertTransform(toNewSceneReferenceTransform); + gt->appendTransform(inv->createEditableCopy()); + } + } + gt->appendTransform(transformFrom->createEditableCopy()); - gt->appendTransform(toNewSceneReferenceTransform->createEditableCopy()); + + if (!emptyDisplaySide) + { + gt->appendTransform(toNewDisplayReferenceTransform->createEditableCopy()); + } vt->setTransform(gt, VIEWTRANSFORM_DIR_FROM_REFERENCE); } // Note that Config::addViewTransform prevents creating a view transform that - // has no transforms, so we may be sure at least one direction will be present. + // has no transforms, so at least one direction will be present. +} + +// FIXME: Make this a functional. +bool hasColorSpaceRefType(const ConstConfigRcPtr & config, ReferenceSpaceType refType) +{ + SearchReferenceSpaceType searchRefType = static_cast(refType); + int n = config->getNumColorSpaces(searchRefType, COLORSPACE_ALL); + return n > 0; +} + +void initializeRefSpaceConverters(ConstTransformRcPtr & inputToBaseGtScene, + ConstTransformRcPtr & inputToBaseGtDisplay, + const ConstConfigRcPtr & baseConfig, + const ConstConfigRcPtr & inputConfig) +{ + // Note: The base config reference space is always used, regardless of strategy. +//std::cout << "initializing ref converters\n"; + + if (hasColorSpaceRefType(baseConfig, REFERENCE_SPACE_SCENE) && + hasColorSpaceRefType(inputConfig, REFERENCE_SPACE_SCENE)) + { +// try +// { + // This may throw. + inputToBaseGtScene = getRefSpaceConverter( + inputConfig, + baseConfig, + REFERENCE_SPACE_SCENE + ); +// } +// catch(const Exception & e) +// { +// LogError(e.what()); +// } + } + else + { + // Always need to initialize both transforms, even if they're empty. + inputToBaseGtScene = GroupTransform::Create(); + } + + // Only attempt to build the converter if the input config has this type of + // reference space. Using the input config for this determination since it is + // only input config color spaces whose reference space is converted. + if (hasColorSpaceRefType(baseConfig, REFERENCE_SPACE_DISPLAY) && + hasColorSpaceRefType(inputConfig, REFERENCE_SPACE_DISPLAY)) + { +// try +// { + inputToBaseGtDisplay = getRefSpaceConverter( + inputConfig, + baseConfig, + REFERENCE_SPACE_DISPLAY + ); +// } +// catch(const Exception & e) +// { +// LogError(e.what()); +// } + } + else + { + // Always need to initialize both transforms, even if they're empty. + inputToBaseGtDisplay = GroupTransform::Create(); + } +} + +bool calcColorSpaceFingerprint(std::vector & fingerprint, const ConstConfigRcPtr & config, const ConstColorSpaceRcPtr & cs) +{ + bool skipColorSpace = false; + // Define a set of (somewhat arbitrary) RGB values to test whether the combined transform is + // enough of an identity. + // TODO: Should we check values outside [0,1]? + std::vector RGBAvals = { 0.4f, 0.23f, 0.07f, 0.f, + 0.35f, 0.66f, 0.16f, 0.f, + 0.2f, 0.11f, 0.86f, 0.f, + 0.f, 0.f, 0.f, 0.f, + 0.04f, 0.03f, 0.02f, 0.f, + 1.f, 1.f, 1.f, 0.f }; +// std::vector RGBAvals = { 0.7f, 0.4f, 0.02f, 0.f, +// 0.02f, 0.6f, 0.2f, 0.f, +// 0.3f, 0.02f, 0.5f, 0.f, +// 0.f, 0.f, 0.f, 0.f, +// 1.f, 1.f, 1.f, 0.f }; + +// FIXME: THIS BREAKS THE TESTS + +// std::vector vals = { 0.7f, 0.4f, 0.02f, 0.f, +// 0.02f, 0.6f, -0.2f, 0.f, +// 0.3f, 0.02f, 1.5f, 0.f, +// 0.f, 0.f, 0.f, 0.f, +// 1.f, 1.f, 1.f, 0.f }; + + ConstTransformRcPtr fromRef = getTransformForDir(cs, COLORSPACE_DIR_FROM_REFERENCE); + + ConstProcessorRcPtr p; + try + { + p = config->getProcessor(fromRef); + } + catch (...) + { + // If the transform doesn't validate (singular matrix, etc.), don't consider it. + return true; + } + + // TODO: Get a group transform and don't bother if it contains a 3d-lut. + // With optimization-none, it should not invert a 3d-lut, regardless of direction? + + std::vector out(RGBAvals.size(), 0.f); + + PackedImageDesc descSrc( &RGBAvals[0], (long) RGBAvals.size() / 4, 1, CHANNEL_ORDERING_RGBA ); + PackedImageDesc descDst( &out[0], (long) RGBAvals.size() / 4, 1, CHANNEL_ORDERING_RGBA ); + + ConstCPUProcessorRcPtr cpu = p->getOptimizedCPUProcessor(OPTIMIZATION_NONE); + cpu->apply(descSrc, descDst); + + fingerprint = out; + + // TODO: add a cacheID to GroupTransform using the opData IDs, use that to do an easier comparison. + // TODO: compare to_refs to to_refs. + return skipColorSpace; +} + +void initializeColorSpacesFingerprints(ColorSpaceFingerprints & fingerprints, const ConstConfigRcPtr & config) +{ + SuspendCacheGuard srcGuard(config); + +// ConstConfigRcPtr builtinConfig = Config::CreateFromFile("ocio://cg-config-latest"); +// // TODO: verify this will convert to the same ref space type. +// const char * srgbName = OCIO::Config::IdentifyBuiltinColorSpace(config, builtinConfig, "srgb_texture"); + + int n = config->getNumColorSpaces(SEARCH_REFERENCE_SPACE_ALL, COLORSPACE_ALL); + fingerprints.vec.clear(); + fingerprints.vec.reserve(n); + for (int i = 0; i < n; ++i) + { + const char * name = config->getColorSpaceNameByIndex(SEARCH_REFERENCE_SPACE_ALL, + COLORSPACE_ALL, + i); + ConstColorSpaceRcPtr cs = config->getColorSpace(name); + if (!cs || cs->isData()) + { + // Don't put data color spaces in the map. + continue; + } + + ConstTransformRcPtr tFrom = cs->getTransform(COLORSPACE_DIR_FROM_REFERENCE); + ConstTransformRcPtr tTo = cs->getTransform(COLORSPACE_DIR_TO_REFERENCE); + if (tFrom && tTo) + { + // Don't bother with color spaces that have both directions defined, + // these are more complicated and less likely to be duplicates. + continue; + } + + std::vector fp; + const bool skipColorSpace = calcColorSpaceFingerprint(fp, config, cs); + if (!skipColorSpace) + { + Fingerprint fprint; + fprint.csName = cs->getName(); + fprint.type = cs->getReferenceSpaceType(); + fprint.vals = fp; + fingerprints.vec.push_back(fprint); + } + } } -// If config contains a color space equivalent to new_cs, return its name. +// If the base config contains a color space equivalent to inputCS, return its name. // Return an empty string if no equivalent color space is found (within the tolerance). -// The ref_space_type specifies the type of new_cs and determines which part of the +// The ref_space_type specifies the type of inputCS and determines which part of the // config is searched. Note: Normally the refType should be set by simply calling -// newCS->getReferenceSpaceType(). Not sure the extra flexibility to search the +// inputCS->getReferenceSpaceType(). Not sure the extra flexibility to search the // other ref space type is needed (perhaps drop the option if this gets added to // the public API). // -const char * findEquivalentColorspace(const ConstConfigRcPtr & config, - const ConstColorSpaceRcPtr & newCS, +const char * findEquivalentColorspace(const ColorSpaceFingerprints & fingerprints, + const ConstConfigRcPtr & inputConfig, + const ConstColorSpaceRcPtr & inputCS, ReferenceSpaceType refType) { - // NB: This assumes that new_cs uses the same reference space as config. - // In general, this means that update_color_reference_space must be called on new_cs + // The fingerprints must first be initialized from the base config. + // NB: The inputConfig/inputCS must use the same reference space as the base config. + // In general, this means that updateReferenceColorspace must be called on inputCS // before calling this function. - if (newCS->isData()) + // TODO: Should data spaces ever be replaced? There is no need for flame? + if (inputCS->isData()) { - for (int i = 0; i < config->getNumColorSpaces(SEARCH_REFERENCE_SPACE_SCENE, COLORSPACE_ALL); ++i) - { - const char * name = config->getColorSpaceNameByIndex(SEARCH_REFERENCE_SPACE_SCENE, COLORSPACE_ALL, i); - ConstColorSpaceRcPtr cs = config->getColorSpace(name); - if (cs->isData()) - { - return cs->getName(); - } - - } return ""; } - // The heuristics need to create a lot of Processors and send RGB values through - // them to try and identify a known color space. Turn off the Processor cache in - // the configs to avoid polluting the cache with transforms that won't be reused - // and avoid the overhead of maintaining the cache. - SuspendCacheGuard srcGuard(config); - - ConstTransformRcPtr fromRef = getTransformForDir(newCS, COLORSPACE_DIR_FROM_REFERENCE); - - + std::vector inputVals; + const bool skipColorSpace = calcColorSpaceFingerprint(inputVals, inputConfig, inputCS); + if (skipColorSpace) + { + return ""; + } // FIXME: Before looping over all color spaces, check to see if there's one with the same name. - SearchReferenceSpaceType searchRefType = static_cast(refType); - for (int i = 0; i < config->getNumColorSpaces(searchRefType, COLORSPACE_ALL); ++i) + const float absTolerance = 1e-3f; + for (const auto & fp : fingerprints.vec) { - const char * name = config->getColorSpaceNameByIndex(searchRefType, COLORSPACE_ALL, i); - ConstColorSpaceRcPtr cs = config->getColorSpace(name); + if (fp.type != refType) + continue; -// TODO: Need to add isdata check to other heuristics too. + std::vector vals = fp.vals; - if (!cs->isData()) + bool matchFound = true; + for (size_t i = 0; i < vals.size(); i++) { - ConstTransformRcPtr toRef = getTransformForDir(cs, COLORSPACE_DIR_TO_REFERENCE); - GroupTransformRcPtr gt = GroupTransform::Create(); - gt->appendTransform(toRef->createEditableCopy()); - gt->appendTransform(fromRef->createEditableCopy()); - - auto p = config->getProcessor(gt); - - // Define a set of (somewhat arbitrary) RGB values to test whether the combined transform is - // enough of an identity. - // TODO: Should we check values outside [0,1]? - std::vector vals = { 0.7f, 0.4f, 0.02f, 0.f, - 0.02f, 0.6f, 0.2f, 0.f, - 0.3f, 0.02f, 0.5f, 0.f, - 0.f, 0.f, 0.f, 0.f, - 1.f, 1.f, 1.f, 0.f }; - -// FIXME: THIS BREAKS THE TESTS - -// std::vector vals = { 0.7f, 0.4f, 0.02f, 0.f, -// 0.02f, 0.6f, -0.2f, 0.f, -// 0.3f, 0.02f, 1.5f, 0.f, -// 0.f, 0.f, 0.f, 0.f, -// 1.f, 1.f, 1.f, 0.f }; - - if (isIdentityTransform(p, vals, 1e-3f)) + if (!EqualWithAbsError(inputVals[i], vals[i], absTolerance)) { - return cs->getName(); + matchFound = false; + continue; } } + if (matchFound) + return fp.csName; } + +// TODO: Need to add isdata check to other heuristics too. + +// if (!cs->isData()) +// { +// // ConstTransformRcPtr toRef = getTransformForDir(cs, COLORSPACE_DIR_TO_REFERENCE); +// // GroupTransformRcPtr gt = GroupTransform::Create(); +// // gt->appendTransform(toRef->createEditableCopy()); +// // gt->appendTransform(fromRef->createEditableCopy()); +// // +// // auto p = baseConfig->getProcessor(gt); +// +// +// +// if (isIdentityTransform(p, vals, 1e-3f)) +// { +// return cs->getName(); +// } +// } +// } + return ""; } +// const char * findEquivalentColorspace(const ConstConfigRcPtr & baseConfig, +// const ConstConfigRcPtr & inputConfig, +// const ConstColorSpaceRcPtr & inputCS, +// ReferenceSpaceType refType) +// { +// // NB: This assumes that new_cs uses the same reference space as config. +// // In general, this means that update_color_reference_space must be called on new_cs +// // before calling this function. +// +// if (inputCS->isData()) +// { +// for (int i = 0; i < baseConfig->getNumColorSpaces(SEARCH_REFERENCE_SPACE_SCENE, COLORSPACE_ALL); ++i) +// { +// const char * name = baseConfig->getColorSpaceNameByIndex(SEARCH_REFERENCE_SPACE_SCENE, COLORSPACE_ALL, i); +// ConstColorSpaceRcPtr cs = baseConfig->getColorSpace(name); +// if (cs->isData()) +// { +// return cs->getName(); +// } +// +// } +// return ""; +// } +// +// // The heuristics need to create a lot of Processors and send RGB values through +// // them to try and identify a known color space. Turn off the Processor cache in +// // the configs to avoid polluting the cache with transforms that won't be reused +// // and avoid the overhead of maintaining the cache. +// SuspendCacheGuard srcGuard(baseConfig); +// +// ConstTransformRcPtr fromRef = getTransformForDir(inputCS, COLORSPACE_DIR_FROM_REFERENCE); +// +// +// // auto p = baseConfig->getProcessor(gt); +// // Define a set of (somewhat arbitrary) RGB values to test whether the combined transform is +// // enough of an identity. +// // TODO: Should we check values outside [0,1]? +// std::vector vals = { 0.7f, 0.4f, 0.02f, 0.f, +// 0.02f, 0.6f, 0.2f, 0.f, +// 0.3f, 0.02f, 0.5f, 0.f, +// 0.f, 0.f, 0.f, 0.f, +// 1.f, 1.f, 1.f, 0.f }; +// +// // FIXME: THIS BREAKS THE TESTS +// +// // std::vector vals = { 0.7f, 0.4f, 0.02f, 0.f, +// // 0.02f, 0.6f, -0.2f, 0.f, +// // 0.3f, 0.02f, 1.5f, 0.f, +// // 0.f, 0.f, 0.f, 0.f, +// // 1.f, 1.f, 1.f, 0.f }; +// +// std::vector out(RGBAvals.size(), 0.f); +// +// PackedImageDesc desc( &RGBAvals[0], (long) RGBAvals.size() / 4, 1, CHANNEL_ORDERING_RGBA ); +// PackedImageDesc descDst( &out[0], (long) RGBAvals.size() / 4, 1, CHANNEL_ORDERING_RGBA ); +// +// ConstCPUProcessorRcPtr cpu = proc->getOptimizedCPUProcessor(OPTIMIZATION_NONE); +// cpu->apply(desc, descDst); +// +// +// // FIXME: Before looping over all color spaces, check to see if there's one with the same name. +// +// SearchReferenceSpaceType searchRefType = static_cast(refType); +// for (int i = 0; i < baseConfig->getNumColorSpaces(searchRefType, COLORSPACE_ALL); ++i) +// { +// const char * name = baseConfig->getColorSpaceNameByIndex(searchRefType, COLORSPACE_ALL, i); +// ConstColorSpaceRcPtr cs = baseConfig->getColorSpace(name); +// +// // TODO: Need to add isdata check to other heuristics too. +// +// if (!cs->isData()) +// { +// // ConstTransformRcPtr toRef = getTransformForDir(cs, COLORSPACE_DIR_TO_REFERENCE); +// // GroupTransformRcPtr gt = GroupTransform::Create(); +// // gt->appendTransform(toRef->createEditableCopy()); +// // gt->appendTransform(fromRef->createEditableCopy()); +// // +// // auto p = baseConfig->getProcessor(gt); +// +// +// +// if (isIdentityTransform(p, vals, 1e-3f)) +// { +// return cs->getName(); +// } +// } +// } +// +// return ""; +// } + } // namespace ConfigUtils } // namespace OCIO_NAMESPACE diff --git a/src/OpenColorIO/ConfigUtils.h b/src/OpenColorIO/ConfigUtils.h index 921d9fabf5..8f704919a7 100644 --- a/src/OpenColorIO/ConfigUtils.h +++ b/src/OpenColorIO/ConfigUtils.h @@ -4,6 +4,8 @@ #ifndef INCLUDED_OCIO_CONFIG_UTILS_H #define INCLUDED_OCIO_CONFIG_UTILS_H +#include + #include namespace OCIO_NAMESPACE @@ -39,16 +41,40 @@ ConstTransformRcPtr getRefSpaceConverter(const ConstConfigRcPtr & srcConfig, const ConstConfigRcPtr & dstConfig, ReferenceSpaceType refSpaceType); +void initializeRefSpaceConverters(ConstTransformRcPtr & inputToBaseGtScene, + ConstTransformRcPtr & inputToBaseGtDisplay, + const ConstConfigRcPtr & baseConfig, + const ConstConfigRcPtr & inputConfig); + void updateReferenceColorspace(ColorSpaceRcPtr & cs, const ConstTransformRcPtr & toNewReferenceTransform); void updateReferenceView(ViewTransformRcPtr & vt, const ConstTransformRcPtr & toNewSceneReferenceTransform, const ConstTransformRcPtr & toNewDisplayReferenceTransform); -const char * findEquivalentColorspace(const ConstConfigRcPtr & config, - const ConstColorSpaceRcPtr & newCs, +struct Fingerprint +{ + const char * csName; + ReferenceSpaceType type; + std::vector vals; +}; +//typedef std::map< std::string, Fingerprint > ColorSpaceFingerprintMap; +struct ColorSpaceFingerprints +{ + std::vector vec; +}; +void initializeColorSpacesFingerprints(ColorSpaceFingerprints & fingerprints, + const ConstConfigRcPtr & config); + +const char * findEquivalentColorspace(const ColorSpaceFingerprints & fingerprints, + const ConstConfigRcPtr & inputConfig, + const ConstColorSpaceRcPtr & inputCS, ReferenceSpaceType refType); +// const char * findEquivalentColorspace(const ConstConfigRcPtr & config, +// const ConstColorSpaceRcPtr & newCs, +// ReferenceSpaceType refType); + // Temporarily deactivate the Processor cache on a Config object. // Currently, this also clears the cache. // diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp index dab1a1f17b..f7a6e5440e 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp +++ b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp @@ -1509,7 +1509,27 @@ void DisplayViewMerger::processActiveLists() } } -void DisplayViewMerger::addUniqueViewTransforms(const ConstConfigRcPtr & cfg) +void DisplayViewMerger::addViewTransform(const ConstConfigRcPtr & cfg, + const char * name, + bool isInput) +{ + ConstViewTransformRcPtr vt = cfg->getViewTransform(name); + if (!vt) return; + + if (!isInput || m_params->isAssumeCommonReferenceSpace()) + { + m_mergedConfig->addViewTransform(vt); + } + else + { + // Add the reference space adapter transforms. + ViewTransformRcPtr eVT = vt->createEditableCopy(); + ConfigUtils::updateReferenceView(eVT, m_inputToBaseGtScene, m_inputToBaseGtDisplay); + m_mergedConfig->addViewTransform(eVT); + } +} + +void DisplayViewMerger::addUniqueViewTransforms(const ConstConfigRcPtr & cfg, bool isInput) { for (int i = 0; i < cfg->getNumViewTransforms(); i++) { @@ -1517,15 +1537,20 @@ void DisplayViewMerger::addUniqueViewTransforms(const ConstConfigRcPtr & cfg) // Take the view from the config if it does not exist in merged config. if (m_mergedConfig->getViewTransform(name) == nullptr) { - m_mergedConfig->addViewTransform(cfg->getViewTransform(name)); + addViewTransform(cfg, name, isInput); } } } void DisplayViewMerger::processViewTransforms(const ConstConfigRcPtr & first, const ConstConfigRcPtr & second, - bool preferSecond) + bool preferSecond, + bool secondIsInput) { + // FIXME: Should do this once for color spaces & view transforms. +// ConstTransformRcPtr inputToBaseGtScene, inputToBaseGtDisplay; +// initializeRefSpaceConverters(inputToBaseGtScene, inputToBaseGtDisplay); + for (int i = 0; i < first->getNumViewTransforms(); i++) { const char * name = first->getViewTransformNameByIndex(i); @@ -1542,18 +1567,18 @@ void DisplayViewMerger::processViewTransforms(const ConstConfigRcPtr & first, if (vt2 && preferSecond) { - m_mergedConfig->addViewTransform(second->getViewTransform(name)); + addViewTransform(second, name, secondIsInput); } else { - m_mergedConfig->addViewTransform(first->getViewTransform(name)); + addViewTransform(first, name, !secondIsInput); } } } // Add the remaining unique views transform. - addUniqueViewTransforms(second); + addUniqueViewTransforms(second, secondIsInput); } void DisplayViewMerger::processViewingRules(const ConstConfigRcPtr & first, @@ -1657,11 +1682,11 @@ void DisplayViewMerger::handlePreferInput() m_mergedConfig->clearViewTransforms(); if (m_params->isInputFirst()) { - processViewTransforms(m_inputConfig, m_baseConfig, false); + processViewTransforms(m_inputConfig, m_baseConfig, false, false); } else { - processViewTransforms(m_baseConfig, m_inputConfig, true); + processViewTransforms(m_baseConfig, m_inputConfig, true, true); } // Merge default_view_transform. @@ -1726,11 +1751,11 @@ void DisplayViewMerger::handlePreferBase() m_mergedConfig->clearViewTransforms(); if (m_params->isInputFirst()) { - processViewTransforms(m_inputConfig, m_baseConfig, true); + processViewTransforms(m_inputConfig, m_baseConfig, true, false); } else { - processViewTransforms(m_baseConfig, m_inputConfig, false); + processViewTransforms(m_baseConfig, m_inputConfig, false, true); } // Merge default_view_transform. @@ -1800,7 +1825,7 @@ void DisplayViewMerger::handleInputOnly() // Merge view_transforms. m_mergedConfig->clearViewTransforms(); - addUniqueViewTransforms(m_inputConfig); + addUniqueViewTransforms(m_inputConfig, true); // Merge default_view_transform. m_mergedConfig->setDefaultViewTransformName(m_inputConfig->getDefaultViewTransformName()); @@ -2389,56 +2414,56 @@ void ColorspacesMerger::updateFamily(std::string & family, bool fromBase) const family = updatedPrefix + family; } -bool hasColorSpaceRefType(const ConstConfigRcPtr & config, ReferenceSpaceType refType) -{ - SearchReferenceSpaceType searchRefType = static_cast(refType); - int n = config->getNumColorSpaces(searchRefType, COLORSPACE_ALL); - return n > 0; -} - -void ColorspacesMerger::initializeRefSpaceConverters(ConstTransformRcPtr & inputToBaseGtScene, - ConstTransformRcPtr & inputToBaseGtDisplay) -{ - // Note: The base config reference space is always used, regardless of strategy. - - if (!m_params->isAssumeCommonReferenceSpace()) - { - if (hasColorSpaceRefType(m_inputConfig, REFERENCE_SPACE_SCENE)) - { - try - { - inputToBaseGtScene = ConfigUtils::getRefSpaceConverter( - m_inputConfig, - m_baseConfig, - REFERENCE_SPACE_SCENE - ); - } - catch(const Exception & e) - { - LogError(e.what()); - } - } - - // Only attempt to build the converter if the input config has this type of - // reference space. Using the input config for this determination since it is - // only input config color spaces whose reference space is converted. - if (hasColorSpaceRefType(m_inputConfig, REFERENCE_SPACE_DISPLAY)) - { - try - { - inputToBaseGtDisplay = ConfigUtils::getRefSpaceConverter( - m_inputConfig, - m_baseConfig, - REFERENCE_SPACE_DISPLAY - ); - } - catch(const Exception & e) - { - LogError(e.what()); - } - } - } -} +// bool hasColorSpaceRefType(const ConstConfigRcPtr & config, ReferenceSpaceType refType) +// { +// SearchReferenceSpaceType searchRefType = static_cast(refType); +// int n = config->getNumColorSpaces(searchRefType, COLORSPACE_ALL); +// return n > 0; +// } +// +// void ColorspacesMerger::initializeRefSpaceConverters(ConstTransformRcPtr & inputToBaseGtScene, +// ConstTransformRcPtr & inputToBaseGtDisplay) +// { +// // Note: The base config reference space is always used, regardless of strategy. +// +// if (!m_params->isAssumeCommonReferenceSpace()) +// { +// if (hasColorSpaceRefType(m_inputConfig, REFERENCE_SPACE_SCENE)) +// { +// try +// { +// inputToBaseGtScene = ConfigUtils::getRefSpaceConverter( +// m_inputConfig, +// m_baseConfig, +// REFERENCE_SPACE_SCENE +// ); +// } +// catch(const Exception & e) +// { +// LogError(e.what()); +// } +// } +// +// // Only attempt to build the converter if the input config has this type of +// // reference space. Using the input config for this determination since it is +// // only input config color spaces whose reference space is converted. +// if (hasColorSpaceRefType(m_inputConfig, REFERENCE_SPACE_DISPLAY)) +// { +// try +// { +// inputToBaseGtDisplay = ConfigUtils::getRefSpaceConverter( +// m_inputConfig, +// m_baseConfig, +// REFERENCE_SPACE_DISPLAY +// ); +// } +// catch(const Exception & e) +// { +// LogError(e.what()); +// } +// } +// } +// } // TODO: Make this a functional inside where it's called from. void ColorspacesMerger::attemptToAddAlias(const ConstConfigRcPtr & mergeConfig, @@ -2452,7 +2477,7 @@ void ColorspacesMerger::attemptToAddAlias(const ConstConfigRcPtr & mergeConfig, // It is assumed that the strategy is prefer_base when this function is called. - // It's OK if aliasName used in the duplicate color space itself. + // It's OK if aliasName is used in the duplicate color space itself. if ((Platform::Strcasecmp(dupeCS->getName(), aliasName) == 0) || hasAlias(dupeCS, aliasName)) { @@ -2485,7 +2510,10 @@ void ColorspacesMerger::attemptToAddAlias(const ConstConfigRcPtr & mergeConfig, dupeCS->addAlias(aliasName); } -bool ColorspacesMerger::handleAvoidDuplicatesOption(ConfigRcPtr & eBase, ColorSpaceRcPtr & inputCS) +bool ColorspacesMerger::handleAvoidDuplicatesOption(ConfigUtils::ColorSpaceFingerprints & fingerprints, + ConfigRcPtr & eBase, + const ConstConfigRcPtr & inputConfig, + ColorSpaceRcPtr & inputCS) { bool notDuplicate = true; @@ -2493,6 +2521,11 @@ bool ColorspacesMerger::handleAvoidDuplicatesOption(ConfigRcPtr & eBase, ColorSp { return notDuplicate; } + // If a color space has the allow-dupes category, don't check if it's a duplicate. + if (inputCS->hasCategory("allow-duplicate")) + { + return notDuplicate; + } // Note: The search for duplicate color spaces only searches for color spaces with // the same reference space type (i.e., scene or display), so it won't remove spaces @@ -2503,15 +2536,31 @@ bool ColorspacesMerger::handleAvoidDuplicatesOption(ConfigRcPtr & eBase, ColorSp // those duplicates in the base won't be removed. But if the input config contains // duplicates, those will be condensed into one space containing aliases for all of // names of the duplicates. + // + // Note: By design, inactive color spaces are included in the search for equivalents + // (e.g., consider the CIE-XYZ-D65 space, which is typically inactive). However, + // when the inactive list is regenerated to avoid listing removed color spaces, + // some color spaces that were inactive may become active. +// const char * duplicateInBase = ConfigUtils::findEquivalentColorspace( +// eBase, +// inputConfig, inputCS, +// inputCS->getReferenceSpaceType() +// ); const char * duplicateInBase = ConfigUtils::findEquivalentColorspace( - eBase, - inputCS, + fingerprints, + inputConfig, inputCS, inputCS->getReferenceSpaceType() ); +// TODO: Could this be refactored to go through the usual merge process? + +// FIXME: Should copy categories too. Maybe encoding. + const ConfigMergingParameters::MergeStrategies strategy = m_params->getColorspaces(); if (duplicateInBase && *duplicateInBase) { +//std::cout << "dupe base: " << duplicateInBase << " input: " << inputCS->getName() << "\n"; + if (strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT) { // m_colorspaceMarkedToBeDeleted.push_back(duplicateInBase); @@ -2523,6 +2572,9 @@ bool ColorspacesMerger::handleAvoidDuplicatesOption(ConfigRcPtr & eBase, ColorSp // (since that's where they originated), but may cause conflicts with other color // spaces in the input config, but these will be handled as the spaces get added // to the merged config by the calling function. + // + // If the base config has more than one color space equivalent to inputCS, only + // the first is replaced. ConstColorSpaceRcPtr dupeCS = eBase->getColorSpace(duplicateInBase); if (dupeCS) @@ -2536,7 +2588,36 @@ bool ColorspacesMerger::handleAvoidDuplicatesOption(ConfigRcPtr & eBase, ColorSp inputCS->addAlias(dupeCS->getAlias(i)); } - eBase->removeColorSpace(duplicateInBase); + // FIXME: This should be controlled by an merge option. + // There are currently no unit tests for this. + for (int i = 0; i < dupeCS->getNumCategories(); i++) + { + inputCS->addCategory(dupeCS->getCategory(i)); + } + + // Trying to merge inputCS would now give misleading notifications about + // conflicts from the newly added aliases, so remove the duplicate. + // If there is more than one input CS that duplicates a given base CS, + // duplicateInBase will have been removed and is now an alias. Since removeCS + // does not work on aliases, get the name of the color space with that alias. + const char * duplicateCurrentName = eBase->getCanonicalName(duplicateInBase); + eBase->removeColorSpace(duplicateCurrentName); + + // If the name is different, notify that it is replacing a color space in base. +// if (Platform::Strcasecmp(inputCS->getName(), duplicateInBase) != 0) +// { + std::ostringstream os; +// os << "Color space '" << inputCS->getName() << "' replaces its equivalent '" +// << duplicateCurrentName << "' in the base config (aliases copied)."; +// os << "Equivalent color space '" << inputCS->getName() << "' from the input config replaces '" +// << duplicateCurrentName << "' in the base config, preserving aliases."; + os << "Equivalent input color space '" << inputCS->getName() << "' replaces '" + << duplicateCurrentName << "' in the base config, preserving aliases."; + notify(os.str(), m_params->isErrorOnConflict()); +// } + + // Still want the caller to proceed merging inputCS into the merge config. + notDuplicate = true; } } else if (strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_BASE) @@ -2545,6 +2626,9 @@ bool ColorspacesMerger::handleAvoidDuplicatesOption(ConfigRcPtr & eBase, ColorSp // Need to be more careful of conflicts, since the modified color space is // receiving aliases from the input config and yet is not going through the // mergeColorSpace checking below. + // + // If the input config has more than one CS that is equivalent to a base CS, + // they are all condensed into that first equivalent base CS. ConstColorSpaceRcPtr cs = eBase->getColorSpace(duplicateInBase); if (cs) @@ -2558,10 +2642,32 @@ bool ColorspacesMerger::handleAvoidDuplicatesOption(ConfigRcPtr & eBase, ColorSp attemptToAddAlias(eBase, eCS, inputCS, inputCS->getAlias(i)); } + for (int i = 0; i < inputCS->getNumCategories(); i++) + { + eCS->addCategory(inputCS->getCategory(i)); + } + // Replace the color space in the merge config. (This preserves its // order in the color space list.) eBase->addColorSpace(eCS); + // If the name is different, notify that it won't replace a color space in base. +// if (Platform::Strcasecmp(inputCS->getName(), duplicateInBase) != 0) +// { + std::ostringstream os; +// os << "The name/aliases of color space '" << inputCS->getName() << +// "' will be transferred its equivalent '" +// << duplicateInBase << "' in the base config."; +// os << "Color space '" << inputCS->getName() << "' won't replace its equivalent '" +// << duplicateCurrentName << "' in the base config (aliases are copied)."; +// os << "Equivalent color space '" << duplicateInBase << "' from the base config overrides '" +// << inputCS->getName() << "' in the input config, preserving aliases."; + os << "Equivalent base color space '" << duplicateInBase << "' overrides '" + << inputCS->getName() << "' in the input config, preserving aliases."; + notify(os.str(), m_params->isErrorOnConflict()); +// } + + // The base color space is edited here, don't want to add inputCS. notDuplicate = false; } } @@ -2740,11 +2846,20 @@ void ColorspacesMerger::mergeColorSpace(ConfigRcPtr & mergeConfig, const ConfigMergingParameters::MergeStrategies strategy = m_params->getColorspaces(); + // // Handle conflicts of the eInputCS aliases with other color spaces or aliases. + // + // First initialize the list of names, since eInputCS is being edited within the loop. + std::vector aliasNames; for (size_t i = 0; i < eInputCS->getNumAliases(); i++) { - const char * aliasName = eInputCS->getAlias(i); + aliasNames.push_back(eInputCS->getAlias(i)); + } + + for (size_t i = 0; i < aliasNames.size(); i++) + { + const char * aliasName = aliasNames[i].c_str(); std::ostringstream os; @@ -2845,35 +2960,42 @@ void ColorspacesMerger::addColorSpaces() mergeConfig->clearNamedTransforms(); - ConstTransformRcPtr inputToBaseGtScene, inputToBaseGtDisplay; - initializeRefSpaceConverters(inputToBaseGtScene, inputToBaseGtDisplay); +// ConstTransformRcPtr inputToBaseGtScene, inputToBaseGtDisplay; +// initializeRefSpaceConverters(inputToBaseGtScene, inputToBaseGtDisplay); // Loop over all active and inactive color spaces of all reference types in the input config. // Merge them into the temp config (which already contains the base color spaces). std::vector addedInputColorSpaces; + ConfigUtils::ColorSpaceFingerprints fingerprints; + if (m_params->isAvoidDuplicates()) + { + ConfigUtils::initializeColorSpacesFingerprints(fingerprints, m_baseConfig); + } + for (int i = 0; i < m_inputConfig->getNumColorSpaces(SEARCH_REFERENCE_SPACE_ALL, COLORSPACE_ALL); ++i) { const char * name = m_inputConfig->getColorSpaceNameByIndex(SEARCH_REFERENCE_SPACE_ALL, COLORSPACE_ALL, i); ConstColorSpaceRcPtr cs = m_inputConfig->getColorSpace(name); - if (!cs) - continue; + if (!cs) continue; + ColorSpaceRcPtr eCS = cs->createEditableCopy(); if (!m_params->isAssumeCommonReferenceSpace()) { if (eCS->getReferenceSpaceType() == REFERENCE_SPACE_DISPLAY) - ConfigUtils::updateReferenceColorspace(eCS, inputToBaseGtDisplay); + ConfigUtils::updateReferenceColorspace(eCS, m_inputToBaseGtDisplay); else - ConfigUtils::updateReferenceColorspace(eCS, inputToBaseGtScene); + ConfigUtils::updateReferenceColorspace(eCS, m_inputToBaseGtScene); } // Doing this against the mergedConfig rather than the base config so that the most // recent state of any aliases that get added or color spaces that are removed are // considered by the duplicate consolidation process. - const bool notDuplicate = handleAvoidDuplicatesOption(mergeConfig, eCS); + const bool notDuplicate = handleAvoidDuplicatesOption(fingerprints, mergeConfig, m_inputConfig, eCS); +// const bool notDuplicate = true; if (notDuplicate && colorSpaceMayBeMerged(mergeConfig, eCS)) { @@ -3538,11 +3660,20 @@ void NamedTransformsMerger::mergeNamedTransform(ConfigRcPtr & mergeConfig, strategy = ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_BASE; } + // // Handle conflicts of the eNT aliases with other color spaces, named transforms, and etc. + // + // First initialize the list of names, since eNT is being edited within the loop. + std::vector aliasNames; for (size_t i = 0; i < eNT->getNumAliases(); i++) { - const char * aliasName = eNT->getAlias(i); + aliasNames.push_back(eNT->getAlias(i)); + } + + for (size_t i = 0; i < aliasNames.size(); i++) + { + const char * aliasName = aliasNames[i].c_str(); // Conflicts with color spaces or roles. (Always remove this alias.) diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.h b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.h index 8e44efcce8..2eb5beacc1 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.h +++ b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.h @@ -11,6 +11,7 @@ #include +#include "ConfigUtils.h" #include "utils/StringUtils.h" #include "Logging.h" @@ -33,6 +34,7 @@ class SectionMerger SectionMerger(MergeHandlerOptions options) : m_baseConfig(options.baseConfig), m_inputConfig(options.inputConfig), m_mergedConfig(options.mergedConfig), m_params(options.params) +// m_inputToBaseGtScene(nullptr), m_inputToBaseGtDisplay(nullptr) { if (!options.baseConfig || !options.inputConfig || !options.mergedConfig || !options.params) { @@ -40,6 +42,12 @@ class SectionMerger } // m_strategy = options.params->getDefaultStrategy(); // m_params->setDefaultStrategy(options.params->getDefaultStrategy()); + +// ConstTransformRcPtr tmp; +// m_inputToBaseGtScene = tmp; +// m_inputToBaseGtDisplay = tmp; + +// initializeRefSpaceConverters(); } void merge() @@ -71,6 +79,68 @@ class SectionMerger void notify(std::string s, bool mustThrow) const; +// // FIXME: Make this a functional. +// bool hasColorSpaceRefType(const ConstConfigRcPtr & config, ReferenceSpaceType refType) +// { +// SearchReferenceSpaceType searchRefType = static_cast(refType); +// int n = config->getNumColorSpaces(searchRefType, COLORSPACE_ALL); +// return n > 0; +// } +// +// void initializeRefSpaceConverters() +// { +// // Note: The base config reference space is always used, regardless of strategy. +// //std::cout << "initializing ref converters\n"; +// +// if (!m_params->isAssumeCommonReferenceSpace()) +// { +// if (hasColorSpaceRefType(m_inputConfig, REFERENCE_SPACE_SCENE)) +// { +// try +// { +// m_inputToBaseGtScene = ConfigUtils::getRefSpaceConverter( +// m_inputConfig, +// m_baseConfig, +// REFERENCE_SPACE_SCENE +// ); +// } +// catch(const Exception & e) +// { +// LogError(e.what()); +// } +// } +// else +// { +// // Always need both transforms, even if they're empty. +// m_inputToBaseGtScene = GroupTransform::Create(); +// } +// +// // Only attempt to build the converter if the input config has this type of +// // reference space. Using the input config for this determination since it is +// // only input config color spaces whose reference space is converted. +// if (hasColorSpaceRefType(m_inputConfig, REFERENCE_SPACE_DISPLAY)) +// { +// try +// { +// m_inputToBaseGtDisplay = ConfigUtils::getRefSpaceConverter( +// m_inputConfig, +// m_baseConfig, +// REFERENCE_SPACE_DISPLAY +// ); +// } +// catch(const Exception & e) +// { +// LogError(e.what()); +// } +// } +// else +// { +// // Always need both transforms, even if they're empty. +// m_inputToBaseGtDisplay = GroupTransform::Create(); +// } +// } +// } + private: virtual void handlePreferInput() { @@ -105,6 +175,11 @@ class SectionMerger const ConfigMergingParametersRcPtr & m_params; ConfigMergingParameters::MergeStrategies m_strategy; +// FIXME: These are initialized separately for display-views and colorspaces, perhaps move +// these up to the config merger level? + ConstTransformRcPtr m_inputToBaseGtScene; + ConstTransformRcPtr m_inputToBaseGtDisplay; + void mergeStringVecWithoutDuplicate(StringUtils::StringVec & input, StringUtils::StringVec & mergedVec) const; void inputFirstMergeStringVec(StringUtils::StringVec & input, @@ -205,6 +280,15 @@ class DisplayViewMerger : public SectionMerger { m_strategy = options.params->getDefaultStrategy(); } + +// initializeRefSpaceConverters(); + if (!options.params->isAssumeCommonReferenceSpace()) + { + ConfigUtils::initializeRefSpaceConverters(m_inputToBaseGtScene, + m_inputToBaseGtDisplay, + m_baseConfig, + m_inputConfig); + } } private: @@ -227,10 +311,12 @@ class DisplayViewMerger : public SectionMerger void processActiveLists(); - void addUniqueViewTransforms(const ConstConfigRcPtr & cfg); + void addViewTransform(const ConstConfigRcPtr & cfg, const char * name, bool isInput); + void addUniqueViewTransforms(const ConstConfigRcPtr & cfg, bool isInput); void processViewTransforms(const ConstConfigRcPtr & first, const ConstConfigRcPtr & second, - bool preferSecond); + bool preferSecond, + bool secondIsInput); void processViewingRules(const ConstConfigRcPtr & first, const ConstConfigRcPtr & second, @@ -283,6 +369,15 @@ class ColorspacesMerger : public SectionMerger { m_strategy = options.params->getDefaultStrategy(); } + +// initializeRefSpaceConverters(); + if (!options.params->isAssumeCommonReferenceSpace()) + { + ConfigUtils::initializeRefSpaceConverters(m_inputToBaseGtScene, + m_inputToBaseGtDisplay, + m_baseConfig, + m_inputConfig); + } } struct ColorspaceNameConflict @@ -341,8 +436,8 @@ class ColorspacesMerger : public SectionMerger void mergeColorSpace(ConfigRcPtr & mergeConfig, ColorSpaceRcPtr & eInputCS, std::vector & addedInputColorSpaces); - void initializeRefSpaceConverters(ConstTransformRcPtr & inputToBaseGtScene, - ConstTransformRcPtr & inputToBaseGtDisplay); +// void initializeRefSpaceConverters(ConstTransformRcPtr & inputToBaseGtScene, +// ConstTransformRcPtr & inputToBaseGtDisplay); void addColorSpaces(); @@ -360,7 +455,11 @@ class ColorspacesMerger : public SectionMerger void handleErrorCodeWhenAddingInputFirst(ColorSpaceRcPtr & eColorspace); void handleErrorCodes(ColorSpaceRcPtr & eColorspace); - bool handleAvoidDuplicatesOption(ConfigRcPtr & eBase, ColorSpaceRcPtr & eColorspace); +// bool handleAvoidDuplicatesOption(ConfigRcPtr & eBase, ColorSpaceRcPtr & eColorspace); + bool handleAvoidDuplicatesOption(ConfigUtils::ColorSpaceFingerprints & fingerprints, + ConfigRcPtr & eBase, + const ConstConfigRcPtr & inputConfig, + ColorSpaceRcPtr & inputCS); void handleAssumeCommonReferenceOption(ColorSpaceRcPtr & eColorspace); void handleMarkedToBeDeletedColorspaces(); diff --git a/tests/cpu/ConfigUtils_tests.cpp b/tests/cpu/ConfigUtils_tests.cpp index fc04a56c42..3e25f49775 100644 --- a/tests/cpu/ConfigUtils_tests.cpp +++ b/tests/cpu/ConfigUtils_tests.cpp @@ -28,7 +28,7 @@ name: base - . roles: - aces_interchange: ap0 +# aces_interchange: ap0 cie_xyz_d65_interchange: CIE-XYZ-D65 file_rules: @@ -85,10 +85,10 @@ colorspaces: # reference space = aces2065-1 R"(ocio_profile_version: 2.1 name: input search_path: lut_dir -inactive_colorspaces: [ACES2065-1] +#inactive_colorspaces: [ACES2065-1] roles: - aces_interchange: ACES2065-1 +# aces_interchange: ACES2065-1 cie_xyz_d65_interchange: CIE-XYZ-D65 file_rules: @@ -111,6 +111,17 @@ inactive_colorspaces: [ACES2065-1] # Matrix from cie-xyz to linear rec.709 - ! {matrix: [ 3.240969941905, -1.537383177570, -0.498610760293, 0, -0.969243636281, 1.875967501508, 0.041555057407, 0, 0.055630079697, -0.203976958889, 1.056971514243, 0, 0, 0, 0, 1 ]} + - ! + name: vt scene ref + from_scene_reference: ! {gamma: 2.4, offset: 0.055, direction: inverse} + to_scene_reference: ! {gamma: 2.4, offset: 0.055} + + - ! + name: vt display ref + description: from base + from_display_reference: ! {gamma: 2.4, offset: 0.055, direction: inverse} + to_display_reference: ! {gamma: 2.4, offset: 0.055} + display_colorspaces: # reference space = linear rec 709 - ! name: sRGB - Display @@ -156,8 +167,16 @@ colorspaces: # reference space = linear rec 709 OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + OCIO::ConstConfigRcPtr cgConfig = OCIO::Config::CreateFromFile("ocio://cg-config-v1.0.0_aces-v1.3_ocio-v2.1"); - // scene-referred reference space +// const char * srcInterchange = nullptr; +// const char * builtinInterchange = nullptr; +// OCIO::Config::IdentifyInterchangeSpace(&srcInterchange, &builtinInterchange, +// inputConfig, "ACES2065-1", cgConfig, "ACES2065-1"); +// std::cout << "src: " << srcInterchange << "\n"; +// std::cout << "dst: " << builtinInterchange << "\n"; + + // Scene-referred reference space check. // Get the transform to convert the scene-referred reference space. auto inputToBaseGtScene = OCIO::ConfigUtils::getRefSpaceConverter(inputConfig, @@ -178,7 +197,8 @@ colorspaces: # reference space = linear rec 709 OCIO_CHECK_EQUAL(colorspaces.size(), 4); // ACES2065-1 no longer needs transforms, it is now the reference space. - // But transforms are not simplified, for clarity in what was done. + // But transforms are not simplified, for clarity in what was done, + // so it is a forward and inverse of the same matrix. { OCIO::ColorSpaceRcPtr cs = colorspaces.at(0)->createEditableCopy(); OCIO::ConfigUtils::updateReferenceColorspace(cs, inputToBaseGtScene); @@ -188,19 +208,19 @@ colorspaces: # reference space = linear rec 709 auto gtx = OCIO::DynamicPtrCast(t); OCIO_REQUIRE_ASSERT(gtx); OCIO_CHECK_EQUAL(gtx->getNumTransforms(), 2); - { std::vector m44(16, 0.0); auto mtx0 = OCIO::DynamicPtrCast(gtx->getTransform(0)); OCIO_REQUIRE_ASSERT(mtx0); + OCIO_CHECK_ASSERT(mtx0->getDirection() == OCIO::TRANSFORM_DIR_FORWARD); mtx0->getMatrix(m44.data()); OCIO_CHECK_CLOSE(m44[0], 2.521686186744, 1e-5f); } - { std::vector m44(16, 0.0); auto mtx1 = OCIO::DynamicPtrCast(gtx->getTransform(1)); OCIO_REQUIRE_ASSERT(mtx1); + OCIO_CHECK_ASSERT(mtx1->getDirection() == OCIO::TRANSFORM_DIR_FORWARD); mtx1->getMatrix(m44.data()); OCIO_CHECK_CLOSE(m44[0], 0.4396329819194919, 1e-5f); } @@ -222,6 +242,7 @@ colorspaces: # reference space = linear rec 709 std::vector m44(16, 0.0); auto mtx0 = OCIO::DynamicPtrCast(gtx->getTransform(1)); OCIO_REQUIRE_ASSERT(mtx0); + OCIO_CHECK_ASSERT(mtx0->getDirection() == OCIO::TRANSFORM_DIR_FORWARD); mtx0->getMatrix(m44.data()); OCIO_CHECK_CLOSE(m44[0], 0.4396329819194919, 1e-5f); OCIO_CHECK_CLOSE(m44[1], 0.3829886981515535, 1e-5f); @@ -229,7 +250,7 @@ colorspaces: # reference space = linear rec 709 OCIO_REQUIRE_ASSERT(!cs->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); } - // rec709 had no transforms but now needs the same matrix. + // rec709 had no transforms but now needs the Rec.709 to ACES2065-1 matrix. { OCIO::ColorSpaceRcPtr cs = colorspaces.at(2)->createEditableCopy(); OCIO::ConfigUtils::updateReferenceColorspace(cs, inputToBaseGtScene); @@ -243,6 +264,7 @@ colorspaces: # reference space = linear rec 709 std::vector m44(16, 0.0); auto mtx0 = OCIO::DynamicPtrCast(gtx->getTransform(0)); OCIO_REQUIRE_ASSERT(mtx0); + OCIO_CHECK_ASSERT(mtx0->getDirection() == OCIO::TRANSFORM_DIR_FORWARD); mtx0->getMatrix(m44.data()); OCIO_CHECK_CLOSE(m44[0], 0.4396329819194919, 1e-5f); OCIO_CHECK_CLOSE(m44[1], 0.3829886981515535, 1e-5f); @@ -255,13 +277,12 @@ colorspaces: # reference space = linear rec 709 OCIO::ColorSpaceRcPtr cs = colorspaces.at(3)->createEditableCopy(); OCIO::ConfigUtils::updateReferenceColorspace(cs, inputToBaseGtScene); OCIO_CHECK_EQUAL(cs->isData(), true); - OCIO_REQUIRE_ASSERT(!cs->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE)) - OCIO_REQUIRE_ASSERT(!cs->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)) + OCIO_REQUIRE_ASSERT(!cs->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE)); + OCIO_REQUIRE_ASSERT(!cs->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); } } - - // display-referred reference space + // Display-referred reference space check. // Get the transform to convert the display-referred reference space. auto inputToBaseGtDisplay = OCIO::ConfigUtils::getRefSpaceConverter(inputConfig, @@ -276,7 +297,6 @@ colorspaces: # reference space = linear rec 709 OCIO::COLORSPACE_ALL, i); OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace(name); - // display-referred colorspace colorspaces.push_back(cs); } OCIO_CHECK_EQUAL(colorspaces.size(), 2); @@ -297,14 +317,17 @@ colorspaces: # reference space = linear rec 709 std::vector m44(16, 0.0); auto mtx0 = OCIO::DynamicPtrCast(gtx->getTransform(0)); OCIO_REQUIRE_ASSERT(mtx0); + OCIO_CHECK_ASSERT(mtx0->getDirection() == OCIO::TRANSFORM_DIR_INVERSE); mtx0->getMatrix(m44.data()); - //OCIO_CHECK_CLOSE(m44[0], 3.240969941907037, 1e-5f); - //OCIO_CHECK_CLOSE(m44[1], -1.537383177571058, 1e-5f); + // The coefficients are for Rec.709 to CIE-XYZ, but the direction is inverse. + OCIO_CHECK_CLOSE(m44[0], 0.412390799266, 1e-5f); + OCIO_CHECK_CLOSE(m44[1], 0.357584339384, 1e-5f); OCIO_CHECK_EQUAL(gtx->getTransform(1)->getTransformType(), OCIO::TRANSFORM_TYPE_EXPONENT_WITH_LINEAR); } // CIE-XYZ-D65 had a matrix but no longer needs transforms, it's now the reference space. + // An additional matrix is added to invert the original matrix. { OCIO::ColorSpaceRcPtr cs = colorspaces.at(1)->createEditableCopy(); OCIO::ConfigUtils::updateReferenceColorspace(cs, inputToBaseGtDisplay); @@ -321,32 +344,38 @@ colorspaces: # reference space = linear rec 709 std::vector m44(16, 0.0); auto mtx0 = OCIO::DynamicPtrCast(gtx->getTransform(0)); OCIO_REQUIRE_ASSERT(mtx0); + OCIO_CHECK_ASSERT(mtx0->getDirection() == OCIO::TRANSFORM_DIR_INVERSE); mtx0->getMatrix(m44.data()); - //OCIO_CHECK_CLOSE(m44[0], 3.240969941907, 1e-5f); + // The coefficients are for Rec.709 to CIE-XYZ, but the direction is inverse. + OCIO_CHECK_CLOSE(m44[0], 0.412390799266, 1e-5f); } - { OCIO_CHECK_EQUAL(gtx->getTransform(1)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); std::vector m44(16, 0.0); auto mtx0 = OCIO::DynamicPtrCast(gtx->getTransform(1)); OCIO_REQUIRE_ASSERT(mtx0); + OCIO_CHECK_ASSERT(mtx0->getDirection() == OCIO::TRANSFORM_DIR_FORWARD); mtx0->getMatrix(m44.data()); OCIO_CHECK_CLOSE(m44[0], 0.412390799266, 1e-5f); } } } + // View transform reference space check. + + // Convert each one of the view transforms and check the result. + // The view transform of the input config goes from linear rec.709 to linear rec.709. + // This needs to be adapted to the base config that goes from cie-xyz to aces2065-1. + std::vector viewTransforms; + for (int v = 0; v < inputConfig->getNumViewTransforms(); v++) + { + const char * name = inputConfig->getViewTransformNameByIndex(v); + viewTransforms.push_back(inputConfig->getViewTransform(name)); + } { - // Convert each one of the view transforms and check the result. - // The view transform of the input config goes from linear rec.709 to linear rec.709. - // This needs to be adapted to the base config that goes from cie-xyz to aces2065-1. - std::vector viewTransforms; - for (int v = 0; v < inputConfig->getNumViewTransforms(); v++) - { - const char * name = inputConfig->getViewTransformNameByIndex(v); - viewTransforms.push_back(inputConfig->getViewTransform(name)); - } +// OCIO_CHECK_EQUAL(inputConfig->getNumViewTransforms(), 3); +// ConstViewTransformRcPtr viewTransform = OCIO::ViewTransformRcPtr vt = viewTransforms[0]->createEditableCopy(); OCIO::ConfigUtils::updateReferenceView(vt, inputToBaseGtScene, inputToBaseGtDisplay); OCIO_REQUIRE_ASSERT(!vt->getTransform(OCIO::VIEWTRANSFORM_DIR_TO_REFERENCE)) @@ -357,14 +386,16 @@ colorspaces: # reference space = linear rec 709 OCIO_REQUIRE_ASSERT(gtx); OCIO_CHECK_EQUAL(gtx->getNumTransforms(), 3); - // Matrix from cie-xyz to rec.709. + // Matrix from ACES2065-1 to Rec.709. { OCIO_CHECK_EQUAL(gtx->getTransform(0)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); std::vector m44(16, 0.0); auto mtx0 = OCIO::DynamicPtrCast(gtx->getTransform(0)); OCIO_REQUIRE_ASSERT(mtx0); + OCIO_CHECK_ASSERT(mtx0->getDirection() == OCIO::TRANSFORM_DIR_INVERSE); mtx0->getMatrix(m44.data()); - //OCIO_CHECK_CLOSE(m44[0], 3.240969941907, 1e-5f); + // The coefficients are for Rec.709 to ACES2065-1, but the direction is inverse. + OCIO_CHECK_CLOSE(m44[0], 0.439632981919, 1e-5f); } // The original group transform from the input config. @@ -373,34 +404,196 @@ colorspaces: # reference space = linear rec 709 auto gtxA = OCIO::DynamicPtrCast(gtx->getTransform(1)); OCIO_REQUIRE_ASSERT(gtxA); OCIO_CHECK_EQUAL(gtxA->getNumTransforms(), 3); - { std::vector m44(16, 0.0); auto mtx0 = OCIO::DynamicPtrCast(gtxA->getTransform(0)); OCIO_REQUIRE_ASSERT(mtx0); + OCIO_CHECK_ASSERT(mtx0->getDirection() == OCIO::TRANSFORM_DIR_FORWARD); mtx0->getMatrix(m44.data()); OCIO_CHECK_CLOSE(m44[0], 0.439632981919, 1e-5f); } - OCIO_CHECK_EQUAL(gtxA->getTransform(1)->getTransformType(), OCIO::TRANSFORM_TYPE_BUILTIN); - { std::vector m44(16, 0.0); auto mtx2 = OCIO::DynamicPtrCast(gtxA->getTransform(2)); OCIO_REQUIRE_ASSERT(mtx2); + OCIO_CHECK_ASSERT(mtx2->getDirection() == OCIO::TRANSFORM_DIR_FORWARD); mtx2->getMatrix(m44.data()); OCIO_CHECK_CLOSE(m44[0], 3.240969941905, 1e-5f); } } - // Matrix from rec.709 to aces2065-1. + // Matrix from Rec.709 to CIE-XYZ. { std::vector m44(16, 0.0); auto mtx2 = OCIO::DynamicPtrCast(gtx->getTransform(2)); OCIO_REQUIRE_ASSERT(mtx2); + OCIO_CHECK_ASSERT(mtx2->getDirection() == OCIO::TRANSFORM_DIR_FORWARD); + mtx2->getMatrix(m44.data()); + OCIO_CHECK_CLOSE(m44[0], 0.412390799266, 1e-5f); + } + } + + // Verify that both directions are converted correctly. + { + OCIO::ViewTransformRcPtr vt = viewTransforms[1]->createEditableCopy(); + OCIO::ConfigUtils::updateReferenceView(vt, inputToBaseGtScene, inputToBaseGtDisplay); + + OCIO_CHECK_EQUAL(vt->getReferenceSpaceType(), OCIO::REFERENCE_SPACE_SCENE); + + { + OCIO::ConstTransformRcPtr t = vt->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_GROUP); + auto gtx = OCIO::DynamicPtrCast(t); + OCIO_REQUIRE_ASSERT(gtx); + OCIO_CHECK_EQUAL(gtx->getNumTransforms(), 3); + } + OCIO::ConstTransformRcPtr t = vt->getTransform(OCIO::VIEWTRANSFORM_DIR_TO_REFERENCE); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_GROUP); + auto gtx = OCIO::DynamicPtrCast(t); + OCIO_REQUIRE_ASSERT(gtx); + OCIO_CHECK_EQUAL(gtx->getNumTransforms(), 3); + + // Matrix from CIE-XYZ to Rec.709. + { + OCIO_CHECK_EQUAL(gtx->getTransform(0)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); + std::vector m44(16, 0.0); + auto mtx2 = OCIO::DynamicPtrCast(gtx->getTransform(0)); + OCIO_REQUIRE_ASSERT(mtx2); + OCIO_CHECK_ASSERT(mtx2->getDirection() == OCIO::TRANSFORM_DIR_INVERSE); mtx2->getMatrix(m44.data()); + // The coefficients are for Rec.709 to CIE-XYZ, but the direction is inverse. + OCIO_CHECK_CLOSE(m44[0], 0.412390799266, 1e-5f); + } + // The original transform from the input config. + { + OCIO_CHECK_EQUAL(gtx->getTransform(1)->getTransformType(), OCIO::TRANSFORM_TYPE_EXPONENT_WITH_LINEAR); + } + // Matrix from Rec.709 to ACES2065-1. + { + std::vector m44(16, 0.0); + auto mtx0 = OCIO::DynamicPtrCast(gtx->getTransform(2)); + OCIO_REQUIRE_ASSERT(mtx0); + OCIO_CHECK_ASSERT(mtx0->getDirection() == OCIO::TRANSFORM_DIR_FORWARD); + mtx0->getMatrix(m44.data()); OCIO_CHECK_CLOSE(m44[0], 0.439632981919, 1e-5f); + } + } + + // Verify that display-ref view transforms have the display converter on both sides. + { + OCIO::ViewTransformRcPtr vt = viewTransforms[2]->createEditableCopy(); + OCIO::ConfigUtils::updateReferenceView(vt, inputToBaseGtScene, inputToBaseGtDisplay); + + OCIO_CHECK_EQUAL(vt->getReferenceSpaceType(), OCIO::REFERENCE_SPACE_DISPLAY); + + // FROM-REF direction. + + OCIO::ConstTransformRcPtr t = vt->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_GROUP); + auto gtx = OCIO::DynamicPtrCast(t); + OCIO_REQUIRE_ASSERT(gtx); + OCIO_CHECK_EQUAL(gtx->getNumTransforms(), 3); + + // Because the reference space type is display, use the XYZ matrix on both ends. + // Matrix from CIE-XYZ to Rec.709. + { + OCIO_CHECK_EQUAL(gtx->getTransform(0)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); + std::vector m44(16, 0.0); + auto mtx2 = OCIO::DynamicPtrCast(gtx->getTransform(0)); + OCIO_REQUIRE_ASSERT(mtx2); + OCIO_CHECK_ASSERT(mtx2->getDirection() == OCIO::TRANSFORM_DIR_INVERSE); + mtx2->getMatrix(m44.data()); + // The coefficients are for Rec.709 to CIE-XYZ, but the direction is inverse. + OCIO_CHECK_CLOSE(m44[0], 0.412390799266, 1e-5f); } + // The original transform from the input config. + { + OCIO_CHECK_EQUAL(gtx->getTransform(1)->getTransformType(), OCIO::TRANSFORM_TYPE_EXPONENT_WITH_LINEAR); + } + // Matrix from Rec.709 to CIE-XYZ. + { + std::vector m44(16, 0.0); + auto mtx0 = OCIO::DynamicPtrCast(gtx->getTransform(2)); + OCIO_REQUIRE_ASSERT(mtx0); + OCIO_CHECK_ASSERT(mtx0->getDirection() == OCIO::TRANSFORM_DIR_FORWARD); + mtx0->getMatrix(m44.data()); + OCIO_CHECK_CLOSE(m44[0], 0.412390799266, 1e-5f); + } + + // TO-REF direction. + + OCIO::ConstTransformRcPtr t1 = vt->getTransform(OCIO::VIEWTRANSFORM_DIR_TO_REFERENCE); + OCIO_CHECK_EQUAL(t1->getTransformType(), OCIO::TRANSFORM_TYPE_GROUP); + gtx = OCIO::DynamicPtrCast(t1); + OCIO_REQUIRE_ASSERT(gtx); + OCIO_CHECK_EQUAL(gtx->getNumTransforms(), 3); + + // Matrix from CIE-XYZ to Rec.709. + { + OCIO_CHECK_EQUAL(gtx->getTransform(0)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); + std::vector m44(16, 0.0); + auto mtx2 = OCIO::DynamicPtrCast(gtx->getTransform(0)); + OCIO_REQUIRE_ASSERT(mtx2); + OCIO_CHECK_ASSERT(mtx2->getDirection() == OCIO::TRANSFORM_DIR_INVERSE); + mtx2->getMatrix(m44.data()); + // The coefficients are for Rec.709 to CIE-XYZ, but the direction is inverse. + OCIO_CHECK_CLOSE(m44[0], 0.412390799266, 1e-5f); + } + // The original transform from the input config. + { + OCIO_CHECK_EQUAL(gtx->getTransform(1)->getTransformType(), OCIO::TRANSFORM_TYPE_EXPONENT_WITH_LINEAR); + } + // Because the reference space type is display, use the XYZ matrix on both ends. + // Matrix from Rec.709 to CIE-XYZ. + { + std::vector m44(16, 0.0); + auto mtx0 = OCIO::DynamicPtrCast(gtx->getTransform(2)); + OCIO_REQUIRE_ASSERT(mtx0); + OCIO_CHECK_ASSERT(mtx0->getDirection() == OCIO::TRANSFORM_DIR_FORWARD); + mtx0->getMatrix(m44.data()); + OCIO_CHECK_CLOSE(m44[0], 0.412390799266, 1e-5f); + } + } + + // Test when the conversion is a no-op (base to base). + // Get the transform to convert the scene-referred reference space. + inputToBaseGtScene = OCIO::ConfigUtils::getRefSpaceConverter(baseConfig, + baseConfig, + OCIO::REFERENCE_SPACE_SCENE); + + { + OCIO::ColorSpaceRcPtr cs = inputConfig->getColorSpace("ACES2065-1")->createEditableCopy(); + OCIO::ConfigUtils::updateReferenceColorspace(cs, inputToBaseGtScene); + OCIO::ConstTransformRcPtr t = cs->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); + } + + { + OCIO::ViewTransformRcPtr vt = viewTransforms[1]->createEditableCopy(); + OCIO::ConfigUtils::updateReferenceView(vt, inputToBaseGtScene, inputToBaseGtDisplay); + { + OCIO::ConstTransformRcPtr t = vt->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_GROUP); + auto gtx = OCIO::DynamicPtrCast(t); + OCIO_REQUIRE_ASSERT(gtx); + OCIO_CHECK_EQUAL(gtx->getNumTransforms(), 2); + OCIO_CHECK_EQUAL(gtx->getTransform(0)->getTransformType(), OCIO::TRANSFORM_TYPE_EXPONENT_WITH_LINEAR); + OCIO_CHECK_EQUAL(gtx->getTransform(1)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); + } + } + + // Both sides are now no-ops. + inputToBaseGtDisplay = OCIO::ConfigUtils::getRefSpaceConverter(inputConfig, + inputConfig, + OCIO::REFERENCE_SPACE_DISPLAY); + { + OCIO::ViewTransformRcPtr vt = viewTransforms[1]->createEditableCopy(); + OCIO::ConfigUtils::updateReferenceView(vt, inputToBaseGtScene, inputToBaseGtDisplay); + { + OCIO::ConstTransformRcPtr t = vt->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_EXPONENT_WITH_LINEAR); + } } } @@ -430,6 +623,12 @@ inactive_colorspaces: [] description: Raw but with a different name. isdata: true + - ! + name: requires ACES cct + isdata: false + description: A color space that requires a space lower in the config that may not have been added yet. + to_scene_reference: ! {src: ACES cct, dst: ref_space} + - ! name: standard RGB isdata: false @@ -481,104 +680,95 @@ inactive_colorspaces: [] OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromFile("ocio://cg-config-v1.0.0_aces-v1.3_ocio-v2.1"); OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); - std::vector colorspaces; - OCIO::SearchReferenceSpaceType refType = OCIO::SEARCH_REFERENCE_SPACE_SCENE; - for (int i = 0; i < inputConfig->getNumColorSpaces(refType, OCIO::COLORSPACE_ALL); ++i) - { - const char * name = inputConfig->getColorSpaceNameByIndex(refType, OCIO::COLORSPACE_ALL, i); - OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace(name); - colorspaces.push_back(cs); - } + OCIO::ConfigUtils::ColorSpaceFingerprints fingerprints; + OCIO::ConfigUtils::initializeColorSpacesFingerprints(fingerprints, baseConfig); + +// for (const auto & pair : fingerprints) +// { +// std::vector vals = pair.second.second; +// +// std::cout << pair.first << "\n"; +// +// for (size_t i = 0; i < vals.size(); i++) +// { +// std::cout << vals[i] << ", "; +// } +// std::cout << "\n"; +// } - // Check 'ref_space' { -// OCIO::ConstColorSpaceRcPtr cs = colorspaces[0]; -// TODO: could omit the vector of color spaces to make this easier to read. OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("ref_space"); - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(baseConfig, - cs, + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, OCIO::REFERENCE_SPACE_SCENE); OCIO_CHECK_EQUAL(name, std::string("ACES2065-1")); } - - // Check 'Unknown' +// { +// OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("Unknown"); +// const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, +// OCIO::REFERENCE_SPACE_SCENE); +// OCIO_CHECK_EQUAL(name, std::string("Raw")); +// } { - OCIO::ConstColorSpaceRcPtr cs = colorspaces[1]; - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(baseConfig, - cs, + OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("standard RGB"); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, OCIO::REFERENCE_SPACE_SCENE); - OCIO_CHECK_EQUAL(name, std::string("Raw")); + OCIO_CHECK_EQUAL(name, std::string("sRGB - Texture")); } - - // Check 'standard RGB' { - OCIO::ConstColorSpaceRcPtr cs = colorspaces[2]; - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(baseConfig, - cs, + OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("approx. standard RGB"); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, OCIO::REFERENCE_SPACE_SCENE); OCIO_CHECK_EQUAL(name, std::string("sRGB - Texture")); } - - // Check 'approx. standard RGB'. Matrix values are different but within tolerance { - OCIO::ConstColorSpaceRcPtr cs = colorspaces[3]; - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(baseConfig, - cs, + OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("very approx. standard RGB"); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, OCIO::REFERENCE_SPACE_SCENE); - OCIO_CHECK_EQUAL(name, std::string("sRGB - Texture")); + OCIO_CHECK_EQUAL(name, std::string("")); } - - // Check 'very approx. standard RGB'. Gamma value is outside tolerance -- no match. { - OCIO::ConstColorSpaceRcPtr cs = colorspaces[4]; - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(baseConfig, - cs, + OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("ACES cct"); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, OCIO::REFERENCE_SPACE_SCENE); - OCIO_CHECK_EQUAL(name, std::string("")); + OCIO_CHECK_EQUAL(name, std::string("ACEScct")); } - - // Check 'ACES cct'. { - OCIO::ConstColorSpaceRcPtr cs = colorspaces[5]; - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(baseConfig, - cs, + OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("requires ACES cct"); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, OCIO::REFERENCE_SPACE_SCENE); OCIO_CHECK_EQUAL(name, std::string("ACEScct")); } - - // Check 'ACES cg' { - OCIO::ConstColorSpaceRcPtr cs = colorspaces[6]; - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(baseConfig, - cs, + OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("ACES cg"); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, OCIO::REFERENCE_SPACE_SCENE); OCIO_CHECK_EQUAL(name, std::string("ACEScg")); } - - // Check 'ACES cg' but with the wrong ref space type -- no match. { - OCIO::ConstColorSpaceRcPtr cs = colorspaces[6]; - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(baseConfig, - cs, + OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("ACES cg"); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, OCIO::REFERENCE_SPACE_DISPLAY); OCIO_CHECK_EQUAL(name, std::string("")); } - - // Check 'pq display'. { - OCIO::ConstColorSpaceRcPtr cs = colorspaces[7]; - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(baseConfig, - cs, + OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("pq display"); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, OCIO::REFERENCE_SPACE_DISPLAY); OCIO_CHECK_EQUAL(name, std::string("Rec.2100-PQ - Display")); } - - // Check 'pq display' but with wrong ref space type -- no match. { - OCIO::ConstColorSpaceRcPtr cs = colorspaces[7]; - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(baseConfig, - cs, + OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("pq display"); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, OCIO::REFERENCE_SPACE_SCENE); OCIO_CHECK_EQUAL(name, std::string("")); } -} \ No newline at end of file +} + +// OCIO_ADD_TEST(MergeConfigs, config_utils_find_equivalent_colorspace2) +// { +// OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromFile("ocio://cg-config-v1.0.0_aces-v1.3_ocio-v2.1"); +// OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromFile("/Users/walkerdo/Documents/work/Autodesk/color/adsk_color_mgmt/OCIO/configs/flame/flame_core_config.ocio"); +// +// OCIO::ConfigUtils::ColorSpaceFingerprintMap fingerprints; +// OCIO::ConfigUtils::initializeColorSpacesFingerprintMap(fingerprints, baseConfig); +// } diff --git a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp index cc3d7351b4..899b97c2fc 100644 --- a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp +++ b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp @@ -132,6 +132,7 @@ void checkForLogOrException(LogType type, int line, std::function setup, { if (type == LOG_TYPE_ERROR) { +// FIXME // OCIO_CHECK_ASSERT_FROM(OCIO::checkAndMuteError(logGuard, s), line); const bool errorFound = OCIO::checkAndMuteError(logGuard, s); @@ -293,11 +294,9 @@ OCIO_ADD_TEST(MergeConfigs, overrides) OCIO::ConstConfigRcPtr inputConfig; OCIO_CHECK_NO_THROW(inputConfig = getInputConfig()); - auto setup = [&baseConfig, &inputConfig] - (OCIO::ConfigMergerRcPtr & merger, - OCIO::ConfigRcPtr mergedConfig, - MergeStrategy strategy, - std::function cb) + // Test that the overrides options are taken into account in the merging process. + + auto setupBasics = [](OCIO::ConfigMergerRcPtr & merger, MergeStrategy strategy) -> OCIO::ConfigMergingParametersRcPtr { OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); merger->addParams(params); @@ -305,35 +304,9 @@ OCIO_ADD_TEST(MergeConfigs, overrides) merger->getParams(0)->setColorspaces(strategy); // Not looking for duplicates as this test does not test that. merger->getParams(0)->setAvoidDuplicates(false); +// merger->getParams(0)->setAssumeCommonReferenceSpace(true); - if (cb) - { - cb(merger); - } - - OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; - // Merge name and description. - OCIO::GeneralMerger(options).merge(); - // Merge active_display, active_views. - OCIO::DisplayViewMerger(options).merge(); - // Merge inactive_colorspaces, environment and search_path. - OCIO::ColorspacesMerger(options).merge(); - }; - - // Test that the overrides options are taken into account in the merging process. - - auto testAllStrategies = [&baseConfig, &setup] - (MergeStrategy strategy, - int line) - { - OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); - OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); - setup(merger, - mergedConfig, - strategy, - [](OCIO::ConfigMergerRcPtr & merger) - { - // overrides + // Set the overrides. merger->getParams(0)->setName("OVR Name"); merger->getParams(0)->setDescription("OVR Desc"); merger->getParams(0)->setSearchPath("OVR1,OVR2"); @@ -342,8 +315,12 @@ OCIO_ADD_TEST(MergeConfigs, overrides) merger->getParams(0)->setActiveDisplays("OVR DISP 1,OVR DISP 2"); merger->getParams(0)->setActiveViews("OVR VIEW 1,OVR VIEW 2"); merger->getParams(0)->setInactiveColorspaces("view_1, ACES2065-1"); - }); + return params; + }; + + auto doTests = [](OCIO::ConfigRcPtr & mergedConfig, int line) + { OCIO_CHECK_EQUAL_FROM(std::string(mergedConfig->getName()), std::string("OVR Name"), line); OCIO_CHECK_EQUAL_FROM(std::string(mergedConfig->getDescription()), std::string("OVR Desc"), line); @@ -362,16 +339,84 @@ OCIO_ADD_TEST(MergeConfigs, overrides) }; // Test sections with strategy = PreferInput - testAllStrategies(MergeStrategy::STRATEGY_PREFER_INPUT, __LINE__); + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() + { + // Merge name and description. + OCIO::GeneralMerger(options).merge(); + // Merge active_display, active_views. + OCIO::DisplayViewMerger(options).merge(); + // Merge inactive_colorspaces, environment and search_path. + OCIO::ColorspacesMerger(options).merge(); + }, + "The Input config contains a value that would override the Base config: shared_views: SHARED_1", + "The Input config contains a value that would override the Base config: display: DISP_1, view: VIEW_1", + "The Input config contains a value that would override the Base config: default_view_transform: Un-tone-mapped-2", + "The Input config contains a value that would override the Base config: viewing_rules: RULE_1", + "Color space 'ACES2065-1' will replace a color space in the base config.", + "Color space 'view_1' will replace a color space in the base config."); + doTests(mergedConfig, __LINE__); + } // Test sections with strategy = PreferBase. - testAllStrategies(MergeStrategy::STRATEGY_PREFER_BASE, __LINE__); + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() + { + // Merge name and description. + OCIO::GeneralMerger(options).merge(); + // Merge active_display, active_views. + OCIO::DisplayViewMerger(options).merge(); + // Merge inactive_colorspaces, environment and search_path. + OCIO::ColorspacesMerger(options).merge(); + }, + "The Input config contains a value that would override the Base config: shared_views: SHARED_1", + "The Input config contains a value that would override the Base config: display: DISP_1, view: VIEW_1", + "The Input config contains a value that would override the Base config: default_view_transform: Un-tone-mapped-2", + "The Input config contains a value that would override the Base config: viewing_rules: RULE_1", + "Color space 'ACES2065-1' was not merged as it's already present in the base config.", + "Color space 'view_1' was not merged as it's already present in the base config."); + doTests(mergedConfig, __LINE__); + } // Test sections with strategy = InputOnly. - testAllStrategies(MergeStrategy::STRATEGY_INPUT_ONLY, __LINE__); + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_INPUT_ONLY); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + // Merge name and description. + OCIO::GeneralMerger(options).merge(); + // Merge active_display, active_views. + OCIO::DisplayViewMerger(options).merge(); + // Merge inactive_colorspaces, environment and search_path. + OCIO::ColorspacesMerger(options).merge(); + doTests(mergedConfig, __LINE__); + } // Test sections with strategy = BaseOnly. - testAllStrategies(MergeStrategy::STRATEGY_BASE_ONLY, __LINE__); + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_BASE_ONLY); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + // Merge name and description. + OCIO::GeneralMerger(options).merge(); + // Merge active_display, active_views. + OCIO::DisplayViewMerger(options).merge(); + // Merge inactive_colorspaces, environment and search_path. + OCIO::ColorspacesMerger(options).merge(); + doTests(mergedConfig, __LINE__); + } // Strategy Remove is not tested as the overrides do not affect that strategy. } @@ -609,23 +654,15 @@ OCIO_ADD_TEST(MergeConfigs, file_rules_section) OCIO::ConstConfigRcPtr inputConfig; OCIO_CHECK_NO_THROW(inputConfig = getInputConfig()); - auto setupFileRules = [&baseConfig, &inputConfig] - (OCIO::ConfigMergerRcPtr & merger, - OCIO::ConfigRcPtr mergedConfig, - MergeStrategy strategy, - std::function cb) + auto setupBasics = [](OCIO::ConfigMergerRcPtr & merger, MergeStrategy strategy) -> OCIO::ConfigMergingParametersRcPtr { OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); merger->addParams(params); merger->getParams(0)->setFileRules(strategy); + merger->getParams(0)->setAssumeCommonReferenceSpace(true); + merger->getParams(0)->setAvoidDuplicates(false); - if (cb) - { - cb(merger); - } - - OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; - OCIO::FileRulesMerger(options).merge(); + return params; }; // Allowed strategies: All @@ -634,17 +671,14 @@ OCIO_ADD_TEST(MergeConfigs, file_rules_section) // Test that the default strategy is used as a fallback if the section strategy was not defined. { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + // Using STRATEGY_UNSET as this simulates that the section is missing from the OCIOM file. + auto params = setupBasics(merger, MergeStrategy::STRATEGY_UNSET); + // Simulate settings from OCIOM file. + merger->getParams(0)->setDefaultStrategy(MergeStrategy::STRATEGY_INPUT_ONLY); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); - setupFileRules(merger, - mergedConfig, - // Using STRATEGY_UNSET as this simulate that the section - // is missing from the OCIOM file. - MergeStrategy::STRATEGY_UNSET, - [](OCIO::ConfigMergerRcPtr & merger) - { - // Simulate settings from OCIOM file. - merger->getParams(0)->setDefaultStrategy(MergeStrategy::STRATEGY_INPUT_ONLY); - }); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::FileRulesMerger(options).merge(); OCIO_CHECK_EQUAL(mergedConfig->isStrictParsingEnabled(), false); @@ -671,12 +705,15 @@ OCIO_ADD_TEST(MergeConfigs, file_rules_section) // Test FileRules section with strategy = PreferInput. { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); - OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(true); - setupFileRules(merger, - mergedConfig, - MergeStrategy::STRATEGY_PREFER_INPUT, - nullptr); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::FileRulesMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: file_rules: TIFF", + "The Input config contains a value that would override the Base config: file_rules: Default"); OCIO::ConstFileRulesRcPtr fr = mergedConfig->getFileRules(); @@ -712,15 +749,16 @@ OCIO_ADD_TEST(MergeConfigs, file_rules_section) // Test FileRules section with strategy = PreferInput, options InputFirst = false. { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); - setupFileRules(merger, - mergedConfig, - MergeStrategy::STRATEGY_PREFER_INPUT, - [](OCIO::ConfigMergerRcPtr & merger) - { - merger->getParams(0)->setInputFirst(false); - }); - + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::FileRulesMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: file_rules: TIFF", + "The Input config contains a value that would override the Base config: file_rules: Default"); + OCIO_CHECK_EQUAL(mergedConfig->isStrictParsingEnabled(), false); OCIO::ConstFileRulesRcPtr fr = mergedConfig->getFileRules(); @@ -756,15 +794,15 @@ OCIO_ADD_TEST(MergeConfigs, file_rules_section) // Test FileRules section with strategy = PreferBase. { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); - OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(true); - setupFileRules(merger, - mergedConfig, - MergeStrategy::STRATEGY_PREFER_BASE, - [](OCIO::ConfigMergerRcPtr & merger) - { - merger->getParams(0)->setInputFirst(true); - }); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::FileRulesMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: file_rules: TIFF", + "The Input config contains a value that would override the Base config: file_rules: Default"); OCIO_CHECK_EQUAL(mergedConfig->isStrictParsingEnabled(), true); @@ -797,14 +835,16 @@ OCIO_ADD_TEST(MergeConfigs, file_rules_section) // Test FileRules section with strategy = PreferBase, options InputFirst = false. { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(false); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); - setupFileRules(merger, - mergedConfig, - MergeStrategy::STRATEGY_PREFER_BASE, - [](OCIO::ConfigMergerRcPtr & merger) - { - merger->getParams(0)->setInputFirst(false); - }); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::FileRulesMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: file_rules: TIFF", + "The Input config contains a value that would override the Base config: file_rules: Default"); + OCIO_CHECK_EQUAL(mergedConfig->isStrictParsingEnabled(), true); OCIO::ConstFileRulesRcPtr fr = mergedConfig->getFileRules(); @@ -835,12 +875,11 @@ OCIO_ADD_TEST(MergeConfigs, file_rules_section) // Test FileRules section with strategy = InputOnly. { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); - OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_INPUT_ONLY); - setupFileRules(merger, - mergedConfig, - MergeStrategy::STRATEGY_INPUT_ONLY, - nullptr); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::FileRulesMerger(options).merge(); OCIO_CHECK_EQUAL(mergedConfig->isStrictParsingEnabled(), false); @@ -867,12 +906,12 @@ OCIO_ADD_TEST(MergeConfigs, file_rules_section) // Test FileRules section with strategy = BaseOnly. { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_BASE_ONLY); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::FileRulesMerger(options).merge(); - setupFileRules(merger, - mergedConfig, - MergeStrategy::STRATEGY_BASE_ONLY, - nullptr); OCIO_CHECK_EQUAL(mergedConfig->isStrictParsingEnabled(), true); OCIO::ConstFileRulesRcPtr fr = mergedConfig->getFileRules(); @@ -897,12 +936,12 @@ OCIO_ADD_TEST(MergeConfigs, file_rules_section) // Test FileRules section with strategy = Remove. { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_REMOVE); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::FileRulesMerger(options).merge(); - setupFileRules(merger, - mergedConfig, - MergeStrategy::STRATEGY_REMOVE, - nullptr); OCIO_CHECK_EQUAL(mergedConfig->isStrictParsingEnabled(), true); OCIO::ConstFileRulesRcPtr fr = mergedConfig->getFileRules(); @@ -936,7 +975,10 @@ OCIO_ADD_TEST(MergeConfigs, file_rules_section) OCIO::MergeHandlerOptions options = { baseConfig, editableInputConfig, params, mergedConfig }; - OCIO_CHECK_NO_THROW(OCIO::FileRulesMerger(options).merge()); + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::FileRulesMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: file_rules: TIFF", + "The Input config contains a value that would override the Base config: file_rules: Default"); OCIO::ConstFileRulesRcPtr fr = mergedConfig->getFileRules(); @@ -1112,23 +1154,12 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) OCIO::ConstConfigRcPtr inputConfig; OCIO_CHECK_NO_THROW(inputConfig = getInputConfig()); - auto setupDisplaysViews = [&baseConfig, &inputConfig] - (OCIO::ConfigMergerRcPtr & merger, - OCIO::ConfigRcPtr mergedConfig, - MergeStrategy strategy, - std::function cb) + auto setupBasics = [](OCIO::ConfigMergerRcPtr & merger, MergeStrategy strategy) -> OCIO::ConfigMergingParametersRcPtr { OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); merger->addParams(params); merger->getParams(0)->setDisplayViews(strategy); - - if (cb) - { - cb(merger); - } - - OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; - OCIO::DisplayViewMerger(options).merge(); + return params; }; // Allowed strategies: All @@ -1137,18 +1168,17 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) // Test that the default strategy is used as a fallback if the section strategy was not defined. { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + + // Using STRATEGY_UNSET as this simulates that the section + // is missing from the OCIOM file. + auto params = setupBasics(merger, MergeStrategy::STRATEGY_UNSET); + // Simulate settings from OCIOM file. + merger->getParams(0)->setDefaultStrategy(MergeStrategy::STRATEGY_INPUT_ONLY); + merger->getParams(0)->setInputFirst(true); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); - setupDisplaysViews(merger, - mergedConfig, - // Using STRATEGY_UNSET as this simulate that the section - // is missing from the OCIOM file. - MergeStrategy::STRATEGY_UNSET, - [](OCIO::ConfigMergerRcPtr & merger) - { - // Simulate settings from OCIOM file. - merger->getParams(0)->setDefaultStrategy(MergeStrategy::STRATEGY_INPUT_ONLY); - merger->getParams(0)->setInputFirst(true); - }); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::DisplayViewMerger(options).merge(); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_1, DISP_3"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), @@ -1216,15 +1246,16 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) // Test display/views with strategy = PreferInput, options InputFirst = true. { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(true); OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); - - setupDisplaysViews(merger, - mergedConfig, - MergeStrategy::STRATEGY_PREFER_INPUT, - [](OCIO::ConfigMergerRcPtr & merger) - { - merger->getParams(0)->setInputFirst(true); - }); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::DisplayViewMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: shared_views: SHARED_1", + "The Input config contains a value that would override the Base config: display: DISP_1, view: VIEW_1", + "The Input config contains a value that would override the Base config: default_view_transform: Un-tone-mapped-2", + "The Input config contains a value that would override the Base config: viewing_rules: RULE_1"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_1, DISP_3, DISP_2"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), @@ -1319,14 +1350,16 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) // Test display/views with strategy=PreferInput, options InputFirst = false. { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); - setupDisplaysViews(merger, - mergedConfig, - MergeStrategy::STRATEGY_PREFER_INPUT, - [](OCIO::ConfigMergerRcPtr & merger) - { - merger->getParams(0)->setInputFirst(false); - }); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::DisplayViewMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: shared_views: SHARED_1", + "The Input config contains a value that would override the Base config: display: DISP_1, view: VIEW_1", + "The Input config contains a value that would override the Base config: default_view_transform: Un-tone-mapped-2", + "The Input config contains a value that would override the Base config: viewing_rules: RULE_1"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_1, DISP_2, DISP_3"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), @@ -1421,14 +1454,16 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) // Test display/views with strategy = PreferBase, options InputFirst = true. { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(true); OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); - setupDisplaysViews(merger, - mergedConfig, - MergeStrategy::STRATEGY_PREFER_BASE, - [](OCIO::ConfigMergerRcPtr & merger) - { - merger->getParams(0)->setInputFirst(true); - }); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::DisplayViewMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: shared_views: SHARED_1", + "The Input config contains a value that would override the Base config: display: DISP_1, view: VIEW_1", + "The Input config contains a value that would override the Base config: default_view_transform: Un-tone-mapped-2", + "The Input config contains a value that would override the Base config: viewing_rules: RULE_1"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_1, DISP_3, DISP_2"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), @@ -1525,14 +1560,16 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) // Test display/views with strategy = PreferBase, options InputFirst = false. { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(false); OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); - setupDisplaysViews(merger, - mergedConfig, - MergeStrategy::STRATEGY_PREFER_BASE, - [](OCIO::ConfigMergerRcPtr & merger) - { - merger->getParams(0)->setInputFirst(false); - }); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::DisplayViewMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: shared_views: SHARED_1", + "The Input config contains a value that would override the Base config: display: DISP_1, view: VIEW_1", + "The Input config contains a value that would override the Base config: default_view_transform: Un-tone-mapped-2", + "The Input config contains a value that would override the Base config: viewing_rules: RULE_1"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_1, DISP_2, DISP_3"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), @@ -1629,11 +1666,10 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) // Test display/views with strategy = BaseOnly. { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_BASE_ONLY); OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); - setupDisplaysViews(merger, - mergedConfig, - MergeStrategy::STRATEGY_BASE_ONLY, - nullptr); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::DisplayViewMerger(options).merge(); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_1, DISP_2"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), @@ -1704,11 +1740,10 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) // Test display/views with strategy = InputOnly. { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_INPUT_ONLY); OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); - setupDisplaysViews(merger, - mergedConfig, - MergeStrategy::STRATEGY_INPUT_ONLY, - nullptr); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::DisplayViewMerger(options).merge(); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_1, DISP_3"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), @@ -1759,7 +1794,7 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped-2"); - // Validate viewing_rules + // Validate viewing_rules OCIO::ConstViewingRulesRcPtr rules = mergedConfig->getViewingRules(); OCIO_CHECK_EQUAL(rules->getNumEntries(), 2); @@ -1786,11 +1821,10 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) // Test display/views with strategy = Remove { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_REMOVE); OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); - setupDisplaysViews(merger, - mergedConfig, - MergeStrategy::STRATEGY_REMOVE, - nullptr); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::DisplayViewMerger(options).merge(); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_2"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), "SHARED_2, VIEW_2"); @@ -2264,6 +2298,7 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section_common_reference_and_duplicates) // // The merged configs will contain color spaces from the input config where // the reference space has been converted to that of the base config. + // The base reference spaces are always used, regardless of strategy. // // Duplicates are removed, even though they use different reference spaces. @@ -2313,9 +2348,22 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section_common_reference_and_duplicates) OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + [&options]() { OCIO::RolesMerger(options).merge(); + OCIO::DisplayViewMerger(options).merge(); + OCIO::ColorspacesMerger(options).merge(); }, +// "The Input config contains a role that would override Base config role 'aces_interchange'.", + "Equivalent input color space 'sRGB - Display' replaces 'sRGB - Display' in the base config, preserving aliases.", + "Equivalent input color space 'CIE-XYZ-D65' replaces 'CIE-XYZ-D65' in the base config, preserving aliases.", + "Equivalent input color space 'ACES2065-1' replaces 'ap0' in the base config, preserving aliases.", + "Equivalent input color space 'sRGB' replaces 'sRGB - Texture' in the base config, preserving aliases.", "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'"); + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 1); +// OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("aces_interchange")), +// std::string("ACES2065-1")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("cie_xyz_d65_interchange")), + std::string("CIE-XYZ-D65")); + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 7); @@ -2327,590 +2375,262 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section_common_reference_and_duplicates) OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("srgb_display")); OCIO_CHECK_EQUAL(cs->getDescription(), std::string("from input")); + // Check that the input config reference space was converted to the base reference space. + // See ConfigUtils_tests.cpp for more detailed testing of the reference space conversion. + { + OCIO_REQUIRE_ASSERT(!cs->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE)); + OCIO::ConstTransformRcPtr t = cs->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE); + OCIO_REQUIRE_ASSERT(t); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_GROUP); + auto gtx = OCIO::DynamicPtrCast(t); + OCIO_REQUIRE_ASSERT(gtx); + OCIO_REQUIRE_EQUAL(gtx->getNumTransforms(), 2); + OCIO_CHECK_EQUAL(gtx->getTransform(0)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); + OCIO_CHECK_EQUAL(gtx->getTransform(1)->getTransformType(), OCIO::TRANSFORM_TYPE_EXPONENT_WITH_LINEAR); + } + auto cs1 = checkColorSpace(mergedConfig, "CIE-XYZ-D65", 1, OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, __LINE__); OCIO_CHECK_EQUAL(cs1->getNumAliases(), 1); OCIO_CHECK_EQUAL(cs1->getAlias(0), std::string("cie_xyz_d65")); + { + OCIO_REQUIRE_ASSERT(!cs1->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE)); + OCIO::ConstTransformRcPtr t = cs1->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE); + OCIO_REQUIRE_ASSERT(t); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_GROUP); + auto gtx = OCIO::DynamicPtrCast(t); + OCIO_REQUIRE_ASSERT(gtx); + OCIO_REQUIRE_EQUAL(gtx->getNumTransforms(), 2); + OCIO_CHECK_EQUAL(gtx->getTransform(0)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); + OCIO_CHECK_EQUAL(gtx->getTransform(1)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); + } } - // Scene-referred spaces. - { - auto cs = checkColorSpace(mergedConfig, "ACES2065-1", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); - OCIO_CHECK_EQUAL(cs->getNumAliases(), 2); - OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("aces")); - // Check for alias ap0 (added from base config). - OCIO_CHECK_EQUAL(cs->getAlias(1), std::string("ap0")); - - auto cs1 = checkColorSpace(mergedConfig, "sRGB", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); - OCIO_CHECK_EQUAL(cs1->getNumAliases(), 2); - // Check for alias sRGB - Texture (added from base config colorspace name). - OCIO_CHECK_EQUAL(cs1->getAlias(0), std::string("sRGB - Texture")); - // Check for alias srgb_tx (added from base config). - OCIO_CHECK_EQUAL(cs1->getAlias(1), std::string("srgb_tx")); - - auto cs2 = checkColorSpace(mergedConfig, "rec709", 2, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); - - auto cs3 = checkColorSpace(mergedConfig, "Raw", 3, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); - OCIO_CHECK_EQUAL(cs3->getNumAliases(), 1); - OCIO_CHECK_EQUAL(cs3->getAlias(0), std::string("Utility - Raw")); - - auto cs4 = checkColorSpace(mergedConfig, "ACEScg", 4, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); - OCIO_CHECK_EQUAL(cs4->getNumAliases(), 0); - } - -// FIXME: Remove the below string and improve the tests above. - - constexpr const char * RESULT { -R"(ocio_profile_version: 2.1 - -environment: - SHOT: 001a - TEXTURE_SPACE: sRGB - Texture -search_path: - - lut_dir - - luts - - . -strictparsing: true -family_separator: "~" -luma: [0.2126, 0.7152, 0.0722] -name: base - -roles: - cie_xyz_d65_interchange: CIE-XYZ-D65 - -file_rules: - - ! {name: Default, colorspace: ACEScg} - -displays: - {} - -active_displays: [] -active_views: [] -inactive_colorspaces: [ACES2065-1] - -display_colorspaces: - - ! - name: sRGB - Display - aliases: [srgb_display] - family: Input~Display~Standard - equalitygroup: "" - bitdepth: unknown - description: from input - isdata: false - allocation: uniform - from_display_reference: ! - children: - - ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1], direction: inverse} - - ! {gamma: 2.4, offset: 0.055, direction: inverse} - - - ! - name: CIE-XYZ-D65 - aliases: [cie_xyz_d65] - family: "Input~" - equalitygroup: "" - bitdepth: unknown - description: The \"CIE XYZ (D65)\" display connection colorspace. - isdata: false - allocation: uniform - from_display_reference: ! - children: - - ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1], direction: inverse} - - ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1]} - -colorspaces: - - ! - name: ACES2065-1 - aliases: [aces, ap0] - family: Input~ACES~Linear - equalitygroup: "" - bitdepth: unknown - description: from input - isdata: false - allocation: uniform - to_scene_reference: ! - children: - - ! {matrix: [2.521686186744, -1.13413098824, -0.387555198504, 0, -0.27647991423, 1.372719087668, -0.096239173438, 0, -0.015378064966, -0.152975335867, 1.168353400833, 0, 0, 0, 0, 1]} - - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} - - - ! - name: sRGB - aliases: [sRGB - Texture, srgb_tx] - family: Input~Texture~ - equalitygroup: "" - bitdepth: unknown - description: from input - isdata: false - allocation: uniform - to_scene_reference: ! - children: - - ! {gamma: 2.4, offset: 0.055} - - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} - - - ! - name: rec709 - family: "Input~" - equalitygroup: "" - bitdepth: unknown - description: from input - isdata: false - allocation: uniform - to_scene_reference: ! - children: - - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} - - - ! - name: Raw - aliases: [Utility - Raw] - family: Input~Utility - equalitygroup: "" - bitdepth: 32f - description: The utility "Raw" colorspace. - isdata: true - categories: [file-io] - allocation: uniform - - - ! - name: ACEScg - family: Base~ACES~Linear - equalitygroup: "" - bitdepth: unknown - description: from base - isdata: false - allocation: uniform - to_scene_reference: ! {style: ACEScg_to_ACES2065-1} -)" }; - - // Test the entire contents of each config. - - std::ostringstream oss; - mergedConfig->serialize(oss); - - std::istringstream resultIss; - resultIss.str(RESULT); - OCIO::ConstConfigRcPtr resultConfig = OCIO::Config::CreateFromStream(resultIss); - std::ostringstream ossResult; - resultConfig->serialize(ossResult); - -// OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); - } - - // PreferInput, Base first. - { - OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); - auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); - merger->getParams(0)->setInputFirst(false); - - OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); - OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; - checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'"); - -// FIXME: Remove the below string and improve the tests above. - - constexpr const char * RESULT { -R"(ocio_profile_version: 2.1 - -environment: - SHOT: 001a - TEXTURE_SPACE: sRGB - Texture -search_path: - - luts - - . - - lut_dir -strictparsing: true -family_separator: "~" -luma: [0.2126, 0.7152, 0.0722] -name: base -roles: - cie_xyz_d65_interchange: CIE-XYZ-D65 -file_rules: - - ! {name: Default, colorspace: ACEScg} -displays: - {} -active_displays: [] -active_views: [] -inactive_colorspaces: [ACES2065-1] - -display_colorspaces: - - ! - name: sRGB - Display - aliases: [srgb_display] - family: Input~Display~Standard - equalitygroup: "" - bitdepth: unknown - description: from input - isdata: false - allocation: uniform - from_display_reference: ! - children: - - ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1], direction: inverse} - - ! {gamma: 2.4, offset: 0.055, direction: inverse} - - - ! - name: CIE-XYZ-D65 - aliases: [cie_xyz_d65] - family: "Input~" - equalitygroup: "" - bitdepth: unknown - description: The \"CIE XYZ (D65)\" display connection colorspace. - isdata: false - allocation: uniform - from_display_reference: ! - children: - - ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1], direction: inverse} - - ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1]} - -colorspaces: - - ! - name: ACEScg - family: Base~ACES~Linear - equalitygroup: "" - bitdepth: unknown - description: from base - isdata: false - allocation: uniform - to_scene_reference: ! {style: ACEScg_to_ACES2065-1} - - # The ap0 colorspace is added as an alias because it is equivalent to the ACES2065-1 colorspace - # in this config. - - ! - name: ACES2065-1 - aliases: [aces, ap0] - family: Input~ACES~Linear - equalitygroup: "" - bitdepth: unknown - description: from input - isdata: false - allocation: uniform - to_scene_reference: ! - children: - - ! {matrix: [2.521686186744, -1.13413098824, -0.387555198504, 0, -0.27647991423, 1.372719087668, -0.096239173438, 0, -0.015378064966, -0.152975335867, 1.168353400833, 0, 0, 0, 0, 1]} - - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} - - # The sRGB - Texture colorspace is added as an alias because it is equivalent to the sRGB - # colorspace in this config. - - ! - name: sRGB - aliases: [sRGB - Texture, srgb_tx] - family: Input~Texture~ - equalitygroup: "" - bitdepth: unknown - description: from input - isdata: false - allocation: uniform - to_scene_reference: ! - children: - - ! {gamma: 2.4, offset: 0.055} - - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} - - - ! - name: rec709 - family: "Input~" - equalitygroup: "" - bitdepth: unknown - description: from input - isdata: false - allocation: uniform - to_scene_reference: ! - children: - - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} - - - ! - name: Raw - aliases: [Utility - Raw] - family: Input~Utility - equalitygroup: "" - bitdepth: 32f - description: The utility "Raw" colorspace. - isdata: true - categories: [file-io] - allocation: uniform -)" }; - - // Test the entire contents of each config. - - OCIO_CHECK_EQUAL(std::string(mergedConfig->getInactiveColorSpaces()), "ACES2065-1"); - - std::ostringstream oss; - mergedConfig->serialize(oss); - - std::istringstream resultIss; - resultIss.str(RESULT); - OCIO::ConstConfigRcPtr resultConfig = OCIO::Config::CreateFromStream(resultIss); - std::ostringstream ossResult; - resultConfig->serialize(ossResult); - -// OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); - } - - // PreferBase, Input first. - { - OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); - auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); - merger->getParams(0)->setInputFirst(true); - - OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); - OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; - checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Input color space 'ACES2065-1' is a duplicate of base color space 'ap0' but was unable to add alias 'aces' since it conflicts with base color space 'ACEScg'"); - -// FIXME: Remove the below string and improve the tests above. - - constexpr const char * RESULT { -R"(ocio_profile_version: 2.1 - -environment: - SHOT: 001a - TEXTURE_SPACE: sRGB - Texture -search_path: - - lut_dir - - luts - - . -strictparsing: true -family_separator: "-" -luma: [0.2126, 0.7152, 0.0722] -name: base -roles: - cie_xyz_d65_interchange: CIE-XYZ-D65 -file_rules: - - ! {name: Default, colorspace: ACEScg} -displays: - {} -active_displays: [] -active_views: [] -inactive_colorspaces: [ACES2065-1] - -display_colorspaces: - - ! - name: sRGB - Display - aliases: [srgb_display] - family: Base-Display-Basic - equalitygroup: "" - bitdepth: unknown - description: from base - isdata: false - allocation: uniform - from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_sRGB} - - - ! - name: CIE-XYZ-D65 - aliases: [cie_xyz_d65] - family: "Base-" - equalitygroup: "" - bitdepth: unknown - description: The \"CIE XYZ (D65)\" display connection colorspace. - isdata: false - allocation: uniform - -colorspaces: - - ! - name: rec709 - family: "Input-" - equalitygroup: "" - bitdepth: unknown - description: from input - isdata: false - allocation: uniform - to_scene_reference: ! - children: - - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} - - - ! - name: Raw - aliases: [Utility - Raw] - family: Input-Utility - equalitygroup: "" - bitdepth: 32f - description: The utility "Raw" colorspace. - isdata: true - categories: [file-io] - allocation: uniform + // Scene-referred spaces. + { + // This is recognized as a duplicate, even though the name is different in the two configs. + auto cs = checkColorSpace(mergedConfig, "ACES2065-1", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 2); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("aces")); + // Check for alias ap0 (added from base config). + OCIO_CHECK_EQUAL(cs->getAlias(1), std::string("ap0")); + { + OCIO_REQUIRE_ASSERT(!cs->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); + OCIO::ConstTransformRcPtr t = cs->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); + OCIO_REQUIRE_ASSERT(t); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_GROUP); + auto gtx = OCIO::DynamicPtrCast(t); + OCIO_REQUIRE_ASSERT(gtx); + OCIO_REQUIRE_EQUAL(gtx->getNumTransforms(), 2); + OCIO_CHECK_EQUAL(gtx->getTransform(0)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); + OCIO_CHECK_EQUAL(gtx->getTransform(1)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); + } - - ! - name: ACEScg - aliases: [aces] - family: Base-ACES-Linear - equalitygroup: "" - bitdepth: unknown - description: from base - isdata: false - allocation: uniform - to_scene_reference: ! {style: ACEScg_to_ACES2065-1} - - - ! - name: ap0 - aliases: [ACES2065-1] - family: Base-ACES-Linear - equalitygroup: "" - bitdepth: unknown - description: from base - isdata: false - allocation: uniform - - - ! - name: sRGB - Texture - aliases: [srgb, srgb_tx] - family: Base-Texture - equalitygroup: "" - bitdepth: unknown - description: from base - isdata: false - allocation: uniform - from_scene_reference: ! - children: - - ! {matrix: [2.52168618674388, -1.13413098823972, -0.387555198504164, 0, -0.276479914229922, 1.37271908766826, -0.096239173438334, 0, -0.0153780649660342, -0.152975335867399, 1.16835340083343, 0, 0, 0, 0, 1]} - - ! {gamma: 2.4, offset: 0.055, direction: inverse} -)" }; + // This is recognized as a duplicate, even though the name is different in the two configs. + auto cs1 = checkColorSpace(mergedConfig, "sRGB", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs1->getNumAliases(), 2); + // Check for alias sRGB - Texture (added from base config colorspace name). + OCIO_CHECK_EQUAL(cs1->getAlias(0), std::string("sRGB - Texture")); + // Check for alias srgb_tx (added from base config). + OCIO_CHECK_EQUAL(cs1->getAlias(1), std::string("srgb_tx")); + { + OCIO_REQUIRE_ASSERT(!cs1->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); + OCIO::ConstTransformRcPtr t = cs1->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); + OCIO_REQUIRE_ASSERT(t); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_GROUP); + auto gtx = OCIO::DynamicPtrCast(t); + OCIO_REQUIRE_ASSERT(gtx); + OCIO_REQUIRE_EQUAL(gtx->getNumTransforms(), 2); + OCIO_CHECK_EQUAL(gtx->getTransform(0)->getTransformType(), OCIO::TRANSFORM_TYPE_EXPONENT_WITH_LINEAR); + OCIO_CHECK_EQUAL(gtx->getTransform(1)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); + } - // Test the entire contents of each config. + auto cs2 = checkColorSpace(mergedConfig, "rec709", 2, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + { + OCIO_REQUIRE_ASSERT(!cs2->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); + OCIO::ConstTransformRcPtr t = cs2->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); + OCIO_REQUIRE_ASSERT(t); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_GROUP); + auto gtx = OCIO::DynamicPtrCast(t); + OCIO_REQUIRE_ASSERT(gtx); + OCIO_REQUIRE_EQUAL(gtx->getNumTransforms(), 1); + OCIO_CHECK_EQUAL(gtx->getTransform(0)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); + } - std::ostringstream oss; - mergedConfig->serialize(oss); + auto cs3 = checkColorSpace(mergedConfig, "Raw", 3, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs3->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs3->getAlias(0), std::string("Utility - Raw")); + OCIO_CHECK_ASSERT(cs3->isData()); + { + OCIO_REQUIRE_ASSERT(!cs3->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE)); + OCIO_REQUIRE_ASSERT(!cs3->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); + } - std::istringstream resultIss; - resultIss.str(RESULT); - OCIO::ConstConfigRcPtr resultConfig = OCIO::Config::CreateFromStream(resultIss); - std::ostringstream ossResult; - resultConfig->serialize(ossResult); + auto cs4 = checkColorSpace(mergedConfig, "ACEScg", 4, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs4->getNumAliases(), 0); + { + OCIO_REQUIRE_ASSERT(!cs4->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); + OCIO::ConstTransformRcPtr t = cs4->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); + OCIO_REQUIRE_ASSERT(t); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_BUILTIN); + } + } -// OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); + // View transforms. + { + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); + OCIO_CHECK_EQUAL(mergedConfig->getViewTransform("SDR Video")->getDescription(), std::string("from input")); + OCIO::ConstTransformRcPtr tf; + OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") + ->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE)); + + // Validate the reference space conversion was added to the transform from the input config. + OCIO_CHECK_EQUAL(tf->getTransformType(), OCIO::TRANSFORM_TYPE_GROUP); + auto gtx = OCIO::DynamicPtrCast(tf); + OCIO_REQUIRE_ASSERT(gtx); + OCIO_REQUIRE_EQUAL(gtx->getNumTransforms(), 3); + OCIO_CHECK_EQUAL(gtx->getTransform(0)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); + OCIO_CHECK_EQUAL(gtx->getTransform(1)->getTransformType(), OCIO::TRANSFORM_TYPE_BUILTIN); + OCIO_CHECK_EQUAL(gtx->getTransform(2)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "vt2"); + OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("vt2") + ->getTransform(OCIO::VIEWTRANSFORM_DIR_TO_REFERENCE)); + + // Validate the reference space conversion was not added to the transform from the base config. + OCIO_CHECK_EQUAL(tf->getTransformType(), OCIO::TRANSFORM_TYPE_EXPONENT_WITH_LINEAR); + } } - // PreferBase, Base first. + // PreferBase, Input first. { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); - merger->getParams(0)->setInputFirst(false); + merger->getParams(0)->setInputFirst(true); OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Input color space 'ACES2065-1' is a duplicate of base color space 'ap0' but was unable to add alias 'aces' since it conflicts with base color space 'ACEScg'"); - -// FIXME: Remove the below string and improve the tests above. + [&options]() { OCIO::RolesMerger(options).merge(); + OCIO::DisplayViewMerger(options).merge(); + OCIO::ColorspacesMerger(options).merge(); }, +// "The Input config contains a role that would override Base config role 'aces_interchange'.", + "Equivalent base color space 'sRGB - Display' overrides 'sRGB - Display' in the input config, preserving aliases.", + "Equivalent base color space 'CIE-XYZ-D65' overrides 'CIE-XYZ-D65' in the input config, preserving aliases.", + "Equivalent base color space 'ap0' overrides 'ACES2065-1' in the input config, preserving aliases.", + "Equivalent base color space 'sRGB - Texture' overrides 'sRGB' in the input config, preserving aliases.", + "Input color space 'ACES2065-1' is a duplicate of base color space 'ap0' but was " + "unable to add alias 'aces' since it conflicts with base color space 'ACEScg'."); - constexpr const char * RESULT { -R"(ocio_profile_version: 2.1 + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 1); +// OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("aces_interchange")), +// std::string("ap0")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("cie_xyz_d65_interchange")), + std::string("CIE-XYZ-D65")); -environment: - SHOT: 001a - TEXTURE_SPACE: sRGB - Texture -search_path: - - luts - - . - - lut_dir -strictparsing: true -family_separator: "-" -luma: [0.2126, 0.7152, 0.0722] -name: base -roles: - cie_xyz_d65_interchange: CIE-XYZ-D65 -file_rules: - - ! {name: Default, colorspace: ACEScg} -displays: - {} -active_displays: [] -active_views: [] -inactive_colorspaces: [ACES2065-1] + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, + OCIO::COLORSPACE_ALL), 7); -display_colorspaces: - - ! - name: sRGB - Display - aliases: [srgb_display] - family: Base-Display-Basic - equalitygroup: "" - bitdepth: unknown - description: from base - isdata: false - allocation: uniform - from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_sRGB} - - - ! - name: CIE-XYZ-D65 - aliases: [cie_xyz_d65] - family: "Base-" - equalitygroup: "" - bitdepth: unknown - description: The \"CIE XYZ (D65)\" display connection colorspace. - isdata: false - allocation: uniform + // Display-referred spaces. + { + auto cs = checkColorSpace(mergedConfig, "sRGB - Display", 0, OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("srgb_display")); + OCIO_CHECK_EQUAL(cs->getDescription(), std::string("from base")); + { + OCIO_REQUIRE_ASSERT(!cs->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE)); + OCIO::ConstTransformRcPtr t = cs->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE); + OCIO_REQUIRE_ASSERT(t); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_BUILTIN); + } -colorspaces: - - ! - name: ACEScg - aliases: [aces] - family: Base-ACES-Linear - equalitygroup: "" - bitdepth: unknown - description: from base - isdata: false - allocation: uniform - to_scene_reference: ! {style: ACEScg_to_ACES2065-1} - - - ! - name: ap0 - aliases: [ACES2065-1] - family: Base-ACES-Linear - equalitygroup: "" - bitdepth: unknown - description: from base - isdata: false - allocation: uniform - - - ! - name: sRGB - Texture - aliases: [srgb, srgb_tx] - family: Base-Texture - equalitygroup: "" - bitdepth: unknown - description: from base - isdata: false - allocation: uniform - from_scene_reference: ! - children: - - ! {matrix: [2.52168618674388, -1.13413098823972, -0.387555198504164, 0, -0.276479914229922, 1.37271908766826, -0.096239173438334, 0, -0.0153780649660342, -0.152975335867399, 1.16835340083343, 0, 0, 0, 0, 1]} - - ! {gamma: 2.4, offset: 0.055, direction: inverse} - - - ! - name: rec709 - family: "Input-" - equalitygroup: "" - bitdepth: unknown - description: from input - isdata: false - allocation: uniform - to_scene_reference: ! - children: - - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} + auto cs1 = checkColorSpace(mergedConfig, "CIE-XYZ-D65", 1, OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, __LINE__); + OCIO_CHECK_EQUAL(cs1->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs1->getAlias(0), std::string("cie_xyz_d65")); + { + OCIO_REQUIRE_ASSERT(!cs1->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE)); + OCIO_REQUIRE_ASSERT(!cs1->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); + } + } - - ! - name: Raw - aliases: [Utility - Raw] - family: Input-Utility - equalitygroup: "" - bitdepth: 32f - description: The utility "Raw" colorspace. - isdata: true - categories: [file-io] - allocation: uniform -)" }; + // Scene-referred spaces. + { + auto cs = checkColorSpace(mergedConfig, "rec709", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + { + OCIO_REQUIRE_ASSERT(!cs->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); + OCIO::ConstTransformRcPtr t = cs->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); + OCIO_REQUIRE_ASSERT(t); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_GROUP); + auto gtx = OCIO::DynamicPtrCast(t); + OCIO_REQUIRE_ASSERT(gtx); + OCIO_REQUIRE_EQUAL(gtx->getNumTransforms(), 1); + OCIO_CHECK_EQUAL(gtx->getTransform(0)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); + } - // Test the entire contents of each config. + auto cs1 = checkColorSpace(mergedConfig, "Raw", 1, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs1->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs1->getAlias(0), std::string("Utility - Raw")); + OCIO_CHECK_ASSERT(cs1->isData()); + { + OCIO_REQUIRE_ASSERT(!cs1->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE)); + OCIO_REQUIRE_ASSERT(!cs1->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); + } - OCIO_CHECK_EQUAL(std::string(mergedConfig->getInactiveColorSpaces()), "ACES2065-1"); + auto cs2 = checkColorSpace(mergedConfig, "ACEScg", 2, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs2->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs2->getAlias(0), std::string("aces")); + { + OCIO_REQUIRE_ASSERT(!cs2->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); + OCIO::ConstTransformRcPtr t = cs2->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); + OCIO_REQUIRE_ASSERT(t); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_BUILTIN); + } - std::ostringstream oss; - mergedConfig->serialize(oss); + auto cs3 = checkColorSpace(mergedConfig, "ap0", 3, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs3->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs3->getAlias(0), std::string("ACES2065-1")); + OCIO_CHECK_ASSERT(!(cs3->isData())); + { + OCIO_REQUIRE_ASSERT(!cs3->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE)); + OCIO_REQUIRE_ASSERT(!cs3->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); + } - std::istringstream resultIss; - resultIss.str(RESULT); - OCIO::ConstConfigRcPtr resultConfig = OCIO::Config::CreateFromStream(resultIss); - std::ostringstream ossResult; - resultConfig->serialize(ossResult); + auto cs4 = checkColorSpace(mergedConfig, "sRGB - Texture", 4, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs4->getNumAliases(), 2); + OCIO_CHECK_EQUAL(cs4->getAlias(0), std::string("srgb")); + OCIO_CHECK_EQUAL(cs4->getAlias(1), std::string("srgb_tx")); + { + OCIO_REQUIRE_ASSERT(!cs4->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE)); + OCIO::ConstTransformRcPtr t = cs4->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE); + OCIO_REQUIRE_ASSERT(t); + OCIO_CHECK_EQUAL(t->getTransformType(), OCIO::TRANSFORM_TYPE_GROUP); + auto gtx = OCIO::DynamicPtrCast(t); + OCIO_REQUIRE_ASSERT(gtx); + OCIO_REQUIRE_EQUAL(gtx->getNumTransforms(), 2); + OCIO_CHECK_EQUAL(gtx->getTransform(0)->getTransformType(), OCIO::TRANSFORM_TYPE_MATRIX); + OCIO_CHECK_EQUAL(gtx->getTransform(1)->getTransformType(), OCIO::TRANSFORM_TYPE_EXPONENT_WITH_LINEAR); + } + } -// OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); + // View transforms. + { + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); + OCIO_CHECK_EQUAL(mergedConfig->getViewTransform("SDR Video")->getDescription(), std::string("from base")); + OCIO::ConstTransformRcPtr tf; + OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") + ->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE)); + + // Validate that no reference space conversion was added, since the base transform was used. + OCIO_CHECK_EQUAL(tf->getTransformType(), OCIO::TRANSFORM_TYPE_BUILTIN); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "vt2"); + OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("vt2") + ->getTransform(OCIO::VIEWTRANSFORM_DIR_TO_REFERENCE)); + + // Validate the reference space conversion was not added to the transform from the base config. + OCIO_CHECK_EQUAL(tf->getTransformType(), OCIO::TRANSFORM_TYPE_EXPONENT_WITH_LINEAR); + } } // Nothing special to test for Input only and Base only. @@ -4279,17 +3999,25 @@ OCIO_ADD_TEST(MergeConfigs, named_transform_section) OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Color space 'view_1' will replace a color space in the base config"); + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, +// "Color space 'view_1' will replace a color space in the base config"); + "Equivalent input color space 'ACES2065-1' replaces 'ACES2065-1' in the base config, preserving aliases.", + "Equivalent input color space 'ACEScct - SomeOtherName' replaces 'ACEScct' in the base config, preserving aliases.", + "Equivalent input color space 'view_1' replaces 'view_1' in the base config, preserving aliases.", + "Equivalent input color space 'view_1B' replaces 'view_1' in the base config, preserving aliases.", + "Equivalent input color space 'view_3' replaces 'view_2' in the base config, preserving aliases.", + "Equivalent input color space 'log_3' replaces 'log_1' in the base config, preserving aliases.", + "Equivalent input color space 'lin_3' replaces 'ACES2065-1' in the base config, preserving aliases."); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Named transform 'nt_both' will replace a named transform in the base config", - "Merged Base named transform 'nt_both' has a conflict with alias 'srgb_tx' in color space 'sRGB - Texture'", - "Merged Base named transform 'nt_base' has an alias 'view_3' that conflicts with color space 'view_3'", - "Merged Input named transform 'nt_both' has a conflict with alias 'Utility - Raw' in color space 'Raw'", - "The name of merged named transform 'nt_input' has a conflict with an alias in named transform 'nt_base'", - "Merged Input named transform 'nt_input' has an alias 'Raw' that conflicts with color space 'Raw'", - "Named transform 'view_2' was not merged as there's a color space with that name"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'nt_both' will replace a named transform in the base config", + "Merged Base named transform 'nt_both' has a conflict with alias 'srgb_tx' in color space 'sRGB - Texture'", + "Merged Base named transform 'nt_base' has an alias 'view_3' that conflicts with color space 'view_3'", + "Merged Input named transform 'nt_both' has a conflict with alias 'Utility - Raw' in color space 'Raw'", + "The name of merged named transform 'nt_input' has a conflict with an alias in named transform 'nt_base'", + "Merged Input named transform 'nt_input' has an alias 'Raw' that conflicts with color space 'Raw'", +// "Named transform 'view_2' was not merged as there's a color space with that name"); + "Named transform 'view_2' was not merged as there's a color space alias with that name."); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 3); @@ -4321,17 +4049,25 @@ OCIO_ADD_TEST(MergeConfigs, named_transform_section) OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Color space 'view_1' will replace a color space in the base config"); + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, +// "Color space 'view_1' will replace a color space in the base config"); + "Equivalent input color space 'ACES2065-1' replaces 'ACES2065-1' in the base config, preserving aliases.", + "Equivalent input color space 'ACEScct - SomeOtherName' replaces 'ACEScct' in the base config, preserving aliases.", + "Equivalent input color space 'view_1' replaces 'view_1' in the base config, preserving aliases.", + "Equivalent input color space 'view_1B' replaces 'view_1' in the base config, preserving aliases.", + "Equivalent input color space 'view_3' replaces 'view_2' in the base config, preserving aliases.", + "Equivalent input color space 'log_3' replaces 'log_1' in the base config, preserving aliases.", + "Equivalent input color space 'lin_3' replaces 'ACES2065-1' in the base config, preserving aliases."); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Named transform 'nt_both' will replace a named transform in the base config", - "Merged Base named transform 'nt_both' has a conflict with alias 'srgb_tx' in color space 'sRGB - Texture'", - "Merged Base named transform 'nt_base' has an alias 'view_3' that conflicts with color space 'view_3'", - "Merged Input named transform 'nt_both' has a conflict with alias 'Utility - Raw' in color space 'Raw'", - "The name of merged named transform 'nt_input' has a conflict with an alias in named transform 'nt_base'", - "Merged Input named transform 'nt_input' has an alias 'Raw' that conflicts with color space 'Raw'", - "Named transform 'view_2' was not merged as there's a color space with that name"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'nt_both' will replace a named transform in the base config", + "Merged Base named transform 'nt_both' has a conflict with alias 'srgb_tx' in color space 'sRGB - Texture'", + "Merged Base named transform 'nt_base' has an alias 'view_3' that conflicts with color space 'view_3'", + "Merged Input named transform 'nt_both' has a conflict with alias 'Utility - Raw' in color space 'Raw'", + "The name of merged named transform 'nt_input' has a conflict with an alias in named transform 'nt_base'", + "Merged Input named transform 'nt_input' has an alias 'Raw' that conflicts with color space 'Raw'", +// "Named transform 'view_2' was not merged as there's a color space with that name"); + "Named transform 'view_2' was not merged as there's a color space alias with that name."); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 3); @@ -4353,7 +4089,9 @@ OCIO_ADD_TEST(MergeConfigs, named_transform_section) OCIO_CHECK_EQUAL(nt->getFamily(), std::string("Input@Raw")); OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from input")); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getInactiveColorSpaces()), "Gamma 2.2 AP1 - Texture, Linear Rec.2020, nt_both, nt_input, view_2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getInactiveColorSpaces()), +/// "Gamma 2.2 AP1 - Texture, Linear Rec.2020, nt_both, nt_input, view_2"); + "Gamma 2.2 AP1 - Texture, Linear Rec.2020, nt_both, nt_input"); } // Test NamedTransform with strategy = PreferBase, options InputFirst = true. @@ -4364,15 +4102,23 @@ OCIO_ADD_TEST(MergeConfigs, named_transform_section) OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Color space 'view_1' was not merged as it's already present in the base config"); + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, +// "Color space 'view_1' was not merged as it's already present in the base config"); + "Equivalent base color space 'ACES2065-1' overrides 'ACES2065-1' in the input config, preserving aliases.", + "Equivalent base color space 'ACEScct' overrides 'ACEScct - SomeOtherName' in the input config, preserving aliases.", + "Equivalent base color space 'view_1' overrides 'view_1' in the input config, preserving aliases.", + "Equivalent base color space 'view_1' overrides 'view_1B' in the input config, preserving aliases.", + "Equivalent base color space 'view_2' overrides 'view_3' in the input config, preserving aliases.", + "Equivalent base color space 'log_1' overrides 'log_3' in the input config, preserving aliases.", + "Equivalent base color space 'ACES2065-1' overrides 'lin_3' in the input config, preserving aliases."); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Merged Base named transform 'nt_both' has a conflict with alias 'srgb_tx' in color space 'sRGB - Texture'", - "Merged Base named transform 'nt_base' has an alias 'view_3' that conflicts with color space 'view_3'", - "Named transform 'nt_both' was not merged as it's already present in the base config", - "Named transform 'nt_input' was not merged as it conflicts with an alias in named transform 'nt_base'", - "Named transform 'view_2' was not merged as there's a color space with that name"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Merged Base named transform 'nt_both' has a conflict with alias 'srgb_tx' in color space 'sRGB - Texture'", +// "Merged Base named transform 'nt_base' has an alias 'view_3' that conflicts with color space 'view_3'", + "Merged Base named transform 'nt_base' has a conflict with alias 'view_3' in color space 'view_2'.", + "Named transform 'nt_both' was not merged as it's already present in the base config", + "Named transform 'nt_input' was not merged as it conflicts with an alias in named transform 'nt_base'", + "Named transform 'view_2' was not merged as there's a color space with that name"); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 2); @@ -4402,15 +4148,23 @@ OCIO_ADD_TEST(MergeConfigs, named_transform_section) OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Color space 'view_1' was not merged as it's already present in the base config"); + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, +// "Color space 'view_1' was not merged as it's already present in the base config"); + "Equivalent base color space 'ACES2065-1' overrides 'ACES2065-1' in the input config, preserving aliases.", + "Equivalent base color space 'ACEScct' overrides 'ACEScct - SomeOtherName' in the input config, preserving aliases.", + "Equivalent base color space 'view_1' overrides 'view_1' in the input config, preserving aliases.", + "Equivalent base color space 'view_1' overrides 'view_1B' in the input config, preserving aliases.", + "Equivalent base color space 'view_2' overrides 'view_3' in the input config, preserving aliases.", + "Equivalent base color space 'log_1' overrides 'log_3' in the input config, preserving aliases.", + "Equivalent base color space 'ACES2065-1' overrides 'lin_3' in the input config, preserving aliases."); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Merged Base named transform 'nt_both' has a conflict with alias 'srgb_tx' in color space 'sRGB - Texture'", - "Merged Base named transform 'nt_base' has an alias 'view_3' that conflicts with color space 'view_3'", - "Named transform 'nt_both' was not merged as it's already present in the base config", - "Named transform 'nt_input' was not merged as it conflicts with an alias in named transform 'nt_base'", - "Named transform 'view_2' was not merged as there's a color space with that name"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Merged Base named transform 'nt_both' has a conflict with alias 'srgb_tx' in color space 'sRGB - Texture'", +// "Merged Base named transform 'nt_base' has an alias 'view_3' that conflicts with color space 'view_3'", + "Merged Base named transform 'nt_base' has a conflict with alias 'view_3' in color space 'view_2'.", + "Named transform 'nt_both' was not merged as it's already present in the base config", + "Named transform 'nt_input' was not merged as it conflicts with an alias in named transform 'nt_base'", + "Named transform 'view_2' was not merged as there's a color space with that name"); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 2); @@ -5666,8 +5420,12 @@ OCIO_ADD_TEST(MergeConfigs, merges_with_ociom_file) [&newMerger, &merger]() { newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); }, "The Input config contains a value that would override the Base config: file_rules: Default", "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", + "Equivalent input color space 'sRGB - Display' replaces 'sRGB - Display' in the base config, preserving aliases.", + "Equivalent input color space 'CIE-XYZ-D65' replaces 'CIE-XYZ-D65' in the base config, preserving aliases.", + "Equivalent input color space 'ACES2065-1' replaces 'ap0' in the base config, preserving aliases.", + "Equivalent input color space 'sRGB' replaces 'sRGB - Texture' in the base config, preserving aliases."); // TODO: Last one should not be necessary. - "The Input config contains a role that would override Base config role 'aces_interchange'"); +// "The Input config contains a role that would override Base config role 'aces_interchange'"); OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); std::ostringstream oss; mergedConfig->serialize(oss); @@ -5701,12 +5459,21 @@ description: Basic merge with default strategy active_displays: [] active_views: [] -inactive_colorspaces: [ACES2065-1] view_transforms: - ! name: SDR Video - from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1} + description: from input + from_scene_reference: ! + children: + - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1], direction: inverse} + - ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1} + - ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1]} + + - ! + name: vt2 + description: from base + to_display_reference: ! {gamma: 2.4, offset: 0.055} display_colorspaces: - ! @@ -5807,7 +5574,9 @@ inactive_colorspaces: [ACES2065-1] resultConfig->serialize(ossResult); //Testing the string of each config -// OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); + + OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); + } } /* @@ -5961,8 +5730,8 @@ inactive_colorspaces: [ACES2065-1] merger->getParams(0)->setAssumeCommonReferenceSpace(true); OCIO::ConstConfigMergerRcPtr newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); - std::ostringstream oss; - mergedConfig->serialize(oss); +// std::ostringstream oss; +// mergedConfig->serialize(oss); OCIO_CHECK_NO_THROW(mergedConfig->validate()); { @@ -5996,12 +5765,13 @@ inactive_colorspaces: [ACES2065-1] { OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); + merger->getParams(0)->setAssumeCommonReferenceSpace(true); // Changing the strategy for colorspace merger to BASE ONLY. // This will break the looks "shot_look" (from input) as it needs the search paths // from the input config. (search_paths are managed by the colorspace merger). merger->getParams(0)->setColorspaces(OCIO::ConfigMergingParameters::STRATEGY_INPUT_ONLY); // The rest of the merges uses PreferInput strategy. - + OCIO::ConstConfigMergerRcPtr newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); auto look = mergedConfig->getLook("shot_look"); @@ -6012,8 +5782,8 @@ inactive_colorspaces: [ACES2065-1] // Therefore, the look's FileTransform can not find "look.cdl" and throws an exception. OCIO_CHECK_THROW(mergedConfig->getProcessor(ltf), OCIO::Exception); - // It can happens with any section that uses the search_paths such as looks, - // named_transforms and colorspaces. + // It can happen with any section that uses the search_paths such as looks, + // named transforms, and colorspaces. } } @@ -6033,8 +5803,8 @@ inactive_colorspaces: [ACES2065-1] OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); OCIO::ConstConfigMergerRcPtr newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); - std::ostringstream oss; - mergedConfig->serialize(oss); +// std::ostringstream oss; +// mergedConfig->serialize(oss); // Test that the merged config is the same of the built-in config used as input. auto bConfig = OCIO::Config::CreateFromBuiltinConfig("cg-config-v1.0.0_aces-v1.3_ocio-v2.1"); @@ -6095,6 +5865,33 @@ R"(ocio_profile_version: 2 name: B family: aces )" }; + + constexpr const char * RESULT { +R"(ocio_profile_version: 2 + +roles: + a: colorspace_a + +file_rules: + - ! {name: Default, colorspace: B} + +colorspaces: + - ! + name: colorspace_a + family: Base/utility + equalitygroup: "" + bitdepth: unknown + isdata: false + allocation: uniform + + - ! + name: B + family: Input/aces + equalitygroup: "" + bitdepth: unknown + isdata: false + allocation: uniform)" }; + std::istringstream bss(BASE); std::istringstream iss(INPUT); OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); @@ -6112,11 +5909,34 @@ R"(ocio_profile_version: 2 params->setAssumeCommonReferenceSpace(true); params->setAvoidDuplicates(false); - OCIO::ConfigRcPtr mergedConfig = OCIO::ConfigMergingHelpers::MergeConfigs(params, baseConfig, inputConfig); +// OCIO::ConfigRcPtr mergedConfig = OCIO::ConfigMergingHelpers::MergeConfigs(params, baseConfig, inputConfig); + OCIO::ConfigRcPtr mergedConfig; + + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, +// [&newMerger, &merger]() { newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); }, + [&mergedConfig, ¶ms, &baseConfig, &inputConfig]() { mergedConfig = OCIO::ConfigMergingHelpers::MergeConfigs(params, baseConfig, inputConfig); }, + "The Input config contains a value that would override the Base config: file_rules: Default"); +// "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", +// TODO: Last one should not be necessary. +// "The Input config contains a role that would override Base config role 'aces_interchange'"); + + +// FIXME: Add a test to check this result. +// std::ostringstream ossResult; +// mergedConfig->serialize(ossResult); +// std::cout << ossResult.str() << "\n"; + + std::ostringstream oss; + mergedConfig->serialize(oss); + + std::istringstream resultIss; + resultIss.str(RESULT); + OCIO::ConstConfigRcPtr resultConfig = OCIO::Config::CreateFromStream(resultIss); + std::ostringstream ossResult; + resultConfig->serialize(ossResult); - std::ostringstream ossResult; - mergedConfig->serialize(ossResult); - std::cout << ossResult.str() << "\n"; + //Testing the string of each config + OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); } OCIO_ADD_TEST(MergeConfigs, merge_single_colorspace) @@ -6167,7 +5987,40 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = OCIO::ConfigMergingHelpers::MergeColorSpace(params, baseConfig, colorspace); - std::ostringstream ossResult; - mergedConfig->serialize(ossResult); - std::cout << ossResult.str() << "\n"; +// FIXME: Add a test to check this result. +// std::ostringstream ossResult; +// mergedConfig->serialize(ossResult); +// std::cout << ossResult.str() << "\n"; +} + +OCIO_ADD_TEST(MergeConfigs, avoid_duplicate_color_spaces) +{ + { +// std::vector paths = { +// std::string(OCIO::GetTestFilesDir()), +// std::string("configs"), +// std::string("mergeconfigs"), +// std::string("merged1"), +// std::string("merged1.ociom") +// }; +// const std::string ociomPath = pystring::os::path::normpath(pystring::os::path::join(paths)); + const std::string ociomPath = "/Users/walkerdo/Documents/work/Autodesk/color/adsk_color_mgmt/OCIO/configs/merging/merge_flame_core.ociom"; + + // PreferInput, Input first + { + OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); + OCIO::ConstConfigMergerRcPtr newMerger; +// checkForLogOrException(LOG_TYPE_WARNING, __LINE__, +// [&newMerger, &merger]() { newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); }, +// "The Input config contains a value that would override the Base config: file_rules: Default", +// "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'"); +// TODO: Last one should not be necessary. +// "The Input config contains a role that would override Base config role 'aces_interchange'"); + newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); + OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); + std::ostringstream oss; + mergedConfig->serialize(oss); +// std::cout << oss.str() << "\n"; + } + } } diff --git a/tests/data/files/configs/mergeconfigs/merged1/base1.ocio b/tests/data/files/configs/mergeconfigs/merged1/base1.ocio index 7ec6f6f3c4..2d52524ed2 100644 --- a/tests/data/files/configs/mergeconfigs/merged1/base1.ocio +++ b/tests/data/files/configs/mergeconfigs/merged1/base1.ocio @@ -11,12 +11,23 @@ search_path: family_separator: "-" roles: - aces_interchange: ap0 +# aces_interchange: ap0 cie_xyz_d65_interchange: CIE-XYZ-D65 file_rules: - ! {name: Default, colorspace: ACEScg} +view_transforms: + - ! + name: SDR Video + description: from base + from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1} + + - ! + name: vt2 + description: from base + to_display_reference: ! {gamma: 2.4, offset: 0.055} + display_colorspaces: # reference space = cie xyz d65 - ! name: sRGB - Display diff --git a/tests/data/files/configs/mergeconfigs/merged1/input1.ocio b/tests/data/files/configs/mergeconfigs/merged1/input1.ocio index b5c789f141..62782ffc4e 100644 --- a/tests/data/files/configs/mergeconfigs/merged1/input1.ocio +++ b/tests/data/files/configs/mergeconfigs/merged1/input1.ocio @@ -1,12 +1,12 @@ ocio_profile_version: 2.1 name: input search_path: lut_dir -inactive_colorspaces: [ACES2065-1] +#inactive_colorspaces: [ACES2065-1] family_separator: "~" roles: - aces_interchange: ACES2065-1 +# aces_interchange: ACES2065-1 cie_xyz_d65_interchange: CIE-XYZ-D65 file_rules: @@ -20,6 +20,7 @@ displays: view_transforms: - ! name: SDR Video + description: from input from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1} display_colorspaces: # reference space = linear rec 709 From efa16fa73cc42284b2efebf0148540796a021050 Mon Sep 17 00:00:00 2001 From: Doug Walker Date: Fri, 24 Jan 2025 00:20:01 -0500 Subject: [PATCH 04/14] Unit test fix Signed-off-by: Doug Walker (cherry picked from commit cbc0f0ec96c8456ceb73f2b6a11b209084613d3f) Signed-off-by: Doug Walker --- .../apphelpers/MergeConfigsHelpers_tests.cpp | 166 +++--------------- 1 file changed, 22 insertions(+), 144 deletions(-) diff --git a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp index 899b97c2fc..1d631fe1e2 100644 --- a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp +++ b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp @@ -5427,155 +5427,30 @@ OCIO_ADD_TEST(MergeConfigs, merges_with_ociom_file) // TODO: Last one should not be necessary. // "The Input config contains a role that would override Base config role 'aces_interchange'"); OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); - std::ostringstream oss; - mergedConfig->serialize(oss); - - constexpr const char * RESULT { -R"(ocio_profile_version: 2.1 - -environment: - SHOT: 001a - TEXTURE_SPACE: sRGB - Texture -search_path: - - lut_dir - - luts - - . -strictparsing: true -family_separator: "~" -luma: [0.2126, 0.7152, 0.0722] -name: Merged1 -description: Basic merge with default strategy - -roles: - cie_xyz_d65_interchange: CIE-XYZ-D65 - -file_rules: - - ! {name: Default, colorspace: sRGB} - -displays: - sRGB - Display: - - ! {name: Raw, colorspace: raw} - - ! {name: ACES 1.0 - SDR Video, view_transform: SDR Video, display_colorspace: sRGB - Display} -active_displays: [] -active_views: [] - -view_transforms: - - ! - name: SDR Video - description: from input - from_scene_reference: ! - children: - - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1], direction: inverse} - - ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1} - - ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1]} + // This test is essentially the same as the first sub-test in the above test + // colorspaces_section_common_reference_and_duplicates. So just do a quick + // sanity test here rather than redoing all the same checks. - - ! - name: vt2 - description: from base - to_display_reference: ! {gamma: 2.4, offset: 0.055} + OCIO_CHECK_EQUAL(mergedConfig->getName(), std::string("Merged1")); + OCIO_CHECK_EQUAL(mergedConfig->getDescription(), std::string("Basic merge with default strategy")); + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, + OCIO::COLORSPACE_ALL), 7); -display_colorspaces: - - ! - name: sRGB - Display - aliases: [srgb_display] - family: Display~Standard - equalitygroup: "" - bitdepth: unknown - description: from input - isdata: false - allocation: uniform - from_display_reference: ! - children: - - ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1], direction: inverse} - - ! {gamma: 2.4, offset: 0.055, direction: inverse} - - ! - name: CIE-XYZ-D65 - aliases: [cie_xyz_d65] - family: "" - equalitygroup: "" - bitdepth: unknown - description: The \"CIE XYZ (D65)\" display connection colorspace. - isdata: false - allocation: uniform - from_display_reference: ! - children: - - ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1], direction: inverse} - - ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1]} -colorspaces: - - ! - name: ACES2065-1 - aliases: [aces, ap0] - family: ACES~Linear - equalitygroup: "" - bitdepth: unknown - description: from input - isdata: false - allocation: uniform - to_scene_reference: ! - children: - - ! {matrix: [2.521686186744, -1.13413098824, -0.387555198504, 0, -0.27647991423, 1.372719087668, -0.096239173438, 0, -0.015378064966, -0.152975335867, 1.168353400833, 0, 0, 0, 0, 1]} - - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} - - - ! - name: sRGB - aliases: [sRGB - Texture, srgb_tx] - family: Texture~ - equalitygroup: "" - bitdepth: unknown - description: from input - isdata: false - allocation: uniform - to_scene_reference: ! - children: - - ! {gamma: 2.4, offset: 0.055} - - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} - - - ! - name: rec709 - family: "" - equalitygroup: "" - bitdepth: unknown - description: from input - isdata: false - allocation: uniform - to_scene_reference: ! - children: - - ! {matrix: [0.439632981919492, 0.382988698151554, 0.177378319928956, 0, 0.0897764429588422, 0.813439428748978, 0.0967841282921771, 0, 0.0175411703831728, 0.111546553302387, 0.870912276314442, 0, 0, 0, 0, 1]} - - - ! - name: Raw - aliases: [Utility - Raw] - family: Utility - equalitygroup: "" - bitdepth: 32f - description: The utility "Raw" colorspace. - isdata: true - categories: [file-io] - allocation: uniform - - - ! - name: ACEScg - family: ACES~Linear - equalitygroup: "" - bitdepth: unknown - description: from base - isdata: false - allocation: uniform - to_scene_reference: ! {style: ACEScg_to_ACES2065-1} - )" }; - - std::istringstream resultIss; - resultIss.str(RESULT); - OCIO::ConstConfigRcPtr resultConfig = OCIO::Config::CreateFromStream(resultIss); - std::ostringstream ossResult; - resultConfig->serialize(ossResult); - - //Testing the string of each config - - OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); +// std::ostringstream oss; +// mergedConfig->serialize(oss); +// +// std::istringstream resultIss; +// resultIss.str(RESULT); +// OCIO::ConstConfigRcPtr resultConfig = OCIO::Config::CreateFromStream(resultIss); +// std::ostringstream ossResult; +// resultConfig->serialize(ossResult); +// +// //Testing the string of each config +// +// OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); } } @@ -5993,6 +5868,7 @@ R"(ocio_profile_version: 2 // std::cout << ossResult.str() << "\n"; } +/* OCIO_ADD_TEST(MergeConfigs, avoid_duplicate_color_spaces) { { @@ -6004,6 +5880,7 @@ OCIO_ADD_TEST(MergeConfigs, avoid_duplicate_color_spaces) // std::string("merged1.ociom") // }; // const std::string ociomPath = pystring::os::path::normpath(pystring::os::path::join(paths)); + const std::string ociomPath = "/Users/walkerdo/Documents/work/Autodesk/color/adsk_color_mgmt/OCIO/configs/merging/merge_flame_core.ociom"; // PreferInput, Input first @@ -6024,3 +5901,4 @@ OCIO_ADD_TEST(MergeConfigs, avoid_duplicate_color_spaces) } } } +*/ From c9fa285fd4eef707b851636e140e67e9d2cc11cf Mon Sep 17 00:00:00 2001 From: Doug Walker Date: Mon, 10 Feb 2025 00:42:19 -0500 Subject: [PATCH 05/14] Improve duplicates detection Signed-off-by: Doug Walker (cherry picked from commit 9871ef4fc9e131d29bf68f5716098a64d9818f9d) Signed-off-by: Doug Walker --- src/OpenColorIO/ConfigUtils.cpp | 347 ++++++++++-------- src/OpenColorIO/ConfigUtils.h | 16 +- .../apphelpers/mergeconfigs/SectionMerger.cpp | 5 +- tests/cpu/ConfigUtils_tests.cpp | 150 ++++++-- .../apphelpers/MergeConfigsHelpers_tests.cpp | 9 + 5 files changed, 336 insertions(+), 191 deletions(-) diff --git a/src/OpenColorIO/ConfigUtils.cpp b/src/OpenColorIO/ConfigUtils.cpp index ca42455f06..d826c227a2 100644 --- a/src/OpenColorIO/ConfigUtils.cpp +++ b/src/OpenColorIO/ConfigUtils.cpp @@ -360,6 +360,7 @@ bool containsBlockedTransform(const ConstTransformRcPtr & transform) { return true; } + return false; } @@ -824,7 +825,9 @@ const char * IdentifyBuiltinColorSpace(const ConstConfigRcPtr & srcConfig, builtinConfig, builtinColorSpaceName, builtinInterchangeName); - if (isIdentityTransform(proc, vals, 1e-3f)) +// if (isIdentityTransform(proc, vals, 1e-3f)) + // Tolerance is just loose enough to accept both bfd and cat02 adaptation. + if (isIdentityTransform(proc, vals, 5e-3f)) { return cs->getName(); } @@ -902,7 +905,7 @@ ConstTransformRcPtr getRefSpaceConverter(const ConstConfigRcPtr & srcConfig, const ConstConfigRcPtr & dstConfig, ReferenceSpaceType refSpaceType) { - ConstConfigRcPtr builtinConfig = Config::CreateFromFile("ocio://cg-config-latest"); + ConstConfigRcPtr builtinConfig = Config::CreateFromBuiltinConfig("ocio://cg-config-latest"); auto getColorspaceOfRefType = [](const ConstConfigRcPtr & config, ReferenceSpaceType refType) -> const char * @@ -975,14 +978,22 @@ ConstTransformRcPtr getRefSpaceConverter(const ConstConfigRcPtr & srcConfig, // simplified/optimized after being combined with the existing transform anyway // since one of these pieces may be the inverse of a color space's existing transform. GroupTransformRcPtr gt = GroupTransform::Create(); - gt->appendTransform(srcFromRef->createEditableCopy()); - gt->appendTransform(srcBuiltinToDstBuiltin); - gt->appendTransform(dstToRef->createEditableCopy()); +// gt->appendTransform(srcFromRef->createEditableCopy()); +// gt->appendTransform(srcBuiltinToDstBuiltin); +// gt->appendTransform(dstToRef->createEditableCopy()); // std::cout << "srcFromRef: " << *srcFromRef << "\n"; // std::cout << "srcToDstBuiltin: " << *srcBuiltinToDstBuiltin << "\n"; // std::cout << "dstToRef: " << *dstToRef << "\n"; // std::cout << "simplified: " << *simplifyTransform(gt) << "\n\n"; + // FIXME: If the src or dst contain FileTransforms, resolve them so there is no dependence + // on the search_path of the original configs. This is necessary for simplifyTransform + // below but would fail if if the conversion involved a transform that may not appear + // in a config, such as a LUT. + gt->appendTransform(srcConfig->getProcessor(srcFromRef)->createGroupTransform()); + gt->appendTransform(srcBuiltinToDstBuiltin); + gt->appendTransform(dstConfig->getProcessor(dstToRef)->createGroupTransform()); + // TODO: Need to ensure that gt would never contain a file transform. // for (size_t t = 0; t < gt->getNumTransforms(); t++) // { @@ -1212,18 +1223,20 @@ void initializeRefSpaceConverters(ConstTransformRcPtr & inputToBaseGtScene, } } -bool calcColorSpaceFingerprint(std::vector & fingerprint, const ConstConfigRcPtr & config, const ConstColorSpaceRcPtr & cs) +bool calcColorSpaceFingerprint(std::vector & fingerprint, const ColorSpaceFingerprints & fingerprints, const ConstConfigRcPtr & config, const ConstColorSpaceRcPtr & cs) { bool skipColorSpace = false; // Define a set of (somewhat arbitrary) RGB values to test whether the combined transform is // enough of an identity. // TODO: Should we check values outside [0,1]? - std::vector RGBAvals = { 0.4f, 0.23f, 0.07f, 0.f, - 0.35f, 0.66f, 0.16f, 0.f, - 0.2f, 0.11f, 0.86f, 0.f, - 0.f, 0.f, 0.f, 0.f, - 0.04f, 0.03f, 0.02f, 0.f, - 1.f, 1.f, 1.f, 0.f }; + +// std::vector RGBAvals = { 0.4f, 0.23f, 0.07f, 0.f, +// 0.35f, 0.66f, 0.16f, 0.f, +// 0.2f, 0.11f, 0.86f, 0.f, +// 0.f, 0.f, 0.f, 0.f, +// 0.04f, 0.03f, 0.02f, 0.f, +// 1.f, 1.f, 1.f, 0.f }; + // std::vector RGBAvals = { 0.7f, 0.4f, 0.02f, 0.f, // 0.02f, 0.6f, 0.2f, 0.f, // 0.3f, 0.02f, 0.5f, 0.f, @@ -1238,46 +1251,178 @@ bool calcColorSpaceFingerprint(std::vector & fingerprint, const ConstConf // 0.f, 0.f, 0.f, 0.f, // 1.f, 1.f, 1.f, 0.f }; - ConstTransformRcPtr fromRef = getTransformForDir(cs, COLORSPACE_DIR_FROM_REFERENCE); + ConstTransformRcPtr fromRef = getTransformForDir(cs, COLORSPACE_DIR_FROM_REFERENCE); + + ConstProcessorRcPtr p; + try + { + p = config->getProcessor(fromRef); + } + catch (...) + { + // If the transform doesn't validate (singular matrix, etc.), don't consider it. + return true; + } + + // TODO: Get a group transform and don't bother if it contains a 3d-lut. + // With optimization-none, it should not invert a 3d-lut, regardless of direction? + + if (cs->getReferenceSpaceType() == REFERENCE_SPACE_DISPLAY) + { + fingerprint = fingerprints.displayRefTestVals; + } + else + { + fingerprint = fingerprints.sceneRefTestVals; + } + const size_t n = fingerprint.size(); + PackedImageDesc desc( &fingerprint[0], (long) n / 4, 1, CHANNEL_ORDERING_RGBA ); + + ConstCPUProcessorRcPtr cpu = p->getOptimizedCPUProcessor(OPTIMIZATION_NONE); + cpu->apply(desc); + + // TODO: add a cacheID to GroupTransform using the opData IDs, use that to do an easier comparison. + // TODO: compare to_refs to to_refs. + return skipColorSpace; +} - ConstProcessorRcPtr p; - try +void initializeTestVals(ColorSpaceFingerprints & fingerprints, const ConstConfigRcPtr & config) +{ + // Define a set of test values that are slightly inside the Rec.709 gamut + // for the most common scene-referred and display-referred reference spaces. + + std::vector ACESvals = { + 0.401273353908f, 0.089901034233f, 0.025611641641f, 0.f, // lin_rec709 {0.9, 0.01, 0.01} + 0.350859941355f, 0.733961091587f, 0.109276432439f, 0.f, // lin_rec709 {0.1, 0.09, 0.01} + 0.171696591718f, 0.104272268468f, 0.786227391453f, 0.f, // lin_rec709 {0.1, 0.02, 0.09} + 0.f , 0.f , 0.f , 0.5f, + 0.037018876439f, 0.030827687576f, 0.021641700645f, 0.f, // lin_rec709 {0.05, 0.03, 0.02} + 1.f , 1.f , 1.f , 1.f }; + + std::vector XYZvals = { + 0.376532370617f, 0.199248715226f, 0.028095006164f, 0.f, // lin_rec709 {0.9, 0.01, 0.01} + 0.327754621322f, 0.646500124103f, 0.116973931525f, 0.f, // lin_rec709 {0.1, 0.09, 0.01} + 0.173708304342f, 0.081402847459f, 0.858056140808f, 0.f, // lin_rec709 {0.1, 0.02, 0.09} + 0.f , 0.f , 0.f , 0.5f, + 0.034956685913f, 0.033530856964f, 0.023553027375f, 0.f, // lin_rec709 {0.05, 0.03, 0.02} + 0.950455927052f, 1.f , 1.089057750760f, 1.f }; + + // Try to convert to the actual reference spaces of the config. + + fingerprints.sceneRefTestVals = ACESvals; + fingerprints.displayRefTestVals = XYZvals; + + ConstProcessorRcPtr p; + try + { + // First check if the config recognizes one of the common names. + ConstColorSpaceRcPtr cs; + cs = config->getColorSpace("aces_interchange"); + if (!cs) { - p = config->getProcessor(fromRef); - } - catch (...) - { - // If the transform doesn't validate (singular matrix, etc.), don't consider it. - return true; + cs = config->getColorSpace("ACES2065-1"); + if (!cs) + { + cs = config->getColorSpace("lin_ap0_scene"); + if (!cs) + { + // Otherwise, see if it's present using a different name. +// std::cout << "--> need lin_rec709\n"; + ConstConfigRcPtr builtinConfig = Config::CreateFromBuiltinConfig("ocio://cg-config-latest"); + // This throws if it cannot find the requested space. + const char * cs_name = + Config::IdentifyBuiltinColorSpace(config, builtinConfig, "aces_interchange"); + cs = config->getColorSpace(cs_name); +// std::cout << "--> identified lin_rec709\n"; + } + } } +// else +// std::cout << "--> found lin_rec709\n"; - // TODO: Get a group transform and don't bother if it contains a 3d-lut. - // With optimization-none, it should not invert a 3d-lut, regardless of direction? + ConstTransformRcPtr toRef = getTransformForDir(cs, COLORSPACE_DIR_TO_REFERENCE); + p = config->getProcessor(toRef); - std::vector out(RGBAvals.size(), 0.f); + const size_t n = ACESvals.size(); + std::vector out(n, 0.f); - PackedImageDesc descSrc( &RGBAvals[0], (long) RGBAvals.size() / 4, 1, CHANNEL_ORDERING_RGBA ); - PackedImageDesc descDst( &out[0], (long) RGBAvals.size() / 4, 1, CHANNEL_ORDERING_RGBA ); + PackedImageDesc descSrc( &ACESvals[0], (long) n / 4, 1, CHANNEL_ORDERING_RGBA ); + PackedImageDesc descDst( &out[0], (long) n / 4, 1, CHANNEL_ORDERING_RGBA ); ConstCPUProcessorRcPtr cpu = p->getOptimizedCPUProcessor(OPTIMIZATION_NONE); cpu->apply(descSrc, descDst); - fingerprint = out; + fingerprints.sceneRefTestVals = out; +// std::cout << "--> computed lin_rec709\n"; + } + catch (...) + { +// std::cout << "--> exception lin_rec709\n"; + fingerprints.sceneRefTestVals = ACESvals; + } - // TODO: add a cacheID to GroupTransform using the opData IDs, use that to do an easier comparison. - // TODO: compare to_refs to to_refs. - return skipColorSpace; + const int m = config->getNumColorSpaces(SEARCH_REFERENCE_SPACE_DISPLAY, COLORSPACE_ALL); + if (m == 0) + { + return; + } + + try + { + // First check if the config recognizes one of the common names. + ConstColorSpaceRcPtr cs; + cs = config->getColorSpace("cie_xyz_d65_interchange"); + if (!cs) + { + cs = config->getColorSpace("CIE-XYZ-D65"); + if (!cs) + { + cs = config->getColorSpace("CIE XYZ-D65"); + if (!cs) + { + // Otherwise, see if it's present using a different name. +// std::cout << "--> need xyz\n"; + ConstConfigRcPtr builtinConfig = Config::CreateFromBuiltinConfig("ocio://cg-config-latest"); + // TODO: verify this will convert to the same ref space type. + const char * cs_name = + Config::IdentifyBuiltinColorSpace(config, builtinConfig, "cie_xyz_d65_interchange"); + cs = config->getColorSpace(cs_name); +// std::cout << "--> identified xyz\n"; + } + } + } +// else +// std::cout << "--> found xyz\n"; + + ConstTransformRcPtr toRef = getTransformForDir(cs, COLORSPACE_DIR_TO_REFERENCE); + p = config->getProcessor(toRef); + + const size_t n = XYZvals.size(); + std::vector out(n, 0.f); + + PackedImageDesc descSrc( &XYZvals[0], (long) n / 4, 1, CHANNEL_ORDERING_RGBA ); + PackedImageDesc descDst( &out[0], (long) n / 4, 1, CHANNEL_ORDERING_RGBA ); + + ConstCPUProcessorRcPtr cpu = p->getOptimizedCPUProcessor(OPTIMIZATION_NONE); + cpu->apply(descSrc, descDst); + + fingerprints.displayRefTestVals = out; +// std::cout << "--> computed xtyz\n"; + } + catch (...) + { +// std::cout << "--> exception xyz\n"; + fingerprints.displayRefTestVals = XYZvals; + } } -void initializeColorSpacesFingerprints(ColorSpaceFingerprints & fingerprints, const ConstConfigRcPtr & config) +void initializeColorSpaceFingerprints(ColorSpaceFingerprints & fingerprints, const ConstConfigRcPtr & config) { SuspendCacheGuard srcGuard(config); -// ConstConfigRcPtr builtinConfig = Config::CreateFromFile("ocio://cg-config-latest"); -// // TODO: verify this will convert to the same ref space type. -// const char * srgbName = OCIO::Config::IdentifyBuiltinColorSpace(config, builtinConfig, "srgb_texture"); + initializeTestVals(fingerprints, config); - int n = config->getNumColorSpaces(SEARCH_REFERENCE_SPACE_ALL, COLORSPACE_ALL); + const int n = config->getNumColorSpaces(SEARCH_REFERENCE_SPACE_ALL, COLORSPACE_ALL); fingerprints.vec.clear(); fingerprints.vec.reserve(n); for (int i = 0; i < n; ++i) @@ -1288,7 +1433,7 @@ void initializeColorSpacesFingerprints(ColorSpaceFingerprints & fingerprints, co ConstColorSpaceRcPtr cs = config->getColorSpace(name); if (!cs || cs->isData()) { - // Don't put data color spaces in the map. + // Don't put data color spaces in the collection. continue; } @@ -1302,7 +1447,7 @@ void initializeColorSpacesFingerprints(ColorSpaceFingerprints & fingerprints, co } std::vector fp; - const bool skipColorSpace = calcColorSpaceFingerprint(fp, config, cs); + const bool skipColorSpace = calcColorSpaceFingerprint(fp, fingerprints, config, cs); if (!skipColorSpace) { Fingerprint fprint; @@ -1317,48 +1462,51 @@ void initializeColorSpacesFingerprints(ColorSpaceFingerprints & fingerprints, co // If the base config contains a color space equivalent to inputCS, return its name. // Return an empty string if no equivalent color space is found (within the tolerance). // The ref_space_type specifies the type of inputCS and determines which part of the -// config is searched. Note: Normally the refType should be set by simply calling -// inputCS->getReferenceSpaceType(). Not sure the extra flexibility to search the -// other ref space type is needed (perhaps drop the option if this gets added to -// the public API). -// +// config is searched. const char * findEquivalentColorspace(const ColorSpaceFingerprints & fingerprints, const ConstConfigRcPtr & inputConfig, - const ConstColorSpaceRcPtr & inputCS, - ReferenceSpaceType refType) + const ConstColorSpaceRcPtr & inputCS) +// ReferenceSpaceType refType) { // The fingerprints must first be initialized from the base config. // NB: The inputConfig/inputCS must use the same reference space as the base config. // In general, this means that updateReferenceColorspace must be called on inputCS // before calling this function. - // TODO: Should data spaces ever be replaced? There is no need for flame? + // TODO: Should data spaces ever be replaced? if (inputCS->isData()) { return ""; } - std::vector inputVals; - const bool skipColorSpace = calcColorSpaceFingerprint(inputVals, inputConfig, inputCS); - if (skipColorSpace) + // Calculate the fingerprint of inputCS from inputConfig. + std::vector inputVals; + const bool skipColorSpace = calcColorSpaceFingerprint(inputVals, fingerprints, inputConfig, inputCS); + if (skipColorSpace) { return ""; } // FIXME: Before looping over all color spaces, check to see if there's one with the same name. - const float absTolerance = 1e-3f; + // Increase from 1e-3 to 5e-3 to allow for use of either Bradford or CAT02 adaptation. + const float absTolerance = 5e-3f; + + // Compare to the fingerprints from the base config. + const size_t n = inputVals.size(); for (const auto & fp : fingerprints.vec) { - if (fp.type != refType) + // Only compare color spaces that are using the same reference space type. + if (fp.type != inputCS->getReferenceSpaceType()) continue; - std::vector vals = fp.vals; - bool matchFound = true; - for (size_t i = 0; i < vals.size(); i++) + for (size_t i = 0; i < n; i++) { - if (!EqualWithAbsError(inputVals[i], vals[i], absTolerance)) + // Comparison is done in the color space, not the reference space. + // Could be linear, gamma-corrected, or log encoding. + // TODO: Could adjust the comparison based on the color space encoding. + if (!EqualWithAbsError(inputVals[i], fp.vals[i], absTolerance)) { matchFound = false; continue; @@ -1392,97 +1540,6 @@ const char * findEquivalentColorspace(const ColorSpaceFingerprints & fingerprint return ""; } -// const char * findEquivalentColorspace(const ConstConfigRcPtr & baseConfig, -// const ConstConfigRcPtr & inputConfig, -// const ConstColorSpaceRcPtr & inputCS, -// ReferenceSpaceType refType) -// { -// // NB: This assumes that new_cs uses the same reference space as config. -// // In general, this means that update_color_reference_space must be called on new_cs -// // before calling this function. -// -// if (inputCS->isData()) -// { -// for (int i = 0; i < baseConfig->getNumColorSpaces(SEARCH_REFERENCE_SPACE_SCENE, COLORSPACE_ALL); ++i) -// { -// const char * name = baseConfig->getColorSpaceNameByIndex(SEARCH_REFERENCE_SPACE_SCENE, COLORSPACE_ALL, i); -// ConstColorSpaceRcPtr cs = baseConfig->getColorSpace(name); -// if (cs->isData()) -// { -// return cs->getName(); -// } -// -// } -// return ""; -// } -// -// // The heuristics need to create a lot of Processors and send RGB values through -// // them to try and identify a known color space. Turn off the Processor cache in -// // the configs to avoid polluting the cache with transforms that won't be reused -// // and avoid the overhead of maintaining the cache. -// SuspendCacheGuard srcGuard(baseConfig); -// -// ConstTransformRcPtr fromRef = getTransformForDir(inputCS, COLORSPACE_DIR_FROM_REFERENCE); -// -// -// // auto p = baseConfig->getProcessor(gt); -// // Define a set of (somewhat arbitrary) RGB values to test whether the combined transform is -// // enough of an identity. -// // TODO: Should we check values outside [0,1]? -// std::vector vals = { 0.7f, 0.4f, 0.02f, 0.f, -// 0.02f, 0.6f, 0.2f, 0.f, -// 0.3f, 0.02f, 0.5f, 0.f, -// 0.f, 0.f, 0.f, 0.f, -// 1.f, 1.f, 1.f, 0.f }; -// -// // FIXME: THIS BREAKS THE TESTS -// -// // std::vector vals = { 0.7f, 0.4f, 0.02f, 0.f, -// // 0.02f, 0.6f, -0.2f, 0.f, -// // 0.3f, 0.02f, 1.5f, 0.f, -// // 0.f, 0.f, 0.f, 0.f, -// // 1.f, 1.f, 1.f, 0.f }; -// -// std::vector out(RGBAvals.size(), 0.f); -// -// PackedImageDesc desc( &RGBAvals[0], (long) RGBAvals.size() / 4, 1, CHANNEL_ORDERING_RGBA ); -// PackedImageDesc descDst( &out[0], (long) RGBAvals.size() / 4, 1, CHANNEL_ORDERING_RGBA ); -// -// ConstCPUProcessorRcPtr cpu = proc->getOptimizedCPUProcessor(OPTIMIZATION_NONE); -// cpu->apply(desc, descDst); -// -// -// // FIXME: Before looping over all color spaces, check to see if there's one with the same name. -// -// SearchReferenceSpaceType searchRefType = static_cast(refType); -// for (int i = 0; i < baseConfig->getNumColorSpaces(searchRefType, COLORSPACE_ALL); ++i) -// { -// const char * name = baseConfig->getColorSpaceNameByIndex(searchRefType, COLORSPACE_ALL, i); -// ConstColorSpaceRcPtr cs = baseConfig->getColorSpace(name); -// -// // TODO: Need to add isdata check to other heuristics too. -// -// if (!cs->isData()) -// { -// // ConstTransformRcPtr toRef = getTransformForDir(cs, COLORSPACE_DIR_TO_REFERENCE); -// // GroupTransformRcPtr gt = GroupTransform::Create(); -// // gt->appendTransform(toRef->createEditableCopy()); -// // gt->appendTransform(fromRef->createEditableCopy()); -// // -// // auto p = baseConfig->getProcessor(gt); -// -// -// -// if (isIdentityTransform(p, vals, 1e-3f)) -// { -// return cs->getName(); -// } -// } -// } -// -// return ""; -// } - } // namespace ConfigUtils } // namespace OCIO_NAMESPACE diff --git a/src/OpenColorIO/ConfigUtils.h b/src/OpenColorIO/ConfigUtils.h index 8f704919a7..a26af390bc 100644 --- a/src/OpenColorIO/ConfigUtils.h +++ b/src/OpenColorIO/ConfigUtils.h @@ -58,22 +58,20 @@ struct Fingerprint ReferenceSpaceType type; std::vector vals; }; -//typedef std::map< std::string, Fingerprint > ColorSpaceFingerprintMap; + struct ColorSpaceFingerprints { std::vector vec; + std::vector sceneRefTestVals; + std::vector displayRefTestVals; }; -void initializeColorSpacesFingerprints(ColorSpaceFingerprints & fingerprints, - const ConstConfigRcPtr & config); + +void initializeColorSpaceFingerprints(ColorSpaceFingerprints & fingerprints, + const ConstConfigRcPtr & config); const char * findEquivalentColorspace(const ColorSpaceFingerprints & fingerprints, const ConstConfigRcPtr & inputConfig, - const ConstColorSpaceRcPtr & inputCS, - ReferenceSpaceType refType); - -// const char * findEquivalentColorspace(const ConstConfigRcPtr & config, -// const ConstColorSpaceRcPtr & newCs, -// ReferenceSpaceType refType); + const ConstColorSpaceRcPtr & inputCS); // Temporarily deactivate the Processor cache on a Config object. // Currently, this also clears the cache. diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp index f7a6e5440e..d5f401b5f4 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp +++ b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp @@ -2548,8 +2548,7 @@ bool ColorspacesMerger::handleAvoidDuplicatesOption(ConfigUtils::ColorSpaceFinge // ); const char * duplicateInBase = ConfigUtils::findEquivalentColorspace( fingerprints, - inputConfig, inputCS, - inputCS->getReferenceSpaceType() + inputConfig, inputCS ); // TODO: Could this be refactored to go through the usual merge process? @@ -2970,7 +2969,7 @@ void ColorspacesMerger::addColorSpaces() ConfigUtils::ColorSpaceFingerprints fingerprints; if (m_params->isAvoidDuplicates()) { - ConfigUtils::initializeColorSpacesFingerprints(fingerprints, m_baseConfig); + ConfigUtils::initializeColorSpaceFingerprints(fingerprints, m_baseConfig); } for (int i = 0; i < m_inputConfig->getNumColorSpaces(SEARCH_REFERENCE_SPACE_ALL, COLORSPACE_ALL); ++i) diff --git a/tests/cpu/ConfigUtils_tests.cpp b/tests/cpu/ConfigUtils_tests.cpp index 3e25f49775..9b9c01585a 100644 --- a/tests/cpu/ConfigUtils_tests.cpp +++ b/tests/cpu/ConfigUtils_tests.cpp @@ -644,7 +644,8 @@ inactive_colorspaces: [] description: sRGB - Texture with truncated matrix values from_scene_reference: ! children: - - ! {matrix: [2.521686, -1.134131, -0.387555, 0, -0.2764799, 1.372719, -0.09623917, 0, -0.01537806, -0.152975, 1.168353, 0, 0, 0, 0, 1]} +# - ! {matrix: [2.521686, -1.134131, -0.387555, 0, -0.2764799, 1.372719, -0.09623917, 0, -0.01537806, -0.152975, 1.168353, 0, 0, 0, 0, 1]} + - ! {matrix: [2.522, -1.134, -0.388, 0, -0.276, 1.373, -0.0962, 0, -0.0154, -0.153, 1.168, 0, 0, 0, 0, 1]} - ! {gamma: 2.4, offset: 0.055, direction: inverse} - ! @@ -653,7 +654,11 @@ inactive_colorspaces: [] description: sRGB - Texture with truncated matrix values and different gamma from_scene_reference: ! children: - - ! {matrix: [2.521686, -1.134131, -0.387555, 0, -0.2764799, 1.372719, -0.09623917, 0, -0.01537806, -0.152975, 1.168353, 0, 0, 0, 0, 1]} + - ! {matrix: [2.52, -1.13, -0.39, 0, -0.28, 1.37, -0.096, 0, -0.015, -0.15, 1.17, 0, 0, 0, 0, 1]} +# - ! {matrix: [2.522, -1.134, -0.388, 0, -0.276, 1.373, -0.0962, 0, -0.0154, -0.153, 1.168, 0, 0, 0, 0, 1]} +# - ! {value: [2.2, 2.2, 2.2, 1], direction: inverse} +# - ! {gamma: 2.2, direction: inverse} +# - ! {gamma: 2.42, offset: 0.055, direction: inverse} - ! {gamma: 2.42, offset: 0.055, direction: inverse} - ! @@ -668,20 +673,53 @@ inactive_colorspaces: [] description: ACEScg but with a Matrix rather than Builtin Transform. to_reference: ! {matrix: [ 0.695452241357, 0.140678696470, 0.163869062172, 0, 0.044794563372, 0.859671118456, 0.095534318172, 0, -0.005525882558, 0.004025210306, 1.001500672252, 0, 0, 0, 0, 1 ]} + - ! + name: pq display scene + isdata: false + description: Rec.2100-PQ - incorrectly as a display + from_reference: ! + children: +# - ! {style: UTILITY - ACES-AP0_to_CIE-XYZ-D65_BFD} + - ! {style: DISPLAY - CIE-XYZ-D65_to_REC.2100-PQ} + +display_colorspaces: - ! name: pq display isdata: false description: Rec.2100-PQ - Display - from_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_REC.2100-PQ} + from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_REC.2100-PQ} + + - ! + name: ACES cg display + isdata: false + description: ACEScg - incorrectly as a display + to_display_reference: ! + children: + - ! {matrix: [ 0.695452241357, 0.140678696470, 0.163869062172, 0, 0.044794563372, 0.859671118456, 0.095534318172, 0, -0.005525882558, 0.004025210306, 1.001500672252, 0, 0, 0, 0, 1 ]} +# - ! {style: UTILITY - ACES-AP0_to_CIE-XYZ-D65_BFD} )" }; +// >>> cs.build_conversion_matrix('ap0','rec 709','cat02').T +// array([[ 2.52193473, -1.1370239 , -0.38491083], +// [-0.27547943, 1.36982898, -0.09434955], +// [-0.01598287, -0.14778923, 1.1637721 ]]) +// >>> cs.build_conversion_matrix('ap0','rec 709','bfd').T +// array([[ 2.52168619, -1.13413099, -0.3875552 ], +// [-0.27647991, 1.37271909, -0.09623917], +// [-0.01537806, -0.15297534, 1.1683534 ]]) + iss.str(INPUT); OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromFile("ocio://cg-config-v1.0.0_aces-v1.3_ocio-v2.1"); OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); OCIO::ConfigUtils::ColorSpaceFingerprints fingerprints; - OCIO::ConfigUtils::initializeColorSpacesFingerprints(fingerprints, baseConfig); + OCIO::ConfigUtils::initializeColorSpaceFingerprints(fingerprints, baseConfig); + +// auto cs = inputConfig->getColorSpace("very approx. standard RGB"); +// auto gt = inputConfig->getProcessor(cs->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)) +// ->createGroupTransform(); +// std::cout << *gt << "\n"; // for (const auto & pair : fingerprints) // { @@ -696,10 +734,27 @@ inactive_colorspaces: [] // std::cout << "\n"; // } +// std::vector vals = fingerprints.sceneRefTestVals; +// for (size_t i = 0; i < vals.size(); i++) +// { +// std::cout << vals[i] << ", "; +// } +// std::cout << "scene\n"; +// std::vector vals1 = fingerprints.displayRefTestVals; +// for (size_t i = 0; i < vals1.size(); i++) +// { +// std::cout << vals1[i] << ", "; +// } +// std::cout << "display\n"; + +// The above prints this: +// 0.401273, 0.089901, 0.0256116, 0, 0.35086, 0.733961, 0.109276, 0, 0.171697, 0.104272, 0.786227, 0, 0, 0, 0, 0.5, 0.0370189, 0.0308277, 0.0216417, 0, 1, 1, 1, 1, scene +// 0.376532, 0.199249, 0.028095, 0, 0.327755, 0.6465, 0.116974, 0, 0.173708, 0.0814028, 0.858056, 0, 0, 0, 0, 0.5, 0.0349567, 0.0335309, 0.023553, 0, 0.950456, 1, 1.08906, 1, display + + { OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("ref_space"); - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, - OCIO::REFERENCE_SPACE_SCENE); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); OCIO_CHECK_EQUAL(name, std::string("ACES2065-1")); } // { @@ -710,65 +765,92 @@ inactive_colorspaces: [] // } { OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("standard RGB"); - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, - OCIO::REFERENCE_SPACE_SCENE); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); OCIO_CHECK_EQUAL(name, std::string("sRGB - Texture")); } { OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("approx. standard RGB"); - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, - OCIO::REFERENCE_SPACE_SCENE); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); OCIO_CHECK_EQUAL(name, std::string("sRGB - Texture")); } { OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("very approx. standard RGB"); - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, - OCIO::REFERENCE_SPACE_SCENE); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); OCIO_CHECK_EQUAL(name, std::string("")); } { OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("ACES cct"); - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, - OCIO::REFERENCE_SPACE_SCENE); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); OCIO_CHECK_EQUAL(name, std::string("ACEScct")); } { OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("requires ACES cct"); - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, - OCIO::REFERENCE_SPACE_SCENE); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); OCIO_CHECK_EQUAL(name, std::string("ACEScct")); } { OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("ACES cg"); - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, - OCIO::REFERENCE_SPACE_SCENE); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); OCIO_CHECK_EQUAL(name, std::string("ACEScg")); } { - OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("ACES cg"); - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, - OCIO::REFERENCE_SPACE_DISPLAY); + OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("ACES cg display"); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); OCIO_CHECK_EQUAL(name, std::string("")); } { OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("pq display"); - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, - OCIO::REFERENCE_SPACE_DISPLAY); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); OCIO_CHECK_EQUAL(name, std::string("Rec.2100-PQ - Display")); } { - OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("pq display"); - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, - OCIO::REFERENCE_SPACE_SCENE); + OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("pq display scene"); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); OCIO_CHECK_EQUAL(name, std::string("")); } } -// OCIO_ADD_TEST(MergeConfigs, config_utils_find_equivalent_colorspace2) -// { -// OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromFile("ocio://cg-config-v1.0.0_aces-v1.3_ocio-v2.1"); -// OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromFile("/Users/walkerdo/Documents/work/Autodesk/color/adsk_color_mgmt/OCIO/configs/flame/flame_core_config.ocio"); -// -// OCIO::ConfigUtils::ColorSpaceFingerprintMap fingerprints; -// OCIO::ConfigUtils::initializeColorSpacesFingerprintMap(fingerprints, baseConfig); -// } +OCIO_ADD_TEST(MergeConfigs, config_utils_find_equivalent_colorspace2) +{ +// OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromFile("ocio://cg-config-v1.0.0_aces-v1.3_ocio-v2.1"); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromFile("/Users/walkerdo/Documents/work/Autodesk/color/adsk_color_mgmt/OCIO/customer configs/FilmLight/TCS_TCAMv3/TCS_TCAMv3.ocio"); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromFile("/Users/walkerdo/Documents/work/Autodesk/color/adsk_color_mgmt/OCIO/configs/flame/flame_core_config.ocio"); + + OCIO::ConfigUtils::ColorSpaceFingerprints fingerprints; + OCIO::ConfigUtils::initializeColorSpaceFingerprints(fingerprints, baseConfig); + +// std::vector vals = fingerprints.sceneRefTestVals; +// for (size_t i = 0; i < vals.size(); i++) +// { +// std::cout << vals[i] << ", "; +// } +// std::cout << "scene\n"; +// std::vector vals1 = fingerprints.displayRefTestVals; +// for (size_t i = 0; i < vals1.size(); i++) +// { +// std::cout << vals1[i] << ", "; +// } +// std::cout << "display\n"; +// +// 0.487301, 0.0881323, 0.0741543, 0, 0.300795, 0.700204, 0.167705, 0, 0.13517, 0.139418, 0.679913, 0, 0, 0, 0, 0.5, 0.0393561, 0.0303888, 0.0239345, 0, 0.999998, 1, 1, 1, scene + + OCIO::ConstTransformRcPtr inputToBaseGtScene; + OCIO::ConstTransformRcPtr inputToBaseGtDisplay; + OCIO::ConfigUtils::initializeRefSpaceConverters(inputToBaseGtScene, + inputToBaseGtDisplay, + baseConfig, + inputConfig); + + { + OCIO::ColorSpaceRcPtr cs = inputConfig->getColorSpace("ACEScct")->createEditableCopy(); + OCIO::ConfigUtils::updateReferenceColorspace(cs, inputToBaseGtScene); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); + OCIO_CHECK_EQUAL(name, std::string("ACEScct: ACEScct : AP1")); + } + { + OCIO::ColorSpaceRcPtr cs = inputConfig->getColorSpace("Apple Log")->createEditableCopy(); + OCIO::ConfigUtils::updateReferenceColorspace(cs, inputToBaseGtScene); + const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); + OCIO_CHECK_EQUAL(name, std::string("Apple: Apple Log : Rec.2020")); + } +} diff --git a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp index 1d631fe1e2..80a0d5cc81 100644 --- a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp +++ b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp @@ -5588,6 +5588,8 @@ inactive_colorspaces: [ACES2065-1] } } */ +std::cout << "merge2\n"; + // Test with external LUT files. { std::vector paths = { @@ -5626,6 +5628,8 @@ inactive_colorspaces: [ACES2065-1] } } +std::cout << "merge3\n"; + // Test that a merge could go wrong if the search_paths are merged with a different strategy // than the other sections. { @@ -5638,6 +5642,9 @@ inactive_colorspaces: [ACES2065-1] }; const std::string ociomPath = pystring::os::path::normpath(pystring::os::path::join(paths)); +// FIXME: The ociom file should not try to do avoid dupes. Is that also throwing? +// The base config is not suitable for find dupes. + { OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); merger->getParams(0)->setAssumeCommonReferenceSpace(true); @@ -5662,6 +5669,8 @@ inactive_colorspaces: [ACES2065-1] } } +std::cout << "merge4\n"; + // Test with a built-in config. { std::vector paths = { From 36eb3ee81b2696526efe030efe9a25991f75655c Mon Sep 17 00:00:00 2001 From: Doug Walker Date: Mon, 10 Feb 2025 00:49:23 -0500 Subject: [PATCH 06/14] Fix unit test Signed-off-by: Doug Walker (cherry picked from commit 914b2f036baeba2b49c35b64790c4ffa47853f0d) Signed-off-by: Doug Walker --- tests/cpu/ConfigUtils_tests.cpp | 88 ++++++++++++++++----------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/tests/cpu/ConfigUtils_tests.cpp b/tests/cpu/ConfigUtils_tests.cpp index 9b9c01585a..57d6c77a35 100644 --- a/tests/cpu/ConfigUtils_tests.cpp +++ b/tests/cpu/ConfigUtils_tests.cpp @@ -810,47 +810,47 @@ inactive_colorspaces: [] } } -OCIO_ADD_TEST(MergeConfigs, config_utils_find_equivalent_colorspace2) -{ -// OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromFile("ocio://cg-config-v1.0.0_aces-v1.3_ocio-v2.1"); - OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromFile("/Users/walkerdo/Documents/work/Autodesk/color/adsk_color_mgmt/OCIO/customer configs/FilmLight/TCS_TCAMv3/TCS_TCAMv3.ocio"); - OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromFile("/Users/walkerdo/Documents/work/Autodesk/color/adsk_color_mgmt/OCIO/configs/flame/flame_core_config.ocio"); - - OCIO::ConfigUtils::ColorSpaceFingerprints fingerprints; - OCIO::ConfigUtils::initializeColorSpaceFingerprints(fingerprints, baseConfig); - -// std::vector vals = fingerprints.sceneRefTestVals; -// for (size_t i = 0; i < vals.size(); i++) -// { -// std::cout << vals[i] << ", "; -// } -// std::cout << "scene\n"; -// std::vector vals1 = fingerprints.displayRefTestVals; -// for (size_t i = 0; i < vals1.size(); i++) -// { -// std::cout << vals1[i] << ", "; -// } -// std::cout << "display\n"; -// -// 0.487301, 0.0881323, 0.0741543, 0, 0.300795, 0.700204, 0.167705, 0, 0.13517, 0.139418, 0.679913, 0, 0, 0, 0, 0.5, 0.0393561, 0.0303888, 0.0239345, 0, 0.999998, 1, 1, 1, scene - - OCIO::ConstTransformRcPtr inputToBaseGtScene; - OCIO::ConstTransformRcPtr inputToBaseGtDisplay; - OCIO::ConfigUtils::initializeRefSpaceConverters(inputToBaseGtScene, - inputToBaseGtDisplay, - baseConfig, - inputConfig); - - { - OCIO::ColorSpaceRcPtr cs = inputConfig->getColorSpace("ACEScct")->createEditableCopy(); - OCIO::ConfigUtils::updateReferenceColorspace(cs, inputToBaseGtScene); - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); - OCIO_CHECK_EQUAL(name, std::string("ACEScct: ACEScct : AP1")); - } - { - OCIO::ColorSpaceRcPtr cs = inputConfig->getColorSpace("Apple Log")->createEditableCopy(); - OCIO::ConfigUtils::updateReferenceColorspace(cs, inputToBaseGtScene); - const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); - OCIO_CHECK_EQUAL(name, std::string("Apple: Apple Log : Rec.2020")); - } -} +// OCIO_ADD_TEST(MergeConfigs, config_utils_find_equivalent_colorspace2) +// { +// // OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromFile("ocio://cg-config-v1.0.0_aces-v1.3_ocio-v2.1"); +// OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromFile("/Users/walkerdo/Documents/work/Autodesk/color/adsk_color_mgmt/OCIO/customer configs/FilmLight/TCS_TCAMv3/TCS_TCAMv3.ocio"); +// OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromFile("/Users/walkerdo/Documents/work/Autodesk/color/adsk_color_mgmt/OCIO/configs/flame/flame_core_config.ocio"); +// +// OCIO::ConfigUtils::ColorSpaceFingerprints fingerprints; +// OCIO::ConfigUtils::initializeColorSpaceFingerprints(fingerprints, baseConfig); +// +// // std::vector vals = fingerprints.sceneRefTestVals; +// // for (size_t i = 0; i < vals.size(); i++) +// // { +// // std::cout << vals[i] << ", "; +// // } +// // std::cout << "scene\n"; +// // std::vector vals1 = fingerprints.displayRefTestVals; +// // for (size_t i = 0; i < vals1.size(); i++) +// // { +// // std::cout << vals1[i] << ", "; +// // } +// // std::cout << "display\n"; +// // +// // 0.487301, 0.0881323, 0.0741543, 0, 0.300795, 0.700204, 0.167705, 0, 0.13517, 0.139418, 0.679913, 0, 0, 0, 0, 0.5, 0.0393561, 0.0303888, 0.0239345, 0, 0.999998, 1, 1, 1, scene +// +// OCIO::ConstTransformRcPtr inputToBaseGtScene; +// OCIO::ConstTransformRcPtr inputToBaseGtDisplay; +// OCIO::ConfigUtils::initializeRefSpaceConverters(inputToBaseGtScene, +// inputToBaseGtDisplay, +// baseConfig, +// inputConfig); +// +// { +// OCIO::ColorSpaceRcPtr cs = inputConfig->getColorSpace("ACEScct")->createEditableCopy(); +// OCIO::ConfigUtils::updateReferenceColorspace(cs, inputToBaseGtScene); +// const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); +// OCIO_CHECK_EQUAL(name, std::string("ACEScct: ACEScct : AP1")); +// } +// { +// OCIO::ColorSpaceRcPtr cs = inputConfig->getColorSpace("Apple Log")->createEditableCopy(); +// OCIO::ConfigUtils::updateReferenceColorspace(cs, inputToBaseGtScene); +// const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); +// OCIO_CHECK_EQUAL(name, std::string("Apple: Apple Log : Rec.2020")); +// } +// } From 9be8b7c81e0d59b6b28024f714672ec547ee046a Mon Sep 17 00:00:00 2001 From: Doug Walker Date: Mon, 10 Mar 2025 00:04:27 -0400 Subject: [PATCH 07/14] Various merge fixes Signed-off-by: Doug Walker (cherry picked from commit f60e990a7288d2a9790cab16ac7475630f6662eb) Signed-off-by: Doug Walker --- include/OpenColorIO/OpenColorAppHelpers.h | 2 +- src/OpenColorIO/ConfigUtils.cpp | 35 +- src/OpenColorIO/ConfigUtils.h | 5 + .../mergeconfigs/MergeConfigsHelpers.h | 4 +- .../apphelpers/mergeconfigs/OCIOMYaml.cpp | 13 +- .../apphelpers/mergeconfigs/SectionMerger.cpp | 64 +++- tests/cpu/ConfigUtils_tests.cpp | 33 ++ .../apphelpers/MergeConfigsHelpers_tests.cpp | 300 +++++++++++++++++- .../mergeconfigs/merged1/merged1.ociom | 2 +- .../configs/mergeconfigs/merged2/merged.ociom | 2 +- .../configs/mergeconfigs/merged3/input.ocio | 10 +- .../configs/mergeconfigs/merged3/lut1.clf | 6 +- .../configs/mergeconfigs/merged3/merged.ociom | 6 +- .../mergeconfigs/merged3/shot1/lut1.clf | 6 +- .../mergeconfigs/merged3/shot1/lut2.clf | 10 + .../configs/mergeconfigs/merged4/merged.ociom | 2 +- .../configs/mergeconfigs/parser_test.ociom | 2 +- 17 files changed, 453 insertions(+), 49 deletions(-) create mode 100644 tests/data/files/configs/mergeconfigs/merged3/shot1/lut2.clf diff --git a/include/OpenColorIO/OpenColorAppHelpers.h b/include/OpenColorIO/OpenColorAppHelpers.h index 75bd78d1e7..b88a7120cf 100644 --- a/include/OpenColorIO/OpenColorAppHelpers.h +++ b/include/OpenColorIO/OpenColorAppHelpers.h @@ -528,7 +528,7 @@ extern OCIOEXPORT std::ostream & operator<<(std::ostream &, const MixingColorSpa * * Let's take the following OCIOM structure: * - * ociom_version: 2.1 + * ociom_version: 1 * search_path: * - . * - subfolder diff --git a/src/OpenColorIO/ConfigUtils.cpp b/src/OpenColorIO/ConfigUtils.cpp index d826c227a2..74b559b5df 100644 --- a/src/OpenColorIO/ConfigUtils.cpp +++ b/src/OpenColorIO/ConfigUtils.cpp @@ -1223,7 +1223,10 @@ void initializeRefSpaceConverters(ConstTransformRcPtr & inputToBaseGtScene, } } -bool calcColorSpaceFingerprint(std::vector & fingerprint, const ColorSpaceFingerprints & fingerprints, const ConstConfigRcPtr & config, const ConstColorSpaceRcPtr & cs) +bool calcColorSpaceFingerprint(std::vector & fingerprintVals, + const ColorSpaceFingerprints & fingerprints, + const ConstConfigRcPtr & config, + const ConstColorSpaceRcPtr & cs) { bool skipColorSpace = false; // Define a set of (somewhat arbitrary) RGB values to test whether the combined transform is @@ -1269,14 +1272,14 @@ bool calcColorSpaceFingerprint(std::vector & fingerprint, const ColorSpac if (cs->getReferenceSpaceType() == REFERENCE_SPACE_DISPLAY) { - fingerprint = fingerprints.displayRefTestVals; + fingerprintVals = fingerprints.displayRefTestVals; } else { - fingerprint = fingerprints.sceneRefTestVals; + fingerprintVals = fingerprints.sceneRefTestVals; } - const size_t n = fingerprint.size(); - PackedImageDesc desc( &fingerprint[0], (long) n / 4, 1, CHANNEL_ORDERING_RGBA ); + const size_t n = fingerprintVals.size(); + PackedImageDesc desc( &fingerprintVals[0], (long) n / 4, 1, CHANNEL_ORDERING_RGBA ); ConstCPUProcessorRcPtr cpu = p->getOptimizedCPUProcessor(OPTIMIZATION_NONE); cpu->apply(desc); @@ -1292,17 +1295,20 @@ void initializeTestVals(ColorSpaceFingerprints & fingerprints, const ConstConfig // for the most common scene-referred and display-referred reference spaces. std::vector ACESvals = { - 0.401273353908f, 0.089901034233f, 0.025611641641f, 0.f, // lin_rec709 {0.9, 0.01, 0.01} - 0.350859941355f, 0.733961091587f, 0.109276432439f, 0.f, // lin_rec709 {0.1, 0.09, 0.01} - 0.171696591718f, 0.104272268468f, 0.786227391453f, 0.f, // lin_rec709 {0.1, 0.02, 0.09} + 0.408933127871f, 0.106169822808f, 0.027842572707f, 0.f, // lin_rec709 {0.9, 0.03, 0.01} + 0.374615373650f, 0.739417755017f, 0.118862613721f, 0.f, // lin_rec709 {0.06, 0.9, 0.02} + 0.171696591718f, 0.104272268468f, 0.786227391453f, 0.f, // lin_rec709 {0.01, 0.02, 0.9} 0.f , 0.f , 0.f , 0.5f, 0.037018876439f, 0.030827687576f, 0.021641700645f, 0.f, // lin_rec709 {0.05, 0.03, 0.02} 1.f , 1.f , 1.f , 1.f }; std::vector XYZvals = { - 0.376532370617f, 0.199248715226f, 0.028095006164f, 0.f, // lin_rec709 {0.9, 0.01, 0.01} - 0.327754621322f, 0.646500124103f, 0.116973931525f, 0.f, // lin_rec709 {0.1, 0.09, 0.01} - 0.173708304342f, 0.081402847459f, 0.858056140808f, 0.f, // lin_rec709 {0.1, 0.02, 0.09} +// 0.376532370617f, 0.199248715226f, 0.028095006164f, 0.f, // lin_rec709 {0.9, 0.01, 0.01} +// 0.327754621322f, 0.646500124103f, 0.116973931525f, 0.f, // lin_rec709 {0.01, 0.9, 0.01} + // Adjusted to keep it inside both Rec.601 and Rec.601 PAL. + 0.383684057405f, 0.213552088801f, 0.030478901760f, 0.f, // lin_rec709 {0.9, 0.03, 0.01} + 0.350178969169f, 0.657853997550f, 0.127445793983f, 0.f, // lin_rec709 {0.06, 0.9, 0.02} + 0.173708304342f, 0.081402847459f, 0.858056140808f, 0.f, // lin_rec709 {0.01, 0.02, 0.9} 0.f , 0.f , 0.f , 0.5f, 0.034956685913f, 0.033530856964f, 0.023553027375f, 0.f, // lin_rec709 {0.05, 0.03, 0.02} 0.950455927052f, 1.f , 1.089057750760f, 1.f }; @@ -1436,6 +1442,13 @@ void initializeColorSpaceFingerprints(ColorSpaceFingerprints & fingerprints, con // Don't put data color spaces in the collection. continue; } + if (cs->hasCategory("is-unique")) + { + // Don't fingerprint color spaces with this category. + // Never want to replace them. +// TODO: May always want to fingerprint everything -- move this to the merge. + continue; + } ConstTransformRcPtr tFrom = cs->getTransform(COLORSPACE_DIR_FROM_REFERENCE); ConstTransformRcPtr tTo = cs->getTransform(COLORSPACE_DIR_TO_REFERENCE); diff --git a/src/OpenColorIO/ConfigUtils.h b/src/OpenColorIO/ConfigUtils.h index a26af390bc..2126da9a91 100644 --- a/src/OpenColorIO/ConfigUtils.h +++ b/src/OpenColorIO/ConfigUtils.h @@ -66,6 +66,11 @@ struct ColorSpaceFingerprints std::vector displayRefTestVals; }; +bool calcColorSpaceFingerprint(std::vector & fingerprintVals, + const ColorSpaceFingerprints & fingerprints, + const ConstConfigRcPtr & config, + const ConstColorSpaceRcPtr & cs); + void initializeColorSpaceFingerprints(ColorSpaceFingerprints & fingerprints, const ConstConfigRcPtr & config); diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h index b69a31e9a1..4edeb3a18f 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h +++ b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h @@ -141,8 +141,8 @@ class ConfigMerger::Impl std::string m_workingDir; // Version for the .ociom file format. - unsigned int m_majorVersion; - unsigned int m_minorVersion; + unsigned int m_majorVersion = 1u; + unsigned int m_minorVersion = 0u; // Vector of merge parameter objects, each one corresponding to one merge. std::vector m_mergeParams; diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp index 76b0e3be74..b22674c736 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp +++ b/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp @@ -69,7 +69,7 @@ inline void OCIOMYaml::throwValueError(const std::string & nodeName, std::ostringstream os; os << "At line " << (key.Mark().line + 1) - << ", the value parsing of the property '" << keyName + << ", the value of the property '" << keyName << "' from '" << nodeName << "' failed: " << msg; throw Exception(os.str().c_str()); @@ -330,6 +330,11 @@ void OCIOMYaml::load(const YAML::Node& node, ConfigMergerRcPtr & merger, const c merger->setMajorVersion(std::stoi(results[0].c_str())); merger->setMinorVersion(std::stoi(results[1].c_str())); } + if (merger->getMajorVersion() > 1u || merger->getMinorVersion() > 0u) + { + throwValueError(it->second.Tag(), it->first, + "The highest supported OCIOM file version is 1.0."); + } } else if (key == "search_path") { @@ -485,10 +490,10 @@ inline void save(YAML::Emitter & out, const ConfigMerger & merger) std::stringstream ss; const unsigned parserMajorVersion = merger.getMajorVersion(); ss << parserMajorVersion; - if (merger.getMinorVersion() != 0) - { +// if (merger.getMinorVersion() != 0) +// { ss << "." << merger.getMinorVersion(); - } +// } out << YAML::Block; out << YAML::BeginMap; diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp index d5f401b5f4..6901042ccb 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp +++ b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp @@ -38,6 +38,7 @@ void splitActiveList(const char * list, StringUtils::StringVec & result) { if (list && *list) { +// FIXME: Need to handle quoted substrings. result = StringUtils::Split(list, ','); } } @@ -226,11 +227,15 @@ void GeneralMerger::handleInputOnly() m_mergedConfig->setDescription(m_inputConfig->getDescription()); } + // Use the higher value for ocio_profile_version. + // Note that the default strategy is used for the GeneralMerger but other strategies + // may be used for other sections of the config and so always use the higher of the + // two config versions. setMergedConfigVersion(m_mergedConfig, m_inputConfig->getMajorVersion(), m_inputConfig->getMinorVersion(), - 0u, // ignore base - 0u); + m_baseConfig->getMajorVersion(), + m_baseConfig->getMinorVersion()); double rgb[3]; m_inputConfig->getDefaultLumaCoefs(rgb); @@ -263,9 +268,13 @@ void GeneralMerger::handleBaseOnly() m_mergedConfig->setDescription(m_baseConfig->getDescription()); } + // Use the higher value for ocio_profile_version. + // Note that the default strategy is used for the GeneralMerger but other strategies + // may be used for other sections of the config and so always use the higher of the + // two config versions. setMergedConfigVersion(m_mergedConfig, - 0u, // ignore input - 0u, + m_inputConfig->getMajorVersion(), + m_inputConfig->getMinorVersion(), m_baseConfig->getMajorVersion(), m_baseConfig->getMinorVersion()); @@ -1178,6 +1187,8 @@ void DisplayViewMerger::processDisplays(const ConstConfigRcPtr & first, // the second config. Want to add it as the same type of view. if (viewIsShared(second, dispName, displayDefinedView)) { + // Note that this may change the order in a way that does not follow + // the preference of input-first or base-first. m_mergedConfig->addDisplaySharedView(dispName, displayDefinedView); } else @@ -2300,7 +2311,48 @@ void ColorspacesMerger::processSearchPaths() const return; } - if (m_params->isInputFirst()) +// TODO: Should the strategy determine which path should go first? +// E.g., if preferInput, give the input paths priority in the search. + +// if (m_params->isInputFirst()) +// { +// m_mergedConfig->clearSearchPaths(); +// // Add all from input config. +// for (int i = 0; i < m_inputConfig->getNumSearchPaths(); i++) +// { +// m_mergedConfig->addSearchPath(m_inputConfig->getSearchPath(i)); +// } +// +// // Only add the new ones from the base config. +// for (int i = 0; i < m_baseConfig->getNumSearchPaths(); i++) +// { +// if (!hasSearchPath(m_inputConfig, m_baseConfig->getSearchPath(i))) +// { +// m_mergedConfig->addSearchPath(m_baseConfig->getSearchPath(i)); +// } +// } +// } +// else +// { +// // NB: The m_mergedConfig is initialized with the contents of the m_baseConfig. +// +// for (int i = 0; i < m_inputConfig->getNumSearchPaths(); i++) +// { +// if (!hasSearchPath(m_baseConfig, m_inputConfig->getSearchPath(i))) +// { +// m_mergedConfig->addSearchPath(m_inputConfig->getSearchPath(i)); +// } +// } +// } + + // Ignoring isInputFirst for the ordering of search paths because it seems that it + // really should be driven by the strategy. E.g., if both base and input have a "luts" + // directory, want to be looking in the right one. + + // But more work is needed here. Absolute paths should be set up for input since + // the working dir is from the base config. + + if (m_params->getColorspaces() == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT) { m_mergedConfig->clearSearchPaths(); // Add all from input config. @@ -2320,7 +2372,7 @@ void ColorspacesMerger::processSearchPaths() const } else { - // NB: The m_mergecConfig is initialized with the contents of the m_baseConfig. + // NB: The m_mergedConfig is initialized with the contents of the m_baseConfig. for (int i = 0; i < m_inputConfig->getNumSearchPaths(); i++) { diff --git a/tests/cpu/ConfigUtils_tests.cpp b/tests/cpu/ConfigUtils_tests.cpp index 57d6c77a35..af805c41ab 100644 --- a/tests/cpu/ConfigUtils_tests.cpp +++ b/tests/cpu/ConfigUtils_tests.cpp @@ -697,6 +697,22 @@ inactive_colorspaces: [] children: - ! {matrix: [ 0.695452241357, 0.140678696470, 0.163869062172, 0, 0.044794563372, 0.859671118456, 0.095534318172, 0, -0.005525882558, 0.004025210306, 1.001500672252, 0, 0, 0, 0, 1 ]} # - ! {style: UTILITY - ACES-AP0_to_CIE-XYZ-D65_BFD} + + - ! + name: Rec.601 - Display + isdata: false + from_display_reference: ! + children: + - ! {matrix: [3.50600328272467, -1.73979072630283, -0.544058268362742, 0, -1.06904755985382, 1.97777888272879, 0.0351714193371952, 0, 0.0563065917341277, -0.196975654820772, 1.04995232821873, 0, 0, 0, 0, 1]} + - ! {value: 2.4, style: mirror, direction: inverse} + + - ! + name: Rec.601 (PAL) - Display + isdata: false + from_display_reference: ! + children: + - ! {matrix: [3.06336109008327, -1.39339017490737, -0.47582373799753, 0, -0.96924363628088, 1.87596750150772, 0.0415550574071756, 0, 0.0678610475535669, -0.228799269620496, 1.06908961801603, 0, 0, 0, 0, 1]} + - ! {value: 2.4, style: mirror, direction: inverse} )" }; // >>> cs.build_conversion_matrix('ap0','rec 709','cat02').T @@ -808,6 +824,23 @@ inactive_colorspaces: [] const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); OCIO_CHECK_EQUAL(name, std::string("")); } + + // Validate that the fingerprints for the smallest likely gamuts are positive. + std::vector fingerprintVals; + OCIO_CHECK_ASSERT(!OCIO::ConfigUtils::calcColorSpaceFingerprint(fingerprintVals, fingerprints, inputConfig, + inputConfig->getColorSpace("Rec.601 - Display"))); + for (size_t i = 0; i < fingerprintVals.size(); i++) + { + OCIO_CHECK_ASSERT(fingerprintVals[i] >= 0.); + } + + OCIO_CHECK_ASSERT(!OCIO::ConfigUtils::calcColorSpaceFingerprint(fingerprintVals, fingerprints, inputConfig, + inputConfig->getColorSpace("Rec.601 (PAL) - Display"))); + for (size_t i = 0; i < fingerprintVals.size(); i++) + { + OCIO_CHECK_ASSERT(fingerprintVals[i] >= 0.); + } + } // OCIO_ADD_TEST(MergeConfigs, config_utils_find_equivalent_colorspace2) diff --git a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp index 80a0d5cc81..6f172eb159 100644 --- a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp +++ b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp @@ -178,7 +178,16 @@ OCIO_ADD_TEST(MergeConfigs, ociom_parser) }; const std::string ociomPath = pystring::os::path::normpath(pystring::os::path::join(paths)); - OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); + // Ensure version is initialized correctly. + OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO_CHECK_EQUAL(merger->getMajorVersion(), 1); + OCIO_CHECK_EQUAL(merger->getMinorVersion(), 0); + + // Test parsing an OCIOM file. + merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); + + OCIO_CHECK_EQUAL(merger->getMajorVersion(), 1); + OCIO_CHECK_EQUAL(merger->getMinorVersion(), 0); // The parser_test.ociom contains only one merge. OCIO::ConstConfigMergingParametersRcPtr p = merger->getParams(0); @@ -189,6 +198,7 @@ OCIO_ADD_TEST(MergeConfigs, ociom_parser) OCIO_CHECK_EQUAL(std::string(p->getBaseConfigName()), std::string("base0.ocio")); OCIO_CHECK_EQUAL(std::string(p->getInputConfigName()), std::string("input0.ocio")); + OCIO_CHECK_EQUAL(std::string(p->getOutputName()), std::string("Merge1")); OCIO_CHECK_EQUAL(std::string(p->getInputFamilyPrefix()), std::string("abc")); OCIO_CHECK_EQUAL(std::string(p->getBaseFamilyPrefix()), std::string("def")); @@ -228,7 +238,63 @@ OCIO_ADD_TEST(MergeConfigs, ociom_parser) OCIO_CHECK_EQUAL(p->getNamedTransforms(), MergeStrategy::STRATEGY_PREFER_BASE); } -//TODOCED Add test for OCIOM writer +OCIO_ADD_TEST(MergeConfigs, ociom_serialization) +{ + std::vector paths = { + std::string(OCIO::GetTestFilesDir()), + std::string("configs"), + std::string("mergeconfigs"), + std::string("parser_test.ociom") + }; + const std::string ociomPath = pystring::os::path::normpath(pystring::os::path::join(paths)); + OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); + + std::ostringstream oss; + merger->serialize(oss); + + constexpr const char * REF { +R"(ociom_version: 1.0 +search_path: + - . +merge: + Merge1: + base: base0.ocio + input: input0.ocio + options: + input_family_prefix: abc + base_family_prefix: def + input_first: true + error_on_conflict: false + default_strategy: InputOnly + avoid_duplicates: true + assume_common_reference_space: false + overrides: + name: my merge + description: my desc + search_path: abc + environment: + test: valueOther + test1: value123 + active_displays: [D1, D2] + active_views: [V1, V2] + inactive_colorspaces: [I1, I2] + params: + roles: + strategy: PreferInput + file_rules: + strategy: PreferBase + display-views: + strategy: InputOnly + looks: + strategy: BaseOnly + colorspaces: + strategy: Remove + named_transform: + strategy: PreferBase)" }; + + std::istringstream rss(REF); + OCIO_CHECK_EQUAL(oss.str(), rss.str()); +} OCIO_ADD_TEST(MergeConfigs, ociom_parser_no_overrides) { @@ -2039,7 +2105,8 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section) std::vector expectedValues = { "differentValue", "value1", "value3" }; compareEnvironmentVar(mergedConfig, expectedNames, expectedValues, __LINE__); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getSearchPath()), std::string(".:abc:def")); + // Note that the search path ignores InputFirst, it works based on the strategy only. + OCIO_CHECK_EQUAL(std::string(mergedConfig->getSearchPath()), std::string(".:def:abc")); OCIO_CHECK_EQUAL(std::string(mergedConfig->getInactiveColorSpaces()), "sRGB - Texture, sRGB - Display, ACEScg, ACES2065-1"); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 6); @@ -2097,7 +2164,8 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section) std::vector expectedValues = { "value", "value1", "value3" }; compareEnvironmentVar(mergedConfig, expectedNames, expectedValues, __LINE__); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getSearchPath()), std::string(".:def:abc")); + // Note that the search path ignores InputFirst, it works based on the strategy only. + OCIO_CHECK_EQUAL(std::string(mergedConfig->getSearchPath()), std::string(".:abc:def")); OCIO_CHECK_EQUAL(std::string(mergedConfig->getInactiveColorSpaces()), "ACES2065-1, sRGB - Display, sRGB - Texture, ACEScg"); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 5); @@ -5588,7 +5656,7 @@ inactive_colorspaces: [ACES2065-1] } } */ -std::cout << "merge2\n"; +//std::cout << "merge3\n"; // Test with external LUT files. { @@ -5604,8 +5672,11 @@ std::cout << "merge2\n"; // PreferInput, Input first { OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); - merger->getParams(0)->setAssumeCommonReferenceSpace(true); - OCIO::ConstConfigMergerRcPtr newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); +// OCIO::ConstConfigMergerRcPtr newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); + OCIO::ConstConfigMergerRcPtr newMerger; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&newMerger, &merger]() { newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); }, + "Color space 'raw' will replace a color space in the base config."); OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); // std::ostringstream oss; // mergedConfig->serialize(oss); @@ -5617,7 +5688,7 @@ std::cout << "merge2\n"; auto tf = cs->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); auto ftf = OCIO::DynamicPtrCast(tf); OCIO_REQUIRE_ASSERT(ftf); - OCIO_CHECK_EQUAL(ftf->getSrc(), std::string("lut1.clf")); + OCIO_CHECK_EQUAL(ftf->getSrc(), std::string("shot1/lut1.clf")); OCIO_CHECK_NO_THROW(mergedConfig->getProcessor(ftf)) } { @@ -5628,7 +5699,7 @@ std::cout << "merge2\n"; } } -std::cout << "merge3\n"; +//std::cout << "merge3\n"; // Test that a merge could go wrong if the search_paths are merged with a different strategy // than the other sections. @@ -5647,7 +5718,7 @@ std::cout << "merge3\n"; { OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); - merger->getParams(0)->setAssumeCommonReferenceSpace(true); +// merger->getParams(0)->setAssumeCommonReferenceSpace(true); // Changing the strategy for colorspace merger to BASE ONLY. // This will break the looks "shot_look" (from input) as it needs the search paths // from the input config. (search_paths are managed by the colorspace merger). @@ -5656,6 +5727,8 @@ std::cout << "merge3\n"; OCIO::ConstConfigMergerRcPtr newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); + OCIO_CHECK_ASSERT(!mergedConfig->getConfigIOProxy()); + auto look = mergedConfig->getLook("shot_look"); auto ltf = look->getTransform(); @@ -5669,7 +5742,7 @@ std::cout << "merge3\n"; } } -std::cout << "merge4\n"; +//std::cout << "merge4\n"; // Test with a built-in config. { @@ -5695,6 +5768,211 @@ std::cout << "merge4\n"; // OCIO_CHECK_EQUAL(std::string(mergedConfig->getCacheID()), std::string(bConfig->getCacheID())); } } +} + +OCIO_ADD_TEST(MergeConfigs, merges_with_ocioz_file) +{ + std::vector pathsLinux = { + std::string(OCIO::GetTestFilesDir()), + std::string("configs"), + std::string("context_test1"), + std::string("context_test1_linux.ocioz") + }; + static const std::string archivePathLinux = pystring::os::path::normpath( + pystring::os::path::join(pathsLinux) + ); + OCIO::ConstConfigRcPtr baseConfig; + OCIO_CHECK_NO_THROW(baseConfig = OCIO::Config::CreateFromFile(archivePathLinux.c_str())); + + std::vector pathsInput = { + std::string(OCIO::GetTestFilesDir()), + std::string("configs"), + std::string("mergeconfigs"), + std::string("merged3"), + std::string("input.ocio") + }; + static const std::string configPathInput = pystring::os::path::normpath( + pystring::os::path::join(pathsInput) + ); + OCIO::ConstConfigRcPtr inputConfig; + OCIO_CHECK_NO_THROW(inputConfig = OCIO::Config::CreateFromFile(configPathInput.c_str())); + + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + params->setInputFirst(false); + MergeStrategy strategy = MergeStrategy::STRATEGY_PREFER_INPUT; + params->setRoles(strategy); + params->setColorspaces(strategy); + params->setNamedTransforms(strategy); + params->setDefaultStrategy(strategy); + params->setInputFamilyPrefix("Input/"); + params->setBaseFamilyPrefix("Base/"); + params->setAssumeCommonReferenceSpace(true); + params->setAvoidDuplicates(false); + +// OCIO::ConfigRcPtr mergedConfig = OCIO::ConfigMergingHelpers::MergeConfigs(params, baseConfig, inputConfig); + OCIO::ConfigRcPtr mergedConfig; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&mergedConfig, ¶ms, &baseConfig, &inputConfig]() { mergedConfig = OCIO::ConfigMergingHelpers::MergeConfigs(params, baseConfig, inputConfig); }, + "Color space 'reference' will replace a color space in the base config.", + "Color space 'raw' will replace a color space in the base config.", + "Color space 'plain_lut1_cs' will replace a color space in the base config.", + "Color space 'shot1_lut1_cs' will replace a color space in the base config."); + +// OCIO::ConfigRcPtr mergedConfig; +// checkForLogOrException(LOG_TYPE_WARNING, __LINE__, +// // [&newMerger, &merger]() { newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); }, +// [&mergedConfig, ¶ms, &baseConfig, &inputConfig]() +// { mergedConfig = OCIO::ConfigMergingHelpers::MergeConfigs(params, baseConfig, inputConfig); }, +// "The Input config contains a value that would override the Base config: file_rules: Default"); + + +// FIXME: Add a test to check this result. +// std::ostringstream ossResult; +// mergedConfig->serialize(ossResult); +// std::cout << ossResult.str() << "\n"; + +// std::ostringstream oss; +// mergedConfig->serialize(oss); +// std::cout << oss.str() << "\n"; + + // The working dir is empty. + OCIO_CHECK_EQUAL(mergedConfig->getWorkingDir(), std::string("")); +//std::cout << "Working dir: " << mergedConfig->getWorkingDir() << "\n"; + // The configIOProxy is not NULL. + OCIO_CHECK_ASSERT(mergedConfig->getConfigIOProxy()); +//std::cout << "IOProxy: " << mergedConfig->getConfigIOProxy() << "\n"; + + OCIO::ContextRcPtr ctx = mergedConfig->getCurrentContext()->createEditableCopy(); + double mat[16] = { 0., 0., 0., 0., + 0., 0., 0., 0., + 0., 0., 0., 0., + 0., 0., 0., 0. }; + + // This is resolved in the OCIOZ base. + { + // Note: the $SHOT = shot4 search path takes precedence for this color space. + OCIO::ConstProcessorRcPtr processor = mergedConfig->getProcessor(ctx, "plain_lut1_cs", "reference"); + OCIO::ConstTransformRcPtr tr = processor->createGroupTransform()->getTransform(0); + auto mtx = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(mtx); + mtx->getMatrix(mat); + OCIO_CHECK_EQUAL(mat[0], 40.); // is 40 in the base config, 20 in input + } + { + OCIO::ConstProcessorRcPtr processor = mergedConfig->getProcessor(ctx, "shot1_lut1_cs", "reference"); + OCIO::ConstTransformRcPtr tr = processor->createGroupTransform()->getTransform(0); + auto mtx = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(mtx); + mtx->getMatrix(mat); + OCIO_CHECK_EQUAL(mat[0], 10.); // is 10 in the base config, 100 in input + } + { + // Will try to resolve it using relative paths and won't find it. + OCIO_CHECK_THROW(mergedConfig->getProcessor(ctx, "shot1_lut2_cs", "reference"), OCIO::Exception); + } + + // Add an absolute search path for the input config. + std::vector pathsInput1 = { + std::string(OCIO::GetTestFilesDir()), + std::string("configs"), + std::string("mergeconfigs"), + std::string("merged3") + }; + static const std::string searchPathInput = pystring::os::path::normpath( + pystring::os::path::join(pathsInput1) + ); +// std::cout << "added absolute search path\n"; + ctx->clearSearchPaths(); + ctx->addSearchPath(searchPathInput.c_str()); + for (int i = 0; i < mergedConfig->getNumSearchPaths(); i++) + { + ctx->addSearchPath(mergedConfig->getSearchPath(i)); + } + + { + OCIO::ConstProcessorRcPtr processor = mergedConfig->getProcessor(ctx, "shot1_lut2_cs", "reference"); + OCIO::ConstTransformRcPtr tr = processor->createGroupTransform()->getTransform(0); + auto mtx = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(mtx); + mtx->getMatrix(mat); + OCIO_CHECK_EQUAL(mat[0], 42.); // doesn't exist in the base config + } + + // FIXME: The next test won't work without this. Is that expected that you need to clear + // the cache after adding a search path, or is there a bug involving the cacheID of processors + // when OCIOZ is being used? + mergedConfig->clearProcessorCache(); + + { + OCIO::ConstProcessorRcPtr processor = mergedConfig->getProcessor(ctx, "shot1_lut1_cs", "reference"); + OCIO::ConstTransformRcPtr tr = processor->createGroupTransform()->getTransform(0); + auto mtx = OCIO::DynamicPtrCast(tr); + OCIO_REQUIRE_ASSERT(mtx); + mtx->getMatrix(mat); + OCIO_CHECK_EQUAL(mat[0], 100.); // is 10 in the base config, 100 in input + } + +// +// std::istringstream resultIss; +// resultIss.str(RESULT); +// OCIO::ConstConfigRcPtr resultConfig = OCIO::Config::CreateFromStream(resultIss); +// std::ostringstream ossResult; +// resultConfig->serialize(ossResult); +// +// //Testing the string of each config +// OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); + + + + + + + +// auto setupBasics = [](OCIO::ConfigMergerRcPtr & merger, MergeStrategy strategy) -> OCIO::ConfigMergingParametersRcPtr +// { +// OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); +// merger->addParams(params); +// // Note that these tests run several of the mergers. +// // Need to run the color space merger too, since that affects how the named transform +// // merger will work (in terms of avoiding conflicts with color space names). +// merger->getParams(0)->setRoles(strategy); +// merger->getParams(0)->setColorspaces(strategy); +// merger->getParams(0)->setNamedTransforms(strategy); +// merger->getParams(0)->setDefaultStrategy(strategy); +// +// merger->getParams(0)->setInputFamilyPrefix("Input/"); +// merger->getParams(0)->setBaseFamilyPrefix("Base/"); +// +// merger->getParams(0)->setAssumeCommonReferenceSpace(true); +// merger->getParams(0)->setAvoidDuplicates(false); +// merger->getParams(0)->setInputFirst(true); +// +// return params; +// }; +// +// { +// OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); +// auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); +// +// OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); +// OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; +// checkForLogOrException(LOG_TYPE_WARNING, __LINE__, +// [&options]() { OCIO::ColorspacesMerger(options).merge(); }, +// "Equivalent input color space 'lin_3' replaces 'ACES2065-1' in the base config, preserving aliases."); +// checkForLogOrException(LOG_TYPE_WARNING, __LINE__, +// [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, +// "Named transform 'view_2' was not merged as there's a color space alias with that name."); +// +// OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 3); +// +// OCIO::ConstNamedTransformRcPtr nt = nullptr; +// nt = checkNamedTransform(mergedConfig, "nt_both", 0, __LINE__); +// OCIO_CHECK_EQUAL(nt->getNumAliases(), 1); +// OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("nametr")); +// OCIO_CHECK_EQUAL(nt->getFamily(), std::string("Input@")); +// OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from input")); +// } + } // Test with an OCIOZ archive // { diff --git a/tests/data/files/configs/mergeconfigs/merged1/merged1.ociom b/tests/data/files/configs/mergeconfigs/merged1/merged1.ociom index 9ca3d0d483..a578e8adcd 100644 --- a/tests/data/files/configs/mergeconfigs/merged1/merged1.ociom +++ b/tests/data/files/configs/mergeconfigs/merged1/merged1.ociom @@ -1,4 +1,4 @@ -ociom_version: 2.1 +ociom_version: 1 search_path: "." merge: diff --git a/tests/data/files/configs/mergeconfigs/merged2/merged.ociom b/tests/data/files/configs/mergeconfigs/merged2/merged.ociom index b0db1537e6..9201afdf3f 100644 --- a/tests/data/files/configs/mergeconfigs/merged2/merged.ociom +++ b/tests/data/files/configs/mergeconfigs/merged2/merged.ociom @@ -1,4 +1,4 @@ -ociom_version: 2.1 +ociom_version: 1.0 search_path: "." # This OCIOM file is used to test multiple merges. diff --git a/tests/data/files/configs/mergeconfigs/merged3/input.ocio b/tests/data/files/configs/mergeconfigs/merged3/input.ocio index 6c6b14dec2..b4f5976d30 100644 --- a/tests/data/files/configs/mergeconfigs/merged3/input.ocio +++ b/tests/data/files/configs/mergeconfigs/merged3/input.ocio @@ -33,6 +33,14 @@ colorspaces: name: raw isdata: true + - ! + name: shot1_lut2_cs + to_reference: ! {src: shot1/lut2.clf} + + - ! + name: plain_lut1_cs + to_scene_reference: ! {src: lut1.clf} + - ! name: shot1_lut1_cs - to_reference: ! {src: lut1.clf} \ No newline at end of file + to_scene_reference: ! {src: shot1/lut1.clf} diff --git a/tests/data/files/configs/mergeconfigs/merged3/lut1.clf b/tests/data/files/configs/mergeconfigs/merged3/lut1.clf index d948a1e5dd..3288a30c04 100644 --- a/tests/data/files/configs/mergeconfigs/merged3/lut1.clf +++ b/tests/data/files/configs/mergeconfigs/merged3/lut1.clf @@ -2,9 +2,9 @@ -5 0 0 -0 5 0 -0 0 5 +55 0 0 +0 55 0 +0 0 55 \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/merged3/merged.ociom b/tests/data/files/configs/mergeconfigs/merged3/merged.ociom index bca325cfe8..64fd4e43c4 100644 --- a/tests/data/files/configs/mergeconfigs/merged3/merged.ociom +++ b/tests/data/files/configs/mergeconfigs/merged3/merged.ociom @@ -1,4 +1,4 @@ -ociom_version: 2.1 +ociom_version: 1.0 search_path: "." # This OCIOM file is used to test that FileTransform's @@ -13,8 +13,8 @@ merge: input_first: true error_on_conflict: false default_strategy: PreferInput - avoid_duplicates: true - assume_common_reference_space: false + avoid_duplicates: false + assume_common_reference_space: true overrides: name: Merged1 description: Basic merge with default strategy diff --git a/tests/data/files/configs/mergeconfigs/merged3/shot1/lut1.clf b/tests/data/files/configs/mergeconfigs/merged3/shot1/lut1.clf index 4750b14b38..2a432852e9 100644 --- a/tests/data/files/configs/mergeconfigs/merged3/shot1/lut1.clf +++ b/tests/data/files/configs/mergeconfigs/merged3/shot1/lut1.clf @@ -2,9 +2,9 @@ -10 0 0 -0 10 0 -0 0 10 +100 0 0 +0 100 0 +0 0 100 \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/merged3/shot1/lut2.clf b/tests/data/files/configs/mergeconfigs/merged3/shot1/lut2.clf new file mode 100644 index 0000000000..e0b154defb --- /dev/null +++ b/tests/data/files/configs/mergeconfigs/merged3/shot1/lut2.clf @@ -0,0 +1,10 @@ + + + + +42 0 0 +0 42 0 +0 0 42 + + + \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/merged4/merged.ociom b/tests/data/files/configs/mergeconfigs/merged4/merged.ociom index e8e27a07e2..14cf8606bc 100644 --- a/tests/data/files/configs/mergeconfigs/merged4/merged.ociom +++ b/tests/data/files/configs/mergeconfigs/merged4/merged.ociom @@ -1,4 +1,4 @@ -ociom_version: 2.1 +ociom_version: 1.0 search_path: "." merge: diff --git a/tests/data/files/configs/mergeconfigs/parser_test.ociom b/tests/data/files/configs/mergeconfigs/parser_test.ociom index bbdcbee8e4..17254cd250 100644 --- a/tests/data/files/configs/mergeconfigs/parser_test.ociom +++ b/tests/data/files/configs/mergeconfigs/parser_test.ociom @@ -44,4 +44,4 @@ merge: strategy: Remove named_transform: - strategy: PreferBase \ No newline at end of file + strategy: PreferBase From 94ae145ef680b63684f08be7d5ac42b78be36f9a Mon Sep 17 00:00:00 2001 From: Doug Walker Date: Sun, 3 Aug 2025 23:04:22 -0400 Subject: [PATCH 08/14] Add more tests and clean-up Signed-off-by: Doug Walker --- include/OpenColorIO/OpenColorAppHelpers.h | 2 +- include/OpenColorIO/OpenColorIO.h | 42 - include/OpenColorIO/OpenColorTypes.h | 38 - src/OpenColorIO/ColorSpaceSet.cpp | 25 +- src/OpenColorIO/Config.cpp | 56 +- src/OpenColorIO/ConfigUtils.cpp | 170 +- src/OpenColorIO/ConfigUtils.h | 1 - src/OpenColorIO/Exception.cpp | 38 - .../mergeconfigs/MergeConfigsHelpers.cpp | 34 +- .../mergeconfigs/MergeConfigsHelpers.h | 20 +- .../apphelpers/mergeconfigs/OCIOMYaml.cpp | 15 +- .../apphelpers/mergeconfigs/SectionMerger.cpp | 633 +------- .../apphelpers/mergeconfigs/SectionMerger.h | 112 +- src/apps/ociomergeconfigs/main.cpp | 26 +- tests/cpu/ConfigUtils_tests.cpp | 130 +- tests/cpu/Config_tests.cpp | 2 +- .../apphelpers/MergeConfigsHelpers_tests.cpp | 1437 ++++++++--------- .../configs/mergeconfigs/base_config.yaml | 1 + .../mergeconfigs/default_strategy.ociom | 25 - .../configs/mergeconfigs/input_config.yaml | 3 +- .../configs/mergeconfigs/merged1/base1.ocio | 3 + .../configs/mergeconfigs/merged1/input1.ocio | 10 +- .../configs/mergeconfigs/merged2/base.ocio | 4 +- .../configs/mergeconfigs/merged2/input.ocio | 3 +- .../configs/mergeconfigs/merged2/merged.ociom | 17 +- .../configs/mergeconfigs/merged3/base.ocio | 1 + .../configs/mergeconfigs/merged3/input.ocio | 7 - 27 files changed, 935 insertions(+), 1920 deletions(-) delete mode 100644 tests/data/files/configs/mergeconfigs/default_strategy.ociom diff --git a/include/OpenColorIO/OpenColorAppHelpers.h b/include/OpenColorIO/OpenColorAppHelpers.h index b88a7120cf..05b888d258 100644 --- a/include/OpenColorIO/OpenColorAppHelpers.h +++ b/include/OpenColorIO/OpenColorAppHelpers.h @@ -587,7 +587,7 @@ class OCIOEXPORT ConfigMergingParameters // not used in this case. If the names match, the item is removed, even if the content // is not identical. STRATEGY_REMOVE, - STRATEGY_UNSET + STRATEGY_UNSPECIFIED }; // Default object diff --git a/include/OpenColorIO/OpenColorIO.h b/include/OpenColorIO/OpenColorIO.h index 2159a06b94..ac4b2627bd 100644 --- a/include/OpenColorIO/OpenColorIO.h +++ b/include/OpenColorIO/OpenColorIO.h @@ -108,48 +108,6 @@ class OCIOEXPORT ExceptionMissingFile : public Exception ~ExceptionMissingFile(); }; -/** - * \brief An exception class for errors detected while adding a colorspace to a config object. - */ -class OCIOEXPORT ExceptionAddColorspace : public Exception -{ -public: - ExceptionAddColorspace() = delete; - /// Constructor that takes a string as the exception message. - explicit ExceptionAddColorspace(const char *, AddColorspaceError errorCode); - /// Constructor that takes an existing exception. - ExceptionAddColorspace(const ExceptionAddColorspace &); - ExceptionAddColorspace & operator= (const ExceptionAddColorspace &) = delete; - - AddColorspaceError getErrorCode() const noexcept; - - ~ExceptionAddColorspace(); - -private: - AddColorspaceError m_errorCode; -}; - -/** - * \brief An exception class for errors detected while adding a named transform to a config object. - */ -class OCIOEXPORT ExceptionAddNamedTransform: public Exception -{ -public: - ExceptionAddNamedTransform() = delete; - /// Constructor that takes a string as the exception message. - explicit ExceptionAddNamedTransform(const char *, AddNamedTransformError errorCode); - /// Constructor that takes an existing exception. - ExceptionAddNamedTransform(const ExceptionAddNamedTransform &); - ExceptionAddNamedTransform & operator= (const ExceptionAddNamedTransform &) = delete; - - AddNamedTransformError getErrorCode() const noexcept; - - ~ExceptionAddNamedTransform(); - -private: - AddNamedTransformError m_errorCode; -}; - // Restore default warning behaviour for Visual Studio. #ifdef _MSC_VER #pragma warning( pop ) diff --git a/include/OpenColorIO/OpenColorTypes.h b/include/OpenColorIO/OpenColorTypes.h index 9cf7fc7343..bb5fe5afab 100644 --- a/include/OpenColorIO/OpenColorTypes.h +++ b/include/OpenColorIO/OpenColorTypes.h @@ -692,44 +692,6 @@ enum ProcessorCacheFlags : unsigned int PROCESSOR_CACHE_DEFAULT = (PROCESSOR_CACHE_ENABLED | PROCESSOR_CACHE_SHARE_DYN_PROPERTIES) }; -// Provides codes for errors if there is any problem when a colorspace is added to a config. -enum AddColorspaceError -{ - ADD_CS_ERROR_NONE = 0, - - ADD_CS_ERROR_EMPTY, - ADD_CS_ERROR_NAME_IDENTICAL_TO_A_ROLE_NAME, - ADD_CS_ERROR_NAME_IDENTICAL_TO_NT_NAME_OR_ALIAS, - ADD_CS_ERROR_NAME_CONTAIN_CTX_VAR_TOKEN, - ADD_CS_ERROR_NAME_IDENTICAL_TO_EXISTING_COLORSPACE_ALIAS, - - ADD_CS_ERROR_ALIAS_IDENTICAL_TO_A_ROLE_NAME, - ADD_CS_ERROR_ALIAS_IDENTICAL_TO_NT_NAME_OR_ALIAS, - ADD_CS_ERROR_ALIAS_CONTAIN_CTX_VAR_TOKEN, - ADD_CS_ERROR_ALIAS_IDENTICAL_TO_EXISTING_COLORSPACE_NAME, - ADD_CS_ERROR_ALIAS_IDENTICAL_TO_EXISTING_COLORSPACE_ALIAS, -}; - -// Provides codes for errors if there is any problem when a named transform is added to a config. -enum AddNamedTransformError -{ - ADD_NT_ERROR_NONE = 0, - - ADD_NT_ERROR_NULL, - ADD_NT_ERROR_EMPTY, - ADD_NT_ERROR_AT_LEAST_ONE_TRANSFORM, - - ADD_NT_ERROR_NAME_IDENTICAL_TO_A_ROLE_NAME, - ADD_NT_ERROR_NAME_IDENTICAL_TO_COLORSPACE_OR_ALIAS, - ADD_NT_ERROR_NAME_CONTAIN_CTX_VAR_TOKEN, - ADD_NT_ERROR_NAME_IDENTICAL_TO_EXISTING_NT_ALIAS, - - ADD_NT_ERROR_ALIAS_IDENTICAL_TO_A_ROLE_NAME, - ADD_NT_ERROR_ALIAS_IDENTICAL_TO_COLORSPACE_OR_ALIAS, - ADD_NT_ERROR_ALIAS_CONTAIN_CTX_VAR_TOKEN, - ADD_NT_ERROR_ALIAS_IDENTICAL_TO_EXISTING_NT_ALIAS -}; - // Conversion extern OCIOEXPORT const char * BoolToString(bool val); diff --git a/src/OpenColorIO/ColorSpaceSet.cpp b/src/OpenColorIO/ColorSpaceSet.cpp index cdb30b32b0..99c659a61b 100644 --- a/src/OpenColorIO/ColorSpaceSet.cpp +++ b/src/OpenColorIO/ColorSpaceSet.cpp @@ -122,8 +122,7 @@ class ColorSpaceSet::Impl const char * csName = cs->getName(); if (!*csName) { - throw ExceptionAddColorspace("Cannot add a color space with an empty name.", - ADD_CS_ERROR_EMPTY); + throw Exception("Cannot add a color space with an empty name."); } auto entryIdx = getIndex(csName); @@ -138,8 +137,7 @@ class ColorSpaceSet::Impl std::ostringstream os; os << "Cannot add '" << csName << "' color space, existing color space, '"; os << m_colorSpaces[entryIdx]->getName() << "' is using this name as an alias."; - throw ExceptionAddColorspace(os.str().c_str(), - ADD_CS_ERROR_NAME_IDENTICAL_TO_EXISTING_COLORSPACE_ALIAS); + throw Exception(os.str().c_str()); } // There is a color space with the same name that will be replaced (if new color space // can be used). @@ -150,7 +148,6 @@ class ColorSpaceSet::Impl for (size_t aidx = 0; aidx < numAliases; ++aidx) { const char * alias = cs->getAlias(aidx); - // Note that getIndex return the index to either a colorspace or an alias. entryIdx = getIndex(alias); // Is an alias of the color space already used by a color space? // Skip existing colorspace that might be replaced. @@ -159,22 +156,8 @@ class ColorSpaceSet::Impl std::ostringstream os; os << "Cannot add '" << csName << "' color space, it has '" << alias; os << "' alias and existing color space, '"; - - // Check if entryIdx is a colorspace. - if (entryIdx < size() && StringUtils::Compare(get(entryIdx)->getName(), alias)) - { - // conflict with a colorspace name - os << m_colorSpaces[entryIdx]->getName() << "' has the same name."; - throw ExceptionAddColorspace(os.str().c_str(), - ADD_CS_ERROR_ALIAS_IDENTICAL_TO_EXISTING_COLORSPACE_NAME); - } - else - { - // Conflict with a colorspace alias. - os << m_colorSpaces[entryIdx]->getName() << "' is using the same alias."; - throw ExceptionAddColorspace(os.str().c_str(), - ADD_CS_ERROR_ALIAS_IDENTICAL_TO_EXISTING_COLORSPACE_ALIAS); - } + os << m_colorSpaces[entryIdx]->getName() << "' is using the same alias."; + throw Exception(os.str().c_str()); } } if (replaceIdx != (size_t)-1) diff --git a/src/OpenColorIO/Config.cpp b/src/OpenColorIO/Config.cpp index 11c4dca0c8..23b11879ba 100644 --- a/src/OpenColorIO/Config.cpp +++ b/src/OpenColorIO/Config.cpp @@ -1199,8 +1199,7 @@ ConstConfigRcPtr Config::CreateFromFile(const char * filename) } else { - // *IMPORTANT NOTE* - // It not the most robust method. Comments at the top of the files would break this. + // TODO: This isn't the most robust method. Comments at the top of the file would break it. // Check for "ociom" at the start of the file. (ociom_profile) if (magicNumber[0] == 'o' && magicNumber[1] == 'c' && @@ -2585,8 +2584,7 @@ void Config::addColorSpace(const ConstColorSpaceRcPtr & original) const std::string name(original->getName()); if (name.empty()) { - throw ExceptionAddColorspace("Color space must have a non-empty name.", - ADD_CS_ERROR_EMPTY); + throw Exception("Color space must have a non-empty name."); } // Check this is not an existing role or named transform. @@ -2595,7 +2593,7 @@ void Config::addColorSpace(const ConstColorSpaceRcPtr & original) std::ostringstream os; os << "Cannot add '" << name << "' color space, there is already a role with this " "name."; - throw ExceptionAddColorspace(os.str().c_str(), ADD_CS_ERROR_NAME_IDENTICAL_TO_A_ROLE_NAME); + throw Exception(os.str().c_str()); } auto nt = getNamedTransform(name.c_str()); if (nt) @@ -2603,8 +2601,7 @@ void Config::addColorSpace(const ConstColorSpaceRcPtr & original) std::ostringstream os; os << "Cannot add '" << name << "' color space, there is already a named transform using " "this name as a name or as an alias: '" << nt->getName() << "'."; - throw ExceptionAddColorspace(os.str().c_str(), - ADD_CS_ERROR_NAME_IDENTICAL_TO_NT_NAME_OR_ALIAS); + throw Exception(os.str().c_str()); } if (getMajorVersion() >= 2 && ContainsContextVariableToken(name)) @@ -2613,8 +2610,7 @@ void Config::addColorSpace(const ConstColorSpaceRcPtr & original) oss << "A color space name '" << name << "' cannot contain a context variable reserved token i.e. % or $."; - throw ExceptionAddColorspace(oss.str().c_str(), - ADD_CS_ERROR_NAME_CONTAIN_CTX_VAR_TOKEN); + throw Exception(oss.str().c_str()); } const size_t numAliases = original->getNumAliases(); @@ -2627,8 +2623,7 @@ void Config::addColorSpace(const ConstColorSpaceRcPtr & original) std::ostringstream os; os << "Cannot add '" << name << "' color space, it has an alias '" << alias << "' and there is already a role with this name."; - throw ExceptionAddColorspace(os.str().c_str(), - ADD_CS_ERROR_ALIAS_IDENTICAL_TO_A_ROLE_NAME); + throw Exception(os.str().c_str()); } auto nt = getNamedTransform(alias); if (nt) @@ -2637,8 +2632,7 @@ void Config::addColorSpace(const ConstColorSpaceRcPtr & original) os << "Cannot add '" << name << "' color space, it has an alias '" << alias << "' and there is already a named transform using this name as a name or as " "an alias: '" << nt->getName() << "'."; - throw ExceptionAddColorspace(os.str().c_str(), - ADD_CS_ERROR_ALIAS_IDENTICAL_TO_NT_NAME_OR_ALIAS); + throw Exception(os.str().c_str()); } if (ContainsContextVariableToken(alias)) { @@ -2646,8 +2640,7 @@ void Config::addColorSpace(const ConstColorSpaceRcPtr & original) os << "Cannot add '" << name << "' color space, it has an alias '" << alias << "' that cannot contain a context variable reserved token i.e. % or $."; - throw ExceptionAddColorspace(os.str().c_str(), - ADD_CS_ERROR_ALIAS_CONTAIN_CTX_VAR_TOKEN); + throw Exception(os.str().c_str()); } } @@ -3182,19 +3175,17 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) { if (!nt) { - throw ExceptionAddNamedTransform("Named transform is null.", ADD_NT_ERROR_NULL); + throw Exception("Named transform is null."); } const std::string name(nt->getName()); if (name.empty()) { - throw ExceptionAddNamedTransform("Named transform must have a non-empty name.", - ADD_NT_ERROR_EMPTY); + throw Exception("Named transform must have a non-empty name."); } if (!nt->getTransform(TRANSFORM_DIR_FORWARD) && !nt->getTransform(TRANSFORM_DIR_INVERSE)) { - throw ExceptionAddNamedTransform("Named transform must define at least one transform.", - ADD_NT_ERROR_AT_LEAST_ONE_TRANSFORM); + throw Exception("Named transform must define at least one transform."); } if (hasRole(name.c_str())) @@ -3202,7 +3193,7 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) std::ostringstream os; os << "Cannot add '" << name << "' named transform, there is already a role with this " "name."; - throw ExceptionAddNamedTransform(os.str().c_str(), ADD_NT_ERROR_NAME_IDENTICAL_TO_A_ROLE_NAME); + throw Exception(os.str().c_str()); } auto cs = getColorSpace(name.c_str()); if (cs) @@ -3210,8 +3201,7 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) std::ostringstream os; os << "Cannot add '" << name << "' named transform, there is already a color space using " "this name as a name or as an alias: '" << cs->getName() << "'."; - throw ExceptionAddNamedTransform(os.str().c_str(), - ADD_NT_ERROR_NAME_IDENTICAL_TO_COLORSPACE_OR_ALIAS); + throw Exception(os.str().c_str()); } if (ContainsContextVariableToken(name)) @@ -3220,7 +3210,7 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) oss << "A named transform name '" << name << "' cannot contain a context variable reserved token i.e. % or $."; - throw ExceptionAddNamedTransform(oss.str().c_str(), ADD_NT_ERROR_NAME_CONTAIN_CTX_VAR_TOKEN); + throw Exception(oss.str().c_str()); } size_t existing = getImpl()->getNamedTransformIndex(name.c_str()); @@ -3235,8 +3225,7 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) std::ostringstream os; os << "Cannot add '" << name << "' named transform, existing named transform, '"; os << existingName << "' is using this name as an alias."; - throw ExceptionAddNamedTransform(os.str().c_str(), - ADD_NT_ERROR_NAME_IDENTICAL_TO_EXISTING_NT_ALIAS); + throw Exception(os.str().c_str()); } // There is a named transform with the same name that will be replaced (if new named // transform can be used). @@ -3253,8 +3242,7 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) std::ostringstream os; os << "Cannot add '" << name << "' named transform, it has an alias '" << alias << "' and there is already a role with this name."; - throw ExceptionAddNamedTransform(os.str().c_str(), - ADD_NT_ERROR_ALIAS_IDENTICAL_TO_A_ROLE_NAME); + throw Exception(os.str().c_str()); } auto cs = getColorSpace(alias); if (cs) @@ -3263,8 +3251,7 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) os << "Cannot add '" << name << "' named transform, it has an alias '" << alias << "' and there is already a color space using this name as a name or as " "an alias: '" << cs->getName() << "'."; - throw ExceptionAddNamedTransform(os.str().c_str(), - ADD_NT_ERROR_ALIAS_IDENTICAL_TO_COLORSPACE_OR_ALIAS); + throw Exception(os.str().c_str()); } if (ContainsContextVariableToken(alias)) { @@ -3272,8 +3259,7 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) oss << "Cannot add '" << name << "' named transform, it has an alias '" << alias << "' that cannot contain a context variable reserved token i.e. % or $."; - throw ExceptionAddNamedTransform(oss.str().c_str(), - ADD_NT_ERROR_ALIAS_CONTAIN_CTX_VAR_TOKEN); + throw Exception(oss.str().c_str()); } existing = getImpl()->getNamedTransformIndex(alias); @@ -3286,8 +3272,7 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) os << "Cannot add '" << name << "' named transform, it has '" << alias; os << "' alias and existing named transform, '"; os << existingName << "' is using the same alias."; - throw ExceptionAddNamedTransform(os.str().c_str(), - ADD_NT_ERROR_ALIAS_IDENTICAL_TO_EXISTING_NT_ALIAS); + throw Exception(os.str().c_str()); } } @@ -3299,8 +3284,7 @@ void Config::addNamedTransform(const ConstNamedTransformRcPtr & nt) std::ostringstream os; os << "Cannot add '" << name << "' named transform, existing named transform, '"; os << existingName << "' is using this name as an alias."; - throw ExceptionAddNamedTransform(os.str().c_str(), - ADD_NT_ERROR_ALIAS_IDENTICAL_TO_EXISTING_NT_ALIAS); + throw Exception(os.str().c_str()); } NamedTransformRcPtr copy = nt->createEditableCopy(); ConstNamedTransformRcPtr namedTransformCopy = copy; diff --git a/src/OpenColorIO/ConfigUtils.cpp b/src/OpenColorIO/ConfigUtils.cpp index 74b559b5df..9a5ecfcda8 100644 --- a/src/OpenColorIO/ConfigUtils.cpp +++ b/src/OpenColorIO/ConfigUtils.cpp @@ -825,7 +825,6 @@ const char * IdentifyBuiltinColorSpace(const ConstConfigRcPtr & srcConfig, builtinConfig, builtinColorSpaceName, builtinInterchangeName); -// if (isIdentityTransform(proc, vals, 1e-3f)) // Tolerance is just loose enough to accept both bfd and cat02 adaptation. if (isIdentityTransform(proc, vals, 5e-3f)) { @@ -840,7 +839,6 @@ const char * IdentifyBuiltinColorSpace(const ConstConfigRcPtr & srcConfig, throw Exception(os.str().c_str()); } - // Simplify a transform by removing nested group transforms and identities. // ConstTransformRcPtr simplifyTransform(const ConstGroupTransformRcPtr & gt) @@ -938,7 +936,6 @@ ConstTransformRcPtr getRefSpaceConverter(const ConstConfigRcPtr & srcConfig, getColorspaceOfRefType(srcConfig, refSpaceType), builtinConfig, getColorspaceOfRefType(builtinConfig, refSpaceType)); -// std::cout << "srcInterchange: " << srcInterchange << "\n"; // Identify an interchange space for the dst config. // Note that the interchange space will always be a linear color space. @@ -950,7 +947,6 @@ ConstTransformRcPtr getRefSpaceConverter(const ConstConfigRcPtr & srcConfig, getColorspaceOfRefType(dstConfig, refSpaceType), builtinConfig, getColorspaceOfRefType(builtinConfig, refSpaceType)); -// std::cout << "dstInterchange: " << dstInterchange << "\n"; // Get the from_ref transform from the srcInterchange space. ConstTransformRcPtr srcFromRef = getTransformForDir(srcConfig->getColorSpace(srcInterchange), @@ -978,30 +974,15 @@ ConstTransformRcPtr getRefSpaceConverter(const ConstConfigRcPtr & srcConfig, // simplified/optimized after being combined with the existing transform anyway // since one of these pieces may be the inverse of a color space's existing transform. GroupTransformRcPtr gt = GroupTransform::Create(); -// gt->appendTransform(srcFromRef->createEditableCopy()); -// gt->appendTransform(srcBuiltinToDstBuiltin); -// gt->appendTransform(dstToRef->createEditableCopy()); -// std::cout << "srcFromRef: " << *srcFromRef << "\n"; -// std::cout << "srcToDstBuiltin: " << *srcBuiltinToDstBuiltin << "\n"; -// std::cout << "dstToRef: " << *dstToRef << "\n"; -// std::cout << "simplified: " << *simplifyTransform(gt) << "\n\n"; - - // FIXME: If the src or dst contain FileTransforms, resolve them so there is no dependence + + // If the src or dst contain FileTransforms, resolve them so there is no dependence // on the search_path of the original configs. This is necessary for simplifyTransform - // below but would fail if if the conversion involved a transform that may not appear + // below and would fail if the conversion involved a transform that may not appear // in a config, such as a LUT. gt->appendTransform(srcConfig->getProcessor(srcFromRef)->createGroupTransform()); gt->appendTransform(srcBuiltinToDstBuiltin); gt->appendTransform(dstConfig->getProcessor(dstToRef)->createGroupTransform()); - // TODO: Need to ensure that gt would never contain a file transform. - // for (size_t t = 0; t < gt->getNumTransforms(); t++) - // { - // if (gt->getTransform(t)->getTransformType() == TRANSFORM_TYPE_FILE) - // { - // throw Exception("Cannot contain FileTransform."); - // } - // } return simplifyTransform(gt); } @@ -1084,8 +1065,7 @@ void updateReferenceView(ViewTransformRcPtr & vt, os << "Could not update view transform reference spaces, converter transforms were not initialized."; throw Exception(os.str().c_str()); } - - // FIXME: Is any more error checking needed? + // TODO: Is any more error checking needed here for robustness? const bool emptySceneSide = transformIsEmpty(toNewSceneReferenceTransform); const bool emptyDisplaySide = transformIsEmpty(toNewDisplayReferenceTransform); @@ -1158,7 +1138,6 @@ void updateReferenceView(ViewTransformRcPtr & vt, // has no transforms, so at least one direction will be present. } -// FIXME: Make this a functional. bool hasColorSpaceRefType(const ConstConfigRcPtr & config, ReferenceSpaceType refType) { SearchReferenceSpaceType searchRefType = static_cast(refType); @@ -1166,30 +1145,24 @@ bool hasColorSpaceRefType(const ConstConfigRcPtr & config, ReferenceSpaceType re return n > 0; } +// Initialize the transforms that will be added to color spaces and view transforms to +// convert the reference space from one config to another. +// void initializeRefSpaceConverters(ConstTransformRcPtr & inputToBaseGtScene, ConstTransformRcPtr & inputToBaseGtDisplay, const ConstConfigRcPtr & baseConfig, const ConstConfigRcPtr & inputConfig) { // Note: The base config reference space is always used, regardless of strategy. -//std::cout << "initializing ref converters\n"; if (hasColorSpaceRefType(baseConfig, REFERENCE_SPACE_SCENE) && hasColorSpaceRefType(inputConfig, REFERENCE_SPACE_SCENE)) { -// try -// { - // This may throw. - inputToBaseGtScene = getRefSpaceConverter( - inputConfig, - baseConfig, - REFERENCE_SPACE_SCENE - ); -// } -// catch(const Exception & e) -// { -// LogError(e.what()); -// } + inputToBaseGtScene = getRefSpaceConverter( + inputConfig, + baseConfig, + REFERENCE_SPACE_SCENE + ); } else { @@ -1203,18 +1176,11 @@ void initializeRefSpaceConverters(ConstTransformRcPtr & inputToBaseGtScene, if (hasColorSpaceRefType(baseConfig, REFERENCE_SPACE_DISPLAY) && hasColorSpaceRefType(inputConfig, REFERENCE_SPACE_DISPLAY)) { -// try -// { - inputToBaseGtDisplay = getRefSpaceConverter( - inputConfig, - baseConfig, - REFERENCE_SPACE_DISPLAY - ); -// } -// catch(const Exception & e) -// { -// LogError(e.what()); -// } + inputToBaseGtDisplay = getRefSpaceConverter( + inputConfig, + baseConfig, + REFERENCE_SPACE_DISPLAY + ); } else { @@ -1223,43 +1189,24 @@ void initializeRefSpaceConverters(ConstTransformRcPtr & inputToBaseGtScene, } } +// Send the test vals through the color space and store the result in fingerprintVals. +// Returns true if the color space should not be considered. +// bool calcColorSpaceFingerprint(std::vector & fingerprintVals, const ColorSpaceFingerprints & fingerprints, const ConstConfigRcPtr & config, const ConstColorSpaceRcPtr & cs) { bool skipColorSpace = false; - // Define a set of (somewhat arbitrary) RGB values to test whether the combined transform is - // enough of an identity. - // TODO: Should we check values outside [0,1]? - -// std::vector RGBAvals = { 0.4f, 0.23f, 0.07f, 0.f, -// 0.35f, 0.66f, 0.16f, 0.f, -// 0.2f, 0.11f, 0.86f, 0.f, -// 0.f, 0.f, 0.f, 0.f, -// 0.04f, 0.03f, 0.02f, 0.f, -// 1.f, 1.f, 1.f, 0.f }; - -// std::vector RGBAvals = { 0.7f, 0.4f, 0.02f, 0.f, -// 0.02f, 0.6f, 0.2f, 0.f, -// 0.3f, 0.02f, 0.5f, 0.f, -// 0.f, 0.f, 0.f, 0.f, -// 1.f, 1.f, 1.f, 0.f }; - -// FIXME: THIS BREAKS THE TESTS - -// std::vector vals = { 0.7f, 0.4f, 0.02f, 0.f, -// 0.02f, 0.6f, -0.2f, 0.f, -// 0.3f, 0.02f, 1.5f, 0.f, -// 0.f, 0.f, 0.f, 0.f, -// 1.f, 1.f, 1.f, 0.f }; + // TODO: Would it be helpful to compare to_refs to to_refs, rather than inverting? ConstTransformRcPtr fromRef = getTransformForDir(cs, COLORSPACE_DIR_FROM_REFERENCE); - ConstProcessorRcPtr p; + ConstCPUProcessorRcPtr cpu; try { - p = config->getProcessor(fromRef); + ConstProcessorRcPtr p = config->getProcessor(fromRef); + cpu = p->getOptimizedCPUProcessor(OPTIMIZATION_NONE); } catch (...) { @@ -1267,8 +1214,7 @@ bool calcColorSpaceFingerprint(std::vector & fingerprintVals, return true; } - // TODO: Get a group transform and don't bother if it contains a 3d-lut. - // With optimization-none, it should not invert a 3d-lut, regardless of direction? + // TODO: Should skip some transforms, e.g. those with a 3d-LUT. if (cs->getReferenceSpaceType() == REFERENCE_SPACE_DISPLAY) { @@ -1281,19 +1227,23 @@ bool calcColorSpaceFingerprint(std::vector & fingerprintVals, const size_t n = fingerprintVals.size(); PackedImageDesc desc( &fingerprintVals[0], (long) n / 4, 1, CHANNEL_ORDERING_RGBA ); - ConstCPUProcessorRcPtr cpu = p->getOptimizedCPUProcessor(OPTIMIZATION_NONE); cpu->apply(desc); - // TODO: add a cacheID to GroupTransform using the opData IDs, use that to do an easier comparison. - // TODO: compare to_refs to to_refs. return skipColorSpace; } +// Define a set of test values to use for a config and store them in the fingerprints struct. +// An attempt is made to convert them to the reference spaces of the config being used. +// There are separate values for scene-referred and display-referred color spaces. +// void initializeTestVals(ColorSpaceFingerprints & fingerprints, const ConstConfigRcPtr & config) { // Define a set of test values that are slightly inside the Rec.709 gamut // for the most common scene-referred and display-referred reference spaces. + // TODO: Including negative values would exclude some matches that are probably + // desirable, it's an open question how strict the matching should be. + std::vector ACESvals = { 0.408933127871f, 0.106169822808f, 0.027842572707f, 0.f, // lin_rec709 {0.9, 0.03, 0.01} 0.374615373650f, 0.739417755017f, 0.118862613721f, 0.f, // lin_rec709 {0.06, 0.9, 0.02} @@ -1303,8 +1253,6 @@ void initializeTestVals(ColorSpaceFingerprints & fingerprints, const ConstConfig 1.f , 1.f , 1.f , 1.f }; std::vector XYZvals = { -// 0.376532370617f, 0.199248715226f, 0.028095006164f, 0.f, // lin_rec709 {0.9, 0.01, 0.01} -// 0.327754621322f, 0.646500124103f, 0.116973931525f, 0.f, // lin_rec709 {0.01, 0.9, 0.01} // Adjusted to keep it inside both Rec.601 and Rec.601 PAL. 0.383684057405f, 0.213552088801f, 0.030478901760f, 0.f, // lin_rec709 {0.9, 0.03, 0.01} 0.350178969169f, 0.657853997550f, 0.127445793983f, 0.f, // lin_rec709 {0.06, 0.9, 0.02} @@ -1333,18 +1281,14 @@ void initializeTestVals(ColorSpaceFingerprints & fingerprints, const ConstConfig if (!cs) { // Otherwise, see if it's present using a different name. -// std::cout << "--> need lin_rec709\n"; ConstConfigRcPtr builtinConfig = Config::CreateFromBuiltinConfig("ocio://cg-config-latest"); // This throws if it cannot find the requested space. const char * cs_name = Config::IdentifyBuiltinColorSpace(config, builtinConfig, "aces_interchange"); cs = config->getColorSpace(cs_name); -// std::cout << "--> identified lin_rec709\n"; } } } -// else -// std::cout << "--> found lin_rec709\n"; ConstTransformRcPtr toRef = getTransformForDir(cs, COLORSPACE_DIR_TO_REFERENCE); p = config->getProcessor(toRef); @@ -1359,11 +1303,9 @@ void initializeTestVals(ColorSpaceFingerprints & fingerprints, const ConstConfig cpu->apply(descSrc, descDst); fingerprints.sceneRefTestVals = out; -// std::cout << "--> computed lin_rec709\n"; } catch (...) { -// std::cout << "--> exception lin_rec709\n"; fingerprints.sceneRefTestVals = ACESvals; } @@ -1387,18 +1329,13 @@ void initializeTestVals(ColorSpaceFingerprints & fingerprints, const ConstConfig if (!cs) { // Otherwise, see if it's present using a different name. -// std::cout << "--> need xyz\n"; ConstConfigRcPtr builtinConfig = Config::CreateFromBuiltinConfig("ocio://cg-config-latest"); - // TODO: verify this will convert to the same ref space type. const char * cs_name = Config::IdentifyBuiltinColorSpace(config, builtinConfig, "cie_xyz_d65_interchange"); cs = config->getColorSpace(cs_name); -// std::cout << "--> identified xyz\n"; } } } -// else -// std::cout << "--> found xyz\n"; ConstTransformRcPtr toRef = getTransformForDir(cs, COLORSPACE_DIR_TO_REFERENCE); p = config->getProcessor(toRef); @@ -1413,15 +1350,17 @@ void initializeTestVals(ColorSpaceFingerprints & fingerprints, const ConstConfig cpu->apply(descSrc, descDst); fingerprints.displayRefTestVals = out; -// std::cout << "--> computed xtyz\n"; } catch (...) { -// std::cout << "--> exception xyz\n"; fingerprints.displayRefTestVals = XYZvals; } } +// Calculate a fingerprint for every color space in a base config. These will be used +// to compare against color spaces in an input config for merging. Store the results in +// the fingerprint struct. +// void initializeColorSpaceFingerprints(ColorSpaceFingerprints & fingerprints, const ConstConfigRcPtr & config) { SuspendCacheGuard srcGuard(config); @@ -1445,8 +1384,8 @@ void initializeColorSpaceFingerprints(ColorSpaceFingerprints & fingerprints, con if (cs->hasCategory("is-unique")) { // Don't fingerprint color spaces with this category. - // Never want to replace them. -// TODO: May always want to fingerprint everything -- move this to the merge. + // This provides a way to identify color spaces that must not be replaced. + // TODO: Perhaps fingerprint everything, and move this to the merge function? continue; } @@ -1476,10 +1415,10 @@ void initializeColorSpaceFingerprints(ColorSpaceFingerprints & fingerprints, con // Return an empty string if no equivalent color space is found (within the tolerance). // The ref_space_type specifies the type of inputCS and determines which part of the // config is searched. +// const char * findEquivalentColorspace(const ColorSpaceFingerprints & fingerprints, const ConstConfigRcPtr & inputConfig, const ConstColorSpaceRcPtr & inputCS) -// ReferenceSpaceType refType) { // The fingerprints must first be initialized from the base config. // NB: The inputConfig/inputCS must use the same reference space as the base config. @@ -1500,9 +1439,11 @@ const char * findEquivalentColorspace(const ColorSpaceFingerprints & fingerprint return ""; } -// FIXME: Before looping over all color spaces, check to see if there's one with the same name. + // TODO: Before looping over all color spaces, check to see if there's one with the same name. + // TODO: Perhaps add a hash based on the transform cacheIDs and check that before trying + // to compare processed pixel values? - // Increase from 1e-3 to 5e-3 to allow for use of either Bradford or CAT02 adaptation. + // Increased from 1e-3 to 5e-3 to allow for use of either Bradford or CAT02 adaptation. const float absTolerance = 5e-3f; // Compare to the fingerprints from the base config. @@ -1511,7 +1452,9 @@ const char * findEquivalentColorspace(const ColorSpaceFingerprints & fingerprint { // Only compare color spaces that are using the same reference space type. if (fp.type != inputCS->getReferenceSpaceType()) + { continue; + } bool matchFound = true; for (size_t i = 0; i < n; i++) @@ -1526,30 +1469,11 @@ const char * findEquivalentColorspace(const ColorSpaceFingerprints & fingerprint } } if (matchFound) + { return fp.csName; + } } - -// TODO: Need to add isdata check to other heuristics too. - -// if (!cs->isData()) -// { -// // ConstTransformRcPtr toRef = getTransformForDir(cs, COLORSPACE_DIR_TO_REFERENCE); -// // GroupTransformRcPtr gt = GroupTransform::Create(); -// // gt->appendTransform(toRef->createEditableCopy()); -// // gt->appendTransform(fromRef->createEditableCopy()); -// // -// // auto p = baseConfig->getProcessor(gt); -// -// -// -// if (isIdentityTransform(p, vals, 1e-3f)) -// { -// return cs->getName(); -// } -// } -// } - return ""; } diff --git a/src/OpenColorIO/ConfigUtils.h b/src/OpenColorIO/ConfigUtils.h index 2126da9a91..559e17d6f2 100644 --- a/src/OpenColorIO/ConfigUtils.h +++ b/src/OpenColorIO/ConfigUtils.h @@ -79,7 +79,6 @@ const char * findEquivalentColorspace(const ColorSpaceFingerprints & fingerprint const ConstColorSpaceRcPtr & inputCS); // Temporarily deactivate the Processor cache on a Config object. -// Currently, this also clears the cache. // class SuspendCacheGuard { diff --git a/src/OpenColorIO/Exception.cpp b/src/OpenColorIO/Exception.cpp index 6c5dbc165b..061324e138 100644 --- a/src/OpenColorIO/Exception.cpp +++ b/src/OpenColorIO/Exception.cpp @@ -35,43 +35,5 @@ ExceptionMissingFile::~ExceptionMissingFile() { } -ExceptionAddColorspace::ExceptionAddColorspace(const char * msg, AddColorspaceError errorCode) - : Exception(msg), m_errorCode(errorCode) -{ -} - -ExceptionAddColorspace::ExceptionAddColorspace(const ExceptionAddColorspace & e) - : Exception(e) -{ -} - -AddColorspaceError ExceptionAddColorspace::getErrorCode() const noexcept -{ - return m_errorCode; -} - -ExceptionAddColorspace::~ExceptionAddColorspace() -{ -} - -ExceptionAddNamedTransform::ExceptionAddNamedTransform(const char * msg, AddNamedTransformError errorCode) - : Exception(msg), m_errorCode(errorCode) -{ -} - -ExceptionAddNamedTransform::ExceptionAddNamedTransform(const ExceptionAddNamedTransform & e) - : Exception(e) -{ -} - -AddNamedTransformError ExceptionAddNamedTransform::getErrorCode() const noexcept -{ - return m_errorCode; -} - -ExceptionAddNamedTransform::~ExceptionAddNamedTransform() -{ -} - } // namespace OCIO_NAMESPACE diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp index 0e5f770f04..c21700d931 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp +++ b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp @@ -22,16 +22,6 @@ namespace OCIO_NAMESPACE { -// -// Config merging feature -// - -/// Private implementation section - -// ... - -/// Public implementation section - ConfigMergingParameters::ConfigMergingParameters() : m_impl(new ConfigMergingParameters::Impl()) { @@ -260,7 +250,7 @@ void ConfigMergingParameters::setRoles(MergeStrategies strategy) ConfigMergingParameters::MergeStrategies ConfigMergingParameters::getRoles() const { - if (getImpl()->m_roles == MergeStrategies::STRATEGY_UNSET) + if (getImpl()->m_roles == MergeStrategies::STRATEGY_UNSPECIFIED) { return getDefaultStrategy(); } @@ -274,7 +264,7 @@ void ConfigMergingParameters::setFileRules(MergeStrategies strategy) ConfigMergingParameters::MergeStrategies ConfigMergingParameters::getFileRules() const { - if (getImpl()->m_fileRules == MergeStrategies::STRATEGY_UNSET) + if (getImpl()->m_fileRules == MergeStrategies::STRATEGY_UNSPECIFIED) { return getDefaultStrategy(); } @@ -288,7 +278,7 @@ void ConfigMergingParameters::setDisplayViews(MergeStrategies strategy) ConfigMergingParameters::MergeStrategies ConfigMergingParameters::getDisplayViews() const { - if (getImpl()->m_displayViews == MergeStrategies::STRATEGY_UNSET) + if (getImpl()->m_displayViews == MergeStrategies::STRATEGY_UNSPECIFIED) { return getDefaultStrategy(); } @@ -302,7 +292,7 @@ void ConfigMergingParameters::setLooks(MergeStrategies strategy) ConfigMergingParameters::MergeStrategies ConfigMergingParameters::getLooks() const { - if (getImpl()->m_looks == MergeStrategies::STRATEGY_UNSET) + if (getImpl()->m_looks == MergeStrategies::STRATEGY_UNSPECIFIED) { return getDefaultStrategy(); } @@ -316,7 +306,7 @@ void ConfigMergingParameters::setColorspaces(MergeStrategies strategy) ConfigMergingParameters::MergeStrategies ConfigMergingParameters::getColorspaces() const { - if (getImpl()->m_colorspaces == MergeStrategies::STRATEGY_UNSET) + if (getImpl()->m_colorspaces == MergeStrategies::STRATEGY_UNSPECIFIED) { return getDefaultStrategy(); } @@ -330,7 +320,7 @@ void ConfigMergingParameters::setNamedTransforms(MergeStrategies strategy) ConfigMergingParameters::MergeStrategies ConfigMergingParameters::getNamedTransforms() const { - if (getImpl()->m_namedTransforms == MergeStrategies::STRATEGY_UNSET) + if (getImpl()->m_namedTransforms == MergeStrategies::STRATEGY_UNSPECIFIED) { return getDefaultStrategy(); } @@ -364,7 +354,7 @@ ConstConfigMergerRcPtr ConfigMerger::Impl::Read(std::istream & istream, const ch ociomParser.load(node, merger, filepath); - // Look at each set of Params and check if there are any 'Unset' sections. + // Look at each set of Params and check if there are any 'Unspecified' sections. // If so, initialize them to the default strategy. // If there are no default, use PreferInput. } @@ -430,6 +420,7 @@ ConfigMergerRcPtr ConfigMerger::Create() return ConfigMergerRcPtr(new ConfigMerger(), &deleter); } +// TODO: Refactor with the loadConfig function below. ConstConfigMergerRcPtr ConfigMerger::CreateFromFile(const char * filepath) { if (!filepath || !*filepath) @@ -618,6 +609,10 @@ ConstConfigRcPtr loadConfig(const ConfigMergerRcPtr merger, value); return Config::CreateFromFile(resolvedfullpath.c_str()); } + // TODO: If the file exists but won't load, this hides the error. + // (Tried using ExceptionMissingFile, but the implementation of that is not what I + // expected, Config::CreateFromFile only uses that if the argument is empty, not + // if it can't read the file.) catch(...) { /* don't capture the exception */ } } @@ -644,6 +639,11 @@ ConstConfigRcPtr loadConfig(const ConfigMergerRcPtr merger, ConstConfigMergerRcPtr MergeConfigs(const ConstConfigMergerRcPtr & merger) { + if (!merger) + { + throw(Exception("The merger object was not initialized.")); + } + ConfigMergerRcPtr editableMerger = merger->createEditableCopy(); for (int i = 0; i < merger->getNumOfConfigMergingParameters(); i++) diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h index 4edeb3a18f..2bb3baf34a 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h +++ b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h @@ -31,13 +31,6 @@ class ConfigMergingParameters::Impl // Overrides used to replace various parameters of a merged config. std::string m_name; std::string m_description; -// std::vector m_searchPaths; -// StringUtils::StringVec m_activeDisplays; -// StringUtils::StringVec m_activeViews; -// StringUtils::StringVec m_inactiveColorspaces; -// mutable std::string m_activeDisplaysStr; -// mutable std::string m_activeViewsStr; -// mutable std::string m_inactiveColorSpaceStr; // Used to store the overrides for the following sections: // search_path, active_displays, active_views and inactive_colorspace. @@ -86,12 +79,12 @@ class ConfigMergingParameters::Impl m_avoidDuplicates = true; m_assumeCommonReferenceSpace = false; - m_roles = STRATEGY_UNSET; - m_fileRules = STRATEGY_UNSET; - m_displayViews = STRATEGY_UNSET; - m_looks = STRATEGY_UNSET; - m_colorspaces = STRATEGY_UNSET; - m_namedTransforms = STRATEGY_UNSET; + m_roles = STRATEGY_UNSPECIFIED; + m_fileRules = STRATEGY_UNSPECIFIED; + m_displayViews = STRATEGY_UNSPECIFIED; + m_looks = STRATEGY_UNSPECIFIED; + m_colorspaces = STRATEGY_UNSPECIFIED; + m_namedTransforms = STRATEGY_UNSPECIFIED; } ~Impl() = default; @@ -108,7 +101,6 @@ class ConfigMergingParameters::Impl // Overrides m_name = rhs.m_name; m_description = rhs.m_description; -// m_searchPaths = rhs.m_searchPaths; // Options m_defaultStrategy = rhs.m_defaultStrategy; diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp index b22674c736..efc713d062 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp +++ b/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp @@ -103,7 +103,7 @@ ConfigMergingParameters::MergeStrategies OCIOMYaml::strategyToEnum(const char * return it->second; } - return ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET; + return ConfigMergingParameters::MergeStrategies::STRATEGY_UNSPECIFIED; } @@ -128,7 +128,7 @@ ConfigMergingParameters::MergeStrategies OCIOMYaml::genericStrategyHandler(const } auto srategyEnum = strategyToEnum(strategy.c_str()); - if (srategyEnum == ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET) + if (srategyEnum == ConfigMergingParameters::MergeStrategies::STRATEGY_UNSPECIFIED) { std::ostringstream os; os << "The value '" << strategy; @@ -173,7 +173,7 @@ void OCIOMYaml::loadOptions(const YAML::Node & node, ConfigMergingParametersRcPt { const std::string & strategy = it->second.as(); auto srategyEnum = strategyToEnum(strategy.c_str()); - if (srategyEnum == ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET) + if (srategyEnum == ConfigMergingParameters::MergeStrategies::STRATEGY_UNSPECIFIED) { std::ostringstream os; os << "The value '" << strategy; @@ -476,8 +476,8 @@ const char * stategyEnumToString(ConfigMergingParameters::MergeStrategies strate case ConfigMergingParameters::MergeStrategies::STRATEGY_REMOVE: return "Remove"; break; - case ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET: - return "Unset"; + case ConfigMergingParameters::MergeStrategies::STRATEGY_UNSPECIFIED: + return "Unspecified"; break; default: return "Unknown"; @@ -490,10 +490,7 @@ inline void save(YAML::Emitter & out, const ConfigMerger & merger) std::stringstream ss; const unsigned parserMajorVersion = merger.getMajorVersion(); ss << parserMajorVersion; -// if (merger.getMinorVersion() != 0) -// { - ss << "." << merger.getMinorVersion(); -// } + ss << "." << merger.getMinorVersion(); out << YAML::Block; out << YAML::BeginMap; diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp index 6901042ccb..20a35922bc 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp +++ b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp @@ -28,17 +28,11 @@ namespace OCIO_NAMESPACE namespace { -// void printStrVec(const StringUtils::StringVec str) -// { -// for (int i=0; isetDefaultLumaCoefs(rgb); } -////////////////////////////////// GeneralMerger end ///////////////////////////////////// - -bool hasAlias(const ConstColorSpaceRcPtr & cs, const char * aliasName) -{ - if (cs) - { - for (size_t i = 0; i < cs->getNumAliases(); i++) - { - if (Platform::Strcasecmp(cs->getAlias(i), aliasName) == 0) - return true; - } - } - return false; -} - -bool hasAlias(const ConstNamedTransformRcPtr & nt, const char * aliasName) -{ - if (nt) - { - for (size_t i = 0; i < nt->getNumAliases(); i++) - { - if (Platform::Strcasecmp(nt->getAlias(i), aliasName) == 0) - return true; - } - } - return false; -} +/////////////////////////////////// GeneralMerger //////////////////////////////////////// -////////////////////////////////////////// RolesMerger /////////////////////////////////// +/////////////////////////////////// RolesMerger ////////////////////////////////////////// void RolesMerger::mergeInputRoles() { @@ -333,7 +301,6 @@ void RolesMerger::mergeInputRoles() if (strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT || strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_INPUT_ONLY) { - m_mergedConfig->setRole(name, roleColorSpaceName); } @@ -360,7 +327,7 @@ void RolesMerger::mergeInputRoles() os << "The Input config contains a role '" << name << "' that would override Base config color space '"; os << existingCS->getName() << "'."; } - else if (hasAlias(existingCS, name)) + else if (existingCS->hasAlias(name)) { os << "The Input config contains a role '" << name << "' that would override an alias of Base config color space '"; os << existingCS->getName() << "'."; @@ -387,7 +354,7 @@ void RolesMerger::mergeInputRoles() os << "The Input config contains a role '" << name << "' that would override Base config named transform: '"; os << existingNT->getName() << "'."; } - else if (hasAlias(existingNT, name)) + else if (existingNT->hasAlias(name)) { os << "The Input config contains a role '" << name << "' that would override an alias of Base config named transform: '"; os << existingNT->getName() << "'."; @@ -448,9 +415,9 @@ void RolesMerger::handleRemove() } } -////////////////////////////////////// RolesMerger end /////////////////////////////////// +/////////////////////////////////// RolesMerger ////////////////////////////////////////// -//////////////////////////////////////// FileRulesMerger ///////////////////////////////// +/////////////////////////////////// FileRulesMerger ////////////////////////////////////// bool fileRulesAreEqual(const ConstFileRulesRcPtr & f1, size_t f1Idx, @@ -749,147 +716,13 @@ void FileRulesMerger::handleRemove() m_mergedConfig->setFileRules(mergedFileRules); } -//////////////////////////////////// FileRulesMerger end ///////////////////////////////// +/////////////////////////////////// FileRulesMerger ////////////////////////////////////// -/////////////////////////////////////// DisplayViewMerger //////////////////////////////// +/////////////////////////////////// DisplayViewMerger //////////////////////////////////// namespace { -bool displayHasView(const ConstConfigRcPtr & cfg, const char * dispName, const char * viewName) -{ - // This returns null if either the display or view doesn't exist. - // It works regardless of whether the display or view are active, - // and it works regardless of whether the view is display-defined - // or if the display has this as a shared view. - // - // It will only check config level shared views if dispName is null. - // It will not check config level shared views if dispName is not null. - const char * cs = cfg->getDisplayViewColorSpaceName(dispName, viewName); - - // All views must have a color space, so if it's not empty, the view exists. - return (cs && *cs); -} - -bool hasVirtualView(const ConstConfigRcPtr & cfg, const char * viewName) -{ - const char * cs = cfg->getVirtualDisplayViewColorSpaceName(viewName); - - // All views must have a color space, so if it's not empty, the view exists. - return (cs && *cs); -} - -void clearSharedViews(ConfigRcPtr & cfg) -{ - int numViews = cfg->getNumViews(VIEW_SHARED, nullptr); - for (int v = numViews - 1; v >= 0; v--) - { - const char * sharedViewName = cfg->getView(VIEW_SHARED, nullptr, v); - if (sharedViewName && *sharedViewName) - { - cfg->removeSharedView(sharedViewName); - } - } -} - -bool viewIsShared(const ConstConfigRcPtr & cfg, - const char * dispName, - const char * viewName) -{ - // Check if a view within a given display is a display-defined view or is referencing - // one of the config's shared views. - - for (int v = 0; v < cfg->getNumViews(VIEW_SHARED, dispName); v++) - { - const char * sharedViewName = cfg->getView(VIEW_SHARED, dispName, v); - if (sharedViewName && *sharedViewName && Platform::Strcasecmp(sharedViewName, viewName) == 0) - { - return true; - } - } - - return false; -} - -bool virtualViewIsShared(const ConstConfigRcPtr & cfg, - const char * viewName) -{ - for (int v = 0; v < cfg->getVirtualDisplayNumViews(VIEW_SHARED); v++) - { - const char * sharedViewName = cfg->getVirtualDisplayView(VIEW_SHARED, v); - if (sharedViewName && *sharedViewName && Platform::Strcasecmp(sharedViewName, viewName) == 0) - { - return true; - } - } - - return false; -} - -bool viewsAreEqual(const ConstConfigRcPtr & first, - const ConstConfigRcPtr & second, - const char * dispName, // may be empty or nullptr for shared views - const char * viewName) -{ - // It's ok to call this even for displays/views that don't exist, it will simply return false. - - // Note that this will return true even if the view is display-defined in one config and a reference - // to a shared view in the other config (both within the same display), as long as the contents match. - - // These calls return null if either the display or view doesn't exist (regardless if it's active). - const char * cs1 = first->getDisplayViewColorSpaceName(dispName, viewName); - const char * cs2 = second->getDisplayViewColorSpaceName(dispName, viewName); - - // If the color space is not null, the display and view exist. - if (cs1 && *cs1 && cs2 && *cs2) - { - // Both configs have a display and view by this name, now check the contents. - if (Platform::Strcasecmp(cs1, cs2) == 0) - { - // Note the remaining strings may be empty in a valid view. - // Intentionally not checking the description since it is not a functional difference. - if ( (Platform::Strcasecmp(first->getDisplayViewLooks(dispName, viewName), - second->getDisplayViewLooks(dispName, viewName)) == 0) && - (Platform::Strcasecmp(first->getDisplayViewTransformName(dispName, viewName), - second->getDisplayViewTransformName(dispName, viewName)) == 0) && - (Platform::Strcasecmp(first->getDisplayViewRule(dispName, viewName), - second->getDisplayViewRule(dispName, viewName)) == 0) ) - { - return true; - } - } - } - return false; -} - -bool virtualViewsAreEqual(const ConstConfigRcPtr & first, - const ConstConfigRcPtr & second, - const char * viewName) -{ - const char * cs1 = first->getVirtualDisplayViewColorSpaceName(viewName); - const char * cs2 = second->getVirtualDisplayViewColorSpaceName(viewName); - - // If the color space is not null, the display and view exist. - if (cs1 && *cs1 && cs2 && *cs2) - { - if (Platform::Strcasecmp(cs1, cs2) == 0) - { - // Note the remaining strings may be empty in a valid view. - // Intentionally not checking the description since it is not a functional difference. - if ( (Platform::Strcasecmp(first->getVirtualDisplayViewLooks(viewName), - second->getVirtualDisplayViewLooks(viewName)) == 0) && - (Platform::Strcasecmp(first->getVirtualDisplayViewTransformName(viewName), - second->getVirtualDisplayViewTransformName(viewName)) == 0) && - (Platform::Strcasecmp(first->getVirtualDisplayViewRule(viewName), - second->getVirtualDisplayViewRule(viewName)) == 0) ) - { - return true; - } - } - } - return false; -} - bool viewTransformsAreEqual(const ConstConfigRcPtr & first, const ConstConfigRcPtr & second, const char * name) @@ -901,7 +734,7 @@ bool viewTransformsAreEqual(const ConstConfigRcPtr & first, // Both configs have a view transform by this name, now check the parts. // Note: Not checking family or description since it is not a functional difference. - // FIXME: Check categories. + // TODO: Check categories. if (vt1->getReferenceSpaceType() != vt2->getReferenceSpaceType()) { @@ -917,7 +750,7 @@ bool viewTransformsAreEqual(const ConstConfigRcPtr & first, return false; } - // FIXME: Compare transforms. + // TODO: Compare transforms. } ConstTransformRcPtr t1_from = vt1->getTransform(VIEWTRANSFORM_DIR_FROM_REFERENCE); @@ -929,7 +762,7 @@ bool viewTransformsAreEqual(const ConstConfigRcPtr & first, return false; } - // FIXME: Compare transforms. + // TODO: Compare transforms. } return true; @@ -1086,7 +919,7 @@ void DisplayViewMerger::addUniqueDisplays(const ConstConfigRcPtr & cfg) // This will return true if the display contains either a display-defined or // shared view with this name. - const bool dispDefinedExists = displayHasView(m_mergedConfig, dispName, displayDefinedView); + const bool dispDefinedExists = m_mergedConfig->hasView(dispName, displayDefinedView); if (displayDefinedView && *displayDefinedView && !dispDefinedExists) { @@ -1106,7 +939,7 @@ void DisplayViewMerger::addUniqueDisplays(const ConstConfigRcPtr & cfg) { const char * sharedViewName = cfg->getView(VIEW_SHARED, dispName, v); - const bool sharedViewExists = displayHasView(m_mergedConfig, dispName, sharedViewName); + const bool sharedViewExists = m_mergedConfig->hasView(dispName, sharedViewName); if (sharedViewName && *sharedViewName && !sharedViewExists) { @@ -1122,7 +955,7 @@ void DisplayViewMerger::addUniqueVirtualViews(const ConstConfigRcPtr & cfg) for (int v = 0; v < cfg->getVirtualDisplayNumViews(VIEW_DISPLAY_DEFINED); v++) { const char * displayDefinedView = cfg->getVirtualDisplayView(VIEW_DISPLAY_DEFINED, v); - const bool dispDefinedExists = hasVirtualView(m_mergedConfig, displayDefinedView); + const bool dispDefinedExists = m_mergedConfig->hasVirtualView(displayDefinedView); if (displayDefinedView && *displayDefinedView && !dispDefinedExists) { m_mergedConfig->addVirtualDisplayView(displayDefinedView, @@ -1138,7 +971,7 @@ void DisplayViewMerger::addUniqueVirtualViews(const ConstConfigRcPtr & cfg) for (int v = 0; v < cfg->getVirtualDisplayNumViews(VIEW_SHARED); v++) { const char * sharedViewName = cfg->getVirtualDisplayView(VIEW_SHARED, v); - const bool sharedViewExists = hasVirtualView(m_mergedConfig, sharedViewName); + const bool sharedViewExists = m_mergedConfig->hasVirtualView(sharedViewName); if (sharedViewName && *sharedViewName && !sharedViewExists) { m_mergedConfig->addVirtualDisplaySharedView(sharedViewName); @@ -1167,9 +1000,9 @@ void DisplayViewMerger::processDisplays(const ConstConfigRcPtr & first, // One case to be aware of is where both configs have the same display with the same // view name, but it's a display-defined view in one and a shared view in the other. // This check will return true if it exists in either form. - const bool existsInSecond = displayHasView(second, dispName, displayDefinedView); + const bool existsInSecond = second->hasView(dispName, displayDefinedView); - if (existsInSecond && !viewsAreEqual(first, second, dispName, displayDefinedView)) + if (existsInSecond && !Config::AreViewsEqual(first, second, dispName, displayDefinedView)) { // Throw or log on conflict. std::ostringstream os; @@ -1185,7 +1018,7 @@ void DisplayViewMerger::processDisplays(const ConstConfigRcPtr & first, // This was a display-defined view in the first config but it may not be in // the second config. Want to add it as the same type of view. - if (viewIsShared(second, dispName, displayDefinedView)) + if (second->isViewShared(dispName, displayDefinedView)) { // Note that this may change the order in a way that does not follow // the preference of input-first or base-first. @@ -1225,19 +1058,19 @@ void DisplayViewMerger::processDisplays(const ConstConfigRcPtr & first, if (sharedViewName && *sharedViewName) { - const bool existsInSecond = displayHasView(second, dispName, sharedViewName); + const bool existsInSecond = second->hasView(dispName, sharedViewName); if (existsInSecond && preferSecond) { // This was a shared view in the first config but it may not be in // the second config. Want to add it as the same type of view. - if (viewIsShared(second, dispName, sharedViewName)) + if (second->isViewShared(dispName, sharedViewName)) { m_mergedConfig->addDisplaySharedView(dispName, sharedViewName); } else { - if (!viewsAreEqual(first, second, dispName, sharedViewName)) + if (!Config::AreViewsEqual(first, second, dispName, sharedViewName)) { // Throw or log on conflict. std::ostringstream os; @@ -1281,9 +1114,9 @@ void DisplayViewMerger::processVirtualDisplay(const ConstConfigRcPtr & first, if (displayDefinedView && *displayDefinedView) { // Check if it displays shared view exists in second config. - const bool existsInSecond = hasVirtualView(second, displayDefinedView); + const bool existsInSecond = second->hasVirtualView(displayDefinedView); - if (existsInSecond && !virtualViewsAreEqual(first, second, displayDefinedView)) + if (existsInSecond && !Config::AreVirtualViewsEqual(first, second, displayDefinedView)) { // Throw or log on conflict. std::ostringstream os; @@ -1299,7 +1132,7 @@ void DisplayViewMerger::processVirtualDisplay(const ConstConfigRcPtr & first, // This was a display-defined view in the first config but it may not be in // the second config. Want to add it as the same type of view. - if (virtualViewIsShared(second, displayDefinedView)) + if (second->isVirtualViewShared(displayDefinedView)) { m_mergedConfig->addVirtualDisplaySharedView(displayDefinedView); } @@ -1335,19 +1168,19 @@ void DisplayViewMerger::processVirtualDisplay(const ConstConfigRcPtr & first, if (sharedViewName && *sharedViewName) { - const bool existsInSecond = hasVirtualView(second, sharedViewName); + const bool existsInSecond = second->hasVirtualView(sharedViewName); if (existsInSecond && preferSecond) { // This was a shared view in the first config but it may not be in // the second config. Want to add it as the same type of view. - if (virtualViewIsShared(second, sharedViewName)) + if (second->isVirtualViewShared(sharedViewName)) { m_mergedConfig->addVirtualDisplaySharedView(sharedViewName); } else { - if (!virtualViewsAreEqual(first, second, sharedViewName)) + if (!Config::AreVirtualViewsEqual(first, second, sharedViewName)) { // Throw or log on conflict. std::ostringstream os; @@ -1386,7 +1219,7 @@ void DisplayViewMerger::addUniqueSharedViews(const ConstConfigRcPtr & cfg) const char * sharedViewName = cfg->getView(VIEW_SHARED, nullptr, v); // Check if shared view exists in merged config. - bool sharedViewExists = displayHasView(m_mergedConfig, nullptr, sharedViewName); + bool sharedViewExists = m_mergedConfig->hasView(nullptr, sharedViewName); if (sharedViewName && *sharedViewName && !sharedViewExists) { @@ -1412,9 +1245,9 @@ void DisplayViewMerger::processSharedViews(const ConstConfigRcPtr & first, if (sharedViewName && *sharedViewName) { // Check if shared view exists in second config. - bool existsInSecond = displayHasView(second, nullptr, sharedViewName); + bool existsInSecond = second->hasView(nullptr, sharedViewName); - if (existsInSecond && !viewsAreEqual(first, second, nullptr, sharedViewName)) + if (existsInSecond && !Config::AreViewsEqual(first, second, nullptr, sharedViewName)) { // Throw or log on conflict. std::ostringstream os; @@ -1558,10 +1391,6 @@ void DisplayViewMerger::processViewTransforms(const ConstConfigRcPtr & first, bool preferSecond, bool secondIsInput) { - // FIXME: Should do this once for color spaces & view transforms. -// ConstTransformRcPtr inputToBaseGtScene, inputToBaseGtDisplay; -// initializeRefSpaceConverters(inputToBaseGtScene, inputToBaseGtDisplay); - for (int i = 0; i < first->getNumViewTransforms(); i++) { const char * name = first->getViewTransformNameByIndex(i); @@ -1660,7 +1489,7 @@ void DisplayViewMerger::handlePreferInput() // Clear displays and shared_views from merged config. m_mergedConfig->clearDisplays(); - clearSharedViews(m_mergedConfig); + m_mergedConfig->clearSharedViews(); // Merge displays and views. // The order is important: shared_views, and then displays. @@ -1729,7 +1558,7 @@ void DisplayViewMerger::handlePreferBase() { // Clear displays and shared_views from merged config. m_mergedConfig->clearDisplays(); - clearSharedViews(m_mergedConfig); + m_mergedConfig->clearSharedViews(); // Merge displays and views. // The order is important: shared_views, and then displays. @@ -1798,7 +1627,7 @@ void DisplayViewMerger::handleInputOnly() { // Clear displays and shared_views from merged config. m_mergedConfig->clearDisplays(); - clearSharedViews(m_mergedConfig); + m_mergedConfig->clearSharedViews(); // Merge displays and views. addUniqueSharedViews(m_inputConfig); @@ -1869,14 +1698,14 @@ void DisplayViewMerger::handleRemove() { // Remove shared_views. - clearSharedViews(m_mergedConfig); + m_mergedConfig->clearSharedViews(); for (int v = 0; v < m_baseConfig->getNumViews(VIEW_SHARED, nullptr); v++) { // Add shared views that are present in the base config and NOT present in the input config. const char * sharedViewName = m_baseConfig->getView(VIEW_SHARED, nullptr, v); if (sharedViewName && *sharedViewName - && !displayHasView(m_inputConfig, nullptr, sharedViewName)) + && !m_inputConfig->hasView(nullptr, sharedViewName)) { m_mergedConfig->addSharedView(sharedViewName, m_baseConfig->getDisplayViewTransformName(nullptr, sharedViewName), @@ -1902,7 +1731,7 @@ void DisplayViewMerger::handleRemove() const char * displayDefinedView = m_baseConfig->getView(VIEW_DISPLAY_DEFINED, dispName, v); // Check if the view is not present in the input config. if (displayDefinedView && *displayDefinedView - && !displayHasView(m_inputConfig, dispName, displayDefinedView)) + && !m_inputConfig->hasView(dispName, displayDefinedView)) { m_mergedConfig->addDisplayView(dispName, displayDefinedView, @@ -1920,7 +1749,7 @@ void DisplayViewMerger::handleRemove() const char * sharedViewName = m_baseConfig->getView(VIEW_SHARED, dispName, v); // Check if the view is not present in the input config. if (sharedViewName && *sharedViewName - && !displayHasView(m_inputConfig, dispName, sharedViewName)) + && !m_inputConfig->hasView(dispName, sharedViewName)) { m_mergedConfig->addDisplaySharedView(dispName, sharedViewName); } @@ -1940,7 +1769,7 @@ void DisplayViewMerger::handleRemove() const char * displayDefinedView = m_baseConfig->getVirtualDisplayView(VIEW_DISPLAY_DEFINED, v); // Check if the view is not present in the input config. if (displayDefinedView && *displayDefinedView - && !hasVirtualView(m_inputConfig, displayDefinedView)) + && !m_inputConfig->hasVirtualView(displayDefinedView)) { // Add the display defined view m_mergedConfig->addVirtualDisplayView(displayDefinedView, @@ -1958,7 +1787,7 @@ void DisplayViewMerger::handleRemove() const char * sharedViewName = m_baseConfig->getVirtualDisplayView(VIEW_SHARED, v); // Check if the view is not present in the input config. if (sharedViewName && *sharedViewName - && !hasVirtualView(m_inputConfig, sharedViewName)) + && !m_inputConfig->hasVirtualView(sharedViewName)) { // Add the shared view m_mergedConfig->addVirtualDisplaySharedView(sharedViewName); @@ -2035,10 +1864,10 @@ void DisplayViewMerger::handleRemove() m_mergedConfig->setViewingRules(mergedRules); } -/////////////////////////////////// DisplayViewMerger end //////////////////////////////// +/////////////////////////////////// DisplayViewMerger //////////////////////////////////// +/////////////////////////////////// LooksMerger ////////////////////////////////////////// -////////////////////////////////////////// LooksMerger //////////////////////////////////////////// void LooksMerger::handlePreferInput() { m_mergedConfig->clearLooks(); @@ -2144,150 +1973,9 @@ void LooksMerger::handleRemove() } } -////////////////////////////////////// LooksMerger end //////////////////////////////////////////// - - -/////////////////////////////////////// ColorspacesMerger ///////////////////////////////////////// - -/* -void ColorspacesMerger::handleErrorCodes(ColorSpaceRcPtr & eColorspace) -{ - switch (errorCode) - { - case ADD_CS_ERROR_NAME_IDENTICAL_TO_A_ROLE_NAME: - skipCurrentColorspace = handleAddCsErrorNameIdenticalToARoleName(eColorspace); - break; - - case ADD_CS_ERROR_NAME_IDENTICAL_TO_NT_NAME_OR_ALIAS: - skipCurrentColorspace = handleAddCsErrorNameIdenticalToNTNameOrAlias(eColorspace); - break; - - case ADD_CS_ERROR_NAME_CONTAIN_CTX_VAR_TOKEN: - // Not handled as it can't happen in this context. - // The config will error out while loading the config (before the merge process). - break; - - case ADD_CS_ERROR_NAME_IDENTICAL_TO_EXISTING_COLORSPACE_ALIAS: - skipCurrentColorspace = handleAddCsErrorNameIdenticalToExistingColorspaceAlias(eColorspace); - break; - - case ADD_CS_ERROR_ALIAS_IDENTICAL_TO_A_ROLE_NAME: - skipCurrentColorspace = handleAddCsErrorAliasIdenticalToARoleName(eColorspace); - break; - - case ADD_CS_ERROR_ALIAS_IDENTICAL_TO_NT_NAME_OR_ALIAS: - skipCurrentColorspace = handleAddCsErrorAliasIdenticalToNTNameOrAlias(eColorspace); - break; - - case ADD_CS_ERROR_ALIAS_CONTAIN_CTX_VAR_TOKEN: - // Not handled as it can't happen in this context. - // The config will error out while loading the config (before the merge process). - break; - - case ADD_CS_ERROR_ALIAS_IDENTICAL_TO_EXISTING_COLORSPACE_NAME: - skipCurrentColorspace = handleAddCsErrorAliasIdenticalToExistingColorspaceName(eColorspace); - break; - - case ADD_CS_ERROR_ALIAS_IDENTICAL_TO_EXISTING_COLORSPACE_ALIAS: - skipCurrentColorspace = handleAddCsErrorAliasIdenticalToExistingColorspaceAlias(eColorspace); - break; - - case ADD_CS_ERROR_NONE: - allErrorsResolved = true; - break; - - case ADD_CS_ERROR_EMPTY: - // Nothing to do. - break; - - default: - break; - } -} -*/ - -//TODO We need to decide if we want to do this or it is the responsibility of the person -// doing the merge. -/* -void ColorspacesMerger::handleMarkedToBeDeletedColorspaces() -{ - // Go through the marked colorspaces, remove them and replace their name. - // colorspace %duplicate% should be deleted and the named replaced everywhere it is used. - - - if (m_colorspaceMarkedToBeDeleted.size() > 0) - { - // A color space name may appear in the following places: - // ColorSpaceTransforms (src, dst) - // DisplayViewTransforms (src) - // Look (process_space) - // View (colorspace, display_colorspace) - // inactive_colorspaces, - // file_rules (colorspace), - // viewing_rules (colorspaces list) - - // roles - // for (int r = 0; r < m_mergedConfig->getNumRoles(); r++) - // { - // auto csName = m_mergedConfig->getRoleColorSpace(r); - // for (int i = 0; i < m_colorspaceMarkedToBeDeleted.size(); i++) - // { - // if (Platform::Strcasecmp(csName, m_colorspaceMarkedToBeDeleted[i].c_str()) == 0) - // { - // // Replace the name with the colorspace that we kept earlier. - // m_mergedConfig->setRole(m_mergedConfig->getRoleName(r), - // m_colorspaceReplacingMarkedCs[i].c_str()); - // } - // } - // } - - // // environment - // for (int e = 0; e < m_mergedConfig->getNumEnvironmentVars(); e++) - // { - // const char * name = m_mergedConfig->getEnvironmentVarNameByIndex(e); - // const char * value = m_mergedConfig->getEnvironmentVarDefault(name); - // for (int i = 0; i < m_colorspaceMarkedToBeDeleted.size(); i++) - // { - // if (Platform::Strcasecmp(value, m_colorspaceMarkedToBeDeleted[i].c_str()) == 0) - // { - // // Replace the name with the colorspace that we kept earlier. - // m_mergedConfig->addEnvironmentVar(name, m_colorspaceReplacingMarkedCs[i].c_str()); - // } - // } - // } - - m_colorspaceMarkedToBeDeleted.clear(); - m_colorspaceReplacingMarkedCs.clear(); - } -} - -void ColorspacesMerger::replaceFamilySeparatorInFamily(ColorSpaceRcPtr & incomingCs) -{ - std::string family = incomingCs->getFamily(); - if (!family.empty()) - { - char separator = '/'; - std::string updatedFamily = ""; - - if (m_params->getColorspaces() == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT) - { - // Incoming colorspaces are from the base config. - separator = m_baseConfig->getFamilySeparator(); - } - else if (m_params->getColorspaces() == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_BASE) - { - // Incoming colorspaces are from the input config. - separator = m_inputConfig->getFamilySeparator(); - } +/////////////////////////////////// LooksMerger ////////////////////////////////////////// - std::string separatorStr(1, separator); - std::string mergedSeparatorStr(1, m_mergedConfig->getFamilySeparator()); - updatedFamily = StringUtils::Replace(incomingCs->getFamily(), separatorStr, mergedSeparatorStr); - incomingCs->setFamily(updatedFamily.c_str()); - } - // Do nothing if family is empty -} -*/ +/////////////////////////////////// ColorspacesMerger //////////////////////////////////// bool hasSearchPath(const ConstConfigRcPtr & cfg, const char * path) { @@ -2311,45 +1999,11 @@ void ColorspacesMerger::processSearchPaths() const return; } -// TODO: Should the strategy determine which path should go first? -// E.g., if preferInput, give the input paths priority in the search. - -// if (m_params->isInputFirst()) -// { -// m_mergedConfig->clearSearchPaths(); -// // Add all from input config. -// for (int i = 0; i < m_inputConfig->getNumSearchPaths(); i++) -// { -// m_mergedConfig->addSearchPath(m_inputConfig->getSearchPath(i)); -// } -// -// // Only add the new ones from the base config. -// for (int i = 0; i < m_baseConfig->getNumSearchPaths(); i++) -// { -// if (!hasSearchPath(m_inputConfig, m_baseConfig->getSearchPath(i))) -// { -// m_mergedConfig->addSearchPath(m_baseConfig->getSearchPath(i)); -// } -// } -// } -// else -// { -// // NB: The m_mergedConfig is initialized with the contents of the m_baseConfig. -// -// for (int i = 0; i < m_inputConfig->getNumSearchPaths(); i++) -// { -// if (!hasSearchPath(m_baseConfig, m_inputConfig->getSearchPath(i))) -// { -// m_mergedConfig->addSearchPath(m_inputConfig->getSearchPath(i)); -// } -// } -// } - // Ignoring isInputFirst for the ordering of search paths because it seems that it // really should be driven by the strategy. E.g., if both base and input have a "luts" // directory, want to be looking in the right one. - // But more work is needed here. Absolute paths should be set up for input since + // TODO: More work is needed here. Absolute paths should be set up for input since // the working dir is from the base config. if (m_params->getColorspaces() == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT) @@ -2466,58 +2120,6 @@ void ColorspacesMerger::updateFamily(std::string & family, bool fromBase) const family = updatedPrefix + family; } -// bool hasColorSpaceRefType(const ConstConfigRcPtr & config, ReferenceSpaceType refType) -// { -// SearchReferenceSpaceType searchRefType = static_cast(refType); -// int n = config->getNumColorSpaces(searchRefType, COLORSPACE_ALL); -// return n > 0; -// } -// -// void ColorspacesMerger::initializeRefSpaceConverters(ConstTransformRcPtr & inputToBaseGtScene, -// ConstTransformRcPtr & inputToBaseGtDisplay) -// { -// // Note: The base config reference space is always used, regardless of strategy. -// -// if (!m_params->isAssumeCommonReferenceSpace()) -// { -// if (hasColorSpaceRefType(m_inputConfig, REFERENCE_SPACE_SCENE)) -// { -// try -// { -// inputToBaseGtScene = ConfigUtils::getRefSpaceConverter( -// m_inputConfig, -// m_baseConfig, -// REFERENCE_SPACE_SCENE -// ); -// } -// catch(const Exception & e) -// { -// LogError(e.what()); -// } -// } -// -// // Only attempt to build the converter if the input config has this type of -// // reference space. Using the input config for this determination since it is -// // only input config color spaces whose reference space is converted. -// if (hasColorSpaceRefType(m_inputConfig, REFERENCE_SPACE_DISPLAY)) -// { -// try -// { -// inputToBaseGtDisplay = ConfigUtils::getRefSpaceConverter( -// m_inputConfig, -// m_baseConfig, -// REFERENCE_SPACE_DISPLAY -// ); -// } -// catch(const Exception & e) -// { -// LogError(e.what()); -// } -// } -// } -// } - -// TODO: Make this a functional inside where it's called from. void ColorspacesMerger::attemptToAddAlias(const ConstConfigRcPtr & mergeConfig, ColorSpaceRcPtr & dupeCS, const ConstColorSpaceRcPtr & inputCS, @@ -2531,7 +2133,7 @@ void ColorspacesMerger::attemptToAddAlias(const ConstConfigRcPtr & mergeConfig, // It's OK if aliasName is used in the duplicate color space itself. if ((Platform::Strcasecmp(dupeCS->getName(), aliasName) == 0) - || hasAlias(dupeCS, aliasName)) + || dupeCS->hasAlias(aliasName)) { // It's already present, no need to add anything. return; @@ -2593,30 +2195,16 @@ bool ColorspacesMerger::handleAvoidDuplicatesOption(ConfigUtils::ColorSpaceFinge // (e.g., consider the CIE-XYZ-D65 space, which is typically inactive). However, // when the inactive list is regenerated to avoid listing removed color spaces, // some color spaces that were inactive may become active. -// const char * duplicateInBase = ConfigUtils::findEquivalentColorspace( -// eBase, -// inputConfig, inputCS, -// inputCS->getReferenceSpaceType() -// ); const char * duplicateInBase = ConfigUtils::findEquivalentColorspace( fingerprints, inputConfig, inputCS ); -// TODO: Could this be refactored to go through the usual merge process? - -// FIXME: Should copy categories too. Maybe encoding. - const ConfigMergingParameters::MergeStrategies strategy = m_params->getColorspaces(); if (duplicateInBase && *duplicateInBase) { -//std::cout << "dupe base: " << duplicateInBase << " input: " << inputCS->getName() << "\n"; - if (strategy == ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT) { -// m_colorspaceMarkedToBeDeleted.push_back(duplicateInBase); -// m_colorspaceReplacingMarkedCs.push_back(inputCS->getName()); - // Add the name and aliases from the duplicate colorspace to the input colorspace. // // Note that the aliases added here should not have conflicts with the base config @@ -2639,8 +2227,7 @@ bool ColorspacesMerger::handleAvoidDuplicatesOption(ConfigUtils::ColorSpaceFinge inputCS->addAlias(dupeCS->getAlias(i)); } - // FIXME: This should be controlled by an merge option. - // There are currently no unit tests for this. + // TODO: This should be controlled by a merge option. for (int i = 0; i < dupeCS->getNumCategories(); i++) { inputCS->addCategory(dupeCS->getCategory(i)); @@ -2654,18 +2241,10 @@ bool ColorspacesMerger::handleAvoidDuplicatesOption(ConfigUtils::ColorSpaceFinge const char * duplicateCurrentName = eBase->getCanonicalName(duplicateInBase); eBase->removeColorSpace(duplicateCurrentName); - // If the name is different, notify that it is replacing a color space in base. -// if (Platform::Strcasecmp(inputCS->getName(), duplicateInBase) != 0) -// { - std::ostringstream os; -// os << "Color space '" << inputCS->getName() << "' replaces its equivalent '" -// << duplicateCurrentName << "' in the base config (aliases copied)."; -// os << "Equivalent color space '" << inputCS->getName() << "' from the input config replaces '" -// << duplicateCurrentName << "' in the base config, preserving aliases."; - os << "Equivalent input color space '" << inputCS->getName() << "' replaces '" - << duplicateCurrentName << "' in the base config, preserving aliases."; - notify(os.str(), m_params->isErrorOnConflict()); -// } + std::ostringstream os; + os << "Equivalent input color space '" << inputCS->getName() << "' replaces '" + << duplicateCurrentName << "' in the base config, preserving aliases."; + notify(os.str(), m_params->isErrorOnConflict()); // Still want the caller to proceed merging inputCS into the merge config. notDuplicate = true; @@ -2702,21 +2281,10 @@ bool ColorspacesMerger::handleAvoidDuplicatesOption(ConfigUtils::ColorSpaceFinge // order in the color space list.) eBase->addColorSpace(eCS); - // If the name is different, notify that it won't replace a color space in base. -// if (Platform::Strcasecmp(inputCS->getName(), duplicateInBase) != 0) -// { - std::ostringstream os; -// os << "The name/aliases of color space '" << inputCS->getName() << -// "' will be transferred its equivalent '" -// << duplicateInBase << "' in the base config."; -// os << "Color space '" << inputCS->getName() << "' won't replace its equivalent '" -// << duplicateCurrentName << "' in the base config (aliases are copied)."; -// os << "Equivalent color space '" << duplicateInBase << "' from the base config overrides '" -// << inputCS->getName() << "' in the input config, preserving aliases."; - os << "Equivalent base color space '" << duplicateInBase << "' overrides '" - << inputCS->getName() << "' in the input config, preserving aliases."; - notify(os.str(), m_params->isErrorOnConflict()); -// } + std::ostringstream os; + os << "Equivalent base color space '" << duplicateInBase << "' overrides '" + << inputCS->getName() << "' in the input config, preserving aliases."; + notify(os.str(), m_params->isErrorOnConflict()); // The base color space is edited here, don't want to add inputCS. notDuplicate = false; @@ -2874,7 +2442,7 @@ void ColorspacesMerger::mergeColorSpace(ConfigRcPtr & mergeConfig, // Verify that the name is actually an alias rather than some other conflict. // (Should never happen.) - if (!hasAlias(existingCS, name)) + if (!existingCS->hasAlias(name)) { std::ostringstream os; os << "Problem merging color space: '" << name << "'."; @@ -2938,7 +2506,7 @@ void ColorspacesMerger::mergeColorSpace(ConfigRcPtr & mergeConfig, eInputCS->removeAlias(aliasName); } } - else if (hasAlias(conflictingCS, aliasName)) + else if (conflictingCS->hasAlias(aliasName)) { // The alias conflicts with an alias of the conflicting color space. @@ -3011,9 +2579,6 @@ void ColorspacesMerger::addColorSpaces() mergeConfig->clearNamedTransforms(); -// ConstTransformRcPtr inputToBaseGtScene, inputToBaseGtDisplay; -// initializeRefSpaceConverters(inputToBaseGtScene, inputToBaseGtDisplay); - // Loop over all active and inactive color spaces of all reference types in the input config. // Merge them into the temp config (which already contains the base color spaces). std::vector addedInputColorSpaces; @@ -3046,7 +2611,6 @@ void ColorspacesMerger::addColorSpaces() // recent state of any aliases that get added or color spaces that are removed are // considered by the duplicate consolidation process. const bool notDuplicate = handleAvoidDuplicatesOption(fingerprints, mergeConfig, m_inputConfig, eCS); -// const bool notDuplicate = true; if (notDuplicate && colorSpaceMayBeMerged(mergeConfig, eCS)) { @@ -3455,10 +3019,9 @@ void ColorspacesMerger::handleRemove() } } -/////////////////////////////////// ColorspacesMerger end ///////////////////////////////////////// - +/////////////////////////////////// ColorspacesMerger //////////////////////////////////// -///////////////////////////////////// NamedTransformsMerger /////////////////////////////////////// +/////////////////////////////////// NamedTransformsMerger //////////////////////////////// void NamedTransformsMerger::updateFamily(std::string & family, bool fromBase) const { @@ -3684,7 +3247,7 @@ void NamedTransformsMerger::mergeNamedTransform(ConfigRcPtr & mergeConfig, // Verify that the name is actually an alias rather than some other conflict. // (Should never happen.) - if (!hasAlias(existingNT, name)) + if (!existingNT->hasAlias(name)) { std::ostringstream os; os << "Problem merging named transform: '" << name << "'."; @@ -3747,7 +3310,7 @@ void NamedTransformsMerger::mergeNamedTransform(ConfigRcPtr & mergeConfig, // Remove the alias from the named transform. eNT->removeAlias(aliasName); } - else if (hasAlias(conflictingCS, aliasName)) + else if (conflictingCS->hasAlias(aliasName)) { // The alias conflicts with an alias of the conflicting color space. @@ -3805,7 +3368,7 @@ void NamedTransformsMerger::mergeNamedTransform(ConfigRcPtr & mergeConfig, eNT->removeAlias(aliasName); } } - else if (hasAlias(conflictingNT, aliasName)) + else if (conflictingNT->hasAlias(aliasName)) { // The alias conflicts with an alias of the conflicting named transform. @@ -3845,17 +3408,11 @@ void NamedTransformsMerger::mergeNamedTransform(ConfigRcPtr & mergeConfig, // (But all name conflicts should have been handled already.) mergeConfig->addNamedTransform(eNT); - // Keep a record that this input color space was added to allow reordering later. + // Keep a record that this input NT was added to allow reordering later. if (!fromBase) { addedInputNamedTransforms.push_back(name); } - - // TODO: Is it ever possible that a CS added to the list would be removed as another is merged? - - // TODO: When color spaces or aliases are removed above, it's possible it could break - // some other part of the config that referenced them. This would include elements such as: - // environment, views, inactive_colorspaces, ColorSpaceTransforms, or DisplayViewTransforms. } void NamedTransformsMerger::addNamedTransforms() @@ -3918,8 +3475,7 @@ void NamedTransformsMerger::addNamedTransforms() // recent state of any aliases that get added or color spaces that are removed are // considered by the duplicate consolidation process. -// FIXME: Handle duplicate named transforms. -// const bool notDuplicate = handleAvoidDuplicatesOption(mergeConfig, eCS); + // TODO: Handle duplicate named transforms. const bool fromBase = false; if (namedTransformMayBeMerged(mergeConfig, eNT, fromBase)) @@ -4015,63 +3571,6 @@ void NamedTransformsMerger::addNamedTransforms() // TODO: What if the environment contains a color space that was removed? } -/* -void NamedTransformsMerger::handleErrorCodes(NamedTransformRcPtr & eNamedTransform) -{ - switch (errorCode) - { - case ADD_NT_ERROR_NONE: - allErrorsResolved = true; - break; - case ADD_NT_ERROR_NULL: - // Should not happen. - break; - case ADD_NT_ERROR_EMPTY: - // Should not happen. - break; - - case ADD_NT_ERROR_AT_LEAST_ONE_TRANSFORM: - skipCurrentNamedTransform = handleAddNtErrorNeedAtLeastOneTransform(eNamedTransform); - break; - - case ADD_NT_ERROR_NAME_IDENTICAL_TO_A_ROLE_NAME: - skipCurrentNamedTransform = handleAddNtErrorNameIdenticalToARoleName(eNamedTransform); - break; - - case ADD_NT_ERROR_NAME_IDENTICAL_TO_COLORSPACE_OR_ALIAS: - skipCurrentNamedTransform = handleAddNtErrorNameIdenticalToColorspaceNameOrAlias(eNamedTransform); - break; - - case ADD_NT_ERROR_NAME_CONTAIN_CTX_VAR_TOKEN: - // Should not happen. It will error out before the merge process. - break; - - case ADD_NT_ERROR_NAME_IDENTICAL_TO_EXISTING_NT_ALIAS: - skipCurrentNamedTransform = handleAddNtErrorNameIdenticalToExistingNtAlias(eNamedTransform); - break; - - case ADD_NT_ERROR_ALIAS_IDENTICAL_TO_A_ROLE_NAME: - skipCurrentNamedTransform = handleAddNtErrorAliasIdenticalToARoleName(eNamedTransform); - break; - - case ADD_NT_ERROR_ALIAS_IDENTICAL_TO_COLORSPACE_OR_ALIAS: - skipCurrentNamedTransform = handleAddNtErrorAliasIdenticalToColorspaceNameOrAlias(eNamedTransform); - break; - - case ADD_NT_ERROR_ALIAS_CONTAIN_CTX_VAR_TOKEN: - // Should not happen. It will error out before the merge process. - break; - - case ADD_NT_ERROR_ALIAS_IDENTICAL_TO_EXISTING_NT_ALIAS: - skipCurrentNamedTransform = handleAddNtErrorAliasIdenticalToExistingNtAlias(eNamedTransform); - break; - - default: - break; - } -} -*/ - void NamedTransformsMerger::handlePreferInput() { addNamedTransforms(); @@ -4176,6 +3675,6 @@ void NamedTransformsMerger::handleRemove() cleanUpInactiveList(m_mergedConfig); } -///////////////////////////////// NamedTransformsMerger end /////////////////////////////////////// +/////////////////////////////////// NamedTransformsMerger //////////////////////////////// } // namespace OCIO_NAMESPACE \ No newline at end of file diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.h b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.h index 2eb5beacc1..ae03b2f015 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.h +++ b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.h @@ -34,20 +34,11 @@ class SectionMerger SectionMerger(MergeHandlerOptions options) : m_baseConfig(options.baseConfig), m_inputConfig(options.inputConfig), m_mergedConfig(options.mergedConfig), m_params(options.params) -// m_inputToBaseGtScene(nullptr), m_inputToBaseGtDisplay(nullptr) { if (!options.baseConfig || !options.inputConfig || !options.mergedConfig || !options.params) { throw Exception("SectionMerger arguments were not initialized."); } -// m_strategy = options.params->getDefaultStrategy(); -// m_params->setDefaultStrategy(options.params->getDefaultStrategy()); - -// ConstTransformRcPtr tmp; -// m_inputToBaseGtScene = tmp; -// m_inputToBaseGtDisplay = tmp; - -// initializeRefSpaceConverters(); } void merge() @@ -69,7 +60,7 @@ class SectionMerger case ConfigMergingParameters::MergeStrategies::STRATEGY_REMOVE: handleRemove(); break; - case ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET: + case ConfigMergingParameters::MergeStrategies::STRATEGY_UNSPECIFIED: // Nothing to do. break; default: @@ -79,68 +70,6 @@ class SectionMerger void notify(std::string s, bool mustThrow) const; -// // FIXME: Make this a functional. -// bool hasColorSpaceRefType(const ConstConfigRcPtr & config, ReferenceSpaceType refType) -// { -// SearchReferenceSpaceType searchRefType = static_cast(refType); -// int n = config->getNumColorSpaces(searchRefType, COLORSPACE_ALL); -// return n > 0; -// } -// -// void initializeRefSpaceConverters() -// { -// // Note: The base config reference space is always used, regardless of strategy. -// //std::cout << "initializing ref converters\n"; -// -// if (!m_params->isAssumeCommonReferenceSpace()) -// { -// if (hasColorSpaceRefType(m_inputConfig, REFERENCE_SPACE_SCENE)) -// { -// try -// { -// m_inputToBaseGtScene = ConfigUtils::getRefSpaceConverter( -// m_inputConfig, -// m_baseConfig, -// REFERENCE_SPACE_SCENE -// ); -// } -// catch(const Exception & e) -// { -// LogError(e.what()); -// } -// } -// else -// { -// // Always need both transforms, even if they're empty. -// m_inputToBaseGtScene = GroupTransform::Create(); -// } -// -// // Only attempt to build the converter if the input config has this type of -// // reference space. Using the input config for this determination since it is -// // only input config color spaces whose reference space is converted. -// if (hasColorSpaceRefType(m_inputConfig, REFERENCE_SPACE_DISPLAY)) -// { -// try -// { -// m_inputToBaseGtDisplay = ConfigUtils::getRefSpaceConverter( -// m_inputConfig, -// m_baseConfig, -// REFERENCE_SPACE_DISPLAY -// ); -// } -// catch(const Exception & e) -// { -// LogError(e.what()); -// } -// } -// else -// { -// // Always need both transforms, even if they're empty. -// m_inputToBaseGtDisplay = GroupTransform::Create(); -// } -// } -// } - private: virtual void handlePreferInput() { @@ -175,8 +104,8 @@ class SectionMerger const ConfigMergingParametersRcPtr & m_params; ConfigMergingParameters::MergeStrategies m_strategy; -// FIXME: These are initialized separately for display-views and colorspaces, perhaps move -// these up to the config merger level? + // TODO: These are initialized separately for display-views and colorspaces, perhaps + // move these up to the config merger level? ConstTransformRcPtr m_inputToBaseGtScene; ConstTransformRcPtr m_inputToBaseGtDisplay; @@ -215,7 +144,7 @@ class RolesMerger : public SectionMerger RolesMerger(MergeHandlerOptions options) : SectionMerger(options) { ConfigMergingParameters::MergeStrategies strat = options.params->getRoles(); - if (strat != ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET) + if (strat != ConfigMergingParameters::MergeStrategies::STRATEGY_UNSPECIFIED) { m_strategy = strat; } @@ -242,7 +171,7 @@ class FileRulesMerger : public SectionMerger FileRulesMerger(MergeHandlerOptions options) : SectionMerger(options) { ConfigMergingParameters::MergeStrategies strat = options.params->getFileRules(); - if (strat != ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET) + if (strat != ConfigMergingParameters::MergeStrategies::STRATEGY_UNSPECIFIED) { m_strategy = strat; } @@ -272,7 +201,7 @@ class DisplayViewMerger : public SectionMerger DisplayViewMerger(MergeHandlerOptions options) : SectionMerger(options) { ConfigMergingParameters::MergeStrategies strat = options.params->getDisplayViews(); - if (strat != ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET) + if (strat != ConfigMergingParameters::MergeStrategies::STRATEGY_UNSPECIFIED) { m_strategy = strat; } @@ -281,9 +210,10 @@ class DisplayViewMerger : public SectionMerger m_strategy = options.params->getDefaultStrategy(); } -// initializeRefSpaceConverters(); if (!options.params->isAssumeCommonReferenceSpace()) { + // TODO: This may throw, is it worth continuing without ref space conversion? + // Just call LogError() and continue? ConfigUtils::initializeRefSpaceConverters(m_inputToBaseGtScene, m_inputToBaseGtDisplay, m_baseConfig, @@ -335,7 +265,7 @@ class LooksMerger : public SectionMerger LooksMerger(MergeHandlerOptions options) : SectionMerger(options) { ConfigMergingParameters::MergeStrategies strat = options.params->getLooks(); - if (strat != ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET) + if (strat != ConfigMergingParameters::MergeStrategies::STRATEGY_UNSPECIFIED) { m_strategy = strat; } @@ -361,7 +291,7 @@ class ColorspacesMerger : public SectionMerger ColorspacesMerger(MergeHandlerOptions options) : SectionMerger(options) { ConfigMergingParameters::MergeStrategies strat = options.params->getColorspaces(); - if (strat != ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET) + if (strat != ConfigMergingParameters::MergeStrategies::STRATEGY_UNSPECIFIED) { m_strategy = strat; } @@ -370,7 +300,6 @@ class ColorspacesMerger : public SectionMerger m_strategy = options.params->getDefaultStrategy(); } -// initializeRefSpaceConverters(); if (!options.params->isAssumeCommonReferenceSpace()) { ConfigUtils::initializeRefSpaceConverters(m_inputToBaseGtScene, @@ -391,12 +320,6 @@ class ColorspacesMerger : public SectionMerger }; private: - // Attributes - - std::vector m_colorspaceMarkedToBeDeleted; - std::vector m_colorspaceReplacingMarkedCs; - - // Methods const std::string getName() const { return "Color Spaces"; } void processSearchPaths() const; @@ -429,15 +352,12 @@ class ColorspacesMerger : public SectionMerger const ConstColorSpaceRcPtr & inputCS, const char * aliasName); -// void updateFamily(ColorSpaceRcPtr & incomingCs, bool fromBase) const; void updateFamily(std::string & family, bool fromBase) const; bool colorSpaceMayBeMerged(const ConstConfigRcPtr & mergeConfig, const ConstColorSpaceRcPtr & inputCS) const; void mergeColorSpace(ConfigRcPtr & mergeConfig, ColorSpaceRcPtr & eInputCS, std::vector & addedInputColorSpaces); -// void initializeRefSpaceConverters(ConstTransformRcPtr & inputToBaseGtScene, -// ConstTransformRcPtr & inputToBaseGtDisplay); void addColorSpaces(); @@ -455,11 +375,10 @@ class ColorspacesMerger : public SectionMerger void handleErrorCodeWhenAddingInputFirst(ColorSpaceRcPtr & eColorspace); void handleErrorCodes(ColorSpaceRcPtr & eColorspace); -// bool handleAvoidDuplicatesOption(ConfigRcPtr & eBase, ColorSpaceRcPtr & eColorspace); bool handleAvoidDuplicatesOption(ConfigUtils::ColorSpaceFingerprints & fingerprints, - ConfigRcPtr & eBase, - const ConstConfigRcPtr & inputConfig, - ColorSpaceRcPtr & inputCS); + ConfigRcPtr & eBase, + const ConstConfigRcPtr & inputConfig, + ColorSpaceRcPtr & inputCS); void handleAssumeCommonReferenceOption(ColorSpaceRcPtr & eColorspace); void handleMarkedToBeDeletedColorspaces(); @@ -481,7 +400,7 @@ class NamedTransformsMerger : public SectionMerger NamedTransformsMerger(MergeHandlerOptions options) : SectionMerger(options) { ConfigMergingParameters::MergeStrategies strat = options.params->getNamedTransforms(); - if (strat != ConfigMergingParameters::MergeStrategies::STRATEGY_UNSET) + if (strat != ConfigMergingParameters::MergeStrategies::STRATEGY_UNSPECIFIED) { m_strategy = strat; } @@ -492,9 +411,6 @@ class NamedTransformsMerger : public SectionMerger } private: - // Attributes - - // Methods const std::string getName() const { return "Named Transforms"; } void updateFamily(std::string & family, bool fromBase) const; diff --git a/src/apps/ociomergeconfigs/main.cpp b/src/apps/ociomergeconfigs/main.cpp index 6240b97eb9..020e45ea5a 100644 --- a/src/apps/ociomergeconfigs/main.cpp +++ b/src/apps/ociomergeconfigs/main.cpp @@ -76,7 +76,6 @@ int main(int argc, const char **argv) // Options std::string baseConfigName; std::string inputConfigName; - std::string mergeParameters; std::string outputFile; bool displayConfig = false; bool displayAllConfig = false; @@ -89,16 +88,15 @@ int main(int argc, const char **argv) OCIO::ConstConfigMergingParametersRcPtr params; OCIO::ConstConfigMergerRcPtr merger; - ap.options("ociomergeconfigs -- Merge two configs\n\n" + ap.options("ociomergeconfigs -- Merge configs using an OCIOM file with merge parameters\n\n" "Usage:\n" - " ociomergeconfigs [options] -b config.ocio -i extra.ocio \n\n", + " ociomergeconfigs [options] mergeFile.ociom \n", "%*", parse_end_args, "", "", "Options:", - "--validate", &validate, "Validate the final merged config", - "--merge %s", &mergeParameters, "Path to merge parameters file (.ociom)", "--out %s", &outputFile, "Filepath to save the merged config", + "--validate", &validate, "Validate the final merged config", "--show-last", &displayConfig, "Display the last merged config to screen", - "--show-all", &displayAllConfig, "Display ALL merged config to screen", + "--show-all", &displayAllConfig, "Display ALL merged configs to screen", "--show-params", &displayParams, "Display merger options (OCIOM)", "--help", &help, "Display the help and exit", "-h", &help, "Display the help and exit", @@ -108,13 +106,22 @@ int main(int argc, const char **argv) if (ap.parse(argc, argv) < 0) { std::cerr << ap.geterror() << std::endl; + ap.usage(); + exit(1); + } + else if (args.size() != 1) + { + std::cerr << "ERROR: Expecting 1 arguments, found " << args.size() << "." << std::endl; + ap.usage(); exit(1); } + const std::string mergeParameters = args[0].c_str(); + if (help) { ap.usage(); - return 0; + exit(0); } // Load the options from the ociom file. @@ -126,6 +133,7 @@ int main(int argc, const char **argv) catch (OCIO::Exception & e) { std::cout << e.what() << std::endl; + exit(1); } try @@ -138,7 +146,7 @@ int main(int argc, const char **argv) LogGuard logGuard; newMerger->getMergedConfig()->validate(); } - catch(OCIO::Exception & exception) + catch (OCIO::Exception & exception) { std::cout << exception.what() << std::endl; exit(1); @@ -190,7 +198,7 @@ int main(int argc, const char **argv) mergedCfg.close(); } } - catch(const std::exception& e) + catch (const std::exception& e) { std::cerr << e.what(); exit(1); diff --git a/tests/cpu/ConfigUtils_tests.cpp b/tests/cpu/ConfigUtils_tests.cpp index af805c41ab..db58c3f62b 100644 --- a/tests/cpu/ConfigUtils_tests.cpp +++ b/tests/cpu/ConfigUtils_tests.cpp @@ -28,7 +28,6 @@ name: base - . roles: -# aces_interchange: ap0 cie_xyz_d65_interchange: CIE-XYZ-D65 file_rules: @@ -88,7 +87,6 @@ search_path: lut_dir #inactive_colorspaces: [ACES2065-1] roles: -# aces_interchange: ACES2065-1 cie_xyz_d65_interchange: CIE-XYZ-D65 file_rules: @@ -147,7 +145,6 @@ colorspaces: # reference space = linear rec 709 - ! name: sRGB -# aliases: [srgb_display] family: Texture~ description: from input to_scene_reference: ! {gamma: 2.4, offset: 0.055} @@ -169,13 +166,6 @@ colorspaces: # reference space = linear rec 709 OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); OCIO::ConstConfigRcPtr cgConfig = OCIO::Config::CreateFromFile("ocio://cg-config-v1.0.0_aces-v1.3_ocio-v2.1"); -// const char * srcInterchange = nullptr; -// const char * builtinInterchange = nullptr; -// OCIO::Config::IdentifyInterchangeSpace(&srcInterchange, &builtinInterchange, -// inputConfig, "ACES2065-1", cgConfig, "ACES2065-1"); -// std::cout << "src: " << srcInterchange << "\n"; -// std::cout << "dst: " << builtinInterchange << "\n"; - // Scene-referred reference space check. // Get the transform to convert the scene-referred reference space. @@ -185,7 +175,9 @@ colorspaces: # reference space = linear rec 709 { // Convert each one of the scene-referred color spaces and check the result. std::vector colorspaces; - for (int i = 0; i < inputConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_SCENE, OCIO::COLORSPACE_ALL); ++i) + const int numSpaces = inputConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_SCENE, + OCIO::COLORSPACE_ALL); + for (int i = 0; i < numSpaces; ++i) { const char * name = inputConfig->getColorSpaceNameByIndex(OCIO::SEARCH_REFERENCE_SPACE_SCENE, OCIO::COLORSPACE_ALL, @@ -291,7 +283,9 @@ colorspaces: # reference space = linear rec 709 { // Convert each one of the display-referred color spaces and check the result. std::vector colorspaces; - for (int i = 0; i < inputConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, OCIO::COLORSPACE_ALL); ++i) + const int numSpaces = inputConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, + OCIO::COLORSPACE_ALL); + for (int i = 0; i < numSpaces; ++i) { const char * name = inputConfig->getColorSpaceNameByIndex(OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, OCIO::COLORSPACE_ALL, @@ -372,10 +366,9 @@ colorspaces: # reference space = linear rec 709 const char * name = inputConfig->getViewTransformNameByIndex(v); viewTransforms.push_back(inputConfig->getViewTransform(name)); } - { + OCIO_CHECK_EQUAL(viewTransforms.size(), 3); -// OCIO_CHECK_EQUAL(inputConfig->getNumViewTransforms(), 3); -// ConstViewTransformRcPtr viewTransform = + { OCIO::ViewTransformRcPtr vt = viewTransforms[0]->createEditableCopy(); OCIO::ConfigUtils::updateReferenceView(vt, inputToBaseGtScene, inputToBaseGtDisplay); OCIO_REQUIRE_ASSERT(!vt->getTransform(OCIO::VIEWTRANSFORM_DIR_TO_REFERENCE)) @@ -644,7 +637,6 @@ inactive_colorspaces: [] description: sRGB - Texture with truncated matrix values from_scene_reference: ! children: -# - ! {matrix: [2.521686, -1.134131, -0.387555, 0, -0.2764799, 1.372719, -0.09623917, 0, -0.01537806, -0.152975, 1.168353, 0, 0, 0, 0, 1]} - ! {matrix: [2.522, -1.134, -0.388, 0, -0.276, 1.373, -0.0962, 0, -0.0154, -0.153, 1.168, 0, 0, 0, 0, 1]} - ! {gamma: 2.4, offset: 0.055, direction: inverse} @@ -655,10 +647,6 @@ inactive_colorspaces: [] from_scene_reference: ! children: - ! {matrix: [2.52, -1.13, -0.39, 0, -0.28, 1.37, -0.096, 0, -0.015, -0.15, 1.17, 0, 0, 0, 0, 1]} -# - ! {matrix: [2.522, -1.134, -0.388, 0, -0.276, 1.373, -0.0962, 0, -0.0154, -0.153, 1.168, 0, 0, 0, 0, 1]} -# - ! {value: [2.2, 2.2, 2.2, 1], direction: inverse} -# - ! {gamma: 2.2, direction: inverse} -# - ! {gamma: 2.42, offset: 0.055, direction: inverse} - ! {gamma: 2.42, offset: 0.055, direction: inverse} - ! @@ -676,10 +664,10 @@ inactive_colorspaces: [] - ! name: pq display scene isdata: false - description: Rec.2100-PQ - incorrectly as a display + description: Rec.2100-PQ - incorrectly as scene-referred from_reference: ! children: -# - ! {style: UTILITY - ACES-AP0_to_CIE-XYZ-D65_BFD} + - ! {style: UTILITY - ACES-AP0_to_CIE-XYZ-D65_BFD} - ! {style: DISPLAY - CIE-XYZ-D65_to_REC.2100-PQ} display_colorspaces: @@ -696,7 +684,6 @@ inactive_colorspaces: [] to_display_reference: ! children: - ! {matrix: [ 0.695452241357, 0.140678696470, 0.163869062172, 0, 0.044794563372, 0.859671118456, 0.095534318172, 0, -0.005525882558, 0.004025210306, 1.001500672252, 0, 0, 0, 0, 1 ]} -# - ! {style: UTILITY - ACES-AP0_to_CIE-XYZ-D65_BFD} - ! name: Rec.601 - Display @@ -715,15 +702,6 @@ inactive_colorspaces: [] - ! {value: 2.4, style: mirror, direction: inverse} )" }; -// >>> cs.build_conversion_matrix('ap0','rec 709','cat02').T -// array([[ 2.52193473, -1.1370239 , -0.38491083], -// [-0.27547943, 1.36982898, -0.09434955], -// [-0.01598287, -0.14778923, 1.1637721 ]]) -// >>> cs.build_conversion_matrix('ap0','rec 709','bfd').T -// array([[ 2.52168619, -1.13413099, -0.3875552 ], -// [-0.27647991, 1.37271909, -0.09623917], -// [-0.01537806, -0.15297534, 1.1683534 ]]) - iss.str(INPUT); OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromFile("ocio://cg-config-v1.0.0_aces-v1.3_ocio-v2.1"); @@ -732,53 +710,11 @@ inactive_colorspaces: [] OCIO::ConfigUtils::ColorSpaceFingerprints fingerprints; OCIO::ConfigUtils::initializeColorSpaceFingerprints(fingerprints, baseConfig); -// auto cs = inputConfig->getColorSpace("very approx. standard RGB"); -// auto gt = inputConfig->getProcessor(cs->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)) -// ->createGroupTransform(); -// std::cout << *gt << "\n"; - -// for (const auto & pair : fingerprints) -// { -// std::vector vals = pair.second.second; -// -// std::cout << pair.first << "\n"; -// -// for (size_t i = 0; i < vals.size(); i++) -// { -// std::cout << vals[i] << ", "; -// } -// std::cout << "\n"; -// } - -// std::vector vals = fingerprints.sceneRefTestVals; -// for (size_t i = 0; i < vals.size(); i++) -// { -// std::cout << vals[i] << ", "; -// } -// std::cout << "scene\n"; -// std::vector vals1 = fingerprints.displayRefTestVals; -// for (size_t i = 0; i < vals1.size(); i++) -// { -// std::cout << vals1[i] << ", "; -// } -// std::cout << "display\n"; - -// The above prints this: -// 0.401273, 0.089901, 0.0256116, 0, 0.35086, 0.733961, 0.109276, 0, 0.171697, 0.104272, 0.786227, 0, 0, 0, 0, 0.5, 0.0370189, 0.0308277, 0.0216417, 0, 1, 1, 1, 1, scene -// 0.376532, 0.199249, 0.028095, 0, 0.327755, 0.6465, 0.116974, 0, 0.173708, 0.0814028, 0.858056, 0, 0, 0, 0, 0.5, 0.0349567, 0.0335309, 0.023553, 0, 0.950456, 1, 1.08906, 1, display - - { OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("ref_space"); const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); OCIO_CHECK_EQUAL(name, std::string("ACES2065-1")); } -// { -// OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("Unknown"); -// const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs, -// OCIO::REFERENCE_SPACE_SCENE); -// OCIO_CHECK_EQUAL(name, std::string("Raw")); -// } { OCIO::ConstColorSpaceRcPtr cs = inputConfig->getColorSpace("standard RGB"); const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); @@ -840,50 +776,4 @@ inactive_colorspaces: [] { OCIO_CHECK_ASSERT(fingerprintVals[i] >= 0.); } - } - -// OCIO_ADD_TEST(MergeConfigs, config_utils_find_equivalent_colorspace2) -// { -// // OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromFile("ocio://cg-config-v1.0.0_aces-v1.3_ocio-v2.1"); -// OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromFile("/Users/walkerdo/Documents/work/Autodesk/color/adsk_color_mgmt/OCIO/customer configs/FilmLight/TCS_TCAMv3/TCS_TCAMv3.ocio"); -// OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromFile("/Users/walkerdo/Documents/work/Autodesk/color/adsk_color_mgmt/OCIO/configs/flame/flame_core_config.ocio"); -// -// OCIO::ConfigUtils::ColorSpaceFingerprints fingerprints; -// OCIO::ConfigUtils::initializeColorSpaceFingerprints(fingerprints, baseConfig); -// -// // std::vector vals = fingerprints.sceneRefTestVals; -// // for (size_t i = 0; i < vals.size(); i++) -// // { -// // std::cout << vals[i] << ", "; -// // } -// // std::cout << "scene\n"; -// // std::vector vals1 = fingerprints.displayRefTestVals; -// // for (size_t i = 0; i < vals1.size(); i++) -// // { -// // std::cout << vals1[i] << ", "; -// // } -// // std::cout << "display\n"; -// // -// // 0.487301, 0.0881323, 0.0741543, 0, 0.300795, 0.700204, 0.167705, 0, 0.13517, 0.139418, 0.679913, 0, 0, 0, 0, 0.5, 0.0393561, 0.0303888, 0.0239345, 0, 0.999998, 1, 1, 1, scene -// -// OCIO::ConstTransformRcPtr inputToBaseGtScene; -// OCIO::ConstTransformRcPtr inputToBaseGtDisplay; -// OCIO::ConfigUtils::initializeRefSpaceConverters(inputToBaseGtScene, -// inputToBaseGtDisplay, -// baseConfig, -// inputConfig); -// -// { -// OCIO::ColorSpaceRcPtr cs = inputConfig->getColorSpace("ACEScct")->createEditableCopy(); -// OCIO::ConfigUtils::updateReferenceColorspace(cs, inputToBaseGtScene); -// const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); -// OCIO_CHECK_EQUAL(name, std::string("ACEScct: ACEScct : AP1")); -// } -// { -// OCIO::ColorSpaceRcPtr cs = inputConfig->getColorSpace("Apple Log")->createEditableCopy(); -// OCIO::ConfigUtils::updateReferenceColorspace(cs, inputToBaseGtScene); -// const char * name = OCIO::ConfigUtils::findEquivalentColorspace(fingerprints, inputConfig, cs); -// OCIO_CHECK_EQUAL(name, std::string("Apple: Apple Log : Rec.2020")); -// } -// } diff --git a/tests/cpu/Config_tests.cpp b/tests/cpu/Config_tests.cpp index 599dc29cf7..6a310aae04 100644 --- a/tests/cpu/Config_tests.cpp +++ b/tests/cpu/Config_tests.cpp @@ -9125,7 +9125,7 @@ OCIO_ADD_TEST(Config, alias_validation) cs->addAlias("colorspace1"); OCIO_CHECK_THROW_WHAT(cfg->addColorSpace(cs), OCIO::Exception, "Cannot add 'colorspace3' " "color space, it has 'colorspace1' alias and existing color space, " - "'colorspace1' has the same name"); + "'colorspace1' is using the same alias"); cs->removeAlias("colorspace1"); OCIO_CHECK_NO_THROW(cfg->setRole("alias", "colorspace2")); diff --git a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp index 6f172eb159..2e304d3069 100644 --- a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp +++ b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp @@ -93,9 +93,6 @@ OCIO::ConstNamedTransformRcPtr checkNamedTransform(const OCIO::ConstConfigRcPtr return nt; } -// FIXME: REMOVE -static constexpr char PREFIX[] { "The Input config contains a value that would override the Base config: " }; - template void loadStringsHelper(std::vector& strings, Arg arg) { @@ -132,9 +129,6 @@ void checkForLogOrException(LogType type, int line, std::function setup, { if (type == LOG_TYPE_ERROR) { -// FIXME -// OCIO_CHECK_ASSERT_FROM(OCIO::checkAndMuteError(logGuard, s), line); - const bool errorFound = OCIO::checkAndMuteError(logGuard, s); if (!errorFound) { @@ -370,7 +364,6 @@ OCIO_ADD_TEST(MergeConfigs, overrides) merger->getParams(0)->setColorspaces(strategy); // Not looking for duplicates as this test does not test that. merger->getParams(0)->setAvoidDuplicates(false); -// merger->getParams(0)->setAssumeCommonReferenceSpace(true); // Set the overrides. merger->getParams(0)->setName("OVR Name"); @@ -495,54 +488,235 @@ OCIO_ADD_TEST(MergeConfigs, general_section) OCIO::ConstConfigRcPtr inputConfig; OCIO_CHECK_NO_THROW(inputConfig = getInputConfig()); -// auto setupGeneral = [&baseConfig, &inputConfig]( -// OCIO::ConfigMergerRcPtr & merger, -// OCIO::ConfigRcPtr mergedConfig, -// std::function cb) -// { -// OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); -// merger->addParams(params); -// -// if (cb) -// { -// cb(merger); -// } -// -// OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; -// OCIO::GeneralMerger(options).merge(); -// }; - -/// FIXME InputFirst has no impact on general. Should test name, desc, profile version. - - // Test general merger (uses default strategy) with options InputFirst = true. -// { -// OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); -// OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); -// setupGeneral(merger, -// mergedConfig, -// { -// merger->getParams(0)->setInputFirst(true); -// }); -// -// -// OCIO_CHECK_EQUAL(std::string(mergedConfig->getName()), std::string("input0")); -// OCIO_CHECK_EQUAL(std::string(mergedConfig->getDescription()), std::string("My description 2")); -// } -// -// // Test general merger (uses default strategy) with options InputFirst = false. -// { -// OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); -// OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); -// setupGeneral(merger, -// mergedConfig, -// [](OCIO::ConfigMergerRcPtr & merger) -// { -// merger->getParams(0)->setInputFirst(false); -// }); -// -// OCIO_CHECK_EQUAL(std::string(mergedConfig->getName()), std::string("input0")); -// OCIO_CHECK_EQUAL(std::string(mergedConfig->getDescription()), std::string("My description 2")); -// } + auto setupBasics = [](OCIO::ConfigMergerRcPtr & merger, MergeStrategy strategy) -> OCIO::ConfigMergingParametersRcPtr + { + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + merger->addParams(params); + // The general strategy is determined by the default strategy. + // However, note that the name and description may be set in the override options, tested above. + merger->getParams(0)->setDefaultStrategy(strategy); + return params; + }; + + double rgb[3] = {0., 0., 0.}; + + // Test that the default strategy is used as a fallback if the section strategy was not defined. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + // Using STRATEGY_UNSPECIFIED as this simulates that the section + // is missing from the OCIOM file. + auto params = setupBasics(merger, MergeStrategy::STRATEGY_UNSPECIFIED); + // Simulate settings from OCIOM file. + merger->getParams(0)->setDefaultStrategy(MergeStrategy::STRATEGY_INPUT_ONLY); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::GeneralMerger(options).merge(); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getName()), + std::string("input0")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDescription()), + std::string("My description 2")); + OCIO_CHECK_EQUAL(mergedConfig->getMajorVersion(), 2); + OCIO_CHECK_EQUAL(mergedConfig->getMinorVersion(), 1); + mergedConfig->getDefaultLumaCoefs(rgb); + OCIO_CHECK_CLOSE(rgb[1], 0.677998, 1e-4); + } + + // Test General section with strategy = PreferInput. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::GeneralMerger(options).merge(); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getName()), + std::string("input0")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDescription()), + std::string("My description 2")); + + OCIO_CHECK_EQUAL(mergedConfig->getMajorVersion(), 2); + OCIO_CHECK_EQUAL(mergedConfig->getMinorVersion(), 1); + + mergedConfig->getDefaultLumaCoefs(rgb); + OCIO_CHECK_CLOSE(rgb[1], 0.677998, 1e-4); + } + + // Test General section with strategy = PreferBase. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::GeneralMerger(options).merge(); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getName()), + std::string("base0")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDescription()), + std::string("My description 1")); + + OCIO_CHECK_EQUAL(mergedConfig->getMajorVersion(), 2); + // Config version is always highest of both configs, regardless of strategy. + OCIO_CHECK_EQUAL(mergedConfig->getMinorVersion(), 1); + + mergedConfig->getDefaultLumaCoefs(rgb); + OCIO_CHECK_CLOSE(rgb[1], 0.7152, 1e-4); + } + + // Test General section with strategy = InputOnly. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_INPUT_ONLY); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::GeneralMerger(options).merge(); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getName()), + std::string("input0")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDescription()), + std::string("My description 2")); + + OCIO_CHECK_EQUAL(mergedConfig->getMajorVersion(), 2); + OCIO_CHECK_EQUAL(mergedConfig->getMinorVersion(), 1); + + mergedConfig->getDefaultLumaCoefs(rgb); + OCIO_CHECK_CLOSE(rgb[1], 0.677998, 1e-4); + } + + // Test General section with strategy = BaseOnly. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_BASE_ONLY); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::GeneralMerger(options).merge(); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getName()), + std::string("base0")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDescription()), + std::string("My description 1")); + + OCIO_CHECK_EQUAL(mergedConfig->getMajorVersion(), 2); + // Config version is always highest of both configs, regardless of strategy. + OCIO_CHECK_EQUAL(mergedConfig->getMinorVersion(), 1); + + mergedConfig->getDefaultLumaCoefs(rgb); + OCIO_CHECK_CLOSE(rgb[1], 0.7152, 1e-4); + } + + { + constexpr const char * BASE { +R"(ocio_profile_version: 1 + +roles: + default: colorspace_a +colorspaces: +- ! + name: colorspace_a +)" }; + + constexpr const char * INPUT { +R"(ocio_profile_version: 2.1 + +luma: [0.262700, 0.677998, 0.059301] +name: input0 +description: | + My description 2 + +roles: + default: colorspace_b +colorspaces: +- ! + name: colorspace_b +)" }; + + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO_CHECK_NO_THROW(baseConfig = OCIO::Config::CreateFromStream(bss)); + OCIO_CHECK_NO_THROW(inputConfig = OCIO::Config::CreateFromStream(iss)); + + // Test General section with strategy = PreferInput. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::GeneralMerger(options).merge(); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getName()), + std::string("input0")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDescription()), + std::string("My description 2")); + + OCIO_CHECK_EQUAL(mergedConfig->getMajorVersion(), 2); + OCIO_CHECK_EQUAL(mergedConfig->getMinorVersion(), 1); + + mergedConfig->getDefaultLumaCoefs(rgb); + OCIO_CHECK_CLOSE(rgb[1], 0.677998, 1e-4); + } + + // Test General section with strategy = PreferBase. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::GeneralMerger(options).merge(); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getName()), + std::string("")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDescription()), + std::string("")); + + OCIO_CHECK_EQUAL(mergedConfig->getMajorVersion(), 2); + // Config version is always highest of both configs, regardless of strategy. + OCIO_CHECK_EQUAL(mergedConfig->getMinorVersion(), 1); + + mergedConfig->getDefaultLumaCoefs(rgb); + OCIO_CHECK_CLOSE(rgb[1], 0.7152, 1e-4); + } + + // Test General section with strategy = InputOnly. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_INPUT_ONLY); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::GeneralMerger(options).merge(); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getName()), + std::string("input0")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDescription()), + std::string("My description 2")); + + OCIO_CHECK_EQUAL(mergedConfig->getMajorVersion(), 2); + OCIO_CHECK_EQUAL(mergedConfig->getMinorVersion(), 1); + + mergedConfig->getDefaultLumaCoefs(rgb); + OCIO_CHECK_CLOSE(rgb[1], 0.677998, 1e-4); + } + + // Test General section with strategy = BaseOnly. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_BASE_ONLY); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::GeneralMerger(options).merge(); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getName()), + std::string("")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDescription()), + std::string("")); + + OCIO_CHECK_EQUAL(mergedConfig->getMajorVersion(), 2); + // Config version is always highest of both configs, regardless of strategy. + OCIO_CHECK_EQUAL(mergedConfig->getMinorVersion(), 1); + + mergedConfig->getDefaultLumaCoefs(rgb); + OCIO_CHECK_CLOSE(rgb[1], 0.7152, 1e-4); + } + } } OCIO_ADD_TEST(MergeConfigs, roles_section) @@ -568,17 +742,17 @@ OCIO_ADD_TEST(MergeConfigs, roles_section) // Test that the default strategy is used as a fallback if the section strategy was not defined. { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); - // Using STRATEGY_UNSET as this simulates that the section + // Using STRATEGY_UNSPECIFIED as this simulates that the section // is missing from the OCIOM file. - auto params = setupBasics(merger, MergeStrategy::STRATEGY_UNSET); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_UNSPECIFIED); // Simulate settings from OCIOM file. merger->getParams(0)->setDefaultStrategy(MergeStrategy::STRATEGY_INPUT_ONLY); OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::RolesMerger(options).merge(); }, - "The Input config contains a role 'g22_ap1_tx' that would override an alias of Base config color space 'Gamma 2.2 AP1 - Texture'", - "The Input config contains a role 'nt_base' that would override Base config named transform: 'nt_base'"); + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'g22_ap1_tx' that would override an alias of Base config color space 'Gamma 2.2 AP1 - Texture'", + "The Input config contains a role 'nt_base' that would override Base config named transform: 'nt_base'"); OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 3); OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("aces_interchange")), @@ -596,10 +770,10 @@ OCIO_ADD_TEST(MergeConfigs, roles_section) OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::RolesMerger(options).merge(); }, - "The Input config contains a role 'g22_ap1_tx' that would override an alias of Base config color space 'Gamma 2.2 AP1 - Texture'", - "The Input config contains a role that would override Base config role 'texture_paint'.", - "The Input config contains a role 'nt_base' that would override Base config named transform: 'nt_base'"); + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'g22_ap1_tx' that would override an alias of Base config color space 'Gamma 2.2 AP1 - Texture'", + "The Input config contains a role that would override Base config role 'texture_paint'.", + "The Input config contains a role 'nt_base' that would override Base config named transform: 'nt_base'"); OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 4); @@ -623,10 +797,10 @@ OCIO_ADD_TEST(MergeConfigs, roles_section) OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::RolesMerger(options).merge(); }, - "The Input config contains a role 'g22_ap1_tx' that would override an alias of Base config color space 'Gamma 2.2 AP1 - Texture'", - "The Input config contains a role that would override Base config role 'texture_paint'.", - "The Input config contains a role 'nt_base' that would override Base config named transform: 'nt_base'"); + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'g22_ap1_tx' that would override an alias of Base config color space 'Gamma 2.2 AP1 - Texture'", + "The Input config contains a role that would override Base config role 'texture_paint'.", + "The Input config contains a role 'nt_base' that would override Base config named transform: 'nt_base'"); OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 4); @@ -650,9 +824,9 @@ OCIO_ADD_TEST(MergeConfigs, roles_section) OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::RolesMerger(options).merge(); }, - "The Input config contains a role 'g22_ap1_tx' that would override an alias of Base config color space 'Gamma 2.2 AP1 - Texture'", - "The Input config contains a role 'nt_base' that would override Base config named transform: 'nt_base'"); + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'g22_ap1_tx' that would override an alias of Base config color space 'Gamma 2.2 AP1 - Texture'", + "The Input config contains a role 'nt_base' that would override Base config named transform: 'nt_base'"); OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 3); @@ -707,8 +881,8 @@ OCIO_ADD_TEST(MergeConfigs, roles_section) OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_ERROR, __LINE__, - [&options]() { OCIO::RolesMerger(options).merge(); }, - "The Input config contains a role 'g22_ap1_tx' that would override an alias of Base config color space 'Gamma 2.2 AP1 - Texture'."); + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'g22_ap1_tx' that would override an alias of Base config color space 'Gamma 2.2 AP1 - Texture'."); } } @@ -737,8 +911,8 @@ OCIO_ADD_TEST(MergeConfigs, file_rules_section) // Test that the default strategy is used as a fallback if the section strategy was not defined. { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); - // Using STRATEGY_UNSET as this simulates that the section is missing from the OCIOM file. - auto params = setupBasics(merger, MergeStrategy::STRATEGY_UNSET); + // Using STRATEGY_UNSPECIFIED as this simulates that the section is missing from the OCIOM file. + auto params = setupBasics(merger, MergeStrategy::STRATEGY_UNSPECIFIED); // Simulate settings from OCIOM file. merger->getParams(0)->setDefaultStrategy(MergeStrategy::STRATEGY_INPUT_ONLY); @@ -777,9 +951,9 @@ OCIO_ADD_TEST(MergeConfigs, file_rules_section) OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::FileRulesMerger(options).merge(); }, - "The Input config contains a value that would override the Base config: file_rules: TIFF", - "The Input config contains a value that would override the Base config: file_rules: Default"); + [&options]() { OCIO::FileRulesMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: file_rules: TIFF", + "The Input config contains a value that would override the Base config: file_rules: Default"); OCIO::ConstFileRulesRcPtr fr = mergedConfig->getFileRules(); @@ -821,9 +995,9 @@ OCIO_ADD_TEST(MergeConfigs, file_rules_section) OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::FileRulesMerger(options).merge(); }, - "The Input config contains a value that would override the Base config: file_rules: TIFF", - "The Input config contains a value that would override the Base config: file_rules: Default"); + [&options]() { OCIO::FileRulesMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: file_rules: TIFF", + "The Input config contains a value that would override the Base config: file_rules: Default"); OCIO_CHECK_EQUAL(mergedConfig->isStrictParsingEnabled(), false); @@ -866,9 +1040,9 @@ OCIO_ADD_TEST(MergeConfigs, file_rules_section) OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::FileRulesMerger(options).merge(); }, - "The Input config contains a value that would override the Base config: file_rules: TIFF", - "The Input config contains a value that would override the Base config: file_rules: Default"); + [&options]() { OCIO::FileRulesMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: file_rules: TIFF", + "The Input config contains a value that would override the Base config: file_rules: Default"); OCIO_CHECK_EQUAL(mergedConfig->isStrictParsingEnabled(), true); @@ -907,9 +1081,9 @@ OCIO_ADD_TEST(MergeConfigs, file_rules_section) OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::FileRulesMerger(options).merge(); }, - "The Input config contains a value that would override the Base config: file_rules: TIFF", - "The Input config contains a value that would override the Base config: file_rules: Default"); + [&options]() { OCIO::FileRulesMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: file_rules: TIFF", + "The Input config contains a value that would override the Base config: file_rules: Default"); OCIO_CHECK_EQUAL(mergedConfig->isStrictParsingEnabled(), true); @@ -1078,6 +1252,8 @@ OCIO_ADD_TEST(MergeConfigs, file_rules_section) } } + constexpr char PREFIX[] { "The Input config contains a value that would override the Base config: " }; + // Test that error_on_conflicts is processed correctly. // strategy = PreferInput, InputFirst = true { @@ -1235,9 +1411,9 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); - // Using STRATEGY_UNSET as this simulates that the section + // Using STRATEGY_UNSPECIFIED as this simulates that the section // is missing from the OCIOM file. - auto params = setupBasics(merger, MergeStrategy::STRATEGY_UNSET); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_UNSPECIFIED); // Simulate settings from OCIOM file. merger->getParams(0)->setDefaultStrategy(MergeStrategy::STRATEGY_INPUT_ONLY); merger->getParams(0)->setInputFirst(true); @@ -1940,6 +2116,8 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) OCIO_CHECK_EQUAL(mergedConfig->getVirtualDisplayView(OCIO::VIEW_SHARED, 0), std::string("SHARED_1")); } + constexpr char PREFIX[] { "The Input config contains a value that would override the Base config: " }; + // Test that error_on_conflicts is processed correctly. // strategy = PreferInput, InputFirst = false { @@ -1995,8 +2173,8 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section) { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); - // Using STRATEGY_UNSET as this simulates that the section is missing from the OCIOM file. - auto params = setupBasics(merger, MergeStrategy::STRATEGY_UNSET); + // Using STRATEGY_UNSPECIFIED as this simulates that the section is missing from the OCIOM file. + auto params = setupBasics(merger, MergeStrategy::STRATEGY_UNSPECIFIED); // Simulate settings from OCIOM file. merger->getParams(0)->setDefaultStrategy(MergeStrategy::STRATEGY_INPUT_ONLY); @@ -2022,12 +2200,12 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section) OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Color space 'sRGB - Display' will replace a color space in the base config", - "Color space 'look' will replace a color space in the base config", - "Merged color space 'look' has a different reference space type than the color space it's replacing", - "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", - "The name of merged color space 'sRGB' has a conflict with an alias in color space 'sRGB - Texture'"); + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Color space 'sRGB - Display' will replace a color space in the base config", + "Color space 'look' will replace a color space in the base config", + "Merged color space 'look' has a different reference space type than the color space it's replacing", + "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", + "The name of merged color space 'sRGB' has a conflict with an alias in color space 'sRGB - Texture'"); OCIO_CHECK_EQUAL(mergedConfig->getFamilySeparator(), '~'); @@ -2092,12 +2270,12 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section) OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Color space 'sRGB - Display' will replace a color space in the base config", - "Color space 'look' will replace a color space in the base config", - "Merged color space 'look' has a different reference space type than the color space it's replacing", - "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", - "The name of merged color space 'sRGB' has a conflict with an alias in color space 'sRGB - Texture'"); + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Color space 'sRGB - Display' will replace a color space in the base config", + "Color space 'look' will replace a color space in the base config", + "Merged color space 'look' has a different reference space type than the color space it's replacing", + "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", + "The name of merged color space 'sRGB' has a conflict with an alias in color space 'sRGB - Texture'"); OCIO_CHECK_EQUAL(mergedConfig->getFamilySeparator(), '~'); @@ -2152,11 +2330,11 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section) OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Color space 'sRGB - Display' was not merged as it's already present in the base config", - "Color space 'look' was not merged as it's already present in the base config", - "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", - "Color space 'sRGB' was not merged as it conflicts with an alias in color space 'sRGB - Texture'"); + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Color space 'sRGB - Display' was not merged as it's already present in the base config", + "Color space 'look' was not merged as it's already present in the base config", + "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", + "Color space 'sRGB' was not merged as it conflicts with an alias in color space 'sRGB - Texture'"); OCIO_CHECK_EQUAL(mergedConfig->getFamilySeparator(), '#'); @@ -2211,11 +2389,11 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section) OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Color space 'sRGB - Display' was not merged as it's already present in the base config", - "Color space 'look' was not merged as it's already present in the base config", - "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", - "Color space 'sRGB' was not merged as it conflicts with an alias in color space 'sRGB - Texture'"); + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Color space 'sRGB - Display' was not merged as it's already present in the base config", + "Color space 'look' was not merged as it's already present in the base config", + "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", + "Color space 'sRGB' was not merged as it conflicts with an alias in color space 'sRGB - Texture'"); OCIO_CHECK_EQUAL(mergedConfig->getFamilySeparator(), '#'); @@ -2416,19 +2594,16 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section_common_reference_and_duplicates) OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::RolesMerger(options).merge(); - OCIO::DisplayViewMerger(options).merge(); - OCIO::ColorspacesMerger(options).merge(); }, -// "The Input config contains a role that would override Base config role 'aces_interchange'.", - "Equivalent input color space 'sRGB - Display' replaces 'sRGB - Display' in the base config, preserving aliases.", - "Equivalent input color space 'CIE-XYZ-D65' replaces 'CIE-XYZ-D65' in the base config, preserving aliases.", - "Equivalent input color space 'ACES2065-1' replaces 'ap0' in the base config, preserving aliases.", - "Equivalent input color space 'sRGB' replaces 'sRGB - Texture' in the base config, preserving aliases.", - "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'"); + [&options]() { OCIO::RolesMerger(options).merge(); + OCIO::DisplayViewMerger(options).merge(); + OCIO::ColorspacesMerger(options).merge(); }, + "Equivalent input color space 'sRGB - Display' replaces 'sRGB - Display' in the base config, preserving aliases.", + "Equivalent input color space 'CIE-XYZ-D65' replaces 'CIE-XYZ-D65' in the base config, preserving aliases.", + "Equivalent input color space 'ACES2065-1' replaces 'ap0' in the base config, preserving aliases.", + "Equivalent input color space 'sRGB' replaces 'sRGB - Texture' in the base config, preserving aliases.", + "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'"); OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 1); -// OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("aces_interchange")), -// std::string("ACES2065-1")); OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("cie_xyz_d65_interchange")), std::string("CIE-XYZ-D65")); @@ -2437,11 +2612,18 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section_common_reference_and_duplicates) // Display-referred spaces. { + // This is a duplicate. auto cs = checkColorSpace(mergedConfig, "sRGB - Display", 0, OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, __LINE__); OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); // Check for alias srgb_display (added from base config). OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("srgb_display")); OCIO_CHECK_EQUAL(cs->getDescription(), std::string("from input")); + OCIO_CHECK_EQUAL(cs->getEncoding(), std::string("sdr-video")); + // Check categories were copied. + OCIO_CHECK_EQUAL(cs->getNumCategories(), 3); + OCIO_CHECK_ASSERT(cs->hasCategory("file-io")); + OCIO_CHECK_ASSERT(cs->hasCategory("texture")); + OCIO_CHECK_ASSERT(cs->hasCategory("display")); // Check that the input config reference space was converted to the base reference space. // See ConfigUtils_tests.cpp for more detailed testing of the reference space conversion. @@ -2481,6 +2663,11 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section_common_reference_and_duplicates) OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("aces")); // Check for alias ap0 (added from base config). OCIO_CHECK_EQUAL(cs->getAlias(1), std::string("ap0")); + // Check categories were copied. + OCIO_CHECK_EQUAL(cs->getNumCategories(), 2); + OCIO_CHECK_ASSERT(cs->hasCategory("file-io")); + OCIO_CHECK_ASSERT(cs->hasCategory("texture")); + OCIO_CHECK_EQUAL(cs->getEncoding(), std::string("scene-linear")); { OCIO_REQUIRE_ASSERT(!cs->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); OCIO::ConstTransformRcPtr t = cs->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); @@ -2500,6 +2687,10 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section_common_reference_and_duplicates) OCIO_CHECK_EQUAL(cs1->getAlias(0), std::string("sRGB - Texture")); // Check for alias srgb_tx (added from base config). OCIO_CHECK_EQUAL(cs1->getAlias(1), std::string("srgb_tx")); + // Check categories were copied. + OCIO_CHECK_EQUAL(cs1->getNumCategories(), 2); + OCIO_CHECK_ASSERT(cs1->hasCategory("file-io")); + OCIO_CHECK_ASSERT(cs1->hasCategory("texture")); { OCIO_REQUIRE_ASSERT(!cs1->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); OCIO::ConstTransformRcPtr t = cs1->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); @@ -2513,6 +2704,8 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section_common_reference_and_duplicates) } auto cs2 = checkColorSpace(mergedConfig, "rec709", 2, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs2->getNumCategories(), 1); + OCIO_CHECK_ASSERT(cs2->hasCategory("texture")); { OCIO_REQUIRE_ASSERT(!cs2->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); OCIO::ConstTransformRcPtr t = cs2->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); @@ -2535,6 +2728,7 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section_common_reference_and_duplicates) auto cs4 = checkColorSpace(mergedConfig, "ACEScg", 4, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); OCIO_CHECK_EQUAL(cs4->getNumAliases(), 0); + OCIO_CHECK_EQUAL(cs4->getNumCategories(), 0); { OCIO_REQUIRE_ASSERT(!cs4->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); OCIO::ConstTransformRcPtr t = cs4->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); @@ -2579,20 +2773,17 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section_common_reference_and_duplicates) OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::RolesMerger(options).merge(); - OCIO::DisplayViewMerger(options).merge(); - OCIO::ColorspacesMerger(options).merge(); }, -// "The Input config contains a role that would override Base config role 'aces_interchange'.", - "Equivalent base color space 'sRGB - Display' overrides 'sRGB - Display' in the input config, preserving aliases.", - "Equivalent base color space 'CIE-XYZ-D65' overrides 'CIE-XYZ-D65' in the input config, preserving aliases.", - "Equivalent base color space 'ap0' overrides 'ACES2065-1' in the input config, preserving aliases.", - "Equivalent base color space 'sRGB - Texture' overrides 'sRGB' in the input config, preserving aliases.", - "Input color space 'ACES2065-1' is a duplicate of base color space 'ap0' but was " - "unable to add alias 'aces' since it conflicts with base color space 'ACEScg'."); + [&options]() { OCIO::RolesMerger(options).merge(); + OCIO::DisplayViewMerger(options).merge(); + OCIO::ColorspacesMerger(options).merge(); }, + "Equivalent base color space 'sRGB - Display' overrides 'sRGB - Display' in the input config, preserving aliases.", + "Equivalent base color space 'CIE-XYZ-D65' overrides 'CIE-XYZ-D65' in the input config, preserving aliases.", + "Equivalent base color space 'ap0' overrides 'ACES2065-1' in the input config, preserving aliases.", + "Equivalent base color space 'sRGB - Texture' overrides 'sRGB' in the input config, preserving aliases.", + "Input color space 'ACES2065-1' is a duplicate of base color space 'ap0' but was " + "unable to add alias 'aces' since it conflicts with base color space 'ACEScg'."); OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 1); -// OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("aces_interchange")), -// std::string("ap0")); OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("cie_xyz_d65_interchange")), std::string("CIE-XYZ-D65")); @@ -2605,7 +2796,13 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section_common_reference_and_duplicates) OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("srgb_display")); OCIO_CHECK_EQUAL(cs->getDescription(), std::string("from base")); - { + OCIO_CHECK_EQUAL(cs->getEncoding(), std::string("")); + // Check categories were copied. + OCIO_CHECK_EQUAL(cs->getNumCategories(), 3); + OCIO_CHECK_ASSERT(cs->hasCategory("file-io")); + OCIO_CHECK_ASSERT(cs->hasCategory("texture")); + OCIO_CHECK_ASSERT(cs->hasCategory("display")); + { OCIO_REQUIRE_ASSERT(!cs->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE)); OCIO::ConstTransformRcPtr t = cs->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE); OCIO_REQUIRE_ASSERT(t); @@ -2624,6 +2821,8 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section_common_reference_and_duplicates) // Scene-referred spaces. { auto cs = checkColorSpace(mergedConfig, "rec709", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumCategories(), 1); + OCIO_CHECK_ASSERT(cs->hasCategory("texture")); { OCIO_REQUIRE_ASSERT(!cs->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); OCIO::ConstTransformRcPtr t = cs->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); @@ -2658,6 +2857,11 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section_common_reference_and_duplicates) OCIO_CHECK_EQUAL(cs3->getNumAliases(), 1); OCIO_CHECK_EQUAL(cs3->getAlias(0), std::string("ACES2065-1")); OCIO_CHECK_ASSERT(!(cs3->isData())); + // Check categories were copied. + OCIO_CHECK_EQUAL(cs3->getNumCategories(), 2); + OCIO_CHECK_ASSERT(cs3->hasCategory("file-io")); + OCIO_CHECK_ASSERT(cs3->hasCategory("texture")); + OCIO_CHECK_EQUAL(cs3->getEncoding(), std::string("")); { OCIO_REQUIRE_ASSERT(!cs3->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE)); OCIO_REQUIRE_ASSERT(!cs3->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE)); @@ -2667,6 +2871,7 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section_common_reference_and_duplicates) OCIO_CHECK_EQUAL(cs4->getNumAliases(), 2); OCIO_CHECK_EQUAL(cs4->getAlias(0), std::string("srgb")); OCIO_CHECK_EQUAL(cs4->getAlias(1), std::string("srgb_tx")); + OCIO_CHECK_EQUAL(cs4->getNumCategories(), 2); { OCIO_REQUIRE_ASSERT(!cs4->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE)); OCIO::ConstTransformRcPtr t = cs4->getTransform(OCIO::COLORSPACE_DIR_FROM_REFERENCE); @@ -2807,9 +3012,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::RolesMerger(options).merge(); - OCIO_CHECK_THROW_WHAT(OCIO::ColorspacesMerger(options).merge(), - OCIO::Exception, - "Color space 'B' was not merged as it's identical to a role name"); + OCIO_CHECK_THROW_WHAT(OCIO::ColorspacesMerger(options).merge(), OCIO::Exception, + "Color space 'B' was not merged as it's identical to a role name"); } } @@ -2850,8 +3054,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::RolesMerger(options).merge(); }, - "The Input config contains a role 'a' that would override Base config color space 'A'"); + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'a' that would override Base config color space 'A'"); OCIO::ColorspacesMerger(options).merge(); OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 0); @@ -2867,8 +3071,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::RolesMerger(options).merge(); }, - "The Input config contains a role 'a' that would override Base config color space 'A'"); + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'a' that would override Base config color space 'A'"); OCIO::ColorspacesMerger(options).merge(); OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 0); @@ -2880,7 +3084,6 @@ R"(ocio_profile_version: 2 } } - // test ADD_CS_ERROR_NAME_IDENTICAL_TO_NT_NAME_OR_ALIAS { { constexpr const char * BASE { @@ -2930,9 +3133,9 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Named transform 'nt_base' was not merged as there's a color space with that name", - "Merged Base named transform 'nt_base_extra' has an alias 'nt_base2' that conflicts with color space 'nt_base2'"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'nt_base' was not merged as there's a color space with that name", + "Merged Base named transform 'nt_base_extra' has an alias 'nt_base2' that conflicts with color space 'nt_base2'"); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "nt_base_extra", 0, __LINE__); @@ -2952,9 +3155,9 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Named transform 'nt_base' was not merged as there's a color space with that name", - "Merged Base named transform 'nt_base_extra' has an alias 'nt_base2' that conflicts with color space 'nt_base2'"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'nt_base' was not merged as there's a color space with that name", + "Merged Base named transform 'nt_base_extra' has an alias 'nt_base2' that conflicts with color space 'nt_base2'"); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "nt_base_extra", 0, __LINE__); @@ -2976,9 +3179,8 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); - OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), - OCIO::Exception, - "Named transform 'nt_base' was not merged as there's a color space with that name"); + OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), OCIO::Exception, + "Named transform 'nt_base' was not merged as there's a color space with that name"); } } @@ -3033,9 +3235,9 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Named transform 'nt_input' was not merged as there's a color space with that name", - "Merged Input named transform 'nt_input_extra' has an alias 'nt_input2' that conflicts with color space 'nt_input2'"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'nt_input' was not merged as there's a color space with that name", + "Merged Input named transform 'nt_input_extra' has an alias 'nt_input2' that conflicts with color space 'nt_input2'"); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "nt_input_extra", 0, __LINE__); @@ -3056,9 +3258,9 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Named transform 'nt_input' was not merged as there's a color space with that name", - "Merged Input named transform 'nt_input_extra' has an alias 'nt_input2' that conflicts with color space 'nt_input2'"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'nt_input' was not merged as there's a color space with that name", + "Merged Input named transform 'nt_input_extra' has an alias 'nt_input2' that conflicts with color space 'nt_input2'"); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "nt_input_extra", 0, __LINE__); @@ -3072,11 +3274,6 @@ R"(ocio_profile_version: 2 } } - // test ADD_CS_ERROR_NAME_CONTAIN_CTX_VAR_TOKEN - // Not handled as it can't happen in this context. - // The config will error out while loading the config (before the merge process). - - // test ADD_CS_ERROR_ALIAS_IDENTICAL_TO_A_ROLE_NAME { { constexpr const char * BASE { @@ -3118,8 +3315,8 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::RolesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Merged color space 'csInput' has an alias 'role_base' that conflicts with a role"); + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'csInput' has an alias 'role_base' that conflicts with a role"); OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 1); OCIO_CHECK_EQUAL(mergedConfig->getRoleName(0), std::string("role_base")); @@ -3139,8 +3336,8 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::RolesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Merged color space 'csInput' has an alias 'role_base' that conflicts with a role"); + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'csInput' has an alias 'role_base' that conflicts with a role"); OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 1); OCIO_CHECK_EQUAL(mergedConfig->getRoleName(0), std::string("role_base")); @@ -3160,9 +3357,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::RolesMerger(options).merge(); - OCIO_CHECK_THROW_WHAT(OCIO::ColorspacesMerger(options).merge(), - OCIO::Exception, - "Merged color space 'csInput' has an alias 'role_base' that conflicts with a role"); + OCIO_CHECK_THROW_WHAT(OCIO::ColorspacesMerger(options).merge(), OCIO::Exception, + "Merged color space 'csInput' has an alias 'role_base' that conflicts with a role"); } } @@ -3203,8 +3399,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::RolesMerger(options).merge(); }, - "The Input config contains a role 'role_input' that would override an alias of Base config color space 'csBase'"); + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'role_input' that would override an alias of Base config color space 'csBase'"); OCIO::ColorspacesMerger(options).merge(); OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 0); @@ -3223,8 +3419,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::RolesMerger(options).merge(); }, - "The Input config contains a role 'role_input' that would override an alias of Base config color space 'csBase'"); + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'role_input' that would override an alias of Base config color space 'csBase'"); OCIO::ColorspacesMerger(options).merge(); OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 0); @@ -3239,7 +3435,6 @@ R"(ocio_profile_version: 2 } } - // test ADD_CS_ERROR_ALIAS_IDENTICAL_TO_NT_NAME_OR_ALIAS { { constexpr const char * BASE { @@ -3288,9 +3483,9 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Named transform 'nt_base' was not merged as there's a color space alias with that name", - "Merged Base named transform 'nt_base_extra' has a conflict with alias 'nt_base2' in color space 'cs_input2'"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'nt_base' was not merged as there's a color space alias with that name", + "Merged Base named transform 'nt_base_extra' has a conflict with alias 'nt_base2' in color space 'cs_input2'"); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "nt_base_extra", 0, __LINE__); @@ -3316,9 +3511,9 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Named transform 'nt_base' was not merged as there's a color space alias with that name", - "Merged Base named transform 'nt_base_extra' has a conflict with alias 'nt_base2' in color space 'cs_input2'"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'nt_base' was not merged as there's a color space alias with that name", + "Merged Base named transform 'nt_base_extra' has a conflict with alias 'nt_base2' in color space 'cs_input2'"); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "nt_base_extra", 0, __LINE__); @@ -3343,9 +3538,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); - OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), - OCIO::Exception, - "Named transform 'nt_base' was not merged as there's a color space alias with that name"); + OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), OCIO::Exception, + "Named transform 'nt_base' was not merged as there's a color space alias with that name"); } } @@ -3395,9 +3589,9 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Named transform 'nt_input' was not merged as there's a color space alias with that name", - "Merged Input named transform 'nt_input_extra' has a conflict with alias 'nt_input2' in color space 'cs_base2'"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'nt_input' was not merged as there's a color space alias with that name", + "Merged Input named transform 'nt_input_extra' has a conflict with alias 'nt_input2' in color space 'cs_base2'"); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "nt_input_extra", 0, __LINE__); @@ -3423,9 +3617,9 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Named transform 'nt_input' was not merged as there's a color space alias with that name", - "Merged Input named transform 'nt_input_extra' has a conflict with alias 'nt_input2' in color space 'cs_base2'"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'nt_input' was not merged as there's a color space alias with that name", + "Merged Input named transform 'nt_input_extra' has a conflict with alias 'nt_input2' in color space 'cs_base2'"); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 1); OCIO::ConstNamedTransformRcPtr nt = checkNamedTransform(mergedConfig, "nt_input_extra", 0, __LINE__); @@ -3445,11 +3639,6 @@ R"(ocio_profile_version: 2 } } - // test ADD_CS_ERROR_ALIAS_CONTAIN_CTX_VAR_TOKEN - // Not handled as it can't happen in this context. - // The config will error out while loading the config (before the merge process). - - // test ADD_CS_ERROR_ALIAS_IDENTICAL_TO_EXISTING_COLORSPACE_ALIAS { { constexpr const char * BASE { @@ -3488,8 +3677,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Merged color space 'cs_input' has a conflict with alias 'my_colorspace' in color space 'cs_base'"); + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'cs_input' has a conflict with alias 'my_colorspace' in color space 'cs_base'"); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); @@ -3509,8 +3698,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Merged color space 'cs_input' has a conflict with alias 'my_colorspace' in color space 'cs_base'"); + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'cs_input' has a conflict with alias 'my_colorspace' in color space 'cs_base'"); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); @@ -3529,8 +3718,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Merged color space 'cs_input' has a conflict with alias 'my_colorspace' in color space 'cs_base'"); + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'cs_input' has a conflict with alias 'my_colorspace' in color space 'cs_base'"); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); @@ -3549,8 +3738,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Merged color space 'cs_input' has a conflict with alias 'my_colorspace' in color space 'cs_base'"); + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'cs_input' has a conflict with alias 'my_colorspace' in color space 'cs_base'"); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); @@ -3570,14 +3759,12 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; - OCIO_CHECK_THROW_WHAT(OCIO::ColorspacesMerger(options).merge(), - OCIO::Exception, - "Merged color space 'cs_input' has a conflict with alias 'my_colorspace' in color space 'cs_base'"); + OCIO_CHECK_THROW_WHAT(OCIO::ColorspacesMerger(options).merge(), OCIO::Exception, + "Merged color space 'cs_input' has a conflict with alias 'my_colorspace' in color space 'cs_base'"); } } } - // Test ADD_CS_ERROR_NAME_IDENTICAL_TO_EXISTING_COLORSPACE_ALIAS { { constexpr const char * BASE { @@ -3614,8 +3801,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "The name of merged color space 'B' has a conflict with an alias in color space 'A'"); + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "The name of merged color space 'B' has a conflict with an alias in color space 'A'"); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); @@ -3634,8 +3821,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Color space 'B' was not merged as it conflicts with an alias in color space 'A'"); + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Color space 'B' was not merged as it conflicts with an alias in color space 'A'"); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 1); @@ -3652,13 +3839,11 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; - OCIO_CHECK_THROW_WHAT(OCIO::ColorspacesMerger(options).merge(), - OCIO::Exception, - "The name of merged color space 'B' has a conflict with an alias in color space 'A'"); + OCIO_CHECK_THROW_WHAT(OCIO::ColorspacesMerger(options).merge(), OCIO::Exception, + "The name of merged color space 'B' has a conflict with an alias in color space 'A'"); } } - // ADD_CS_ERROR_ALIAS_IDENTICAL_TO_EXISTING_COLORSPACE_NAME { constexpr const char * BASE { R"(ocio_profile_version: 2 @@ -3693,8 +3878,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Merged color space 'B' has an alias 'A' that conflicts with color space 'A'"); + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'B' has an alias 'A' that conflicts with color space 'A'"); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 1); @@ -3710,8 +3895,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Merged color space 'B' has an alias 'A' that conflicts with color space 'A'"); + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'B' has an alias 'A' that conflicts with color space 'A'"); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 1); @@ -3726,8 +3911,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Merged color space 'B' has an alias 'A' that conflicts with color space 'A'"); + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'B' has an alias 'A' that conflicts with color space 'A'"); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); @@ -3746,8 +3931,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::ColorspacesMerger(options).merge(); }, - "Merged color space 'B' has an alias 'A' that conflicts with color space 'A'"); + [&options]() { OCIO::ColorspacesMerger(options).merge(); }, + "Merged color space 'B' has an alias 'A' that conflicts with color space 'A'"); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); @@ -3766,9 +3951,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; - OCIO_CHECK_THROW_WHAT(OCIO::ColorspacesMerger(options).merge(), - OCIO::Exception, - "Merged color space 'B' has an alias 'A' that conflicts with color space 'A'"); + OCIO_CHECK_THROW_WHAT(OCIO::ColorspacesMerger(options).merge(), OCIO::Exception, + "Merged color space 'B' has an alias 'A' that conflicts with color space 'A'"); } } } @@ -3813,9 +3997,9 @@ OCIO_ADD_TEST(MergeConfigs, looks_section) OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); setupLooks(baseConfig, inputConfig, merger, mergedConfig, - // Using STRATEGY_UNSET as this simulate that the section + // Using STRATEGY_UNSPECIFIED as this simulate that the section // is missing from the OCIOM file. - MergeStrategy::STRATEGY_UNSET, + MergeStrategy::STRATEGY_UNSPECIFIED, [](OCIO::ConfigMergerRcPtr & merger) { // Simulate settings from OCIOM file. @@ -4024,9 +4208,9 @@ OCIO_ADD_TEST(MergeConfigs, named_transform_section) // Test that the default strategy is used as a fallback if the section strategy was not defined. { OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); - // Using STRATEGY_UNSET as this simulate that the section + // Using STRATEGY_UNSPECIFIED as this simulate that the section // is missing from the OCIOM file. - auto params = setupBasics(merger, MergeStrategy::STRATEGY_UNSET); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_UNSPECIFIED); // Simulate settings from OCIOM file. merger->getParams(0)->setDefaultStrategy(MergeStrategy::STRATEGY_INPUT_ONLY); @@ -4068,7 +4252,6 @@ OCIO_ADD_TEST(MergeConfigs, named_transform_section) OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, [&options]() { OCIO::ColorspacesMerger(options).merge(); }, -// "Color space 'view_1' will replace a color space in the base config"); "Equivalent input color space 'ACES2065-1' replaces 'ACES2065-1' in the base config, preserving aliases.", "Equivalent input color space 'ACEScct - SomeOtherName' replaces 'ACEScct' in the base config, preserving aliases.", "Equivalent input color space 'view_1' replaces 'view_1' in the base config, preserving aliases.", @@ -4084,7 +4267,6 @@ OCIO_ADD_TEST(MergeConfigs, named_transform_section) "Merged Input named transform 'nt_both' has a conflict with alias 'Utility - Raw' in color space 'Raw'", "The name of merged named transform 'nt_input' has a conflict with an alias in named transform 'nt_base'", "Merged Input named transform 'nt_input' has an alias 'Raw' that conflicts with color space 'Raw'", -// "Named transform 'view_2' was not merged as there's a color space with that name"); "Named transform 'view_2' was not merged as there's a color space alias with that name."); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 3); @@ -4118,7 +4300,6 @@ OCIO_ADD_TEST(MergeConfigs, named_transform_section) OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, [&options]() { OCIO::ColorspacesMerger(options).merge(); }, -// "Color space 'view_1' will replace a color space in the base config"); "Equivalent input color space 'ACES2065-1' replaces 'ACES2065-1' in the base config, preserving aliases.", "Equivalent input color space 'ACEScct - SomeOtherName' replaces 'ACEScct' in the base config, preserving aliases.", "Equivalent input color space 'view_1' replaces 'view_1' in the base config, preserving aliases.", @@ -4134,7 +4315,6 @@ OCIO_ADD_TEST(MergeConfigs, named_transform_section) "Merged Input named transform 'nt_both' has a conflict with alias 'Utility - Raw' in color space 'Raw'", "The name of merged named transform 'nt_input' has a conflict with an alias in named transform 'nt_base'", "Merged Input named transform 'nt_input' has an alias 'Raw' that conflicts with color space 'Raw'", -// "Named transform 'view_2' was not merged as there's a color space with that name"); "Named transform 'view_2' was not merged as there's a color space alias with that name."); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 3); @@ -4158,7 +4338,6 @@ OCIO_ADD_TEST(MergeConfigs, named_transform_section) OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from input")); OCIO_CHECK_EQUAL(std::string(mergedConfig->getInactiveColorSpaces()), -/// "Gamma 2.2 AP1 - Texture, Linear Rec.2020, nt_both, nt_input, view_2"); "Gamma 2.2 AP1 - Texture, Linear Rec.2020, nt_both, nt_input"); } @@ -4171,7 +4350,6 @@ OCIO_ADD_TEST(MergeConfigs, named_transform_section) OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, [&options]() { OCIO::ColorspacesMerger(options).merge(); }, -// "Color space 'view_1' was not merged as it's already present in the base config"); "Equivalent base color space 'ACES2065-1' overrides 'ACES2065-1' in the input config, preserving aliases.", "Equivalent base color space 'ACEScct' overrides 'ACEScct - SomeOtherName' in the input config, preserving aliases.", "Equivalent base color space 'view_1' overrides 'view_1' in the input config, preserving aliases.", @@ -4182,7 +4360,6 @@ OCIO_ADD_TEST(MergeConfigs, named_transform_section) checkForLogOrException(LOG_TYPE_WARNING, __LINE__, [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, "Merged Base named transform 'nt_both' has a conflict with alias 'srgb_tx' in color space 'sRGB - Texture'", -// "Merged Base named transform 'nt_base' has an alias 'view_3' that conflicts with color space 'view_3'", "Merged Base named transform 'nt_base' has a conflict with alias 'view_3' in color space 'view_2'.", "Named transform 'nt_both' was not merged as it's already present in the base config", "Named transform 'nt_input' was not merged as it conflicts with an alias in named transform 'nt_base'", @@ -4217,7 +4394,6 @@ OCIO_ADD_TEST(MergeConfigs, named_transform_section) OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, [&options]() { OCIO::ColorspacesMerger(options).merge(); }, -// "Color space 'view_1' was not merged as it's already present in the base config"); "Equivalent base color space 'ACES2065-1' overrides 'ACES2065-1' in the input config, preserving aliases.", "Equivalent base color space 'ACEScct' overrides 'ACEScct - SomeOtherName' in the input config, preserving aliases.", "Equivalent base color space 'view_1' overrides 'view_1' in the input config, preserving aliases.", @@ -4228,7 +4404,6 @@ OCIO_ADD_TEST(MergeConfigs, named_transform_section) checkForLogOrException(LOG_TYPE_WARNING, __LINE__, [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, "Merged Base named transform 'nt_both' has a conflict with alias 'srgb_tx' in color space 'sRGB - Texture'", -// "Merged Base named transform 'nt_base' has an alias 'view_3' that conflicts with color space 'view_3'", "Merged Base named transform 'nt_base' has a conflict with alias 'view_3' in color space 'view_2'.", "Named transform 'nt_both' was not merged as it's already present in the base config", "Named transform 'nt_input' was not merged as it conflicts with an alias in named transform 'nt_base'", @@ -4355,12 +4530,7 @@ OCIO_ADD_TEST(MergeConfigs, named_transform_section_errors) return params; }; - // Test ADD_NT_ERROR_AT_LEAST_ONE_TRANSFORM, - { - - } - - // Test ADD_NT_ERROR_NAME_IDENTICAL_TO_A_ROLE_NAME, + // NT name matches a role name. { { constexpr const char * BASE { @@ -4413,8 +4583,8 @@ R"(ocio_profile_version: 2 OCIO::RolesMerger(options).merge(); OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Named transform 'B' was not merged as it's identical to a role name"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'B' was not merged as it's identical to a role name"); OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 1); OCIO_CHECK_EQUAL(mergedConfig->getRoleName(0), std::string("b")); @@ -4433,8 +4603,8 @@ R"(ocio_profile_version: 2 OCIO::RolesMerger(options).merge(); OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Named transform 'B' was not merged as it's identical to a role name"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'B' was not merged as it's identical to a role name"); OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 1); OCIO_CHECK_EQUAL(mergedConfig->getRoleName(0), std::string("b")); @@ -4451,9 +4621,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; - OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), - OCIO::Exception, - "Named transform 'B' was not merged as it's identical to a role name"); + OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), OCIO::Exception, + "Named transform 'B' was not merged as it's identical to a role name"); } } @@ -4495,8 +4664,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::RolesMerger(options).merge(); }, - "The Input config contains a role 'a' that would override Base config named transform: 'A'"); + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'a' that would override Base config named transform: 'A'"); OCIO::ColorspacesMerger(options).merge(); OCIO::NamedTransformsMerger(options).merge(); @@ -4512,8 +4681,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::RolesMerger(options).merge(); }, - "The Input config contains a role 'a' that would override Base config named transform: 'A'"); + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'a' that would override Base config named transform: 'A'"); OCIO::ColorspacesMerger(options).merge(); OCIO::NamedTransformsMerger(options).merge(); @@ -4525,7 +4694,7 @@ R"(ocio_profile_version: 2 } } - // Test ADD_NT_ERROR_NAME_IDENTICAL_TO_COLORSPACE_OR_ALIAS, + // NT name matches a color space name. { { constexpr const char * BASE { @@ -4581,9 +4750,9 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Named transform 'B' was not merged as there's a color space with that name", - "Named transform 'B1' was not merged as there's a color space alias with that name"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'B' was not merged as there's a color space with that name", + "Named transform 'B1' was not merged as there's a color space alias with that name"); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 0); @@ -4605,9 +4774,9 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Named transform 'B' was not merged as there's a color space with that name", - "Named transform 'B1' was not merged as there's a color space alias with that name"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'B' was not merged as there's a color space with that name", + "Named transform 'B1' was not merged as there's a color space alias with that name"); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 0); @@ -4631,9 +4800,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); - OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), - OCIO::Exception, - "Named transform 'B' was not merged as there's a color space with that name"); + OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), OCIO::Exception, + "Named transform 'B' was not merged as there's a color space with that name"); } } @@ -4687,9 +4855,9 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Named transform 'A' was not merged as there's a color space with that name", - "Named transform 'A1' was not merged as there's a color space alias with that name"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'A' was not merged as there's a color space with that name", + "Named transform 'A1' was not merged as there's a color space alias with that name"); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 0); @@ -4710,9 +4878,9 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Named transform 'A' was not merged as there's a color space with that name", - "Named transform 'A1' was not merged as there's a color space alias with that name"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'A' was not merged as there's a color space with that name", + "Named transform 'A1' was not merged as there's a color space alias with that name"); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 0); @@ -4728,11 +4896,7 @@ R"(ocio_profile_version: 2 } } - // Test ADD_NT_ERROR_NAME_CONTAIN_CTX_VAR_TOKEN, - // Not handled as it can't happen in this context. - // The config will error out while loading the config (before the merge process). - - // Test ADD_NT_ERROR_NAME_IDENTICAL_TO_EXISTING_NT_ALIAS, + // NT name matches an NT alias. { { constexpr const char * BASE { @@ -4784,8 +4948,8 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "The name of merged named transform 'B' has a conflict with an alias in named transform 'A'"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "The name of merged named transform 'B' has a conflict with an alias in named transform 'A'"); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); @@ -4805,8 +4969,8 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "The name of merged named transform 'B' has a conflict with an alias in named transform 'A'"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "The name of merged named transform 'B' has a conflict with an alias in named transform 'A'"); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); @@ -4825,9 +4989,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); - OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), - OCIO::Exception, - "The name of merged named transform 'B' has a conflict with an alias in named transform 'A'"); + OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), OCIO::Exception, + "The name of merged named transform 'B' has a conflict with an alias in named transform 'A'"); } } @@ -4880,8 +5043,8 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Merged Input named transform 'B' has an alias 'A' that conflicts with named transform 'A'"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Merged Input named transform 'B' has an alias 'A' that conflicts with named transform 'A'"); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); @@ -4900,8 +5063,8 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Merged Input named transform 'B' has an alias 'A' that conflicts with named transform 'A'"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Merged Input named transform 'B' has an alias 'A' that conflicts with named transform 'A'"); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); @@ -4916,7 +5079,7 @@ R"(ocio_profile_version: 2 } } - // Test ADD_NT_ERROR_ALIAS_IDENTICAL_TO_A_ROLE_NAME, + // NT alias matches a role name. { { constexpr const char * BASE { @@ -4965,8 +5128,8 @@ R"(ocio_profile_version: 2 OCIO::RolesMerger(options).merge(); OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Merged Input named transform 'B' has an alias 'B1' that conflicts with a role"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Merged Input named transform 'B' has an alias 'B1' that conflicts with a role"); OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 1); OCIO_CHECK_EQUAL(mergedConfig->getRoleName(0), std::string("b1")); @@ -4988,8 +5151,8 @@ R"(ocio_profile_version: 2 OCIO::RolesMerger(options).merge(); OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Merged Input named transform 'B' has an alias 'B1' that conflicts with a role"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Merged Input named transform 'B' has an alias 'B1' that conflicts with a role"); OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 1); OCIO_CHECK_EQUAL(mergedConfig->getRoleName(0), std::string("b1")); @@ -5011,9 +5174,8 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::RolesMerger(options).merge(); OCIO::ColorspacesMerger(options).merge(); - OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), - OCIO::Exception, - "Merged Input named transform 'B' has an alias 'B1' that conflicts with a role"); + OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), OCIO::Exception, + "Merged Input named transform 'B' has an alias 'B1' that conflicts with a role"); } } @@ -5062,8 +5224,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::RolesMerger(options).merge(); }, - "The Input config contains a role 'a1' that would override an alias of Base config named transform: 'B'"); + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'a1' that would override an alias of Base config named transform: 'B'"); OCIO::ColorspacesMerger(options).merge(); OCIO::NamedTransformsMerger(options).merge(); @@ -5085,8 +5247,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::RolesMerger(options).merge(); }, - "The Input config contains a role 'a1' that would override an alias of Base config named transform: 'B'"); + [&options]() { OCIO::RolesMerger(options).merge(); }, + "The Input config contains a role 'a1' that would override an alias of Base config named transform: 'B'"); OCIO::ColorspacesMerger(options).merge(); OCIO::NamedTransformsMerger(options).merge(); @@ -5103,7 +5265,7 @@ R"(ocio_profile_version: 2 } } - // Test ADD_NT_ERROR_ALIAS_IDENTICAL_TO_COLORSPACE_OR_ALIAS, + // NT name matches color space alias. { { constexpr const char * BASE { @@ -5159,9 +5321,9 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Named transform 'B' was not merged as there's a color space with that name", - "Named transform 'B1' was not merged as there's a color space alias with that name"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'B' was not merged as there's a color space with that name", + "Named transform 'B1' was not merged as there's a color space alias with that name"); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 0); @@ -5184,9 +5346,9 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Named transform 'B' was not merged as there's a color space with that name", - "Named transform 'B1' was not merged as there's a color space alias with that name"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'B' was not merged as there's a color space with that name", + "Named transform 'B1' was not merged as there's a color space alias with that name"); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 0); @@ -5209,9 +5371,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); - OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), - OCIO::Exception, - "Named transform 'B' was not merged as there's a color space with that name"); + OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), OCIO::Exception, + "Named transform 'B' was not merged as there's a color space with that name"); } } @@ -5268,9 +5429,9 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Named transform 'A' was not merged as there's a color space with that name", - "Named transform 'A1' was not merged as there's a color space alias with that name"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'A' was not merged as there's a color space with that name", + "Named transform 'A1' was not merged as there's a color space alias with that name"); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 0); @@ -5293,9 +5454,9 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Named transform 'A' was not merged as there's a color space with that name", - "Named transform 'A1' was not merged as there's a color space alias with that name"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Named transform 'A' was not merged as there's a color space with that name", + "Named transform 'A1' was not merged as there's a color space alias with that name"); OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 0); @@ -5312,11 +5473,7 @@ R"(ocio_profile_version: 2 } } - // Test ADD_NT_ERROR_ALIAS_CONTAIN_CTX_VAR_TOKEN, - // Not handled as it can't happen in this context. - // The config will error out while loading the config (before the merge process). - - // Test ADD_NT_ERROR_ALIAS_IDENTICAL_TO_EXISTING_NT_ALIAS + // NT alias matches existing NT alias. { { constexpr const char * BASE { @@ -5370,8 +5527,8 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Merged Input named transform 'B' has a conflict with alias 'my_colorspace' in named transform 'A'"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Merged Input named transform 'B' has a conflict with alias 'my_colorspace' in named transform 'A'"); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); @@ -5392,8 +5549,8 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Merged Input named transform 'B' has a conflict with alias 'my_colorspace' in named transform 'A'"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Merged Input named transform 'B' has a conflict with alias 'my_colorspace' in named transform 'A'"); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); @@ -5415,8 +5572,8 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Merged Input named transform 'B' has a conflict with alias 'my_colorspace' in named transform 'A'"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Merged Input named transform 'B' has a conflict with alias 'my_colorspace' in named transform 'A'"); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); @@ -5437,8 +5594,8 @@ R"(ocio_profile_version: 2 OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, - "Merged Input named transform 'B' has a conflict with alias 'my_colorspace' in named transform 'A'"); + [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, + "Merged Input named transform 'B' has a conflict with alias 'my_colorspace' in named transform 'A'"); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 2); @@ -5460,9 +5617,8 @@ R"(ocio_profile_version: 2 OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; OCIO::ColorspacesMerger(options).merge(); - OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), - OCIO::Exception, - "Merged Input named transform 'B' has a conflict with alias 'my_colorspace' in named transform 'A'"); + OCIO_CHECK_THROW_WHAT(OCIO::NamedTransformsMerger(options).merge(), OCIO::Exception, + "Merged Input named transform 'B' has a conflict with alias 'my_colorspace' in named transform 'A'"); } } } @@ -5485,15 +5641,13 @@ OCIO_ADD_TEST(MergeConfigs, merges_with_ociom_file) OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); OCIO::ConstConfigMergerRcPtr newMerger; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&newMerger, &merger]() { newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); }, - "The Input config contains a value that would override the Base config: file_rules: Default", - "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", + [&newMerger, &merger]() { newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); }, + "The Input config contains a value that would override the Base config: file_rules: Default", + "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", "Equivalent input color space 'sRGB - Display' replaces 'sRGB - Display' in the base config, preserving aliases.", "Equivalent input color space 'CIE-XYZ-D65' replaces 'CIE-XYZ-D65' in the base config, preserving aliases.", "Equivalent input color space 'ACES2065-1' replaces 'ap0' in the base config, preserving aliases.", "Equivalent input color space 'sRGB' replaces 'sRGB - Texture' in the base config, preserving aliases."); -// TODO: Last one should not be necessary. -// "The Input config contains a role that would override Base config role 'aces_interchange'"); OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); // This test is essentially the same as the first sub-test in the above test @@ -5504,27 +5658,11 @@ OCIO_ADD_TEST(MergeConfigs, merges_with_ociom_file) OCIO_CHECK_EQUAL(mergedConfig->getDescription(), std::string("Basic merge with default strategy")); OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, OCIO::COLORSPACE_ALL), 7); - - - -// std::ostringstream oss; -// mergedConfig->serialize(oss); -// -// std::istringstream resultIss; -// resultIss.str(RESULT); -// OCIO::ConstConfigRcPtr resultConfig = OCIO::Config::CreateFromStream(resultIss); -// std::ostringstream ossResult; -// resultConfig->serialize(ossResult); -// -// //Testing the string of each config -// -// OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); - } } -/* - // Test is very similar as the previous one but it has two merges in - // the OCIOM file and it is using the output of the first merged config + + // Test is similar to the previous one but it has two merges in the + // OCIOM file and it is using the output of the first merged config // as the input for the second merge. { std::vector paths = { @@ -5536,127 +5674,59 @@ OCIO_ADD_TEST(MergeConfigs, merges_with_ociom_file) }; const std::string ociomPath = pystring::os::path::normpath(pystring::os::path::join(paths)); - // PreferInput, Input first { OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); OCIO::ConstConfigMergerRcPtr newMerger; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&newMerger, &merger]() { newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); }, - "The Input config contains a value that would override the Base config: file_rules: Default", - "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'"); + [&newMerger, &merger]() { newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); }, + "The Input config contains a value that would override the Base config: file_rules: Default", + "The Input config contains a role that would override Base config role 'cie_xyz_d65_interchange'", + "Color space 'sRGB - Display' was not merged as it's already present in the base config", + "Color space 'CIE-XYZ-D65' was not merged as it's already present in the base config", + "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", + "Color space 'sRGB' was not merged as it conflicts with an alias in color space 'sRGB - Texture'", + "Equivalent base color space 'ap0' overrides 'rec709' in the input config, preserving aliases"); OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); - std::ostringstream oss; - mergedConfig->serialize(oss); - - constexpr const char * RESULT { -R"(ocio_profile_version: 2.1 - -environment: - {} -search_path: lut_dir -strictparsing: true -luma: [0.2126, 0.7152, 0.0722] -name: Merged2 -description: Same as the input -roles: - cie_xyz_d65_interchange: CIE-XYZ-D65 + OCIO_CHECK_NO_THROW(mergedConfig->validate()); -file_rules: - - ! {name: Default, colorspace: sRGB} + OCIO_CHECK_EQUAL(mergedConfig->getName(), std::string("Merged2")); + OCIO_CHECK_EQUAL(mergedConfig->getDescription(), std::string("Description override")); + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, + OCIO::COLORSPACE_ALL), 7); -displays: - sRGB - Display: - - ! {name: Raw, colorspace: raw} - - ! {name: ACES 1.0 - SDR Video, view_transform: SDR Video, display_colorspace: sRGB - Display} + // The second merge replaces the file rules of the first merge with the input config. + OCIO::ConstFileRulesRcPtr fr = mergedConfig->getFileRules(); + OCIO_CHECK_EQUAL(fr->getNumEntries(), 1); + OCIO_CHECK_EQUAL(std::string(fr->getName(0)), "Default"); + OCIO_CHECK_EQUAL(std::string(fr->getColorSpace(0)), "sRGB"); -active_displays: [] -active_views: [] -inactive_colorspaces: [ACES2065-1] + // The second merge replaces the roles of the first merge with the input config. + OCIO_CHECK_EQUAL(mergedConfig->getNumRoles(), 1); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getRoleColorSpace("cie_xyz_d65_interchange")), + std::string("CIE-XYZ-D65")); -view_transforms: - - ! - name: SDR Video - from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1} + // The rest of the config should be the result of the first merge. -display_colorspaces: - - ! - name: sRGB - Display - aliases: [srgb_display] - family: Display~Standard - equalitygroup: "" - bitdepth: unknown - description: from input - isdata: false - allocation: uniform - from_display_reference: ! {gamma: 2.4, offset: 0.055, direction: inverse} - - - ! - name: CIE-XYZ-D65 - aliases: [cie_xyz_d65] - family: "" - equalitygroup: "" - bitdepth: unknown - description: The \"CIE XYZ (D65)\" display connection colorspace. - isdata: false - allocation: uniform - from_display_reference: ! {matrix: [0.412390799266, 0.357584339384, 0.180480788402, 0, 0.212639005872, 0.715168678768, 0.072192315361, 0, 0.019330818716, 0.119194779795, 0.95053215225, 0, 0, 0, 0, 1]} + OCIO_CHECK_EQUAL(mergedConfig->getNumDisplaysAll(), 1); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplay(0)), "sRGB - Display"); + OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_DISPLAY_DEFINED, "sRGB - Display"), 2); -colorspaces: - - ! - name: ACES2065-1 - aliases: [aces] - family: ACES~Linear - equalitygroup: "" - bitdepth: unknown - description: from input - isdata: false - allocation: uniform - to_scene_reference: ! {matrix: [2.521686186744, -1.13413098824, -0.387555198504, 0, -0.27647991423, 1.372719087668, -0.096239173438, 0, -0.015378064966, -0.152975335867, 1.168353400833, 0, 0, 0, 0, 1]} - - - ! - name: sRGB - family: Texture~ - equalitygroup: "" - bitdepth: unknown - description: from input - isdata: false - allocation: uniform - to_scene_reference: ! {gamma: 2.4, offset: 0.055} - - - ! - name: rec709 - family: "" - equalitygroup: "" - bitdepth: unknown - description: from input - isdata: false - allocation: uniform - - - ! - name: Raw - aliases: [Utility - Raw] - family: Utility - equalitygroup: "" - bitdepth: 32f - description: The utility "Raw" colorspace. - isdata: true - categories: [file-io] - allocation: uniform - )" }; + OCIO::ConstColorSpaceRcPtr cs = nullptr; + cs = checkColorSpace(mergedConfig, "sRGB - Display", 0, OCIO::SEARCH_REFERENCE_SPACE_DISPLAY, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 1); + OCIO_CHECK_EQUAL(cs->getAlias(0), std::string("srgb_display")); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("Display-Basic")); + OCIO_CHECK_EQUAL(cs->getDescription(), std::string("from base")); - std::istringstream resultIss; - resultIss.str(RESULT); - OCIO::ConstConfigRcPtr resultConfig = OCIO::Config::CreateFromStream(resultIss); - std::ostringstream ossResult; - resultConfig->serialize(ossResult); + cs = checkColorSpace(mergedConfig, "ACES2065-1", 0, OCIO::SEARCH_REFERENCE_SPACE_SCENE, __LINE__); + OCIO_CHECK_EQUAL(cs->getNumAliases(), 0); + OCIO_CHECK_EQUAL(cs->getFamily(), std::string("ACES~Linear")); + OCIO_CHECK_EQUAL(cs->getDescription(), std::string("from input")); - //Testing the string of each config -// OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getInactiveColorSpaces()), "ACES2065-1"); } } -*/ -//std::cout << "merge3\n"; // Test with external LUT files. { @@ -5672,17 +5742,13 @@ inactive_colorspaces: [ACES2065-1] // PreferInput, Input first { OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); -// OCIO::ConstConfigMergerRcPtr newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); OCIO::ConstConfigMergerRcPtr newMerger; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&newMerger, &merger]() { newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); }, + [&newMerger, &merger]() { newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); }, "Color space 'raw' will replace a color space in the base config."); OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); -// std::ostringstream oss; -// mergedConfig->serialize(oss); OCIO_CHECK_NO_THROW(mergedConfig->validate()); - { OCIO_CHECK_EQUAL(mergedConfig->getSearchPath(), std::string("./$SHOT:./shot1:shot2:.")); auto cs = mergedConfig->getColorSpace("shot1_lut1_cs"); auto tf = cs->getTransform(OCIO::COLORSPACE_DIR_TO_REFERENCE); @@ -5690,17 +5756,13 @@ inactive_colorspaces: [ACES2065-1] OCIO_REQUIRE_ASSERT(ftf); OCIO_CHECK_EQUAL(ftf->getSrc(), std::string("shot1/lut1.clf")); OCIO_CHECK_NO_THROW(mergedConfig->getProcessor(ftf)) - } - { + auto look = mergedConfig->getLook("shot_look"); auto ltf = look->getTransform(); OCIO_CHECK_NO_THROW(mergedConfig->getProcessor(ltf)); - } } } -//std::cout << "merge3\n"; - // Test that a merge could go wrong if the search_paths are merged with a different strategy // than the other sections. { @@ -5713,21 +5775,17 @@ inactive_colorspaces: [ACES2065-1] }; const std::string ociomPath = pystring::os::path::normpath(pystring::os::path::join(paths)); -// FIXME: The ociom file should not try to do avoid dupes. Is that also throwing? -// The base config is not suitable for find dupes. - { OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); -// merger->getParams(0)->setAssumeCommonReferenceSpace(true); - // Changing the strategy for colorspace merger to BASE ONLY. - // This will break the looks "shot_look" (from input) as it needs the search paths - // from the input config. (search_paths are managed by the colorspace merger). + // Changing the strategy for colorspace merger to INPUT_ONLY. + // This will break the looks "shot_look" (from base) as it needs the search paths + // from the base config (search_paths are managed by the colorspace merger). merger->getParams(0)->setColorspaces(OCIO::ConfigMergingParameters::STRATEGY_INPUT_ONLY); // The rest of the merges uses PreferInput strategy. - + OCIO::ConstConfigMergerRcPtr newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); - OCIO_CHECK_ASSERT(!mergedConfig->getConfigIOProxy()); + OCIO_CHECK_ASSERT(!mergedConfig->getConfigIOProxy()); auto look = mergedConfig->getLook("shot_look"); auto ltf = look->getTransform(); @@ -5742,8 +5800,6 @@ inactive_colorspaces: [ACES2065-1] } } -//std::cout << "merge4\n"; - // Test with a built-in config. { std::vector paths = { @@ -5760,12 +5816,12 @@ inactive_colorspaces: [ACES2065-1] OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); OCIO::ConstConfigMergerRcPtr newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); -// std::ostringstream oss; -// mergedConfig->serialize(oss); - // Test that the merged config is the same of the built-in config used as input. - auto bConfig = OCIO::Config::CreateFromBuiltinConfig("cg-config-v1.0.0_aces-v1.3_ocio-v2.1"); -// OCIO_CHECK_EQUAL(std::string(mergedConfig->getCacheID()), std::string(bConfig->getCacheID())); + OCIO_CHECK_NO_THROW(mergedConfig->validate()); + + OCIO_CHECK_EQUAL(mergedConfig->getName(), std::string("cg-config-v1.0.0_aces-v1.3_ocio-v2.1")); + OCIO_CHECK_EQUAL(mergedConfig->getNumColorSpaces(OCIO::SEARCH_REFERENCE_SPACE_ALL, + OCIO::COLORSPACE_ALL), 20); } } } @@ -5797,56 +5853,38 @@ OCIO_ADD_TEST(MergeConfigs, merges_with_ocioz_file) OCIO::ConstConfigRcPtr inputConfig; OCIO_CHECK_NO_THROW(inputConfig = OCIO::Config::CreateFromFile(configPathInput.c_str())); - OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); - params->setInputFirst(false); - MergeStrategy strategy = MergeStrategy::STRATEGY_PREFER_INPUT; - params->setRoles(strategy); - params->setColorspaces(strategy); - params->setNamedTransforms(strategy); - params->setDefaultStrategy(strategy); - params->setInputFamilyPrefix("Input/"); - params->setBaseFamilyPrefix("Base/"); - params->setAssumeCommonReferenceSpace(true); - params->setAvoidDuplicates(false); - -// OCIO::ConfigRcPtr mergedConfig = OCIO::ConfigMergingHelpers::MergeConfigs(params, baseConfig, inputConfig); - OCIO::ConfigRcPtr mergedConfig; - checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&mergedConfig, ¶ms, &baseConfig, &inputConfig]() { mergedConfig = OCIO::ConfigMergingHelpers::MergeConfigs(params, baseConfig, inputConfig); }, - "Color space 'reference' will replace a color space in the base config.", - "Color space 'raw' will replace a color space in the base config.", - "Color space 'plain_lut1_cs' will replace a color space in the base config.", - "Color space 'shot1_lut1_cs' will replace a color space in the base config."); - -// OCIO::ConfigRcPtr mergedConfig; -// checkForLogOrException(LOG_TYPE_WARNING, __LINE__, -// // [&newMerger, &merger]() { newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); }, -// [&mergedConfig, ¶ms, &baseConfig, &inputConfig]() -// { mergedConfig = OCIO::ConfigMergingHelpers::MergeConfigs(params, baseConfig, inputConfig); }, -// "The Input config contains a value that would override the Base config: file_rules: Default"); - - -// FIXME: Add a test to check this result. -// std::ostringstream ossResult; -// mergedConfig->serialize(ossResult); -// std::cout << ossResult.str() << "\n"; - -// std::ostringstream oss; -// mergedConfig->serialize(oss); -// std::cout << oss.str() << "\n"; - - // The working dir is empty. - OCIO_CHECK_EQUAL(mergedConfig->getWorkingDir(), std::string("")); -//std::cout << "Working dir: " << mergedConfig->getWorkingDir() << "\n"; - // The configIOProxy is not NULL. - OCIO_CHECK_ASSERT(mergedConfig->getConfigIOProxy()); -//std::cout << "IOProxy: " << mergedConfig->getConfigIOProxy() << "\n"; - - OCIO::ContextRcPtr ctx = mergedConfig->getCurrentContext()->createEditableCopy(); - double mat[16] = { 0., 0., 0., 0., - 0., 0., 0., 0., - 0., 0., 0., 0., - 0., 0., 0., 0. }; + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + params->setInputFirst(false); + MergeStrategy strategy = MergeStrategy::STRATEGY_PREFER_INPUT; + params->setRoles(strategy); + params->setColorspaces(strategy); + params->setNamedTransforms(strategy); + params->setDefaultStrategy(strategy); + params->setInputFamilyPrefix("Input/"); + params->setBaseFamilyPrefix("Base/"); + params->setAssumeCommonReferenceSpace(true); + params->setAvoidDuplicates(false); + + { + OCIO::ConfigRcPtr mergedConfig; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&mergedConfig, ¶ms, &baseConfig, &inputConfig]() + { mergedConfig = OCIO::ConfigMergingHelpers::MergeConfigs(params, baseConfig, inputConfig); }, + "Color space 'reference' will replace a color space in the base config.", + "Color space 'raw' will replace a color space in the base config.", + "Color space 'plain_lut1_cs' will replace a color space in the base config.", + "Color space 'shot1_lut1_cs' will replace a color space in the base config."); + + // The working dir is empty. + OCIO_CHECK_EQUAL(mergedConfig->getWorkingDir(), std::string("")); + // The configIOProxy is not NULL. + OCIO_CHECK_ASSERT(mergedConfig->getConfigIOProxy()); + + OCIO::ContextRcPtr ctx = mergedConfig->getCurrentContext()->createEditableCopy(); + double mat[16] = { 0., 0., 0., 0., + 0., 0., 0., 0., + 0., 0., 0., 0., + 0., 0., 0., 0. }; // This is resolved in the OCIOZ base. { @@ -5871,17 +5909,17 @@ OCIO_ADD_TEST(MergeConfigs, merges_with_ocioz_file) OCIO_CHECK_THROW(mergedConfig->getProcessor(ctx, "shot1_lut2_cs", "reference"), OCIO::Exception); } - // Add an absolute search path for the input config. - std::vector pathsInput1 = { - std::string(OCIO::GetTestFilesDir()), - std::string("configs"), - std::string("mergeconfigs"), - std::string("merged3") - }; - static const std::string searchPathInput = pystring::os::path::normpath( - pystring::os::path::join(pathsInput1) - ); -// std::cout << "added absolute search path\n"; + // Add an absolute search path for the input config. + std::vector pathsInput1 = { + std::string(OCIO::GetTestFilesDir()), + std::string("configs"), + std::string("mergeconfigs"), + std::string("merged3") + }; + static const std::string searchPathInput = pystring::os::path::normpath( + pystring::os::path::join(pathsInput1) + ); + ctx->clearSearchPaths(); ctx->addSearchPath(searchPathInput.c_str()); for (int i = 0; i < mergedConfig->getNumSearchPaths(); i++) @@ -5898,7 +5936,7 @@ OCIO_ADD_TEST(MergeConfigs, merges_with_ocioz_file) OCIO_CHECK_EQUAL(mat[0], 42.); // doesn't exist in the base config } - // FIXME: The next test won't work without this. Is that expected that you need to clear + // TODO: The next test won't work without this. Is that expected that you need to clear // the cache after adding a search path, or is there a bug involving the cacheID of processors // when OCIOZ is being used? mergedConfig->clearProcessorCache(); @@ -5911,98 +5949,13 @@ OCIO_ADD_TEST(MergeConfigs, merges_with_ocioz_file) mtx->getMatrix(mat); OCIO_CHECK_EQUAL(mat[0], 100.); // is 10 in the base config, 100 in input } - -// -// std::istringstream resultIss; -// resultIss.str(RESULT); -// OCIO::ConstConfigRcPtr resultConfig = OCIO::Config::CreateFromStream(resultIss); -// std::ostringstream ossResult; -// resultConfig->serialize(ossResult); -// -// //Testing the string of each config -// OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); - - - - - - - -// auto setupBasics = [](OCIO::ConfigMergerRcPtr & merger, MergeStrategy strategy) -> OCIO::ConfigMergingParametersRcPtr -// { -// OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); -// merger->addParams(params); -// // Note that these tests run several of the mergers. -// // Need to run the color space merger too, since that affects how the named transform -// // merger will work (in terms of avoiding conflicts with color space names). -// merger->getParams(0)->setRoles(strategy); -// merger->getParams(0)->setColorspaces(strategy); -// merger->getParams(0)->setNamedTransforms(strategy); -// merger->getParams(0)->setDefaultStrategy(strategy); -// -// merger->getParams(0)->setInputFamilyPrefix("Input/"); -// merger->getParams(0)->setBaseFamilyPrefix("Base/"); -// -// merger->getParams(0)->setAssumeCommonReferenceSpace(true); -// merger->getParams(0)->setAvoidDuplicates(false); -// merger->getParams(0)->setInputFirst(true); -// -// return params; -// }; -// -// { -// OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); -// auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); -// -// OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); -// OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; -// checkForLogOrException(LOG_TYPE_WARNING, __LINE__, -// [&options]() { OCIO::ColorspacesMerger(options).merge(); }, -// "Equivalent input color space 'lin_3' replaces 'ACES2065-1' in the base config, preserving aliases."); -// checkForLogOrException(LOG_TYPE_WARNING, __LINE__, -// [&options]() { OCIO::NamedTransformsMerger(options).merge(); }, -// "Named transform 'view_2' was not merged as there's a color space alias with that name."); -// -// OCIO_CHECK_EQUAL(mergedConfig->getNumNamedTransforms(OCIO::NAMEDTRANSFORM_ALL), 3); -// -// OCIO::ConstNamedTransformRcPtr nt = nullptr; -// nt = checkNamedTransform(mergedConfig, "nt_both", 0, __LINE__); -// OCIO_CHECK_EQUAL(nt->getNumAliases(), 1); -// OCIO_CHECK_EQUAL(nt->getAlias(0), std::string("nametr")); -// OCIO_CHECK_EQUAL(nt->getFamily(), std::string("Input@")); -// OCIO_CHECK_EQUAL(nt->getDescription(), std::string("from input")); -// } - + } } - // Test with an OCIOZ archive - // { - // std::vector paths = { - // std::string(OCIO::GetTestFilesDir()), - // std::string("configs"), - // std::string("mergeconfigs"), - // std::string("merged4"), - // std::string("merged.ociom") - // }; - // const std::string ociomPath = pystring::os::path::normpath(pystring::os::path::join(paths)); - - // // InputOnly - // { - // OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); - // // Update the merge to point to the OCIOZ archive as the input. - // merger->getParams(0)->setInputConfigName(""); - - // OCIO::ConstConfigMergerRcPtr newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); - // OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); - // std::ostringstream oss; - // mergedConfig->serialize(oss); - // OCIO_CHECK_NO_THROW(mergedConfig->validate()); - // } - //} OCIO_ADD_TEST(MergeConfigs, merge_in_memory_configs) { - constexpr const char * BASE { -R"(ocio_profile_version: 2 + constexpr const char * BASE { +R"(ocio_profile_version: 2.1 file_rules: - ! {name: Default, colorspace: A} @@ -6016,7 +5969,7 @@ R"(ocio_profile_version: 2 family: utility )" }; - constexpr const char * INPUT { + constexpr const char * INPUT { R"(ocio_profile_version: 2 file_rules: @@ -6028,8 +5981,8 @@ R"(ocio_profile_version: 2 family: aces )" }; - constexpr const char * RESULT { -R"(ocio_profile_version: 2 + constexpr const char * RESULT { +R"(ocio_profile_version: 2.1 roles: a: colorspace_a @@ -6054,56 +6007,44 @@ R"(ocio_profile_version: 2 isdata: false allocation: uniform)" }; - std::istringstream bss(BASE); - std::istringstream iss(INPUT); - OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); - OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + params->setInputFirst(false); + MergeStrategy strategy = MergeStrategy::STRATEGY_PREFER_INPUT; + params->setRoles(strategy); + params->setColorspaces(strategy); + params->setNamedTransforms(strategy); + params->setDefaultStrategy(strategy); + params->setInputFamilyPrefix("Input/"); + params->setBaseFamilyPrefix("Base/"); + params->setAssumeCommonReferenceSpace(true); + params->setAvoidDuplicates(false); + + OCIO::ConfigRcPtr mergedConfig; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&mergedConfig, ¶ms, &baseConfig, &inputConfig]() + { mergedConfig = OCIO::ConfigMergingHelpers::MergeConfigs(params, baseConfig, inputConfig); }, + "The Input config contains a value that would override the Base config: file_rules: Default"); - OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); - params->setInputFirst(false); - MergeStrategy strategy = MergeStrategy::STRATEGY_PREFER_INPUT; - params->setRoles(strategy); - params->setColorspaces(strategy); - params->setNamedTransforms(strategy); - params->setDefaultStrategy(strategy); - params->setInputFamilyPrefix("Input/"); - params->setBaseFamilyPrefix("Base/"); - params->setAssumeCommonReferenceSpace(true); - params->setAvoidDuplicates(false); - -// OCIO::ConfigRcPtr mergedConfig = OCIO::ConfigMergingHelpers::MergeConfigs(params, baseConfig, inputConfig); - OCIO::ConfigRcPtr mergedConfig; + std::ostringstream oss; + mergedConfig->serialize(oss); - checkForLogOrException(LOG_TYPE_WARNING, __LINE__, -// [&newMerger, &merger]() { newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); }, - [&mergedConfig, ¶ms, &baseConfig, &inputConfig]() { mergedConfig = OCIO::ConfigMergingHelpers::MergeConfigs(params, baseConfig, inputConfig); }, - "The Input config contains a value that would override the Base config: file_rules: Default"); -// "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", -// TODO: Last one should not be necessary. -// "The Input config contains a role that would override Base config role 'aces_interchange'"); - - -// FIXME: Add a test to check this result. -// std::ostringstream ossResult; -// mergedConfig->serialize(ossResult); -// std::cout << ossResult.str() << "\n"; - - std::ostringstream oss; - mergedConfig->serialize(oss); - - std::istringstream resultIss; - resultIss.str(RESULT); - OCIO::ConstConfigRcPtr resultConfig = OCIO::Config::CreateFromStream(resultIss); - std::ostringstream ossResult; - resultConfig->serialize(ossResult); - - //Testing the string of each config - OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); + std::istringstream resultIss; + resultIss.str(RESULT); + OCIO::ConstConfigRcPtr resultConfig = OCIO::Config::CreateFromStream(resultIss); + std::ostringstream ossResult; + resultConfig->serialize(ossResult); + + OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); } OCIO_ADD_TEST(MergeConfigs, merge_single_colorspace) { - constexpr const char * BASE { + constexpr const char * BASE { R"(ocio_profile_version: 2 file_rules: @@ -6118,8 +6059,8 @@ R"(ocio_profile_version: 2 family: utility )" }; - constexpr const char * INPUT { -R"(ocio_profile_version: 2 + constexpr const char * INPUT { +R"(ocio_profile_version: 2.1 file_rules: - ! {name: Default, colorspace: B} @@ -6129,63 +6070,73 @@ R"(ocio_profile_version: 2 name: B family: aces )" }; - std::istringstream bss(BASE); - std::istringstream iss(INPUT); - OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); - OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); - OCIO::ConstColorSpaceRcPtr colorspace = inputConfig->getColorSpace("B"); - OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); - params->setInputFirst(false); - MergeStrategy strategy = MergeStrategy::STRATEGY_PREFER_INPUT; - params->setRoles(strategy); - params->setColorspaces(strategy); - params->setNamedTransforms(strategy); - params->setDefaultStrategy(strategy); - params->setInputFamilyPrefix("Input/"); - params->setBaseFamilyPrefix("Base/"); - params->setAssumeCommonReferenceSpace(true); - params->setAvoidDuplicates(false); - - OCIO::ConfigRcPtr mergedConfig = OCIO::ConfigMergingHelpers::MergeColorSpace(params, baseConfig, colorspace); - -// FIXME: Add a test to check this result. -// std::ostringstream ossResult; -// mergedConfig->serialize(ossResult); -// std::cout << ossResult.str() << "\n"; -} + constexpr const char * RESULT { +R"(ocio_profile_version: 2 -/* -OCIO_ADD_TEST(MergeConfigs, avoid_duplicate_color_spaces) -{ - { -// std::vector paths = { -// std::string(OCIO::GetTestFilesDir()), -// std::string("configs"), -// std::string("mergeconfigs"), -// std::string("merged1"), -// std::string("merged1.ociom") -// }; -// const std::string ociomPath = pystring::os::path::normpath(pystring::os::path::join(paths)); +environment: + {} +search_path: "" +strictparsing: true +luma: [0.2126, 0.7152, 0.0722] + +roles: + a: colorspace_a - const std::string ociomPath = "/Users/walkerdo/Documents/work/Autodesk/color/adsk_color_mgmt/OCIO/configs/merging/merge_flame_core.ociom"; +file_rules: + - ! {name: Default, colorspace: A} - // PreferInput, Input first - { - OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); - OCIO::ConstConfigMergerRcPtr newMerger; -// checkForLogOrException(LOG_TYPE_WARNING, __LINE__, -// [&newMerger, &merger]() { newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); }, -// "The Input config contains a value that would override the Base config: file_rules: Default", -// "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'"); -// TODO: Last one should not be necessary. -// "The Input config contains a role that would override Base config role 'aces_interchange'"); - newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); - OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); - std::ostringstream oss; - mergedConfig->serialize(oss); -// std::cout << oss.str() << "\n"; - } - } +displays: + {} + +active_displays: [] +active_views: [] + +colorspaces: + - ! + name: colorspace_a + family: Base/utility + equalitygroup: "" + bitdepth: unknown + isdata: false + allocation: uniform + + - ! + name: B + family: Input/aces + equalitygroup: "" + bitdepth: unknown + isdata: false + allocation: uniform)" }; + + std::istringstream bss(BASE); + std::istringstream iss(INPUT); + OCIO::ConstConfigRcPtr baseConfig = OCIO::Config::CreateFromStream(bss); + OCIO::ConstConfigRcPtr inputConfig = OCIO::Config::CreateFromStream(iss); + OCIO::ConstColorSpaceRcPtr colorspace = inputConfig->getColorSpace("B"); + + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + params->setInputFirst(false); + MergeStrategy strategy = MergeStrategy::STRATEGY_PREFER_INPUT; + params->setRoles(strategy); + params->setColorspaces(strategy); + params->setNamedTransforms(strategy); + params->setDefaultStrategy(strategy); + params->setInputFamilyPrefix("Input/"); + params->setBaseFamilyPrefix("Base/"); + params->setAssumeCommonReferenceSpace(true); + params->setAvoidDuplicates(false); + + OCIO::ConfigRcPtr mergedConfig = OCIO::ConfigMergingHelpers::MergeColorSpace(params, baseConfig, colorspace); + + std::ostringstream oss; + mergedConfig->serialize(oss); + + std::istringstream resultIss; + resultIss.str(RESULT); + OCIO::ConstConfigRcPtr resultConfig = OCIO::Config::CreateFromStream(resultIss); + std::ostringstream ossResult; + resultConfig->serialize(ossResult); + + OCIO_CHECK_EQUAL(oss.str(), ossResult.str()); } -*/ diff --git a/tests/data/files/configs/mergeconfigs/base_config.yaml b/tests/data/files/configs/mergeconfigs/base_config.yaml index cf4a881358..d0f95a4208 100644 --- a/tests/data/files/configs/mergeconfigs/base_config.yaml +++ b/tests/data/files/configs/mergeconfigs/base_config.yaml @@ -8,6 +8,7 @@ search_path: - . - abc +luma: [0.2126, 0.7152, 0.0722] name: base0 description: | My description 1 diff --git a/tests/data/files/configs/mergeconfigs/default_strategy.ociom b/tests/data/files/configs/mergeconfigs/default_strategy.ociom deleted file mode 100644 index 03b949e21f..0000000000 --- a/tests/data/files/configs/mergeconfigs/default_strategy.ociom +++ /dev/null @@ -1,25 +0,0 @@ -ociom_version: 1.0 -search_path: "." - -merge: - Merge1: - base: input0.ocio - input: input2.ocio - options: - input_family_prefix: "" - base_family_prefix: "" - input_first: true - error_on_conflict: false - default_strategy: InputOnly - avoid_duplicates: true - assume_common_reference_space: false - overrides: - name: my merge - description: my desc - search_path: "abc" - environment: - test: valueOther - test1: value123 - active_displays: ["D1", "D2"] - active_views: ["V1", "V2"] - inactive_colorspaces: ["I1", "I2"] \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/input_config.yaml b/tests/data/files/configs/mergeconfigs/input_config.yaml index 159bd3e841..ededdb91d4 100644 --- a/tests/data/files/configs/mergeconfigs/input_config.yaml +++ b/tests/data/files/configs/mergeconfigs/input_config.yaml @@ -1,4 +1,4 @@ -ocio_profile_version: 2 +ocio_profile_version: 2.1 environment: test: differentValue @@ -8,6 +8,7 @@ search_path: - . - def +luma: [0.262700, 0.677998, 0.059301] name: input0 description: | My description 2 diff --git a/tests/data/files/configs/mergeconfigs/merged1/base1.ocio b/tests/data/files/configs/mergeconfigs/merged1/base1.ocio index 2d52524ed2..9479937814 100644 --- a/tests/data/files/configs/mergeconfigs/merged1/base1.ocio +++ b/tests/data/files/configs/mergeconfigs/merged1/base1.ocio @@ -34,6 +34,7 @@ display_colorspaces: # reference space = cie xyz d65 aliases: [srgb_display] family: Display-Basic description: from base + categories: [file-io, display] from_display_reference: ! {style: DISPLAY - CIE-XYZ-D65_to_sRGB} - ! @@ -53,6 +54,7 @@ colorspaces: # reference space = aces2065-1 - ! name: ap0 family: ACES-Linear + categories: [file-io] description: from base - ! @@ -60,6 +62,7 @@ colorspaces: # reference space = aces2065-1 family: Texture aliases: [srgb, srgb_tx] description: from base + categories: [file-io] from_scene_reference: ! children: - ! {matrix: [2.52168618674388, -1.13413098823972, -0.387555198504164, 0, -0.276479914229922, 1.37271908766826, -0.096239173438334, 0, -0.0153780649660342, -0.152975335867399, 1.16835340083343, 0, 0, 0, 0, 1]} diff --git a/tests/data/files/configs/mergeconfigs/merged1/input1.ocio b/tests/data/files/configs/mergeconfigs/merged1/input1.ocio index 62782ffc4e..b912236bef 100644 --- a/tests/data/files/configs/mergeconfigs/merged1/input1.ocio +++ b/tests/data/files/configs/mergeconfigs/merged1/input1.ocio @@ -29,6 +29,8 @@ display_colorspaces: # reference space = linear rec 709 aliases: [] family: Display~Standard description: from input + categories: [file-io, texture] + encoding: sdr-video from_display_reference: ! {gamma: 2.4, offset: 0.055, direction: inverse} - ! @@ -44,17 +46,23 @@ colorspaces: # reference space = linear rec 709 aliases: [aces] family: ACES~Linear description: from input + categories: [texture] + encoding: scene-linear to_scene_reference: ! {matrix: [ 2.521686186744, -1.134130988240, -0.387555198504, 0, -0.276479914230, 1.372719087668, -0.096239173438, 0, -0.015378064966, -0.152975335867, 1.168353400833, 0, 0, 0, 0, 1 ]} - ! name: sRGB family: Texture~ description: from input + categories: [texture] + encoding: sdr-video to_scene_reference: ! {gamma: 2.4, offset: 0.055} - ! name: rec709 description: from input + categories: [texture] + encoding: sdr-video - ! name: Raw @@ -64,5 +72,5 @@ colorspaces: # reference space = linear rec 709 bitdepth: 32f description: The utility "Raw" colorspace. isdata: true - categories: [file-io] + categories: [file-io, texture] allocation: uniform \ No newline at end of file diff --git a/tests/data/files/configs/mergeconfigs/merged2/base.ocio b/tests/data/files/configs/mergeconfigs/merged2/base.ocio index acbfa4eede..68bfb730d3 100644 --- a/tests/data/files/configs/mergeconfigs/merged2/base.ocio +++ b/tests/data/files/configs/mergeconfigs/merged2/base.ocio @@ -9,9 +9,11 @@ search_path: - . roles: - cie_xyz_d65_interchange: CIE-XYZ-D65 + cie_xyz_d65_interchange: ap0 + scene_linear: ACEScg file_rules: + - ! {name: OpenEXR, colorspace: ACEScg, extension: "exr", pattern: "*"} - ! {name: Default, colorspace: ACEScg} display_colorspaces: # reference space = cie xyz d65 diff --git a/tests/data/files/configs/mergeconfigs/merged2/input.ocio b/tests/data/files/configs/mergeconfigs/merged2/input.ocio index 379b8241b0..14bc2d7774 100644 --- a/tests/data/files/configs/mergeconfigs/merged2/input.ocio +++ b/tests/data/files/configs/mergeconfigs/merged2/input.ocio @@ -1,7 +1,6 @@ ocio_profile_version: 2.1 name: input search_path: lut_dir -inactive_colorspaces: [ACES2065-1] roles: cie_xyz_d65_interchange: CIE-XYZ-D65 @@ -19,6 +18,8 @@ view_transforms: name: SDR Video from_scene_reference: ! {style: ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1} +inactive_colorspaces: [ACES2065-1] + display_colorspaces: # reference space = linear rec 709 - ! name: sRGB - Display diff --git a/tests/data/files/configs/mergeconfigs/merged2/merged.ociom b/tests/data/files/configs/mergeconfigs/merged2/merged.ociom index 9201afdf3f..3c4a9390f8 100644 --- a/tests/data/files/configs/mergeconfigs/merged2/merged.ociom +++ b/tests/data/files/configs/mergeconfigs/merged2/merged.ociom @@ -11,9 +11,9 @@ merge: base_family_prefix: "" input_first: true error_on_conflict: false - default_strategy: PreferInput + default_strategy: PreferBase avoid_duplicates: true - assume_common_reference_space: false + assume_common_reference_space: true overrides: name: Merged1 description: Basic merge with default strategy @@ -30,14 +30,19 @@ merge: base_family_prefix: "" input_first: true error_on_conflict: false - default_strategy: InputOnly + default_strategy: BaseOnly avoid_duplicates: true - assume_common_reference_space: false + assume_common_reference_space: true overrides: name: Merged2 - description: Same as the input + description: Description override search_path: "" environment: {} active_displays: [] active_views: [] - inactive_colorspaces: [] \ No newline at end of file + inactive_colorspaces: [] + params: + roles: + strategy: InputOnly + file_rules: + strategy: InputOnly diff --git a/tests/data/files/configs/mergeconfigs/merged3/base.ocio b/tests/data/files/configs/mergeconfigs/merged3/base.ocio index cbf1e63f20..a901d59972 100644 --- a/tests/data/files/configs/mergeconfigs/merged3/base.ocio +++ b/tests/data/files/configs/mergeconfigs/merged3/base.ocio @@ -2,6 +2,7 @@ ocio_profile_version: 2.1 environment: SHOT: shot1 + CCCID: look-02 search_path: - ./$SHOT diff --git a/tests/data/files/configs/mergeconfigs/merged3/input.ocio b/tests/data/files/configs/mergeconfigs/merged3/input.ocio index b4f5976d30..898b948325 100644 --- a/tests/data/files/configs/mergeconfigs/merged3/input.ocio +++ b/tests/data/files/configs/mergeconfigs/merged3/input.ocio @@ -3,7 +3,6 @@ ocio_profile_version: 2.1 environment: SHOT: shot4 LUT_PATH: shot3/lut1.clf - CCCID: look-02 search_path: - ./$SHOT @@ -17,12 +16,6 @@ displays: sRGB: - ! {name: Raw, colorspace: raw} -looks: - - ! - name: shot_look - process_space: reference - transform: ! {src: "looks.cdl", cccid: $CCCID} - colorspaces: - ! From 1a83a0f80452f008e6e04df8c6b34738b829b6fa Mon Sep 17 00:00:00 2001 From: Doug Walker Date: Mon, 4 Aug 2025 01:26:18 -0400 Subject: [PATCH 09/14] Improve comments Signed-off-by: Doug Walker --- include/OpenColorIO/OpenColorAppHelpers.h | 206 ++++++++++-------- src/OpenColorIO/Config.cpp | 4 +- src/OpenColorIO/ConfigUtils.h | 2 - .../mergeconfigs/MergeConfigsHelpers.cpp | 10 +- .../mergeconfigs/MergeConfigsHelpers.h | 2 +- .../apphelpers/mergeconfigs/OCIOMYaml.cpp | 2 +- src/apps/ociomergeconfigs/main.cpp | 2 +- .../apphelpers/MergeConfigsHelpers_tests.cpp | 11 +- .../configs/mergeconfigs/parser_test.ociom | 4 +- 9 files changed, 141 insertions(+), 102 deletions(-) diff --git a/include/OpenColorIO/OpenColorAppHelpers.h b/include/OpenColorIO/OpenColorAppHelpers.h index 05b888d258..0843277f27 100644 --- a/include/OpenColorIO/OpenColorAppHelpers.h +++ b/include/OpenColorIO/OpenColorAppHelpers.h @@ -522,49 +522,9 @@ class OCIOEXPORT MixingColorSpaceManager extern OCIOEXPORT std::ostream & operator<<(std::ostream &, const MixingColorSpaceManager &); /** - * The ConfigMergingParameters class represent all the options that a merge can have. + * The ConfigMergingParameters class represents all the options that a merge can have. * - * In terms of OCIOM file, it represent one of the merges in a OCIOM file. - * - * Let's take the following OCIOM structure: - * - * ociom_version: 1 - * search_path: - * - . - * - subfolder - * merge: - * Merge_ADD_THIS: - * [...] - * Merge_ADD_THAT: - * [...] - * - * In the OCIOM above, there would be two instances of ConfigMergingParameters. - * One for the merge "Merge_ADD_THIS" and one for the merge "Merge_ADD_THAT". - * - * Where the [...] have the following structure: - * Merge1: - * base: base1.ocio - * input: base1.ocio - * options: - * input_family_prefix: "" - * base_family_prefix: "" - * input_first: true - * error_on_conflict: false - * default_strategy: PreferInput - * avoid_duplicates: true - * assume_common_reference_space: false - * overrides: - * name: "" - * description: "" - * search_path: "" - * environment: {} - * active_displays: [] - * active_views: [] - * inactive_colorspaces: [] - * params: - * roles: - * strategy: PreferInput - * [...] + * In terms of OCIOM file, it represent one of the merges in an OCIOM file. * */ class OCIOEXPORT ConfigMergingParameters @@ -573,125 +533,138 @@ class OCIOEXPORT ConfigMergingParameters enum MergeStrategies { - // Merge, pieces from the input config replace those from the base config. - // On conflict, take from input. + /// Combine elements of the base and input configs, with the input taking priority. STRATEGY_PREFER_INPUT = 0, - // Merge, pieces from the input config are ignored. - // On conflict, take from base. + /// Combine elements of the base and input configs, with the base taking priority. STRATEGY_PREFER_BASE, - // Don't merge, replace the base content with the content of the input config. + /// Use only the base elements for that section of the config. STRATEGY_INPUT_ONLY, - // Don't merge, just keep the base content. + /// Use only the input elements for that section of the config. STRATEGY_BASE_ONLY, - // Pieces from the input config are removed from the base config. The prefixes are - // not used in this case. If the names match, the item is removed, even if the content - // is not identical. + /// The elements in the input config are removed from the base config. (If the names + /// match, the item is removed, even if the content is not identical.) STRATEGY_REMOVE, + /// Strategy has not been set yet. STRATEGY_UNSPECIFIED }; - // Default object static ConfigMergingParametersRcPtr Create(); ConfigMergingParametersRcPtr createEditableCopy() const; + /// Set the file name of the base config. This is used along with the search path of + /// the ConfigMerger object. void setBaseConfigName(const char * baseConfig); const char * getBaseConfigName() const; + /// Set the file name of the base config. This is used along with the search path of + /// the ConfigMerger object. void setInputConfigName(const char * inputConfig); const char * getInputConfigName() const; + /// Set a name to use for this merger. This may be used as the input or base config name + /// in subsequent mergers. void setOutputName(const char * outputName); const char * getOutputName() const; // Options + + /// Set the default strategy. This will be used if the strategy for a given config section + /// is not set, and will be used for basic attributes such as the config description. void setDefaultStrategy(const ConfigMergingParameters::MergeStrategies strategy); ConfigMergingParameters::MergeStrategies getDefaultStrategy() const; - /** - * @brief Set the Input Family Prefix object - * - * The default separator '/' must be used here. - * It will be replaced by the right separator based on the merged parameters. - * - * @param prefix Prefix - */ + /// Set a prefix to add to the family of input config items. (It must use '/' as the + /// separator and will be replaced by the actual default separator of the config.) void setInputFamilyPrefix(const char * prefix); const char * getInputFamilyPrefix() const; - /** - * @brief Set the Base Family Prefix object - * - * The default separator '/' must be used here. - * It will be replaced by the right separator based on the merged parameters. - * - * @param prefix Prefix - */ + /// Set a prefix to add to the family of base config items. (It must use '/' as the + /// separator and will be replaced by the actual default separator of the config.) void setBaseFamilyPrefix(const char * prefix); const char * getBaseFamilyPrefix() const; + /// If true, items from the input config will precede those of the base config. void setInputFirst(bool enabled); bool isInputFirst() const; + /// If true, throw an exception rather than log a warning when a conflict is detected. void setErrorOnConflict(bool enabled); bool isErrorOnConflict() const; + /// If true, a color space from the input config is compared against those of the base + /// config. If it is mathematically equivalent, it is not added. Instead, its name and + /// aliases are added to the original color space. void setAvoidDuplicates(bool enabled); bool isAvoidDuplicates() const; + /// If false, the reference spaces of the base and input config are compared and color + /// spaces from the input config will be adjusted to use the reference space of the base. + /// If the interchange roles are not set, heuristics will be used to try and determine + /// the reference space. void setAssumeCommonReferenceSpace(bool enabled); bool isAssumeCommonReferenceSpace() const; // Overrides + + /// Override the name of the merged config. void setName(const char * mergedConfigName); const char * getName() const; + /// Override the description of the merged config. void setDescription(const char * mergedConfigDesc); const char * getDescription() const; + /// Override the a context variable in the merged config. void addEnvironmentVar(const char * name, const char * defaultValue); int getNumEnvironmentVars() const; const char * getEnvironmentVar(int index) const; const char * getEnvironmentVarValue(int index) const; + /// Override the search_path of the merged config. void setSearchPath(const char * path); void addSearchPath(const char * path); const char * getSearchPath() const; + /// Override the active_displays of the merged config. void setActiveDisplays(const char * displays); const char * getActiveDisplays() const; + /// Override the active_views of the merged config. void setActiveViews(const char * views); const char * getActiveViews() const; + /// Override the inactive_colorspaces of the merged config. void setInactiveColorspaces(const char * colorspaces); const char * getInactiveColorSpaces() const; - //////////// + // Config section strategies - // roles + /// Set the merge strategy for the roles section. void setRoles(MergeStrategies strategy); MergeStrategies getRoles() const; - // file_rules + /// Set the merge strategy for the file_rules section. void setFileRules(MergeStrategies strategy); MergeStrategies getFileRules() const; - // Includes shared_views, displays, view_transforms, viewing_rules, virtual_display, - // active_display, active_views and default_view_transform. + /// Set the merge strategy for the displays/views section. + /// This includes shared_views, displays, view_transforms, viewing_rules, + /// virtual_display, active_display, active_views, and default_view_transform. void setDisplayViews(MergeStrategies strategy); MergeStrategies getDisplayViews() const; - // looks + /// Set the merge strategy for the looks section. void setLooks(MergeStrategies strategy); MergeStrategies getLooks() const; - // Includes colorspaces, display_colorspaces, environment, - // search_path, family_separator and inactive_colorspaces. + /// Set the merge strategy for the color spaces section. + /// This includes colorspaces, display_colorspaces, environment, search_path, + /// family_separator, and inactive_colorspaces. void setColorspaces(MergeStrategies strategy); MergeStrategies getColorspaces() const; - // named_transforms + /// Set the merge strategy for the named_transforms section. void setNamedTransforms(MergeStrategies strategy); MergeStrategies getNamedTransforms() const; @@ -718,12 +691,65 @@ extern OCIOEXPORT std::ostream & operator<<(std::ostream &, const ConfigMergingP /** * The ConfigMerger class is the controller for the merging process. * - * It is controlling the ociom_version, the search_path to find the base and input config, - * and the merges. + * It may be read from or serialized to an OCIOM file. + * + * It is controlling the search_path to find the base and input config, and the merge parameters. * - * It contains an instance of ConfigMergingParameters for each merges present under the "merge" + * It contains an instance of ConfigMergingParameters for each merge present under the "merge" * section. * + * For example, consider the following OCIOM file contents: + * + * ociom_version: 1.0 + * search_path: + * - /usr/local/configs + * - . + * merge: + * Merge_ADD_THIS: + * [...] + * Merge_ADD_THAT: + * [...] + * + * For this OCIOM, there would be two instances of ConfigMergingParameters. + * One for the merge with output name "Merge_ADD_THIS" and one for "Merge_ADD_THAT". + * + * Where the [...] sections have the following structure: + * + * Merge_ADD_THIS: + * base: base.ocio + * input: input.ocio + * options: + * input_family_prefix: "" + * base_family_prefix: "" + * input_first: true + * error_on_conflict: false + * default_strategy: PreferInput + * avoid_duplicates: false + * assume_common_reference_space: true + * overrides: + * name: "" + * description: "" + * search_path: "" + * environment: {} + * active_displays: [] + * active_views: [] + * inactive_colorspaces: [] + * params: + * roles: + * strategy: PreferBase + * file_rules: + * strategy: PreferInput + * display-views: + * strategy: InputOnly + * looks: + * strategy: BaseOnly + * colorspaces: + * strategy: PreferInput + * named_transform: + * strategy: Remove + * + * The indentation is significant and must be as shown. Default items may be omitted. + * */ class OCIOEXPORT ConfigMerger { @@ -735,29 +761,37 @@ class OCIOEXPORT ConfigMerger ConfigMergerRcPtr createEditableCopy() const; + /// These search paths are used to locate the input and base config. + /// Set the entire search path. The ':' character is used to separate paths. void setSearchPath(const char * path); + /// Add a single path to the search paths. void addSearchPath(const char * path); + /// Get the number of search paths. int getNumSearchPaths() const; const char * getSearchPath(int index) const; void setWorkingDir(const char * dirname); const char * getWorkingDir() const; + /// Get the parameters for one of the merges. ConfigMergingParametersRcPtr getParams(int index) const; - int getNumOfConfigMergingParameters() const; + int getNumConfigMergingParameters() const; void addParams(ConfigMergingParametersRcPtr params); - void addMergedConfig(ConstConfigRcPtr cfg); - + /// Get the final merged config. ConstConfigRcPtr getMergedConfig() const; + /// Get one of the merged configs (if there are a series of merges). ConstConfigRcPtr getMergedConfig(int index) const; + void addMergedConfig(ConstConfigRcPtr cfg); + + /// Serialize to the OCIOM file format. void serialize(std::ostream& os) const; + /// Set the version of the OCIOM file format. void setMajorVersion(unsigned int major); void setMinorVersion(unsigned int minor); void setVersion(unsigned int major, unsigned int minor); - unsigned int getMajorVersion() const; unsigned int getMinorVersion() const; @@ -791,7 +825,7 @@ namespace ConfigMergingHelpers * programmatically configuring it. * * \param merger Merger object - * \return OCIOEXPORT + * \return a merger object (call getMergedConfig to obtain the result) */ extern OCIOEXPORT ConstConfigMergerRcPtr MergeConfigs(const ConstConfigMergerRcPtr & merger); @@ -811,7 +845,7 @@ extern OCIOEXPORT ConfigRcPtr MergeConfigs(const ConfigMergingParametersRcPtr & * \brief Merge a single color space into the base config, using the supplied merge parameters. * * Note that the assumeCommonReferenceSpace merge parameter will be ignored and set to true. - * To use automatice reference space conversion, add the color space to an input config that + * To use automatic reference space conversion, add the color space to an input config that * has the necessary interchange role set. * * \param params ConfigMergingParameters controlling the merger. diff --git a/src/OpenColorIO/Config.cpp b/src/OpenColorIO/Config.cpp index 23b11879ba..ec90e19de0 100644 --- a/src/OpenColorIO/Config.cpp +++ b/src/OpenColorIO/Config.cpp @@ -1201,7 +1201,7 @@ ConstConfigRcPtr Config::CreateFromFile(const char * filename) { // TODO: This isn't the most robust method. Comments at the top of the file would break it. - // Check for "ociom" at the start of the file. (ociom_profile) + // Check for "ociom" at the start of the file (ociom_version). if (magicNumber[0] == 'o' && magicNumber[1] == 'c' && magicNumber[2] == 'i' && magicNumber[3] == 'o' && magicNumber[4] == 'm' ) { @@ -1211,7 +1211,7 @@ ConstConfigRcPtr Config::CreateFromFile(const char * filename) ConstConfigMergerRcPtr merger = ConfigMerger::CreateFromFile(filename); ConstConfigMergerRcPtr newMerger = ConfigMergingHelpers::MergeConfigs(merger); - // return final merged config. + // Return final merged config. return newMerger->getMergedConfig(); } catch(const Exception & e) diff --git a/src/OpenColorIO/ConfigUtils.h b/src/OpenColorIO/ConfigUtils.h index 559e17d6f2..4965a6e2d5 100644 --- a/src/OpenColorIO/ConfigUtils.h +++ b/src/OpenColorIO/ConfigUtils.h @@ -4,8 +4,6 @@ #ifndef INCLUDED_OCIO_CONFIG_UTILS_H #define INCLUDED_OCIO_CONFIG_UTILS_H -#include - #include namespace OCIO_NAMESPACE diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp index c21700d931..cd98c3b74a 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp +++ b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp @@ -387,7 +387,7 @@ ConstConfigRcPtr ConfigMerger::Impl::loadConfig(const char * value) const catch(...) { /* don't capture the exception */ } // Must be a reference to a config from a previous merge. - for (int i = 0; i < getNumOfConfigMergingParameters(); i++) + for (int i = 0; i < getNumConfigMergingParameters(); i++) { if (Platform::Strcasecmp(getParams(i)->getOutputName(), value) == 0) { @@ -499,7 +499,7 @@ ConfigMergingParametersRcPtr ConfigMerger::getParams(int index) const return nullptr; } -int ConfigMerger::getNumOfConfigMergingParameters() const +int ConfigMerger::getNumConfigMergingParameters() const { return static_cast(getImpl()->m_mergeParams.size()); } @@ -562,7 +562,7 @@ ConstConfigRcPtr ConfigMerger::getMergedConfig() const ConstConfigRcPtr ConfigMerger::getMergedConfig(int index) const { - if (index < static_cast(getImpl()->m_mergedConfigs.size())) + if (index >= 0 && index < static_cast(getImpl()->m_mergedConfigs.size())) { return getImpl()->m_mergedConfigs.at(index); } @@ -625,7 +625,7 @@ ConstConfigRcPtr loadConfig(const ConfigMergerRcPtr merger, catch(...) { /* don't capture the exception */ } // Must be a reference to a config from a previous merge. - for (int i = 0; i < merger->getNumOfConfigMergingParameters(); i++) + for (int i = 0; i < merger->getNumConfigMergingParameters(); i++) { if (Platform::Strcasecmp(merger->getParams(i)->getOutputName(), value) == 0) { @@ -646,7 +646,7 @@ ConstConfigMergerRcPtr MergeConfigs(const ConstConfigMergerRcPtr & merger) ConfigMergerRcPtr editableMerger = merger->createEditableCopy(); - for (int i = 0; i < merger->getNumOfConfigMergingParameters(); i++) + for (int i = 0; i < merger->getNumConfigMergingParameters(); i++) { ConstConfigMergingParametersRcPtr params = merger->getParams(i); diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h index 2bb3baf34a..0daa56630c 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h +++ b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h @@ -198,7 +198,7 @@ class ConfigMerger::Impl return m_mergeParams.at(index); } - int getNumOfConfigMergingParameters() const + int getNumConfigMergingParameters() const { return static_cast(m_mergeParams.size()); } diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp index efc713d062..e95b9ee6c5 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp +++ b/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp @@ -507,7 +507,7 @@ inline void save(YAML::Emitter & out, const ConfigMerger & merger) out << YAML::Key << "merge"; out << YAML::Value << YAML::BeginMap; - for (int mp = 0; mp < merger.getNumOfConfigMergingParameters(); mp++) + for (int mp = 0; mp < merger.getNumConfigMergingParameters(); mp++) { // Serialized every merge section. ConfigMergingParametersRcPtr p = merger.getParams(mp); diff --git a/src/apps/ociomergeconfigs/main.cpp b/src/apps/ociomergeconfigs/main.cpp index 020e45ea5a..e70b2f6306 100644 --- a/src/apps/ociomergeconfigs/main.cpp +++ b/src/apps/ociomergeconfigs/main.cpp @@ -167,7 +167,7 @@ int main(int argc, const char **argv) // "Show-all" option take priority over the "show" option. if (displayAllConfig) { - for (int i = 0; i < merger->getNumOfConfigMergingParameters(); i++) + for (int i = 0; i < merger->getNumConfigMergingParameters(); i++) { std::cout << "*********************" << std::endl; std::cout << "Merged Config " << i << std::endl; diff --git a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp index 2e304d3069..e5f303f76e 100644 --- a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp +++ b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp @@ -183,12 +183,16 @@ OCIO_ADD_TEST(MergeConfigs, ociom_parser) OCIO_CHECK_EQUAL(merger->getMajorVersion(), 1); OCIO_CHECK_EQUAL(merger->getMinorVersion(), 0); + // Check the search path for finding the base and input configs. + OCIO_CHECK_EQUAL(merger->getNumSearchPaths(), 2); + OCIO_CHECK_EQUAL(std::string(merger->getSearchPath(0)), std::string("/usr/local/configs")); + OCIO_CHECK_EQUAL(std::string(merger->getSearchPath(1)), std::string(".")); + // The parser_test.ociom contains only one merge. + OCIO_CHECK_EQUAL(merger->getNumConfigMergingParameters(), 1); OCIO::ConstConfigMergingParametersRcPtr p = merger->getParams(0); // Test that the all the options are loaded correctly. - // Note that is does not test all possibilities. - // e.g. it does not test all the strategies for all sections. OCIO_CHECK_EQUAL(std::string(p->getBaseConfigName()), std::string("base0.ocio")); OCIO_CHECK_EQUAL(std::string(p->getInputConfigName()), std::string("input0.ocio")); @@ -198,7 +202,7 @@ OCIO_ADD_TEST(MergeConfigs, ociom_parser) OCIO_CHECK_EQUAL(std::string(p->getBaseFamilyPrefix()), std::string("def")); OCIO_CHECK_EQUAL(p->isInputFirst(), true); OCIO_CHECK_EQUAL(p->isErrorOnConflict(), false); - // PreferInput + OCIO_CHECK_EQUAL(p->getDefaultStrategy(), MergeStrategy::STRATEGY_INPUT_ONLY); OCIO_CHECK_EQUAL(p->isAvoidDuplicates(), true); OCIO_CHECK_EQUAL(p->isAssumeCommonReferenceSpace(), false); @@ -249,6 +253,7 @@ OCIO_ADD_TEST(MergeConfigs, ociom_serialization) constexpr const char * REF { R"(ociom_version: 1.0 search_path: + - /usr/local/configs - . merge: Merge1: diff --git a/tests/data/files/configs/mergeconfigs/parser_test.ociom b/tests/data/files/configs/mergeconfigs/parser_test.ociom index 17254cd250..402c0a79b2 100644 --- a/tests/data/files/configs/mergeconfigs/parser_test.ociom +++ b/tests/data/files/configs/mergeconfigs/parser_test.ociom @@ -1,5 +1,7 @@ ociom_version: 1.0 -search_path: "." +search_path: + - /usr/local/configs + - . merge: Merge1: From 9af24da59087e034ab769d9f330d320bbc47f0a7 Mon Sep 17 00:00:00 2001 From: Doug Walker Date: Thu, 28 Aug 2025 01:06:45 -0400 Subject: [PATCH 10/14] Remove CreateFromFile support Signed-off-by: Doug Walker --- include/OpenColorIO/OpenColorAppHelpers.h | 6 +- src/OpenColorIO/Config.cpp | 29 +------ .../mergeconfigs/MergeConfigsHelpers.cpp | 82 ++++++++++++++++-- .../apphelpers/mergeconfigs/OCIOMYaml.cpp | 74 +++++++++------- .../apphelpers/mergeconfigs/OCIOMYaml.h | 21 ++--- .../apphelpers/mergeconfigs/SectionMerger.cpp | 85 ++++++++++--------- .../apphelpers/MergeConfigsHelpers_tests.cpp | 34 +++++++- .../configs/mergeconfigs/parser_test.ociom | 2 +- .../parser_test_no_overrides.ociom | 2 +- 9 files changed, 211 insertions(+), 124 deletions(-) diff --git a/include/OpenColorIO/OpenColorAppHelpers.h b/include/OpenColorIO/OpenColorAppHelpers.h index 0843277f27..f848c5acd1 100644 --- a/include/OpenColorIO/OpenColorAppHelpers.h +++ b/include/OpenColorIO/OpenColorAppHelpers.h @@ -522,7 +522,7 @@ class OCIOEXPORT MixingColorSpaceManager extern OCIOEXPORT std::ostream & operator<<(std::ostream &, const MixingColorSpaceManager &); /** - * The ConfigMergingParameters class represents all the options that a merge can have. + * The ConfigMergingParameters class holds the options that control how a merge is done. * * In terms of OCIOM file, it represent one of the merges in an OCIOM file. * @@ -537,9 +537,9 @@ class OCIOEXPORT ConfigMergingParameters STRATEGY_PREFER_INPUT = 0, /// Combine elements of the base and input configs, with the base taking priority. STRATEGY_PREFER_BASE, - /// Use only the base elements for that section of the config. - STRATEGY_INPUT_ONLY, /// Use only the input elements for that section of the config. + STRATEGY_INPUT_ONLY, + /// Use only the base elements for that section of the config. STRATEGY_BASE_ONLY, /// The elements in the input config are removed from the base config. (If the names /// match, the item is removed, even if the content is not identical.) diff --git a/src/OpenColorIO/Config.cpp b/src/OpenColorIO/Config.cpp index ec90e19de0..d46c7ec3d8 100644 --- a/src/OpenColorIO/Config.cpp +++ b/src/OpenColorIO/Config.cpp @@ -1179,8 +1179,8 @@ ConstConfigRcPtr Config::CreateFromFile(const char * filename) throw Exception (os.str().c_str()); } - char magicNumber[5] = { 0 }; - if (ifstream.read(magicNumber, 5)) + char magicNumber[2] = { 0 }; + if (ifstream.read(magicNumber, 2)) { // Check if it is an OCIOZ archive. if (magicNumber[0] == 'P' && magicNumber[1] == 'K') @@ -1197,32 +1197,9 @@ ConstConfigRcPtr Config::CreateFromFile(const char * filename) ciop->buildEntries(); return CreateFromConfigIOProxy(ciop); } - else - { - // TODO: This isn't the most robust method. Comments at the top of the file would break it. - - // Check for "ociom" at the start of the file (ociom_version). - if (magicNumber[0] == 'o' && magicNumber[1] == 'c' && - magicNumber[2] == 'i' && magicNumber[3] == 'o' && magicNumber[4] == 'm' ) - { - try - { - ifstream.close(); - - ConstConfigMergerRcPtr merger = ConfigMerger::CreateFromFile(filename); - ConstConfigMergerRcPtr newMerger = ConfigMergingHelpers::MergeConfigs(merger); - // Return final merged config. - return newMerger->getMergedConfig(); - } - catch(const Exception & e) - { - throw e; - } - } - } } - // Not an OCIOZ archive or OCIOM file. Continue as usual. + // Not an OCIOZ archive. Continue as usual. ifstream.clear(); ifstream.seekg(0); return Config::Impl::Read(ifstream, filename); diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp index cd98c3b74a..ac718b072f 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp +++ b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp @@ -43,13 +43,6 @@ void ConfigMergingParameters::deleter(ConfigMergingParameters * c) delete c; } -//TODO Not implemented -std::ostream & operator<<(std::ostream & os, const ConfigMergingParameters & ms) -{ - (void)ms; - return os; -} - ConfigMergingParametersRcPtr ConfigMergingParameters::createEditableCopy() const { ConfigMergingParametersRcPtr params = ConfigMergingParameters::Create(); @@ -327,6 +320,75 @@ ConfigMergingParameters::MergeStrategies ConfigMergingParameters::getNamedTransf return getImpl()->m_namedTransforms; } +std::ostream & operator<<(std::ostream & os, const ConfigMergingParameters & params) +{ + os << "<"; + bool first = true; + + auto print_str = [&](const char* label, const char* value) { + if (value && *value) + { + if (!first) os << ", "; + os << label << ": " << value; + first = false; + } + }; + + auto print_bool = [&](const char* label, bool value) { + if (!first) os << ", "; + os << label << ": " << (value ? "true" : "false"); + first = false; + }; + + auto print_enum = [&](const char* label, ConfigMergingParameters::MergeStrategies value) { + if (!first) os << ", "; + os << label << ": " << OCIOMYaml::EnumToStrategyString(value); + first = false; + }; + + print_str("base", params.getBaseConfigName()); + print_str("input", params.getInputConfigName()); + print_str("output_name", params.getOutputName()); + print_str("input_family_prefix", params.getInputFamilyPrefix()); + print_str("base_family_prefix", params.getBaseFamilyPrefix()); + print_bool("input_first", params.isInputFirst()); + print_bool("error_on_conflict", params.isErrorOnConflict()); + print_enum("default_strategy", params.getDefaultStrategy()); + print_bool("avoid_duplicates", params.isAvoidDuplicates()); + print_bool("assume_common_reference_space", params.isAssumeCommonReferenceSpace()); + print_str("name", params.getName()); + print_str("description", params.getDescription()); + print_str("search_path", params.getSearchPath()); + print_str("active_displays", params.getActiveDisplays()); + print_str("active_views", params.getActiveViews()); + print_str("inactive_colorspaces", params.getInactiveColorSpaces()); + print_enum("roles", params.getRoles()); + print_enum("file_rules", params.getFileRules()); + print_enum("display-views", params.getDisplayViews()); + print_enum("looks", params.getLooks()); + print_enum("colorspaces", params.getColorspaces()); + print_enum("named_transforms", params.getNamedTransforms()); + + // Environment vars. + int numEnv = params.getNumEnvironmentVars(); + if (numEnv > 0) + { + if (!first) os << ", "; + os << "environment: ["; + for (int i = 0; i < numEnv; ++i) + { + if (i > 0) os << ", "; + os << params.getEnvironmentVar(i); + const char* val = params.getEnvironmentVarValue(i); + if (val && *val) os << "=" << val; + } + os << "]"; + } + + os << ">"; + return os; +} + ///////////////////////////////////////// // Implementation ConfigMerger ///////////////////////////////////////// @@ -524,6 +586,12 @@ void ConfigMerger::serialize(std::ostream& os) const } } +std::ostream & operator<<(std::ostream & os, const ConfigMerger & m) +{ + m.serialize(os); + return os; +} + unsigned int ConfigMerger::getMajorVersion() const { return getImpl()->m_majorVersion; diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp index e95b9ee6c5..9707d86cfe 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp +++ b/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp @@ -19,16 +19,21 @@ namespace OCIO_NAMESPACE { +std::unordered_map OCIOMYaml::m_mergeStrategiesMap; + OCIOMYaml::OCIOMYaml() { - m_mergeStrategiesMap["PreferInput"] = ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT; - m_mergeStrategiesMap["PreferBase"] = ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_BASE; - m_mergeStrategiesMap["InputOnly"] = ConfigMergingParameters::MergeStrategies::STRATEGY_INPUT_ONLY; - m_mergeStrategiesMap["BaseOnly"] = ConfigMergingParameters::MergeStrategies::STRATEGY_BASE_ONLY; - m_mergeStrategiesMap["Remove"] = ConfigMergingParameters::MergeStrategies::STRATEGY_REMOVE; + if (m_mergeStrategiesMap.empty()) + { + m_mergeStrategiesMap["PreferInput"] = ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_INPUT; + m_mergeStrategiesMap["PreferBase"] = ConfigMergingParameters::MergeStrategies::STRATEGY_PREFER_BASE; + m_mergeStrategiesMap["InputOnly"] = ConfigMergingParameters::MergeStrategies::STRATEGY_INPUT_ONLY; + m_mergeStrategiesMap["BaseOnly"] = ConfigMergingParameters::MergeStrategies::STRATEGY_BASE_ONLY; + m_mergeStrategiesMap["Remove"] = ConfigMergingParameters::MergeStrategies::STRATEGY_REMOVE; + } } -inline void OCIOMYaml::load(const YAML::Node & node, std::string & x) +void OCIOMYaml::load(const YAML::Node & node, std::string & x) { try { @@ -44,7 +49,7 @@ inline void OCIOMYaml::load(const YAML::Node & node, std::string & x) } } -inline void OCIOMYaml::load(const YAML::Node & node, std::vector & x) +void OCIOMYaml::load(const YAML::Node & node, std::vector & x) { try { @@ -60,7 +65,7 @@ inline void OCIOMYaml::load(const YAML::Node & node, std::vector & } } -inline void OCIOMYaml::throwValueError(const std::string & nodeName, +void OCIOMYaml::throwValueError(const std::string & nodeName, const YAML::Node & key, const std::string & msg) { @@ -75,7 +80,7 @@ inline void OCIOMYaml::throwValueError(const std::string & nodeName, throw Exception(os.str().c_str()); } -inline void OCIOMYaml::CheckDuplicates(const YAML::Node & node) +void OCIOMYaml::CheckDuplicates(const YAML::Node & node) { std::unordered_set keyset; @@ -95,17 +100,6 @@ inline void OCIOMYaml::CheckDuplicates(const YAML::Node & node) } } } -ConfigMergingParameters::MergeStrategies OCIOMYaml::strategyToEnum(const char * enumStr) const -{ - auto it = m_mergeStrategiesMap.find(enumStr); - if (it != m_mergeStrategiesMap.end()) - { - return it->second; - } - - return ConfigMergingParameters::MergeStrategies::STRATEGY_UNSPECIFIED; -} - ConfigMergingParameters::MergeStrategies OCIOMYaml::genericStrategyHandler(const YAML::Node & pnode, const YAML::Node & node) { @@ -127,7 +121,7 @@ ConfigMergingParameters::MergeStrategies OCIOMYaml::genericStrategyHandler(const } } - auto srategyEnum = strategyToEnum(strategy.c_str()); + auto srategyEnum = OCIOMYaml::StrategyStringToEnum(strategy.c_str()); if (srategyEnum == ConfigMergingParameters::MergeStrategies::STRATEGY_UNSPECIFIED) { std::ostringstream os; @@ -172,7 +166,7 @@ void OCIOMYaml::loadOptions(const YAML::Node & node, ConfigMergingParametersRcPt else if (key == "default_strategy") { const std::string & strategy = it->second.as(); - auto srategyEnum = strategyToEnum(strategy.c_str()); + auto srategyEnum = OCIOMYaml::StrategyStringToEnum(strategy.c_str()); if (srategyEnum == ConfigMergingParameters::MergeStrategies::STRATEGY_UNSPECIFIED) { std::ostringstream os; @@ -290,7 +284,7 @@ void OCIOMYaml::loadParams(const YAML::Node & node, ConfigMergingParametersRcPtr { params->setColorspaces(genericStrategyHandler(it->first, it->second)); } - else if (key == "named_transform") + else if (key == "named_transforms") { params->setNamedTransforms(genericStrategyHandler(it->first, it->second)); } @@ -457,7 +451,18 @@ void OCIOMYaml::read(std::istream & istream, ConfigMergerRcPtr & merger, const c } } -const char * stategyEnumToString(ConfigMergingParameters::MergeStrategies strategy) +ConfigMergingParameters::MergeStrategies OCIOMYaml::StrategyStringToEnum(const char * enumStr) +{ + auto it = m_mergeStrategiesMap.find(enumStr); + if (it != m_mergeStrategiesMap.end()) + { + return it->second; + } + + return ConfigMergingParameters::MergeStrategies::STRATEGY_UNSPECIFIED; +} + +const char * OCIOMYaml::EnumToStrategyString(ConfigMergingParameters::MergeStrategies strategy) { switch (strategy) { @@ -485,6 +490,9 @@ const char * stategyEnumToString(ConfigMergingParameters::MergeStrategies strate } } +namespace +{ + inline void save(YAML::Emitter & out, const ConfigMerger & merger) { std::stringstream ss; @@ -524,7 +532,7 @@ inline void save(YAML::Emitter & out, const ConfigMerger & merger) out << YAML::Key << "base_family_prefix" << YAML::Value << p->getBaseFamilyPrefix(); out << YAML::Key << "input_first" << YAML::Value << p->isInputFirst(); out << YAML::Key << "error_on_conflict" << YAML::Value << p->isErrorOnConflict(); - out << YAML::Key << "default_strategy" << YAML::Value << stategyEnumToString(p->getDefaultStrategy()); + out << YAML::Key << "default_strategy" << YAML::Value << OCIOMYaml::EnumToStrategyString(p->getDefaultStrategy()); out << YAML::Key << "avoid_duplicates" << YAML::Value << p->isAvoidDuplicates(); out << YAML::Key << "assume_common_reference_space" << YAML::Value << p->isAssumeCommonReferenceSpace(); // End of options section. @@ -576,32 +584,32 @@ inline void save(YAML::Emitter & out, const ConfigMerger & merger) out << YAML::Key << "roles"; out << YAML::Value << YAML::BeginMap; - out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getRoles()); + out << YAML::Key << "strategy" << YAML::Value << OCIOMYaml::EnumToStrategyString(p->getRoles()); out << YAML::EndMap; out << YAML::Key << "file_rules"; out << YAML::Value << YAML::BeginMap; - out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getFileRules()); + out << YAML::Key << "strategy" << YAML::Value << OCIOMYaml::EnumToStrategyString(p->getFileRules()); out << YAML::EndMap; out << YAML::Key << "display-views"; out << YAML::Value << YAML::BeginMap; - out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getDisplayViews()); + out << YAML::Key << "strategy" << YAML::Value << OCIOMYaml::EnumToStrategyString(p->getDisplayViews()); out << YAML::EndMap; out << YAML::Key << "looks"; out << YAML::Value << YAML::BeginMap; - out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getLooks()); + out << YAML::Key << "strategy" << YAML::Value << OCIOMYaml::EnumToStrategyString(p->getLooks()); out << YAML::EndMap; out << YAML::Key << "colorspaces"; out << YAML::Value << YAML::BeginMap; - out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getColorspaces()); + out << YAML::Key << "strategy" << YAML::Value << OCIOMYaml::EnumToStrategyString(p->getColorspaces()); out << YAML::EndMap; - out << YAML::Key << "named_transform"; + out << YAML::Key << "named_transforms"; out << YAML::Value << YAML::BeginMap; - out << YAML::Key << "strategy" << YAML::Value << stategyEnumToString(p->getNamedTransforms()); + out << YAML::Key << "strategy" << YAML::Value << OCIOMYaml::EnumToStrategyString(p->getNamedTransforms()); out << YAML::EndMap; // End of params section. @@ -617,6 +625,8 @@ inline void save(YAML::Emitter & out, const ConfigMerger & merger) out << YAML::EndMap; } +} // anon. + void OCIOMYaml::write(std::ostream & ostream, const ConfigMerger & merger) { YAML::Emitter out; diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.h b/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.h index 9bbbda0536..e550d04875 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.h +++ b/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.h @@ -26,26 +26,14 @@ class OCIOMYaml const std::string & msg); void CheckDuplicates(const YAML::Node & node); - /** - * \brief Load the options section. - */ void loadOptions(const YAML::Node & node, ConfigMergingParametersRcPtr & params); - /** - * \brief Load the overrides section. - */ + void loadOverrides(const YAML::Node & node, ConfigMergingParametersRcPtr & params); - /** - * \brief Load the params section. - */ + void loadParams(const YAML::Node & node, ConfigMergingParametersRcPtr & params); ConfigMergingParameters::MergeStrategies genericStrategyHandler(const YAML::Node & pnode, const YAML::Node & node); - /** - * \brief Converts a string into a ConfigMergingParameters::MergeStrategies enum. - */ - ConfigMergingParameters::MergeStrategies strategyToEnum(const char * enumStr) const; - void read(std::istream & istream, ConfigMergerRcPtr & merger, const char * filepath); void write(std::ostream & ostream, const ConfigMerger & merger); @@ -63,8 +51,11 @@ class OCIOMYaml */ int countMerges(const YAML::Node& node); + static ConfigMergingParameters::MergeStrategies StrategyStringToEnum(const char * enumStr); + static const char * EnumToStrategyString(ConfigMergingParameters::MergeStrategies strategy); + private: - std::unordered_map m_mergeStrategiesMap; + static std::unordered_map m_mergeStrategiesMap; }; } // namespace OCIO_NAMESPACE diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp index 20a35922bc..adf9ab7222 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp +++ b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp @@ -419,6 +419,9 @@ void RolesMerger::handleRemove() /////////////////////////////////// FileRulesMerger ////////////////////////////////////// +namespace +{ + bool fileRulesAreEqual(const ConstFileRulesRcPtr & f1, size_t f1Idx, const ConstFileRulesRcPtr & f2, @@ -515,6 +518,8 @@ void copyRule(const ConstFileRulesRcPtr & input, // rule source } } +} // anon. + void FileRulesMerger::addRulesIfNotPresent(const ConstFileRulesRcPtr & input, FileRulesRcPtr & merged) const { @@ -1977,6 +1982,9 @@ void LooksMerger::handleRemove() /////////////////////////////////// ColorspacesMerger //////////////////////////////////// +namespace +{ + bool hasSearchPath(const ConstConfigRcPtr & cfg, const char * path) { for (int i = 0; i < cfg->getNumSearchPaths(); i++) @@ -1989,6 +1997,45 @@ bool hasSearchPath(const ConstConfigRcPtr & cfg, const char * path) return false; } +void cleanUpInactiveList(ConfigRcPtr & mergeConfig) +{ + StringUtils::StringVec originalList, validList; + splitActiveList(mergeConfig->getInactiveColorSpaces(), originalList); + for (auto & item : originalList) + { + const std::string name = StringUtils::Trim(item); + ConstColorSpaceRcPtr existingCS = mergeConfig->getColorSpace(name.c_str()); + ConstNamedTransformRcPtr existingNT = mergeConfig->getNamedTransform(name.c_str()); + + if (existingCS) + { + // Don't want aliases in the inactive list. + if (Platform::Strcasecmp(existingCS->getName(), name.c_str()) == 0) + { + validList.push_back(name); + } + } + else if (existingNT) + { + if (Platform::Strcasecmp(existingNT->getName(), name.c_str()) == 0) + { + validList.push_back(name); + } + } + } + mergeConfig->setInactiveColorSpaces(StringUtils::Join(validList, ',').c_str()); +} + +std::string replaceSeparator(std::string str, char inSep, char outSep) +{ + std::string defaultSeparatorStr(1, inSep); + std::string mergedSeparatorStr(1, outSep); + std::string updatedStr = StringUtils::Replace(str, defaultSeparatorStr, mergedSeparatorStr); + return updatedStr; +} + +} // anon. + void ColorspacesMerger::processSearchPaths() const { const char * searchPaths = m_params->getSearchPath(); @@ -2038,43 +2085,6 @@ void ColorspacesMerger::processSearchPaths() const } } -void cleanUpInactiveList(ConfigRcPtr & mergeConfig) -{ - StringUtils::StringVec originalList, validList; - splitActiveList(mergeConfig->getInactiveColorSpaces(), originalList); - for (auto & item : originalList) - { - const std::string name = StringUtils::Trim(item); - ConstColorSpaceRcPtr existingCS = mergeConfig->getColorSpace(name.c_str()); - ConstNamedTransformRcPtr existingNT = mergeConfig->getNamedTransform(name.c_str()); - - if (existingCS) - { - // Don't want aliases in the inactive list. - if (Platform::Strcasecmp(existingCS->getName(), name.c_str()) == 0) - { - validList.push_back(name); - } - } - else if (existingNT) - { - if (Platform::Strcasecmp(existingNT->getName(), name.c_str()) == 0) - { - validList.push_back(name); - } - } - } - mergeConfig->setInactiveColorSpaces(StringUtils::Join(validList, ',').c_str()); -} - -std::string replaceSeparator(std::string str, char inSep, char outSep) -{ - std::string defaultSeparatorStr(1, inSep); - std::string mergedSeparatorStr(1, outSep); - std::string updatedStr = StringUtils::Replace(str, defaultSeparatorStr, mergedSeparatorStr); - return updatedStr; -} - void ColorspacesMerger::updateFamily(std::string & family, bool fromBase) const { // Note that if a prefix is present, it is always added, even if the CS did not have a family. @@ -2294,7 +2304,6 @@ bool ColorspacesMerger::handleAvoidDuplicatesOption(ConfigUtils::ColorSpaceFinge return notDuplicate; } - bool ColorspacesMerger::colorSpaceMayBeMerged(const ConstConfigRcPtr & mergeConfig, const ConstColorSpaceRcPtr & inputCS) const { diff --git a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp index e5f303f76e..bbb38e2816 100644 --- a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp +++ b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp @@ -236,6 +236,33 @@ OCIO_ADD_TEST(MergeConfigs, ociom_parser) OCIO_CHECK_EQUAL(p->getNamedTransforms(), MergeStrategy::STRATEGY_PREFER_BASE); } +OCIO_ADD_TEST(MergeConfigs, params_serialization) +{ + std::vector paths = { + std::string(OCIO::GetTestFilesDir()), + std::string("configs"), + std::string("mergeconfigs"), + std::string("parser_test.ociom") + }; + const std::string ociomPath = pystring::os::path::normpath(pystring::os::path::join(paths)); + + OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); + OCIO::ConstConfigMergingParametersRcPtr p = merger->getParams(0); + + static constexpr char REF[] + = ""; + + std::ostringstream oss; + oss << *p; + + OCIO_CHECK_EQUAL(oss.str(), REF); +} + OCIO_ADD_TEST(MergeConfigs, ociom_serialization) { std::vector paths = { @@ -288,11 +315,16 @@ R"(ociom_version: 1.0 strategy: BaseOnly colorspaces: strategy: Remove - named_transform: + named_transforms: strategy: PreferBase)" }; std::istringstream rss(REF); OCIO_CHECK_EQUAL(oss.str(), rss.str()); + + std::ostringstream oss2; + oss2 << *merger; + + OCIO_CHECK_EQUAL(oss2.str(), rss.str()); } OCIO_ADD_TEST(MergeConfigs, ociom_parser_no_overrides) diff --git a/tests/data/files/configs/mergeconfigs/parser_test.ociom b/tests/data/files/configs/mergeconfigs/parser_test.ociom index 402c0a79b2..b41b7c3953 100644 --- a/tests/data/files/configs/mergeconfigs/parser_test.ociom +++ b/tests/data/files/configs/mergeconfigs/parser_test.ociom @@ -45,5 +45,5 @@ merge: # search_path, family_separator and inactive_colorspaces. strategy: Remove - named_transform: + named_transforms: strategy: PreferBase diff --git a/tests/data/files/configs/mergeconfigs/parser_test_no_overrides.ociom b/tests/data/files/configs/mergeconfigs/parser_test_no_overrides.ociom index 93ffbcc65d..37cf5d3855 100644 --- a/tests/data/files/configs/mergeconfigs/parser_test_no_overrides.ociom +++ b/tests/data/files/configs/mergeconfigs/parser_test_no_overrides.ociom @@ -43,5 +43,5 @@ merge: # search_path, family_separator and inactive_colorspaces. strategy: Remove - named_transform: + named_transforms: strategy: PreferBase \ No newline at end of file From 5a43d354434c2b2722156312ac15436015ed44ca Mon Sep 17 00:00:00 2001 From: Doug Walker Date: Sun, 31 Aug 2025 22:59:25 -0400 Subject: [PATCH 11/14] Add Python binding Signed-off-by: Doug Walker --- include/OpenColorIO/OpenColorAppHelpers.h | 81 ++-- .../mergeconfigs/MergeConfigsHelpers.cpp | 199 ++++----- .../mergeconfigs/MergeConfigsHelpers.h | 30 +- .../apphelpers/mergeconfigs/OCIOMYaml.cpp | 26 +- .../apphelpers/mergeconfigs/SectionMerger.cpp | 413 +++++++++-------- .../apphelpers/mergeconfigs/SectionMerger.h | 56 ++- src/apps/ociomergeconfigs/main.cpp | 2 +- src/bindings/python/CMakeLists.txt | 1 + src/bindings/python/PyOpenColorIO.cpp | 1 + src/bindings/python/PyOpenColorIO.h | 1 + src/bindings/python/PyTypes.cpp | 8 + .../python/apphelpers/PyMergeConfigs.cpp | 230 ++++++++++ .../apphelpers/MergeConfigsHelpers_tests.cpp | 422 ++++++++++++------ .../mergeconfigs/merged1/merged1.ociom | 2 +- .../configs/mergeconfigs/merged2/merged.ociom | 4 +- .../configs/mergeconfigs/merged3/merged.ociom | 2 +- .../configs/mergeconfigs/merged4/merged.ociom | 2 +- .../configs/mergeconfigs/parser_test.ociom | 9 +- .../parser_test_no_overrides.ociom | 9 +- tests/python/MergeConfigsTest.py | 249 +++++++++++ tests/python/OpenColorIOTestSuite.py | 2 + 21 files changed, 1206 insertions(+), 543 deletions(-) create mode 100644 src/bindings/python/apphelpers/PyMergeConfigs.cpp create mode 100644 tests/python/MergeConfigsTest.py diff --git a/include/OpenColorIO/OpenColorAppHelpers.h b/include/OpenColorIO/OpenColorAppHelpers.h index f848c5acd1..b615d90ed3 100644 --- a/include/OpenColorIO/OpenColorAppHelpers.h +++ b/include/OpenColorIO/OpenColorAppHelpers.h @@ -571,39 +571,42 @@ class OCIOEXPORT ConfigMergingParameters /// Set the default strategy. This will be used if the strategy for a given config section /// is not set, and will be used for basic attributes such as the config description. + /// Default = STRATEGY_PREFER_INPUT. void setDefaultStrategy(const ConfigMergingParameters::MergeStrategies strategy); ConfigMergingParameters::MergeStrategies getDefaultStrategy() const; /// Set a prefix to add to the family of input config items. (It must use '/' as the - /// separator and will be replaced by the actual default separator of the config.) + /// separator and will be replaced by the actual family separator of the config.) void setInputFamilyPrefix(const char * prefix); const char * getInputFamilyPrefix() const; /// Set a prefix to add to the family of base config items. (It must use '/' as the - /// separator and will be replaced by the actual default separator of the config.) + /// separator and will be replaced by the actual family separator of the config.) void setBaseFamilyPrefix(const char * prefix); const char * getBaseFamilyPrefix() const; - /// If true, items from the input config will precede those of the base config. + /// If true, items from the input config will by higher in the file than those of the + /// base config. Default = true. void setInputFirst(bool enabled); bool isInputFirst() const; /// If true, throw an exception rather than log a warning when a conflict is detected. + /// Default = false. void setErrorOnConflict(bool enabled); bool isErrorOnConflict() const; /// If true, a color space from the input config is compared against those of the base /// config. If it is mathematically equivalent, it is not added. Instead, its name and - /// aliases are added to the original color space. + /// aliases are added to the original color space. Default = true. void setAvoidDuplicates(bool enabled); bool isAvoidDuplicates() const; - /// If false, the reference spaces of the base and input config are compared and color + /// If true, the reference spaces of the base and input config are compared and color /// spaces from the input config will be adjusted to use the reference space of the base. /// If the interchange roles are not set, heuristics will be used to try and determine - /// the reference space. - void setAssumeCommonReferenceSpace(bool enabled); - bool isAssumeCommonReferenceSpace() const; + /// the reference space. Default = true. + void setAdjustInputReferenceSpace(bool enabled); + bool isAdjustInputReferenceSpace() const; // Overrides @@ -615,8 +618,9 @@ class OCIOEXPORT ConfigMergingParameters void setDescription(const char * mergedConfigDesc); const char * getDescription() const; - /// Override the a context variable in the merged config. + /// Override a context variable in the merged config. void addEnvironmentVar(const char * name, const char * defaultValue); + /// Get the number of context variable overrides. int getNumEnvironmentVars() const; const char * getEnvironmentVar(int index) const; const char * getEnvironmentVarValue(int index) const; @@ -629,13 +633,14 @@ class OCIOEXPORT ConfigMergingParameters /// Override the active_displays of the merged config. void setActiveDisplays(const char * displays); const char * getActiveDisplays() const; +// REMOVE? /// Override the active_views of the merged config. void setActiveViews(const char * views); const char * getActiveViews() const; /// Override the inactive_colorspaces of the merged config. - void setInactiveColorspaces(const char * colorspaces); + void setInactiveColorSpaces(const char * colorspaces); const char * getInactiveColorSpaces() const; // Config section strategies @@ -649,10 +654,15 @@ class OCIOEXPORT ConfigMergingParameters MergeStrategies getFileRules() const; /// Set the merge strategy for the displays/views section. - /// This includes shared_views, displays, view_transforms, viewing_rules, - /// virtual_display, active_display, active_views, and default_view_transform. + /// This includes shared_views, displays, viewing_rules, + /// virtual_display, active_display, and active_views. void setDisplayViews(MergeStrategies strategy); MergeStrategies getDisplayViews() const; + + /// Set the merge strategy for the view_transforms section. + /// This includes the view_transforms and default_view_transform. + void setViewTransforms(MergeStrategies strategy); + MergeStrategies getViewTransforms() const; /// Set the merge strategy for the looks section. void setLooks(MergeStrategies strategy); @@ -685,7 +695,6 @@ class OCIOEXPORT ConfigMergingParameters const Impl * getImpl() const { return m_impl; } }; -//TODO Not implemented. extern OCIOEXPORT std::ostream & operator<<(std::ostream &, const ConfigMergingParameters &); /** @@ -724,8 +733,8 @@ extern OCIOEXPORT std::ostream & operator<<(std::ostream &, const ConfigMergingP * input_first: true * error_on_conflict: false * default_strategy: PreferInput - * avoid_duplicates: false - * assume_common_reference_space: true + * avoid_duplicates: true + * adjust_input_reference_space: true * overrides: * name: "" * description: "" @@ -741,6 +750,8 @@ extern OCIOEXPORT std::ostream & operator<<(std::ostream &, const ConfigMergingP * strategy: PreferInput * display-views: * strategy: InputOnly + * view_transforms: + * strategy: InputOnly * looks: * strategy: BaseOnly * colorspaces: @@ -756,7 +767,7 @@ class OCIOEXPORT ConfigMerger public: static ConfigMergerRcPtr Create(); - // Create based on the ociom file. + // Create by parsing an OCIOM file. static ConstConfigMergerRcPtr CreateFromFile(const char * filepath); ConfigMergerRcPtr createEditableCopy() const; @@ -773,24 +784,34 @@ class OCIOEXPORT ConfigMerger void setWorkingDir(const char * dirname); const char * getWorkingDir() const; - /// Get the parameters for one of the merges. + /// Get the parameters for one of the merges. Returns null if index is out of range. ConfigMergingParametersRcPtr getParams(int index) const; int getNumConfigMergingParameters() const; void addParams(ConfigMergingParametersRcPtr params); + /** + * \brief Execute the merge(s) based on the merger object. + * + * Execute the merge(s) based on the merger object that was previously populated by using + * ConfigMerger::CreateFromFile or created from scratch by using ConfigMerger::Create() and + * programmatically configuring it. + * + * \param merger Merger object + * \return a merger object (call getMergedConfig to obtain the result) + */ + ConstConfigMergerRcPtr mergeConfigs() const; + /// Get the final merged config. ConstConfigRcPtr getMergedConfig() const; - /// Get one of the merged configs (if there are a series of merges). + /// Get one of the merged configs (if there are a series of merges). Returns null + /// if index is out of range. ConstConfigRcPtr getMergedConfig(int index) const; - - void addMergedConfig(ConstConfigRcPtr cfg); + int getNumMergedConfigs() const; /// Serialize to the OCIOM file format. void serialize(std::ostream& os) const; /// Set the version of the OCIOM file format. - void setMajorVersion(unsigned int major); - void setMinorVersion(unsigned int minor); void setVersion(unsigned int major, unsigned int minor); unsigned int getMajorVersion() const; unsigned int getMinorVersion() const; @@ -812,23 +833,11 @@ class OCIOEXPORT ConfigMerger const Impl * getImpl() const { return m_impl; } }; -extern OCIOEXPORT std::ostream & operator<<(std::ostream &, const ColorSpaceMenuHelper &); +extern OCIOEXPORT std::ostream & operator<<(std::ostream &, const ConfigMerger &); namespace ConfigMergingHelpers { -/** - * \brief Execute the merge(s) based on the merger object. - * - * Execute the merge(s) based on the merger object that was previously populated by using - * ConfigMerger::CreateFromFile or created from scratch by using ConfigMerger::Create() and - * programmatically configuring it. - * - * \param merger Merger object - * \return a merger object (call getMergedConfig to obtain the result) - */ -extern OCIOEXPORT ConstConfigMergerRcPtr MergeConfigs(const ConstConfigMergerRcPtr & merger); - /** * \brief Merge the input into the base config, using the supplied merge parameters. * @@ -844,7 +853,7 @@ extern OCIOEXPORT ConfigRcPtr MergeConfigs(const ConfigMergingParametersRcPtr & /** * \brief Merge a single color space into the base config, using the supplied merge parameters. * - * Note that the assumeCommonReferenceSpace merge parameter will be ignored and set to true. + * Note that the AdjustInputReferenceSpace merge parameter will be ignored and set to false. * To use automatic reference space conversion, add the color space to an input config that * has the necessary interchange role set. * diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp index ac718b072f..57a3d00136 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp +++ b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp @@ -146,7 +146,7 @@ const char * ConfigMergingParameters::getActiveViews() const return getImpl()->m_overrideCfg->getActiveViews(); } -void ConfigMergingParameters::setInactiveColorspaces(const char * colorspaces) +void ConfigMergingParameters::setInactiveColorSpaces(const char * colorspaces) { getImpl()->m_overrideCfg->setInactiveColorSpaces(colorspaces); } @@ -226,14 +226,14 @@ bool ConfigMergingParameters::isAvoidDuplicates() const return getImpl()->m_avoidDuplicates; } -void ConfigMergingParameters::setAssumeCommonReferenceSpace(bool enabled) +void ConfigMergingParameters::setAdjustInputReferenceSpace(bool enabled) { - getImpl()->m_assumeCommonReferenceSpace = enabled; + getImpl()->m_adjustInputReferenceSpace = enabled; } -bool ConfigMergingParameters::isAssumeCommonReferenceSpace() const +bool ConfigMergingParameters::isAdjustInputReferenceSpace() const { - return getImpl()->m_assumeCommonReferenceSpace; + return getImpl()->m_adjustInputReferenceSpace; } void ConfigMergingParameters::setRoles(MergeStrategies strategy) @@ -278,6 +278,20 @@ ConfigMergingParameters::MergeStrategies ConfigMergingParameters::getDisplayView return getImpl()->m_displayViews; } +void ConfigMergingParameters::setViewTransforms(MergeStrategies strategy) +{ + getImpl()->m_viewTransforms = strategy; +} + +ConfigMergingParameters::MergeStrategies ConfigMergingParameters::getViewTransforms() const +{ + if (getImpl()->m_viewTransforms == MergeStrategies::STRATEGY_UNSPECIFIED) + { + return getDefaultStrategy(); + } + return getImpl()->m_viewTransforms; +} + void ConfigMergingParameters::setLooks(MergeStrategies strategy) { getImpl()->m_looks = strategy; @@ -355,7 +369,7 @@ std::ostream & operator<<(std::ostream & os, const ConfigMergingParameters & par print_bool("error_on_conflict", params.isErrorOnConflict()); print_enum("default_strategy", params.getDefaultStrategy()); print_bool("avoid_duplicates", params.isAvoidDuplicates()); - print_bool("assume_common_reference_space", params.isAssumeCommonReferenceSpace()); + print_bool("adjust_input_reference_space", params.isAdjustInputReferenceSpace()); print_str("name", params.getName()); print_str("description", params.getDescription()); print_str("search_path", params.getSearchPath()); @@ -365,6 +379,7 @@ std::ostream & operator<<(std::ostream & os, const ConfigMergingParameters & par print_enum("roles", params.getRoles()); print_enum("file_rules", params.getFileRules()); print_enum("display-views", params.getDisplayViews()); + print_enum("view_transforms", params.getViewTransforms()); print_enum("looks", params.getLooks()); print_enum("colorspaces", params.getColorspaces()); print_enum("named_transforms", params.getNamedTransforms()); @@ -431,14 +446,48 @@ ConstConfigMergerRcPtr ConfigMerger::Impl::Read(std::istream & istream, const ch return merger; } -ConstConfigRcPtr ConfigMerger::Impl::loadConfig(const char * value) const +ConstConfigRcPtr ConfigMerger::Impl::loadConfig(const char * value) { - try + // Get the absolute path. + StringUtils::StringVec searchpaths; + + if (m_searchPaths.size() == 0) { - // Try to load the provided config name as a file. - return Config::CreateFromFile(value); + searchpaths.emplace_back(m_workingDir); + } + + for (size_t i = 0; i < m_searchPaths.size(); ++i) + { + // Resolve variables in case the expansion adds slashes. + const std::string path = m_searchPaths[i]; + + // Remove trailing "/", and spaces. + std::string dirname = StringUtils::RightTrim(StringUtils::Trim(path), '/'); + + if (!pystring::os::path::isabs(dirname)) + { + dirname = pystring::os::path::join(m_workingDir, dirname); + } + + searchpaths.push_back(pystring::os::path::normpath(dirname)); + } + + for (size_t i = 0; i < searchpaths.size(); ++i) + { + try + { + // Try to load the provided config using the search paths. + // Return as soon as they find a valid path. + const std::string resolvedfullpath = pystring::os::path::join(searchpaths[i], + value); + return Config::CreateFromFile(resolvedfullpath.c_str()); + } + // TODO: If the file exists but won't load, this hides the error. + // (Tried using ExceptionMissingFile, but the implementation of that is not what I + // expected, Config::CreateFromFile only uses that if the argument is empty, not + // if it can't read the file.) + catch(...) { /* don't capture the exception */ } } - catch(...) { /* don't capture the exception */ } // Try to load the provided base config name as a built-in config. try @@ -449,21 +498,19 @@ ConstConfigRcPtr ConfigMerger::Impl::loadConfig(const char * value) const catch(...) { /* don't capture the exception */ } // Must be a reference to a config from a previous merge. - for (int i = 0; i < getNumConfigMergingParameters(); i++) + for (size_t i = 0; i < m_mergeParams.size(); i++) { - if (Platform::Strcasecmp(getParams(i)->getOutputName(), value) == 0) + if (Platform::Strcasecmp(m_mergeParams.at(i)->getOutputName(), value) == 0) { // Use the config from the index. - if (i < (int) m_mergedConfigs.size()) - { - return m_mergedConfigs.at(i); - } + return m_mergedConfigs.at(i); } } return nullptr; } + // Public ConfigMerger::ConfigMerger() : m_impl(new ConfigMerger::Impl()) @@ -482,7 +529,6 @@ ConfigMergerRcPtr ConfigMerger::Create() return ConfigMergerRcPtr(new ConfigMerger(), &deleter); } -// TODO: Refactor with the loadConfig function below. ConstConfigMergerRcPtr ConfigMerger::CreateFromFile(const char * filepath) { if (!filepath || !*filepath) @@ -554,7 +600,7 @@ const char * ConfigMerger::getWorkingDir() const ConfigMergingParametersRcPtr ConfigMerger::getParams(int index) const { - if (index < static_cast(getImpl()->m_mergeParams.size())) + if (index >= 0 && index < static_cast(getImpl()->m_mergeParams.size())) { return getImpl()->m_mergeParams.at(index); } @@ -597,30 +643,20 @@ unsigned int ConfigMerger::getMajorVersion() const return getImpl()->m_majorVersion; } -void ConfigMerger::setMajorVersion(unsigned int version) -{ - getImpl()->m_majorVersion = version; -} - unsigned int ConfigMerger::getMinorVersion() const { return getImpl()->m_minorVersion; } -void ConfigMerger::setMinorVersion(unsigned int version) -{ - getImpl()->m_minorVersion = version; -} - void ConfigMerger::setVersion(unsigned int major, unsigned int minor) { - setMajorVersion(major); - setMinorVersion(minor); + getImpl()->m_majorVersion = major; + getImpl()->m_minorVersion = minor; } -void ConfigMerger::addMergedConfig(ConstConfigRcPtr cfg) +int ConfigMerger::getNumMergedConfigs() const { - getImpl()->m_mergedConfigs.push_back(cfg); + return getImpl()->m_mergedConfigs.size(); } ConstConfigRcPtr ConfigMerger::getMergedConfig() const @@ -637,92 +673,19 @@ ConstConfigRcPtr ConfigMerger::getMergedConfig(int index) const return nullptr; } -namespace ConfigMergingHelpers -{ - -ConstConfigRcPtr loadConfig(const ConfigMergerRcPtr merger, - const char * value) -{ - // Get the absolute path. - StringUtils::StringVec searchpaths; - - if (merger->getNumSearchPaths() == 0) - { - merger->addSearchPath(merger->getWorkingDir()); - } - - for (int i = 0; i < merger->getNumSearchPaths(); ++i) - { - // Resolve variables in case the expansion adds slashes. - const std::string path = merger->getSearchPath(i); - - // Remove trailing "/", and spaces. - std::string dirname = StringUtils::RightTrim(StringUtils::Trim(path), '/'); - - if (!pystring::os::path::isabs(dirname)) - { - dirname = pystring::os::path::join(merger->getWorkingDir(), dirname); - } - - searchpaths.push_back(pystring::os::path::normpath(dirname)); - } - - for (size_t i = 0; i < searchpaths.size(); ++i) - { - try - { - // Try to load the provided config using the search paths. - // Return as soon as they find a valid path. - const std::string resolvedfullpath = pystring::os::path::join(searchpaths[i], - value); - return Config::CreateFromFile(resolvedfullpath.c_str()); - } - // TODO: If the file exists but won't load, this hides the error. - // (Tried using ExceptionMissingFile, but the implementation of that is not what I - // expected, Config::CreateFromFile only uses that if the argument is empty, not - // if it can't read the file.) - catch(...) { /* don't capture the exception */ } - } - - // Try to load the provided base config name as a built-in config. - try - { - // Check if the base config name is a built-in config. - return Config::CreateFromBuiltinConfig(value); - } - catch(...) { /* don't capture the exception */ } - - // Must be a reference to a config from a previous merge. - for (int i = 0; i < merger->getNumConfigMergingParameters(); i++) - { - if (Platform::Strcasecmp(merger->getParams(i)->getOutputName(), value) == 0) - { - // Use the config from the index. - return merger->getMergedConfig(i); - } - } - - return nullptr; -} - -ConstConfigMergerRcPtr MergeConfigs(const ConstConfigMergerRcPtr & merger) +ConstConfigMergerRcPtr ConfigMerger::mergeConfigs() const { - if (!merger) - { - throw(Exception("The merger object was not initialized.")); - } - - ConfigMergerRcPtr editableMerger = merger->createEditableCopy(); + ConfigMergerRcPtr editableMerger = this->createEditableCopy(); - for (int i = 0; i < merger->getNumConfigMergingParameters(); i++) + for (int i = 0; i < getNumConfigMergingParameters(); i++) { - ConstConfigMergingParametersRcPtr params = merger->getParams(i); + ConfigMergingParametersRcPtr params = getImpl()->m_mergeParams[i]; // Load base config. - ConstConfigRcPtr baseCfg = loadConfig(editableMerger, params->getBaseConfigName()); + ConstConfigRcPtr baseCfg = editableMerger->getImpl()->loadConfig(params->getBaseConfigName()); // Load input config. - ConstConfigRcPtr inputCfg = loadConfig(editableMerger, params->getInputConfigName()); + ConstConfigRcPtr inputCfg = editableMerger->getImpl()->loadConfig(params->getInputConfigName()); if (baseCfg && inputCfg) { @@ -732,11 +695,12 @@ ConstConfigMergerRcPtr MergeConfigs(const ConstConfigMergerRcPtr & merger) // Process merge. try { - MergeHandlerOptions options = { baseCfg, inputCfg, merger->getParams(i), mergedConfig }; + MergeHandlerOptions options = { baseCfg, inputCfg, params, mergedConfig }; GeneralMerger(options).merge(); RolesMerger(options).merge(); FileRulesMerger(options).merge(); DisplayViewMerger(options).merge(); + ViewTransformsMerger(options).merge(); LooksMerger(options).merge(); ColorspacesMerger(options).merge(); NamedTransformsMerger(options).merge(); @@ -747,7 +711,8 @@ ConstConfigMergerRcPtr MergeConfigs(const ConstConfigMergerRcPtr & merger) } // Add new config object to m_mergedConfigs so they can be used for following merges. - editableMerger->addMergedConfig(mergedConfig); + editableMerger->getImpl()->m_mergedConfigs.push_back(mergedConfig); + } else { @@ -758,6 +723,9 @@ ConstConfigMergerRcPtr MergeConfigs(const ConstConfigMergerRcPtr & merger) return editableMerger; } +namespace ConfigMergingHelpers +{ + ConfigRcPtr MergeConfigs(const ConfigMergingParametersRcPtr & params, const ConstConfigRcPtr & baseConfig, const ConstConfigRcPtr & inputConfig) @@ -778,6 +746,7 @@ ConfigRcPtr MergeConfigs(const ConfigMergingParametersRcPtr & params, RolesMerger(options).merge(); FileRulesMerger(options).merge(); DisplayViewMerger(options).merge(); + ViewTransformsMerger(options).merge(); LooksMerger(options).merge(); ColorspacesMerger(options).merge(); NamedTransformsMerger(options).merge(); @@ -809,7 +778,7 @@ ConfigRcPtr MergeColorSpace(const ConfigMergingParametersRcPtr & params, // With only the color space, the reference space is unknown, so turn off // automatic reference space conversion to the reference space of the base config. ConfigMergingParametersRcPtr eParams = params->createEditableCopy(); - eParams->setAssumeCommonReferenceSpace(true); + eParams->setAdjustInputReferenceSpace(false); // Process the merge. try diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h index 0daa56630c..f118a5f82a 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h +++ b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h @@ -42,7 +42,7 @@ class ConfigMergingParameters::Impl bool m_inputFirst; bool m_errorOnConflict; bool m_avoidDuplicates; - bool m_assumeCommonReferenceSpace; + bool m_adjustInputReferenceSpace; // Merge strategy for each section of the config. @@ -50,9 +50,10 @@ class ConfigMergingParameters::Impl MergeStrategies m_defaultStrategy; MergeStrategies m_roles; MergeStrategies m_fileRules; - // Includes shared_views, displays, view_transforms, viewing_rules, virtual_display, - // active_display, active_views, and default_view_transform. + // Includes shared_views, displays, viewing_rules, virtual_display, active_display, active_views. MergeStrategies m_displayViews; + // Includes view_transforms and default_view_transform. + MergeStrategies m_viewTransforms; MergeStrategies m_looks; // Includes colorspaces, environment, search_path, family_separator, and inactive_colorspaces. MergeStrategies m_colorspaces; @@ -77,11 +78,12 @@ class ConfigMergingParameters::Impl m_inputFirst = true; m_errorOnConflict = false; m_avoidDuplicates = true; - m_assumeCommonReferenceSpace = false; + m_adjustInputReferenceSpace = true; m_roles = STRATEGY_UNSPECIFIED; m_fileRules = STRATEGY_UNSPECIFIED; m_displayViews = STRATEGY_UNSPECIFIED; + m_viewTransforms = STRATEGY_UNSPECIFIED; m_looks = STRATEGY_UNSPECIFIED; m_colorspaces = STRATEGY_UNSPECIFIED; m_namedTransforms = STRATEGY_UNSPECIFIED; @@ -109,11 +111,12 @@ class ConfigMergingParameters::Impl m_inputFirst = rhs.m_inputFirst; m_errorOnConflict = rhs.m_errorOnConflict; m_avoidDuplicates = rhs.m_avoidDuplicates; - m_assumeCommonReferenceSpace = rhs.m_assumeCommonReferenceSpace; + m_adjustInputReferenceSpace = rhs.m_adjustInputReferenceSpace; m_roles = rhs.m_roles; m_fileRules = rhs.m_fileRules; m_displayViews = rhs.m_displayViews; + m_viewTransforms = rhs.m_viewTransforms; m_looks = rhs.m_looks; m_colorspaces = rhs.m_colorspaces; m_namedTransforms = rhs.m_namedTransforms; @@ -144,7 +147,6 @@ class ConfigMerger::Impl Impl() { - } ~Impl() = default; @@ -187,21 +189,7 @@ class ConfigMerger::Impl * 3 - If not found, try to use the name as the output of a previous merge. * 4 - If still not found, return an empty config object. */ - ConstConfigRcPtr loadConfig(const char * value) const; - - ConfigMergingParametersRcPtr getParams(int index) const - { - if (index >= 0 && index < static_cast(m_mergeParams.size())) - { - return nullptr; - } - return m_mergeParams.at(index); - } - - int getNumConfigMergingParameters() const - { - return static_cast(m_mergeParams.size()); - } + ConstConfigRcPtr loadConfig(const char * value); }; } // namespace OCIO_NAMESPACE diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp index 9707d86cfe..3afddf3474 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp +++ b/src/OpenColorIO/apphelpers/mergeconfigs/OCIOMYaml.cpp @@ -159,9 +159,14 @@ void OCIOMYaml::loadOptions(const YAML::Node & node, ConfigMergingParametersRcPt { params->setAvoidDuplicates(it->second.as()); } + else if (key == "adjust_input_reference_space") + { + params->setAdjustInputReferenceSpace(it->second.as()); + } else if (key == "assume_common_reference_space") { - params->setAssumeCommonReferenceSpace(it->second.as()); + // Need to support this as a synonym for adjust_input_reference_space. + params->setAdjustInputReferenceSpace(!it->second.as()); } else if (key == "default_strategy") { @@ -251,7 +256,7 @@ void OCIOMYaml::loadOverrides(const YAML::Node & node, ConfigMergingParametersRc std::vector inactiveCSs; load(it->second, inactiveCSs); const std::string inactivecCSsStr = StringUtils::Join(inactiveCSs, ','); - params->setInactiveColorspaces(inactivecCSsStr.c_str()); + params->setInactiveColorSpaces(inactivecCSsStr.c_str()); } } } @@ -276,6 +281,10 @@ void OCIOMYaml::loadParams(const YAML::Node & node, ConfigMergingParametersRcPtr { params->setDisplayViews(genericStrategyHandler(it->first, it->second)); } + else if (key == "view_transforms") + { + params->setViewTransforms(genericStrategyHandler(it->first, it->second)); + } else if (key == "looks") { params->setLooks(genericStrategyHandler(it->first, it->second)); @@ -317,12 +326,12 @@ void OCIOMYaml::load(const YAML::Node& node, ConfigMergerRcPtr & merger, const c if(results.size() == 1) { - merger->setMajorVersion(std::stoi(results[0].c_str())); + merger->setVersion(std::stoi(results[0].c_str()), 0); } else if(results.size() == 2) { - merger->setMajorVersion(std::stoi(results[0].c_str())); - merger->setMinorVersion(std::stoi(results[1].c_str())); + merger->setVersion(std::stoi(results[0].c_str()), + std::stoi(results[1].c_str())); } if (merger->getMajorVersion() > 1u || merger->getMinorVersion() > 0u) { @@ -534,7 +543,7 @@ inline void save(YAML::Emitter & out, const ConfigMerger & merger) out << YAML::Key << "error_on_conflict" << YAML::Value << p->isErrorOnConflict(); out << YAML::Key << "default_strategy" << YAML::Value << OCIOMYaml::EnumToStrategyString(p->getDefaultStrategy()); out << YAML::Key << "avoid_duplicates" << YAML::Value << p->isAvoidDuplicates(); - out << YAML::Key << "assume_common_reference_space" << YAML::Value << p->isAssumeCommonReferenceSpace(); + out << YAML::Key << "adjust_input_reference_space" << YAML::Value << p->isAdjustInputReferenceSpace(); // End of options section. out << YAML::EndMap; out << YAML::Newline; @@ -597,6 +606,11 @@ inline void save(YAML::Emitter & out, const ConfigMerger & merger) out << YAML::Key << "strategy" << YAML::Value << OCIOMYaml::EnumToStrategyString(p->getDisplayViews()); out << YAML::EndMap; + out << YAML::Key << "view_transforms"; + out << YAML::Value << YAML::BeginMap; + out << YAML::Key << "strategy" << YAML::Value << OCIOMYaml::EnumToStrategyString(p->getViewTransforms()); + out << YAML::EndMap; + out << YAML::Key << "looks"; out << YAML::Value << YAML::BeginMap; out << YAML::Key << "strategy" << YAML::Value << OCIOMYaml::EnumToStrategyString(p->getLooks()); diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp index adf9ab7222..0619b150ae 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp +++ b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp @@ -728,53 +728,6 @@ void FileRulesMerger::handleRemove() namespace { -bool viewTransformsAreEqual(const ConstConfigRcPtr & first, - const ConstConfigRcPtr & second, - const char * name) -{ - ConstViewTransformRcPtr vt1 = first->getViewTransform(name); - ConstViewTransformRcPtr vt2 = second->getViewTransform(name); - if (vt1 && vt2) - { - // Both configs have a view transform by this name, now check the parts. - // Note: Not checking family or description since it is not a functional difference. - - // TODO: Check categories. - - if (vt1->getReferenceSpaceType() != vt2->getReferenceSpaceType()) - { - return false; - } - - ConstTransformRcPtr t1_to = vt1->getTransform(VIEWTRANSFORM_DIR_TO_REFERENCE); - ConstTransformRcPtr t2_to = vt2->getTransform(VIEWTRANSFORM_DIR_TO_REFERENCE); - if (t1_to || t2_to) - { - if (!t1_to || !t2_to) // one of them has a transform but the other does not - { - return false; - } - - // TODO: Compare transforms. - } - - ConstTransformRcPtr t1_from = vt1->getTransform(VIEWTRANSFORM_DIR_FROM_REFERENCE); - ConstTransformRcPtr t2_from = vt2->getTransform(VIEWTRANSFORM_DIR_FROM_REFERENCE); - if (t1_from || t2_from) - { - if (!t1_from || !t2_from) // one of them has a transform but the other does not - { - return false; - } - - // TODO: Compare transforms. - } - - return true; - } - return false; -} - bool viewingRulesAreEqual(const ConstViewingRulesRcPtr & r1, size_t r1Idx, const ConstViewingRulesRcPtr & r2, @@ -1358,74 +1311,6 @@ void DisplayViewMerger::processActiveLists() } } -void DisplayViewMerger::addViewTransform(const ConstConfigRcPtr & cfg, - const char * name, - bool isInput) -{ - ConstViewTransformRcPtr vt = cfg->getViewTransform(name); - if (!vt) return; - - if (!isInput || m_params->isAssumeCommonReferenceSpace()) - { - m_mergedConfig->addViewTransform(vt); - } - else - { - // Add the reference space adapter transforms. - ViewTransformRcPtr eVT = vt->createEditableCopy(); - ConfigUtils::updateReferenceView(eVT, m_inputToBaseGtScene, m_inputToBaseGtDisplay); - m_mergedConfig->addViewTransform(eVT); - } -} - -void DisplayViewMerger::addUniqueViewTransforms(const ConstConfigRcPtr & cfg, bool isInput) -{ - for (int i = 0; i < cfg->getNumViewTransforms(); i++) - { - const char * name = cfg->getViewTransformNameByIndex(i); - // Take the view from the config if it does not exist in merged config. - if (m_mergedConfig->getViewTransform(name) == nullptr) - { - addViewTransform(cfg, name, isInput); - } - } -} - -void DisplayViewMerger::processViewTransforms(const ConstConfigRcPtr & first, - const ConstConfigRcPtr & second, - bool preferSecond, - bool secondIsInput) -{ - for (int i = 0; i < first->getNumViewTransforms(); i++) - { - const char * name = first->getViewTransformNameByIndex(i); - if (name && *name) - { - ConstViewTransformRcPtr vt2 = second->getViewTransform(name); - if (vt2 && !viewTransformsAreEqual(first, second, name)) - { - std::ostringstream os; - os << "The Input config contains a value that would override "; - os << "the Base config: view_transforms: " << name; - notify(os.str(), m_params->isErrorOnConflict()); - } - - if (vt2 && preferSecond) - { - addViewTransform(second, name, secondIsInput); - } - else - { - addViewTransform(first, name, !secondIsInput); - } - } - } - - // Add the remaining unique views transform. - - addUniqueViewTransforms(second, secondIsInput); -} - void DisplayViewMerger::processViewingRules(const ConstConfigRcPtr & first, const ConstConfigRcPtr & second, bool preferSecond) const @@ -1523,31 +1408,6 @@ void DisplayViewMerger::handlePreferInput() // Merge active_displays and active_views. processActiveLists(); - // Merge view_transforms. - m_mergedConfig->clearViewTransforms(); - if (m_params->isInputFirst()) - { - processViewTransforms(m_inputConfig, m_baseConfig, false, false); - } - else - { - processViewTransforms(m_baseConfig, m_inputConfig, true, true); - } - - // Merge default_view_transform. - const char * baseName = m_baseConfig->getDefaultViewTransformName(); - const char * inputName = m_inputConfig->getDefaultViewTransformName(); - if (!(Platform::Strcasecmp(baseName, inputName) == 0)) - { - notify("The Input config contains a value that would override the Base config: "\ - "default_view_transform: " + std::string(inputName), m_params->isErrorOnConflict()); - } - // If the input config does not specify a default, keep the one from the base. - if (inputName && *inputName) - { - m_mergedConfig->setDefaultViewTransformName(inputName); - } - // Merge viewing_rules. if (m_params->isInputFirst()) { @@ -1592,31 +1452,6 @@ void DisplayViewMerger::handlePreferBase() // Merge active_displays and active_views. processActiveLists(); - // Merge view_transforms. - m_mergedConfig->clearViewTransforms(); - if (m_params->isInputFirst()) - { - processViewTransforms(m_inputConfig, m_baseConfig, true, false); - } - else - { - processViewTransforms(m_baseConfig, m_inputConfig, false, true); - } - - // Merge default_view_transform. - const char * baseName = m_baseConfig->getDefaultViewTransformName(); - const char * inputName = m_inputConfig->getDefaultViewTransformName(); - if (!(Platform::Strcasecmp(baseName, inputName) == 0)) - { - notify("The Input config contains a value that would override the Base config: "\ - "default_view_transform: " + std::string(inputName), m_params->isErrorOnConflict()); - } - // Only use the input if the base is missing. - if (!baseName || !*baseName) - { - m_mergedConfig->setDefaultViewTransformName(inputName); - } - // Merge viewing_rules. if (m_params->isInputFirst()) { @@ -1668,13 +1503,6 @@ void DisplayViewMerger::handleInputOnly() m_mergedConfig->setActiveViews(m_inputConfig->getActiveViews()); } - // Merge view_transforms. - m_mergedConfig->clearViewTransforms(); - addUniqueViewTransforms(m_inputConfig, true); - - // Merge default_view_transform. - m_mergedConfig->setDefaultViewTransformName(m_inputConfig->getDefaultViewTransformName()); - // Merge viewing_rules. m_mergedConfig->setViewingRules(m_inputConfig->getViewingRules()); } @@ -1824,27 +1652,6 @@ void DisplayViewMerger::handleRemove() } m_mergedConfig->setActiveViews(StringUtils::Join(mergedActiveViews, ',').c_str()); - // Remove from view_transforms. - m_mergedConfig->clearViewTransforms(); - // Add view transforms that are present in the base config and NOT present in the input config. - for (int i = 0; i < m_baseConfig->getNumViewTransforms(); i++) - { - const char * name = m_baseConfig->getViewTransformNameByIndex(i); - if (m_inputConfig->getViewTransform(name) == nullptr) - { - m_mergedConfig->addViewTransform(m_baseConfig->getViewTransform(name)); - } - } - - // Handle default_view_transform. - // Leave the base alone unless it identified a view transform that was removed. - const char * baseName = m_baseConfig->getDefaultViewTransformName(); - if (m_mergedConfig->getViewTransform(baseName) == nullptr) - { - // Set to empty string, the first view transform will be used by default. - m_mergedConfig->setDefaultViewTransformName(""); - } - // Handle viewing_rules. ViewingRulesRcPtr mergedRules = ViewingRules::Create(); @@ -1871,6 +1678,224 @@ void DisplayViewMerger::handleRemove() /////////////////////////////////// DisplayViewMerger //////////////////////////////////// +/////////////////////////////////// ViewTransformMerger //////////////////////////////////// + +namespace +{ + +bool viewTransformsAreEqual(const ConstConfigRcPtr & first, + const ConstConfigRcPtr & second, + const char * name) +{ + ConstViewTransformRcPtr vt1 = first->getViewTransform(name); + ConstViewTransformRcPtr vt2 = second->getViewTransform(name); + if (vt1 && vt2) + { + // Both configs have a view transform by this name, now check the parts. + // Note: Not checking family or description since it is not a functional difference. + + // TODO: Check categories. + + if (vt1->getReferenceSpaceType() != vt2->getReferenceSpaceType()) + { + return false; + } + + ConstTransformRcPtr t1_to = vt1->getTransform(VIEWTRANSFORM_DIR_TO_REFERENCE); + ConstTransformRcPtr t2_to = vt2->getTransform(VIEWTRANSFORM_DIR_TO_REFERENCE); + if (t1_to || t2_to) + { + if (!t1_to || !t2_to) // one of them has a transform but the other does not + { + return false; + } + + // TODO: Compare transforms. + } + + ConstTransformRcPtr t1_from = vt1->getTransform(VIEWTRANSFORM_DIR_FROM_REFERENCE); + ConstTransformRcPtr t2_from = vt2->getTransform(VIEWTRANSFORM_DIR_FROM_REFERENCE); + if (t1_from || t2_from) + { + if (!t1_from || !t2_from) // one of them has a transform but the other does not + { + return false; + } + + // TODO: Compare transforms. + } + + return true; + } + return false; +} + +} // anon. + +void ViewTransformsMerger::addViewTransform(const ConstConfigRcPtr & cfg, + const char * name, + bool isInput) +{ + ConstViewTransformRcPtr vt = cfg->getViewTransform(name); + if (!vt) return; + + if (!isInput || !m_params->isAdjustInputReferenceSpace()) + { + m_mergedConfig->addViewTransform(vt); + } + else + { + // Add the reference space adapter transforms. + ViewTransformRcPtr eVT = vt->createEditableCopy(); + ConfigUtils::updateReferenceView(eVT, m_inputToBaseGtScene, m_inputToBaseGtDisplay); + m_mergedConfig->addViewTransform(eVT); + } +} + +void ViewTransformsMerger::addUniqueViewTransforms(const ConstConfigRcPtr & cfg, bool isInput) +{ + for (int i = 0; i < cfg->getNumViewTransforms(); i++) + { + const char * name = cfg->getViewTransformNameByIndex(i); + // Take the view from the config if it does not exist in merged config. + if (m_mergedConfig->getViewTransform(name) == nullptr) + { + addViewTransform(cfg, name, isInput); + } + } +} + +void ViewTransformsMerger::processViewTransforms(const ConstConfigRcPtr & first, + const ConstConfigRcPtr & second, + bool preferSecond, + bool secondIsInput) +{ + for (int i = 0; i < first->getNumViewTransforms(); i++) + { + const char * name = first->getViewTransformNameByIndex(i); + if (name && *name) + { + ConstViewTransformRcPtr vt2 = second->getViewTransform(name); + if (vt2 && !viewTransformsAreEqual(first, second, name)) + { + std::ostringstream os; + os << "The Input config contains a value that would override "; + os << "the Base config: view_transforms: " << name; + notify(os.str(), m_params->isErrorOnConflict()); + } + + if (vt2 && preferSecond) + { + addViewTransform(second, name, secondIsInput); + } + else + { + addViewTransform(first, name, !secondIsInput); + } + } + } + + // Add the remaining unique views transform. + + addUniqueViewTransforms(second, secondIsInput); +} + +void ViewTransformsMerger::handlePreferInput() +{ + // Merge view_transforms. + m_mergedConfig->clearViewTransforms(); + if (m_params->isInputFirst()) + { + processViewTransforms(m_inputConfig, m_baseConfig, false, false); + } + else + { + processViewTransforms(m_baseConfig, m_inputConfig, true, true); + } + + // Merge default_view_transform. + const char * baseName = m_baseConfig->getDefaultViewTransformName(); + const char * inputName = m_inputConfig->getDefaultViewTransformName(); + if (!(Platform::Strcasecmp(baseName, inputName) == 0)) + { + notify("The Input config contains a value that would override the Base config: "\ + "default_view_transform: " + std::string(inputName), m_params->isErrorOnConflict()); + } + // If the input config does not specify a default, keep the one from the base. + if (inputName && *inputName) + { + m_mergedConfig->setDefaultViewTransformName(inputName); + } +} + +void ViewTransformsMerger::handlePreferBase() +{ + // Merge view_transforms. + m_mergedConfig->clearViewTransforms(); + if (m_params->isInputFirst()) + { + processViewTransforms(m_inputConfig, m_baseConfig, true, false); + } + else + { + processViewTransforms(m_baseConfig, m_inputConfig, false, true); + } + + // Merge default_view_transform. + const char * baseName = m_baseConfig->getDefaultViewTransformName(); + const char * inputName = m_inputConfig->getDefaultViewTransformName(); + if (!(Platform::Strcasecmp(baseName, inputName) == 0)) + { + notify("The Input config contains a value that would override the Base config: "\ + "default_view_transform: " + std::string(inputName), m_params->isErrorOnConflict()); + } + // Only use the input if the base is missing. + if (!baseName || !*baseName) + { + m_mergedConfig->setDefaultViewTransformName(inputName); + } +} + +void ViewTransformsMerger::handleInputOnly() +{ + // Merge view_transforms. + m_mergedConfig->clearViewTransforms(); + addUniqueViewTransforms(m_inputConfig, true); + + // Merge default_view_transform. + m_mergedConfig->setDefaultViewTransformName(m_inputConfig->getDefaultViewTransformName()); +} + +void ViewTransformsMerger::handleBaseOnly() +{ +} + +void ViewTransformsMerger::handleRemove() +{ + // Remove from view_transforms. + m_mergedConfig->clearViewTransforms(); + // Add view transforms that are present in the base config and NOT present in the input config. + for (int i = 0; i < m_baseConfig->getNumViewTransforms(); i++) + { + const char * name = m_baseConfig->getViewTransformNameByIndex(i); + if (m_inputConfig->getViewTransform(name) == nullptr) + { + m_mergedConfig->addViewTransform(m_baseConfig->getViewTransform(name)); + } + } + + // Handle default_view_transform. + // Leave the base alone unless it identified a view transform that was removed. + const char * baseName = m_baseConfig->getDefaultViewTransformName(); + if (m_mergedConfig->getViewTransform(baseName) == nullptr) + { + // Set to empty string, the first view transform will be used by default. + m_mergedConfig->setDefaultViewTransformName(""); + } +} + +/////////////////////////////////// ViewTransformMerger //////////////////////////////////// + /////////////////////////////////// LooksMerger ////////////////////////////////////////// void LooksMerger::handlePreferInput() @@ -2608,7 +2633,7 @@ void ColorspacesMerger::addColorSpaces() ColorSpaceRcPtr eCS = cs->createEditableCopy(); - if (!m_params->isAssumeCommonReferenceSpace()) + if (m_params->isAdjustInputReferenceSpace()) { if (eCS->getReferenceSpaceType() == REFERENCE_SPACE_DISPLAY) ConfigUtils::updateReferenceColorspace(eCS, m_inputToBaseGtDisplay); diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.h b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.h index ae03b2f015..2fa6141555 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.h +++ b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.h @@ -209,16 +209,6 @@ class DisplayViewMerger : public SectionMerger { m_strategy = options.params->getDefaultStrategy(); } - - if (!options.params->isAssumeCommonReferenceSpace()) - { - // TODO: This may throw, is it worth continuing without ref space conversion? - // Just call LogError() and continue? - ConfigUtils::initializeRefSpaceConverters(m_inputToBaseGtScene, - m_inputToBaseGtDisplay, - m_baseConfig, - m_inputConfig); - } } private: @@ -241,6 +231,46 @@ class DisplayViewMerger : public SectionMerger void processActiveLists(); + void processViewingRules(const ConstConfigRcPtr & first, + const ConstConfigRcPtr & second, + bool preferSecond) const; + + void handlePreferInput(); + void handlePreferBase(); + void handleInputOnly(); + void handleBaseOnly(); + void handleRemove(); +}; + +class ViewTransformsMerger : public SectionMerger +{ +public: + ViewTransformsMerger(MergeHandlerOptions options) : SectionMerger(options) + { + ConfigMergingParameters::MergeStrategies strat = options.params->getViewTransforms(); + if (strat != ConfigMergingParameters::MergeStrategies::STRATEGY_UNSPECIFIED) + { + m_strategy = strat; + } + else + { + m_strategy = options.params->getDefaultStrategy(); + } + + if (options.params->isAdjustInputReferenceSpace()) + { + // TODO: This may throw, is it worth continuing without ref space conversion? + // Just call LogError() and continue? + ConfigUtils::initializeRefSpaceConverters(m_inputToBaseGtScene, + m_inputToBaseGtDisplay, + m_baseConfig, + m_inputConfig); + } + } + +private: + const std::string getName() const { return "View Transforms"; } + void addViewTransform(const ConstConfigRcPtr & cfg, const char * name, bool isInput); void addUniqueViewTransforms(const ConstConfigRcPtr & cfg, bool isInput); void processViewTransforms(const ConstConfigRcPtr & first, @@ -248,10 +278,6 @@ class DisplayViewMerger : public SectionMerger bool preferSecond, bool secondIsInput); - void processViewingRules(const ConstConfigRcPtr & first, - const ConstConfigRcPtr & second, - bool preferSecond) const; - void handlePreferInput(); void handlePreferBase(); void handleInputOnly(); @@ -300,7 +326,7 @@ class ColorspacesMerger : public SectionMerger m_strategy = options.params->getDefaultStrategy(); } - if (!options.params->isAssumeCommonReferenceSpace()) + if (options.params->isAdjustInputReferenceSpace()) { ConfigUtils::initializeRefSpaceConverters(m_inputToBaseGtScene, m_inputToBaseGtDisplay, diff --git a/src/apps/ociomergeconfigs/main.cpp b/src/apps/ociomergeconfigs/main.cpp index e70b2f6306..2e45c2b1c2 100644 --- a/src/apps/ociomergeconfigs/main.cpp +++ b/src/apps/ociomergeconfigs/main.cpp @@ -138,7 +138,7 @@ int main(int argc, const char **argv) try { - OCIO::ConstConfigMergerRcPtr newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); + OCIO::ConstConfigMergerRcPtr newMerger = merger->mergeConfigs(); if (validate) { try diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index 94af56302e..fac01e2c12 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -55,6 +55,7 @@ set(SOURCES apphelpers/PyColorSpaceHelpers.cpp apphelpers/PyDisplayViewHelpers.cpp apphelpers/PyLegacyViewingPipeline.cpp + apphelpers/PyMergeConfigs.cpp apphelpers/PyMixingHelpers.cpp transforms/PyAllocationTransform.cpp transforms/PyBuiltinTransform.cpp diff --git a/src/bindings/python/PyOpenColorIO.cpp b/src/bindings/python/PyOpenColorIO.cpp index 7adda36bb3..f66e6d540a 100644 --- a/src/bindings/python/PyOpenColorIO.cpp +++ b/src/bindings/python/PyOpenColorIO.cpp @@ -97,6 +97,7 @@ PYBIND11_MODULE(PyOpenColorIO, m) // OpenColorIOAppHelpers bindPyColorSpaceMenuHelpers(m); + bindPyConfigMergingHelpers(m); bindPyDisplayViewHelpers(m); bindPyLegacyViewingPipeline(m); bindPyMixingHelpers(m); diff --git a/src/bindings/python/PyOpenColorIO.h b/src/bindings/python/PyOpenColorIO.h index a803c540e3..3c691761b1 100644 --- a/src/bindings/python/PyOpenColorIO.h +++ b/src/bindings/python/PyOpenColorIO.h @@ -56,6 +56,7 @@ void bindPyTransform(py::module & m); // OpenColorIOAppHelpers void bindPyColorSpaceMenuHelpers(py::module & m); +void bindPyConfigMergingHelpers(py::module & m); void bindPyDisplayViewHelpers(py::module & m); void bindPyLegacyViewingPipeline(py::module & m); void bindPyMixingHelpers(py::module & m); diff --git a/src/bindings/python/PyTypes.cpp b/src/bindings/python/PyTypes.cpp index 5b22b56195..dd287bc300 100644 --- a/src/bindings/python/PyTypes.cpp +++ b/src/bindings/python/PyTypes.cpp @@ -270,6 +270,14 @@ void bindPyTypes(py::module & m) m, "MixingColorSpaceManager", DOC(MixingColorSpaceManager)); + py::class_( + m, "ConfigMergingParameters", + DOC(ConfigMergingParameters)); + + py::class_( + m, "ConfigMerger", + DOC(ConfigMerger)); + // Enums py::enum_( m, "LoggingLevel", py::arithmetic(), diff --git a/src/bindings/python/apphelpers/PyMergeConfigs.cpp b/src/bindings/python/apphelpers/PyMergeConfigs.cpp new file mode 100644 index 0000000000..4c7e08fe05 --- /dev/null +++ b/src/bindings/python/apphelpers/PyMergeConfigs.cpp @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + +#include "PyOpenColorIO.h" +#include "PyUtils.h" + +namespace OCIO_NAMESPACE +{ + +//void bindPyConfigMergingParameters(py::module & m); + +void bindPyConfigMergingHelpers(py::module & m) +{ + auto mConfigMergingHelpers = m.def_submodule("ConfigMergingHelpers"); + + auto clsConfigMergingParameters = py::class_( + m.attr("ConfigMergingParameters")); + + auto enumMergeStrategies = + py::enum_( + clsConfigMergingParameters, "MergeStrategies", + DOC(ConfigMergingParameters, MergeStrategies)); + + clsConfigMergingParameters + .def_static("Create", &ConfigMergingParameters::Create, + DOC(ConfigMergingParameters, Create)) + .def("__deepcopy__", [](const ConstConfigMergingParametersRcPtr & self, py::dict) + { + return self->createEditableCopy(); + }, + "memo"_a) + .def("setBaseConfigName", &ConfigMergingParameters::setBaseConfigName, "baseConfig"_a, + DOC(ConfigMergingParameters, setBaseConfigName)) + .def("getBaseConfigName", &ConfigMergingParameters::getBaseConfigName, + DOC(ConfigMergingParameters, getBaseConfigName)) + .def("setInputConfigName", &ConfigMergingParameters::setInputConfigName, "inputConfig"_a, + DOC(ConfigMergingParameters, setInputConfigName)) + .def("getInputConfigName", &ConfigMergingParameters::getInputConfigName, + DOC(ConfigMergingParameters, getInputConfigName)) + .def("setOutputName", &ConfigMergingParameters::setOutputName, "outputName"_a, + DOC(ConfigMergingParameters, setOutputName)) + .def("getOutputName", &ConfigMergingParameters::getOutputName, + DOC(ConfigMergingParameters, getOutputName)) + .def("setDefaultStrategy", &ConfigMergingParameters::setDefaultStrategy, "strategy"_a, + DOC(ConfigMergingParameters, setDefaultStrategy)) + .def("getDefaultStrategy", &ConfigMergingParameters::getDefaultStrategy, + DOC(ConfigMergingParameters, getDefaultStrategy)) + .def("setInputFamilyPrefix", &ConfigMergingParameters::setInputFamilyPrefix, "prefix"_a, + DOC(ConfigMergingParameters, setInputFamilyPrefix)) + .def("getInputFamilyPrefix", &ConfigMergingParameters::getInputFamilyPrefix, + DOC(ConfigMergingParameters, getInputFamilyPrefix)) + .def("setBaseFamilyPrefix", &ConfigMergingParameters::setBaseFamilyPrefix, "prefix"_a, + DOC(ConfigMergingParameters, setBaseFamilyPrefix)) + .def("getBaseFamilyPrefix", &ConfigMergingParameters::getBaseFamilyPrefix, + DOC(ConfigMergingParameters, getBaseFamilyPrefix)) + .def("setInputFirst", &ConfigMergingParameters::setInputFirst, "enabled"_a, + DOC(ConfigMergingParameters, setInputFirst)) + .def("isInputFirst", &ConfigMergingParameters::isInputFirst, + DOC(ConfigMergingParameters, isInputFirst)) + .def("setErrorOnConflict", &ConfigMergingParameters::setErrorOnConflict, "enabled"_a, + DOC(ConfigMergingParameters, setErrorOnConflict)) + .def("isErrorOnConflict", &ConfigMergingParameters::isErrorOnConflict, + DOC(ConfigMergingParameters, isErrorOnConflict)) + .def("setAvoidDuplicates", &ConfigMergingParameters::setAvoidDuplicates, "enabled"_a, + DOC(ConfigMergingParameters, setAvoidDuplicates)) + .def("isAvoidDuplicates", &ConfigMergingParameters::isAvoidDuplicates, + DOC(ConfigMergingParameters, isAvoidDuplicates)) + .def("setAdjustInputReferenceSpace", &ConfigMergingParameters::setAdjustInputReferenceSpace, "enabled"_a, + DOC(ConfigMergingParameters, setAdjustInputReferenceSpace)) + .def("isAdjustInputReferenceSpace", &ConfigMergingParameters::isAdjustInputReferenceSpace, + DOC(ConfigMergingParameters, isAdjustInputReferenceSpace)) + .def("setName", &ConfigMergingParameters::setName, "mergedConfigName"_a, + DOC(ConfigMergingParameters, setName)) + .def("getName", &ConfigMergingParameters::getName, + DOC(ConfigMergingParameters, getName)) + .def("setDescription", &ConfigMergingParameters::setDescription, "mergedConfigDesc"_a, + DOC(ConfigMergingParameters, setDescription)) + .def("getDescription", &ConfigMergingParameters::getDescription, + DOC(ConfigMergingParameters, getDescription)) + + .def("addEnvironmentVar", &ConfigMergingParameters::addEnvironmentVar, "name"_a, "defaultValue"_a, + DOC(ConfigMergingParameters, addEnvironmentVar)) + .def("getNumEnvironmentVars", &ConfigMergingParameters::getNumEnvironmentVars, + DOC(ConfigMergingParameters, getNumEnvironmentVars)) + .def("getEnvironmentVar", &ConfigMergingParameters::getEnvironmentVar, "index"_a, + DOC(ConfigMergingParameters, getEnvironmentVar)) + .def("getEnvironmentVarValue", &ConfigMergingParameters::getEnvironmentVarValue, "index"_a, + DOC(ConfigMergingParameters, getEnvironmentVarValue)) + + .def("setSearchPath", &ConfigMergingParameters::setSearchPath, "path"_a, + DOC(ConfigMergingParameters, setSearchPath)) + .def("addSearchPath", &ConfigMergingParameters::addSearchPath, "path"_a, + DOC(ConfigMergingParameters, addSearchPath)) + .def("getSearchPath", &ConfigMergingParameters::getSearchPath, + DOC(ConfigMergingParameters, getSearchPath)) + + .def("setActiveDisplays", &ConfigMergingParameters::setActiveDisplays, "displays"_a, + DOC(ConfigMergingParameters, setActiveDisplays)) + .def("getActiveDisplays", &ConfigMergingParameters::getActiveDisplays, + DOC(ConfigMergingParameters, getActiveDisplays)) + .def("setActiveViews", &ConfigMergingParameters::setActiveViews, "views"_a, + DOC(ConfigMergingParameters, setActiveViews)) + .def("getActiveViews", &ConfigMergingParameters::getActiveViews, + DOC(ConfigMergingParameters, getActiveViews)) + .def("setInactiveColorSpaces", &ConfigMergingParameters::setInactiveColorSpaces, "colorspaces"_a, + DOC(ConfigMergingParameters, setInactiveColorSpaces)) + .def("getInactiveColorSpaces", &ConfigMergingParameters::getInactiveColorSpaces, + DOC(ConfigMergingParameters, getInactiveColorSpaces)) + + .def("setRoles", &ConfigMergingParameters::setRoles, "strategy"_a, + DOC(ConfigMergingParameters, setRoles)) + .def("getRoles", &ConfigMergingParameters::getRoles, + DOC(ConfigMergingParameters, getRoles)) + .def("setFileRules", &ConfigMergingParameters::setFileRules, "strategy"_a, + DOC(ConfigMergingParameters, setFileRules)) + .def("getFileRules", &ConfigMergingParameters::getFileRules, + DOC(ConfigMergingParameters, getFileRules)) + .def("setDisplayViews", &ConfigMergingParameters::setDisplayViews, "strategy"_a, + DOC(ConfigMergingParameters, setDisplayViews)) + .def("getDisplayViews", &ConfigMergingParameters::getDisplayViews, + DOC(ConfigMergingParameters, getDisplayViews)) + .def("setViewTransforms", &ConfigMergingParameters::setViewTransforms, "strategy"_a, + DOC(ConfigMergingParameters, setViewTransforms)) + .def("getViewTransforms", &ConfigMergingParameters::getViewTransforms, + DOC(ConfigMergingParameters, getViewTransforms)) + .def("setLooks", &ConfigMergingParameters::setLooks, "strategy"_a, + DOC(ConfigMergingParameters, setLooks)) + .def("getLooks", &ConfigMergingParameters::getLooks, + DOC(ConfigMergingParameters, getLooks)) + .def("setColorspaces", &ConfigMergingParameters::setColorspaces, "strategy"_a, + DOC(ConfigMergingParameters, setColorspaces)) + .def("getColorspaces", &ConfigMergingParameters::getColorspaces, + DOC(ConfigMergingParameters, getColorspaces)) + .def("setNamedTransforms", &ConfigMergingParameters::setNamedTransforms, "strategy"_a, + DOC(ConfigMergingParameters, setNamedTransforms)) + .def("getNamedTransforms", &ConfigMergingParameters::getNamedTransforms, + DOC(ConfigMergingParameters, getNamedTransforms)); + + enumMergeStrategies + .value("STRATEGY_PREFER_INPUT", ConfigMergingParameters::STRATEGY_PREFER_INPUT, + DOC(ConfigMergingParameters, MergeStrategies, STRATEGY_PREFER_INPUT)) + .value("STRATEGY_PREFER_BASE", ConfigMergingParameters::STRATEGY_PREFER_BASE, + DOC(ConfigMergingParameters, MergeStrategies, STRATEGY_PREFER_BASE)) + .value("STRATEGY_INPUT_ONLY", ConfigMergingParameters::STRATEGY_INPUT_ONLY, + DOC(ConfigMergingParameters, MergeStrategies, STRATEGY_INPUT_ONLY)) + .value("STRATEGY_BASE_ONLY", ConfigMergingParameters::STRATEGY_BASE_ONLY, + DOC(ConfigMergingParameters, MergeStrategies, STRATEGY_BASE_ONLY)) + .value("STRATEGY_REMOVE", ConfigMergingParameters::STRATEGY_REMOVE, + DOC(ConfigMergingParameters, MergeStrategies, STRATEGY_REMOVE)) + .value("STRATEGY_UNSPECIFIED", ConfigMergingParameters::STRATEGY_UNSPECIFIED, + DOC(ConfigMergingParameters, MergeStrategies, STRATEGY_UNSPECIFIED)) + .export_values(); + + defRepr(clsConfigMergingParameters); + + // ConfigMerger binding + auto clsConfigMerger = py::class_( + m.attr("ConfigMerger")); + + clsConfigMerger + .def_static("Create", &ConfigMerger::Create, + DOC(ConfigMerger, Create)) + .def_static("CreateFromFile", &ConfigMerger::CreateFromFile, "filepath"_a, + DOC(ConfigMerger, CreateFromFile)) + .def("__deepcopy__", [](const ConstConfigMergerRcPtr & self, py::dict) + { + return self->createEditableCopy(); + }, + "memo"_a) + + .def("setSearchPath", &ConfigMerger::setSearchPath, "path"_a, + DOC(ConfigMerger, setSearchPath)) + .def("addSearchPath", &ConfigMerger::addSearchPath, "path"_a, + DOC(ConfigMerger, addSearchPath)) + .def("getNumSearchPaths", &ConfigMerger::getNumSearchPaths, + DOC(ConfigMerger, getNumSearchPaths)) + .def("getSearchPath", &ConfigMerger::getSearchPath, "index"_a, + DOC(ConfigMerger, getSearchPath)) + + .def("setWorkingDir", &ConfigMerger::setWorkingDir, "dirname"_a, + DOC(ConfigMerger, setWorkingDir)) + .def("getWorkingDir", &ConfigMerger::getWorkingDir, + DOC(ConfigMerger, getWorkingDir)) + .def("getParams", &ConfigMerger::getParams, "index"_a, + DOC(ConfigMerger, getParams)) + .def("getNumConfigMergingParameters", &ConfigMerger::getNumConfigMergingParameters, + DOC(ConfigMerger, getNumConfigMergingParameters)) + .def("addParams", &ConfigMerger::addParams, "params"_a, + DOC(ConfigMerger, addParams)) + .def("mergeConfigs", &ConfigMerger::mergeConfigs, + DOC(ConfigMerger, mergeConfigs)) + .def("getNumMergedConfigs", &ConfigMerger::getNumMergedConfigs, + DOC(ConfigMerger, getNumMergedConfigs)) + .def("getMergedConfig", + py::overload_cast<>(&ConfigMerger::getMergedConfig, py::const_), + DOC(ConfigMerger, getMergedConfig)) + .def("getMergedConfig", + py::overload_cast(&ConfigMerger::getMergedConfig, py::const_), + "index"_a, + DOC(ConfigMerger, getMergedConfig, 2)) + .def("serialize", [](const ConfigMerger & self) { + std::ostringstream os; + self.serialize(os); + return os.str(); + }, DOC(ConfigMerger, serialize)) + .def("setVersion", &ConfigMerger::setVersion, "major"_a, "minor"_a, + DOC(ConfigMerger, setVersion)) + .def("getMajorVersion", &ConfigMerger::getMajorVersion, + DOC(ConfigMerger, getMajorVersion)) + .def("getMinorVersion", &ConfigMerger::getMinorVersion, + DOC(ConfigMerger, getMinorVersion)); + + defRepr(clsConfigMerger); + + // ConfigMergingHelpers namespace functions + mConfigMergingHelpers + .def("MergeConfigs", + py::overload_cast( + &ConfigMergingHelpers::MergeConfigs), + "params"_a, "baseConfig"_a, "inputConfig"_a, + DOC(ConfigMergingHelpers, MergeConfigs, 2)) + .def("MergeColorSpace", + &ConfigMergingHelpers::MergeColorSpace, + "params"_a, "baseConfig"_a, "colorspace"_a, + DOC(ConfigMergingHelpers, MergeColorSpace)); +} + +} // namespace OCIO_NAMESPACE diff --git a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp index bbb38e2816..a49d97a586 100644 --- a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp +++ b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp @@ -205,7 +205,7 @@ OCIO_ADD_TEST(MergeConfigs, ociom_parser) OCIO_CHECK_EQUAL(p->getDefaultStrategy(), MergeStrategy::STRATEGY_INPUT_ONLY); OCIO_CHECK_EQUAL(p->isAvoidDuplicates(), true); - OCIO_CHECK_EQUAL(p->isAssumeCommonReferenceSpace(), false); + OCIO_CHECK_EQUAL(p->isAdjustInputReferenceSpace(), true); OCIO_CHECK_EQUAL(std::string(p->getName()), std::string("my merge")); OCIO_CHECK_EQUAL(std::string(p->getDescription()), std::string("my desc")); @@ -252,10 +252,11 @@ OCIO_ADD_TEST(MergeConfigs, params_serialization) static constexpr char REF[] = ""; + "roles: PreferInput, file_rules: PreferBase, display-views: InputOnly, view_transforms: PreferBase, " + "looks: BaseOnly, colorspaces: Remove, named_transforms: PreferBase, " + "environment: [test=valueOther, test1=value123]>"; std::ostringstream oss; oss << *p; @@ -293,7 +294,7 @@ R"(ociom_version: 1.0 error_on_conflict: false default_strategy: InputOnly avoid_duplicates: true - assume_common_reference_space: false + adjust_input_reference_space: true overrides: name: my merge description: my desc @@ -311,6 +312,8 @@ R"(ociom_version: 1.0 strategy: PreferBase display-views: strategy: InputOnly + view_transforms: + strategy: PreferBase looks: strategy: BaseOnly colorspaces: @@ -356,7 +359,7 @@ OCIO_ADD_TEST(MergeConfigs, ociom_parser_no_overrides) // PreferInput OCIO_CHECK_EQUAL(p->getDefaultStrategy(), MergeStrategy::STRATEGY_INPUT_ONLY); OCIO_CHECK_EQUAL(p->isAvoidDuplicates(), true); - OCIO_CHECK_EQUAL(p->isAssumeCommonReferenceSpace(), false); + OCIO_CHECK_EQUAL(p->isAdjustInputReferenceSpace(), true); OCIO_CHECK_EQUAL(std::string(p->getName()), std::string("")); OCIO_CHECK_EQUAL(std::string(p->getDescription()), std::string("")); @@ -369,17 +372,12 @@ OCIO_ADD_TEST(MergeConfigs, ociom_parser_no_overrides) OCIO_CHECK_EQUAL(std::string(p->getActiveViews()), std::string("")); OCIO_CHECK_EQUAL(std::string(p->getInactiveColorSpaces()), std::string("")); - // PreferInput OCIO_CHECK_EQUAL(p->getRoles(), MergeStrategy::STRATEGY_PREFER_INPUT); - // PreferBase OCIO_CHECK_EQUAL(p->getFileRules(), MergeStrategy::STRATEGY_PREFER_BASE); - // InputOnly OCIO_CHECK_EQUAL(p->getDisplayViews(), MergeStrategy::STRATEGY_INPUT_ONLY); - // BaseOnly + OCIO_CHECK_EQUAL(p->getViewTransforms(), MergeStrategy::STRATEGY_PREFER_BASE); OCIO_CHECK_EQUAL(p->getLooks(), MergeStrategy::STRATEGY_BASE_ONLY); - // Remove OCIO_CHECK_EQUAL(p->getColorspaces(), MergeStrategy::STRATEGY_REMOVE); - // PreferBase OCIO_CHECK_EQUAL(p->getNamedTransforms(), MergeStrategy::STRATEGY_PREFER_BASE); } @@ -410,7 +408,7 @@ OCIO_ADD_TEST(MergeConfigs, overrides) merger->getParams(0)->addEnvironmentVar("OVR2", "VALUE2"); merger->getParams(0)->setActiveDisplays("OVR DISP 1,OVR DISP 2"); merger->getParams(0)->setActiveViews("OVR VIEW 1,OVR VIEW 2"); - merger->getParams(0)->setInactiveColorspaces("view_1, ACES2065-1"); + merger->getParams(0)->setInactiveColorSpaces("view_1, ACES2065-1"); return params; }; @@ -452,7 +450,6 @@ OCIO_ADD_TEST(MergeConfigs, overrides) }, "The Input config contains a value that would override the Base config: shared_views: SHARED_1", "The Input config contains a value that would override the Base config: display: DISP_1, view: VIEW_1", - "The Input config contains a value that would override the Base config: default_view_transform: Un-tone-mapped-2", "The Input config contains a value that would override the Base config: viewing_rules: RULE_1", "Color space 'ACES2065-1' will replace a color space in the base config.", "Color space 'view_1' will replace a color space in the base config."); @@ -477,7 +474,6 @@ OCIO_ADD_TEST(MergeConfigs, overrides) }, "The Input config contains a value that would override the Base config: shared_views: SHARED_1", "The Input config contains a value that would override the Base config: display: DISP_1, view: VIEW_1", - "The Input config contains a value that would override the Base config: default_view_transform: Un-tone-mapped-2", "The Input config contains a value that would override the Base config: viewing_rules: RULE_1", "Color space 'ACES2065-1' was not merged as it's already present in the base config.", "Color space 'view_1' was not merged as it's already present in the base config."); @@ -936,7 +932,7 @@ OCIO_ADD_TEST(MergeConfigs, file_rules_section) OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); merger->addParams(params); merger->getParams(0)->setFileRules(strategy); - merger->getParams(0)->setAssumeCommonReferenceSpace(true); + merger->getParams(0)->setAdjustInputReferenceSpace(false); merger->getParams(0)->setAvoidDuplicates(false); return params; @@ -1463,8 +1459,6 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), "SHARED_1, SHARED_3, VIEW_1, VIEW_3"); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "Un-tone-mapped-2"); - // Validate shared_views OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, nullptr), 2); OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 0)), "SHARED_1"); @@ -1493,11 +1487,6 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3", 0)), "VIEW_1"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3", 1)), "VIEW_3"); - // Validate view_transforms - OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 2); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped-2"); - // Validate viewing_rules OCIO::ConstViewingRulesRcPtr rules = mergedConfig->getViewingRules(); @@ -1533,16 +1522,12 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) [&options]() { OCIO::DisplayViewMerger(options).merge(); }, "The Input config contains a value that would override the Base config: shared_views: SHARED_1", "The Input config contains a value that would override the Base config: display: DISP_1, view: VIEW_1", - "The Input config contains a value that would override the Base config: default_view_transform: Un-tone-mapped-2", "The Input config contains a value that would override the Base config: viewing_rules: RULE_1"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_1, DISP_3, DISP_2"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), "SHARED_1, SHARED_3, VIEW_1, VIEW_3, SHARED_2, VIEW_2"); - // Validate default_view_transform - OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "Un-tone-mapped-2"); - // Validate shared_views OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, nullptr), 3); OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 0)), "SHARED_1"); @@ -1582,20 +1567,6 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2", 0)), "VIEW_1"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2", 1)), "VIEW_2"); - // Validate view_transforms - - OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 3); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); - OCIO::ConstTransformRcPtr tf; - OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") - ->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE)); - auto bi = OCIO_DYNAMIC_POINTER_CAST(tf); - OCIO_REQUIRE_ASSERT(bi); - OCIO_CHECK_EQUAL(std::string(bi->getStyle()), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1"); - - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped-2"); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), "Un-tone-mapped"); - // Validate viewing_rules OCIO::ConstViewingRulesRcPtr rules = mergedConfig->getViewingRules(); @@ -1637,15 +1608,12 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) [&options]() { OCIO::DisplayViewMerger(options).merge(); }, "The Input config contains a value that would override the Base config: shared_views: SHARED_1", "The Input config contains a value that would override the Base config: display: DISP_1, view: VIEW_1", - "The Input config contains a value that would override the Base config: default_view_transform: Un-tone-mapped-2", "The Input config contains a value that would override the Base config: viewing_rules: RULE_1"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_1, DISP_2, DISP_3"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), "SHARED_1, SHARED_2, VIEW_1, VIEW_2, SHARED_3, VIEW_3"); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "Un-tone-mapped-2"); - // Validate shared_views OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, nullptr), 3); OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 0)), "SHARED_1"); @@ -1686,20 +1654,6 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3", 1)), "VIEW_3"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewLooks("DISP_3", "VIEW_3")), "look_input"); - // Validate view_transforms - - OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 3); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), std::string("SDR Video")); - OCIO::ConstTransformRcPtr tf; - OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") - ->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE)); - auto bi = OCIO_DYNAMIC_POINTER_CAST(tf); - OCIO_REQUIRE_ASSERT(bi); - OCIO_CHECK_EQUAL(std::string(bi->getStyle()), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1"); - - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), std::string("Un-tone-mapped")); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), std::string("Un-tone-mapped-2")); - // Validate viewing_rules OCIO::ConstViewingRulesRcPtr rules = mergedConfig->getViewingRules(); @@ -1741,15 +1695,12 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) [&options]() { OCIO::DisplayViewMerger(options).merge(); }, "The Input config contains a value that would override the Base config: shared_views: SHARED_1", "The Input config contains a value that would override the Base config: display: DISP_1, view: VIEW_1", - "The Input config contains a value that would override the Base config: default_view_transform: Un-tone-mapped-2", "The Input config contains a value that would override the Base config: viewing_rules: RULE_1"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_1, DISP_3, DISP_2"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), "SHARED_1, SHARED_3, VIEW_1, VIEW_3, SHARED_2, VIEW_2"); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "SDR Video"); - // Validate shared_views OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, nullptr), 3); OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 0)), "SHARED_1"); @@ -1792,20 +1743,6 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2", 1)), "VIEW_2"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewLooks("DISP_2", "VIEW_2")), "look_base"); - // Validate view_transforms - - OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 3); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); - OCIO::ConstTransformRcPtr tf; - OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") - ->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE)); - auto bi = OCIO_DYNAMIC_POINTER_CAST(tf); - OCIO_REQUIRE_ASSERT(bi); - OCIO_CHECK_EQUAL(std::string(bi->getStyle()), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO_1.0"); - - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped-2"); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), "Un-tone-mapped"); - // Validate viewing_rules OCIO::ConstViewingRulesRcPtr rules = mergedConfig->getViewingRules(); @@ -1847,15 +1784,12 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) [&options]() { OCIO::DisplayViewMerger(options).merge(); }, "The Input config contains a value that would override the Base config: shared_views: SHARED_1", "The Input config contains a value that would override the Base config: display: DISP_1, view: VIEW_1", - "The Input config contains a value that would override the Base config: default_view_transform: Un-tone-mapped-2", "The Input config contains a value that would override the Base config: viewing_rules: RULE_1"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_1, DISP_2, DISP_3"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), "SHARED_1, SHARED_2, VIEW_1, VIEW_2, SHARED_3, VIEW_3"); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "SDR Video"); - // Validate shared_views OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, nullptr), 3); OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 0)), "SHARED_1"); @@ -1898,20 +1832,6 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3", 1)), "VIEW_3"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewLooks("DISP_3", "VIEW_3")), "look_input"); - // Validate view_transforms - - OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 3); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); - OCIO::ConstTransformRcPtr tf; - OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") - ->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE)); - auto bi = OCIO_DYNAMIC_POINTER_CAST(tf); - OCIO_REQUIRE_ASSERT(bi); - OCIO_CHECK_EQUAL(std::string(bi->getStyle()), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO_1.0"); - - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped"); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), "Un-tone-mapped-2"); - // Validate viewing_rules OCIO::ConstViewingRulesRcPtr rules = mergedConfig->getViewingRules(); @@ -1954,8 +1874,6 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), "SHARED_1, SHARED_2, VIEW_1, VIEW_2"); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "SDR Video"); - // Validate shared_views OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, nullptr), 2); OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 0)), "SHARED_1"); @@ -1988,11 +1906,6 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2", 1)), "VIEW_2"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewLooks("DISP_2", "VIEW_2")), "look_base"); - // Validate view_transforms - OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 2); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped"); - // Validate viewing_rules OCIO::ConstViewingRulesRcPtr rules = mergedConfig->getViewingRules(); @@ -2028,8 +1941,6 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), "SHARED_1, SHARED_3, VIEW_1, VIEW_3"); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "Un-tone-mapped-2"); - // Validate shared_views OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, nullptr), 2); OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 0)), "SHARED_1"); @@ -2060,19 +1971,6 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_3", 1)), "VIEW_3"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewLooks("DISP_3", "VIEW_3")), "look_input"); - // Validate view_transforms - - OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 2); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); - OCIO::ConstTransformRcPtr tf; - OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") - ->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE)); - auto bi = OCIO_DYNAMIC_POINTER_CAST(tf); - OCIO_REQUIRE_ASSERT(bi); - OCIO_CHECK_EQUAL(std::string(bi->getStyle()), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1"); - - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped-2"); - // Validate viewing_rules OCIO::ConstViewingRulesRcPtr rules = mergedConfig->getViewingRules(); @@ -2108,10 +2006,6 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveDisplays()), "DISP_2"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getActiveViews()), "SHARED_2, VIEW_2"); - // Note that the "SDR Video" view transform was removed, so the "SDR Video" value - // of the default view transform was reset to empty (will use the first one by default). - OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), ""); - // Validate shared_views OCIO_CHECK_EQUAL(mergedConfig->getNumViews(OCIO::VIEW_SHARED, nullptr), 1); OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_SHARED, nullptr, 0)), "SHARED_2"); @@ -2134,10 +2028,6 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) OCIO_CHECK_EQUAL(std::string(mergedConfig->getView(OCIO::VIEW_DISPLAY_DEFINED, "DISP_2", 1)), "VIEW_2"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getDisplayViewLooks("DISP_2", "VIEW_2")), "look_base"); - // Validate view_transforms - OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 1); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), std::string("Un-tone-mapped")); - // Validate viewing_rules OCIO::ConstViewingRulesRcPtr rules = mergedConfig->getViewingRules(); OCIO_CHECK_EQUAL(rules->getNumEntries(), 1); @@ -2153,8 +2043,6 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) OCIO_CHECK_EQUAL(mergedConfig->getVirtualDisplayView(OCIO::VIEW_SHARED, 0), std::string("SHARED_1")); } - constexpr char PREFIX[] { "The Input config contains a value that would override the Base config: " }; - // Test that error_on_conflicts is processed correctly. // strategy = PreferInput, InputFirst = false { @@ -2167,21 +2055,262 @@ OCIO_ADD_TEST(MergeConfigs, displays_views_section) merger->getParams(0)->setInputFirst(false); merger->getParams(0)->setErrorOnConflict(true); - // Test that an error is thrown when the input config's COLORSPACE is different + constexpr char PREFIX[] { "The Input config contains a value that would override the Base config: " }; + + // Test that an error is thrown when the input config values are different. { OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_ERROR, __LINE__, [&options]() { OCIO::DisplayViewMerger(options).merge(); }, std::string(PREFIX) + std::string("shared_views: SHARED_1"), std::string(PREFIX) + std::string("display: DISP_1, views: VIEW_1"), - std::string(PREFIX) + std::string("default_view_transform: SDR Video"), - std::string(PREFIX) + std::string("view_transforms: SDR Video"), std::string(PREFIX) + std::string("viewing_rules: RULE_1"), std::string(PREFIX) + std::string("virtual_display: ACES")); } } } +OCIO_ADD_TEST(MergeConfigs, view_transforms_section) +{ + OCIO::ConstConfigRcPtr baseConfig; + OCIO_CHECK_NO_THROW(baseConfig = getBaseConfig()); + + OCIO::ConstConfigRcPtr inputConfig; + OCIO_CHECK_NO_THROW(inputConfig = getInputConfig()); + + auto setupBasics = [](OCIO::ConfigMergerRcPtr & merger, MergeStrategy strategy) -> OCIO::ConfigMergingParametersRcPtr + { + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + merger->addParams(params); + merger->getParams(0)->setViewTransforms(strategy); + return params; + }; + + // Allowed strategies: All + // Allowed merge options: All + + // Test that the default strategy is used as a fallback if the section strategy was not defined. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + + // Using STRATEGY_UNSPECIFIED as this simulates that the section + // is missing from the OCIOM file. + auto params = setupBasics(merger, MergeStrategy::STRATEGY_UNSPECIFIED); + // Simulate settings from OCIOM file. + merger->getParams(0)->setDefaultStrategy(MergeStrategy::STRATEGY_INPUT_ONLY); + merger->getParams(0)->setInputFirst(true); + + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ViewTransformsMerger(options).merge(); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "Un-tone-mapped-2"); + + // Validate view_transforms + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped-2"); + } + + // Test display/views with strategy = PreferInput, options InputFirst = true. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(true); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ViewTransformsMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: default_view_transform: Un-tone-mapped-2" + ); + + // Validate default_view_transform + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "Un-tone-mapped-2"); + + // Validate view_transforms + + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); + OCIO::ConstTransformRcPtr tf; + OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") + ->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE)); + auto bi = OCIO_DYNAMIC_POINTER_CAST(tf); + OCIO_REQUIRE_ASSERT(bi); + OCIO_CHECK_EQUAL(std::string(bi->getStyle()), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped-2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), "Un-tone-mapped"); + } + + // Test display/views with strategy=PreferInput, options InputFirst = false. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ViewTransformsMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: default_view_transform: Un-tone-mapped-2" + ); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "Un-tone-mapped-2"); + + // Validate view_transforms + + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), std::string("SDR Video")); + OCIO::ConstTransformRcPtr tf; + OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") + ->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE)); + auto bi = OCIO_DYNAMIC_POINTER_CAST(tf); + OCIO_REQUIRE_ASSERT(bi); + OCIO_CHECK_EQUAL(std::string(bi->getStyle()), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), std::string("Un-tone-mapped")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), std::string("Un-tone-mapped-2")); + } + + // Test display/views with strategy = PreferBase, options InputFirst = true. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(true); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ViewTransformsMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: default_view_transform: Un-tone-mapped-2" + ); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "SDR Video"); + + // Validate view_transforms + + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); + OCIO::ConstTransformRcPtr tf; + OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") + ->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE)); + auto bi = OCIO_DYNAMIC_POINTER_CAST(tf); + OCIO_REQUIRE_ASSERT(bi); + OCIO_CHECK_EQUAL(std::string(bi->getStyle()), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO_1.0"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped-2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), "Un-tone-mapped"); + } + + // Test display/views with strategy = PreferBase, options InputFirst = false. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_PREFER_BASE); + merger->getParams(0)->setInputFirst(false); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_WARNING, __LINE__, + [&options]() { OCIO::ViewTransformsMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: default_view_transform: Un-tone-mapped-2" + ); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "SDR Video"); + + // Validate view_transforms + + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 3); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); + OCIO::ConstTransformRcPtr tf; + OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") + ->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE)); + auto bi = OCIO_DYNAMIC_POINTER_CAST(tf); + OCIO_REQUIRE_ASSERT(bi); + OCIO_CHECK_EQUAL(std::string(bi->getStyle()), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO_1.0"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), "Un-tone-mapped-2"); + } + + // Test display/views with strategy = BaseOnly. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_BASE_ONLY); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ViewTransformsMerger(options).merge(); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "SDR Video"); + + // Validate view_transforms + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped"); + } + + // Test display/views with strategy = InputOnly. + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_INPUT_ONLY); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ViewTransformsMerger(options).merge(); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "Un-tone-mapped-2"); + + // Validate view_transforms + + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 2); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); + OCIO::ConstTransformRcPtr tf; + OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") + ->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE)); + auto bi = OCIO_DYNAMIC_POINTER_CAST(tf); + OCIO_REQUIRE_ASSERT(bi); + OCIO_CHECK_EQUAL(std::string(bi->getStyle()), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1"); + + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped-2"); + } + + // Test display/views with strategy = Remove + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + auto params = setupBasics(merger, MergeStrategy::STRATEGY_REMOVE); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + OCIO::ViewTransformsMerger(options).merge(); + + // Note that the "SDR Video" view transform was removed, so the "SDR Video" value + // of the default view transform was reset to empty (will use the first one by default). + OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), ""); + + // Validate view_transforms + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 1); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), std::string("Un-tone-mapped")); + } + + // Test that error_on_conflicts is processed correctly. + // strategy = PreferInput, InputFirst = false + { + OCIO::ConfigMergerRcPtr merger = OCIO::ConfigMerger::Create(); + OCIO::ConfigRcPtr mergedConfig = baseConfig->createEditableCopy(); + + OCIO::ConfigMergingParametersRcPtr params = OCIO::ConfigMergingParameters::Create(); + merger->addParams(params); + merger->getParams(0)->setViewTransforms(MergeStrategy::STRATEGY_PREFER_INPUT); + merger->getParams(0)->setInputFirst(false); + merger->getParams(0)->setErrorOnConflict(true); + + constexpr char PREFIX[] { "The Input config contains a value that would override the Base config: " }; + + // Test that an error is thrown when the the input values are different. + { + OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; + checkForLogOrException(LOG_TYPE_ERROR, __LINE__, + [&options]() { OCIO::ViewTransformsMerger(options).merge(); }, + std::string(PREFIX) + std::string("default_view_transform: Un-tone-mapped-2"), + std::string(PREFIX) + std::string("view_transforms: SDR Video")); + } + } +} + OCIO_ADD_TEST(MergeConfigs, colorspaces_section) { OCIO::ConstConfigRcPtr baseConfig; @@ -2200,7 +2329,7 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section) merger->getParams(0)->setInputFamilyPrefix("Input/"); merger->getParams(0)->setBaseFamilyPrefix("Base/"); - merger->getParams(0)->setAssumeCommonReferenceSpace(true); + merger->getParams(0)->setAdjustInputReferenceSpace(false); merger->getParams(0)->setAvoidDuplicates(false); return params; @@ -2616,7 +2745,7 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section_common_reference_and_duplicates) merger->getParams(0)->setInputFamilyPrefix("Input/"); merger->getParams(0)->setBaseFamilyPrefix("Base/"); - merger->getParams(0)->setAssumeCommonReferenceSpace(false); + merger->getParams(0)->setAdjustInputReferenceSpace(true); merger->getParams(0)->setAvoidDuplicates(true); return params; @@ -2633,6 +2762,7 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section_common_reference_and_duplicates) checkForLogOrException(LOG_TYPE_WARNING, __LINE__, [&options]() { OCIO::RolesMerger(options).merge(); OCIO::DisplayViewMerger(options).merge(); + OCIO::ViewTransformsMerger(options).merge(); OCIO::ColorspacesMerger(options).merge(); }, "Equivalent input color space 'sRGB - Display' replaces 'sRGB - Display' in the base config, preserving aliases.", "Equivalent input color space 'CIE-XYZ-D65' replaces 'CIE-XYZ-D65' in the base config, preserving aliases.", @@ -2812,6 +2942,7 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section_common_reference_and_duplicates) checkForLogOrException(LOG_TYPE_WARNING, __LINE__, [&options]() { OCIO::RolesMerger(options).merge(); OCIO::DisplayViewMerger(options).merge(); + OCIO::ViewTransformsMerger(options).merge(); OCIO::ColorspacesMerger(options).merge(); }, "Equivalent base color space 'sRGB - Display' overrides 'sRGB - Display' in the input config, preserving aliases.", "Equivalent base color space 'CIE-XYZ-D65' overrides 'CIE-XYZ-D65' in the input config, preserving aliases.", @@ -2961,7 +3092,7 @@ OCIO_ADD_TEST(MergeConfigs, colorspaces_section_errors) merger->getParams(0)->setInputFamilyPrefix("Input/"); merger->getParams(0)->setBaseFamilyPrefix("Base/"); - merger->getParams(0)->setAssumeCommonReferenceSpace(true); + merger->getParams(0)->setAdjustInputReferenceSpace(false); merger->getParams(0)->setAvoidDuplicates(false); return params; @@ -4063,7 +4194,7 @@ OCIO_ADD_TEST(MergeConfigs, looks_section) MergeStrategy::STRATEGY_PREFER_INPUT, [](OCIO::ConfigMergerRcPtr & merger) { - merger->getParams(0)->setAssumeCommonReferenceSpace(true); + merger->getParams(0)->setAdjustInputReferenceSpace(false); }); OCIO_CHECK_EQUAL(mergedConfig->getNumLooks(), 3); @@ -4090,7 +4221,7 @@ OCIO_ADD_TEST(MergeConfigs, looks_section) [](OCIO::ConfigMergerRcPtr & merger) { merger->getParams(0)->setInputFirst(false); - merger->getParams(0)->setAssumeCommonReferenceSpace(true); + merger->getParams(0)->setAdjustInputReferenceSpace(false); }); OCIO_CHECK_EQUAL(mergedConfig->getNumLooks(), 3); @@ -4116,7 +4247,7 @@ OCIO_ADD_TEST(MergeConfigs, looks_section) [](OCIO::ConfigMergerRcPtr & merger) { merger->getParams(0)->setInputFirst(true); - merger->getParams(0)->setAssumeCommonReferenceSpace(true); + merger->getParams(0)->setAdjustInputReferenceSpace(false); }); OCIO_CHECK_EQUAL(mergedConfig->getNumLooks(), 3); @@ -4142,7 +4273,7 @@ OCIO_ADD_TEST(MergeConfigs, looks_section) [](OCIO::ConfigMergerRcPtr & merger) { merger->getParams(0)->setInputFirst(false); - merger->getParams(0)->setAssumeCommonReferenceSpace(true); + merger->getParams(0)->setAdjustInputReferenceSpace(false); }); OCIO_CHECK_EQUAL(mergedConfig->getNumLooks(), 3); @@ -4235,7 +4366,7 @@ OCIO_ADD_TEST(MergeConfigs, named_transform_section) merger->getParams(0)->setInputFamilyPrefix("Input/"); merger->getParams(0)->setBaseFamilyPrefix("Base/"); - merger->getParams(0)->setAssumeCommonReferenceSpace(true); + merger->getParams(0)->setAdjustInputReferenceSpace(false); merger->getParams(0)->setAvoidDuplicates(true); merger->getParams(0)->setInputFirst(true); @@ -4561,7 +4692,7 @@ OCIO_ADD_TEST(MergeConfigs, named_transform_section_errors) merger->getParams(0)->setInputFamilyPrefix("Input/"); merger->getParams(0)->setBaseFamilyPrefix("Base/"); - merger->getParams(0)->setAssumeCommonReferenceSpace(true); + merger->getParams(0)->setAdjustInputReferenceSpace(false); merger->getParams(0)->setAvoidDuplicates(false); return params; @@ -5678,7 +5809,7 @@ OCIO_ADD_TEST(MergeConfigs, merges_with_ociom_file) OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); OCIO::ConstConfigMergerRcPtr newMerger; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&newMerger, &merger]() { newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); }, + [&newMerger, &merger]() { newMerger = merger->mergeConfigs(); }, "The Input config contains a value that would override the Base config: file_rules: Default", "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", "Equivalent input color space 'sRGB - Display' replaces 'sRGB - Display' in the base config, preserving aliases.", @@ -5715,7 +5846,7 @@ OCIO_ADD_TEST(MergeConfigs, merges_with_ociom_file) OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); OCIO::ConstConfigMergerRcPtr newMerger; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&newMerger, &merger]() { newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); }, + [&newMerger, &merger]() { newMerger = merger->mergeConfigs(); }, "The Input config contains a value that would override the Base config: file_rules: Default", "The Input config contains a role that would override Base config role 'cie_xyz_d65_interchange'", "Color space 'sRGB - Display' was not merged as it's already present in the base config", @@ -5723,6 +5854,9 @@ OCIO_ADD_TEST(MergeConfigs, merges_with_ociom_file) "Merged color space 'ACES2065-1' has a conflict with alias 'aces' in color space 'ACEScg'", "Color space 'sRGB' was not merged as it conflicts with an alias in color space 'sRGB - Texture'", "Equivalent base color space 'ap0' overrides 'rec709' in the input config, preserving aliases"); + + OCIO_CHECK_EQUAL(newMerger->getNumMergedConfigs(), 2); + OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); OCIO_CHECK_NO_THROW(mergedConfig->validate()); @@ -5781,7 +5915,7 @@ OCIO_ADD_TEST(MergeConfigs, merges_with_ociom_file) OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); OCIO::ConstConfigMergerRcPtr newMerger; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, - [&newMerger, &merger]() { newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); }, + [&newMerger, &merger]() { newMerger = merger->mergeConfigs(); }, "Color space 'raw' will replace a color space in the base config."); OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); OCIO_CHECK_NO_THROW(mergedConfig->validate()); @@ -5820,7 +5954,7 @@ OCIO_ADD_TEST(MergeConfigs, merges_with_ociom_file) merger->getParams(0)->setColorspaces(OCIO::ConfigMergingParameters::STRATEGY_INPUT_ONLY); // The rest of the merges uses PreferInput strategy. - OCIO::ConstConfigMergerRcPtr newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); + OCIO::ConstConfigMergerRcPtr newMerger = merger->mergeConfigs(); OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); OCIO_CHECK_ASSERT(!mergedConfig->getConfigIOProxy()); @@ -5851,7 +5985,7 @@ OCIO_ADD_TEST(MergeConfigs, merges_with_ociom_file) // InputOnly { OCIO::ConstConfigMergerRcPtr merger = OCIO::ConfigMerger::CreateFromFile(ociomPath.c_str()); - OCIO::ConstConfigMergerRcPtr newMerger = OCIO::ConfigMergingHelpers::MergeConfigs(merger); + OCIO::ConstConfigMergerRcPtr newMerger = merger->mergeConfigs(); OCIO::ConstConfigRcPtr mergedConfig = newMerger->getMergedConfig(); OCIO_CHECK_NO_THROW(mergedConfig->validate()); @@ -5899,7 +6033,7 @@ OCIO_ADD_TEST(MergeConfigs, merges_with_ocioz_file) params->setDefaultStrategy(strategy); params->setInputFamilyPrefix("Input/"); params->setBaseFamilyPrefix("Base/"); - params->setAssumeCommonReferenceSpace(true); + params->setAdjustInputReferenceSpace(false); params->setAvoidDuplicates(false); { @@ -6058,7 +6192,7 @@ R"(ocio_profile_version: 2.1 params->setDefaultStrategy(strategy); params->setInputFamilyPrefix("Input/"); params->setBaseFamilyPrefix("Base/"); - params->setAssumeCommonReferenceSpace(true); + params->setAdjustInputReferenceSpace(false); params->setAvoidDuplicates(false); OCIO::ConfigRcPtr mergedConfig; @@ -6161,7 +6295,7 @@ active_views: [] params->setDefaultStrategy(strategy); params->setInputFamilyPrefix("Input/"); params->setBaseFamilyPrefix("Base/"); - params->setAssumeCommonReferenceSpace(true); + params->setAdjustInputReferenceSpace(false); params->setAvoidDuplicates(false); OCIO::ConfigRcPtr mergedConfig = OCIO::ConfigMergingHelpers::MergeColorSpace(params, baseConfig, colorspace); diff --git a/tests/data/files/configs/mergeconfigs/merged1/merged1.ociom b/tests/data/files/configs/mergeconfigs/merged1/merged1.ociom index a578e8adcd..a9768deac1 100644 --- a/tests/data/files/configs/mergeconfigs/merged1/merged1.ociom +++ b/tests/data/files/configs/mergeconfigs/merged1/merged1.ociom @@ -12,7 +12,7 @@ merge: error_on_conflict: false default_strategy: PreferInput avoid_duplicates: true - assume_common_reference_space: false + adjust_input_reference_space: true overrides: name: Merged1 description: Basic merge with default strategy diff --git a/tests/data/files/configs/mergeconfigs/merged2/merged.ociom b/tests/data/files/configs/mergeconfigs/merged2/merged.ociom index 3c4a9390f8..18970fb330 100644 --- a/tests/data/files/configs/mergeconfigs/merged2/merged.ociom +++ b/tests/data/files/configs/mergeconfigs/merged2/merged.ociom @@ -13,7 +13,7 @@ merge: error_on_conflict: false default_strategy: PreferBase avoid_duplicates: true - assume_common_reference_space: true + adjust_input_reference_space: false overrides: name: Merged1 description: Basic merge with default strategy @@ -32,7 +32,7 @@ merge: error_on_conflict: false default_strategy: BaseOnly avoid_duplicates: true - assume_common_reference_space: true + adjust_input_reference_space: false overrides: name: Merged2 description: Description override diff --git a/tests/data/files/configs/mergeconfigs/merged3/merged.ociom b/tests/data/files/configs/mergeconfigs/merged3/merged.ociom index 64fd4e43c4..90f706e8e0 100644 --- a/tests/data/files/configs/mergeconfigs/merged3/merged.ociom +++ b/tests/data/files/configs/mergeconfigs/merged3/merged.ociom @@ -14,7 +14,7 @@ merge: error_on_conflict: false default_strategy: PreferInput avoid_duplicates: false - assume_common_reference_space: true + adjust_input_reference_space: false overrides: name: Merged1 description: Basic merge with default strategy diff --git a/tests/data/files/configs/mergeconfigs/merged4/merged.ociom b/tests/data/files/configs/mergeconfigs/merged4/merged.ociom index 14cf8606bc..76248cacd1 100644 --- a/tests/data/files/configs/mergeconfigs/merged4/merged.ociom +++ b/tests/data/files/configs/mergeconfigs/merged4/merged.ociom @@ -12,7 +12,7 @@ merge: error_on_conflict: false default_strategy: InputOnly avoid_duplicates: true - assume_common_reference_space: false + adjust_input_reference_space: true overrides: name: "" description: "" diff --git a/tests/data/files/configs/mergeconfigs/parser_test.ociom b/tests/data/files/configs/mergeconfigs/parser_test.ociom index b41b7c3953..7e8dbf0113 100644 --- a/tests/data/files/configs/mergeconfigs/parser_test.ociom +++ b/tests/data/files/configs/mergeconfigs/parser_test.ociom @@ -14,7 +14,7 @@ merge: error_on_conflict: false default_strategy: InputOnly avoid_duplicates: true - assume_common_reference_space: false + adjust_input_reference_space: true overrides: name: my merge description: my desc @@ -33,10 +33,13 @@ merge: strategy: PreferBase display-views: - # Includes shared_views, displays, view_transforms, viewing_rules, virtual_display, - # active_display, active_views and default_view_transform. + # Includes shared_views, displays, viewing_rules, virtual_display, + # active_display, and active_views. strategy: InputOnly + view_transforms: + strategy: PreferBase + looks: strategy: BaseOnly diff --git a/tests/data/files/configs/mergeconfigs/parser_test_no_overrides.ociom b/tests/data/files/configs/mergeconfigs/parser_test_no_overrides.ociom index 37cf5d3855..db1c9fd9da 100644 --- a/tests/data/files/configs/mergeconfigs/parser_test_no_overrides.ociom +++ b/tests/data/files/configs/mergeconfigs/parser_test_no_overrides.ociom @@ -12,7 +12,7 @@ merge: error_on_conflict: false default_strategy: InputOnly avoid_duplicates: true - assume_common_reference_space: false + adjust_input_reference_space: true # If no overrides are needed, the overrides can be # removed from the file or initialized as follows: # overrides: @@ -31,10 +31,13 @@ merge: strategy: PreferBase display-views: - # Includes shared_views, displays, view_transforms, viewing_rules, virtual_display, - # active_display, active_views and default_view_transform. + # Includes shared_views, displays, viewing_rules, virtual_display, + # active_display, and active_views. strategy: InputOnly + view_transforms: + strategy: PreferBase + looks: strategy: BaseOnly diff --git a/tests/python/MergeConfigsTest.py b/tests/python/MergeConfigsTest.py new file mode 100644 index 0000000000..3044ac5215 --- /dev/null +++ b/tests/python/MergeConfigsTest.py @@ -0,0 +1,249 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright Contributors to the OpenColorIO Project. + +import unittest + +import PyOpenColorIO as OCIO + +from UnitTestUtils import (TEST_DATAFILES_DIR, MuteLogging) + +class ConfigMergingHelpersTest(unittest.TestCase): + + def test_ConfigMergingParameters_defaults(self): + + params = OCIO.ConfigMergingParameters.Create() + self.assertIsInstance(params, OCIO.ConfigMergingParameters) + self.assertEqual(params.getBaseConfigName(), "") + self.assertEqual(params.getInputConfigName(), "") + self.assertEqual(params.getOutputName(), "merged") + self.assertEqual(params.getDefaultStrategy(), OCIO.ConfigMergingParameters.STRATEGY_PREFER_INPUT) + self.assertEqual(params.getInputFamilyPrefix(), "") + self.assertEqual(params.getBaseFamilyPrefix(), "") + self.assertTrue(params.isInputFirst()) + self.assertFalse(params.isErrorOnConflict()) + self.assertTrue(params.isAvoidDuplicates()) + self.assertTrue(params.isAdjustInputReferenceSpace()) + self.assertEqual(params.getName(), "") + self.assertEqual(params.getDescription(), "") + self.assertEqual(params.getNumEnvironmentVars(), 0) + self.assertEqual(params.getSearchPath(), "") + self.assertEqual(params.getActiveDisplays(), "") + self.assertEqual(params.getActiveViews(), "") + self.assertEqual(params.getInactiveColorSpaces(), "") + self.assertEqual(params.getRoles(), OCIO.ConfigMergingParameters.STRATEGY_PREFER_INPUT) + self.assertEqual(params.getFileRules(), OCIO.ConfigMergingParameters.STRATEGY_PREFER_INPUT) + self.assertEqual(params.getDisplayViews(), OCIO.ConfigMergingParameters.STRATEGY_PREFER_INPUT) + self.assertEqual(params.getViewTransforms(), OCIO.ConfigMergingParameters.STRATEGY_PREFER_INPUT) + self.assertEqual(params.getLooks(), OCIO.ConfigMergingParameters.STRATEGY_PREFER_INPUT) + self.assertEqual(params.getColorspaces(), OCIO.ConfigMergingParameters.STRATEGY_PREFER_INPUT) + self.assertEqual(params.getNamedTransforms(), OCIO.ConfigMergingParameters.STRATEGY_PREFER_INPUT) + + def test_ConfigMergingParameters_setters(self): + + params = OCIO.ConfigMergingParameters.Create() + params.setBaseConfigName("base") + self.assertEqual(params.getBaseConfigName(), "base") + params.setInputConfigName("input") + self.assertEqual(params.getInputConfigName(), "input") + params.setOutputName("merged") + self.assertEqual(params.getOutputName(), "merged") + params.setDefaultStrategy(OCIO.ConfigMergingParameters.STRATEGY_PREFER_BASE) + self.assertEqual(params.getDefaultStrategy(), OCIO.ConfigMergingParameters.STRATEGY_PREFER_BASE) + params.setInputFamilyPrefix("iprefix") + self.assertEqual(params.getInputFamilyPrefix(), "iprefix") + params.setBaseFamilyPrefix("bprefix") + self.assertEqual(params.getBaseFamilyPrefix(), "bprefix") + params.setInputFirst(False) + self.assertFalse(params.isInputFirst()) + params.setErrorOnConflict(True) + self.assertTrue(params.isErrorOnConflict()) + params.setAvoidDuplicates(False) + self.assertFalse(params.isAvoidDuplicates()) + params.setAdjustInputReferenceSpace(False) + self.assertFalse(params.isAdjustInputReferenceSpace()) + params.setName("name") + self.assertEqual(params.getName(), "name") + params.setDescription("desc") + self.assertEqual(params.getDescription(), "desc") + params.addEnvironmentVar("var1", "value 1") + self.assertEqual(params.getNumEnvironmentVars(), 1) + self.assertEqual(params.getEnvironmentVar(0), "var1") + self.assertEqual(params.getEnvironmentVarValue(0), "value 1") + params.addEnvironmentVar("var2", "value 2") + self.assertEqual(params.getNumEnvironmentVars(), 2) + self.assertEqual(params.getEnvironmentVar(1), "var2") + self.assertEqual(params.getEnvironmentVarValue(1), "value 2") + params.setSearchPath("path1:path2") + self.assertEqual(params.getSearchPath(), "path1:path2") + params.addSearchPath("path3:path4") + self.assertEqual(params.getSearchPath(), "path1:path2:path3:path4") + params.setActiveDisplays("disp1, disp2") + self.assertEqual(params.getActiveDisplays(), "disp1, disp2") + params.setActiveViews("view1, view2") + self.assertEqual(params.getActiveViews(), "view1, view2") + params.setInactiveColorSpaces("cs1, cs2, cs3") + self.assertEqual(params.getInactiveColorSpaces(), "cs1, cs2, cs3") + params.setRoles(OCIO.ConfigMergingParameters.STRATEGY_PREFER_BASE) + self.assertEqual(params.getRoles(), OCIO.ConfigMergingParameters.STRATEGY_PREFER_BASE) + params.setFileRules(OCIO.ConfigMergingParameters.STRATEGY_PREFER_BASE) + self.assertEqual(params.getFileRules(), OCIO.ConfigMergingParameters.STRATEGY_PREFER_BASE) + params.setDisplayViews(OCIO.ConfigMergingParameters.STRATEGY_INPUT_ONLY) + self.assertEqual(params.getDisplayViews(), OCIO.ConfigMergingParameters.STRATEGY_INPUT_ONLY) + params.setViewTransforms(OCIO.ConfigMergingParameters.STRATEGY_BASE_ONLY) + self.assertEqual(params.getViewTransforms(), OCIO.ConfigMergingParameters.STRATEGY_BASE_ONLY) + params.setLooks(OCIO.ConfigMergingParameters.STRATEGY_BASE_ONLY) + self.assertEqual(params.getLooks(), OCIO.ConfigMergingParameters.STRATEGY_BASE_ONLY) + params.setColorspaces(OCIO.ConfigMergingParameters.STRATEGY_REMOVE) + self.assertEqual(params.getColorspaces(), OCIO.ConfigMergingParameters.STRATEGY_REMOVE) + params.setNamedTransforms(OCIO.ConfigMergingParameters.STRATEGY_PREFER_BASE) + self.assertEqual(params.getNamedTransforms(), OCIO.ConfigMergingParameters.STRATEGY_PREFER_BASE) + + def test_ConfigMerger_defaults(self): + + merger = OCIO.ConfigMerger.Create() + self.assertEqual(merger.getNumSearchPaths(), 0) + self.assertEqual(merger.getWorkingDir(), "") + self.assertEqual(merger.getNumConfigMergingParameters(), 0) + self.assertEqual(merger.getMajorVersion(), 1) + self.assertEqual(merger.getMinorVersion(), 0) + + def test_ConfigMerger_setters(self): + + merger = OCIO.ConfigMerger.Create() + merger.setSearchPath("/var/tmp") + self.assertEqual(merger.getNumSearchPaths(), 1) + self.assertEqual(merger.getSearchPath(0), "/var/tmp") + merger.addSearchPath("/usr/local") + self.assertEqual(merger.getNumSearchPaths(), 2) + self.assertEqual(merger.getSearchPath(1), "/usr/local") + merger.setSearchPath("/var/tmp") + self.assertEqual(merger.getNumSearchPaths(), 1) + self.assertEqual(merger.getSearchPath(0), "/var/tmp") + + merger.setWorkingDir("/var/tmp") + self.assertEqual(merger.getWorkingDir(), "/var/tmp") + self.assertEqual(merger.getNumConfigMergingParameters(), 0) + self.assertEqual(merger.getMajorVersion(), 1) + self.assertEqual(merger.getMinorVersion(), 0) + + params = OCIO.ConfigMergingParameters.Create() + params.setBaseConfigName("base_name") + merger.addParams(params) + self.assertEqual(merger.getNumConfigMergingParameters(), 1) + params2 = merger.getParams(0) + self.assertEqual(params2.getBaseConfigName(), "base_name") + merger.addParams(params) + self.assertEqual(merger.getNumConfigMergingParameters(), 2) + + txt = merger.serialize() + self.assertEqual(txt[0:18], "ociom_version: 1.0") + + merger.setVersion(2, 3) + self.assertEqual(merger.getMajorVersion(), 2) + self.assertEqual(merger.getMinorVersion(), 3) + + def test_ConfigMerger_parse(self): + import os + + ociom_file = os.path.normpath( + os.path.join( + TEST_DATAFILES_DIR, 'configs', 'mergeconfigs', 'merged2', 'merged.ociom' + ) + ) + merger = OCIO.ConfigMerger.CreateFromFile(ociom_file) + self.assertEqual(merger.getNumConfigMergingParameters(), 2) + + params1 = merger.getParams(0) + self.assertEqual(params1.getOutputName(), "Merge1") + self.assertEqual(params1.getDefaultStrategy(), OCIO.ConfigMergingParameters.STRATEGY_PREFER_BASE) + params2 = merger.getParams(1) + self.assertEqual(params2.getOutputName(), "Merge2") + self.assertEqual(params2.getDefaultStrategy(), OCIO.ConfigMergingParameters.STRATEGY_BASE_ONLY) + self.assertEqual(params2.getDescription(), "Description override") + + def test_ExecuteMerger(self): + import os + + ociom_file = os.path.normpath( + os.path.join( + TEST_DATAFILES_DIR, 'configs', 'mergeconfigs', 'merged2', 'merged.ociom' + ) + ) + merger = OCIO.ConfigMerger.CreateFromFile(ociom_file) + + # Mute expected warnings from this merge in the log such as: + # [OpenColorIO Warning]: The Input config contains a value that would override the Base config: file_rules: Default + log = MuteLogging() + with log: + merger2 = merger.mergeConfigs() + + # The full merger consists of two merges (two sets of params). + self.assertEqual(merger2.getNumMergedConfigs(), 2) + + # Test result of the first merge. + cfg = merger2.getMergedConfig(0) + cs = cfg.getColorSpace("ACES2065-1") + self.assertEqual(cs.getFamily(), "ACES~Linear") + self.assertEqual(cs.getDescription(), "from input") + + self.assertEqual(len(cfg.getRoles()), 2) + self.assertEqual(cfg.getRoleColorSpace("cie_xyz_d65_interchange"), "ap0") + + # Test result of the second merge. + cfg = merger2.getMergedConfig(1) + self.assertEqual(len(cfg.getRoles()), 1) + self.assertEqual(cfg.getRoleColorSpace("cie_xyz_d65_interchange"), "CIE-XYZ-D65") + + def test_MergeConfigs(self): + import os + + ociom_file = os.path.normpath( + os.path.join( + TEST_DATAFILES_DIR, 'configs', 'mergeconfigs', 'merged2', 'merged.ociom' + ) + ) + merger = OCIO.ConfigMerger.CreateFromFile(ociom_file) + params = merger.getParams(0) + + base_file = os.path.normpath( + os.path.join( + TEST_DATAFILES_DIR, 'configs', 'mergeconfigs', 'merged2', 'base.ocio' + ) + ) + base_cfg = OCIO.Config.CreateFromFile(base_file) + input_file = os.path.normpath( + os.path.join( + TEST_DATAFILES_DIR, 'configs', 'mergeconfigs', 'merged2', 'input.ocio' + ) + ) + input_cfg = OCIO.Config.CreateFromFile(input_file) + + # Mute expected warnings from this merge in the log such as: + # [OpenColorIO Warning]: The Input config contains a value that would override the Base config: file_rules: Default + log = MuteLogging() + with log: + cfg = OCIO.ConfigMergingHelpers.MergeConfigs(params, base_cfg, input_cfg) + + self.assertEqual(len(cfg.getRoles()), 2) + self.assertEqual(cfg.getRoleColorSpace("cie_xyz_d65_interchange"), "ap0") + + cs = cfg.getColorSpace("ACES2065-1") + self.assertEqual(cs.getFamily(), "ACES~Linear") + self.assertEqual(cs.getDescription(), "from input") + + def test_MergeColorSpace(self): + + params = OCIO.ConfigMergingParameters.Create() + base = OCIO.Config.CreateFromBuiltinConfig("cg-config-latest") + cs = OCIO.ColorSpace(name="my_cs") + cs.setTransform(OCIO.FixedFunctionTransform(OCIO.FIXED_FUNCTION_XYZ_TO_xyY), OCIO.COLORSPACE_DIR_TO_REFERENCE) + + cfg2 = OCIO.ConfigMergingHelpers.MergeColorSpace(params, base, cs) + + cs2 = cfg2.getColorSpace("my_cs") + ff = cs2.getTransform(OCIO.COLORSPACE_DIR_TO_REFERENCE) + self.assertEqual(ff.getStyle(), OCIO.FIXED_FUNCTION_XYZ_TO_xyY) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/python/OpenColorIOTestSuite.py b/tests/python/OpenColorIOTestSuite.py index 89bd110087..0a0470531a 100755 --- a/tests/python/OpenColorIOTestSuite.py +++ b/tests/python/OpenColorIOTestSuite.py @@ -80,6 +80,7 @@ import Lut1DTransformTest import Lut3DTransformTest import MatrixTransformTest +import MergeConfigsTest import MixingHelpersTest import NamedTransformTest import OCIOZArchiveTest @@ -138,6 +139,7 @@ def suite(): suite.addTest(loader.loadTestsFromModule(Lut1DTransformTest)) suite.addTest(loader.loadTestsFromModule(Lut3DTransformTest)) suite.addTest(loader.loadTestsFromModule(MatrixTransformTest)) + suite.addTest(loader.loadTestsFromModule(MergeConfigsTest)) suite.addTest(loader.loadTestsFromModule(MixingHelpersTest)) suite.addTest(loader.loadTestsFromModule(NamedTransformTest)) suite.addTest(loader.loadTestsFromModule(OCIOZArchiveTest)) From 98737fb7e3a4c89f5e433484d6ce76dfee04a519 Mon Sep 17 00:00:00 2001 From: Doug Walker Date: Fri, 12 Sep 2025 23:34:41 -0400 Subject: [PATCH 12/14] Improve view transform comparison Signed-off-by: Doug Walker --- .../mergeconfigs/MergeConfigsHelpers.cpp | 2 +- .../mergeconfigs/MergeConfigsHelpers.h | 2 +- .../apphelpers/mergeconfigs/SectionMerger.cpp | 28 +++++++++--- .../apphelpers/MergeConfigsHelpers_tests.cpp | 44 +++++++++++++------ .../configs/mergeconfigs/base_config.yaml | 7 +++ .../configs/mergeconfigs/input_config.yaml | 7 +++ 6 files changed, 70 insertions(+), 20 deletions(-) diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp index 57a3d00136..b31e5b8fbb 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp +++ b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp @@ -446,7 +446,7 @@ ConstConfigMergerRcPtr ConfigMerger::Impl::Read(std::istream & istream, const ch return merger; } -ConstConfigRcPtr ConfigMerger::Impl::loadConfig(const char * value) +ConstConfigRcPtr ConfigMerger::Impl::loadConfig(const char * value) const { // Get the absolute path. StringUtils::StringVec searchpaths; diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h index f118a5f82a..67824d0602 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h +++ b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h @@ -189,7 +189,7 @@ class ConfigMerger::Impl * 3 - If not found, try to use the name as the output of a previous merge. * 4 - If still not found, return an empty config object. */ - ConstConfigRcPtr loadConfig(const char * value); + ConstConfigRcPtr loadConfig(const char * value) const; }; } // namespace OCIO_NAMESPACE diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp index 0619b150ae..33c41f2931 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp +++ b/src/OpenColorIO/apphelpers/mergeconfigs/SectionMerger.cpp @@ -1710,7 +1710,16 @@ bool viewTransformsAreEqual(const ConstConfigRcPtr & first, return false; } - // TODO: Compare transforms. + // Compare transforms. NB: This is a fast comparison that does not load file transforms. + std::ostringstream oss1; + oss1 << *t1_to; + std::ostringstream oss2; + oss2 << *t2_to; + + if (oss1.str() != oss2.str()) + { + return false; + } } ConstTransformRcPtr t1_from = vt1->getTransform(VIEWTRANSFORM_DIR_FROM_REFERENCE); @@ -1722,7 +1731,16 @@ bool viewTransformsAreEqual(const ConstConfigRcPtr & first, return false; } - // TODO: Compare transforms. + // Compare transforms. NB: This is a fast comparison that does not load file transforms. + std::ostringstream oss1; + oss1 << *t1_from; + std::ostringstream oss2; + oss2 << *t2_from; + + if (oss1.str() != oss2.str()) + { + return false; + } } return true; @@ -1733,8 +1751,8 @@ bool viewTransformsAreEqual(const ConstConfigRcPtr & first, } // anon. void ViewTransformsMerger::addViewTransform(const ConstConfigRcPtr & cfg, - const char * name, - bool isInput) + const char * name, + bool isInput) { ConstViewTransformRcPtr vt = cfg->getViewTransform(name); if (!vt) return; @@ -1795,7 +1813,7 @@ void ViewTransformsMerger::processViewTransforms(const ConstConfigRcPtr & first, } } - // Add the remaining unique views transform. + // Add the remaining unique view transforms. addUniqueViewTransforms(second, secondIsInput); } diff --git a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp index a49d97a586..26dd83acc0 100644 --- a/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp +++ b/tests/cpu/apphelpers/MergeConfigsHelpers_tests.cpp @@ -2107,9 +2107,11 @@ OCIO_ADD_TEST(MergeConfigs, view_transforms_section) OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "Un-tone-mapped-2"); // Validate view_transforms - OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 2); + + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 3); OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped-2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), "Equal"); } // Test display/views with strategy = PreferInput, options InputFirst = true. @@ -2121,6 +2123,7 @@ OCIO_ADD_TEST(MergeConfigs, view_transforms_section) OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, [&options]() { OCIO::ViewTransformsMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: view_transforms: SDR Video", "The Input config contains a value that would override the Base config: default_view_transform: Un-tone-mapped-2" ); @@ -2129,17 +2132,21 @@ OCIO_ADD_TEST(MergeConfigs, view_transforms_section) // Validate view_transforms - OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 3); + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 4); OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); OCIO::ConstTransformRcPtr tf; OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") ->getTransform(OCIO::VIEWTRANSFORM_DIR_FROM_REFERENCE)); auto bi = OCIO_DYNAMIC_POINTER_CAST(tf); OCIO_REQUIRE_ASSERT(bi); + // Note that the style of "SDR Video" differs between input and base, which is why a warning is + // logged for that one, whereas the transform for "Equal" is the same in input and base. OCIO_CHECK_EQUAL(std::string(bi->getStyle()), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped-2"); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), "Un-tone-mapped"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), "Equal"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(3)), "Un-tone-mapped"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransform("Equal")->getDescription()), "from input"); } // Test display/views with strategy=PreferInput, options InputFirst = false. @@ -2151,6 +2158,7 @@ OCIO_ADD_TEST(MergeConfigs, view_transforms_section) OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, [&options]() { OCIO::ViewTransformsMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: view_transforms: SDR Video", "The Input config contains a value that would override the Base config: default_view_transform: Un-tone-mapped-2" ); @@ -2158,7 +2166,7 @@ OCIO_ADD_TEST(MergeConfigs, view_transforms_section) // Validate view_transforms - OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 3); + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 4); OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), std::string("SDR Video")); OCIO::ConstTransformRcPtr tf; OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") @@ -2168,7 +2176,8 @@ OCIO_ADD_TEST(MergeConfigs, view_transforms_section) OCIO_CHECK_EQUAL(std::string(bi->getStyle()), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), std::string("Un-tone-mapped")); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), std::string("Un-tone-mapped-2")); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), "Equal"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(3)), std::string("Un-tone-mapped-2")); } // Test display/views with strategy = PreferBase, options InputFirst = true. @@ -2180,6 +2189,7 @@ OCIO_ADD_TEST(MergeConfigs, view_transforms_section) OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, [&options]() { OCIO::ViewTransformsMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: view_transforms: SDR Video", "The Input config contains a value that would override the Base config: default_view_transform: Un-tone-mapped-2" ); @@ -2187,7 +2197,7 @@ OCIO_ADD_TEST(MergeConfigs, view_transforms_section) // Validate view_transforms - OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 3); + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 4); OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); OCIO::ConstTransformRcPtr tf; OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") @@ -2197,7 +2207,9 @@ OCIO_ADD_TEST(MergeConfigs, view_transforms_section) OCIO_CHECK_EQUAL(std::string(bi->getStyle()), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO_1.0"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped-2"); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), "Un-tone-mapped"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), "Equal"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(3)), "Un-tone-mapped"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransform("Equal")->getDescription()), "from base"); } // Test display/views with strategy = PreferBase, options InputFirst = false. @@ -2209,6 +2221,7 @@ OCIO_ADD_TEST(MergeConfigs, view_transforms_section) OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_WARNING, __LINE__, [&options]() { OCIO::ViewTransformsMerger(options).merge(); }, + "The Input config contains a value that would override the Base config: view_transforms: SDR Video", "The Input config contains a value that would override the Base config: default_view_transform: Un-tone-mapped-2" ); @@ -2216,7 +2229,7 @@ OCIO_ADD_TEST(MergeConfigs, view_transforms_section) // Validate view_transforms - OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 3); + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 4); OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); OCIO::ConstTransformRcPtr tf; OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") @@ -2226,7 +2239,8 @@ OCIO_ADD_TEST(MergeConfigs, view_transforms_section) OCIO_CHECK_EQUAL(std::string(bi->getStyle()), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO_1.0"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped"); - OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), "Un-tone-mapped-2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), "Equal"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(3)), "Un-tone-mapped-2"); } // Test display/views with strategy = BaseOnly. @@ -2240,9 +2254,11 @@ OCIO_ADD_TEST(MergeConfigs, view_transforms_section) OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), "SDR Video"); // Validate view_transforms - OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 2); + + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 3); OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), "Equal"); } // Test display/views with strategy = InputOnly. @@ -2257,7 +2273,7 @@ OCIO_ADD_TEST(MergeConfigs, view_transforms_section) // Validate view_transforms - OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 2); + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 3); OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), "SDR Video"); OCIO::ConstTransformRcPtr tf; OCIO_CHECK_NO_THROW(tf = mergedConfig->getViewTransform("SDR Video") @@ -2267,6 +2283,7 @@ OCIO_ADD_TEST(MergeConfigs, view_transforms_section) OCIO_CHECK_EQUAL(std::string(bi->getStyle()), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO-P3lim_1.1"); OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(1)), "Un-tone-mapped-2"); + OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(2)), "Equal"); } // Test display/views with strategy = Remove @@ -2282,6 +2299,7 @@ OCIO_ADD_TEST(MergeConfigs, view_transforms_section) OCIO_CHECK_EQUAL(std::string(mergedConfig->getDefaultViewTransformName()), ""); // Validate view_transforms + OCIO_CHECK_EQUAL(mergedConfig->getNumViewTransforms(), 1); OCIO_CHECK_EQUAL(std::string(mergedConfig->getViewTransformNameByIndex(0)), std::string("Un-tone-mapped")); } @@ -2305,8 +2323,8 @@ OCIO_ADD_TEST(MergeConfigs, view_transforms_section) OCIO::MergeHandlerOptions options = { baseConfig, inputConfig, params, mergedConfig }; checkForLogOrException(LOG_TYPE_ERROR, __LINE__, [&options]() { OCIO::ViewTransformsMerger(options).merge(); }, - std::string(PREFIX) + std::string("default_view_transform: Un-tone-mapped-2"), - std::string(PREFIX) + std::string("view_transforms: SDR Video")); + std::string(PREFIX) + std::string("view_transforms: SDR Video"), + std::string(PREFIX) + std::string("default_view_transform: Un-tone-mapped-2")); } } } diff --git a/tests/data/files/configs/mergeconfigs/base_config.yaml b/tests/data/files/configs/mergeconfigs/base_config.yaml index d0f95a4208..833929a8dd 100644 --- a/tests/data/files/configs/mergeconfigs/base_config.yaml +++ b/tests/data/files/configs/mergeconfigs/base_config.yaml @@ -72,6 +72,13 @@ view_transforms: - ! name: Un-tone-mapped from_scene_reference: ! {style: UTILITY - ACES-AP0_to_CIE-XYZ-D65_BFD} + - ! + name: Equal + description: from base + from_scene_reference: ! + children: + - ! {matrix: [2.52168618674388, -1.13413098823972, -0.387555198504164, 0, -0.276479914229922, 1.37271908766826, -0.096239173438334, 0, -0.0153780649660342, -0.152975335867399, 1.16835340083343, 0, 0, 0, 0, 1]} + - ! {gamma: 2.4, offset: 0.055, direction: inverse} named_transforms: - ! diff --git a/tests/data/files/configs/mergeconfigs/input_config.yaml b/tests/data/files/configs/mergeconfigs/input_config.yaml index ededdb91d4..a2ef5e9240 100644 --- a/tests/data/files/configs/mergeconfigs/input_config.yaml +++ b/tests/data/files/configs/mergeconfigs/input_config.yaml @@ -74,6 +74,13 @@ view_transforms: - ! name: Un-tone-mapped-2 from_scene_reference: ! {style: UTILITY - ACES-AP0_to_CIE-XYZ-D65_BFD} + - ! + name: Equal + description: from input + from_scene_reference: ! + children: + - ! {matrix: [2.52168618674388, -1.13413098823972, -0.387555198504164, 0, -0.276479914229922, 1.37271908766826, -0.096239173438334, 0, -0.0153780649660342, -0.152975335867399, 1.16835340083343, 0, 0, 0, 0, 1]} + - ! {gamma: 2.4, offset: 0.055, direction: inverse} named_transforms: - ! From 5bcc35fde3125eb4cbb427123e6a1913a08a7a29 Mon Sep 17 00:00:00 2001 From: Doug Walker Date: Sat, 13 Sep 2025 00:26:34 -0400 Subject: [PATCH 13/14] Address Remi's comments Signed-off-by: Doug Walker --- include/OpenColorIO/OpenColorAppHelpers.h | 13 +++++++++---- setup.py | 1 + .../apphelpers/mergeconfigs/MergeConfigsHelpers.h | 5 +++-- src/apps/ociomergeconfigs/CMakeLists.txt | 4 +++- src/apps/ociomergeconfigs/main.cpp | 12 ++++++------ 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/include/OpenColorIO/OpenColorAppHelpers.h b/include/OpenColorIO/OpenColorAppHelpers.h index b615d90ed3..523b12caac 100644 --- a/include/OpenColorIO/OpenColorAppHelpers.h +++ b/include/OpenColorIO/OpenColorAppHelpers.h @@ -557,7 +557,7 @@ class OCIOEXPORT ConfigMergingParameters void setBaseConfigName(const char * baseConfig); const char * getBaseConfigName() const; - /// Set the file name of the base config. This is used along with the search path of + /// Set the file name of the input config. This is used along with the search path of /// the ConfigMerger object. void setInputConfigName(const char * inputConfig); const char * getInputConfigName() const; @@ -585,7 +585,7 @@ class OCIOEXPORT ConfigMergingParameters void setBaseFamilyPrefix(const char * prefix); const char * getBaseFamilyPrefix() const; - /// If true, items from the input config will by higher in the file than those of the + /// If true, items from the input config will be higher in the file than those of the /// base config. Default = true. void setInputFirst(bool enabled); bool isInputFirst() const; @@ -633,7 +633,6 @@ class OCIOEXPORT ConfigMergingParameters /// Override the active_displays of the merged config. void setActiveDisplays(const char * displays); const char * getActiveDisplays() const; -// REMOVE? /// Override the active_views of the merged config. void setActiveViews(const char * views); @@ -781,6 +780,13 @@ class OCIOEXPORT ConfigMerger int getNumSearchPaths() const; const char * getSearchPath(int index) const; + /** + * \brief Set the home directory used to resolve relative search paths. + * + * The working directory defaults to the location of the OCIOM file. It is used to convert + * any relative paths to absolute. If no search paths have been set, the working directory + * will be used as the fallback search path. + */ void setWorkingDir(const char * dirname); const char * getWorkingDir() const; @@ -796,7 +802,6 @@ class OCIOEXPORT ConfigMerger * ConfigMerger::CreateFromFile or created from scratch by using ConfigMerger::Create() and * programmatically configuring it. * - * \param merger Merger object * \return a merger object (call getMergedConfig to obtain the result) */ ConstConfigMergerRcPtr mergeConfigs() const; diff --git a/setup.py b/setup.py index 6481424bab..b55c534ed9 100644 --- a/setup.py +++ b/setup.py @@ -216,6 +216,7 @@ def build_extension(self, ext): 'ociodisplay=PyOpenColorIO.command_line:main', 'ociolutimage=PyOpenColorIO.command_line:main', 'ociomakeclf=PyOpenColorIO.command_line:main', + 'ociomergeconfigs=PyOpenColorIO.command_line:main', 'ocioperf=PyOpenColorIO.command_line:main', 'ociowrite=PyOpenColorIO.command_line:main', # Python applications diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h index 67824d0602..a7d628f177 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h +++ b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.h @@ -72,7 +72,6 @@ class ConfigMergingParameters::Impl m_overrideCfg->clearEnvironmentVars(); // Options - m_defaultStrategy = STRATEGY_PREFER_INPUT; m_inputFamilyPrefix = ""; m_baseFamilyPrefix = ""; m_inputFirst = true; @@ -80,6 +79,7 @@ class ConfigMergingParameters::Impl m_avoidDuplicates = true; m_adjustInputReferenceSpace = true; + m_defaultStrategy = STRATEGY_PREFER_INPUT; m_roles = STRATEGY_UNSPECIFIED; m_fileRules = STRATEGY_UNSPECIFIED; m_displayViews = STRATEGY_UNSPECIFIED; @@ -103,9 +103,9 @@ class ConfigMergingParameters::Impl // Overrides m_name = rhs.m_name; m_description = rhs.m_description; + m_overrideCfg = rhs.m_overrideCfg; // Options - m_defaultStrategy = rhs.m_defaultStrategy; m_inputFamilyPrefix = rhs.m_inputFamilyPrefix; m_baseFamilyPrefix = rhs.m_baseFamilyPrefix; m_inputFirst = rhs.m_inputFirst; @@ -113,6 +113,7 @@ class ConfigMergingParameters::Impl m_avoidDuplicates = rhs.m_avoidDuplicates; m_adjustInputReferenceSpace = rhs.m_adjustInputReferenceSpace; + m_defaultStrategy = rhs.m_defaultStrategy; m_roles = rhs.m_roles; m_fileRules = rhs.m_fileRules; m_displayViews = rhs.m_displayViews; diff --git a/src/apps/ociomergeconfigs/CMakeLists.txt b/src/apps/ociomergeconfigs/CMakeLists.txt index 9d88aa4e75..5a2a5bbe12 100644 --- a/src/apps/ociomergeconfigs/CMakeLists.txt +++ b/src/apps/ociomergeconfigs/CMakeLists.txt @@ -22,9 +22,11 @@ target_link_libraries(ociomergeconfigs apputils pystring::pystring OpenColorIO - MINIZIP::minizip-ng ) +include(StripUtils) +ocio_strip_binary(ociomergeconfigs) + install(TARGETS ociomergeconfigs RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) diff --git a/src/apps/ociomergeconfigs/main.cpp b/src/apps/ociomergeconfigs/main.cpp index 2e45c2b1c2..7069e15f98 100644 --- a/src/apps/ociomergeconfigs/main.cpp +++ b/src/apps/ociomergeconfigs/main.cpp @@ -90,16 +90,16 @@ int main(int argc, const char **argv) ap.options("ociomergeconfigs -- Merge configs using an OCIOM file with merge parameters\n\n" "Usage:\n" - " ociomergeconfigs [options] mergeFile.ociom \n", - "%*", parse_end_args, "", - "", "Options:", + " ociomergeconfigs [options] mergeFile.ociom --out mergedConfig.ocio\n", + "%*", parse_end_args, "", + "", "Options:", "--out %s", &outputFile, "Filepath to save the merged config", "--validate", &validate, "Validate the final merged config", "--show-last", &displayConfig, "Display the last merged config to screen", "--show-all", &displayAllConfig, "Display ALL merged configs to screen", - "--show-params", &displayParams, "Display merger options (OCIOM)", - "--help", &help, "Display the help and exit", - "-h", &help, "Display the help and exit", + "--show-params", &displayParams, "Display merger options from OCIOM file", + "--help", &help, "Display the help and exit", + "-h", &help, "Display the help and exit", NULL ); From e73112b3b11d68a69d86915be4a3669ea714021c Mon Sep 17 00:00:00 2001 From: Doug Walker Date: Tue, 30 Sep 2025 17:38:27 -0400 Subject: [PATCH 14/14] Fix build breaks Signed-off-by: Doug Walker --- .../apphelpers/mergeconfigs/MergeConfigsHelpers.cpp | 2 +- src/bindings/python/apphelpers/PyMergeConfigs.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp index b31e5b8fbb..ab74ed9975 100644 --- a/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp +++ b/src/OpenColorIO/apphelpers/mergeconfigs/MergeConfigsHelpers.cpp @@ -656,7 +656,7 @@ void ConfigMerger::setVersion(unsigned int major, unsigned int minor) int ConfigMerger::getNumMergedConfigs() const { - return getImpl()->m_mergedConfigs.size(); + return static_cast(getImpl()->m_mergedConfigs.size()); } ConstConfigRcPtr ConfigMerger::getMergedConfig() const diff --git a/src/bindings/python/apphelpers/PyMergeConfigs.cpp b/src/bindings/python/apphelpers/PyMergeConfigs.cpp index 4c7e08fe05..d5104bf55a 100644 --- a/src/bindings/python/apphelpers/PyMergeConfigs.cpp +++ b/src/bindings/python/apphelpers/PyMergeConfigs.cpp @@ -197,7 +197,7 @@ void bindPyConfigMergingHelpers(py::module & m) .def("getMergedConfig", py::overload_cast(&ConfigMerger::getMergedConfig, py::const_), "index"_a, - DOC(ConfigMerger, getMergedConfig, 2)) + DOC(ConfigMerger, getMergedConfig)) .def("serialize", [](const ConfigMerger & self) { std::ostringstream os; self.serialize(os); @@ -220,7 +220,7 @@ void bindPyConfigMergingHelpers(py::module & m) const ConstConfigRcPtr &>( &ConfigMergingHelpers::MergeConfigs), "params"_a, "baseConfig"_a, "inputConfig"_a, - DOC(ConfigMergingHelpers, MergeConfigs, 2)) + DOC(ConfigMergingHelpers, MergeConfigs)) .def("MergeColorSpace", &ConfigMergingHelpers::MergeColorSpace, "params"_a, "baseConfig"_a, "colorspace"_a,