diff options
Diffstat (limited to 'src/core/LookTransform.cpp')
-rw-r--r-- | src/core/LookTransform.cpp | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/src/core/LookTransform.cpp b/src/core/LookTransform.cpp new file mode 100644 index 0000000..0092d16 --- /dev/null +++ b/src/core/LookTransform.cpp @@ -0,0 +1,405 @@ +/* +Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al. +All Rights Reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of Sony Pictures Imageworks nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <OpenColorIO/OpenColorIO.h> + +#include <algorithm> +#include <iterator> + +#include "LookParse.h" +#include "NoOps.h" +#include "OpBuilders.h" +#include "ParseUtils.h" +#include "pystring/pystring.h" + + +OCIO_NAMESPACE_ENTER +{ + LookTransformRcPtr LookTransform::Create() + { + return LookTransformRcPtr(new LookTransform(), &deleter); + } + + void LookTransform::deleter(LookTransform* t) + { + delete t; + } + + + class LookTransform::Impl + { + public: + TransformDirection dir_; + std::string src_; + std::string dst_; + std::string looks_; + + Impl() : + dir_(TRANSFORM_DIR_FORWARD) + { } + + ~Impl() + { } + + Impl& operator= (const Impl & rhs) + { + dir_ = rhs.dir_; + src_ = rhs.src_; + dst_ = rhs.dst_; + looks_ = rhs.looks_; + return *this; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + + + LookTransform::LookTransform() + : m_impl(new LookTransform::Impl) + { + } + + TransformRcPtr LookTransform::createEditableCopy() const + { + LookTransformRcPtr transform = LookTransform::Create(); + *(transform->m_impl) = *m_impl; + return transform; + } + + LookTransform::~LookTransform() + { + delete m_impl; + m_impl = NULL; + } + + LookTransform& LookTransform::operator= (const LookTransform & rhs) + { + *m_impl = *rhs.m_impl; + return *this; + } + + TransformDirection LookTransform::getDirection() const + { + return getImpl()->dir_; + } + + void LookTransform::setDirection(TransformDirection dir) + { + getImpl()->dir_ = dir; + } + + const char * LookTransform::getSrc() const + { + return getImpl()->src_.c_str(); + } + + void LookTransform::setSrc(const char * src) + { + getImpl()->src_ = src; + } + + const char * LookTransform::getDst() const + { + return getImpl()->dst_.c_str(); + } + + void LookTransform::setDst(const char * dst) + { + getImpl()->dst_ = dst; + } + + void LookTransform::setLooks(const char * looks) + { + getImpl()->looks_ = looks; + } + + const char * LookTransform::getLooks() const + { + return getImpl()->looks_.c_str(); + } + + std::ostream& operator<< (std::ostream& os, const LookTransform& t) + { + os << "<LookTransform "; + os << "src=" << t.getSrc() << ", "; + os << "dst=" << t.getDst() << ", "; + os << "looks=" << t.getLooks() << ", "; + os << "direction=" << TransformDirectionToString(t.getDirection()) << ", "; + os << ">\n"; + return os; + } + + //////////////////////////////////////////////////////////////////////////// + + + + + namespace + { + + void RunLookTokens(OpRcPtrVec & ops, + ConstColorSpaceRcPtr & currentColorSpace, + bool skipColorSpaceConversions, + const Config& config, + const ConstContextRcPtr & context, + const LookParseResult::Tokens & lookTokens) + { + if(lookTokens.empty()) return; + + for(unsigned int i=0; i<lookTokens.size(); ++i) + { + const std::string & lookName = lookTokens[i].name; + + if(lookName.empty()) continue; + + ConstLookRcPtr look = config.getLook(lookName.c_str()); + if(!look) + { + std::ostringstream os; + os << "RunLookTokens error. "; + os << "The specified look, '" << lookName; + os << "', cannot be found. "; + if(config.getNumLooks() == 0) + { + os << " (No looks defined in config)"; + } + else + { + os << " (looks: "; + for(int ii=0; ii<config.getNumLooks(); ++ii) + { + if(ii != 0) os << ", "; + os << config.getLookNameByIndex(ii); + } + os << ")"; + } + + throw Exception(os.str().c_str()); + } + + // Put the new ops into a temp array, to see if it's a no-op + // If it is a no-op, dont bother doing the colorspace conversion. + OpRcPtrVec tmpOps; + + if(lookTokens[i].dir == TRANSFORM_DIR_FORWARD) + { + CreateLookNoOp(tmpOps, lookName); + if(look->getTransform()) + { + BuildOps(tmpOps, config, context, look->getTransform(), TRANSFORM_DIR_FORWARD); + } + else if(look->getInverseTransform()) + { + BuildOps(tmpOps, config, context, look->getInverseTransform(), TRANSFORM_DIR_INVERSE); + } + } + else if(lookTokens[i].dir == TRANSFORM_DIR_INVERSE) + { + CreateLookNoOp(tmpOps, std::string("-") + lookName); + if(look->getInverseTransform()) + { + BuildOps(tmpOps, config, context, look->getInverseTransform(), TRANSFORM_DIR_FORWARD); + } + else if(look->getTransform()) + { + BuildOps(tmpOps, config, context, look->getTransform(), TRANSFORM_DIR_INVERSE); + } + } + else + { + std::ostringstream os; + os << "BuildLookOps error. "; + os << "The specified look, '" << lookTokens[i].name; + os << "' has an ill-defined transform direction."; + throw Exception(os.str().c_str()); + } + + if(!IsOpVecNoOp(tmpOps)) + { + if(!skipColorSpaceConversions) + { + ConstColorSpaceRcPtr processColorSpace = config.getColorSpace(look->getProcessSpace()); + if(!processColorSpace) + { + std::ostringstream os; + os << "RunLookTokens error. "; + os << "The specified look, '" << lookTokens[i].name; + os << "', requires processing in the ColorSpace, '"; + os << look->getProcessSpace() << "' which is not defined."; + throw Exception(os.str().c_str()); + } + + BuildColorSpaceOps(ops, config, context, + currentColorSpace, + processColorSpace); + currentColorSpace = processColorSpace; + } + + std::copy(tmpOps.begin(), tmpOps.end(), std::back_inserter(ops)); + } + } + } + + } // anon namespace + + //////////////////////////////////////////////////////////////////////////// + + + void BuildLookOps(OpRcPtrVec & ops, + const Config& config, + const ConstContextRcPtr & context, + const LookTransform & lookTransform, + TransformDirection dir) + { + ConstColorSpaceRcPtr src, dst; + src = config.getColorSpace( lookTransform.getSrc() ); + dst = config.getColorSpace( lookTransform.getDst() ); + + if(!src) + { + std::ostringstream os; + os << "BuildLookOps error."; + os << "The specified lookTransform specifies a src colorspace, '"; + os << lookTransform.getSrc() << "', which is not defined."; + throw Exception(os.str().c_str()); + } + + if(!dst) + { + std::ostringstream os; + os << "BuildLookOps error."; + os << "The specified lookTransform specifies a dst colorspace, '"; + os << lookTransform.getDst() << "', which is not defined."; + throw Exception(os.str().c_str()); + } + + LookParseResult looks; + looks.parse(lookTransform.getLooks()); + + // We must handle the inverse src/dst colorspace transformation explicitly. + if(dir == TRANSFORM_DIR_INVERSE) + { + std::swap(src, dst); + looks.reverse(); + } + else if(dir == TRANSFORM_DIR_UNKNOWN) + { + std::ostringstream os; + os << "BuildLookOps error. A valid transform direction must be specified."; + throw Exception(os.str().c_str()); + } + + ConstColorSpaceRcPtr currentColorSpace = src; + BuildLookOps(ops, + currentColorSpace, + false, + config, + context, + looks); + + BuildColorSpaceOps(ops, config, context, + currentColorSpace, + dst); + } + + void BuildLookOps(OpRcPtrVec & ops, + ConstColorSpaceRcPtr & currentColorSpace, + bool skipColorSpaceConversions, + const Config& config, + const ConstContextRcPtr & context, + const LookParseResult & looks) + { + const LookParseResult::Options & options = looks.getOptions(); + + if(options.empty()) + { + // Do nothing + } + else if(options.size() == 1) + { + // As an optimization, if we only have a single look option, + // just push back onto the final location + RunLookTokens(ops, + currentColorSpace, + skipColorSpaceConversions, + config, + context, + options[0]); + } + else + { + // If we have multiple look options, try each one in order, + // and if we can create the ops without a missing file exception, + // push back it's results and return + + bool success = false; + std::ostringstream os; + + OpRcPtrVec tmpOps; + ConstColorSpaceRcPtr cs; + + for(unsigned int i=0; i<options.size(); ++i) + { + cs = currentColorSpace; + tmpOps.clear(); + + try + { + RunLookTokens(tmpOps, + cs, + skipColorSpaceConversions, + config, + context, + options[i]); + success = true; + break; + } + catch(ExceptionMissingFile & e) + { + if(i != 0) os << " ... "; + + os << "("; + LookParseResult::serialize(os, options[i]); + os << ") " << e.what(); + } + } + + if(success) + { + currentColorSpace = cs; + std::copy(tmpOps.begin(), tmpOps.end(), std::back_inserter(ops)); + } + else + { + throw ExceptionMissingFile(os.str().c_str()); + } + } + } +} +OCIO_NAMESPACE_EXIT |