1 /*
2 Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al.
3 All Rights Reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
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.
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #include <OpenColorIO/OpenColorIO.h>
30 
31 #include "NoOps.h"
32 #include "OpBuilders.h"
33 
34 
35 OCIO_NAMESPACE_ENTER
36 {
37     ColorSpaceTransformRcPtr ColorSpaceTransform::Create()
38     {
39         return ColorSpaceTransformRcPtr(new ColorSpaceTransform(), &deleter);
40     }
41 
42     void ColorSpaceTransform::deleter(ColorSpaceTransform* t)
43     {
44         delete t;
45     }
46 
47 
48     class ColorSpaceTransform::Impl
49     {
50     public:
51         TransformDirection dir_;
52         std::string src_;
53         std::string dst_;
54 
55         Impl() :
56             dir_(TRANSFORM_DIR_FORWARD)
57         { }
58 
59         ~Impl()
60         { }
61 
62         Impl& operator= (const Impl & rhs)
63         {
64             dir_ = rhs.dir_;
65             src_ = rhs.src_;
66             dst_ = rhs.dst_;
67             return *this;
68         }
69     };
70 
71     ///////////////////////////////////////////////////////////////////////////
72 
73 
74 
75     ColorSpaceTransform::ColorSpaceTransform()
76         : m_impl(new ColorSpaceTransform::Impl)
77     {
78     }
79 
80     TransformRcPtr ColorSpaceTransform::createEditableCopy() const
81     {
82         ColorSpaceTransformRcPtr transform = ColorSpaceTransform::Create();
83         *(transform->m_impl) = *m_impl;
84         return transform;
85     }
86 
87     ColorSpaceTransform::~ColorSpaceTransform()
88     {
89         delete m_impl;
90         m_impl = NULL;
91     }
92 
93     ColorSpaceTransform& ColorSpaceTransform::operator= (const ColorSpaceTransform & rhs)
94     {
95         *m_impl = *rhs.m_impl;
96         return *this;
97     }
98 
99     TransformDirection ColorSpaceTransform::getDirection() const
100     {
101         return getImpl()->dir_;
102     }
103 
104     void ColorSpaceTransform::setDirection(TransformDirection dir)
105     {
106         getImpl()->dir_ = dir;
107     }
108 
109     const char * ColorSpaceTransform::getSrc() const
110     {
111         return getImpl()->src_.c_str();
112     }
113 
114     void ColorSpaceTransform::setSrc(const char * src)
115     {
116         getImpl()->src_ = src;
117     }
118 
119     const char * ColorSpaceTransform::getDst() const
120     {
121         return getImpl()->dst_.c_str();
122     }
123 
124     void ColorSpaceTransform::setDst(const char * dst)
125     {
126         getImpl()->dst_ = dst;
127     }
128 
129     std::ostream& operator<< (std::ostream& os, const ColorSpaceTransform& t)
130     {
131         os << "<ColorSpaceTransform ";
132         os << "direction=" << TransformDirectionToString(t.getDirection()) << ", ";
133         os << "src=" << t.getSrc() << ", ";
134         os << "dst=" << t.getDst();
135         os << ">";
136         return os;
137     }
138 
139 
140     ///////////////////////////////////////////////////////////////////////////////////////////////////////
141 
142     void BuildColorSpaceOps(OpRcPtrVec & ops,
143                             const Config& config,
144                             const ConstContextRcPtr & context,
145                             const ColorSpaceTransform & colorSpaceTransform,
146                             TransformDirection dir)
147     {
148         TransformDirection combinedDir = CombineTransformDirections(dir,
149                                                   colorSpaceTransform.getDirection());
150 
151         ConstColorSpaceRcPtr src, dst;
152 
153         if(combinedDir == TRANSFORM_DIR_FORWARD)
154         {
155             src = config.getColorSpace( context->resolveStringVar( colorSpaceTransform.getSrc() ) );
156             dst = config.getColorSpace( context->resolveStringVar( colorSpaceTransform.getDst() ) );
157         }
158         else if(combinedDir == TRANSFORM_DIR_INVERSE)
159         {
160             dst = config.getColorSpace( context->resolveStringVar( colorSpaceTransform.getSrc() ) );
161             src = config.getColorSpace( context->resolveStringVar( colorSpaceTransform.getDst() ) );
162         }
163 
164         BuildColorSpaceOps(ops, config, context, src, dst);
165     }
166 
167     namespace
168     {
169         bool AreColorSpacesInSameEqualityGroup(const ConstColorSpaceRcPtr & csa,
170                                                const ConstColorSpaceRcPtr & csb)
171         {
172             std::string a = csa->getEqualityGroup();
173             std::string b = csb->getEqualityGroup();
174 
175             if(!a.empty()) return (a==b);
176             return false;
177         }
178     }
179 
180     void BuildColorSpaceOps(OpRcPtrVec & ops,
181                             const Config & config,
182                             const ConstContextRcPtr & context,
183                             const ConstColorSpaceRcPtr & srcColorSpace,
184                             const ConstColorSpaceRcPtr & dstColorSpace)
185     {
186         if(!srcColorSpace)
187             throw Exception("BuildColorSpaceOps failed, null srcColorSpace.");
188         if(!dstColorSpace)
189             throw Exception("BuildColorSpaceOps failed, null dstColorSpace.");
190 
191         if(AreColorSpacesInSameEqualityGroup(srcColorSpace, dstColorSpace))
192             return;
193         if(dstColorSpace->isData() || srcColorSpace->isData())
194             return;
195 
196         // Consider dt8 -> vd8?
197         // One would have to explode the srcColorSpace->getTransform(COLORSPACE_DIR_TO_REFERENCE);
198         // result, and walk through it step by step.  If the dstColorspace family were
199         // ever encountered in transit, we'd want to short circuit the result.
200 
201         AllocationData srcAllocation;
202         srcAllocation.allocation = srcColorSpace->getAllocation();
203         srcAllocation.vars.resize( srcColorSpace->getAllocationNumVars());
204         if(srcAllocation.vars.size() > 0)
205         {
206             srcColorSpace->getAllocationVars(&srcAllocation.vars[0]);
207         }
208 
209         CreateGpuAllocationNoOp(ops, srcAllocation);
210 
211         // Go to the reference space, either by using
212         // * cs->ref in the forward direction
213         // * ref->cs in the inverse direction
214         if(srcColorSpace->getTransform(COLORSPACE_DIR_TO_REFERENCE))
215         {
216             BuildOps(ops, config, context, srcColorSpace->getTransform(COLORSPACE_DIR_TO_REFERENCE), TRANSFORM_DIR_FORWARD);
217         }
218         else if(srcColorSpace->getTransform(COLORSPACE_DIR_FROM_REFERENCE))
219         {
220             BuildOps(ops, config, context, srcColorSpace->getTransform(COLORSPACE_DIR_FROM_REFERENCE), TRANSFORM_DIR_INVERSE);
221         }
222         // Otherwise, both are not defined so its a no-op. This is not an error condition.
223 
224         // Go from the reference space, either by using
225         // * ref->cs in the forward direction
226         // * cs->ref in the inverse direction
227         if(dstColorSpace->getTransform(COLORSPACE_DIR_FROM_REFERENCE))
228         {
229             BuildOps(ops, config, context, dstColorSpace->getTransform(COLORSPACE_DIR_FROM_REFERENCE), TRANSFORM_DIR_FORWARD);
230         }
231         else if(dstColorSpace->getTransform(COLORSPACE_DIR_TO_REFERENCE))
232         {
233             BuildOps(ops, config, context, dstColorSpace->getTransform(COLORSPACE_DIR_TO_REFERENCE), TRANSFORM_DIR_INVERSE);
234         }
235         // Otherwise, both are not defined so its a no-op. This is not an error condition.
236 
237         AllocationData dstAllocation;
238         dstAllocation.allocation = dstColorSpace->getAllocation();
239         dstAllocation.vars.resize( dstColorSpace->getAllocationNumVars());
240         if(dstAllocation.vars.size() > 0)
241         {
242             dstColorSpace->getAllocationVars(&dstAllocation.vars[0]);
243         }
244 
245         CreateGpuAllocationNoOp(ops, dstAllocation);
246     }
247 }
248 OCIO_NAMESPACE_EXIT
249