PageRenderTime 67ms CodeModel.GetById 14ms app.highlight 47ms RepoModel.GetById 2ms app.codeStats 0ms

/src/core/LookTransform.cpp

http://github.com/imageworks/OpenColorIO
C++ | 405 lines | 306 code | 60 blank | 39 comment | 38 complexity | 7b816b11a8effe7358c5f2f7c429983b MD5 | raw file
  1/*
  2Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al.
  3All Rights Reserved.
  4
  5Redistribution and use in source and binary forms, with or without
  6modification, are permitted provided that the following conditions are
  7met:
  8* Redistributions of source code must retain the above copyright
  9  notice, this list of conditions and the following disclaimer.
 10* Redistributions in binary form must reproduce the above copyright
 11  notice, this list of conditions and the following disclaimer in the
 12  documentation and/or other materials provided with the distribution.
 13* Neither the name of Sony Pictures Imageworks nor the names of its
 14  contributors may be used to endorse or promote products derived from
 15  this software without specific prior written permission.
 16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 17"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 18LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 19A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 20OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 21SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 22LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 23DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 24THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 25(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 26OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 27*/
 28
 29#include <OpenColorIO/OpenColorIO.h>
 30
 31#include <algorithm>
 32#include <iterator>
 33
 34#include "LookParse.h"
 35#include "NoOps.h"
 36#include "OpBuilders.h"
 37#include "ParseUtils.h"
 38#include "pystring/pystring.h"
 39
 40
 41OCIO_NAMESPACE_ENTER
 42{
 43    LookTransformRcPtr LookTransform::Create()
 44    {
 45        return LookTransformRcPtr(new LookTransform(), &deleter);
 46    }
 47    
 48    void LookTransform::deleter(LookTransform* t)
 49    {
 50        delete t;
 51    }
 52    
 53    
 54    class LookTransform::Impl
 55    {
 56    public:
 57        TransformDirection dir_;
 58        std::string src_;
 59        std::string dst_;
 60        std::string looks_;
 61        
 62        Impl() :
 63            dir_(TRANSFORM_DIR_FORWARD)
 64        { }
 65        
 66        ~Impl()
 67        { }
 68        
 69        Impl& operator= (const Impl & rhs)
 70        {
 71            dir_ = rhs.dir_;
 72            src_ = rhs.src_;
 73            dst_ = rhs.dst_;
 74            looks_ = rhs.looks_;
 75            return *this;
 76        }
 77    };
 78    
 79    ///////////////////////////////////////////////////////////////////////////
 80    
 81    
 82    
 83    LookTransform::LookTransform()
 84        : m_impl(new LookTransform::Impl)
 85    {
 86    }
 87    
 88    TransformRcPtr LookTransform::createEditableCopy() const
 89    {
 90        LookTransformRcPtr transform = LookTransform::Create();
 91        *(transform->m_impl) = *m_impl;
 92        return transform;
 93    }
 94    
 95    LookTransform::~LookTransform()
 96    {
 97        delete m_impl;
 98        m_impl = NULL;
 99    }
100    
101    LookTransform& LookTransform::operator= (const LookTransform & rhs)
102    {
103        *m_impl = *rhs.m_impl;
104        return *this;
105    }
106    
107    TransformDirection LookTransform::getDirection() const
108    {
109        return getImpl()->dir_;
110    }
111    
112    void LookTransform::setDirection(TransformDirection dir)
113    {
114        getImpl()->dir_ = dir;
115    }
116    
117    const char * LookTransform::getSrc() const
118    {
119        return getImpl()->src_.c_str();
120    }
121    
122    void LookTransform::setSrc(const char * src)
123    {
124        getImpl()->src_ = src;
125    }
126    
127    const char * LookTransform::getDst() const
128    {
129        return getImpl()->dst_.c_str();
130    }
131    
132    void LookTransform::setDst(const char * dst)
133    {
134        getImpl()->dst_ = dst;
135    }
136    
137    void LookTransform::setLooks(const char * looks)
138    {
139        getImpl()->looks_ = looks;
140    }
141    
142    const char * LookTransform::getLooks() const
143    {
144        return getImpl()->looks_.c_str();
145    }
146    
147    std::ostream& operator<< (std::ostream& os, const LookTransform& t)
148    {
149        os << "<LookTransform ";
150        os << "src=" << t.getSrc() << ", ";
151        os << "dst=" << t.getDst() << ", ";
152        os << "looks=" << t.getLooks() << ", ";
153        os << "direction=" << TransformDirectionToString(t.getDirection()) << ", ";
154        os << ">\n";
155        return os;
156    }
157    
158    ////////////////////////////////////////////////////////////////////////////
159    
160    
161    
162    
163    namespace
164    {
165    
166    void RunLookTokens(OpRcPtrVec & ops,
167                       ConstColorSpaceRcPtr & currentColorSpace,
168                       bool skipColorSpaceConversions,
169                       const Config& config,
170                       const ConstContextRcPtr & context,
171                       const LookParseResult::Tokens & lookTokens)
172    {
173        if(lookTokens.empty()) return;
174        
175        for(unsigned int i=0; i<lookTokens.size(); ++i)
176        {
177            const std::string & lookName = lookTokens[i].name;
178            
179            if(lookName.empty()) continue;
180            
181            ConstLookRcPtr look = config.getLook(lookName.c_str());
182            if(!look)
183            {
184                std::ostringstream os;
185                os << "RunLookTokens error. ";
186                os << "The specified look, '" << lookName;
187                os << "', cannot be found. ";
188                if(config.getNumLooks() == 0)
189                {
190                    os << " (No looks defined in config)";
191                }
192                else
193                {
194                    os << " (looks: ";
195                    for(int ii=0; ii<config.getNumLooks(); ++ii)
196                    {
197                        if(ii != 0) os << ", ";
198                        os << config.getLookNameByIndex(ii);
199                    }
200                    os << ")";
201                }
202                
203                throw Exception(os.str().c_str());
204            }
205            
206            // Put the new ops into a temp array, to see if it's a no-op
207            // If it is a no-op, dont bother doing the colorspace conversion.
208            OpRcPtrVec tmpOps;
209            
210            if(lookTokens[i].dir == TRANSFORM_DIR_FORWARD)
211            {
212                CreateLookNoOp(tmpOps, lookName);
213                if(look->getTransform())
214                {
215                    BuildOps(tmpOps, config, context, look->getTransform(), TRANSFORM_DIR_FORWARD);
216                }
217                else if(look->getInverseTransform())
218                {
219                    BuildOps(tmpOps, config, context, look->getInverseTransform(), TRANSFORM_DIR_INVERSE);
220                }
221            }
222            else if(lookTokens[i].dir == TRANSFORM_DIR_INVERSE)
223            {
224                CreateLookNoOp(tmpOps, std::string("-") + lookName);
225                if(look->getInverseTransform())
226                {
227                    BuildOps(tmpOps, config, context, look->getInverseTransform(), TRANSFORM_DIR_FORWARD);
228                }
229                else if(look->getTransform())
230                {
231                    BuildOps(tmpOps, config, context, look->getTransform(), TRANSFORM_DIR_INVERSE);
232                }
233            }
234            else
235            {
236                std::ostringstream os;
237                os << "BuildLookOps error. ";
238                os << "The specified look, '" << lookTokens[i].name;
239                os << "' has an ill-defined transform direction.";
240                throw Exception(os.str().c_str());
241            }
242            
243            if(!IsOpVecNoOp(tmpOps))
244            {
245                if(!skipColorSpaceConversions)
246                {
247                    ConstColorSpaceRcPtr processColorSpace = config.getColorSpace(look->getProcessSpace());
248                    if(!processColorSpace)
249                    {
250                        std::ostringstream os;
251                        os << "RunLookTokens error. ";
252                        os << "The specified look, '" << lookTokens[i].name;
253                        os << "', requires processing in the ColorSpace, '";
254                        os << look->getProcessSpace() << "' which is not defined.";
255                        throw Exception(os.str().c_str());
256                    }
257                    
258                    BuildColorSpaceOps(ops, config, context,
259                                       currentColorSpace,
260                                       processColorSpace);
261                    currentColorSpace = processColorSpace;
262                }
263                
264                std::copy(tmpOps.begin(), tmpOps.end(), std::back_inserter(ops));
265            }
266        }
267    }
268    
269    } // anon namespace
270    
271    ////////////////////////////////////////////////////////////////////////////
272    
273    
274    void BuildLookOps(OpRcPtrVec & ops,
275                      const Config& config,
276                      const ConstContextRcPtr & context,
277                      const LookTransform & lookTransform,
278                      TransformDirection dir)
279    {
280        ConstColorSpaceRcPtr src, dst;
281        src = config.getColorSpace( lookTransform.getSrc() );
282        dst = config.getColorSpace( lookTransform.getDst() );
283        
284        if(!src)
285        {
286            std::ostringstream os;
287            os << "BuildLookOps error.";
288            os << "The specified lookTransform specifies a src colorspace, '";
289            os <<  lookTransform.getSrc() << "', which is not defined.";
290            throw Exception(os.str().c_str());
291        }
292        
293        if(!dst)
294        {
295            std::ostringstream os;
296            os << "BuildLookOps error.";
297            os << "The specified lookTransform specifies a dst colorspace, '";
298            os <<  lookTransform.getDst() << "', which is not defined.";
299            throw Exception(os.str().c_str());
300        }
301        
302        LookParseResult looks;
303        looks.parse(lookTransform.getLooks());
304        
305        // We must handle the inverse src/dst colorspace transformation explicitly.
306        if(dir == TRANSFORM_DIR_INVERSE)
307        {
308            std::swap(src, dst);
309            looks.reverse();
310        }
311        else if(dir == TRANSFORM_DIR_UNKNOWN)
312        {
313            std::ostringstream os;
314            os << "BuildLookOps error. A valid transform direction must be specified.";
315            throw Exception(os.str().c_str());
316        }
317        
318        ConstColorSpaceRcPtr currentColorSpace = src;
319        BuildLookOps(ops,
320                     currentColorSpace,
321                     false,
322                     config,
323                     context,
324                     looks);
325        
326        BuildColorSpaceOps(ops, config, context,
327                           currentColorSpace,
328                           dst);
329    }
330    
331    void BuildLookOps(OpRcPtrVec & ops,
332                      ConstColorSpaceRcPtr & currentColorSpace,
333                      bool skipColorSpaceConversions,
334                      const Config& config,
335                      const ConstContextRcPtr & context,
336                      const LookParseResult & looks)
337    {
338        const LookParseResult::Options & options = looks.getOptions();
339        
340        if(options.empty())
341        {
342            // Do nothing
343        }
344        else if(options.size() == 1)
345        {
346            // As an optimization, if we only have a single look option,
347            // just push back onto the final location
348            RunLookTokens(ops,
349                          currentColorSpace,
350                          skipColorSpaceConversions,
351                          config,
352                          context,
353                          options[0]);
354        }
355        else
356        {
357            // If we have multiple look options, try each one in order,
358            // and if we can create the ops without a missing file exception,
359            // push back it's results and return
360            
361            bool success = false;
362            std::ostringstream os;
363            
364            OpRcPtrVec tmpOps;
365            ConstColorSpaceRcPtr cs;
366            
367            for(unsigned int i=0; i<options.size(); ++i)
368            {
369                cs = currentColorSpace;
370                tmpOps.clear();
371                
372                try
373                {
374                    RunLookTokens(tmpOps,
375                                  cs,
376                                  skipColorSpaceConversions,
377                                  config,
378                                  context,
379                                  options[i]);
380                    success = true;
381                    break;
382                }
383                catch(ExceptionMissingFile & e)
384                {
385                    if(i != 0) os << "  ...  ";
386                    
387                    os << "(";
388                    LookParseResult::serialize(os, options[i]);
389                    os << ") " << e.what();
390                }
391            }
392            
393            if(success)
394            {
395                currentColorSpace = cs;
396                std::copy(tmpOps.begin(), tmpOps.end(), std::back_inserter(ops));
397            }
398            else
399            {
400                throw ExceptionMissingFile(os.str().c_str());
401            }
402        }
403    }
404}
405OCIO_NAMESPACE_EXIT