Skip to content

Instantly share code, notes, and snippets.

@remia
Created October 22, 2020 20:59
Show Gist options
  • Save remia/2a928bc32bb1e9b514dff30f98782b2a to your computer and use it in GitHub Desktop.
Save remia/2a928bc32bb1e9b514dff30f98782b2a to your computer and use it in GitHub Desktop.
OCIO LookTransform inversion
diff --git a/src/OpenColorIO/transforms/LookTransform.cpp b/src/OpenColorIO/transforms/LookTransform.cpp
index 5458e9a9..8afee104 100755
--- a/src/OpenColorIO/transforms/LookTransform.cpp
+++ b/src/OpenColorIO/transforms/LookTransform.cpp
@@ -327,12 +327,13 @@ void BuildLookOps(OpRcPtrVec & ops,
looks.parse(lookTransform.getLooks());
// We must handle the inverse src/dst colorspace transformation explicitly.
- if(dir == TRANSFORM_DIR_INVERSE)
+ auto combinedDir = CombineTransformDirections(dir, lookTransform.getDirection());
+ if(combinedDir == TRANSFORM_DIR_INVERSE)
{
std::swap(src, dst);
looks.reverse();
}
- else if(dir == TRANSFORM_DIR_UNKNOWN)
+ else if(combinedDir == TRANSFORM_DIR_UNKNOWN)
{
std::ostringstream os;
os << "BuildLookOps error. A valid transform direction must be specified.";
@@ -430,7 +431,7 @@ void BuildLookOps(OpRcPtrVec & ops,
}
}
-bool CollectContextVariables(const Config & config,
+bool CollectContextVariables(const Config & config,
const Context & context,
const LookTransform & look,
ContextRcPtr & usedContextVars)
diff --git a/tests/cpu/transforms/LookTransform_tests.cpp b/tests/cpu/transforms/LookTransform_tests.cpp
index 89c265e0..522891dd 100644
--- a/tests/cpu/transforms/LookTransform_tests.cpp
+++ b/tests/cpu/transforms/LookTransform_tests.cpp
@@ -2,7 +2,10 @@
// Copyright Contributors to the OpenColorIO Project.
+#include "ops/cdl/CDLOpData.h"
#include "ops/fixedfunction/FixedFunctionOpData.h"
+#include "ops/gamma/GammaOpData.h"
+#include "ops/log/LogOpData.h"
#include "transforms/LookTransform.cpp"
@@ -559,3 +562,191 @@ colorspaces:
OCIO_CHECK_EQUAL(std::string("FILE2"), usedContextVars->getStringVarNameByIndex(1));
OCIO_CHECK_EQUAL(std::string("cdl_test1.cc"), usedContextVars->getStringVarByIndex(1));}
+
+OCIO_ADD_TEST(LookTransform, inline_look_transform)
+{
+ constexpr const char * OCIO_CONFIG{ R"(
+ocio_profile_version: 2
+
+search_path: luts
+
+roles:
+ default: raw
+
+displays:
+ sRGB:
+ - !<View> {name: Raw, colorspace: raw}
+
+looks:
+ - !<Look>
+ name: look1
+ process_space: log
+ transform: !<CDLTransform> {sat: 0.8}
+
+colorspaces:
+ - !<ColorSpace>
+ name: raw
+ family: raw
+ bitdepth: 32f
+ isdata: false
+
+ - !<ColorSpace>
+ name: log
+ to_reference: !<LogTransform> {base: 2, direction: inverse}
+
+ - !<ColorSpace>
+ name: vd
+ from_reference: !<ExponentTransform> {value: [2.4, 2.4, 2.4, 1], direction: inverse}
+
+ - !<ColorSpace>
+ name: vd_graded
+ from_reference: !<GroupTransform>
+ children:
+ - !<LookTransform> {src: raw, dst: vd, looks: look1}
+
+ - !<ColorSpace>
+ name: vd_graded_2
+ to_reference: !<GroupTransform>
+ children:
+ - !<LookTransform> {src: raw, dst: vd, looks: look1, direction: inverse}
+
+)" };
+
+ std::istringstream is;
+ is.str(OCIO_CONFIG);
+
+ OCIO::ConstConfigRcPtr config;
+ OCIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
+ OCIO_CHECK_NO_THROW(config->validate());
+
+ OCIO::ConstColorSpaceRcPtr srcColorSpace;
+ OCIO_CHECK_NO_THROW(srcColorSpace = config->getColorSpace("raw"));
+ OCIO::ConstColorSpaceRcPtr dstColorSpace;
+ OCIO_CHECK_NO_THROW(dstColorSpace = config->getColorSpace("vd_graded"));
+
+ OCIO::OpRcPtrVec ops;
+ OCIO_CHECK_NO_THROW(BuildColorSpaceOps(ops, *config, config->getCurrentContext(),
+ srcColorSpace, dstColorSpace, false));
+ OCIO_CHECK_NO_THROW(ops.validate());
+ OCIO_REQUIRE_EQUAL(ops.size(), 11);
+ OCIO::ConstOpRcPtr op = ops[0];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+ op = ops[1];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+ op = ops[2]; // raw to log
+ OCIO_REQUIRE_EQUAL(op->data()->getType(), OCIO::OpData::LogType);
+ auto lg = OCIO_DYNAMIC_POINTER_CAST<const OCIO::LogOpData>(op->data());
+ OCIO_CHECK_ASSERT(lg);
+ OCIO_CHECK_EQUAL(lg->getDirection(), OCIO::TRANSFORM_DIR_FORWARD);
+ op = ops[3];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+ op = ops[4];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+ op = ops[5]; // look
+ OCIO_REQUIRE_EQUAL(op->data()->getType(), OCIO::OpData::CDLType);
+ auto cdl = OCIO_DYNAMIC_POINTER_CAST<const OCIO::CDLOpData>(op->data());
+ OCIO_CHECK_ASSERT(cdl);
+ OCIO_CHECK_EQUAL(cdl->getDirection(), OCIO::TRANSFORM_DIR_FORWARD);
+ op = ops[6];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+ op = ops[7]; // log to raw
+ OCIO_REQUIRE_EQUAL(op->data()->getType(), OCIO::OpData::LogType);
+ lg = OCIO_DYNAMIC_POINTER_CAST<const OCIO::LogOpData>(op->data());
+ OCIO_CHECK_ASSERT(lg);
+ OCIO_CHECK_EQUAL(lg->getDirection(), OCIO::TRANSFORM_DIR_INVERSE);
+ op = ops[8]; // raw to vd
+ OCIO_REQUIRE_EQUAL(op->data()->getType(), OCIO::OpData::GammaType);
+ auto gm = OCIO_DYNAMIC_POINTER_CAST<const OCIO::GammaOpData>(op->data());
+ OCIO_CHECK_ASSERT(gm);
+ OCIO_CHECK_EQUAL(gm->getDirection(), OCIO::TRANSFORM_DIR_INVERSE);
+ op = ops[9];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+ op = ops[10];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+
+ // Test in inverse direction.
+ ops.clear();
+ OCIO_CHECK_NO_THROW(BuildColorSpaceOps(ops, *config, config->getCurrentContext(),
+ dstColorSpace, srcColorSpace, false));
+ OCIO_REQUIRE_EQUAL(ops.size(), 11);
+ OCIO_CHECK_NO_THROW(ops.validate());
+ op = ops[0];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+ op = ops[1];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+ op = ops[2]; // vd to raw
+ OCIO_REQUIRE_EQUAL(op->data()->getType(), OCIO::OpData::GammaType);
+ gm = OCIO_DYNAMIC_POINTER_CAST<const OCIO::GammaOpData>(op->data());
+ OCIO_CHECK_ASSERT(gm);
+ OCIO_CHECK_EQUAL(gm->getDirection(), OCIO::TRANSFORM_DIR_FORWARD);
+ op = ops[3]; // raw to log
+ OCIO_REQUIRE_EQUAL(op->data()->getType(), OCIO::OpData::LogType);
+ lg = OCIO_DYNAMIC_POINTER_CAST<const OCIO::LogOpData>(op->data());
+ OCIO_CHECK_ASSERT(lg);
+ OCIO_CHECK_EQUAL(lg->getDirection(), OCIO::TRANSFORM_DIR_FORWARD);
+ op = ops[4];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+ op = ops[5];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+ op = ops[6]; // look
+ OCIO_REQUIRE_EQUAL(op->data()->getType(), OCIO::OpData::CDLType);
+ cdl = OCIO_DYNAMIC_POINTER_CAST<const OCIO::CDLOpData>(op->data());
+ OCIO_CHECK_ASSERT(cdl);
+ OCIO_CHECK_EQUAL(cdl->getDirection(), OCIO::TRANSFORM_DIR_INVERSE);
+ op = ops[7];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+ op = ops[8]; // log to raw
+ OCIO_REQUIRE_EQUAL(op->data()->getType(), OCIO::OpData::LogType);
+ lg = OCIO_DYNAMIC_POINTER_CAST<const OCIO::LogOpData>(op->data());
+ OCIO_CHECK_ASSERT(lg);
+ OCIO_CHECK_EQUAL(lg->getDirection(), OCIO::TRANSFORM_DIR_INVERSE);
+ op = ops[9];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+ op = ops[10];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+
+ // Compare to vd_graded_2 that should be identical (only diference is that
+ // it's defined using to_reference instead of from_reference)
+ OCIO::ConstColorSpaceRcPtr dstColorSpace2;
+ OCIO_CHECK_NO_THROW(dstColorSpace2 = config->getColorSpace("vd_graded_2"));
+
+ OCIO::OpRcPtrVec ops2;
+ OCIO_CHECK_NO_THROW(BuildColorSpaceOps(ops2, *config, config->getCurrentContext(),
+ dstColorSpace2, srcColorSpace, false));
+ OCIO_REQUIRE_EQUAL(ops2.size(), 11);
+ OCIO_CHECK_NO_THROW(ops2.validate());
+ op = ops2[0];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+ op = ops2[1];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+ op = ops2[2]; // vd to raw
+ OCIO_REQUIRE_EQUAL(op->data()->getType(), OCIO::OpData::GammaType);
+ gm = OCIO_DYNAMIC_POINTER_CAST<const OCIO::GammaOpData>(op->data());
+ OCIO_CHECK_ASSERT(gm);
+ OCIO_CHECK_EQUAL(gm->getDirection(), OCIO::TRANSFORM_DIR_FORWARD);
+ op = ops2[3]; // raw to log
+ OCIO_REQUIRE_EQUAL(op->data()->getType(), OCIO::OpData::LogType);
+ lg = OCIO_DYNAMIC_POINTER_CAST<const OCIO::LogOpData>(op->data());
+ OCIO_CHECK_ASSERT(lg);
+ OCIO_CHECK_EQUAL(lg->getDirection(), OCIO::TRANSFORM_DIR_FORWARD);
+ op = ops2[4];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+ op = ops2[5];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+ op = ops2[6]; // look
+ OCIO_REQUIRE_EQUAL(op->data()->getType(), OCIO::OpData::CDLType);
+ cdl = OCIO_DYNAMIC_POINTER_CAST<const OCIO::CDLOpData>(op->data());
+ OCIO_CHECK_ASSERT(cdl);
+ OCIO_CHECK_EQUAL(cdl->getDirection(), OCIO::TRANSFORM_DIR_INVERSE);
+ op = ops2[7];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+ op = ops2[8]; // log to raw
+ OCIO_REQUIRE_EQUAL(op->data()->getType(), OCIO::OpData::LogType);
+ lg = OCIO_DYNAMIC_POINTER_CAST<const OCIO::LogOpData>(op->data());
+ OCIO_CHECK_ASSERT(lg);
+ OCIO_CHECK_EQUAL(lg->getDirection(), OCIO::TRANSFORM_DIR_INVERSE);
+ op = ops2[9];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+ op = ops2[10];
+ OCIO_CHECK_ASSERT(op->isNoOpType());
+}
\ No newline at end of file
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment