1 /*
2 Copyright (c) 2003-2012 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 
30 #include "OpenColorIO_AE_Context.h"
31 
32 #include <fstream>
33 #include <map>
34 #include <sstream>
35 
36 #include "ocioicc.h"
37 
38 #include "OpenColorIO_AE_Dialogs.h"
39 
40 
41 
42 
43 static const char mac_delimiter = '/';
44 static const char win_delimiter = '\\';
45 
46 #ifdef WIN_ENV
47 static const char delimiter = win_delimiter;
48 #else
49 static const char delimiter = mac_delimiter;
50 #endif
51 
52 static const int LUT3D_EDGE_SIZE = 32;
53 
54 
Path(const std::string & path,const std::string & dir)55 Path::Path(const std::string &path, const std::string &dir) :
56     _path(path),
57     _dir(dir)
58 {
59 
60 }
61 
62 
Path(const Path & path)63 Path::Path(const Path &path)
64 {
65     _path = path._path;
66     _dir  = path._dir;
67 }
68 
69 
full_path() const70 std::string Path::full_path() const
71 {
72     if( !_path.empty() && is_relative(_path) && !_dir.empty() )
73     {
74         std::vector<std::string> path_vec = components( convert_delimiters(_path) );
75         std::vector<std::string> dir_vec = components(_dir);
76 
77         int up_dirs = 0;
78         int down_dirs = 0;
79 
80         while(down_dirs < path_vec.size() - 1 &&
81                 (path_vec[down_dirs] == ".." || path_vec[down_dirs] == ".") )
82         {
83             down_dirs++;
84 
85             if(path_vec[down_dirs] == "..")
86                 up_dirs++;
87         }
88 
89 
90         std::string path;
91 
92         if(path_type(_dir) == TYPE_MAC)
93             path += mac_delimiter;
94 
95         for(int i=0; i < dir_vec.size() - up_dirs; i++)
96         {
97             path += dir_vec[i] + delimiter;
98         }
99 
100         for(int i = down_dirs; i < path_vec.size() - 1; i++)
101         {
102             path += path_vec[i] + delimiter;
103         }
104 
105         path += path_vec.back();
106 
107         return path;
108     }
109     else
110     {
111         return _path;
112     }
113 }
114 
115 
relative_path(bool force) const116 std::string Path::relative_path(bool force) const
117 {
118     if( _dir.empty() || _path.empty() || is_relative(_path) )
119     {
120         return _path;
121     }
122     else
123     {
124         std::vector<std::string> path_vec = components(_path);
125         std::vector<std::string> dir_vec = components(_dir);
126 
127         int match_idx = 0;
128 
129         while(match_idx < path_vec.size() &&
130                 match_idx < dir_vec.size() &&
131                 path_vec[match_idx] == dir_vec[match_idx])
132             match_idx++;
133 
134         if(match_idx == 0)
135         {
136             // can't do relative path
137             if(force)
138                 return _path;
139             else
140                 return "";
141         }
142         else
143         {
144             std::string rel_path;
145 
146             // is the file in a folder below or actually inside the dir?
147             if(match_idx == dir_vec.size())
148             {
149                 rel_path += std::string(".") + delimiter;
150             }
151             else
152             {
153                 for(int i = match_idx; i < dir_vec.size(); i++)
154                 {
155                     rel_path += std::string("..") + delimiter;
156                 }
157             }
158 
159             for(int i = match_idx; i < path_vec.size() - 1; i++)
160             {
161                 rel_path += path_vec[i] + delimiter;
162             }
163 
164             rel_path += path_vec.back();
165 
166             return rel_path;
167         }
168     }
169 }
170 
171 
exists() const172 bool Path::exists() const
173 {
174     std::string path = full_path();
175 
176     if(path.empty())
177         return false;
178 
179     std::ifstream f( path.c_str() );
180 
181     return !!f;
182 }
183 
184 
path_type(const std::string & path)185 Path::PathType Path::path_type(const std::string &path)
186 {
187     if( path.empty() )
188     {
189         return TYPE_UNKNOWN;
190     }
191     if(path[0] == mac_delimiter)
192     {
193         return TYPE_MAC;
194     }
195     else if(path[1] == ':' && path[2] == win_delimiter)
196     {
197         return TYPE_WIN;
198     }
199     else if(path[0] == win_delimiter && path[1] == win_delimiter)
200     {
201         return TYPE_WIN;
202     }
203     else
204     {
205         size_t mac_pos = path.find(mac_delimiter);
206         size_t win_pos = path.find(win_delimiter);
207 
208         if(mac_pos != std::string::npos && win_pos == std::string::npos)
209         {
210             return TYPE_MAC;
211         }
212         else if(mac_pos == std::string::npos && win_pos != std::string::npos)
213         {
214             return TYPE_WIN;
215         }
216         else if(mac_pos == std::string::npos && win_pos == std::string::npos)
217         {
218             return TYPE_UNKNOWN;
219         }
220         else // neither npos?
221         {
222             if(mac_pos < win_pos)
223                 return TYPE_MAC;
224             else
225                 return TYPE_WIN;
226         }
227     }
228 }
229 
230 
is_relative(const std::string & path)231 bool Path::is_relative(const std::string &path)
232 {
233     Path::PathType type = path_type(path);
234 
235     if(type == TYPE_MAC)
236     {
237         return (path[0] != mac_delimiter);
238     }
239     else if(type == TYPE_WIN)
240     {
241         return !( (path[1] == ':' && path[2] == win_delimiter) ||
242                   (path[0] == win_delimiter && path[1] == win_delimiter) );
243     }
244     else
245     {   // TYPE_UNKNOWN
246 
247         // just a filename perhaps?
248         // should never have this: even a file in the same directory will be ./file.ocio
249         // we'll assume it's relative, but raise a stink during debugging
250         assert(type != TYPE_UNKNOWN);
251 
252         return true;
253     }
254 }
255 
256 
convert_delimiters(const std::string & path)257 std::string Path::convert_delimiters(const std::string &path)
258 {
259 #ifdef WIN_ENV
260     const char search = mac_delimiter;
261     const char replace = win_delimiter;
262 #else
263     const char search = win_delimiter;
264     const char replace = mac_delimiter;
265 #endif
266 
267     std::string path_copy = path;
268 
269     for(int i=0; i < path_copy.size(); i++)
270     {
271         if(path_copy[i] == search)
272             path_copy[i] = replace;
273     }
274 
275     return path_copy;
276 }
277 
278 
components(const std::string & path)279 std::vector<std::string> Path::components(const std::string &path)
280 {
281     std::vector<std::string> vec;
282 
283     size_t pos = 0;
284     size_t len = path.size();
285 
286     size_t start, finish;
287 
288     while(path[pos] == delimiter && pos < len)
289         pos++;
290 
291     while(pos < len)
292     {
293         start = pos;
294 
295         while(path[pos] != delimiter && pos < len)
296             pos++;
297 
298         finish = ((pos == len - 1) ? pos : pos - 1);
299 
300         vec.push_back( path.substr(start, 1 + finish - start) );
301 
302         while(path[pos] == delimiter && pos < len)
303             pos++;
304     }
305 
306     return vec;
307 }
308 
309 
310 #pragma mark-
311 
312 
OpenColorIO_AE_Context(const std::string & path,OCIO_Source source)313 OpenColorIO_AE_Context::OpenColorIO_AE_Context(const std::string &path, OCIO_Source source) :
314     _gl_init(false)
315 {
316     _action = OCIO_ACTION_NONE;
317 
318 
319     _source = source;
320 
321     if(_source == OCIO_SOURCE_ENVIRONMENT)
322     {
323         char *file = getenv("OCIO");
324 
325         if(file)
326         {
327             _path = file;
328         }
329         else
330             throw OCIO::Exception("No $OCIO environment variable.");
331     }
332     else if(_source == OCIO_SOURCE_STANDARD)
333     {
334         _config_name = path;
335 
336         _path = GetStdConfigPath(_config_name);
337 
338         if( _path.empty() )
339             throw OCIO::Exception("Error getting config.");
340     }
341     else
342     {
343         _path = path;
344     }
345 
346 
347     if(!_path.empty())
348     {
349         std::string the_extension = _path.substr( _path.find_last_of('.') + 1 );
350 
351         if(the_extension == "ocio")
352         {
353             _config = OCIO::Config::CreateFromFile( _path.c_str() );
354 
355             _config->sanityCheck();
356 
357             for(int i=0; i < _config->getNumColorSpaces(); ++i)
358             {
359                 const char *colorSpaceName = _config->getColorSpaceNameByIndex(i);
360 
361                 OCIO::ConstColorSpaceRcPtr colorSpace = _config->getColorSpace(colorSpaceName);
362 
363                 const char *family = colorSpace->getFamily();
364 
365                 _inputs.push_back(colorSpaceName);
366 
367                 const std::string fullPath = (family == NULL ? colorSpaceName : std::string(family) + "/" + colorSpaceName);
368 
369                 _inputsFullPath.push_back(fullPath);
370             }
371 
372 
373             for(int i=0; i < _config->getNumDisplays(); ++i)
374             {
375                 _devices.push_back( _config->getDisplay(i) );
376             }
377 
378 
379             OCIO::ConstColorSpaceRcPtr defaultInput = _config->getColorSpace(OCIO::ROLE_DEFAULT);
380 
381             const char *defaultInputName = (defaultInput ? defaultInput->getName() : OCIO::ROLE_DEFAULT);
382 
383 
384             setupConvert(defaultInputName, defaultInputName);
385 
386 
387             const char *defaultDisplay = _config->getDefaultDisplay();
388             const char *defaultTransform = _config->getDefaultView(defaultDisplay);
389 
390             _device = defaultDisplay;
391             _transform = defaultTransform;
392         }
393         else
394         {
395             _config = OCIO::Config::Create();
396 
397             setupLUT(false, OCIO_INTERP_LINEAR);
398         }
399     }
400     else
401         throw OCIO::Exception("Got nothin");
402 }
403 
404 
OpenColorIO_AE_Context(const ArbitraryData * arb_data,const std::string & dir)405 OpenColorIO_AE_Context::OpenColorIO_AE_Context(const ArbitraryData *arb_data, const std::string &dir) :
406     _gl_init(false)
407 {
408     _action = OCIO_ACTION_NONE;
409 
410 
411     _source = arb_data->source;
412 
413     if(_source == OCIO_SOURCE_ENVIRONMENT)
414     {
415         char *file = getenv("OCIO");
416 
417         if(file)
418         {
419             _path = file;
420         }
421         else
422             throw OCIO::Exception("No $OCIO environment variable.");
423     }
424     else if(_source == OCIO_SOURCE_STANDARD)
425     {
426         _config_name = arb_data->path;
427 
428         _path = GetStdConfigPath(_config_name);
429 
430         if( _path.empty() )
431             throw OCIO::Exception("Error getting config.");
432     }
433     else
434     {
435         Path absolute_path(arb_data->path, dir);
436         Path relative_path(arb_data->relative_path, dir);
437 
438         if( absolute_path.exists() )
439         {
440             _path = absolute_path.full_path();
441         }
442         else
443         {
444             _path = relative_path.full_path();
445         }
446     }
447 
448 
449     if(!_path.empty())
450     {
451         std::string the_extension = _path.substr( _path.find_last_of('.') + 1 );
452 
453         if(the_extension == "ocio")
454         {
455             _config = OCIO::Config::CreateFromFile( _path.c_str() );
456 
457             _config->sanityCheck();
458 
459             for(int i=0; i < _config->getNumColorSpaces(); ++i)
460             {
461                 const char *colorSpaceName = _config->getColorSpaceNameByIndex(i);
462 
463                 OCIO::ConstColorSpaceRcPtr colorSpace = _config->getColorSpace(colorSpaceName);
464 
465                 const char *family = colorSpace->getFamily();
466 
467                 _inputs.push_back(colorSpaceName);
468 
469                 const std::string fullPath = (family == NULL ? colorSpaceName : std::string(family) + "/" + colorSpaceName);
470 
471                 _inputsFullPath.push_back(fullPath);
472             }
473 
474 
475             for(int i=0; i < _config->getNumDisplays(); ++i)
476             {
477                 _devices.push_back( _config->getDisplay(i) );
478             }
479 
480             if(arb_data->action == OCIO_ACTION_CONVERT)
481             {
482                 setupConvert(arb_data->input, arb_data->output);
483 
484                 _device = arb_data->device;
485                 _transform = arb_data->transform;
486             }
487             else
488             {
489                 setupDisplay(arb_data->input, arb_data->device, arb_data->transform);
490 
491                 _output = arb_data->output;
492             }
493         }
494         else
495         {
496             _config = OCIO::Config::Create();
497 
498             setupLUT(arb_data->invert, arb_data->interpolation);
499         }
500     }
501     else
502         throw OCIO::Exception("Got nothin");
503 }
504 
505 
~OpenColorIO_AE_Context()506 OpenColorIO_AE_Context::~OpenColorIO_AE_Context()
507 {
508     if(_gl_init)
509     {
510         glDeleteShader(_fragShader);
511         glDeleteProgram(_program);
512         glDeleteTextures(1, &_imageTexID);
513 
514         if(_bufferWidth != 0 && _bufferHeight != 0)
515             glDeleteRenderbuffersEXT(1, &_renderBuffer);
516     }
517 }
518 
519 
Verify(const ArbitraryData * arb_data,const std::string & dir)520 bool OpenColorIO_AE_Context::Verify(const ArbitraryData *arb_data, const std::string &dir)
521 {
522     if(_source != arb_data->source)
523         return false;
524 
525     if(_source == OCIO_SOURCE_STANDARD)
526     {
527         if(_config_name != arb_data->path)
528             return false;
529     }
530     else if(_source == OCIO_SOURCE_CUSTOM)
531     {
532         // comparing the paths, cheking relative path only if necessary
533         if(_path != arb_data->path)
534         {
535             std::string rel_path(arb_data->relative_path);
536 
537             if( !dir.empty() && !rel_path.empty() )
538             {
539                 Path relative_path(rel_path, dir);
540 
541                 if( _path != relative_path.full_path() )
542                     return false;
543             }
544             else
545                 return false;
546         }
547     }
548 
549     // we can switch between Convert and Display, but not LUT and non-LUT
550     if((arb_data->action == OCIO_ACTION_NONE) ||
551         (_action == OCIO_ACTION_LUT && arb_data->action != OCIO_ACTION_LUT) ||
552         (_action != OCIO_ACTION_LUT && arb_data->action == OCIO_ACTION_LUT) )
553     {
554         return false;
555     }
556 
557     bool force_reset = (_action != arb_data->action);
558 
559 
560     // If the type and path are compatible, we can patch up
561     // differences here and return true.
562     // Returning false means the context will be deleted and rebuilt.
563     if(arb_data->action == OCIO_ACTION_LUT)
564     {
565         if(_invert != (bool)arb_data->invert ||
566             _interpolation != arb_data->interpolation ||
567             force_reset)
568         {
569             setupLUT(arb_data->invert, arb_data->interpolation);
570         }
571     }
572     else if(arb_data->action == OCIO_ACTION_CONVERT)
573     {
574         if(_input != arb_data->input ||
575             _output != arb_data->output ||
576             force_reset)
577         {
578             setupConvert(arb_data->input, arb_data->output);
579         }
580     }
581     else if(arb_data->action == OCIO_ACTION_DISPLAY)
582     {
583         if(_input != arb_data->input ||
584             _device != arb_data->device ||
585             _transform != arb_data->transform ||
586             force_reset)
587         {
588             setupDisplay(arb_data->input, arb_data->device, arb_data->transform);
589         }
590     }
591     else
592         throw OCIO::Exception("Bad OCIO type");
593 
594 
595     return true;
596 }
597 
598 
setupConvert(const char * input,const char * output)599 void OpenColorIO_AE_Context::setupConvert(const char *input, const char *output)
600 {
601     OCIO::ColorSpaceTransformRcPtr transform = OCIO::ColorSpaceTransform::Create();
602 
603     transform->setSrc(input);
604     transform->setDst(output);
605     transform->setDirection(OCIO::TRANSFORM_DIR_FORWARD);
606 
607     _input = input;
608     _output = output;
609 
610     _processor = _config->getProcessor(transform);
611 
612     _action = OCIO_ACTION_CONVERT;
613 
614     UpdateOCIOGLState();
615 }
616 
617 
setupDisplay(const char * input,const char * device,const char * xform)618 void OpenColorIO_AE_Context::setupDisplay(const char *input, const char *device, const char *xform)
619 {
620     _transforms.clear();
621 
622     bool xformValid = false;
623 
624     for(int i=0; i < _config->getNumViews(device); i++)
625     {
626         const std::string transformName = _config->getView(device, i);
627 
628         if(transformName == xform)
629             xformValid = true;
630 
631         _transforms.push_back(transformName);
632     }
633 
634     if(!xformValid)
635         xform = _config->getDefaultView(device);
636 
637 
638     OCIO::DisplayTransformRcPtr transform = OCIO::DisplayTransform::Create();
639 
640     transform->setInputColorSpaceName(input);
641     transform->setDisplay(device);
642     transform->setView(xform);
643 
644     _input = input;
645     _device = device;
646     _transform = xform;
647 
648 
649     _processor = _config->getProcessor(transform);
650 
651     _action = OCIO_ACTION_DISPLAY;
652 
653     UpdateOCIOGLState();
654 }
655 
656 
setupLUT(bool invert,OCIO_Interp interpolation)657 void OpenColorIO_AE_Context::setupLUT(bool invert, OCIO_Interp interpolation)
658 {
659     OCIO::FileTransformRcPtr transform = OCIO::FileTransform::Create();
660 
661     if(interpolation != OCIO_INTERP_NEAREST && interpolation != OCIO_INTERP_LINEAR &&
662         interpolation != OCIO_INTERP_TETRAHEDRAL && interpolation != OCIO_INTERP_BEST)
663     {
664         interpolation = OCIO_INTERP_LINEAR;
665     }
666 
667     transform->setSrc( _path.c_str() );
668     transform->setInterpolation(static_cast<OCIO::Interpolation>(interpolation));
669     transform->setDirection(invert ? OCIO::TRANSFORM_DIR_INVERSE : OCIO::TRANSFORM_DIR_FORWARD);
670 
671     _processor = _config->getProcessor(transform);
672 
673     _invert = invert;
674     _interpolation = interpolation;
675 
676     _action = OCIO_ACTION_LUT;
677 
678     UpdateOCIOGLState();
679 }
680 
681 
ExportLUT(const std::string & path,const std::string & display_icc_path)682 bool OpenColorIO_AE_Context::ExportLUT(const std::string &path, const std::string &display_icc_path)
683 {
684     std::string the_extension = path.substr( path.find_last_of('.') + 1 );
685 
686     try{
687 
688     if(the_extension == "icc")
689     {
690         int cubesize = 32;
691         int whitepointtemp = 6505;
692         std::string copyright = "OpenColorIO, Sony Imageworks";
693 
694         // create a description tag from the filename
695         size_t filename_start = path.find_last_of(delimiter) + 1;
696         size_t filename_end = path.find_last_of('.') - 1;
697 
698         std::string description = path.substr(path.find_last_of(delimiter) + 1,
699                                             1 + filename_end - filename_start);
700 
701         SaveICCProfileToFile(path, _processor, cubesize, whitepointtemp,
702                                 display_icc_path, description, copyright, false);
703     }
704     else
705     {
706         // this code lovingly pulled from ociobakelut
707 
708         // need an extension->format map (yes, just did this one call up)
709         std::map<std::string, std::string> extensions;
710 
711         for(int i=0; i < OCIO::Baker::getNumFormats(); ++i)
712         {
713             const char *extension = OCIO::Baker::getFormatExtensionByIndex(i);
714             const char *format = OCIO::Baker::getFormatNameByIndex(i);
715 
716             extensions[ extension ] = format;
717         }
718 
719         std::string format = extensions[ the_extension ];
720 
721 
722         OCIO::BakerRcPtr baker = OCIO::Baker::Create();
723 
724         baker->setFormat(format.c_str());
725 
726         if(_action == OCIO_ACTION_CONVERT)
727         {
728             baker->setConfig(_config);
729             baker->setInputSpace(_input.c_str());
730             baker->setTargetSpace(_output.c_str());
731 
732             std::ofstream f(path.c_str());
733             baker->bake(f);
734         }
735         else if(_action == OCIO_ACTION_DISPLAY)
736         {
737             OCIO::ConfigRcPtr editableConfig = _config->createEditableCopy();
738 
739             OCIO::ColorSpaceRcPtr inputColorSpace = OCIO::ColorSpace::Create();
740             std::string inputspace = "RawInput";
741             inputColorSpace->setName(inputspace.c_str());
742             editableConfig->addColorSpace(inputColorSpace);
743 
744 
745             OCIO::ColorSpaceRcPtr outputColorSpace = OCIO::ColorSpace::Create();
746             std::string outputspace = "ProcessedOutput";
747             outputColorSpace->setName(outputspace.c_str());
748 
749             OCIO::DisplayTransformRcPtr transform = OCIO::DisplayTransform::Create();
750 
751             transform->setInputColorSpaceName(_input.c_str());
752             transform->setView(_transform.c_str());
753             transform->setDisplay(_device.c_str());
754 
755             outputColorSpace->setTransform(transform, OCIO::COLORSPACE_DIR_FROM_REFERENCE);
756 
757             editableConfig->addColorSpace(outputColorSpace);
758 
759 
760             baker->setConfig(editableConfig);
761             baker->setInputSpace(inputspace.c_str());
762             baker->setTargetSpace(outputspace.c_str());
763 
764             std::ofstream f(path.c_str());
765             baker->bake(f);
766         }
767         else if(_action == OCIO_ACTION_LUT)
768         {
769             OCIO::ConfigRcPtr editableConfig = OCIO::Config::Create();
770 
771             OCIO::ColorSpaceRcPtr inputColorSpace = OCIO::ColorSpace::Create();
772             std::string inputspace = "RawInput";
773             inputColorSpace->setName(inputspace.c_str());
774             editableConfig->addColorSpace(inputColorSpace);
775 
776 
777             OCIO::ColorSpaceRcPtr outputColorSpace = OCIO::ColorSpace::Create();
778             std::string outputspace = "ProcessedOutput";
779             outputColorSpace->setName(outputspace.c_str());
780 
781             OCIO::FileTransformRcPtr transform = OCIO::FileTransform::Create();
782 
783             transform = OCIO::FileTransform::Create();
784             transform->setSrc(_path.c_str());
785             transform->setInterpolation(static_cast<OCIO::Interpolation>(_interpolation));
786             transform->setDirection(_invert ? OCIO::TRANSFORM_DIR_INVERSE : OCIO::TRANSFORM_DIR_FORWARD);
787 
788             outputColorSpace->setTransform(transform, OCIO::COLORSPACE_DIR_FROM_REFERENCE);
789 
790             editableConfig->addColorSpace(outputColorSpace);
791 
792 
793             baker->setConfig(editableConfig);
794             baker->setInputSpace(inputspace.c_str());
795             baker->setTargetSpace(outputspace.c_str());
796 
797             std::ofstream f(path.c_str());
798             baker->bake(f);
799         }
800     }
801 
802     }catch(...) { return false; }
803 
804     return true;
805 }
806 
807 
InitOCIOGL()808 void OpenColorIO_AE_Context::InitOCIOGL()
809 {
810     if(!_gl_init)
811     {
812         SetPluginContext();
813 
814         glGenTextures(1, &_imageTexID);
815         glGenTextures(1, &_lut3dTexID);
816 
817         int num3Dentries = 3*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE;
818         _lut3d.resize(num3Dentries);
819         memset(&_lut3d[0], 0, sizeof(float)*num3Dentries);
820 
821         glActiveTexture(GL_TEXTURE1);
822         glBindTexture(GL_TEXTURE_3D, _lut3dTexID);
823         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
824         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
825         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
826         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
827         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
828         glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA32F_ARB,
829                         LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE,
830                             0, GL_RGB,GL_FLOAT, &_lut3d[0]);
831 
832         _fragShader = 0;
833         _program = 0;
834 
835         _bufferWidth = _bufferHeight = 0;
836 
837         _gl_init = true;
838 
839         SetAEContext();
840     }
841 }
842 
843 
844 static const char * g_fragShaderText = ""
845 "\n"
846 "uniform sampler2D tex1;\n"
847 "uniform sampler3D tex2;\n"
848 "\n"
849 "void main()\n"
850 "{\n"
851 "    vec4 col = texture2D(tex1, gl_TexCoord[0].st);\n"
852 "    gl_FragColor = OCIODisplay(col, tex2);\n"
853 "}\n";
854 
855 
CompileShaderText(GLenum shaderType,const char * text)856 static GLuint CompileShaderText(GLenum shaderType, const char *text)
857 {
858     GLuint shader;
859     GLint stat;
860 
861     shader = glCreateShader(shaderType);
862     glShaderSource(shader, 1, (const GLchar **) &text, NULL);
863     glCompileShader(shader);
864     glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
865 
866     if (!stat)
867     {
868         GLchar log[1000];
869         GLsizei len;
870         glGetShaderInfoLog(shader, 1000, &len, log);
871         return 0;
872     }
873 
874     return shader;
875 }
876 
877 
LinkShaders(GLuint fragShader)878 static GLuint LinkShaders(GLuint fragShader)
879 {
880     if (!fragShader) return 0;
881 
882     GLuint program = glCreateProgram();
883 
884     if (fragShader)
885         glAttachShader(program, fragShader);
886 
887     glLinkProgram(program);
888 
889     // check link
890     {
891         GLint stat;
892         glGetProgramiv(program, GL_LINK_STATUS, &stat);
893         if (!stat) {
894             GLchar log[1000];
895             GLsizei len;
896             glGetProgramInfoLog(program, 1000, &len, log);
897             //fprintf(stderr, "Shader link error:\n%s\n", log);
898             return 0;
899         }
900     }
901 
902     return program;
903 }
904 
905 
UpdateOCIOGLState()906 void OpenColorIO_AE_Context::UpdateOCIOGLState()
907 {
908     if(_gl_init)
909     {
910         SetPluginContext();
911 
912         // Step 1: Create a GPU Shader Description
913         OCIO::GpuShaderDesc shaderDesc;
914         shaderDesc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_0);
915         shaderDesc.setFunctionName("OCIODisplay");
916         shaderDesc.setLut3DEdgeLen(LUT3D_EDGE_SIZE);
917 
918         // Step 2: Compute the 3D LUT
919         std::string lut3dCacheID = _processor->getGpuLut3DCacheID(shaderDesc);
920         if(lut3dCacheID != _lut3dcacheid)
921         {
922             _lut3dcacheid = lut3dCacheID;
923             _processor->getGpuLut3D(&_lut3d[0], shaderDesc);
924         }
925 
926         // Step 3: Compute the Shader
927         std::string shaderCacheID = _processor->getGpuShaderTextCacheID(shaderDesc);
928         if(_program == 0 || shaderCacheID != _shadercacheid)
929         {
930             _shadercacheid = shaderCacheID;
931 
932             std::ostringstream os;
933             os << _processor->getGpuShaderText(shaderDesc) << "\n";
934             os << g_fragShaderText;
935 
936             if(_fragShader) glDeleteShader(_fragShader);
937             _fragShader = CompileShaderText(GL_FRAGMENT_SHADER, os.str().c_str());
938             if(_program) glDeleteProgram(_program);
939             _program = LinkShaders(_fragShader);
940         }
941 
942         SetAEContext();
943     }
944 }
945 
946 
ProcessWorldGL(PF_EffectWorld * float_world)947 bool OpenColorIO_AE_Context::ProcessWorldGL(PF_EffectWorld *float_world)
948 {
949     if(!_gl_init)
950     {
951         InitOCIOGL();
952         UpdateOCIOGLState();
953     }
954 
955 
956     if(_program == 0 || _fragShader == 0)
957         return false;
958 
959 
960     SetPluginContext();
961 
962 
963     GLint max;
964     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
965 
966     if(max < float_world->width || max < float_world->height || GL_NO_ERROR != glGetError())
967     {
968         SetAEContext();
969         return false;
970     }
971 
972 
973     PF_PixelFloat *pix = (PF_PixelFloat *)float_world->data;
974     float *rgba_origin = &pix->red;
975 
976 
977     glActiveTexture(GL_TEXTURE0);
978     glBindTexture(GL_TEXTURE_2D, _imageTexID);
979     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, float_world->width, float_world->height, 0,
980         GL_RGBA, GL_FLOAT, rgba_origin);
981     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
982     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
983     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
984     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
985 
986 
987     glBindTexture(GL_TEXTURE_3D, _lut3dTexID);
988     glTexSubImage3D(GL_TEXTURE_3D, 0,
989                     0, 0, 0,
990                     LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE,
991                     GL_RGB, GL_FLOAT, &_lut3d[0]);
992 
993 
994     glUseProgram(_program);
995     glUniform1i(glGetUniformLocation(_program, "tex1"), 0);
996     glUniform1i(glGetUniformLocation(_program, "tex2"), 1);
997 
998 
999     if(GL_NO_ERROR != glGetError())
1000     {
1001         SetAEContext();
1002         return false;
1003     }
1004 
1005 
1006     glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, GetFrameBuffer());
1007 
1008     if(_bufferWidth != float_world->width || _bufferHeight != float_world->height)
1009     {
1010         if(_bufferWidth != 0 && _bufferHeight != 0)
1011             glDeleteRenderbuffersEXT(1, &_renderBuffer);
1012 
1013         _bufferWidth = float_world->width;
1014         _bufferHeight = float_world->height;
1015 
1016         glGenRenderbuffersEXT(1, &_renderBuffer);
1017         glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _renderBuffer);
1018         glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA, _bufferWidth, _bufferHeight);
1019 
1020         // attach renderbuffer to framebuffer
1021         glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1022                                         GL_RENDERBUFFER_EXT, _renderBuffer);
1023     }
1024 
1025     if(GL_FRAMEBUFFER_COMPLETE_EXT != glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT))
1026     {
1027         SetAEContext();
1028         return false;
1029     }
1030 
1031     glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
1032 
1033 
1034     glViewport(0, 0, float_world->width, float_world->height);
1035     glMatrixMode(GL_PROJECTION);
1036     glLoadIdentity();
1037     glOrtho(0.0, float_world->width, 0.0, float_world->height, -100.0, 100.0);
1038     glMatrixMode(GL_MODELVIEW);
1039     glLoadIdentity();
1040 
1041 
1042     glEnable(GL_TEXTURE_2D);
1043     glClearColor(0.1f, 0.1f, 0.1f, 0.0f);
1044     glClear(GL_COLOR_BUFFER_BIT);
1045     glColor3f(1, 1, 1);
1046 
1047     glPushMatrix();
1048     glBegin(GL_QUADS);
1049     glTexCoord2f(0.0f, 1.0f);
1050     glVertex2f(0.0f, float_world->height);
1051 
1052     glTexCoord2f(0.0f, 0.0f);
1053     glVertex2f(0.0f, 0.0f);
1054 
1055     glTexCoord2f(1.0f, 0.0f);
1056     glVertex2f(float_world->width, 0.0f);
1057 
1058     glTexCoord2f(1.0f, 1.0f);
1059     glVertex2f(float_world->width, float_world->height);
1060 
1061     glEnd();
1062     glPopMatrix();
1063 
1064     glDisable(GL_TEXTURE_2D);
1065 
1066 
1067     glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
1068     glReadPixels(0, 0, float_world->width, float_world->height,
1069                     GL_RGBA, GL_FLOAT, rgba_origin);
1070 
1071 
1072     glFinish();
1073 
1074 
1075     SetAEContext();
1076 
1077     return true;
1078 }
1079