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