summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/aftereffects/DrawbotBot.cpp239
-rw-r--r--src/aftereffects/DrawbotBot.h89
-rwxr-xr-xsrc/aftereffects/OpenColorIO_AE.cpp1133
-rwxr-xr-xsrc/aftereffects/OpenColorIO_AE.h227
-rw-r--r--src/aftereffects/OpenColorIO_AE_ArbData.cpp408
-rw-r--r--src/aftereffects/OpenColorIO_AE_Context.cpp1051
-rw-r--r--src/aftereffects/OpenColorIO_AE_Context.h153
-rw-r--r--src/aftereffects/OpenColorIO_AE_Dialogs.h60
-rw-r--r--src/aftereffects/OpenColorIO_AE_GL.h61
-rw-r--r--src/aftereffects/OpenColorIO_AE_PiPL.r102
-rw-r--r--src/aftereffects/OpenColorIO_AE_UI.cpp1229
-rwxr-xr-xsrc/aftereffects/mac/OpenColorIO_AE.plugin-Info.plist24
-rw-r--r--src/aftereffects/mac/OpenColorIO_AE_Dialogs_Cocoa.mm237
-rw-r--r--src/aftereffects/mac/OpenColorIO_AE_GL_Cocoa.mm178
-rw-r--r--src/aftereffects/mac/OpenColorIO_AE_Menu.h45
-rw-r--r--src/aftereffects/mac/OpenColorIO_AE_Menu.m114
-rw-r--r--src/aftereffects/mac/OpenColorIO_AE_MonitorProfileChooser.xib494
-rw-r--r--src/aftereffects/mac/OpenColorIO_AE_MonitorProfileChooser_Controller.h46
-rw-r--r--src/aftereffects/mac/OpenColorIO_AE_MonitorProfileChooser_Controller.m195
-rw-r--r--src/aftereffects/vc/vc9/OpenColorABI.h100
-rw-r--r--src/aftereffects/vc/vc9/OpenColorIO.vcproj667
-rw-r--r--src/aftereffects/vc/vc9/aftereffects/OpenColorIO_AE.sln57
-rw-r--r--src/aftereffects/vc/vc9/aftereffects/OpenColorIO_AE.vcproj448
-rw-r--r--src/aftereffects/vc/vc9/ext/glew.vcproj319
-rw-r--r--src/aftereffects/vc/vc9/ext/lcms.vcproj407
-rw-r--r--src/aftereffects/vc/vc9/ext/tinyxml.vcproj323
-rw-r--r--src/aftereffects/vc/vc9/ext/yaml.vcproj603
-rw-r--r--src/aftereffects/win/OpenColorIO.rc99
-rw-r--r--src/aftereffects/win/OpenColorIO_AE_Dialogs_Win.cpp564
-rw-r--r--src/aftereffects/win/OpenColorIO_AE_GL_Win.cpp212
-rw-r--r--src/aftereffects/win/resource.h17
-rw-r--r--src/aftereffects/xcode/OpenColorABI.h100
-rw-r--r--src/aftereffects/xcode/OpenColorIO.xcodeproj/project.pbxproj589
-rwxr-xr-xsrc/aftereffects/xcode/aftereffects/OpenColorIO_AE.xcodeproj/project.pbxproj509
-rw-r--r--src/aftereffects/xcode/ext/lcms.xcodeproj/project.pbxproj343
-rw-r--r--src/aftereffects/xcode/ext/tinyxml.xcodeproj/project.pbxproj248
-rw-r--r--src/aftereffects/xcode/ext/yaml.xcodeproj/project.pbxproj571
-rw-r--r--src/apps/ociobakelut/CMakeLists.txt46
-rw-r--r--src/apps/ociobakelut/main.cpp537
-rw-r--r--src/apps/ociobakelut/ocioicc.cpp251
-rw-r--r--src/apps/ociobakelut/ocioicc.h71
-rw-r--r--src/apps/ociocheck/CMakeLists.txt17
-rw-r--r--src/apps/ociocheck/main.cpp301
-rw-r--r--src/apps/ocioconvert/CMakeLists.txt16
-rw-r--r--src/apps/ocioconvert/main.cpp309
-rw-r--r--src/apps/ociodisplay/CMakeLists.txt11
-rw-r--r--src/apps/ociodisplay/main.cpp734
-rw-r--r--src/apps/ociolutimage/CMakeLists.txt16
-rw-r--r--src/apps/ociolutimage/main.cpp398
-rw-r--r--src/apps/share/argparse.cpp528
-rw-r--r--src/apps/share/argparse.h181
-rw-r--r--src/apps/share/pystring.cpp1658
-rw-r--r--src/apps/share/pystring.h438
-rw-r--r--src/apps/share/strutil.cpp86
-rw-r--r--src/apps/share/strutil.h83
-rw-r--r--src/core/AllocationOp.cpp128
-rw-r--r--src/core/AllocationOp.h45
-rw-r--r--src/core/AllocationTransform.cpp182
-rw-r--r--src/core/Baker.cpp297
-rw-r--r--src/core/CDLTransform.cpp776
-rw-r--r--src/core/CDLTransform.h53
-rw-r--r--src/core/CMakeLists.txt93
-rw-r--r--src/core/Caching.cpp47
-rw-r--r--src/core/ColorSpace.cpp270
-rw-r--r--src/core/ColorSpaceTransform.cpp246
-rw-r--r--src/core/Config.cpp2223
-rw-r--r--src/core/Context.cpp364
-rw-r--r--src/core/DisplayTransform.cpp410
-rw-r--r--src/core/Exception.cpp74
-rw-r--r--src/core/ExponentOps.cpp372
-rw-r--r--src/core/ExponentOps.h50
-rw-r--r--src/core/ExponentTransform.cpp151
-rw-r--r--src/core/FileFormat3DL.cpp638
-rw-r--r--src/core/FileFormatCC.cpp151
-rw-r--r--src/core/FileFormatCCC.cpp195
-rw-r--r--src/core/FileFormatCSP.cpp1112
-rw-r--r--src/core/FileFormatHDL.cpp1481
-rw-r--r--src/core/FileFormatIridasCube.cpp398
-rw-r--r--src/core/FileFormatIridasItx.cpp336
-rw-r--r--src/core/FileFormatIridasLook.cpp1356
-rw-r--r--src/core/FileFormatPandora.cpp286
-rw-r--r--src/core/FileFormatSpi1D.cpp261
-rw-r--r--src/core/FileFormatSpi3D.cpp209
-rw-r--r--src/core/FileFormatSpiMtx.cpp195
-rw-r--r--src/core/FileFormatTruelight.cpp620
-rw-r--r--src/core/FileFormatVF.cpp297
-rw-r--r--src/core/FileTransform.cpp579
-rw-r--r--src/core/FileTransform.h156
-rw-r--r--src/core/GpuShaderDesc.cpp131
-rw-r--r--src/core/GpuShaderUtils.cpp193
-rw-r--r--src/core/GpuShaderUtils.h58
-rw-r--r--src/core/GroupTransform.cpp196
-rw-r--r--src/core/HashUtils.cpp71
-rw-r--r--src/core/HashUtils.h48
-rw-r--r--src/core/ImageDesc.cpp392
-rw-r--r--src/core/ImagePacking.cpp407
-rw-r--r--src/core/ImagePacking.h71
-rw-r--r--src/core/LogOps.cpp499
-rw-r--r--src/core/LogOps.h57
-rw-r--r--src/core/LogTransform.cpp157
-rw-r--r--src/core/Logging.cpp156
-rw-r--r--src/core/Logging.h47
-rw-r--r--src/core/Look.cpp163
-rw-r--r--src/core/LookParse.cpp309
-rw-r--r--src/core/LookParse.h79
-rw-r--r--src/core/LookTransform.cpp405
-rw-r--r--src/core/Lut1DOp.cpp1038
-rw-r--r--src/core/Lut1DOp.h107
-rw-r--r--src/core/Lut3DOp.cpp982
-rw-r--r--src/core/Lut3DOp.h114
-rw-r--r--src/core/MathUtils.cpp603
-rw-r--r--src/core/MathUtils.h186
-rw-r--r--src/core/MatrixOps.cpp788
-rw-r--r--src/core/MatrixOps.h75
-rw-r--r--src/core/MatrixTransform.cpp386
-rw-r--r--src/core/Mutex.h115
-rw-r--r--src/core/NoOps.cpp641
-rw-r--r--src/core/NoOps.h67
-rw-r--r--src/core/OCIOYaml.cpp1218
-rw-r--r--src/core/OCIOYaml.h125
-rw-r--r--src/core/Op.cpp126
-rw-r--r--src/core/Op.h136
-rw-r--r--src/core/OpBuilders.h125
-rw-r--r--src/core/OpOptimizers.cpp364
-rw-r--r--src/core/ParseUtils.cpp438
-rw-r--r--src/core/ParseUtils.h89
-rw-r--r--src/core/PathUtils.cpp229
-rw-r--r--src/core/PathUtils.h95
-rw-r--r--src/core/Platform.h202
-rw-r--r--src/core/PrivateTypes.h54
-rw-r--r--src/core/Processor.cpp640
-rw-r--r--src/core/Processor.h132
-rw-r--r--src/core/SSE.h37
-rw-r--r--src/core/ScanlineHelper.cpp123
-rw-r--r--src/core/ScanlineHelper.h78
-rw-r--r--src/core/Transform.cpp175
-rw-r--r--src/core/TruelightOp.cpp395
-rw-r--r--src/core/TruelightOp.h44
-rw-r--r--src/core/TruelightTransform.cpp365
-rw-r--r--src/core/UnitTest.cpp39
-rw-r--r--src/core/UnitTest.h38
-rw-r--r--src/core/md5/md5.cpp391
-rw-r--r--src/core/md5/md5.h97
-rw-r--r--src/core/pystring/pystring.cpp1658
-rw-r--r--src/core/pystring/pystring.h438
-rw-r--r--src/core_tests/CMakeLists.txt51
-rw-r--r--src/core_tests/ocio_core_tests.sh.in8
-rw-r--r--src/jniglue/CMakeLists.txt92
-rw-r--r--src/jniglue/JNIBaker.cpp264
-rw-r--r--src/jniglue/JNIColorSpace.cpp239
-rw-r--r--src/jniglue/JNIConfig.cpp607
-rw-r--r--src/jniglue/JNIContext.cpp170
-rw-r--r--src/jniglue/JNIGlobals.cpp417
-rw-r--r--src/jniglue/JNIGpuShaderDesc.cpp125
-rw-r--r--src/jniglue/JNIImageDesc.cpp309
-rw-r--r--src/jniglue/JNILook.cpp131
-rw-r--r--src/jniglue/JNIProcessor.cpp133
-rw-r--r--src/jniglue/JNITransforms.cpp1151
-rw-r--r--src/jniglue/JNIUtil.cpp122
-rw-r--r--src/jniglue/JNIUtil.h282
-rw-r--r--src/jniglue/LoadLibrary.java.in40
-rw-r--r--src/jniglue/Manifest.txt.in7
-rw-r--r--src/jniglue/org/OpenColorIO/Allocation.java44
-rw-r--r--src/jniglue/org/OpenColorIO/AllocationTransform.java42
-rw-r--r--src/jniglue/org/OpenColorIO/Baker.java62
-rw-r--r--src/jniglue/org/OpenColorIO/BitDepth.java56
-rw-r--r--src/jniglue/org/OpenColorIO/CDLTransform.java56
-rw-r--r--src/jniglue/org/OpenColorIO/ColorSpace.java59
-rw-r--r--src/jniglue/org/OpenColorIO/ColorSpaceDirection.java44
-rw-r--r--src/jniglue/org/OpenColorIO/ColorSpaceTransform.java41
-rw-r--r--src/jniglue/org/OpenColorIO/Config.java96
-rw-r--r--src/jniglue/org/OpenColorIO/Context.java52
-rw-r--r--src/jniglue/org/OpenColorIO/DisplayTransform.java55
-rw-r--r--src/jniglue/org/OpenColorIO/ExceptionBase.java37
-rw-r--r--src/jniglue/org/OpenColorIO/ExceptionMissingFile.java37
-rw-r--r--src/jniglue/org/OpenColorIO/ExponentTransform.java39
-rw-r--r--src/jniglue/org/OpenColorIO/FileTransform.java46
-rw-r--r--src/jniglue/org/OpenColorIO/Globals.java78
-rw-r--r--src/jniglue/org/OpenColorIO/GpuLanguage.java46
-rw-r--r--src/jniglue/org/OpenColorIO/GpuShaderDesc.java46
-rw-r--r--src/jniglue/org/OpenColorIO/GroupTransform.java42
-rw-r--r--src/jniglue/org/OpenColorIO/ImageDesc.java36
-rw-r--r--src/jniglue/org/OpenColorIO/Interpolation.java48
-rw-r--r--src/jniglue/org/OpenColorIO/LogTransform.java39
-rw-r--r--src/jniglue/org/OpenColorIO/LoggingLevel.java48
-rw-r--r--src/jniglue/org/OpenColorIO/Look.java48
-rw-r--r--src/jniglue/org/OpenColorIO/LookTransform.java43
-rw-r--r--src/jniglue/org/OpenColorIO/MatrixTransform.java54
-rw-r--r--src/jniglue/org/OpenColorIO/PackedImageDesc.java59
-rw-r--r--src/jniglue/org/OpenColorIO/PlanarImageDesc.java63
-rw-r--r--src/jniglue/org/OpenColorIO/Processor.java51
-rw-r--r--src/jniglue/org/OpenColorIO/Transform.java41
-rw-r--r--src/jniglue/org/OpenColorIO/TransformDirection.java44
-rw-r--r--src/jniglue/org/OpenColorIO/TruelightTransform.java58
-rw-r--r--src/jniglue/tests/CMakeLists.txt17
-rw-r--r--src/jniglue/tests/org/OpenColorIO/BakerTest.java84
-rw-r--r--src/jniglue/tests/org/OpenColorIO/ColorSpaceTest.java41
-rw-r--r--src/jniglue/tests/org/OpenColorIO/ConfigTest.java220
-rw-r--r--src/jniglue/tests/org/OpenColorIO/ContextTest.java38
-rw-r--r--src/jniglue/tests/org/OpenColorIO/GlobalsTest.java150
-rw-r--r--src/jniglue/tests/org/OpenColorIO/GpuShaderDescTest.java24
-rw-r--r--src/jniglue/tests/org/OpenColorIO/LookTest.java35
-rw-r--r--src/jniglue/tests/org/OpenColorIO/OpenColorIOTestSuite.java30
-rw-r--r--src/jniglue/tests/org/OpenColorIO/PackedImageDescTest.java39
-rw-r--r--src/jniglue/tests/org/OpenColorIO/PlanarImageDescTest.java51
-rw-r--r--src/jniglue/tests/org/OpenColorIO/TransformsTest.java237
-rw-r--r--src/jniglue/tests/org/OpenColorIO/test.cc11
-rw-r--r--src/mari/1.4v1/README10
-rwxr-xr-xsrc/mari/1.4v1/_ocio_filter.py127
-rwxr-xr-xsrc/mari/1.4v1/_ocio_toolbar.py1279
-rwxr-xr-xsrc/mari/1.4v1/ocio.py789
-rw-r--r--src/mari/prototype/README3
-rw-r--r--src/mari/prototype/ociodisplay.py242
-rw-r--r--src/mari/prototype/ociofiletransform.py93
-rw-r--r--src/nuke/CMakeLists.txt138
-rw-r--r--src/nuke/OCIOCDLTransform/OCIOCDLTransform.cpp387
-rw-r--r--src/nuke/OCIOCDLTransform/OCIOCDLTransform.h137
-rw-r--r--src/nuke/OCIOColorSpace/OCIOColorSpace.cpp376
-rw-r--r--src/nuke/OCIOColorSpace/OCIOColorSpace.h120
-rw-r--r--src/nuke/OCIODisplay/OCIODisplay.cpp561
-rw-r--r--src/nuke/OCIODisplay/OCIODisplay.h133
-rw-r--r--src/nuke/OCIOFileTransform/OCIOFileTransform.cpp287
-rw-r--r--src/nuke/OCIOFileTransform/OCIOFileTransform.h128
-rw-r--r--src/nuke/OCIOLogConvert/OCIOLogConvert.cpp179
-rw-r--r--src/nuke/OCIOLogConvert/OCIOLogConvert.h101
-rw-r--r--src/nuke/OCIOLookTransform/OCIOLookTransform.cpp533
-rw-r--r--src/nuke/OCIOLookTransform/OCIOLookTransform.h140
-rw-r--r--src/pyglue/CMakeLists.txt106
-rw-r--r--src/pyglue/DocStrings/AllocationTransform.py54
-rw-r--r--src/pyglue/DocStrings/CDLTransform.py141
-rw-r--r--src/pyglue/DocStrings/ColorSpace.py103
-rw-r--r--src/pyglue/DocStrings/ColorSpaceTransform.py51
-rw-r--r--src/pyglue/DocStrings/Config.py527
-rw-r--r--src/pyglue/DocStrings/Constants.py43
-rw-r--r--src/pyglue/DocStrings/Context.py32
-rw-r--r--src/pyglue/DocStrings/DisplayTransform.py222
-rw-r--r--src/pyglue/DocStrings/Exception.py11
-rw-r--r--src/pyglue/DocStrings/ExceptionMissingFile.py11
-rw-r--r--src/pyglue/DocStrings/ExponentTransform.py31
-rw-r--r--src/pyglue/DocStrings/FileTransform.py19
-rw-r--r--src/pyglue/DocStrings/GroupTransform.py21
-rw-r--r--src/pyglue/DocStrings/LogTransform.py26
-rw-r--r--src/pyglue/DocStrings/Look.py35
-rw-r--r--src/pyglue/DocStrings/LookTransform.py19
-rw-r--r--src/pyglue/DocStrings/MatrixTransform.py29
-rw-r--r--src/pyglue/DocStrings/OpenColorIO.py17
-rw-r--r--src/pyglue/DocStrings/Processor.py141
-rw-r--r--src/pyglue/DocStrings/ProcessorMetadata.py34
-rw-r--r--src/pyglue/DocStrings/Transform.py19
-rw-r--r--src/pyglue/DocStrings/__init__.py23
-rw-r--r--src/pyglue/PyAllocationTransform.cpp300
-rw-r--r--src/pyglue/PyCDLTransform.cpp611
-rw-r--r--src/pyglue/PyColorSpace.cpp756
-rw-r--r--src/pyglue/PyColorSpace.h52
-rw-r--r--src/pyglue/PyColorSpaceTransform.cpp294
-rw-r--r--src/pyglue/PyConfig.cpp1220
-rw-r--r--src/pyglue/PyConfig.h52
-rw-r--r--src/pyglue/PyConstants.cpp239
-rw-r--r--src/pyglue/PyConstants.h41
-rw-r--r--src/pyglue/PyContext.cpp494
-rw-r--r--src/pyglue/PyContext.h52
-rw-r--r--src/pyglue/PyDisplayTransform.cpp577
-rw-r--r--src/pyglue/PyExponentTransform.cpp269
-rw-r--r--src/pyglue/PyFileTransform.cpp344
-rw-r--r--src/pyglue/PyGroupTransform.cpp397
-rw-r--r--src/pyglue/PyLogTransform.cpp251
-rw-r--r--src/pyglue/PyLook.cpp450
-rw-r--r--src/pyglue/PyLook.h50
-rw-r--r--src/pyglue/PyLookTransform.cpp343
-rw-r--r--src/pyglue/PyMain.cpp236
-rw-r--r--src/pyglue/PyMatrixTransform.cpp630
-rw-r--r--src/pyglue/PyProcessor.cpp500
-rw-r--r--src/pyglue/PyProcessor.h50
-rw-r--r--src/pyglue/PyProcessorMetadata.cpp245
-rw-r--r--src/pyglue/PyProcessorMetadata.h50
-rw-r--r--src/pyglue/PyTransform.cpp411
-rw-r--r--src/pyglue/PyTransform.h81
-rw-r--r--src/pyglue/PyUtil.cpp742
-rw-r--r--src/pyglue/PyUtil.h103
-rw-r--r--src/pyglue/createPyDocH.py86
-rw-r--r--src/rv/Makefile6
-rw-r--r--src/rv/Mu/rvload1
-rw-r--r--src/rv/Mu/rvload22
-rw-r--r--src/rv/Packages/.gitignore1
-rw-r--r--src/rv/Packages/rvinstall1
-rw-r--r--src/rv/Python/PACKAGE12
-rw-r--r--src/rv/Python/ociorv.py288
287 files changed, 72835 insertions, 0 deletions
diff --git a/src/aftereffects/DrawbotBot.cpp b/src/aftereffects/DrawbotBot.cpp
new file mode 100644
index 0000000..3d6cee6
--- /dev/null
+++ b/src/aftereffects/DrawbotBot.cpp
@@ -0,0 +1,239 @@
+/*
+Copyright (c) 2003-2012 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 "DrawbotBot.h"
+
+
+DrawbotBot::DrawbotBot(struct SPBasicSuite *pica_basicP, PF_ContextH contextH, A_long appl_id) :
+ suites(pica_basicP),
+ _appl_id(appl_id),
+ _suiteP(NULL),
+ _drawbot_ref(NULL),
+ _supplier_ref(NULL),
+ _surface_ref(NULL)
+{
+ suites.EffectCustomUISuite1()->PF_GetDrawingReference(contextH, &_drawbot_ref);
+
+ _suiteP = suites.SupplierSuiteCurrent();
+
+ suites.DrawbotSuiteCurrent()->GetSupplier(_drawbot_ref, &_supplier_ref);
+ suites.DrawbotSuiteCurrent()->GetSurface(_drawbot_ref, &_surface_ref);
+
+ _brush_pos.x = 0.f;
+ _brush_pos.y = 0.f;
+
+ SetColor(PF_App_Color_TEXT);
+
+ _suiteP->GetDefaultFontSize(_supplier_ref, &_font_size);
+}
+
+
+DrawbotBot::~DrawbotBot()
+{
+
+}
+
+
+void DrawbotBot::SetColor(PF_App_ColorType color, float a)
+{
+ if(_appl_id == 'FXTC')
+ {
+ PF_App_Color app_color;
+
+ suites.AppSuite4()->PF_AppGetColor(color, &app_color);
+
+ _brush_color.red = (float)app_color.red / (float)PF_MAX_CHAN16;
+ _brush_color.green = (float)app_color.green / (float)PF_MAX_CHAN16;
+ _brush_color.blue = (float)app_color.blue / (float)PF_MAX_CHAN16;
+ }
+ else
+ {
+ // Premiere isn't doing this properly, so I'll have to.
+ // Only supporting the colors I'm actually using at the moment.
+ switch(color)
+ {
+ case PF_App_Color_BLACK:
+ _brush_color.red = _brush_color.green = _brush_color.blue = 0.f;
+ break;
+
+ case PF_App_Color_WHITE:
+ _brush_color.red = _brush_color.green = _brush_color.blue = 1.f;
+ break;
+
+ case PF_App_Color_RED:
+ _brush_color.red = 1.f;
+ _brush_color.green = _brush_color.blue = 0.f;
+ break;
+
+ case PF_App_Color_TEXT_DISABLED:
+ _brush_color.red = _brush_color.green = _brush_color.blue = 0.6f;
+ break;
+
+ case PF_App_Color_SHADOW:
+ _brush_color.red = _brush_color.green = _brush_color.blue = 0.3f;
+ break;
+
+ case PF_App_Color_HILITE:
+ _brush_color.red = _brush_color.green = _brush_color.blue = 0.8f;
+ break;
+
+ case PF_App_Color_LIGHT_TINGE:
+ _brush_color.red = _brush_color.green = _brush_color.blue = 0.7f;
+ break;
+
+ case PF_App_Color_BUTTON_FILL:
+ _brush_color.red = _brush_color.green = _brush_color.blue = 0.5f;
+ break;
+
+ case PF_App_Color_BUTTON_PRESSED_FILL:
+ _brush_color.red = _brush_color.green = _brush_color.blue = 0.3f;
+ break;
+
+ case PF_App_Color_PANEL_BACKGROUND:
+ {
+ PF_App_Color app_color;
+ suites.AppSuite4()->PF_AppGetBgColor(&app_color);
+
+ _brush_color.red = (float)app_color.red / (float)65535;
+ _brush_color.green = (float)app_color.green / (float)65535;
+ _brush_color.blue = (float)app_color.blue / (float)65535;
+ }
+ break;
+
+ default:
+ _brush_color.red = _brush_color.green = _brush_color.blue = 0.9f;
+ break;
+ }
+ }
+
+ _brush_color.alpha = a;
+}
+
+
+void DrawbotBot::DrawLineTo(float x, float y, float brush_size)
+{
+ DRAWBOT_PathP pathP(_suiteP, _supplier_ref);
+ DRAWBOT_PenP penP(_suiteP, _supplier_ref, &_brush_color, brush_size);
+
+ suites.PathSuiteCurrent()->MoveTo(pathP.Get(), _brush_pos.x, _brush_pos.y);
+
+ suites.PathSuiteCurrent()->LineTo(pathP.Get(), x, y);
+
+ suites.SurfaceSuiteCurrent()->StrokePath(_surface_ref, penP.Get(), pathP.Get());
+
+ MoveTo(x, y);
+}
+
+
+void DrawbotBot::DrawRect(float w, float h, float brush_size) const
+{
+ DRAWBOT_PathP pathP(_suiteP, _supplier_ref);
+ DRAWBOT_PenP penP(_suiteP, _supplier_ref, &_brush_color, brush_size);
+
+ DRAWBOT_RectF32 rect;
+
+ rect.left = _brush_pos.x - 0.5f;
+ rect.top = _brush_pos.y - 0.5f;
+ rect.width = w;
+ rect.height = h;
+
+ suites.PathSuiteCurrent()->AddRect(pathP.Get(), &rect);
+
+ suites.SurfaceSuiteCurrent()->StrokePath(_surface_ref, penP.Get(), pathP.Get());
+}
+
+void DrawbotBot::PaintRect(float w, float h) const
+{
+ DRAWBOT_RectF32 rect;
+
+ rect.left = _brush_pos.x;
+ rect.top = _brush_pos.y;
+ rect.width = w;
+ rect.height = h;
+
+ suites.SurfaceSuiteCurrent()->PaintRect(_surface_ref, &_brush_color, &rect);
+}
+
+
+void DrawbotBot::PaintTriangle(float w, float h) const
+{
+ DRAWBOT_PathP pathP(_suiteP, _supplier_ref);
+ DRAWBOT_BrushP brushP(_suiteP, _supplier_ref, &_brush_color);
+
+ suites.PathSuiteCurrent()->MoveTo(pathP.Get(), _brush_pos.x, _brush_pos.y);
+
+ suites.PathSuiteCurrent()->LineTo(pathP.Get(), _brush_pos.x + w, _brush_pos.y);
+
+ suites.PathSuiteCurrent()->LineTo(pathP.Get(), _brush_pos.x + (w / 2.f),
+ _brush_pos.y + h);
+
+ suites.PathSuiteCurrent()->Close(pathP.Get());
+
+ suites.SurfaceSuiteCurrent()->FillPath(_surface_ref, brushP.Get(), pathP.Get(),
+ kDRAWBOT_FillType_Default);
+}
+
+
+void DrawbotBot::DrawString(
+ const DRAWBOT_UTF16Char *str,
+ DRAWBOT_TextAlignment align,
+ DRAWBOT_TextTruncation truncate,
+ float truncation_width) const
+{
+ DRAWBOT_BrushP brushP(_suiteP, _supplier_ref, &_brush_color);
+ DRAWBOT_FontP fontP(_suiteP, _supplier_ref, _font_size);
+
+ suites.SurfaceSuiteCurrent()->DrawString(_surface_ref, brushP.Get(), fontP.Get(), str,
+ &_brush_pos, align, truncate, truncation_width);
+}
+
+
+void DrawbotBot::DrawString(
+ const char *str,
+ DRAWBOT_TextAlignment align,
+ DRAWBOT_TextTruncation truncate,
+ float truncation_width) const
+{
+ DRAWBOT_UTF16Char u_str[256] = {'\0'};
+
+ DRAWBOT_UTF16Char *u = u_str;
+ const char *c = str;
+
+ if(*c != '\0')
+ {
+ do{
+ *u++ = *c++;
+
+ }while(*c != '\0');
+
+ *u = '\0';
+ }
+
+ DrawString(u_str, align, truncate, truncation_width);
+} \ No newline at end of file
diff --git a/src/aftereffects/DrawbotBot.h b/src/aftereffects/DrawbotBot.h
new file mode 100644
index 0000000..bd55ace
--- /dev/null
+++ b/src/aftereffects/DrawbotBot.h
@@ -0,0 +1,89 @@
+/*
+Copyright (c) 2003-2012 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.
+*/
+
+
+#ifndef _DRAWBOTBOT_H_
+#define _DRAWBOTBOT_H_
+
+#include "AEGP_SuiteHandler.h"
+
+
+class DrawbotBot
+{
+ public:
+
+ DrawbotBot(struct SPBasicSuite *pica_basicP, PF_ContextH contextH, A_long appl_id);
+ ~DrawbotBot();
+
+ void MoveTo(DRAWBOT_PointF32 pos) { _brush_pos = pos; }
+ void MoveTo(float x, float y) { _brush_pos.x = x; _brush_pos.y = y; }
+ void Move(float x = 0, float y = 0) { _brush_pos.x += x; _brush_pos.y += y; }
+
+ void SetColor(PF_App_ColorType color, float a = 1.f);
+ void SetColor(DRAWBOT_ColorRGBA color) { _brush_color = color; }
+ void SetColor(float r, float g, float b, float a = 1.f)
+ { _brush_color.red = r; _brush_color.green = g;
+ _brush_color.blue = b; _brush_color.alpha = a; }
+
+ DRAWBOT_PointF32 Pos() const { return _brush_pos; }
+ float FontSize() const { return _font_size; }
+
+ void DrawLineTo(float x, float y, float brush_size = 0.5f);
+
+ void DrawRect(float w, float h, float brush_size = 0.5f) const;
+ void PaintRect(float w, float h) const;
+
+ void PaintTriangle(float w, float h) const;
+
+ void DrawString(const DRAWBOT_UTF16Char *str,
+ DRAWBOT_TextAlignment align = kDRAWBOT_TextAlignment_Default,
+ DRAWBOT_TextTruncation truncate = kDRAWBOT_TextTruncation_None,
+ float truncation_width = 0.f) const;
+ void DrawString(const char *str,
+ DRAWBOT_TextAlignment align = kDRAWBOT_TextAlignment_Default,
+ DRAWBOT_TextTruncation truncate = kDRAWBOT_TextTruncation_None,
+ float truncation_width = 0.f) const;
+
+
+ private:
+ AEGP_SuiteHandler suites;
+ A_long _appl_id;
+
+ DRAWBOT_SupplierSuiteCurrent *_suiteP;
+
+ DRAWBOT_DrawRef _drawbot_ref;
+ DRAWBOT_SupplierRef _supplier_ref;
+ DRAWBOT_SurfaceRef _surface_ref;
+
+ DRAWBOT_PointF32 _brush_pos;
+ DRAWBOT_ColorRGBA _brush_color;
+ float _font_size;
+};
+
+
+#endif // _DRAWBOTBOT_H_ \ No newline at end of file
diff --git a/src/aftereffects/OpenColorIO_AE.cpp b/src/aftereffects/OpenColorIO_AE.cpp
new file mode 100755
index 0000000..cd89091
--- /dev/null
+++ b/src/aftereffects/OpenColorIO_AE.cpp
@@ -0,0 +1,1133 @@
+/*
+Copyright (c) 2003-2012 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_AE.h"
+
+#include "OpenColorIO_AE_Context.h"
+#include "OpenColorIO_AE_Dialogs.h"
+
+#include "AEGP_SuiteHandler.h"
+
+// this lives in OpenColorIO_AE_UI.cpp
+std::string GetProjectDir(PF_InData *in_data);
+
+
+static PF_Err About(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output )
+{
+ PF_SPRINTF( out_data->return_msg,
+ "OpenColorIO\r\r"
+ "opencolorio.org\r"
+ "version %s",
+ OCIO::GetVersion() );
+
+ return PF_Err_NONE;
+}
+
+
+static PF_Err GlobalSetup(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output )
+{
+ out_data->my_version = PF_VERSION( MAJOR_VERSION,
+ MINOR_VERSION,
+ BUG_VERSION,
+ STAGE_VERSION,
+ BUILD_VERSION);
+
+ out_data->out_flags = PF_OutFlag_DEEP_COLOR_AWARE |
+ PF_OutFlag_PIX_INDEPENDENT |
+ PF_OutFlag_CUSTOM_UI |
+ PF_OutFlag_USE_OUTPUT_EXTENT |
+ PF_OutFlag_I_HAVE_EXTERNAL_DEPENDENCIES;
+
+ out_data->out_flags2 = PF_OutFlag2_PARAM_GROUP_START_COLLAPSED_FLAG |
+ PF_OutFlag2_SUPPORTS_SMART_RENDER |
+ PF_OutFlag2_FLOAT_COLOR_AWARE |
+ PF_OutFlag2_PPRO_DO_NOT_CLONE_SEQUENCE_DATA_FOR_RENDER;
+
+
+ GlobalSetup_GL();
+
+
+ if(in_data->appl_id == 'PrMr')
+ {
+ PF_PixelFormatSuite1 *pfS = NULL;
+
+ in_data->pica_basicP->AcquireSuite(kPFPixelFormatSuite,
+ kPFPixelFormatSuiteVersion1,
+ (const void **)&pfS);
+
+ if(pfS)
+ {
+ pfS->ClearSupportedPixelFormats(in_data->effect_ref);
+
+ pfS->AddSupportedPixelFormat(in_data->effect_ref,
+ PrPixelFormat_BGRA_4444_32f_Linear);
+
+ in_data->pica_basicP->ReleaseSuite(kPFPixelFormatSuite,
+ kPFPixelFormatSuiteVersion1);
+ }
+ }
+
+ return PF_Err_NONE;
+}
+
+
+static PF_Err GlobalSetdown(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output )
+{
+ GlobalSetdown_GL();
+
+ return PF_Err_NONE;
+}
+
+
+static PF_Err ParamsSetup(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output)
+{
+ PF_Err err = PF_Err_NONE;
+ PF_ParamDef def;
+
+
+ // readout
+ AEFX_CLR_STRUCT(def);
+ // we can time_vary once we're willing to print and scan ArbData text
+ def.flags = PF_ParamFlag_CANNOT_TIME_VARY;
+
+ ArbNewDefault(in_data, out_data, NULL, &def.u.arb_d.dephault);
+
+ PF_ADD_ARBITRARY("OCIO",
+ UI_CONTROL_WIDTH,
+ UI_CONTROL_HEIGHT,
+ PF_PUI_CONTROL,
+ def.u.arb_d.dephault,
+ OCIO_DATA,
+ NULL);
+
+
+ AEFX_CLR_STRUCT(def);
+ PF_ADD_CHECKBOX("",
+ "Use GPU",
+ FALSE,
+ 0,
+ OCIO_GPU_ID);
+
+
+ out_data->num_params = OCIO_NUM_PARAMS;
+
+ // register custom UI
+ if (!err)
+ {
+ PF_CustomUIInfo ci;
+
+ AEFX_CLR_STRUCT(ci);
+
+ ci.events = PF_CustomEFlag_EFFECT;
+
+ ci.comp_ui_width = ci.comp_ui_height = 0;
+ ci.comp_ui_alignment = PF_UIAlignment_NONE;
+
+ ci.layer_ui_width = 0;
+ ci.layer_ui_height = 0;
+ ci.layer_ui_alignment = PF_UIAlignment_NONE;
+
+ ci.preview_ui_width = 0;
+ ci.preview_ui_height = 0;
+ ci.layer_ui_alignment = PF_UIAlignment_NONE;
+
+ err = (*(in_data->inter.register_ui))(in_data->effect_ref, &ci);
+ }
+
+
+ return err;
+}
+
+static PF_Err SequenceSetup(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output )
+{
+ PF_Err err = PF_Err_NONE;
+
+ SequenceData *seq_data = NULL;
+
+ // set up sequence data
+ if( (in_data->sequence_data == NULL) )
+ {
+ out_data->sequence_data = PF_NEW_HANDLE( sizeof(SequenceData) );
+
+ seq_data = (SequenceData *)PF_LOCK_HANDLE(out_data->sequence_data);
+
+ seq_data->path[0] = '\0';
+ seq_data->relative_path[0] = '\0';
+ }
+ else // reset pre-existing sequence data
+ {
+ if( PF_GET_HANDLE_SIZE(in_data->sequence_data) != sizeof(SequenceData) )
+ {
+ PF_RESIZE_HANDLE(sizeof(SequenceData), &in_data->sequence_data);
+ }
+
+ seq_data = (SequenceData *)PF_LOCK_HANDLE(in_data->sequence_data);
+ }
+
+
+ seq_data->status = STATUS_UNKNOWN;
+ seq_data->gpu_err = GPU_ERR_NONE;
+ seq_data->prem_status = PREMIERE_UNKNOWN;
+ seq_data->context = NULL;
+
+
+ PF_UNLOCK_HANDLE(in_data->sequence_data);
+
+ return err;
+}
+
+
+static PF_Err SequenceSetdown(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output )
+{
+ PF_Err err = PF_Err_NONE;
+
+ if(in_data->sequence_data)
+ {
+ SequenceData *seq_data = (SequenceData *)PF_LOCK_HANDLE(out_data->sequence_data);
+
+ if(seq_data->context)
+ {
+ delete seq_data->context;
+
+ seq_data->status = STATUS_UNKNOWN;
+ seq_data->gpu_err = GPU_ERR_NONE;
+ seq_data->prem_status = PREMIERE_UNKNOWN;
+ seq_data->context = NULL;
+ }
+
+ PF_DISPOSE_HANDLE(in_data->sequence_data);
+ }
+
+ return err;
+}
+
+
+static PF_Err SequenceFlatten(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output )
+{
+ PF_Err err = PF_Err_NONE;
+
+ if(in_data->sequence_data)
+ {
+ SequenceData *seq_data = (SequenceData *)PF_LOCK_HANDLE(in_data->sequence_data);
+
+ if(seq_data->context)
+ {
+ delete seq_data->context;
+
+ seq_data->status = STATUS_UNKNOWN;
+ seq_data->gpu_err = GPU_ERR_NONE;
+ seq_data->prem_status = PREMIERE_UNKNOWN;
+ seq_data->context = NULL;
+ }
+
+ PF_UNLOCK_HANDLE(in_data->sequence_data);
+ }
+
+ return err;
+}
+
+
+
+static PF_Boolean IsEmptyRect(const PF_LRect *r){
+ return (r->left >= r->right) || (r->top >= r->bottom);
+}
+
+#ifndef mmin
+ #define mmin(a,b) ((a) < (b) ? (a) : (b))
+ #define mmax(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+
+static void UnionLRect(const PF_LRect *src, PF_LRect *dst)
+{
+ if (IsEmptyRect(dst)) {
+ *dst = *src;
+ } else if (!IsEmptyRect(src)) {
+ dst->left = mmin(dst->left, src->left);
+ dst->top = mmin(dst->top, src->top);
+ dst->right = mmax(dst->right, src->right);
+ dst->bottom = mmax(dst->bottom, src->bottom);
+ }
+}
+
+
+static PF_Err PreRender(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_PreRenderExtra *extra)
+{
+ PF_Err err = PF_Err_NONE;
+ PF_RenderRequest req = extra->input->output_request;
+ PF_CheckoutResult in_result;
+
+ req.preserve_rgb_of_zero_alpha = TRUE;
+
+ ERR(extra->cb->checkout_layer( in_data->effect_ref,
+ OCIO_INPUT,
+ OCIO_INPUT,
+ &req,
+ in_data->current_time,
+ in_data->time_step,
+ in_data->time_scale,
+ &in_result));
+
+
+ UnionLRect(&in_result.result_rect, &extra->output->result_rect);
+ UnionLRect(&in_result.max_result_rect, &extra->output->max_result_rect);
+
+ return err;
+}
+
+#pragma mark-
+
+
+template <typename InFormat, typename OutFormat>
+static inline OutFormat Convert(InFormat in);
+
+template <>
+static inline float Convert<A_u_char, float>(A_u_char in)
+{
+ return (float)in / (float)PF_MAX_CHAN8;
+}
+
+template <>
+static inline float Convert<A_u_short, float>(A_u_short in)
+{
+ return (float)in / (float)PF_MAX_CHAN16;
+}
+
+template <>
+static inline float Convert<float, float>(float in)
+{
+ return in;
+}
+
+static inline float Clamp(float in)
+{
+ return (in > 1.f ? 1.f : in < 0.f ? 0.f : in);
+}
+
+template <>
+static inline A_u_char Convert<float, A_u_char>(float in)
+{
+ return ( Clamp(in) * (float)PF_MAX_CHAN8 ) + 0.5f;
+}
+
+template <>
+static inline A_u_short Convert<float, A_u_short>(float in)
+{
+ return ( Clamp(in) * (float)PF_MAX_CHAN16 ) + 0.5f;
+}
+
+
+
+typedef struct {
+ PF_InData *in_data;
+ void *in_buffer;
+ A_long in_rowbytes;
+ void *out_buffer;
+ A_long out_rowbytes;
+ int width;
+} IterateData;
+
+template <typename InFormat, typename OutFormat>
+static PF_Err CopyWorld_Iterate(
+ void *refconPV,
+ A_long thread_indexL,
+ A_long i,
+ A_long iterationsL)
+{
+ PF_Err err = PF_Err_NONE;
+
+ IterateData *i_data = (IterateData *)refconPV;
+ PF_InData *in_data = i_data->in_data;
+
+ InFormat *in_pix = (InFormat *)((char *)i_data->in_buffer + (i * i_data->in_rowbytes));
+ OutFormat *out_pix = (OutFormat *)((char *)i_data->out_buffer + (i * i_data->out_rowbytes));
+
+#ifdef NDEBUG
+ if(thread_indexL == 0)
+ err = PF_ABORT(in_data);
+#endif
+
+ for(int x=0; x < i_data->width; x++)
+ {
+ *out_pix++ = Convert<InFormat, OutFormat>( *in_pix++ );
+ }
+
+ return err;
+}
+
+
+typedef struct {
+ PF_InData *in_data;
+ void *in_buffer;
+ A_long in_rowbytes;
+ int width;
+} SwapData;
+
+static PF_Err Swap_Iterate(
+ void *refconPV,
+ A_long thread_indexL,
+ A_long i,
+ A_long iterationsL)
+{
+ PF_Err err = PF_Err_NONE;
+
+ SwapData *i_data = (SwapData *)refconPV;
+ PF_InData *in_data = i_data->in_data;
+
+ PF_PixelFloat *pix = (PF_PixelFloat *)((char *)i_data->in_buffer + (i * i_data->in_rowbytes));
+
+#ifdef NDEBUG
+ if(thread_indexL == 0)
+ err = PF_ABORT(in_data);
+#endif
+
+ for(int x=0; x < i_data->width; x++)
+ {
+ float temp;
+
+ // BGRA -> ARGB
+ temp = pix->alpha; // BGRA temp B
+ pix->alpha = pix->blue; // AGRA temp B
+ pix->blue = temp; // AGRB temp B
+ temp = pix->red; // AGRB temp G
+ pix->red = pix->green; // ARRB temp G
+ pix->green = temp; // ARGB temp G
+
+ pix++;
+ }
+
+ return err;
+}
+
+
+typedef struct {
+ PF_InData *in_data;
+ void *buffer;
+ A_long rowbytes;
+ int width;
+ OpenColorIO_AE_Context *context;
+} ProcessData;
+
+static PF_Err Process_Iterate(
+ void *refconPV,
+ A_long thread_indexL,
+ A_long i,
+ A_long iterationsL)
+{
+ PF_Err err = PF_Err_NONE;
+
+ ProcessData *i_data = (ProcessData *)refconPV;
+ PF_InData *in_data = i_data->in_data;
+
+ PF_PixelFloat *pix = (PF_PixelFloat *)((char *)i_data->buffer + (i * i_data->rowbytes));
+
+#ifdef NDEBUG
+ if(thread_indexL == 0)
+ err = PF_ABORT(in_data);
+#endif
+
+ try
+ {
+ float *rOut = &pix->red;
+
+ OCIO::PackedImageDesc img(rOut, i_data->width, 1, 4);
+
+ i_data->context->processor()->apply(img);
+ }
+ catch(...)
+ {
+ err = PF_Err_INTERNAL_STRUCT_DAMAGED;
+ }
+
+
+ return err;
+}
+
+
+// two functions below to get Premiere to run my functions multi-threaded
+// because they couldn't bother to give me PF_Iterate8Suite1->iterate_generic
+
+typedef PF_Err (*GenericIterator)(void *refconPV,
+ A_long thread_indexL,
+ A_long i,
+ A_long iterationsL);
+
+typedef struct {
+ PF_InData *in_data;
+ GenericIterator fn_func;
+ void *refconPV;
+ A_long height;
+} FakeData;
+
+static PF_Err MyFakeIterator(
+ void *refcon,
+ A_long x,
+ A_long y,
+ PF_Pixel *in,
+ PF_Pixel *out)
+{
+ PF_Err err = PF_Err_NONE;
+
+ FakeData *i_data = (FakeData *)refcon;
+ PF_InData *in_data = i_data->in_data;
+
+ err = i_data->fn_func(i_data->refconPV, 1, y, i_data->height);
+
+ return err;
+}
+
+typedef PF_Err (*GenericIterateFunc)(
+ A_long iterationsL,
+ void *refconPV,
+ GenericIterator fn_func);
+
+static PF_Err MyGenericIterateFunc(
+ A_long iterationsL,
+ void *refconPV,
+ GenericIterator fn_func)
+{
+ PF_Err err = PF_Err_NONE;
+
+ PF_InData **in_dataH = (PF_InData **)refconPV; // always put PF_InData first
+ PF_InData *in_data = *in_dataH;
+
+ PF_Iterate8Suite1 *i8sP = NULL;
+ in_data->pica_basicP->AcquireSuite(kPFIterate8Suite, kPFIterate8SuiteVersion1, (const void **)&i8sP);
+
+ if(i8sP && i8sP->iterate)
+ {
+ PF_EffectWorld fake_world;
+ PF_NEW_WORLD(1, iterationsL, PF_NewWorldFlag_NONE, &fake_world);
+
+
+ FakeData i_data = { in_data, fn_func, refconPV, iterationsL };
+
+ err = i8sP->iterate(in_data, 0, iterationsL, &fake_world, NULL,
+ (void *)&i_data, MyFakeIterator, &fake_world);
+
+
+ PF_DISPOSE_WORLD(&fake_world);
+
+ in_data->pica_basicP->ReleaseSuite(kPFIterate8Suite, kPFIterate8SuiteVersion1);
+ }
+ else
+ {
+ for(int i=0; i < iterationsL && !err; i++)
+ {
+ err = fn_func(refconPV, 0, i, iterationsL);
+ }
+ }
+
+ return err;
+}
+
+
+static PF_Err DoRender(
+ PF_InData *in_data,
+ PF_EffectWorld *input,
+ PF_ParamDef *OCIO_data,
+ PF_ParamDef *OCIO_gpu,
+ PF_OutData *out_data,
+ PF_EffectWorld *output)
+{
+ PF_Err err = PF_Err_NONE;
+
+ AEGP_SuiteHandler suites(in_data->pica_basicP);
+
+ PF_PixelFormatSuite1 *pfS = NULL;
+ PF_WorldSuite2 *wsP = NULL;
+
+ err = in_data->pica_basicP->AcquireSuite(kPFPixelFormatSuite, kPFPixelFormatSuiteVersion1, (const void **)&pfS);
+ err = in_data->pica_basicP->AcquireSuite(kPFWorldSuite, kPFWorldSuiteVersion2, (const void **)&wsP);
+
+ if(!err)
+ {
+ ArbitraryData *arb_data = (ArbitraryData *)PF_LOCK_HANDLE(OCIO_data->u.arb_d.value);
+ SequenceData *seq_data = (SequenceData *)PF_LOCK_HANDLE(in_data->sequence_data);
+
+ try
+ {
+ seq_data->status = STATUS_OK;
+
+ std::string dir = GetProjectDir(in_data);
+
+ // must always verify that our context lines up with the parameters
+ // things like undo can change them without notice
+ if(seq_data->context != NULL)
+ {
+ bool verified = seq_data->context->Verify(arb_data, dir);
+
+ if(!verified)
+ {
+ delete seq_data->context;
+
+ seq_data->status = STATUS_UNKNOWN;
+ seq_data->context = NULL;
+ }
+ }
+
+
+ if(arb_data->action == OCIO_ACTION_NONE)
+ {
+ seq_data->status = STATUS_NO_FILE;
+ }
+ else if(seq_data->context == NULL)
+ {
+ seq_data->source = arb_data->source;
+
+ if(arb_data->source == OCIO_SOURCE_ENVIRONMENT)
+ {
+ char *file = std::getenv("OCIO");
+
+ if(file == NULL)
+ seq_data->status = STATUS_FILE_MISSING;
+ }
+ else if(arb_data->source == OCIO_SOURCE_STANDARD)
+ {
+ std::string path = GetStdConfigPath(arb_data->path);
+
+ if( path.empty() )
+ {
+ seq_data->status = STATUS_FILE_MISSING;
+ }
+ else
+ {
+ strncpy(seq_data->path, arb_data->path, ARB_PATH_LEN);
+ strncpy(seq_data->relative_path, arb_data->relative_path, ARB_PATH_LEN);
+ }
+ }
+ else if(arb_data->source == OCIO_SOURCE_CUSTOM)
+ {
+ Path absolute_path(arb_data->path, dir);
+ Path relative_path(arb_data->relative_path, dir);
+ Path seq_absolute_path(seq_data->path, dir);
+ Path seq_relative_path(seq_data->relative_path, dir);
+
+ if( absolute_path.exists() )
+ {
+ seq_data->status = STATUS_USING_ABSOLUTE;
+
+ strncpy(seq_data->path, absolute_path.full_path().c_str(), ARB_PATH_LEN);
+ strncpy(seq_data->relative_path, absolute_path.relative_path(false).c_str(), ARB_PATH_LEN);
+ }
+ else if( relative_path.exists() )
+ {
+ seq_data->status = STATUS_USING_RELATIVE;
+
+ strncpy(seq_data->path, relative_path.full_path().c_str(), ARB_PATH_LEN);
+ strncpy(seq_data->relative_path, relative_path.relative_path(false).c_str(), ARB_PATH_LEN);
+ }
+ else if( seq_absolute_path.exists() )
+ {
+ // In some cases, we may have a good path in sequence options but not in
+ // the arbitrary parameter. An alert will not be provided because it is the
+ // sequence options that get checked. Therefore, we have to use the sequence
+ // options as a last resort. We copy the path back to arb data, but the change
+ // should not stick.
+ seq_data->status = STATUS_USING_ABSOLUTE;
+
+ strncpy(arb_data->path, seq_absolute_path.full_path().c_str(), ARB_PATH_LEN);
+ strncpy(arb_data->relative_path, seq_absolute_path.relative_path(false).c_str(), ARB_PATH_LEN);
+ }
+ else if( seq_relative_path.exists() )
+ {
+ seq_data->status = STATUS_USING_RELATIVE;
+
+ strncpy(arb_data->path, seq_relative_path.full_path().c_str(), ARB_PATH_LEN);
+ strncpy(arb_data->relative_path, seq_relative_path.relative_path(false).c_str(), ARB_PATH_LEN);
+ }
+ else
+ seq_data->status = STATUS_FILE_MISSING;
+ }
+
+
+ if(seq_data->status != STATUS_FILE_MISSING)
+ {
+ seq_data->context = new OpenColorIO_AE_Context(arb_data, dir);
+ }
+ }
+ }
+ catch(...)
+ {
+ seq_data->status = STATUS_OCIO_ERROR;
+ }
+
+
+ if(seq_data->status == STATUS_FILE_MISSING || seq_data->status == STATUS_OCIO_ERROR)
+ {
+ err = PF_Err_INTERNAL_STRUCT_DAMAGED;
+ }
+
+
+ if(!err)
+ {
+ if(seq_data->context == NULL || seq_data->context->processor()->isNoOp())
+ {
+ err = PF_COPY(input, output, NULL, NULL);
+ }
+ else
+ {
+ GenericIterateFunc iterate_generic = suites.Iterate8Suite1()->iterate_generic;
+
+ if(iterate_generic == NULL)
+ iterate_generic = MyGenericIterateFunc; // thanks a lot, Premiere
+
+ // OpenColorIO only does float worlds
+ // might have to create one
+ PF_EffectWorld *float_world = NULL;
+
+ PF_EffectWorld temp_world_data;
+ PF_EffectWorld *temp_world = NULL;
+ PF_Handle temp_worldH = NULL;
+
+
+ PF_PixelFormat format;
+ wsP->PF_GetPixelFormat(output, &format);
+
+ if(in_data->appl_id == 'PrMr' && pfS)
+ {
+ // the regular world suite function will give a bogus value for Premiere
+ pfS->GetPixelFormat(output, (PrPixelFormat *)&format);
+
+ seq_data->prem_status = (format == PrPixelFormat_BGRA_4444_32f_Linear ?
+ PREMIERE_LINEAR : PREMIERE_NON_LINEAR);
+ }
+
+
+ A_Boolean use_gpu = OCIO_gpu->u.bd.value;
+ seq_data->gpu_err = GPU_ERR_NONE;
+ A_long non_padded_rowbytes = sizeof(PF_PixelFloat) * output->width;
+
+
+ if(format == PF_PixelFormat_ARGB128 &&
+ (!use_gpu || output->rowbytes == non_padded_rowbytes)) // GPU doesn't do padding
+ {
+ err = PF_COPY(input, output, NULL, NULL);
+
+ float_world = output;
+ }
+ else
+ {
+ temp_worldH = PF_NEW_HANDLE(non_padded_rowbytes * (output->height + 1)); // little extra because we go over by a channel
+
+ if(temp_worldH)
+ {
+ temp_world_data.data = (PF_PixelPtr)PF_LOCK_HANDLE(temp_worldH);
+
+ temp_world_data.width = output->width;
+ temp_world_data.height = output->height;
+ temp_world_data.rowbytes = non_padded_rowbytes;
+
+ float_world = temp_world = &temp_world_data;
+
+ // convert to new temp float world
+ IterateData i_data = { in_data, input->data, input->rowbytes,
+ float_world->data, float_world->rowbytes,
+ float_world->width * 4 };
+
+ if(format == PF_PixelFormat_ARGB32 || format == PrPixelFormat_BGRA_4444_8u)
+ {
+ err = iterate_generic(float_world->height, &i_data,
+ CopyWorld_Iterate<A_u_char, float>);
+ }
+ else if(format == PF_PixelFormat_ARGB64)
+ {
+ err = iterate_generic(float_world->height, &i_data,
+ CopyWorld_Iterate<A_u_short, float>);
+ }
+ else if(format == PF_PixelFormat_ARGB128 ||
+ format == PrPixelFormat_BGRA_4444_32f ||
+ format == PrPixelFormat_BGRA_4444_32f_Linear)
+ {
+ err = iterate_generic(float_world->height, &i_data,
+ CopyWorld_Iterate<float, float>);
+ }
+
+ // switch BGRA to ARGB for premiere
+ if(!err &&
+ (format == PrPixelFormat_BGRA_4444_8u ||
+ format == PrPixelFormat_BGRA_4444_32f_Linear ||
+ format == PrPixelFormat_BGRA_4444_32f))
+ {
+ SwapData s_data = { in_data, float_world->data,
+ float_world->rowbytes, float_world->width };
+
+ err = iterate_generic(float_world->height, &s_data,
+ Swap_Iterate);
+ }
+ }
+ else
+ err = PF_Err_OUT_OF_MEMORY;
+ }
+
+
+ if(!err)
+ {
+ bool gpu_rendered = false;
+
+ // OpenColorIO processing
+ if(use_gpu)
+ {
+ if( HaveOpenGL() )
+ {
+ gpu_rendered = seq_data->context->ProcessWorldGL(float_world);
+
+ if(!gpu_rendered)
+ seq_data->gpu_err = GPU_ERR_RENDER_ERR;
+ }
+ else
+ seq_data->gpu_err = GPU_ERR_INSUFFICIENT;
+ }
+
+ if(!gpu_rendered)
+ {
+ ProcessData p_data = { in_data,
+ float_world->data,
+ float_world->rowbytes,
+ float_world->width,
+ seq_data->context };
+
+ err = iterate_generic(float_world->height, &p_data, Process_Iterate);
+ }
+ }
+
+
+ // copy back to non-float world and dispose
+ if(temp_world)
+ {
+ if(!err &&
+ (format == PrPixelFormat_BGRA_4444_8u ||
+ format == PrPixelFormat_BGRA_4444_32f_Linear ||
+ format == PrPixelFormat_BGRA_4444_32f))
+ {
+ SwapData s_data = { in_data, float_world->data,
+ float_world->rowbytes, float_world->width };
+
+ err = iterate_generic(float_world->height, &s_data, Swap_Iterate);
+ }
+
+ if(!err)
+ {
+ IterateData i_data = { in_data, float_world->data,
+ float_world->rowbytes, output->data,
+ output->rowbytes, output->width * 4 };
+
+ if(format == PF_PixelFormat_ARGB32 || format == PrPixelFormat_BGRA_4444_8u)
+ {
+ err = iterate_generic(output->height, &i_data,
+ CopyWorld_Iterate<float, A_u_char>);
+ }
+ else if(format == PF_PixelFormat_ARGB64)
+ {
+ err = iterate_generic(output->height, &i_data,
+ CopyWorld_Iterate<float, A_u_short>);
+ }
+ else if(format == PF_PixelFormat_ARGB128 ||
+ format == PrPixelFormat_BGRA_4444_32f ||
+ format == PrPixelFormat_BGRA_4444_32f_Linear)
+ {
+ err = iterate_generic(output->height, &i_data,
+ CopyWorld_Iterate<float, float>);
+ }
+
+ }
+
+ PF_DISPOSE_HANDLE(temp_worldH);
+ }
+
+
+ PF_UNLOCK_HANDLE(OCIO_data->u.arb_d.value);
+ PF_UNLOCK_HANDLE(in_data->sequence_data);
+
+
+ if(seq_data->gpu_err == GPU_ERR_INSUFFICIENT)
+ {
+ suites.AdvAppSuite2()->PF_AppendInfoText("OpenColorIO: GPU Insufficient");
+ }
+ else if(seq_data->gpu_err == GPU_ERR_RENDER_ERR)
+ {
+ suites.AdvAppSuite2()->PF_AppendInfoText("OpenColorIO: GPU Render Error");
+ }
+ }
+ }
+ }
+
+ if(pfS)
+ in_data->pica_basicP->ReleaseSuite(kPFPixelFormatSuite, kPFPixelFormatSuiteVersion1);
+
+ if(wsP)
+ in_data->pica_basicP->ReleaseSuite(kPFWorldSuite, kPFWorldSuiteVersion2);
+
+
+
+ return err;
+}
+
+
+static PF_Err SmartRender(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_SmartRenderExtra *extra)
+
+{
+ PF_Err err = PF_Err_NONE,
+ err2 = PF_Err_NONE;
+
+ PF_EffectWorld *input, *output;
+
+ PF_ParamDef OCIO_data, OCIO_gpu;
+
+ // zero-out parameters
+ AEFX_CLR_STRUCT(OCIO_data);
+ AEFX_CLR_STRUCT(OCIO_gpu);
+
+
+ // checkout input & output buffers.
+ ERR( extra->cb->checkout_layer_pixels( in_data->effect_ref, OCIO_INPUT, &input) );
+ ERR( extra->cb->checkout_output( in_data->effect_ref, &output) );
+
+
+ // bail before param checkout
+ if(err)
+ return err;
+
+#define PF_CHECKOUT_PARAM_NOW( PARAM, DEST ) \
+ PF_CHECKOUT_PARAM( in_data, (PARAM), in_data->current_time,\
+ in_data->time_step, in_data->time_scale, DEST )
+
+ // checkout the required params
+ ERR( PF_CHECKOUT_PARAM_NOW( OCIO_DATA, &OCIO_data ) );
+ ERR( PF_CHECKOUT_PARAM_NOW( OCIO_GPU, &OCIO_gpu ) );
+
+ ERR(DoRender( in_data,
+ input,
+ &OCIO_data,
+ &OCIO_gpu,
+ out_data,
+ output));
+
+ // Always check in, no matter what the error condition!
+ ERR2( PF_CHECKIN_PARAM(in_data, &OCIO_data ) );
+ ERR2( PF_CHECKIN_PARAM(in_data, &OCIO_gpu ) );
+
+
+ return err;
+
+}
+
+
+static PF_Err Render(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output )
+{
+ return DoRender(in_data,
+ &params[OCIO_INPUT]->u.ld,
+ params[OCIO_DATA],
+ params[OCIO_GPU],
+ out_data,
+ output);
+}
+
+
+static PF_Err GetExternalDependencies(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ExtDependenciesExtra *extra)
+
+{
+ PF_Err err = PF_Err_NONE;
+
+ SequenceData *seq_data = (SequenceData *)PF_LOCK_HANDLE(in_data->sequence_data);
+
+ if(seq_data == NULL)
+ return PF_Err_BAD_CALLBACK_PARAM;
+
+
+ std::string dependency;
+
+ if(seq_data->source == OCIO_SOURCE_ENVIRONMENT)
+ {
+ if(extra->check_type == PF_DepCheckType_ALL_DEPENDENCIES)
+ {
+ dependency = "$OCIO environment variable";
+ }
+ else if(extra->check_type == PF_DepCheckType_MISSING_DEPENDENCIES)
+ {
+ char *file = std::getenv("OCIO");
+
+ if(!file)
+ dependency = "$OCIO environment variable";
+ }
+ }
+ else if(seq_data->source == OCIO_SOURCE_STANDARD)
+ {
+ if(extra->check_type == PF_DepCheckType_ALL_DEPENDENCIES)
+ {
+ dependency = "OCIO configuration " + std::string(seq_data->path);
+ }
+ else if(extra->check_type == PF_DepCheckType_MISSING_DEPENDENCIES)
+ {
+ std::string path = GetStdConfigPath(seq_data->path);
+
+ if( path.empty() )
+ dependency = "OCIO configuration " + std::string(seq_data->path);
+ }
+ }
+ else if(seq_data->source == OCIO_SOURCE_CUSTOM && seq_data->path[0] != '\0')
+ {
+ std::string dir = GetProjectDir(in_data);
+
+ Path absolute_path(seq_data->path, "");
+ Path relative_path(seq_data->relative_path, dir);
+
+ if(extra->check_type == PF_DepCheckType_ALL_DEPENDENCIES)
+ {
+ if( !absolute_path.exists() && relative_path.exists() )
+ {
+ dependency = relative_path.full_path();
+ }
+ else
+ dependency = absolute_path.full_path();
+ }
+ else if(extra->check_type == PF_DepCheckType_MISSING_DEPENDENCIES &&
+ !absolute_path.exists() && !relative_path.exists() )
+ {
+ dependency = absolute_path.full_path();
+ }
+ }
+
+
+ if( !dependency.empty() )
+ {
+ extra->dependencies_strH = PF_NEW_HANDLE(sizeof(char) * (dependency.size() + 1));
+
+ char *p = (char *)PF_LOCK_HANDLE(extra->dependencies_strH);
+
+ strcpy(p, dependency.c_str());
+ }
+
+
+ PF_UNLOCK_HANDLE(in_data->sequence_data);
+
+ return err;
+}
+
+
+DllExport PF_Err PluginMain(
+ PF_Cmd cmd,
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output,
+ void *extra)
+{
+ PF_Err err = PF_Err_NONE;
+
+ try {
+ switch(cmd) {
+ case PF_Cmd_ABOUT:
+ err = About(in_data,out_data,params,output);
+ break;
+ case PF_Cmd_GLOBAL_SETUP:
+ err = GlobalSetup(in_data,out_data,params,output);
+ break;
+ case PF_Cmd_GLOBAL_SETDOWN:
+ err = GlobalSetdown(in_data,out_data,params,output);
+ break;
+ case PF_Cmd_PARAMS_SETUP:
+ err = ParamsSetup(in_data,out_data,params,output);
+ break;
+ case PF_Cmd_SEQUENCE_SETUP:
+ case PF_Cmd_SEQUENCE_RESETUP:
+ err = SequenceSetup(in_data, out_data, params, output);
+ break;
+ case PF_Cmd_SEQUENCE_FLATTEN:
+ err = SequenceFlatten(in_data, out_data, params, output);
+ break;
+ case PF_Cmd_SEQUENCE_SETDOWN:
+ err = SequenceSetdown(in_data, out_data, params, output);
+ break;
+ case PF_Cmd_SMART_PRE_RENDER:
+ err = PreRender(in_data, out_data, (PF_PreRenderExtra*)extra);
+ break;
+ case PF_Cmd_SMART_RENDER:
+ err = SmartRender(in_data, out_data, (PF_SmartRenderExtra*)extra);
+ break;
+ case PF_Cmd_RENDER:
+ err = Render(in_data, out_data, params, output);
+ break;
+ case PF_Cmd_EVENT:
+ err = HandleEvent(in_data, out_data, params, output, (PF_EventExtra *)extra);
+ break;
+ case PF_Cmd_ARBITRARY_CALLBACK:
+ err = HandleArbitrary(in_data, out_data, params, output, (PF_ArbParamsExtra *)extra);
+ break;
+ case PF_Cmd_GET_EXTERNAL_DEPENDENCIES:
+ err = GetExternalDependencies(in_data, out_data, (PF_ExtDependenciesExtra *)extra);
+ break;
+ }
+ }
+ catch(PF_Err &thrown_err) { err = thrown_err; }
+ catch(...) { err = PF_Err_INTERNAL_STRUCT_DAMAGED; }
+
+ return err;
+}
diff --git a/src/aftereffects/OpenColorIO_AE.h b/src/aftereffects/OpenColorIO_AE.h
new file mode 100755
index 0000000..98eb314
--- /dev/null
+++ b/src/aftereffects/OpenColorIO_AE.h
@@ -0,0 +1,227 @@
+/*
+Copyright (c) 2003-2012 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.
+*/
+
+#pragma once
+
+#ifndef _OPENCOLORIO_AE_H_
+#define _OPENCOLORIO_AE_H_
+
+
+//#define PF_DEEP_COLOR_AWARE 1 // do we really still need this?
+
+#include "AEConfig.h"
+#include "entry.h"
+#include "SPTypes.h"
+#include "PrSDKAESupport.h"
+#include "AE_Macros.h"
+#include "Param_Utils.h"
+#include "AE_Effect.h"
+#include "AE_EffectUI.h"
+#include "AE_EffectCB.h"
+
+
+#ifdef MSWindows
+ #include <Windows.h>
+#else
+ #ifndef __MACH__
+ #include "string.h"
+ #endif
+#endif
+
+
+// Versioning information
+#define MAJOR_VERSION 1
+#define MINOR_VERSION 0
+#define BUG_VERSION 0
+#define STAGE_VERSION PF_Stage_RELEASE
+#define BUILD_VERSION 0
+
+// Paramater constants
+enum {
+ OCIO_INPUT = 0,
+ OCIO_DATA,
+ OCIO_GPU,
+
+ OCIO_NUM_PARAMS
+};
+
+enum {
+ OCIO_DATA_ID = 1,
+ OCIO_GPU_ID
+};
+
+
+// Our Arbitrary Data struct
+
+#define CURRENT_ARB_VERSION 1
+#define ARB_PATH_LEN 255
+#define ARB_SPACE_LEN 63
+
+enum {
+ OCIO_ACTION_NONE = 0,
+ OCIO_ACTION_LUT,
+ OCIO_ACTION_CONVERT,
+ OCIO_ACTION_DISPLAY
+};
+typedef A_u_char OCIO_Action;
+
+enum {
+ OCIO_STORAGE_NONE = 0,
+ OCIO_STORAGE_ZIP_FILE
+};
+typedef A_u_char OCIO_Storage;
+
+enum {
+ OCIO_SOURCE_NONE = 0,
+ OCIO_SOURCE_ENVIRONMENT,
+ OCIO_SOURCE_STANDARD,
+ OCIO_SOURCE_CUSTOM
+};
+typedef A_u_char OCIO_Source;
+
+enum {
+ OCIO_INTERP_UNKNOWN = 0,
+ OCIO_INTERP_NEAREST = 1,
+ OCIO_INTERP_LINEAR = 2,
+ OCIO_INTERP_TETRAHEDRAL = 3,
+ OCIO_INTERP_BEST = 255
+};
+typedef A_u_char OCIO_Interp;
+
+typedef struct {
+ A_u_char version; // version of this data structure
+ OCIO_Action action;
+ A_Boolean invert; // only used for LUTs
+ OCIO_Storage storage; // storage not used...yet
+ A_u_long storage_size;
+ OCIO_Source source;
+ OCIO_Interp interpolation;
+ A_u_char reserved[54]; // 64 pre-path bytes
+ char path[ARB_PATH_LEN+1];
+ char relative_path[ARB_PATH_LEN+1];
+ char input[ARB_SPACE_LEN+1];
+ char output[ARB_SPACE_LEN+1];
+ char transform[ARB_SPACE_LEN+1];
+ char device[ARB_SPACE_LEN+1];
+ char look[ARB_SPACE_LEN+1]; // not used currently
+ A_u_char storage_buf[1];
+} ArbitraryData;
+
+
+#ifdef __cplusplus
+
+class OpenColorIO_AE_Context;
+
+enum {
+ STATUS_UNKNOWN = 0,
+ STATUS_OK,
+ STATUS_NO_FILE,
+ STATUS_USING_ABSOLUTE,
+ STATUS_USING_RELATIVE,
+ STATUS_FILE_MISSING,
+ STATUS_OCIO_ERROR
+};
+typedef A_u_char FileStatus;
+
+enum {
+ GPU_ERR_NONE = 0,
+ GPU_ERR_INSUFFICIENT,
+ GPU_ERR_RENDER_ERR
+};
+typedef A_u_char GPUErr;
+
+enum {
+ PREMIERE_UNKNOWN = 0,
+ PREMIERE_LINEAR,
+ PREMIERE_NON_LINEAR
+};
+typedef A_u_char PremiereStatus;
+
+typedef struct {
+ FileStatus status;
+ GPUErr gpu_err;
+ PremiereStatus prem_status;
+ OCIO_Source source;
+ OpenColorIO_AE_Context *context;
+ char path[ARB_PATH_LEN+1];
+ char relative_path[ARB_PATH_LEN+1];
+} SequenceData;
+
+#endif
+
+
+
+#define UI_CONTROL_HEIGHT 200
+#define UI_CONTROL_WIDTH 500
+
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+
+// Prototypes
+
+DllExport PF_Err PluginMain(
+ PF_Cmd cmd,
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output,
+ void *extra) ;
+
+
+PF_Err HandleEvent(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output,
+ PF_EventExtra *extra );
+
+
+PF_Err ArbNewDefault( // needed by ParamSetup()
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ void *refconPV,
+ PF_ArbitraryH *arbPH);
+
+PF_Err HandleArbitrary(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output,
+ PF_ArbParamsExtra *extra);
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+
+
+#endif // _OPENCOLORIO_AE_H_ \ No newline at end of file
diff --git a/src/aftereffects/OpenColorIO_AE_ArbData.cpp b/src/aftereffects/OpenColorIO_AE_ArbData.cpp
new file mode 100644
index 0000000..0e55541
--- /dev/null
+++ b/src/aftereffects/OpenColorIO_AE_ArbData.cpp
@@ -0,0 +1,408 @@
+/*
+Copyright (c) 2003-2012 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_AE.h"
+
+#include "OpenColorIO_AE_Context.h"
+
+#include <assert.h>
+
+
+PF_Err ArbNewDefault(PF_InData *in_data, PF_OutData *out_data,
+ void *refconPV,
+ PF_ArbitraryH *arbPH)
+{
+ PF_Err err = PF_Err_NONE;
+
+ if(arbPH)
+ {
+ *arbPH = PF_NEW_HANDLE( sizeof(ArbitraryData) );
+
+ if(*arbPH)
+ {
+ ArbitraryData *arb_data = (ArbitraryData *)PF_LOCK_HANDLE(*arbPH);
+
+ // set up defaults
+ arb_data->version = CURRENT_ARB_VERSION;
+
+ arb_data->action = OCIO_ACTION_NONE;
+ arb_data->invert = FALSE;
+
+ arb_data->storage = OCIO_STORAGE_NONE;
+ arb_data->storage_size = 0;
+ arb_data->source = OCIO_SOURCE_NONE;
+ arb_data->interpolation = OCIO_INTERP_LINEAR;
+
+ arb_data->path[0] = '\0';
+ arb_data->relative_path[0] = '\0';
+
+ arb_data->input[0] = '\0';
+ arb_data->output[0] = '\0';
+ arb_data->transform[0] = '\0';
+ arb_data->device[0] = '\0';
+ arb_data->look[0] = '\0';
+
+
+ // set default with environment variable if it's set
+ char *file = std::getenv("OCIO");
+
+ if(file)
+ {
+ try
+ {
+ OpenColorIO_AE_Context context(file, OCIO_SOURCE_ENVIRONMENT);
+
+ strncpy(arb_data->path, file, ARB_PATH_LEN);
+
+ arb_data->action = context.getAction();
+ arb_data->source = OCIO_SOURCE_ENVIRONMENT;
+
+ if(arb_data->action != OCIO_ACTION_LUT)
+ {
+ strncpy(arb_data->input, context.getInput().c_str(), ARB_SPACE_LEN);
+ strncpy(arb_data->output, context.getOutput().c_str(), ARB_SPACE_LEN);
+ strncpy(arb_data->transform, context.getTransform().c_str(), ARB_SPACE_LEN);
+ strncpy(arb_data->device, context.getDevice().c_str(), ARB_SPACE_LEN);
+ }
+ }
+ catch(...) {}
+ }
+
+
+ PF_UNLOCK_HANDLE(*arbPH);
+ }
+ }
+
+ return err;
+}
+
+
+static PF_Err ArbDispose(PF_InData *in_data, PF_OutData *out_data,
+ void *refconPV,
+ PF_ArbitraryH arbH)
+{
+ if(arbH)
+ PF_DISPOSE_HANDLE(arbH);
+
+ return PF_Err_NONE;
+}
+
+
+static void CopyArbData(ArbitraryData *out_arb_data, ArbitraryData *in_arb_data)
+{
+ // copy contents
+ out_arb_data->version = in_arb_data->version;
+
+ out_arb_data->action = in_arb_data->action;
+
+ out_arb_data->invert = in_arb_data->invert;
+
+ out_arb_data->storage = in_arb_data->storage;
+ out_arb_data->storage_size = in_arb_data->storage_size;
+
+ out_arb_data->source = in_arb_data->source;
+
+ out_arb_data->interpolation = in_arb_data->interpolation;
+
+ strcpy(out_arb_data->path, in_arb_data->path);
+ strcpy(out_arb_data->relative_path, in_arb_data->relative_path);
+
+ strcpy(out_arb_data->input, in_arb_data->input);
+ strcpy(out_arb_data->output, in_arb_data->output);
+ strcpy(out_arb_data->transform, in_arb_data->transform);
+ strcpy(out_arb_data->device, in_arb_data->device);
+ strcpy(out_arb_data->look, in_arb_data->look);
+}
+
+
+static PF_Err ArbCopy(PF_InData *in_data, PF_OutData *out_data,
+ void *refconPV,
+ PF_ArbitraryH src_arbH,
+ PF_ArbitraryH *dst_arbPH)
+{
+ PF_Err err = PF_Err_NONE;
+
+ if(src_arbH && dst_arbPH)
+ {
+ // allocate using the creation function
+ err = ArbNewDefault(in_data, out_data, refconPV, dst_arbPH);
+
+ if(!err)
+ {
+ ArbitraryData *in_arb_data = (ArbitraryData *)PF_LOCK_HANDLE(src_arbH),
+ *out_arb_data = (ArbitraryData *)PF_LOCK_HANDLE(*dst_arbPH);
+
+ CopyArbData(out_arb_data, in_arb_data);
+
+ PF_UNLOCK_HANDLE(src_arbH);
+ PF_UNLOCK_HANDLE(*dst_arbPH);
+ }
+ }
+
+ return err;
+}
+
+
+static PF_Err ArbFlatSize(PF_InData *in_data, PF_OutData *out_data,
+ void *refconPV,
+ PF_ArbitraryH arbH,
+ A_u_long *flat_data_sizePLu)
+{
+ // flat is the same size as inflated
+ if(arbH)
+ *flat_data_sizePLu = PF_GET_HANDLE_SIZE(arbH);
+
+ return PF_Err_NONE;
+}
+
+
+static void SwapArbData(ArbitraryData *arb_data)
+{
+
+}
+
+
+static PF_Err ArbFlatten(PF_InData *in_data, PF_OutData *out_data,
+ void *refconPV,
+ PF_ArbitraryH arbH,
+ A_u_long buf_sizeLu,
+ void *flat_dataPV)
+{
+ PF_Err err = PF_Err_NONE;
+
+ if(arbH && flat_dataPV)
+ {
+ // they provide the buffer, we just move data
+ ArbitraryData *in_arb_data = (ArbitraryData *)PF_LOCK_HANDLE(arbH),
+ *out_arb_data = (ArbitraryData *)flat_dataPV;
+
+ assert(buf_sizeLu >= PF_GET_HANDLE_SIZE(arbH));
+
+ CopyArbData(out_arb_data, in_arb_data);
+
+ #ifdef AE_BIG_ENDIAN
+ // not that we're doing a PPC version of this...
+ SwapArbData(out_arb_data);
+ #endif
+
+ PF_UNLOCK_HANDLE(arbH);
+ }
+
+ return err;
+}
+
+
+static PF_Err ArbUnFlatten(PF_InData *in_data, PF_OutData *out_data,
+ void *refconPV,
+ A_u_long buf_sizeLu,
+ const void *flat_dataPV,
+ PF_ArbitraryH *arbPH)
+{
+ PF_Err err = PF_Err_NONE;
+
+ if(arbPH && flat_dataPV)
+ {
+ // they provide a flat buffer, we have to make the handle
+ err = ArbNewDefault(in_data, out_data, refconPV, arbPH);
+
+ if(!err && *arbPH)
+ {
+ ArbitraryData *in_arb_data = (ArbitraryData *)flat_dataPV,
+ *out_arb_data = (ArbitraryData *)PF_LOCK_HANDLE(*arbPH);
+
+ assert(buf_sizeLu <= PF_GET_HANDLE_SIZE(*arbPH));
+
+ CopyArbData(out_arb_data, in_arb_data);
+
+ #ifdef AE_BIG_ENDIAN
+ SwapArbData(out_arb_data);
+ #endif
+
+ PF_UNLOCK_HANDLE(*arbPH);
+ }
+ }
+
+ return err;
+}
+
+static PF_Err ArbInterpolate(PF_InData *in_data, PF_OutData *out_data,
+ void *refconPV,
+ PF_ArbitraryH left_arbH,
+ PF_ArbitraryH right_arbH,
+ PF_FpLong tF,
+ PF_ArbitraryH *interpPH)
+{
+ PF_Err err = PF_Err_NONE;
+
+ assert(FALSE); // we shouldn't be doing this
+
+ if(left_arbH && right_arbH && interpPH)
+ {
+ // allocate using our own func
+ err = ArbNewDefault(in_data, out_data, refconPV, interpPH);
+
+ if(!err && *interpPH)
+ {
+ // we're just going to copy the left_data
+ ArbitraryData *in_arb_data = (ArbitraryData *)PF_LOCK_HANDLE(left_arbH),
+ *out_arb_data = (ArbitraryData *)PF_LOCK_HANDLE(*interpPH);
+
+ CopyArbData(out_arb_data, in_arb_data);
+
+ PF_UNLOCK_HANDLE(left_arbH);
+ PF_UNLOCK_HANDLE(*interpPH);
+ }
+ }
+
+ return err;
+}
+
+
+static PF_Err ArbCompare(PF_InData *in_data, PF_OutData *out_data,
+ void *refconPV,
+ PF_ArbitraryH a_arbH,
+ PF_ArbitraryH b_arbH,
+ PF_ArbCompareResult *compareP)
+{
+ PF_Err err = PF_Err_NONE;
+
+ if(a_arbH && b_arbH)
+ {
+ ArbitraryData *a_data = (ArbitraryData *)PF_LOCK_HANDLE(a_arbH),
+ *b_data = (ArbitraryData *)PF_LOCK_HANDLE(b_arbH);
+
+
+ if( a_data->version == b_data->version &&
+ a_data->action == b_data->action &&
+ a_data->invert == b_data->invert &&
+ a_data->source == b_data->source &&
+ a_data->interpolation == b_data->interpolation &&
+ !strcmp(a_data->path, b_data->path) &&
+ !strcmp(a_data->input, b_data->input) &&
+ !strcmp(a_data->output, b_data->output) &&
+ !strcmp(a_data->transform, b_data->transform) &&
+ !strcmp(a_data->device, b_data->device) &&
+ !strcmp(a_data->look, b_data->look) )
+ {
+ *compareP = PF_ArbCompare_EQUAL;
+ }
+ else
+ {
+ *compareP = PF_ArbCompare_NOT_EQUAL;
+ }
+
+
+ PF_UNLOCK_HANDLE(a_arbH);
+ PF_UNLOCK_HANDLE(b_arbH);
+ }
+
+ return err;
+}
+
+
+PF_Err HandleArbitrary(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output,
+ PF_ArbParamsExtra *extra)
+{
+ PF_Err err = PF_Err_NONE;
+
+ if(extra->id == OCIO_DATA_ID)
+ {
+ switch(extra->which_function)
+ {
+ case PF_Arbitrary_NEW_FUNC:
+ err = ArbNewDefault(in_data, out_data,
+ extra->u.new_func_params.refconPV,
+ extra->u.new_func_params.arbPH);
+ break;
+ case PF_Arbitrary_DISPOSE_FUNC:
+ err = ArbDispose(in_data, out_data,
+ extra->u.dispose_func_params.refconPV,
+ extra->u.dispose_func_params.arbH);
+ break;
+ case PF_Arbitrary_COPY_FUNC:
+ err = ArbCopy(in_data, out_data, extra->u.copy_func_params.refconPV,
+ extra->u.copy_func_params.src_arbH,
+ extra->u.copy_func_params.dst_arbPH);
+ break;
+ case PF_Arbitrary_FLAT_SIZE_FUNC:
+ err = ArbFlatSize(in_data, out_data,
+ extra->u.flat_size_func_params.refconPV,
+ extra->u.flat_size_func_params.arbH,
+ extra->u.flat_size_func_params.flat_data_sizePLu);
+ break;
+ case PF_Arbitrary_FLATTEN_FUNC:
+ err = ArbFlatten(in_data, out_data,
+ extra->u.flatten_func_params.refconPV,
+ extra->u.flatten_func_params.arbH,
+ extra->u.flatten_func_params.buf_sizeLu,
+ extra->u.flatten_func_params.flat_dataPV);
+ break;
+ case PF_Arbitrary_UNFLATTEN_FUNC:
+ err = ArbUnFlatten(in_data, out_data,
+ extra->u.unflatten_func_params.refconPV,
+ extra->u.unflatten_func_params.buf_sizeLu,
+ extra->u.unflatten_func_params.flat_dataPV,
+ extra->u.unflatten_func_params.arbPH);
+ break;
+ case PF_Arbitrary_INTERP_FUNC:
+ err = ArbInterpolate(in_data, out_data,
+ extra->u.interp_func_params.refconPV,
+ extra->u.interp_func_params.left_arbH,
+ extra->u.interp_func_params.right_arbH,
+ extra->u.interp_func_params.tF,
+ extra->u.interp_func_params.interpPH);
+ break;
+ case PF_Arbitrary_COMPARE_FUNC:
+ err = ArbCompare(in_data, out_data,
+ extra->u.compare_func_params.refconPV,
+ extra->u.compare_func_params.a_arbH,
+ extra->u.compare_func_params.b_arbH,
+ extra->u.compare_func_params.compareP);
+ break;
+ // these are necessary for copying and pasting keyframes
+ // for now, we better not be called to do this
+ case PF_Arbitrary_PRINT_SIZE_FUNC:
+ assert(FALSE);
+ break;
+ case PF_Arbitrary_PRINT_FUNC:
+ assert(FALSE);
+ break;
+ case PF_Arbitrary_SCAN_FUNC:
+ assert(FALSE);
+ break;
+ }
+ }
+
+
+ return err;
+}
diff --git a/src/aftereffects/OpenColorIO_AE_Context.cpp b/src/aftereffects/OpenColorIO_AE_Context.cpp
new file mode 100644
index 0000000..1da7ee8
--- /dev/null
+++ b/src/aftereffects/OpenColorIO_AE_Context.cpp
@@ -0,0 +1,1051 @@
+/*
+Copyright (c) 2003-2012 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_AE_Context.h"
+
+#include <fstream>
+#include <map>
+#include <sstream>
+
+#include "ocioicc.h"
+
+#include "OpenColorIO_AE_Dialogs.h"
+
+
+
+
+static const char mac_delimiter = '/';
+static const char win_delimiter = '\\';
+
+#ifdef WIN_ENV
+static const char delimiter = win_delimiter;
+#else
+static const char delimiter = mac_delimiter;
+#endif
+
+static const int LUT3D_EDGE_SIZE = 32;
+
+
+Path::Path(const std::string &path, const std::string &dir) :
+ _path(path),
+ _dir(dir)
+{
+
+}
+
+
+Path::Path(const Path &path)
+{
+ _path = path._path;
+ _dir = path._dir;
+}
+
+
+std::string Path::full_path() const
+{
+ if( is_relative(_path) && !_dir.empty() )
+ {
+ std::vector<std::string> path_vec = components( convert_delimiters(_path) );
+ std::vector<std::string> dir_vec = components(_dir);
+
+ int up_dirs = 0;
+ int down_dirs = 0;
+
+ while(down_dirs < path_vec.size() - 1 &&
+ (path_vec[down_dirs] == ".." || path_vec[down_dirs] == ".") )
+ {
+ down_dirs++;
+
+ if(path_vec[down_dirs] == "..")
+ up_dirs++;
+ }
+
+
+ std::string path;
+
+ if(path_type(_dir) == TYPE_MAC)
+ path += mac_delimiter;
+
+ for(int i=0; i < dir_vec.size() - up_dirs; i++)
+ {
+ path += dir_vec[i] + delimiter;
+ }
+
+ for(int i = down_dirs; i < path_vec.size() - 1; i++)
+ {
+ path += path_vec[i] + delimiter;
+ }
+
+ path += path_vec.back();
+
+ return path;
+ }
+ else
+ {
+ return _path;
+ }
+}
+
+
+std::string Path::relative_path(bool force) const
+{
+ if( is_relative(_path) || _dir.empty() || _path.empty() )
+ {
+ return _path;
+ }
+ else
+ {
+ std::vector<std::string> path_vec = components(_path);
+ std::vector<std::string> dir_vec = components(_dir);
+
+ int match_idx = 0;
+
+ while(match_idx < path_vec.size() &&
+ match_idx < dir_vec.size() &&
+ path_vec[match_idx] == dir_vec[match_idx])
+ match_idx++;
+
+ if(match_idx == 0)
+ {
+ // can't do relative path
+ if(force)
+ return _path;
+ else
+ return "";
+ }
+ else
+ {
+ std::string rel_path;
+
+ // is the file in a folder below or actually inside the dir?
+ if(match_idx == dir_vec.size())
+ {
+ rel_path += std::string(".") + delimiter;
+ }
+ else
+ {
+ for(int i = match_idx; i < dir_vec.size(); i++)
+ {
+ rel_path += std::string("..") + delimiter;
+ }
+ }
+
+ for(int i = match_idx; i < path_vec.size() - 1; i++)
+ {
+ rel_path += path_vec[i] + delimiter;
+ }
+
+ rel_path += path_vec.back();
+
+ return rel_path;
+ }
+ }
+}
+
+
+bool Path::exists() const
+{
+ std::string path = full_path();
+
+ if(path.empty())
+ return false;
+
+ std::ifstream f( path.c_str() );
+
+ return !!f;
+}
+
+
+Path::PathType Path::path_type(std::string path)
+{
+ if( path.empty() )
+ {
+ return TYPE_UNKNOWN;
+ }
+ if(path[0] == mac_delimiter)
+ {
+ return TYPE_MAC;
+ }
+ else if(path[1] == ':' && path[2] == win_delimiter)
+ {
+ return TYPE_WIN;
+ }
+ else if(path[0] == win_delimiter && path[1] == win_delimiter)
+ {
+ return TYPE_WIN;
+ }
+ else
+ {
+ size_t mac_pos = path.find(mac_delimiter);
+ size_t win_pos = path.find(win_delimiter);
+
+ if(mac_pos != std::string::npos && win_pos == std::string::npos)
+ {
+ return TYPE_MAC;
+ }
+ else if(mac_pos == std::string::npos && win_pos != std::string::npos)
+ {
+ return TYPE_WIN;
+ }
+ else if(mac_pos == std::string::npos && win_pos == std::string::npos)
+ {
+ return TYPE_UNKNOWN;
+ }
+ else // neither npos?
+ {
+ if(mac_pos < win_pos)
+ return TYPE_MAC;
+ else
+ return TYPE_WIN;
+ }
+ }
+}
+
+
+bool Path::is_relative(std::string path)
+{
+ Path::PathType type = path_type(path);
+
+ if(type == TYPE_MAC)
+ {
+ return (path[0] != mac_delimiter);
+ }
+ else if(type == TYPE_WIN)
+ {
+ return !( (path[1] == ':' && path[2] == win_delimiter) ||
+ (path[0] == win_delimiter && path[1] == win_delimiter) );
+ }
+ else
+ { // TYPE_UNKNOWN
+
+ // just a filename perhaps?
+ // should never have this: even a file in the same directory will be ./file.ocio
+ // we'll assume it's relative, but raise a stink during debugging
+ assert(type != TYPE_UNKNOWN);
+
+ return true;
+ }
+}
+
+
+std::string Path::convert_delimiters(std::string path)
+{
+#ifdef WIN_ENV
+ char search = mac_delimiter;
+ char replace = win_delimiter;
+#else
+ char search = win_delimiter;
+ char replace = mac_delimiter;
+#endif
+
+ for(int i=0; i < path.size(); i++)
+ {
+ if(path[i] == search)
+ path[i] = replace;
+ }
+
+ return path;
+}
+
+
+std::vector<std::string> Path::components(std::string path)
+{
+ std::vector<std::string> vec;
+
+ size_t pos = 0;
+ size_t len = path.size();
+
+ size_t start, finish;
+
+ while(path[pos] == delimiter && pos < len)
+ pos++;
+
+ while(pos < len)
+ {
+ start = pos;
+
+ while(path[pos] != delimiter && pos < len)
+ pos++;
+
+ finish = ((pos == len - 1) ? pos : pos - 1);
+
+ vec.push_back( path.substr(start, 1 + finish - start) );
+
+ while(path[pos] == delimiter && pos < len)
+ pos++;
+ }
+
+ return vec;
+}
+
+
+#pragma mark-
+
+
+OpenColorIO_AE_Context::OpenColorIO_AE_Context(const std::string &path, OCIO_Source source) :
+ _gl_init(false)
+{
+ _action = OCIO_ACTION_NONE;
+
+
+ _source = source;
+
+ if(_source == OCIO_SOURCE_ENVIRONMENT)
+ {
+ char *file = getenv("OCIO");
+
+ if(file)
+ {
+ _path = file;
+ }
+ else
+ throw OCIO::Exception("No $OCIO environment variable.");
+ }
+ else if(_source == OCIO_SOURCE_STANDARD)
+ {
+ _config_name = path;
+
+ _path = GetStdConfigPath(_config_name);
+
+ if( _path.empty() )
+ throw OCIO::Exception("Error getting config.");
+ }
+ else
+ {
+ _path = path;
+ }
+
+
+ if(!_path.empty())
+ {
+ std::string the_extension = _path.substr( _path.find_last_of('.') + 1 );
+
+ if(the_extension == "ocio")
+ {
+ _config = OCIO::Config::CreateFromFile( _path.c_str() );
+
+ _config->sanityCheck();
+
+ for(int i=0; i < _config->getNumColorSpaces(); ++i)
+ {
+ _inputs.push_back( _config->getColorSpaceNameByIndex(i) );
+ }
+
+
+ for(int i=0; i < _config->getNumDisplays(); ++i)
+ {
+ _devices.push_back( _config->getDisplay(i) );
+ }
+
+ const char * defaultDisplay = _config->getDefaultDisplay();
+ const char * defaultTransform = _config->getDefaultView(defaultDisplay);
+
+ for(int i=0; i < _config->getNumViews(defaultDisplay); ++i)
+ {
+ _transforms.push_back( _config->getView(defaultDisplay, i) );
+ }
+
+
+ OCIO::ConstColorSpaceRcPtr defaultInput = _config->getColorSpace(OCIO::ROLE_SCENE_LINEAR);
+
+ const char *defaultInputName = (defaultInput ? defaultInput->getName() : OCIO::ROLE_SCENE_LINEAR);
+
+
+ setupConvert(defaultInputName, defaultInputName);
+
+ _transform = defaultTransform;
+ _device = defaultDisplay;
+ }
+ else
+ {
+ _config = OCIO::Config::Create();
+
+ setupLUT(false, OCIO_INTERP_LINEAR);
+ }
+ }
+ else
+ throw OCIO::Exception("Got nothin");
+}
+
+
+OpenColorIO_AE_Context::OpenColorIO_AE_Context(const ArbitraryData *arb_data, const std::string &dir) :
+ _gl_init(false)
+{
+ _action = OCIO_ACTION_NONE;
+
+
+ _source = arb_data->source;
+
+ if(_source == OCIO_SOURCE_ENVIRONMENT)
+ {
+ char *file = getenv("OCIO");
+
+ if(file)
+ {
+ _path = file;
+ }
+ else
+ throw OCIO::Exception("No $OCIO environment variable.");
+ }
+ else if(_source == OCIO_SOURCE_STANDARD)
+ {
+ _config_name = arb_data->path;
+
+ _path = GetStdConfigPath(_config_name);
+
+ if( _path.empty() )
+ throw OCIO::Exception("Error getting config.");
+ }
+ else
+ {
+ Path absolute_path(arb_data->path, dir);
+ Path relative_path(arb_data->relative_path, dir);
+
+ if( absolute_path.exists() )
+ {
+ _path = absolute_path.full_path();
+ }
+ else
+ {
+ _path = relative_path.full_path();
+ }
+ }
+
+
+ if(!_path.empty())
+ {
+ std::string the_extension = _path.substr( _path.find_last_of('.') + 1 );
+
+ if(the_extension == "ocio")
+ {
+ _config = OCIO::Config::CreateFromFile( _path.c_str() );
+
+ _config->sanityCheck();
+
+ for(int i=0; i < _config->getNumColorSpaces(); ++i)
+ {
+ _inputs.push_back( _config->getColorSpaceNameByIndex(i) );
+ }
+
+
+ for(int i=0; i < _config->getNumDisplays(); ++i)
+ {
+ _devices.push_back( _config->getDisplay(i) );
+ }
+
+ const char * defaultDisplay = _config->getDefaultDisplay();
+ const char * defaultTransform = _config->getDefaultView(defaultDisplay);
+
+ for(int i=0; i < _config->getNumViews(defaultDisplay); ++i)
+ {
+ _transforms.push_back( _config->getView(defaultDisplay, i) );
+ }
+
+
+ if(arb_data->action == OCIO_ACTION_CONVERT)
+ {
+ setupConvert(arb_data->input, arb_data->output);
+
+ _transform = arb_data->transform;
+ _device = arb_data->device;
+ }
+ else
+ {
+ setupDisplay(arb_data->input, arb_data->transform, arb_data->device);
+
+ _output = arb_data->output;
+ }
+ }
+ else
+ {
+ _config = OCIO::Config::Create();
+
+ setupLUT(arb_data->invert, arb_data->interpolation);
+ }
+ }
+ else
+ throw OCIO::Exception("Got nothin");
+}
+
+
+OpenColorIO_AE_Context::~OpenColorIO_AE_Context()
+{
+ if(_gl_init)
+ {
+ glDeleteShader(_fragShader);
+ glDeleteProgram(_program);
+ glDeleteTextures(1, &_imageTexID);
+
+ if(_bufferWidth != 0 && _bufferHeight != 0)
+ glDeleteRenderbuffersEXT(1, &_renderBuffer);
+ }
+}
+
+
+bool OpenColorIO_AE_Context::Verify(const ArbitraryData *arb_data, const std::string &dir)
+{
+ if(_source != arb_data->source)
+ return false;
+
+ if(_source == OCIO_SOURCE_STANDARD)
+ {
+ if(_config_name != arb_data->path)
+ return false;
+ }
+ else if(_source == OCIO_SOURCE_CUSTOM)
+ {
+ // comparing the paths, cheking relative path only if necessary
+ if(_path != arb_data->path)
+ {
+ std::string rel_path(arb_data->relative_path);
+
+ if( !dir.empty() && !rel_path.empty() )
+ {
+ Path relative_path(rel_path, dir);
+
+ if( _path != relative_path.full_path() )
+ return false;
+ }
+ else
+ return false;
+ }
+ }
+
+ // we can switch between Convert and Display, but not LUT and non-LUT
+ if((arb_data->action == OCIO_ACTION_NONE) ||
+ (_action == OCIO_ACTION_LUT && arb_data->action != OCIO_ACTION_LUT) ||
+ (_action != OCIO_ACTION_LUT && arb_data->action == OCIO_ACTION_LUT) )
+ {
+ return false;
+ }
+
+ bool force_reset = (_action != arb_data->action);
+
+
+ // If the type and path are compatible, we can patch up
+ // differences here and return true.
+ // Returning false means the context will be deleted and rebuilt.
+ if(arb_data->action == OCIO_ACTION_LUT)
+ {
+ if(_invert != (bool)arb_data->invert ||
+ _interpolation != arb_data->interpolation ||
+ force_reset)
+ {
+ setupLUT(arb_data->invert, arb_data->interpolation);
+ }
+ }
+ else if(arb_data->action == OCIO_ACTION_CONVERT)
+ {
+ if(_input != arb_data->input ||
+ _output != arb_data->output ||
+ force_reset)
+ {
+ setupConvert(arb_data->input, arb_data->output);
+ }
+ }
+ else if(arb_data->action == OCIO_ACTION_DISPLAY)
+ {
+ if(_input != arb_data->input ||
+ _transform != arb_data->transform ||
+ _device != arb_data->device ||
+ force_reset)
+ {
+ setupDisplay(arb_data->input, arb_data->transform, arb_data->device);
+ }
+ }
+ else
+ throw OCIO::Exception("Bad OCIO type");
+
+
+ return true;
+}
+
+
+void OpenColorIO_AE_Context::setupConvert(const char *input, const char *output)
+{
+ OCIO::ColorSpaceTransformRcPtr transform = OCIO::ColorSpaceTransform::Create();
+
+ transform->setSrc(input);
+ transform->setDst(output);
+ transform->setDirection(OCIO::TRANSFORM_DIR_FORWARD);
+
+ _input = input;
+ _output = output;
+
+ _processor = _config->getProcessor(transform);
+
+ _action = OCIO_ACTION_CONVERT;
+
+ UpdateOCIOGLState();
+}
+
+
+void OpenColorIO_AE_Context::setupDisplay(const char *input, const char *xform, const char *device)
+{
+ OCIO::DisplayTransformRcPtr transform = OCIO::DisplayTransform::Create();
+
+ transform->setInputColorSpaceName(input);
+ transform->setView(xform);
+ transform->setDisplay(device);
+
+ _input = input;
+ _transform = xform;
+ _device = device;
+
+
+ _processor = _config->getProcessor(transform);
+
+ _action = OCIO_ACTION_DISPLAY;
+
+ UpdateOCIOGLState();
+}
+
+
+void OpenColorIO_AE_Context::setupLUT(bool invert, OCIO_Interp interpolation)
+{
+ OCIO::FileTransformRcPtr transform = OCIO::FileTransform::Create();
+
+ if(interpolation != OCIO_INTERP_NEAREST && interpolation != OCIO_INTERP_LINEAR &&
+ interpolation != OCIO_INTERP_TETRAHEDRAL && interpolation != OCIO_INTERP_BEST)
+ {
+ interpolation = OCIO_INTERP_LINEAR;
+ }
+
+ transform->setSrc( _path.c_str() );
+ transform->setInterpolation(static_cast<OCIO::Interpolation>(interpolation));
+ transform->setDirection(invert ? OCIO::TRANSFORM_DIR_INVERSE : OCIO::TRANSFORM_DIR_FORWARD);
+
+ _processor = _config->getProcessor(transform);
+
+ _invert = invert;
+ _interpolation = interpolation;
+
+ _action = OCIO_ACTION_LUT;
+
+ UpdateOCIOGLState();
+}
+
+
+bool OpenColorIO_AE_Context::ExportLUT(const std::string &path, const std::string &display_icc_path)
+{
+ std::string the_extension = path.substr( path.find_last_of('.') + 1 );
+
+ try{
+
+ if(the_extension == "icc")
+ {
+ int cubesize = 32;
+ int whitepointtemp = 6505;
+ std::string copyright = "OpenColorIO, Sony Imageworks";
+
+ // create a description tag from the filename
+ size_t filename_start = path.find_last_of(delimiter) + 1;
+ size_t filename_end = path.find_last_of('.') - 1;
+
+ std::string description = path.substr(path.find_last_of(delimiter) + 1,
+ 1 + filename_end - filename_start);
+
+ SaveICCProfileToFile(path, _processor, cubesize, whitepointtemp,
+ display_icc_path, description, copyright, false);
+ }
+ else
+ {
+ // this code lovingly pulled from ociobakelut
+
+ // need an extension->format map (yes, just did this one call up)
+ std::map<std::string, std::string> extensions;
+
+ for(int i=0; i < OCIO::Baker::getNumFormats(); ++i)
+ {
+ const char *extension = OCIO::Baker::getFormatExtensionByIndex(i);
+ const char *format = OCIO::Baker::getFormatNameByIndex(i);
+
+ extensions[ extension ] = format;
+ }
+
+ std::string format = extensions[ the_extension ];
+
+
+ OCIO::BakerRcPtr baker = OCIO::Baker::Create();
+
+ baker->setFormat(format.c_str());
+
+ if(_action == OCIO_ACTION_CONVERT)
+ {
+ baker->setConfig(_config);
+ baker->setInputSpace(_input.c_str());
+ baker->setTargetSpace(_output.c_str());
+
+ std::ofstream f(path.c_str());
+ baker->bake(f);
+ }
+ else if(_action == OCIO_ACTION_DISPLAY)
+ {
+ OCIO::ConfigRcPtr editableConfig = _config->createEditableCopy();
+
+ OCIO::ColorSpaceRcPtr inputColorSpace = OCIO::ColorSpace::Create();
+ std::string inputspace = "RawInput";
+ inputColorSpace->setName(inputspace.c_str());
+ editableConfig->addColorSpace(inputColorSpace);
+
+
+ OCIO::ColorSpaceRcPtr outputColorSpace = OCIO::ColorSpace::Create();
+ std::string outputspace = "ProcessedOutput";
+ outputColorSpace->setName(outputspace.c_str());
+
+ OCIO::DisplayTransformRcPtr transform = OCIO::DisplayTransform::Create();
+
+ transform->setInputColorSpaceName(_input.c_str());
+ transform->setView(_transform.c_str());
+ transform->setDisplay(_device.c_str());
+
+ outputColorSpace->setTransform(transform, OCIO::COLORSPACE_DIR_FROM_REFERENCE);
+
+ editableConfig->addColorSpace(outputColorSpace);
+
+
+ baker->setConfig(editableConfig);
+ baker->setInputSpace(inputspace.c_str());
+ baker->setTargetSpace(outputspace.c_str());
+
+ std::ofstream f(path.c_str());
+ baker->bake(f);
+ }
+ else if(_action == OCIO_ACTION_LUT)
+ {
+ OCIO::ConfigRcPtr editableConfig = OCIO::Config::Create();
+
+ OCIO::ColorSpaceRcPtr inputColorSpace = OCIO::ColorSpace::Create();
+ std::string inputspace = "RawInput";
+ inputColorSpace->setName(inputspace.c_str());
+ editableConfig->addColorSpace(inputColorSpace);
+
+
+ OCIO::ColorSpaceRcPtr outputColorSpace = OCIO::ColorSpace::Create();
+ std::string outputspace = "ProcessedOutput";
+ outputColorSpace->setName(outputspace.c_str());
+
+ OCIO::FileTransformRcPtr transform = OCIO::FileTransform::Create();
+
+ transform = OCIO::FileTransform::Create();
+ transform->setSrc(_path.c_str());
+ transform->setInterpolation(static_cast<OCIO::Interpolation>(_interpolation));
+ transform->setDirection(_invert ? OCIO::TRANSFORM_DIR_INVERSE : OCIO::TRANSFORM_DIR_FORWARD);
+
+ outputColorSpace->setTransform(transform, OCIO::COLORSPACE_DIR_FROM_REFERENCE);
+
+ editableConfig->addColorSpace(outputColorSpace);
+
+
+ baker->setConfig(editableConfig);
+ baker->setInputSpace(inputspace.c_str());
+ baker->setTargetSpace(outputspace.c_str());
+
+ std::ofstream f(path.c_str());
+ baker->bake(f);
+ }
+ }
+
+ }catch(...) { return false; }
+
+ return true;
+}
+
+
+void OpenColorIO_AE_Context::InitOCIOGL()
+{
+ if(!_gl_init)
+ {
+ SetPluginContext();
+
+ glGenTextures(1, &_imageTexID);
+ glGenTextures(1, &_lut3dTexID);
+
+ int num3Dentries = 3*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE;
+ _lut3d.resize(num3Dentries);
+ memset(&_lut3d[0], 0, sizeof(float)*num3Dentries);
+
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_3D, _lut3dTexID);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA32F_ARB,
+ LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE,
+ 0, GL_RGB,GL_FLOAT, &_lut3d[0]);
+
+ _fragShader = 0;
+ _program = 0;
+
+ _bufferWidth = _bufferHeight = 0;
+
+ _gl_init = true;
+
+ SetAEContext();
+ }
+}
+
+
+static const char * g_fragShaderText = ""
+"\n"
+"uniform sampler2D tex1;\n"
+"uniform sampler3D tex2;\n"
+"\n"
+"void main()\n"
+"{\n"
+" vec4 col = texture2D(tex1, gl_TexCoord[0].st);\n"
+" gl_FragColor = OCIODisplay(col, tex2);\n"
+"}\n";
+
+
+static GLuint CompileShaderText(GLenum shaderType, const char *text)
+{
+ GLuint shader;
+ GLint stat;
+
+ shader = glCreateShader(shaderType);
+ glShaderSource(shader, 1, (const GLchar **) &text, NULL);
+ glCompileShader(shader);
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
+
+ if (!stat)
+ {
+ GLchar log[1000];
+ GLsizei len;
+ glGetShaderInfoLog(shader, 1000, &len, log);
+ return 0;
+ }
+
+ return shader;
+}
+
+
+static GLuint LinkShaders(GLuint fragShader)
+{
+ if (!fragShader) return 0;
+
+ GLuint program = glCreateProgram();
+
+ if (fragShader)
+ glAttachShader(program, fragShader);
+
+ glLinkProgram(program);
+
+ // check link
+ {
+ GLint stat;
+ glGetProgramiv(program, GL_LINK_STATUS, &stat);
+ if (!stat) {
+ GLchar log[1000];
+ GLsizei len;
+ glGetProgramInfoLog(program, 1000, &len, log);
+ //fprintf(stderr, "Shader link error:\n%s\n", log);
+ return 0;
+ }
+ }
+
+ return program;
+}
+
+
+void OpenColorIO_AE_Context::UpdateOCIOGLState()
+{
+ if(_gl_init)
+ {
+ SetPluginContext();
+
+ // Step 1: Create a GPU Shader Description
+ OCIO::GpuShaderDesc shaderDesc;
+ shaderDesc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_0);
+ shaderDesc.setFunctionName("OCIODisplay");
+ shaderDesc.setLut3DEdgeLen(LUT3D_EDGE_SIZE);
+
+ // Step 2: Compute the 3D LUT
+ std::string lut3dCacheID = _processor->getGpuLut3DCacheID(shaderDesc);
+ if(lut3dCacheID != _lut3dcacheid)
+ {
+ _lut3dcacheid = lut3dCacheID;
+ _processor->getGpuLut3D(&_lut3d[0], shaderDesc);
+ }
+
+ // Step 3: Compute the Shader
+ std::string shaderCacheID = _processor->getGpuShaderTextCacheID(shaderDesc);
+ if(_program == 0 || shaderCacheID != _shadercacheid)
+ {
+ _shadercacheid = shaderCacheID;
+
+ std::ostringstream os;
+ os << _processor->getGpuShaderText(shaderDesc) << "\n";
+ os << g_fragShaderText;
+
+ if(_fragShader) glDeleteShader(_fragShader);
+ _fragShader = CompileShaderText(GL_FRAGMENT_SHADER, os.str().c_str());
+ if(_program) glDeleteProgram(_program);
+ _program = LinkShaders(_fragShader);
+ }
+
+ SetAEContext();
+ }
+}
+
+
+bool OpenColorIO_AE_Context::ProcessWorldGL(PF_EffectWorld *float_world)
+{
+ if(!_gl_init)
+ {
+ InitOCIOGL();
+ UpdateOCIOGLState();
+ }
+
+
+ if(_program == 0 || _fragShader == 0)
+ return false;
+
+
+ SetPluginContext();
+
+
+ GLint max;
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
+
+ if(max < float_world->width || max < float_world->height || GL_NO_ERROR != glGetError())
+ {
+ SetAEContext();
+ return false;
+ }
+
+
+ PF_PixelFloat *pix = (PF_PixelFloat *)float_world->data;
+ float *rgba_origin = &pix->red;
+
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, _imageTexID);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, float_world->width, float_world->height, 0,
+ GL_RGBA, GL_FLOAT, rgba_origin);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+
+
+ glBindTexture(GL_TEXTURE_3D, _lut3dTexID);
+ glTexSubImage3D(GL_TEXTURE_3D, 0,
+ 0, 0, 0,
+ LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE,
+ GL_RGB, GL_FLOAT, &_lut3d[0]);
+
+
+ glUseProgram(_program);
+ glUniform1i(glGetUniformLocation(_program, "tex1"), 0);
+ glUniform1i(glGetUniformLocation(_program, "tex2"), 1);
+
+
+ if(GL_NO_ERROR != glGetError())
+ {
+ SetAEContext();
+ return false;
+ }
+
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, GetFrameBuffer());
+
+ if(_bufferWidth != float_world->width || _bufferHeight != float_world->height)
+ {
+ if(_bufferWidth != 0 && _bufferHeight != 0)
+ glDeleteRenderbuffersEXT(1, &_renderBuffer);
+
+ _bufferWidth = float_world->width;
+ _bufferHeight = float_world->height;
+
+ glGenRenderbuffersEXT(1, &_renderBuffer);
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _renderBuffer);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA, _bufferWidth, _bufferHeight);
+
+ // attach renderbuffer to framebuffer
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_RENDERBUFFER_EXT, _renderBuffer);
+ }
+
+ if(GL_FRAMEBUFFER_COMPLETE_EXT != glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT))
+ {
+ SetAEContext();
+ return false;
+ }
+
+ glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+
+
+ glViewport(0, 0, float_world->width, float_world->height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0.0, float_world->width, 0.0, float_world->height, -100.0, 100.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+
+ glEnable(GL_TEXTURE_2D);
+ glClearColor(0.1f, 0.1f, 0.1f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glColor3f(1, 1, 1);
+
+ glPushMatrix();
+ glBegin(GL_QUADS);
+ glTexCoord2f(0.0f, 1.0f);
+ glVertex2f(0.0f, float_world->height);
+
+ glTexCoord2f(0.0f, 0.0f);
+ glVertex2f(0.0f, 0.0f);
+
+ glTexCoord2f(1.0f, 0.0f);
+ glVertex2f(float_world->width, 0.0f);
+
+ glTexCoord2f(1.0f, 1.0f);
+ glVertex2f(float_world->width, float_world->height);
+
+ glEnd();
+ glPopMatrix();
+
+ glDisable(GL_TEXTURE_2D);
+
+
+ glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
+ glReadPixels(0, 0, float_world->width, float_world->height,
+ GL_RGBA, GL_FLOAT, rgba_origin);
+
+
+ glFinish();
+
+
+ SetAEContext();
+
+ return true;
+}
diff --git a/src/aftereffects/OpenColorIO_AE_Context.h b/src/aftereffects/OpenColorIO_AE_Context.h
new file mode 100644
index 0000000..8a3bf42
--- /dev/null
+++ b/src/aftereffects/OpenColorIO_AE_Context.h
@@ -0,0 +1,153 @@
+/*
+Copyright (c) 2003-2012 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.
+*/
+
+
+#ifndef _OPENCOLORIO_AE_CONTEXT_H_
+#define _OPENCOLORIO_AE_CONTEXT_H_
+
+#include <string>
+#include <vector>
+
+#include "OpenColorIO_AE.h"
+#include "OpenColorIO_AE_GL.h"
+
+#include <OpenColorIO/OpenColorIO.h>
+namespace OCIO = OCIO_NAMESPACE;
+
+
+
+// yeah, this probably could/should go in a seperate file
+class Path
+{
+ public:
+ Path(const std::string &path, const std::string &dir);
+ Path(const Path &path);
+ ~Path() {}
+
+ std::string full_path() const;
+ std::string relative_path(bool force) const;
+
+ bool exists() const;
+
+ private:
+ std::string _path;
+ std::string _dir;
+
+ typedef enum {
+ TYPE_UNKNOWN = 0,
+ TYPE_MAC,
+ TYPE_WIN
+ } PathType;
+
+ static PathType path_type(std::string path);
+ static bool is_relative(std::string path);
+ static std::string convert_delimiters(std::string path);
+ static std::vector<std::string> components(std::string path);
+};
+
+
+class OpenColorIO_AE_Context
+{
+ public:
+ OpenColorIO_AE_Context(const std::string &path, OCIO_Source source);
+ OpenColorIO_AE_Context(const ArbitraryData *arb_data, const std::string &dir);
+ ~OpenColorIO_AE_Context();
+
+ bool Verify(const ArbitraryData *arb_data, const std::string &dir);
+
+ void setupConvert(const char *input, const char *output);
+ void setupDisplay(const char *input, const char *transform, const char *device);
+ void setupLUT(bool invert, OCIO_Interp interpolation);
+
+ typedef std::vector<std::string> SpaceVec;
+
+ OCIO_Action getAction() const { return _action; }
+ const std::string & getInput() const { return _input; }
+ const std::string & getOutput() const { return _output; }
+ const std::string & getTransform() const { return _transform; }
+ const std::string & getDevice() const { return _device; }
+ const SpaceVec & getInputs() const { return _inputs; }
+ const SpaceVec & getTransforms() const { return _transforms; }
+ const SpaceVec & getDevices() const { return _devices; }
+
+ const OCIO::ConstProcessorRcPtr & processor() const { return _processor; }
+
+ bool ExportLUT(const std::string &path, const std::string &display_icc_path);
+
+ bool ProcessWorldGL(PF_EffectWorld *float_world);
+
+ private:
+ std::string _path;
+ OCIO_Source _source;
+ std::string _config_name;
+
+ OCIO_Action _action;
+
+ std::string _input;
+ std::string _output;
+ std::string _transform;
+ std::string _device;
+ SpaceVec _inputs;
+ SpaceVec _transforms;
+ SpaceVec _devices;
+
+ bool _invert;
+ OCIO_Interp _interpolation;
+
+
+ OCIO::ConstConfigRcPtr _config;
+ OCIO::ConstProcessorRcPtr _processor;
+
+
+ bool _gl_init;
+
+ GLuint _fragShader;
+ GLuint _program;
+
+ GLuint _imageTexID;
+
+ GLuint _lut3dTexID;
+ std::vector<float> _lut3d;
+ std::string _lut3dcacheid;
+ std::string _shadercacheid;
+
+ std::string _inputColorSpace;
+ std::string _display;
+ std::string _transformName;
+
+
+ GLuint _renderBuffer;
+ int _bufferWidth;
+ int _bufferHeight;
+
+ void InitOCIOGL();
+ void UpdateOCIOGLState();
+};
+
+
+#endif // _OPENCOLORIO_AE_CONTEXT_H_ \ No newline at end of file
diff --git a/src/aftereffects/OpenColorIO_AE_Dialogs.h b/src/aftereffects/OpenColorIO_AE_Dialogs.h
new file mode 100644
index 0000000..a2e9f26
--- /dev/null
+++ b/src/aftereffects/OpenColorIO_AE_Dialogs.h
@@ -0,0 +1,60 @@
+/*
+Copyright (c) 2003-2012 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.
+*/
+
+#ifndef _OPENCOLORIC_AE_DIALOG_H_
+#define _OPENCOLORIC_AE_DIALOG_H_
+
+#include <string>
+#include <map>
+#include <vector>
+
+typedef std::map<std::string, std::string> ExtensionMap; // map[ ext ] = format
+
+bool OpenFile(char *path, int buf_len, const ExtensionMap &extensions, const void *hwnd);
+
+bool SaveFile(char *path, int buf_len, const ExtensionMap &extensions, const void *hwnd);
+
+bool GetMonitorProfile(char *path, int buf_len, const void *hwnd);
+
+
+typedef std::vector<std::string> ConfigVec;
+
+void GetStdConfigs(ConfigVec &configs);
+
+std::string GetStdConfigPath(const std::string &name);
+
+
+typedef std::vector<std::string> MenuVec;
+
+int PopUpMenu(const MenuVec &menu_items, int selected_index, const void *hwnd);
+
+
+void ErrorMessage(const char *message, const void *hwnd);
+
+
+#endif // _OPENCOLORIC_AE_DIALOG_H_ \ No newline at end of file
diff --git a/src/aftereffects/OpenColorIO_AE_GL.h b/src/aftereffects/OpenColorIO_AE_GL.h
new file mode 100644
index 0000000..2c9683c
--- /dev/null
+++ b/src/aftereffects/OpenColorIO_AE_GL.h
@@ -0,0 +1,61 @@
+/*
+Copyright (c) 2003-2012 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.
+*/
+
+
+#ifndef _OPENCOLORIO_AE_GL_H_
+#define _OPENCOLORIO_AE_GL_H_
+
+#include "AEConfig.h"
+
+#ifdef AE_OS_WIN
+ #include <GL/glew.h>
+ #include <GL/wglew.h>
+#elif defined(AE_OS_MAC)
+ #include <OpenGL/OpenGL.h>
+ #include <OpenGL/gl.h>
+ #include <OpenGL/glu.h>
+ #include <OpenGL/glext.h>
+ #include <AGL/agl.h>
+#endif
+
+
+void GlobalSetup_GL();
+
+bool HaveOpenGL();
+
+// must surround plug-in OpenGL calls with these functions so that AE
+// doesn't know we're borrowing the OpenGL renderer
+void SetPluginContext();
+void SetAEContext();
+
+GLuint GetFrameBuffer();
+
+void GlobalSetdown_GL();
+
+
+#endif // _OPENCOLORIO_AE_GL_H_ \ No newline at end of file
diff --git a/src/aftereffects/OpenColorIO_AE_PiPL.r b/src/aftereffects/OpenColorIO_AE_PiPL.r
new file mode 100644
index 0000000..3d08070
--- /dev/null
+++ b/src/aftereffects/OpenColorIO_AE_PiPL.r
@@ -0,0 +1,102 @@
+/*
+Copyright (c) 2003-2012 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 "AEConfig.h"
+
+#include "AE_EffectVers.h"
+
+#ifndef AE_OS_WIN
+ #include "AE_General.r"
+#endif
+
+resource 'PiPL' (16000) {
+ { /* array properties: 12 elements */
+ /* [1] */
+ Kind {
+ AEEffect
+ },
+ /* [2] */
+ Name {
+ "OpenColorIO"
+ },
+ /* [3] */
+ Category {
+ "Utility"
+ },
+
+#ifdef AE_OS_WIN
+ #ifdef AE_PROC_INTELx64
+ CodeWin64X86 {"PluginMain"},
+ #else
+ CodeWin32X86 {"PluginMain"},
+ #endif
+#else
+ #ifdef AE_PROC_INTELx64
+ CodeMacIntel64 {"PluginMain"},
+ #else
+ CodeMachOPowerPC {"PluginMain"},
+ CodeMacIntel32 {"PluginMain"},
+ #endif
+#endif /* [6] */
+ AE_PiPL_Version {
+ 2,
+ 0
+ },
+ /* [7] */
+ AE_Effect_Spec_Version {
+ PF_PLUG_IN_VERSION,
+ PF_PLUG_IN_SUBVERS
+ },
+ /* [8] */
+ AE_Effect_Version {
+ 525824 /* 2.0 */
+ },
+ /* [9] */
+ AE_Effect_Info_Flags {
+ 0
+ },
+ /* [10] */
+ AE_Effect_Global_OutFlags {
+ 50365504
+ },
+ AE_Effect_Global_OutFlags_2 {
+ 37896
+ },
+ /* [11] */
+ AE_Effect_Match_Name {
+ "OpenColorIO"
+ },
+ /* [12] */
+ AE_Reserved_Info {
+ 0
+ }
+ }
+};
+
+
+
diff --git a/src/aftereffects/OpenColorIO_AE_UI.cpp b/src/aftereffects/OpenColorIO_AE_UI.cpp
new file mode 100644
index 0000000..b5634bf
--- /dev/null
+++ b/src/aftereffects/OpenColorIO_AE_UI.cpp
@@ -0,0 +1,1229 @@
+/*
+Copyright (c) 2003-2012 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_AE.h"
+
+#include "OpenColorIO_AE_Context.h"
+#include "OpenColorIO_AE_Dialogs.h"
+
+#include "DrawbotBot.h"
+
+
+
+// UI drawing constants
+
+#define LEFT_MARGIN 5
+#define TOP_MARGIN 5
+#define RIGHT_MARGIN 50
+
+#define FILE_LABEL_WIDTH 35
+
+#define FIELD_HEIGHT 22
+
+#define FIELD_TEXT_INDENT_H 10
+#define FIELD_TEXT_INDENT_V 4
+
+#define BUTTONS_INDENT_H (LEFT_MARGIN + 70)
+
+#define BUTTONS_GAP_V 20
+#define BUTTONS_GAP_H 30
+
+#define BUTTON_HEIGHT 20
+#define BUTTON_WIDTH 80
+
+#define BUTTON_TEXT_INDENT_V 2
+
+#define MENUS_INDENT_H 0
+
+#define MENUS_GAP_V 20
+
+#define MENU_LABEL_WIDTH 100
+#define MENU_LABEL_SPACE 5
+
+#define MENU_WIDTH 150
+#define MENU_HEIGHT 20
+
+#define MENU_TEXT_INDENT_H 10
+#define MENU_TEXT_INDENT_V 2
+
+#define MENU_ARROW_WIDTH 14
+#define MENU_ARROW_HEIGHT 7
+
+#define MENU_ARROW_SPACE_H 8
+#define MENU_ARROW_SPACE_V 7
+
+#define MENU_SHADOW_OFFSET 3
+
+#define MENU_SPACE_V 20
+
+#define TEXT_COLOR PF_App_Color_TEXT_DISABLED
+
+
+
+typedef enum {
+ REGION_NONE=0,
+ REGION_CONFIG_MENU,
+ REGION_PATH,
+ REGION_CONVERT_BUTTON,
+ REGION_DISPLAY_BUTTON,
+ REGION_EXPORT_BUTTON,
+ REGION_MENU1,
+ REGION_MENU2,
+ REGION_MENU3
+} UIRegion;
+
+
+static UIRegion WhichRegion(PF_Point ui_point, bool menus, bool third_menu)
+{
+ int field_top = TOP_MARGIN;
+ int field_bottom = field_top + FIELD_HEIGHT;
+
+ if(ui_point.v >= field_top && ui_point.v <= field_bottom)
+ {
+ int menu_left = LEFT_MARGIN + MENUS_INDENT_H + MENU_LABEL_WIDTH;
+ int menu_right = menu_left + MENU_WIDTH;
+
+ if(ui_point.h >= menu_left && ui_point.h <= menu_right)
+ {
+ return REGION_CONFIG_MENU;
+ }
+ else
+ {
+ int field_left = MENUS_INDENT_H + MENU_LABEL_WIDTH + MENU_LABEL_SPACE +
+ MENU_WIDTH + FIELD_TEXT_INDENT_H;
+
+ if(ui_point.h >= field_left)
+ return REGION_PATH;
+ }
+ }
+ else
+ {
+ int buttons_top = field_bottom + BUTTONS_GAP_V;
+ int buttons_bottom = buttons_top + BUTTON_HEIGHT;
+
+ if(ui_point.v >= buttons_top && ui_point.v <= buttons_bottom)
+ {
+ int convert_left = BUTTONS_INDENT_H;
+ int convert_right = convert_left + BUTTON_WIDTH;
+ int display_left = convert_right + BUTTONS_GAP_H;
+ int display_right = display_left + BUTTON_WIDTH;
+ int export_left = display_right + BUTTONS_GAP_H;
+ int export_right = export_left + BUTTON_WIDTH;
+
+ if(ui_point.h >= convert_left && ui_point.h <= convert_right)
+ return REGION_CONVERT_BUTTON;
+ else if(ui_point.h >= display_left && ui_point.h <= display_right)
+ return REGION_DISPLAY_BUTTON;
+ else if(ui_point.h >= export_left && ui_point.h <= export_right)
+ return REGION_EXPORT_BUTTON;
+ }
+ else if(menus)
+ {
+ int menu_left = LEFT_MARGIN + MENUS_INDENT_H + MENU_LABEL_WIDTH;
+ int menu_right = menu_left + MENU_WIDTH;
+
+ if(ui_point.h >= menu_left && ui_point.h <= menu_right)
+ {
+ int menu1_top = buttons_bottom + MENUS_GAP_V;
+ int menu1_bottom = menu1_top + MENU_HEIGHT;
+ int menu2_top = menu1_bottom + MENU_SPACE_V;
+ int menu2_bottom = menu2_top + MENU_HEIGHT;
+ int menu3_top = menu2_bottom + MENU_SPACE_V;
+ int menu3_bottom = menu3_top + MENU_HEIGHT;
+
+ if(ui_point.v >= menu1_top && ui_point.v <= menu1_bottom)
+ return REGION_MENU1;
+ else if(ui_point.v >= menu2_top && ui_point.v <= menu2_bottom)
+ return REGION_MENU2;
+ else if(third_menu && ui_point.v >= menu3_top && ui_point.v <= menu3_bottom)
+ return REGION_MENU3;
+ }
+ }
+ }
+
+ return REGION_NONE;
+}
+
+
+static void DrawMenu(DrawbotBot &bot, const char *label, const char *item)
+{
+ DRAWBOT_PointF32 original = bot.Pos();
+
+ float text_height = bot.FontSize();
+
+ bot.Move(MENU_LABEL_WIDTH, MENU_TEXT_INDENT_V + text_height);
+
+ bot.SetColor(TEXT_COLOR);
+ bot.DrawString(label, kDRAWBOT_TextAlignment_Right);
+
+ bot.Move(MENU_LABEL_SPACE, -(MENU_TEXT_INDENT_V + text_height));
+
+ DRAWBOT_PointF32 menu_corner = bot.Pos();
+
+ bot.Move(MENU_SHADOW_OFFSET, MENU_SHADOW_OFFSET);
+ bot.SetColor(PF_App_Color_BLACK, 0.3f);
+ bot.PaintRect(MENU_WIDTH, MENU_HEIGHT);
+ bot.MoveTo(menu_corner);
+
+ bot.SetColor(PF_App_Color_SHADOW);
+ bot.PaintRect(MENU_WIDTH, MENU_HEIGHT);
+
+ bot.SetColor(PF_App_Color_HILITE);
+ bot.DrawRect(MENU_WIDTH, MENU_HEIGHT);
+
+ bot.Move(MENU_TEXT_INDENT_H, MENU_TEXT_INDENT_V + text_height);
+
+ bot.SetColor(TEXT_COLOR);
+ bot.DrawString(item,
+ kDRAWBOT_TextAlignment_Left,
+ kDRAWBOT_TextTruncation_EndEllipsis,
+ MENU_WIDTH - MENU_TEXT_INDENT_H - MENU_TEXT_INDENT_H -
+ MENU_ARROW_WIDTH - MENU_ARROW_SPACE_H - MENU_ARROW_SPACE_H);
+
+ bot.MoveTo(menu_corner.x + MENU_WIDTH - MENU_ARROW_SPACE_H - MENU_ARROW_WIDTH,
+ menu_corner.y + MENU_ARROW_SPACE_V);
+
+ bot.SetColor(PF_App_Color_LIGHT_TINGE);
+ bot.PaintTriangle(MENU_ARROW_WIDTH, MENU_ARROW_HEIGHT);
+
+ bot.MoveTo(original);
+}
+
+
+static void DrawButton(DrawbotBot &bot, const char *label, int width, bool pressed)
+{
+ DRAWBOT_PointF32 original = bot.Pos();
+
+ float text_height = bot.FontSize();
+
+
+ PF_App_ColorType button_color = (pressed ? PF_App_Color_BUTTON_PRESSED_FILL : PF_App_Color_BUTTON_FILL);
+ PF_App_ColorType button_hilite = (pressed ? PF_App_Color_BLACK : PF_App_Color_HILITE);
+ PF_App_ColorType button_lowlite = (pressed ? PF_App_Color_HILITE : PF_App_Color_BLACK);
+
+
+ bot.SetColor(button_color);
+ bot.PaintRect(width, BUTTON_HEIGHT);
+
+ float brush_size = (pressed ? 1.f : 0.5f);
+
+ bot.SetColor(button_hilite);
+ bot.MoveTo(original.x + 1, original.y + BUTTON_HEIGHT - 1);
+
+ bot.DrawLineTo(original.x + 1, original.y + 1, brush_size);
+ bot.DrawLineTo(original.x + width - 1, original.y + 1, brush_size);
+
+ bot.MoveTo(original); // annoying corner pixel
+ bot.SetColor(button_hilite, 0.3f);
+ bot.PaintRect(1, 1);
+
+
+ brush_size = (pressed ? 0.5f : 1.f);
+
+ bot.SetColor(button_lowlite);
+ bot.MoveTo(original.x + 1, original.y + BUTTON_HEIGHT - 1);
+
+ bot.DrawLineTo(original.x + width - 1, original.y + BUTTON_HEIGHT - 1, brush_size);
+ bot.DrawLineTo(original.x + width - 1, original.y + 2, brush_size);
+
+ bot.MoveTo(original.x + width - 1, original.y + BUTTON_HEIGHT - 1); // corner
+ bot.SetColor(button_lowlite, 0.3f);
+ bot.PaintRect(1, 1);
+
+
+ bot.MoveTo(original.x + (width / 2), original.y + text_height + BUTTON_TEXT_INDENT_V);
+
+ if(pressed)
+ bot.Move(2, 2);
+
+ bot.SetColor(TEXT_COLOR);
+ bot.DrawString(label, kDRAWBOT_TextAlignment_Center);
+
+ bot.MoveTo(original);
+}
+
+
+static PF_Err DrawEvent(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output,
+ PF_EventExtra *event_extra)
+{
+ PF_Err err = PF_Err_NONE;
+
+
+ if(!(event_extra->evt_in_flags & PF_EI_DONT_DRAW) &&
+ params[OCIO_DATA]->u.arb_d.value != NULL)
+ {
+ if(event_extra->effect_win.area == PF_EA_CONTROL)
+ {
+ ArbitraryData *arb_data = (ArbitraryData *)PF_LOCK_HANDLE(params[OCIO_DATA]->u.arb_d.value);
+ SequenceData *seq_data = (SequenceData *)PF_LOCK_HANDLE(in_data->sequence_data);
+
+ DrawbotBot bot(in_data->pica_basicP, event_extra->contextH, in_data->appl_id);
+
+
+ int panel_left = event_extra->effect_win.current_frame.left;
+ int panel_top = event_extra->effect_win.current_frame.top;
+ int panel_width = event_extra->effect_win.current_frame.right;
+ int panel_height = event_extra->effect_win.current_frame.bottom;
+ float text_height = bot.FontSize();
+
+ if(in_data->appl_id != 'FXTC')
+ {
+ // for Premiere we need to paint the background first
+ bot.SetColor(PF_App_Color_PANEL_BACKGROUND);
+ bot.MoveTo(panel_left, panel_top);
+ bot.PaintRect(panel_width, panel_height);
+ }
+
+
+ // configuration menu
+ bot.MoveTo(panel_left + MENUS_INDENT_H, panel_top + TOP_MARGIN);
+
+ std::string config_menu_text = arb_data->path;
+
+ if(arb_data->source == OCIO_SOURCE_NONE)
+ {
+ config_menu_text = "(none)";
+ }
+ if(arb_data->source == OCIO_SOURCE_ENVIRONMENT)
+ {
+ config_menu_text = "$OCIO";
+ }
+ else if(arb_data->source == OCIO_SOURCE_CUSTOM)
+ {
+ config_menu_text = (arb_data->action == OCIO_ACTION_LUT ? "LUT" : "Custom");
+ }
+
+ DrawMenu(bot, "Configuration:", config_menu_text.c_str());
+
+
+ if(arb_data->source == OCIO_SOURCE_CUSTOM ||
+ arb_data->source == OCIO_SOURCE_ENVIRONMENT)
+ {
+ // path text field
+ int field_left = panel_left + MENUS_INDENT_H + MENU_LABEL_WIDTH +
+ MENU_LABEL_SPACE + MENU_WIDTH + FIELD_TEXT_INDENT_H;
+
+ bot.MoveTo(field_left, panel_top + TOP_MARGIN);
+
+ int field_width = MAX(panel_width - field_left + panel_left - RIGHT_MARGIN, 60);
+
+ bot.SetColor(PF_App_Color_SHADOW);
+ bot.PaintRect(field_width, FIELD_HEIGHT);
+ bot.SetColor(PF_App_Color_BLACK);
+ bot.DrawRect(field_width, FIELD_HEIGHT);
+
+ bot.Move(FIELD_TEXT_INDENT_H, FIELD_TEXT_INDENT_V + text_height);
+
+ bot.SetColor(TEXT_COLOR);
+
+ std::string file_string = "(none)";
+
+ if(arb_data->source == OCIO_SOURCE_ENVIRONMENT)
+ {
+ char *file = std::getenv("OCIO");
+
+ if(file)
+ file_string = file;
+ }
+ else
+ {
+ file_string = (seq_data->status == STATUS_USING_RELATIVE ?
+ arb_data->relative_path : arb_data->path);
+ }
+
+
+ bot.DrawString(file_string.c_str(),
+ kDRAWBOT_TextAlignment_Default,
+ kDRAWBOT_TextTruncation_PathEllipsis,
+ field_width - (2 * FIELD_TEXT_INDENT_H));
+ }
+
+
+ if(seq_data->status == STATUS_FILE_MISSING)
+ {
+ bot.MoveTo(panel_left + MENU_LABEL_WIDTH + MENU_LABEL_SPACE,
+ panel_top + MENU_HEIGHT + BUTTONS_GAP_V + BUTTON_HEIGHT + BUTTONS_GAP_V);
+
+ bot.SetColor(PF_App_Color_RED);
+ bot.PaintRect(200, 50);
+
+ bot.Move(100, 25 + (bot.FontSize() / 2));
+ bot.SetColor(PF_App_Color_WHITE);
+
+ if(arb_data->source == OCIO_SOURCE_ENVIRONMENT)
+ bot.DrawString("$OCIO NOT SET", kDRAWBOT_TextAlignment_Center);
+ else
+ bot.DrawString("FILE MISSING", kDRAWBOT_TextAlignment_Center);
+ }
+ else
+ {
+ // buttons
+ int field_bottom = panel_top + TOP_MARGIN + FIELD_HEIGHT;
+ int buttons_top = field_bottom + BUTTONS_GAP_V;
+
+ // GPU alert
+ if(seq_data->gpu_err != GPU_ERR_NONE)
+ {
+ bot.MoveTo(panel_left + MENU_LABEL_WIDTH + MENU_LABEL_SPACE,
+ field_bottom + bot.FontSize() + BUTTON_TEXT_INDENT_V);
+
+ if(seq_data->gpu_err == GPU_ERR_INSUFFICIENT)
+ {
+ bot.DrawString("GPU Insufficient");
+ }
+ else if(seq_data->gpu_err == GPU_ERR_RENDER_ERR)
+ {
+ bot.DrawString("GPU Render Error");
+ }
+ }
+
+ #ifndef NDEBUG
+ // Premiere color space (only for debugging purposes)
+ if(in_data->appl_id == 'PrMr' && seq_data->prem_status != PREMIERE_UNKNOWN)
+ {
+ bot.MoveTo(panel_left + MENU_LABEL_WIDTH + MENU_LABEL_SPACE + 200,
+ field_bottom + bot.FontSize() + BUTTON_TEXT_INDENT_V);
+
+ bot.SetColor(PF_App_Color_WHITE);
+
+ if(seq_data->prem_status == PREMIERE_LINEAR)
+ {
+ bot.DrawString("Linear Float");
+ }
+ else if(seq_data->prem_status == PREMIERE_NON_LINEAR)
+ {
+ bot.DrawString("Non-Linear Float");
+ }
+ }
+ #endif
+
+ // Export button
+ if(arb_data->action != OCIO_ACTION_NONE)
+ {
+ bot.MoveTo(panel_left + BUTTONS_INDENT_H + (2 * (BUTTON_WIDTH + BUTTONS_GAP_H)), buttons_top);
+
+ DrawButton(bot, "Export...", BUTTON_WIDTH, false);
+ }
+
+ if(arb_data->action == OCIO_ACTION_LUT)
+ {
+ // Invert button
+ bot.MoveTo(panel_left + BUTTONS_INDENT_H, buttons_top);
+
+ DrawButton(bot, "Invert", BUTTON_WIDTH, arb_data->invert);
+
+ // interpolation menu
+ int buttons_bottom = buttons_top + BUTTON_HEIGHT;
+
+ bot.MoveTo(panel_left + MENUS_INDENT_H, buttons_bottom + MENUS_GAP_V);
+
+ const char *txt = arb_data->interpolation == OCIO_INTERP_NEAREST ? "Nearest Neighbor" :
+ arb_data->interpolation == OCIO_INTERP_LINEAR ? "Linear" :
+ arb_data->interpolation == OCIO_INTERP_TETRAHEDRAL ? "Tetrahedral" :
+ arb_data->interpolation == OCIO_INTERP_BEST ? "Best" :
+ "Unknown";
+
+ DrawMenu(bot, "Interpolation:", txt);
+ }
+ else if(arb_data->action == OCIO_ACTION_CONVERT ||
+ arb_data->action == OCIO_ACTION_DISPLAY)
+ {
+ // Convert/Display buttons
+ bot.MoveTo(panel_left + BUTTONS_INDENT_H, buttons_top);
+
+ DrawButton(bot, "Convert", BUTTON_WIDTH,
+ arb_data->action == OCIO_ACTION_CONVERT);
+
+ bot.Move(BUTTON_WIDTH + BUTTONS_GAP_H);
+
+ DrawButton(bot, "Display", BUTTON_WIDTH,
+ arb_data->action == OCIO_ACTION_DISPLAY);
+
+
+ // menus
+ int buttons_bottom = buttons_top + BUTTON_HEIGHT;
+
+ bot.MoveTo(panel_left + MENUS_INDENT_H, buttons_bottom + MENUS_GAP_V);
+
+ if(arb_data->action == OCIO_ACTION_CONVERT)
+ {
+ DrawMenu(bot, "Input Space:", arb_data->input);
+
+ bot.Move(0, MENU_HEIGHT + MENU_SPACE_V);
+
+ DrawMenu(bot, "Output Space:", arb_data->output);
+ }
+ else if(arb_data->action == OCIO_ACTION_DISPLAY)
+ {
+ // color space transformations
+ DrawMenu(bot, "Input Space:", arb_data->input);
+
+ bot.Move(0, MENU_HEIGHT + MENU_SPACE_V);
+
+ DrawMenu(bot, "Transform:", arb_data->transform);
+
+ bot.Move(0, MENU_HEIGHT + MENU_SPACE_V);
+
+ DrawMenu(bot, "Device:", arb_data->device);
+ }
+ }
+ }
+
+
+ event_extra->evt_out_flags = PF_EO_HANDLED_EVENT;
+
+ PF_UNLOCK_HANDLE(params[OCIO_DATA]->u.arb_d.value);
+ PF_UNLOCK_HANDLE(in_data->sequence_data);
+ }
+ }
+
+ return err;
+}
+
+
+std::string GetProjectDir(PF_InData *in_data)
+{
+ if(in_data->appl_id == 'PrMr')
+ return std::string("");
+
+ AEGP_SuiteHandler suites(in_data->pica_basicP);
+
+ AEGP_ProjectH projH = NULL;
+ suites.ProjSuite5()->AEGP_GetProjectByIndex(0, &projH);
+
+ AEGP_MemHandle pathH = NULL;
+ suites.ProjSuite5()->AEGP_GetProjectPath(projH, &pathH);
+
+ if(pathH)
+ {
+ std::string proj_dir;
+
+ A_UTF16Char *path = NULL;
+ suites.MemorySuite1()->AEGP_LockMemHandle(pathH, (void **)&path);
+
+ if(path)
+ {
+ // poor-man's unicode copy
+ char c_path[AEGP_MAX_PATH_SIZE];
+
+ char *c = c_path;
+ A_UTF16Char *s = path;
+
+ do{
+ *c++ = *s;
+ }while(*s++ != '\0');
+
+#ifdef WIN_ENV
+#define PATH_DELIMITER '\\'
+#else
+#define PATH_DELIMITER '/'
+#endif
+
+ std::string proj_path(c_path);
+
+ if(proj_path.find_last_of(PATH_DELIMITER) != std::string::npos)
+ {
+ proj_dir = proj_path.substr(0, proj_path.find_last_of(PATH_DELIMITER));
+ }
+ }
+
+ suites.MemorySuite1()->AEGP_FreeMemHandle(pathH);
+
+ return proj_dir;
+ }
+
+ return std::string("");
+}
+
+
+static int FindInVec(const std::vector<std::string> &vec, const std::string val)
+{
+ for(int i=0; i < vec.size(); i++)
+ {
+ if(vec[i] == val)
+ return i;
+ }
+
+ return -1;
+}
+
+
+static void DoClickPath(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output,
+ PF_EventExtra *event_extra,
+ ArbitraryData *arb_data,
+ SequenceData *seq_data)
+{
+ ExtensionMap extensions;
+
+ for(int i=0; i < OCIO::FileTransform::getNumFormats(); i++)
+ {
+ const char *extension = OCIO::FileTransform::getFormatExtensionByIndex(i);
+ const char *format = OCIO::FileTransform::getFormatNameByIndex(i);
+
+ extensions[ extension ] = format;
+ }
+
+ extensions[ "ocio" ] = "OCIO Format";
+
+
+ void *hwndOwner = NULL;
+
+#ifdef WIN_ENV
+ PF_GET_PLATFORM_DATA(PF_PlatData_MAIN_WND, &hwndOwner);
+#endif
+
+ char c_path[ARB_PATH_LEN + 1] = { '\0' };
+
+ bool result = OpenFile(c_path, ARB_PATH_LEN, extensions, hwndOwner);
+
+
+ if(result)
+ {
+ Path path(c_path, GetProjectDir(in_data));
+
+ OpenColorIO_AE_Context *new_context = new OpenColorIO_AE_Context(path.full_path(),
+ OCIO_SOURCE_CUSTOM);
+
+ if(new_context == NULL)
+ throw OCIO::Exception("WTF?");
+
+
+ if(seq_data->context)
+ {
+ delete seq_data->context;
+ }
+
+ seq_data->context = new_context;
+
+ arb_data->source = seq_data->source = OCIO_SOURCE_CUSTOM;
+
+ strncpy(arb_data->path, path.full_path().c_str(), ARB_PATH_LEN);
+ strncpy(arb_data->relative_path, path.relative_path(false).c_str(), ARB_PATH_LEN);
+
+ strncpy(seq_data->path, arb_data->path, ARB_PATH_LEN);
+ strncpy(seq_data->relative_path, arb_data->relative_path, ARB_PATH_LEN);
+
+
+ // try to retain settings if it looks like the same situation,
+ // possibly fixing a moved path
+ if(OCIO_ACTION_NONE == arb_data->action ||
+ (OCIO_ACTION_LUT == new_context->getAction() && OCIO_ACTION_LUT != arb_data->action) ||
+ (OCIO_ACTION_LUT != new_context->getAction() && OCIO_ACTION_LUT == arb_data->action) ||
+ (OCIO_ACTION_LUT != new_context->getAction() &&
+ (-1 == FindInVec(new_context->getInputs(), arb_data->input) ||
+ -1 == FindInVec(new_context->getInputs(), arb_data->output) ||
+ -1 == FindInVec(new_context->getTransforms(), arb_data->transform) ||
+ -1 == FindInVec(new_context->getDevices(), arb_data->device) ) ) )
+ {
+ // Configuration is different, so initialize defaults
+ arb_data->action = seq_data->context->getAction();
+
+ if(arb_data->action == OCIO_ACTION_LUT)
+ {
+ arb_data->invert = FALSE;
+ arb_data->interpolation = OCIO_INTERP_LINEAR;
+ }
+ else
+ {
+ strncpy(arb_data->input, seq_data->context->getInput().c_str(), ARB_SPACE_LEN);
+ strncpy(arb_data->output, seq_data->context->getOutput().c_str(), ARB_SPACE_LEN);
+ strncpy(arb_data->transform, seq_data->context->getTransform().c_str(), ARB_SPACE_LEN);
+ strncpy(arb_data->device, seq_data->context->getDevice().c_str(), ARB_SPACE_LEN);
+ }
+ }
+ else
+ {
+ // Configuration is the same, retain current settings
+ if(arb_data->action == OCIO_ACTION_LUT)
+ {
+ seq_data->context->setupLUT(arb_data->invert, arb_data->interpolation);
+ }
+ else if(arb_data->action == OCIO_ACTION_CONVERT)
+ {
+ seq_data->context->setupConvert(arb_data->input, arb_data->output);
+ }
+ else if(arb_data->action == OCIO_ACTION_DISPLAY)
+ {
+ seq_data->context->setupDisplay(arb_data->input, arb_data->transform, arb_data->device);
+ }
+ }
+
+ params[OCIO_DATA]->uu.change_flags = PF_ChangeFlag_CHANGED_VALUE;
+
+ seq_data->status = STATUS_USING_ABSOLUTE;
+ }
+}
+
+
+static void DoClickConfig(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output,
+ PF_EventExtra *event_extra,
+ ArbitraryData *arb_data,
+ SequenceData *seq_data)
+{
+ void *hwndOwner = NULL;
+
+#ifdef WIN_ENV
+ PF_GET_PLATFORM_DATA(PF_PlatData_MAIN_WND, &hwndOwner);
+#endif
+
+ ConfigVec configs;
+ GetStdConfigs(configs);
+
+ if(configs.size() == 0)
+ configs.push_back("(nada)"); // menu makes a gray entry that says "No configs in $PATH"
+
+
+ MenuVec menu_items;
+ int selected = 0;
+
+ menu_items.push_back("$OCIO"); // menu will gray this out if $OCIO is not defined
+
+ menu_items.push_back("(-"); // this tells the menu to make a seperator
+
+ for(ConfigVec::const_iterator i = configs.begin(); i != configs.end(); ++i)
+ {
+ menu_items.push_back( *i );
+
+ if(arb_data->source == OCIO_SOURCE_STANDARD && arb_data->path == *i)
+ {
+ selected = menu_items.size() - 1;
+ }
+ }
+
+ menu_items.push_back("(-");
+
+ menu_items.push_back("Custom...");
+
+ int custom_choice = menu_items.size() - 1;
+
+ if(arb_data->source == OCIO_SOURCE_CUSTOM)
+ {
+ selected = -1;
+ }
+
+
+ int choice = PopUpMenu(menu_items, selected, hwndOwner);
+
+
+ if(choice == custom_choice)
+ {
+ // custom is the same as clicking the path
+ DoClickPath(in_data, out_data, params, output, event_extra, arb_data, seq_data);
+ }
+ else if(choice != selected)
+ {
+ OpenColorIO_AE_Context *new_context = NULL;
+
+ if(choice == 0)
+ {
+ // $OCIO
+ char *file = std::getenv("OCIO");
+
+ if(file)
+ {
+ Path path(file, GetProjectDir(in_data));
+
+ new_context = new OpenColorIO_AE_Context(path.full_path(),
+ OCIO_SOURCE_ENVIRONMENT);
+
+ arb_data->source = seq_data->source = OCIO_SOURCE_ENVIRONMENT;
+
+ strncpy(arb_data->path, path.full_path().c_str(), ARB_PATH_LEN);
+ strncpy(arb_data->relative_path, path.relative_path(false).c_str(), ARB_PATH_LEN);
+ }
+ else
+ throw OCIO::Exception("No $OCIO environment variable defined.");
+ }
+ else
+ {
+ // standard configs
+ std::string config = configs[choice - 2];
+
+ std::string path = GetStdConfigPath(config);
+
+ if( !path.empty() )
+ {
+ new_context = new OpenColorIO_AE_Context(config, OCIO_SOURCE_STANDARD);
+
+ arb_data->source = seq_data->source = OCIO_SOURCE_STANDARD;
+
+ strncpy(arb_data->path, config.c_str(), ARB_PATH_LEN);
+ strncpy(arb_data->relative_path, path.c_str(), ARB_PATH_LEN);
+ }
+ else
+ throw OCIO::Exception("Problem loading OCIO configuration.");
+ }
+
+
+ if(new_context)
+ {
+ if(seq_data->context)
+ {
+ delete seq_data->context;
+ }
+
+ seq_data->context = new_context;
+
+
+ strncpy(seq_data->path, arb_data->path, ARB_PATH_LEN);
+ strncpy(seq_data->relative_path, arb_data->relative_path, ARB_PATH_LEN);
+
+ // try to retain settings if it looks like the same situation,
+ // possibly fixing a moved path
+ if(OCIO_ACTION_NONE == arb_data->action ||
+ (OCIO_ACTION_LUT == new_context->getAction() && OCIO_ACTION_LUT != arb_data->action) ||
+ (OCIO_ACTION_LUT != new_context->getAction() && OCIO_ACTION_LUT == arb_data->action) ||
+ (OCIO_ACTION_LUT != new_context->getAction() &&
+ (-1 == FindInVec(new_context->getInputs(), arb_data->input) ||
+ -1 == FindInVec(new_context->getInputs(), arb_data->output) ||
+ -1 == FindInVec(new_context->getTransforms(), arb_data->transform) ||
+ -1 == FindInVec(new_context->getDevices(), arb_data->device) ) ) )
+ {
+ // Configuration is different, so initialize defaults
+ arb_data->action = seq_data->context->getAction();
+
+ if(arb_data->action == OCIO_ACTION_LUT)
+ {
+ arb_data->invert = FALSE;
+ arb_data->interpolation = OCIO_INTERP_LINEAR;
+ }
+ else
+ {
+ strncpy(arb_data->input, seq_data->context->getInput().c_str(), ARB_SPACE_LEN);
+ strncpy(arb_data->output, seq_data->context->getOutput().c_str(), ARB_SPACE_LEN);
+ strncpy(arb_data->transform, seq_data->context->getTransform().c_str(), ARB_SPACE_LEN);
+ strncpy(arb_data->device, seq_data->context->getDevice().c_str(), ARB_SPACE_LEN);
+ }
+ }
+ else
+ {
+ // Configuration is the same, retain current settings
+ if(arb_data->action == OCIO_ACTION_LUT)
+ {
+ seq_data->context->setupLUT(arb_data->invert, arb_data->interpolation);
+ }
+ else if(arb_data->action == OCIO_ACTION_CONVERT)
+ {
+ seq_data->context->setupConvert(arb_data->input, arb_data->output);
+ }
+ else if(arb_data->action == OCIO_ACTION_DISPLAY)
+ {
+ seq_data->context->setupDisplay(arb_data->input, arb_data->transform, arb_data->device);
+ }
+ }
+
+ params[OCIO_DATA]->uu.change_flags = PF_ChangeFlag_CHANGED_VALUE;
+
+ seq_data->status = STATUS_OK;
+ }
+ }
+}
+
+
+static void DoClickConvertDisplay(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output,
+ PF_EventExtra *event_extra,
+ ArbitraryData *arb_data,
+ SequenceData *seq_data,
+ UIRegion reg )
+{
+ if(arb_data->action == OCIO_ACTION_LUT)
+ {
+ if(reg == REGION_CONVERT_BUTTON) // i.e. Invert
+ {
+ // doing it this way so that any exceptions thrown by setupLUT
+ // because the LUT can't be inverted are thrown before
+ // I actually chenge the ArbData setting
+ seq_data->context->setupLUT(!arb_data->invert, arb_data->interpolation);
+
+ arb_data->invert = !arb_data->invert;
+
+ params[OCIO_DATA]->uu.change_flags = PF_ChangeFlag_CHANGED_VALUE;
+ }
+ }
+ else if(arb_data->action == OCIO_ACTION_CONVERT || arb_data->action == OCIO_ACTION_DISPLAY)
+ {
+ if(reg == REGION_CONVERT_BUTTON && arb_data->action != OCIO_ACTION_CONVERT)
+ {
+ arb_data->action = OCIO_ACTION_CONVERT;
+
+ seq_data->context->setupConvert(arb_data->input, arb_data->output);
+
+ params[OCIO_DATA]->uu.change_flags = PF_ChangeFlag_CHANGED_VALUE;
+ }
+ else if(reg == REGION_DISPLAY_BUTTON && arb_data->action != OCIO_ACTION_DISPLAY)
+ {
+ arb_data->action = OCIO_ACTION_DISPLAY;
+
+ seq_data->context->setupDisplay(arb_data->input, arb_data->transform, arb_data->device);
+
+ params[OCIO_DATA]->uu.change_flags = PF_ChangeFlag_CHANGED_VALUE;
+ }
+ }
+}
+
+
+static void DoClickExport(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output,
+ PF_EventExtra *event_extra,
+ ArbitraryData *arb_data,
+ SequenceData *seq_data,
+ UIRegion reg )
+{
+ ExtensionMap extensions;
+
+ for(int i=0; i < OCIO::Baker::getNumFormats(); ++i)
+ {
+ const char *extension = OCIO::Baker::getFormatExtensionByIndex(i);
+ const char *format = OCIO::Baker::getFormatNameByIndex(i);
+
+ extensions[ extension ] = format;
+ }
+
+ extensions[ "icc" ] = "ICC Profile";
+
+
+ void *hwndOwner = NULL;
+
+#ifdef WIN_ENV
+ PF_GET_PLATFORM_DATA(PF_PlatData_MAIN_WND, &hwndOwner);
+#endif
+
+ char path[256] = { '\0' };
+
+ bool result = SaveFile(path, 255, extensions, hwndOwner);
+
+
+ if(result)
+ {
+ std::string the_path(path);
+ std::string the_extension = the_path.substr( the_path.find_last_of('.') + 1 );
+
+ bool do_export = true;
+
+ std::string monitor_icc_path;
+
+ if(the_extension == "icc")
+ {
+ char monitor_path[256] = {'\0'};
+
+ do_export = GetMonitorProfile(monitor_path, 255, hwndOwner);
+
+ if(monitor_path[0] != '\0')
+ monitor_icc_path = monitor_path;
+ }
+
+ if(do_export)
+ seq_data->context->ExportLUT(the_path, monitor_icc_path);
+ }
+}
+
+
+static void DoClickMenus(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output,
+ PF_EventExtra *event_extra,
+ ArbitraryData *arb_data,
+ SequenceData *seq_data,
+ UIRegion reg )
+{
+ if(seq_data->context != NULL && arb_data->action == seq_data->context->getAction())
+ {
+ MenuVec menu_items;
+ int selected_item;
+
+ if(arb_data->action == OCIO_ACTION_LUT)
+ {
+ if(reg == REGION_MENU1)
+ {
+ menu_items.push_back("Nearest Neighbor");
+ menu_items.push_back("Linear");
+ menu_items.push_back("Tetrahedral");
+ menu_items.push_back("(-");
+ menu_items.push_back("Best");
+
+ selected_item = arb_data->interpolation == OCIO_INTERP_NEAREST ? 0 :
+ arb_data->interpolation == OCIO_INTERP_LINEAR ? 1 :
+ arb_data->interpolation == OCIO_INTERP_TETRAHEDRAL ? 2 :
+ arb_data->interpolation == OCIO_INTERP_BEST ? 4 :
+ -1;
+ }
+ }
+ else if(arb_data->action == OCIO_ACTION_CONVERT)
+ {
+ menu_items = seq_data->context->getInputs();
+
+ if(reg == REGION_MENU1)
+ {
+ selected_item = FindInVec(menu_items, arb_data->input);
+ }
+ else
+ {
+ selected_item = FindInVec(menu_items, arb_data->output);
+ }
+ }
+ else if(arb_data->action == OCIO_ACTION_DISPLAY)
+ {
+ if(reg == REGION_MENU1)
+ {
+ menu_items = seq_data->context->getInputs();
+
+ selected_item = FindInVec(menu_items, arb_data->input);
+ }
+ else if(reg == REGION_MENU2)
+ {
+ menu_items = seq_data->context->getTransforms();
+
+ selected_item = FindInVec(menu_items, arb_data->transform);
+ }
+ else if(reg == REGION_MENU3)
+ {
+ menu_items = seq_data->context->getDevices();
+
+ selected_item = FindInVec(menu_items, arb_data->device);
+ }
+ }
+
+
+
+ void *hwndOwner = NULL;
+
+ #ifdef WIN_ENV
+ PF_GET_PLATFORM_DATA(PF_PlatData_MAIN_WND, &hwndOwner);
+ #endif
+
+ int result = PopUpMenu(menu_items, selected_item, hwndOwner);
+
+
+ if(result != selected_item)
+ {
+ std::string color_space = menu_items[ result ];
+
+ if(arb_data->action == OCIO_ACTION_LUT)
+ {
+ if(reg == REGION_MENU1)
+ {
+ arb_data->interpolation = result == 0 ? OCIO_INTERP_NEAREST :
+ result == 2 ? OCIO_INTERP_TETRAHEDRAL :
+ result == 4 ? OCIO_INTERP_BEST :
+ OCIO_INTERP_LINEAR;
+
+ seq_data->context->setupLUT(arb_data->invert, arb_data->interpolation);
+ }
+ }
+ else if(arb_data->action == OCIO_ACTION_CONVERT)
+ {
+ if(reg == REGION_MENU1)
+ {
+ strncpy(arb_data->input, color_space.c_str(), ARB_SPACE_LEN);
+ }
+ else if(reg == REGION_MENU2)
+ {
+ strncpy(arb_data->output, color_space.c_str(), ARB_SPACE_LEN);
+ }
+
+ seq_data->context->setupConvert(arb_data->input, arb_data->output);
+ }
+ else if(arb_data->action == OCIO_ACTION_DISPLAY)
+ {
+ if(reg == REGION_MENU1)
+ {
+ strncpy(arb_data->input, color_space.c_str(), ARB_SPACE_LEN);
+ }
+ else if(reg == REGION_MENU2)
+ {
+ strncpy(arb_data->transform, color_space.c_str(), ARB_SPACE_LEN);
+ }
+ else if(reg == REGION_MENU3)
+ {
+ strncpy(arb_data->device, color_space.c_str(), ARB_SPACE_LEN);
+ }
+
+ seq_data->context->setupDisplay(arb_data->input, arb_data->transform, arb_data->device);
+ }
+
+ params[OCIO_DATA]->uu.change_flags = PF_ChangeFlag_CHANGED_VALUE;
+ }
+ }
+}
+
+
+static PF_Err DoClick(
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output,
+ PF_EventExtra *event_extra )
+{
+ PF_Err err = PF_Err_NONE;
+
+ ArbitraryData *arb_data = (ArbitraryData *)PF_LOCK_HANDLE(params[OCIO_DATA]->u.arb_d.value);
+ SequenceData *seq_data = (SequenceData *)PF_LOCK_HANDLE(in_data->sequence_data);
+
+
+ if(event_extra->effect_win.area == PF_EA_CONTROL)
+ {
+ bool menus_visible = (arb_data->action != OCIO_ACTION_NONE);
+ bool third_menu = (arb_data->action == OCIO_ACTION_DISPLAY);
+
+ PF_Point local_point;
+
+ local_point.h = event_extra->u.do_click.screen_point.h - event_extra->effect_win.current_frame.left;
+ local_point.v = event_extra->u.do_click.screen_point.v - event_extra->effect_win.current_frame.top;
+
+ UIRegion reg = WhichRegion(local_point, menus_visible, third_menu);
+
+ if(reg != REGION_NONE)
+ {
+ try
+ {
+ if(reg == REGION_CONFIG_MENU)
+ {
+ DoClickConfig(in_data, out_data, params, output,
+ event_extra, arb_data, seq_data);
+ }
+ else if(reg == REGION_PATH)
+ {
+ if(arb_data->source == OCIO_SOURCE_CUSTOM)
+ {
+ DoClickPath(in_data, out_data, params, output,
+ event_extra, arb_data, seq_data);
+ }
+ }
+ else if(arb_data->action != OCIO_ACTION_NONE &&
+ seq_data->status != STATUS_FILE_MISSING)
+ {
+ if(seq_data->context == NULL)
+ {
+ seq_data->context = new OpenColorIO_AE_Context(arb_data,
+ GetProjectDir(in_data) );
+ }
+
+ if(reg == REGION_CONVERT_BUTTON || reg == REGION_DISPLAY_BUTTON)
+ {
+ DoClickConvertDisplay(in_data, out_data, params, output,
+ event_extra, arb_data, seq_data, reg);
+ }
+ else if(reg == REGION_EXPORT_BUTTON)
+ {
+ DoClickExport(in_data, out_data, params, output,
+ event_extra, arb_data, seq_data, reg);
+ }
+ else // must be a menu then
+ {
+ DoClickMenus(in_data, out_data, params, output,
+ event_extra, arb_data, seq_data, reg);
+ }
+ }
+ }
+ catch(std::exception &e)
+ {
+ if(in_data->appl_id == 'FXTC')
+ {
+ PF_SPRINTF(out_data->return_msg, e.what());
+
+ out_data->out_flags |= PF_OutFlag_DISPLAY_ERROR_MESSAGE;
+ }
+ else
+ {
+ void *hwndOwner = NULL;
+
+ #ifdef WIN_ENV
+ PF_GET_PLATFORM_DATA(PF_PlatData_MAIN_WND, &hwndOwner);
+ #endif
+
+ ErrorMessage(e.what(), hwndOwner);
+ }
+ }
+ catch(...)
+ {
+ PF_SPRINTF(out_data->return_msg, "Unknown error");
+
+ out_data->out_flags |= PF_OutFlag_DISPLAY_ERROR_MESSAGE;
+ }
+ }
+ }
+
+
+ PF_UNLOCK_HANDLE(params[OCIO_DATA]->u.arb_d.value);
+ PF_UNLOCK_HANDLE(in_data->sequence_data);
+
+ event_extra->evt_out_flags = PF_EO_HANDLED_EVENT;
+
+ return err;
+}
+
+
+PF_Err HandleEvent (
+ PF_InData *in_data,
+ PF_OutData *out_data,
+ PF_ParamDef *params[],
+ PF_LayerDef *output,
+ PF_EventExtra *extra )
+{
+ PF_Err err = PF_Err_NONE;
+
+ extra->evt_out_flags = 0;
+
+ if(!err)
+ {
+ switch(extra->e_type)
+ {
+ case PF_Event_DRAW:
+ err = DrawEvent(in_data, out_data, params, output, extra);
+ break;
+
+ case PF_Event_DO_CLICK:
+ err = DoClick(in_data, out_data, params, output, extra);
+ break;
+ }
+ }
+
+ return err;
+}
diff --git a/src/aftereffects/mac/OpenColorIO_AE.plugin-Info.plist b/src/aftereffects/mac/OpenColorIO_AE.plugin-Info.plist
new file mode 100755
index 0000000..45ad29d
--- /dev/null
+++ b/src/aftereffects/mac/OpenColorIO_AE.plugin-Info.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleIdentifier</key>
+ <string>org.OpenColorIO.AfterEffects</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>OpenColorIO</string>
+ <key>CFBundleExecutable</key>
+ <string>OpenColorIO</string>
+ <key>CFBundlePackageType</key>
+ <string>eFKT</string>
+ <key>CFBundleSignature</key>
+ <string>FXTC</string>
+ <key>NSAppleScriptEnabled</key>
+ <string>No</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>© 2011 OpenColorIO</string>
+ <key>LSRequiresCarbon</key>
+ <true/>
+</dict>
+</plist>
diff --git a/src/aftereffects/mac/OpenColorIO_AE_Dialogs_Cocoa.mm b/src/aftereffects/mac/OpenColorIO_AE_Dialogs_Cocoa.mm
new file mode 100644
index 0000000..24a048f
--- /dev/null
+++ b/src/aftereffects/mac/OpenColorIO_AE_Dialogs_Cocoa.mm
@@ -0,0 +1,237 @@
+/*
+Copyright (c) 2003-2012 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_AE_Dialogs.h"
+
+#import "OpenColorIO_AE_MonitorProfileChooser_Controller.h"
+
+#import "OpenColorIO_AE_Menu.h"
+
+
+bool OpenFile(char *path, int buf_len, const ExtensionMap &extensions, const void *hwnd)
+{
+ NSOpenPanel *panel = [NSOpenPanel openPanel];
+
+ [panel setTitle:@"OpenColorIO"];
+
+
+ NSMutableArray *extension_array = [[NSMutableArray alloc] init];
+ std::string message = "Formats: ";
+ bool first_one = true;
+
+ for(ExtensionMap::const_iterator i = extensions.begin(); i != extensions.end(); i++)
+ {
+ [extension_array addObject:[NSString stringWithUTF8String:i->first.c_str()]];
+
+ if(first_one)
+ first_one = false;
+ else
+ message += ", ";
+
+ message += "." + i->first;
+ }
+
+ [panel setMessage:[NSString stringWithUTF8String:message.c_str()]];
+
+
+ NSInteger result = [panel runModalForTypes:extension_array];
+
+
+ [extension_array release];
+
+
+ if(result == NSOKButton)
+ {
+ return [[panel filename] getCString:path
+ maxLength:buf_len
+ encoding:NSASCIIStringEncoding];
+ }
+ else
+ return false;
+}
+
+
+bool SaveFile(char *path, int buf_len, const ExtensionMap &extensions, const void *hwnd)
+{
+ NSSavePanel *panel = [NSSavePanel savePanel];
+
+ [panel setTitle:@"OpenColorIO"];
+
+
+ NSMutableArray *extension_array = [[NSMutableArray alloc] init];
+ std::string message = "Formats: ";
+ bool first_one = true;
+
+ for(ExtensionMap::const_iterator i = extensions.begin(); i != extensions.end(); i++)
+ {
+ [extension_array addObject:[NSString stringWithUTF8String:i->first.c_str()]];
+
+ if(first_one)
+ first_one = false;
+ else
+ message += ", ";
+
+ message += i->second + " (." + i->first + ")";
+ }
+
+ [panel setAllowedFileTypes:extension_array];
+ [panel setMessage:[NSString stringWithUTF8String:message.c_str()]];
+
+
+ NSInteger result = [panel runModal];
+
+
+ [extension_array release];
+
+
+ if(result == NSOKButton)
+ {
+ return [[panel filename] getCString:path
+ maxLength:buf_len
+ encoding:NSASCIIStringEncoding];
+ }
+ else
+ return false;
+}
+
+
+bool GetMonitorProfile(char *path, int buf_len, const void *hwnd)
+{
+ bool hit_ok = false;
+
+ Class ui_controller_class = [[NSBundle bundleWithIdentifier:@"org.OpenColorIO.AfterEffects"]
+ classNamed:@"OpenColorIO_AE_MonitorProfileChooser_Controller"];
+
+ if(ui_controller_class)
+ {
+ OpenColorIO_AE_MonitorProfileChooser_Controller *ui_controller = [[ui_controller_class alloc] init];
+
+ if(ui_controller)
+ {
+ NSWindow *my_window = [ui_controller getWindow];
+
+ if(my_window)
+ {
+ NSInteger result = [NSApp runModalForWindow:my_window];
+
+ if(result == NSRunStoppedResponse)
+ {
+ [ui_controller getMonitorProfile:path bufferSize:buf_len];
+
+ hit_ok = true;
+ }
+
+ [my_window release];
+ }
+
+ [ui_controller release];
+ }
+ }
+
+ return hit_ok;
+}
+
+
+void GetStdConfigs(ConfigVec &configs)
+{
+ const char *ocio_dir = "/Library/Application Support/OpenColorIO/";
+
+ NSFileManager *man = [NSFileManager defaultManager];
+
+ NSDirectoryEnumerator *enumerator = [man enumeratorAtPath:[NSString stringWithUTF8String:ocio_dir]];
+
+ for(NSString *file in enumerator)
+ {
+ std::string config_path(ocio_dir);
+
+ config_path += [file UTF8String];
+
+ config_path += "/config.ocio";
+
+ [enumerator skipDescendents];
+
+ if([man fileExistsAtPath:[NSString stringWithUTF8String:config_path.c_str()]])
+ {
+ configs.push_back( [file UTF8String] );
+ }
+ }
+}
+
+
+std::string GetStdConfigPath(const std::string &name)
+{
+ const char *ocio_dir = "/Library/Application Support/OpenColorIO/";
+
+ std::string config_path = ocio_dir + name + "/config.ocio";
+
+ if( [[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithUTF8String:config_path.c_str()]] )
+ {
+ return config_path;
+ }
+ else
+ {
+ return "";
+ }
+}
+
+
+int PopUpMenu(const MenuVec &menu_items, int selected_index, const void *hwnd)
+{
+ NSMutableArray *item_array = [[NSMutableArray alloc] init];
+
+ for(MenuVec::const_iterator i = menu_items.begin(); i != menu_items.end(); i++)
+ {
+ [item_array addObject:[NSString stringWithUTF8String:i->c_str()]];
+ }
+
+
+ OpenColorIO_AE_Menu *menu = [[OpenColorIO_AE_Menu alloc] init:item_array
+ selectedItem:selected_index];
+
+ [menu showMenu];
+
+ NSInteger item = [menu selectedItem];
+
+ [menu release];
+ [item_array release];
+
+ return item;
+}
+
+
+void ErrorMessage(const char *message, const void *hwnd)
+{
+ NSAlert *alert = [[NSAlert alloc] init];
+
+ [alert setMessageText:[NSString stringWithUTF8String:message]];
+
+ [alert runModal];
+
+ [alert release];
+}
+
diff --git a/src/aftereffects/mac/OpenColorIO_AE_GL_Cocoa.mm b/src/aftereffects/mac/OpenColorIO_AE_GL_Cocoa.mm
new file mode 100644
index 0000000..3fc3797
--- /dev/null
+++ b/src/aftereffects/mac/OpenColorIO_AE_GL_Cocoa.mm
@@ -0,0 +1,178 @@
+/*
+Copyright (c) 2003-2012 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_AE_GL.h"
+
+#import <Cocoa/Cocoa.h>
+
+
+
+static NSWindow *g_win = nil;
+static AGLContext g_context = NULL;
+static GLuint g_framebuffer;
+
+
+static bool HaveRequiredExtensions()
+{
+ const GLubyte *strVersion = glGetString(GL_VERSION);
+ const GLubyte *strExt = glGetString(GL_EXTENSIONS);
+
+ if(strVersion == NULL || strExt == NULL)
+ return false;
+
+ float gl_version;
+ sscanf((char *)strVersion, "%f", &gl_version);
+
+#define CheckExtension(N) gluCheckExtension((const GLubyte *)N, strExt)
+
+ return (gl_version >= 2.0 &&
+ CheckExtension("GL_ARB_color_buffer_float") &&
+ CheckExtension("GL_ARB_texture_float") &&
+ CheckExtension("GL_ARB_vertex_program") &&
+ CheckExtension("GL_ARB_vertex_shader") &&
+ CheckExtension("GL_ARB_texture_cube_map") &&
+ CheckExtension("GL_ARB_fragment_shader") &&
+ CheckExtension("GL_ARB_draw_buffers") &&
+ CheckExtension("GL_ARB_framebuffer_object") );
+}
+
+
+void GlobalSetup_GL()
+{
+ GLint aAttribs[64];
+ u_short nIndexS= -1;
+
+ aAttribs[++nIndexS] = AGL_RGBA;
+ aAttribs[++nIndexS] = AGL_DOUBLEBUFFER;
+ aAttribs[++nIndexS] = AGL_COLOR_FLOAT;
+
+ aAttribs[++nIndexS] = AGL_RED_SIZE;
+ aAttribs[++nIndexS] = 32;
+ aAttribs[++nIndexS] = AGL_GREEN_SIZE;
+ aAttribs[++nIndexS] = 32;
+ aAttribs[++nIndexS] = AGL_BLUE_SIZE;
+ aAttribs[++nIndexS] = 32;
+ aAttribs[++nIndexS] = AGL_ALPHA_SIZE;
+ aAttribs[++nIndexS] = 32;
+
+ aAttribs[++nIndexS] = AGL_NONE;
+
+
+ AGLPixelFormat oPixelFormat = aglChoosePixelFormat(NULL, 0, aAttribs);
+
+ if(oPixelFormat)
+ {
+ g_context = aglCreateContext(oPixelFormat, NULL);
+
+ aglDestroyPixelFormat(oPixelFormat);
+ }
+
+
+ if(g_context == NULL)
+ return;
+
+
+ g_win = [[NSWindow alloc] initWithContentRect:NSZeroRect
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+
+
+ aglSetDrawable(g_context, (AGLDrawable)[[g_win graphicsContext] graphicsPort]);
+
+ glFlush();
+
+
+ SetPluginContext();
+
+
+
+ GLint units;
+ glGetIntegerv(GL_MAX_TEXTURE_UNITS, &units);
+
+
+ if( !HaveRequiredExtensions() || units < 2)
+ {
+ GlobalSetdown_GL();
+ SetAEContext();
+ return;
+ }
+
+ glGenFramebuffersEXT(1, &g_framebuffer);
+
+
+ SetAEContext();
+}
+
+
+bool HaveOpenGL()
+{
+ return (g_context != NULL && g_win != nil);
+}
+
+
+static AGLContext g_ae_context;
+
+void SetPluginContext()
+{
+ g_ae_context = aglGetCurrentContext();
+
+ aglSetCurrentContext(g_context);
+}
+
+
+void SetAEContext()
+{
+ // g_ae_context might be NULL...so be it
+ aglSetCurrentContext(g_ae_context);
+}
+
+
+GLuint GetFrameBuffer()
+{
+ return g_framebuffer;
+}
+
+
+void GlobalSetdown_GL()
+{
+ if(g_context)
+ {
+ aglDestroyContext(g_context);
+ g_context = NULL;
+
+ glDeleteFramebuffersEXT(1, &g_framebuffer);
+ }
+
+ if(g_win)
+ {
+ [g_win release];
+ g_win = nil;
+ }
+}
diff --git a/src/aftereffects/mac/OpenColorIO_AE_Menu.h b/src/aftereffects/mac/OpenColorIO_AE_Menu.h
new file mode 100644
index 0000000..e8920fa
--- /dev/null
+++ b/src/aftereffects/mac/OpenColorIO_AE_Menu.h
@@ -0,0 +1,45 @@
+/*
+Copyright (c) 2003-2012 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.
+*/
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface OpenColorIO_AE_Menu : NSView {
+ NSArray *menu_items;
+ NSInteger chosen_item;
+}
+
+- (id)init:(NSArray *)menuItems selectedItem:(NSInteger)selected;
+
+- (void)showMenu;
+
+- (IBAction)menuItemAction:(id)sender;
+
+- (NSInteger)selectedItem;
+
+@end
diff --git a/src/aftereffects/mac/OpenColorIO_AE_Menu.m b/src/aftereffects/mac/OpenColorIO_AE_Menu.m
new file mode 100644
index 0000000..6d0a44b
--- /dev/null
+++ b/src/aftereffects/mac/OpenColorIO_AE_Menu.m
@@ -0,0 +1,114 @@
+/*
+Copyright (c) 2003-2012 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.
+*/
+
+#import "OpenColorIO_AE_Menu.h"
+
+
+@implementation OpenColorIO_AE_Menu
+
+- (id)init:(NSArray *)menuItems selectedItem:(NSInteger)selected {
+ self = [super init];
+
+ menu_items = menuItems;
+ chosen_item = selected;
+
+ return self;
+}
+
+- (void)showMenu {
+
+ // Doing some pretty weird stuff here.
+ // I need to bring up a contextual menu without AE giving me an NSView.
+ // To get the screen position, I use global NSApp methods.
+ // And I need to make an NSView to give to popUpContextMenu:
+ // so I can catch the selectors it sends, so I made this an NSView subclass.
+
+ NSMenu *menu = [[NSMenu alloc] initWithTitle:@"Pop-Up"];
+
+ [menu setAutoenablesItems:FALSE];
+
+
+ NSUInteger i;
+
+ for(i=0; i < [menu_items count]; i++)
+ {
+ if( [[menu_items objectAtIndex:i] isEqualToString:@"(-"] )
+ {
+ [menu addItem:[NSMenuItem separatorItem]];
+ }
+ else
+ {
+ NSMenuItem *item = [menu addItemWithTitle:[menu_items objectAtIndex:i]
+ action:@selector(menuItemAction:)
+ keyEquivalent:@""];
+
+ [item setTag:i];
+
+ if(i == chosen_item)
+ [item setState:NSOnState];
+
+ if([[menu_items objectAtIndex:i] isEqualToString:@"$OCIO"] && NULL == getenv("OCIO"))
+ {
+ [item setEnabled:FALSE];
+ [item setState:NSOffState];
+ }
+ else if([[menu_items objectAtIndex:i] isEqualToString:@"(nada)"])
+ {
+ [item setTitle:@"No configs in /Library/Application Support/OpenColorIO/"];
+ [item setEnabled:FALSE];
+ }
+ }
+ }
+
+
+ id fakeMouseEvent=[NSEvent mouseEventWithType:NSLeftMouseDown
+ location: [[NSApp keyWindow] convertScreenToBase:[NSEvent mouseLocation]]
+ modifierFlags:0
+ timestamp:0
+ windowNumber: [[NSApp keyWindow] windowNumber]
+ context:nil
+ eventNumber:0
+ clickCount:1
+ pressure:0];
+
+ [NSMenu popUpContextMenu:menu withEvent:fakeMouseEvent forView:self];
+
+ [menu release];
+}
+
+- (IBAction)menuItemAction:(id)sender {
+ NSMenuItem *item = (NSMenuItem *)sender;
+
+ chosen_item = [item tag];
+}
+
+- (NSInteger)selectedItem {
+ return chosen_item;
+}
+
+@end
diff --git a/src/aftereffects/mac/OpenColorIO_AE_MonitorProfileChooser.xib b/src/aftereffects/mac/OpenColorIO_AE_MonitorProfileChooser.xib
new file mode 100644
index 0000000..4e18dbe
--- /dev/null
+++ b/src/aftereffects/mac/OpenColorIO_AE_MonitorProfileChooser.xib
@@ -0,0 +1,494 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
+ <data>
+ <int key="IBDocument.SystemTarget">1050</int>
+ <string key="IBDocument.SystemVersion">10K549</string>
+ <string key="IBDocument.InterfaceBuilderVersion">851</string>
+ <string key="IBDocument.AppKitVersion">1038.36</string>
+ <string key="IBDocument.HIToolboxVersion">461.00</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="NS.object.0">851</string>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <integer value="1"/>
+ </object>
+ <object class="NSArray" key="IBDocument.PluginDependencies">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ </object>
+ <object class="NSMutableDictionary" key="IBDocument.Metadata">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys" id="0">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSCustomObject" id="1001">
+ <string key="NSClassName">OpenColorIO_AE_MonitorProfileChooser_Controller</string>
+ </object>
+ <object class="NSCustomObject" id="1003">
+ <string key="NSClassName">FirstResponder</string>
+ </object>
+ <object class="NSCustomObject" id="1004">
+ <string key="NSClassName">NSApplication</string>
+ </object>
+ <object class="NSWindowTemplate" id="1005">
+ <int key="NSWindowStyleMask">1</int>
+ <int key="NSWindowBacking">2</int>
+ <string key="NSWindowRect">{{196, 369}, {364, 141}}</string>
+ <int key="NSWTFlags">544735232</int>
+ <string key="NSWindowTitle">OpenColorIO</string>
+ <string key="NSWindowClass">NSWindow</string>
+ <nil key="NSViewClass"/>
+ <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string>
+ <object class="NSView" key="NSWindowView" id="1006">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSPopUpButton" id="313635640">
+ <reference key="NSNextResponder" ref="1006"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{125, 87}, {222, 26}}</string>
+ <reference key="NSSuperview" ref="1006"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSPopUpButtonCell" key="NSCell" id="127421210">
+ <int key="NSCellFlags">-2076049856</int>
+ <int key="NSCellFlags2">2048</int>
+ <object class="NSFont" key="NSSupport" id="928433575">
+ <string key="NSName">LucidaGrande</string>
+ <double key="NSSize">13</double>
+ <int key="NSfFlags">1044</int>
+ </object>
+ <reference key="NSControlView" ref="313635640"/>
+ <int key="NSButtonFlags">109199615</int>
+ <int key="NSButtonFlags2">129</int>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ <nil key="NSMenuItem"/>
+ <bool key="NSMenuItemRespectAlignment">YES</bool>
+ <object class="NSMenu" key="NSMenu" id="39894973">
+ <string key="NSTitle">OtherViews</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="NSMenuFont" ref="928433575"/>
+ </object>
+ <int key="NSSelectedIndex">-1</int>
+ <int key="NSPreferredEdge">1</int>
+ <bool key="NSUsesItemFromMenu">YES</bool>
+ <bool key="NSAltersState">YES</bool>
+ <int key="NSArrowPosition">2</int>
+ </object>
+ </object>
+ <object class="NSTextField" id="116991834">
+ <reference key="NSNextResponder" ref="1006"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{17, 94}, {106, 17}}</string>
+ <reference key="NSSuperview" ref="1006"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="292780847">
+ <int key="NSCellFlags">68288064</int>
+ <int key="NSCellFlags2">138413056</int>
+ <string key="NSContents">Monitor Profile:</string>
+ <reference key="NSSupport" ref="928433575"/>
+ <reference key="NSControlView" ref="116991834"/>
+ <object class="NSColor" key="NSBackgroundColor">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">controlColor</string>
+ <object class="NSColor" key="NSColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC42NjY2NjY2ODY1AA</bytes>
+ </object>
+ </object>
+ <object class="NSColor" key="NSTextColor">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">controlTextColor</string>
+ <object class="NSColor" key="NSColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MAA</bytes>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSButton" id="995505874">
+ <reference key="NSNextResponder" ref="1006"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{254, 12}, {96, 32}}</string>
+ <reference key="NSSuperview" ref="1006"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="15784021">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">OK</string>
+ <reference key="NSSupport" ref="928433575"/>
+ <reference key="NSControlView" ref="995505874"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">129</int>
+ <string key="NSAlternateContents"/>
+ <string type="base64-UTF8" key="NSKeyEquivalent">DQ</string>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSButton" id="1070422003">
+ <reference key="NSNextResponder" ref="1006"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{158, 12}, {96, 32}}</string>
+ <reference key="NSSuperview" ref="1006"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="393092215">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Cancel</string>
+ <reference key="NSSupport" ref="928433575"/>
+ <reference key="NSControlView" ref="1070422003"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">129</int>
+ <string key="NSAlternateContents"/>
+ <string type="base64-UTF8" key="NSKeyEquivalent">Gw</string>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ </object>
+ <string key="NSFrameSize">{364, 141}</string>
+ <reference key="NSSuperview"/>
+ </object>
+ <string key="NSScreenRect">{{0, 0}, {1680, 1028}}</string>
+ <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string>
+ </object>
+ </object>
+ <object class="IBObjectContainer" key="IBDocument.Objects">
+ <object class="NSMutableArray" key="connectionRecords">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">profileMenu</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="313635640"/>
+ </object>
+ <int key="connectionID">15</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">window</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="1005"/>
+ </object>
+ <int key="connectionID">16</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">clickCancel:</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="1070422003"/>
+ </object>
+ <int key="connectionID">17</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">clickOK:</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="995505874"/>
+ </object>
+ <int key="connectionID">18</int>
+ </object>
+ </object>
+ <object class="IBMutableOrderedSet" key="objectRecords">
+ <object class="NSArray" key="orderedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBObjectRecord">
+ <int key="objectID">0</int>
+ <reference key="object" ref="0"/>
+ <reference key="children" ref="1000"/>
+ <nil key="parent"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-2</int>
+ <reference key="object" ref="1001"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">File's Owner</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-1</int>
+ <reference key="object" ref="1003"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">First Responder</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-3</int>
+ <reference key="object" ref="1004"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">Application</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">1</int>
+ <reference key="object" ref="1005"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1006"/>
+ </object>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">2</int>
+ <reference key="object" ref="1006"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="313635640"/>
+ <reference ref="116991834"/>
+ <reference ref="995505874"/>
+ <reference ref="1070422003"/>
+ </object>
+ <reference key="parent" ref="1005"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">3</int>
+ <reference key="object" ref="313635640"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="127421210"/>
+ </object>
+ <reference key="parent" ref="1006"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">4</int>
+ <reference key="object" ref="127421210"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="39894973"/>
+ </object>
+ <reference key="parent" ref="313635640"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">5</int>
+ <reference key="object" ref="39894973"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="parent" ref="127421210"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">9</int>
+ <reference key="object" ref="116991834"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="292780847"/>
+ </object>
+ <reference key="parent" ref="1006"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">10</int>
+ <reference key="object" ref="292780847"/>
+ <reference key="parent" ref="116991834"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">11</int>
+ <reference key="object" ref="995505874"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="15784021"/>
+ </object>
+ <reference key="parent" ref="1006"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">12</int>
+ <reference key="object" ref="15784021"/>
+ <reference key="parent" ref="995505874"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">13</int>
+ <reference key="object" ref="1070422003"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="393092215"/>
+ </object>
+ <reference key="parent" ref="1006"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">14</int>
+ <reference key="object" ref="393092215"/>
+ <reference key="parent" ref="1070422003"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="flattenedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>1.IBEditorWindowLastContentRect</string>
+ <string>1.IBPluginDependency</string>
+ <string>1.IBWindowTemplateEditedContentRect</string>
+ <string>1.NSWindowTemplate.visibleAtLaunch</string>
+ <string>1.WindowOrigin</string>
+ <string>1.editorWindowContentRectSynchronizationRect</string>
+ <string>10.IBPluginDependency</string>
+ <string>11.IBPluginDependency</string>
+ <string>11.IBViewBoundsToFrameTransform</string>
+ <string>12.IBPluginDependency</string>
+ <string>13.IBPluginDependency</string>
+ <string>13.IBViewBoundsToFrameTransform</string>
+ <string>14.IBPluginDependency</string>
+ <string>2.IBPluginDependency</string>
+ <string>3.IBPluginDependency</string>
+ <string>3.IBViewBoundsToFrameTransform</string>
+ <string>4.IBPluginDependency</string>
+ <string>5.IBEditorWindowLastContentRect</string>
+ <string>5.IBPluginDependency</string>
+ <string>9.IBPluginDependency</string>
+ <string>9.IBViewBoundsToFrameTransform</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>{{498, 559}, {364, 141}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{498, 559}, {364, 141}}</string>
+ <boolean value="NO"/>
+ <string>{196, 240}</string>
+ <string>{{202, 428}, {480, 270}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABDfgAAwigAAA</bytes>
+ </object>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABDfgAAwigAAA</bytes>
+ </object>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABDFAAAw1oAAA</bytes>
+ </object>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{598, 628}, {110, 4}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABCIAAAw1gAAA</bytes>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="unlocalizedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference key="dict.sortedKeys" ref="0"/>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="activeLocalization"/>
+ <object class="NSMutableDictionary" key="localizations">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference key="dict.sortedKeys" ref="0"/>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="sourceID"/>
+ <int key="maxID">18</int>
+ </object>
+ <object class="IBClassDescriber" key="IBDocument.Classes">
+ <object class="NSMutableArray" key="referencedPartialClassDescriptions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBPartialClassDescription">
+ <string key="className">OpenColorIO_AE_MonitorProfileChooser_Controller</string>
+ <string key="superclassName">NSObject</string>
+ <object class="NSMutableDictionary" key="actions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>clickCancel:</string>
+ <string>clickOK:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSButton</string>
+ <string>NSButton</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="actionInfosByName">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>clickCancel:</string>
+ <string>clickOK:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBActionInfo">
+ <string key="name">clickCancel:</string>
+ <string key="candidateClassName">NSButton</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">clickOK:</string>
+ <string key="candidateClassName">NSButton</string>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>profileMenu</string>
+ <string>window</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSPopUpButton</string>
+ <string>NSWindow</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>profileMenu</string>
+ <string>window</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBToOneOutletInfo">
+ <string key="name">profileMenu</string>
+ <string key="candidateClassName">NSPopUpButton</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">window</string>
+ <string key="candidateClassName">NSWindow</string>
+ </object>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">OpenColorIO_AE_MonitorProfileChooser_Controller.h</string>
+ </object>
+ </object>
+ </object>
+ </object>
+ <int key="IBDocument.localizationMode">0</int>
+ <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
+ <integer value="1050" key="NS.object.0"/>
+ </object>
+ <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
+ <integer value="3000" key="NS.object.0"/>
+ </object>
+ <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
+ <string key="IBDocument.LastKnownRelativeProjectPath">OpenColorIO_AE.xcodeproj</string>
+ <int key="IBDocument.defaultPropertyAccessControl">3</int>
+ </data>
+</archive>
diff --git a/src/aftereffects/mac/OpenColorIO_AE_MonitorProfileChooser_Controller.h b/src/aftereffects/mac/OpenColorIO_AE_MonitorProfileChooser_Controller.h
new file mode 100644
index 0000000..024fa29
--- /dev/null
+++ b/src/aftereffects/mac/OpenColorIO_AE_MonitorProfileChooser_Controller.h
@@ -0,0 +1,46 @@
+/*
+Copyright (c) 2003-2012 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.
+*/
+
+#import <Cocoa/Cocoa.h>
+
+@interface OpenColorIO_AE_MonitorProfileChooser_Controller : NSObject {
+ IBOutlet NSPopUpButton *profileMenu;
+ IBOutlet NSWindow *window;
+
+ NSMutableArray *name_array;
+ NSMapTable *profile_map;
+}
+
+- (IBAction)clickOK:(NSButton *)sender;
+- (IBAction)clickCancel:(NSButton *)sender;
+
+- (NSWindow *)getWindow;
+
+- (BOOL)getMonitorProfile:(char *)path bufferSize:(int)buf_len;
+
+@end
diff --git a/src/aftereffects/mac/OpenColorIO_AE_MonitorProfileChooser_Controller.m b/src/aftereffects/mac/OpenColorIO_AE_MonitorProfileChooser_Controller.m
new file mode 100644
index 0000000..323a83c
--- /dev/null
+++ b/src/aftereffects/mac/OpenColorIO_AE_MonitorProfileChooser_Controller.m
@@ -0,0 +1,195 @@
+/*
+Copyright (c) 2003-2012 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.
+*/
+
+#import "OpenColorIO_AE_MonitorProfileChooser_Controller.h"
+
+
+typedef struct {
+ NSMutableArray *name_array;
+ NSMapTable *profile_map;
+ const char *monitor_profile_path;
+ char *monitor_profile_name;
+} IterateData;
+
+static OSErr profIterateProc(CMProfileIterateData* data, void* refcon)
+{
+ OSErr err = noErr;
+
+ IterateData *i_data = (IterateData *)refcon;
+
+ if(data->header.dataColorSpace == cmRGBData && data->location.locType == cmPathBasedProfile)
+ {
+ [i_data->name_array addObject:[NSString stringWithUTF8String:data->asciiName]];
+
+ [i_data->profile_map setObject:[NSString stringWithUTF8String:data->location.u.pathLoc.path]
+ forKey:[NSString stringWithUTF8String:data->asciiName] ];
+
+ if( i_data->monitor_profile_path &&
+ !strcmp(data->location.u.pathLoc.path, i_data->monitor_profile_path) )
+ {
+ strncpy(i_data->monitor_profile_name, data->asciiName, 255);
+ }
+ }
+
+ return err;
+}
+
+
+
+@implementation OpenColorIO_AE_MonitorProfileChooser_Controller
+
+- (id)init {
+ self = [super init];
+
+ if(!([NSBundle loadNibNamed:@"OpenColorIO_AE_MonitorProfileChooser" owner:self]))
+ return nil;
+
+
+ [window center];
+
+ // Originally tried to implement this with two NSArrays, one with paths and
+ // one with profile names (ICC descriptions). The problem is that when you
+ // add items to NSArrays one at a time, they auto-sort. But then it turns out I
+ // WANT them to sort because the profiles come in random order and the menu looks
+ // terrible if they're not sorted.
+
+ // So I make an NSArray to set up the menu and an NSMapTable to convert from the
+ // selected menu item to the actual path. Got that?
+
+
+ name_array = [[NSMutableArray alloc] init];
+ profile_map = [[NSMapTable alloc] init];
+
+
+ // get monitor profile path
+
+ // Oddly enough, the "Name" given to me by ColorSync for this is often "Display",
+ // but if you get the profile's description, you get something like
+ // "Apple Cinema HD Display". So to see if ColorSync runs accross the the monitor's
+ // profile so I can select it, I have to compare the paths, and then save the name
+ // I'm currently getting.
+
+ CMProfileRef prof;
+ CMProfileLocation profLoc;
+
+ UInt32 locationSize = cmCurrentProfileLocationSize;
+
+ // Get the main GDevice.
+ CGDirectDisplayID theAVID = CGMainDisplayID();
+
+ // Get the profile for that AVID.
+ CMError err = CMGetProfileByAVID(theAVID, &prof);
+
+ // Get location (FSRef) for that profile
+ err = NCMGetProfileLocation(prof, &profLoc, &locationSize);
+
+ const char *monitor_profile_path = NULL;
+ char monitor_profile_name[256] = { '\0' };
+
+ if(profLoc.locType == cmPathBasedProfile)
+ {
+ monitor_profile_path = profLoc.u.pathLoc.path;
+ }
+
+
+
+ // build profile map and name array
+ IterateData i_data = { name_array, profile_map, monitor_profile_path, monitor_profile_name };
+
+ UInt32 seed = 0;
+ UInt32 count;
+
+ CMProfileIterateUPP iterateUPP;
+ iterateUPP = NewCMProfileIterateUPP((CMProfileIterateProcPtr)&profIterateProc);
+
+ err = CMIterateColorSyncFolder(iterateUPP, &seed, &count, (void *)&i_data);
+
+ DisposeCMProfileIterateUPP(iterateUPP);
+
+
+
+ // set up menu with array
+ [profileMenu addItemsWithTitles:name_array];
+
+
+
+ // choose the display profile name if we have it (usually "Display")
+ if(monitor_profile_name[0] != '\0')
+ {
+ [profileMenu selectItemWithTitle:[NSString stringWithUTF8String:monitor_profile_name]];
+ }
+ else if(monitor_profile_path != NULL)
+ {
+ // somehow the display profile wasn't found during iteration
+ // so let's add it
+ CFStringRef m_name;
+
+ err = CMCopyProfileDescriptionString(prof, &m_name);
+
+ NSString *ns_name = (NSString *)monitor_profile_name;
+
+ [profile_map setObject:[NSString stringWithUTF8String:monitor_profile_path]
+ forKey:ns_name ];
+
+ [profileMenu addItemWithTitle:ns_name];
+
+ [profileMenu selectItemWithTitle:ns_name];
+
+ CFRelease(m_name);
+ }
+
+ return self;
+}
+
+- (void)dealloc {
+ [name_array release];
+ [profile_map release];
+
+ [super dealloc];
+}
+
+- (IBAction)clickOK:(NSButton *)sender {
+ [NSApp stopModal];
+}
+
+- (IBAction)clickCancel:(NSButton *)sender {
+ [NSApp abortModal];
+}
+
+- (NSWindow *)getWindow {
+ return window;
+}
+
+- (BOOL)getMonitorProfile:(char *)path bufferSize:(int)buf_len {
+ NSString *icc_name = [[profileMenu selectedItem] title];
+ NSString *icc_path = [profile_map objectForKey:icc_name];
+
+ return [icc_path getCString:path maxLength:buf_len encoding:NSMacOSRomanStringEncoding];
+}
+
+@end
diff --git a/src/aftereffects/vc/vc9/OpenColorABI.h b/src/aftereffects/vc/vc9/OpenColorABI.h
new file mode 100644
index 0000000..acbb8b4
--- /dev/null
+++ b/src/aftereffects/vc/vc9/OpenColorABI.h
@@ -0,0 +1,100 @@
+/*
+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.
+*/
+
+#ifndef INCLUDED_OCIO_OPENCOLORABI_H
+#define INCLUDED_OCIO_OPENCOLORABI_H
+
+// Makefile configuration options
+#define OCIO_NAMESPACE OpenColorIO
+#define OCIO_USE_BOOST_PTR 1
+#define OCIO_VERSION "1.0.7"
+#define OCIO_VERSION_NS v1
+
+/* Version as a single 4-byte hex number, e.g. 0x01050200 == 1.5.2
+ Use this for numeric comparisons, e.g. #if OCIO_VERSION_HEX >= ...
+ Note: in the case where SOVERSION is overridden at compile-time,
+ this will reflect the original API version number.
+ */
+#define OCIO_VERSION_HEX ((1 << 24) | \
+ (0 << 16) | \
+ (7 << 8))
+
+
+// Namespace / version mojo
+#define OCIO_NAMESPACE_ENTER namespace OCIO_NAMESPACE { namespace OCIO_VERSION_NS
+#define OCIO_NAMESPACE_EXIT using namespace OCIO_VERSION_NS; }
+#define OCIO_NAMESPACE_USING using namespace OCIO_NAMESPACE;
+
+// shared_ptr / dynamic_pointer_cast
+#if OCIO_USE_BOOST_PTR
+#include <boost/shared_ptr.hpp>
+#define OCIO_SHARED_PTR boost::shared_ptr
+#define OCIO_DYNAMIC_POINTER_CAST boost::dynamic_pointer_cast
+#elif __GNUC__ >= 4
+#include <tr1/memory>
+#define OCIO_SHARED_PTR std::tr1::shared_ptr
+#define OCIO_DYNAMIC_POINTER_CAST std::tr1::dynamic_pointer_cast
+#else
+#error OCIO needs gcc 4 or later to get access to <tr1/memory> (or specify USE_BOOST_PTR instead)
+#endif
+
+#ifdef OpenColorIO_SHARED
+ // If supported, define OCIOEXPORT, OCIOHIDDEN
+ // (used to choose which symbols to export from OpenColorIO)
+ #if defined __linux__ || __APPLE__
+ #if __GNUC__ >= 4
+ #define OCIOEXPORT __attribute__ ((visibility("default")))
+ #define OCIOHIDDEN __attribute__ ((visibility("hidden")))
+ #else
+ #define OCIOEXPORT
+ #define OCIOHIDDEN
+ #endif
+ #elif defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS) || defined(_MSC_VER)
+ // Windows requires you to export from the main library and then import in any others
+ #if defined OpenColorIO_EXPORTS
+ #define OCIOEXPORT __declspec(dllexport)
+ #else
+ #define OCIOEXPORT __declspec(dllimport)
+ #endif
+ #define OCIOHIDDEN
+ #else // Others platforms not supported atm
+ #define OCIOEXPORT
+ #define OCIOHIDDEN
+ #endif
+#else
+ #define OCIOEXPORT
+ #define OCIOHIDDEN
+#endif
+
+// Windows defines these troublesome macros that collide with std::limits
+#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS) || defined(_MSC_VER)
+#undef min
+#undef max
+#endif
+
+#endif // INCLUDED_OCIO_OPENCOLORABI_H
diff --git a/src/aftereffects/vc/vc9/OpenColorIO.vcproj b/src/aftereffects/vc/vc9/OpenColorIO.vcproj
new file mode 100644
index 0000000..45b17d2
--- /dev/null
+++ b/src/aftereffects/vc/vc9/OpenColorIO.vcproj
@@ -0,0 +1,667 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="OpenColorIO"
+ ProjectGUID="{8B308357-C548-49D9-9134-8A61D57D524C}"
+ RootNamespace="OpenColorIO"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..\..\export;..\..\..\..\src\core;..\..\..\..\ext\boost_1_48_0;..\..\..\..\ext\tinyxml;&quot;..\..\..\..\ext\yaml-cpp\include&quot;;.\"
+ PreprocessorDefinitions="TIXML_USE_STL"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..\..\export;..\..\..\..\src\core;..\..\..\..\ext\boost_1_48_0;..\..\..\..\ext\tinyxml;&quot;..\..\..\..\ext\yaml-cpp\include&quot;;.\"
+ PreprocessorDefinitions="TIXML_USE_STL"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\..\..\export;..\..\..\..\src\core;..\..\..\..\ext\boost_1_48_0;..\..\..\..\ext\tinyxml;&quot;..\..\..\..\ext\yaml-cpp\include&quot;;.\"
+ PreprocessorDefinitions="NDEBUG;TIXML_USE_STL"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\..\..\export;..\..\..\..\src\core;..\..\..\..\ext\boost_1_48_0;..\..\..\..\ext\tinyxml;&quot;..\..\..\..\ext\yaml-cpp\include&quot;;.\"
+ PreprocessorDefinitions="NDEBUG;TIXML_USE_STL"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\..\src\core\AllocationOp.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\AllocationTransform.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\Baker.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\Caching.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\CDLTransform.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\ColorSpace.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\ColorSpaceTransform.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\Config.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\Context.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\DisplayTransform.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\Exception.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\ExponentOps.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\ExponentTransform.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\FileFormat3DL.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\FileFormatCC.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\FileFormatCCC.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\FileFormatCSP.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\FileFormatHDL.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\FileFormatIridasCube.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\FileFormatIridasItx.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\core\FileFormatIridasLook.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\FileFormatPandora.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\FileFormatSpi1D.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\FileFormatSpi3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\FileFormatSpiMtx.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\FileFormatTruelight.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\FileFormatVF.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\FileTransform.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\GpuShaderDesc.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\GpuShaderUtils.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\GroupTransform.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\HashUtils.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\ImageDesc.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\ImagePacking.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\Logging.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\LogOps.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\LogTransform.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\Look.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\core\LookParse.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\LookTransform.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\Lut1DOp.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\Lut3DOp.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\MathUtils.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\MatrixOps.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\MatrixTransform.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\md5\md5.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\core\NoOps.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\OCIOYaml.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\Op.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\core\OpOptimizers.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\ParseUtils.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\PathUtils.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\Processor.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\pystring\pystring.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\ScanlineHelper.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\Transform.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\TruelightOp.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\TruelightTransform.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\UnitTest.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\..\..\src\core\AllocationOp.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\CDLTransform.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\ExponentOps.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\FileTransform.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\GpuShaderUtils.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\HashUtils.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\ImagePacking.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\Logging.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\LogOps.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\core\LookParse.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\Lut1DOp.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\Lut3DOp.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\MathUtils.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\MatrixOps.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\md5\md5.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\Mutex.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\core\NoOps.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\OCIOYaml.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\Op.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\OpBuilders.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\export\OpenColorIO\OpenColorIO.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\export\OpenColorIO\OpenColorTransforms.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\export\OpenColorIO\OpenColorTypes.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\ParseUtils.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\PathUtils.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\Platform.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\PrivateTypes.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\Processor.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\pystring\pystring.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\ScanlineHelper.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\SSE.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\TruelightOp.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\core\UnitTest.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/aftereffects/vc/vc9/aftereffects/OpenColorIO_AE.sln b/src/aftereffects/vc/vc9/aftereffects/OpenColorIO_AE.sln
new file mode 100644
index 0000000..61155eb
--- /dev/null
+++ b/src/aftereffects/vc/vc9/aftereffects/OpenColorIO_AE.sln
@@ -0,0 +1,57 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenColorIO_AE", "OpenColorIO_AE.vcproj", "{78FCC6BC-06A9-43AE-827A-1B68FFB7D75F}"
+ ProjectSection(ProjectDependencies) = postProject
+ {069FB60C-57CE-4D0F-9EC2-068E2A3F2930} = {069FB60C-57CE-4D0F-9EC2-068E2A3F2930}
+ {8B308357-C548-49D9-9134-8A61D57D524C} = {8B308357-C548-49D9-9134-8A61D57D524C}
+ {A19BA95E-D8ED-4958-883B-32561AF905EA} = {A19BA95E-D8ED-4958-883B-32561AF905EA}
+ {CC244BA5-4CA8-4B4F-B4CA-3394BF9E9FED} = {CC244BA5-4CA8-4B4F-B4CA-3394BF9E9FED}
+ {F1DAC6DE-348A-4215-87B2-7584578291AC} = {F1DAC6DE-348A-4215-87B2-7584578291AC}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenColorIO", "..\OpenColorIO.vcproj", "{8B308357-C548-49D9-9134-8A61D57D524C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lcms", "..\ext\lcms.vcproj", "{069FB60C-57CE-4D0F-9EC2-068E2A3F2930}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinyxml", "..\ext\tinyxml.vcproj", "{A19BA95E-D8ED-4958-883B-32561AF905EA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yaml", "..\ext\yaml.vcproj", "{F1DAC6DE-348A-4215-87B2-7584578291AC}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glew", "..\ext\glew.vcproj", "{CC244BA5-4CA8-4B4F-B4CA-3394BF9E9FED}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {78FCC6BC-06A9-43AE-827A-1B68FFB7D75F}.Debug|x64.ActiveCfg = Debug|x64
+ {78FCC6BC-06A9-43AE-827A-1B68FFB7D75F}.Debug|x64.Build.0 = Debug|x64
+ {78FCC6BC-06A9-43AE-827A-1B68FFB7D75F}.Release|x64.ActiveCfg = Release|x64
+ {78FCC6BC-06A9-43AE-827A-1B68FFB7D75F}.Release|x64.Build.0 = Release|x64
+ {8B308357-C548-49D9-9134-8A61D57D524C}.Debug|x64.ActiveCfg = Debug|x64
+ {8B308357-C548-49D9-9134-8A61D57D524C}.Debug|x64.Build.0 = Debug|x64
+ {8B308357-C548-49D9-9134-8A61D57D524C}.Release|x64.ActiveCfg = Release|x64
+ {8B308357-C548-49D9-9134-8A61D57D524C}.Release|x64.Build.0 = Release|x64
+ {069FB60C-57CE-4D0F-9EC2-068E2A3F2930}.Debug|x64.ActiveCfg = Debug|x64
+ {069FB60C-57CE-4D0F-9EC2-068E2A3F2930}.Debug|x64.Build.0 = Debug|x64
+ {069FB60C-57CE-4D0F-9EC2-068E2A3F2930}.Release|x64.ActiveCfg = Release|x64
+ {069FB60C-57CE-4D0F-9EC2-068E2A3F2930}.Release|x64.Build.0 = Release|x64
+ {A19BA95E-D8ED-4958-883B-32561AF905EA}.Debug|x64.ActiveCfg = Debug|x64
+ {A19BA95E-D8ED-4958-883B-32561AF905EA}.Debug|x64.Build.0 = Debug|x64
+ {A19BA95E-D8ED-4958-883B-32561AF905EA}.Release|x64.ActiveCfg = Release|x64
+ {A19BA95E-D8ED-4958-883B-32561AF905EA}.Release|x64.Build.0 = Release|x64
+ {F1DAC6DE-348A-4215-87B2-7584578291AC}.Debug|x64.ActiveCfg = Debug|x64
+ {F1DAC6DE-348A-4215-87B2-7584578291AC}.Debug|x64.Build.0 = Debug|x64
+ {F1DAC6DE-348A-4215-87B2-7584578291AC}.Release|x64.ActiveCfg = Release|x64
+ {F1DAC6DE-348A-4215-87B2-7584578291AC}.Release|x64.Build.0 = Release|x64
+ {CC244BA5-4CA8-4B4F-B4CA-3394BF9E9FED}.Debug|x64.ActiveCfg = Debug|x64
+ {CC244BA5-4CA8-4B4F-B4CA-3394BF9E9FED}.Debug|x64.Build.0 = Debug|x64
+ {CC244BA5-4CA8-4B4F-B4CA-3394BF9E9FED}.Release|x64.ActiveCfg = Release|x64
+ {CC244BA5-4CA8-4B4F-B4CA-3394BF9E9FED}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/src/aftereffects/vc/vc9/aftereffects/OpenColorIO_AE.vcproj b/src/aftereffects/vc/vc9/aftereffects/OpenColorIO_AE.vcproj
new file mode 100644
index 0000000..c95c0b0
--- /dev/null
+++ b/src/aftereffects/vc/vc9/aftereffects/OpenColorIO_AE.vcproj
@@ -0,0 +1,448 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="OpenColorIO_AE"
+ ProjectGUID="{78FCC6BC-06A9-43AE-827A-1B68FFB7D75F}"
+ RootNamespace="OpenColorIO_AE"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="3"
+ TypeLibraryName=".\Debug/OpenColorIO_AE.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\;..\..\..;..\..\..\..\apps\ociobakelut;..\..\..\..\..\export;..\..\..\..\..\ext\boost_1_48_0;&quot;..\..\..\..\..\ext\lcms2-2.1\include&quot;;&quot;..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Headers&quot;;&quot;..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Headers\SP&quot;;&quot;..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Headers\Win&quot;;&quot;..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Resources&quot;;&quot;..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Util&quot;;&quot;..\..\..\..\..\ext\glew-1.7.0\include&quot;"
+ PreprocessorDefinitions="MSWindows;WIN32;_DEBUG;_WINDOWS;GLEW_STATIC"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ PrecompiledHeaderThrough="AE_Effect.h"
+ AssemblerOutput="4"
+ BrowseInformation="1"
+ WarningLevel="2"
+ WarnAsError="false"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ AdditionalIncludeDirectories=""
+ ShowProgress="true"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ AdditionalDependencies="Mscms.lib opengl32.lib"
+ ShowProgress="0"
+ OutputFile="C:\Program Files\Adobe\Adobe After Effects CS6\Support Files\Plug-ins\OpenColorIO.aex"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ IgnoreDefaultLibraryNames="libcmt.lib"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(IntDir)\OpenColorIO_AE.pdb"
+ SubSystem="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ ImportLibrary="$(IntDir)\OpenColorIO_AE.lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ UseFAT32Workaround="true"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="3"
+ TypeLibraryName=".\Debug/OpenColorIO_AE.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="..\;..\..\..;..\..\..\..\apps\ociobakelut;..\..\..\..\..\export;..\..\..\..\..\ext\boost_1_48_0;&quot;..\..\..\..\..\ext\lcms2-2.1\include&quot;;&quot;..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Headers&quot;;&quot;..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Headers\SP&quot;;&quot;..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Headers\Win&quot;;&quot;..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Resources&quot;;&quot;..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Util&quot;;&quot;..\..\..\..\..\ext\glew-1.7.0\include&quot;"
+ PreprocessorDefinitions="MSWindows;WIN32;NDEBUG;_WINDOWS;GLEW_STATIC"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ PrecompiledHeaderThrough="AE_Effect.h"
+ AssemblerOutput="4"
+ BrowseInformation="1"
+ WarningLevel="2"
+ WarnAsError="false"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="0"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ AdditionalIncludeDirectories=""
+ ShowProgress="true"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ AdditionalDependencies="Mscms.lib opengl32.lib"
+ ShowProgress="0"
+ OutputFile="$(OutDir)\OpenColorIO.aex"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ IgnoreDefaultLibraryNames="libcmt.lib"
+ GenerateDebugInformation="false"
+ ProgramDatabaseFile="$(IntDir)\OpenColorIO_AE.pdb"
+ SubSystem="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ ImportLibrary="$(IntDir)\OpenColorIO_AE.lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ UseFAT32Workaround="true"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Supporting Code"
+ Filter="cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+ >
+ <File
+ RelativePath="..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Util\AEGP_SuiteHandler.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Util\MissingSuiteError.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\apps\ociobakelut\ocioicc.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;fi;fd"
+ >
+ <File
+ RelativePath="..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Util\AEGP_SuiteHandler.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\DrawbotBot.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\apps\ociobakelut\ocioicc.h"
+ >
+ </File>
+ <File
+ RelativePath="..\OpenColorABI.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\OpenColorIO_AE.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\OpenColorIO_AE_Context.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\OpenColorIO_AE_Dialogs.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\OpenColorIO_AE_GL.h"
+ >
+ </File>
+ <Filter
+ Name="AE"
+ >
+ <File
+ RelativePath="..\..\..\Headers\A.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\Headers\AE_AdvEffectSuites.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\Headers\AE_Effect.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\Headers\AE_EffectCB.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\Headers\AE_EffectCBSuites.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\Headers\AE_EffectSuites.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\Util\AE_EffectSuitesHelper.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\Headers\AE_EffectUI.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\Headers\AE_GeneralPlug.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\Headers\AE_GeneralPlugOld.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\Headers\AE_IO.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\Headers\AE_Macros.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\Util\AEFX_ArbParseHelper.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\Util\AEGP_SuiteHandler.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\Util\entry.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\Headers\FIEL_Public.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\Util\Param_Utils.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\Headers\PF_Masks.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\Headers\PR_Public.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\Headers\PT_Public.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\Util\String_Utils.h"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+ >
+ <File
+ RelativePath="..\..\..\win\OpenColorIO.rc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\OpenColorIO_AE_PiPL.r"
+ >
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Compiling the PiPL"
+ CommandLine="cl /I &quot;$(ProjectDir)..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Headers&quot; /D USE_AE_EFFECT_VERS /EP &quot;..\..\..\$(InputName).r&quot; &gt; &quot;$(IntDir)&quot;\\&quot;$(InputName).rr&quot;&#x0D;&#x0A;&quot;$(ProjectDir)..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Resources\PiPLTool&quot; &quot;$(IntDir)\$(InputName).rr&quot; &quot;$(IntDir)\$(InputName).rrc&quot;&#x0D;&#x0A;cl /D &quot;MSWindows&quot; /EP $(IntDir)\$(InputName).rrc &gt; &quot;$(ProjectDir)&quot;\\&quot;$(InputName)&quot;.rc&#x0D;&#x0A;"
+ Outputs="$(ProjectDir)\$(InputName).rc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Compiling the PiPL"
+ CommandLine="cl /I &quot;$(ProjectDir)..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Headers&quot; /D USE_AE_EFFECT_VERS /EP &quot;..\..\..\$(InputName).r&quot; &gt; &quot;$(IntDir)&quot;\\&quot;$(InputName).rr&quot;&#x0D;&#x0A;&quot;$(ProjectDir)..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Resources\PiPLTool&quot; &quot;$(IntDir)\$(InputName).rr&quot; &quot;$(IntDir)\$(InputName).rrc&quot;&#x0D;&#x0A;cl /D &quot;MSWindows&quot; /EP $(IntDir)\$(InputName).rrc &gt; &quot;$(ProjectDir)&quot;\\&quot;$(InputName)&quot;.rc&#x0D;&#x0A;"
+ Outputs="$(ProjectDir)\$(InputName).rc"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\OpenColorIO_AE_PiPL.rc"
+ >
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ AdditionalIncludeDirectories=""
+ ShowProgress="true"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ AdditionalIncludeDirectories=""
+ ShowProgress="true"
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <File
+ RelativePath="..\..\..\DrawbotBot.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\OpenColorIO_AE.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\OpenColorIO_AE_ArbData.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\OpenColorIO_AE_Context.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\win\OpenColorIO_AE_Dialogs_Win.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\win\OpenColorIO_AE_GL_Win.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\OpenColorIO_AE_UI.cpp"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/aftereffects/vc/vc9/ext/glew.vcproj b/src/aftereffects/vc/vc9/ext/glew.vcproj
new file mode 100644
index 0000000..dad7be7
--- /dev/null
+++ b/src/aftereffects/vc/vc9/ext/glew.vcproj
@@ -0,0 +1,319 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="glew"
+ ProjectGUID="{CC244BA5-4CA8-4B4F-B4CA-3394BF9E9FED}"
+ RootNamespace="glew"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..\..\..\ext\glew-1.7.0\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;GLEW_STATIC"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\..\..\..\ext\glew-1.7.0\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;GLEW_STATIC"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..\..\..\ext\glew-1.7.0\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;GLEW_STATIC"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\..\..\..\ext\glew-1.7.0\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;GLEW_STATIC"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\..\..\ext\glew-1.7.0\src\glew.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\glew-1.7.0\src\glewinfo.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\..\..\..\ext\glew-1.7.0\include\GL\glew.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\glew-1.7.0\include\GL\glxew.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\glew-1.7.0\include\GL\wglew.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/aftereffects/vc/vc9/ext/lcms.vcproj b/src/aftereffects/vc/vc9/ext/lcms.vcproj
new file mode 100644
index 0000000..d8dfbb4
--- /dev/null
+++ b/src/aftereffects/vc/vc9/ext/lcms.vcproj
@@ -0,0 +1,407 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="lcms"
+ ProjectGUID="{069FB60C-57CE-4D0F-9EC2-068E2A3F2930}"
+ RootNamespace="lcms"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="&quot;..\..\..\..\..\ext\lcms2-2.1\include&quot;"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="&quot;..\..\..\..\..\ext\lcms2-2.1\include&quot;"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="&quot;..\..\..\..\..\ext\lcms2-2.1\include&quot;"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="&quot;..\..\..\..\..\ext\lcms2-2.1\include&quot;"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmscam02.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmscgats.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmscnvrt.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmserr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmsgamma.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmsgmt.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmsintrp.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmsio0.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmsio1.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmslut.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmsmd5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmsmtrx.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmsnamed.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmsopt.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmspack.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmspcs.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmsplugin.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmsps2.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmssamp.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmssm.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmstypes.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmsvirt.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmswtpnt.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\cmsxform.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\include\lcms2.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\src\lcms2_internal.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\lcms2-2.1\include\lcms2_plugin.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/aftereffects/vc/vc9/ext/tinyxml.vcproj b/src/aftereffects/vc/vc9/ext/tinyxml.vcproj
new file mode 100644
index 0000000..691f399
--- /dev/null
+++ b/src/aftereffects/vc/vc9/ext/tinyxml.vcproj
@@ -0,0 +1,323 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="tinyxml"
+ ProjectGUID="{A19BA95E-D8ED-4958-883B-32561AF905EA}"
+ RootNamespace="tinyxml"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..\..\..\ext\tinyxml"
+ PreprocessorDefinitions="TIXML_USE_STL"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..\..\..\ext\tinyxml"
+ PreprocessorDefinitions="TIXML_USE_STL"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\..\..\..\ext\tinyxml"
+ PreprocessorDefinitions="NDEBUG;TIXML_USE_STL"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\..\..\..\ext\tinyxml"
+ PreprocessorDefinitions="NDEBUG;TIXML_USE_STL"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\..\..\ext\tinyxml\tinystr.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\tinyxml\tinyxml.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\tinyxml\tinyxmlerror.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\tinyxml\tinyxmlparser.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\..\..\..\ext\tinyxml\tinystr.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\tinyxml\tinyxml.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/aftereffects/vc/vc9/ext/yaml.vcproj b/src/aftereffects/vc/vc9/ext/yaml.vcproj
new file mode 100644
index 0000000..46a0fe5
--- /dev/null
+++ b/src/aftereffects/vc/vc9/ext/yaml.vcproj
@@ -0,0 +1,603 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="yaml"
+ ProjectGUID="{F1DAC6DE-348A-4215-87B2-7584578291AC}"
+ RootNamespace="yaml"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="&quot;..\..\..\..\..\ext\yaml-cpp\include&quot;"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="&quot;..\..\..\..\..\ext\yaml-cpp\include&quot;"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="&quot;..\..\..\..\..\ext\yaml-cpp\include&quot;"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="build\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="&quot;..\..\..\..\..\ext\yaml-cpp\include&quot;"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\aliasmanager.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\binary.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\conversion.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\directives.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\emitfromevents.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\emitter.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\emitterstate.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\emitterutils.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\exp.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\contrib\graphbuilder.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\contrib\graphbuilderadapter.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\contrib\graphbuilderadapter.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\iterator.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\node.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\nodebuilder.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\nodeownership.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\null.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\ostream.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\parser.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\regex.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\scanner.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\scanscalar.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\scantag.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\scantoken.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\simplekey.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\singledocparser.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\stream.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\tag.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\aliasmanager.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\anchor.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\contrib\anchordict.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\collectionstack.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\conversion.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\directives.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\dll.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\emitfromevents.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\emitter.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\emittermanip.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\emitterstate.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\emitterutils.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\eventhandler.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\exceptions.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\exp.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\contrib\graphbuilder.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\indentation.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\iterator.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\iterpriv.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\ltnode.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\mark.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\node.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\nodebuilder.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\nodeimpl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\nodeownership.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\nodereadimpl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\nodeutil.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\noncopyable.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\null.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\ostream.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\parser.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\ptr_stack.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\ptr_vector.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\regex.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\regeximpl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\scanner.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\scanscalar.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\scantag.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\setting.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\singledocparser.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\stlemitter.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\stlnode.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\stream.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\streamcharsource.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\stringsource.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\tag.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\src\token.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\traits.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\ext\yaml-cpp\include\yaml-cpp\yaml.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/aftereffects/win/OpenColorIO.rc b/src/aftereffects/win/OpenColorIO.rc
new file mode 100644
index 0000000..e93fa8c
--- /dev/null
+++ b/src/aftereffects/win/OpenColorIO.rc
@@ -0,0 +1,99 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+PROFILEDIALOG DIALOGEX 0, 0, 233, 78
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "OpenColorIO"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,176,57,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,117,57,50,14
+ COMBOBOX 3,74,20,133,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Monitor Profile:",IDC_STATIC,15,20,55,12,SS_CENTERIMAGE,WS_EX_RIGHT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ "PROFILEDIALOG", DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 226
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 71
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/src/aftereffects/win/OpenColorIO_AE_Dialogs_Win.cpp b/src/aftereffects/win/OpenColorIO_AE_Dialogs_Win.cpp
new file mode 100644
index 0000000..78e8648
--- /dev/null
+++ b/src/aftereffects/win/OpenColorIO_AE_Dialogs_Win.cpp
@@ -0,0 +1,564 @@
+/*
+Copyright (c) 2003-2012 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_AE_Dialogs.h"
+
+#include <list>
+
+#include <Windows.h>
+#include <Shlobj.h>
+#include <Icm.h>
+
+
+#include "lcms2.h"
+
+
+HINSTANCE hDllInstance = NULL;
+
+static void AppendString(char *text, int &length, const char *str, int len = -1)
+{
+ if(len < 0)
+ len = strlen(str);
+
+ const char *in = str;
+ char *out = &text[length];
+
+ for(int i=0; i < len; i++)
+ {
+ *out++ = *in++;
+
+ length++;
+ }
+}
+
+static void AppendNull(char *text, int &length)
+{
+ AppendString(text, length, "\0\0", 1);
+}
+
+static void MakeFilterText(char *filter_text,
+ const ExtensionMap &extensions,
+ bool do_combined)
+{
+ // Construct the Windows file dialog filter string, which looks like this:
+ //
+ // "All OCIO files\0"
+ // "*.ocio;*.cube;*.vf;*.mga\0"
+ // "OpenColorIO (*.ocio)\0"
+ // "*.ocio\0"
+ // "Iridas (*.cube)\0"
+ // "*.cube\0"
+ // "Nuke Vectorfield (*.vf)\0"
+ // "*.vf\0"
+ // "Apple Color (*.mga)\0"
+ // "*.mga\0"
+ // "\0";
+ //
+ // Note the inline nulls and final double-null, which foil regular string functions.
+
+ char combined_entry[512];
+ int combined_length = 0;
+
+ char seperate_entries[512];
+ int seperate_length = 0;
+
+ AppendString(combined_entry, combined_length, "All OCIO files");
+ AppendNull(combined_entry, combined_length);
+
+ for(ExtensionMap::const_iterator i = extensions.begin(); i != extensions.end(); i++)
+ {
+ std::string extension = i->first;
+ std::string format = i->second;
+
+ std::string format_part = format + " (*." + extension + ")";
+ std::string extension_part = "*." + extension;
+ std::string combined_part = extension_part + ";";
+
+ AppendString(seperate_entries, seperate_length, format_part.c_str(), format_part.size());
+ AppendNull(seperate_entries, seperate_length);
+ AppendString(seperate_entries, seperate_length, extension_part.c_str(), extension_part.size());
+ AppendNull(seperate_entries, seperate_length);
+
+ AppendString(combined_entry, combined_length, combined_part.c_str(), combined_part.size());
+ }
+
+ AppendNull(seperate_entries, seperate_length);
+ AppendNull(combined_entry, combined_length);
+
+
+ char *in = combined_entry;
+ char *out = filter_text;
+
+ if(do_combined)
+ {
+ for(int i=0; i < combined_length; i++)
+ *out++ = *in++;
+ }
+
+ in = seperate_entries;
+
+ for(int i=0; i < seperate_length; i++)
+ *out++ = *in++;
+}
+
+
+bool OpenFile(char *path, int buf_len, const ExtensionMap &extensions, const void *hwnd)
+{
+ const char *my_lpstrTitle = "Import OCIO";
+ const char *my_lpstrDefExt = "ocio";
+
+ char my_lpstrFilter[512];
+ MakeFilterText(my_lpstrFilter, extensions, true);
+
+
+ OPENFILENAME lpofn;
+
+ lpofn.lStructSize = sizeof(lpofn);
+ lpofn.hwndOwner = (HWND)hwnd;
+ lpofn.hInstance = hDllInstance;
+ lpofn.lpstrFilter = my_lpstrFilter;
+ lpofn.lpstrCustomFilter = NULL;
+ lpofn.nMaxCustFilter = 0;
+ lpofn.nFilterIndex = 0;
+ lpofn.lpstrFile = path;
+ lpofn.nMaxFile = buf_len;
+ lpofn.lpstrFileTitle = path;
+ lpofn.nMaxFileTitle = buf_len;
+ lpofn.lpstrInitialDir = NULL;
+ lpofn.lpstrTitle = my_lpstrTitle;
+ lpofn.Flags = OFN_LONGNAMES |
+ OFN_HIDEREADONLY |
+ OFN_PATHMUSTEXIST |
+ OFN_OVERWRITEPROMPT;
+ lpofn.nFileOffset = 0;
+ lpofn.nFileExtension = 0;
+ lpofn.lpstrDefExt = my_lpstrDefExt;
+ lpofn.lCustData = 0;
+ lpofn.lpfnHook = NULL;
+ lpofn.lpTemplateName = NULL;
+ lpofn.lStructSize = sizeof(lpofn);
+
+ return GetOpenFileName(&lpofn);
+}
+
+
+bool SaveFile(char *path, int buf_len, const ExtensionMap &extensions, const void *hwnd)
+{
+ const char *my_lpstrTitle = "Export OCIO";
+ const char *my_lpstrDefExt = "icc";
+
+ char my_lpstrFilter[256];
+ MakeFilterText(my_lpstrFilter, extensions, false);
+
+
+ OPENFILENAME lpofn;
+
+ lpofn.lStructSize = sizeof(lpofn);
+ lpofn.hwndOwner = (HWND)hwnd;
+ lpofn.hInstance = hDllInstance;
+ lpofn.lpstrFilter = my_lpstrFilter;
+ lpofn.lpstrCustomFilter = NULL;
+ lpofn.nMaxCustFilter = 0;
+ lpofn.nFilterIndex = 0;
+ lpofn.lpstrFile = path;
+ lpofn.nMaxFile = buf_len;
+ lpofn.lpstrFileTitle = path;
+ lpofn.nMaxFileTitle = buf_len;
+ lpofn.lpstrInitialDir = NULL;
+ lpofn.lpstrTitle = my_lpstrTitle;
+ lpofn.Flags = OFN_LONGNAMES |
+ OFN_HIDEREADONLY |
+ OFN_PATHMUSTEXIST |
+ OFN_OVERWRITEPROMPT;
+ lpofn.nFileOffset = 0;
+ lpofn.nFileExtension = 0;
+ lpofn.lpstrDefExt = my_lpstrDefExt;
+ lpofn.lCustData = 0;
+ lpofn.lpfnHook = NULL;
+ lpofn.lpTemplateName = NULL;
+ lpofn.lStructSize = sizeof(lpofn);
+
+ return GetSaveFileName(&lpofn);
+}
+
+// dialog item IDs
+enum {
+ DLOG_noUI = -1,
+ DLOG_OK = IDOK, // was 1
+ DLOG_Cancel = IDCANCEL, // was 2
+ DLOG_Profile_Menu = 3
+};
+
+
+static std::vector<std::string> *g_profile_vec = NULL;
+static int g_selected_item = DLOG_noUI;
+
+static WORD g_item_clicked = 0;
+
+static BOOL CALLBACK DialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ BOOL fError;
+
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ do{
+ // add profile list to combo boxe
+ HWND menu = GetDlgItem(hwndDlg, DLOG_Profile_Menu);
+
+ for(int i=0; i < g_profile_vec->size(); i++)
+ {
+ SendMessage(menu, (UINT)CB_ADDSTRING,
+ (WPARAM)wParam, (LPARAM)(LPCTSTR)g_profile_vec->at(i).c_str() );
+
+ SendMessage(menu,(UINT)CB_SETITEMDATA,
+ (WPARAM)i, (LPARAM)(DWORD)i); // channel index number
+
+ if( g_selected_item == i )
+ SendMessage(menu, CB_SETCURSEL, (WPARAM)i, (LPARAM)0);
+ }
+ }while(0);
+ return FALSE;
+
+ case WM_COMMAND:
+ g_item_clicked = LOWORD(wParam);
+
+ switch(LOWORD(wParam))
+ {
+ case DLOG_OK:
+ case DLOG_Cancel: // do the same thing, but g_item_clicked differ
+ do{
+ HWND menu = GetDlgItem(hwndDlg, DLOG_Profile_Menu);
+
+ LRESULT cur_sel = SendMessage(menu, (UINT)CB_GETCURSEL,
+ (WPARAM)0, (LPARAM)0);
+
+ g_selected_item = SendMessage(menu, (UINT)CB_GETITEMDATA,
+ (WPARAM)cur_sel, (LPARAM)0);
+
+ }while(0);
+
+ EndDialog(hwndDlg, 0);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+bool GetMonitorProfile(char *path, int buf_len, const void *hwnd)
+{
+ std::list<std::string> profile_descriptions;
+ std::map<std::string, std::string> profile_paths;
+
+ // path to the monitor's profile
+ char monitor_profile_path[256] = { '\0' };
+ DWORD path_size = 256;
+ BOOL get_icm_result = GetICMProfile(GetDC((HWND)hwnd), &path_size, monitor_profile_path);
+
+ // directory where Windows stores its profiles
+ char profile_directory[256] = { '\0' };
+ DWORD dir_name_size = 256;
+ BOOL get_color_dir_result = GetColorDirectory(NULL, profile_directory, &dir_name_size);
+
+ // Get the profile file names from Windows
+ ENUMTYPE enum_type;
+ enum_type.dwSize = sizeof(ENUMTYPE);
+ enum_type.dwVersion = ENUM_TYPE_VERSION;
+ enum_type.dwFields = ET_DEVICECLASS; // alternately could use ET_CLASS
+ enum_type.dwDeviceClass = CLASS_MONITOR;
+
+ BYTE *buf = NULL;
+ DWORD buf_size = 0;
+ DWORD num_profiles = 0;
+
+ BOOL other_enum_result = EnumColorProfiles(NULL, &enum_type,
+ buf, &buf_size, &num_profiles);
+
+ if(buf_size > 0 && num_profiles > 0)
+ {
+ buf = (BYTE *)malloc(buf_size);
+
+ other_enum_result = EnumColorProfiles(NULL, &enum_type,
+ buf, &buf_size, &num_profiles);
+
+ if(other_enum_result)
+ {
+ // build a list of the profile descriptions
+ // and a map to return the paths
+ char *prof_name = (char *)buf;
+
+ for(int i=0; i < num_profiles; i++)
+ {
+ std::string prof = prof_name;
+ std::string prof_path = std::string(profile_directory) + "\\" + prof_name;
+
+ cmsHPROFILE hProfile = cmsOpenProfileFromFile(prof_path.c_str(), "r");
+
+ // Note: Windows will give us profiles that aren't ICC (.cdmp for example).
+ // Don't worry, LittleCMS will just return NULL for those.
+ if(hProfile)
+ {
+ char profile_description[256];
+
+ cmsUInt32Number got_desc = cmsGetProfileInfoASCII(hProfile,
+ cmsInfoDescription,
+ "en", "US",
+ profile_description,
+ 256);
+
+ if(got_desc)
+ {
+ profile_descriptions.push_back(profile_description);
+
+ profile_paths[ profile_description ] = prof_path;
+ }
+
+ cmsCloseProfile(hProfile);
+ }
+
+ prof_name += strlen(prof_name) + 1;
+ }
+ }
+
+ free(buf);
+ }
+
+
+ if(profile_descriptions.size() > 0)
+ {
+ // set a vector and selected index for building the profile menu
+ profile_descriptions.sort();
+ profile_descriptions.unique();
+
+ std::vector<std::string> profile_vec;
+ int selected = 0;
+
+ for(std::list<std::string>::const_iterator i = profile_descriptions.begin(); i != profile_descriptions.end(); i++)
+ {
+ profile_vec.push_back( *i );
+
+ if( profile_paths[ *i ] == monitor_profile_path)
+ {
+ selected = profile_vec.size() - 1;
+ }
+ }
+
+ // run the dialog
+ g_profile_vec = &profile_vec;
+ g_selected_item = selected;
+
+ int status = DialogBox(hDllInstance, (LPSTR)"PROFILEDIALOG",
+ (HWND)hwnd, (DLGPROC)DialogProc);
+
+
+ if(status == -1)
+ {
+ // dialog didn't open, my bad
+ return true;
+ }
+ else if(g_item_clicked == DLOG_Cancel)
+ {
+ return false;
+ }
+ else
+ {
+ strncpy(path, profile_paths[ profile_vec[ g_selected_item ] ].c_str(), buf_len);
+
+ return true;
+ }
+ }
+ else
+ return true;
+}
+
+
+int PopUpMenu(const MenuVec &menu_items, int selected_index, const void *hwnd)
+{
+ HMENU menu = CreatePopupMenu();
+
+ if(menu)
+ {
+ for(int i=0; i < menu_items.size(); i++)
+ {
+ std::string label = menu_items[i];
+
+ UINT flags = (i == selected_index ? (MF_STRING | MF_CHECKED) : MF_STRING);
+
+ if(label == "(-")
+ {
+ flags |= MF_SEPARATOR;
+ }
+ else if(label == "$OCIO")
+ {
+ char *file = std::getenv("OCIO");
+
+ if(file == NULL)
+ flags |= MF_GRAYED;
+ }
+ else if(label == "(nada)")
+ {
+ flags |= MF_GRAYED;
+
+ char appdata_path[MAX_PATH];
+ HRESULT result = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL,
+ SHGFP_TYPE_CURRENT, appdata_path);
+
+ if(result == S_OK)
+ {
+ label = "No configs in " + std::string(appdata_path) + "\\OpenColorIO\\";
+ }
+ }
+
+ AppendMenu(menu, flags, i + 1, label.c_str());
+ }
+
+ POINT pos;
+ GetCursorPos(&pos);
+
+ int result = TrackPopupMenuEx(menu,
+ (TPM_NONOTIFY | TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD),
+ pos.x, pos.y, (HWND)hwnd, NULL);
+
+ DestroyMenu(menu);
+
+ if(result == 0)
+ {
+ // means the user clicked off the menu
+ return selected_index;
+ }
+ else
+ return result - 1;
+ }
+ else
+ return selected_index;
+}
+
+
+void GetStdConfigs(ConfigVec &configs)
+{
+ char appdata_path[MAX_PATH];
+
+ HRESULT result = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL,
+ SHGFP_TYPE_CURRENT, appdata_path);
+
+ if(result == S_OK)
+ {
+ std::string dir_path = std::string(appdata_path) + "\\OpenColorIO\\";
+
+ std::string search_path = dir_path + "*";
+
+ WIN32_FIND_DATA find_data;
+
+ HANDLE searchH = FindFirstFile(search_path.c_str(), &find_data);
+
+ if(searchH != INVALID_HANDLE_VALUE)
+ {
+ if(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ std::string config_path = dir_path + find_data.cFileName + "\\config.ocio";
+
+ WIN32_FIND_DATA find_data_temp;
+
+ HANDLE fileH = FindFirstFile(config_path.c_str(), &find_data_temp);
+
+ if(fileH != INVALID_HANDLE_VALUE)
+ {
+ configs.push_back(find_data.cFileName);
+
+ FindClose(fileH);
+ }
+ }
+
+ while( FindNextFile(searchH, &find_data) )
+ {
+ if(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ std::string config_path = dir_path + find_data.cFileName + "\\config.ocio";
+
+ WIN32_FIND_DATA find_data_temp;
+
+ HANDLE fileH = FindFirstFile(config_path.c_str(), &find_data_temp);
+
+ if(fileH != INVALID_HANDLE_VALUE)
+ {
+ configs.push_back(find_data.cFileName);
+
+ FindClose(fileH);
+ }
+ }
+ }
+
+ FindClose(searchH);
+ }
+ }
+}
+
+
+std::string GetStdConfigPath(const std::string &name)
+{
+ char appdata_path[MAX_PATH];
+
+ HRESULT result = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL,
+ SHGFP_TYPE_CURRENT, appdata_path);
+
+ if(result == S_OK)
+ {
+ std::string config_path = std::string(appdata_path) + "\\OpenColorIO\\" +
+ name + "\\config.ocio";
+
+ WIN32_FIND_DATA find_data;
+
+ HANDLE searchH = FindFirstFile(config_path.c_str(), &find_data);
+
+ if(searchH != INVALID_HANDLE_VALUE)
+ {
+ FindClose(searchH);
+
+ return config_path;
+ }
+ }
+
+ return "";
+}
+
+
+void ErrorMessage(const char *message , const void *hwnd)
+{
+ MessageBox((HWND)hwnd, message, "OpenColorIO", MB_OK);
+}
+
+
+BOOL WINAPI DllMain(HANDLE hInstance, DWORD fdwReason, LPVOID lpReserved)
+{
+ if (fdwReason == DLL_PROCESS_ATTACH)
+ hDllInstance = (HINSTANCE)hInstance;
+
+ return TRUE;
+}
diff --git a/src/aftereffects/win/OpenColorIO_AE_GL_Win.cpp b/src/aftereffects/win/OpenColorIO_AE_GL_Win.cpp
new file mode 100644
index 0000000..867522a
--- /dev/null
+++ b/src/aftereffects/win/OpenColorIO_AE_GL_Win.cpp
@@ -0,0 +1,212 @@
+/*
+Copyright (c) 2003-2012 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_AE_GL.h"
+
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+static HWND g_win = NULL;
+static HDC g_hdc = NULL;
+static HGLRC g_context = NULL;
+static GLuint g_framebuffer;
+
+
+static bool HaveRequiredExtensions()
+{
+ const GLubyte *strVersion = glGetString(GL_VERSION);
+ const GLubyte *strExt = glGetString(GL_EXTENSIONS);
+
+ if(strVersion == NULL)
+ return false;
+
+#define CheckExtension(N) glewIsExtensionSupported(N)
+
+ return (GLEW_VERSION_2_0 &&
+ CheckExtension("GL_ARB_color_buffer_float") &&
+ CheckExtension("GL_ARB_texture_float") &&
+ CheckExtension("GL_ARB_vertex_program") &&
+ CheckExtension("GL_ARB_vertex_shader") &&
+ CheckExtension("GL_ARB_texture_cube_map") &&
+ CheckExtension("GL_ARB_fragment_shader") &&
+ CheckExtension("GL_ARB_draw_buffers") &&
+ CheckExtension("GL_ARB_framebuffer_object") );
+}
+
+
+void GlobalSetup_GL()
+{
+ GLenum init = glewInit();
+
+ if(init != GLEW_OK)
+ return;
+
+
+ WNDCLASSEX winClass;
+ MSG uMsg;
+
+ memset(&uMsg,0,sizeof(uMsg));
+
+ winClass.lpszClassName = "OpenColorIO_AE_Win_Class";
+ winClass.cbSize = sizeof(WNDCLASSEX);
+ winClass.style = CS_HREDRAW | CS_VREDRAW;
+ winClass.lpfnWndProc = DefWindowProc;
+ winClass.hInstance = NULL;
+ winClass.hIcon = NULL;
+ winClass.hIconSm = NULL;
+ winClass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
+ winClass.lpszMenuName = NULL;
+ winClass.cbClsExtra = 0;
+ winClass.cbWndExtra = 0;
+
+ if( !( RegisterClassEx(&winClass) ) )
+ return;
+
+ g_win = CreateWindowEx( NULL, "OpenColorIO_AE_Win_Class",
+ "OpenGL-using FBOs in AE",
+ 0, 0,
+ 0, 50, 50,
+ NULL,
+ NULL,
+ NULL,
+ NULL );
+
+ if(g_win == NULL)
+ return;
+
+ g_hdc = GetDC(g_win);
+
+
+ int pixelFormat;
+
+ PIXELFORMATDESCRIPTOR pfd;
+ ZeroMemory( &pfd, sizeof( pfd ) );
+
+ pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
+ pfd.nVersion = 1;
+ pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
+ pfd.iPixelType = PFD_TYPE_RGBA;
+ pfd.cColorBits = 128;
+ pfd.cDepthBits = 32;
+ pfd.cStencilBits = 32;
+ pfd.iLayerType = PFD_MAIN_PLANE;
+
+ pixelFormat = ChoosePixelFormat(g_hdc, &pfd);
+
+ BOOL set_format = SetPixelFormat(g_hdc, pixelFormat, &pfd);
+
+ if(!set_format)
+ {
+ GlobalSetdown_GL();
+ return;
+ }
+
+ g_context = wglCreateContext(g_hdc);
+
+ glFlush();
+
+ if(g_context == NULL)
+ {
+ GlobalSetdown_GL();
+ return;
+ }
+
+
+ SetPluginContext();
+
+
+ GLint units;
+ glGetIntegerv(GL_MAX_TEXTURE_UNITS, &units);
+
+
+ if( !HaveRequiredExtensions() || units < 2)
+ {
+ GlobalSetdown_GL();
+ SetAEContext();
+ return;
+ }
+
+ glGenFramebuffersEXT(1, &g_framebuffer);
+
+
+ SetAEContext();
+}
+
+
+bool HaveOpenGL()
+{
+ return (g_context != NULL && g_win != NULL);
+}
+
+
+static HDC g_ae_hdc;
+static HGLRC g_ae_context;
+
+void SetPluginContext()
+{
+ g_ae_hdc = wglGetCurrentDC();
+ g_ae_context = wglGetCurrentContext();
+
+ wglMakeCurrent(g_hdc, g_context);
+}
+
+
+void SetAEContext()
+{
+ wglMakeCurrent(g_ae_hdc, g_ae_context);
+}
+
+
+GLuint GetFrameBuffer()
+{
+ return g_framebuffer;
+}
+
+
+void GlobalSetdown_GL()
+{
+ if(g_context)
+ {
+ wglDeleteContext(g_context);
+ g_context = NULL;
+
+ glDeleteFramebuffersEXT(1, &g_framebuffer);
+ }
+
+ if(g_win)
+ {
+ ReleaseDC(g_win, g_hdc);
+ g_win = NULL;
+ g_hdc = NULL;
+
+ UnregisterClass("OpenColorIO_AE_Win_Class", NULL);
+ }
+}
diff --git a/src/aftereffects/win/resource.h b/src/aftereffects/win/resource.h
new file mode 100644
index 0000000..2191cce
--- /dev/null
+++ b/src/aftereffects/win/resource.h
@@ -0,0 +1,17 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by OpenColorIO.rc
+//
+#define IDB_BITMAP1 102
+#define BANNER1 102
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 103
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1002
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/aftereffects/xcode/OpenColorABI.h b/src/aftereffects/xcode/OpenColorABI.h
new file mode 100644
index 0000000..a3ce756
--- /dev/null
+++ b/src/aftereffects/xcode/OpenColorABI.h
@@ -0,0 +1,100 @@
+/*
+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.
+*/
+
+#ifndef INCLUDED_OCIO_OPENCOLORABI_H
+#define INCLUDED_OCIO_OPENCOLORABI_H
+
+// Makefile configuration options
+#define OCIO_NAMESPACE OpenColorIO
+#define OCIO_USE_BOOST_PTR 0
+#define OCIO_VERSION "1.0.7"
+#define OCIO_VERSION_NS v1
+
+/* Version as a single 4-byte hex number, e.g. 0x01050200 == 1.5.2
+ Use this for numeric comparisons, e.g. #if OCIO_VERSION_HEX >= ...
+ Note: in the case where SOVERSION is overridden at compile-time,
+ this will reflect the original API version number.
+ */
+#define OCIO_VERSION_HEX ((1 << 24) | \
+ (0 << 16) | \
+ (7 << 8))
+
+
+// Namespace / version mojo
+#define OCIO_NAMESPACE_ENTER namespace OCIO_NAMESPACE { namespace OCIO_VERSION_NS
+#define OCIO_NAMESPACE_EXIT using namespace OCIO_VERSION_NS; }
+#define OCIO_NAMESPACE_USING using namespace OCIO_NAMESPACE;
+
+// shared_ptr / dynamic_pointer_cast
+#if OCIO_USE_BOOST_PTR
+#include <boost/shared_ptr.hpp>
+#define OCIO_SHARED_PTR boost::shared_ptr
+#define OCIO_DYNAMIC_POINTER_CAST boost::dynamic_pointer_cast
+#elif __GNUC__ >= 4
+#include <tr1/memory>
+#define OCIO_SHARED_PTR std::tr1::shared_ptr
+#define OCIO_DYNAMIC_POINTER_CAST std::tr1::dynamic_pointer_cast
+#else
+#error OCIO needs gcc 4 or later to get access to <tr1/memory> (or specify USE_BOOST_PTR instead)
+#endif
+
+#ifdef OpenColorIO_SHARED
+ // If supported, define OCIOEXPORT, OCIOHIDDEN
+ // (used to choose which symbols to export from OpenColorIO)
+ #if defined __linux__ || __APPLE__
+ #if __GNUC__ >= 4
+ #define OCIOEXPORT __attribute__ ((visibility("default")))
+ #define OCIOHIDDEN __attribute__ ((visibility("hidden")))
+ #else
+ #define OCIOEXPORT
+ #define OCIOHIDDEN
+ #endif
+ #elif defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS) || defined(_MSC_VER)
+ // Windows requires you to export from the main library and then import in any others
+ #if defined OpenColorIO_EXPORTS
+ #define OCIOEXPORT __declspec(dllexport)
+ #else
+ #define OCIOEXPORT __declspec(dllimport)
+ #endif
+ #define OCIOHIDDEN
+ #else // Others platforms not supported atm
+ #define OCIOEXPORT
+ #define OCIOHIDDEN
+ #endif
+#else
+ #define OCIOEXPORT
+ #define OCIOHIDDEN
+#endif
+
+// Windows defines these troublesome macros that collide with std::limits
+#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS) || defined(_MSC_VER)
+#undef min
+#undef max
+#endif
+
+#endif // INCLUDED_OCIO_OPENCOLORABI_H
diff --git a/src/aftereffects/xcode/OpenColorIO.xcodeproj/project.pbxproj b/src/aftereffects/xcode/OpenColorIO.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..eb84949
--- /dev/null
+++ b/src/aftereffects/xcode/OpenColorIO.xcodeproj/project.pbxproj
@@ -0,0 +1,589 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 2A7CACBB15536CD700F52C98 /* FileFormatIridasLook.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A7CACB515536CD700F52C98 /* FileFormatIridasLook.cpp */; };
+ 2A7CACBC15536CD700F52C98 /* LookParse.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A7CACB615536CD700F52C98 /* LookParse.cpp */; };
+ 2A7CACBD15536CD700F52C98 /* LookParse.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A7CACB715536CD700F52C98 /* LookParse.h */; };
+ 2A7CACBE15536CD700F52C98 /* NoOps.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A7CACB815536CD700F52C98 /* NoOps.cpp */; };
+ 2A7CACBF15536CD700F52C98 /* NoOps.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A7CACB915536CD700F52C98 /* NoOps.h */; };
+ 2A7CACC015536CD700F52C98 /* OpOptimizers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A7CACBA15536CD700F52C98 /* OpOptimizers.cpp */; };
+ 2ACF56CC14776A1E00991ED5 /* AllocationOp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF567614776A1E00991ED5 /* AllocationOp.cpp */; };
+ 2ACF56CD14776A1E00991ED5 /* AllocationOp.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF567714776A1E00991ED5 /* AllocationOp.h */; };
+ 2ACF56CE14776A1E00991ED5 /* AllocationTransform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF567814776A1E00991ED5 /* AllocationTransform.cpp */; };
+ 2ACF56CF14776A1E00991ED5 /* Baker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF567914776A1E00991ED5 /* Baker.cpp */; };
+ 2ACF56D014776A1E00991ED5 /* Caching.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF567A14776A1E00991ED5 /* Caching.cpp */; };
+ 2ACF56D114776A1E00991ED5 /* CDLTransform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF567B14776A1E00991ED5 /* CDLTransform.cpp */; };
+ 2ACF56D214776A1E00991ED5 /* CDLTransform.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF567C14776A1E00991ED5 /* CDLTransform.h */; };
+ 2ACF56D314776A1E00991ED5 /* ColorSpace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF567D14776A1E00991ED5 /* ColorSpace.cpp */; };
+ 2ACF56D414776A1E00991ED5 /* ColorSpaceTransform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF567E14776A1E00991ED5 /* ColorSpaceTransform.cpp */; };
+ 2ACF56D514776A1E00991ED5 /* Config.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF567F14776A1E00991ED5 /* Config.cpp */; };
+ 2ACF56D614776A1E00991ED5 /* Context.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF568014776A1E00991ED5 /* Context.cpp */; };
+ 2ACF56D714776A1E00991ED5 /* DisplayTransform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF568114776A1E00991ED5 /* DisplayTransform.cpp */; };
+ 2ACF56D814776A1E00991ED5 /* Exception.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF568214776A1E00991ED5 /* Exception.cpp */; };
+ 2ACF56D914776A1E00991ED5 /* ExponentOps.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF568314776A1E00991ED5 /* ExponentOps.cpp */; };
+ 2ACF56DA14776A1E00991ED5 /* ExponentOps.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF568414776A1E00991ED5 /* ExponentOps.h */; };
+ 2ACF56DB14776A1E00991ED5 /* ExponentTransform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF568514776A1E00991ED5 /* ExponentTransform.cpp */; };
+ 2ACF56DC14776A1E00991ED5 /* FileFormat3DL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF568614776A1E00991ED5 /* FileFormat3DL.cpp */; };
+ 2ACF56DD14776A1E00991ED5 /* FileFormatCC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF568714776A1E00991ED5 /* FileFormatCC.cpp */; };
+ 2ACF56DE14776A1E00991ED5 /* FileFormatCCC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF568814776A1E00991ED5 /* FileFormatCCC.cpp */; };
+ 2ACF56DF14776A1E00991ED5 /* FileFormatCSP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF568914776A1E00991ED5 /* FileFormatCSP.cpp */; };
+ 2ACF56E014776A1E00991ED5 /* FileFormatHDL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF568A14776A1E00991ED5 /* FileFormatHDL.cpp */; };
+ 2ACF56E114776A1E00991ED5 /* FileFormatIridasCube.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF568B14776A1E00991ED5 /* FileFormatIridasCube.cpp */; };
+ 2ACF56E214776A1E00991ED5 /* FileFormatIridasItx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF568C14776A1E00991ED5 /* FileFormatIridasItx.cpp */; };
+ 2ACF56E314776A1E00991ED5 /* FileFormatPandora.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF568D14776A1E00991ED5 /* FileFormatPandora.cpp */; };
+ 2ACF56E414776A1E00991ED5 /* FileFormatSpi1D.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF568E14776A1E00991ED5 /* FileFormatSpi1D.cpp */; };
+ 2ACF56E514776A1E00991ED5 /* FileFormatSpi3D.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF568F14776A1E00991ED5 /* FileFormatSpi3D.cpp */; };
+ 2ACF56E614776A1E00991ED5 /* FileFormatSpiMtx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF569014776A1E00991ED5 /* FileFormatSpiMtx.cpp */; };
+ 2ACF56E714776A1E00991ED5 /* FileFormatTruelight.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF569114776A1E00991ED5 /* FileFormatTruelight.cpp */; };
+ 2ACF56E814776A1E00991ED5 /* FileFormatVF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF569214776A1E00991ED5 /* FileFormatVF.cpp */; };
+ 2ACF56E914776A1E00991ED5 /* FileTransform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF569314776A1E00991ED5 /* FileTransform.cpp */; };
+ 2ACF56EA14776A1E00991ED5 /* FileTransform.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF569414776A1E00991ED5 /* FileTransform.h */; };
+ 2ACF56EC14776A1E00991ED5 /* GpuShaderDesc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF569614776A1E00991ED5 /* GpuShaderDesc.cpp */; };
+ 2ACF56ED14776A1E00991ED5 /* GpuShaderUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF569714776A1E00991ED5 /* GpuShaderUtils.cpp */; };
+ 2ACF56EE14776A1E00991ED5 /* GpuShaderUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF569814776A1E00991ED5 /* GpuShaderUtils.h */; };
+ 2ACF56EF14776A1E00991ED5 /* GroupTransform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF569914776A1E00991ED5 /* GroupTransform.cpp */; };
+ 2ACF56F014776A1E00991ED5 /* HashUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF569A14776A1E00991ED5 /* HashUtils.cpp */; };
+ 2ACF56F114776A1E00991ED5 /* HashUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF569B14776A1E00991ED5 /* HashUtils.h */; };
+ 2ACF56F214776A1E00991ED5 /* ImageDesc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF569C14776A1E00991ED5 /* ImageDesc.cpp */; };
+ 2ACF56F314776A1E00991ED5 /* ImagePacking.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF569D14776A1E00991ED5 /* ImagePacking.cpp */; };
+ 2ACF56F414776A1E00991ED5 /* ImagePacking.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF569E14776A1E00991ED5 /* ImagePacking.h */; };
+ 2ACF56F514776A1E00991ED5 /* Logging.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF569F14776A1E00991ED5 /* Logging.cpp */; };
+ 2ACF56F614776A1E00991ED5 /* Logging.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56A014776A1E00991ED5 /* Logging.h */; };
+ 2ACF56F714776A1E00991ED5 /* LogOps.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56A114776A1E00991ED5 /* LogOps.cpp */; };
+ 2ACF56F814776A1E00991ED5 /* LogOps.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56A214776A1E00991ED5 /* LogOps.h */; };
+ 2ACF56F914776A1E00991ED5 /* LogTransform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56A314776A1E00991ED5 /* LogTransform.cpp */; };
+ 2ACF56FA14776A1E00991ED5 /* Look.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56A414776A1E00991ED5 /* Look.cpp */; };
+ 2ACF56FB14776A1E00991ED5 /* LookTransform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56A514776A1E00991ED5 /* LookTransform.cpp */; };
+ 2ACF56FC14776A1E00991ED5 /* Lut1DOp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56A614776A1E00991ED5 /* Lut1DOp.cpp */; };
+ 2ACF56FD14776A1E00991ED5 /* Lut1DOp.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56A714776A1E00991ED5 /* Lut1DOp.h */; };
+ 2ACF56FE14776A1E00991ED5 /* Lut3DOp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56A814776A1E00991ED5 /* Lut3DOp.cpp */; };
+ 2ACF56FF14776A1E00991ED5 /* Lut3DOp.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56A914776A1E00991ED5 /* Lut3DOp.h */; };
+ 2ACF570014776A1E00991ED5 /* MathUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56AA14776A1E00991ED5 /* MathUtils.cpp */; };
+ 2ACF570114776A1E00991ED5 /* MathUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56AB14776A1E00991ED5 /* MathUtils.h */; };
+ 2ACF570214776A1E00991ED5 /* MatrixOps.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56AC14776A1E00991ED5 /* MatrixOps.cpp */; };
+ 2ACF570314776A1E00991ED5 /* MatrixOps.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56AD14776A1E00991ED5 /* MatrixOps.h */; };
+ 2ACF570414776A1E00991ED5 /* MatrixTransform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56AE14776A1E00991ED5 /* MatrixTransform.cpp */; };
+ 2ACF570514776A1E00991ED5 /* md5.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56B014776A1E00991ED5 /* md5.cpp */; };
+ 2ACF570614776A1E00991ED5 /* md5.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56B114776A1E00991ED5 /* md5.h */; };
+ 2ACF570714776A1E00991ED5 /* Mutex.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56B214776A1E00991ED5 /* Mutex.h */; };
+ 2ACF570814776A1E00991ED5 /* OCIOYaml.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56B314776A1E00991ED5 /* OCIOYaml.cpp */; };
+ 2ACF570914776A1E00991ED5 /* OCIOYaml.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56B414776A1E00991ED5 /* OCIOYaml.h */; };
+ 2ACF570A14776A1E00991ED5 /* Op.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56B514776A1E00991ED5 /* Op.cpp */; };
+ 2ACF570B14776A1E00991ED5 /* Op.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56B614776A1E00991ED5 /* Op.h */; };
+ 2ACF570C14776A1E00991ED5 /* OpBuilders.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56B714776A1E00991ED5 /* OpBuilders.h */; };
+ 2ACF570D14776A1E00991ED5 /* ParseUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56B814776A1E00991ED5 /* ParseUtils.cpp */; };
+ 2ACF570E14776A1E00991ED5 /* ParseUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56B914776A1E00991ED5 /* ParseUtils.h */; };
+ 2ACF570F14776A1E00991ED5 /* PathUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56BA14776A1E00991ED5 /* PathUtils.cpp */; };
+ 2ACF571014776A1E00991ED5 /* PathUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56BB14776A1E00991ED5 /* PathUtils.h */; };
+ 2ACF571114776A1E00991ED5 /* Platform.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56BC14776A1E00991ED5 /* Platform.h */; };
+ 2ACF571214776A1E00991ED5 /* PrivateTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56BD14776A1E00991ED5 /* PrivateTypes.h */; };
+ 2ACF571314776A1E00991ED5 /* Processor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56BE14776A1E00991ED5 /* Processor.cpp */; };
+ 2ACF571414776A1E00991ED5 /* Processor.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56BF14776A1E00991ED5 /* Processor.h */; };
+ 2ACF571514776A1E00991ED5 /* pystring.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56C114776A1E00991ED5 /* pystring.cpp */; };
+ 2ACF571614776A1E00991ED5 /* pystring.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56C214776A1E00991ED5 /* pystring.h */; };
+ 2ACF571714776A1E00991ED5 /* ScanlineHelper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56C314776A1E00991ED5 /* ScanlineHelper.cpp */; };
+ 2ACF571814776A1E00991ED5 /* ScanlineHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56C414776A1E00991ED5 /* ScanlineHelper.h */; };
+ 2ACF571914776A1E00991ED5 /* SSE.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56C514776A1E00991ED5 /* SSE.h */; };
+ 2ACF571A14776A1E00991ED5 /* Transform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56C614776A1E00991ED5 /* Transform.cpp */; };
+ 2ACF571B14776A1E00991ED5 /* TruelightOp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56C714776A1E00991ED5 /* TruelightOp.cpp */; };
+ 2ACF571C14776A1E00991ED5 /* TruelightOp.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56C814776A1E00991ED5 /* TruelightOp.h */; };
+ 2ACF571D14776A1E00991ED5 /* TruelightTransform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56C914776A1E00991ED5 /* TruelightTransform.cpp */; };
+ 2ACF571E14776A1E00991ED5 /* UnitTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF56CA14776A1E00991ED5 /* UnitTest.cpp */; };
+ 2ACF571F14776A1E00991ED5 /* UnitTest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF56CB14776A1E00991ED5 /* UnitTest.h */; };
+ 2ACF573F14776B7000991ED5 /* OpenColorABI.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF573E14776B7000991ED5 /* OpenColorABI.h */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 2A7CACB515536CD700F52C98 /* FileFormatIridasLook.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileFormatIridasLook.cpp; sourceTree = "<group>"; };
+ 2A7CACB615536CD700F52C98 /* LookParse.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LookParse.cpp; sourceTree = "<group>"; };
+ 2A7CACB715536CD700F52C98 /* LookParse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LookParse.h; sourceTree = "<group>"; };
+ 2A7CACB815536CD700F52C98 /* NoOps.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NoOps.cpp; sourceTree = "<group>"; };
+ 2A7CACB915536CD700F52C98 /* NoOps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NoOps.h; sourceTree = "<group>"; };
+ 2A7CACBA15536CD700F52C98 /* OpOptimizers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OpOptimizers.cpp; sourceTree = "<group>"; };
+ 2ACF567114776A0A00991ED5 /* libOpenColorIO.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libOpenColorIO.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2ACF567614776A1E00991ED5 /* AllocationOp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AllocationOp.cpp; sourceTree = "<group>"; };
+ 2ACF567714776A1E00991ED5 /* AllocationOp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AllocationOp.h; sourceTree = "<group>"; };
+ 2ACF567814776A1E00991ED5 /* AllocationTransform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AllocationTransform.cpp; sourceTree = "<group>"; };
+ 2ACF567914776A1E00991ED5 /* Baker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Baker.cpp; sourceTree = "<group>"; };
+ 2ACF567A14776A1E00991ED5 /* Caching.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Caching.cpp; sourceTree = "<group>"; };
+ 2ACF567B14776A1E00991ED5 /* CDLTransform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CDLTransform.cpp; sourceTree = "<group>"; };
+ 2ACF567C14776A1E00991ED5 /* CDLTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDLTransform.h; sourceTree = "<group>"; };
+ 2ACF567D14776A1E00991ED5 /* ColorSpace.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ColorSpace.cpp; sourceTree = "<group>"; };
+ 2ACF567E14776A1E00991ED5 /* ColorSpaceTransform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ColorSpaceTransform.cpp; sourceTree = "<group>"; };
+ 2ACF567F14776A1E00991ED5 /* Config.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Config.cpp; sourceTree = "<group>"; };
+ 2ACF568014776A1E00991ED5 /* Context.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Context.cpp; sourceTree = "<group>"; };
+ 2ACF568114776A1E00991ED5 /* DisplayTransform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DisplayTransform.cpp; sourceTree = "<group>"; };
+ 2ACF568214776A1E00991ED5 /* Exception.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Exception.cpp; sourceTree = "<group>"; };
+ 2ACF568314776A1E00991ED5 /* ExponentOps.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExponentOps.cpp; sourceTree = "<group>"; };
+ 2ACF568414776A1E00991ED5 /* ExponentOps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExponentOps.h; sourceTree = "<group>"; };
+ 2ACF568514776A1E00991ED5 /* ExponentTransform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExponentTransform.cpp; sourceTree = "<group>"; };
+ 2ACF568614776A1E00991ED5 /* FileFormat3DL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileFormat3DL.cpp; sourceTree = "<group>"; };
+ 2ACF568714776A1E00991ED5 /* FileFormatCC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileFormatCC.cpp; sourceTree = "<group>"; };
+ 2ACF568814776A1E00991ED5 /* FileFormatCCC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileFormatCCC.cpp; sourceTree = "<group>"; };
+ 2ACF568914776A1E00991ED5 /* FileFormatCSP.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileFormatCSP.cpp; sourceTree = "<group>"; };
+ 2ACF568A14776A1E00991ED5 /* FileFormatHDL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileFormatHDL.cpp; sourceTree = "<group>"; };
+ 2ACF568B14776A1E00991ED5 /* FileFormatIridasCube.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileFormatIridasCube.cpp; sourceTree = "<group>"; };
+ 2ACF568C14776A1E00991ED5 /* FileFormatIridasItx.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileFormatIridasItx.cpp; sourceTree = "<group>"; };
+ 2ACF568D14776A1E00991ED5 /* FileFormatPandora.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileFormatPandora.cpp; sourceTree = "<group>"; };
+ 2ACF568E14776A1E00991ED5 /* FileFormatSpi1D.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileFormatSpi1D.cpp; sourceTree = "<group>"; };
+ 2ACF568F14776A1E00991ED5 /* FileFormatSpi3D.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileFormatSpi3D.cpp; sourceTree = "<group>"; };
+ 2ACF569014776A1E00991ED5 /* FileFormatSpiMtx.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileFormatSpiMtx.cpp; sourceTree = "<group>"; };
+ 2ACF569114776A1E00991ED5 /* FileFormatTruelight.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileFormatTruelight.cpp; sourceTree = "<group>"; };
+ 2ACF569214776A1E00991ED5 /* FileFormatVF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileFormatVF.cpp; sourceTree = "<group>"; };
+ 2ACF569314776A1E00991ED5 /* FileTransform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileTransform.cpp; sourceTree = "<group>"; };
+ 2ACF569414776A1E00991ED5 /* FileTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileTransform.h; sourceTree = "<group>"; };
+ 2ACF569614776A1E00991ED5 /* GpuShaderDesc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GpuShaderDesc.cpp; sourceTree = "<group>"; };
+ 2ACF569714776A1E00991ED5 /* GpuShaderUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GpuShaderUtils.cpp; sourceTree = "<group>"; };
+ 2ACF569814776A1E00991ED5 /* GpuShaderUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GpuShaderUtils.h; sourceTree = "<group>"; };
+ 2ACF569914776A1E00991ED5 /* GroupTransform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GroupTransform.cpp; sourceTree = "<group>"; };
+ 2ACF569A14776A1E00991ED5 /* HashUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HashUtils.cpp; sourceTree = "<group>"; };
+ 2ACF569B14776A1E00991ED5 /* HashUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HashUtils.h; sourceTree = "<group>"; };
+ 2ACF569C14776A1E00991ED5 /* ImageDesc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageDesc.cpp; sourceTree = "<group>"; };
+ 2ACF569D14776A1E00991ED5 /* ImagePacking.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImagePacking.cpp; sourceTree = "<group>"; };
+ 2ACF569E14776A1E00991ED5 /* ImagePacking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImagePacking.h; sourceTree = "<group>"; };
+ 2ACF569F14776A1E00991ED5 /* Logging.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Logging.cpp; sourceTree = "<group>"; };
+ 2ACF56A014776A1E00991ED5 /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Logging.h; sourceTree = "<group>"; };
+ 2ACF56A114776A1E00991ED5 /* LogOps.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogOps.cpp; sourceTree = "<group>"; };
+ 2ACF56A214776A1E00991ED5 /* LogOps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogOps.h; sourceTree = "<group>"; };
+ 2ACF56A314776A1E00991ED5 /* LogTransform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogTransform.cpp; sourceTree = "<group>"; };
+ 2ACF56A414776A1E00991ED5 /* Look.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Look.cpp; sourceTree = "<group>"; };
+ 2ACF56A514776A1E00991ED5 /* LookTransform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LookTransform.cpp; sourceTree = "<group>"; };
+ 2ACF56A614776A1E00991ED5 /* Lut1DOp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Lut1DOp.cpp; sourceTree = "<group>"; };
+ 2ACF56A714776A1E00991ED5 /* Lut1DOp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Lut1DOp.h; sourceTree = "<group>"; };
+ 2ACF56A814776A1E00991ED5 /* Lut3DOp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Lut3DOp.cpp; sourceTree = "<group>"; };
+ 2ACF56A914776A1E00991ED5 /* Lut3DOp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Lut3DOp.h; sourceTree = "<group>"; };
+ 2ACF56AA14776A1E00991ED5 /* MathUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MathUtils.cpp; sourceTree = "<group>"; };
+ 2ACF56AB14776A1E00991ED5 /* MathUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MathUtils.h; sourceTree = "<group>"; };
+ 2ACF56AC14776A1E00991ED5 /* MatrixOps.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MatrixOps.cpp; sourceTree = "<group>"; };
+ 2ACF56AD14776A1E00991ED5 /* MatrixOps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MatrixOps.h; sourceTree = "<group>"; };
+ 2ACF56AE14776A1E00991ED5 /* MatrixTransform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MatrixTransform.cpp; sourceTree = "<group>"; };
+ 2ACF56B014776A1E00991ED5 /* md5.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = md5.cpp; sourceTree = "<group>"; };
+ 2ACF56B114776A1E00991ED5 /* md5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = md5.h; sourceTree = "<group>"; };
+ 2ACF56B214776A1E00991ED5 /* Mutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Mutex.h; sourceTree = "<group>"; };
+ 2ACF56B314776A1E00991ED5 /* OCIOYaml.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OCIOYaml.cpp; sourceTree = "<group>"; };
+ 2ACF56B414776A1E00991ED5 /* OCIOYaml.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCIOYaml.h; sourceTree = "<group>"; };
+ 2ACF56B514776A1E00991ED5 /* Op.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Op.cpp; sourceTree = "<group>"; };
+ 2ACF56B614776A1E00991ED5 /* Op.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Op.h; sourceTree = "<group>"; };
+ 2ACF56B714776A1E00991ED5 /* OpBuilders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpBuilders.h; sourceTree = "<group>"; };
+ 2ACF56B814776A1E00991ED5 /* ParseUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParseUtils.cpp; sourceTree = "<group>"; };
+ 2ACF56B914776A1E00991ED5 /* ParseUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParseUtils.h; sourceTree = "<group>"; };
+ 2ACF56BA14776A1E00991ED5 /* PathUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PathUtils.cpp; sourceTree = "<group>"; };
+ 2ACF56BB14776A1E00991ED5 /* PathUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PathUtils.h; sourceTree = "<group>"; };
+ 2ACF56BC14776A1E00991ED5 /* Platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Platform.h; sourceTree = "<group>"; };
+ 2ACF56BD14776A1E00991ED5 /* PrivateTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrivateTypes.h; sourceTree = "<group>"; };
+ 2ACF56BE14776A1E00991ED5 /* Processor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Processor.cpp; sourceTree = "<group>"; };
+ 2ACF56BF14776A1E00991ED5 /* Processor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Processor.h; sourceTree = "<group>"; };
+ 2ACF56C114776A1E00991ED5 /* pystring.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pystring.cpp; sourceTree = "<group>"; };
+ 2ACF56C214776A1E00991ED5 /* pystring.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pystring.h; sourceTree = "<group>"; };
+ 2ACF56C314776A1E00991ED5 /* ScanlineHelper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScanlineHelper.cpp; sourceTree = "<group>"; };
+ 2ACF56C414776A1E00991ED5 /* ScanlineHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScanlineHelper.h; sourceTree = "<group>"; };
+ 2ACF56C514776A1E00991ED5 /* SSE.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSE.h; sourceTree = "<group>"; };
+ 2ACF56C614776A1E00991ED5 /* Transform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Transform.cpp; sourceTree = "<group>"; };
+ 2ACF56C714776A1E00991ED5 /* TruelightOp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TruelightOp.cpp; sourceTree = "<group>"; };
+ 2ACF56C814776A1E00991ED5 /* TruelightOp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TruelightOp.h; sourceTree = "<group>"; };
+ 2ACF56C914776A1E00991ED5 /* TruelightTransform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TruelightTransform.cpp; sourceTree = "<group>"; };
+ 2ACF56CA14776A1E00991ED5 /* UnitTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnitTest.cpp; sourceTree = "<group>"; };
+ 2ACF56CB14776A1E00991ED5 /* UnitTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnitTest.h; sourceTree = "<group>"; };
+ 2ACF573E14776B7000991ED5 /* OpenColorABI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenColorABI.h; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 2ACF566F14776A0A00991ED5 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 034768DDFF38A45A11DB9C8B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF567114776A0A00991ED5 /* libOpenColorIO.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 0867D691FE84028FC02AAC07 /* OpenColorIO */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF573E14776B7000991ED5 /* OpenColorABI.h */,
+ 2ACF567514776A1E00991ED5 /* core */,
+ 034768DDFF38A45A11DB9C8B /* Products */,
+ );
+ name = OpenColorIO;
+ sourceTree = "<group>";
+ };
+ 2ACF567514776A1E00991ED5 /* core */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF567614776A1E00991ED5 /* AllocationOp.cpp */,
+ 2ACF567714776A1E00991ED5 /* AllocationOp.h */,
+ 2ACF567814776A1E00991ED5 /* AllocationTransform.cpp */,
+ 2ACF567914776A1E00991ED5 /* Baker.cpp */,
+ 2ACF567A14776A1E00991ED5 /* Caching.cpp */,
+ 2ACF567B14776A1E00991ED5 /* CDLTransform.cpp */,
+ 2ACF567C14776A1E00991ED5 /* CDLTransform.h */,
+ 2ACF567D14776A1E00991ED5 /* ColorSpace.cpp */,
+ 2ACF567E14776A1E00991ED5 /* ColorSpaceTransform.cpp */,
+ 2ACF567F14776A1E00991ED5 /* Config.cpp */,
+ 2ACF568014776A1E00991ED5 /* Context.cpp */,
+ 2ACF568114776A1E00991ED5 /* DisplayTransform.cpp */,
+ 2ACF568214776A1E00991ED5 /* Exception.cpp */,
+ 2ACF568314776A1E00991ED5 /* ExponentOps.cpp */,
+ 2ACF568414776A1E00991ED5 /* ExponentOps.h */,
+ 2ACF568514776A1E00991ED5 /* ExponentTransform.cpp */,
+ 2ACF568614776A1E00991ED5 /* FileFormat3DL.cpp */,
+ 2ACF568714776A1E00991ED5 /* FileFormatCC.cpp */,
+ 2ACF568814776A1E00991ED5 /* FileFormatCCC.cpp */,
+ 2ACF568914776A1E00991ED5 /* FileFormatCSP.cpp */,
+ 2ACF568A14776A1E00991ED5 /* FileFormatHDL.cpp */,
+ 2ACF568B14776A1E00991ED5 /* FileFormatIridasCube.cpp */,
+ 2ACF568C14776A1E00991ED5 /* FileFormatIridasItx.cpp */,
+ 2A7CACB515536CD700F52C98 /* FileFormatIridasLook.cpp */,
+ 2ACF568D14776A1E00991ED5 /* FileFormatPandora.cpp */,
+ 2ACF568E14776A1E00991ED5 /* FileFormatSpi1D.cpp */,
+ 2ACF568F14776A1E00991ED5 /* FileFormatSpi3D.cpp */,
+ 2ACF569014776A1E00991ED5 /* FileFormatSpiMtx.cpp */,
+ 2ACF569114776A1E00991ED5 /* FileFormatTruelight.cpp */,
+ 2ACF569214776A1E00991ED5 /* FileFormatVF.cpp */,
+ 2ACF569314776A1E00991ED5 /* FileTransform.cpp */,
+ 2ACF569414776A1E00991ED5 /* FileTransform.h */,
+ 2ACF569614776A1E00991ED5 /* GpuShaderDesc.cpp */,
+ 2ACF569714776A1E00991ED5 /* GpuShaderUtils.cpp */,
+ 2ACF569814776A1E00991ED5 /* GpuShaderUtils.h */,
+ 2ACF569914776A1E00991ED5 /* GroupTransform.cpp */,
+ 2ACF569A14776A1E00991ED5 /* HashUtils.cpp */,
+ 2ACF569B14776A1E00991ED5 /* HashUtils.h */,
+ 2ACF569C14776A1E00991ED5 /* ImageDesc.cpp */,
+ 2ACF569D14776A1E00991ED5 /* ImagePacking.cpp */,
+ 2ACF569E14776A1E00991ED5 /* ImagePacking.h */,
+ 2ACF569F14776A1E00991ED5 /* Logging.cpp */,
+ 2ACF56A014776A1E00991ED5 /* Logging.h */,
+ 2ACF56A114776A1E00991ED5 /* LogOps.cpp */,
+ 2ACF56A214776A1E00991ED5 /* LogOps.h */,
+ 2A7CACB615536CD700F52C98 /* LookParse.cpp */,
+ 2A7CACB715536CD700F52C98 /* LookParse.h */,
+ 2ACF56A314776A1E00991ED5 /* LogTransform.cpp */,
+ 2ACF56A414776A1E00991ED5 /* Look.cpp */,
+ 2ACF56A514776A1E00991ED5 /* LookTransform.cpp */,
+ 2ACF56A614776A1E00991ED5 /* Lut1DOp.cpp */,
+ 2ACF56A714776A1E00991ED5 /* Lut1DOp.h */,
+ 2ACF56A814776A1E00991ED5 /* Lut3DOp.cpp */,
+ 2ACF56A914776A1E00991ED5 /* Lut3DOp.h */,
+ 2ACF56AA14776A1E00991ED5 /* MathUtils.cpp */,
+ 2ACF56AB14776A1E00991ED5 /* MathUtils.h */,
+ 2ACF56AC14776A1E00991ED5 /* MatrixOps.cpp */,
+ 2ACF56AD14776A1E00991ED5 /* MatrixOps.h */,
+ 2ACF56AE14776A1E00991ED5 /* MatrixTransform.cpp */,
+ 2ACF56AF14776A1E00991ED5 /* md5 */,
+ 2ACF56B214776A1E00991ED5 /* Mutex.h */,
+ 2A7CACB815536CD700F52C98 /* NoOps.cpp */,
+ 2A7CACB915536CD700F52C98 /* NoOps.h */,
+ 2ACF56B314776A1E00991ED5 /* OCIOYaml.cpp */,
+ 2ACF56B414776A1E00991ED5 /* OCIOYaml.h */,
+ 2ACF56B514776A1E00991ED5 /* Op.cpp */,
+ 2ACF56B614776A1E00991ED5 /* Op.h */,
+ 2ACF56B714776A1E00991ED5 /* OpBuilders.h */,
+ 2A7CACBA15536CD700F52C98 /* OpOptimizers.cpp */,
+ 2ACF56B814776A1E00991ED5 /* ParseUtils.cpp */,
+ 2ACF56B914776A1E00991ED5 /* ParseUtils.h */,
+ 2ACF56BA14776A1E00991ED5 /* PathUtils.cpp */,
+ 2ACF56BB14776A1E00991ED5 /* PathUtils.h */,
+ 2ACF56BC14776A1E00991ED5 /* Platform.h */,
+ 2ACF56BD14776A1E00991ED5 /* PrivateTypes.h */,
+ 2ACF56BE14776A1E00991ED5 /* Processor.cpp */,
+ 2ACF56BF14776A1E00991ED5 /* Processor.h */,
+ 2ACF56C014776A1E00991ED5 /* pystring */,
+ 2ACF56C314776A1E00991ED5 /* ScanlineHelper.cpp */,
+ 2ACF56C414776A1E00991ED5 /* ScanlineHelper.h */,
+ 2ACF56C514776A1E00991ED5 /* SSE.h */,
+ 2ACF56C614776A1E00991ED5 /* Transform.cpp */,
+ 2ACF56C714776A1E00991ED5 /* TruelightOp.cpp */,
+ 2ACF56C814776A1E00991ED5 /* TruelightOp.h */,
+ 2ACF56C914776A1E00991ED5 /* TruelightTransform.cpp */,
+ 2ACF56CA14776A1E00991ED5 /* UnitTest.cpp */,
+ 2ACF56CB14776A1E00991ED5 /* UnitTest.h */,
+ );
+ name = core;
+ path = ../../core;
+ sourceTree = SOURCE_ROOT;
+ };
+ 2ACF56AF14776A1E00991ED5 /* md5 */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF56B014776A1E00991ED5 /* md5.cpp */,
+ 2ACF56B114776A1E00991ED5 /* md5.h */,
+ );
+ path = md5;
+ sourceTree = "<group>";
+ };
+ 2ACF56C014776A1E00991ED5 /* pystring */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF56C114776A1E00991ED5 /* pystring.cpp */,
+ 2ACF56C214776A1E00991ED5 /* pystring.h */,
+ );
+ path = pystring;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 2ACF566D14776A0A00991ED5 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2ACF56CD14776A1E00991ED5 /* AllocationOp.h in Headers */,
+ 2ACF56D214776A1E00991ED5 /* CDLTransform.h in Headers */,
+ 2ACF56DA14776A1E00991ED5 /* ExponentOps.h in Headers */,
+ 2ACF56EA14776A1E00991ED5 /* FileTransform.h in Headers */,
+ 2ACF56EE14776A1E00991ED5 /* GpuShaderUtils.h in Headers */,
+ 2ACF56F114776A1E00991ED5 /* HashUtils.h in Headers */,
+ 2ACF56F414776A1E00991ED5 /* ImagePacking.h in Headers */,
+ 2ACF56F614776A1E00991ED5 /* Logging.h in Headers */,
+ 2ACF56F814776A1E00991ED5 /* LogOps.h in Headers */,
+ 2ACF56FD14776A1E00991ED5 /* Lut1DOp.h in Headers */,
+ 2ACF56FF14776A1E00991ED5 /* Lut3DOp.h in Headers */,
+ 2ACF570114776A1E00991ED5 /* MathUtils.h in Headers */,
+ 2ACF570314776A1E00991ED5 /* MatrixOps.h in Headers */,
+ 2ACF570614776A1E00991ED5 /* md5.h in Headers */,
+ 2ACF570714776A1E00991ED5 /* Mutex.h in Headers */,
+ 2ACF570914776A1E00991ED5 /* OCIOYaml.h in Headers */,
+ 2ACF570B14776A1E00991ED5 /* Op.h in Headers */,
+ 2ACF570C14776A1E00991ED5 /* OpBuilders.h in Headers */,
+ 2ACF570E14776A1E00991ED5 /* ParseUtils.h in Headers */,
+ 2ACF571014776A1E00991ED5 /* PathUtils.h in Headers */,
+ 2ACF571114776A1E00991ED5 /* Platform.h in Headers */,
+ 2ACF571214776A1E00991ED5 /* PrivateTypes.h in Headers */,
+ 2ACF571414776A1E00991ED5 /* Processor.h in Headers */,
+ 2ACF571614776A1E00991ED5 /* pystring.h in Headers */,
+ 2ACF571814776A1E00991ED5 /* ScanlineHelper.h in Headers */,
+ 2ACF571914776A1E00991ED5 /* SSE.h in Headers */,
+ 2ACF571C14776A1E00991ED5 /* TruelightOp.h in Headers */,
+ 2ACF571F14776A1E00991ED5 /* UnitTest.h in Headers */,
+ 2ACF573F14776B7000991ED5 /* OpenColorABI.h in Headers */,
+ 2A7CACBD15536CD700F52C98 /* LookParse.h in Headers */,
+ 2A7CACBF15536CD700F52C98 /* NoOps.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 2ACF567014776A0A00991ED5 /* OpenColorIO */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2ACF567414776A1300991ED5 /* Build configuration list for PBXNativeTarget "OpenColorIO" */;
+ buildPhases = (
+ 2ACF566D14776A0A00991ED5 /* Headers */,
+ 2ACF566E14776A0A00991ED5 /* Sources */,
+ 2ACF566F14776A0A00991ED5 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = OpenColorIO;
+ productName = OpenColorIO;
+ productReference = 2ACF567114776A0A00991ED5 /* libOpenColorIO.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 0867D690FE84028FC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 1DEB916408733D950010E9CD /* Build configuration list for PBXProject "OpenColorIO" */;
+ compatibilityVersion = "Xcode 3.1";
+ developmentRegion = English;
+ hasScannedForEncodings = 1;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
+ mainGroup = 0867D691FE84028FC02AAC07 /* OpenColorIO */;
+ productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 2ACF567014776A0A00991ED5 /* OpenColorIO */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 2ACF566E14776A0A00991ED5 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2ACF56CC14776A1E00991ED5 /* AllocationOp.cpp in Sources */,
+ 2ACF56CE14776A1E00991ED5 /* AllocationTransform.cpp in Sources */,
+ 2ACF56CF14776A1E00991ED5 /* Baker.cpp in Sources */,
+ 2ACF56D014776A1E00991ED5 /* Caching.cpp in Sources */,
+ 2ACF56D114776A1E00991ED5 /* CDLTransform.cpp in Sources */,
+ 2ACF56D314776A1E00991ED5 /* ColorSpace.cpp in Sources */,
+ 2ACF56D414776A1E00991ED5 /* ColorSpaceTransform.cpp in Sources */,
+ 2ACF56D514776A1E00991ED5 /* Config.cpp in Sources */,
+ 2ACF56D614776A1E00991ED5 /* Context.cpp in Sources */,
+ 2ACF56D714776A1E00991ED5 /* DisplayTransform.cpp in Sources */,
+ 2ACF56D814776A1E00991ED5 /* Exception.cpp in Sources */,
+ 2ACF56D914776A1E00991ED5 /* ExponentOps.cpp in Sources */,
+ 2ACF56DB14776A1E00991ED5 /* ExponentTransform.cpp in Sources */,
+ 2ACF56DC14776A1E00991ED5 /* FileFormat3DL.cpp in Sources */,
+ 2ACF56DD14776A1E00991ED5 /* FileFormatCC.cpp in Sources */,
+ 2ACF56DE14776A1E00991ED5 /* FileFormatCCC.cpp in Sources */,
+ 2ACF56DF14776A1E00991ED5 /* FileFormatCSP.cpp in Sources */,
+ 2ACF56E014776A1E00991ED5 /* FileFormatHDL.cpp in Sources */,
+ 2ACF56E114776A1E00991ED5 /* FileFormatIridasCube.cpp in Sources */,
+ 2ACF56E214776A1E00991ED5 /* FileFormatIridasItx.cpp in Sources */,
+ 2ACF56E314776A1E00991ED5 /* FileFormatPandora.cpp in Sources */,
+ 2ACF56E414776A1E00991ED5 /* FileFormatSpi1D.cpp in Sources */,
+ 2ACF56E514776A1E00991ED5 /* FileFormatSpi3D.cpp in Sources */,
+ 2ACF56E614776A1E00991ED5 /* FileFormatSpiMtx.cpp in Sources */,
+ 2ACF56E714776A1E00991ED5 /* FileFormatTruelight.cpp in Sources */,
+ 2ACF56E814776A1E00991ED5 /* FileFormatVF.cpp in Sources */,
+ 2ACF56E914776A1E00991ED5 /* FileTransform.cpp in Sources */,
+ 2ACF56EC14776A1E00991ED5 /* GpuShaderDesc.cpp in Sources */,
+ 2ACF56ED14776A1E00991ED5 /* GpuShaderUtils.cpp in Sources */,
+ 2ACF56EF14776A1E00991ED5 /* GroupTransform.cpp in Sources */,
+ 2ACF56F014776A1E00991ED5 /* HashUtils.cpp in Sources */,
+ 2ACF56F214776A1E00991ED5 /* ImageDesc.cpp in Sources */,
+ 2ACF56F314776A1E00991ED5 /* ImagePacking.cpp in Sources */,
+ 2ACF56F514776A1E00991ED5 /* Logging.cpp in Sources */,
+ 2ACF56F714776A1E00991ED5 /* LogOps.cpp in Sources */,
+ 2ACF56F914776A1E00991ED5 /* LogTransform.cpp in Sources */,
+ 2ACF56FA14776A1E00991ED5 /* Look.cpp in Sources */,
+ 2ACF56FB14776A1E00991ED5 /* LookTransform.cpp in Sources */,
+ 2ACF56FC14776A1E00991ED5 /* Lut1DOp.cpp in Sources */,
+ 2ACF56FE14776A1E00991ED5 /* Lut3DOp.cpp in Sources */,
+ 2ACF570014776A1E00991ED5 /* MathUtils.cpp in Sources */,
+ 2ACF570214776A1E00991ED5 /* MatrixOps.cpp in Sources */,
+ 2ACF570414776A1E00991ED5 /* MatrixTransform.cpp in Sources */,
+ 2ACF570514776A1E00991ED5 /* md5.cpp in Sources */,
+ 2ACF570814776A1E00991ED5 /* OCIOYaml.cpp in Sources */,
+ 2ACF570A14776A1E00991ED5 /* Op.cpp in Sources */,
+ 2ACF570D14776A1E00991ED5 /* ParseUtils.cpp in Sources */,
+ 2ACF570F14776A1E00991ED5 /* PathUtils.cpp in Sources */,
+ 2ACF571314776A1E00991ED5 /* Processor.cpp in Sources */,
+ 2ACF571514776A1E00991ED5 /* pystring.cpp in Sources */,
+ 2ACF571714776A1E00991ED5 /* ScanlineHelper.cpp in Sources */,
+ 2ACF571A14776A1E00991ED5 /* Transform.cpp in Sources */,
+ 2ACF571B14776A1E00991ED5 /* TruelightOp.cpp in Sources */,
+ 2ACF571D14776A1E00991ED5 /* TruelightTransform.cpp in Sources */,
+ 2ACF571E14776A1E00991ED5 /* UnitTest.cpp in Sources */,
+ 2A7CACBB15536CD700F52C98 /* FileFormatIridasLook.cpp in Sources */,
+ 2A7CACBC15536CD700F52C98 /* LookParse.cpp in Sources */,
+ 2A7CACBE15536CD700F52C98 /* NoOps.cpp in Sources */,
+ 2A7CACC015536CD700F52C98 /* OpOptimizers.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 1DEB916508733D950010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = TIXML_USE_STL;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ ../../../export,
+ ../../../ext/tinyxml,
+ "../../../ext/yaml-cpp/include",
+ );
+ ONLY_ACTIVE_ARCH = YES;
+ PREBINDING = NO;
+ SDKROOT = macosx10.5;
+ };
+ name = Debug;
+ };
+ 1DEB916608733D950010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ NDEBUG,
+ TIXML_USE_STL,
+ );
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ ../../../export,
+ ../../../ext/tinyxml,
+ "../../../ext/yaml-cpp/include",
+ );
+ PREBINDING = NO;
+ SDKROOT = macosx10.5;
+ };
+ name = Release;
+ };
+ 2ACF567214776A0A00991ED5 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ INSTALL_PATH = /usr/local/lib;
+ PREBINDING = NO;
+ PRODUCT_NAME = OpenColorIO;
+ };
+ name = Debug;
+ };
+ 2ACF567314776A0A00991ED5 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/local/lib;
+ PREBINDING = NO;
+ PRODUCT_NAME = OpenColorIO;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1DEB916408733D950010E9CD /* Build configuration list for PBXProject "OpenColorIO" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB916508733D950010E9CD /* Debug */,
+ 1DEB916608733D950010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 2ACF567414776A1300991ED5 /* Build configuration list for PBXNativeTarget "OpenColorIO" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2ACF567214776A0A00991ED5 /* Debug */,
+ 2ACF567314776A0A00991ED5 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
+}
diff --git a/src/aftereffects/xcode/aftereffects/OpenColorIO_AE.xcodeproj/project.pbxproj b/src/aftereffects/xcode/aftereffects/OpenColorIO_AE.xcodeproj/project.pbxproj
new file mode 100755
index 0000000..84253ae
--- /dev/null
+++ b/src/aftereffects/xcode/aftereffects/OpenColorIO_AE.xcodeproj/project.pbxproj
@@ -0,0 +1,509 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 44;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 2A180A6914801EB90000D11A /* OpenColorIO_AE_MonitorProfileChooser.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2A180A6814801EB90000D11A /* OpenColorIO_AE_MonitorProfileChooser.xib */; };
+ 2A180A6D14801FFA0000D11A /* OpenColorIO_AE_MonitorProfileChooser_Controller.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A180A6B14801FFA0000D11A /* OpenColorIO_AE_MonitorProfileChooser_Controller.m */; };
+ 2A3BAA7110C0F40600AD32F2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A3BAA7010C0F40600AD32F2 /* Cocoa.framework */; };
+ 2A4A0AF61554679400D5AEB7 /* ocioicc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A4A0AF41554679400D5AEB7 /* ocioicc.cpp */; };
+ 2A60CADB1491A51C009D6DBF /* OpenColorIO_AE_GL_Cocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2A60CADA1491A51C009D6DBF /* OpenColorIO_AE_GL_Cocoa.mm */; };
+ 2A60CB091491A9FF009D6DBF /* AGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A60CB081491A9FF009D6DBF /* AGL.framework */; };
+ 2A60CB0B1491A9FF009D6DBF /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A60CB0A1491A9FF009D6DBF /* OpenGL.framework */; };
+ 2AF56B96147A431100F9968C /* OpenColorIO_AE_ArbData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2AF56B8F147A431100F9968C /* OpenColorIO_AE_ArbData.cpp */; };
+ 2AF56B99147A431100F9968C /* OpenColorIO_AE_PiPL.r in Rez */ = {isa = PBXBuildFile; fileRef = 2AF56B92147A431100F9968C /* OpenColorIO_AE_PiPL.r */; };
+ 2AF56B9A147A431100F9968C /* OpenColorIO_AE_UI.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2AF56B93147A431100F9968C /* OpenColorIO_AE_UI.cpp */; };
+ 2AF56B9B147A431100F9968C /* OpenColorIO_AE.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2AF56B94147A431100F9968C /* OpenColorIO_AE.cpp */; };
+ 2AF56BA0147A458800F9968C /* AEGP_SuiteHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2AF56B9D147A458800F9968C /* AEGP_SuiteHandler.cpp */; };
+ 2AF56BA1147A458800F9968C /* MissingSuiteError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2AF56B9F147A458800F9968C /* MissingSuiteError.cpp */; };
+ 2AF56C24147A54A300F9968C /* OpenColorIO_AE_Dialogs_Cocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2AF56B90147A431100F9968C /* OpenColorIO_AE_Dialogs_Cocoa.mm */; };
+ 2AF56D06147AB5C900F9968C /* DrawbotBot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2AF56D04147AB5C900F9968C /* DrawbotBot.cpp */; };
+ 2AF56EE8147AD11200F9968C /* libOpenColorIO.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AF56EE7147AD10E00F9968C /* libOpenColorIO.a */; };
+ 2AF57004147AE17200F9968C /* libtinyxml.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AF56FFB147AE16A00F9968C /* libtinyxml.a */; };
+ 2AF57005147AE17400F9968C /* libyaml.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AF57001147AE16A00F9968C /* libyaml.a */; };
+ 2AF57B93147C6FE000F9968C /* OpenColorIO_AE_Menu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AF57B92147C6FE000F9968C /* OpenColorIO_AE_Menu.m */; };
+ 2AF57D20147C994100F9968C /* OpenColorIO_AE_Context.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2AF57D1F147C994100F9968C /* OpenColorIO_AE_Context.cpp */; };
+ 2AF999CB147E1DD200FEB83B /* liblcms.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AF999C8147E1DCA00FEB83B /* liblcms.a */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 2AF56EE6147AD10E00F9968C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 2AF56EE2147AD10E00F9968C /* OpenColorIO.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 2ACF567114776A0A00991ED5;
+ remoteInfo = OpenColorIO;
+ };
+ 2AF56FFA147AE16A00F9968C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 2AF56FF0147AE16A00F9968C /* tinyxml.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 2ACF55441477682B00991ED5;
+ remoteInfo = tinyxml;
+ };
+ 2AF57000147AE16A00F9968C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 2AF56FF3147AE16A00F9968C /* yaml.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 2ACF559C1477692300991ED5;
+ remoteInfo = yaml;
+ };
+ 2AF57012147AE18600F9968C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 2AF56FF0147AE16A00F9968C /* tinyxml.xcodeproj */;
+ proxyType = 1;
+ remoteGlobalIDString = 2ACF55431477682B00991ED5;
+ remoteInfo = tinyxml;
+ };
+ 2AF57014147AE18600F9968C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 2AF56FF3147AE16A00F9968C /* yaml.xcodeproj */;
+ proxyType = 1;
+ remoteGlobalIDString = 2ACF559B1477692300991ED5;
+ remoteInfo = yaml;
+ };
+ 2AF57016147AE18600F9968C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 2AF56EE2147AD10E00F9968C /* OpenColorIO.xcodeproj */;
+ proxyType = 1;
+ remoteGlobalIDString = 2ACF567014776A0A00991ED5;
+ remoteInfo = OpenColorIO;
+ };
+ 2AF999C7147E1DCA00FEB83B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 2AF999C0147E1DCA00FEB83B /* lcms.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 2ACF9E56147824F500991ED5;
+ remoteInfo = lcms;
+ };
+ 2AF999CC147E1DDB00FEB83B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 2AF999C0147E1DCA00FEB83B /* lcms.xcodeproj */;
+ proxyType = 1;
+ remoteGlobalIDString = 2ACF9E55147824F500991ED5;
+ remoteInfo = lcms;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 2A180A6814801EB90000D11A /* OpenColorIO_AE_MonitorProfileChooser.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = OpenColorIO_AE_MonitorProfileChooser.xib; path = ../../mac/OpenColorIO_AE_MonitorProfileChooser.xib; sourceTree = "<group>"; };
+ 2A180A6B14801FFA0000D11A /* OpenColorIO_AE_MonitorProfileChooser_Controller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OpenColorIO_AE_MonitorProfileChooser_Controller.m; path = ../../mac/OpenColorIO_AE_MonitorProfileChooser_Controller.m; sourceTree = "<group>"; usesTabs = 0; };
+ 2A180A6C14801FFA0000D11A /* OpenColorIO_AE_MonitorProfileChooser_Controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OpenColorIO_AE_MonitorProfileChooser_Controller.h; path = ../../mac/OpenColorIO_AE_MonitorProfileChooser_Controller.h; sourceTree = "<group>"; usesTabs = 0; };
+ 2A3BAA7010C0F40600AD32F2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
+ 2A4A0AF41554679400D5AEB7 /* ocioicc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ocioicc.cpp; path = ../../../apps/ociobakelut/ocioicc.cpp; sourceTree = SOURCE_ROOT; };
+ 2A4A0AF51554679400D5AEB7 /* ocioicc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ocioicc.h; path = ../../../apps/ociobakelut/ocioicc.h; sourceTree = SOURCE_ROOT; };
+ 2A60CAD91491A506009D6DBF /* OpenColorIO_AE_GL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OpenColorIO_AE_GL.h; path = ../../OpenColorIO_AE_GL.h; sourceTree = SOURCE_ROOT; usesTabs = 0; };
+ 2A60CADA1491A51C009D6DBF /* OpenColorIO_AE_GL_Cocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = OpenColorIO_AE_GL_Cocoa.mm; path = ../../mac/OpenColorIO_AE_GL_Cocoa.mm; sourceTree = SOURCE_ROOT; usesTabs = 0; };
+ 2A60CB081491A9FF009D6DBF /* AGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AGL.framework; path = System/Library/Frameworks/AGL.framework; sourceTree = SDKROOT; };
+ 2A60CB0A1491A9FF009D6DBF /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
+ 2AF56B8F147A431100F9968C /* OpenColorIO_AE_ArbData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OpenColorIO_AE_ArbData.cpp; path = ../../OpenColorIO_AE_ArbData.cpp; sourceTree = SOURCE_ROOT; usesTabs = 0; };
+ 2AF56B90147A431100F9968C /* OpenColorIO_AE_Dialogs_Cocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = OpenColorIO_AE_Dialogs_Cocoa.mm; path = ../../mac/OpenColorIO_AE_Dialogs_Cocoa.mm; sourceTree = SOURCE_ROOT; usesTabs = 0; };
+ 2AF56B92147A431100F9968C /* OpenColorIO_AE_PiPL.r */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.rez; name = OpenColorIO_AE_PiPL.r; path = ../../OpenColorIO_AE_PiPL.r; sourceTree = SOURCE_ROOT; usesTabs = 0; };
+ 2AF56B93147A431100F9968C /* OpenColorIO_AE_UI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OpenColorIO_AE_UI.cpp; path = ../../OpenColorIO_AE_UI.cpp; sourceTree = SOURCE_ROOT; usesTabs = 0; };
+ 2AF56B94147A431100F9968C /* OpenColorIO_AE.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OpenColorIO_AE.cpp; path = ../../OpenColorIO_AE.cpp; sourceTree = SOURCE_ROOT; usesTabs = 0; };
+ 2AF56B95147A431100F9968C /* OpenColorIO_AE.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OpenColorIO_AE.h; path = ../../OpenColorIO_AE.h; sourceTree = SOURCE_ROOT; usesTabs = 0; };
+ 2AF56B9D147A458800F9968C /* AEGP_SuiteHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AEGP_SuiteHandler.cpp; path = "../../../../ext/Adobe After Effects CS5 SDK/Examples/Util/AEGP_SuiteHandler.cpp"; sourceTree = SOURCE_ROOT; usesTabs = 0; };
+ 2AF56B9E147A458800F9968C /* AEGP_SuiteHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AEGP_SuiteHandler.h; path = "../../../../ext/Adobe After Effects CS5 SDK/Examples/Util/AEGP_SuiteHandler.h"; sourceTree = SOURCE_ROOT; usesTabs = 0; };
+ 2AF56B9F147A458800F9968C /* MissingSuiteError.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MissingSuiteError.cpp; path = "../../../../ext/Adobe After Effects CS5 SDK/Examples/Util/MissingSuiteError.cpp"; sourceTree = SOURCE_ROOT; usesTabs = 0; };
+ 2AF56D04147AB5C900F9968C /* DrawbotBot.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DrawbotBot.cpp; path = ../../DrawbotBot.cpp; sourceTree = SOURCE_ROOT; usesTabs = 0; };
+ 2AF56D05147AB5C900F9968C /* DrawbotBot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DrawbotBot.h; path = ../../DrawbotBot.h; sourceTree = SOURCE_ROOT; usesTabs = 0; };
+ 2AF56EE2147AD10E00F9968C /* OpenColorIO.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = OpenColorIO.xcodeproj; path = ../OpenColorIO.xcodeproj; sourceTree = SOURCE_ROOT; };
+ 2AF56FF0147AE16A00F9968C /* tinyxml.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = tinyxml.xcodeproj; path = ../ext/tinyxml.xcodeproj; sourceTree = SOURCE_ROOT; };
+ 2AF56FF3147AE16A00F9968C /* yaml.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = yaml.xcodeproj; path = ../ext/yaml.xcodeproj; sourceTree = SOURCE_ROOT; };
+ 2AF57171147B36F300F9968C /* OpenColorIO_AE_Dialogs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OpenColorIO_AE_Dialogs.h; path = ../../OpenColorIO_AE_Dialogs.h; sourceTree = SOURCE_ROOT; usesTabs = 0; };
+ 2AF57B91147C6FE000F9968C /* OpenColorIO_AE_Menu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OpenColorIO_AE_Menu.h; path = ../../mac/OpenColorIO_AE_Menu.h; sourceTree = "<group>"; usesTabs = 0; };
+ 2AF57B92147C6FE000F9968C /* OpenColorIO_AE_Menu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OpenColorIO_AE_Menu.m; path = ../../mac/OpenColorIO_AE_Menu.m; sourceTree = "<group>"; usesTabs = 0; };
+ 2AF57D1E147C994100F9968C /* OpenColorIO_AE_Context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OpenColorIO_AE_Context.h; path = ../../OpenColorIO_AE_Context.h; sourceTree = SOURCE_ROOT; usesTabs = 0; };
+ 2AF57D1F147C994100F9968C /* OpenColorIO_AE_Context.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OpenColorIO_AE_Context.cpp; path = ../../OpenColorIO_AE_Context.cpp; sourceTree = SOURCE_ROOT; usesTabs = 0; };
+ 2AF999C0147E1DCA00FEB83B /* lcms.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = lcms.xcodeproj; path = ../ext/lcms.xcodeproj; sourceTree = SOURCE_ROOT; };
+ C4E618CC095A3CE80012CA3F /* OpenColorIO.plugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OpenColorIO.plugin; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ C4E618CA095A3CE80012CA3F /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2A3BAA7110C0F40600AD32F2 /* Cocoa.framework in Frameworks */,
+ 2AF56EE8147AD11200F9968C /* libOpenColorIO.a in Frameworks */,
+ 2AF57004147AE17200F9968C /* libtinyxml.a in Frameworks */,
+ 2AF57005147AE17400F9968C /* libyaml.a in Frameworks */,
+ 2AF999CB147E1DD200FEB83B /* liblcms.a in Frameworks */,
+ 2A60CB091491A9FF009D6DBF /* AGL.framework in Frameworks */,
+ 2A60CB0B1491A9FF009D6DBF /* OpenGL.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 2AF56EE3147AD10E00F9968C /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 2AF56EE7147AD10E00F9968C /* libOpenColorIO.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 2AF56FF1147AE16A00F9968C /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 2AF56FFB147AE16A00F9968C /* libtinyxml.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 2AF56FF4147AE16A00F9968C /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 2AF57001147AE16A00F9968C /* libyaml.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 2AF999C1147E1DCA00FEB83B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 2AF999C8147E1DCA00FEB83B /* liblcms.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ C4E6187C095A3C800012CA3F = {
+ isa = PBXGroup;
+ children = (
+ 2AF56B95147A431100F9968C /* OpenColorIO_AE.h */,
+ 2AF56B94147A431100F9968C /* OpenColorIO_AE.cpp */,
+ 2AF57D1E147C994100F9968C /* OpenColorIO_AE_Context.h */,
+ 2AF57D1F147C994100F9968C /* OpenColorIO_AE_Context.cpp */,
+ 2AF56B8F147A431100F9968C /* OpenColorIO_AE_ArbData.cpp */,
+ 2AF56B93147A431100F9968C /* OpenColorIO_AE_UI.cpp */,
+ 2A60CAD91491A506009D6DBF /* OpenColorIO_AE_GL.h */,
+ 2A60CADA1491A51C009D6DBF /* OpenColorIO_AE_GL_Cocoa.mm */,
+ 2AF57171147B36F300F9968C /* OpenColorIO_AE_Dialogs.h */,
+ 2AF56B90147A431100F9968C /* OpenColorIO_AE_Dialogs_Cocoa.mm */,
+ 2AF57B91147C6FE000F9968C /* OpenColorIO_AE_Menu.h */,
+ 2AF57B92147C6FE000F9968C /* OpenColorIO_AE_Menu.m */,
+ 2AF56B92147A431100F9968C /* OpenColorIO_AE_PiPL.r */,
+ 2AF56B9E147A458800F9968C /* AEGP_SuiteHandler.h */,
+ 2AF56B9D147A458800F9968C /* AEGP_SuiteHandler.cpp */,
+ 2AF56B9F147A458800F9968C /* MissingSuiteError.cpp */,
+ 2AF56D05147AB5C900F9968C /* DrawbotBot.h */,
+ 2AF56D04147AB5C900F9968C /* DrawbotBot.cpp */,
+ 2A4A0AF51554679400D5AEB7 /* ocioicc.h */,
+ 2A4A0AF41554679400D5AEB7 /* ocioicc.cpp */,
+ 2A180A6814801EB90000D11A /* OpenColorIO_AE_MonitorProfileChooser.xib */,
+ 2A180A6C14801FFA0000D11A /* OpenColorIO_AE_MonitorProfileChooser_Controller.h */,
+ 2A180A6B14801FFA0000D11A /* OpenColorIO_AE_MonitorProfileChooser_Controller.m */,
+ 2AF56EE2147AD10E00F9968C /* OpenColorIO.xcodeproj */,
+ 2AF56FF0147AE16A00F9968C /* tinyxml.xcodeproj */,
+ 2AF56FF3147AE16A00F9968C /* yaml.xcodeproj */,
+ 2AF999C0147E1DCA00FEB83B /* lcms.xcodeproj */,
+ C4E6188C095A3C800012CA3F /* Products */,
+ 2A3BAA7010C0F40600AD32F2 /* Cocoa.framework */,
+ 2A60CB081491A9FF009D6DBF /* AGL.framework */,
+ 2A60CB0A1491A9FF009D6DBF /* OpenGL.framework */,
+ );
+ comments = "SDK Backwards is some pretty rudimentary audio processing, but the flags and params are handled in an appropriate manner.";
+ sourceTree = "<group>";
+ };
+ C4E6188C095A3C800012CA3F /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ C4E618CC095A3CE80012CA3F /* OpenColorIO.plugin */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ C4E618CB095A3CE80012CA3F /* OpenColorIO */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C4E618CE095A3CE90012CA3F /* Build configuration list for PBXNativeTarget "OpenColorIO" */;
+ buildPhases = (
+ C4E618C8095A3CE80012CA3F /* Resources */,
+ C4E618C9095A3CE80012CA3F /* Sources */,
+ C4E618CA095A3CE80012CA3F /* Frameworks */,
+ C4E618EA095A3E040012CA3F /* Rez */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 2AF57013147AE18600F9968C /* PBXTargetDependency */,
+ 2AF57015147AE18600F9968C /* PBXTargetDependency */,
+ 2AF57017147AE18600F9968C /* PBXTargetDependency */,
+ 2AF999CD147E1DDB00FEB83B /* PBXTargetDependency */,
+ );
+ name = OpenColorIO;
+ productName = SDK_Backwards.plugin;
+ productReference = C4E618CC095A3CE80012CA3F /* OpenColorIO.plugin */;
+ productType = "com.apple.product-type.bundle";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ C4E6187E095A3C800012CA3F /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = C4E6187F095A3C800012CA3F /* Build configuration list for PBXProject "OpenColorIO_AE" */;
+ compatibilityVersion = "Xcode 3.0";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
+ mainGroup = C4E6187C095A3C800012CA3F;
+ productRefGroup = C4E6188C095A3C800012CA3F /* Products */;
+ projectDirPath = "";
+ projectReferences = (
+ {
+ ProductGroup = 2AF999C1147E1DCA00FEB83B /* Products */;
+ ProjectRef = 2AF999C0147E1DCA00FEB83B /* lcms.xcodeproj */;
+ },
+ {
+ ProductGroup = 2AF56EE3147AD10E00F9968C /* Products */;
+ ProjectRef = 2AF56EE2147AD10E00F9968C /* OpenColorIO.xcodeproj */;
+ },
+ {
+ ProductGroup = 2AF56FF1147AE16A00F9968C /* Products */;
+ ProjectRef = 2AF56FF0147AE16A00F9968C /* tinyxml.xcodeproj */;
+ },
+ {
+ ProductGroup = 2AF56FF4147AE16A00F9968C /* Products */;
+ ProjectRef = 2AF56FF3147AE16A00F9968C /* yaml.xcodeproj */;
+ },
+ );
+ projectRoot = "";
+ targets = (
+ C4E618CB095A3CE80012CA3F /* OpenColorIO */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXReferenceProxy section */
+ 2AF56EE7147AD10E00F9968C /* libOpenColorIO.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libOpenColorIO.a;
+ remoteRef = 2AF56EE6147AD10E00F9968C /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 2AF56FFB147AE16A00F9968C /* libtinyxml.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libtinyxml.a;
+ remoteRef = 2AF56FFA147AE16A00F9968C /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 2AF57001147AE16A00F9968C /* libyaml.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libyaml.a;
+ remoteRef = 2AF57000147AE16A00F9968C /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 2AF999C8147E1DCA00FEB83B /* liblcms.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = liblcms.a;
+ remoteRef = 2AF999C7147E1DCA00FEB83B /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+/* End PBXReferenceProxy section */
+
+/* Begin PBXResourcesBuildPhase section */
+ C4E618C8095A3CE80012CA3F /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2A180A6914801EB90000D11A /* OpenColorIO_AE_MonitorProfileChooser.xib in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXRezBuildPhase section */
+ C4E618EA095A3E040012CA3F /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2AF56B99147A431100F9968C /* OpenColorIO_AE_PiPL.r in Rez */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXRezBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ C4E618C9095A3CE80012CA3F /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2AF56B96147A431100F9968C /* OpenColorIO_AE_ArbData.cpp in Sources */,
+ 2AF56B9A147A431100F9968C /* OpenColorIO_AE_UI.cpp in Sources */,
+ 2AF56B9B147A431100F9968C /* OpenColorIO_AE.cpp in Sources */,
+ 2AF56BA0147A458800F9968C /* AEGP_SuiteHandler.cpp in Sources */,
+ 2AF56BA1147A458800F9968C /* MissingSuiteError.cpp in Sources */,
+ 2AF56C24147A54A300F9968C /* OpenColorIO_AE_Dialogs_Cocoa.mm in Sources */,
+ 2AF56D06147AB5C900F9968C /* DrawbotBot.cpp in Sources */,
+ 2AF57B93147C6FE000F9968C /* OpenColorIO_AE_Menu.m in Sources */,
+ 2AF57D20147C994100F9968C /* OpenColorIO_AE_Context.cpp in Sources */,
+ 2A180A6D14801FFA0000D11A /* OpenColorIO_AE_MonitorProfileChooser_Controller.m in Sources */,
+ 2A60CADB1491A51C009D6DBF /* OpenColorIO_AE_GL_Cocoa.mm in Sources */,
+ 2A4A0AF61554679400D5AEB7 /* ocioicc.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 2AF57013147AE18600F9968C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ name = tinyxml;
+ targetProxy = 2AF57012147AE18600F9968C /* PBXContainerItemProxy */;
+ };
+ 2AF57015147AE18600F9968C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ name = yaml;
+ targetProxy = 2AF57014147AE18600F9968C /* PBXContainerItemProxy */;
+ };
+ 2AF57017147AE18600F9968C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ name = OpenColorIO;
+ targetProxy = 2AF57016147AE18600F9968C /* PBXContainerItemProxy */;
+ };
+ 2AF999CD147E1DDB00FEB83B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ name = lcms;
+ targetProxy = 2AF999CC147E1DDB00FEB83B /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 2A1BAC2310C3C82A00244D12 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ AE_SDK = "\"../../../../ext/Adobe After Effects CS5 SDK\"";
+ "AE_SDK[arch=i386]" = "\"../../../../ext/Adobe After Effects CS3 SDK\"";
+ "AE_SDK[arch=ppc]" = "\"../../../../ext/Adobe After Effects CS3 SDK\"";
+ ARCHS = x86_64;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_MODEL_TUNING = "";
+ GCC_OPTIMIZATION_LEVEL = 3;
+ GCC_PREPROCESSOR_DEFINITIONS = NDEBUG;
+ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
+ HEADER_SEARCH_PATHS = (
+ ../,
+ "$(AE_SDK)/Examples/Headers",
+ "$(AE_SDK)/Examples/Util",
+ "$(AE_SDK)/Examples/Headers/SP",
+ "$(AE_SDK)/Examples/Resources",
+ ../../../../export,
+ ../../../../src/core,
+ ../../../../ext/tinyxml,
+ "../../../../ext/yaml-cpp/include",
+ "../../../../ext/lcms2-2.1/include",
+ );
+ REZ_PREPROCESSOR_DEFINITIONS = __MACH__;
+ REZ_SEARCH_PATHS = "$(SDK_PATH)/Developer/Headers/FlatCarbon";
+ SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk";
+ };
+ name = Release;
+ };
+ 2A1BAC2410C3C82A00244D12 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "$(SDKROOT)/System/Library/Frameworks/Carbon.framework/Headers/Carbon.h";
+ GENERATE_PKGINFO_FILE = YES;
+ INFOPLIST_FILE = "../../mac/OpenColorIO_AE.plugin-Info.plist";
+ INSTALL_PATH = "$(HOME)/Library/Bundles";
+ LINK_WITH_STANDARD_LIBRARIES = YES;
+ PREBINDING = NO;
+ PRODUCT_NAME = OpenColorIO;
+ WRAPPER_EXTENSION = plugin;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ C4E61880095A3C800012CA3F /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ AE_SDK = "\"../../../../ext/Adobe After Effects CS5 SDK\"";
+ "AE_SDK[arch=i386]" = "\"../../../../ext/Adobe After Effects CS3 SDK\"";
+ "AE_SDK[arch=ppc]" = "\"../../../../ext/Adobe After Effects CS3 SDK\"";
+ ARCHS = x86_64;
+ COPY_PHASE_STRIP = NO;
+ GCC_MODEL_TUNING = "";
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
+ HEADER_SEARCH_PATHS = (
+ ../,
+ "$(AE_SDK)/Examples/Headers",
+ "$(AE_SDK)/Examples/Util",
+ "$(AE_SDK)/Examples/Headers/SP",
+ "$(AE_SDK)/Examples/Resources",
+ ../../../../export,
+ ../../../../src/core,
+ ../../../../ext/tinyxml,
+ "../../../../ext/yaml-cpp/include",
+ "../../../../ext/lcms2-2.1/include",
+ );
+ REZ_PREPROCESSOR_DEFINITIONS = __MACH__;
+ REZ_SEARCH_PATHS = "$(SDK_PATH)/Developer/Headers/FlatCarbon";
+ SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk";
+ STRIP_INSTALLED_PRODUCT = NO;
+ };
+ name = Debug;
+ };
+ C4E618CF095A3CE90012CA3F /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "$(SDKROOT)/System/Library/Frameworks/Carbon.framework/Headers/Carbon.h";
+ GENERATE_PKGINFO_FILE = YES;
+ INFOPLIST_FILE = "../../mac/OpenColorIO_AE.plugin-Info.plist";
+ INSTALL_PATH = "$(HOME)/Library/Bundles";
+ LINK_WITH_STANDARD_LIBRARIES = YES;
+ PREBINDING = NO;
+ PRODUCT_NAME = OpenColorIO;
+ WRAPPER_EXTENSION = plugin;
+ ZERO_LINK = NO;
+ };
+ name = Debug;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ C4E6187F095A3C800012CA3F /* Build configuration list for PBXProject "OpenColorIO_AE" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C4E61880095A3C800012CA3F /* Debug */,
+ 2A1BAC2310C3C82A00244D12 /* Release */,
+ );
+ defaultConfigurationIsVisible = 1;
+ defaultConfigurationName = Debug;
+ };
+ C4E618CE095A3CE90012CA3F /* Build configuration list for PBXNativeTarget "OpenColorIO" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C4E618CF095A3CE90012CA3F /* Debug */,
+ 2A1BAC2410C3C82A00244D12 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Debug;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = C4E6187E095A3C800012CA3F /* Project object */;
+}
diff --git a/src/aftereffects/xcode/ext/lcms.xcodeproj/project.pbxproj b/src/aftereffects/xcode/ext/lcms.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..42e7bda
--- /dev/null
+++ b/src/aftereffects/xcode/ext/lcms.xcodeproj/project.pbxproj
@@ -0,0 +1,343 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 2ACF9F2C1478251500991ED5 /* lcms2.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF9E6D1478251500991ED5 /* lcms2.h */; };
+ 2ACF9F2D1478251500991ED5 /* lcms2_plugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF9E6E1478251500991ED5 /* lcms2_plugin.h */; };
+ 2ACF9F311478251500991ED5 /* cmscam02.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9ECE1478251500991ED5 /* cmscam02.c */; };
+ 2ACF9F321478251500991ED5 /* cmscgats.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9ECF1478251500991ED5 /* cmscgats.c */; };
+ 2ACF9F331478251500991ED5 /* cmscnvrt.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9ED01478251500991ED5 /* cmscnvrt.c */; };
+ 2ACF9F341478251500991ED5 /* cmserr.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9ED11478251500991ED5 /* cmserr.c */; };
+ 2ACF9F351478251500991ED5 /* cmsgamma.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9ED21478251500991ED5 /* cmsgamma.c */; };
+ 2ACF9F361478251500991ED5 /* cmsgmt.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9ED31478251500991ED5 /* cmsgmt.c */; };
+ 2ACF9F371478251500991ED5 /* cmsintrp.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9ED41478251500991ED5 /* cmsintrp.c */; };
+ 2ACF9F381478251500991ED5 /* cmsio0.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9ED51478251500991ED5 /* cmsio0.c */; };
+ 2ACF9F391478251500991ED5 /* cmsio1.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9ED61478251500991ED5 /* cmsio1.c */; };
+ 2ACF9F3A1478251500991ED5 /* cmslut.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9ED71478251500991ED5 /* cmslut.c */; };
+ 2ACF9F3B1478251500991ED5 /* cmsmd5.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9ED81478251500991ED5 /* cmsmd5.c */; };
+ 2ACF9F3C1478251500991ED5 /* cmsmtrx.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9ED91478251500991ED5 /* cmsmtrx.c */; };
+ 2ACF9F3D1478251500991ED5 /* cmsnamed.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9EDA1478251500991ED5 /* cmsnamed.c */; };
+ 2ACF9F3E1478251500991ED5 /* cmsopt.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9EDB1478251500991ED5 /* cmsopt.c */; };
+ 2ACF9F3F1478251500991ED5 /* cmspack.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9EDC1478251500991ED5 /* cmspack.c */; };
+ 2ACF9F401478251500991ED5 /* cmspcs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9EDD1478251500991ED5 /* cmspcs.c */; };
+ 2ACF9F411478251500991ED5 /* cmsplugin.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9EDE1478251500991ED5 /* cmsplugin.c */; };
+ 2ACF9F421478251500991ED5 /* cmsps2.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9EDF1478251500991ED5 /* cmsps2.c */; };
+ 2ACF9F431478251500991ED5 /* cmssamp.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9EE01478251500991ED5 /* cmssamp.c */; };
+ 2ACF9F441478251500991ED5 /* cmssm.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9EE11478251500991ED5 /* cmssm.c */; };
+ 2ACF9F451478251500991ED5 /* cmstypes.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9EE21478251500991ED5 /* cmstypes.c */; };
+ 2ACF9F461478251500991ED5 /* cmsvirt.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9EE31478251500991ED5 /* cmsvirt.c */; };
+ 2ACF9F471478251500991ED5 /* cmswtpnt.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9EE41478251500991ED5 /* cmswtpnt.c */; };
+ 2ACF9F481478251500991ED5 /* cmsxform.c in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF9EE51478251500991ED5 /* cmsxform.c */; };
+ 2ACF9F491478251500991ED5 /* lcms2_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF9EE71478251500991ED5 /* lcms2_internal.h */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 2ACF9E56147824F500991ED5 /* liblcms.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = liblcms.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2ACF9E6D1478251500991ED5 /* lcms2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lcms2.h; sourceTree = "<group>"; };
+ 2ACF9E6E1478251500991ED5 /* lcms2_plugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lcms2_plugin.h; sourceTree = "<group>"; };
+ 2ACF9ECE1478251500991ED5 /* cmscam02.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmscam02.c; sourceTree = "<group>"; };
+ 2ACF9ECF1478251500991ED5 /* cmscgats.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmscgats.c; sourceTree = "<group>"; };
+ 2ACF9ED01478251500991ED5 /* cmscnvrt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmscnvrt.c; sourceTree = "<group>"; };
+ 2ACF9ED11478251500991ED5 /* cmserr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmserr.c; sourceTree = "<group>"; };
+ 2ACF9ED21478251500991ED5 /* cmsgamma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmsgamma.c; sourceTree = "<group>"; };
+ 2ACF9ED31478251500991ED5 /* cmsgmt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmsgmt.c; sourceTree = "<group>"; };
+ 2ACF9ED41478251500991ED5 /* cmsintrp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmsintrp.c; sourceTree = "<group>"; };
+ 2ACF9ED51478251500991ED5 /* cmsio0.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmsio0.c; sourceTree = "<group>"; };
+ 2ACF9ED61478251500991ED5 /* cmsio1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmsio1.c; sourceTree = "<group>"; };
+ 2ACF9ED71478251500991ED5 /* cmslut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmslut.c; sourceTree = "<group>"; };
+ 2ACF9ED81478251500991ED5 /* cmsmd5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmsmd5.c; sourceTree = "<group>"; };
+ 2ACF9ED91478251500991ED5 /* cmsmtrx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmsmtrx.c; sourceTree = "<group>"; };
+ 2ACF9EDA1478251500991ED5 /* cmsnamed.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmsnamed.c; sourceTree = "<group>"; };
+ 2ACF9EDB1478251500991ED5 /* cmsopt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmsopt.c; sourceTree = "<group>"; };
+ 2ACF9EDC1478251500991ED5 /* cmspack.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmspack.c; sourceTree = "<group>"; };
+ 2ACF9EDD1478251500991ED5 /* cmspcs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmspcs.c; sourceTree = "<group>"; };
+ 2ACF9EDE1478251500991ED5 /* cmsplugin.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmsplugin.c; sourceTree = "<group>"; };
+ 2ACF9EDF1478251500991ED5 /* cmsps2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmsps2.c; sourceTree = "<group>"; };
+ 2ACF9EE01478251500991ED5 /* cmssamp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmssamp.c; sourceTree = "<group>"; };
+ 2ACF9EE11478251500991ED5 /* cmssm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmssm.c; sourceTree = "<group>"; };
+ 2ACF9EE21478251500991ED5 /* cmstypes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmstypes.c; sourceTree = "<group>"; };
+ 2ACF9EE31478251500991ED5 /* cmsvirt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmsvirt.c; sourceTree = "<group>"; };
+ 2ACF9EE41478251500991ED5 /* cmswtpnt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmswtpnt.c; sourceTree = "<group>"; };
+ 2ACF9EE51478251500991ED5 /* cmsxform.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmsxform.c; sourceTree = "<group>"; };
+ 2ACF9EE71478251500991ED5 /* lcms2_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lcms2_internal.h; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 2ACF9E54147824F500991ED5 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 034768DDFF38A45A11DB9C8B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF9E56147824F500991ED5 /* liblcms.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 0867D691FE84028FC02AAC07 /* lcms */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF9E5A1478251500991ED5 /* lcms2-2.1 */,
+ 034768DDFF38A45A11DB9C8B /* Products */,
+ );
+ name = lcms;
+ sourceTree = "<group>";
+ };
+ 2ACF9E5A1478251500991ED5 /* lcms2-2.1 */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF9E6C1478251500991ED5 /* include */,
+ 2ACF9ECD1478251500991ED5 /* src */,
+ );
+ name = "lcms2-2.1";
+ path = "../../../../ext/lcms2-2.1";
+ sourceTree = SOURCE_ROOT;
+ };
+ 2ACF9E6C1478251500991ED5 /* include */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF9E6D1478251500991ED5 /* lcms2.h */,
+ 2ACF9E6E1478251500991ED5 /* lcms2_plugin.h */,
+ );
+ path = include;
+ sourceTree = "<group>";
+ };
+ 2ACF9ECD1478251500991ED5 /* src */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF9ECE1478251500991ED5 /* cmscam02.c */,
+ 2ACF9ECF1478251500991ED5 /* cmscgats.c */,
+ 2ACF9ED01478251500991ED5 /* cmscnvrt.c */,
+ 2ACF9ED11478251500991ED5 /* cmserr.c */,
+ 2ACF9ED21478251500991ED5 /* cmsgamma.c */,
+ 2ACF9ED31478251500991ED5 /* cmsgmt.c */,
+ 2ACF9ED41478251500991ED5 /* cmsintrp.c */,
+ 2ACF9ED51478251500991ED5 /* cmsio0.c */,
+ 2ACF9ED61478251500991ED5 /* cmsio1.c */,
+ 2ACF9ED71478251500991ED5 /* cmslut.c */,
+ 2ACF9ED81478251500991ED5 /* cmsmd5.c */,
+ 2ACF9ED91478251500991ED5 /* cmsmtrx.c */,
+ 2ACF9EDA1478251500991ED5 /* cmsnamed.c */,
+ 2ACF9EDB1478251500991ED5 /* cmsopt.c */,
+ 2ACF9EDC1478251500991ED5 /* cmspack.c */,
+ 2ACF9EDD1478251500991ED5 /* cmspcs.c */,
+ 2ACF9EDE1478251500991ED5 /* cmsplugin.c */,
+ 2ACF9EDF1478251500991ED5 /* cmsps2.c */,
+ 2ACF9EE01478251500991ED5 /* cmssamp.c */,
+ 2ACF9EE11478251500991ED5 /* cmssm.c */,
+ 2ACF9EE21478251500991ED5 /* cmstypes.c */,
+ 2ACF9EE31478251500991ED5 /* cmsvirt.c */,
+ 2ACF9EE41478251500991ED5 /* cmswtpnt.c */,
+ 2ACF9EE51478251500991ED5 /* cmsxform.c */,
+ 2ACF9EE71478251500991ED5 /* lcms2_internal.h */,
+ );
+ path = src;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 2ACF9E52147824F500991ED5 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2ACF9F2C1478251500991ED5 /* lcms2.h in Headers */,
+ 2ACF9F2D1478251500991ED5 /* lcms2_plugin.h in Headers */,
+ 2ACF9F491478251500991ED5 /* lcms2_internal.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 2ACF9E55147824F500991ED5 /* lcms */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2ACF9E59147824FB00991ED5 /* Build configuration list for PBXNativeTarget "lcms" */;
+ buildPhases = (
+ 2AF569A814799AF900F9968C /* Unpack lcms2 */,
+ 2ACF9E52147824F500991ED5 /* Headers */,
+ 2ACF9E53147824F500991ED5 /* Sources */,
+ 2ACF9E54147824F500991ED5 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = lcms;
+ productName = lcms;
+ productReference = 2ACF9E56147824F500991ED5 /* liblcms.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 0867D690FE84028FC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 1DEB916408733D950010E9CD /* Build configuration list for PBXProject "lcms" */;
+ compatibilityVersion = "Xcode 3.1";
+ developmentRegion = English;
+ hasScannedForEncodings = 1;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
+ mainGroup = 0867D691FE84028FC02AAC07 /* lcms */;
+ productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 2ACF9E55147824F500991ED5 /* lcms */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 2AF569A814799AF900F9968C /* Unpack lcms2 */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/../../../../ext/lcms2-2.1.tar.gz",
+ );
+ name = "Unpack lcms2";
+ outputPaths = (
+ "$(SRCROOT)/../../../../ext/lcms2-2.1",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "cd $SRCROOT/../../../../ext\n\nif [ ! -d lcms2-2.1 ]\nthen\n\ttar -xzf lcms2-2.1.tar.gz\nfi\n";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 2ACF9E53147824F500991ED5 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2ACF9F311478251500991ED5 /* cmscam02.c in Sources */,
+ 2ACF9F321478251500991ED5 /* cmscgats.c in Sources */,
+ 2ACF9F331478251500991ED5 /* cmscnvrt.c in Sources */,
+ 2ACF9F341478251500991ED5 /* cmserr.c in Sources */,
+ 2ACF9F351478251500991ED5 /* cmsgamma.c in Sources */,
+ 2ACF9F361478251500991ED5 /* cmsgmt.c in Sources */,
+ 2ACF9F371478251500991ED5 /* cmsintrp.c in Sources */,
+ 2ACF9F381478251500991ED5 /* cmsio0.c in Sources */,
+ 2ACF9F391478251500991ED5 /* cmsio1.c in Sources */,
+ 2ACF9F3A1478251500991ED5 /* cmslut.c in Sources */,
+ 2ACF9F3B1478251500991ED5 /* cmsmd5.c in Sources */,
+ 2ACF9F3C1478251500991ED5 /* cmsmtrx.c in Sources */,
+ 2ACF9F3D1478251500991ED5 /* cmsnamed.c in Sources */,
+ 2ACF9F3E1478251500991ED5 /* cmsopt.c in Sources */,
+ 2ACF9F3F1478251500991ED5 /* cmspack.c in Sources */,
+ 2ACF9F401478251500991ED5 /* cmspcs.c in Sources */,
+ 2ACF9F411478251500991ED5 /* cmsplugin.c in Sources */,
+ 2ACF9F421478251500991ED5 /* cmsps2.c in Sources */,
+ 2ACF9F431478251500991ED5 /* cmssamp.c in Sources */,
+ 2ACF9F441478251500991ED5 /* cmssm.c in Sources */,
+ 2ACF9F451478251500991ED5 /* cmstypes.c in Sources */,
+ 2ACF9F461478251500991ED5 /* cmsvirt.c in Sources */,
+ 2ACF9F471478251500991ED5 /* cmswtpnt.c in Sources */,
+ 2ACF9F481478251500991ED5 /* cmsxform.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 1DEB916508733D950010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ PREBINDING = NO;
+ SDKROOT = macosx10.5;
+ };
+ name = Debug;
+ };
+ 1DEB916608733D950010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_PREPROCESSOR_DEFINITIONS = NDEBUG;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ PREBINDING = NO;
+ SDKROOT = macosx10.5;
+ };
+ name = Release;
+ };
+ 2ACF9E57147824F600991ED5 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ INSTALL_PATH = /usr/local/lib;
+ PREBINDING = NO;
+ PRODUCT_NAME = lcms;
+ };
+ name = Debug;
+ };
+ 2ACF9E58147824F600991ED5 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/local/lib;
+ PREBINDING = NO;
+ PRODUCT_NAME = lcms;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1DEB916408733D950010E9CD /* Build configuration list for PBXProject "lcms" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB916508733D950010E9CD /* Debug */,
+ 1DEB916608733D950010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 2ACF9E59147824FB00991ED5 /* Build configuration list for PBXNativeTarget "lcms" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2ACF9E57147824F600991ED5 /* Debug */,
+ 2ACF9E58147824F600991ED5 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
+}
diff --git a/src/aftereffects/xcode/ext/tinyxml.xcodeproj/project.pbxproj b/src/aftereffects/xcode/ext/tinyxml.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..2f07451
--- /dev/null
+++ b/src/aftereffects/xcode/ext/tinyxml.xcodeproj/project.pbxproj
@@ -0,0 +1,248 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 2ACF55501477685000991ED5 /* tinystr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF554A1477685000991ED5 /* tinystr.cpp */; };
+ 2ACF55511477685000991ED5 /* tinystr.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF554B1477685000991ED5 /* tinystr.h */; };
+ 2ACF55521477685000991ED5 /* tinyxml.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF554C1477685000991ED5 /* tinyxml.cpp */; };
+ 2ACF55531477685000991ED5 /* tinyxml.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF554D1477685000991ED5 /* tinyxml.h */; };
+ 2ACF55541477685000991ED5 /* tinyxmlerror.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF554E1477685000991ED5 /* tinyxmlerror.cpp */; };
+ 2ACF55551477685000991ED5 /* tinyxmlparser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF554F1477685000991ED5 /* tinyxmlparser.cpp */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 2ACF55441477682B00991ED5 /* libtinyxml.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libtinyxml.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2ACF554A1477685000991ED5 /* tinystr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tinystr.cpp; sourceTree = "<group>"; };
+ 2ACF554B1477685000991ED5 /* tinystr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tinystr.h; sourceTree = "<group>"; };
+ 2ACF554C1477685000991ED5 /* tinyxml.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tinyxml.cpp; sourceTree = "<group>"; };
+ 2ACF554D1477685000991ED5 /* tinyxml.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tinyxml.h; sourceTree = "<group>"; };
+ 2ACF554E1477685000991ED5 /* tinyxmlerror.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tinyxmlerror.cpp; sourceTree = "<group>"; };
+ 2ACF554F1477685000991ED5 /* tinyxmlparser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tinyxmlparser.cpp; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 2ACF55421477682B00991ED5 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 034768DDFF38A45A11DB9C8B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF55441477682B00991ED5 /* libtinyxml.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 0867D691FE84028FC02AAC07 /* tinyxml */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF55481477685000991ED5 /* tinyxml */,
+ 034768DDFF38A45A11DB9C8B /* Products */,
+ );
+ name = tinyxml;
+ sourceTree = "<group>";
+ };
+ 2ACF55481477685000991ED5 /* tinyxml */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF554A1477685000991ED5 /* tinystr.cpp */,
+ 2ACF554B1477685000991ED5 /* tinystr.h */,
+ 2ACF554C1477685000991ED5 /* tinyxml.cpp */,
+ 2ACF554D1477685000991ED5 /* tinyxml.h */,
+ 2ACF554E1477685000991ED5 /* tinyxmlerror.cpp */,
+ 2ACF554F1477685000991ED5 /* tinyxmlparser.cpp */,
+ );
+ name = tinyxml;
+ path = ../../../../ext/tinyxml;
+ sourceTree = SOURCE_ROOT;
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 2ACF55401477682B00991ED5 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2ACF55511477685000991ED5 /* tinystr.h in Headers */,
+ 2ACF55531477685000991ED5 /* tinyxml.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 2ACF55431477682B00991ED5 /* tinyxml */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2ACF55471477683C00991ED5 /* Build configuration list for PBXNativeTarget "tinyxml" */;
+ buildPhases = (
+ 2AF569961479999900F9968C /* Unpack tinyxml */,
+ 2ACF55401477682B00991ED5 /* Headers */,
+ 2ACF55411477682B00991ED5 /* Sources */,
+ 2ACF55421477682B00991ED5 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = tinyxml;
+ productName = tinyxml;
+ productReference = 2ACF55441477682B00991ED5 /* libtinyxml.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 0867D690FE84028FC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 1DEB916408733D950010E9CD /* Build configuration list for PBXProject "tinyxml" */;
+ compatibilityVersion = "Xcode 3.1";
+ developmentRegion = English;
+ hasScannedForEncodings = 1;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
+ mainGroup = 0867D691FE84028FC02AAC07 /* tinyxml */;
+ productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 2ACF55431477682B00991ED5 /* tinyxml */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 2AF569961479999900F9968C /* Unpack tinyxml */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/../../../../ext/tinyxml_2_6_1.tar.gz",
+ "$(SRCROOT)/../../../../ext/tinyxml_2_6_1.patch",
+ );
+ name = "Unpack tinyxml";
+ outputPaths = (
+ "$(SRCROOT)/../../../../ext/tinyxml",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "cd $SRCROOT/../../../../ext\n\nif [ ! -d tinyxml ]\nthen\n\ttar -xzf tinyxml_2_6_1.tar.gz\n\tpatch -p0 < tinyxml_2_6_1.patch\nfi\n";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 2ACF55411477682B00991ED5 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2ACF55501477685000991ED5 /* tinystr.cpp in Sources */,
+ 2ACF55521477685000991ED5 /* tinyxml.cpp in Sources */,
+ 2ACF55541477685000991ED5 /* tinyxmlerror.cpp in Sources */,
+ 2ACF55551477685000991ED5 /* tinyxmlparser.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 1DEB916508733D950010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = TIXML_USE_STL;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ PREBINDING = NO;
+ SDKROOT = macosx10.5;
+ };
+ name = Debug;
+ };
+ 1DEB916608733D950010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ NDEBUG,
+ TIXML_USE_STL,
+ );
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ PREBINDING = NO;
+ SDKROOT = macosx10.5;
+ };
+ name = Release;
+ };
+ 2ACF55451477682B00991ED5 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ INSTALL_PATH = /usr/local/lib;
+ PREBINDING = NO;
+ PRODUCT_NAME = tinyxml;
+ };
+ name = Debug;
+ };
+ 2ACF55461477682B00991ED5 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/local/lib;
+ PREBINDING = NO;
+ PRODUCT_NAME = tinyxml;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1DEB916408733D950010E9CD /* Build configuration list for PBXProject "tinyxml" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB916508733D950010E9CD /* Debug */,
+ 1DEB916608733D950010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 2ACF55471477683C00991ED5 /* Build configuration list for PBXNativeTarget "tinyxml" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2ACF55451477682B00991ED5 /* Debug */,
+ 2ACF55461477682B00991ED5 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
+}
diff --git a/src/aftereffects/xcode/ext/yaml.xcodeproj/project.pbxproj b/src/aftereffects/xcode/ext/yaml.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..2dc9cbc
--- /dev/null
+++ b/src/aftereffects/xcode/ext/yaml.xcodeproj/project.pbxproj
@@ -0,0 +1,571 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 2AB6B01315538484007C3547 /* binary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2AB6B01215538484007C3547 /* binary.cpp */; };
+ 2ACF55F21477693B00991ED5 /* aliasmanager.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55A31477693B00991ED5 /* aliasmanager.h */; };
+ 2ACF55F31477693B00991ED5 /* anchor.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55A41477693B00991ED5 /* anchor.h */; };
+ 2ACF55F41477693B00991ED5 /* anchordict.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55A61477693B00991ED5 /* anchordict.h */; };
+ 2ACF55F51477693B00991ED5 /* graphbuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55A71477693B00991ED5 /* graphbuilder.h */; };
+ 2ACF55F61477693B00991ED5 /* conversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55A81477693B00991ED5 /* conversion.h */; };
+ 2ACF55F71477693B00991ED5 /* dll.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55A91477693B00991ED5 /* dll.h */; };
+ 2ACF55F81477693B00991ED5 /* emitfromevents.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55AA1477693B00991ED5 /* emitfromevents.h */; };
+ 2ACF55F91477693B00991ED5 /* emitter.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55AB1477693B00991ED5 /* emitter.h */; };
+ 2ACF55FA1477693B00991ED5 /* emittermanip.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55AC1477693B00991ED5 /* emittermanip.h */; };
+ 2ACF55FB1477693B00991ED5 /* eventhandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55AD1477693B00991ED5 /* eventhandler.h */; };
+ 2ACF55FC1477693B00991ED5 /* exceptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55AE1477693B00991ED5 /* exceptions.h */; };
+ 2ACF55FD1477693B00991ED5 /* iterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55AF1477693B00991ED5 /* iterator.h */; };
+ 2ACF55FE1477693B00991ED5 /* ltnode.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55B01477693B00991ED5 /* ltnode.h */; };
+ 2ACF55FF1477693B00991ED5 /* mark.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55B11477693B00991ED5 /* mark.h */; };
+ 2ACF56001477693B00991ED5 /* node.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55B21477693B00991ED5 /* node.h */; };
+ 2ACF56011477693B00991ED5 /* nodeimpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55B31477693B00991ED5 /* nodeimpl.h */; };
+ 2ACF56021477693B00991ED5 /* nodereadimpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55B41477693B00991ED5 /* nodereadimpl.h */; };
+ 2ACF56031477693B00991ED5 /* nodeutil.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55B51477693B00991ED5 /* nodeutil.h */; };
+ 2ACF56041477693B00991ED5 /* noncopyable.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55B61477693B00991ED5 /* noncopyable.h */; };
+ 2ACF56051477693B00991ED5 /* null.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55B71477693B00991ED5 /* null.h */; };
+ 2ACF56061477693B00991ED5 /* ostream.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55B81477693B00991ED5 /* ostream.h */; };
+ 2ACF56071477693B00991ED5 /* parser.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55B91477693B00991ED5 /* parser.h */; };
+ 2ACF56081477693B00991ED5 /* stlemitter.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55BA1477693B00991ED5 /* stlemitter.h */; };
+ 2ACF56091477693B00991ED5 /* stlnode.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55BB1477693B00991ED5 /* stlnode.h */; };
+ 2ACF560A1477693B00991ED5 /* traits.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55BC1477693B00991ED5 /* traits.h */; };
+ 2ACF560B1477693B00991ED5 /* yaml.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55BD1477693B00991ED5 /* yaml.h */; };
+ 2ACF560C1477693B00991ED5 /* aliasmanager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55BF1477693B00991ED5 /* aliasmanager.cpp */; };
+ 2ACF560D1477693B00991ED5 /* collectionstack.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55C01477693B00991ED5 /* collectionstack.h */; };
+ 2ACF560E1477693B00991ED5 /* graphbuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55C21477693B00991ED5 /* graphbuilder.cpp */; };
+ 2ACF560F1477693B00991ED5 /* graphbuilderadapter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55C31477693B00991ED5 /* graphbuilderadapter.cpp */; };
+ 2ACF56101477693B00991ED5 /* graphbuilderadapter.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55C41477693B00991ED5 /* graphbuilderadapter.h */; };
+ 2ACF56111477693B00991ED5 /* conversion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55C51477693B00991ED5 /* conversion.cpp */; };
+ 2ACF56121477693B00991ED5 /* directives.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55C61477693B00991ED5 /* directives.cpp */; };
+ 2ACF56131477693B00991ED5 /* directives.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55C71477693B00991ED5 /* directives.h */; };
+ 2ACF56141477693B00991ED5 /* emitfromevents.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55C81477693B00991ED5 /* emitfromevents.cpp */; };
+ 2ACF56151477693B00991ED5 /* emitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55C91477693B00991ED5 /* emitter.cpp */; };
+ 2ACF56161477693B00991ED5 /* emitterstate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55CA1477693B00991ED5 /* emitterstate.cpp */; };
+ 2ACF56171477693B00991ED5 /* emitterstate.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55CB1477693B00991ED5 /* emitterstate.h */; };
+ 2ACF56181477693B00991ED5 /* emitterutils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55CC1477693B00991ED5 /* emitterutils.cpp */; };
+ 2ACF56191477693B00991ED5 /* emitterutils.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55CD1477693B00991ED5 /* emitterutils.h */; };
+ 2ACF561A1477693B00991ED5 /* exp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55CE1477693B00991ED5 /* exp.cpp */; };
+ 2ACF561B1477693B00991ED5 /* exp.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55CF1477693B00991ED5 /* exp.h */; };
+ 2ACF561C1477693B00991ED5 /* indentation.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55D01477693B00991ED5 /* indentation.h */; };
+ 2ACF561D1477693B00991ED5 /* iterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55D11477693B00991ED5 /* iterator.cpp */; };
+ 2ACF561E1477693B00991ED5 /* iterpriv.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55D21477693B00991ED5 /* iterpriv.h */; };
+ 2ACF561F1477693B00991ED5 /* node.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55D31477693B00991ED5 /* node.cpp */; };
+ 2ACF56201477693B00991ED5 /* nodebuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55D41477693B00991ED5 /* nodebuilder.cpp */; };
+ 2ACF56211477693B00991ED5 /* nodebuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55D51477693B00991ED5 /* nodebuilder.h */; };
+ 2ACF56221477693B00991ED5 /* nodeownership.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55D61477693B00991ED5 /* nodeownership.cpp */; };
+ 2ACF56231477693B00991ED5 /* nodeownership.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55D71477693B00991ED5 /* nodeownership.h */; };
+ 2ACF56241477693B00991ED5 /* null.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55D81477693B00991ED5 /* null.cpp */; };
+ 2ACF56251477693B00991ED5 /* ostream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55D91477693B00991ED5 /* ostream.cpp */; };
+ 2ACF56261477693B00991ED5 /* parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55DA1477693B00991ED5 /* parser.cpp */; };
+ 2ACF56271477693B00991ED5 /* ptr_stack.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55DB1477693B00991ED5 /* ptr_stack.h */; };
+ 2ACF56281477693B00991ED5 /* ptr_vector.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55DC1477693B00991ED5 /* ptr_vector.h */; };
+ 2ACF56291477693B00991ED5 /* regex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55DD1477693B00991ED5 /* regex.cpp */; };
+ 2ACF562A1477693B00991ED5 /* regex.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55DE1477693B00991ED5 /* regex.h */; };
+ 2ACF562B1477693B00991ED5 /* regeximpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55DF1477693B00991ED5 /* regeximpl.h */; };
+ 2ACF562C1477693B00991ED5 /* scanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55E01477693B00991ED5 /* scanner.cpp */; };
+ 2ACF562D1477693B00991ED5 /* scanner.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55E11477693B00991ED5 /* scanner.h */; };
+ 2ACF562E1477693B00991ED5 /* scanscalar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55E21477693B00991ED5 /* scanscalar.cpp */; };
+ 2ACF562F1477693B00991ED5 /* scanscalar.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55E31477693B00991ED5 /* scanscalar.h */; };
+ 2ACF56301477693B00991ED5 /* scantag.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55E41477693B00991ED5 /* scantag.cpp */; };
+ 2ACF56311477693B00991ED5 /* scantag.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55E51477693B00991ED5 /* scantag.h */; };
+ 2ACF56321477693B00991ED5 /* scantoken.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55E61477693B00991ED5 /* scantoken.cpp */; };
+ 2ACF56331477693B00991ED5 /* setting.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55E71477693B00991ED5 /* setting.h */; };
+ 2ACF56341477693B00991ED5 /* simplekey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55E81477693B00991ED5 /* simplekey.cpp */; };
+ 2ACF56351477693B00991ED5 /* singledocparser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55E91477693B00991ED5 /* singledocparser.cpp */; };
+ 2ACF56361477693B00991ED5 /* singledocparser.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55EA1477693B00991ED5 /* singledocparser.h */; };
+ 2ACF56371477693B00991ED5 /* stream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55EB1477693B00991ED5 /* stream.cpp */; };
+ 2ACF56381477693B00991ED5 /* stream.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55EC1477693B00991ED5 /* stream.h */; };
+ 2ACF56391477693B00991ED5 /* streamcharsource.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55ED1477693B00991ED5 /* streamcharsource.h */; };
+ 2ACF563A1477693B00991ED5 /* stringsource.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55EE1477693B00991ED5 /* stringsource.h */; };
+ 2ACF563B1477693B00991ED5 /* tag.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF55EF1477693B00991ED5 /* tag.cpp */; };
+ 2ACF563C1477693B00991ED5 /* tag.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55F01477693B00991ED5 /* tag.h */; };
+ 2ACF563D1477693B00991ED5 /* token.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACF55F11477693B00991ED5 /* token.h */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 2AB6B01215538484007C3547 /* binary.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = binary.cpp; sourceTree = "<group>"; };
+ 2ACF559C1477692300991ED5 /* libyaml.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libyaml.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2ACF55A31477693B00991ED5 /* aliasmanager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aliasmanager.h; sourceTree = "<group>"; };
+ 2ACF55A41477693B00991ED5 /* anchor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = anchor.h; sourceTree = "<group>"; };
+ 2ACF55A61477693B00991ED5 /* anchordict.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = anchordict.h; sourceTree = "<group>"; };
+ 2ACF55A71477693B00991ED5 /* graphbuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = graphbuilder.h; sourceTree = "<group>"; };
+ 2ACF55A81477693B00991ED5 /* conversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = conversion.h; sourceTree = "<group>"; };
+ 2ACF55A91477693B00991ED5 /* dll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dll.h; sourceTree = "<group>"; };
+ 2ACF55AA1477693B00991ED5 /* emitfromevents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = emitfromevents.h; sourceTree = "<group>"; };
+ 2ACF55AB1477693B00991ED5 /* emitter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = emitter.h; sourceTree = "<group>"; };
+ 2ACF55AC1477693B00991ED5 /* emittermanip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = emittermanip.h; sourceTree = "<group>"; };
+ 2ACF55AD1477693B00991ED5 /* eventhandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eventhandler.h; sourceTree = "<group>"; };
+ 2ACF55AE1477693B00991ED5 /* exceptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exceptions.h; sourceTree = "<group>"; };
+ 2ACF55AF1477693B00991ED5 /* iterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iterator.h; sourceTree = "<group>"; };
+ 2ACF55B01477693B00991ED5 /* ltnode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ltnode.h; sourceTree = "<group>"; };
+ 2ACF55B11477693B00991ED5 /* mark.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mark.h; sourceTree = "<group>"; };
+ 2ACF55B21477693B00991ED5 /* node.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = node.h; sourceTree = "<group>"; };
+ 2ACF55B31477693B00991ED5 /* nodeimpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nodeimpl.h; sourceTree = "<group>"; };
+ 2ACF55B41477693B00991ED5 /* nodereadimpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nodereadimpl.h; sourceTree = "<group>"; };
+ 2ACF55B51477693B00991ED5 /* nodeutil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nodeutil.h; sourceTree = "<group>"; };
+ 2ACF55B61477693B00991ED5 /* noncopyable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = noncopyable.h; sourceTree = "<group>"; };
+ 2ACF55B71477693B00991ED5 /* null.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = null.h; sourceTree = "<group>"; };
+ 2ACF55B81477693B00991ED5 /* ostream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ostream.h; sourceTree = "<group>"; };
+ 2ACF55B91477693B00991ED5 /* parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parser.h; sourceTree = "<group>"; };
+ 2ACF55BA1477693B00991ED5 /* stlemitter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stlemitter.h; sourceTree = "<group>"; };
+ 2ACF55BB1477693B00991ED5 /* stlnode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stlnode.h; sourceTree = "<group>"; };
+ 2ACF55BC1477693B00991ED5 /* traits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = traits.h; sourceTree = "<group>"; };
+ 2ACF55BD1477693B00991ED5 /* yaml.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = yaml.h; sourceTree = "<group>"; };
+ 2ACF55BF1477693B00991ED5 /* aliasmanager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = aliasmanager.cpp; sourceTree = "<group>"; };
+ 2ACF55C01477693B00991ED5 /* collectionstack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = collectionstack.h; sourceTree = "<group>"; };
+ 2ACF55C21477693B00991ED5 /* graphbuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = graphbuilder.cpp; sourceTree = "<group>"; };
+ 2ACF55C31477693B00991ED5 /* graphbuilderadapter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = graphbuilderadapter.cpp; sourceTree = "<group>"; };
+ 2ACF55C41477693B00991ED5 /* graphbuilderadapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = graphbuilderadapter.h; sourceTree = "<group>"; };
+ 2ACF55C51477693B00991ED5 /* conversion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = conversion.cpp; sourceTree = "<group>"; };
+ 2ACF55C61477693B00991ED5 /* directives.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = directives.cpp; sourceTree = "<group>"; };
+ 2ACF55C71477693B00991ED5 /* directives.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = directives.h; sourceTree = "<group>"; };
+ 2ACF55C81477693B00991ED5 /* emitfromevents.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = emitfromevents.cpp; sourceTree = "<group>"; };
+ 2ACF55C91477693B00991ED5 /* emitter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = emitter.cpp; sourceTree = "<group>"; };
+ 2ACF55CA1477693B00991ED5 /* emitterstate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = emitterstate.cpp; sourceTree = "<group>"; };
+ 2ACF55CB1477693B00991ED5 /* emitterstate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = emitterstate.h; sourceTree = "<group>"; };
+ 2ACF55CC1477693B00991ED5 /* emitterutils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = emitterutils.cpp; sourceTree = "<group>"; };
+ 2ACF55CD1477693B00991ED5 /* emitterutils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = emitterutils.h; sourceTree = "<group>"; };
+ 2ACF55CE1477693B00991ED5 /* exp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = exp.cpp; sourceTree = "<group>"; };
+ 2ACF55CF1477693B00991ED5 /* exp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exp.h; sourceTree = "<group>"; };
+ 2ACF55D01477693B00991ED5 /* indentation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = indentation.h; sourceTree = "<group>"; };
+ 2ACF55D11477693B00991ED5 /* iterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = iterator.cpp; sourceTree = "<group>"; };
+ 2ACF55D21477693B00991ED5 /* iterpriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iterpriv.h; sourceTree = "<group>"; };
+ 2ACF55D31477693B00991ED5 /* node.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = node.cpp; sourceTree = "<group>"; };
+ 2ACF55D41477693B00991ED5 /* nodebuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = nodebuilder.cpp; sourceTree = "<group>"; };
+ 2ACF55D51477693B00991ED5 /* nodebuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nodebuilder.h; sourceTree = "<group>"; };
+ 2ACF55D61477693B00991ED5 /* nodeownership.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = nodeownership.cpp; sourceTree = "<group>"; };
+ 2ACF55D71477693B00991ED5 /* nodeownership.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nodeownership.h; sourceTree = "<group>"; };
+ 2ACF55D81477693B00991ED5 /* null.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = null.cpp; sourceTree = "<group>"; };
+ 2ACF55D91477693B00991ED5 /* ostream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ostream.cpp; sourceTree = "<group>"; };
+ 2ACF55DA1477693B00991ED5 /* parser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = parser.cpp; sourceTree = "<group>"; };
+ 2ACF55DB1477693B00991ED5 /* ptr_stack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ptr_stack.h; sourceTree = "<group>"; };
+ 2ACF55DC1477693B00991ED5 /* ptr_vector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ptr_vector.h; sourceTree = "<group>"; };
+ 2ACF55DD1477693B00991ED5 /* regex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = regex.cpp; sourceTree = "<group>"; };
+ 2ACF55DE1477693B00991ED5 /* regex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = regex.h; sourceTree = "<group>"; };
+ 2ACF55DF1477693B00991ED5 /* regeximpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = regeximpl.h; sourceTree = "<group>"; };
+ 2ACF55E01477693B00991ED5 /* scanner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scanner.cpp; sourceTree = "<group>"; };
+ 2ACF55E11477693B00991ED5 /* scanner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scanner.h; sourceTree = "<group>"; };
+ 2ACF55E21477693B00991ED5 /* scanscalar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scanscalar.cpp; sourceTree = "<group>"; };
+ 2ACF55E31477693B00991ED5 /* scanscalar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scanscalar.h; sourceTree = "<group>"; };
+ 2ACF55E41477693B00991ED5 /* scantag.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scantag.cpp; sourceTree = "<group>"; };
+ 2ACF55E51477693B00991ED5 /* scantag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scantag.h; sourceTree = "<group>"; };
+ 2ACF55E61477693B00991ED5 /* scantoken.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scantoken.cpp; sourceTree = "<group>"; };
+ 2ACF55E71477693B00991ED5 /* setting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = setting.h; sourceTree = "<group>"; };
+ 2ACF55E81477693B00991ED5 /* simplekey.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = simplekey.cpp; sourceTree = "<group>"; };
+ 2ACF55E91477693B00991ED5 /* singledocparser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = singledocparser.cpp; sourceTree = "<group>"; };
+ 2ACF55EA1477693B00991ED5 /* singledocparser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = singledocparser.h; sourceTree = "<group>"; };
+ 2ACF55EB1477693B00991ED5 /* stream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = stream.cpp; sourceTree = "<group>"; };
+ 2ACF55EC1477693B00991ED5 /* stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stream.h; sourceTree = "<group>"; };
+ 2ACF55ED1477693B00991ED5 /* streamcharsource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = streamcharsource.h; sourceTree = "<group>"; };
+ 2ACF55EE1477693B00991ED5 /* stringsource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stringsource.h; sourceTree = "<group>"; };
+ 2ACF55EF1477693B00991ED5 /* tag.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tag.cpp; sourceTree = "<group>"; };
+ 2ACF55F01477693B00991ED5 /* tag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tag.h; sourceTree = "<group>"; };
+ 2ACF55F11477693B00991ED5 /* token.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = token.h; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 2ACF559A1477692300991ED5 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 034768DDFF38A45A11DB9C8B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF559C1477692300991ED5 /* libyaml.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 0867D691FE84028FC02AAC07 /* yaml */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF55A01477693B00991ED5 /* yaml-cpp */,
+ 034768DDFF38A45A11DB9C8B /* Products */,
+ );
+ name = yaml;
+ sourceTree = "<group>";
+ };
+ 2ACF55A01477693B00991ED5 /* yaml-cpp */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF55A11477693B00991ED5 /* include */,
+ 2ACF55BE1477693B00991ED5 /* src */,
+ );
+ name = "yaml-cpp";
+ path = "../../../../ext/yaml-cpp";
+ sourceTree = SOURCE_ROOT;
+ };
+ 2ACF55A11477693B00991ED5 /* include */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF55A21477693B00991ED5 /* yaml-cpp */,
+ );
+ path = include;
+ sourceTree = "<group>";
+ };
+ 2ACF55A21477693B00991ED5 /* yaml-cpp */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF55A31477693B00991ED5 /* aliasmanager.h */,
+ 2ACF55A41477693B00991ED5 /* anchor.h */,
+ 2ACF55A51477693B00991ED5 /* contrib */,
+ 2ACF55A81477693B00991ED5 /* conversion.h */,
+ 2ACF55A91477693B00991ED5 /* dll.h */,
+ 2ACF55AA1477693B00991ED5 /* emitfromevents.h */,
+ 2ACF55AB1477693B00991ED5 /* emitter.h */,
+ 2ACF55AC1477693B00991ED5 /* emittermanip.h */,
+ 2ACF55AD1477693B00991ED5 /* eventhandler.h */,
+ 2ACF55AE1477693B00991ED5 /* exceptions.h */,
+ 2ACF55AF1477693B00991ED5 /* iterator.h */,
+ 2ACF55B01477693B00991ED5 /* ltnode.h */,
+ 2ACF55B11477693B00991ED5 /* mark.h */,
+ 2ACF55B21477693B00991ED5 /* node.h */,
+ 2ACF55B31477693B00991ED5 /* nodeimpl.h */,
+ 2ACF55B41477693B00991ED5 /* nodereadimpl.h */,
+ 2ACF55B51477693B00991ED5 /* nodeutil.h */,
+ 2ACF55B61477693B00991ED5 /* noncopyable.h */,
+ 2ACF55B71477693B00991ED5 /* null.h */,
+ 2ACF55B81477693B00991ED5 /* ostream.h */,
+ 2ACF55B91477693B00991ED5 /* parser.h */,
+ 2ACF55BA1477693B00991ED5 /* stlemitter.h */,
+ 2ACF55BB1477693B00991ED5 /* stlnode.h */,
+ 2ACF55BC1477693B00991ED5 /* traits.h */,
+ 2ACF55BD1477693B00991ED5 /* yaml.h */,
+ );
+ path = "yaml-cpp";
+ sourceTree = "<group>";
+ };
+ 2ACF55A51477693B00991ED5 /* contrib */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF55A61477693B00991ED5 /* anchordict.h */,
+ 2ACF55A71477693B00991ED5 /* graphbuilder.h */,
+ );
+ path = contrib;
+ sourceTree = "<group>";
+ };
+ 2ACF55BE1477693B00991ED5 /* src */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF55BF1477693B00991ED5 /* aliasmanager.cpp */,
+ 2AB6B01215538484007C3547 /* binary.cpp */,
+ 2ACF55C01477693B00991ED5 /* collectionstack.h */,
+ 2ACF55C11477693B00991ED5 /* contrib */,
+ 2ACF55C51477693B00991ED5 /* conversion.cpp */,
+ 2ACF55C61477693B00991ED5 /* directives.cpp */,
+ 2ACF55C71477693B00991ED5 /* directives.h */,
+ 2ACF55C81477693B00991ED5 /* emitfromevents.cpp */,
+ 2ACF55C91477693B00991ED5 /* emitter.cpp */,
+ 2ACF55CA1477693B00991ED5 /* emitterstate.cpp */,
+ 2ACF55CB1477693B00991ED5 /* emitterstate.h */,
+ 2ACF55CC1477693B00991ED5 /* emitterutils.cpp */,
+ 2ACF55CD1477693B00991ED5 /* emitterutils.h */,
+ 2ACF55CE1477693B00991ED5 /* exp.cpp */,
+ 2ACF55CF1477693B00991ED5 /* exp.h */,
+ 2ACF55D01477693B00991ED5 /* indentation.h */,
+ 2ACF55D11477693B00991ED5 /* iterator.cpp */,
+ 2ACF55D21477693B00991ED5 /* iterpriv.h */,
+ 2ACF55D31477693B00991ED5 /* node.cpp */,
+ 2ACF55D41477693B00991ED5 /* nodebuilder.cpp */,
+ 2ACF55D51477693B00991ED5 /* nodebuilder.h */,
+ 2ACF55D61477693B00991ED5 /* nodeownership.cpp */,
+ 2ACF55D71477693B00991ED5 /* nodeownership.h */,
+ 2ACF55D81477693B00991ED5 /* null.cpp */,
+ 2ACF55D91477693B00991ED5 /* ostream.cpp */,
+ 2ACF55DA1477693B00991ED5 /* parser.cpp */,
+ 2ACF55DB1477693B00991ED5 /* ptr_stack.h */,
+ 2ACF55DC1477693B00991ED5 /* ptr_vector.h */,
+ 2ACF55DD1477693B00991ED5 /* regex.cpp */,
+ 2ACF55DE1477693B00991ED5 /* regex.h */,
+ 2ACF55DF1477693B00991ED5 /* regeximpl.h */,
+ 2ACF55E01477693B00991ED5 /* scanner.cpp */,
+ 2ACF55E11477693B00991ED5 /* scanner.h */,
+ 2ACF55E21477693B00991ED5 /* scanscalar.cpp */,
+ 2ACF55E31477693B00991ED5 /* scanscalar.h */,
+ 2ACF55E41477693B00991ED5 /* scantag.cpp */,
+ 2ACF55E51477693B00991ED5 /* scantag.h */,
+ 2ACF55E61477693B00991ED5 /* scantoken.cpp */,
+ 2ACF55E71477693B00991ED5 /* setting.h */,
+ 2ACF55E81477693B00991ED5 /* simplekey.cpp */,
+ 2ACF55E91477693B00991ED5 /* singledocparser.cpp */,
+ 2ACF55EA1477693B00991ED5 /* singledocparser.h */,
+ 2ACF55EB1477693B00991ED5 /* stream.cpp */,
+ 2ACF55EC1477693B00991ED5 /* stream.h */,
+ 2ACF55ED1477693B00991ED5 /* streamcharsource.h */,
+ 2ACF55EE1477693B00991ED5 /* stringsource.h */,
+ 2ACF55EF1477693B00991ED5 /* tag.cpp */,
+ 2ACF55F01477693B00991ED5 /* tag.h */,
+ 2ACF55F11477693B00991ED5 /* token.h */,
+ );
+ path = src;
+ sourceTree = "<group>";
+ };
+ 2ACF55C11477693B00991ED5 /* contrib */ = {
+ isa = PBXGroup;
+ children = (
+ 2ACF55C21477693B00991ED5 /* graphbuilder.cpp */,
+ 2ACF55C31477693B00991ED5 /* graphbuilderadapter.cpp */,
+ 2ACF55C41477693B00991ED5 /* graphbuilderadapter.h */,
+ );
+ path = contrib;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 2ACF55981477692300991ED5 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2ACF55F21477693B00991ED5 /* aliasmanager.h in Headers */,
+ 2ACF55F31477693B00991ED5 /* anchor.h in Headers */,
+ 2ACF55F41477693B00991ED5 /* anchordict.h in Headers */,
+ 2ACF55F51477693B00991ED5 /* graphbuilder.h in Headers */,
+ 2ACF55F61477693B00991ED5 /* conversion.h in Headers */,
+ 2ACF55F71477693B00991ED5 /* dll.h in Headers */,
+ 2ACF55F81477693B00991ED5 /* emitfromevents.h in Headers */,
+ 2ACF55F91477693B00991ED5 /* emitter.h in Headers */,
+ 2ACF55FA1477693B00991ED5 /* emittermanip.h in Headers */,
+ 2ACF55FB1477693B00991ED5 /* eventhandler.h in Headers */,
+ 2ACF55FC1477693B00991ED5 /* exceptions.h in Headers */,
+ 2ACF55FD1477693B00991ED5 /* iterator.h in Headers */,
+ 2ACF55FE1477693B00991ED5 /* ltnode.h in Headers */,
+ 2ACF55FF1477693B00991ED5 /* mark.h in Headers */,
+ 2ACF56001477693B00991ED5 /* node.h in Headers */,
+ 2ACF56011477693B00991ED5 /* nodeimpl.h in Headers */,
+ 2ACF56021477693B00991ED5 /* nodereadimpl.h in Headers */,
+ 2ACF56031477693B00991ED5 /* nodeutil.h in Headers */,
+ 2ACF56041477693B00991ED5 /* noncopyable.h in Headers */,
+ 2ACF56051477693B00991ED5 /* null.h in Headers */,
+ 2ACF56061477693B00991ED5 /* ostream.h in Headers */,
+ 2ACF56071477693B00991ED5 /* parser.h in Headers */,
+ 2ACF56081477693B00991ED5 /* stlemitter.h in Headers */,
+ 2ACF56091477693B00991ED5 /* stlnode.h in Headers */,
+ 2ACF560A1477693B00991ED5 /* traits.h in Headers */,
+ 2ACF560B1477693B00991ED5 /* yaml.h in Headers */,
+ 2ACF560D1477693B00991ED5 /* collectionstack.h in Headers */,
+ 2ACF56101477693B00991ED5 /* graphbuilderadapter.h in Headers */,
+ 2ACF56131477693B00991ED5 /* directives.h in Headers */,
+ 2ACF56171477693B00991ED5 /* emitterstate.h in Headers */,
+ 2ACF56191477693B00991ED5 /* emitterutils.h in Headers */,
+ 2ACF561B1477693B00991ED5 /* exp.h in Headers */,
+ 2ACF561C1477693B00991ED5 /* indentation.h in Headers */,
+ 2ACF561E1477693B00991ED5 /* iterpriv.h in Headers */,
+ 2ACF56211477693B00991ED5 /* nodebuilder.h in Headers */,
+ 2ACF56231477693B00991ED5 /* nodeownership.h in Headers */,
+ 2ACF56271477693B00991ED5 /* ptr_stack.h in Headers */,
+ 2ACF56281477693B00991ED5 /* ptr_vector.h in Headers */,
+ 2ACF562A1477693B00991ED5 /* regex.h in Headers */,
+ 2ACF562B1477693B00991ED5 /* regeximpl.h in Headers */,
+ 2ACF562D1477693B00991ED5 /* scanner.h in Headers */,
+ 2ACF562F1477693B00991ED5 /* scanscalar.h in Headers */,
+ 2ACF56311477693B00991ED5 /* scantag.h in Headers */,
+ 2ACF56331477693B00991ED5 /* setting.h in Headers */,
+ 2ACF56361477693B00991ED5 /* singledocparser.h in Headers */,
+ 2ACF56381477693B00991ED5 /* stream.h in Headers */,
+ 2ACF56391477693B00991ED5 /* streamcharsource.h in Headers */,
+ 2ACF563A1477693B00991ED5 /* stringsource.h in Headers */,
+ 2ACF563C1477693B00991ED5 /* tag.h in Headers */,
+ 2ACF563D1477693B00991ED5 /* token.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 2ACF559B1477692300991ED5 /* yaml */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2ACF559F1477692B00991ED5 /* Build configuration list for PBXNativeTarget "yaml" */;
+ buildPhases = (
+ 2AF56976147991F700F9968C /* Unpack yaml */,
+ 2ACF55981477692300991ED5 /* Headers */,
+ 2ACF55991477692300991ED5 /* Sources */,
+ 2ACF559A1477692300991ED5 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = yaml;
+ productName = yaml;
+ productReference = 2ACF559C1477692300991ED5 /* libyaml.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 0867D690FE84028FC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 1DEB916408733D950010E9CD /* Build configuration list for PBXProject "yaml" */;
+ compatibilityVersion = "Xcode 3.1";
+ developmentRegion = English;
+ hasScannedForEncodings = 1;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
+ mainGroup = 0867D691FE84028FC02AAC07 /* yaml */;
+ productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 2ACF559B1477692300991ED5 /* yaml */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 2AF56976147991F700F9968C /* Unpack yaml */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/../../../../ext/yaml-cpp-0.3.0.tar.gz",
+ "$(SRCROOT)/../../../../ext/yaml-cpp-0.3.0.patch",
+ );
+ name = "Unpack yaml";
+ outputPaths = (
+ "$(SRCROOT)/../../../../ext/yaml-cpp",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "cd $SRCROOT/../../../../ext\n\nif [ ! -d yaml-cpp ]\nthen\n\ttar -xzf yaml-cpp-0.3.0.tar.gz\n\tpatch -p0 < yaml-cpp-0.3.0.patch\nfi\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 2ACF55991477692300991ED5 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2ACF560C1477693B00991ED5 /* aliasmanager.cpp in Sources */,
+ 2ACF560E1477693B00991ED5 /* graphbuilder.cpp in Sources */,
+ 2ACF560F1477693B00991ED5 /* graphbuilderadapter.cpp in Sources */,
+ 2ACF56111477693B00991ED5 /* conversion.cpp in Sources */,
+ 2ACF56121477693B00991ED5 /* directives.cpp in Sources */,
+ 2ACF56141477693B00991ED5 /* emitfromevents.cpp in Sources */,
+ 2ACF56151477693B00991ED5 /* emitter.cpp in Sources */,
+ 2ACF56161477693B00991ED5 /* emitterstate.cpp in Sources */,
+ 2ACF56181477693B00991ED5 /* emitterutils.cpp in Sources */,
+ 2ACF561A1477693B00991ED5 /* exp.cpp in Sources */,
+ 2ACF561D1477693B00991ED5 /* iterator.cpp in Sources */,
+ 2ACF561F1477693B00991ED5 /* node.cpp in Sources */,
+ 2ACF56201477693B00991ED5 /* nodebuilder.cpp in Sources */,
+ 2ACF56221477693B00991ED5 /* nodeownership.cpp in Sources */,
+ 2ACF56241477693B00991ED5 /* null.cpp in Sources */,
+ 2ACF56251477693B00991ED5 /* ostream.cpp in Sources */,
+ 2ACF56261477693B00991ED5 /* parser.cpp in Sources */,
+ 2ACF56291477693B00991ED5 /* regex.cpp in Sources */,
+ 2ACF562C1477693B00991ED5 /* scanner.cpp in Sources */,
+ 2ACF562E1477693B00991ED5 /* scanscalar.cpp in Sources */,
+ 2ACF56301477693B00991ED5 /* scantag.cpp in Sources */,
+ 2ACF56321477693B00991ED5 /* scantoken.cpp in Sources */,
+ 2ACF56341477693B00991ED5 /* simplekey.cpp in Sources */,
+ 2ACF56351477693B00991ED5 /* singledocparser.cpp in Sources */,
+ 2ACF56371477693B00991ED5 /* stream.cpp in Sources */,
+ 2ACF563B1477693B00991ED5 /* tag.cpp in Sources */,
+ 2AB6B01315538484007C3547 /* binary.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 1DEB916508733D950010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = "../../../../ext/yaml-cpp/include";
+ ONLY_ACTIVE_ARCH = YES;
+ PREBINDING = NO;
+ SDKROOT = macosx10.5;
+ };
+ name = Debug;
+ };
+ 1DEB916608733D950010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_PREPROCESSOR_DEFINITIONS = NDEBUG;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = "../../../../ext/yaml-cpp/include";
+ PREBINDING = NO;
+ SDKROOT = macosx10.5;
+ };
+ name = Release;
+ };
+ 2ACF559D1477692300991ED5 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ INSTALL_PATH = /usr/local/lib;
+ PREBINDING = NO;
+ PRODUCT_NAME = yaml;
+ };
+ name = Debug;
+ };
+ 2ACF559E1477692300991ED5 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/local/lib;
+ PREBINDING = NO;
+ PRODUCT_NAME = yaml;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1DEB916408733D950010E9CD /* Build configuration list for PBXProject "yaml" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB916508733D950010E9CD /* Debug */,
+ 1DEB916608733D950010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 2ACF559F1477692B00991ED5 /* Build configuration list for PBXNativeTarget "yaml" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2ACF559D1477692300991ED5 /* Debug */,
+ 2ACF559E1477692300991ED5 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
+}
diff --git a/src/apps/ociobakelut/CMakeLists.txt b/src/apps/ociobakelut/CMakeLists.txt
new file mode 100644
index 0000000..c15d156
--- /dev/null
+++ b/src/apps/ociobakelut/CMakeLists.txt
@@ -0,0 +1,46 @@
+# LCMS
+include(FindPkgConfig FindPackageMessage)
+pkg_check_modules(LCMS QUIET lcms2)
+if(LCMS_FOUND AND (LCMS_VERSION VERSION_EQUAL 2.1 OR LCMS_VERSION VERSION_GREATER 2.1))
+ FIND_PACKAGE_MESSAGE(LCMS "Found lcms: ${LCMS_LIBRARIES}"
+ "${LCMS_INCLUDE_DIR}")
+else()
+ message(STATUS "Using bundled lcms.")
+ set(LCMS_VERSION 2.1)
+ set(LCMS_BUNDLED TRUE)
+ ExternalProject_Add(LCMS
+ URL ${CMAKE_SOURCE_DIR}/ext/lcms2-${LCMS_VERSION}.tar.gz
+ BUILD_IN_SOURCE 1
+ CONFIGURE_COMMAND ./configure --prefix=${PROJECT_BINARY_DIR}/ext/dist --without-jpeg --without-tiff --without-zlib
+ BUILD_COMMAND make
+ INSTALL_COMMAND make install
+ )
+ set(LCMS_INCLUDE_DIRS ${PROJECT_BINARY_DIR}/ext/dist/include)
+ set(LCMS_LIBRARY_DIRS ${PROJECT_BINARY_DIR}/ext/dist/lib)
+ set(LCMS_LIBRARIES ${PROJECT_BINARY_DIR}/ext/dist/lib/liblcms2.a)
+endif()
+
+file(GLOB_RECURSE share_src_files "${CMAKE_SOURCE_DIR}/src/apps/share/*.cpp")
+
+include_directories(
+ ${CMAKE_SOURCE_DIR}/export/
+ ${CMAKE_BINARY_DIR}/export/
+ ${CMAKE_SOURCE_DIR}/src/apps/share/
+ ${LCMS_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${LCMS_LIBRARY_DIRS}
+)
+
+add_executable(ociobakelut ${share_src_files} main.cpp ocioicc.cpp)
+
+if(LCMS_BUNDLED)
+ add_dependencies(ociobakelut LCMS)
+endif()
+
+target_link_libraries(ociobakelut
+ ${LCMS_LIBRARIES}
+ OpenColorIO)
+
+install(TARGETS ociobakelut DESTINATION ${CMAKE_INSTALL_EXEC_PREFIX}/bin)
diff --git a/src/apps/ociobakelut/main.cpp b/src/apps/ociobakelut/main.cpp
new file mode 100644
index 0000000..265d464
--- /dev/null
+++ b/src/apps/ociobakelut/main.cpp
@@ -0,0 +1,537 @@
+/*
+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 <cmath>
+#include <cstdlib>
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <vector>
+
+#include <OpenColorIO/OpenColorIO.h>
+namespace OCIO = OCIO_NAMESPACE;
+
+#include "argparse.h"
+#include "ocioicc.h"
+
+static std::string outputfile;
+
+static int
+parse_end_args(int argc, const char *argv[])
+{
+ if(argc>0)
+ {
+ outputfile = argv[0];
+ }
+
+ return 0;
+}
+
+OCIO::GroupTransformRcPtr
+parse_luts(int argc, const char *argv[]);
+
+int main (int argc, const char* argv[])
+{
+
+ bool help = false;
+ int cubesize = -1;
+ int shapersize = -1; // cubsize^2
+ std::string format;
+ std::string inputconfig;
+ std::string inputspace;
+ std::string shaperspace;
+ std::string looks;
+ std::string outputspace;
+ bool usestdout = false;
+ bool verbose = false;
+
+ int whitepointtemp = 6505;
+ std::string displayicc;
+ std::string description;
+ std::string copyright = "OpenColorIO (Sony Imageworks)";
+
+ // What are the allowed baker output formats?
+ std::ostringstream formats;
+ formats << "the lut format to bake: ";
+ for(int i=0; i<OCIO::Baker::getNumFormats(); ++i)
+ {
+ if(i!=0) formats << ", ";
+ formats << OCIO::Baker::getFormatNameByIndex(i);
+ formats << " (." << OCIO::Baker::getFormatExtensionByIndex(i) << ")";
+ }
+ formats << ", icc (.icc)";
+
+ std::string formatstr = formats.str();
+
+ std::string dummystr;
+ float dummyf1, dummyf2, dummyf3;
+
+ ArgParse ap;
+ ap.options("ociobakelut -- create a new LUT or icc profile from an OCIO config or lut file(s)\n\n"
+ "usage: ociobakelut [options] <OUTPUTFILE.LUT>\n\n"
+ "example: ociobakelut --inputspace lg10 --outputspace srgb8 --format flame lg_to_srgb.3dl\n"
+ "example: ociobakelut --lut filmlut.3dl --lut calibration.3dl --format flame display.3dl\n"
+ "example: ociobakelut --lut look.3dl --offset 0.01 -0.02 0.03 --lut display.3dl --format flame display_with_look.3dl\n"
+ "example: ociobakelut --inputspace lg10 --outputspace srgb8 --format icc ~/Library/ColorSync/Profiles/test.icc\n"
+ "example: ociobakelut --lut filmlut.3dl --lut calibration.3dl --format icc ~/Library/ColorSync/Profiles/test.icc\n\n",
+ "%*", parse_end_args, "",
+ "<SEPARATOR>", "Using Existing OCIO Configurations",
+ "--inputspace %s", &inputspace, "Input OCIO ColorSpace (or Role)",
+ "--outputspace %s", &outputspace, "Output OCIO ColorSpace (or Role)",
+ "--shaperspace %s", &shaperspace, "the OCIO ColorSpace or Role, for the shaper",
+ "--looks %s", &looks, "the OCIO looks to apply",
+ "--iconfig %s", &inputconfig, "Input .ocio configuration file (default: $OCIO)\n",
+ "<SEPARATOR>", "Config-Free LUT Baking",
+ "<SEPARATOR>", " (all options can be specified multiple times, each is applied in order)",
+ "--lut %s", &dummystr, "Specify a LUT (forward direction)",
+ "--invlut %s", &dummystr, "Specify a LUT (inverse direction)",
+ "--slope %f %f %f", &dummyf1, &dummyf2, &dummyf3, "slope",
+ "--offset %f %f %f", &dummyf1, &dummyf2, &dummyf3, "offset (float)",
+ "--offset10 %f %f %f", &dummyf1, &dummyf2, &dummyf3, "offset (10-bit)",
+ "--power %f %f %f", &dummyf1, &dummyf2, &dummyf3, "power",
+ "--sat %f", &dummyf1, "saturation (ASC-CDL luma coefficients)\n",
+ "<SEPARATOR>", "Baking Options",
+ "--format %s", &format, formatstr.c_str(),
+ "--shapersize %d", &shapersize, "size of the shaper (default: format specific)",
+ "--cubesize %d", &cubesize, "size of the cube (default: format specific)",
+ "--stdout", &usestdout, "Write to stdout (rather than file)",
+ "--v", &verbose, "Verbose",
+ "--help", &help, "Print help message\n",
+ "<SEPARATOR>", "ICC Options",
+ //"--cubesize %d", &cubesize, "size of the icc CLUT cube (default: 32)",
+ "--whitepoint %d", &whitepointtemp, "whitepoint for the profile (default: 6505)",
+ "--displayicc %s", &displayicc , "an icc profile which matches the OCIO profiles target display",
+ "--description %s", &description , "a meaningful description, this will show up in UI like photoshop",
+ "--copyright %s", &copyright , "a copyright field\n",
+ // TODO: add --metadata option
+ NULL);
+
+ if (ap.parse(argc, argv) < 0)
+ {
+ std::cout << ap.geterror() << std::endl;
+ ap.usage();
+ std::cout << "\n";
+ return 1;
+ }
+
+ if (help || (argc == 1 ))
+ {
+ ap.usage();
+ std::cout << "\n";
+ return 1;
+ }
+
+ // If we're printing to stdout, disable verbose printouts
+ if(usestdout)
+ {
+ verbose = false;
+ }
+
+ // Create the OCIO processor for the specified transform.
+ OCIO::ConstConfigRcPtr config;
+
+
+ OCIO::GroupTransformRcPtr groupTransform;
+
+ try
+ {
+ groupTransform = parse_luts(argc, argv);
+ }
+ catch(const OCIO::Exception & e)
+ {
+ std::cerr << "\nERROR: " << e.what() << std::endl;
+ std::cerr << "See --help for more info." << std::endl;
+ return 1;
+ }
+ catch(...)
+ {
+ std::cerr << "\nERROR: An unknown error occurred in parse_luts" << std::endl;
+ std::cerr << "See --help for more info." << std::endl;
+ return 1;
+ }
+
+ if(!groupTransform)
+ {
+ std::cerr << "\nERROR: parse_luts returned null transform" << std::endl;
+ std::cerr << "See --help for more info." << std::endl;
+ return 1;
+ }
+
+ // If --luts have been specified, synthesize a new (temporary) configuration
+ // with the transformation embedded in a colorspace.
+ if(!groupTransform->empty())
+ {
+ if(!inputspace.empty())
+ {
+ std::cerr << "\nERROR: --inputspace is not allowed when using --lut\n\n";
+ std::cerr << "See --help for more info." << std::endl;
+ return 1;
+ }
+ if(!outputspace.empty())
+ {
+ std::cerr << "\nERROR: --outputspace is not allowed when using --lut\n\n";
+ std::cerr << "See --help for more info." << std::endl;
+ return 1;
+ }
+ if(!looks.empty())
+ {
+ std::cerr << "\nERROR: --looks is not allowed when using --lut\n\n";
+ std::cerr << "See --help for more info." << std::endl;
+ return 1;
+ }
+ if(!shaperspace.empty())
+ {
+ std::cerr << "\nERROR: --shaperspace is not allowed when using --lut\n\n";
+ std::cerr << "See --help for more info." << std::endl;
+ return 1;
+ }
+
+ OCIO::ConfigRcPtr editableConfig = OCIO::Config::Create();
+
+ OCIO::ColorSpaceRcPtr inputColorSpace = OCIO::ColorSpace::Create();
+ inputspace = "RawInput";
+ inputColorSpace->setName(inputspace.c_str());
+ editableConfig->addColorSpace(inputColorSpace);
+
+ OCIO::ColorSpaceRcPtr outputColorSpace = OCIO::ColorSpace::Create();
+ outputspace = "ProcessedOutput";
+ outputColorSpace->setName(outputspace.c_str());
+
+ outputColorSpace->setTransform(groupTransform,
+ OCIO::COLORSPACE_DIR_FROM_REFERENCE);
+
+ if(verbose)
+ {
+ std::cout << "[OpenColorIO DEBUG]: Specified Transform:";
+ std::cout << *groupTransform;
+ std::cout << "\n";
+ }
+
+ editableConfig->addColorSpace(outputColorSpace);
+ config = editableConfig;
+ }
+ else
+ {
+
+ if(inputspace.empty())
+ {
+ std::cerr << "\nERROR: You must specify the --inputspace.\n\n";
+ std::cerr << "See --help for more info." << std::endl;
+ return 1;
+ }
+
+ if(outputspace.empty())
+ {
+ std::cerr << "\nERROR: You must specify the --outputspace.\n\n";
+ std::cerr << "See --help for more info." << std::endl;
+ return 1;
+ }
+
+ if(format.empty())
+ {
+ std::cerr << "\nERROR: You must specify the lut format using --format.\n\n";
+ std::cerr << "See --help for more info." << std::endl;
+ return 1;
+ }
+
+ if(!inputconfig.empty())
+ {
+ if(!usestdout && verbose)
+ std::cout << "[OpenColorIO INFO]: Loading " << inputconfig << std::endl;
+ config = OCIO::Config::CreateFromFile(inputconfig.c_str());
+ }
+ else if(getenv("OCIO"))
+ {
+ if(!usestdout && verbose)
+ std::cout << "[OpenColorIO INFO]: Loading $OCIO " << getenv("OCIO") << std::endl;
+ config = OCIO::Config::CreateFromEnv();
+ }
+ else
+ {
+ std::cerr << "ERROR: You must specify an input ocio configuration ";
+ std::cerr << "(either with --iconfig or $OCIO).\n\n";
+ ap.usage ();
+ return 1;
+ }
+ }
+
+ if(outputfile.empty() && !usestdout)
+ {
+ std::cerr << "\nERROR: You must specify the outputfile or --stdout.\n\n";
+ std::cerr << "See --help for more info." << std::endl;
+ return 1;
+ }
+
+ try
+ {
+ if(format == "icc")
+ {
+ if(usestdout)
+ {
+ std::cerr << "\nERROR: --stdout not supported when writing icc profiles.\n\n";
+ std::cerr << "See --help for more info." << std::endl;
+ return 1;
+ }
+
+ if(outputfile.empty())
+ {
+ std::cerr << "ERROR: you need to specify a output icc path\n";
+ std::cerr << "See --help for more info." << std::endl;
+ return 1;
+ }
+
+ if(copyright.empty())
+ {
+ std::cerr << "ERROR: need to specify a --copyright to embed in the icc profile\n";
+ std::cerr << "See --help for more info." << std::endl;
+ return 1;
+ }
+
+ if(cubesize<2) cubesize = 32; // default
+
+ OCIO::ConstProcessorRcPtr processor;
+ if (!looks.empty())
+ {
+ OCIO::LookTransformRcPtr transform =
+ OCIO::LookTransform::Create();
+ transform->setLooks(looks.c_str());
+ transform->setSrc(inputspace.c_str());
+ transform->setDst(outputspace.c_str());
+ processor = config->getProcessor(transform,
+ OCIO::TRANSFORM_DIR_FORWARD);
+ }
+ else
+ {
+ processor = config->getProcessor(inputspace.c_str(),
+ outputspace.c_str());
+ }
+
+ SaveICCProfileToFile(outputfile,
+ processor,
+ cubesize,
+ whitepointtemp,
+ displayicc,
+ description,
+ copyright,
+ verbose);
+ }
+ else
+ {
+
+ OCIO::BakerRcPtr baker = OCIO::Baker::Create();
+
+ // setup the baker for our lut type
+ baker->setConfig(config);
+ baker->setFormat(format.c_str());
+ baker->setInputSpace(inputspace.c_str());
+ baker->setShaperSpace(shaperspace.c_str());
+ baker->setLooks(looks.c_str());
+ baker->setTargetSpace(outputspace.c_str());
+ if(shapersize!=-1) baker->setShaperSize(shapersize);
+ if(cubesize!=-1) baker->setCubeSize(cubesize);
+
+ // output lut
+ std::ostringstream output;
+
+ if(!usestdout && verbose)
+ std::cout << "[OpenColorIO INFO]: Baking '" << format << "' lut" << std::endl;
+
+ if(usestdout)
+ {
+ baker->bake(std::cout);
+ }
+ else
+ {
+ std::ofstream f(outputfile.c_str());
+ baker->bake(f);
+ if(verbose)
+ std::cout << "[OpenColorIO INFO]: Wrote '" << outputfile << "'" << std::endl;
+ }
+ }
+ }
+ catch(OCIO::Exception & exception)
+ {
+ std::cerr << "OCIO Error: " << exception.what() << std::endl;
+ std::cerr << "See --help for more info." << std::endl;
+ return 1;
+ }
+ catch (std::exception& exception)
+ {
+ std::cerr << "Error: " << exception.what() << "\n";
+ std::cerr << "See --help for more info." << std::endl;
+ return 1;
+ }
+ catch(...)
+ {
+ std::cerr << "Unknown OCIO error encountered." << std::endl;
+ std::cerr << "See --help for more info." << std::endl;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+// TODO: Replace this dirty argument parsing code with a clean version
+// that leverages the same codepath for the standard arguments. If
+// the OIIO derived argparse does not suffice, options we may want to consider
+// include simpleopt, tclap, ultraopt
+
+// TODO: Use better input validation, instead of atof.
+// If too few arguments are provides for scale (let's say only two) and
+// the following argument is the start of another flag (let's say "--invlut")
+// then atof() will likely try to convert "--invlut" to its double equivalent,
+// resulting in an invalid (or at least undesired) scale value.
+
+OCIO::GroupTransformRcPtr
+parse_luts(int argc, const char *argv[])
+{
+ OCIO::GroupTransformRcPtr groupTransform = OCIO::GroupTransform::Create();
+
+ for(int i=0; i<argc; ++i)
+ {
+ std::string arg(argv[i]);
+
+ if(arg == "--lut" || arg == "-lut")
+ {
+ if(i+1>=argc)
+ {
+ throw OCIO::Exception("Error parsing --lut. Invalid num args");
+ }
+
+ OCIO::FileTransformRcPtr t = OCIO::FileTransform::Create();
+ t->setSrc(argv[i+1]);
+ t->setInterpolation(OCIO::INTERP_BEST);
+ groupTransform->push_back(t);
+
+ i += 1;
+ }
+ else if(arg == "--invlut" || arg == "-invlut")
+ {
+ if(i+1>=argc)
+ {
+ throw OCIO::Exception("Error parsing --invlut. Invalid num args");
+ }
+
+ OCIO::FileTransformRcPtr t = OCIO::FileTransform::Create();
+ t->setSrc(argv[i+1]);
+ t->setInterpolation(OCIO::INTERP_BEST);
+ t->setDirection(OCIO::TRANSFORM_DIR_INVERSE);
+ groupTransform->push_back(t);
+
+ i += 1;
+ }
+ else if(arg == "--slope" || arg == "-slope")
+ {
+ if(i+3>=argc)
+ {
+ throw OCIO::Exception("Error parsing --slope. Invalid num args");
+ }
+
+ OCIO::CDLTransformRcPtr t = OCIO::CDLTransform::Create();
+
+ float scale[3];
+ scale[0] = (float) atof(argv[i+1]);
+ scale[1] = (float) atof(argv[i+2]);
+ scale[2] = (float) atof(argv[i+3]);
+ t->setSlope(scale);
+ groupTransform->push_back(t);
+
+ i += 3;
+ }
+ else if(arg == "--offset" || arg == "-offset")
+ {
+ if(i+3>=argc)
+ {
+ throw OCIO::Exception("Error parsing --offset. Invalid num args");
+ }
+
+ OCIO::CDLTransformRcPtr t = OCIO::CDLTransform::Create();
+
+ float offset[3];
+ offset[0] = (float) atof(argv[i+1]);
+ offset[1] = (float) atof(argv[i+2]);
+ offset[2] = (float) atof(argv[i+3]);
+ t->setOffset(offset);
+ groupTransform->push_back(t);
+
+ i += 3;
+ }
+ else if(arg == "--offset10" || arg == "-offset10")
+ {
+ if(i+3>=argc)
+ {
+ throw OCIO::Exception("Error parsing --offset10. Invalid num args");
+ }
+
+ OCIO::CDLTransformRcPtr t = OCIO::CDLTransform::Create();
+
+ float offset[3];
+ offset[0] = (float) atof(argv[i+1]) / 1023.0f;
+ offset[1] = (float) atof(argv[i+2]) / 1023.0f;
+ offset[2] = (float) atof(argv[i+3]) / 1023.0f;
+ t->setOffset(offset);
+ groupTransform->push_back(t);
+ i += 3;
+ }
+ else if(arg == "--power" || arg == "-power")
+ {
+ if(i+3>=argc)
+ {
+ throw OCIO::Exception("Error parsing --power. Invalid num args");
+ }
+
+ OCIO::CDLTransformRcPtr t = OCIO::CDLTransform::Create();
+
+ float power[3];
+ power[0] = (float) atof(argv[i+1]);
+ power[1] = (float) atof(argv[i+2]);
+ power[2] = (float) atof(argv[i+3]);
+ t->setPower(power);
+ groupTransform->push_back(t);
+
+ i += 3;
+ }
+ else if(arg == "--sat" || arg == "-sat")
+ {
+ if(i+1>=argc)
+ {
+ throw OCIO::Exception("Error parsing --sat. Invalid num args");
+ }
+
+ OCIO::CDLTransformRcPtr t = OCIO::CDLTransform::Create();
+ t->setSat((float) atof(argv[i+1]));
+ groupTransform->push_back(t);
+
+ i += 1;
+ }
+ }
+
+ return groupTransform;
+}
+
diff --git a/src/apps/ociobakelut/ocioicc.cpp b/src/apps/ociobakelut/ocioicc.cpp
new file mode 100644
index 0000000..2975f4a
--- /dev/null
+++ b/src/apps/ociobakelut/ocioicc.cpp
@@ -0,0 +1,251 @@
+/*
+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 <cmath>
+#include <cstring>
+#include <cstdlib>
+#include <iostream>
+#include <sstream>
+#include <vector>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "ocioicc.h"
+
+#include "lcms2.h"
+#include "lcms2_plugin.h"
+
+OCIO_NAMESPACE_ENTER
+{
+
+
+namespace
+{
+void ErrorHandler(cmsContext /*ContextID*/, cmsUInt32Number /*ErrorCode*/, const char *Text)
+{
+ std::cerr << "OCIO Error: " << Text << "\n";
+ return;
+}
+
+typedef struct
+{
+ cmsHTRANSFORM to_PCS16;
+ cmsHTRANSFORM from_PCS16;
+ //OCIO::ConstProcessorRcPtr shaper_processor;
+ OCIO::ConstProcessorRcPtr processor;
+} SamplerData;
+
+static void Add3GammaCurves(cmsPipeline* lut, cmsFloat64Number Curve)
+{
+ cmsToneCurve* id = cmsBuildGamma(NULL, Curve);
+ cmsToneCurve* id3[3];
+ id3[0] = id;
+ id3[1] = id;
+ id3[2] = id;
+ cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(NULL, 3, id3));
+ cmsFreeToneCurve(id);
+}
+
+static void AddIdentityMatrix(cmsPipeline* lut)
+{
+ const cmsFloat64Number Identity[] = {
+ 1, 0, 0,
+ 0, 1, 0,
+ 0, 0, 1,
+ 0, 0, 0 };
+ cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocMatrix(NULL, 3, 3, Identity, NULL));
+}
+
+static cmsInt32Number Display2PCS_Sampler16(const cmsUInt16Number in[], cmsUInt16Number out[], void* userdata)
+{
+ //std::cout << "r" << in[0] << " g" << in[1] << " b" << in[2] << "\n";
+ SamplerData* data = (SamplerData*) userdata;
+ cmsFloat32Number pix[3] = { static_cast<float>(in[0])/65535.f,
+ static_cast<float>(in[1])/65535.f,
+ static_cast<float>(in[2])/65535.f};
+ data->processor->applyRGB(pix);
+ out[0] = (cmsUInt16Number)std::max(std::min(pix[0] * 65535.f, 65535.f), 0.f);
+ out[1] = (cmsUInt16Number)std::max(std::min(pix[1] * 65535.f, 65535.f), 0.f);
+ out[2] = (cmsUInt16Number)std::max(std::min(pix[2] * 65535.f, 65535.f), 0.f);
+ cmsDoTransform(data->to_PCS16, out, out, 1);
+ return 1;
+}
+
+static cmsInt32Number PCS2Display_Sampler16(const cmsUInt16Number in[], cmsUInt16Number out[], void* userdata)
+{
+ //std::cout << "r" << in[0] << " g" << in[1] << " b" << in[2] << "\n";
+ SamplerData* data = (SamplerData*) userdata;
+ cmsDoTransform(data->from_PCS16, in, out, 1);
+ // we don't have a reverse Lab -> Display transform
+ return 1;
+}
+} // anon namespace
+
+
+void SaveICCProfileToFile(const std::string & outputfile,
+ ConstProcessorRcPtr & processor,
+ int cubesize,
+ int whitepointtemp,
+ const std::string & displayicc,
+ const std::string & description,
+ const std::string & copyright,
+ bool verbose)
+{
+
+ // Create the ICC Profile
+
+ // Setup the Error Handler
+ cmsSetLogErrorHandler(ErrorHandler);
+
+ // D65 white point
+ cmsCIExyY whitePoint;
+ cmsWhitePointFromTemp(&whitePoint, whitepointtemp);
+
+ // LAB PCS
+ cmsHPROFILE labProfile = cmsCreateLab4ProfileTHR(NULL, &whitePoint);
+
+ // Display (OCIO sRGB cube -> LAB)
+ cmsHPROFILE DisplayProfile;
+ if(displayicc != "") DisplayProfile = cmsOpenProfileFromFile(displayicc.c_str(), "r");
+ else DisplayProfile = cmsCreate_sRGBProfileTHR(NULL);
+
+ // Create an empty RGB Profile
+ cmsHPROFILE hProfile = cmsCreateRGBProfileTHR(NULL, &whitePoint, NULL, NULL);
+
+ if(verbose)
+ std::cout << "[OpenColorIO INFO]: Setting up Profile: " << outputfile << "\n";
+
+ // Added Header fields
+ cmsSetProfileVersion(hProfile, 4.2);
+ cmsSetDeviceClass(hProfile, cmsSigDisplayClass);
+ cmsSetColorSpace(hProfile, cmsSigRgbData);
+ cmsSetPCS(hProfile, cmsSigLabData);
+ cmsSetHeaderRenderingIntent(hProfile, INTENT_PERCEPTUAL);
+
+ //
+ cmsMLU* DescriptionMLU = cmsMLUalloc(NULL, 1);
+ cmsMLU* CopyrightMLU = cmsMLUalloc(NULL, 1);
+ cmsMLUsetASCII(DescriptionMLU, "en", "US", description.c_str());
+ cmsMLUsetASCII(CopyrightMLU, "en", "US", copyright.c_str());
+ cmsWriteTag(hProfile, cmsSigProfileDescriptionTag, DescriptionMLU);
+ cmsWriteTag(hProfile, cmsSigCopyrightTag, CopyrightMLU);
+
+ //
+ SamplerData data;
+ data.processor = processor;
+
+ // 16Bit
+ data.to_PCS16 = cmsCreateTransform(DisplayProfile, TYPE_RGB_16, labProfile, TYPE_LabV2_16,
+ INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE);
+ data.from_PCS16 = cmsCreateTransform(labProfile, TYPE_LabV2_16, DisplayProfile, TYPE_RGB_16,
+ INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE);
+
+ //
+ // AToB0Tag - Device to PCS (16-bit) intent of 0 (perceptual)
+ //
+ // cmsSigCurveSetElemType
+ // `- cmsSigCLutElemType
+ // `- cmsSigCurveSetElemType
+ // `- cmsSigMatrixElemType
+ // `- cmsSigCurveSetElemType
+ //
+
+ if(verbose)
+ std::cout << "[OpenColorIO INFO]: Adding AToB0Tag\n";
+ cmsPipeline* AToB0Tag = cmsPipelineAlloc(NULL, 3, 3);
+
+ Add3GammaCurves(AToB0Tag, 1.f); // cmsSigCurveSetElemType
+
+ // cmsSigCLutElemType
+ cmsStage* AToB0Clut = cmsStageAllocCLut16bit(NULL, cubesize, 3, 3, NULL);
+
+ if(verbose)
+ std::cout << "[OpenColorIO INFO]: Sampling AToB0 CLUT from Display to Lab\n";
+ cmsStageSampleCLut16bit(AToB0Clut, Display2PCS_Sampler16, &data, 0);
+ cmsPipelineInsertStage(AToB0Tag, cmsAT_END, AToB0Clut);
+
+ Add3GammaCurves(AToB0Tag, 1.f); // cmsSigCurveSetElemType
+ AddIdentityMatrix(AToB0Tag); // cmsSigMatrixElemType
+ Add3GammaCurves(AToB0Tag, 1.f); // cmsSigCurveSetElemType
+
+ // Add AToB0Tag
+ cmsWriteTag(hProfile, cmsSigAToB0Tag, AToB0Tag);
+ cmsPipelineFree(AToB0Tag);
+
+ //
+ // BToA0Tag - PCS to Device space (16-bit) intent of 0 (perceptual)
+ //
+ // cmsSigCurveSetElemType
+ // `- cmsSigMatrixElemType
+ // `- cmsSigCurveSetElemType
+ // `- cmsSigCLutElemType
+ // `- cmsSigCurveSetElemType
+ //
+ if(verbose)
+ std::cout << "[OpenColorIO INFO]: Adding BToA0Tag\n";
+ cmsPipeline* BToA0Tag = cmsPipelineAlloc(NULL, 3, 3);
+
+ Add3GammaCurves(BToA0Tag, 1.f); // cmsSigCurveSetElemType
+ AddIdentityMatrix(BToA0Tag); // cmsSigMatrixElemType
+ Add3GammaCurves(BToA0Tag, 1.f); // cmsSigCurveSetElemType
+
+ // cmsSigCLutElemType
+ cmsStage* BToA0Clut = cmsStageAllocCLut16bit(NULL, cubesize, 3, 3, NULL);
+ if(verbose)
+ std::cout << "[OpenColorIO INFO]: Sampling BToA0 CLUT from Lab to Display\n";
+ cmsStageSampleCLut16bit(BToA0Clut, PCS2Display_Sampler16, &data, 0);
+ cmsPipelineInsertStage(BToA0Tag, cmsAT_END, BToA0Clut);
+
+ Add3GammaCurves(BToA0Tag, 1.f); // cmsSigCurveSetElemType
+
+ // Add BToA0Tag
+ cmsWriteTag(hProfile, cmsSigBToA0Tag, BToA0Tag);
+ cmsPipelineFree(BToA0Tag);
+
+ //
+ // D2Bx - Device to PCS (float) (Not Yet Impl)
+ //
+
+ //
+ // B2Dx - PCS to Device (float) (Not Yet Impl)
+ //
+
+ //
+ // Write
+ //
+ if(verbose)
+ std::cout << "[OpenColorIO INFO]: Writing " << outputfile << std::endl;
+ cmsSaveProfileToFile(hProfile, outputfile.c_str());
+ cmsCloseProfile(hProfile);
+
+ if(verbose)
+ std::cout << "[OpenColorIO INFO]: Finished\n";
+}
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/apps/ociobakelut/ocioicc.h b/src/apps/ociobakelut/ocioicc.h
new file mode 100644
index 0000000..030fbe3
--- /dev/null
+++ b/src/apps/ociobakelut/ocioicc.h
@@ -0,0 +1,71 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_OCIOICC_H
+#define INCLUDED_OCIO_OCIOICC_H
+
+#include <string>
+
+#include <OpenColorIO/OpenColorIO.h>
+namespace OCIO = OCIO_NAMESPACE;
+
+OCIO_NAMESPACE_ENTER
+{
+
+//
+// Build an ICC profile for doing soft proofing
+//
+// N-component LUT-based display profile required tags
+// ------------------------------------------------------------------------------
+// Tag Name General Description
+// ------------------------------------------------------------------------------
+// profileDescriptionTag Structure containing invariant and localizable
+// versions of the profile name for display
+// AToB0Tag Device to PCS: 8-bit or 16-bit data: intent of 0
+// BToA0Tag PCS to Device space: 8-bit or 16-bit data: intent of 0
+// mediaWhitePointTag Media XYZ white point
+// copyrightTag Profile copyright information
+// chromaticAdaptationTag Converts XYZ colour from the actual illumination
+// source to PCS illuminant. Required only if the actual
+// illumination source is not D50.
+
+void SaveICCProfileToFile(const std::string & outputfile,
+ ConstProcessorRcPtr & processor,
+ int cubesize,
+ int whitepointtemp,
+ const std::string & displayicc,
+ const std::string & description,
+ const std::string & copyright,
+ bool verbose);
+
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
+
diff --git a/src/apps/ociocheck/CMakeLists.txt b/src/apps/ociocheck/CMakeLists.txt
new file mode 100644
index 0000000..f8902e4
--- /dev/null
+++ b/src/apps/ociocheck/CMakeLists.txt
@@ -0,0 +1,17 @@
+file(GLOB_RECURSE share_src_files "${CMAKE_SOURCE_DIR}/src/apps/share/*.cpp")
+
+include_directories(
+ ${CMAKE_SOURCE_DIR}/export/
+ ${CMAKE_BINARY_DIR}/export/
+ ${CMAKE_SOURCE_DIR}/src/apps/share/
+ )
+
+add_executable(ociocheck
+ main.cpp
+ ${share_src_files})
+
+target_link_libraries(ociocheck
+ OpenColorIO
+ )
+
+install(TARGETS ociocheck DESTINATION ${CMAKE_INSTALL_EXEC_PREFIX}/bin)
diff --git a/src/apps/ociocheck/main.cpp b/src/apps/ociocheck/main.cpp
new file mode 100644
index 0000000..725985e
--- /dev/null
+++ b/src/apps/ociocheck/main.cpp
@@ -0,0 +1,301 @@
+/*
+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 <cstdlib>
+#include <iostream>
+#include <fstream>
+#include <set>
+#include <vector>
+
+#include <OpenColorIO/OpenColorIO.h>
+namespace OCIO = OCIO_NAMESPACE;
+
+#include "argparse.h"
+
+
+const char * DESC_STRING = "\n\n"
+"ociocheck is useful to validate that the specified .ocio configuration\n"
+"is valid, and that all the color transforms are defined.\n"
+"For example, it is possible that the configuration may reference\n"
+"lookup tables that do not exist. ociocheck will find these cases.\n\n"
+"ociocheck can also be used to clean up formatting on an existing profile\n"
+"that has been manually edited, using the '-o' option.\n";
+
+int main(int argc, const char **argv)
+{
+ bool help = false;
+ int errorcount = 0;
+ std::string inputconfig;
+ std::string outputconfig;
+
+ ArgParse ap;
+ ap.options("ociocheck -- validate an OpenColorIO configuration\n\n"
+ "usage: ociocheck [options]\n",
+ "--help", &help, "Print help message",
+ "--iconfig %s", &inputconfig, "Input .ocio configuration file (default: $OCIO)",
+ "--oconfig %s", &outputconfig, "Output .ocio file",
+ NULL);
+
+ if (ap.parse(argc, argv) < 0)
+ {
+ std::cout << ap.geterror() << std::endl;
+ ap.usage();
+ std::cout << DESC_STRING;
+ return 1;
+ }
+
+ if (help)
+ {
+ ap.usage();
+ std::cout << DESC_STRING;
+ return 1;
+ }
+
+ try
+ {
+ OCIO::ConstConfigRcPtr config;
+
+ std::cout << std::endl;
+ std::cout << "OpenColorIO Library Version: " << OCIO::GetVersion() << std::endl;
+ std::cout << "OpenColorIO Library VersionHex: " << OCIO::GetVersionHex() << std::endl;
+
+ if(!inputconfig.empty())
+ {
+ std::cout << "Loading " << inputconfig << std::endl;
+ config = OCIO::Config::CreateFromFile(inputconfig.c_str());
+ }
+ else if(getenv("OCIO"))
+ {
+ std::cout << "Loading $OCIO " << getenv("OCIO") << std::endl;
+ config = OCIO::Config::CreateFromEnv();
+ }
+ else
+ {
+ std::cout << "ERROR: You must specify an input ocio configuration ";
+ std::cout << "(either with --iconfig or $OCIO).\n";
+ ap.usage ();
+ std::cout << DESC_STRING;
+ return 1;
+ }
+
+ std::cout << std::endl;
+ std::cout << "** General **" << std::endl;
+ std::cout << "Search Path: " << config->getSearchPath() << std::endl;
+ std::cout << "Working Dir: " << config->getWorkingDir() << std::endl;
+
+ std::cout << std::endl;
+ std::cout << "Default Display: " << config->getDefaultDisplay() << std::endl;
+ std::cout << "Default View: " << config->getDefaultView(config->getDefaultDisplay()) << std::endl;
+
+ {
+ std::cout << std::endl;
+ std::cout << "** Roles **" << std::endl;
+
+ std::set<std::string> usedroles;
+ const char * allroles[] = { OCIO::ROLE_DEFAULT, OCIO::ROLE_SCENE_LINEAR,
+ OCIO::ROLE_DATA, OCIO::ROLE_REFERENCE,
+ OCIO::ROLE_COMPOSITING_LOG, OCIO::ROLE_COLOR_TIMING,
+ OCIO::ROLE_COLOR_PICKING,
+ OCIO::ROLE_TEXTURE_PAINT, OCIO::ROLE_MATTE_PAINT,
+ NULL };
+ int MAXROLES=256;
+ for(int i=0;i<MAXROLES; ++i)
+ {
+ const char * role = allroles[i];
+ if(!role) break;
+ usedroles.insert(role);
+
+ OCIO::ConstColorSpaceRcPtr cs = config->getColorSpace(role);
+ if(cs)
+ {
+ std::cout << cs->getName() << " (" << role << ")" << std::endl;
+ }
+ else
+ {
+ std::cout << "ERROR: NOT DEFINED" << " (" << role << ")" << std::endl;
+ errorcount += 1;
+ }
+ }
+
+ for(int i=0; i<config->getNumRoles(); ++i)
+ {
+ const char * role = config->getRoleName(i);
+ if(usedroles.find(role) != usedroles.end()) continue;
+
+ OCIO::ConstColorSpaceRcPtr cs = config->getColorSpace(role);
+ if(cs)
+ {
+ std::cout << cs->getName() << " (" << role << ": user)" << std::endl;
+ }
+ else
+ {
+ std::cout << "ERROR: NOT DEFINED" << " (" << role << ")" << std::endl;
+ errorcount += 1;
+ }
+
+ }
+ }
+
+ std::cout << std::endl;
+ std::cout << "** ColorSpaces **" << std::endl;
+ OCIO::ConstColorSpaceRcPtr lin = config->getColorSpace(OCIO::ROLE_SCENE_LINEAR);
+ if(!lin)
+ {
+ std::cout << "Error: scene_linear role must be defined." << std::endl;
+ errorcount += 1;
+ }
+ else
+ {
+ for(int i=0; i<config->getNumColorSpaces(); ++i)
+ {
+ OCIO::ConstColorSpaceRcPtr cs = config->getColorSpace(config->getColorSpaceNameByIndex(i));
+
+ bool convertsToLinear = true;
+ std::string convertsToLinearErrorText;
+
+ bool convertsFromLinear = true;
+ std::string convertsFromLinearErrorText;
+
+ try
+ {
+ OCIO::ConstProcessorRcPtr p = config->getProcessor(cs, lin);
+ }
+ catch(OCIO::Exception & exception)
+ {
+ convertsToLinear = false;
+ convertsToLinearErrorText = exception.what();
+ }
+
+ try
+ {
+ OCIO::ConstProcessorRcPtr p = config->getProcessor(lin, cs);
+ }
+ catch(OCIO::Exception & exception)
+ {
+ convertsFromLinear = false;
+ convertsFromLinearErrorText = exception.what();
+ }
+
+ if(convertsToLinear && convertsFromLinear)
+ {
+ std::cout << cs->getName() << std::endl;
+ }
+ else if(!convertsToLinear && !convertsFromLinear)
+ {
+ std::cout << cs->getName();
+ std::cout << " -- error" << std::endl;
+ std::cout << "\t" << convertsToLinearErrorText << std::endl;
+ std::cout << "\t" << convertsFromLinearErrorText << std::endl;
+
+ errorcount += 1;
+ }
+ else if(convertsToLinear)
+ {
+ std::cout << cs->getName();
+ std::cout << " -- input only" << std::endl;
+ }
+ else if(convertsFromLinear)
+ {
+ std::cout << cs->getName();
+ std::cout << " -- output only" << std::endl;
+ }
+ }
+ }
+
+ std::cout << std::endl;
+ std::cout << "** Looks **" << std::endl;
+ if(config->getNumLooks()>0)
+ {
+ for(int i=0; i<config->getNumLooks(); ++i)
+ {
+ std::cout << config->getLookNameByIndex(i) << std::endl;
+ }
+ }
+ else
+ {
+ std::cout << "no looks defined" << std::endl;
+ }
+ std::cout << std::endl;
+ std::cout << "** Sanity Check **" << std::endl;
+
+ try
+ {
+ config->sanityCheck();
+ std::cout << "passed" << std::endl;
+ }
+ catch(OCIO::Exception & exception)
+ {
+ std::cout << "ERROR" << std::endl;
+ errorcount += 1;
+ std::cout << exception.what() << std::endl;
+ }
+
+ if(!outputconfig.empty())
+ {
+ std::ofstream output;
+ output.open(outputconfig.c_str());
+
+ if(!output.is_open())
+ {
+ std::cout << "Error opening " << outputconfig << " for writing." << std::endl;
+ }
+ else
+ {
+ config->serialize(output);
+ output.close();
+ std::cout << "Wrote " << outputconfig << std::endl;
+ }
+ }
+ }
+ catch(OCIO::Exception & exception)
+ {
+ std::cout << "ERROR: " << exception.what() << std::endl;
+ return 1;
+ } catch (std::exception& exception) {
+ std::cout << "ERROR: " << exception.what() << "\n";
+ return 1;
+ }
+ catch(...)
+ {
+ std::cout << "Unknown error encountered." << std::endl;
+ return 1;
+ }
+
+
+ std::cout << std::endl;
+ if(errorcount == 0)
+ {
+ std::cout << "Tests complete." << std::endl << std::endl;
+ return 0;
+ }
+ else
+ {
+ std::cout << errorcount << " tests failed." << std::endl << std::endl;
+ return 1;
+ }
+}
diff --git a/src/apps/ocioconvert/CMakeLists.txt b/src/apps/ocioconvert/CMakeLists.txt
new file mode 100644
index 0000000..5c5eb76
--- /dev/null
+++ b/src/apps/ocioconvert/CMakeLists.txt
@@ -0,0 +1,16 @@
+if (OIIO_FOUND)
+ include_directories(
+ ${CMAKE_SOURCE_DIR}/export/
+ ${CMAKE_BINARY_DIR}/export/
+ ${CMAKE_SOURCE_DIR}/src/apps/share/
+ ${OIIO_INCLUDES}
+ )
+
+ file(GLOB_RECURSE share_src_files "${CMAKE_SOURCE_DIR}/src/apps/share/*.cpp")
+
+ add_executable(ocioconvert ${share_src_files} main.cpp)
+
+ target_link_libraries(ocioconvert ${OIIO_LIBRARIES} OpenColorIO dl)
+
+ install(TARGETS ocioconvert DESTINATION ${CMAKE_INSTALL_EXEC_PREFIX}/bin)
+endif()
diff --git a/src/apps/ocioconvert/main.cpp b/src/apps/ocioconvert/main.cpp
new file mode 100644
index 0000000..32a3c34
--- /dev/null
+++ b/src/apps/ocioconvert/main.cpp
@@ -0,0 +1,309 @@
+/*
+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 <cstdlib>
+#include <iostream>
+#include <sstream>
+#include <vector>
+
+#include <OpenColorIO/OpenColorIO.h>
+namespace OCIO = OCIO_NAMESPACE;
+
+#include <OpenImageIO/imageio.h>
+#include <OpenImageIO/typedesc.h>
+#if (OIIO_VERSION < 10100)
+namespace OIIO = OIIO_NAMESPACE;
+#endif
+
+
+#include "argparse.h"
+
+// array of non openimageIO arguments
+static std::vector<std::string> args;
+
+
+// fill 'args' array with openimageIO arguments
+static int
+parse_end_args(int argc, const char *argv[])
+{
+ while(argc>0)
+ {
+ args.push_back(argv[0]);
+ argc--;
+ argv++;
+ }
+
+ return 0;
+}
+
+
+bool ParseNameValuePair(std::string& name, std::string& value,
+ const std::string& input);
+
+bool StringToFloat(float * fval, const char * str);
+
+bool StringToInt(int * ival, const char * str);
+
+int main(int argc, const char **argv)
+{
+ ArgParse ap;
+
+ std::vector<std::string> floatAttrs;
+ std::vector<std::string> intAttrs;
+ std::vector<std::string> stringAttrs;
+
+ ap.options("ocioconvert -- apply colorspace transform to an image \n\n"
+ "usage: ocioconvert [options] inputimage inputcolorspace outputimage outputcolorspace\n\n",
+ "%*", parse_end_args, "",
+ "<SEPARATOR>", "OpenImageIO options",
+ "--float-attribute %L", &floatAttrs, "name=float pair defining OIIO float attribute",
+ "--int-attribute %L", &intAttrs, "name=int pair defining OIIO int attribute",
+ "--string-attribute %L", &stringAttrs, "name=string pair defining OIIO string attribute",
+ NULL
+ );
+ if (ap.parse (argc, argv) < 0) {
+ std::cerr << ap.geterror() << std::endl;
+ ap.usage ();
+ exit(1);
+ }
+
+ if(args.size()!=4)
+ {
+ ap.usage();
+ exit(1);
+ }
+
+ const char * inputimage = args[0].c_str();
+ const char * inputcolorspace = args[1].c_str();
+ const char * outputimage = args[2].c_str();
+ const char * outputcolorspace = args[3].c_str();
+
+ OIIO::ImageSpec spec;
+ std::vector<float> img;
+ int imgwidth = 0;
+ int imgheight = 0;
+ int components = 0;
+
+
+ // Load the image
+ std::cerr << "Loading " << inputimage << std::endl;
+ try
+ {
+ OIIO::ImageInput* f = OIIO::ImageInput::create(inputimage);
+ if(!f)
+ {
+ std::cerr << "Could not create image input." << std::endl;
+ exit(1);
+ }
+
+ f->open(inputimage, spec);
+
+ std::string error = f->geterror();
+ if(!error.empty())
+ {
+ std::cerr << "Error loading image " << error << std::endl;
+ exit(1);
+ }
+
+ imgwidth = spec.width;
+ imgheight = spec.height;
+ components = spec.nchannels;
+
+ img.resize(imgwidth*imgheight*components);
+ memset(&img[0], 0, imgwidth*imgheight*components*sizeof(float));
+
+ f->read_image(OIIO::TypeDesc::TypeFloat, &img[0]);
+ delete f;
+
+ }
+ catch(...)
+ {
+ std::cerr << "Error loading file.";
+ exit(1);
+ }
+
+ // Process the image
+ try
+ {
+ // Load the current config.
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+
+ // Get the processor
+ OCIO::ConstProcessorRcPtr processor = config->getProcessor(inputcolorspace, outputcolorspace);
+
+ // Wrap the image in a light-weight ImageDescription
+ OCIO::PackedImageDesc imageDesc(&img[0], imgwidth, imgheight, components);
+
+ // Apply the color transformation (in place)
+ processor->apply(imageDesc);
+ }
+ catch(OCIO::Exception & exception)
+ {
+ std::cerr << "OCIO Error: " << exception.what() << std::endl;
+ exit(1);
+ }
+ catch(...)
+ {
+ std::cerr << "Unknown OCIO error encountered." << std::endl;
+ exit(1);
+ }
+
+
+
+ //
+ // set the provided OpenImageIO attributes
+ //
+ bool parseerror = false;
+ for(unsigned int i=0; i<floatAttrs.size(); ++i)
+ {
+ std::string name, value;
+ float fval = 0.0f;
+
+ if(!ParseNameValuePair(name, value, floatAttrs[i]) ||
+ !StringToFloat(&fval,value.c_str()))
+ {
+ std::cerr << "Error: attribute string '" << floatAttrs[i] << "' should be in the form name=floatvalue\n";
+ parseerror = true;
+ continue;
+ }
+
+ spec.attribute(name, fval);
+ }
+
+ for(unsigned int i=0; i<intAttrs.size(); ++i)
+ {
+ std::string name, value;
+ int ival = 0;
+ if(!ParseNameValuePair(name, value, intAttrs[i]) ||
+ !StringToInt(&ival,value.c_str()))
+ {
+ std::cerr << "Error: attribute string '" << intAttrs[i] << "' should be in the form name=intvalue\n";
+ parseerror = true;
+ continue;
+ }
+
+ spec.attribute(name, ival);
+ }
+
+ for(unsigned int i=0; i<stringAttrs.size(); ++i)
+ {
+ std::string name, value;
+ if(!ParseNameValuePair(name, value, stringAttrs[i]))
+ {
+ std::cerr << "Error: attribute string '" << stringAttrs[i] << "' should be in the form name=value\n";
+ parseerror = true;
+ continue;
+ }
+
+ spec.attribute(name, value);
+ }
+
+ if(parseerror)
+ {
+ exit(1);
+ }
+
+
+
+
+ // Write out the result
+ try
+ {
+ OIIO::ImageOutput* f = OIIO::ImageOutput::create(outputimage);
+ if(!f)
+ {
+ std::cerr << "Could not create output input." << std::endl;
+ exit(1);
+ }
+
+ f->open(outputimage, spec);
+ f->write_image(OIIO::TypeDesc::FLOAT, &img[0]);
+ f->close();
+ delete f;
+ }
+ catch(...)
+ {
+ std::cerr << "Error loading file.";
+ exit(1);
+ }
+
+ std::cerr << "Wrote " << outputimage << std::endl;
+
+ return 0;
+}
+
+
+// Parse name=value parts
+// return true on success
+
+bool ParseNameValuePair(std::string& name,
+ std::string& value,
+ const std::string& input)
+{
+ // split string into name=value
+ size_t pos = input.find('=');
+ if(pos==std::string::npos) return false;
+
+ name = input.substr(0,pos);
+ value = input.substr(pos+1);
+ return true;
+}
+
+// return true on success
+bool StringToFloat(float * fval, const char * str)
+{
+ if(!str) return false;
+
+ std::istringstream inputStringstream(str);
+ float x;
+ if(!(inputStringstream >> x))
+ {
+ return false;
+ }
+
+ if(fval) *fval = x;
+ return true;
+}
+
+bool StringToInt(int * ival, const char * str)
+{
+ if(!str) return false;
+
+ std::istringstream inputStringstream(str);
+ int x;
+ if(!(inputStringstream >> x))
+ {
+ return false;
+ }
+
+ if(ival) *ival = x;
+ return true;
+}
+
+
+
+
diff --git a/src/apps/ociodisplay/CMakeLists.txt b/src/apps/ociodisplay/CMakeLists.txt
new file mode 100644
index 0000000..e80e9f9
--- /dev/null
+++ b/src/apps/ociodisplay/CMakeLists.txt
@@ -0,0 +1,11 @@
+include_directories(
+ ${CMAKE_SOURCE_DIR}/export/
+ ${CMAKE_BINARY_DIR}/export/
+ ${OPENGL_INCLUDE_DIR}
+ ${OIIO_INCLUDES}
+ ${GLEW_INCLUDES}
+)
+add_executable(ociodisplay main.cpp)
+# set_target_properties(ociodisplay PROPERTIES INSTALL_RPATH ${OIIO_LIBRARIES} )
+target_link_libraries(ociodisplay ${GLEW_LIBRARIES} ${GLUT_LIBRARY} ${OPENGL_LIBRARY} ${OIIO_LIBRARIES} OpenColorIO)
+install(TARGETS ociodisplay DESTINATION ${CMAKE_INSTALL_EXEC_PREFIX}/bin)
diff --git a/src/apps/ociodisplay/main.cpp b/src/apps/ociodisplay/main.cpp
new file mode 100644
index 0000000..1b7f5a6
--- /dev/null
+++ b/src/apps/ociodisplay/main.cpp
@@ -0,0 +1,734 @@
+/*
+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 <cstdlib>
+#include <cmath>
+#include <cstdio>
+#include <cstring>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <vector>
+
+#ifdef __APPLE__
+#include <OpenGL/gl.h>
+#include <OpenGL/glext.h>
+#include <GLUT/glut.h>
+#else
+#include <GL/glew.h>
+#include <GL/gl.h>
+#include <GL/glext.h>
+#include <GL/glut.h>
+#endif
+
+#include <OpenColorIO/OpenColorIO.h>
+namespace OCIO = OCIO_NAMESPACE;
+
+#include <OpenImageIO/imageio.h>
+#include <OpenImageIO/typedesc.h>
+#if (OIIO_VERSION < 10100)
+namespace OIIO = OIIO_NAMESPACE;
+#endif
+
+GLint g_win = 0;
+int g_winWidth = 0;
+int g_winHeight = 0;
+
+GLuint g_fragShader = 0;
+GLuint g_program = 0;
+
+GLuint g_imageTexID;
+float g_imageAspect;
+
+GLuint g_lut3dTexID;
+const int LUT3D_EDGE_SIZE = 32;
+std::vector<float> g_lut3d;
+std::string g_lut3dcacheid;
+std::string g_shadercacheid;
+
+std::string g_inputColorSpace;
+std::string g_display;
+std::string g_transformName;
+
+float g_exposure_fstop = 0.0f;
+float g_display_gamma = 1.0f;
+int g_channelHot[4] = { 1, 1, 1, 1 }; // show rgb
+
+
+void UpdateOCIOGLState();
+
+static void InitImageTexture(const char * filename)
+{
+ glGenTextures(1, &g_imageTexID);
+
+ std::vector<float> img;
+ int texWidth = 512;
+ int texHeight = 512;
+ int components = 4;
+
+ if(filename)
+ {
+ std::cout << "loading: " << filename << std::endl;
+ try
+ {
+ OIIO::ImageInput* f = OIIO::ImageInput::create(filename);
+ if(!f)
+ {
+ std::cerr << "Could not create image input." << std::endl;
+ exit(1);
+ }
+
+ OIIO::ImageSpec spec;
+ f->open(filename, spec);
+
+ std::string error = f->geterror();
+ if(!error.empty())
+ {
+ std::cerr << "Error loading image " << error << std::endl;
+ exit(1);
+ }
+
+ texWidth = spec.width;
+ texHeight = spec.height;
+ components = spec.nchannels;
+
+ img.resize(texWidth*texHeight*components);
+ memset(&img[0], 0, texWidth*texHeight*components*sizeof(float));
+
+ f->read_image(OIIO::TypeDesc::TypeFloat, &img[0]);
+ delete f;
+ }
+ catch(...)
+ {
+ std::cerr << "Error loading file.";
+ exit(1);
+ }
+ }
+ // If no file is provided, use a default gradient texture
+ else
+ {
+ std::cout << "No image specified, loading gradient." << std::endl;
+
+ img.resize(texWidth*texHeight*components);
+ memset(&img[0], 0, texWidth*texHeight*components*sizeof(float));
+
+ for(int y=0; y<texHeight; ++y)
+ {
+ for(int x=0; x<texWidth; ++x)
+ {
+ float c = (float)x/((float)texWidth-1.0f);
+ img[components*(texWidth*y+x) + 0] = c;
+ img[components*(texWidth*y+x) + 1] = c;
+ img[components*(texWidth*y+x) + 2] = c;
+ img[components*(texWidth*y+x) + 3] = 1.0f;
+ }
+ }
+ }
+
+
+ GLenum format = 0;
+ if(components == 4) format = GL_RGBA;
+ else if(components == 3) format = GL_RGB;
+ else
+ {
+ std::cerr << "Cannot load image with " << components << " components." << std::endl;
+ exit(1);
+ }
+
+ g_imageAspect = 1.0;
+ if(texHeight!=0)
+ {
+ g_imageAspect = (float) texWidth / (float) texHeight;
+ }
+
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, g_imageTexID);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, texWidth, texHeight, 0,
+ format, GL_FLOAT, &img[0]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+}
+
+void InitOCIO(const char * filename)
+{
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+ g_display = config->getDefaultDisplay();
+ g_transformName = config->getDefaultView(g_display.c_str());
+
+ g_inputColorSpace = OCIO::ROLE_SCENE_LINEAR;
+ if(filename)
+ {
+ std::string cs = config->parseColorSpaceFromString(filename);
+ if(!cs.empty())
+ {
+ g_inputColorSpace = cs;
+ std::cout << "colorspace: " << cs << std::endl;
+ }
+ else
+ {
+ std::cout << "colorspace: " << g_inputColorSpace << " \t(could not determine from filename, using default)" << std::endl;
+ }
+ }
+}
+
+static void AllocateLut3D()
+{
+ glGenTextures(1, &g_lut3dTexID);
+
+ int num3Dentries = 3*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE;
+ g_lut3d.resize(num3Dentries);
+ memset(&g_lut3d[0], 0, sizeof(float)*num3Dentries);
+
+ glActiveTexture(GL_TEXTURE2);
+
+ glBindTexture(GL_TEXTURE_3D, g_lut3dTexID);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F_ARB,
+ LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE,
+ 0, GL_RGB,GL_FLOAT, &g_lut3d[0]);
+}
+
+/*
+static void
+Idle(void)
+{
+ // + Do Work
+ glutPostRedisplay();
+}
+*/
+
+void Redisplay(void)
+{
+ float windowAspect = 1.0;
+ if(g_winHeight != 0)
+ {
+ windowAspect = (float)g_winWidth/(float)g_winHeight;
+ }
+
+ float pts[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; // x0,y0,x1,y1
+ if(windowAspect>g_imageAspect)
+ {
+ float imgWidthScreenSpace = g_imageAspect * (float)g_winHeight;
+ pts[0] = (float)g_winWidth * 0.5f - (float)imgWidthScreenSpace * 0.5f;
+ pts[2] = (float)g_winWidth * 0.5f + (float)imgWidthScreenSpace * 0.5f;
+ pts[1] = 0.0f;
+ pts[3] = (float)g_winHeight;
+ }
+ else
+ {
+ float imgHeightScreenSpace = (float)g_winWidth / g_imageAspect;
+ pts[0] = 0.0f;
+ pts[2] = (float)g_winWidth;
+ pts[1] = (float)g_winHeight * 0.5f - imgHeightScreenSpace * 0.5f;
+ pts[3] = (float)g_winHeight * 0.5f + imgHeightScreenSpace * 0.5f;
+ }
+
+ glEnable(GL_TEXTURE_2D);
+ glClearColor(0.1f, 0.1f, 0.1f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glColor3f(1, 1, 1);
+
+ glPushMatrix();
+ glBegin(GL_QUADS);
+ glTexCoord2f(0.0f, 1.0f);
+ glVertex2f(pts[0], pts[1]);
+
+ glTexCoord2f(0.0f, 0.0f);
+ glVertex2f(pts[0], pts[3]);
+
+ glTexCoord2f(1.0f, 0.0f);
+ glVertex2f(pts[2], pts[3]);
+
+ glTexCoord2f(1.0f, 1.0f);
+ glVertex2f(pts[2], pts[1]);
+
+ glEnd();
+ glPopMatrix();
+
+ glDisable(GL_TEXTURE_2D);
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape(int width, int height)
+{
+ g_winWidth = width;
+ g_winHeight = height;
+
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0.0, g_winWidth, 0.0, g_winHeight, -100.0, 100.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+
+static void CleanUp(void)
+{
+ glDeleteShader(g_fragShader);
+ glDeleteProgram(g_program);
+ glutDestroyWindow(g_win);
+}
+
+
+static void Key(unsigned char key, int /*x*/, int /*y*/)
+{
+ if(key == 'c' || key == 'C')
+ {
+ g_channelHot[0] = 1;
+ g_channelHot[1] = 1;
+ g_channelHot[2] = 1;
+ g_channelHot[3] = 1;
+ }
+ else if(key == 'r' || key == 'R')
+ {
+ g_channelHot[0] = 1;
+ g_channelHot[1] = 0;
+ g_channelHot[2] = 0;
+ g_channelHot[3] = 0;
+ }
+ else if(key == 'g' || key == 'G')
+ {
+ g_channelHot[0] = 0;
+ g_channelHot[1] = 1;
+ g_channelHot[2] = 0;
+ g_channelHot[3] = 0;
+ }
+ else if(key == 'b' || key == 'B')
+ {
+ g_channelHot[0] = 0;
+ g_channelHot[1] = 0;
+ g_channelHot[2] = 1;
+ g_channelHot[3] = 0;
+ }
+ else if(key == 'a' || key == 'A')
+ {
+ g_channelHot[0] = 0;
+ g_channelHot[1] = 0;
+ g_channelHot[2] = 0;
+ g_channelHot[3] = 1;
+ }
+ else if(key == 'l' || key == 'L')
+ {
+ g_channelHot[0] = 1;
+ g_channelHot[1] = 1;
+ g_channelHot[2] = 1;
+ g_channelHot[3] = 0;
+ }
+ else if(key == 27)
+ {
+ CleanUp();
+ exit(0);
+ }
+
+ UpdateOCIOGLState();
+ glutPostRedisplay();
+}
+
+
+static void SpecialKey(int key, int x, int y)
+{
+ (void) x;
+ (void) y;
+
+ int mod = glutGetModifiers();
+
+ if(key == GLUT_KEY_UP && (mod & GLUT_ACTIVE_CTRL))
+ {
+ g_exposure_fstop += 0.25f;
+ }
+ else if(key == GLUT_KEY_DOWN && (mod & GLUT_ACTIVE_CTRL))
+ {
+ g_exposure_fstop -= 0.25f;
+ }
+ else if(key == GLUT_KEY_HOME && (mod & GLUT_ACTIVE_CTRL))
+ {
+ g_exposure_fstop = 0.0f;
+ g_display_gamma = 1.0f;
+ }
+
+ else if(key == GLUT_KEY_UP && (mod & GLUT_ACTIVE_ALT))
+ {
+ g_display_gamma *= 1.1f;
+ }
+ else if(key == GLUT_KEY_DOWN && (mod & GLUT_ACTIVE_ALT))
+ {
+ g_display_gamma /= 1.1f;
+ }
+ else if(key == GLUT_KEY_HOME && (mod & GLUT_ACTIVE_ALT))
+ {
+ g_exposure_fstop = 0.0f;
+ g_display_gamma = 1.0f;
+ }
+
+ UpdateOCIOGLState();
+
+ glutPostRedisplay();
+}
+
+GLuint
+CompileShaderText(GLenum shaderType, const char *text)
+{
+ GLuint shader;
+ GLint stat;
+
+ shader = glCreateShader(shaderType);
+ glShaderSource(shader, 1, (const GLchar **) &text, NULL);
+ glCompileShader(shader);
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
+
+ if (!stat)
+ {
+ GLchar log[1000];
+ GLsizei len;
+ glGetShaderInfoLog(shader, 1000, &len, log);
+ fprintf(stderr, "Error: problem compiling shader: %s\n", log);
+ return 0;
+ }
+
+ return shader;
+}
+
+GLuint
+LinkShaders(GLuint fragShader)
+{
+ if (!fragShader) return 0;
+
+ GLuint program = glCreateProgram();
+
+ if (fragShader)
+ glAttachShader(program, fragShader);
+
+ glLinkProgram(program);
+
+ /* check link */
+ {
+ GLint stat;
+ glGetProgramiv(program, GL_LINK_STATUS, &stat);
+ if (!stat) {
+ GLchar log[1000];
+ GLsizei len;
+ glGetProgramInfoLog(program, 1000, &len, log);
+ fprintf(stderr, "Shader link error:\n%s\n", log);
+ return 0;
+ }
+ }
+
+ return program;
+}
+
+const char * g_fragShaderText = ""
+"\n"
+"uniform sampler2D tex1;\n"
+"uniform sampler3D tex2;\n"
+"\n"
+"void main()\n"
+"{\n"
+" vec4 col = texture2D(tex1, gl_TexCoord[0].st);\n"
+" gl_FragColor = OCIODisplay(col, tex2);\n"
+"}\n";
+
+
+void UpdateOCIOGLState()
+{
+ // Step 0: Get the processor using any of the pipelines mentioned above.
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+
+ OCIO::DisplayTransformRcPtr transform = OCIO::DisplayTransform::Create();
+ transform->setInputColorSpaceName( g_inputColorSpace.c_str() );
+ transform->setDisplay( g_display.c_str() );
+ transform->setView( g_transformName.c_str() );
+
+ // Add optional transforms to create a full-featured, "canonical" display pipeline
+ // Fstop exposure control (in SCENE_LINEAR)
+ {
+ float gain = powf(2.0f, g_exposure_fstop);
+ const float slope4f[] = { gain, gain, gain, gain };
+ float m44[16];
+ float offset4[4];
+ OCIO::MatrixTransform::Scale(m44, offset4, slope4f);
+ OCIO::MatrixTransformRcPtr mtx = OCIO::MatrixTransform::Create();
+ mtx->setValue(m44, offset4);
+ transform->setLinearCC(mtx);
+ }
+
+ // Channel swizzling
+ {
+ float lumacoef[3];
+ config->getDefaultLumaCoefs(lumacoef);
+ float m44[16];
+ float offset[4];
+ OCIO::MatrixTransform::View(m44, offset, g_channelHot, lumacoef);
+ OCIO::MatrixTransformRcPtr swizzle = OCIO::MatrixTransform::Create();
+ swizzle->setValue(m44, offset);
+ transform->setChannelView(swizzle);
+ }
+
+ // Post-display transform gamma
+ {
+ float exponent = 1.0f/std::max(1e-6f, static_cast<float>(g_display_gamma));
+ const float exponent4f[] = { exponent, exponent, exponent, exponent };
+ OCIO::ExponentTransformRcPtr expTransform = OCIO::ExponentTransform::Create();
+ expTransform->setValue(exponent4f);
+ transform->setDisplayCC(expTransform);
+ }
+
+ OCIO::ConstProcessorRcPtr processor;
+ try
+ {
+ processor = config->getProcessor(transform);
+ }
+ catch(OCIO::Exception & e)
+ {
+ std::cerr << e.what() << std::endl;
+ return;
+ }
+ catch(...)
+ {
+ return;
+ }
+
+ // Step 1: Create a GPU Shader Description
+ OCIO::GpuShaderDesc shaderDesc;
+ shaderDesc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_0);
+ shaderDesc.setFunctionName("OCIODisplay");
+ shaderDesc.setLut3DEdgeLen(LUT3D_EDGE_SIZE);
+
+ // Step 2: Compute the 3D LUT
+ std::string lut3dCacheID = processor->getGpuLut3DCacheID(shaderDesc);
+ if(lut3dCacheID != g_lut3dcacheid)
+ {
+ //std::cerr << "Computing 3DLut " << g_lut3dcacheid << std::endl;
+
+ g_lut3dcacheid = lut3dCacheID;
+ processor->getGpuLut3D(&g_lut3d[0], shaderDesc);
+
+ glBindTexture(GL_TEXTURE_3D, g_lut3dTexID);
+ glTexSubImage3D(GL_TEXTURE_3D, 0,
+ 0, 0, 0,
+ LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE,
+ GL_RGB,GL_FLOAT, &g_lut3d[0]);
+ }
+
+ // Step 3: Compute the Shader
+ std::string shaderCacheID = processor->getGpuShaderTextCacheID(shaderDesc);
+ if(g_program == 0 || shaderCacheID != g_shadercacheid)
+ {
+ //std::cerr << "Computing Shader " << g_shadercacheid << std::endl;
+
+ g_shadercacheid = shaderCacheID;
+
+ std::ostringstream os;
+ os << processor->getGpuShaderText(shaderDesc) << "\n";
+ os << g_fragShaderText;
+ //std::cerr << os.str() << std::endl;
+
+ if(g_fragShader) glDeleteShader(g_fragShader);
+ g_fragShader = CompileShaderText(GL_FRAGMENT_SHADER, os.str().c_str());
+ if(g_program) glDeleteProgram(g_program);
+ g_program = LinkShaders(g_fragShader);
+ }
+
+ glUseProgram(g_program);
+ glUniform1i(glGetUniformLocation(g_program, "tex1"), 1);
+ glUniform1i(glGetUniformLocation(g_program, "tex2"), 2);
+}
+
+void menuCallback(int /*id*/)
+{
+ glutPostRedisplay();
+}
+
+void imageColorSpace_CB(int id)
+{
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+ const char * name = config->getColorSpaceNameByIndex(id);
+ if(!name) return;
+
+ g_inputColorSpace = name;
+
+ UpdateOCIOGLState();
+ glutPostRedisplay();
+}
+
+void displayDevice_CB(int id)
+{
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+ const char * display = config->getDisplay(id);
+ if(!display) return;
+
+ g_display = display;
+
+ const char * csname = config->getDisplayColorSpaceName(g_display.c_str(), g_transformName.c_str());
+ if(!csname)
+ {
+ g_transformName = config->getDefaultView(g_display.c_str());
+ }
+
+ UpdateOCIOGLState();
+ glutPostRedisplay();
+}
+
+void transform_CB(int id)
+{
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+
+ const char * transform = config->getView(g_display.c_str(), id);
+ if(!transform) return;
+
+ g_transformName = transform;
+
+ UpdateOCIOGLState();
+ glutPostRedisplay();
+}
+
+static void PopulateOCIOMenus()
+{
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+
+
+ int csMenuID = glutCreateMenu(imageColorSpace_CB);
+ for(int i=0; i<config->getNumColorSpaces(); ++i)
+ {
+ glutAddMenuEntry(config->getColorSpaceNameByIndex(i), i);
+ }
+
+ int deviceMenuID = glutCreateMenu(displayDevice_CB);
+ for(int i=0; i<config->getNumDisplays(); ++i)
+ {
+ glutAddMenuEntry(config->getDisplay(i), i);
+ }
+
+ int transformMenuID = glutCreateMenu(transform_CB);
+ const char * defaultDisplay = config->getDefaultDisplay();
+ for(int i=0; i<config->getNumViews(defaultDisplay); ++i)
+ {
+ glutAddMenuEntry(config->getView(defaultDisplay, i), i);
+ }
+
+ glutCreateMenu(menuCallback);
+ glutAddSubMenu("Image ColorSpace", csMenuID);
+ glutAddSubMenu("Transform", transformMenuID);
+ glutAddSubMenu("Device", deviceMenuID);
+
+ glutAttachMenu(GLUT_RIGHT_BUTTON);
+}
+
+const char * USAGE_TEXT = "\n"
+"Keys:\n"
+"\tCtrl+Up: Exposure +1/4 stop (in scene linear)\n"
+"\tCtrl+Down: Exposure -1/4 stop (in scene linear)\n"
+"\tCtrl+Home: Reset Exposure + Gamma\n"
+"\n"
+"\tAlt+Up: Gamma up (post display transform)\n"
+"\tAlt+Down: Gamma down (post display transform)\n"
+"\tAlt+Home: Reset Exposure + Gamma\n"
+"\n"
+"\tC: View Color\n"
+"\tR: View Red \n"
+"\tG: View Green\n"
+"\tB: View Blue\n"
+"\tA: View Alpha\n"
+"\tL: View Luma\n"
+"\n"
+"\tRight-Mouse Button: Configure Display / Transform / ColorSpace\n"
+"\n"
+"\tEsc: Quit\n";
+
+int main(int argc, char **argv)
+{
+ glutInit(&argc, argv);
+
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+ glutInitWindowSize(512, 512);
+ glutInitWindowPosition (100, 100);
+
+ g_win = glutCreateWindow(argv[0]);
+
+#ifndef __APPLE__
+ glewInit();
+ if (!glewIsSupported("GL_VERSION_2_0"))
+ {
+ printf("OpenGL 2.0 not supported\n");
+ exit(1);
+ }
+#endif
+
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutSpecialFunc(SpecialKey);
+ glutDisplayFunc(Redisplay);
+
+ const char * filename = 0;
+ if(argc>1) filename = argv[1];
+
+ std::cout << USAGE_TEXT << std::endl;
+
+ // TODO: switch profiles based on shading language
+ // std::cout << "GL_SHADING_LANGUAGE_VERSION: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
+ AllocateLut3D();
+
+ InitImageTexture(filename);
+ try
+ {
+ InitOCIO(filename);
+ }
+ catch(OCIO::Exception & e)
+ {
+ std::cerr << e.what() << std::endl;
+ exit(1);
+ }
+
+ PopulateOCIOMenus();
+
+ Reshape(1024, 512);
+
+ UpdateOCIOGLState();
+
+ Redisplay();
+
+ /*
+ if (Anim)
+ {
+ glutIdleFunc(Idle);
+ }
+ */
+
+ glutMainLoop();
+
+ return 0;
+}
diff --git a/src/apps/ociolutimage/CMakeLists.txt b/src/apps/ociolutimage/CMakeLists.txt
new file mode 100644
index 0000000..86bc0e7
--- /dev/null
+++ b/src/apps/ociolutimage/CMakeLists.txt
@@ -0,0 +1,16 @@
+if (OIIO_FOUND)
+ include_directories(
+ ${CMAKE_SOURCE_DIR}/export/
+ ${CMAKE_BINARY_DIR}/export/
+ ${CMAKE_SOURCE_DIR}/src/apps/share/
+ ${OIIO_INCLUDES}
+ )
+
+ file(GLOB_RECURSE share_src_files "${CMAKE_SOURCE_DIR}/src/apps/share/*.cpp")
+
+ add_executable(ociolutimage ${share_src_files} main.cpp)
+
+ target_link_libraries(ociolutimage ${OIIO_LIBRARIES} OpenColorIO dl)
+
+ install(TARGETS ociolutimage DESTINATION ${CMAKE_INSTALL_EXEC_PREFIX}/bin)
+endif()
diff --git a/src/apps/ociolutimage/main.cpp b/src/apps/ociolutimage/main.cpp
new file mode 100644
index 0000000..2d5906b
--- /dev/null
+++ b/src/apps/ociolutimage/main.cpp
@@ -0,0 +1,398 @@
+/*
+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>
+namespace OCIO = OCIO_NAMESPACE;
+OCIO_NAMESPACE_USING;
+
+#include <OpenImageIO/imageio.h>
+#include <OpenImageIO/typedesc.h>
+#if (OIIO_VERSION < 10100)
+namespace OIIO = OIIO_NAMESPACE;
+#endif
+
+#include "argparse.h"
+
+#include <algorithm>
+#include <cmath>
+#include <fstream>
+#include <string>
+#include <sstream>
+
+#include "pystring.h"
+
+enum Lut3DOrder
+{
+ LUT3DORDER_FAST_RED = 0,
+ LUT3DORDER_FAST_BLUE
+};
+
+void WriteLut3D(const std::string & filename, const float* lutdata, int edgeLen);
+void GenerateIdentityLut3D(float* img, int edgeLen, int numChannels, Lut3DOrder lut3DOrder);
+
+
+void GetLutImageSize(int & width, int & height,
+ int cubesize, int maxwidth)
+{
+ // Compute the image width / height
+ width = cubesize*cubesize;
+ if(maxwidth>0 && width>=maxwidth)
+ {
+ // TODO: Do something smarter here to find a better multiple,
+ // to create a more pleasing gradient rendition.
+ // Use prime divisors / lowest common denominator, if possible?
+ width = std::min(maxwidth, width);
+ }
+
+ int numpixels = cubesize*cubesize*cubesize;
+ height = (int)(ceilf((float)numpixels/(float)width));
+}
+
+
+void Generate(int cubesize, int maxwidth,
+ const std::string & outputfile,
+ const std::string & configfile,
+ const std::string & incolorspace,
+ const std::string & outcolorspace)
+{
+ int width = 0;
+ int height = 0;
+ int numchannels = 3;
+ GetLutImageSize(width, height, cubesize, maxwidth);
+
+ std::vector<float> img;
+ img.resize(width*height*numchannels, 0);
+
+ GenerateIdentityLut3D(&img[0], cubesize, numchannels, LUT3DORDER_FAST_RED);
+
+ if(!incolorspace.empty() || !outcolorspace.empty())
+ {
+ OCIO::ConstConfigRcPtr config = OCIO::Config::Create();
+ if(!configfile.empty())
+ {
+ config = OCIO::Config::CreateFromFile(configfile.c_str());
+ }
+ else if(getenv("OCIO"))
+ {
+ config = OCIO::Config::CreateFromEnv();
+ }
+ else
+ {
+ std::ostringstream os;
+ os << "You must specify an ocio configuration ";
+ os << "(either with --config or $OCIO).";
+ throw Exception(os.str().c_str());
+ }
+
+ OCIO::ConstProcessorRcPtr processor =
+ config->getProcessor(incolorspace.c_str(), outcolorspace.c_str());
+
+ OCIO::PackedImageDesc imgdesc(&img[0], width, height, 3);
+ processor->apply(imgdesc);
+ }
+
+ OIIO::ImageOutput* f = OIIO::ImageOutput::create(outputfile);
+ if(!f)
+ {
+ throw Exception( "Could not create output image.");
+ }
+
+ OIIO::ImageSpec spec(width, height, numchannels, OIIO::TypeDesc::TypeFloat);
+
+ // TODO: If DPX, force 16-bit output?
+ f->open(outputfile, spec);
+ f->write_image(OIIO::TypeDesc::FLOAT, &img[0]);
+ f->close();
+ delete f;
+}
+
+
+void Extract(int cubesize, int maxwidth,
+ const std::string & inputfile,
+ const std::string & outputfile)
+{
+ // Read the image
+ OIIO::ImageInput* f = OIIO::ImageInput::create(inputfile);
+ if(!f)
+ {
+ throw Exception("Could not create input image.");
+ }
+
+ OIIO::ImageSpec spec;
+ f->open(inputfile, spec);
+
+ std::string error = f->geterror();
+ if(!error.empty())
+ {
+ std::ostringstream os;
+ os << "Error loading image " << error;
+ throw Exception(os.str().c_str());
+ }
+
+ int width = 0;
+ int height = 0;
+ GetLutImageSize(width, height, cubesize, maxwidth);
+
+ if(spec.width != width || spec.height != height)
+ {
+ std::ostringstream os;
+ os << "Image does not have expected dimensions. ";
+ os << "Expected " << width << "x" << height << ", ";
+ os << "Found " << spec.width << "x" << spec.height;
+ throw Exception(os.str().c_str());
+ }
+
+ if(spec.nchannels<3)
+ {
+ throw Exception("Image must have 3 or more channels.");
+ }
+
+ int lut3DNumPixels = cubesize*cubesize*cubesize;
+
+ if(spec.width*spec.height<lut3DNumPixels)
+ {
+ throw Exception("Image is not large enough to contain expected 3dlut.");
+ }
+
+ // TODO: confirm no data window?
+ std::vector<float> img;
+ img.resize(spec.width*spec.height*spec.nchannels, 0);
+ f->read_image(OIIO::TypeDesc::TypeFloat, &img[0]);
+ delete f;
+
+ // Repack into rgb
+ // Convert the RGB[...] image to an RGB image, in place.
+ // Of course, this only works because we're doing it from left to right
+ // so old pixels are read before they're written over
+
+ if(spec.nchannels > 3)
+ {
+ for(int i=0; i<lut3DNumPixels; ++i)
+ {
+ img[3*i+0] = img[spec.nchannels*i+0];
+ img[3*i+1] = img[spec.nchannels*i+1];
+ img[3*i+2] = img[spec.nchannels*i+2];
+ }
+ }
+
+ img.resize(lut3DNumPixels*3);
+
+ // Write the output lut
+ WriteLut3D(outputfile, &img[0], cubesize);
+}
+
+
+
+int main (int argc, const char* argv[])
+{
+ bool generate = false;
+ bool extract = false;
+ int cubesize = 32;
+ int maxwidth = 2048;
+ std::string inputfile;
+ std::string outputfile;
+ std::string config;
+ std::string incolorspace;
+ std::string outcolorspace;
+
+ // TODO: Add optional allocation transform instead of colorconvert
+ ArgParse ap;
+ ap.options("ociolutimage -- Convert a 3dlut to or from an image\n\n"
+ "usage: ociolutimage [options] <OUTPUTFILE.LUT>\n\n"
+ "example: ociolutimage --generate --output lut.exr\n"
+ "example: ociolutimage --extract --input lut.exr --output output.spi3d\n",
+ "<SEPARATOR>", "",
+ "--generate", &generate, "Generate a lattice image",
+ "--extract", &extract, "Extract a 3dlut from an input image",
+ "<SEPARATOR>", "",
+ "--cubesize %d", &cubesize, "Size of the cube (default: 32)",
+ "--maxwidth %d", &maxwidth, "Specify maximum width of the image (default: 2048)",
+ "--input %s", &inputfile, "Specify the input filename",
+ "--output %s", &outputfile, "Specify the output filename",
+ "<SEPARATOR>", "",
+ "--config %s", &config, ".ocio configuration file (default: $OCIO)",
+ "--colorconvert %s %s", &incolorspace, &outcolorspace, "Apply a color space conversion to the image.",
+ NULL);
+
+ if (ap.parse(argc, argv) < 0)
+ {
+ std::cout << ap.geterror() << std::endl;
+ ap.usage();
+ std::cout << "\n";
+ return 1;
+ }
+
+ if (argc == 1 )
+ {
+ ap.usage();
+ std::cout << "\n";
+ return 1;
+ }
+
+ if(generate)
+ {
+ try
+ {
+ Generate(cubesize, maxwidth,
+ outputfile,
+ config, incolorspace, outcolorspace);
+ }
+ catch(std::exception & e)
+ {
+ std::cerr << "Error generating image: " << e.what() << std::endl;
+ exit(1);
+ }
+ catch(...)
+ {
+ std::cerr << "Error generating image. An unknown error occurred.\n";
+ exit(1);
+ }
+ }
+ else if(extract)
+ {
+ try
+ {
+ Extract(cubesize, maxwidth,
+ inputfile, outputfile);
+ }
+ catch(std::exception & e)
+ {
+ std::cerr << "Error extracting lut: " << e.what() << std::endl;
+ exit(1);
+ }
+ catch(...)
+ {
+ std::cerr << "Error extracting lut. An unknown error occurred.\n";
+ exit(1);
+ }
+ }
+ else
+ {
+ std::cerr << "Must specify either --generate or --extract.\n";
+ exit(1);
+ }
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TODO: These should be exposed from inside OCIO, in appropriate time.
+//
+
+inline int GetLut3DIndex_B(int indexR, int indexG, int indexB,
+ int sizeR, int sizeG, int /*sizeB*/)
+{
+ return 3 * (indexR + sizeR * (indexG + sizeG * indexB));
+}
+
+inline int GetLut3DIndex_R(int indexR, int indexG, int indexB,
+ int /*sizeR*/, int sizeG, int sizeB)
+{
+ return 3 * (indexB + sizeB * (indexG + sizeG * indexR));
+}
+
+void GenerateIdentityLut3D(float* img, int edgeLen, int numChannels,
+ Lut3DOrder lut3DOrder)
+{
+ if(!img) return;
+ if(numChannels < 3)
+ {
+ throw Exception("Cannot generate idenitity 3d lut with less than 3 channels.");
+ }
+
+ float c = 1.0f / ((float)edgeLen - 1.0f);
+
+ if(lut3DOrder == LUT3DORDER_FAST_RED)
+ {
+ for(int i=0; i<edgeLen*edgeLen*edgeLen; i++)
+ {
+ img[numChannels*i+0] = (float)(i%edgeLen) * c;
+ img[numChannels*i+1] = (float)((i/edgeLen)%edgeLen) * c;
+ img[numChannels*i+2] = (float)((i/edgeLen/edgeLen)%edgeLen) * c;
+ }
+ }
+ else if(lut3DOrder == LUT3DORDER_FAST_BLUE)
+ {
+ for(int i=0; i<edgeLen*edgeLen*edgeLen; i++)
+ {
+ img[numChannels*i+0] = (float)((i/edgeLen/edgeLen)%edgeLen) * c;
+ img[numChannels*i+1] = (float)((i/edgeLen)%edgeLen) * c;
+ img[numChannels*i+2] = (float)(i%edgeLen) * c;
+ }
+ }
+ else
+ {
+ throw Exception("Unknown Lut3DOrder.");
+ }
+}
+
+void WriteLut3D(const std::string & filename, const float* lutdata, int edgeLen)
+{
+ if(!pystring::endswith(filename,".spi3d"))
+ {
+ std::ostringstream os;
+ os << "Only .spi3d writing is currently supported. ";
+ os << "As a work around, please write a .spi3d file, and then use ";
+ os << "ociobakelut for transcoding.";
+ throw Exception(os.str().c_str());
+ }
+
+ std::ofstream output;
+ output.open(filename.c_str());
+ if(!output.is_open())
+ {
+ std::ostringstream os;
+ os << "Error opening " << filename << " for writing.";
+ throw Exception(os.str().c_str());
+ }
+
+ output << "SPILUT 1.0\n";
+ output << "3 3\n";
+ output << edgeLen << " " << edgeLen << " " << edgeLen << "\n";
+
+ int index = 0;
+ for(int rindex=0; rindex<edgeLen; ++rindex)
+ {
+ for(int gindex=0; gindex<edgeLen; ++gindex)
+ {
+ for(int bindex=0; bindex<edgeLen; ++bindex)
+ {
+ index = GetLut3DIndex_B(rindex, gindex, bindex,
+ edgeLen, edgeLen, edgeLen);
+
+ output << rindex << " " << gindex << " " << bindex << " ";
+ output << lutdata[index+0] << " ";
+ output << lutdata[index+1] << " ";
+ output << lutdata[index+2] << "\n";
+ }
+ }
+ }
+
+ output.close();
+}
diff --git a/src/apps/share/argparse.cpp b/src/apps/share/argparse.cpp
new file mode 100644
index 0000000..ea61d78
--- /dev/null
+++ b/src/apps/share/argparse.cpp
@@ -0,0 +1,528 @@
+/*
+ Copyright 2008 Larry Gritz and the other authors and contributors.
+ All Rights Reserved.
+ Based on BSD-licensed software Copyright 2004 NVIDIA Corp.
+
+ 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 the software's owners 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.
+
+ (This is the Modified BSD License)
+*/
+
+
+#include <cstring>
+#include <cctype>
+#include <cassert>
+#include <cstdlib>
+#include <iostream>
+#include <cstdarg>
+#include <iterator>
+
+#include "strutil.h"
+#include "argparse.h"
+
+/*
+OIIO_NAMESPACE_ENTER
+{
+*/
+
+class ArgOption {
+public:
+ typedef int (*callback_t) (int, const char**);
+
+ ArgOption (const char *str);
+ ~ArgOption () { }
+
+ int initialize ();
+
+ int parameter_count () const { return m_count; }
+ const std::string & name() const { return m_flag; }
+
+ const std::string & fmt() const { return m_format; }
+
+ bool is_flag () const { return m_type == Flag; }
+ bool is_sublist () const { return m_type == Sublist; }
+ bool is_regular () const { return m_type == Regular; }
+
+ void add_parameter (int i, void *p);
+
+ void set_parameter (int i, const char *argv);
+
+ void add_argument (const char *argv);
+ int invoke_callback () const;
+
+ int invoke_callback (int argc, const char **argv) const {
+ return m_callback ? m_callback (argc, argv) : 0;
+ }
+
+ void set_callback (callback_t cb) { m_callback = cb; }
+
+ void found_on_command_line () { m_repetitions++; }
+ int parsed_count () const { return m_repetitions; }
+
+ void description (const char *d) { m_descript = d; }
+ const std::string & description() const { return m_descript; }
+
+private:
+ enum OptionType { None, Regular, Flag, Sublist };
+
+ std::string m_format; // original format string
+ std::string m_flag; // just the -flag_foo part
+ std::string m_code; // paramter types, eg "df"
+ std::string m_descript;
+ OptionType m_type;
+ int m_count; // number of parameters
+ std::vector<void *> m_param; // pointers to app data vars
+ callback_t m_callback;
+ int m_repetitions; // number of times on cmd line
+ std::vector<std::string> m_argv;
+};
+
+
+
+// Constructor. Does not do any parsing or error checking.
+// Make sure to call initialize() right after construction.
+ArgOption::ArgOption (const char *str)
+ : m_format(str), m_type(None), m_count(0),
+ m_callback(NULL), m_repetitions(0)
+{
+}
+
+
+
+// Parses the format string ("-option %s %d %f") to extract the
+// flag ("-option") and create a code string ("sdf"). After the
+// code string is created, the param list of void* pointers is
+// allocated to hold the argument variable pointers.
+int
+ArgOption::initialize()
+{
+ size_t n;
+ const char *s;
+
+ if (m_format.empty() || m_format == "%*") {
+ m_type = Sublist;
+ m_count = 1; // sublist callback function pointer
+ m_code = "*";
+ m_flag = "";
+ } else if (m_format == "<SEPARATOR>") {
+ } else {
+ // extract the flag name
+ s = &m_format[0];
+ assert(*s == '-');
+ assert(isalpha(s[1]) || (s[1] == '-' && isalpha(s[2])));
+
+ s++;
+ if (*s == '-')
+ s++;
+
+ while (isalnum(*s) || *s == '_' || *s == '-') s++;
+
+ if (! *s) {
+ m_flag = m_format;
+ m_type = Flag;
+ m_count = 1;
+ m_code = "b";
+ } else {
+ n = s - (&m_format[0]);
+ m_flag.assign (m_format.begin(), m_format.begin()+n);
+
+ // Parse the scanf-like parameters
+
+ m_type = Regular;
+
+ n = (m_format.length() - n) / 2; // conservative estimate
+ m_code.clear ();
+
+ while (*s != '\0') {
+ if (*s == '%') {
+ s++;
+ assert(*s != '\0');
+
+ m_count++; // adding another parameter
+
+ switch (*s) {
+ case 'd': // 32bit int
+ case 'g': // float
+ case 'f': // float
+ case 'F': // double
+ case 's': // string
+ case 'L': // vector<string>
+ assert (m_type == Regular);
+ m_code += *s;
+ break;
+
+ case '*':
+ assert(m_count == 1);
+ m_type = Sublist;
+ break;
+
+ default:
+ std::cerr << "Programmer error: Unknown option ";
+ std::cerr << "type string \"" << *s << "\"" << "\n";
+ abort();
+ }
+ }
+
+ s++;
+ }
+ }
+ }
+
+ // Allocate space for the parameter pointers and initialize to NULL
+ m_param.resize (m_count, NULL);
+
+ return 0;
+}
+
+
+
+// Stores the pointer to an argument in the param list and
+// initializes flag options to FALSE.
+// FIXME -- there is no such initialization. Bug?
+void
+ArgOption::add_parameter (int i, void *p)
+{
+ assert (i >= 0 && i < m_count);
+ m_param[i] = p;
+}
+
+
+
+// Given a string from argv, set the associated option parameter
+// at index i using the format conversion code in the code string.
+void
+ArgOption::set_parameter (int i, const char *argv)
+{
+ assert(i < m_count);
+
+ switch (m_code[i]) {
+ case 'd':
+ *(int *)m_param[i] = atoi(argv);
+ break;
+
+ case 'f':
+ case 'g':
+ *(float *)m_param[i] = (float)atof(argv);
+ break;
+
+ case 'F':
+ *(double *)m_param[i] = atof(argv);
+ break;
+
+ case 's':
+ *(std::string *)m_param[i] = argv;
+ break;
+
+ case 'S':
+ *(std::string *)m_param[i] = argv;
+ break;
+
+ case 'L':
+ ((std::vector<std::string> *)m_param[i])->push_back (argv);
+ break;
+
+ case 'b':
+ *(bool *)m_param[i] = true;
+ break;
+
+ case '*':
+ default:
+ abort();
+ }
+}
+
+
+
+// Call the sublist callback if any arguments have been parsed
+int
+ArgOption::invoke_callback () const
+{
+ assert (m_count == 1);
+
+ int argc = (int) m_argv.size();
+ if (argc == 0)
+ return 0;
+
+ // Convert the argv's to char*[]
+ const char **myargv = (const char **) alloca (argc * sizeof(const char *));
+ for (int i = 0; i < argc; ++i)
+ myargv[i] = m_argv[i].c_str();
+ return invoke_callback (argc, myargv);
+}
+
+
+
+// Add an argument to this sublist option
+void
+ArgOption::add_argument (const char *argv)
+{
+ m_argv.push_back (argv);
+}
+
+
+
+
+
+ArgParse::ArgParse (int argc, const char **argv)
+ : m_argc(argc), m_argv(argv), m_global(NULL)
+{
+}
+
+
+
+ArgParse::~ArgParse()
+{
+ for (unsigned int i=0; i<m_option.size(); ++i) {
+ ArgOption *opt = m_option[i];
+ delete opt;
+ }
+}
+
+
+
+// Top level command line parsing function called after all options
+// have been parsed and created from the format strings. This function
+// parses the command line (argc,argv) stored internally in the constructor.
+// Each command line argument is parsed and checked to see if it matches an
+// existing option. If there is no match, and error is reported and the
+// function returns early. If there is a match, all the arguments for
+// that option are parsed and the associated variables are set.
+int
+ArgParse::parse (int xargc, const char **xargv)
+{
+ m_argc = xargc;
+ m_argv = xargv;
+
+ for (int i = 1; i < m_argc; i++) {
+ if (m_argv[i][0] == '-' &&
+ (isalpha (m_argv[i][1]) || m_argv[i][1] == '-')) { // flag
+ ArgOption *option = find_option (m_argv[i]);
+ if (option == NULL) {
+ error ("Invalid option \"%s\"", m_argv[i]);
+ return -1;
+ }
+
+ option->found_on_command_line();
+
+ if (option->is_flag()) {
+ option->set_parameter(0, NULL);
+ } else {
+ assert (option->is_regular());
+ for (int j = 0; j < option->parameter_count(); j++) {
+ if (j+i+1 >= m_argc) {
+ error ("Missing parameter %d from option "
+ "\"%s\"", j+1, option->name().c_str());
+ return -1;
+ }
+ option->set_parameter (j, m_argv[i+j+1]);
+ }
+ i += option->parameter_count();
+ }
+ } else {
+ // not an option nor an option parameter, glob onto global list
+ if (m_global)
+ m_global->invoke_callback (1, m_argv+i);
+ else {
+ error ("Argument \"%s\" does not have an associated "
+ "option", m_argv[i]);
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+
+// Primary entry point. This function accepts a set of format strings
+// and variable pointers. Each string contains an option name and a
+// scanf-like format string to enumerate the arguments of that option
+// (eg. "-option %d %f %s"). The format string is followed by a list
+// of pointers to the argument variables, just like scanf. All format
+// strings and arguments are parsed to create a list of ArgOption objects.
+// After all ArgOptions are created, the command line is parsed and
+// the sublist option callbacks are invoked.
+int
+ArgParse::options (const char *intro, ...)
+{
+ va_list ap;
+ va_start (ap, intro);
+
+ m_intro = intro;
+ for (const char *cur = va_arg(ap, char *); cur; cur = va_arg(ap, char *)) {
+ if (find_option (cur) &&
+ strcmp(cur, "<SEPARATOR>")) {
+ error ("Option \"%s\" is multiply defined", cur);
+ return -1;
+ }
+
+ // Build a new option and then parse the values
+ ArgOption *option = new ArgOption (cur);
+ if (option->initialize() < 0) {
+ return -1;
+ }
+
+ if (cur[0] == '\0' ||
+ (cur[0] == '%' && cur[1] == '*' && cur[2] == '\0')) {
+ // set default global option
+ m_global = option;
+ }
+
+ // Grab any parameters and store them with this option
+ for (int i = 0; i < option->parameter_count(); i++) {
+ void *p = va_arg (ap, void *);
+ if (p == NULL) {
+ error ("Missing argument parameter for \"%s\"",
+ option->name().c_str());
+ return -1;
+ }
+
+ option->add_parameter (i, p);
+
+ if (option == m_global)
+ option->set_callback ((ArgOption::callback_t)p);
+ }
+
+ // Last argument is description
+ option->description ((const char *) va_arg (ap, const char *));
+ m_option.push_back(option);
+ }
+
+ va_end (ap);
+ return 0;
+}
+
+
+
+// Find an option by name in the option vector
+ArgOption *
+ArgParse::find_option (const char *name)
+{
+ for (std::vector<ArgOption *>::const_iterator i = m_option.begin();
+ i != m_option.end(); i++) {
+ const char *opt = (*i)->name().c_str();
+ if (! strcmp(name, opt))
+ return *i;
+ // Match even if the user mixes up one dash or two
+ if (name[0] == '-' && name[1] == '-' && opt[0] == '-' && opt[1] != '-')
+ if (! strcmp (name+1, opt))
+ return *i;
+ if (name[0] == '-' && name[1] != '-' && opt[0] == '-' && opt[1] == '-')
+ if (! strcmp (name, opt+1))
+ return *i;
+ }
+
+ return NULL;
+}
+
+
+
+int
+ArgParse::found (const char *option_name)
+{
+ ArgOption *option = find_option(option_name);
+ if (option == NULL) return 0;
+ return option->parsed_count();
+}
+
+
+
+void
+ArgParse::error (const char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+ m_errmessage = Strutil::vformat (format, ap);
+ va_end (ap);
+}
+
+std::string
+ArgParse::geterror () const
+{
+ std::string e = m_errmessage;
+ m_errmessage.clear ();
+ return e;
+}
+
+
+void
+ArgParse::usage () const
+{
+ const size_t longline = 40;
+ std::cout << m_intro << '\n';
+ size_t maxlen = 0;
+
+ for (unsigned int i=0; i<m_option.size(); ++i) {
+ ArgOption *opt = m_option[i];
+ size_t fmtlen = opt->fmt().length();
+ // Option lists > 40 chars will be split into multiple lines
+ if (fmtlen < longline)
+ maxlen = std::max (maxlen, fmtlen);
+ }
+
+ for (unsigned int i=0; i<m_option.size(); ++i) {
+ ArgOption *opt = m_option[i];
+ if (opt->description().length()) {
+ size_t fmtlen = opt->fmt().length();
+ if (opt->fmt() == "<SEPARATOR>")
+ std::cout << opt->description() << '\n';
+ else if (fmtlen < longline)
+ std::cout << " " << opt->fmt()
+ << std::string (maxlen + 2 - fmtlen, ' ')
+ << opt->description() << '\n';
+ else
+ std::cout << " " << opt->fmt() << "\n "
+ << std::string (maxlen + 2, ' ')
+ << opt->description() << '\n';
+ }
+ }
+}
+
+
+
+std::string
+ArgParse::command_line () const
+{
+ std::string s;
+ for (int i = 0; i < m_argc; ++i) {
+ if (strchr (m_argv[i], ' ')) {
+ s += '\"';
+ s += m_argv[i];
+ s += '\"';
+ } else {
+ s += m_argv[i];
+ }
+ if (i < m_argc-1)
+ s += ' ';
+ }
+ return s;
+}
+
+
+/*
+}
+OIIO_NAMESPACE_EXIT
+*/
+
diff --git a/src/apps/share/argparse.h b/src/apps/share/argparse.h
new file mode 100644
index 0000000..fd3ec6d
--- /dev/null
+++ b/src/apps/share/argparse.h
@@ -0,0 +1,181 @@
+/*
+ Copyright 2008 Larry Gritz and the other authors and contributors.
+ All Rights Reserved.
+ Based on BSD-licensed software Copyright 2004 NVIDIA Corp.
+
+ 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 the software's owners 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.
+
+ (This is the Modified BSD License)
+*/
+
+
+/// \file
+/// \brief Simple parsing of program command-line arguments.
+
+
+#ifndef OPENCOLORIO_ARGPARSE_H
+#define OPENCOLORIO_ARGPARSE_H
+
+#include <vector>
+
+#ifndef OPENCOLORIO_PRINTF_ARGS /* See comments in strutil.h */
+# ifndef __GNUC__
+# define __attribute__(x)
+# endif
+# define OPENCOLORIO_PRINTF_ARGS(fmtarg_pos, vararg_pos) \
+ __attribute__ ((format (printf, fmtarg_pos, vararg_pos) ))
+#endif
+
+/*
+OIIO_NAMESPACE_ENTER
+{
+*/
+
+class ArgOption; // Forward declaration
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+///
+/// \class ArgParse
+///
+/// Argument Parsing
+///
+/// The parse function takes a list of options and variables or functions
+/// for storing option values and return <0 on failure:
+///
+/// \code
+/// static int
+/// parse_files (int argc, const char *argv[])
+/// {
+/// for (int i = 0; i < argc; i++)
+/// filenames.push_back (argv[i]);
+/// return 0;
+/// }
+///
+/// ...
+///
+/// ArgParse ap;
+///
+/// ap.options ("Usage: myapp [options] filename...",
+/// "%*", parse_objects, "",
+/// "-camera %f %f %f", &camera[0], &camera[1], &camera[2],
+/// "set the camera position",
+/// "-lookat %f %f %f", &lx, &ly, &lz,
+/// "set the position of interest",
+/// "-oversampling %d", &oversampling, "oversamping rate",
+/// "-passes %d", &passes, "number of passes",
+/// "-lens %f %f %f", &aperture, &focalDistance, &focalLength,
+/// "set aperture, focal distance, focal length",
+/// "-format %d %d %f", &width, &height, &aspect,
+/// "set width, height, aspect ratio",
+/// "-v", &flag, "verbose output",
+/// NULL);
+///
+/// if (ap.parse (argc, argv) < 0) {
+/// std::cerr << ap.geterror() << std::endl;
+/// ap.usage ();
+/// return EXIT_FAILURE;
+/// }
+/// \endcode
+///
+/// The available argument types are:
+/// - no \% argument - bool flag
+/// - \%d - 32bit integer
+/// - \%f - 32bit float
+/// - \%F - 64bit float (double)
+/// - \%s - std::string
+/// - \%L - std::vector<std::string> (takes 1 arg, appends to list)
+/// - \%* - catch all non-options and pass individually as an (argc,argv)
+/// sublist to a callback, each immediately after it's found
+///
+/// There are several special format tokens:
+/// - "<SEPARATOR>" - not an option at all, just a description to print
+/// in the usage output.
+///
+/// Notes:
+/// - If an option doesn't have any arguments, a flag argument is assumed.
+/// - Flags are initialized to false. No other variables are initialized.
+/// - The empty string, "", is used as a global sublist (ie. "%*").
+/// - Sublist functions are all of the form "int func(int argc, char **argv)".
+/// - If a sublist function returns -1, parse() will terminate early.
+///
+/////////////////////////////////////////////////////////////////////////////
+
+
+class ArgParse {
+public:
+ ArgParse (int argc=0, const char **argv=NULL);
+ ~ArgParse ();
+
+ /// Declare the command line options. After the introductory
+ /// message, parameters are a set of format strings and variable
+ /// pointers. Each string contains an option name and a scanf-like
+ /// format string to enumerate the arguments of that option
+ /// (eg. "-option %d %f %s"). The format string is followed by a
+ /// list of pointers to the argument variables, just like scanf. A
+ /// NULL terminates the list.
+ int options (const char *intro, ...);
+
+ /// With the options already set up, parse the command line.
+ /// Return 0 if ok, -1 if it's a malformed command line.
+ int parse (int argc, const char **argv);
+
+ /// Return any error messages generated during the course of parse()
+ /// (and clear any error flags). If no error has occurred since the
+ /// last time geterror() was called, it will return an empty string.
+ std::string geterror () const;
+
+ /// Deprecated
+ ///
+ std::string error_message () const { return geterror (); }
+
+ /// Print the usage message to stdout. The usage message is
+ /// generated and formatted automatically based on the command and
+ /// description arguments passed to parse().
+ void usage () const;
+
+ /// Return the entire command-line as one string.
+ ///
+ std::string command_line () const;
+
+private:
+ int m_argc; // a copy of the command line argc
+ const char **m_argv; // a copy of the command line argv
+ mutable std::string m_errmessage; // error message
+ ArgOption *m_global; // option for extra cmd line arguments
+ std::string m_intro;
+ std::vector<ArgOption *> m_option;
+
+ ArgOption *find_option(const char *name);
+ void error (const char *format, ...) OPENCOLORIO_PRINTF_ARGS(2,3);
+ int found (const char *option); // number of times option was parsed
+};
+
+/*
+}
+OIIO_NAMESPACE_EXIT
+*/
+
+#endif // OPENCOLORIO_ARGPARSE_H
diff --git a/src/apps/share/pystring.cpp b/src/apps/share/pystring.cpp
new file mode 100644
index 0000000..7805162
--- /dev/null
+++ b/src/apps/share/pystring.cpp
@@ -0,0 +1,1658 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2008-2010, Sony Pictures Imageworks Inc
+// 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 the organization 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 "pystring.h"
+
+#include <algorithm>
+#include <cctype>
+#include <cstring>
+#include <iostream>
+#include <sstream>
+
+OCIO_NAMESPACE_ENTER
+{
+
+namespace pystring
+{
+
+#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS) || defined(_MSC_VER)
+#ifndef WINDOWS
+#define WINDOWS
+#endif
+#endif
+
+// This definition codes from configure.in in the python src.
+// Strictly speaking this limits us to str sizes of 2**31.
+// Should we wish to handle this limit, we could use an architecture
+// specific #defines and read from ssize_t (unistd.h) if the header exists.
+// But in the meantime, the use of int assures maximum arch compatibility.
+// This must also equal the size used in the end = MAX_32BIT_INT default arg.
+
+typedef int Py_ssize_t;
+
+/* helper macro to fixup start/end slice values */
+#define ADJUST_INDICES(start, end, len) \
+ if (end > len) \
+ end = len; \
+ else if (end < 0) { \
+ end += len; \
+ if (end < 0) \
+ end = 0; \
+ } \
+ if (start < 0) { \
+ start += len; \
+ if (start < 0) \
+ start = 0; \
+ }
+
+
+ namespace {
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// why doesn't the std::reverse work?
+ ///
+ void reverse_strings( std::vector< std::string > & result)
+ {
+ for (std::vector< std::string >::size_type i = 0; i < result.size() / 2; i++ )
+ {
+ std::swap(result[i], result[result.size() - 1 - i]);
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ void split_whitespace( const std::string & str, std::vector< std::string > & result, int maxsplit )
+ {
+ std::string::size_type i, j, len = str.size();
+ for (i = j = 0; i < len; )
+ {
+
+ while ( i < len && ::isspace( str[i] ) ) i++;
+ j = i;
+
+ while ( i < len && ! ::isspace( str[i]) ) i++;
+
+
+
+ if (j < i)
+ {
+ if ( maxsplit-- <= 0 ) break;
+
+ result.push_back( str.substr( j, i - j ));
+
+ while ( i < len && ::isspace( str[i])) i++;
+ j = i;
+ }
+ }
+ if (j < len)
+ {
+ result.push_back( str.substr( j, len - j ));
+ }
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ void rsplit_whitespace( const std::string & str, std::vector< std::string > & result, int maxsplit )
+ {
+ std::string::size_type len = str.size();
+ std::string::size_type i, j;
+ for (i = j = len; i > 0; )
+ {
+
+ while ( i > 0 && ::isspace( str[i - 1] ) ) i--;
+ j = i;
+
+ while ( i > 0 && ! ::isspace( str[i - 1]) ) i--;
+
+
+
+ if (j > i)
+ {
+ if ( maxsplit-- <= 0 ) break;
+
+ result.push_back( str.substr( i, j - i ));
+
+ while ( i > 0 && ::isspace( str[i - 1])) i--;
+ j = i;
+ }
+ }
+ if (j > 0)
+ {
+ result.push_back( str.substr( 0, j ));
+ }
+ //std::reverse( result, result.begin(), result.end() );
+ reverse_strings( result );
+ }
+
+ } //anonymous namespace
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ void split( const std::string & str, std::vector< std::string > & result, const std::string & sep, int maxsplit )
+ {
+ result.clear();
+
+ if ( maxsplit < 0 ) maxsplit = MAX_32BIT_INT;//result.max_size();
+
+
+ if ( sep.size() == 0 )
+ {
+ split_whitespace( str, result, maxsplit );
+ return;
+ }
+
+ std::string::size_type i,j, len = str.size(), n = sep.size();
+
+ i = j = 0;
+
+ while ( i+n <= len )
+ {
+ if ( str[i] == sep[0] && str.substr( i, n ) == sep )
+ {
+ if ( maxsplit-- <= 0 ) break;
+
+ result.push_back( str.substr( j, i - j ) );
+ i = j = i + n;
+ }
+ else
+ {
+ i++;
+ }
+ }
+
+ result.push_back( str.substr( j, len-j ) );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ void rsplit( const std::string & str, std::vector< std::string > & result, const std::string & sep, int maxsplit )
+ {
+ if ( maxsplit < 0 )
+ {
+ split( str, result, sep, 0 );
+ return;
+ }
+
+ result.clear();
+
+ if ( sep.size() == 0 )
+ {
+ rsplit_whitespace( str, result, maxsplit );
+ return;
+ }
+
+ std::string::size_type i,j, len = str.size(), n = sep.size();
+
+ i = j = len;
+
+ while ( i > n )
+ {
+ if ( str[i - 1] == sep[n - 1] && str.substr( i - n, n ) == sep )
+ {
+ if ( maxsplit-- <= 0 ) break;
+
+ result.push_back( str.substr( i, j - i ) );
+ i = j = i - n;
+ }
+ else
+ {
+ i--;
+ }
+ }
+
+ result.push_back( str.substr( 0, j ) );
+ reverse_strings( result );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ #define LEFTSTRIP 0
+ #define RIGHTSTRIP 1
+ #define BOTHSTRIP 2
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string do_strip( const std::string & str, int striptype, const std::string & chars )
+ {
+ Py_ssize_t len = (Py_ssize_t) str.size(), i, j, charslen = (Py_ssize_t) chars.size();
+
+ if ( charslen == 0 )
+ {
+ i = 0;
+ if ( striptype != RIGHTSTRIP )
+ {
+ while ( i < len && ::isspace( str[i] ) )
+ {
+ i++;
+ }
+ }
+
+ j = len;
+ if ( striptype != LEFTSTRIP )
+ {
+ do
+ {
+ j--;
+ }
+ while (j >= i && ::isspace(str[j]));
+
+ j++;
+ }
+
+
+ }
+ else
+ {
+ const char * sep = chars.c_str();
+
+ i = 0;
+ if ( striptype != RIGHTSTRIP )
+ {
+ while ( i < len && memchr(sep, str[i], charslen) )
+ {
+ i++;
+ }
+ }
+
+ j = len;
+ if (striptype != LEFTSTRIP)
+ {
+ do
+ {
+ j--;
+ }
+ while (j >= i && memchr(sep, str[j], charslen) );
+ j++;
+ }
+
+
+ }
+
+ if ( i == 0 && j == len )
+ {
+ return str;
+ }
+ else
+ {
+ return str.substr( i, j - i );
+ }
+
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ void partition( const std::string & str, const std::string & sep, std::vector< std::string > & result )
+ {
+ result.resize(3);
+ int index = find( str, sep );
+ if ( index < 0 )
+ {
+ result[0] = str;
+ result[1] = "";
+ result[2] = "";
+ }
+ else
+ {
+ result[0] = str.substr( 0, index );
+ result[1] = sep;
+ result[2] = str.substr( index + sep.size(), str.size() );
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ void rpartition( const std::string & str, const std::string & sep, std::vector< std::string > & result )
+ {
+ result.resize(3);
+ int index = rfind( str, sep );
+ if ( index < 0 )
+ {
+ result[0] = "";
+ result[1] = "";
+ result[2] = str;
+ }
+ else
+ {
+ result[0] = str.substr( 0, index );
+ result[1] = sep;
+ result[2] = str.substr( index + sep.size(), str.size() );
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string strip( const std::string & str, const std::string & chars )
+ {
+ return do_strip( str, BOTHSTRIP, chars );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string lstrip( const std::string & str, const std::string & chars )
+ {
+ return do_strip( str, LEFTSTRIP, chars );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string rstrip( const std::string & str, const std::string & chars )
+ {
+ return do_strip( str, RIGHTSTRIP, chars );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string join( const std::string & str, const std::vector< std::string > & seq )
+ {
+ std::vector< std::string >::size_type seqlen = seq.size(), i;
+
+ if ( seqlen == 0 ) return "";
+ if ( seqlen == 1 ) return seq[0];
+
+ std::string result( seq[0] );
+
+ for ( i = 1; i < seqlen; ++i )
+ {
+ result += str + seq[i];
+
+ }
+
+
+ return result;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+
+ namespace
+ {
+ /* Matches the end (direction >= 0) or start (direction < 0) of self
+ * against substr, using the start and end arguments. Returns
+ * -1 on error, 0 if not found and 1 if found.
+ */
+
+ int _string_tailmatch(const std::string & self, const std::string & substr,
+ Py_ssize_t start, Py_ssize_t end,
+ int direction)
+ {
+ Py_ssize_t len = (Py_ssize_t) self.size();
+ Py_ssize_t slen = (Py_ssize_t) substr.size();
+
+ const char* sub = substr.c_str();
+ const char* str = self.c_str();
+
+ ADJUST_INDICES(start, end, len);
+
+ if (direction < 0) {
+ // startswith
+ if (start+slen > len)
+ return 0;
+ } else {
+ // endswith
+ if (end-start < slen || start > len)
+ return 0;
+ if (end-slen > start)
+ start = end - slen;
+ }
+ if (end-start >= slen)
+ return (!std::memcmp(str+start, sub, slen));
+
+ return 0;
+ }
+ }
+
+ bool endswith( const std::string & str, const std::string & suffix, int start, int end )
+ {
+ int result = _string_tailmatch(str, suffix,
+ (Py_ssize_t) start, (Py_ssize_t) end, +1);
+ //if (result == -1) // TODO: Error condition
+
+ return static_cast<bool>(result);
+ }
+
+
+ bool startswith( const std::string & str, const std::string & prefix, int start, int end )
+ {
+ int result = _string_tailmatch(str, prefix,
+ (Py_ssize_t) start, (Py_ssize_t) end, -1);
+ //if (result == -1) // TODO: Error condition
+
+ return static_cast<bool>(result);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+
+ bool isalnum( const std::string & str )
+ {
+ std::string::size_type len = str.size(), i;
+ if ( len == 0 ) return false;
+
+
+ if( len == 1 )
+ {
+ return ::isalnum( str[0] );
+ }
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( !::isalnum( str[i] ) ) return false;
+ }
+ return true;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ bool isalpha( const std::string & str )
+ {
+ std::string::size_type len = str.size(), i;
+ if ( len == 0 ) return false;
+ if( len == 1 ) return ::isalpha( (int) str[0] );
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( !::isalpha( (int) str[i] ) ) return false;
+ }
+ return true;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ bool isdigit( const std::string & str )
+ {
+ std::string::size_type len = str.size(), i;
+ if ( len == 0 ) return false;
+ if( len == 1 ) return ::isdigit( str[0] );
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( ! ::isdigit( str[i] ) ) return false;
+ }
+ return true;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ bool islower( const std::string & str )
+ {
+ std::string::size_type len = str.size(), i;
+ if ( len == 0 ) return false;
+ if( len == 1 ) return ::islower( str[0] );
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( !::islower( str[i] ) ) return false;
+ }
+ return true;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ bool isspace( const std::string & str )
+ {
+ std::string::size_type len = str.size(), i;
+ if ( len == 0 ) return false;
+ if( len == 1 ) return ::isspace( str[0] );
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( !::isspace( str[i] ) ) return false;
+ }
+ return true;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ bool istitle( const std::string & str )
+ {
+ std::string::size_type len = str.size(), i;
+
+ if ( len == 0 ) return false;
+ if ( len == 1 ) return ::isupper( str[0] );
+
+ bool cased = false, previous_is_cased = false;
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( ::isupper( str[i] ) )
+ {
+ if ( previous_is_cased )
+ {
+ return false;
+ }
+
+ previous_is_cased = true;
+ cased = true;
+ }
+ else if ( ::islower( str[i] ) )
+ {
+ if (!previous_is_cased)
+ {
+ return false;
+ }
+
+ previous_is_cased = true;
+ cased = true;
+
+ }
+ else
+ {
+ previous_is_cased = false;
+ }
+ }
+
+ return cased;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ bool isupper( const std::string & str )
+ {
+ std::string::size_type len = str.size(), i;
+ if ( len == 0 ) return false;
+ if( len == 1 ) return ::isupper( str[0] );
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( !::isupper( str[i] ) ) return false;
+ }
+ return true;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string capitalize( const std::string & str )
+ {
+ std::string s( str );
+ std::string::size_type len = s.size(), i;
+
+ if ( len > 0)
+ {
+ if (::islower(s[0])) s[0] = (char) ::toupper( s[0] );
+ }
+
+ for ( i = 1; i < len; ++i )
+ {
+ if (::isupper(s[i])) s[i] = (char) ::tolower( s[i] );
+ }
+
+ return s;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string lower( const std::string & str )
+ {
+ std::string s( str );
+ std::string::size_type len = s.size(), i;
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( ::isupper( s[i] ) ) s[i] = (char) ::tolower( s[i] );
+ }
+
+ return s;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string upper( const std::string & str )
+ {
+ std::string s( str ) ;
+ std::string::size_type len = s.size(), i;
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( ::islower( s[i] ) ) s[i] = (char) ::toupper( s[i] );
+ }
+
+ return s;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string swapcase( const std::string & str )
+ {
+ std::string s( str );
+ std::string::size_type len = s.size(), i;
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( ::islower( s[i] ) ) s[i] = (char) ::toupper( s[i] );
+ else if (::isupper( s[i] ) ) s[i] = (char) ::tolower( s[i] );
+ }
+
+ return s;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string title( const std::string & str )
+ {
+ std::string s( str );
+ std::string::size_type len = s.size(), i;
+ bool previous_is_cased = false;
+
+ for ( i = 0; i < len; ++i )
+ {
+ int c = s[i];
+ if ( ::islower(c) )
+ {
+ if ( !previous_is_cased )
+ {
+ s[i] = (char) ::toupper(c);
+ }
+ previous_is_cased = true;
+ }
+ else if ( ::isupper(c) )
+ {
+ if ( previous_is_cased )
+ {
+ s[i] = (char) ::tolower(c);
+ }
+ previous_is_cased = true;
+ }
+ else
+ {
+ previous_is_cased = false;
+ }
+ }
+
+ return s;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string translate( const std::string & str, const std::string & table, const std::string & deletechars )
+ {
+ std::string s;
+ std::string::size_type len = str.size(), dellen = deletechars.size();
+
+ if ( table.size() != 256 )
+ {
+ // TODO : raise exception instead
+ return str;
+ }
+
+ //if nothing is deleted, use faster code
+ if ( dellen == 0 )
+ {
+ s = str;
+ for ( std::string::size_type i = 0; i < len; ++i )
+ {
+ s[i] = table[ s[i] ];
+ }
+ return s;
+ }
+
+
+ int trans_table[256];
+ for ( int i = 0; i < 256; i++)
+ {
+ trans_table[i] = table[i];
+ }
+
+ for ( std::string::size_type i = 0; i < dellen; i++)
+ {
+ trans_table[(int) deletechars[i] ] = -1;
+ }
+
+ for ( std::string::size_type i = 0; i < len; ++i )
+ {
+ if ( trans_table[ (int) str[i] ] != -1 )
+ {
+ s += table[ str[i] ];
+ }
+ }
+
+ return s;
+
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string zfill( const std::string & str, int width )
+ {
+ int len = (int)str.size();
+
+ if ( len >= width )
+ {
+ return str;
+ }
+
+ std::string s( str );
+
+ int fill = width - len;
+
+ s = std::string( fill, '0' ) + s;
+
+
+ if ( s[fill] == '+' || s[fill] == '-' )
+ {
+ s[0] = s[fill];
+ s[fill] = '0';
+ }
+
+ return s;
+
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string ljust( const std::string & str, int width )
+ {
+ std::string::size_type len = str.size();
+ if ( (( int ) len ) >= width ) return str;
+ return str + std::string( width - len, ' ' );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string rjust( const std::string & str, int width )
+ {
+ std::string::size_type len = str.size();
+ if ( (( int ) len ) >= width ) return str;
+ return std::string( width - len, ' ' ) + str;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string center( const std::string & str, int width )
+ {
+ int len = (int) str.size();
+ int marg, left;
+
+ if ( len >= width ) return str;
+
+ marg = width - len;
+ left = marg / 2 + (marg & width & 1);
+
+ return std::string( left, ' ' ) + str + std::string( marg - left, ' ' );
+
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string slice( const std::string & str, int start, int end )
+ {
+ ADJUST_INDICES(start, end, (int) str.size());
+ if ( start >= end ) return "";
+ return str.substr( start, end - start );
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ int find( const std::string & str, const std::string & sub, int start, int end )
+ {
+ ADJUST_INDICES(start, end, (int) str.size());
+
+ std::string::size_type result = str.find( sub, start );
+
+ // If we cannot find the string, or if the end-point of our found substring is past
+ // the allowed end limit, return that it can't be found.
+ if( result == std::string::npos ||
+ (result + sub.size() > (std::string::size_type)end) )
+ {
+ return -1;
+ }
+
+ return (int) result;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ int index( const std::string & str, const std::string & sub, int start, int end )
+ {
+ return find( str, sub, start, end );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ int rfind( const std::string & str, const std::string & sub, int start, int end )
+ {
+ ADJUST_INDICES(start, end, (int) str.size());
+
+ std::string::size_type result = str.rfind( sub, end );
+
+ if( result == std::string::npos ||
+ result < (std::string::size_type)start ||
+ (result + sub.size() > (std::string::size_type)end))
+ return -1;
+
+ return (int)result;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ int rindex( const std::string & str, const std::string & sub, int start, int end )
+ {
+ return rfind( str, sub, start, end );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string expandtabs( const std::string & str, int tabsize )
+ {
+ std::string s( str );
+
+ std::string::size_type len = str.size(), i = 0;
+ int offset = 0;
+
+ int j = 0;
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( str[i] == '\t' )
+ {
+
+ if ( tabsize > 0 )
+ {
+ int fillsize = tabsize - (j % tabsize);
+ j += fillsize;
+ s.replace( i + offset, 1, std::string( fillsize, ' ' ));
+ offset += fillsize - 1;
+ }
+ else
+ {
+ s.replace( i + offset, 1, "" );
+ offset -= 1;
+ }
+
+ }
+ else
+ {
+ j++;
+
+ if (str[i] == '\n' || str[i] == '\r')
+ {
+ j = 0;
+ }
+ }
+ }
+
+ return s;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ int count( const std::string & str, const std::string & substr, int start, int end )
+ {
+ int nummatches = 0;
+ int cursor = start;
+
+ while ( 1 )
+ {
+ cursor = find( str, substr, cursor, end );
+
+ if ( cursor < 0 ) break;
+
+ cursor += (int) substr.size();
+ nummatches += 1;
+ }
+
+ return nummatches;
+
+
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string replace( const std::string & str, const std::string & oldstr, const std::string & newstr, int count )
+ {
+ int sofar = 0;
+ int cursor = 0;
+ std::string s( str );
+
+ std::string::size_type oldlen = oldstr.size(), newlen = newstr.size();
+
+ while ( ( cursor = find( s, oldstr, cursor ) ) != -1 )
+ {
+ if ( count > -1 && sofar >= count )
+ {
+ break;
+ }
+
+ s.replace( cursor, oldlen, newstr );
+
+ cursor += (int) newlen;
+ ++sofar;
+ }
+
+ return s;
+
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ void splitlines( const std::string & str, std::vector< std::string > & result, bool keepends )
+ {
+ result.clear();
+ std::string::size_type len = str.size(), i, j, eol;
+
+ for (i = j = 0; i < len; )
+ {
+ while (i < len && str[i] != '\n' && str[i] != '\r') i++;
+
+ eol = i;
+ if (i < len)
+ {
+ if (str[i] == '\r' && i + 1 < len && str[i+1] == '\n')
+ {
+ i += 2;
+ }
+ else
+ {
+ i++;
+ }
+ if (keepends)
+ eol = i;
+
+ }
+
+ result.push_back( str.substr( j, eol - j ) );
+ j = i;
+
+ }
+
+ if (j < len)
+ {
+ result.push_back( str.substr( j, len - j ) );
+ }
+
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string mul( const std::string & str, int n )
+ {
+ // Early exits
+ if (n <= 0) return "";
+ if (n == 1) return str;
+
+ std::ostringstream os;
+ for(int i=0; i<n; ++i)
+ {
+ os << str;
+ }
+ return os.str();
+ }
+
+
+
+namespace os
+{
+namespace path
+{
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ /// These functions are C++ ports of the python2.6 versions of os.path,
+ /// and come from genericpath.py, ntpath.py, posixpath.py
+
+ /// Split a pathname into drive and path specifiers.
+ /// Returns drivespec, pathspec. Either part may be empty.
+ void splitdrive_nt(std::string & drivespec, std::string & pathspec,
+ const std::string & p)
+ {
+ if(pystring::slice(p, 1, 2) == ":")
+ {
+ std::string path = p; // In case drivespec == p
+ drivespec = pystring::slice(path, 0, 2);
+ pathspec = pystring::slice(path, 2);
+ }
+ else
+ {
+ drivespec = "";
+ pathspec = p;
+ }
+ }
+
+ // On Posix, drive is always empty
+ void splitdrive_posix(std::string & drivespec, std::string & pathspec,
+ const std::string & path)
+ {
+ drivespec = "";
+ pathspec = path;
+ }
+
+ void splitdrive(std::string & drivespec, std::string & pathspec,
+ const std::string & path)
+ {
+#ifdef WINDOWS
+ return splitdrive_nt(drivespec, pathspec, path);
+#else
+ return splitdrive_posix(drivespec, pathspec, path);
+#endif
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+
+ // Test whether a path is absolute
+ // In windows, if the character to the right of the colon
+ // is a forward or backslash it's absolute.
+ bool isabs_nt(const std::string & path)
+ {
+ std::string drivespec, pathspec;
+ splitdrive_nt(drivespec, pathspec, path);
+ if(pathspec.empty()) return false;
+ return ((pathspec[0] == '/') || (pathspec[0] == '\\'));
+ }
+
+ bool isabs_posix(const std::string & s)
+ {
+ return pystring::startswith(s, "/");
+ }
+
+ bool isabs(const std::string & path)
+ {
+#ifdef WINDOWS
+ return isabs_nt(path);
+#else
+ return isabs_posix(path);
+#endif
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+
+ std::string abspath_nt(const std::string & path, const std::string & cwd)
+ {
+ std::string p = path;
+ if(!isabs_nt(p)) p = join_nt(cwd, p);
+ return normpath_nt(p);
+ }
+
+ std::string abspath_posix(const std::string & path, const std::string & cwd)
+ {
+ std::string p = path;
+ if(!isabs_posix(p)) p = join_posix(cwd, p);
+ return normpath_posix(p);
+ }
+
+ std::string abspath(const std::string & path, const std::string & cwd)
+ {
+#ifdef WINDOWS
+ return abspath_nt(path, cwd);
+#else
+ return abspath_posix(path, cwd);
+#endif
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+
+ std::string join_nt(const std::vector< std::string > & paths)
+ {
+ if(paths.empty()) return "";
+ if(paths.size() == 1) return paths[0];
+
+ std::string path = paths[0];
+
+ for(unsigned int i=1; i<paths.size(); ++i)
+ {
+ std::string b = paths[i];
+
+ bool b_nts = false;
+ if(path.empty())
+ {
+ b_nts = true;
+ }
+ else if(isabs_nt(b))
+ {
+ // This probably wipes out path so far. However, it's more
+ // complicated if path begins with a drive letter:
+ // 1. join('c:', '/a') == 'c:/a'
+ // 2. join('c:/', '/a') == 'c:/a'
+ // But
+ // 3. join('c:/a', '/b') == '/b'
+ // 4. join('c:', 'd:/') = 'd:/'
+ // 5. join('c:/', 'd:/') = 'd:/'
+
+ if( (pystring::slice(path, 1, 2) != ":") ||
+ (pystring::slice(b, 1, 2) == ":") )
+ {
+ // Path doesnt start with a drive letter
+ b_nts = true;
+ }
+ // Else path has a drive letter, and b doesn't but is absolute.
+ else if((path.size()>3) ||
+ ((path.size()==3) && !pystring::endswith(path, "/") && !pystring::endswith(path, "\\")))
+ {
+ b_nts = true;
+ }
+ }
+
+ if(b_nts)
+ {
+ path = b;
+ }
+ else
+ {
+ // Join, and ensure there's a separator.
+ // assert len(path) > 0
+ if( pystring::endswith(path, "/") || pystring::endswith(path, "\\"))
+ {
+ if(pystring::startswith(b,"/") || pystring::startswith(b,"\\"))
+ {
+ path += pystring::slice(b, 1);
+ }
+ else
+ {
+ path += b;
+ }
+ }
+ else if(pystring::endswith(path, ":"))
+ {
+ path += b;
+ }
+ else if(!b.empty())
+ {
+ if(pystring::startswith(b,"/") || pystring::startswith(b,"\\"))
+ {
+ path += b;
+ }
+ else
+ {
+ path += "\\" + b;
+ }
+ }
+ else
+ {
+ // path is not empty and does not end with a backslash,
+ // but b is empty; since, e.g., split('a/') produces
+ // ('a', ''), it's best if join() adds a backslash in
+ // this case.
+ path += "\\";
+ }
+ }
+ }
+
+ return path;
+ }
+
+ // Join two or more pathname components, inserting "\\" as needed.
+ std::string join_nt(const std::string & a, const std::string & b)
+ {
+ std::vector< std::string > paths(2);
+ paths[0] = a;
+ paths[1] = b;
+ return join_nt(paths);
+ }
+
+ // Join pathnames.
+ // If any component is an absolute path, all previous path components
+ // will be discarded.
+ // Ignore the previous parts if a part is absolute.
+ // Insert a '/' unless the first part is empty or already ends in '/'.
+
+ std::string join_posix(const std::vector< std::string > & paths)
+ {
+ if(paths.empty()) return "";
+ if(paths.size() == 1) return paths[0];
+
+ std::string path = paths[0];
+
+ for(unsigned int i=1; i<paths.size(); ++i)
+ {
+ std::string b = paths[i];
+ if(pystring::startswith(b, "/"))
+ {
+ path = b;
+ }
+ else if(path.empty() || pystring::endswith(path, "/"))
+ {
+ path += b;
+ }
+ else
+ {
+ path += "/" + b;
+ }
+ }
+
+ return path;
+ }
+
+ std::string join_posix(const std::string & a, const std::string & b)
+ {
+ std::vector< std::string > paths(2);
+ paths[0] = a;
+ paths[1] = b;
+ return join_posix(paths);
+ }
+
+ std::string join(const std::string & path1, const std::string & path2)
+ {
+#ifdef WINDOWS
+ return join_nt(path1, path2);
+#else
+ return join_posix(path1, path2);
+#endif
+ }
+
+
+ std::string join(const std::vector< std::string > & paths)
+ {
+#ifdef WINDOWS
+ return join_nt(paths);
+#else
+ return join_posix(paths);
+#endif
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+
+
+ // Split a pathname.
+ // Return (head, tail) where tail is everything after the final slash.
+ // Either part may be empty
+
+ void split_nt(std::string & head, std::string & tail, const std::string & path)
+ {
+ std::string d, p;
+ splitdrive_nt(d, p, path);
+
+ // set i to index beyond p's last slash
+ int i = (int)p.size();
+
+ while(i>0 && (p[i-1] != '\\') && (p[i-1] != '/'))
+ {
+ i = i - 1;
+ }
+
+ head = pystring::slice(p,0,i);
+ tail = pystring::slice(p,i); // now tail has no slashes
+
+ // remove trailing slashes from head, unless it's all slashes
+ std::string head2 = head;
+ while(!head2.empty() && ((pystring::slice(head2,-1) == "/") ||
+ (pystring::slice(head2,-1) == "\\")))
+ {
+ head2 = pystring::slice(head,0,-1);
+ }
+
+ if(!head2.empty()) head = head2;
+ head = d + head;
+ }
+
+
+ // Split a path in head (everything up to the last '/') and tail (the
+ // rest). If the path ends in '/', tail will be empty. If there is no
+ // '/' in the path, head will be empty.
+ // Trailing '/'es are stripped from head unless it is the root.
+
+ void split_posix(std::string & head, std::string & tail, const std::string & p)
+ {
+ int i = pystring::rfind(p, "/") + 1;
+
+ head = pystring::slice(p,0,i);
+ tail = pystring::slice(p,i);
+
+ if(!head.empty() && (head != pystring::mul("/", (int) head.size())))
+ {
+ head = pystring::rstrip(head, "/");
+ }
+ }
+
+ void split(std::string & head, std::string & tail, const std::string & path)
+ {
+#ifdef WINDOWS
+ return split_nt(head, tail, path);
+#else
+ return split_posix(head, tail, path);
+#endif
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+
+ std::string basename_nt(const std::string & path)
+ {
+ std::string head, tail;
+ split_nt(head, tail, path);
+ return tail;
+ }
+
+ std::string basename_posix(const std::string & path)
+ {
+ std::string head, tail;
+ split_posix(head, tail, path);
+ return tail;
+ }
+
+ std::string basename(const std::string & path)
+ {
+#ifdef WINDOWS
+ return basename_nt(path);
+#else
+ return basename_posix(path);
+#endif
+ }
+
+ std::string dirname_nt(const std::string & path)
+ {
+ std::string head, tail;
+ split_nt(head, tail, path);
+ return head;
+ }
+
+ std::string dirname_posix(const std::string & path)
+ {
+ std::string head, tail;
+ split_posix(head, tail, path);
+ return head;
+ }
+
+ std::string dirname(const std::string & path)
+ {
+#ifdef WINDOWS
+ return dirname_nt(path);
+#else
+ return dirname_posix(path);
+#endif
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+
+ // Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B.
+ std::string normpath_nt(const std::string & p)
+ {
+ std::string path = p;
+ path = pystring::replace(path, "/","\\");
+
+ std::string prefix;
+ splitdrive_nt(prefix, path, path);
+
+ // We need to be careful here. If the prefix is empty, and the path starts
+ // with a backslash, it could either be an absolute path on the current
+ // drive (\dir1\dir2\file) or a UNC filename (\\server\mount\dir1\file). It
+ // is therefore imperative NOT to collapse multiple backslashes blindly in
+ // that case.
+ // The code below preserves multiple backslashes when there is no drive
+ // letter. This means that the invalid filename \\\a\b is preserved
+ // unchanged, where a\\\b is normalised to a\b. It's not clear that there
+ // is any better behaviour for such edge cases.
+
+ if(prefix.empty())
+ {
+ // No drive letter - preserve initial backslashes
+ while(pystring::slice(path,0,1) == "\\")
+ {
+ prefix = prefix + "\\";
+ path = pystring::slice(path,1);
+ }
+ }
+ else
+ {
+ // We have a drive letter - collapse initial backslashes
+ if(pystring::startswith(path, "\\"))
+ {
+ prefix = prefix + "\\";
+ path = pystring::lstrip(path, "\\");
+ }
+ }
+
+ std::vector<std::string> comps;
+ pystring::split(path, comps, "\\");
+
+ int i = 0;
+
+ while(i<(int)comps.size())
+ {
+ if(comps[i].empty() || comps[i] == ".")
+ {
+ comps.erase(comps.begin()+i);
+ }
+ else if(comps[i] == "..")
+ {
+ if(i>0 && comps[i-1] != "..")
+ {
+ comps.erase(comps.begin()+i-1, comps.begin()+i+1);
+ i -= 1;
+ }
+ else if(i == 0 && pystring::endswith(prefix, "\\"))
+ {
+ comps.erase(comps.begin()+i);
+ }
+ else
+ {
+ i += 1;
+ }
+ }
+ else
+ {
+ i += 1;
+ }
+ }
+
+ // If the path is now empty, substitute '.'
+ if(prefix.empty() && comps.empty())
+ {
+ comps.push_back(".");
+ }
+
+ return prefix + pystring::join("\\", comps);
+ }
+
+ // Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
+ // It should be understood that this may change the meaning of the path
+ // if it contains symbolic links!
+ // Normalize path, eliminating double slashes, etc.
+
+ std::string normpath_posix(const std::string & p)
+ {
+ if(p.empty()) return ".";
+
+ std::string path = p;
+
+ int initial_slashes = pystring::startswith(path,"/") ? 1 : 0;
+
+ // POSIX allows one or two initial slashes, but treats three or more
+ // as single slash.
+
+ if (initial_slashes && pystring::startswith(path,"//")
+ && !pystring::startswith(path,"///"))
+ initial_slashes = 2;
+
+ std::vector<std::string> comps, new_comps;
+ pystring::split(path, comps, "/");
+
+ for(unsigned int i=0; i<comps.size(); ++i)
+ {
+ std::string comp = comps[i];
+ if(comp.empty() || comp == ".")
+ continue;
+
+ if( (comp != "..") || ((initial_slashes == 0) && new_comps.empty()) ||
+ (!new_comps.empty() && new_comps[new_comps.size()-1] == ".."))
+ {
+ new_comps.push_back(comp);
+ }
+ else if (!new_comps.empty())
+ {
+ new_comps.pop_back();
+ }
+ }
+
+ path = pystring::join("/", new_comps);
+
+ if (initial_slashes > 0)
+ path = pystring::mul("/",initial_slashes) + path;
+
+ if(path.empty()) return ".";
+ return path;
+ }
+
+ std::string normpath(const std::string & path)
+ {
+#ifdef WINDOWS
+ return normpath_nt(path);
+#else
+ return normpath_posix(path);
+#endif
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+
+ // Split the extension from a pathname.
+ // Extension is everything from the last dot to the end, ignoring
+ // leading dots. Returns "(root, ext)"; ext may be empty.
+ // It is always true that root + ext == p
+
+ void splitext_generic(std::string & root, std::string & ext,
+ const std::string & p,
+ const std::string & sep,
+ const std::string & altsep,
+ const std::string & extsep)
+ {
+ int sepIndex = pystring::rfind(p, sep);
+ if(!altsep.empty())
+ {
+ int altsepIndex = pystring::rfind(p, altsep);
+ sepIndex = std::max(sepIndex, altsepIndex);
+ }
+
+ int dotIndex = pystring::rfind(p, extsep);
+ if(dotIndex > sepIndex)
+ {
+ // Skip all leading dots
+ int filenameIndex = sepIndex + 1;
+
+ while(filenameIndex < dotIndex)
+ {
+ if(pystring::slice(p,filenameIndex) != extsep)
+ {
+ root = pystring::slice(p, 0, dotIndex);
+ ext = pystring::slice(p, dotIndex);
+ return;
+ }
+
+ filenameIndex += 1;
+ }
+ }
+
+ root = p;
+ ext = "";
+ }
+
+ void splitext_nt(std::string & root, std::string & ext, const std::string & path)
+ {
+ return splitext_generic(root, ext, path,
+ "\\", "/", ".");
+ }
+
+ void splitext_posix(std::string & root, std::string & ext, const std::string & path)
+ {
+ return splitext_generic(root, ext, path,
+ "/", "", ".");
+ }
+
+ void splitext(std::string & root, std::string & ext, const std::string & path)
+ {
+#ifdef WINDOWS
+ return splitext_nt(root, ext, path);
+#else
+ return splitext_posix(root, ext, path);
+#endif
+ }
+
+} // namespace path
+} // namespace os
+
+
+}//namespace pystring
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/apps/share/pystring.h b/src/apps/share/pystring.h
new file mode 100644
index 0000000..f0729db
--- /dev/null
+++ b/src/apps/share/pystring.h
@@ -0,0 +1,438 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2008-2010, Sony Pictures Imageworks Inc
+// 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 the organization 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.
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDED_OCIO_PYSTRING_H
+#define INCLUDED_OCIO_PYSTRING_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include <string>
+#include <vector>
+
+OCIO_NAMESPACE_ENTER
+{
+// Version 1.1.2
+// https://github.com/imageworks/pystring/tarball/v1.1.2
+
+namespace pystring
+{
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @mainpage pystring
+ ///
+ /// This is a set of functions matching the interface and behaviors of python string methods
+ /// (as of python 2.3) using std::string.
+ ///
+ /// Overlapping functionality ( such as index and slice/substr ) of std::string is included
+ /// to match python interfaces.
+ ///
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @defgroup functions pystring
+ /// @{
+
+
+ #define MAX_32BIT_INT 2147483647
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string with only its first character capitalized.
+ ///
+ std::string capitalize( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return centered in a string of length width. Padding is done using spaces.
+ ///
+ std::string center( const std::string & str, int width );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return the number of occurrences of substring sub in string S[start:end]. Optional
+ /// arguments start and end are interpreted as in slice notation.
+ ///
+ int count( const std::string & str, const std::string & substr, int start = 0, int end = MAX_32BIT_INT);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return True if the string ends with the specified suffix, otherwise return False. With
+ /// optional start, test beginning at that position. With optional end, stop comparing at that position.
+ ///
+ bool endswith( const std::string & str, const std::string & suffix, int start = 0, int end = MAX_32BIT_INT );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string where all tab characters are expanded using spaces. If tabsize
+ /// is not given, a tab size of 8 characters is assumed.
+ ///
+ std::string expandtabs( const std::string & str, int tabsize = 8);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return the lowest index in the string where substring sub is found, such that sub is
+ /// contained in the range [start, end). Optional arguments start and end are interpreted as
+ /// in slice notation. Return -1 if sub is not found.
+ ///
+ int find( const std::string & str, const std::string & sub, int start = 0, int end = MAX_32BIT_INT );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Synonym of find right now. Python version throws exceptions. This one currently doesn't
+ ///
+ int index( const std::string & str, const std::string & sub, int start = 0, int end = MAX_32BIT_INT );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return true if all characters in the string are alphanumeric and there is at least one
+ /// character, false otherwise.
+ ///
+ bool isalnum( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return true if all characters in the string are alphabetic and there is at least one
+ /// character, false otherwise
+ ///
+ bool isalpha( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return true if all characters in the string are digits and there is at least one
+ /// character, false otherwise.
+ ///
+ bool isdigit( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return true if all cased characters in the string are lowercase and there is at least one
+ /// cased character, false otherwise.
+ ///
+ bool islower( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return true if there are only whitespace characters in the string and there is at least
+ /// one character, false otherwise.
+ ///
+ bool isspace( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return true if the string is a titlecased string and there is at least one character,
+ /// i.e. uppercase characters may only follow uncased characters and lowercase characters only
+ /// cased ones. Return false otherwise.
+ ///
+ bool istitle( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return true if all cased characters in the string are uppercase and there is at least one
+ /// cased character, false otherwise.
+ ///
+ bool isupper( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a string which is the concatenation of the strings in the sequence seq.
+ /// The separator between elements is the str argument
+ ///
+ std::string join( const std::string & str, const std::vector< std::string > & seq );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return the string left justified in a string of length width. Padding is done using
+ /// spaces. The original string is returned if width is less than str.size().
+ ///
+ std::string ljust( const std::string & str, int width );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string converted to lowercase.
+ ///
+ std::string lower( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string with leading characters removed. If chars is omitted or None,
+ /// whitespace characters are removed. If given and not "", chars must be a string; the
+ /// characters in the string will be stripped from the beginning of the string this method
+ /// is called on (argument "str" ).
+ ///
+ std::string lstrip( const std::string & str, const std::string & chars = "" );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string, concatenated N times, together.
+ /// Corresponds to the __mul__ operator.
+ ///
+ std::string mul( const std::string & str, int n);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Split the string around first occurance of sep.
+ /// Three strings will always placed into result. If sep is found, the strings will
+ /// be the text before sep, sep itself, and the remaining text. If sep is
+ /// not found, the original string will be returned with two empty strings.
+ ///
+ void partition( const std::string & str, const std::string & sep, std::vector< std::string > & result );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string with all occurrences of substring old replaced by new. If
+ /// the optional argument count is given, only the first count occurrences are replaced.
+ ///
+ std::string replace( const std::string & str, const std::string & oldstr, const std::string & newstr, int count = -1);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return the highest index in the string where substring sub is found, such that sub is
+ /// contained within s[start,end]. Optional arguments start and end are interpreted as in
+ /// slice notation. Return -1 on failure.
+ ///
+ int rfind( const std::string & str, const std::string & sub, int start = 0, int end = MAX_32BIT_INT );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Currently a synonym of rfind. The python version raises exceptions. This one currently
+ /// does not
+ ///
+ int rindex( const std::string & str, const std::string & sub, int start = 0, int end = MAX_32BIT_INT );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return the string right justified in a string of length width. Padding is done using
+ /// spaces. The original string is returned if width is less than str.size().
+ ///
+ std::string rjust( const std::string & str, int width);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Split the string around last occurance of sep.
+ /// Three strings will always placed into result. If sep is found, the strings will
+ /// be the text before sep, sep itself, and the remaining text. If sep is
+ /// not found, the original string will be returned with two empty strings.
+ ///
+ void rpartition( const std::string & str, const std::string & sep, std::vector< std::string > & result );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string with trailing characters removed. If chars is "", whitespace
+ /// characters are removed. If not "", the characters in the string will be stripped from the
+ /// end of the string this method is called on.
+ ///
+ std::string rstrip( const std::string & str, const std::string & chars = "" );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Fills the "result" list with the words in the string, using sep as the delimiter string.
+ /// If maxsplit is > -1, at most maxsplit splits are done. If sep is "",
+ /// any whitespace string is a separator.
+ ///
+ void split( const std::string & str, std::vector< std::string > & result, const std::string & sep = "", int maxsplit = -1);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Fills the "result" list with the words in the string, using sep as the delimiter string.
+ /// Does a number of splits starting at the end of the string, the result still has the
+ /// split strings in their original order.
+ /// If maxsplit is > -1, at most maxsplit splits are done. If sep is "",
+ /// any whitespace string is a separator.
+ ///
+ void rsplit( const std::string & str, std::vector< std::string > & result, const std::string & sep = "", int maxsplit = -1);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a list of the lines in the string, breaking at line boundaries. Line breaks
+ /// are not included in the resulting list unless keepends is given and true.
+ ///
+ void splitlines( const std::string & str, std::vector< std::string > & result, bool keepends = false );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return True if string starts with the prefix, otherwise return False. With optional start,
+ /// test string beginning at that position. With optional end, stop comparing string at that
+ /// position
+ ///
+ bool startswith( const std::string & str, const std::string & prefix, int start = 0, int end = MAX_32BIT_INT );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string with leading and trailing characters removed. If chars is "",
+ /// whitespace characters are removed. If given not "", the characters in the string will be
+ /// stripped from the both ends of the string this method is called on.
+ ///
+ std::string strip( const std::string & str, const std::string & chars = "" );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string with uppercase characters converted to lowercase and vice versa.
+ ///
+ std::string swapcase( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a titlecased version of the string: words start with uppercase characters,
+ /// all remaining cased characters are lowercase.
+ ///
+ std::string title( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string where all characters occurring in the optional argument
+ /// deletechars are removed, and the remaining characters have been mapped through the given
+ /// translation table, which must be a string of length 256.
+ ///
+ std::string translate( const std::string & str, const std::string & table, const std::string & deletechars = "");
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string converted to uppercase.
+ ///
+ std::string upper( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return the numeric string left filled with zeros in a string of length width. The original
+ /// string is returned if width is less than str.size().
+ ///
+ std::string zfill( const std::string & str, int width );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief function matching python's slice functionality.
+ ///
+ std::string slice( const std::string & str, int start = 0, int end = MAX_32BIT_INT);
+
+ ///
+ /// @ }
+ ///
+
+
+namespace os
+{
+namespace path
+{
+ // All of the function below have three versions.
+ // Example:
+ // join(...)
+ // join_nt(...)
+ // join_posix(...)
+ //
+ // The regular function dispatches to the other versions - based on the OS
+ // at compile time - to match the result you'd get from the python
+ // interepreter on the same operating system
+ //
+ // Should you want to 'lock off' to a particular version of the string
+ // manipulation across *all* operating systems, use the version with the
+ // _OS you are interested in. I.e., you can use posix style path joining,
+ // even on Windows, with join_posix.
+ //
+ // The naming, (nt, posix) matches the cpython source implementation.
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @defgroup functions pystring::os::path
+ /// @{
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return the base name of pathname path. This is the second half of the pair returned
+ /// by split(path). Note that the result of this function is different from the Unix basename
+ /// program; where basename for '/foo/bar/' returns 'bar', the basename() function returns an
+ /// empty string ('').
+
+ std::string basename(const std::string & path);
+ std::string basename_nt(const std::string & path);
+ std::string basename_posix(const std::string & path);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return the directory name of pathname path. This is the first half of the pair
+ /// returned by split(path).
+
+ std::string dirname(const std::string & path);
+ std::string dirname_nt(const std::string & path);
+ std::string dirname_posix(const std::string & path);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return True if path is an absolute pathname. On Unix, that means it begins with a
+ /// slash, on Windows that it begins with a (back)slash after chopping off a potential drive
+ /// letter.
+
+ bool isabs(const std::string & path);
+ bool isabs_nt(const std::string & path);
+ bool isabs_posix(const std::string & s);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a normalized absolutized version of the pathname path.
+ ///
+ /// NOTE: This differs from the interface of the python equivalent in that it requires you
+ /// to pass in the current working directory as an argument.
+
+ std::string abspath(const std::string & path, const std::string & cwd);
+ std::string abspath_nt(const std::string & path, const std::string & cwd);
+ std::string abspath_posix(const std::string & path, const std::string & cwd);
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Join one or more path components intelligently. If any component is an absolute
+ /// path, all previous components (on Windows, including the previous drive letter, if there
+ /// was one) are thrown away, and joining continues. The return value is the concatenation of
+ /// path1, and optionally path2, etc., with exactly one directory separator (os.sep) inserted
+ /// between components, unless path2 is empty. Note that on Windows, since there is a current
+ /// directory for each drive, os.path.join("c:", "foo") represents a path relative to the
+ /// current directory on drive C: (c:foo), not c:\foo.
+
+ /// This dispatches based on the compilation OS
+ std::string join(const std::string & path1, const std::string & path2);
+ std::string join_nt(const std::string & path1, const std::string & path2);
+ std::string join_posix(const std::string & path1, const std::string & path2);
+
+ std::string join(const std::vector< std::string > & paths);
+ std::string join_nt(const std::vector< std::string > & paths);
+ std::string join_posix(const std::vector< std::string > & paths);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Normalize a pathname. This collapses redundant separators and up-level references
+ /// so that A//B, A/B/, A/./B and A/foo/../B all become A/B. It does not normalize the case
+ /// (use normcase() for that). On Windows, it converts forward slashes to backward slashes.
+ /// It should be understood that this may change the meaning of the path if it contains
+ /// symbolic links!
+
+ std::string normpath(const std::string & path);
+ std::string normpath_nt(const std::string & path);
+ std::string normpath_posix(const std::string & path);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Split the pathname path into a pair, (head, tail) where tail is the last pathname
+ /// component and head is everything leading up to that. The tail part will never contain a
+ /// slash; if path ends in a slash, tail will be empty. If there is no slash in path, head
+ /// will be empty. If path is empty, both head and tail are empty. Trailing slashes are
+ /// stripped from head unless it is the root (one or more slashes only). In all cases,
+ /// join(head, tail) returns a path to the same location as path (but the strings may
+ /// differ).
+
+ void split(std::string & head, std::string & tail, const std::string & path);
+ void split_nt(std::string & head, std::string & tail, const std::string & path);
+ void split_posix(std::string & head, std::string & tail, const std::string & path);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Split the pathname path into a pair (drive, tail) where drive is either a drive
+ /// specification or the empty string. On systems which do not use drive specifications,
+ /// drive will always be the empty string. In all cases, drive + tail will be the same as
+ /// path.
+
+ void splitdrive(std::string & drivespec, std::string & pathspec, const std::string & path);
+ void splitdrive_nt(std::string & drivespec, std::string & pathspec, const std::string & p);
+ void splitdrive_posix(std::string & drivespec, std::string & pathspec, const std::string & path);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Split the pathname path into a pair (root, ext) such that root + ext == path, and
+ /// ext is empty or begins with a period and contains at most one period. Leading periods on
+ /// the basename are ignored; splitext('.cshrc') returns ('.cshrc', '').
+
+ void splitext(std::string & root, std::string & ext, const std::string & path);
+ void splitext_nt(std::string & root, std::string & ext, const std::string & path);
+ void splitext_posix(std::string & root, std::string & ext, const std::string & path);
+
+ ///
+ /// @ }
+ ///
+} // namespace path
+} // namespace os
+
+} // namespace pystring
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/apps/share/strutil.cpp b/src/apps/share/strutil.cpp
new file mode 100644
index 0000000..58938bb
--- /dev/null
+++ b/src/apps/share/strutil.cpp
@@ -0,0 +1,86 @@
+/*
+ Copyright 2008 Larry Gritz and the other authors and contributors.
+ 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 the software's owners 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.
+
+ (This is the Modified BSD License)
+*/
+
+
+#include <string>
+#include <cstdarg>
+#include <cstdio>
+#include <vector>
+#include <iostream>
+#include <cmath>
+
+#include "strutil.h"
+
+
+
+std::string
+Strutil::vformat (const char *fmt, va_list ap)
+{
+ // Allocate a buffer on the stack that's big enough for us almost
+ // all the time. Be prepared to allocate dynamically if it doesn't fit.
+ size_t size = 1024;
+ char stackbuf[1024];
+ std::vector<char> dynamicbuf;
+ char *buf = &stackbuf[0];
+
+ while (1) {
+ // Try to vsnprintf into our buffer.
+ va_list apsave;
+#ifdef va_copy
+ va_copy (apsave, ap);
+#else
+ apsave = ap;
+#endif
+ int needed = vsnprintf (buf, size, fmt, ap);
+ va_end (ap);
+
+ // NB. C99 (which modern Linux and OS X follow) says vsnprintf
+ // failure returns the length it would have needed. But older
+ // glibc and current Windows return -1 for failure, i.e., not
+ // telling us how much was needed.
+
+ if (needed < (int)size && needed >= 0) {
+ // It fit fine so we're done.
+ return std::string (buf, (size_t) needed);
+ }
+
+ // vsnprintf reported that it wanted to write more characters
+ // than we allotted. So try again using a dynamic buffer. This
+ // doesn't happen very often if we chose our initial size well.
+ size = (needed > 0) ? (needed+1) : (size*2);
+ dynamicbuf.resize (size);
+ buf = &dynamicbuf[0];
+#ifdef va_copy
+ va_copy (ap, apsave);
+#else
+ ap = apsave;
+#endif
+ }
+}
diff --git a/src/apps/share/strutil.h b/src/apps/share/strutil.h
new file mode 100644
index 0000000..44b50da
--- /dev/null
+++ b/src/apps/share/strutil.h
@@ -0,0 +1,83 @@
+/*
+ Copyright 2008 Larry Gritz and the other authors and contributors.
+ 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 the software's owners 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.
+
+ (This is the Modified BSD License)
+*/
+
+
+/////////////////////////////////////////////////////////////////////////
+/// @file strutil.h
+///
+/// @brief String-related utilities, all in namespace Strutil.
+/////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef OPENCOLORIO_STRUTIL_H
+#define OPENCOLORIO_STRUTIL_H
+
+#include <cstdarg>
+#include <string>
+#include <cstring>
+#include <map>
+
+
+#ifndef OPENCOLORIO_PRINTF_ARGS
+# ifndef __GNUC__
+# define __attribute__(x)
+# endif
+ // Enable printf-like warnings with gcc by attaching
+ // OPENIMAGEIO_PRINTF_ARGS to printf-like functions. Eg:
+ //
+ // void foo (const char* fmt, ...) OPENCOLORIO_PRINTF_ARGS(1,2);
+ //
+ // The arguments specify the positions of the format string and the the
+ // beginning of the varargs parameter list respectively.
+ //
+ // For member functions with arguments like the example above, you need
+ // OPENCOLORIO_PRINTF_ARGS(2,3) instead. (gcc includes the implicit this
+ // pointer when it counts member function arguments.)
+# define OPENCOLORIO_PRINTF_ARGS(fmtarg_pos, vararg_pos) \
+ __attribute__ ((format (printf, fmtarg_pos, vararg_pos) ))
+#endif
+
+
+
+/// @namespace Strutil
+///
+/// @brief String-related utilities.
+namespace Strutil {
+
+/// Return a std::string formatted from printf-like arguments -- passed
+/// already as a va_list.
+std::string vformat (const char *fmt, va_list ap)
+ OPENCOLORIO_PRINTF_ARGS(1,0);
+
+}; // namespace Strutil
+
+
+#endif // OPENCOLORIO_STRUTIL_H
diff --git a/src/core/AllocationOp.cpp b/src/core/AllocationOp.cpp
new file mode 100644
index 0000000..ed4c9db
--- /dev/null
+++ b/src/core/AllocationOp.cpp
@@ -0,0 +1,128 @@
+/*
+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 "AllocationOp.h"
+#include "LogOps.h"
+#include "MatrixOps.h"
+#include "Op.h"
+
+#include <OpenColorIO/OpenColorIO.h>
+
+OCIO_NAMESPACE_ENTER
+{
+
+ void CreateAllocationOps(OpRcPtrVec & ops,
+ const AllocationData & data,
+ TransformDirection dir)
+ {
+ if(data.allocation == ALLOCATION_UNIFORM)
+ {
+ float oldmin[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ float oldmax[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
+ float newmin[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ float newmax[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
+
+ if(data.vars.size() >= 2)
+ {
+ for(int i=0; i<3; ++i)
+ {
+ oldmin[i] = data.vars[0];
+ oldmax[i] = data.vars[1];
+ }
+ }
+
+ CreateFitOp(ops,
+ oldmin, oldmax,
+ newmin, newmax,
+ dir);
+ }
+ else if(data.allocation == ALLOCATION_LG2)
+ {
+ float oldmin[4] = { -10.0f, -10.0f, -10.0f, 0.0f };
+ float oldmax[4] = { 6.0f, 6.0f, 6.0f, 1.0f };
+ float newmin[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ float newmax[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
+
+ if(data.vars.size() >= 2)
+ {
+ for(int i=0; i<3; ++i)
+ {
+ oldmin[i] = data.vars[0];
+ oldmax[i] = data.vars[1];
+ }
+ }
+
+
+ // Log Settings
+ // output = k * log(mx+b, base) + kb
+
+ float k[3] = { 1.0f, 1.0f, 1.0f };
+ float m[3] = { 1.0f, 1.0f, 1.0f };
+ float b[3] = { 0.0f, 0.0f, 0.0f };
+ float base[3] = { 2.0f, 2.0f, 2.0f };
+ float kb[3] = { 0.0f, 0.0f, 0.0f };
+
+ if(data.vars.size() >= 3)
+ {
+ for(int i=0; i<3; ++i)
+ {
+ b[i] = data.vars[2];
+ }
+ }
+
+ if(dir == TRANSFORM_DIR_FORWARD)
+ {
+ CreateLogOp(ops, k, m, b, base, kb, dir);
+
+ CreateFitOp(ops,
+ oldmin, oldmax,
+ newmin, newmax,
+ dir);
+ }
+ else if(dir == TRANSFORM_DIR_INVERSE)
+ {
+ CreateFitOp(ops,
+ oldmin, oldmax,
+ newmin, newmax,
+ dir);
+
+ CreateLogOp(ops, k, m, b, base, kb, dir);
+ }
+ else
+ {
+ throw Exception("Cannot BuildAllocationOps, unspecified transform direction.");
+ }
+ }
+ else
+ {
+ throw Exception("Unsupported Allocation Type.");
+ }
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/AllocationOp.h b/src/core/AllocationOp.h
new file mode 100644
index 0000000..8fd491f
--- /dev/null
+++ b/src/core/AllocationOp.h
@@ -0,0 +1,45 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_ALLOCATIONOP_H
+#define INCLUDED_OCIO_ALLOCATIONOP_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "Op.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ void CreateAllocationOps(OpRcPtrVec & ops,
+ const AllocationData & data,
+ TransformDirection dir);
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/AllocationTransform.cpp b/src/core/AllocationTransform.cpp
new file mode 100644
index 0000000..592b36e
--- /dev/null
+++ b/src/core/AllocationTransform.cpp
@@ -0,0 +1,182 @@
+/*
+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 <cstring>
+#include <sstream>
+#include <vector>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "AllocationOp.h"
+#include "OpBuilders.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ AllocationTransformRcPtr AllocationTransform::Create()
+ {
+ return AllocationTransformRcPtr(new AllocationTransform(), &deleter);
+ }
+
+ void AllocationTransform::deleter(AllocationTransform* t)
+ {
+ delete t;
+ }
+
+
+ class AllocationTransform::Impl
+ {
+ public:
+ TransformDirection dir_;
+ Allocation allocation_;
+ std::vector<float> vars_;
+
+ Impl() :
+ dir_(TRANSFORM_DIR_FORWARD),
+ allocation_(ALLOCATION_UNIFORM)
+ { }
+
+ ~Impl()
+ { }
+
+ Impl& operator= (const Impl & rhs)
+ {
+ dir_ = rhs.dir_;
+ allocation_ = rhs.allocation_;
+ vars_ = rhs.vars_;
+ return *this;
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ AllocationTransform::AllocationTransform()
+ : m_impl(new AllocationTransform::Impl)
+ {
+ }
+
+ TransformRcPtr AllocationTransform::createEditableCopy() const
+ {
+ AllocationTransformRcPtr transform = AllocationTransform::Create();
+ *(transform->m_impl) = *m_impl;
+ return transform;
+ }
+
+ AllocationTransform::~AllocationTransform()
+ {
+ delete m_impl;
+ m_impl = NULL;
+ }
+
+ AllocationTransform& AllocationTransform::operator= (const AllocationTransform & rhs)
+ {
+ *m_impl = *rhs.m_impl;
+ return *this;
+ }
+
+ TransformDirection AllocationTransform::getDirection() const
+ {
+ return getImpl()->dir_;
+ }
+
+ void AllocationTransform::setDirection(TransformDirection dir)
+ {
+ getImpl()->dir_ = dir;
+ }
+
+
+ Allocation AllocationTransform::getAllocation() const
+ {
+ return getImpl()->allocation_;
+ }
+
+ void AllocationTransform::setAllocation(Allocation allocation)
+ {
+ getImpl()->allocation_ = allocation;
+ }
+
+ int AllocationTransform::getNumVars() const
+ {
+ return static_cast<int>(getImpl()->vars_.size());
+ }
+
+ void AllocationTransform::getVars(float * vars) const
+ {
+ if(!getImpl()->vars_.empty())
+ {
+ memcpy(vars,
+ &getImpl()->vars_[0],
+ getImpl()->vars_.size()*sizeof(float));
+ }
+ }
+
+ void AllocationTransform::setVars(int numvars, const float * vars)
+ {
+ getImpl()->vars_.resize(numvars);
+
+ if(!getImpl()->vars_.empty())
+ {
+ memcpy(&getImpl()->vars_[0],
+ vars,
+ numvars*sizeof(float));
+ }
+ }
+
+ std::ostream& operator<< (std::ostream& os, const AllocationTransform& t)
+ {
+ os << "<AllocationTransform ";
+ os << "direction=" << TransformDirectionToString(t.getDirection()) << ", ";
+ os << ">\n";
+
+ return os;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ void BuildAllocationOps(OpRcPtrVec & ops,
+ const Config& /*config*/,
+ const AllocationTransform& allocationTransform,
+ TransformDirection dir)
+ {
+ TransformDirection combinedDir = CombineTransformDirections(dir,
+ allocationTransform.getDirection());
+
+ AllocationData data;
+ data.allocation = allocationTransform.getAllocation();
+ data.vars.resize(allocationTransform.getNumVars());
+ if(!data.vars.empty())
+ {
+ allocationTransform.getVars(&data.vars[0]);
+ }
+
+ CreateAllocationOps(ops, data, combinedDir);
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/Baker.cpp b/src/core/Baker.cpp
new file mode 100644
index 0000000..581df5f
--- /dev/null
+++ b/src/core/Baker.cpp
@@ -0,0 +1,297 @@
+/*
+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 <vector>
+#include <iostream>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "FileTransform.h"
+#include "MathUtils.h"
+#include "pystring/pystring.h"
+
+OCIO_NAMESPACE_ENTER
+{
+
+ BakerRcPtr Baker::Create()
+ {
+ return BakerRcPtr(new Baker(), &deleter);
+ }
+
+ void Baker::deleter(Baker* c)
+ {
+ delete c;
+ }
+
+ class Baker::Impl
+ {
+ public:
+
+ ConfigRcPtr config_;
+ std::string formatName_;
+ std::string type_;
+ std::string metadata_;
+ std::string inputSpace_;
+ std::string shaperSpace_;
+ std::string looks_;
+ std::string targetSpace_;
+ int shapersize_;
+ int cubesize_;
+
+ Impl() :
+ shapersize_(-1),
+ cubesize_(-1)
+ {
+ }
+
+ ~Impl()
+ {
+ }
+
+ Impl& operator= (const Impl & rhs)
+ {
+ config_ = rhs.config_;
+ formatName_ = rhs.formatName_;
+ inputSpace_ = rhs.inputSpace_;
+ shaperSpace_ = rhs.shaperSpace_;
+ looks_ = rhs.looks_;
+ targetSpace_ = rhs.targetSpace_;
+ shapersize_ = rhs.shapersize_;
+ cubesize_ = rhs.cubesize_;
+ return *this;
+ }
+ };
+
+ Baker::Baker()
+ : m_impl(new Baker::Impl)
+ {
+ }
+
+ Baker::~Baker()
+ {
+ delete m_impl;
+ m_impl = NULL;
+ }
+
+ BakerRcPtr Baker::createEditableCopy() const
+ {
+ BakerRcPtr oven = Baker::Create();
+ *oven->m_impl = *m_impl;
+ return oven;
+ }
+
+ void Baker::setConfig(const ConstConfigRcPtr & config)
+ {
+ getImpl()->config_ = config->createEditableCopy();
+ }
+
+ ConstConfigRcPtr Baker::getConfig() const
+ {
+ return getImpl()->config_;
+ }
+
+ int Baker::getNumFormats()
+ {
+ return FormatRegistry::GetInstance().getNumFormats(FORMAT_CAPABILITY_WRITE);
+ }
+
+ const char * Baker::getFormatNameByIndex(int index)
+ {
+ return FormatRegistry::GetInstance().getFormatNameByIndex(FORMAT_CAPABILITY_WRITE, index);
+ }
+
+ const char * Baker::getFormatExtensionByIndex(int index)
+ {
+ return FormatRegistry::GetInstance().getFormatExtensionByIndex(FORMAT_CAPABILITY_WRITE, index);
+ }
+
+ void Baker::setFormat(const char * formatName)
+ {
+ getImpl()->formatName_ = formatName;
+ }
+
+ const char * Baker::getFormat() const
+ {
+ return getImpl()->formatName_.c_str();
+ }
+
+ void Baker::setType(const char * type)
+ {
+ getImpl()->type_ = type;
+ }
+
+ const char * Baker::getType() const
+ {
+ return getImpl()->type_.c_str();
+ }
+
+ void Baker::setMetadata(const char * metadata)
+ {
+ getImpl()->metadata_ = metadata;
+ }
+
+ const char * Baker::getMetadata() const
+ {
+ return getImpl()->metadata_.c_str();
+ }
+
+ void Baker::setInputSpace(const char * inputSpace)
+ {
+ getImpl()->inputSpace_ = inputSpace;
+ }
+
+ const char * Baker::getInputSpace() const
+ {
+ return getImpl()->inputSpace_.c_str();
+ }
+
+ void Baker::setShaperSpace(const char * shaperSpace)
+ {
+ getImpl()->shaperSpace_ = shaperSpace;
+ }
+
+ const char * Baker::getShaperSpace() const
+ {
+ return getImpl()->shaperSpace_.c_str();
+ }
+
+ void Baker::setLooks(const char * looks)
+ {
+ getImpl()->looks_ = looks;
+ }
+
+ const char * Baker::getLooks() const
+ {
+ return getImpl()->looks_.c_str();
+ }
+
+ void Baker::setTargetSpace(const char * targetSpace)
+ {
+ getImpl()->targetSpace_ = targetSpace;
+ }
+
+ const char * Baker::getTargetSpace() const
+ {
+ return getImpl()->targetSpace_.c_str();
+ }
+
+ void Baker::setShaperSize(int shapersize)
+ {
+ getImpl()->shapersize_ = shapersize;
+ }
+
+ int Baker::getShaperSize() const
+ {
+ return getImpl()->shapersize_;
+ }
+
+ void Baker::setCubeSize(int cubesize)
+ {
+ getImpl()->cubesize_ = cubesize;
+ }
+
+ int Baker::getCubeSize() const
+ {
+ return getImpl()->cubesize_;
+ }
+
+ void Baker::bake(std::ostream & os) const
+ {
+ FileFormat* fmt = FormatRegistry::GetInstance().getFileFormatByName(getImpl()->formatName_);
+
+ if(!fmt)
+ {
+ std::ostringstream err;
+ err << "The format named '" << getImpl()->formatName_;
+ err << "' could not be found. ";
+ throw Exception(err.str().c_str());
+ }
+
+ try
+ {
+ fmt->Write(*this, getImpl()->formatName_, os);
+ }
+ catch(std::exception & e)
+ {
+ std::ostringstream err;
+ err << "Error baking " << getImpl()->formatName_ << ":";
+ err << e.what();
+ throw Exception(err.str().c_str());
+ }
+
+ //
+ // TODO:
+ //
+ // - throw exception when we don't have inputSpace and targetSpace
+ // at least set
+ // - check limits of shaper and target, throw exception if we can't
+ // write that much data in x format
+ // - check that the shaper is 1D transform only, throw excpetion
+ // - check the file format supports shapers, 1D and 3D
+ // - add some checks to make sure we are monotonic
+ // - deal with the case of writing out non cube formats (1D only)
+ // - do a compare between ocio transform and output lut transform
+ // throw error if we going beyond tolerance
+ //
+ }
+
+}
+OCIO_NAMESPACE_EXIT
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef OCIO_UNIT_TEST
+
+namespace OCIO = OCIO_NAMESPACE;
+#include "UnitTest.h"
+
+/*
+OIIO_ADD_TEST(Baker_Unit_Tests, test_listlutwriters)
+{
+
+ std::vector<std::string> current_writers;
+ current_writers.push_back("cinespace");
+ current_writers.push_back("houdini");
+
+ OCIO::BakerRcPtr baker = OCIO::Baker::Create();
+
+ OIIO_CHECK_EQUAL(baker->getNumFormats(), (int)current_writers.size());
+
+ std::vector<std::string> test;
+ for(int i = 0; i < baker->getNumFormats(); ++i)
+ test.push_back(baker->getFormatNameByIndex(i));
+
+ for(unsigned int i = 0; i < current_writers.size(); ++i)
+ OIIO_CHECK_EQUAL(current_writers[i], test[i]);
+
+}
+*/
+
+#endif // OCIO_BUILD_TESTS
+
+
diff --git a/src/core/CDLTransform.cpp b/src/core/CDLTransform.cpp
new file mode 100644
index 0000000..0e321ff
--- /dev/null
+++ b/src/core/CDLTransform.cpp
@@ -0,0 +1,776 @@
+/*
+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 <fstream>
+#include <tinyxml.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "CDLTransform.h"
+#include "ExponentOps.h"
+#include "MatrixOps.h"
+#include "MathUtils.h"
+#include "Mutex.h"
+#include "OpBuilders.h"
+#include "ParseUtils.h"
+#include "pystring/pystring.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ /*
+ "<ColorCorrection id=''>"
+ " <SOPNode>"
+ " <Description/> "
+ " <Slope>1 1 1</Slope> "
+ " <Offset>0 0 0</Offset> "
+ " <Power>1 1 1</Power> "
+ " </SOPNode> "
+ " <SatNode>"
+ " <Saturation> 1 </Saturation> "
+ " </SatNode> "
+ " </ColorCorrection>";
+
+ */
+
+ // http://ticpp.googlecode.com/svn/docs/ticpp_8h-source.html#l01670
+
+ void SetTiXmlText( TiXmlElement* element, const char * value)
+ {
+ if ( element->NoChildren() )
+ {
+ element->LinkEndChild( new TiXmlText( value ) );
+ }
+ else
+ {
+ if ( 0 == element->GetText() )
+ {
+ element->InsertBeforeChild( element->FirstChild(), TiXmlText( value ) );
+ }
+ else
+ {
+ // There already is text, so change it
+ element->FirstChild()->SetValue( value );
+ }
+ }
+ }
+
+ std::string BuildXML(const CDLTransform & cdl)
+ {
+ TiXmlDocument doc;
+
+ // TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "" );
+ TiXmlElement * root = new TiXmlElement( "ColorCorrection" );
+ doc.LinkEndChild( root );
+ root->SetAttribute("id", cdl.getID());
+
+ TiXmlElement * sop = new TiXmlElement( "SOPNode" );
+ root->LinkEndChild( sop );
+
+ TiXmlElement * desc = new TiXmlElement( "Description" );
+ sop->LinkEndChild( desc );
+ SetTiXmlText(desc, cdl.getDescription());
+
+ TiXmlElement * slope = new TiXmlElement( "Slope" );
+ sop->LinkEndChild( slope );
+ float slopeval[3];
+ cdl.getSlope(slopeval);
+ SetTiXmlText(slope, FloatVecToString(slopeval, 3).c_str());
+
+ TiXmlElement * offset = new TiXmlElement( "Offset" );
+ sop->LinkEndChild( offset );
+ float offsetval[3];
+ cdl.getOffset(offsetval);
+ SetTiXmlText(offset, FloatVecToString(offsetval, 3).c_str());
+
+ TiXmlElement * power = new TiXmlElement( "Power" );
+ sop->LinkEndChild( power );
+ float powerval[3];
+ cdl.getPower(powerval);
+ SetTiXmlText(power, FloatVecToString(powerval, 3).c_str());
+
+ TiXmlElement * sat = new TiXmlElement( "SatNode" );
+ root->LinkEndChild( sat );
+
+ TiXmlElement * saturation = new TiXmlElement( "Saturation" );
+ sat->LinkEndChild( saturation );
+ SetTiXmlText(saturation, FloatToString(cdl.getSat()).c_str());
+
+ TiXmlPrinter printer;
+ printer.SetStreamPrinting();
+ doc.Accept( &printer );
+ return printer.Str();
+ }
+ }
+
+ void LoadCDL(CDLTransform * cdl, TiXmlElement * root)
+ {
+ if(!cdl) return;
+
+ if(!root)
+ {
+ std::ostringstream os;
+ os << "Error loading CDL xml. ";
+ os << "Null root element.";
+ throw Exception(os.str().c_str());
+ }
+
+ if(std::string(root->Value()) != "ColorCorrection")
+ {
+ std::ostringstream os;
+ os << "Error loading CDL xml. ";
+ os << "Root element is type '" << root->Value() << "', ";
+ os << "ColorCorrection expected.";
+ throw Exception(os.str().c_str());
+ }
+
+ TiXmlHandle handle( root );
+
+ const char * id = root->Attribute("id");
+ if(!id) id = "";
+
+ cdl->setID(id);
+
+ TiXmlElement* desc = handle.FirstChild( "SOPNode" ).FirstChild("Description").ToElement();
+ if(desc)
+ {
+ const char * text = desc->GetText();
+ if(text) cdl->setDescription(text);
+ }
+
+ std::vector<std::string> lineParts;
+ std::vector<float> floatArray;
+
+ TiXmlElement* slope = handle.FirstChild( "SOPNode" ).FirstChild("Slope").ToElement();
+ if(slope)
+ {
+ const char * text = slope->GetText();
+ if(text)
+ {
+ pystring::split(pystring::strip(text), lineParts);
+ if((lineParts.size() != 3) || (!StringVecToFloatVec(floatArray, lineParts)))
+ {
+ std::ostringstream os;
+ os << "Error loading CDL xml. ";
+ os << id << ".SOPNode.Slope text '";
+ os << text << "' is not convertible to 3 floats.";
+ throw Exception(os.str().c_str());
+ }
+ cdl->setSlope(&floatArray[0]);
+ }
+ }
+
+ TiXmlElement* offset = handle.FirstChild( "SOPNode" ).FirstChild("Offset").ToElement();
+ if(offset)
+ {
+ const char * text = offset->GetText();
+ if(text)
+ {
+ pystring::split(pystring::strip(text), lineParts);
+ if((lineParts.size() != 3) || (!StringVecToFloatVec(floatArray, lineParts)))
+ {
+ std::ostringstream os;
+ os << "Error loading CDL xml. ";
+ os << id << ".SOPNode.Offset text '";
+ os << text << "' is not convertible to 3 floats.";
+ throw Exception(os.str().c_str());
+ }
+ cdl->setOffset(&floatArray[0]);
+ }
+ }
+
+ TiXmlElement* power = handle.FirstChild( "SOPNode" ).FirstChild("Power").ToElement();
+ if(power)
+ {
+ const char * text = power->GetText();
+ if(text)
+ {
+ pystring::split(pystring::strip(text), lineParts);
+ if((lineParts.size() != 3) || (!StringVecToFloatVec(floatArray, lineParts)))
+ {
+ std::ostringstream os;
+ os << "Error loading CDL xml. ";
+ os << id << ".SOPNode.Power text '";
+ os << text << "' is not convertible to 3 floats.";
+ throw Exception(os.str().c_str());
+ }
+ cdl->setPower(&floatArray[0]);
+ }
+ }
+
+ TiXmlElement* sat = handle.FirstChild( "SatNode" ).FirstChild("Saturation").ToElement();
+ if(sat)
+ {
+ const char * text = sat->GetText();
+ if(text)
+ {
+ float satval = 1.0f;
+ if(!StringToFloat(&satval, text))
+ {
+ std::ostringstream os;
+ os << "Error loading CDL xml. ";
+ os << id << ".SatNode.Saturation text '";
+ os << text << "' is not convertible to float.";
+ throw Exception(os.str().c_str());
+ }
+ cdl->setSat(satval);
+ }
+ }
+ }
+
+
+
+ void GetCDLTransforms(CDLTransformMap & transforms,
+ TiXmlElement * cccRootElement)
+ {
+ if(std::string(cccRootElement->Value()) != "ColorCorrectionCollection")
+ {
+ std::ostringstream os;
+ os << "GetCDLTransforms Error. ";
+ os << "Root element is type '" << cccRootElement->Value() << "', ";
+ os << "ColorCorrectionCollection expected.";
+ throw Exception(os.str().c_str());
+ }
+
+ TiXmlNode * child = cccRootElement->FirstChild("ColorCorrection");
+ while(child)
+ {
+ CDLTransformRcPtr transform = CDLTransform::Create();
+ LoadCDL(transform.get(), child->ToElement());
+
+ std::string id = transform->getID();
+ if(id.empty())
+ {
+ std::ostringstream os;
+ os << "Error loading ccc xml, ";
+ os << "All ASC ColorCorrections must specify an 'id' value.";
+ throw Exception(os.str().c_str());
+ }
+
+ CDLTransformMap::iterator iter = transforms.find(id);
+ if(iter != transforms.end())
+ {
+ std::ostringstream os;
+ os << "Error loading ccc xml. ";
+ os << "All ASC ColorCorrections must specify a unique 'id' value. ";
+ os << "Duplicate elements with '" << id << "' found.";
+ throw Exception(os.str().c_str());
+ }
+
+ transforms[id] = transform;
+
+ child = child->NextSibling("ColorCorrection");
+ }
+ }
+
+ void LoadCDL(CDLTransform * cdl, const char * xml)
+ {
+ if(!xml || (strlen(xml) == 0))
+ {
+ std::ostringstream os;
+ os << "Error loading CDL xml. ";
+ os << "Null string provided.";
+ throw Exception(os.str().c_str());
+ }
+
+ TiXmlDocument doc;
+ doc.Parse(xml);
+
+ if(doc.Error())
+ {
+ std::ostringstream os;
+ os << "Error loading CDL xml. ";
+ os << doc.ErrorDesc() << " (line ";
+ os << doc.ErrorRow() << ", character ";
+ os << doc.ErrorCol() << ")";
+ throw Exception(os.str().c_str());
+ }
+
+ if(!doc.RootElement())
+ {
+ std::ostringstream os;
+ os << "Error loading CDL xml, ";
+ os << "please confirm the xml is valid.";
+ throw Exception(os.str().c_str());
+ }
+
+ LoadCDL(cdl, doc.RootElement()->ToElement());
+ }
+
+ CDLTransformRcPtr CDLTransform::Create()
+ {
+ return CDLTransformRcPtr(new CDLTransform(), &deleter);
+ }
+
+ namespace
+ {
+ std::string GetCDLLocalCacheKey(const std::string & src,
+ const std::string & cccid)
+ {
+ return src + " : " + cccid;
+ }
+
+ CDLTransformMap g_cache;
+ Mutex g_cacheMutex;
+ }
+
+ void ClearCDLTransformFileCache()
+ {
+ AutoMutex lock(g_cacheMutex);
+ g_cache.clear();
+ }
+
+ // TODO: Expose functions for introspecting in ccc file
+ // TODO: Share caching with normal cdl pathway
+
+ CDLTransformRcPtr CDLTransform::CreateFromFile(const char * src, const char * cccid)
+ {
+ if(!src || (strlen(src) == 0) || !cccid)
+ {
+ std::ostringstream os;
+ os << "Error loading CDL xml. ";
+ os << "Source file not specified.";
+ throw Exception(os.str().c_str());
+ }
+
+ // Check cache
+ AutoMutex lock(g_cacheMutex);
+ {
+ CDLTransformMap::iterator iter =
+ g_cache.find(GetCDLLocalCacheKey(src,cccid));
+ if(iter != g_cache.end())
+ {
+ return iter->second;
+ }
+ }
+
+ std::ifstream istream(src);
+ if(istream.fail()) {
+ std::ostringstream os;
+ os << "Error could not read CDL source file '" << src;
+ os << "'. Please verify the file exists and appropriate ";
+ os << "permissions are set.";
+ throw Exception (os.str().c_str());
+ }
+
+ // Read the file into a string.
+ std::ostringstream rawdata;
+ rawdata << istream.rdbuf();
+ std::string xml = rawdata.str();
+
+ if(xml.empty())
+ {
+ std::ostringstream os;
+ os << "Error loading CDL xml. ";
+ os << "The specified source file, '";
+ os << src << "' appears to be empty.";
+ throw Exception(os.str().c_str());
+ }
+
+ TiXmlDocument doc;
+ doc.Parse(xml.c_str());
+
+ if(doc.Error())
+ {
+ std::ostringstream os;
+ os << "Error loading CDL xml from file '";
+ os << src << "'. ";
+ os << doc.ErrorDesc() << " (line ";
+ os << doc.ErrorRow() << ", character ";
+ os << doc.ErrorCol() << ")";
+ throw Exception(os.str().c_str());
+ }
+
+ if(!doc.RootElement())
+ {
+ std::ostringstream os;
+ os << "Error loading CDL xml from file '";
+ os << src << "'. ";
+ os << "Please confirm the xml is valid.";
+ throw Exception(os.str().c_str());
+ }
+
+ std::string rootValue = doc.RootElement()->Value();
+ if(rootValue == "ColorCorrection")
+ {
+ // Load a single ColorCorrection into the cache
+ CDLTransformRcPtr cdl = CDLTransform::Create();
+ LoadCDL(cdl.get(), doc.RootElement()->ToElement());
+ g_cache[GetCDLLocalCacheKey(src,cccid)] = cdl;
+ return cdl;
+ }
+ else if(rootValue == "ColorCorrectionCollection")
+ {
+ // Load all CCs from the ColorCorrectionCollection
+ // into the cache
+
+ CDLTransformMap transforms;
+ GetCDLTransforms(transforms, doc.RootElement());
+
+ if(transforms.empty())
+ {
+ std::ostringstream os;
+ os << "Error loading ccc xml. ";
+ os << "No ColorCorrection elements found in file '";
+ os << src << "'.";
+ throw Exception(os.str().c_str());
+ }
+
+ for(CDLTransformMap::iterator iter = transforms.begin();
+ iter != transforms.end();
+ ++iter)
+ {
+ g_cache[GetCDLLocalCacheKey(src,iter->first)] = iter->second;
+ }
+
+ CDLTransformMap::iterator cciter = g_cache.find(GetCDLLocalCacheKey(src,cccid));
+ if(cciter == g_cache.end())
+ {
+ std::ostringstream os;
+ os << "Error loading ccc xml. ";
+ os << "The specified cccid " << cccid << " ";
+ os << "could not be found in file '";
+ os << src << "'.";
+ throw Exception(os.str().c_str());
+ }
+
+ return cciter->second;
+ }
+
+ std::ostringstream os;
+ os << "Error loading CDL xml from file '";
+ os << src << "'. ";
+ os << "Root xml element is type '" << rootValue << "', ";
+ os << "ColorCorrection or ColorCorrectionCollection expected.";
+ throw Exception(os.str().c_str());
+ }
+
+ void CDLTransform::deleter(CDLTransform* t)
+ {
+ delete t;
+ }
+
+ class CDLTransform::Impl
+ {
+ public:
+ TransformDirection dir_;
+
+ float sop_[9];
+ float sat_;
+ std::string id_;
+ std::string description_;
+
+ mutable std::string xml_;
+
+ Impl() :
+ dir_(TRANSFORM_DIR_FORWARD),
+ sat_(1.0f)
+ {
+ sop_[0] = 1.0f;
+ sop_[1] = 1.0f;
+ sop_[2] = 1.0f;
+ sop_[3] = 0.0f;
+ sop_[4] = 0.0f;
+ sop_[5] = 0.0f;
+ sop_[6] = 1.0f;
+ sop_[7] = 1.0f;
+ sop_[8] = 1.0f;
+ }
+
+ ~Impl()
+ {
+
+ }
+
+ Impl& operator= (const Impl & rhs)
+ {
+ dir_ = rhs.dir_;
+
+ memcpy(sop_, rhs.sop_, sizeof(float)*9);
+ sat_ = rhs.sat_;
+ id_ = rhs.id_;
+ description_ = rhs.description_;
+
+ return *this;
+ }
+
+ };
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+
+ CDLTransform::CDLTransform()
+ : m_impl(new CDLTransform::Impl)
+ {
+ }
+
+ TransformRcPtr CDLTransform::createEditableCopy() const
+ {
+ CDLTransformRcPtr transform = CDLTransform::Create();
+ *(transform->m_impl) = *m_impl;
+ return transform;
+ }
+
+ CDLTransform::~CDLTransform()
+ {
+ delete m_impl;
+ m_impl = NULL;
+ }
+
+ CDLTransform& CDLTransform::operator= (const CDLTransform & rhs)
+ {
+ *m_impl = *rhs.m_impl;
+ return *this;
+ }
+
+ TransformDirection CDLTransform::getDirection() const
+ {
+ return getImpl()->dir_;
+ }
+
+ void CDLTransform::setDirection(TransformDirection dir)
+ {
+ getImpl()->dir_ = dir;
+ }
+
+ const char * CDLTransform::getXML() const
+ {
+ getImpl()->xml_ = BuildXML(*this);
+ return getImpl()->xml_.c_str();
+ }
+
+ void CDLTransform::setXML(const char * xml)
+ {
+ LoadCDL(this, xml);
+ }
+
+ // We use this approach, rather than comparing XML to get around the
+ // case where setXML with extra data was provided.
+
+ bool CDLTransform::equals(const ConstCDLTransformRcPtr & other) const
+ {
+ if(!other) return false;
+
+ if(getImpl()->dir_ != other->getImpl()->dir_) return false;
+
+ const float abserror = 1e-9f;
+
+ for(int i=0; i<9; ++i)
+ {
+ if(!equalWithAbsError(getImpl()->sop_[i], other->getImpl()->sop_[i], abserror))
+ {
+ return false;
+ }
+ }
+
+ if(!equalWithAbsError(getImpl()->sat_, other->getImpl()->sat_, abserror))
+ {
+ return false;
+ }
+
+ if(getImpl()->id_ != other->getImpl()->id_)
+ {
+ return false;
+ }
+
+ if(getImpl()->description_ != other->getImpl()->description_)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ void CDLTransform::setSlope(const float * rgb)
+ {
+ memcpy(&getImpl()->sop_[0], rgb, sizeof(float)*3);
+ }
+
+ void CDLTransform::getSlope(float * rgb) const
+ {
+ memcpy(rgb, &getImpl()->sop_[0], sizeof(float)*3);
+ }
+
+ void CDLTransform::setOffset(const float * rgb)
+ {
+ memcpy(&getImpl()->sop_[3], rgb, sizeof(float)*3);
+ }
+
+ void CDLTransform::getOffset(float * rgb) const
+ {
+ memcpy(rgb, &getImpl()->sop_[3], sizeof(float)*3);
+ }
+
+ void CDLTransform::setPower(const float * rgb)
+ {
+ memcpy(&getImpl()->sop_[6], rgb, sizeof(float)*3);
+ }
+
+ void CDLTransform::getPower(float * rgb) const
+ {
+ memcpy(rgb, &getImpl()->sop_[6], sizeof(float)*3);
+ }
+
+ void CDLTransform::setSOP(const float * vec9)
+ {
+ memcpy(&getImpl()->sop_, vec9, sizeof(float)*9);
+ }
+
+ void CDLTransform::getSOP(float * vec9) const
+ {
+ memcpy(vec9, &getImpl()->sop_, sizeof(float)*9);
+ }
+
+ void CDLTransform::setSat(float sat)
+ {
+ getImpl()->sat_ = sat;
+ }
+
+ float CDLTransform::getSat() const
+ {
+ return getImpl()->sat_;
+ }
+
+ void CDLTransform::getSatLumaCoefs(float * rgb) const
+ {
+ if(!rgb) return;
+ rgb[0] = 0.2126f;
+ rgb[1] = 0.7152f;
+ rgb[2] = 0.0722f;
+ }
+
+ void CDLTransform::setID(const char * id)
+ {
+ if(id)
+ {
+ getImpl()->id_ = id;
+ }
+ else
+ {
+ getImpl()->id_ = "";
+ }
+ }
+
+ const char * CDLTransform::getID() const
+ {
+ return getImpl()->id_.c_str();
+ }
+
+ void CDLTransform::setDescription(const char * desc)
+ {
+ if(desc)
+ {
+ getImpl()->description_ = desc;
+ }
+ else
+ {
+ getImpl()->description_ = "";
+ }
+ }
+
+ const char * CDLTransform::getDescription() const
+ {
+ return getImpl()->description_.c_str();
+ }
+
+ std::ostream& operator<< (std::ostream& os, const CDLTransform& t)
+ {
+ float sop[9];
+ t.getSOP(sop);
+
+ os << "<CDLTransform ";
+ os << "direction=" << TransformDirectionToString(t.getDirection()) << ", ";
+ os << "sop=";
+ for (unsigned int i=0; i<9; ++i)
+ {
+ if(i!=0) os << " ";
+ os << sop[i];
+ }
+ os << ", ";
+ os << "sat=" << t.getSat() << ",";
+ os << TransformDirectionToString(t.getDirection()) << ", ";
+ os << ">\n";
+ return os;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ void BuildCDLOps(OpRcPtrVec & ops,
+ const Config & /*config*/,
+ const CDLTransform & cdlTransform,
+ TransformDirection dir)
+ {
+ float scale4[] = { 1.0f, 1.0f, 1.0f, 1.0f };
+ cdlTransform.getSlope(scale4);
+
+ float offset4[] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ cdlTransform.getOffset(offset4);
+
+ float power4[] = { 1.0f, 1.0f, 1.0f, 1.0f };
+ cdlTransform.getPower(power4);
+
+ float lumaCoef3[] = { 1.0f, 1.0f, 1.0f };
+ cdlTransform.getSatLumaCoefs(lumaCoef3);
+
+ float sat = cdlTransform.getSat();
+
+ TransformDirection combinedDir = CombineTransformDirections(dir,
+ cdlTransform.getDirection());
+
+ // TODO: Confirm ASC Sat math is correct.
+ // TODO: Handle Clamping conditions more explicitly
+
+ if(combinedDir == TRANSFORM_DIR_FORWARD)
+ {
+ // 1) Scale + Offset
+ CreateScaleOffsetOp(ops, scale4, offset4, TRANSFORM_DIR_FORWARD);
+
+ // 2) Power + Clamp
+ CreateExponentOp(ops, power4, TRANSFORM_DIR_FORWARD);
+
+ // 3) Saturation + Clamp
+ CreateSaturationOp(ops, sat, lumaCoef3, TRANSFORM_DIR_FORWARD);
+ }
+ else if(combinedDir == TRANSFORM_DIR_INVERSE)
+ {
+ // 3) Saturation + Clamp
+ CreateSaturationOp(ops, sat, lumaCoef3, TRANSFORM_DIR_INVERSE);
+
+ // 2) Power + Clamp
+ CreateExponentOp(ops, power4, TRANSFORM_DIR_INVERSE);
+
+ // 1) Scale + Offset
+ CreateScaleOffsetOp(ops, scale4, offset4, TRANSFORM_DIR_INVERSE);
+ }
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/CDLTransform.h b/src/core/CDLTransform.h
new file mode 100644
index 0000000..8b945ad
--- /dev/null
+++ b/src/core/CDLTransform.h
@@ -0,0 +1,53 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_CDLTRANSFORM_H
+#define INCLUDED_OCIO_CDLTRANSFORM_H
+
+#include <map>
+#include <tinyxml.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+OCIO_NAMESPACE_ENTER
+{
+ typedef std::map<std::string,CDLTransformRcPtr> CDLTransformMap;
+
+ void ClearCDLTransformFileCache();
+
+ void LoadCDL(CDLTransform * cdl, const char * xml);
+ void LoadCDL(CDLTransform * cdl, TiXmlElement * root);
+
+ // Get a map of transform cccid : cdl transform
+ void GetCDLTransforms(CDLTransformMap & transforms,
+ TiXmlElement * cccroot);
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
new file mode 100644
index 0000000..50194f3
--- /dev/null
+++ b/src/core/CMakeLists.txt
@@ -0,0 +1,93 @@
+###############################################################################
+### OCIO CORE ###
+
+include_directories(
+ ${CMAKE_SOURCE_DIR}/export/
+ ${CMAKE_BINARY_DIR}/export/
+ ${EXTERNAL_INCLUDE_DIRS}
+ ${CMAKE_SOURCE_DIR}/ext/oiio/src/include
+)
+
+file(GLOB_RECURSE core_src_files "${CMAKE_SOURCE_DIR}/src/core/*.cpp")
+file(GLOB_RECURSE core_export_headers "${CMAKE_SOURCE_DIR}/export/OpenColorIO/*.h")
+
+message(STATUS "Create OpenColorABI.h from OpenColorABI.h.in")
+configure_file(${CMAKE_SOURCE_DIR}/export/OpenColorIO/OpenColorABI.h.in
+ ${CMAKE_BINARY_DIR}/export/OpenColorABI.h @ONLY)
+list(APPEND core_export_headers ${CMAKE_BINARY_DIR}/export/OpenColorABI.h)
+
+# SHARED
+
+if(OCIO_BUILD_SHARED)
+ add_library(OpenColorIO SHARED ${core_src_files})
+
+ if(USE_EXTERNAL_TINYXML)
+ target_link_libraries(OpenColorIO ${TINYXML_LIBRARIES})
+ else(USE_EXTERNAL_TINYXML)
+ add_dependencies(OpenColorIO tinyxml)
+ endif(USE_EXTERNAL_TINYXML)
+
+ if(USE_EXTERNAL_YAML)
+ target_link_libraries(OpenColorIO ${YAML_CPP_LIBRARIES})
+ else(USE_EXTERNAL_YAML)
+ add_dependencies(OpenColorIO YAML_CPP_LOCAL)
+ endif()
+
+ if(WIN32)
+ target_link_libraries(OpenColorIO
+ debug ${EXTERNAL_DEBUG_LIBRARIES}
+ optimized ${EXTERNAL_OPTIMIZED_LIBRARIES}
+ general ${EXTERNAL_GENERAL_LIBRARIES})
+ else()
+ target_link_libraries(OpenColorIO ${EXTERNAL_GENERAL_LIBRARIES})
+ endif()
+ set_target_properties(OpenColorIO PROPERTIES
+ OUTPUT_NAME OpenColorIO
+ COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}"
+ LINK_FLAGS "${EXTERNAL_LINK_FLAGS}")
+
+ message(STATUS "Setting OCIO SOVERSION to: ${SOVERSION}")
+ set_target_properties(OpenColorIO PROPERTIES
+ VERSION ${OCIO_VERSION}
+ SOVERSION ${SOVERSION})
+
+ install(TARGETS OpenColorIO DESTINATION ${CMAKE_INSTALL_EXEC_PREFIX}/lib${LIB_SUFFIX})
+endif()
+
+# STATIC
+
+if(OCIO_BUILD_STATIC)
+ list(REMOVE_ITEM core_src_files ${CMAKE_SOURCE_DIR}/src/core/UnitTest.cpp)
+ add_library(OpenColorIO_STATIC STATIC ${core_src_files})
+ add_dependencies(OpenColorIO_STATIC tinyxml YAML_CPP_LOCAL)
+ if(WIN32)
+ target_link_libraries(OpenColorIO_STATIC
+ debug ${EXTERNAL_DEBUG_LIBRARIES}
+ optimized ${EXTERNAL_OPTIMIZED_LIBRARIES}
+ general ${EXTERNAL_GENERAL_LIBRARIES})
+ else()
+ target_link_libraries(OpenColorIO_STATIC ${EXTERNAL_GENERAL_LIBRARIES})
+ endif()
+ set_target_properties(OpenColorIO_STATIC PROPERTIES
+ OUTPUT_NAME OpenColorIO
+ COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}"
+ LINK_FLAGS "${EXTERNAL_LINK_FLAGS}")
+
+ message(STATUS "Setting OCIO SOVERSION to: ${SOVERSION}")
+ set_target_properties(OpenColorIO_STATIC PROPERTIES
+ VERSION ${OCIO_VERSION}
+ SOVERSION ${SOVERSION})
+
+ install(TARGETS OpenColorIO_STATIC DESTINATION ${CMAKE_INSTALL_EXEC_PREFIX}/lib)
+endif()
+
+# public interface
+install(FILES ${core_export_headers}
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/include/OpenColorIO/)
+
+# pkg-config
+message(STATUS "Create OpenColorIO.pc from OpenColorIO.pc.in")
+configure_file(${CMAKE_SOURCE_DIR}/export/pkgconfig/OpenColorIO.pc.in
+ ${CMAKE_CURRENT_BINARY_DIR}/OpenColorIO.pc @ONLY)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/OpenColorIO.pc
+ DESTINATION ${CMAKE_INSTALL_EXEC_PREFIX}/lib${LIB_SUFFIX}/pkgconfig/)
diff --git a/src/core/Caching.cpp b/src/core/Caching.cpp
new file mode 100644
index 0000000..afb0e7c
--- /dev/null
+++ b/src/core/Caching.cpp
@@ -0,0 +1,47 @@
+/*
+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 "CDLTransform.h"
+#include "PathUtils.h"
+#include "FileTransform.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ // TODO: Processors which the user hangs onto have local caches.
+ // Should these be cleared?
+
+ void ClearAllCaches()
+ {
+ ClearPathCaches();
+ ClearFileTransformCaches();
+ ClearCDLTransformFileCache();
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/ColorSpace.cpp b/src/core/ColorSpace.cpp
new file mode 100644
index 0000000..ed2a473
--- /dev/null
+++ b/src/core/ColorSpace.cpp
@@ -0,0 +1,270 @@
+/*
+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 <cstring>
+#include <sstream>
+#include <vector>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+OCIO_NAMESPACE_ENTER
+{
+ ColorSpaceRcPtr ColorSpace::Create()
+ {
+ return ColorSpaceRcPtr(new ColorSpace(), &deleter);
+ }
+
+ void ColorSpace::deleter(ColorSpace* c)
+ {
+ delete c;
+ }
+
+
+ class ColorSpace::Impl
+ {
+ public:
+ std::string name_;
+ std::string family_;
+ std::string equalityGroup_;
+ std::string description_;
+
+ BitDepth bitDepth_;
+ bool isData_;
+
+ Allocation allocation_;
+ std::vector<float> allocationVars_;
+
+ TransformRcPtr toRefTransform_;
+ TransformRcPtr fromRefTransform_;
+
+ bool toRefSpecified_;
+ bool fromRefSpecified_;
+
+ Impl() :
+ bitDepth_(BIT_DEPTH_UNKNOWN),
+ isData_(false),
+ allocation_(ALLOCATION_UNIFORM),
+ toRefSpecified_(false),
+ fromRefSpecified_(false)
+ { }
+
+ ~Impl()
+ { }
+
+ Impl& operator= (const Impl & rhs)
+ {
+ name_ = rhs.name_;
+ family_ = rhs.family_;
+ equalityGroup_ = rhs.equalityGroup_;
+ description_ = rhs.description_;
+ bitDepth_ = rhs.bitDepth_;
+ isData_ = rhs.isData_;
+ allocation_ = rhs.allocation_;
+ allocationVars_ = rhs.allocationVars_;
+
+ toRefTransform_ = rhs.toRefTransform_;
+ if(toRefTransform_) toRefTransform_ = toRefTransform_->createEditableCopy();
+
+ fromRefTransform_ = rhs.fromRefTransform_;
+ if(fromRefTransform_) fromRefTransform_ = fromRefTransform_->createEditableCopy();
+
+ toRefSpecified_ = rhs.toRefSpecified_;
+ fromRefSpecified_ = rhs.fromRefSpecified_;
+ return *this;
+ }
+ };
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+
+ ColorSpace::ColorSpace()
+ : m_impl(new ColorSpace::Impl)
+ {
+ }
+
+ ColorSpace::~ColorSpace()
+ {
+ delete m_impl;
+ m_impl = NULL;
+ }
+
+ ColorSpaceRcPtr ColorSpace::createEditableCopy() const
+ {
+ ColorSpaceRcPtr cs = ColorSpace::Create();
+ *cs->m_impl = *m_impl;
+ return cs;
+ }
+
+ const char * ColorSpace::getName() const
+ {
+ return getImpl()->name_.c_str();
+ }
+
+ void ColorSpace::setName(const char * name)
+ {
+ getImpl()->name_ = name;
+ }
+ const char * ColorSpace::getFamily() const
+ {
+ return getImpl()->family_.c_str();
+ }
+
+ void ColorSpace::setFamily(const char * family)
+ {
+ getImpl()->family_ = family;
+ }
+
+ const char * ColorSpace::getEqualityGroup() const
+ {
+ return getImpl()->equalityGroup_.c_str();
+ }
+
+ void ColorSpace::setEqualityGroup(const char * equalityGroup)
+ {
+ getImpl()->equalityGroup_ = equalityGroup;
+ }
+
+ const char * ColorSpace::getDescription() const
+ {
+ return getImpl()->description_.c_str();
+ }
+
+ void ColorSpace::setDescription(const char * description)
+ {
+ getImpl()->description_ = description;
+ }
+
+ BitDepth ColorSpace::getBitDepth() const
+ {
+ return getImpl()->bitDepth_;
+ }
+
+ void ColorSpace::setBitDepth(BitDepth bitDepth)
+ {
+ getImpl()->bitDepth_ = bitDepth;
+ }
+
+ bool ColorSpace::isData() const
+ {
+ return getImpl()->isData_;
+ }
+
+ void ColorSpace::setIsData(bool val)
+ {
+ getImpl()->isData_ = val;
+ }
+
+ Allocation ColorSpace::getAllocation() const
+ {
+ return getImpl()->allocation_;
+ }
+
+ void ColorSpace::setAllocation(Allocation allocation)
+ {
+ getImpl()->allocation_ = allocation;
+ }
+
+ int ColorSpace::getAllocationNumVars() const
+ {
+ return static_cast<int>(getImpl()->allocationVars_.size());
+ }
+
+ void ColorSpace::getAllocationVars(float * vars) const
+ {
+ if(!getImpl()->allocationVars_.empty())
+ {
+ memcpy(vars,
+ &getImpl()->allocationVars_[0],
+ getImpl()->allocationVars_.size()*sizeof(float));
+ }
+ }
+
+ void ColorSpace::setAllocationVars(int numvars, const float * vars)
+ {
+ getImpl()->allocationVars_.resize(numvars);
+
+ if(!getImpl()->allocationVars_.empty())
+ {
+ memcpy(&getImpl()->allocationVars_[0],
+ vars,
+ numvars*sizeof(float));
+ }
+ }
+
+ ConstTransformRcPtr ColorSpace::getTransform(ColorSpaceDirection dir) const
+ {
+ if(dir == COLORSPACE_DIR_TO_REFERENCE)
+ return getImpl()->toRefTransform_;
+ else if(dir == COLORSPACE_DIR_FROM_REFERENCE)
+ return getImpl()->fromRefTransform_;
+
+ throw Exception("Unspecified ColorSpaceDirection");
+ }
+
+ void ColorSpace::setTransform(const ConstTransformRcPtr & transform,
+ ColorSpaceDirection dir)
+ {
+ TransformRcPtr transformCopy;
+ if(transform) transformCopy = transform->createEditableCopy();
+
+ if(dir == COLORSPACE_DIR_TO_REFERENCE)
+ getImpl()->toRefTransform_ = transformCopy;
+ else if(dir == COLORSPACE_DIR_FROM_REFERENCE)
+ getImpl()->fromRefTransform_ = transformCopy;
+ else
+ throw Exception("Unspecified ColorSpaceDirection");
+ }
+
+ std::ostream& operator<< (std::ostream& os, const ColorSpace& cs)
+ {
+ os << "<ColorSpace ";
+ os << "name=" << cs.getName() << ", ";
+ os << "family=" << cs.getFamily() << ", ";
+ os << "equalityGroup=" << cs.getEqualityGroup() << ", ";
+ os << "bitDepth=" << BitDepthToString(cs.getBitDepth()) << ", ";
+ os << "isData=" << BoolToString(cs.isData()) << ", ";
+ os << "allocation=" << AllocationToString(cs.getAllocation()) << ", ";
+ os << ">\n";
+
+ if(cs.getTransform(COLORSPACE_DIR_TO_REFERENCE))
+ {
+ os << "\t" << cs.getName() << " --> Reference\n";
+ os << cs.getTransform(COLORSPACE_DIR_TO_REFERENCE);
+ }
+
+ if(cs.getTransform(COLORSPACE_DIR_FROM_REFERENCE))
+ {
+ os << "\tReference --> " << cs.getName() << "\n";
+ os << cs.getTransform(COLORSPACE_DIR_FROM_REFERENCE);
+ }
+ return os;
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/ColorSpaceTransform.cpp b/src/core/ColorSpaceTransform.cpp
new file mode 100644
index 0000000..92f3878
--- /dev/null
+++ b/src/core/ColorSpaceTransform.cpp
@@ -0,0 +1,246 @@
+/*
+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 "NoOps.h"
+#include "OpBuilders.h"
+
+
+OCIO_NAMESPACE_ENTER
+{
+ ColorSpaceTransformRcPtr ColorSpaceTransform::Create()
+ {
+ return ColorSpaceTransformRcPtr(new ColorSpaceTransform(), &deleter);
+ }
+
+ void ColorSpaceTransform::deleter(ColorSpaceTransform* t)
+ {
+ delete t;
+ }
+
+
+ class ColorSpaceTransform::Impl
+ {
+ public:
+ TransformDirection dir_;
+ std::string src_;
+ std::string dst_;
+
+ Impl() :
+ dir_(TRANSFORM_DIR_FORWARD)
+ { }
+
+ ~Impl()
+ { }
+
+ Impl& operator= (const Impl & rhs)
+ {
+ dir_ = rhs.dir_;
+ src_ = rhs.src_;
+ dst_ = rhs.dst_;
+ return *this;
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+
+ ColorSpaceTransform::ColorSpaceTransform()
+ : m_impl(new ColorSpaceTransform::Impl)
+ {
+ }
+
+ TransformRcPtr ColorSpaceTransform::createEditableCopy() const
+ {
+ ColorSpaceTransformRcPtr transform = ColorSpaceTransform::Create();
+ *(transform->m_impl) = *m_impl;
+ return transform;
+ }
+
+ ColorSpaceTransform::~ColorSpaceTransform()
+ {
+ delete m_impl;
+ m_impl = NULL;
+ }
+
+ ColorSpaceTransform& ColorSpaceTransform::operator= (const ColorSpaceTransform & rhs)
+ {
+ *m_impl = *rhs.m_impl;
+ return *this;
+ }
+
+ TransformDirection ColorSpaceTransform::getDirection() const
+ {
+ return getImpl()->dir_;
+ }
+
+ void ColorSpaceTransform::setDirection(TransformDirection dir)
+ {
+ getImpl()->dir_ = dir;
+ }
+
+ const char * ColorSpaceTransform::getSrc() const
+ {
+ return getImpl()->src_.c_str();
+ }
+
+ void ColorSpaceTransform::setSrc(const char * src)
+ {
+ getImpl()->src_ = src;
+ }
+
+ const char * ColorSpaceTransform::getDst() const
+ {
+ return getImpl()->dst_.c_str();
+ }
+
+ void ColorSpaceTransform::setDst(const char * dst)
+ {
+ getImpl()->dst_ = dst;
+ }
+
+ std::ostream& operator<< (std::ostream& os, const ColorSpaceTransform& t)
+ {
+ os << "<ColorSpaceTransform ";
+ os << "direction=" << TransformDirectionToString(t.getDirection()) << ", ";
+ os << ">\n";
+ return os;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ void BuildColorSpaceOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ const ColorSpaceTransform & colorSpaceTransform,
+ TransformDirection dir)
+ {
+ TransformDirection combinedDir = CombineTransformDirections(dir,
+ colorSpaceTransform.getDirection());
+
+ ConstColorSpaceRcPtr src, dst;
+
+ if(combinedDir == TRANSFORM_DIR_FORWARD)
+ {
+ src = config.getColorSpace( colorSpaceTransform.getSrc() );
+ dst = config.getColorSpace( colorSpaceTransform.getDst() );
+ }
+ else if(combinedDir == TRANSFORM_DIR_INVERSE)
+ {
+ dst = config.getColorSpace( colorSpaceTransform.getSrc() );
+ src = config.getColorSpace( colorSpaceTransform.getDst() );
+ }
+
+ BuildColorSpaceOps(ops, config, context, src, dst);
+ }
+
+ namespace
+ {
+ bool AreColorSpacesInSameEqualityGroup(const ConstColorSpaceRcPtr & csa,
+ const ConstColorSpaceRcPtr & csb)
+ {
+ std::string a = csa->getEqualityGroup();
+ std::string b = csb->getEqualityGroup();
+
+ if(!a.empty()) return (a==b);
+ return false;
+ }
+ }
+
+ void BuildColorSpaceOps(OpRcPtrVec & ops,
+ const Config & config,
+ const ConstContextRcPtr & context,
+ const ConstColorSpaceRcPtr & srcColorSpace,
+ const ConstColorSpaceRcPtr & dstColorSpace)
+ {
+ if(!srcColorSpace)
+ throw Exception("BuildColorSpaceOps failed, null srcColorSpace.");
+ if(!dstColorSpace)
+ throw Exception("BuildColorSpaceOps failed, null dstColorSpace.");
+
+ if(AreColorSpacesInSameEqualityGroup(srcColorSpace, dstColorSpace))
+ return;
+ if(dstColorSpace->isData() || srcColorSpace->isData())
+ return;
+
+ // Consider dt8 -> vd8?
+ // One would have to explode the srcColorSpace->getTransform(COLORSPACE_DIR_TO_REFERENCE);
+ // result, and walk through it step by step. If the dstColorspace family were
+ // ever encountered in transit, we'd want to short circuit the result.
+
+ AllocationData srcAllocation;
+ srcAllocation.allocation = srcColorSpace->getAllocation();
+ srcAllocation.vars.resize( srcColorSpace->getAllocationNumVars());
+ if(srcAllocation.vars.size() > 0)
+ {
+ srcColorSpace->getAllocationVars(&srcAllocation.vars[0]);
+ }
+
+ CreateGpuAllocationNoOp(ops, srcAllocation);
+
+ // Go to the reference space, either by using
+ // * cs->ref in the forward direction
+ // * ref->cs in the inverse direction
+ if(srcColorSpace->getTransform(COLORSPACE_DIR_TO_REFERENCE))
+ {
+ BuildOps(ops, config, context, srcColorSpace->getTransform(COLORSPACE_DIR_TO_REFERENCE), TRANSFORM_DIR_FORWARD);
+ }
+ else if(srcColorSpace->getTransform(COLORSPACE_DIR_FROM_REFERENCE))
+ {
+ BuildOps(ops, config, context, srcColorSpace->getTransform(COLORSPACE_DIR_FROM_REFERENCE), TRANSFORM_DIR_INVERSE);
+ }
+ // Otherwise, both are not defined so its a no-op. This is not an error condition.
+
+ // Go from the reference space, either by using
+ // * ref->cs in the forward direction
+ // * cs->ref in the inverse direction
+ if(dstColorSpace->getTransform(COLORSPACE_DIR_FROM_REFERENCE))
+ {
+ BuildOps(ops, config, context, dstColorSpace->getTransform(COLORSPACE_DIR_FROM_REFERENCE), TRANSFORM_DIR_FORWARD);
+ }
+ else if(dstColorSpace->getTransform(COLORSPACE_DIR_TO_REFERENCE))
+ {
+ BuildOps(ops, config, context, dstColorSpace->getTransform(COLORSPACE_DIR_TO_REFERENCE), TRANSFORM_DIR_INVERSE);
+ }
+ // Otherwise, both are not defined so its a no-op. This is not an error condition.
+
+ AllocationData dstAllocation;
+ dstAllocation.allocation = dstColorSpace->getAllocation();
+ dstAllocation.vars.resize( dstColorSpace->getAllocationNumVars());
+ if(dstAllocation.vars.size() > 0)
+ {
+ dstColorSpace->getAllocationVars(&dstAllocation.vars[0]);
+ }
+
+ CreateGpuAllocationNoOp(ops, dstAllocation);
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/Config.cpp b/src/core/Config.cpp
new file mode 100644
index 0000000..985990f
--- /dev/null
+++ b/src/core/Config.cpp
@@ -0,0 +1,2223 @@
+/*
+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 <cstdlib>
+#include <cstring>
+#include <set>
+#include <sstream>
+#include <fstream>
+#include <utility>
+#include <vector>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "HashUtils.h"
+#include "Logging.h"
+#include "LookParse.h"
+#include "MathUtils.h"
+#include "Mutex.h"
+#include "OpBuilders.h"
+#include "PathUtils.h"
+#include "ParseUtils.h"
+#include "Processor.h"
+#include "PrivateTypes.h"
+#include "pystring/pystring.h"
+#include "OCIOYaml.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ const char * OCIO_CONFIG_ENVVAR = "OCIO";
+ const char * OCIO_ACTIVE_DISPLAYS_ENVVAR = "OCIO_ACTIVE_DISPLAYS";
+ const char * OCIO_ACTIVE_VIEWS_ENVVAR = "OCIO_ACTIVE_VIEWS";
+
+ enum Sanity
+ {
+ SANITY_UNKNOWN = 0,
+ SANITY_SANE,
+ SANITY_INSANE
+ };
+
+ // These are the 709 primaries specified by the ASC.
+ const float DEFAULT_LUMA_COEFF_R = 0.2126f;
+ const float DEFAULT_LUMA_COEFF_G = 0.7152f;
+ const float DEFAULT_LUMA_COEFF_B = 0.0722f;
+
+ const char * INTERNAL_RAW_PROFILE =
+ "ocio_profile_version: 1\n"
+ "strictparsing: false\n"
+ "roles:\n"
+ " default: raw\n"
+ "displays:\n"
+ " sRGB:\n"
+ " - !<View> {name: Raw, colorspace: raw}\n"
+ "colorspaces:\n"
+ " - !<ColorSpace>\n"
+ " name: raw\n"
+ " family: raw\n"
+ " equalitygroup:\n"
+ " bitdepth: 32f\n"
+ " isdata: true\n"
+ " allocation: uniform\n"
+ " description: 'A raw color space. Conversions to and from this space are no-ops.'\n";
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ const char * GetVersion()
+ {
+ return OCIO_VERSION;
+ }
+
+ int GetVersionHex()
+ {
+ return OCIO_VERSION_HEX;
+ }
+
+ namespace
+ {
+ ConstConfigRcPtr g_currentConfig;
+ Mutex g_currentConfigLock;
+ }
+
+ ConstConfigRcPtr GetCurrentConfig()
+ {
+ AutoMutex lock(g_currentConfigLock);
+
+ if(!g_currentConfig)
+ {
+ g_currentConfig = Config::CreateFromEnv();
+ }
+
+ return g_currentConfig;
+ }
+
+ void SetCurrentConfig(const ConstConfigRcPtr & config)
+ {
+ AutoMutex lock(g_currentConfigLock);
+
+ g_currentConfig = config->createEditableCopy();
+ }
+
+ namespace
+ {
+
+ // Roles
+ // (lower case role name: colorspace name)
+ std::string LookupRole(const StringMap & roles, const std::string & rolename)
+ {
+ StringMap::const_iterator iter = roles.find(pystring::lower(rolename));
+ if(iter == roles.end()) return "";
+ return iter->second;
+ }
+
+
+ void GetFileReferences(std::set<std::string> & files,
+ const ConstTransformRcPtr & transform)
+ {
+ if(!transform) return;
+
+ if(ConstGroupTransformRcPtr groupTransform = \
+ DynamicPtrCast<const GroupTransform>(transform))
+ {
+ for(int i=0; i<groupTransform->size(); ++i)
+ {
+ GetFileReferences(files, groupTransform->getTransform(i));
+ }
+ }
+ else if(ConstFileTransformRcPtr fileTransform = \
+ DynamicPtrCast<const FileTransform>(transform))
+ {
+ files.insert(fileTransform->getSrc());
+ }
+ }
+
+ void GetColorSpaceReferences(std::set<std::string> & colorSpaceNames,
+ const ConstTransformRcPtr & transform)
+ {
+ if(!transform) return;
+
+ if(ConstGroupTransformRcPtr groupTransform = \
+ DynamicPtrCast<const GroupTransform>(transform))
+ {
+ for(int i=0; i<groupTransform->size(); ++i)
+ {
+ GetColorSpaceReferences(colorSpaceNames, groupTransform->getTransform(i));
+ }
+ }
+ else if(ConstColorSpaceTransformRcPtr colorSpaceTransform = \
+ DynamicPtrCast<const ColorSpaceTransform>(transform))
+ {
+ colorSpaceNames.insert(colorSpaceTransform->getSrc());
+ colorSpaceNames.insert(colorSpaceTransform->getDst());
+ }
+ else if(ConstDisplayTransformRcPtr displayTransform = \
+ DynamicPtrCast<const DisplayTransform>(transform))
+ {
+ colorSpaceNames.insert(displayTransform->getInputColorSpaceName());
+ }
+ else if(ConstLookTransformRcPtr lookTransform = \
+ DynamicPtrCast<const LookTransform>(transform))
+ {
+ colorSpaceNames.insert(colorSpaceTransform->getSrc());
+ colorSpaceNames.insert(colorSpaceTransform->getDst());
+ }
+ }
+
+
+ bool FindColorSpaceIndex(int * index,
+ const ColorSpaceVec & colorspaces,
+ const std::string & csname)
+ {
+ if(csname.empty()) return false;
+
+ std::string csnamelower = pystring::lower(csname);
+
+ for(unsigned int i = 0; i < colorspaces.size(); ++i)
+ {
+ if(csnamelower == pystring::lower(colorspaces[i]->getName()))
+ {
+ if(index) *index = i;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ // Displays
+ struct View
+ {
+ std::string name;
+ std::string colorspace;
+ std::string looks;
+
+ View() { }
+
+ View(const std::string & name_,
+ const std::string & colorspace_,
+ const std::string & looksList_) :
+ name(name_),
+ colorspace(colorspace_),
+ looks(looksList_)
+ { }
+ };
+
+ typedef std::vector<View> ViewVec;
+ typedef std::map<std::string, ViewVec> DisplayMap; // (display name : ViewVec)
+
+ void operator >> (const YAML::Node& node, View& v)
+ {
+ if(node.Tag() != "View")
+ return;
+
+ std::string key, stringval;
+
+ for (YAML::Iterator iter = node.begin();
+ iter != node.end();
+ ++iter)
+ {
+ iter.first() >> key;
+
+ if(key == "name")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ v.name = stringval;
+ }
+ else if(key == "colorspace")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ v.colorspace = stringval;
+ }
+ else if(key == "looks" || key == "look")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ v.looks = stringval;
+ }
+ else
+ {
+ LogUnknownKeyWarning(node.Tag(), iter.first());
+ }
+ }
+
+ if(v.name.empty())
+ {
+ throw Exception("View does not specify 'name'.");
+ }
+ if(v.colorspace.empty())
+ {
+ std::ostringstream os;
+ os << "View '" << v.name << "' ";
+ os << "does not specify colorspace.";
+ throw Exception(os.str().c_str());
+ }
+ }
+
+ YAML::Emitter& operator << (YAML::Emitter& out, View view)
+ {
+ out << YAML::VerbatimTag("View");
+ out << YAML::Flow;
+ out << YAML::BeginMap;
+ out << YAML::Key << "name" << YAML::Value << view.name;
+ out << YAML::Key << "colorspace" << YAML::Value << view.colorspace;
+ if(!view.looks.empty()) out << YAML::Key << "looks" << YAML::Value << view.looks;
+ out << YAML::EndMap;
+ return out;
+ }
+
+ DisplayMap::iterator find_display(DisplayMap & displays, const std::string & display)
+ {
+ for(DisplayMap::iterator iter = displays.begin();
+ iter != displays.end();
+ ++iter)
+ {
+ if(StrEqualsCaseIgnore(display, iter->first)) return iter;
+ }
+ return displays.end();
+ }
+
+ DisplayMap::const_iterator find_display_const(const DisplayMap & displays, const std::string & display)
+ {
+ for(DisplayMap::const_iterator iter = displays.begin();
+ iter != displays.end();
+ ++iter)
+ {
+ if(StrEqualsCaseIgnore(display, iter->first)) return iter;
+ }
+ return displays.end();
+ }
+
+ int find_view(const ViewVec & vec, const std::string & name)
+ {
+ for(unsigned int i=0; i<vec.size(); ++i)
+ {
+ if(StrEqualsCaseIgnore(name, vec[i].name)) return i;
+ }
+ return -1;
+ }
+
+ void AddDisplay(DisplayMap & displays,
+ const std::string & display,
+ const std::string & view,
+ const std::string & colorspace,
+ const std::string & looks)
+ {
+ DisplayMap::iterator iter = find_display(displays, display);
+ if(iter == displays.end())
+ {
+ ViewVec views;
+ views.push_back( View(view, colorspace, looks) );
+ displays[display] = views;
+ }
+ else
+ {
+ ViewVec & views = iter->second;
+ int index = find_view(views, view);
+ if(index<0)
+ {
+ views.push_back( View(view, colorspace, looks) );
+ }
+ else
+ {
+ views[index].colorspace = colorspace;
+ views[index].looks = looks;
+ }
+ }
+ }
+
+ void ComputeDisplays(StringVec & displayCache,
+ const DisplayMap & displays,
+ const StringVec & activeDisplays,
+ const StringVec & activeDisplaysEnvOverride)
+ {
+ displayCache.clear();
+
+ StringVec displayMasterList;
+ for(DisplayMap::const_iterator iter = displays.begin();
+ iter != displays.end();
+ ++iter)
+ {
+ displayMasterList.push_back(iter->first);
+ }
+
+ // Apply the env override if it's not empty.
+ if(!activeDisplaysEnvOverride.empty())
+ {
+ displayCache = IntersectStringVecsCaseIgnore(displayMasterList, activeDisplaysEnvOverride);
+ if(!displayCache.empty()) return;
+ }
+ // Otherwise, aApply the active displays if it's not empty.
+ else if(!activeDisplays.empty())
+ {
+ displayCache = IntersectStringVecsCaseIgnore(displayMasterList, activeDisplays);
+ if(!displayCache.empty()) return;
+ }
+
+ displayCache = displayMasterList;
+ }
+
+
+
+ } // namespace
+
+ class Config::Impl
+ {
+ public:
+ ContextRcPtr context_;
+ std::string description_;
+ ColorSpaceVec colorspaces_;
+ StringMap roles_;
+ LookVec looksList_;
+
+ DisplayMap displays_;
+ StringVec activeDisplays_;
+ StringVec activeDisplaysEnvOverride_;
+ StringVec activeViews_;
+ StringVec activeViewsEnvOverride_;
+
+ mutable std::string activeDisplaysStr_;
+ mutable std::string activeViewsStr_;
+ mutable StringVec displayCache_;
+
+ // Misc
+ std::vector<float> defaultLumaCoefs_;
+ bool strictParsing_;
+
+ mutable Sanity sanity_;
+ mutable std::string sanitytext_;
+
+ mutable Mutex cacheidMutex_;
+ mutable StringMap cacheids_;
+ mutable std::string cacheidnocontext_;
+
+ Impl() :
+ context_(Context::Create()),
+ strictParsing_(true),
+ sanity_(SANITY_UNKNOWN)
+ {
+ context_->loadEnvironment();
+
+ char* activeDisplays = std::getenv(OCIO_ACTIVE_DISPLAYS_ENVVAR);
+ SplitStringEnvStyle(activeDisplaysEnvOverride_, activeDisplays);
+
+ char * activeViews = std::getenv(OCIO_ACTIVE_VIEWS_ENVVAR);
+ SplitStringEnvStyle(activeViewsEnvOverride_, activeViews);
+
+ defaultLumaCoefs_.resize(3);
+ defaultLumaCoefs_[0] = DEFAULT_LUMA_COEFF_R;
+ defaultLumaCoefs_[1] = DEFAULT_LUMA_COEFF_G;
+ defaultLumaCoefs_[2] = DEFAULT_LUMA_COEFF_B;
+ }
+
+ ~Impl()
+ {
+
+ }
+
+ Impl& operator= (const Impl & rhs)
+ {
+ context_ = rhs.context_->createEditableCopy();
+ description_ = rhs.description_;
+
+ // Deep copy the colorspaces
+ colorspaces_.clear();
+ colorspaces_.reserve(rhs.colorspaces_.size());
+ for(unsigned int i=0; i<rhs.colorspaces_.size(); ++i)
+ {
+ colorspaces_.push_back(rhs.colorspaces_[i]->createEditableCopy());
+ }
+
+ // Deep copy the looks
+ looksList_.clear();
+ looksList_.reserve(rhs.looksList_.size());
+ for(unsigned int i=0; i<rhs.looksList_.size(); ++i)
+ {
+ looksList_.push_back(rhs.looksList_[i]->createEditableCopy());
+ }
+
+ // Assignment operator will suffice for these
+ roles_ = rhs.roles_;
+
+ displays_ = rhs.displays_;
+ activeDisplays_ = rhs.activeDisplays_;
+ activeViews_ = rhs.activeViews_;
+ activeViewsEnvOverride_ = rhs.activeViewsEnvOverride_;
+ activeDisplaysEnvOverride_ = rhs.activeDisplaysEnvOverride_;
+ activeDisplaysStr_ = rhs.activeDisplaysStr_;
+ displayCache_ = rhs.displayCache_;
+
+ defaultLumaCoefs_ = rhs.defaultLumaCoefs_;
+ strictParsing_ = rhs.strictParsing_;
+
+ sanity_ = rhs.sanity_;
+ sanitytext_ = rhs.sanitytext_;
+
+ cacheids_ = rhs.cacheids_;
+ cacheidnocontext_ = cacheidnocontext_;
+ return *this;
+ }
+
+ void load(std::istream & istream, const char * name);
+
+ // Any time you modify the state of the config, you must call this
+ // to reset internal cache states. You also should do this in a
+ // thread safe manner by acquiring the cacheidMutex_;
+ void resetCacheIDs();
+
+ // Get all internal transforms (to generate cacheIDs, validation, etc).
+ // This currently crawls colorspaces + looks
+ void getAllIntenalTransforms(ConstTransformVec & transformVec) const;
+ };
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ ConfigRcPtr Config::Create()
+ {
+ return ConfigRcPtr(new Config(), &deleter);
+ }
+
+ void Config::deleter(Config* c)
+ {
+ delete c;
+ }
+
+ ConstConfigRcPtr Config::CreateFromEnv()
+ {
+ char* file = std::getenv(OCIO_CONFIG_ENVVAR);
+ if(file) return CreateFromFile(file);
+
+ std::ostringstream os;
+ os << "Color management disabled. ";
+ os << "(Specify the $OCIO environment variable to enable.)";
+ LogInfo(os.str());
+
+ std::istringstream istream;
+ istream.str(INTERNAL_RAW_PROFILE);
+
+ ConfigRcPtr config = Config::Create();
+ config->getImpl()->load(istream, "");
+ return config;
+ }
+
+ ConstConfigRcPtr Config::CreateFromFile(const char * filename)
+ {
+ std::ifstream istream(filename);
+ if(istream.fail()) {
+ std::ostringstream os;
+ os << "Error could not read '" << filename;
+ os << "' OCIO profile.";
+ throw Exception (os.str().c_str());
+ }
+
+ ConfigRcPtr config = Config::Create();
+ config->getImpl()->load(istream, filename);
+ return config;
+ }
+
+ ConstConfigRcPtr Config::CreateFromStream(std::istream & istream)
+ {
+ ConfigRcPtr config = Config::Create();
+ config->getImpl()->load(istream, "");
+ return config;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+
+ Config::Config()
+ : m_impl(new Config::Impl)
+ {
+ }
+
+ Config::~Config()
+ {
+ delete m_impl;
+ m_impl = NULL;
+ }
+
+ ConfigRcPtr Config::createEditableCopy() const
+ {
+ ConfigRcPtr config = Config::Create();
+ *config->m_impl = *m_impl;
+ return config;
+ }
+
+ void Config::sanityCheck() const
+ {
+ if(getImpl()->sanity_ == SANITY_SANE) return;
+ if(getImpl()->sanity_ == SANITY_INSANE)
+ {
+ throw Exception(getImpl()->sanitytext_.c_str());
+ }
+
+ getImpl()->sanity_ = SANITY_INSANE;
+ getImpl()->sanitytext_ = "";
+
+
+ ///// COLORSPACES
+ StringSet existingColorSpaces;
+
+ // Confirm all ColorSpaces are valid
+ for(unsigned int i=0; i<getImpl()->colorspaces_.size(); ++i)
+ {
+ if(!getImpl()->colorspaces_[i])
+ {
+ std::ostringstream os;
+ os << "Config failed sanitycheck. ";
+ os << "The colorspace at index " << i << " is null.";
+ getImpl()->sanitytext_ = os.str();
+ throw Exception(getImpl()->sanitytext_.c_str());
+ }
+
+ const char * name = getImpl()->colorspaces_[i]->getName();
+ if(!name || strlen(name) == 0)
+ {
+ std::ostringstream os;
+ os << "Config failed sanitycheck. ";
+ os << "The colorspace at index " << i << " is not named.";
+ getImpl()->sanitytext_ = os.str();
+ throw Exception(getImpl()->sanitytext_.c_str());
+ }
+
+ std::string namelower = pystring::lower(name);
+ StringSet::const_iterator it = existingColorSpaces.find(namelower);
+ if(it != existingColorSpaces.end())
+ {
+ std::ostringstream os;
+ os << "Config failed sanitycheck. ";
+ os << "Two colorspaces are defined with the same name, '";
+ os << namelower << "'.";
+ getImpl()->sanitytext_ = os.str();
+ throw Exception(getImpl()->sanitytext_.c_str());
+ }
+
+ existingColorSpaces.insert(namelower);
+ }
+
+ // Confirm all roles are valid
+ {
+ for(StringMap::const_iterator iter = getImpl()->roles_.begin(),
+ end = getImpl()->roles_.end(); iter!=end; ++iter)
+ {
+ int csindex = -1;
+ if(!FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, iter->second))
+ {
+ std::ostringstream os;
+ os << "Config failed sanitycheck. ";
+ os << "The role '" << iter->first << "' ";
+ os << "refers to a colorspace, '" << iter->second << "', ";
+ os << "which is not defined.";
+ getImpl()->sanitytext_ = os.str();
+ throw Exception(getImpl()->sanitytext_.c_str());
+ }
+
+ // Confirm no name conflicts between colorspaces and roles
+ if(FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, iter->first))
+ {
+ std::ostringstream os;
+ os << "Config failed sanitycheck. ";
+ os << "The role '" << iter->first << "' ";
+ os << " is in conflict with a colorspace of the same name.";
+ getImpl()->sanitytext_ = os.str();
+ throw Exception(getImpl()->sanitytext_.c_str());
+ }
+ }
+ }
+
+ ///// DISPLAYS
+
+ int numviews = 0;
+
+ // Confirm all Displays transforms refer to colorspaces that exit
+ for(DisplayMap::const_iterator iter = getImpl()->displays_.begin();
+ iter != getImpl()->displays_.end();
+ ++iter)
+ {
+ std::string display = iter->first;
+ const ViewVec & views = iter->second;
+ if(views.empty())
+ {
+ std::ostringstream os;
+ os << "Config failed sanitycheck. ";
+ os << "The display '" << display << "' ";
+ os << "does not define any views.";
+ getImpl()->sanitytext_ = os.str();
+ throw Exception(getImpl()->sanitytext_.c_str());
+ }
+
+ for(unsigned int i=0; i<views.size(); ++i)
+ {
+ if(views[i].name.empty() || views[i].colorspace.empty())
+ {
+ std::ostringstream os;
+ os << "Config failed sanitycheck. ";
+ os << "The display '" << display << "' ";
+ os << "defines a view with an empty name and/or colorspace.";
+ getImpl()->sanitytext_ = os.str();
+ throw Exception(getImpl()->sanitytext_.c_str());
+ }
+
+ int csindex = -1;
+ if(!FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, views[i].colorspace))
+ {
+ std::ostringstream os;
+ os << "Config failed sanitycheck. ";
+ os << "The display '" << display << "' ";
+ os << "refers to a colorspace, '" << views[i].colorspace << "', ";
+ os << "which is not defined.";
+ getImpl()->sanitytext_ = os.str();
+ throw Exception(getImpl()->sanitytext_.c_str());
+ }
+
+ // Confirm looks references exist
+ LookParseResult looks;
+ const LookParseResult::Options & options = looks.parse(views[i].looks);
+
+ for(unsigned int optionindex=0;
+ optionindex<options.size();
+ ++optionindex)
+ {
+ for(unsigned int tokenindex=0;
+ tokenindex<options[optionindex].size();
+ ++tokenindex)
+ {
+ std::string look = options[optionindex][tokenindex].name;
+
+ if(!look.empty() && !getLook(look.c_str()))
+ {
+ std::ostringstream os;
+ os << "Config failed sanitycheck. ";
+ os << "The display '" << display << "' ";
+ os << "refers to a look, '" << look << "', ";
+ os << "which is not defined.";
+ getImpl()->sanitytext_ = os.str();
+ throw Exception(getImpl()->sanitytext_.c_str());
+ }
+ }
+ }
+
+ ++numviews;
+ }
+ }
+
+ // Confirm at least one display entry exists.
+ if(numviews == 0)
+ {
+ std::ostringstream os;
+ os << "Config failed sanitycheck. ";
+ os << "No displays are specified.";
+ getImpl()->sanitytext_ = os.str();
+ throw Exception(getImpl()->sanitytext_.c_str());
+ }
+
+ // Confirm for all Transforms that reference internal colorspaces,
+ // the named space exists
+ {
+ ConstTransformVec allTransforms;
+ getImpl()->getAllIntenalTransforms(allTransforms);
+
+ std::set<std::string> colorSpaceNames;
+ for(unsigned int i=0; i<colorSpaceNames.size(); ++i)
+ {
+ GetColorSpaceReferences(colorSpaceNames, allTransforms[i]);
+ }
+
+ for(std::set<std::string>::iterator iter = colorSpaceNames.begin();
+ iter != colorSpaceNames.end(); ++iter)
+ {
+ int csindex = -1;
+ if(!FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, *iter))
+ {
+ std::ostringstream os;
+ os << "Config failed sanitycheck. ";
+ os << "This config references a ColorSpace, '" << *iter << "', ";
+ os << "which is not defined.";
+ getImpl()->sanitytext_ = os.str();
+ throw Exception(getImpl()->sanitytext_.c_str());
+ }
+ }
+ }
+
+ ///// LOOKS
+
+ // For all looks, confirm the process space exists and the look is named
+ for(unsigned int i=0; i<getImpl()->looksList_.size(); ++i)
+ {
+ std::string name = getImpl()->looksList_[i]->getName();
+ if(name.empty())
+ {
+ std::ostringstream os;
+ os << "Config failed sanitycheck. ";
+ os << "The look at index '" << i << "' ";
+ os << "does not specify a name.";
+ getImpl()->sanitytext_ = os.str();
+ throw Exception(getImpl()->sanitytext_.c_str());
+ }
+
+ std::string processSpace = getImpl()->looksList_[i]->getProcessSpace();
+ if(processSpace.empty())
+ {
+ std::ostringstream os;
+ os << "Config failed sanitycheck. ";
+ os << "The look '" << name << "' ";
+ os << "does not specify a process space.";
+ getImpl()->sanitytext_ = os.str();
+ throw Exception(getImpl()->sanitytext_.c_str());
+ }
+
+ int csindex=0;
+ if(!FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, processSpace))
+ {
+ std::ostringstream os;
+ os << "Config failed sanitycheck. ";
+ os << "The look '" << name << "' ";
+ os << "specifies a process color space, '";
+ os << processSpace << "', which is not defined.";
+ getImpl()->sanitytext_ = os.str();
+ throw Exception(getImpl()->sanitytext_.c_str());
+ }
+ }
+
+
+
+ // Everything is groovy.
+ getImpl()->sanity_ = SANITY_SANE;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ const char * Config::getDescription() const
+ {
+ return getImpl()->description_.c_str();
+ }
+
+ void Config::setDescription(const char * description)
+ {
+ getImpl()->description_ = description;
+
+ AutoMutex lock(getImpl()->cacheidMutex_);
+ getImpl()->resetCacheIDs();
+ }
+
+
+ // RESOURCES //////////////////////////////////////////////////////////////
+
+ ConstContextRcPtr Config::getCurrentContext() const
+ {
+ return getImpl()->context_;
+ }
+
+ const char * Config::getSearchPath() const
+ {
+ return getImpl()->context_->getSearchPath();
+ }
+
+ void Config::setSearchPath(const char * path)
+ {
+ getImpl()->context_->setSearchPath(path);
+
+ AutoMutex lock(getImpl()->cacheidMutex_);
+ getImpl()->resetCacheIDs();
+ }
+
+ const char * Config::getWorkingDir() const
+ {
+ return getImpl()->context_->getWorkingDir();
+ }
+
+ void Config::setWorkingDir(const char * dirname)
+ {
+ getImpl()->context_->setWorkingDir(dirname);
+
+ AutoMutex lock(getImpl()->cacheidMutex_);
+ getImpl()->resetCacheIDs();
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ int Config::getNumColorSpaces() const
+ {
+ return static_cast<int>(getImpl()->colorspaces_.size());
+ }
+
+ const char * Config::getColorSpaceNameByIndex(int index) const
+ {
+ if(index<0 || index >= (int)getImpl()->colorspaces_.size())
+ {
+ return "";
+ }
+
+ return getImpl()->colorspaces_[index]->getName();
+ }
+
+ ConstColorSpaceRcPtr Config::getColorSpace(const char * name) const
+ {
+ int index = getIndexForColorSpace(name);
+ if(index<0 || index >= (int)getImpl()->colorspaces_.size())
+ {
+ return ColorSpaceRcPtr();
+ }
+
+ return getImpl()->colorspaces_[index];
+ }
+
+ int Config::getIndexForColorSpace(const char * name) const
+ {
+ int csindex = -1;
+
+ // Check to see if the name is a color space
+ if( FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, name) )
+ {
+ return csindex;
+ }
+
+ // Check to see if the name is a role
+ std::string csname = LookupRole(getImpl()->roles_, name);
+ if( FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, csname) )
+ {
+ return csindex;
+ }
+
+ // Is a default role defined?
+ // (And, are we allowed to use it)
+ if(!getImpl()->strictParsing_)
+ {
+ csname = LookupRole(getImpl()->roles_, ROLE_DEFAULT);
+ if( FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, csname) )
+ {
+ return csindex;
+ }
+ }
+
+ return -1;
+ }
+
+ void Config::addColorSpace(const ConstColorSpaceRcPtr & original)
+ {
+ ColorSpaceRcPtr cs = original->createEditableCopy();
+
+ std::string name = cs->getName();
+ if(name.empty())
+ throw Exception("Cannot addColorSpace with an empty name.");
+
+ // Check to see if the colorspace already exists
+ int csindex = -1;
+ if( FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, name) )
+ {
+ getImpl()->colorspaces_[csindex] = cs;
+ }
+ else
+ {
+ // Otherwise, add it
+ getImpl()->colorspaces_.push_back( cs );
+ }
+
+ AutoMutex lock(getImpl()->cacheidMutex_);
+ getImpl()->resetCacheIDs();
+ }
+
+ void Config::clearColorSpaces()
+ {
+ getImpl()->colorspaces_.clear();
+ }
+
+
+
+
+
+
+ const char * Config::parseColorSpaceFromString(const char * str) const
+ {
+ if(!str) return "";
+
+ // Search the entire filePath, including directory name (if provided)
+ // convert the filename to lowercase.
+ std::string fullstr = pystring::lower(std::string(str));
+
+ // See if it matches a lut name.
+ // This is the position of the RIGHT end of the colorspace substring, not the left
+ int rightMostColorPos=-1;
+ std::string rightMostColorspace = "";
+ int rightMostColorSpaceIndex = -1;
+
+ // Find the right-most occcurance within the string for each colorspace.
+ for (unsigned int i=0; i<getImpl()->colorspaces_.size(); ++i)
+ {
+ std::string csname = pystring::lower(getImpl()->colorspaces_[i]->getName());
+
+ // find right-most extension matched in filename
+ int colorspacePos = pystring::rfind(fullstr, csname);
+ if(colorspacePos < 0)
+ continue;
+
+ // If we have found a match, move the pointer over to the right end of the substring
+ // This will allow us to find the longest name that matches the rightmost colorspace
+ colorspacePos += (int)csname.size();
+
+ if ( (colorspacePos > rightMostColorPos) ||
+ ((colorspacePos == rightMostColorPos) && (csname.size() > rightMostColorspace.size()))
+ )
+ {
+ rightMostColorPos = colorspacePos;
+ rightMostColorspace = csname;
+ rightMostColorSpaceIndex = i;
+ }
+ }
+
+ if(rightMostColorSpaceIndex>=0)
+ {
+ return getImpl()->colorspaces_[rightMostColorSpaceIndex]->getName();
+ }
+
+ if(!getImpl()->strictParsing_)
+ {
+ // Is a default role defined?
+ std::string csname = LookupRole(getImpl()->roles_, ROLE_DEFAULT);
+ if(!csname.empty())
+ {
+ int csindex = -1;
+ if( FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, csname) )
+ {
+ // This is necessary to not return a reference to
+ // a local variable.
+ return getImpl()->colorspaces_[csindex]->getName();
+ }
+ }
+ }
+
+ return "";
+ }
+
+ bool Config::isStrictParsingEnabled() const
+ {
+ return getImpl()->strictParsing_;
+ }
+
+ void Config::setStrictParsingEnabled(bool enabled)
+ {
+ getImpl()->strictParsing_ = enabled;
+
+ AutoMutex lock(getImpl()->cacheidMutex_);
+ getImpl()->resetCacheIDs();
+ }
+
+ // Roles
+ void Config::setRole(const char * role, const char * colorSpaceName)
+ {
+ // Set the role
+ if(colorSpaceName)
+ {
+ getImpl()->roles_[pystring::lower(role)] = std::string(colorSpaceName);
+ }
+ // Unset the role
+ else
+ {
+ StringMap::iterator iter = getImpl()->roles_.find(pystring::lower(role));
+ if(iter != getImpl()->roles_.end())
+ {
+ getImpl()->roles_.erase(iter);
+ }
+ }
+
+ AutoMutex lock(getImpl()->cacheidMutex_);
+ getImpl()->resetCacheIDs();
+ }
+
+ int Config::getNumRoles() const
+ {
+ return static_cast<int>(getImpl()->roles_.size());
+ }
+
+ bool Config::hasRole(const char * role) const
+ {
+ return LookupRole(getImpl()->roles_, role) == "" ? false : true;
+ }
+
+ const char * Config::getRoleName(int index) const
+ {
+ if(index < 0 || index >= (int)getImpl()->roles_.size()) return "";
+ StringMap::const_iterator iter = getImpl()->roles_.begin();
+ for(int i = 0; i < index; ++i) ++iter;
+ return iter->first.c_str();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // Display/View Registration
+
+
+ const char * Config::getDefaultDisplay() const
+ {
+ if(getImpl()->displayCache_.empty())
+ {
+ ComputeDisplays(getImpl()->displayCache_,
+ getImpl()->displays_,
+ getImpl()->activeDisplays_,
+ getImpl()->activeDisplaysEnvOverride_);
+ }
+
+ int index = -1;
+
+ if(!getImpl()->activeDisplaysEnvOverride_.empty())
+ {
+ StringVec orderedDisplays = IntersectStringVecsCaseIgnore(getImpl()->activeDisplaysEnvOverride_,
+ getImpl()->displayCache_);
+ if(!orderedDisplays.empty())
+ {
+ index = FindInStringVecCaseIgnore(getImpl()->displayCache_, orderedDisplays[0]);
+ }
+ }
+ else if(!getImpl()->activeDisplays_.empty())
+ {
+ StringVec orderedDisplays = IntersectStringVecsCaseIgnore(getImpl()->activeDisplays_,
+ getImpl()->displayCache_);
+ if(!orderedDisplays.empty())
+ {
+ index = FindInStringVecCaseIgnore(getImpl()->displayCache_, orderedDisplays[0]);
+ }
+ }
+
+ if(index >= 0)
+ {
+ return getImpl()->displayCache_[index].c_str();
+ }
+
+ if(!getImpl()->displayCache_.empty())
+ {
+ return getImpl()->displayCache_[0].c_str();
+ }
+
+ return "";
+ }
+
+
+ int Config::getNumDisplays() const
+ {
+ if(getImpl()->displayCache_.empty())
+ {
+ ComputeDisplays(getImpl()->displayCache_,
+ getImpl()->displays_,
+ getImpl()->activeDisplays_,
+ getImpl()->activeDisplaysEnvOverride_);
+ }
+
+ return static_cast<int>(getImpl()->displayCache_.size());
+ }
+
+ const char * Config::getDisplay(int index) const
+ {
+ if(getImpl()->displayCache_.empty())
+ {
+ ComputeDisplays(getImpl()->displayCache_,
+ getImpl()->displays_,
+ getImpl()->activeDisplays_,
+ getImpl()->activeDisplaysEnvOverride_);
+ }
+
+ if(index>=0 || index < static_cast<int>(getImpl()->displayCache_.size()))
+ {
+ return getImpl()->displayCache_[index].c_str();
+ }
+
+ return "";
+ }
+
+ const char * Config::getDefaultView(const char * display) const
+ {
+ if(getImpl()->displayCache_.empty())
+ {
+ ComputeDisplays(getImpl()->displayCache_,
+ getImpl()->displays_,
+ getImpl()->activeDisplays_,
+ getImpl()->activeDisplaysEnvOverride_);
+ }
+
+ if(!display) return "";
+
+ DisplayMap::const_iterator iter = find_display_const(getImpl()->displays_, display);
+ if(iter == getImpl()->displays_.end()) return "";
+
+ const ViewVec & views = iter->second;
+
+ StringVec masterViews;
+ for(unsigned int i=0; i<views.size(); ++i)
+ {
+ masterViews.push_back(views[i].name);
+ }
+
+ int index = -1;
+
+ if(!getImpl()->activeViewsEnvOverride_.empty())
+ {
+ StringVec orderedViews = IntersectStringVecsCaseIgnore(getImpl()->activeViewsEnvOverride_,
+ masterViews);
+ if(!orderedViews.empty())
+ {
+ index = FindInStringVecCaseIgnore(masterViews, orderedViews[0]);
+ }
+ }
+ else if(!getImpl()->activeViews_.empty())
+ {
+ StringVec orderedViews = IntersectStringVecsCaseIgnore(getImpl()->activeViews_,
+ masterViews);
+ if(!orderedViews.empty())
+ {
+ index = FindInStringVecCaseIgnore(masterViews, orderedViews[0]);
+ }
+ }
+
+ if(index >= 0)
+ {
+ return views[index].name.c_str();
+ }
+
+ if(!views.empty())
+ {
+ return views[0].name.c_str();
+ }
+
+ return "";
+ }
+
+ int Config::getNumViews(const char * display) const
+ {
+ if(getImpl()->displayCache_.empty())
+ {
+ ComputeDisplays(getImpl()->displayCache_,
+ getImpl()->displays_,
+ getImpl()->activeDisplays_,
+ getImpl()->activeDisplaysEnvOverride_);
+ }
+
+ if(!display) return 0;
+
+ DisplayMap::const_iterator iter = find_display_const(getImpl()->displays_, display);
+ if(iter == getImpl()->displays_.end()) return 0;
+
+ const ViewVec & views = iter->second;
+ return static_cast<int>(views.size());
+ }
+
+ const char * Config::getView(const char * display, int index) const
+ {
+ if(getImpl()->displayCache_.empty())
+ {
+ ComputeDisplays(getImpl()->displayCache_,
+ getImpl()->displays_,
+ getImpl()->activeDisplays_,
+ getImpl()->activeDisplaysEnvOverride_);
+ }
+
+ if(!display) return "";
+
+ DisplayMap::const_iterator iter = find_display_const(getImpl()->displays_, display);
+ if(iter == getImpl()->displays_.end()) return "";
+
+ const ViewVec & views = iter->second;
+ return views[index].name.c_str();
+ }
+
+ const char * Config::getDisplayColorSpaceName(const char * display, const char * view) const
+ {
+ if(!display || !view) return "";
+
+ DisplayMap::const_iterator iter = find_display_const(getImpl()->displays_, display);
+ if(iter == getImpl()->displays_.end()) return "";
+
+ const ViewVec & views = iter->second;
+ int index = find_view(views, view);
+ if(index<0) return "";
+
+ return views[index].colorspace.c_str();
+ }
+
+ const char * Config::getDisplayLooks(const char * display, const char * view) const
+ {
+ if(!display || !view) return "";
+
+ DisplayMap::const_iterator iter = find_display_const(getImpl()->displays_, display);
+ if(iter == getImpl()->displays_.end()) return "";
+
+ const ViewVec & views = iter->second;
+ int index = find_view(views, view);
+ if(index<0) return "";
+
+ return views[index].looks.c_str();
+ }
+
+ void Config::addDisplay(const char * display, const char * view,
+ const char * colorSpaceName, const char * lookName)
+ {
+
+ if(!display || !view || !colorSpaceName || !lookName) return;
+
+ AddDisplay(getImpl()->displays_,
+ display, view, colorSpaceName, lookName);
+ getImpl()->displayCache_.clear();
+
+ AutoMutex lock(getImpl()->cacheidMutex_);
+ getImpl()->resetCacheIDs();
+ }
+
+ void Config::clearDisplays()
+ {
+ getImpl()->displays_.clear();
+ getImpl()->displayCache_.clear();
+
+ AutoMutex lock(getImpl()->cacheidMutex_);
+ getImpl()->resetCacheIDs();
+ }
+
+ void Config::setActiveDisplays(const char * displays)
+ {
+ getImpl()->activeDisplays_.clear();
+ SplitStringEnvStyle(getImpl()->activeDisplays_, displays);
+
+ getImpl()->displayCache_.clear();
+
+ AutoMutex lock(getImpl()->cacheidMutex_);
+ getImpl()->resetCacheIDs();
+ }
+
+ const char * Config::getActiveDisplays() const
+ {
+ getImpl()->activeDisplaysStr_ = JoinStringEnvStyle(getImpl()->activeDisplays_);
+ return getImpl()->activeDisplaysStr_.c_str();
+ }
+
+ void Config::setActiveViews(const char * views)
+ {
+ getImpl()->activeViews_.clear();
+ SplitStringEnvStyle(getImpl()->activeViews_, views);
+
+ getImpl()->displayCache_.clear();
+
+ AutoMutex lock(getImpl()->cacheidMutex_);
+ getImpl()->resetCacheIDs();
+ }
+
+ const char * Config::getActiveViews() const
+ {
+ getImpl()->activeViewsStr_ = JoinStringEnvStyle(getImpl()->activeViews_);
+ return getImpl()->activeViewsStr_.c_str();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ void Config::getDefaultLumaCoefs(float * c3) const
+ {
+ memcpy(c3, &getImpl()->defaultLumaCoefs_[0], 3*sizeof(float));
+ }
+
+ void Config::setDefaultLumaCoefs(const float * c3)
+ {
+ memcpy(&getImpl()->defaultLumaCoefs_[0], c3, 3*sizeof(float));
+
+ AutoMutex lock(getImpl()->cacheidMutex_);
+ getImpl()->resetCacheIDs();
+ }
+
+
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+
+
+ ConstLookRcPtr Config::getLook(const char * name) const
+ {
+ std::string namelower = pystring::lower(name);
+
+ for(unsigned int i=0; i<getImpl()->looksList_.size(); ++i)
+ {
+ if(pystring::lower(getImpl()->looksList_[i]->getName()) == namelower)
+ {
+ return getImpl()->looksList_[i];
+ }
+ }
+
+ return ConstLookRcPtr();
+ }
+
+ int Config::getNumLooks() const
+ {
+ return static_cast<int>(getImpl()->looksList_.size());
+ }
+
+ const char * Config::getLookNameByIndex(int index) const
+ {
+ if(index<0 || index>=static_cast<int>(getImpl()->looksList_.size()))
+ {
+ return "";
+ }
+
+ return getImpl()->looksList_[index]->getName();
+ }
+
+ void Config::addLook(const ConstLookRcPtr & look)
+ {
+ std::string name = look->getName();
+ if(name.empty())
+ throw Exception("Cannot addLook with an empty name.");
+
+ std::string namelower = pystring::lower(name);
+
+ // If the look exists, replace it
+ for(unsigned int i=0; i<getImpl()->looksList_.size(); ++i)
+ {
+ if(pystring::lower(getImpl()->looksList_[i]->getName()) == namelower)
+ {
+ getImpl()->looksList_[i] = look->createEditableCopy();
+ return;
+ }
+ }
+
+ // Otherwise, add it
+ getImpl()->looksList_.push_back(look->createEditableCopy());
+
+ AutoMutex lock(getImpl()->cacheidMutex_);
+ getImpl()->resetCacheIDs();
+ }
+
+ void Config::clearLooks()
+ {
+ getImpl()->looksList_.clear();
+
+ AutoMutex lock(getImpl()->cacheidMutex_);
+ getImpl()->resetCacheIDs();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+
+ ConstProcessorRcPtr Config::getProcessor(const ConstColorSpaceRcPtr & src,
+ const ConstColorSpaceRcPtr & dst) const
+ {
+ ConstContextRcPtr context = getCurrentContext();
+ return getProcessor(context, src, dst);
+ }
+
+ ConstProcessorRcPtr Config::getProcessor(const ConstContextRcPtr & context,
+ const ConstColorSpaceRcPtr & src,
+ const ConstColorSpaceRcPtr & dst) const
+ {
+ if(!src)
+ {
+ throw Exception("Config::GetProcessor failed. Source colorspace is null.");
+ }
+ if(!dst)
+ {
+ throw Exception("Config::GetProcessor failed. Destination colorspace is null.");
+ }
+
+ ProcessorRcPtr processor = Processor::Create();
+ processor->getImpl()->addColorSpaceConversion(*this, context, src, dst);
+ processor->getImpl()->finalize();
+ return processor;
+ }
+
+ ConstProcessorRcPtr Config::getProcessor(const char * srcName,
+ const char * dstName) const
+ {
+ ConstContextRcPtr context = getCurrentContext();
+ return getProcessor(context, srcName, dstName);
+ }
+
+ //! Names can be colorspace name or role name
+ ConstProcessorRcPtr Config::getProcessor(const ConstContextRcPtr & context,
+ const char * srcName,
+ const char * dstName) const
+ {
+ ConstColorSpaceRcPtr src = getColorSpace(srcName);
+ if(!src)
+ {
+ std::ostringstream os;
+ os << "Could not find colorspace '" << srcName << "'.";
+ throw Exception(os.str().c_str());
+ }
+
+ ConstColorSpaceRcPtr dst = getColorSpace(dstName);
+ if(!dst)
+ {
+ std::ostringstream os;
+ os << "Could not find colorspace '" << dstName << "'.";
+ throw Exception(os.str().c_str());
+ }
+
+ return getProcessor(context, src, dst);
+ }
+
+
+ ConstProcessorRcPtr Config::getProcessor(const ConstTransformRcPtr& transform) const
+ {
+ return getProcessor(transform, TRANSFORM_DIR_FORWARD);
+ }
+
+
+ ConstProcessorRcPtr Config::getProcessor(const ConstTransformRcPtr& transform,
+ TransformDirection direction) const
+ {
+ ConstContextRcPtr context = getCurrentContext();
+ return getProcessor(context, transform, direction);
+ }
+
+ ConstProcessorRcPtr Config::getProcessor(const ConstContextRcPtr & context,
+ const ConstTransformRcPtr& transform,
+ TransformDirection direction) const
+ {
+ ProcessorRcPtr processor = Processor::Create();
+ processor->getImpl()->addTransform(*this, context, transform, direction);
+ processor->getImpl()->finalize();
+ return processor;
+ }
+
+ std::ostream& operator<< (std::ostream& os, const Config& config)
+ {
+ config.serialize(os);
+ return os;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // CacheID
+
+ const char * Config::getCacheID() const
+ {
+ return getCacheID(getCurrentContext());
+ }
+
+ const char * Config::getCacheID(const ConstContextRcPtr & context) const
+ {
+ AutoMutex lock(getImpl()->cacheidMutex_);
+
+ // A null context will use the empty cacheid
+ std::string contextcacheid = "";
+ if(context) contextcacheid = context->getCacheID();
+
+ StringMap::const_iterator cacheiditer = getImpl()->cacheids_.find(contextcacheid);
+ if(cacheiditer != getImpl()->cacheids_.end())
+ {
+ return cacheiditer->second.c_str();
+ }
+
+ // Include the hash of the yaml config serialization
+ if(getImpl()->cacheidnocontext_.empty())
+ {
+ std::stringstream cacheid;
+ serialize(cacheid);
+ std::string fullstr = cacheid.str();
+ getImpl()->cacheidnocontext_ = CacheIDHash(fullstr.c_str(), (int)fullstr.size());
+ }
+
+ // Also include all file references, using the context (if specified)
+ std::string fileReferencesFashHash = "";
+ if(context)
+ {
+ std::ostringstream filehash;
+
+ ConstTransformVec allTransforms;
+ getImpl()->getAllIntenalTransforms(allTransforms);
+
+ std::set<std::string> files;
+ for(unsigned int i=0; i<allTransforms.size(); ++i)
+ {
+ GetFileReferences(files, allTransforms[i]);
+ }
+
+ for(std::set<std::string>::iterator iter = files.begin();
+ iter != files.end(); ++iter)
+ {
+ if(iter->empty()) continue;
+ filehash << *iter << "=";
+
+ try
+ {
+ std::string resolvedLocation = context->resolveFileLocation(iter->c_str());
+ filehash << GetFastFileHash(resolvedLocation) << " ";
+ }
+ catch(...)
+ {
+ filehash << "? ";
+ continue;
+ }
+ }
+
+ std::string fullstr = filehash.str();
+ fileReferencesFashHash = CacheIDHash(fullstr.c_str(), (int)fullstr.size());
+ }
+
+ getImpl()->cacheids_[contextcacheid] = getImpl()->cacheidnocontext_ + ":" + fileReferencesFashHash;
+ return getImpl()->cacheids_[contextcacheid].c_str();
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Serialization
+
+ void Config::serialize(std::ostream& os) const
+ {
+ try
+ {
+ YAML::Emitter out;
+ out << YAML::Block;
+ out << YAML::BeginMap;
+ out << YAML::Key << "ocio_profile_version" << YAML::Value << 1;
+ out << YAML::Newline;
+
+ out << YAML::Key << "search_path" << YAML::Value << getImpl()->context_->getSearchPath();
+ out << YAML::Key << "strictparsing" << YAML::Value << getImpl()->strictParsing_;
+ out << YAML::Key << "luma" << YAML::Value << YAML::Flow << getImpl()->defaultLumaCoefs_;
+
+ if(getImpl()->description_ != "")
+ {
+ out << YAML::Newline;
+ out << YAML::Key << "description";
+ out << YAML::Value << getImpl()->description_;
+ }
+
+ // Roles
+ out << YAML::Newline;
+ out << YAML::Key << "roles";
+ out << YAML::Value << getImpl()->roles_;
+
+ // Displays
+ out << YAML::Newline;
+ out << YAML::Key << "displays";
+ out << YAML::Value << getImpl()->displays_;
+ out << YAML::Newline;
+ out << YAML::Key << "active_displays";
+ out << YAML::Value << YAML::Flow << getImpl()->activeDisplays_;
+ out << YAML::Key << "active_views";
+ out << YAML::Value << YAML::Flow << getImpl()->activeViews_;
+
+ // Looks
+ if(!getImpl()->looksList_.empty())
+ {
+ out << YAML::Newline;
+ out << YAML::Key << "looks";
+ out << YAML::Value << getImpl()->looksList_;
+ }
+
+ // ColorSpaces
+ {
+ out << YAML::Newline;
+ out << YAML::Key << "colorspaces";
+ out << YAML::Value << getImpl()->colorspaces_;
+ }
+
+ out << YAML::EndMap;
+
+ os << out.c_str();
+ }
+ catch( const std::exception & e)
+ {
+ std::ostringstream error;
+ error << "Error building YAML: " << e.what();
+ throw Exception(error.str().c_str());
+ }
+ }
+
+ void Config::Impl::load(std::istream & istream, const char * filename)
+ {
+ try
+ {
+ YAML::Parser parser(istream);
+ YAML::Node node;
+ parser.GetNextDocument(node);
+
+ // check profile version
+ int profile_version = 0;
+ if(node.FindValue("ocio_profile_version") == NULL)
+ {
+ std::ostringstream os;
+ os << "The specified file ";
+ os << "does not appear to be an OCIO configuration.";
+ throw Exception (os.str().c_str());
+ }
+
+ node["ocio_profile_version"] >> profile_version;
+ if(profile_version > 1)
+ {
+ std::ostringstream os;
+ os << "This .ocio config ";
+ if(filename && *filename)
+ {
+ os << " '" << filename << "' ";
+ }
+ os << "is version " << profile_version << ". ";
+ os << "This version of the OpenColorIO library (" << OCIO_VERSION ") ";
+ os << "is not known to be able to load this profile. ";
+ os << "An attempt will be made, but there are no guarantees that the ";
+ os << "results will be accurate. Continue at your own risk.";
+ LogWarning(os.str());
+ }
+
+
+ std::string key, stringval;
+ bool boolval = false;
+
+ for (YAML::Iterator iter = node.begin();
+ iter != node.end();
+ ++iter)
+ {
+ iter.first() >> key;
+
+ if(key == "ocio_profile_version") { } // Already handled above.
+ else if(key == "search_path" || key == "resource_path")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ context_->setSearchPath(stringval.c_str());
+ }
+ else if(key == "strictparsing")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<bool>(boolval))
+ strictParsing_ = boolval;
+ }
+ else if(key == "description")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ description_ = stringval;
+ }
+ else if(key == "luma")
+ {
+ std::vector<float> val;
+ if (iter.second().Type() != YAML::NodeType::Null)
+ {
+ iter.second() >> val;
+ if(val.size() != 3)
+ {
+ std::ostringstream os;
+ os << "'luma' field must be 3 ";
+ os << "floats. Found '" << val.size() << "'.";
+ throw Exception(os.str().c_str());
+ }
+ defaultLumaCoefs_ = val;
+ }
+ }
+ else if(key == "roles")
+ {
+ const YAML::Node& roles = iter.second();
+ if(roles.Type() != YAML::NodeType::Map)
+ {
+ std::ostringstream os;
+ os << "'roles' field needs to be a (name: key) map.";
+ throw Exception(os.str().c_str());
+ }
+ for (YAML::Iterator it = roles.begin();
+ it != roles.end(); ++it)
+ {
+ std::string k, v;
+ it.first() >> k;
+ it.second() >> v;
+ roles_[pystring::lower(k)] = v;
+ }
+ }
+ else if(key == "displays")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null)
+ {
+ iter.second() >> displays_;
+ }
+ }
+ else if(key == "active_displays")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null)
+ {
+ iter.second() >> activeDisplays_;
+ }
+ }
+ else if(key == "active_views")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null)
+ {
+ iter.second() >> activeViews_;
+ }
+ }
+ else if(key == "colorspaces")
+ {
+ const YAML::Node& colorspaces = iter.second();
+
+ if(colorspaces.Type() != YAML::NodeType::Sequence)
+ {
+ std::ostringstream os;
+ os << "'colorspaces' field needs to be a (- !<ColorSpace>) list.";
+ throw Exception(os.str().c_str());
+ }
+
+ for(unsigned i = 0; i < colorspaces.size(); ++i)
+ {
+ if(colorspaces[i].Tag() == "ColorSpace")
+ {
+ ColorSpaceRcPtr cs = ColorSpace::Create();
+ colorspaces[i] >> cs;
+ colorspaces_.push_back( cs );
+ }
+ else
+ {
+ std::ostringstream os;
+ os << "Unknown element found in colorspaces:";
+ os << colorspaces[i].Tag() << ". Only ColorSpace(s)";
+ os << " currently handled.";
+ LogWarning(os.str());
+ }
+ }
+ }
+ else if(key == "looks")
+ {
+ const YAML::Node& looks = iter.second();
+
+ if(looks.Type() != YAML::NodeType::Sequence)
+ {
+ std::ostringstream os;
+ os << "'looks' field needs to be a (- !<Look>) list.";
+ throw Exception(os.str().c_str());
+ }
+
+ for(unsigned i = 0; i < looks.size(); ++i)
+ {
+ if(looks[i].Tag() == "Look")
+ {
+ LookRcPtr look = Look::Create();
+ looks[i] >> look;
+ looksList_.push_back( look );
+ }
+ else
+ {
+ std::ostringstream os;
+ os << "Unknown element found in looks:";
+ os << looks[i].Tag() << ". Only Look(s)";
+ os << " currently handled.";
+ LogWarning(os.str());
+ }
+ }
+ }
+ else
+ {
+ LogUnknownKeyWarning("profile", iter.first());
+ }
+ }
+
+ if(filename)
+ {
+ std::string realfilename = pystring::os::path::abspath(filename);
+ std::string configrootdir = pystring::os::path::dirname(realfilename);
+ context_->setWorkingDir(configrootdir.c_str());
+ }
+ }
+ catch( const std::exception & e)
+ {
+ std::ostringstream os;
+ os << "Error: Loading the OCIO profile ";
+ if(filename) os << "'" << filename << "' ";
+ os << "failed. " << e.what();
+ throw Exception(os.str().c_str());
+ }
+ }
+
+ void Config::Impl::resetCacheIDs()
+ {
+ cacheids_.clear();
+ cacheidnocontext_ = "";
+ sanity_ = SANITY_UNKNOWN;
+ sanitytext_ = "";
+ }
+
+ void Config::Impl::getAllIntenalTransforms(ConstTransformVec & transformVec) const
+ {
+ // Grab all transforms from the ColorSpaces
+ for(unsigned int i=0; i<colorspaces_.size(); ++i)
+ {
+ if(colorspaces_[i]->getTransform(COLORSPACE_DIR_TO_REFERENCE))
+ transformVec.push_back(colorspaces_[i]->getTransform(COLORSPACE_DIR_TO_REFERENCE));
+ if(colorspaces_[i]->getTransform(COLORSPACE_DIR_FROM_REFERENCE))
+ transformVec.push_back(colorspaces_[i]->getTransform(COLORSPACE_DIR_FROM_REFERENCE));
+ }
+
+ // Grab all transforms from the Looks
+ for(unsigned int i=0; i<looksList_.size(); ++i)
+ {
+ if(looksList_[i]->getTransform())
+ transformVec.push_back(looksList_[i]->getTransform());
+ if(looksList_[i]->getInverseTransform())
+ transformVec.push_back(looksList_[i]->getInverseTransform());
+ }
+
+ }
+}
+OCIO_NAMESPACE_EXIT
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef OCIO_UNIT_TEST
+
+namespace OCIO = OCIO_NAMESPACE;
+#include "UnitTest.h"
+
+#include <sys/stat.h>
+#include "pystring/pystring.h"
+
+#if 0
+OIIO_ADD_TEST(Config, test_searchpath_filesystem)
+{
+
+ OCIO::EnvMap env = OCIO::GetEnvMap();
+ std::string OCIO_TEST_AREA("$OCIO_TEST_AREA");
+ EnvExpand(&OCIO_TEST_AREA, &env);
+
+ OCIO::ConfigRcPtr config = OCIO::Config::Create();
+
+ // basic get/set/expand
+ config->setSearchPath("."
+ ":$OCIO_TEST1"
+ ":/$OCIO_JOB/${OCIO_SEQ}/$OCIO_SHOT/ocio");
+
+ OIIO_CHECK_ASSERT(strcmp(config->getSearchPath(),
+ ".:$OCIO_TEST1:/$OCIO_JOB/${OCIO_SEQ}/$OCIO_SHOT/ocio") == 0);
+ OIIO_CHECK_ASSERT(strcmp(config->getSearchPath(true),
+ ".:foobar:/meatballs/cheesecake/mb-cc-001/ocio") == 0);
+
+ // find some files
+ config->setSearchPath(".."
+ ":$OCIO_TEST1"
+ ":${OCIO_TEST_AREA}/test_search/one"
+ ":$OCIO_TEST_AREA/test_search/two");
+
+ // setup for search test
+ std::string base_dir("$OCIO_TEST_AREA/test_search/");
+ EnvExpand(&base_dir, &env);
+ mkdir(base_dir.c_str(), 0777);
+
+ std::string one_dir("$OCIO_TEST_AREA/test_search/one/");
+ EnvExpand(&one_dir, &env);
+ mkdir(one_dir.c_str(), 0777);
+
+ std::string two_dir("$OCIO_TEST_AREA/test_search/two/");
+ EnvExpand(&two_dir, &env);
+ mkdir(two_dir.c_str(), 0777);
+
+ std::string lut1(one_dir+"somelut1.lut");
+ std::ofstream somelut1(lut1.c_str());
+ somelut1.close();
+
+ std::string lut2(two_dir+"somelut2.lut");
+ std::ofstream somelut2(lut2.c_str());
+ somelut2.close();
+
+ std::string lut3(two_dir+"somelut3.lut");
+ std::ofstream somelut3(lut3.c_str());
+ somelut3.close();
+
+ std::string lutdotdot(OCIO_TEST_AREA+"/lutdotdot.lut");
+ std::ofstream somelutdotdot(lutdotdot.c_str());
+ somelutdotdot.close();
+
+ // basic search test
+ OIIO_CHECK_ASSERT(strcmp(config->findFile("somelut1.lut"),
+ lut1.c_str()) == 0);
+ OIIO_CHECK_ASSERT(strcmp(config->findFile("somelut2.lut"),
+ lut2.c_str()) == 0);
+ OIIO_CHECK_ASSERT(strcmp(config->findFile("somelut3.lut"),
+ lut3.c_str()) == 0);
+ OIIO_CHECK_ASSERT(strcmp(config->findFile("lutdotdot.lut"),
+ lutdotdot.c_str()) == 0);
+
+}
+#endif
+
+OIIO_ADD_TEST(Config, InternalRawProfile)
+{
+ std::istringstream is;
+ is.str(OCIO::INTERNAL_RAW_PROFILE);
+ OIIO_CHECK_NO_THOW(OCIO::ConstConfigRcPtr config = OCIO::Config::CreateFromStream(is));
+}
+
+OIIO_ADD_TEST(Config, SimpleConfig)
+{
+
+ std::string SIMPLE_PROFILE =
+ "ocio_profile_version: 1\n"
+ "resource_path: luts\n"
+ "strictparsing: false\n"
+ "luma: [0.2126, 0.7152, 0.0722]\n"
+ "roles:\n"
+ " compositing_log: lgh\n"
+ " default: raw\n"
+ " scene_linear: lnh\n"
+ "displays:\n"
+ " sRGB:\n"
+ " - !<View> {name: Film1D, colorspace: vd8}\n"
+ " - !<View> {name: Log, colorspace: lg10}\n"
+ " - !<View> {name: Raw, colorspace: raw}\n"
+ "colorspaces:\n"
+ " - !<ColorSpace>\n"
+ " name: raw\n"
+ " family: raw\n"
+ " equalitygroup: \n"
+ " bitdepth: 32f\n"
+ " description: |\n"
+ " A raw color space. Conversions to and from this space are no-ops.\n"
+ " isdata: true\n"
+ " allocation: uniform\n"
+ " - !<ColorSpace>\n"
+ " name: lnh\n"
+ " family: ln\n"
+ " equalitygroup: \n"
+ " bitdepth: 16f\n"
+ " description: |\n"
+ " The show reference space. This is a sensor referred linear\n"
+ " representation of the scene with primaries that correspond to\n"
+ " scanned film. 0.18 in this space corresponds to a properly\n"
+ " exposed 18% grey card.\n"
+ " isdata: false\n"
+ " allocation: lg2\n"
+ " - !<ColorSpace>\n"
+ " name: loads_of_transforms\n"
+ " family: vd8\n"
+ " equalitygroup: \n"
+ " bitdepth: 8ui\n"
+ " description: 'how many transforms can we use?'\n"
+ " isdata: false\n"
+ " allocation: uniform\n"
+ " to_reference: !<GroupTransform>\n"
+ " direction: forward\n"
+ " children:\n"
+ " - !<FileTransform>\n"
+ " src: diffusemult.spimtx\n"
+ " interpolation: unknown\n"
+ " - !<ColorSpaceTransform>\n"
+ " src: vd8\n"
+ " dst: lnh\n"
+ " - !<ExponentTransform>\n"
+ " value: [2.2, 2.2, 2.2, 1]\n"
+ " - !<MatrixTransform>\n"
+ " matrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]\n"
+ " offset: [0, 0, 0, 0]\n"
+ " - !<CDLTransform>\n"
+ " slope: [1, 1, 1]\n"
+ " offset: [0, 0, 0]\n"
+ " power: [1, 1, 1]\n"
+ " saturation: 1\n"
+ "\n";
+
+ std::istringstream is;
+ is.str(SIMPLE_PROFILE);
+ OCIO::ConstConfigRcPtr config;
+ OIIO_CHECK_NO_THOW(config = OCIO::Config::CreateFromStream(is));
+}
+
+OIIO_ADD_TEST(Config, Roles)
+{
+
+ std::string SIMPLE_PROFILE =
+ "ocio_profile_version: 1\n"
+ "strictparsing: false\n"
+ "roles:\n"
+ " compositing_log: lgh\n"
+ " default: raw\n"
+ " scene_linear: lnh\n"
+ "colorspaces:\n"
+ " - !<ColorSpace>\n"
+ " name: raw\n"
+ " - !<ColorSpace>\n"
+ " name: lnh\n"
+ " - !<ColorSpace>\n"
+ " name: lgh\n"
+ "\n";
+
+ std::istringstream is;
+ is.str(SIMPLE_PROFILE);
+ OCIO::ConstConfigRcPtr config;
+ OIIO_CHECK_NO_THOW(config = OCIO::Config::CreateFromStream(is));
+
+ OIIO_CHECK_EQUAL(config->getNumRoles(), 3);
+
+ OIIO_CHECK_ASSERT(config->hasRole("compositing_log") == true);
+ OIIO_CHECK_ASSERT(config->hasRole("cheese") == false);
+ OIIO_CHECK_ASSERT(config->hasRole("") == false);
+
+ OIIO_CHECK_ASSERT(strcmp(config->getRoleName(2), "scene_linear") == 0);
+ OIIO_CHECK_ASSERT(strcmp(config->getRoleName(0), "compositing_log") == 0);
+ OIIO_CHECK_ASSERT(strcmp(config->getRoleName(1), "default") == 0);
+ OIIO_CHECK_ASSERT(strcmp(config->getRoleName(10), "") == 0);
+ OIIO_CHECK_ASSERT(strcmp(config->getRoleName(-4), "") == 0);
+
+}
+
+OIIO_ADD_TEST(Config, Serialize)
+{
+
+ OCIO::ConfigRcPtr config = OCIO::Config::Create();
+ {
+ OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create();
+ cs->setName("testing");
+ cs->setFamily("test");
+ OCIO::FileTransformRcPtr transform1 = \
+ OCIO::FileTransform::Create();
+ OCIO::GroupTransformRcPtr groupTransform = OCIO::GroupTransform::Create();
+ groupTransform->push_back(transform1);
+ cs->setTransform(groupTransform, OCIO::COLORSPACE_DIR_TO_REFERENCE);
+ config->addColorSpace(cs);
+ config->setRole( OCIO::ROLE_COMPOSITING_LOG, cs->getName() );
+ }
+ {
+ OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create();
+ cs->setName("testing2");
+ cs->setFamily("test");
+ OCIO::ExponentTransformRcPtr transform1 = \
+ OCIO::ExponentTransform::Create();
+ OCIO::GroupTransformRcPtr groupTransform = OCIO::GroupTransform::Create();
+ groupTransform->push_back(transform1);
+ cs->setTransform(groupTransform, OCIO::COLORSPACE_DIR_TO_REFERENCE);
+ config->addColorSpace(cs);
+ config->setRole( OCIO::ROLE_COMPOSITING_LOG, cs->getName() );
+ }
+
+ // for testing
+ //std::ofstream outfile("/tmp/test.ocio");
+ //config->serialize(outfile);
+ //outfile.close();
+
+ std::ostringstream os;
+ config->serialize(os);
+
+ std::string PROFILE_OUT =
+ "ocio_profile_version: 1\n"
+ "\n"
+ "search_path: \"\"\n"
+ "strictparsing: true\n"
+ "luma: [0.2126, 0.7152, 0.0722]\n"
+ "\n"
+ "roles:\n"
+ " compositing_log: testing2\n"
+ "\n"
+ "displays:\n"
+ " {}\n"
+ "\n"
+ "active_displays: []\n"
+ "active_views: []\n"
+ "\n"
+ "colorspaces:\n"
+ " - !<ColorSpace>\n"
+ " name: testing\n"
+ " family: test\n"
+ " equalitygroup: \"\"\n"
+ " bitdepth: unknown\n"
+ " isdata: false\n"
+ " allocation: uniform\n"
+ " to_reference: !<GroupTransform>\n"
+ " children:\n"
+ " - !<FileTransform> {src: \"\", interpolation: unknown}\n"
+ "\n"
+ " - !<ColorSpace>\n"
+ " name: testing2\n"
+ " family: test\n"
+ " equalitygroup: \"\"\n"
+ " bitdepth: unknown\n"
+ " isdata: false\n"
+ " allocation: uniform\n"
+ " to_reference: !<GroupTransform>\n"
+ " children:\n"
+ " - !<ExponentTransform> {value: [1, 1, 1, 1]}\n";
+
+ std::vector<std::string> osvec;
+ OCIO::pystring::splitlines(os.str(), osvec);
+ std::vector<std::string> PROFILE_OUTvec;
+ OCIO::pystring::splitlines(PROFILE_OUT, PROFILE_OUTvec);
+
+ OIIO_CHECK_EQUAL(osvec.size(), PROFILE_OUTvec.size());
+ for(unsigned int i = 0; i < PROFILE_OUTvec.size(); ++i)
+ OIIO_CHECK_EQUAL(osvec[i], PROFILE_OUTvec[i]);
+}
+
+
+OIIO_ADD_TEST(Config, SanityCheck)
+{
+ {
+ std::string SIMPLE_PROFILE =
+ "ocio_profile_version: 1\n"
+ "colorspaces:\n"
+ " - !<ColorSpace>\n"
+ " name: raw\n"
+ " - !<ColorSpace>\n"
+ " name: raw\n"
+ "strictparsing: false\n"
+ "roles:\n"
+ " default: raw\n"
+ "displays:\n"
+ " sRGB:\n"
+ " - !<View> {name: Raw, colorspace: raw}\n"
+ "\n";
+
+ std::istringstream is;
+ is.str(SIMPLE_PROFILE);
+ OCIO::ConstConfigRcPtr config;
+ OIIO_CHECK_NO_THOW(config = OCIO::Config::CreateFromStream(is));
+
+ OIIO_CHECK_THOW(config->sanityCheck(), OCIO::Exception);
+ }
+
+ {
+ std::string SIMPLE_PROFILE =
+ "ocio_profile_version: 1\n"
+ "colorspaces:\n"
+ " - !<ColorSpace>\n"
+ " name: raw\n"
+ "strictparsing: false\n"
+ "roles:\n"
+ " default: raw\n"
+ "displays:\n"
+ " sRGB:\n"
+ " - !<View> {name: Raw, colorspace: raw}\n"
+ "\n";
+
+ std::istringstream is;
+ is.str(SIMPLE_PROFILE);
+ OCIO::ConstConfigRcPtr config;
+ OIIO_CHECK_NO_THOW(config = OCIO::Config::CreateFromStream(is));
+
+ OIIO_CHECK_NO_THOW(config->sanityCheck());
+ }
+}
+
+
+#endif // OCIO_UNIT_TEST
diff --git a/src/core/Context.cpp b/src/core/Context.cpp
new file mode 100644
index 0000000..25d4ea7
--- /dev/null
+++ b/src/core/Context.cpp
@@ -0,0 +1,364 @@
+/*
+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 <map>
+#include <string>
+#include <iostream>
+#include <sstream>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "HashUtils.h"
+#include "Mutex.h"
+#include "PathUtils.h"
+#include "pystring/pystring.h"
+
+OCIO_NAMESPACE_ENTER
+{
+
+namespace
+{
+ typedef std::map< std::string, std::string> StringMap;
+
+ void GetAbsoluteSearchPaths(std::vector<std::string> & searchpaths,
+ const std::string & pathString,
+ const std::string & configRootDir);
+}
+
+ class Context::Impl
+ {
+ public:
+ std::string searchPath_;
+ std::string workingDir_;
+ EnvMap envMap_;
+
+ mutable std::string cacheID_;
+ mutable StringMap resultsCache_;
+ mutable Mutex resultsCacheMutex_;
+
+ Impl()
+ {
+ }
+
+ ~Impl()
+ {
+
+ }
+
+ Impl& operator= (const Impl & rhs)
+ {
+ AutoMutex lock1(resultsCacheMutex_);
+ AutoMutex lock2(rhs.resultsCacheMutex_);
+
+ searchPath_ = rhs.searchPath_;
+ workingDir_ = rhs.workingDir_;
+ envMap_ = rhs.envMap_;
+
+ resultsCache_ = rhs.resultsCache_;
+ cacheID_ = rhs.cacheID_;
+
+ return *this;
+ }
+ };
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ ContextRcPtr Context::Create()
+ {
+ return ContextRcPtr(new Context(), &deleter);
+ }
+
+ void Context::deleter(Context* c)
+ {
+ delete c;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+
+ Context::Context()
+ : m_impl(new Context::Impl)
+ {
+ }
+
+ Context::~Context()
+ {
+ delete m_impl;
+ m_impl = NULL;
+ }
+
+ ContextRcPtr Context::createEditableCopy() const
+ {
+ ContextRcPtr context = Context::Create();
+ *context->m_impl = *getImpl();
+ return context;
+ }
+
+ const char * Context::getCacheID() const
+ {
+ AutoMutex lock(getImpl()->resultsCacheMutex_);
+
+ if(getImpl()->cacheID_.empty())
+ {
+ std::ostringstream cacheid;
+ cacheid << "Search Path " << getImpl()->searchPath_ << " ";
+ cacheid << "Working Dir " << getImpl()->workingDir_ << " ";
+
+ for (EnvMap::const_iterator iter = getImpl()->envMap_.begin(),
+ end = getImpl()->envMap_.end();
+ iter != end; ++iter)
+ {
+ cacheid << iter->first << "=" << iter->second << " ";
+ }
+
+ std::string fullstr = cacheid.str();
+ getImpl()->cacheID_ = CacheIDHash(fullstr.c_str(), (int)fullstr.size());
+ }
+
+ return getImpl()->cacheID_.c_str();
+ }
+
+ void Context::setSearchPath(const char * path)
+ {
+ AutoMutex lock(getImpl()->resultsCacheMutex_);
+
+ getImpl()->searchPath_ = path;
+ getImpl()->resultsCache_.clear();
+ getImpl()->cacheID_ = "";
+ }
+
+ const char * Context::getSearchPath() const
+ {
+ return getImpl()->searchPath_.c_str();
+ }
+
+ void Context::setWorkingDir(const char * dirname)
+ {
+ AutoMutex lock(getImpl()->resultsCacheMutex_);
+
+ getImpl()->workingDir_ = dirname;
+ getImpl()->resultsCache_.clear();
+ getImpl()->cacheID_ = "";
+ }
+
+ const char * Context::getWorkingDir() const
+ {
+ return getImpl()->workingDir_.c_str();
+ }
+
+ void Context::loadEnvironment()
+ {
+ LoadEnvironment(getImpl()->envMap_);
+ }
+
+ void Context::setStringVar(const char * name, const char * value)
+ {
+ if(!name) return;
+
+ AutoMutex lock(getImpl()->resultsCacheMutex_);
+ getImpl()->resultsCache_.clear();
+ getImpl()->cacheID_ = "";
+
+ // Set the value if specified
+ if(value)
+ {
+ getImpl()->envMap_[name] = value;
+ }
+ // If a null value is specified, erase it
+ else
+ {
+ EnvMap::iterator iter = getImpl()->envMap_.find(name);
+ if(iter != getImpl()->envMap_.end())
+ {
+ getImpl()->envMap_.erase(iter);
+ }
+ }
+ }
+
+ const char * Context::getStringVar(const char * name) const
+ {
+ if(!name) return "";
+
+ EnvMap::const_iterator iter = getImpl()->envMap_.find(name);
+ if(iter != getImpl()->envMap_.end())
+ {
+ return iter->second.c_str();
+ }
+
+ return "";
+ }
+
+ int Context::getNumStringVars() const
+ {
+ return static_cast<int>(getImpl()->envMap_.size());
+ }
+
+ const char * Context::getStringVarNameByIndex(int index) const
+ {
+ if(index < 0 || index >= static_cast<int>(getImpl()->envMap_.size()))
+ return "";
+
+ EnvMap::const_iterator iter = getImpl()->envMap_.begin();
+ for(int count = 0; count<index; ++count) ++iter;
+
+ return iter->first.c_str();
+ }
+
+ const char * Context::resolveStringVar(const char * val) const
+ {
+ AutoMutex lock(getImpl()->resultsCacheMutex_);
+
+ if(!val || !*val)
+ {
+ return "";
+ }
+
+ StringMap::const_iterator iter = getImpl()->resultsCache_.find(val);
+ if(iter != getImpl()->resultsCache_.end())
+ {
+ return iter->second.c_str();
+ }
+
+
+ std::string resolvedval = EnvExpand(val, getImpl()->envMap_);
+
+ getImpl()->resultsCache_[val] = resolvedval;
+ return getImpl()->resultsCache_[val].c_str();
+ }
+
+
+
+ const char * Context::resolveFileLocation(const char * filename) const
+ {
+ AutoMutex lock(getImpl()->resultsCacheMutex_);
+
+ if(!filename || !*filename)
+ {
+ return "";
+ }
+
+ StringMap::const_iterator iter = getImpl()->resultsCache_.find(filename);
+ if(iter != getImpl()->resultsCache_.end())
+ {
+ return iter->second.c_str();
+ }
+
+ // Load an absolute file reference
+ if(pystring::os::path::isabs(filename))
+ {
+ std::string expandedfullpath = EnvExpand(filename, getImpl()->envMap_);
+ if(FileExists(expandedfullpath))
+ {
+ getImpl()->resultsCache_[filename] = expandedfullpath;
+ return getImpl()->resultsCache_[filename].c_str();
+ }
+
+ std::ostringstream errortext;
+ errortext << "The specified absolute file reference ";
+ errortext << "'" << expandedfullpath << "' could not be located. ";
+ throw Exception(errortext.str().c_str());
+ }
+
+ // Load a relative file reference
+ // Prep the search path vector
+ // TODO: Cache this prepped vector?
+ std::vector<std::string> searchpaths;
+ GetAbsoluteSearchPaths(searchpaths,
+ getImpl()->searchPath_,
+ getImpl()->workingDir_);
+
+ // Loop over each path, and try to find the file
+ std::ostringstream errortext;
+ errortext << "The specified file reference ";
+ errortext << " '" << filename << "' could not be located. ";
+ errortext << "The following attempts were made: ";
+
+ for (unsigned int i = 0; i < searchpaths.size(); ++i)
+ {
+ // Make an attempt to find the lut in one of the search paths
+ std::string fullpath = pystring::os::path::join(searchpaths[i], filename);
+ std::string expandedfullpath = EnvExpand(fullpath, getImpl()->envMap_);
+ if(FileExists(expandedfullpath))
+ {
+ getImpl()->resultsCache_[filename] = expandedfullpath;
+ return getImpl()->resultsCache_[filename].c_str();
+ }
+ if(i!=0) errortext << " : ";
+ errortext << expandedfullpath;
+ }
+
+ throw ExceptionMissingFile(errortext.str().c_str());
+ }
+
+ std::ostream& operator<< (std::ostream& os, const Context& context)
+ {
+ os << "Context:\n";
+ for(int i=0; i<context.getNumStringVars(); ++i)
+ {
+ const char * key = context.getStringVarNameByIndex(i);
+ os << key << "=" << context.getStringVar(key) << "\n";
+ }
+ return os;
+ }
+
+
+namespace
+{
+ void GetAbsoluteSearchPaths(std::vector<std::string> & searchpaths,
+ const std::string & pathString,
+ const std::string & workingDir)
+ {
+ if(pathString.empty())
+ {
+ searchpaths.push_back(workingDir);
+ return;
+ }
+
+ std::vector<std::string> parts;
+ pystring::split(pathString, parts, ":");
+
+ for (unsigned int i = 0; i < parts.size(); ++i)
+ {
+ // Remove trailing "/", and spaces
+ std::string dirname = pystring::rstrip(pystring::strip(parts[i]), "/");
+
+ if(!pystring::os::path::isabs(dirname))
+ {
+ dirname = pystring::os::path::join(workingDir, dirname);
+ }
+
+ searchpaths.push_back(pystring::os::path::normpath(dirname));
+ }
+ }
+}
+
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/DisplayTransform.cpp b/src/core/DisplayTransform.cpp
new file mode 100644
index 0000000..35216db
--- /dev/null
+++ b/src/core/DisplayTransform.cpp
@@ -0,0 +1,410 @@
+/*
+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 "OpBuilders.h"
+
+#include <cmath>
+#include <cstring>
+#include <iterator>
+
+OCIO_NAMESPACE_ENTER
+{
+ DisplayTransformRcPtr DisplayTransform::Create()
+ {
+ return DisplayTransformRcPtr(new DisplayTransform(), &deleter);
+ }
+
+ void DisplayTransform::deleter(DisplayTransform* t)
+ {
+ delete t;
+ }
+
+ class DisplayTransform::Impl
+ {
+ public:
+ TransformDirection dir_;
+ std::string inputColorSpaceName_;
+ TransformRcPtr linearCC_;
+ TransformRcPtr colorTimingCC_;
+ TransformRcPtr channelView_;
+ std::string display_;
+ std::string view_;
+ TransformRcPtr displayCC_;
+
+ std::string looksOverride_;
+ bool looksOverrideEnabled_;
+
+ Impl() :
+ dir_(TRANSFORM_DIR_FORWARD),
+ looksOverrideEnabled_(false)
+ { }
+
+ ~Impl()
+ { }
+
+ Impl& operator= (const Impl & rhs)
+ {
+ dir_ = rhs.dir_;
+ inputColorSpaceName_ = rhs.inputColorSpaceName_;
+
+ linearCC_ = rhs.linearCC_;
+ if(linearCC_) linearCC_ = linearCC_->createEditableCopy();
+
+ colorTimingCC_ = rhs.colorTimingCC_;
+ if(colorTimingCC_) colorTimingCC_ = colorTimingCC_->createEditableCopy();
+
+ channelView_ = rhs.channelView_;
+ if(channelView_) channelView_ = channelView_->createEditableCopy();
+
+ display_ = rhs.display_;
+ view_ = rhs.view_;
+
+ displayCC_ = rhs.displayCC_;
+ if(displayCC_) displayCC_ = displayCC_->createEditableCopy();
+
+ looksOverride_ = rhs.looksOverride_;
+ looksOverrideEnabled_ = rhs.looksOverrideEnabled_;
+
+ return *this;
+ }
+ };
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+
+ DisplayTransform::DisplayTransform()
+ : m_impl(new DisplayTransform::Impl)
+ {
+ }
+
+ TransformRcPtr DisplayTransform::createEditableCopy() const
+ {
+ DisplayTransformRcPtr transform = DisplayTransform::Create();
+ *(transform->m_impl) = *m_impl;
+ return transform;
+ }
+
+ DisplayTransform::~DisplayTransform()
+ {
+ delete m_impl;
+ m_impl = NULL;
+ }
+
+ DisplayTransform& DisplayTransform::operator= (const DisplayTransform & rhs)
+ {
+ *m_impl = *rhs.m_impl;
+ return *this;
+ }
+
+ TransformDirection DisplayTransform::getDirection() const
+ {
+ return getImpl()->dir_;
+ }
+
+ void DisplayTransform::setDirection(TransformDirection dir)
+ {
+ getImpl()->dir_ = dir;
+ }
+
+ void DisplayTransform::setInputColorSpaceName(const char * name)
+ {
+ getImpl()->inputColorSpaceName_ = name;
+ }
+
+ const char * DisplayTransform::getInputColorSpaceName() const
+ {
+ return getImpl()->inputColorSpaceName_.c_str();
+ }
+
+ void DisplayTransform::setLinearCC(const ConstTransformRcPtr & cc)
+ {
+ getImpl()->linearCC_ = cc->createEditableCopy();
+ }
+
+ ConstTransformRcPtr DisplayTransform::getLinearCC() const
+ {
+ return getImpl()->linearCC_;
+ }
+
+ void DisplayTransform::setColorTimingCC(const ConstTransformRcPtr & cc)
+ {
+ getImpl()->colorTimingCC_ = cc->createEditableCopy();
+ }
+
+ ConstTransformRcPtr DisplayTransform::getColorTimingCC() const
+ {
+ return getImpl()->colorTimingCC_;
+ }
+
+ void DisplayTransform::setChannelView(const ConstTransformRcPtr & transform)
+ {
+ getImpl()->channelView_ = transform->createEditableCopy();
+ }
+
+ ConstTransformRcPtr DisplayTransform::getChannelView() const
+ {
+ return getImpl()->channelView_;
+ }
+
+ void DisplayTransform::setDisplay(const char * display)
+ {
+ getImpl()->display_ = display;
+ }
+
+ const char * DisplayTransform::getDisplay() const
+ {
+ return getImpl()->display_.c_str();
+ }
+
+ void DisplayTransform::setView(const char * view)
+ {
+ getImpl()->view_ = view;
+ }
+
+ const char * DisplayTransform::getView() const
+ {
+ return getImpl()->view_.c_str();
+ }
+
+ void DisplayTransform::setDisplayCC(const ConstTransformRcPtr & cc)
+ {
+ getImpl()->displayCC_ = cc->createEditableCopy();
+ }
+
+ ConstTransformRcPtr DisplayTransform::getDisplayCC() const
+ {
+ return getImpl()->displayCC_;
+ }
+
+ void DisplayTransform::setLooksOverride(const char * looks)
+ {
+ getImpl()->looksOverride_ = looks;
+ }
+
+ const char * DisplayTransform::getLooksOverride() const
+ {
+ return getImpl()->looksOverride_.c_str();
+ }
+
+ void DisplayTransform::setLooksOverrideEnabled(bool enabled)
+ {
+ getImpl()->looksOverrideEnabled_ = enabled;
+ }
+
+ bool DisplayTransform::getLooksOverrideEnabled() const
+ {
+ return getImpl()->looksOverrideEnabled_;
+ }
+
+ std::ostream& operator<< (std::ostream& os, const DisplayTransform& t)
+ {
+ os << "<DisplayTransform ";
+ os << "direction=" << TransformDirectionToString(t.getDirection()) << ", ";
+ os << "inputColorSpace=" << t.getInputColorSpaceName() << ", ";
+ os << "display=" << t.getDisplay() << ", ";
+ os << "view=" << t.getView() << ", ";
+ os << ">\n";
+ return os;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+
+ void BuildDisplayOps(OpRcPtrVec & ops,
+ const Config & config,
+ const ConstContextRcPtr & context,
+ const DisplayTransform & displayTransform,
+ TransformDirection dir)
+ {
+ TransformDirection combinedDir = CombineTransformDirections(dir,
+ displayTransform.getDirection());
+ if(combinedDir != TRANSFORM_DIR_FORWARD)
+ {
+ std::ostringstream os;
+ os << "DisplayTransform can only be applied in the forward direction.";
+ throw Exception(os.str().c_str());
+ }
+
+ std::string inputColorSpaceName = displayTransform.getInputColorSpaceName();
+ ConstColorSpaceRcPtr inputColorSpace = config.getColorSpace(inputColorSpaceName.c_str());
+ if(!inputColorSpace)
+ {
+ std::ostringstream os;
+ os << "DisplayTransform error.";
+ if(inputColorSpaceName.empty()) os << " InputColorSpaceName is unspecified.";
+ else os << " Cannot find inputColorSpace, named '" << inputColorSpaceName << "'.";
+ throw Exception(os.str().c_str());
+ }
+
+ std::string display = displayTransform.getDisplay();
+ std::string view = displayTransform.getView();
+
+ std::string displayColorSpaceName = config.getDisplayColorSpaceName(display.c_str(), view.c_str());
+ ConstColorSpaceRcPtr displayColorspace = config.getColorSpace(displayColorSpaceName.c_str());
+ if(!displayColorspace)
+ {
+ std::ostringstream os;
+ os << "DisplayTransform error.";
+ os << " Cannot find display colorspace, '" << displayColorSpaceName << "'.";
+ throw Exception(os.str().c_str());
+ }
+
+ bool skipColorSpaceConversions = (inputColorSpace->isData() || displayColorspace->isData());
+
+ // If we're viewing alpha, also skip all color space conversions.
+ // If the user does uses a different transform for the channel view,
+ // in place of a simple matrix, they run the risk that when viewing alpha
+ // the colorspace transforms will not be skipped. (I.e., filmlook will be applied
+ // to alpha.) If this ever becomes an issue, additional engineering will be
+ // added at that time.
+
+ ConstMatrixTransformRcPtr typedChannelView = DynamicPtrCast<const MatrixTransform>(
+ displayTransform.getChannelView());
+ if(typedChannelView)
+ {
+ float matrix44[16];
+ typedChannelView->getValue(matrix44, 0x0);
+
+ if((matrix44[3]>0.0f) || (matrix44[7]>0.0f) || (matrix44[11]>0.0f))
+ {
+ skipColorSpaceConversions = true;
+ }
+ }
+
+
+
+ ConstColorSpaceRcPtr currentColorSpace = inputColorSpace;
+
+
+
+ // Apply a transform in ROLE_SCENE_LINEAR
+ ConstTransformRcPtr linearCC = displayTransform.getLinearCC();
+ if(linearCC)
+ {
+ // 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;
+ BuildOps(tmpOps, config, context, linearCC, TRANSFORM_DIR_FORWARD);
+
+ if(!IsOpVecNoOp(tmpOps))
+ {
+ ConstColorSpaceRcPtr targetColorSpace = config.getColorSpace(ROLE_SCENE_LINEAR);
+
+ if(!skipColorSpaceConversions)
+ {
+ BuildColorSpaceOps(ops, config, context,
+ currentColorSpace,
+ targetColorSpace);
+ currentColorSpace = targetColorSpace;
+ }
+
+ std::copy(tmpOps.begin(), tmpOps.end(), std::back_inserter(ops));
+ }
+ }
+
+
+ // Apply a color correction, in ROLE_COLOR_TIMING
+ ConstTransformRcPtr colorTimingCC = displayTransform.getColorTimingCC();
+ if(colorTimingCC)
+ {
+ // 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;
+ BuildOps(tmpOps, config, context, colorTimingCC, TRANSFORM_DIR_FORWARD);
+
+ if(!IsOpVecNoOp(tmpOps))
+ {
+ ConstColorSpaceRcPtr targetColorSpace = config.getColorSpace(ROLE_COLOR_TIMING);
+
+ if(!skipColorSpaceConversions)
+ {
+ BuildColorSpaceOps(ops, config, context,
+ currentColorSpace,
+ targetColorSpace);
+ currentColorSpace = targetColorSpace;
+ }
+
+ std::copy(tmpOps.begin(), tmpOps.end(), std::back_inserter(ops));
+ }
+ }
+
+ // Apply a look, if specified
+ LookParseResult looks;
+ if(displayTransform.getLooksOverrideEnabled())
+ {
+ looks.parse(displayTransform.getLooksOverride());
+ }
+ else if(!skipColorSpaceConversions)
+ {
+ looks.parse(config.getDisplayLooks(display.c_str(), view.c_str()));
+ }
+
+ if(!looks.empty())
+ {
+ BuildLookOps(ops,
+ currentColorSpace,
+ skipColorSpaceConversions,
+ config,
+ context,
+ looks);
+ }
+
+ // Apply a channel view
+ ConstTransformRcPtr channelView = displayTransform.getChannelView();
+ if(channelView)
+ {
+ BuildOps(ops, config, context, channelView, TRANSFORM_DIR_FORWARD);
+ }
+
+
+ // Apply the conversion to the display color space
+ if(!skipColorSpaceConversions)
+ {
+ BuildColorSpaceOps(ops, config, context,
+ currentColorSpace,
+ displayColorspace);
+ currentColorSpace = displayColorspace;
+ }
+
+
+ // Apply a display cc
+ ConstTransformRcPtr displayCC = displayTransform.getDisplayCC();
+ if(displayCC)
+ {
+ BuildOps(ops, config, context, displayCC, TRANSFORM_DIR_FORWARD);
+ }
+
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/Exception.cpp b/src/core/Exception.cpp
new file mode 100644
index 0000000..b3d514c
--- /dev/null
+++ b/src/core/Exception.cpp
@@ -0,0 +1,74 @@
+/*
+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>
+
+OCIO_NAMESPACE_ENTER
+{
+
+ Exception::Exception(const char * msg) throw()
+ : std::exception(),
+ msg_(msg)
+ {}
+
+ Exception::Exception(const Exception& e) throw()
+ : std::exception(),
+ msg_(e.msg_)
+ {}
+
+ //*** operator=
+ Exception& Exception::operator=(const Exception& e) throw()
+ {
+ msg_ = e.msg_;
+ return *this;
+ }
+
+ //*** ~Exception
+ Exception::~Exception() throw()
+ {
+ }
+
+ //*** what
+ const char* Exception::what() const throw()
+ {
+ return msg_.c_str();
+ }
+
+
+
+
+ ExceptionMissingFile::ExceptionMissingFile(const char * msg) throw()
+ : Exception(msg)
+ {}
+
+ ExceptionMissingFile::ExceptionMissingFile(const ExceptionMissingFile& e) throw()
+ : Exception(e)
+ {}
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/ExponentOps.cpp b/src/core/ExponentOps.cpp
new file mode 100644
index 0000000..56e34d4
--- /dev/null
+++ b/src/core/ExponentOps.cpp
@@ -0,0 +1,372 @@
+/*
+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 <cmath>
+#include <cstring>
+#include <sstream>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "ExponentOps.h"
+#include "GpuShaderUtils.h"
+#include "MathUtils.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ void ApplyClampExponent(float* rgbaBuffer, long numPixels,
+ const float* exp4)
+ {
+ for(long pixelIndex=0; pixelIndex<numPixels; ++pixelIndex)
+ {
+ rgbaBuffer[0] = powf( std::max(0.0f, rgbaBuffer[0]), exp4[0]);
+ rgbaBuffer[1] = powf( std::max(0.0f, rgbaBuffer[1]), exp4[1]);
+ rgbaBuffer[2] = powf( std::max(0.0f, rgbaBuffer[2]), exp4[2]);
+ rgbaBuffer[3] = powf( std::max(0.0f, rgbaBuffer[3]), exp4[3]);
+
+ rgbaBuffer += 4;
+ }
+ }
+
+ const int FLOAT_DECIMALS = 7;
+ }
+
+
+ namespace
+ {
+ class ExponentOp : public Op
+ {
+ public:
+ ExponentOp(const float * exp4,
+ TransformDirection direction);
+ virtual ~ExponentOp();
+
+ virtual OpRcPtr clone() const;
+
+ virtual std::string getInfo() const;
+ virtual std::string getCacheID() const;
+
+ virtual bool isNoOp() const;
+ virtual bool isSameType(const OpRcPtr & op) const;
+ virtual bool isInverse(const OpRcPtr & op) const;
+
+ virtual bool canCombineWith(const OpRcPtr & op) const;
+ virtual void combineWith(OpRcPtrVec & ops, const OpRcPtr & secondOp) const;
+
+ virtual bool hasChannelCrosstalk() const;
+ virtual void finalize();
+ virtual void apply(float* rgbaBuffer, long numPixels) const;
+
+ virtual bool supportsGpuShader() const;
+ virtual void writeGpuShader(std::ostream & shader,
+ const std::string & pixelName,
+ const GpuShaderDesc & shaderDesc) const;
+ private:
+ float m_exp4[4];
+
+ // Set in finalize
+ std::string m_cacheID;
+ };
+
+ typedef OCIO_SHARED_PTR<ExponentOp> ExponentOpRcPtr;
+
+
+ ExponentOp::ExponentOp(const float * exp4,
+ TransformDirection direction):
+ Op()
+ {
+ if(direction == TRANSFORM_DIR_UNKNOWN)
+ {
+ throw Exception("Cannot create ExponentOp with unspecified transform direction.");
+ }
+
+ if(direction == TRANSFORM_DIR_INVERSE)
+ {
+ for(int i=0; i<4; ++i)
+ {
+ if(!IsScalarEqualToZero(exp4[i]))
+ {
+ m_exp4[i] = 1.0f / exp4[i];
+ }
+ else
+ {
+ throw Exception("Cannot apply ExponentOp op, Cannot apply 0.0 exponent in the inverse.");
+ }
+ }
+ }
+ else
+ {
+ memcpy(m_exp4, exp4, 4*sizeof(float));
+ }
+ }
+
+ OpRcPtr ExponentOp::clone() const
+ {
+ OpRcPtr op = OpRcPtr(new ExponentOp(m_exp4, TRANSFORM_DIR_FORWARD));
+ return op;
+ }
+
+ ExponentOp::~ExponentOp()
+ { }
+
+ std::string ExponentOp::getInfo() const
+ {
+ return "<ExponentOp>";
+ }
+
+ std::string ExponentOp::getCacheID() const
+ {
+ return m_cacheID;
+ }
+
+ bool ExponentOp::isNoOp() const
+ {
+ return IsVecEqualToOne(m_exp4, 4);
+ }
+
+ bool ExponentOp::isSameType(const OpRcPtr & op) const
+ {
+ ExponentOpRcPtr typedRcPtr = DynamicPtrCast<ExponentOp>(op);
+ if(!typedRcPtr) return false;
+ return true;
+ }
+
+ bool ExponentOp::isInverse(const OpRcPtr & op) const
+ {
+ ExponentOpRcPtr typedRcPtr = DynamicPtrCast<ExponentOp>(op);
+ if(!typedRcPtr) return false;
+
+ float combined[4] = { m_exp4[0]*typedRcPtr->m_exp4[0],
+ m_exp4[1]*typedRcPtr->m_exp4[1],
+ m_exp4[2]*typedRcPtr->m_exp4[2],
+ m_exp4[3]*typedRcPtr->m_exp4[3] };
+
+ return IsVecEqualToOne(combined, 4);
+ }
+
+ bool ExponentOp::canCombineWith(const OpRcPtr & op) const
+ {
+ return isSameType(op);
+ }
+
+
+ void ExponentOp::combineWith(OpRcPtrVec & ops, const OpRcPtr & secondOp) const
+ {
+ ExponentOpRcPtr typedRcPtr = DynamicPtrCast<ExponentOp>(secondOp);
+ if(!typedRcPtr)
+ {
+ std::ostringstream os;
+ os << "ExponentOp can only be combined with other ";
+ os << "ExponentOps. secondOp:" << secondOp->getInfo();
+ throw Exception(os.str().c_str());
+ }
+
+ float combined[4] = { m_exp4[0]*typedRcPtr->m_exp4[0],
+ m_exp4[1]*typedRcPtr->m_exp4[1],
+ m_exp4[2]*typedRcPtr->m_exp4[2],
+ m_exp4[3]*typedRcPtr->m_exp4[3] };
+
+ CreateExponentOp(ops, combined, TRANSFORM_DIR_FORWARD);
+ }
+
+ bool ExponentOp::hasChannelCrosstalk() const
+ {
+ return false;
+ }
+
+ void ExponentOp::finalize()
+ {
+ // Create the cacheID
+ std::ostringstream cacheIDStream;
+ cacheIDStream << "<ExponentOp ";
+ cacheIDStream.precision(FLOAT_DECIMALS);
+ for(int i=0; i<4; ++i)
+ {
+ cacheIDStream << m_exp4[i] << " ";
+ }
+ cacheIDStream << ">";
+ m_cacheID = cacheIDStream.str();
+ }
+
+ void ExponentOp::apply(float* rgbaBuffer, long numPixels) const
+ {
+ if(!rgbaBuffer) return;
+
+ ApplyClampExponent(rgbaBuffer, numPixels, m_exp4);
+ }
+
+ bool ExponentOp::supportsGpuShader() const
+ {
+ return true;
+ }
+
+ void ExponentOp::writeGpuShader(std::ostream & shader,
+ const std::string & pixelName,
+ const GpuShaderDesc & shaderDesc) const
+ {
+ GpuLanguage lang = shaderDesc.getLanguage();
+ float zerovec[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+
+ shader << pixelName << " = pow(";
+ shader << "max(" << pixelName << ", " << GpuTextHalf4(zerovec, lang) << ")";
+ shader << ", " << GpuTextHalf4(m_exp4, lang) << ");\n";
+ }
+
+ } // Anon namespace
+
+
+
+ void CreateExponentOp(OpRcPtrVec & ops,
+ const float * exp4,
+ TransformDirection direction)
+ {
+ bool expIsIdentity = IsVecEqualToOne(exp4, 4);
+ if(expIsIdentity) return;
+
+ ops.push_back( ExponentOpRcPtr(new ExponentOp(exp4, direction)) );
+ }
+}
+OCIO_NAMESPACE_EXIT
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef OCIO_UNIT_TEST
+
+#include "UnitTest.h"
+
+OCIO_NAMESPACE_USING
+
+OIIO_ADD_TEST(ExponentOps, Value)
+{
+ float exp1[4] = { 1.2f, 1.3f, 1.4f, 1.5f };
+
+ OpRcPtrVec ops;
+ CreateExponentOp(ops, exp1, TRANSFORM_DIR_FORWARD);
+ CreateExponentOp(ops, exp1, TRANSFORM_DIR_INVERSE);
+ OIIO_CHECK_EQUAL(ops.size(), 2);
+
+ for(unsigned int i=0; i<ops.size(); ++i)
+ {
+ ops[i]->finalize();
+ }
+
+ float error = 1e-6f;
+
+ const float source[] = { 0.5f, 0.5f, 0.5f, 0.5f, };
+
+ const float result1[] = { 0.43527528164806206f, 0.40612619817811774f,
+ 0.37892914162759955f, 0.35355339059327379f };
+
+ float tmp[4];
+ memcpy(tmp, source, 4*sizeof(float));
+ ops[0]->apply(tmp, 1);
+
+ for(unsigned int i=0; i<4; ++i)
+ {
+ OIIO_CHECK_CLOSE(tmp[i], result1[i], error);
+ }
+
+ ops[1]->apply(tmp, 1);
+ for(unsigned int i=0; i<4; ++i)
+ {
+ OIIO_CHECK_CLOSE(tmp[i], source[i], error);
+ }
+}
+
+OIIO_ADD_TEST(ExponentOps, Inverse)
+{
+ float exp1[4] = { 2.0f, 1.02345f, 5.651321f, 0.12345678910f };
+ float exp2[4] = { 2.0f, 2.0f, 2.0f, 2.0f };
+
+ OpRcPtrVec ops;
+
+ CreateExponentOp(ops, exp1, TRANSFORM_DIR_FORWARD);
+ CreateExponentOp(ops, exp1, TRANSFORM_DIR_INVERSE);
+ CreateExponentOp(ops, exp2, TRANSFORM_DIR_FORWARD);
+ CreateExponentOp(ops, exp2, TRANSFORM_DIR_INVERSE);
+
+ OIIO_CHECK_EQUAL(ops.size(), 4);
+
+ OIIO_CHECK_ASSERT(ops[0]->isSameType(ops[1]));
+ OIIO_CHECK_ASSERT(ops[0]->isSameType(ops[2]));
+ OIIO_CHECK_ASSERT(ops[0]->isSameType(ops[3]->clone()));
+
+ OIIO_CHECK_EQUAL(ops[0]->isInverse(ops[0]), false);
+ OIIO_CHECK_EQUAL(ops[0]->isInverse(ops[1]), true);
+ OIIO_CHECK_EQUAL(ops[1]->isInverse(ops[0]), true);
+ OIIO_CHECK_EQUAL(ops[0]->isInverse(ops[2]), false);
+ OIIO_CHECK_EQUAL(ops[0]->isInverse(ops[3]), false);
+ OIIO_CHECK_EQUAL(ops[3]->isInverse(ops[0]), false);
+ OIIO_CHECK_EQUAL(ops[2]->isInverse(ops[3]), true);
+ OIIO_CHECK_EQUAL(ops[3]->isInverse(ops[2]), true);
+ OIIO_CHECK_EQUAL(ops[3]->isInverse(ops[3]), false);
+}
+
+OIIO_ADD_TEST(ExponentOps, Combining)
+{
+ float exp1[4] = { 2.0f, 2.0f, 2.0f, 1.0f };
+ float exp2[4] = { 1.2f, 1.2f, 1.2f, 1.0f };
+
+ OpRcPtrVec ops;
+ CreateExponentOp(ops, exp1, TRANSFORM_DIR_FORWARD);
+ CreateExponentOp(ops, exp2, TRANSFORM_DIR_FORWARD);
+ OIIO_CHECK_EQUAL(ops.size(), 2);
+
+ float error = 1e-6f;
+ const float source[] = { 0.5f, 0.5f, 0.5f, 0.5f, };
+ const float result[] = { 0.18946457081379978f, 0.18946457081379978f,
+ 0.18946457081379978f, 0.5f };
+
+ float tmp[4];
+ memcpy(tmp, source, 4*sizeof(float));
+ ops[0]->apply(tmp, 1);
+ ops[1]->apply(tmp, 1);
+
+ for(unsigned int i=0; i<4; ++i)
+ {
+ OIIO_CHECK_CLOSE(tmp[i], result[i], error);
+ }
+
+
+ OpRcPtrVec combined;
+ ops[0]->combineWith(combined, ops[1]);
+ OIIO_CHECK_EQUAL(combined.size(), 1);
+
+ float tmp2[4];
+ memcpy(tmp2, source, 4*sizeof(float));
+ combined[0]->apply(tmp2, 1);
+
+ for(unsigned int i=0; i<4; ++i)
+ {
+ OIIO_CHECK_CLOSE(tmp2[i], result[i], error);
+ }
+}
+
+#endif // OCIO_UNIT_TEST
diff --git a/src/core/ExponentOps.h b/src/core/ExponentOps.h
new file mode 100644
index 0000000..95dd1f6
--- /dev/null
+++ b/src/core/ExponentOps.h
@@ -0,0 +1,50 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_EXPONENTOP_H
+#define INCLUDED_OCIO_EXPONENTOP_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "Op.h"
+
+#include <vector>
+
+OCIO_NAMESPACE_ENTER
+{
+ // If the exponent is 1.0, this will return without clamping
+ // Otherwise, will be clamped between [0.0, inf]
+
+ void CreateExponentOp(OpRcPtrVec & ops,
+ const float * exponent4,
+ TransformDirection direction);
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/ExponentTransform.cpp b/src/core/ExponentTransform.cpp
new file mode 100644
index 0000000..7bc180f
--- /dev/null
+++ b/src/core/ExponentTransform.cpp
@@ -0,0 +1,151 @@
+/*
+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 <cstring>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "ExponentOps.h"
+#include "OpBuilders.h"
+
+
+OCIO_NAMESPACE_ENTER
+{
+ ExponentTransformRcPtr ExponentTransform::Create()
+ {
+ return ExponentTransformRcPtr(new ExponentTransform(), &deleter);
+ }
+
+ void ExponentTransform::deleter(ExponentTransform* t)
+ {
+ delete t;
+ }
+
+
+ class ExponentTransform::Impl
+ {
+ public:
+ TransformDirection dir_;
+ float value_[4];
+
+ Impl() :
+ dir_(TRANSFORM_DIR_FORWARD)
+ {
+ for(int i=0; i<4; ++i)
+ {
+ value_[i] = 1.0f;
+ }
+ }
+
+ ~Impl()
+ { }
+
+ Impl& operator= (const Impl & rhs)
+ {
+ dir_ = rhs.dir_;
+ memcpy(value_, rhs.value_, 4*sizeof(float));
+ return *this;
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+
+ ExponentTransform::ExponentTransform()
+ : m_impl(new ExponentTransform::Impl)
+ {
+ }
+
+ TransformRcPtr ExponentTransform::createEditableCopy() const
+ {
+ ExponentTransformRcPtr transform = ExponentTransform::Create();
+ *(transform->m_impl) = *m_impl;
+ return transform;
+ }
+
+ ExponentTransform::~ExponentTransform()
+ {
+ delete m_impl;
+ m_impl = NULL;
+ }
+
+ ExponentTransform& ExponentTransform::operator= (const ExponentTransform & rhs)
+ {
+ *m_impl = *rhs.m_impl;
+ return *this;
+ }
+
+ TransformDirection ExponentTransform::getDirection() const
+ {
+ return getImpl()->dir_;
+ }
+
+ void ExponentTransform::setDirection(TransformDirection dir)
+ {
+ getImpl()->dir_ = dir;
+ }
+
+ void ExponentTransform::setValue(const float * vec4)
+ {
+ if(vec4) memcpy(getImpl()->value_, vec4, 4*sizeof(float));
+ }
+
+ void ExponentTransform::getValue(float * vec4) const
+ {
+ if(vec4) memcpy(vec4, getImpl()->value_, 4*sizeof(float));
+ }
+
+ std::ostream& operator<< (std::ostream& os, const ExponentTransform& t)
+ {
+ os << "<ExponentTransform ";
+ os << "direction=" << TransformDirectionToString(t.getDirection()) << ", ";
+ os << ">\n";
+ return os;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ void BuildExponentOps(OpRcPtrVec & ops,
+ const Config& /*config*/,
+ const ExponentTransform & transform,
+ TransformDirection dir)
+ {
+ TransformDirection combinedDir = CombineTransformDirections(dir,
+ transform.getDirection());
+
+ float vec4[4];
+ transform.getValue(vec4);
+
+ CreateExponentOp(ops,
+ vec4,
+ combinedDir);
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/FileFormat3DL.cpp b/src/core/FileFormat3DL.cpp
new file mode 100644
index 0000000..9d7e131
--- /dev/null
+++ b/src/core/FileFormat3DL.cpp
@@ -0,0 +1,638 @@
+/*
+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 "FileTransform.h"
+#include "Lut1DOp.h"
+#include "Lut3DOp.h"
+#include "MathUtils.h"
+#include "ParseUtils.h"
+#include "pystring/pystring.h"
+
+#include <algorithm>
+#include <cmath>
+#include <cstdio>
+#include <sstream>
+
+/*
+// Discreet's Flame Lut Format
+// Use a loose interpretation of the format to allow other 3d luts that look
+// similar, but dont strictly adhere to the real definition.
+
+// If line starts with text or # skip it
+// If line is a bunch of ints (more than 3) , it's the 1d shaper lut
+
+// All remaining lines of size 3 int are data
+// cube size is determined from num entries
+// The bit depth of the shaper lut and the 3d lut need not be the same.
+
+Example 1, FLAME
+# Comment here
+0 64 128 192 256 320 384 448 512 576 640 704 768 832 896 960 1023
+
+0 0 0
+0 0 100
+0 0 200
+
+
+Example 2, LUSTRE
+#Tokens required by applications - do not edit
+3DMESH
+Mesh 4 12
+0 64 128 192 256 320 384 448 512 576 640 704 768 832 896 960 1023
+
+
+
+0 17 17
+0 0 88
+0 0 157
+9 101 197
+0 118 308
+...
+
+4092 4094 4094
+
+#Tokens required by applications - do not edit
+
+LUT8
+gamma 1.0
+
+In this example, the 3D LUT has an input bit depth of 4 bits and an output
+bit depth of 12 bits. You use the input value to calculate the RGB triplet
+to be 17*17*17 (where 17=(2 to the power of 4)+1, and 4 is the input bit
+depth). The first triplet is the output value at (0,0,0);(0,0,1);...;
+(0,0,16) r,g,b coordinates; the second triplet is the output value at
+(0,1,0);(0,1,1);...;(0,1,16) r,g,b coordinates; and so on. You use the output
+bit depth to set the output bit depth range (12 bits or 0-4095).
+NoteLustre supports an input and output depth of 16 bits for 3D LUTs; however,
+in the processing pipeline, the BLACK_LEVEL to WHITE_LEVEL range is only 14
+bits. This means that even if the 3D LUT is 16 bits, it is normalized to
+fit the BLACK_LEVEL to WHITE_LEVEL range of Lustre.
+In Lustre, 3D LUT files can contain grids of 17 cubed, 33 cubed, and 65 cubed;
+however, Lustre converts 17 cubed and 65 cubed grids to 33 cubed for internal
+processing on the output (for rendering and calibration), but not on the input
+3D LUT.
+*/
+
+
+OCIO_NAMESPACE_ENTER
+{
+ ////////////////////////////////////////////////////////////////
+
+ namespace
+ {
+ class LocalCachedFile : public CachedFile
+ {
+ public:
+ LocalCachedFile () :
+ has1D(false),
+ has3D(false)
+ {
+ lut1D = Lut1D::Create();
+ lut3D = Lut3D::Create();
+ };
+ ~LocalCachedFile() {};
+
+ bool has1D;
+ bool has3D;
+ Lut1DRcPtr lut1D;
+ Lut3DRcPtr lut3D;
+ };
+
+ typedef OCIO_SHARED_PTR<LocalCachedFile> LocalCachedFileRcPtr;
+
+
+
+ class LocalFileFormat : public FileFormat
+ {
+ public:
+
+ ~LocalFileFormat() {};
+
+ virtual void GetFormatInfo(FormatInfoVec & formatInfoVec) const;
+
+ virtual CachedFileRcPtr Read(std::istream & istream) const;
+
+ virtual void Write(const Baker & baker,
+ const std::string & formatName,
+ std::ostream & ostream) const;
+
+ virtual void BuildFileOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const;
+ };
+
+
+
+
+
+
+ // We use the maximum value found in the lut to infer
+ // the bit depth. While this is fugly. We dont believe
+ // there is a better way, looking at the file, to
+ // determine this.
+ //
+ // Note: We allow for 2x overshoot in the luts.
+ // As we dont allow for odd bit depths, this isnt a big deal.
+ // So sizes from 1/2 max - 2x max are valid
+ //
+ // FILE EXPECTED MAX CORRECTLY DECODED IF MAX IN THIS RANGE
+ // 8-bit 255 [0, 511]
+ // 10-bit 1023 [512, 2047]
+ // 12-bit 4095 [2048, 8191]
+ // 14-bit 16383 [8192, 32767]
+ // 16-bit 65535 [32768, 131071+]
+
+ int GetLikelyLutBitDepth(int testval)
+ {
+ const int MIN_BIT_DEPTH = 8;
+ const int MAX_BIT_DEPTH = 16;
+
+ if(testval < 0) return -1;
+
+ // Only test even bit depths
+ for(int bitDepth = MIN_BIT_DEPTH;
+ bitDepth <= MAX_BIT_DEPTH; bitDepth+=2)
+ {
+ int maxcode = static_cast<int>(pow(2.0,bitDepth));
+ int adjustedMax = maxcode * 2 - 1;
+ if(testval<=adjustedMax) return bitDepth;
+ }
+
+ return MAX_BIT_DEPTH;
+ }
+
+ int GetMaxValueFromIntegerBitDepth(int bitDepth)
+ {
+ return static_cast<int>( pow(2.0, bitDepth) ) - 1;
+ }
+
+ int GetClampedIntFromNormFloat(float val, float scale)
+ {
+ val = std::min(std::max(0.0f, val), 1.0f) * scale;
+ return static_cast<int>(roundf(val));
+ }
+
+ void LocalFileFormat::GetFormatInfo(FormatInfoVec & formatInfoVec) const
+ {
+ FormatInfo info;
+ info.name = "flame";
+ info.extension = "3dl";
+ info.capabilities = (FORMAT_CAPABILITY_READ | FORMAT_CAPABILITY_WRITE);
+ formatInfoVec.push_back(info);
+
+ FormatInfo info2 = info;
+ info2.name = "lustre";
+ formatInfoVec.push_back(info2);
+ }
+
+ // Try and load the format
+ // Raise an exception if it can't be loaded.
+
+ CachedFileRcPtr LocalFileFormat::Read(std::istream & istream) const
+ {
+ std::vector<int> rawshaper;
+ std::vector<int> raw3d;
+
+ // Parse the file 3d lut data to an int array
+ {
+ const int MAX_LINE_SIZE = 4096;
+ char lineBuffer[MAX_LINE_SIZE];
+
+ std::vector<std::string> lineParts;
+ std::vector<int> tmpData;
+
+ while(istream.good())
+ {
+ istream.getline(lineBuffer, MAX_LINE_SIZE);
+
+ // Strip and split the line
+ pystring::split(pystring::strip(lineBuffer), lineParts);
+
+ if(lineParts.empty()) continue;
+ if((lineParts.size() > 0) && pystring::startswith(lineParts[0],"#")) continue;
+
+ // If we havent found a list of ints, continue
+ if(!StringVecToIntVec(tmpData, lineParts)) continue;
+
+ // If we've found more than 3 ints, and dont have
+ // a shaper lut yet, we've got it!
+ if(tmpData.size()>3 && rawshaper.empty())
+ {
+ for(unsigned int i=0; i<tmpData.size(); ++i)
+ {
+ rawshaper.push_back(tmpData[i]);
+ }
+ }
+
+ // If we've found 3 ints, add it to our 3dlut.
+ if(tmpData.size() == 3)
+ {
+ raw3d.push_back(tmpData[0]);
+ raw3d.push_back(tmpData[1]);
+ raw3d.push_back(tmpData[2]);
+ }
+ }
+ }
+
+ if(raw3d.empty() && rawshaper.empty())
+ {
+ std::ostringstream os;
+ os << "Error parsing .3dl file.";
+ os << "Does not appear to contain a valid shaper lut or a 3D lut.";
+ throw Exception(os.str().c_str());
+ }
+
+ LocalCachedFileRcPtr cachedFile = LocalCachedFileRcPtr(new LocalCachedFile());
+
+ // If all we're doing to parse the format is to read in sets of 3 numbers,
+ // it's possible that other formats will accidentally be able to be read
+ // mistakenly as .3dl files. We can exclude a huge segement of these mis-reads
+ // by screening for files that use float represenations. I.e., if the MAX
+ // value of the lut is a small number (such as <128.0) it's likely not an integer
+ // format, and thus not a likely 3DL file.
+
+ const int FORMAT3DL_CODEVALUE_LOWEST_PLAUSIBLE_MAXINT = 128;
+
+ // Interpret the shaper lut
+ if(!rawshaper.empty())
+ {
+ cachedFile->has1D = true;
+
+ // Find the maximum shaper lut value to infer bit-depth
+ int shapermax = 0;
+ for(unsigned int i=0; i<rawshaper.size(); ++i)
+ {
+ shapermax = std::max(shapermax, rawshaper[i]);
+ }
+
+ if(shapermax<FORMAT3DL_CODEVALUE_LOWEST_PLAUSIBLE_MAXINT)
+ {
+ std::ostringstream os;
+ os << "Error parsing .3dl file.";
+ os << "The maximum shaper lut value, " << shapermax;
+ os << ", is unreasonably low. This lut is probably not a .3dl ";
+ os << "file, but instead a related format that shares a similar ";
+ os << "structure.";
+
+ throw Exception(os.str().c_str());
+ }
+
+ int shaperbitdepth = GetLikelyLutBitDepth(shapermax);
+ if(shaperbitdepth<0)
+ {
+ std::ostringstream os;
+ os << "Error parsing .3dl file.";
+ os << "The maximum shaper lut value, " << shapermax;
+ os << ", does not correspond to any likely bit depth. ";
+ os << "Please confirm source file is valid.";
+ throw Exception(os.str().c_str());
+ }
+
+ int bitdepthmax = GetMaxValueFromIntegerBitDepth(shaperbitdepth);
+ float scale = 1.0f / static_cast<float>(bitdepthmax);
+
+ for(int channel=0; channel<3; ++channel)
+ {
+ cachedFile->lut1D->luts[channel].resize(rawshaper.size());
+
+ for(unsigned int i=0; i<rawshaper.size(); ++i)
+ {
+ cachedFile->lut1D->luts[channel][i] = static_cast<float>(rawshaper[i])*scale;
+ }
+ }
+
+ // The error threshold will be 2 code values. This will allow
+ // shaper luts which use different int conversions (round vs. floor)
+ // to both be optimized.
+ // Required: Abs Tolerance
+
+ const int FORMAT3DL_SHAPER_CODEVALUE_TOLERANCE = 2;
+ cachedFile->lut1D->maxerror = FORMAT3DL_SHAPER_CODEVALUE_TOLERANCE*scale;
+ cachedFile->lut1D->errortype = ERROR_ABSOLUTE;
+ }
+
+
+
+ // Interpret the parsed data.
+ if(!raw3d.empty())
+ {
+ cachedFile->has3D = true;
+
+ // Find the maximum shaper lut value to infer bit-depth
+ int lut3dmax = 0;
+ for(unsigned int i=0; i<raw3d.size(); ++i)
+ {
+ lut3dmax = std::max(lut3dmax, raw3d[i]);
+ }
+
+ if(lut3dmax<FORMAT3DL_CODEVALUE_LOWEST_PLAUSIBLE_MAXINT)
+ {
+ std::ostringstream os;
+ os << "Error parsing .3dl file.";
+ os << "The maximum 3d lut value, " << lut3dmax;
+ os << ", is unreasonably low. This lut is probably not a .3dl ";
+ os << "file, but instead a related format that shares a similar ";
+ os << "structure.";
+
+ throw Exception(os.str().c_str());
+ }
+
+ int lut3dbitdepth = GetLikelyLutBitDepth(lut3dmax);
+ if(lut3dbitdepth<0)
+ {
+ std::ostringstream os;
+ os << "Error parsing .3dl file.";
+ os << "The maximum 3d lut value, " << lut3dmax;
+ os << ", does not correspond to any likely bit depth. ";
+ os << "Please confirm source file is valid.";
+ throw Exception(os.str().c_str());
+ }
+
+ int bitdepthmax = GetMaxValueFromIntegerBitDepth(lut3dbitdepth);
+ float scale = 1.0f / static_cast<float>(bitdepthmax);
+
+ // Interpret the int array as a 3dlut
+ int lutEdgeLen = Get3DLutEdgeLenFromNumPixels((int)raw3d.size()/3);
+
+ // Reformat 3D data
+ cachedFile->lut3D->size[0] = lutEdgeLen;
+ cachedFile->lut3D->size[1] = lutEdgeLen;
+ cachedFile->lut3D->size[2] = lutEdgeLen;
+ cachedFile->lut3D->lut.reserve(lutEdgeLen * lutEdgeLen * lutEdgeLen * 3);
+
+ for(int rIndex=0; rIndex<lutEdgeLen; ++rIndex)
+ {
+ for(int gIndex=0; gIndex<lutEdgeLen; ++gIndex)
+ {
+ for(int bIndex=0; bIndex<lutEdgeLen; ++bIndex)
+ {
+ int i = GetLut3DIndex_B(rIndex, gIndex, bIndex,
+ lutEdgeLen, lutEdgeLen, lutEdgeLen);
+
+ cachedFile->lut3D->lut.push_back(static_cast<float>(raw3d[i+0]) * scale);
+ cachedFile->lut3D->lut.push_back(static_cast<float>(raw3d[i+1]) * scale);
+ cachedFile->lut3D->lut.push_back(static_cast<float>(raw3d[i+2]) * scale);
+ }
+ }
+ }
+ }
+
+ return cachedFile;
+ }
+
+ // 65 -> 6
+ // 33 -> 5
+ // 17 -> 4
+
+ int CubeDimensionLenToLustreBitDepth(int size)
+ {
+ float logval = logf(static_cast<float>(size-1)) / logf(2.0);
+ return static_cast<int>(logval);
+ }
+
+ void LocalFileFormat::Write(const Baker & baker,
+ const std::string & formatName,
+ std::ostream & ostream) const
+ {
+ int DEFAULT_CUBE_SIZE = 0;
+ int SHAPER_BIT_DEPTH = 10;
+ int CUBE_BIT_DEPTH = 12;
+
+ if(formatName == "lustre")
+ {
+ DEFAULT_CUBE_SIZE = 33;
+ }
+ else if(formatName == "flame")
+ {
+ DEFAULT_CUBE_SIZE = 17;
+ }
+ else
+ {
+ std::ostringstream os;
+ os << "Unknown 3dl format name, '";
+ os << formatName << "'.";
+ throw Exception(os.str().c_str());
+ }
+
+ ConstConfigRcPtr config = baker.getConfig();
+
+ int cubeSize = baker.getCubeSize();
+ if(cubeSize==-1) cubeSize = DEFAULT_CUBE_SIZE;
+ cubeSize = std::max(2, cubeSize); // smallest cube is 2x2x2
+
+ int shaperSize = baker.getShaperSize();
+ if(shaperSize==-1) shaperSize = cubeSize;
+
+ std::vector<float> cubeData;
+ cubeData.resize(cubeSize*cubeSize*cubeSize*3);
+ GenerateIdentityLut3D(&cubeData[0], cubeSize, 3, LUT3DORDER_FAST_BLUE);
+ PackedImageDesc cubeImg(&cubeData[0], cubeSize*cubeSize*cubeSize, 1, 3);
+
+ // Apply our conversion from the input space to the output space.
+ ConstProcessorRcPtr inputToTarget;
+ std::string looks = baker.getLooks();
+ if (!looks.empty())
+ {
+ LookTransformRcPtr transform = LookTransform::Create();
+ transform->setLooks(looks.c_str());
+ transform->setSrc(baker.getInputSpace());
+ transform->setDst(baker.getTargetSpace());
+ inputToTarget = config->getProcessor(transform,
+ TRANSFORM_DIR_FORWARD);
+ }
+ else
+ {
+ inputToTarget = config->getProcessor(baker.getInputSpace(),
+ baker.getTargetSpace());
+ }
+ inputToTarget->apply(cubeImg);
+
+ // Write out the file.
+ // For for maximum compatibility with other apps, we will
+ // not utilize the shaper or output any metadata
+
+ if(formatName == "lustre")
+ {
+ int meshInputBitDepth = CubeDimensionLenToLustreBitDepth(cubeSize);
+ ostream << "3DMESH\n";
+ ostream << "Mesh " << meshInputBitDepth << " " << CUBE_BIT_DEPTH << "\n";
+ }
+
+ std::vector<float> shaperData(shaperSize);
+ GenerateIdentityLut1D(&shaperData[0], shaperSize, 1);
+
+ float shaperScale = static_cast<float>(
+ GetMaxValueFromIntegerBitDepth(SHAPER_BIT_DEPTH));
+
+ for(unsigned int i=0; i<shaperData.size(); ++i)
+ {
+ if(i != 0) ostream << " ";
+ int val = GetClampedIntFromNormFloat(shaperData[i], shaperScale);
+ ostream << val;
+ }
+ ostream << "\n";
+
+ // Write out the 3D Cube
+ float cubeScale = static_cast<float>(
+ GetMaxValueFromIntegerBitDepth(CUBE_BIT_DEPTH));
+ if(cubeSize < 2)
+ {
+ throw Exception("Internal cube size exception.");
+ }
+ for(int i=0; i<cubeSize*cubeSize*cubeSize; ++i)
+ {
+ int r = GetClampedIntFromNormFloat(cubeData[3*i+0], cubeScale);
+ int g = GetClampedIntFromNormFloat(cubeData[3*i+1], cubeScale);
+ int b = GetClampedIntFromNormFloat(cubeData[3*i+2], cubeScale);
+ ostream << r << " " << g << " " << b << "\n";
+ }
+ ostream << "\n";
+
+ if(formatName == "lustre")
+ {
+ ostream << "LUT8\n";
+ ostream << "gamma 1.0\n";
+ }
+ }
+
+ void
+ LocalFileFormat::BuildFileOps(OpRcPtrVec & ops,
+ const Config& /*config*/,
+ const ConstContextRcPtr & /*context*/,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const
+ {
+ LocalCachedFileRcPtr cachedFile = DynamicPtrCast<LocalCachedFile>(untypedCachedFile);
+
+ // This should never happen.
+ if(!cachedFile)
+ {
+ std::ostringstream os;
+ os << "Cannot build .3dl Op. Invalid cache type.";
+ throw Exception(os.str().c_str());
+ }
+
+ TransformDirection newDir = CombineTransformDirections(dir,
+ fileTransform.getDirection());
+ if(newDir == TRANSFORM_DIR_UNKNOWN)
+ {
+ std::ostringstream os;
+ os << "Cannot build file format transform,";
+ os << " unspecified transform direction.";
+ throw Exception(os.str().c_str());
+ }
+
+ // TODO: INTERP_LINEAR should not be hard-coded.
+ // Instead query 'highest' interpolation?
+ // (right now, it's linear). If cubic is added, consider
+ // using it
+
+ if(newDir == TRANSFORM_DIR_FORWARD)
+ {
+ if(cachedFile->has1D)
+ {
+ CreateLut1DOp(ops, cachedFile->lut1D,
+ INTERP_LINEAR, newDir);
+ }
+ if(cachedFile->has3D)
+ {
+ CreateLut3DOp(ops, cachedFile->lut3D,
+ fileTransform.getInterpolation(), newDir);
+ }
+ }
+ else if(newDir == TRANSFORM_DIR_INVERSE)
+ {
+ if(cachedFile->has3D)
+ {
+ CreateLut3DOp(ops, cachedFile->lut3D,
+ fileTransform.getInterpolation(), newDir);
+ }
+ if(cachedFile->has1D)
+ {
+ CreateLut1DOp(ops, cachedFile->lut1D,
+ INTERP_LINEAR, newDir);
+ }
+ }
+ }
+ }
+
+ FileFormat * CreateFileFormat3DL()
+ {
+ return new LocalFileFormat();
+ }
+}
+OCIO_NAMESPACE_EXIT
+
+#ifdef OCIO_UNIT_TEST
+
+namespace OCIO = OCIO_NAMESPACE;
+#include "UnitTest.h"
+
+// FILE EXPECTED MAX CORRECTLY DECODED IF MAX IN THIS RANGE
+// 8-bit 255 [0, 511]
+// 10-bit 1023 [512, 2047]
+// 12-bit 4095 [2048, 8191]
+// 14-bit 16383 [8192, 32767]
+// 16-bit 65535 [32768, 131071]
+
+OIIO_ADD_TEST(FileFormat3DL, GetLikelyLutBitDepth)
+{
+ OIIO_CHECK_EQUAL(OCIO::GetLikelyLutBitDepth(-1), -1);
+
+ OIIO_CHECK_EQUAL(OCIO::GetLikelyLutBitDepth(0), 8);
+ OIIO_CHECK_EQUAL(OCIO::GetLikelyLutBitDepth(1), 8);
+ OIIO_CHECK_EQUAL(OCIO::GetLikelyLutBitDepth(255), 8);
+ OIIO_CHECK_EQUAL(OCIO::GetLikelyLutBitDepth(256), 8);
+ OIIO_CHECK_EQUAL(OCIO::GetLikelyLutBitDepth(511), 8);
+
+ OIIO_CHECK_EQUAL(OCIO::GetLikelyLutBitDepth(512), 10);
+ OIIO_CHECK_EQUAL(OCIO::GetLikelyLutBitDepth(1023), 10);
+ OIIO_CHECK_EQUAL(OCIO::GetLikelyLutBitDepth(1024), 10);
+ OIIO_CHECK_EQUAL(OCIO::GetLikelyLutBitDepth(2047), 10);
+
+ OIIO_CHECK_EQUAL(OCIO::GetLikelyLutBitDepth(2048), 12);
+ OIIO_CHECK_EQUAL(OCIO::GetLikelyLutBitDepth(4095), 12);
+ OIIO_CHECK_EQUAL(OCIO::GetLikelyLutBitDepth(4096), 12);
+ OIIO_CHECK_EQUAL(OCIO::GetLikelyLutBitDepth(8191), 12);
+
+ OIIO_CHECK_EQUAL(OCIO::GetLikelyLutBitDepth(16383), 14);
+
+ OIIO_CHECK_EQUAL(OCIO::GetLikelyLutBitDepth(65535), 16);
+ OIIO_CHECK_EQUAL(OCIO::GetLikelyLutBitDepth(65536), 16);
+ OIIO_CHECK_EQUAL(OCIO::GetLikelyLutBitDepth(131071), 16);
+
+ OIIO_CHECK_EQUAL(OCIO::GetLikelyLutBitDepth(131072), 16);
+}
+
+#endif // OCIO_UNIT_TEST
diff --git a/src/core/FileFormatCC.cpp b/src/core/FileFormatCC.cpp
new file mode 100644
index 0000000..ade09a6
--- /dev/null
+++ b/src/core/FileFormatCC.cpp
@@ -0,0 +1,151 @@
+/*
+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 "FileTransform.h"
+#include "OpBuilders.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ ////////////////////////////////////////////////////////////////
+
+ namespace
+ {
+ class LocalCachedFile : public CachedFile
+ {
+ public:
+ LocalCachedFile ()
+ {
+ transform = CDLTransform::Create();
+ };
+
+ ~LocalCachedFile() {};
+
+ CDLTransformRcPtr transform;
+ };
+
+ typedef OCIO_SHARED_PTR<LocalCachedFile> LocalCachedFileRcPtr;
+
+
+
+ class LocalFileFormat : public FileFormat
+ {
+ public:
+
+ ~LocalFileFormat() {};
+
+ virtual void GetFormatInfo(FormatInfoVec & formatInfoVec) const;
+
+ virtual CachedFileRcPtr Read(std::istream & istream) const;
+
+ virtual void BuildFileOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const;
+ };
+
+ void LocalFileFormat::GetFormatInfo(FormatInfoVec & formatInfoVec) const
+ {
+ FormatInfo info;
+ info.name = "ColorCorrection";
+ info.extension = "cc";
+ info.capabilities = FORMAT_CAPABILITY_READ;
+ formatInfoVec.push_back(info);
+ }
+
+ // Try and load the format
+ // Raise an exception if it can't be loaded.
+
+ CachedFileRcPtr LocalFileFormat::Read(std::istream & istream) const
+ {
+ std::ostringstream rawdata;
+ rawdata << istream.rdbuf();
+
+ LocalCachedFileRcPtr cachedFile = LocalCachedFileRcPtr(new LocalCachedFile());
+
+ try
+ {
+ cachedFile->transform->setXML(rawdata.str().c_str());
+ }
+ catch(Exception & e)
+ {
+ std::ostringstream os;
+ os << "Error parsing .cc file. ";
+ os << "Does not appear to contain a valid ASC CDL XML:";
+ os << e.what();
+ throw Exception(os.str().c_str());
+ }
+
+ return cachedFile;
+ }
+
+ void
+ LocalFileFormat::BuildFileOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & /*context*/,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const
+ {
+ LocalCachedFileRcPtr cachedFile = DynamicPtrCast<LocalCachedFile>(untypedCachedFile);
+
+ // This should never happen.
+ if(!cachedFile)
+ {
+ std::ostringstream os;
+ os << "Cannot build .cc Op. Invalid cache type.";
+ throw Exception(os.str().c_str());
+ }
+
+ TransformDirection newDir = CombineTransformDirections(dir,
+ fileTransform.getDirection());
+ if(newDir == TRANSFORM_DIR_UNKNOWN)
+ {
+ std::ostringstream os;
+ os << "Cannot build file format transform,";
+ os << " unspecified transform direction.";
+ throw Exception(os.str().c_str());
+ }
+
+ BuildCDLOps(ops,
+ config,
+ *cachedFile->transform,
+ newDir);
+ }
+ }
+
+ FileFormat * CreateFileFormatCC()
+ {
+ return new LocalFileFormat();
+ }
+}
+OCIO_NAMESPACE_EXIT
+
diff --git a/src/core/FileFormatCCC.cpp b/src/core/FileFormatCCC.cpp
new file mode 100644
index 0000000..ec43803
--- /dev/null
+++ b/src/core/FileFormatCCC.cpp
@@ -0,0 +1,195 @@
+/*
+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 <map>
+#include <tinyxml.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "CDLTransform.h"
+#include "FileTransform.h"
+#include "OpBuilders.h"
+#include "pystring/pystring.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ ////////////////////////////////////////////////////////////////
+
+ namespace
+ {
+ typedef std::map<std::string,CDLTransformRcPtr> CDLMap;
+
+ class LocalCachedFile : public CachedFile
+ {
+ public:
+ LocalCachedFile () {};
+
+ ~LocalCachedFile() {};
+
+ CDLMap transforms;
+ };
+
+ typedef OCIO_SHARED_PTR<LocalCachedFile> LocalCachedFileRcPtr;
+ typedef OCIO_SHARED_PTR<TiXmlDocument> TiXmlDocumentRcPtr;
+
+
+
+ class LocalFileFormat : public FileFormat
+ {
+ public:
+
+ ~LocalFileFormat() {};
+
+ virtual void GetFormatInfo(FormatInfoVec & formatInfoVec) const;
+
+ virtual CachedFileRcPtr Read(std::istream & istream) const;
+
+ virtual void BuildFileOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const;
+ };
+
+ void LocalFileFormat::GetFormatInfo(FormatInfoVec & formatInfoVec) const
+ {
+ FormatInfo info;
+ info.name = "ColorCorrectionCollection";
+ info.extension = "ccc";
+ info.capabilities = FORMAT_CAPABILITY_READ;
+ formatInfoVec.push_back(info);
+ }
+
+ // Try and load the format
+ // Raise an exception if it can't be loaded.
+
+ CachedFileRcPtr LocalFileFormat::Read(std::istream & istream) const
+ {
+ std::ostringstream rawdata;
+ rawdata << istream.rdbuf();
+
+ LocalCachedFileRcPtr cachedFile = LocalCachedFileRcPtr(new LocalCachedFile());
+
+ TiXmlDocumentRcPtr doc = TiXmlDocumentRcPtr(new TiXmlDocument());
+ doc->Parse(rawdata.str().c_str());
+
+ if(doc->Error())
+ {
+ std::ostringstream os;
+ os << "XML Parse Error. ";
+ os << doc->ErrorDesc() << " (line ";
+ os << doc->ErrorRow() << ", character ";
+ os << doc->ErrorCol() << ")";
+ throw Exception(os.str().c_str());
+ }
+
+ TiXmlElement* rootElement = doc->RootElement();
+ if(!rootElement)
+ {
+ std::ostringstream os;
+ os << "Error loading xml. Null root element.";
+ throw Exception(os.str().c_str());
+ }
+
+ if(std::string(rootElement->Value()) != "ColorCorrectionCollection")
+ {
+ std::ostringstream os;
+ os << "Error loading ccc xml. ";
+ os << "Root element is type '" << rootElement->Value() << "', ";
+ os << "ColorCorrectionCollection expected.";
+ throw Exception(os.str().c_str());
+ }
+
+ GetCDLTransforms(cachedFile->transforms, rootElement);
+
+ if(cachedFile->transforms.empty())
+ {
+ std::ostringstream os;
+ os << "Error loading ccc xml. ";
+ os << "No ColorCorrection elements found.";
+ throw Exception(os.str().c_str());
+ }
+
+ return cachedFile;
+ }
+
+ void
+ LocalFileFormat::BuildFileOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const
+ {
+ LocalCachedFileRcPtr cachedFile = DynamicPtrCast<LocalCachedFile>(untypedCachedFile);
+
+ // This should never happen.
+ if(!cachedFile)
+ {
+ std::ostringstream os;
+ os << "Cannot build .ccc Op. Invalid cache type.";
+ throw Exception(os.str().c_str());
+ }
+
+ TransformDirection newDir = CombineTransformDirections(dir,
+ fileTransform.getDirection());
+ if(newDir == TRANSFORM_DIR_UNKNOWN)
+ {
+ std::ostringstream os;
+ os << "Cannot build ASC FileTransform,";
+ os << " unspecified transform direction.";
+ throw Exception(os.str().c_str());
+ }
+
+ std::string cccid = fileTransform.getCCCId();
+ cccid = context->resolveStringVar(cccid.c_str());
+
+ CDLMap::const_iterator iter = cachedFile->transforms.find(cccid);
+ if(iter == cachedFile->transforms.end())
+ {
+ std::ostringstream os;
+ os << "Cannot build ASC FileTransform, specified cccid '";
+ os << cccid << "' not found in " << fileTransform.getSrc();
+ throw Exception(os.str().c_str());
+ }
+
+ BuildCDLOps(ops,
+ config,
+ *(iter->second),
+ newDir);
+ }
+ }
+
+ FileFormat * CreateFileFormatCCC()
+ {
+ return new LocalFileFormat();
+ }
+}
+OCIO_NAMESPACE_EXIT
+
diff --git a/src/core/FileFormatCSP.cpp b/src/core/FileFormatCSP.cpp
new file mode 100644
index 0000000..eae4d9d
--- /dev/null
+++ b/src/core/FileFormatCSP.cpp
@@ -0,0 +1,1112 @@
+/*
+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 <cassert>
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <iterator>
+#include <sstream>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "FileTransform.h"
+#include "Lut1DOp.h"
+#include "Lut3DOp.h"
+#include "MathUtils.h"
+#include "ParseUtils.h"
+#include "pystring/pystring.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ const int NUM_PRELUT_SAMPLES = 65536; // 2**16 samples
+ // Always use linear interpolation for preluts to get the
+ // best precision
+ const Interpolation PRELUT_INTERPOLATION = INTERP_LINEAR;
+
+ typedef struct rsr_Interpolator1D_Raw_
+ {
+ float * stims;
+ float * values;
+ unsigned int length;
+ } rsr_Interpolator1D_Raw;
+
+ rsr_Interpolator1D_Raw * rsr_Interpolator1D_Raw_create( unsigned int prelutLength );
+ void rsr_Interpolator1D_Raw_destroy( rsr_Interpolator1D_Raw * prelut );
+
+
+ /* An opaque handle to the cineSpace 1D Interpolator object */
+ typedef struct rsr_Interpolator1D_ rsr_Interpolator1D;
+
+ rsr_Interpolator1D * rsr_Interpolator1D_createFromRaw( rsr_Interpolator1D_Raw * data );
+ void rsr_Interpolator1D_destroy( rsr_Interpolator1D * rawdata );
+ float rsr_Interpolator1D_interpolate( float x, rsr_Interpolator1D * data );
+
+
+ /*
+ * =========== INTERNAL HELPER FUNCTIONS ============
+ */
+ struct rsr_Interpolator1D_
+ {
+ int nSamplePoints;
+ float * stims;
+
+ /* 5 * (nSamplePoints-1) long, holding a sequence of
+ * 1.0/delta, a, b, c, d
+ * such that the curve in interval i is given by
+ * z = (stims[i] - x)* (1.0/delta)
+ * y = a + b*z + c*z^2 + d*z^3
+ */
+ float * parameters;
+
+ float minValue; /* = f( stims[0] ) */
+ float maxValue; /* = f(stims[nSamplePoints-1] ) */
+ };
+
+ static int rsr_internal_I1D_refineSegment( float x, float * data, int low, int high )
+ {
+ int midPoint;
+
+ // TODO: Change assert to an exception?
+ assert( x>= data[low] );
+ assert( x<= data[high] );
+ assert( (high-low) > 0);
+ if( high-low==1 ) return low;
+
+ midPoint = (low+high)/2;
+ if( x<data[midPoint] ) return rsr_internal_I1D_refineSegment(x, data, low, midPoint );
+ return rsr_internal_I1D_refineSegment(x, data, midPoint, high );
+ }
+
+ static int rsr_internal_I1D_findSegmentContaining( float x, float * data, int n )
+ {
+ return rsr_internal_I1D_refineSegment(x, data, 0, n-1);
+ }
+
+ /*
+ * =========== USER FUNCTIONS ============
+ */
+
+
+ void rsr_Interpolator1D_destroy( rsr_Interpolator1D * data )
+ {
+ if(data==NULL) return;
+ free(data->stims);
+ free(data->parameters);
+ free(data);
+ }
+
+
+
+ float rsr_Interpolator1D_interpolate( float x, rsr_Interpolator1D * data )
+ {
+ int segId;
+ float * segdata;
+ float invDelta;
+ float a,b,c,d,z;
+
+ assert(data!=NULL);
+
+ /* Is x in range? */
+ if( isnan(x) ) return x;
+
+ if( x<data->stims[0] ) return data->minValue;
+ if (x>data->stims[ data->nSamplePoints -1] ) return data->maxValue;
+
+ /* Ok so its between the begining and end .. lets find out where... */
+ segId = rsr_internal_I1D_findSegmentContaining( x, data->stims, data->nSamplePoints );
+
+ assert(data->parameters !=NULL );
+
+ segdata = data->parameters + 5 * segId;
+
+ invDelta = segdata[0];
+ a = segdata[1];
+ b = segdata[2];
+ c = segdata[3];
+ d = segdata[4];
+
+ z = ( x - data->stims[segId] ) * invDelta;
+
+ return a + z * ( b + z * ( c + d * z ) ) ;
+
+ }
+
+ rsr_Interpolator1D * rsr_Interpolator1D_createFromRaw( rsr_Interpolator1D_Raw * data )
+ {
+ rsr_Interpolator1D * retval = NULL;
+ /* Check the sanity of the data */
+ assert(data!=NULL);
+ assert(data->length>=2);
+ assert(data->stims!=NULL);
+ assert(data->values!=NULL);
+
+ /* Create the real data. */
+ retval = (rsr_Interpolator1D*)malloc( sizeof(rsr_Interpolator1D) ); // OCIO change: explicit cast
+ if(retval==NULL)
+ {
+ return NULL;
+ }
+
+ retval->stims = (float*)malloc( sizeof(float) * data->length ); // OCIO change: explicit cast
+ if(retval->stims==NULL)
+ {
+ free(retval);
+ return NULL;
+ }
+ memcpy( retval->stims, data->stims, sizeof(float) * data->length );
+
+ retval->parameters = (float*)malloc( 5*sizeof(float) * ( data->length - 1 ) ); // OCIO change: explicit cast
+ if(retval->parameters==NULL)
+ {
+ free(retval->stims);
+ free(retval);
+ return NULL;
+ }
+ retval->nSamplePoints = data->length;
+ retval->minValue = data->values[0];
+ retval->maxValue = data->values[ data->length -1];
+
+ /* Now the fun part .. filling in the coeficients. */
+ if(data->length==2)
+ {
+ retval->parameters[0] = 1.0f/(data->stims[1]-data->stims[0]);
+ retval->parameters[1] = data->values[0];
+ retval->parameters[2] = ( data->values[1] - data->values[0] );
+ retval->parameters[3] = 0;
+ retval->parameters[4] = 0;
+ }
+ else
+ {
+ unsigned int i;
+ float * params = retval->parameters;
+ for(i=0; i< data->length-1; ++i)
+ {
+ float f0 = data->values[i+0];
+ float f1 = data->values[i+1];
+
+ params[0] = 1.0f/(retval->stims[i+1]-retval->stims[i+0]);
+
+ if(i==0)
+ {
+ float delta = data->stims[i+1] - data->stims[i];
+ float delta2 = (data->stims[i+2] - data->stims[i+1])/delta;
+ float f2 = data->values[i+2];
+
+ float dfdx1 = (f2-f0)/(1+delta2);
+ params[1] = 1.0f * f0 + 0.0f * f1 + 0.0f * dfdx1;
+ params[2] = -2.0f * f0 + 2.0f * f1 - 1.0f * dfdx1;
+ params[3] = 1.0f * f0 - 1.0f * f1 + 1.0f * dfdx1;
+ params[4] = 0.0;
+ }
+ else if (i==data->length-2)
+ {
+ float delta = data->stims[i+1] - data->stims[i];
+ float delta1 = (data->stims[i]-data->stims[i-1])/delta;
+ float fn1 = data->values[i-1];
+ float dfdx0 = (f1-fn1)/(1+delta1);
+ params[1] = 1.0f * f0 + 0.0f * f1 + 0.0f * dfdx0;
+ params[2] = 0.0f * f0 + 0.0f * f1 + 1.0f * dfdx0;
+ params[3] = -1.0f * f0 + 1.0f * f1 - 1.0f * dfdx0;
+ params[4] = 0.0;
+ }
+ else
+ {
+ float delta = data->stims[i+1] - data->stims[i];
+ float fn1=data->values[i-1];
+ float delta1 = (data->stims[i] - data->stims[i-1])/delta;
+
+ float f2=data->values[i+2];
+ float delta2 = (data->stims[i+2] - data->stims[i+1])/delta;
+
+ float dfdx0 = (f1-fn1)/(1.0f+delta1);
+ float dfdx1 = (f2-f0)/(1.0f+delta2);
+
+ params[1] = 1.0f * f0 + 0.0f * dfdx0 + 0.0f * f1 + 0.0f * dfdx1;
+ params[2] = 0.0f * f0 + 1.0f * dfdx0 + 0.0f * f1 + 0.0f * dfdx1;
+ params[3] =-3.0f * f0 - 2.0f * dfdx0 + 3.0f * f1 - 1.0f * dfdx1;
+ params[4] = 2.0f * f0 + 1.0f * dfdx0 - 2.0f * f1 + 1.0f * dfdx1;
+ }
+
+ params+=5;
+ }
+ }
+ return retval;
+ }
+
+ rsr_Interpolator1D_Raw * rsr_Interpolator1D_Raw_create( unsigned int prelutLength)
+ {
+ unsigned int i;
+ rsr_Interpolator1D_Raw * prelut = (rsr_Interpolator1D_Raw*)malloc( sizeof(rsr_Interpolator1D_Raw) ); // OCIO change: explicit cast
+ if(prelut==NULL) return NULL;
+
+ prelut->stims = (float*)malloc( sizeof(float) * prelutLength ); // OCIO change: explicit cast
+ if(prelut->stims==NULL)
+ {
+ free(prelut);
+ return NULL;
+ }
+
+ prelut->values = (float*)malloc( sizeof(float) * prelutLength ); // OCIO change: explicit cast
+ if(prelut->values == NULL)
+ {
+ free(prelut->stims);
+ free(prelut);
+ return NULL;
+ }
+
+ prelut->length = prelutLength;
+
+ for( i=0; i<prelutLength; ++i )
+ {
+ prelut->stims[i] = 0.0;
+ prelut->values[i] = 0.0;
+ }
+
+ return prelut;
+ }
+
+ void rsr_Interpolator1D_Raw_destroy( rsr_Interpolator1D_Raw * prelut )
+ {
+ if(prelut==NULL) return;
+ free( prelut->stims );
+ free( prelut->values );
+ free( prelut );
+ }
+
+ } // End unnamed namespace for Interpolators.c
+
+ namespace
+ {
+ class CachedFileCSP : public CachedFile
+ {
+ public:
+ CachedFileCSP () :
+ hasprelut(false),
+ csptype("unknown"),
+ metadata("none")
+ {
+ prelut = Lut1D::Create();
+ lut1D = Lut1D::Create();
+ lut3D = Lut3D::Create();
+ };
+ ~CachedFileCSP() {};
+
+ bool hasprelut;
+ std::string csptype;
+ std::string metadata;
+ Lut1DRcPtr prelut;
+ Lut1DRcPtr lut1D;
+ Lut3DRcPtr lut3D;
+ };
+ typedef OCIO_SHARED_PTR<CachedFileCSP> CachedFileCSPRcPtr;
+
+
+
+ class LocalFileFormat : public FileFormat
+ {
+ public:
+
+ ~LocalFileFormat() {};
+
+ virtual void GetFormatInfo(FormatInfoVec & formatInfoVec) const;
+
+ virtual CachedFileRcPtr Read(std::istream & istream) const;
+
+ virtual void Write(const Baker & baker,
+ const std::string & formatName,
+ std::ostream & ostream) const;
+
+ virtual void BuildFileOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const;
+ };
+
+
+ // TODO: remove this when we don't need to debug
+ /*
+ template<class T>
+ std::ostream& operator<< (std::ostream& os, const std::vector<T>& v)
+ {
+ copy(v.begin(), v.end(), std::ostream_iterator<T>(std::cout, " "));
+ return os;
+ }
+ */
+
+ void LocalFileFormat::GetFormatInfo(FormatInfoVec & formatInfoVec) const
+ {
+ FormatInfo info;
+ info.name = "cinespace";
+ info.extension = "csp";
+ info.capabilities = (FORMAT_CAPABILITY_READ | FORMAT_CAPABILITY_WRITE);
+ formatInfoVec.push_back(info);
+ }
+
+ CachedFileRcPtr
+ LocalFileFormat::Read(std::istream & istream) const
+ {
+
+ // this shouldn't happen
+ if (!istream)
+ {
+ throw Exception ("file stream empty when trying to read csp lut");
+ }
+
+ Lut1DRcPtr prelut_ptr = Lut1D::Create();
+ Lut1DRcPtr lut1d_ptr = Lut1D::Create();
+ Lut3DRcPtr lut3d_ptr = Lut3D::Create();
+
+ // try and read the lut header
+ std::string line;
+ nextline (istream, line);
+ if (line != "CSPLUTV100")
+ {
+ std::ostringstream os;
+ os << "Lut doesn't seem to be a csp file, expected 'CSPLUTV100'.";
+ os << "First line: '" << line << "'.";
+ throw Exception(os.str().c_str());
+ }
+
+ // next line tells us if we are reading a 1D or 3D lut
+ nextline (istream, line);
+ if (line != "1D" && line != "3D")
+ {
+ std::ostringstream os;
+ os << "Unsupported CSP lut type. Require 1D or 3D. ";
+ os << "Found, '" << line << "'.";
+ throw Exception(os.str().c_str());
+ }
+ std::string csptype = line;
+
+ // read meta data block
+ std::string metadata;
+ std::streampos curr_pos = istream.tellg ();
+ nextline (istream, line);
+ if (line == "BEGIN METADATA")
+ {
+ while (line != "END METADATA" || !istream)
+ {
+ nextline (istream, line);
+ if (line != "END METADATA")
+ metadata += line + "\n";
+ }
+ }
+ else
+ {
+ istream.seekg (curr_pos);
+ }
+
+ // Make 3 vectors of prelut inputs + output values
+ std::vector<float> prelut_in[3];
+ std::vector<float> prelut_out[3];
+ bool useprelut[3] = { false, false, false };
+
+ // Parse the prelut block
+ for (int c = 0; c < 3; ++c)
+ {
+ // how many points do we have for this channel
+ nextline (istream, line);
+ int cpoints = 0;
+
+ if(!StringToInt(&cpoints, line.c_str()) || cpoints<0)
+ {
+ std::ostringstream os;
+ os << "Prelut does not specify valid dimension size on channel '";
+ os << c << ": " << line;
+ throw Exception(os.str().c_str());
+ }
+
+ if(cpoints>=2)
+ {
+ std::vector<std::string> inputparts, outputparts;
+
+ nextline (istream, line);
+ pystring::split(pystring::strip(line), inputparts);
+
+ nextline (istream, line);
+ pystring::split(pystring::strip(line), outputparts);
+
+ if(static_cast<int>(inputparts.size()) != cpoints ||
+ static_cast<int>(outputparts.size()) != cpoints)
+ {
+ std::ostringstream os;
+ os << "Prelut does not specify the expected number of data points. ";
+ os << "Expected: " << cpoints << ".";
+ os << "Found: " << inputparts.size() << ", " << outputparts.size() << ".";
+ throw Exception(os.str().c_str());
+ }
+
+ if(!StringVecToFloatVec(prelut_in[c], inputparts) ||
+ !StringVecToFloatVec(prelut_out[c], outputparts))
+ {
+ std::ostringstream os;
+ os << "Prelut data is malformed, cannot to float array.";
+ throw Exception(os.str().c_str());
+ }
+
+
+ useprelut[c] = (!VecsEqualWithRelError(&(prelut_in[c][0]), static_cast<int>(prelut_in[c].size()),
+ &(prelut_out[c][0]), static_cast<int>(prelut_out[c].size()),
+ 1e-6f));
+ }
+ else
+ {
+ // Even though it's probably not part of the spec, why not allow for a size 0
+ // in a channel to be specified? It should be synonymous with identity,
+ // and allows the code lower down to assume all 3 channels exist
+
+ prelut_in[c].push_back(0.0f);
+ prelut_in[c].push_back(1.0f);
+ prelut_out[c].push_back(0.0f);
+ prelut_out[c].push_back(1.0f);
+ useprelut[c] = false;
+ }
+ }
+
+ if (csptype == "1D")
+ {
+
+ // how many 1D lut points do we have
+ nextline (istream, line);
+ int points1D = atoi (line.c_str());
+
+ //
+ float from_min = 0.0;
+ float from_max = 1.0;
+ for(int i=0; i<3; ++i)
+ {
+ lut1d_ptr->from_min[i] = from_min;
+ lut1d_ptr->from_max[i] = from_max;
+ lut1d_ptr->luts[i].clear();
+ lut1d_ptr->luts[i].reserve(points1D);
+ }
+
+ for(int i = 0; i < points1D; ++i)
+ {
+
+ // scan for the three floats
+ float lp[3];
+ nextline (istream, line);
+ if (sscanf (line.c_str(), "%f %f %f",
+ &lp[0], &lp[1], &lp[2]) != 3) {
+ throw Exception ("malformed 1D csp lut");
+ }
+
+ // store each channel
+ lut1d_ptr->luts[0].push_back(lp[0]);
+ lut1d_ptr->luts[1].push_back(lp[1]);
+ lut1d_ptr->luts[2].push_back(lp[2]);
+
+ }
+
+ }
+ else if (csptype == "3D")
+ {
+ // read the cube size
+ nextline (istream, line);
+ if (sscanf (line.c_str(), "%d %d %d",
+ &lut3d_ptr->size[0],
+ &lut3d_ptr->size[1],
+ &lut3d_ptr->size[2]) != 3 ) {
+ throw Exception("malformed 3D csp lut, couldn't read cube size");
+ }
+
+
+ // resize cube
+ int num3dentries = lut3d_ptr->size[0] * lut3d_ptr->size[1] * lut3d_ptr->size[2];
+ lut3d_ptr->lut.resize(num3dentries * 3);
+
+ for(int i=0; i<num3dentries; ++i)
+ {
+ // load the cube
+ nextline (istream, line);
+
+ if(sscanf (line.c_str(), "%f %f %f",
+ &lut3d_ptr->lut[3*i+0],
+ &lut3d_ptr->lut[3*i+1],
+ &lut3d_ptr->lut[3*i+2]) != 3 )
+ {
+ std::ostringstream os;
+ os << "Malformed 3D csp lut, couldn't read cube row (";
+ os << i << "): " << line << " .";
+ throw Exception(os.str().c_str());
+ }
+ }
+ }
+
+ CachedFileCSPRcPtr cachedFile = CachedFileCSPRcPtr (new CachedFileCSP ());
+ cachedFile->csptype = csptype;
+ cachedFile->metadata = metadata;
+
+ if(useprelut[0] || useprelut[1] || useprelut[2])
+ {
+ cachedFile->hasprelut = true;
+
+ for (int c = 0; c < 3; ++c)
+ {
+ size_t prelut_numpts = prelut_in[c].size();
+ float from_min = prelut_in[c][0];
+ float from_max = prelut_in[c][prelut_numpts-1];
+
+ // Allocate the interpolator
+ rsr_Interpolator1D_Raw * cprelut_raw =
+ rsr_Interpolator1D_Raw_create(static_cast<unsigned int>(prelut_numpts));
+
+ // Copy our prelut data into the interpolator
+ for(size_t i=0; i<prelut_numpts; ++i)
+ {
+ cprelut_raw->stims[i] = prelut_in[c][i];
+ cprelut_raw->values[i] = prelut_out[c][i];
+ }
+
+ // Create interpolater, to resample to simple 1D lut
+ rsr_Interpolator1D * interpolater =
+ rsr_Interpolator1D_createFromRaw(cprelut_raw);
+
+ // Resample into 1D lut
+ // TODO: Fancy spline analysis to determine required number of samples
+ prelut_ptr->from_min[c] = from_min;
+ prelut_ptr->from_max[c] = from_max;
+ prelut_ptr->luts[c].clear();
+ prelut_ptr->luts[c].reserve(NUM_PRELUT_SAMPLES);
+
+ for (int i = 0; i < NUM_PRELUT_SAMPLES; ++i)
+ {
+ float interpo = float(i) / float(NUM_PRELUT_SAMPLES-1);
+ float srcval = lerpf(from_min, from_max, interpo);
+ float newval = rsr_Interpolator1D_interpolate(srcval, interpolater);
+ prelut_ptr->luts[c].push_back(newval);
+ }
+
+ rsr_Interpolator1D_Raw_destroy(cprelut_raw);
+ rsr_Interpolator1D_destroy(interpolater);
+ }
+
+ prelut_ptr->maxerror = 1e-6f;
+ prelut_ptr->errortype = ERROR_RELATIVE;
+
+ cachedFile->prelut = prelut_ptr;
+ }
+
+ if(csptype == "1D")
+ {
+ lut1d_ptr->maxerror = 0.0f;
+ lut1d_ptr->errortype = ERROR_RELATIVE;
+ cachedFile->lut1D = lut1d_ptr;
+ }
+ else if (csptype == "3D")
+ {
+ cachedFile->lut3D = lut3d_ptr;
+ }
+
+ return cachedFile;
+ }
+
+
+ void LocalFileFormat::Write(const Baker & baker,
+ const std::string & /*formatName*/,
+ std::ostream & ostream) const
+ {
+ const int DEFAULT_CUBE_SIZE = 32;
+ const int DEFAULT_SHAPER_SIZE = 1024;
+
+ ConstConfigRcPtr config = baker.getConfig();
+
+ // TODO: Add 1d/3d lut writing switch, using hasChannelCrosstalk
+ int cubeSize = baker.getCubeSize();
+ if(cubeSize==-1) cubeSize = DEFAULT_CUBE_SIZE;
+ cubeSize = std::max(2, cubeSize); // smallest cube is 2x2x2
+ std::vector<float> cubeData;
+ cubeData.resize(cubeSize*cubeSize*cubeSize*3);
+ GenerateIdentityLut3D(&cubeData[0], cubeSize, 3, LUT3DORDER_FAST_RED);
+ PackedImageDesc cubeImg(&cubeData[0], cubeSize*cubeSize*cubeSize, 1, 3);
+
+ std::string looks = baker.getLooks();
+
+ std::vector<float> shaperInData;
+ std::vector<float> shaperOutData;
+
+ // Use an explicitly shaper space
+ // TODO: Use the optional allocation for the shaper space,
+ // instead of the implied 0-1 uniform allocation
+ std::string shaperSpace = baker.getShaperSpace();
+ if(!shaperSpace.empty())
+ {
+ int shaperSize = baker.getShaperSize();
+ if(shaperSize<0) shaperSize = DEFAULT_SHAPER_SIZE;
+ if(shaperSize<2)
+ {
+ std::ostringstream os;
+ os << "When a shaper space has been specified, '";
+ os << baker.getShaperSpace() << "', a shaper size less than 2 is not allowed.";
+ throw Exception(os.str().c_str());
+ }
+
+ shaperOutData.resize(shaperSize*3);
+ shaperInData.resize(shaperSize*3);
+ GenerateIdentityLut1D(&shaperOutData[0], shaperSize, 3);
+ GenerateIdentityLut1D(&shaperInData[0], shaperSize, 3);
+
+ ConstProcessorRcPtr shaperToInput = config->getProcessor(baker.getShaperSpace(), baker.getInputSpace());
+ if(shaperToInput->hasChannelCrosstalk())
+ {
+ // TODO: Automatically turn shaper into non-crosstalked version?
+ std::ostringstream os;
+ os << "The specified shaperSpace, '";
+ os << baker.getShaperSpace() << "' has channel crosstalk, which is not appropriate for shapers. ";
+ os << "Please select an alternate shaper space or omit this option.";
+ throw Exception(os.str().c_str());
+ }
+ PackedImageDesc shaperInImg(&shaperInData[0], shaperSize, 1, 3);
+ shaperToInput->apply(shaperInImg);
+
+ ConstProcessorRcPtr shaperToTarget;
+ if (!looks.empty())
+ {
+ LookTransformRcPtr transform = LookTransform::Create();
+ transform->setLooks(looks.c_str());
+ transform->setSrc(baker.getShaperSpace());
+ transform->setDst(baker.getTargetSpace());
+ shaperToTarget = config->getProcessor(transform,
+ TRANSFORM_DIR_FORWARD);
+ }
+ else
+ {
+ shaperToTarget = config->getProcessor(baker.getShaperSpace(),
+ baker.getTargetSpace());
+ }
+ shaperToTarget->apply(cubeImg);
+ }
+ else
+ {
+ // A shaper is not specified, let's fake one, using the input space allocation as
+ // our guide
+
+ ConstColorSpaceRcPtr inputColorSpace = config->getColorSpace(baker.getInputSpace());
+
+ if(!inputColorSpace)
+ {
+ std::ostringstream os;
+ os << "Could not find colorspace '" << baker.getInputSpace() << "'";
+ throw Exception(os.str().c_str());
+ }
+
+ // Let's make an allocation transform for this colorspace
+ AllocationTransformRcPtr allocationTransform = AllocationTransform::Create();
+ allocationTransform->setAllocation(inputColorSpace->getAllocation());
+
+ // numVars may be '0'
+ int numVars = inputColorSpace->getAllocationNumVars();
+ if(numVars>0)
+ {
+ std::vector<float> vars(numVars);
+ inputColorSpace->getAllocationVars(&vars[0]);
+ allocationTransform->setVars(numVars, &vars[0]);
+ }
+ else
+ {
+ allocationTransform->setVars(0, NULL);
+ }
+
+ // What size shaper should we make?
+ int shaperSize = baker.getShaperSize();
+ if(shaperSize<0) shaperSize = DEFAULT_SHAPER_SIZE;
+ shaperSize = std::max(2, shaperSize);
+ if(inputColorSpace->getAllocation() == ALLOCATION_UNIFORM)
+ {
+ // This is an awesome optimization.
+ // If we know it's a uniform scaling, only 2 points will suffice!
+ shaperSize = 2;
+ }
+ shaperOutData.resize(shaperSize*3);
+ shaperInData.resize(shaperSize*3);
+ GenerateIdentityLut1D(&shaperOutData[0], shaperSize, 3);
+ GenerateIdentityLut1D(&shaperInData[0], shaperSize, 3);
+
+ // Apply the forward to the allocation to the output shaper y axis, and the cube
+ ConstProcessorRcPtr shaperToInput = config->getProcessor(allocationTransform, TRANSFORM_DIR_INVERSE);
+ PackedImageDesc shaperInImg(&shaperInData[0], shaperSize, 1, 3);
+ shaperToInput->apply(shaperInImg);
+ shaperToInput->apply(cubeImg);
+
+ // Apply the 3d lut to the remainder (from the input to the output)
+ ConstProcessorRcPtr inputToTarget;
+ if (!looks.empty())
+ {
+ LookTransformRcPtr transform = LookTransform::Create();
+ transform->setLooks(looks.c_str());
+ transform->setSrc(baker.getInputSpace());
+ transform->setDst(baker.getTargetSpace());
+ inputToTarget = config->getProcessor(transform,
+ TRANSFORM_DIR_FORWARD);
+ }
+ else
+ {
+ inputToTarget = config->getProcessor(baker.getInputSpace(), baker.getTargetSpace());
+ }
+ inputToTarget->apply(cubeImg);
+ }
+
+ // Write out the file
+ ostream << "CSPLUTV100\n";
+ ostream << "3D\n";
+ ostream << "BEGIN METADATA\n";
+ std::string metadata = baker.getMetadata();
+ if(!metadata.empty())
+ {
+ ostream << metadata << "\n";
+ }
+ ostream << "END METADATA\n";
+ ostream << "\n";
+
+ // Write out the 1D Prelut
+ ostream.setf(std::ios::fixed, std::ios::floatfield);
+ ostream.precision(6);
+
+ if(shaperInData.size()<2 || shaperOutData.size() != shaperInData.size())
+ {
+ throw Exception("Internal shaper size exception.");
+ }
+
+ if(!shaperInData.empty())
+ {
+ for(int c=0; c<3; ++c)
+ {
+ ostream << shaperInData.size()/3 << "\n";
+ for(unsigned int i = 0; i<shaperInData.size()/3; ++i)
+ {
+ if(i != 0) ostream << " ";
+ ostream << shaperInData[3*i+c];
+ }
+ ostream << "\n";
+
+ for(unsigned int i = 0; i<shaperInData.size()/3; ++i)
+ {
+ if(i != 0) ostream << " ";
+ ostream << shaperOutData[3*i+c];
+ }
+ ostream << "\n";
+ }
+ }
+ ostream << "\n";
+
+ // Write out the 3D Cube
+ if(cubeSize < 2)
+ {
+ throw Exception("Internal cube size exception.");
+ }
+ ostream << cubeSize << " " << cubeSize << " " << cubeSize << "\n";
+ for(int i=0; i<cubeSize*cubeSize*cubeSize; ++i)
+ {
+ ostream << cubeData[3*i+0] << " " << cubeData[3*i+1] << " " << cubeData[3*i+2] << "\n";
+ }
+ ostream << "\n";
+ }
+
+ void
+ LocalFileFormat::BuildFileOps(OpRcPtrVec & ops,
+ const Config& /*config*/,
+ const ConstContextRcPtr & /*context*/,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const
+ {
+
+ CachedFileCSPRcPtr cachedFile = DynamicPtrCast<CachedFileCSP>(untypedCachedFile);
+
+ // This should never happen.
+ if(!cachedFile)
+ {
+ std::ostringstream os;
+ os << "Cannot build CSP Op. Invalid cache type.";
+ throw Exception(os.str().c_str());
+ }
+
+ TransformDirection newDir = CombineTransformDirections(dir,
+ fileTransform.getDirection());
+
+ if(newDir == TRANSFORM_DIR_FORWARD)
+ {
+ if(cachedFile->hasprelut)
+ {
+ CreateLut1DOp(ops, cachedFile->prelut,
+ PRELUT_INTERPOLATION, newDir);
+ }
+ if(cachedFile->csptype == "1D")
+ CreateLut1DOp(ops, cachedFile->lut1D,
+ fileTransform.getInterpolation(), newDir);
+ else if(cachedFile->csptype == "3D")
+ CreateLut3DOp(ops, cachedFile->lut3D,
+ fileTransform.getInterpolation(), newDir);
+ }
+ else if(newDir == TRANSFORM_DIR_INVERSE)
+ {
+ if(cachedFile->csptype == "1D")
+ CreateLut1DOp(ops, cachedFile->lut1D,
+ fileTransform.getInterpolation(), newDir);
+ else if(cachedFile->csptype == "3D")
+ CreateLut3DOp(ops, cachedFile->lut3D,
+ fileTransform.getInterpolation(), newDir);
+ if(cachedFile->hasprelut)
+ {
+ CreateLut1DOp(ops, cachedFile->prelut,
+ PRELUT_INTERPOLATION, newDir);
+ }
+ }
+
+ return;
+
+ }
+ }
+
+ FileFormat * CreateFileFormatCSP()
+ {
+ return new LocalFileFormat();
+ }
+}
+OCIO_NAMESPACE_EXIT
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef OCIO_UNIT_TEST
+
+namespace OCIO = OCIO_NAMESPACE;
+#include "UnitTest.h"
+
+OIIO_ADD_TEST(FileFormatCSP, simple1D)
+{
+ std::ostringstream strebuf;
+ strebuf << "CSPLUTV100" << "\n";
+ strebuf << "1D" << "\n";
+ strebuf << "" << "\n";
+ strebuf << "BEGIN METADATA" << "\n";
+ strebuf << "foobar" << "\n";
+ strebuf << "END METADATA" << "\n";
+ strebuf << "" << "\n";
+ strebuf << "2" << "\n";
+ strebuf << "0.0 1.0" << "\n";
+ strebuf << "0.0 2.0" << "\n";
+ strebuf << "6" << "\n";
+ strebuf << "0.0 0.2 0.4 0.6 0.8 1.0" << "\n";
+ strebuf << "0.0 0.4 0.8 1.2 1.6 2.0" << "\n";
+ strebuf << "3" << "\n";
+ strebuf << "0.0 0.1 1.0" << "\n";
+ strebuf << "0.0 0.2 2.0" << "\n";
+ strebuf << "" << "\n";
+ strebuf << "6" << "\n";
+ strebuf << "0.0 0.0 0.0" << "\n";
+ strebuf << "0.2 0.3 0.1" << "\n";
+ strebuf << "0.4 0.5 0.2" << "\n";
+ strebuf << "0.5 0.6 0.3" << "\n";
+ strebuf << "0.6 0.8 0.4" << "\n";
+ strebuf << "1.0 0.9 0.5" << "\n";
+
+ float red[6] = { 0.0f, 0.2f, 0.4f, 0.5f, 0.6f, 1.0f };
+ float green[6] = { 0.0f, 0.3f, 0.5f, 0.6f, 0.8f, 0.9f };
+ float blue[6] = { 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f };
+
+ std::istringstream simple1D;
+ simple1D.str(strebuf.str());
+
+ // Read file
+ OCIO::LocalFileFormat tester;
+ OCIO::CachedFileRcPtr cachedFile = tester.Read(simple1D);
+ OCIO::CachedFileCSPRcPtr csplut = OCIO::DynamicPtrCast<OCIO::CachedFileCSP>(cachedFile);
+
+ // check prelut data (note: the spline is resampled into a 1D LUT)
+ for(int c=0; c<3; ++c)
+ {
+ for (unsigned int i = 0; i < csplut->prelut->luts[c].size(); i += 128)
+ {
+ float input = float(i) / float(csplut->prelut->luts[c].size()-1);
+ float output = csplut->prelut->luts[c][i];
+ OIIO_CHECK_CLOSE(input*2.0f, output, 1e-4);
+ }
+ }
+ // check 1D data
+ // red
+ unsigned int i;
+ for(i = 0; i < csplut->lut1D->luts[0].size(); ++i)
+ OIIO_CHECK_EQUAL(red[i], csplut->lut1D->luts[0][i]);
+ // green
+ for(i = 0; i < csplut->lut1D->luts[1].size(); ++i)
+ OIIO_CHECK_EQUAL(green[i], csplut->lut1D->luts[1][i]);
+ // blue
+ for(i = 0; i < csplut->lut1D->luts[2].size(); ++i)
+ OIIO_CHECK_EQUAL(blue[i], csplut->lut1D->luts[2][i]);
+
+}
+
+OIIO_ADD_TEST(FileFormatCSP, simple3D)
+{
+ std::ostringstream strebuf;
+ strebuf << "CSPLUTV100" << "\n";
+ strebuf << "3D" << "\n";
+ strebuf << "" << "\n";
+ strebuf << "BEGIN METADATA" << "\n";
+ strebuf << "foobar" << "\n";
+ strebuf << "END METADATA" << "\n";
+ strebuf << "" << "\n";
+ strebuf << "11" << "\n";
+ strebuf << "0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0" << "\n";
+ strebuf << "0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0" << "\n";
+ strebuf << "6" << "\n";
+ strebuf << "0.0 0.2 0.4 0.6 0.8 1.0" << "\n";
+ strebuf << "0.0 0.2000000 0.4 0.6 0.8 1.0" << "\n";
+ strebuf << "5" << "\n";
+ strebuf << "0.0 0.25 0.5 0.6 0.7" << "\n";
+ strebuf << "0.0 0.25000001 0.5 0.6 0.7" << "\n";
+ strebuf << "" << "\n";
+ strebuf << "1 2 3" << "\n";
+ strebuf << "0.0 0.0 0.0" << "\n";
+ strebuf << "1.0 0.0 0.0" << "\n";
+ strebuf << "0.0 0.5 0.0" << "\n";
+ strebuf << "1.0 0.5 0.0" << "\n";
+ strebuf << "0.0 1.0 0.0" << "\n";
+ strebuf << "1.0 1.0 0.0" << "\n";
+
+ float cube[1 * 2 * 3 * 3] = { 0.0, 0.0, 0.0,
+ 1.0, 0.0, 0.0,
+ 0.0, 0.5, 0.0,
+ 1.0, 0.5, 0.0,
+ 0.0, 1.0, 0.0,
+ 1.0, 1.0, 0.0 };
+
+ std::istringstream simple3D;
+ simple3D.str(strebuf.str());
+
+ // Load file
+ OCIO::LocalFileFormat tester;
+ OCIO::CachedFileRcPtr cachedFile = tester.Read(simple3D);
+ OCIO::CachedFileCSPRcPtr csplut = OCIO::DynamicPtrCast<OCIO::CachedFileCSP>(cachedFile);
+
+ // check prelut data
+ OIIO_CHECK_ASSERT(csplut->hasprelut == false);
+
+ // check cube data
+ for(unsigned int i = 0; i < csplut->lut3D->lut.size(); ++i) {
+ OIIO_CHECK_EQUAL(cube[i], csplut->lut3D->lut[i]);
+ }
+
+ // check baker output
+ OCIO::ConfigRcPtr config = OCIO::Config::Create();
+ {
+ OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create();
+ cs->setName("lnf");
+ cs->setFamily("lnf");
+ config->addColorSpace(cs);
+ config->setRole(OCIO::ROLE_REFERENCE, cs->getName());
+ }
+ {
+ OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create();
+ cs->setName("shaper");
+ cs->setFamily("shaper");
+ OCIO::ExponentTransformRcPtr transform1 = OCIO::ExponentTransform::Create();
+ float test[4] = {2.6f, 2.6f, 2.6f, 1.0f};
+ transform1->setValue(test);
+ cs->setTransform(transform1, OCIO::COLORSPACE_DIR_TO_REFERENCE);
+ config->addColorSpace(cs);
+ }
+ {
+ OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create();
+ cs->setName("target");
+ cs->setFamily("target");
+ OCIO::CDLTransformRcPtr transform1 = OCIO::CDLTransform::Create();
+ float rgb[3] = {0.1f, 0.1f, 0.1f};
+ transform1->setOffset(rgb);
+ cs->setTransform(transform1, OCIO::COLORSPACE_DIR_FROM_REFERENCE);
+ config->addColorSpace(cs);
+ }
+
+ /*
+ std::string bout =
+ "CSPLUTV100\n"
+ "3D\n"
+ "\n"
+ "BEGIN METADATA\n"
+ "date: 2011:02:21 15:22:55\n"
+ "END METADATA\n"
+ "\n"
+ "10\n"
+ "0.000000 0.111111 0.222222 0.333333 0.444444 0.555556 0.666667 0.777778 0.888889 1.000000\n"
+ "0.000000 0.429520 0.560744 0.655378 0.732058 0.797661 0.855604 0.907865 0.955710 1.000000\n"
+ "10\n"
+ "0.000000 0.111111 0.222222 0.333333 0.444444 0.555556 0.666667 0.777778 0.888889 1.000000\n"
+ "0.000000 0.429520 0.560744 0.655378 0.732058 0.797661 0.855604 0.907865 0.955710 1.000000\n"
+ "10\n"
+ "0.000000 0.111111 0.222222 0.333333 0.444444 0.555556 0.666667 0.777778 0.888889 1.000000\n"
+ "0.000000 0.429520 0.560744 0.655378 0.732058 0.797661 0.855604 0.907865 0.955710 1.000000\n"
+ "\n"
+ "2 2 2\n"
+ "0.100000 0.100000 0.100000\n"
+ "1.000000 0.100000 0.100000\n"
+ "0.100000 1.000000 0.100000\n"
+ "1.000000 1.000000 0.100000\n"
+ "0.100000 0.100000 1.000000\n"
+ "1.000000 0.100000 1.000000\n"
+ "0.100000 1.000000 1.000000\n"
+ "1.000000 1.000000 1.000000\n"
+ "\n";
+
+ OCIO::BakerRcPtr baker = OCIO::Baker::Create();
+ baker->setConfig(config);
+ baker->setFormat("cinespace");
+ baker->setInputSpace("lnf");
+ baker->setShaperSpace("shaper");
+ baker->setTargetSpace("target");
+ baker->setShaperSize(10);
+ baker->setCubeSize(2);
+ std::ostringstream output;
+ baker->bake(output);
+
+ //
+ std::vector<std::string> osvec;
+ OCIO::pystring::splitlines(output.str(), osvec);
+ std::vector<std::string> resvec;
+ OCIO::pystring::splitlines(bout, resvec);
+ OIIO_CHECK_EQUAL(osvec.size(), resvec.size());
+ for(unsigned int i = 0; i < resvec.size(); ++i)
+ {
+ // skip timestamp line
+ if(i != 4) OIIO_CHECK_EQUAL(osvec[i], resvec[i]);
+ }
+ */
+
+}
+
+// TODO: More strenuous tests of prelut resampling (non-noop preluts)
+
+#endif // OCIO_UNIT_TEST
diff --git a/src/core/FileFormatHDL.cpp b/src/core/FileFormatHDL.cpp
new file mode 100644
index 0000000..995ef9f
--- /dev/null
+++ b/src/core/FileFormatHDL.cpp
@@ -0,0 +1,1481 @@
+/*
+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.
+*/
+
+/*
+
+ Houdini LUTs
+ http://www.sidefx.com/docs/hdk11.0/hdk_io_lut.html
+
+ Types:
+ - 1D Lut (partial support)
+ - 3D Lut
+ - 3D Lut with 1D Prelut
+
+ TODO:
+ - Add support for other 1D types (R, G, B, A, RGB, RGBA, All)
+ we only support type 'C' atm.
+ - Add support for 'Sampling' tag
+
+*/
+
+#include <cstdio>
+#include <iostream>
+#include <iterator>
+#include <cmath>
+#include <vector>
+#include <string>
+#include <algorithm>
+#include <map>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "FileTransform.h"
+#include "Lut1DOp.h"
+#include "Lut3DOp.h"
+#include "ParseUtils.h"
+#include "MathUtils.h"
+#include "pystring/pystring.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ // HDL parser helpers
+
+ // HDL headers/LUT's are shoved into these datatypes
+ typedef std::map<std::string, std::vector<std::string> > StringToStringVecMap;
+ typedef std::map<std::string, std::vector<float> > StringToFloatVecMap;
+
+ void
+ readHeaders(StringToStringVecMap& headers,
+ std::istream& istream)
+ {
+ std::string line;
+ while(nextline(istream, line))
+ {
+ std::vector<std::string> chunks;
+
+ // Remove trailing/leading whitespace, lower-case and
+ // split into words
+ pystring::split(pystring::lower(pystring::strip(line)), chunks);
+
+ // Skip empty lines
+ if(chunks.empty()) continue;
+
+ // Stop looking for headers at the "LUT:" line
+ if(chunks[0] == "lut:") break;
+
+ // Use first index as key, and remove it from the value
+ std::string key = chunks[0];
+ chunks.erase(chunks.begin());
+
+ headers[key] = chunks;
+ }
+ }
+
+ // Try to grab key (e.g "version") from headers. Throws
+ // exception if not found, or if number of chunks in value is
+ // not between min_vals and max_vals (e.g the "length" key
+ // must exist, and must have either 1 or 2 values)
+ std::vector<std::string>
+ findHeaderItem(StringToStringVecMap& headers,
+ const std::string key,
+ const unsigned int min_vals,
+ const unsigned int max_vals)
+ {
+ StringToStringVecMap::iterator iter;
+ iter = headers.find(key);
+
+ // Error if key is not found
+ if(iter == headers.end())
+ {
+ std::ostringstream os;
+ os << "'" << key << "' line not found";
+ throw Exception(os.str().c_str());
+ }
+
+ // Error if incorrect number of values is found
+ if(iter->second.size() < min_vals ||
+ iter->second.size() > max_vals)
+ {
+ std::ostringstream os;
+ os << "Incorrect number of chunks (" << iter->second.size() << ")";
+ os << " after '" << key << "' line, expected ";
+
+ if(min_vals == max_vals)
+ {
+ os << min_vals;
+ }
+ else
+ {
+ os << "between " << min_vals << " and " << max_vals;
+ }
+
+ throw Exception(os.str().c_str());
+ }
+
+ return iter->second;
+ }
+
+ // Simple wrapper to call findHeaderItem with a fixed number
+ // of values (e.g "version" should have a single value)
+ std::vector<std::string>
+ findHeaderItem(StringToStringVecMap& chunks,
+ const std::string key,
+ const unsigned int numvals)
+ {
+ return findHeaderItem(chunks, key, numvals, numvals);
+ }
+
+ // Crudely parse LUT's - doesn't do any length checking etc,
+ // just grabs a series of floats for Pre{...}, 3d{...} etc
+ // Does some basic error checking, but there are situations
+ // were it could incorrectly accept broken data (like
+ // "Pre{0.0\n1.0}blah"), but hopefully none where it misses
+ // data
+ void
+ readLuts(std::istream& istream,
+ StringToFloatVecMap& lutValues)
+ {
+ // State variables
+ bool inlut = false;
+ std::string lutname;
+
+ std::string word;
+
+ while(istream >> word)
+ {
+ if(!inlut)
+ {
+ if(word == "{")
+ {
+ // Lone "{" is for a 3D
+ inlut = true;
+ lutname = "3d";
+ }
+ else
+ {
+ // Named lut, e.g "Pre {"
+ inlut = true;
+ lutname = pystring::lower(word);
+
+ // Ensure next word is "{"
+ std::string nextword;
+ istream >> nextword;
+ if(nextword != "{")
+ {
+ std::ostringstream os;
+ os << "Malformed LUT - Unknown word '";
+ os << word << "' after LUT name '";
+ os << nextword << "'";
+ throw Exception(os.str().c_str());
+ }
+ }
+ }
+ else if(word == "}")
+ {
+ // end of LUT
+ inlut = false;
+ lutname = "";
+ }
+ else if(inlut)
+ {
+ // StringToFloat was far slower, for 787456 values:
+ // - StringToFloat took 3879 (avg nanoseconds per value)
+ // - stdtod took 169 nanoseconds
+ char* endptr = 0;
+ float v = static_cast<float>(strtod(word.c_str(), &endptr));
+
+ if(!*endptr)
+ {
+ // Since each word should contain a single
+ // float value, the pointer should be null
+ lutValues[lutname].push_back(v);
+ }
+ else
+ {
+ // stdtod endptr still contained stuff,
+ // meaning an invalid float value
+ std::ostringstream os;
+ os << "Invalid float value in " << lutname;
+ os << " LUT, '" << word << "'";
+ throw Exception(os.str().c_str());
+ }
+ }
+ else
+ {
+ std::ostringstream os;
+ os << "Unexpected word, possibly a value outside";
+ os <<" a LUT {} block. Word was '" << word << "'";
+ throw Exception(os.str().c_str());
+
+ }
+ }
+ }
+
+ } // end anonymous "HDL parser helpers" namespace
+
+ namespace
+ {
+ class CachedFileHDL : public CachedFile
+ {
+ public:
+ CachedFileHDL ()
+ {
+ hdlversion = "unknown";
+ hdlformat = "unknown";
+ hdltype = "unknown";
+ hdlblack = 0.0;
+ hdlwhite = 1.0;
+ lut1D = Lut1D::Create();
+ lut3D = Lut3D::Create();
+ };
+ ~CachedFileHDL() {};
+ std::string hdlversion;
+ std::string hdlformat;
+ std::string hdltype;
+ float to_min; // TODO: maybe add this to Lut1DOp?
+ float to_max; // TODO: maybe add this to Lut1DOp?
+ float hdlblack;
+ float hdlwhite;
+ Lut1DRcPtr lut1D;
+ Lut3DRcPtr lut3D;
+ };
+ typedef OCIO_SHARED_PTR<CachedFileHDL> CachedFileHDLRcPtr;
+
+ class LocalFileFormat : public FileFormat
+ {
+ public:
+
+ ~LocalFileFormat() {};
+
+ virtual void GetFormatInfo(FormatInfoVec & formatInfoVec) const;
+
+ virtual CachedFileRcPtr Read(std::istream & istream) const;
+
+ virtual void Write(const Baker & baker,
+ const std::string & formatName,
+ std::ostream & ostream) const;
+
+ virtual void BuildFileOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const;
+ };
+
+ void LocalFileFormat::GetFormatInfo(FormatInfoVec & formatInfoVec) const
+ {
+ FormatInfo info;
+ info.name = "houdini";
+ info.extension = "lut";
+ info.capabilities = FORMAT_CAPABILITY_READ | FORMAT_CAPABILITY_WRITE;
+ formatInfoVec.push_back(info);
+ }
+
+ CachedFileRcPtr
+ LocalFileFormat::Read(std::istream & istream) const
+ {
+
+ // this shouldn't happen
+ if (!istream)
+ throw Exception ("file stream empty when trying to read Houdini lut");
+
+ //
+ CachedFileHDLRcPtr cachedFile = CachedFileHDLRcPtr (new CachedFileHDL ());
+ Lut1DRcPtr lut1d_ptr = Lut1D::Create();
+ Lut3DRcPtr lut3d_ptr = Lut3D::Create();
+
+ // Parse headers into key-value pairs
+ StringToStringVecMap header_chunks;
+ StringToStringVecMap::iterator iter;
+
+ // Read headers, ending after the "LUT:" line
+ readHeaders(header_chunks, istream);
+
+ // Grab useful values from headers
+ std::vector<std::string> value;
+
+ // "Version 3" - format version (currently one version
+ // number per LUT type)
+ value = findHeaderItem(header_chunks, "version", 1);
+ cachedFile->hdlversion = value[0];
+
+ // "Format any" - bit depth of image the LUT should be
+ // applied to (this is basically ignored)
+ value = findHeaderItem(header_chunks, "format", 1);
+ cachedFile->hdlformat = value[0];
+
+ // "Type 3d" - type of LUT
+ {
+ value = findHeaderItem(header_chunks, "type", 1);
+
+ cachedFile->hdltype = value[0];
+ }
+
+ // "From 0.0 1.0" - range of input values
+ {
+ float from_min, from_max;
+
+ value = findHeaderItem(header_chunks, "from", 2);
+
+ if(!StringToFloat(&from_min, value[0].c_str()) ||
+ !StringToFloat(&from_max, value[1].c_str()))
+ {
+ std::ostringstream os;
+ os << "Invalid float value(s) on 'From' line, '";
+ os << value[0] << "' and '" << value[1] << "'";
+ throw Exception(os.str().c_str());
+ }
+
+ for(int i = 0; i < 3; ++i)
+ {
+ lut1d_ptr->from_min[i] = from_min;
+ lut1d_ptr->from_max[i] = from_max;
+ }
+ }
+
+
+ // "To 0.0 1.0" - range of values in LUT (e.g "0 255"
+ // to specify values as 8-bit numbers, usually "0 1")
+ {
+ float to_min, to_max;
+
+ value = findHeaderItem(header_chunks, "to", 2);
+
+ if(!StringToFloat(&to_min, value[0].c_str()) ||
+ !StringToFloat(&to_max, value[1].c_str()))
+ {
+ std::ostringstream os;
+ os << "Invalid float value(s) on 'To' line, '";
+ os << value[0] << "' and '" << value[1] << "'";
+ throw Exception(os.str().c_str());
+ }
+ cachedFile->to_min = to_min;
+ cachedFile->to_max = to_max;
+ }
+
+ // "Black 0" and "White 1" - obsolete options, should be 0
+ // and 1
+
+ {
+ value = findHeaderItem(header_chunks, "black", 1);
+
+ float black;
+
+ if(!StringToFloat(&black, value[0].c_str()))
+ {
+ std::ostringstream os;
+ os << "Invalid float value on 'Black' line, '";
+ os << value[0] << "'";
+ throw Exception(os.str().c_str());
+ }
+ cachedFile->hdlblack = black;
+ }
+
+ {
+ value = findHeaderItem(header_chunks, "white", 1);
+
+ float white;
+
+ if(!StringToFloat(&white, value[0].c_str()))
+ {
+ std::ostringstream os;
+ os << "Invalid float value on 'White' line, '";
+ os << value[0] << "'";
+ throw Exception(os.str().c_str());
+ }
+ cachedFile->hdlwhite = white;
+ }
+
+
+ // Verify type is valid and supported - used to handle
+ // length sensibly, and checking the LUT later
+ {
+ std::string ltype = cachedFile->hdltype;
+ if(ltype != "3d" && ltype != "3d+1d" && ltype != "c")
+ {
+ std::ostringstream os;
+ os << "Unsupported Houdini LUT type: '" << ltype << "'";
+ throw Exception(os.str().c_str());
+ }
+ }
+
+
+ // "Length 2" or "Length 2 5" - either "[cube size]", or "[cube
+ // size] [prelut size]"
+ int size_3d = -1;
+ int size_prelut = -1;
+ int size_1d = -1;
+
+ {
+ std::vector<int> lut_sizes;
+
+ value = findHeaderItem(header_chunks, "length", 1, 2);
+ for(unsigned int i = 0; i < value.size(); ++i)
+ {
+ int tmpsize = -1;
+ if(!StringToInt(&tmpsize, value[i].c_str()))
+ {
+ std::ostringstream os;
+ os << "Invalid integer on 'Length' line: ";
+ os << "'" << value[0] << "'";
+ throw Exception(os.str().c_str());
+ }
+ lut_sizes.push_back(tmpsize);
+ }
+
+ if(cachedFile->hdltype == "3d" || cachedFile->hdltype == "3d+1d")
+ {
+ // Set cube size
+ size_3d = lut_sizes[0];
+
+ lut3d_ptr->size[0] = lut_sizes[0];
+ lut3d_ptr->size[1] = lut_sizes[0];
+ lut3d_ptr->size[2] = lut_sizes[0];
+ }
+
+ if(cachedFile->hdltype == "c")
+ {
+ size_1d = lut_sizes[0];
+ }
+
+ if(cachedFile->hdltype == "3d+1d")
+ {
+ size_prelut = lut_sizes[1];
+ }
+ }
+
+ // Read stuff after "LUT:"
+ StringToFloatVecMap lut_data;
+ readLuts(istream, lut_data);
+
+ //
+ StringToFloatVecMap::iterator lut_iter;
+
+ if(cachedFile->hdltype == "3d+1d")
+ {
+ // Read prelut, and bind onto cachedFile
+ lut_iter = lut_data.find("pre");
+ if(lut_iter == lut_data.end())
+ {
+ std::ostringstream os;
+ os << "3D+1D LUT should contain Pre{} LUT section";
+ throw Exception(os.str().c_str());
+ }
+
+ if(size_prelut != static_cast<int>(lut_iter->second.size()))
+ {
+ std::ostringstream os;
+ os << "Pre{} LUT was " << lut_iter->second.size();
+ os << " values long, expected " << size_prelut << " values";
+ throw Exception(os.str().c_str());
+ }
+
+ lut1d_ptr->luts[0] = lut_iter->second;
+ lut1d_ptr->luts[1] = lut_iter->second;
+ lut1d_ptr->luts[2] = lut_iter->second;
+ lut1d_ptr->maxerror = 0.0f;
+ lut1d_ptr->errortype = ERROR_RELATIVE;
+ cachedFile->lut1D = lut1d_ptr;
+ }
+
+ if(cachedFile->hdltype == "3d" ||
+ cachedFile->hdltype == "3d+1d")
+ {
+ // Bind 3D LUT to lut3d_ptr, along with some
+ // slightly-elabourate error messages
+
+ lut_iter = lut_data.find("3d");
+ if(lut_iter == lut_data.end())
+ {
+ std::ostringstream os;
+ os << "3D LUT section not found";
+ throw Exception(os.str().c_str());
+ }
+
+ int size_3d_cubed = size_3d * size_3d * size_3d;
+
+ if(size_3d_cubed * 3 != static_cast<int>(lut_iter->second.size()))
+ {
+ int foundsize = static_cast<int>(lut_iter->second.size());
+ int foundlines = foundsize / 3;
+
+ std::ostringstream os;
+ os << "3D LUT contains incorrect number of values. ";
+ os << "Contained " << foundsize << " values ";
+ os << "(" << foundlines << " lines), ";
+ os << "expected " << (size_3d_cubed*3) << " values ";
+ os << "(" << size_3d_cubed << " lines)";
+ throw Exception(os.str().c_str());
+ }
+
+ lut3d_ptr->lut = lut_iter->second;
+
+ // Bind to cachedFile
+ cachedFile->lut3D = lut3d_ptr;
+ }
+
+ if(cachedFile->hdltype == "c")
+ {
+ // Bind simple 1D RGB LUT
+ lut_iter = lut_data.find("rgb");
+ if(lut_iter == lut_data.end())
+ {
+ std::ostringstream os;
+ os << "3D+1D LUT should contain Pre{} LUT section";
+ throw Exception(os.str().c_str());
+ }
+
+ if(size_1d != static_cast<int>(lut_iter->second.size()))
+ {
+ std::ostringstream os;
+ os << "RGB{} LUT was " << lut_iter->second.size();
+ os << " values long, expected " << size_1d << " values";
+ throw Exception(os.str().c_str());
+ }
+
+ lut1d_ptr->luts[0] = lut_iter->second;
+ lut1d_ptr->luts[1] = lut_iter->second;
+ lut1d_ptr->luts[2] = lut_iter->second;
+ lut1d_ptr->maxerror = 0.0f;
+ lut1d_ptr->errortype = ERROR_RELATIVE;
+ cachedFile->lut1D = lut1d_ptr;
+ }
+
+ return cachedFile;
+ }
+
+ void LocalFileFormat::Write(const Baker & baker,
+ const std::string & formatName,
+ std::ostream & ostream) const
+ {
+
+ if(formatName != "houdini")
+ {
+ std::ostringstream os;
+ os << "Unknown hdl format name, '";
+ os << formatName << "'.";
+ throw Exception(os.str().c_str());
+ }
+
+ // Get config
+ ConstConfigRcPtr config = baker.getConfig();
+
+ // setup the floating point precision
+ ostream.setf(std::ios::fixed, std::ios::floatfield);
+ ostream.precision(6);
+
+ // Default sizes
+ const int DEFAULT_SHAPER_SIZE = 1024;
+ // MPlay produces bad results with 32^3 cube (in a way
+ // that looks more quantised than even "nearest"
+ // interpolation in OCIOFileTransform)
+ const int DEFAULT_CUBE_SIZE = 64;
+ const int DEFAULT_1D_SIZE = 1024;
+
+ // Get configured sizes
+ int cubeSize = baker.getCubeSize();
+ int shaperSize = baker.getShaperSize();
+ // FIXME: Misusing cube size to set 1D LUT size, as it seemed
+ // slightly less confusing than using the shaper LUT size
+ int onedSize = baker.getCubeSize();
+
+ // Defaults and sanity check on cube size
+ if(cubeSize == -1) cubeSize = DEFAULT_CUBE_SIZE;
+ if(cubeSize < 0) cubeSize = DEFAULT_CUBE_SIZE;
+ if(cubeSize<2)
+ {
+ std::ostringstream os;
+ os << "Cube size must be 2 or larger (was " << cubeSize << ")";
+ throw Exception(os.str().c_str());
+ }
+
+ // ..and same for shaper size
+ if(shaperSize<0) shaperSize = DEFAULT_SHAPER_SIZE;
+ if(shaperSize<2)
+ {
+ std::ostringstream os;
+ os << "A shaper space ('" << baker.getShaperSpace() << "') has";
+ os << " been specified, so the shaper size must be 2 or larger";
+ throw Exception(os.str().c_str());
+ }
+
+ // ..and finally, for the 1D LUT size
+ if(onedSize == -1) onedSize = DEFAULT_1D_SIZE;
+ if(onedSize < 2)
+ {
+ std::ostringstream os;
+ os << "1D LUT size must be higher than 2 (was " << onedSize << ")";
+ throw Exception(os.str().c_str());
+ }
+
+ // Version numbers
+ const int HDL_1D = 1; // 1D LUT version number
+ const int HDL_3D = 2; // 3D LUT version number
+ const int HDL_3D1D = 3; // 3D LUT with 1D prelut
+
+ // Get spaces from baker
+ const std::string shaperSpace = baker.getShaperSpace();
+ const std::string inputSpace = baker.getInputSpace();
+ const std::string targetSpace = baker.getTargetSpace();
+ const std::string looks = baker.getLooks();
+
+ // Determine required LUT type
+ ConstProcessorRcPtr inputToTargetProc;
+ if (!looks.empty())
+ {
+ LookTransformRcPtr transform = LookTransform::Create();
+ transform->setLooks(looks.c_str());
+ transform->setSrc(inputSpace.c_str());
+ transform->setDst(targetSpace.c_str());
+ inputToTargetProc = config->getProcessor(transform,
+ TRANSFORM_DIR_FORWARD);
+ }
+ else
+ {
+ inputToTargetProc = config->getProcessor(
+ inputSpace.c_str(),
+ targetSpace.c_str());
+ }
+
+ int required_lut = -1;
+
+ if(inputToTargetProc->hasChannelCrosstalk())
+ {
+ if(shaperSpace.empty())
+ {
+ // Has crosstalk, but no prelut, so need 3D LUT
+ required_lut = HDL_3D;
+ }
+ else
+ {
+ // Crosstalk with shaper-space
+ required_lut = HDL_3D1D;
+ }
+ }
+ else
+ {
+ // No crosstalk
+ required_lut = HDL_1D;
+ }
+
+ if(required_lut == -1)
+ {
+ // Unnecessary paranoia
+ throw Exception(
+ "Internal logic error, LUT type was not determined");
+ }
+
+ // Make prelut
+ std::vector<float> prelutData;
+
+ float fromInStart = 0; // for "From:" part of header
+ float fromInEnd = 1;
+
+ if(required_lut == HDL_3D1D)
+ {
+ // TODO: Later we only grab the green channel for the prelut,
+ // should ensure the prelut is monochromatic somehow?
+
+ ConstProcessorRcPtr inputToShaperProc = config->getProcessor(
+ inputSpace.c_str(),
+ shaperSpace.c_str());
+
+ if(inputToShaperProc->hasChannelCrosstalk())
+ {
+ // TODO: Automatically turn shaper into
+ // non-crosstalked version?
+ std::ostringstream os;
+ os << "The specified shaperSpace, '" << baker.getShaperSpace();
+ os << "' has channel crosstalk, which is not appropriate for";
+ os << " shapers. Please select an alternate shaper space or";
+ os << " omit this option.";
+ throw Exception(os.str().c_str());
+ }
+
+ // Calculate min/max value
+ {
+ // Get input value of 1.0 in shaper space, as this
+ // is the higest value that is transformed by the
+ // cube (e.g for a generic lin-to-log trasnform,
+ // what the log value 1.0 is in linear).
+ ConstProcessorRcPtr shaperToInputProc = config->getProcessor(
+ shaperSpace.c_str(),
+ inputSpace.c_str());
+
+ float minval[3] = {0.0f, 0.0f, 0.0f};
+ float maxval[3] = {1.0f, 1.0f, 1.0f};
+
+ shaperToInputProc->applyRGB(minval);
+ shaperToInputProc->applyRGB(maxval);
+
+ // Grab green channel, as this is the one used later
+ fromInStart = minval[1];
+ fromInEnd = maxval[1];
+ }
+
+ // Generate the identity prelut values, then apply the transform.
+ // Prelut is linearly sampled from fromInStart to fromInEnd
+ prelutData.resize(shaperSize*3);
+
+ for (int i = 0; i < shaperSize; ++i)
+ {
+ const float x = (float)(double(i) / double(shaperSize - 1));
+ float cur_value = lerpf(fromInStart, fromInEnd, x);
+
+ prelutData[3*i+0] = cur_value;
+ prelutData[3*i+1] = cur_value;
+ prelutData[3*i+2] = cur_value;
+ }
+
+ PackedImageDesc prelutImg(&prelutData[0], shaperSize, 1, 3);
+ inputToShaperProc->apply(prelutImg);
+ }
+
+ // TODO: Do same "auto prelut" input-space allocation as FileFormatCSP?
+
+ // Make 3D LUT
+ std::vector<float> cubeData;
+ if(required_lut == HDL_3D || required_lut == HDL_3D1D)
+ {
+ cubeData.resize(cubeSize*cubeSize*cubeSize*3);
+
+ GenerateIdentityLut3D(&cubeData[0], cubeSize, 3, LUT3DORDER_FAST_RED);
+ PackedImageDesc cubeImg(&cubeData[0], cubeSize*cubeSize*cubeSize, 1, 3);
+
+ ConstProcessorRcPtr cubeProc;
+ if(required_lut == HDL_3D1D)
+ {
+ // Prelut goes from input-to-shaper, so cube goes from shaper-to-target
+ if (!looks.empty())
+ {
+ LookTransformRcPtr transform = LookTransform::Create();
+ transform->setLooks(looks.c_str());
+ transform->setSrc(inputSpace.c_str());
+ transform->setDst(targetSpace.c_str());
+ cubeProc = config->getProcessor(transform,
+ TRANSFORM_DIR_FORWARD);
+ }
+ else
+ {
+ cubeProc = config->getProcessor(shaperSpace.c_str(),
+ targetSpace.c_str());
+ }
+ }
+ else
+ {
+ // No prelut, so cube goes from input-to-target
+ cubeProc = inputToTargetProc;
+ }
+
+
+ cubeProc->apply(cubeImg);
+ }
+
+
+ // Make 1D LUT
+ std::vector<float> onedData;
+ if(required_lut == HDL_1D)
+ {
+ onedData.resize(onedSize * 3);
+
+ GenerateIdentityLut1D(&onedData[0], onedSize, 3);
+ PackedImageDesc onedImg(&onedData[0], onedSize, 1, 3);
+
+ inputToTargetProc->apply(onedImg);
+ }
+
+
+ // Write the file contents
+ ostream << "Version\t\t" << required_lut << "\n";
+ ostream << "Format\t\t" << "any" << "\n";
+
+ ostream << "Type\t\t";
+ if(required_lut == HDL_1D)
+ ostream << "RGB";
+ if(required_lut == HDL_3D)
+ ostream << "3D";
+ if(required_lut == HDL_3D1D)
+ ostream << "3D+1D";
+ ostream << "\n";
+
+ ostream << "From\t\t" << fromInStart << " " << fromInEnd << "\n";
+ ostream << "To\t\t" << 0.0f << " " << 1.0f << "\n";
+ ostream << "Black\t\t" << 0.0f << "\n";
+ ostream << "White\t\t" << 1.0f << "\n";
+
+ if(required_lut == HDL_3D1D)
+ ostream << "Length\t\t" << cubeSize << " " << shaperSize << "\n";
+ if(required_lut == HDL_3D)
+ ostream << "Length\t\t" << cubeSize << "\n";
+ if(required_lut == HDL_1D)
+ ostream << "Length\t\t" << onedSize << "\n";
+
+ ostream << "LUT:\n";
+
+ // Write prelut
+ if(required_lut == HDL_3D1D)
+ {
+ ostream << "Pre {\n";
+ for(int i=0; i < shaperSize; ++i)
+ {
+ // Grab green channel from RGB prelut
+ ostream << "\t" << prelutData[i*3+1] << "\n";
+ }
+ ostream << "}\n";
+ }
+
+ // Write "3D {" part of output of 3D+1D LUT
+ if(required_lut == HDL_3D1D)
+ {
+ ostream << "3D {\n";
+ }
+
+ // Write the slightly-different "{" without line for the 3D-only LUT
+ if(required_lut == HDL_3D)
+ {
+ ostream << " {\n";
+ }
+
+ // Write the cube data after the "{"
+ if(required_lut == HDL_3D || required_lut == HDL_3D1D)
+ {
+ for(int i=0; i < cubeSize*cubeSize*cubeSize; ++i)
+ {
+ // TODO: Original baker code clamped values to
+ // 1.0, was this necessary/desirable?
+
+ ostream << "\t" << cubeData[3*i+0];
+ ostream << " " << cubeData[3*i+1];
+ ostream << " " << cubeData[3*i+2] << "\n";
+ }
+
+ // Write closing "}"
+ ostream << " }\n";
+ }
+
+ // Write out channels for 1D LUT
+ if(required_lut == HDL_1D)
+ {
+ ostream << "R {\n";
+ for(int i=0; i < onedSize; ++i)
+ ostream << "\t" << onedData[i*3+0] << "\n";
+ ostream << "}\n";
+
+ ostream << "G {\n";
+ for(int i=0; i < onedSize; ++i)
+ ostream << "\t" << onedData[i*3+1] << "\n";
+ ostream << "}\n";
+
+ ostream << "B {\n";
+ for(int i=0; i < onedSize; ++i)
+ ostream << "\t" << onedData[i*3+2] << "\n";
+ ostream << "}\n";
+ }
+ }
+
+ void
+ LocalFileFormat::BuildFileOps(OpRcPtrVec & ops,
+ const Config& /*config*/,
+ const ConstContextRcPtr & /*context*/,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const
+ {
+
+ CachedFileHDLRcPtr cachedFile = DynamicPtrCast<CachedFileHDL>(untypedCachedFile);
+
+ // This should never happen.
+ if(!cachedFile)
+ {
+ std::ostringstream os;
+ os << "Cannot build Houdini Op. Invalid cache type.";
+ throw Exception(os.str().c_str());
+ }
+
+ TransformDirection newDir = CombineTransformDirections(dir,
+ fileTransform.getDirection());
+
+ if(newDir == TRANSFORM_DIR_FORWARD) {
+ if(cachedFile->hdltype == "c")
+ {
+ CreateLut1DOp(ops, cachedFile->lut1D,
+ fileTransform.getInterpolation(), newDir);
+ }
+ else if(cachedFile->hdltype == "3d")
+ {
+ CreateLut3DOp(ops, cachedFile->lut3D,
+ fileTransform.getInterpolation(), newDir);
+ }
+ else if(cachedFile->hdltype == "3d+1d")
+ {
+ CreateLut1DOp(ops, cachedFile->lut1D,
+ fileTransform.getInterpolation(), newDir);
+ CreateLut3DOp(ops, cachedFile->lut3D,
+ fileTransform.getInterpolation(), newDir);
+ }
+ else
+ {
+ throw Exception("Unhandled hdltype while creating forward ops");
+ }
+ } else if(newDir == TRANSFORM_DIR_INVERSE) {
+ if(cachedFile->hdltype == "c")
+ {
+ CreateLut1DOp(ops, cachedFile->lut1D,
+ fileTransform.getInterpolation(), newDir);
+ }
+ else if(cachedFile->hdltype == "3d")
+ {
+ CreateLut3DOp(ops, cachedFile->lut3D,
+ fileTransform.getInterpolation(), newDir);
+ }
+ else if(cachedFile->hdltype == "3d+1d")
+ {
+ CreateLut3DOp(ops, cachedFile->lut3D,
+ fileTransform.getInterpolation(), newDir);
+ CreateLut1DOp(ops, cachedFile->lut1D,
+ fileTransform.getInterpolation(), newDir);
+ }
+ else
+ {
+ throw Exception("Unhandled hdltype while creating reverse ops");
+ }
+ }
+ return;
+ }
+ }
+
+ FileFormat * CreateFileFormatHDL()
+ {
+ return new LocalFileFormat();
+ }
+}
+OCIO_NAMESPACE_EXIT
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef OCIO_UNIT_TEST
+
+namespace OCIO = OCIO_NAMESPACE;
+#include "UnitTest.h"
+
+OIIO_ADD_TEST(FileFormatHDL, Read1D)
+{
+ std::ostringstream strebuf;
+ strebuf << "Version\t\t1" << "\n";
+ strebuf << "Format\t\tany" << "\n";
+ strebuf << "Type\t\tC" << "\n";
+ strebuf << "From\t\t0.1 3.2" << "\n";
+ strebuf << "To\t\t0 1" << "\n";
+ strebuf << "Black\t\t0" << "\n";
+ strebuf << "White\t\t0.99" << "\n";
+ strebuf << "Length\t\t9" << "\n";
+ strebuf << "LUT:" << "\n";
+ strebuf << "RGB {" << "\n";
+ strebuf << "\t0" << "\n";
+ strebuf << "\t0.000977517" << "\n";
+ strebuf << "\t0.00195503" << "\n";
+ strebuf << "\t0.00293255" << "\n";
+ strebuf << "\t0.00391007" << "\n";
+ strebuf << "\t0.00488759" << "\n";
+ strebuf << "\t0.0058651" << "\n";
+ strebuf << "\t0.999022" << "\n";
+ strebuf << "\t1.67 }" << "\n";
+
+ //
+ float from_min = 0.1f;
+ float from_max = 3.2f;
+ float to_min = 0.0f;
+ float to_max = 1.0f;
+ float black = 0.0f;
+ float white = 0.99f;
+ float lut1d[9] = { 0.0f, 0.000977517f, 0.00195503f, 0.00293255f,
+ 0.00391007f, 0.00488759f, 0.0058651f, 0.999022f, 1.67f };
+
+ std::istringstream simple3D1D;
+ simple3D1D.str(strebuf.str());
+
+ // Load file
+ OCIO::LocalFileFormat tester;
+ OCIO::CachedFileRcPtr cachedFile = tester.Read(simple3D1D);
+ OCIO::CachedFileHDLRcPtr lut = OCIO::DynamicPtrCast<OCIO::CachedFileHDL>(cachedFile);
+
+ //
+ OIIO_CHECK_EQUAL(to_min, lut->to_min);
+ OIIO_CHECK_EQUAL(to_max, lut->to_max);
+ OIIO_CHECK_EQUAL(black, lut->hdlblack);
+ OIIO_CHECK_EQUAL(white, lut->hdlwhite);
+
+ // check 1D data (each channel has the same data)
+ for(int c = 0; c < 3; ++c) {
+ OIIO_CHECK_EQUAL(from_min, lut->lut1D->from_min[c]);
+ OIIO_CHECK_EQUAL(from_max, lut->lut1D->from_max[c]);
+
+ OIIO_CHECK_EQUAL(9, lut->lut1D->luts[c].size());
+
+ for(unsigned int i = 0; i < lut->lut1D->luts[c].size(); ++i) {
+ OIIO_CHECK_EQUAL(lut1d[i], lut->lut1D->luts[c][i]);
+ }
+ }
+}
+
+OIIO_ADD_TEST(FileFormatHDL, Bake1D)
+{
+
+ OCIO::ConfigRcPtr config = OCIO::Config::Create();
+
+ // Add lnf space
+ {
+ OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create();
+ cs->setName("lnf");
+ cs->setFamily("lnf");
+ config->addColorSpace(cs);
+ config->setRole(OCIO::ROLE_REFERENCE, cs->getName());
+ }
+
+ // Add target space
+ {
+ OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create();
+ cs->setName("target");
+ cs->setFamily("target");
+ OCIO::CDLTransformRcPtr transform1 = OCIO::CDLTransform::Create();
+
+ float rgb[3] = {0.1f, 0.1f, 0.1f};
+ transform1->setOffset(rgb);
+
+ cs->setTransform(transform1, OCIO::COLORSPACE_DIR_FROM_REFERENCE);
+ config->addColorSpace(cs);
+ }
+
+ std::string bout =
+ "Version\t\t1\n"
+ "Format\t\tany\n"
+ "Type\t\tRGB\n"
+ "From\t\t0.000000 1.000000\n"
+ "To\t\t0.000000 1.000000\n"
+ "Black\t\t0.000000\n"
+ "White\t\t1.000000\n"
+ "Length\t\t10\n"
+ "LUT:\n"
+ "R {\n"
+ "\t0.100000\n"
+ "\t0.211111\n"
+ "\t0.322222\n"
+ "\t0.433333\n"
+ "\t0.544444\n"
+ "\t0.655556\n"
+ "\t0.766667\n"
+ "\t0.877778\n"
+ "\t0.988889\n"
+ "\t1.100000\n"
+ " }\n"
+ "G {\n"
+ "\t0.100000\n"
+ "\t0.211111\n"
+ "\t0.322222\n"
+ "\t0.433333\n"
+ "\t0.544444\n"
+ "\t0.655556\n"
+ "\t0.766667\n"
+ "\t0.877778\n"
+ "\t0.988889\n"
+ "\t1.100000\n"
+ " }\n"
+ "B {\n"
+ "\t0.100000\n"
+ "\t0.211111\n"
+ "\t0.322222\n"
+ "\t0.433333\n"
+ "\t0.544444\n"
+ "\t0.655556\n"
+ "\t0.766667\n"
+ "\t0.877778\n"
+ "\t0.988889\n"
+ "\t1.100000\n"
+ " }\n";
+
+ //
+ OCIO::BakerRcPtr baker = OCIO::Baker::Create();
+ baker->setConfig(config);
+ baker->setFormat("houdini");
+ baker->setInputSpace("lnf");
+ baker->setTargetSpace("target");
+ baker->setCubeSize(10); // FIXME: Misusing the cube size to set the 1D LUT size
+ std::ostringstream output;
+ baker->bake(output);
+
+ //std::cerr << "The LUT: " << std::endl << output.str() << std::endl;
+ //std::cerr << "Expected:" << std::endl << bout << std::endl;
+
+ //
+ std::vector<std::string> osvec;
+ OCIO::pystring::splitlines(output.str(), osvec);
+ std::vector<std::string> resvec;
+ OCIO::pystring::splitlines(bout, resvec);
+ OIIO_CHECK_EQUAL(osvec.size(), resvec.size());
+ for(unsigned int i = 0; i < std::min(osvec.size(), resvec.size()); ++i)
+ OIIO_CHECK_EQUAL(OCIO::pystring::strip(osvec[i]), OCIO::pystring::strip(resvec[i]));
+
+}
+
+OIIO_ADD_TEST(FileFormatHDL, Read3D)
+{
+ std::ostringstream strebuf;
+ strebuf << "Version 2" << "\n";
+ strebuf << "Format any" << "\n";
+ strebuf << "Type 3D" << "\n";
+ strebuf << "From 0.2 0.9" << "\n";
+ strebuf << "To 0.001 0.999" << "\n";
+ strebuf << "Black 0.002" << "\n";
+ strebuf << "White 0.98" << "\n";
+ strebuf << "Length 2" << "\n";
+ strebuf << "LUT:" << "\n";
+ strebuf << " {" << "\n";
+ strebuf << " 0 0 0" << "\n";
+ strebuf << " 0 0 0" << "\n";
+ strebuf << " 0 0.390735 2.68116e-28" << "\n";
+ strebuf << " 0 0.390735 0" << "\n";
+ strebuf << " 0 0 0" << "\n";
+ strebuf << " 0 0 0.599397" << "\n";
+ strebuf << " 0 0.601016 0" << "\n";
+ strebuf << " 0 0.601016 0.917034" << "\n";
+ strebuf << " }" << "\n";
+
+ std::istringstream simple3D1D;
+ simple3D1D.str(strebuf.str());
+ // Load file
+ OCIO::LocalFileFormat tester;
+ OCIO::CachedFileRcPtr cachedFile = tester.Read(simple3D1D);
+ OCIO::CachedFileHDLRcPtr lut = OCIO::DynamicPtrCast<OCIO::CachedFileHDL>(cachedFile);
+
+ //
+ //float from_min = 0.2;
+ //float from_max = 0.9;
+ float to_min = 0.001f;
+ float to_max = 0.999f;
+ float black = 0.002f;
+ float white = 0.98f;
+ float cube[2 * 2 * 2 * 3 ] = {
+ 0.f, 0.f, 0.f,
+ 0.f, 0.f, 0.f,
+ 0.f, 0.390735f, 2.68116e-28f,
+ 0.f, 0.390735f, 0.f,
+ 0.f, 0.f, 0.f,
+ 0.f, 0.f, 0.599397f,
+ 0.f, 0.601016f, 0.f,
+ 0.f, 0.601016f, 0.917034f };
+
+ //
+ OIIO_CHECK_EQUAL(to_min, lut->to_min);
+ OIIO_CHECK_EQUAL(to_max, lut->to_max);
+ OIIO_CHECK_EQUAL(black, lut->hdlblack);
+ OIIO_CHECK_EQUAL(white, lut->hdlwhite);
+
+ // check cube data
+ OIIO_CHECK_EQUAL(2*2*2*3, lut->lut3D->lut.size());
+
+ for(unsigned int i = 0; i < lut->lut3D->lut.size(); ++i) {
+ OIIO_CHECK_EQUAL(cube[i], lut->lut3D->lut[i]);
+ }
+}
+
+OIIO_ADD_TEST(FileFormatHDL, Bake3D)
+{
+ OCIO::ConfigRcPtr config = OCIO::Config::Create();
+
+ // Set luma coef's to simple values
+ {
+ float lumaCoef[3] = {0.333f, 0.333f, 0.333f};
+ config->setDefaultLumaCoefs(lumaCoef);
+ }
+
+ // Add lnf space
+ {
+ OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create();
+ cs->setName("lnf");
+ cs->setFamily("lnf");
+ config->addColorSpace(cs);
+ config->setRole(OCIO::ROLE_REFERENCE, cs->getName());
+ }
+
+ // Add target space
+ {
+ OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create();
+ cs->setName("target");
+ cs->setFamily("target");
+ OCIO::CDLTransformRcPtr transform1 = OCIO::CDLTransform::Create();
+
+ // Set saturation to cause channel crosstalk, making a 3D LUT
+ transform1->setSat(0.5f);
+
+ cs->setTransform(transform1, OCIO::COLORSPACE_DIR_FROM_REFERENCE);
+ config->addColorSpace(cs);
+ }
+
+ std::string bout =
+ "Version\t\t2\n"
+ "Format\t\tany\n"
+ "Type\t\t3D\n"
+ "From\t\t0.000000 1.000000\n"
+ "To\t\t0.000000 1.000000\n"
+ "Black\t\t0.000000\n"
+ "White\t\t1.000000\n"
+ "Length\t\t2\n"
+ "LUT:\n"
+ " {\n"
+ "\t0.000000 0.000000 0.000000\n"
+ "\t0.606300 0.106300 0.106300\n"
+ "\t0.357600 0.857600 0.357600\n"
+ "\t0.963900 0.963900 0.463900\n"
+ "\t0.036100 0.036100 0.536100\n"
+ "\t0.642400 0.142400 0.642400\n"
+ "\t0.393700 0.893700 0.893700\n"
+ "\t1.000000 1.000000 1.000000\n"
+ " }\n";
+
+ //
+ OCIO::BakerRcPtr baker = OCIO::Baker::Create();
+ baker->setConfig(config);
+ baker->setFormat("houdini");
+ baker->setInputSpace("lnf");
+ baker->setTargetSpace("target");
+ baker->setCubeSize(2);
+ std::ostringstream output;
+ baker->bake(output);
+
+ //std::cerr << "The LUT: " << std::endl << output.str() << std::endl;
+ //std::cerr << "Expected:" << std::endl << bout << std::endl;
+
+ //
+ std::vector<std::string> osvec;
+ OCIO::pystring::splitlines(output.str(), osvec);
+ std::vector<std::string> resvec;
+ OCIO::pystring::splitlines(bout, resvec);
+ OIIO_CHECK_EQUAL(osvec.size(), resvec.size());
+ for(unsigned int i = 0; i < std::min(osvec.size(), resvec.size()); ++i)
+ OIIO_CHECK_EQUAL(OCIO::pystring::strip(osvec[i]), OCIO::pystring::strip(resvec[i]));
+}
+
+OIIO_ADD_TEST(FileFormatHDL, Read3D1D)
+{
+ std::ostringstream strebuf;
+ strebuf << "Version 3" << "\n";
+ strebuf << "Format any" << "\n";
+ strebuf << "Type 3D+1D" << "\n";
+ strebuf << "From 0.005478 14.080103" << "\n";
+ strebuf << "To 0 1" << "\n";
+ strebuf << "Black 0" << "\n";
+ strebuf << "White 1" << "\n";
+ strebuf << "Length 2 10" << "\n";
+ strebuf << "LUT:" << "\n";
+ strebuf << "Pre {" << "\n";
+ strebuf << " 0.994922" << "\n";
+ strebuf << " 0.995052" << "\n";
+ strebuf << " 0.995181" << "\n";
+ strebuf << " 0.995310" << "\n";
+ strebuf << " 0.995439" << "\n";
+ strebuf << " 0.995568" << "\n";
+ strebuf << " 0.995697" << "\n";
+ strebuf << " 0.995826" << "\n";
+ strebuf << " 0.995954" << "\n";
+ strebuf << " 0.996082" << "\n";
+ strebuf << "}" << "\n";
+ strebuf << "3D {" << "\n";
+ strebuf << " 0.093776 0.093776 0.093776" << "\n";
+ strebuf << " 0.105219 0.093776 0.093776" << "\n";
+ strebuf << " 0.118058 0.093776 0.093776" << "\n";
+ strebuf << " 0.132463 0.093776 0.093776" << "\n";
+ strebuf << " 0.148626 0.093776 0.093776" << "\n";
+ strebuf << " 0.166761 0.093776 0.093776" << "\n";
+ strebuf << " 0.187109 0.093776 0.093776" << "\n";
+ strebuf << " 0.209939 0.093776 0.093776" << "\n";
+ strebuf << "}" << "\n";
+
+ //
+ float from_min = 0.005478f;
+ float from_max = 14.080103f;
+ float to_min = 0.0f;
+ float to_max = 1.0f;
+ float black = 0.0f;
+ float white = 1.0f;
+ float prelut[10] = { 0.994922f, 0.995052f, 0.995181f, 0.995310f, 0.995439f,
+ 0.995568f, 0.995697f, 0.995826f, 0.995954f, 0.996082f };
+ float cube[2 * 2 * 2 * 3 ] = {
+ 0.093776f, 0.093776f, 0.093776f,
+ 0.105219f, 0.093776f, 0.093776f,
+ 0.118058f, 0.093776f, 0.093776f,
+ 0.132463f, 0.093776f, 0.093776f,
+ 0.148626f, 0.093776f, 0.093776f,
+ 0.166761f, 0.093776f, 0.093776f,
+ 0.187109f, 0.093776f, 0.093776f,
+ 0.209939f, 0.093776f, 0.093776f };
+
+ std::istringstream simple3D1D;
+ simple3D1D.str(strebuf.str());
+
+ // Load file
+ OCIO::LocalFileFormat tester;
+ OCIO::CachedFileRcPtr cachedFile = tester.Read(simple3D1D);
+ OCIO::CachedFileHDLRcPtr lut = OCIO::DynamicPtrCast<OCIO::CachedFileHDL>(cachedFile);
+
+ //
+ OIIO_CHECK_EQUAL(to_min, lut->to_min);
+ OIIO_CHECK_EQUAL(to_max, lut->to_max);
+ OIIO_CHECK_EQUAL(black, lut->hdlblack);
+ OIIO_CHECK_EQUAL(white, lut->hdlwhite);
+
+ // check prelut data (each channel has the same data)
+ for(int c = 0; c < 3; ++c) {
+ OIIO_CHECK_EQUAL(from_min, lut->lut1D->from_min[c]);
+ OIIO_CHECK_EQUAL(from_max, lut->lut1D->from_max[c]);
+ OIIO_CHECK_EQUAL(10, lut->lut1D->luts[c].size());
+
+ for(unsigned int i = 0; i < lut->lut1D->luts[c].size(); ++i) {
+ OIIO_CHECK_EQUAL(prelut[i], lut->lut1D->luts[c][i]);
+ }
+ }
+
+ OIIO_CHECK_EQUAL(2*2*2*3, lut->lut3D->lut.size());
+
+ // check cube data
+ for(unsigned int i = 0; i < lut->lut3D->lut.size(); ++i) {
+ OIIO_CHECK_EQUAL(cube[i], lut->lut3D->lut[i]);
+ }
+}
+
+OIIO_ADD_TEST(FileFormatHDL, Bake3D1D)
+{
+ // check baker output
+ OCIO::ConfigRcPtr config = OCIO::Config::Create();
+
+ // Set luma coef's to simple values
+ {
+ float lumaCoef[3] = {0.333f, 0.333f, 0.333f};
+ config->setDefaultLumaCoefs(lumaCoef);
+ }
+
+ // Add lnf space
+ {
+ OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create();
+ cs->setName("lnf");
+ cs->setFamily("lnf");
+ config->addColorSpace(cs);
+ config->setRole(OCIO::ROLE_REFERENCE, cs->getName());
+ }
+
+ // Add shaper space
+ {
+ OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create();
+ cs->setName("shaper");
+ cs->setFamily("shaper");
+ OCIO::ExponentTransformRcPtr transform1 = OCIO::ExponentTransform::Create();
+ float test[4] = {2.6f, 2.6f, 2.6f, 1.0f};
+ transform1->setValue(test);
+ cs->setTransform(transform1, OCIO::COLORSPACE_DIR_TO_REFERENCE);
+ config->addColorSpace(cs);
+ }
+
+ // Add target space
+ {
+ OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create();
+ cs->setName("target");
+ cs->setFamily("target");
+ OCIO::CDLTransformRcPtr transform1 = OCIO::CDLTransform::Create();
+
+ // Set saturation to cause channel crosstalk, making a 3D LUT
+ transform1->setSat(0.5f);
+
+ cs->setTransform(transform1, OCIO::COLORSPACE_DIR_FROM_REFERENCE);
+ config->addColorSpace(cs);
+ }
+
+ std::string bout =
+ "Version\t\t3\n"
+ "Format\t\tany\n"
+ "Type\t\t3D+1D\n"
+ "From\t\t0.000000 1.000000\n"
+ "To\t\t0.000000 1.000000\n"
+ "Black\t\t0.000000\n"
+ "White\t\t1.000000\n"
+ "Length\t\t2 10\n"
+ "LUT:\n"
+ "Pre {\n"
+ "\t0.000000\n"
+ "\t0.429520\n"
+ "\t0.560744\n"
+ "\t0.655378\n"
+ "\t0.732057\n"
+ "\t0.797661\n"
+ "\t0.855604\n"
+ "\t0.907865\n"
+ "\t0.955710\n"
+ "\t1.000000\n"
+ "}\n"
+ "3D {\n"
+ "\t0.000000 0.000000 0.000000\n"
+ "\t0.606300 0.106300 0.106300\n"
+ "\t0.357600 0.857600 0.357600\n"
+ "\t0.963900 0.963900 0.463900\n"
+ "\t0.036100 0.036100 0.536100\n"
+ "\t0.642400 0.142400 0.642400\n"
+ "\t0.393700 0.893700 0.893700\n"
+ "\t1.000000 1.000000 1.000000\n"
+ "}\n";
+
+ //
+ OCIO::BakerRcPtr baker = OCIO::Baker::Create();
+ baker->setConfig(config);
+ baker->setFormat("houdini");
+ baker->setInputSpace("lnf");
+ baker->setShaperSpace("shaper");
+ baker->setTargetSpace("target");
+ baker->setShaperSize(10);
+ baker->setCubeSize(2);
+ std::ostringstream output;
+ baker->bake(output);
+
+ //std::cerr << "The LUT: " << std::endl << output.str() << std::endl;
+ //std::cerr << "Expected:" << std::endl << bout << std::endl;
+
+ //
+ std::vector<std::string> osvec;
+ OCIO::pystring::splitlines(output.str(), osvec);
+ std::vector<std::string> resvec;
+ OCIO::pystring::splitlines(bout, resvec);
+ OIIO_CHECK_EQUAL(osvec.size(), resvec.size());
+
+ // TODO: Get this working on osx
+ /*
+ for(unsigned int i = 0; i < std::min(osvec.size(), resvec.size()); ++i)
+ OIIO_CHECK_EQUAL(OCIO::pystring::strip(osvec[i]), OCIO::pystring::strip(resvec[i]));
+ */
+}
+
+#endif // OCIO_BUILD_TESTS
diff --git a/src/core/FileFormatIridasCube.cpp b/src/core/FileFormatIridasCube.cpp
new file mode 100644
index 0000000..6b2a496
--- /dev/null
+++ b/src/core/FileFormatIridasCube.cpp
@@ -0,0 +1,398 @@
+/*
+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 <cstdio>
+#include <cstring>
+#include <iterator>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "FileTransform.h"
+#include "Lut1DOp.h"
+#include "Lut3DOp.h"
+#include "ParseUtils.h"
+#include "pystring/pystring.h"
+
+/*
+
+http://doc.iridas.com/index.php/LUT_Formats
+
+#comments start with '#'
+#title is currently ignored, but it's not an error to enter one
+TITLE "title"
+
+#LUT_1D_SIZE M or
+#LUT_3D_SIZE M
+#where M is the size of the texture
+#a 3D texture has the size M x M x M
+#e.g. LUT_3D_SIZE 16 creates a 16 x 16 x 16 3D texture
+LUT_3D_SIZE 2
+
+#Default input value range (domain) is 0.0 (black) to 1.0 (white)
+#Specify other min/max values to map the cube to any custom input
+#range you wish to use, for example if you're working with HDR data
+DOMAIN_MIN 0.0 0.0 0.0
+DOMAIN_MAX 1.0 1.0 1.0
+
+#for 1D textures, the data is simply a list of floating point values,
+#three per line, in RGB order
+#for 3D textures, the data is also RGB, and ordered in such a way
+#that the red coordinate changes fastest, then the green coordinate,
+#and finally, the blue coordinate changes slowest:
+0.0 0.0 0.0
+1.0 0.0 0.0
+0.0 1.0 0.0
+1.0 1.0 0.0
+0.0 0.0 1.0
+1.0 0.0 1.0
+0.0 1.0 1.0
+1.0 1.0 1.0
+
+#Note that the LUT data is not limited to any particular range
+#and can contain values under 0.0 and over 1.0
+#The processing application might however still clip the
+#output values to the 0.0 - 1.0 range, depending on the internal
+#precision of that application's pipeline
+#IRIDAS applications generally use a floating point pipeline
+#with little or no clipping
+
+
+*/
+
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ class LocalCachedFile : public CachedFile
+ {
+ public:
+ LocalCachedFile () :
+ has1D(false),
+ has3D(false)
+ {
+ lut1D = Lut1D::Create();
+ lut3D = Lut3D::Create();
+ };
+ ~LocalCachedFile() {};
+
+ bool has1D;
+ bool has3D;
+ Lut1DRcPtr lut1D;
+ Lut3DRcPtr lut3D;
+ };
+
+ typedef OCIO_SHARED_PTR<LocalCachedFile> LocalCachedFileRcPtr;
+
+
+
+ class LocalFileFormat : public FileFormat
+ {
+ public:
+
+ ~LocalFileFormat() {};
+
+ virtual void GetFormatInfo(FormatInfoVec & formatInfoVec) const;
+
+ virtual CachedFileRcPtr Read(std::istream & istream) const;
+
+ virtual void BuildFileOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const;
+ };
+
+ void LocalFileFormat::GetFormatInfo(FormatInfoVec & formatInfoVec) const
+ {
+ FormatInfo info;
+ info.name = "iridas_cube";
+ info.extension = "cube";
+ info.capabilities = FORMAT_CAPABILITY_READ;
+ formatInfoVec.push_back(info);
+ }
+
+ CachedFileRcPtr
+ LocalFileFormat::Read(std::istream & istream) const
+ {
+ // this shouldn't happen
+ if(!istream)
+ {
+ throw Exception ("File stream empty when trying to read Iridas .cube lut");
+ }
+
+ // Parse the file
+ std::vector<float> raw;
+
+ int size3d[] = { 0, 0, 0 };
+ int size1d = 0;
+
+ bool in1d = false;
+ bool in3d = false;
+
+ float domain_min[] = { 0.0f, 0.0f, 0.0f };
+ float domain_max[] = { 1.0f, 1.0f, 1.0f };
+
+ {
+ std::string line;
+ std::vector<std::string> parts;
+ std::vector<float> tmpfloats;
+
+ while(nextline(istream, line))
+ {
+ // All lines starting with '#' are comments
+ if(pystring::startswith(line,"#")) continue;
+
+ // Strip, lowercase, and split the line
+ pystring::split(pystring::lower(pystring::strip(line)), parts);
+ if(parts.empty()) continue;
+
+ if(pystring::lower(parts[0]) == "title")
+ {
+ // Optional, and currently unhandled
+ }
+ else if(pystring::lower(parts[0]) == "lut_1d_size")
+ {
+ if(parts.size() != 2 || !StringToInt( &size1d, parts[1].c_str()))
+ {
+ throw Exception("Malformed LUT_1D_SIZE tag in Iridas .cube lut.");
+ }
+
+ raw.reserve(3*size1d);
+ in1d = true;
+ }
+ else if(pystring::lower(parts[0]) == "lut_2d_size")
+ {
+ throw Exception("Unsupported Iridas .cube lut tag: 'LUT_2D_SIZE'.");
+ }
+ else if(pystring::lower(parts[0]) == "lut_3d_size")
+ {
+ int size = 0;
+
+ if(parts.size() != 2 || !StringToInt( &size, parts[1].c_str()))
+ {
+ throw Exception("Malformed LUT_3D_SIZE tag in Iridas .cube lut.");
+ }
+ size3d[0] = size;
+ size3d[1] = size;
+ size3d[2] = size;
+
+ raw.reserve(3*size3d[0]*size3d[1]*size3d[2]);
+ in3d = true;
+ }
+ else if(pystring::lower(parts[0]) == "domain_min")
+ {
+ if(parts.size() != 4 ||
+ !StringToFloat( &domain_min[0], parts[1].c_str()) ||
+ !StringToFloat( &domain_min[1], parts[2].c_str()) ||
+ !StringToFloat( &domain_min[2], parts[3].c_str()))
+ {
+ throw Exception("Malformed DOMAIN_MIN tag in Iridas .cube lut.");
+ }
+ }
+ else if(pystring::lower(parts[0]) == "domain_max")
+ {
+ if(parts.size() != 4 ||
+ !StringToFloat( &domain_max[0], parts[1].c_str()) ||
+ !StringToFloat( &domain_max[1], parts[2].c_str()) ||
+ !StringToFloat( &domain_max[2], parts[3].c_str()))
+ {
+ throw Exception("Malformed DOMAIN_MAX tag in Iridas .cube lut.");
+ }
+ }
+ else
+ {
+ // It must be a float triple!
+
+ if(!StringVecToFloatVec(tmpfloats, parts) || tmpfloats.size() != 3)
+ {
+ std::ostringstream os;
+ os << "Malformed color triples specified in Iridas .cube lut:";
+ os << "'" << line << "'.";
+ throw Exception(os.str().c_str());
+ }
+
+ for(int i=0; i<3; ++i)
+ {
+ raw.push_back(tmpfloats[i]);
+ }
+ }
+ }
+ }
+
+ // Interpret the parsed data, validate lut sizes
+
+ LocalCachedFileRcPtr cachedFile = LocalCachedFileRcPtr(new LocalCachedFile());
+
+ if(in1d)
+ {
+ if(size1d != static_cast<int>(raw.size()/3))
+ {
+ std::ostringstream os;
+ os << "Parse error in Iridas .cube lut. ";
+ os << "Incorrect number of lut1d entries. ";
+ os << "Found " << raw.size()/3 << ", expected " << size1d << ".";
+ throw Exception(os.str().c_str());
+ }
+
+ // Reformat 1D data
+ if(size1d>0)
+ {
+ cachedFile->has1D = true;
+ memcpy(cachedFile->lut1D->from_min, domain_min, 3*sizeof(float));
+ memcpy(cachedFile->lut1D->from_max, domain_max, 3*sizeof(float));
+
+ for(int channel=0; channel<3; ++channel)
+ {
+ cachedFile->lut1D->luts[channel].resize(size1d);
+ for(int i=0; i<size1d; ++i)
+ {
+ cachedFile->lut1D->luts[channel][i] = raw[3*i+channel];
+ }
+ }
+
+ // 1e-5 rel error is a good threshold when float numbers near 0
+ // are written out with 6 decimal places of precision. This is
+ // a bit aggressive, I.e., changes in the 6th decimal place will
+ // be considered roundoff error, but changes in the 5th decimal
+ // will be considered lut 'intent'.
+ // 1.0
+ // 1.000005 equal to 1.0
+ // 1.000007 equal to 1.0
+ // 1.000010 not equal
+ // 0.0
+ // 0.000001 not equal
+
+ cachedFile->lut1D->maxerror = 1e-5f;
+ cachedFile->lut1D->errortype = ERROR_RELATIVE;
+ }
+ }
+ else if(in3d)
+ {
+ cachedFile->has3D = true;
+
+ if(size3d[0]*size3d[1]*size3d[2] != static_cast<int>(raw.size()/3))
+ {
+ std::ostringstream os;
+ os << "Parse error in Iridas .cube lut. ";
+ os << "Incorrect number of lut3d entries. ";
+ os << "Found " << raw.size()/3 << ", expected " << size3d[0]*size3d[1]*size3d[2] << ".";
+ throw Exception(os.str().c_str());
+ }
+
+ // Reformat 3D data
+ memcpy(cachedFile->lut3D->from_min, domain_min, 3*sizeof(float));
+ memcpy(cachedFile->lut3D->from_max, domain_max, 3*sizeof(float));
+ cachedFile->lut3D->size[0] = size3d[0];
+ cachedFile->lut3D->size[1] = size3d[1];
+ cachedFile->lut3D->size[2] = size3d[2];
+ cachedFile->lut3D->lut = raw;
+ }
+ else
+ {
+ std::ostringstream os;
+ os << "Parse error in Iridas .cube lut. ";
+ os << "Lut type (1D/3D) unspecified.";
+ throw Exception(os.str().c_str());
+ }
+
+ return cachedFile;
+ }
+
+ void
+ LocalFileFormat::BuildFileOps(OpRcPtrVec & ops,
+ const Config& /*config*/,
+ const ConstContextRcPtr & /*context*/,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const
+ {
+ LocalCachedFileRcPtr cachedFile = DynamicPtrCast<LocalCachedFile>(untypedCachedFile);
+
+ // This should never happen.
+ if(!cachedFile)
+ {
+ std::ostringstream os;
+ os << "Cannot build Iridas .cube Op. Invalid cache type.";
+ throw Exception(os.str().c_str());
+ }
+
+ TransformDirection newDir = CombineTransformDirections(dir,
+ fileTransform.getDirection());
+ if(newDir == TRANSFORM_DIR_UNKNOWN)
+ {
+ std::ostringstream os;
+ os << "Cannot build file format transform,";
+ os << " unspecified transform direction.";
+ throw Exception(os.str().c_str());
+ }
+
+ // TODO: INTERP_LINEAR should not be hard-coded.
+ // Instead query 'highest' interpolation?
+ // (right now, it's linear). If cubic is added, consider
+ // using it
+
+ if(newDir == TRANSFORM_DIR_FORWARD)
+ {
+ if(cachedFile->has1D)
+ {
+ CreateLut1DOp(ops, cachedFile->lut1D,
+ INTERP_LINEAR, newDir);
+ }
+ if(cachedFile->has3D)
+ {
+ CreateLut3DOp(ops, cachedFile->lut3D,
+ fileTransform.getInterpolation(), newDir);
+ }
+ }
+ else if(newDir == TRANSFORM_DIR_INVERSE)
+ {
+ if(cachedFile->has3D)
+ {
+ CreateLut3DOp(ops, cachedFile->lut3D,
+ fileTransform.getInterpolation(), newDir);
+ }
+ if(cachedFile->has1D)
+ {
+ CreateLut1DOp(ops, cachedFile->lut1D,
+ INTERP_LINEAR, newDir);
+ }
+ }
+ }
+ }
+
+ FileFormat * CreateFileFormatIridasCube()
+ {
+ return new LocalFileFormat();
+ }
+}
+OCIO_NAMESPACE_EXIT
+
+
+///////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/FileFormatIridasItx.cpp b/src/core/FileFormatIridasItx.cpp
new file mode 100644
index 0000000..43af60e
--- /dev/null
+++ b/src/core/FileFormatIridasItx.cpp
@@ -0,0 +1,336 @@
+/*
+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 <cstdio>
+#include <cstring>
+#include <iterator>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "FileTransform.h"
+#include "Lut1DOp.h"
+#include "Lut3DOp.h"
+#include "ParseUtils.h"
+#include "pystring/pystring.h"
+
+/*
+
+Iridas itx format
+LUT_3D_SIZE M
+
+#LUT_3D_SIZE M
+#where M is the size of the texture
+#a 3D texture has the size M x M x M
+#e.g. LUT_3D_SIZE 16 creates a 16 x 16 x 16 3D texture
+
+#for 1D textures, the data is simply a list of floating point values,
+#three per line, in RGB order
+#for 3D textures, the data is also RGB, and ordered in such a way
+#that the red coordinate changes fastest, then the green coordinate,
+#and finally, the blue coordinate changes slowest:
+0.0 0.0 0.0
+1.0 0.0 0.0
+0.0 1.0 0.0
+1.0 1.0 0.0
+0.0 0.0 1.0
+1.0 0.0 1.0
+0.0 1.0 1.0
+1.0 1.0 1.0
+*/
+
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ class LocalCachedFile : public CachedFile
+ {
+ public:
+ LocalCachedFile ()
+ {
+ lut3D = Lut3D::Create();
+ };
+ ~LocalCachedFile() {};
+
+ Lut3DRcPtr lut3D;
+ };
+
+ typedef OCIO_SHARED_PTR<LocalCachedFile> LocalCachedFileRcPtr;
+
+
+
+ class LocalFileFormat : public FileFormat
+ {
+ public:
+
+ ~LocalFileFormat() {};
+
+ virtual void GetFormatInfo(FormatInfoVec & formatInfoVec) const;
+
+ virtual CachedFileRcPtr Read(std::istream & istream) const;
+
+ virtual void Write(const Baker & baker,
+ const std::string & formatName,
+ std::ostream & ostream) const;
+
+ virtual void BuildFileOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const;
+ };
+
+ void LocalFileFormat::GetFormatInfo(FormatInfoVec & formatInfoVec) const
+ {
+ FormatInfo info;
+ info.name = "iridas_itx";
+ info.extension = "itx";
+ info.capabilities = (FORMAT_CAPABILITY_READ | FORMAT_CAPABILITY_WRITE);
+ formatInfoVec.push_back(info);
+ }
+
+ CachedFileRcPtr
+ LocalFileFormat::Read(std::istream & istream) const
+ {
+ // this shouldn't happen
+ if(!istream)
+ {
+ throw Exception ("File stream empty when trying to read Iridas .itx lut");
+ }
+
+ // Parse the file
+ std::vector<float> raw;
+
+ int size3d[] = { 0, 0, 0 };
+ bool in3d = false;
+
+ {
+ std::string line;
+ std::vector<std::string> parts;
+ std::vector<float> tmpfloats;
+
+ while(nextline(istream, line))
+ {
+ // All lines starting with '#' are comments
+ if(pystring::startswith(line,"#")) continue;
+
+ // Strip, lowercase, and split the line
+ pystring::split(pystring::lower(pystring::strip(line)), parts);
+ if(parts.empty()) continue;
+
+ if(pystring::lower(parts[0]) == "lut_3d_size")
+ {
+ int size = 0;
+
+ if(parts.size() != 2 || !StringToInt( &size, parts[1].c_str()))
+ {
+ throw Exception("Malformed LUT_3D_SIZE tag in Iridas .itx lut.");
+ }
+ size3d[0] = size;
+ size3d[1] = size;
+ size3d[2] = size;
+
+ raw.reserve(3*size3d[0]*size3d[1]*size3d[2]);
+ in3d = true;
+ }
+ else if(in3d)
+ {
+ // It must be a float triple!
+
+ if(!StringVecToFloatVec(tmpfloats, parts) || tmpfloats.size() != 3)
+ {
+ std::ostringstream os;
+ os << "Malformed color triples specified in Iridas .itx lut:";
+ os << "'" << line << "'.";
+ throw Exception(os.str().c_str());
+ }
+
+ for(int i=0; i<3; ++i)
+ {
+ raw.push_back(tmpfloats[i]);
+ }
+ }
+ }
+ }
+
+ // Interpret the parsed data, validate lut sizes
+
+ LocalCachedFileRcPtr cachedFile = LocalCachedFileRcPtr(new LocalCachedFile());
+
+ if(in3d)
+ {
+ if(size3d[0]*size3d[1]*size3d[2] != static_cast<int>(raw.size()/3))
+ {
+ std::ostringstream os;
+ os << "Parse error in Iridas .itx lut. ";
+ os << "Incorrect number of lut3d entries. ";
+ os << "Found " << raw.size()/3 << ", expected " << size3d[0]*size3d[1]*size3d[2] << ".";
+ throw Exception(os.str().c_str());
+ }
+
+ // Reformat 3D data
+ cachedFile->lut3D->size[0] = size3d[0];
+ cachedFile->lut3D->size[1] = size3d[1];
+ cachedFile->lut3D->size[2] = size3d[2];
+ cachedFile->lut3D->lut = raw;
+ }
+ else
+ {
+ std::ostringstream os;
+ os << "Parse error in Iridas .itx lut. ";
+ os << "Lut type (1D/3D) unspecified.";
+ throw Exception(os.str().c_str());
+ }
+
+ return cachedFile;
+ }
+
+ void LocalFileFormat::Write(const Baker & baker,
+ const std::string & formatName,
+ std::ostream & ostream) const
+ {
+ int DEFAULT_CUBE_SIZE = 64;
+
+ if(formatName != "iridas_itx")
+ {
+ std::ostringstream os;
+ os << "Unknown 3dl format name, '";
+ os << formatName << "'.";
+ throw Exception(os.str().c_str());
+ }
+
+ ConstConfigRcPtr config = baker.getConfig();
+
+ int cubeSize = baker.getCubeSize();
+ if(cubeSize==-1) cubeSize = DEFAULT_CUBE_SIZE;
+ cubeSize = std::max(2, cubeSize); // smallest cube is 2x2x2
+
+ std::vector<float> cubeData;
+ cubeData.resize(cubeSize*cubeSize*cubeSize*3);
+ GenerateIdentityLut3D(&cubeData[0], cubeSize, 3, LUT3DORDER_FAST_RED);
+ PackedImageDesc cubeImg(&cubeData[0], cubeSize*cubeSize*cubeSize, 1, 3);
+
+ // Apply our conversion from the input space to the output space.
+ ConstProcessorRcPtr inputToTarget;
+ std::string looks = baker.getLooks();
+ if (!looks.empty())
+ {
+ LookTransformRcPtr transform = LookTransform::Create();
+ transform->setLooks(looks.c_str());
+ transform->setSrc(baker.getInputSpace());
+ transform->setDst(baker.getTargetSpace());
+ inputToTarget = config->getProcessor(transform,
+ TRANSFORM_DIR_FORWARD);
+ }
+ else
+ {
+ inputToTarget = config->getProcessor(baker.getInputSpace(),
+ baker.getTargetSpace());
+ }
+ inputToTarget->apply(cubeImg);
+
+ // Write out the file.
+ // For for maximum compatibility with other apps, we will
+ // not utilize the shaper or output any metadata
+
+ ostream << "LUT_3D_SIZE " << cubeSize << "\n";
+ if(cubeSize < 2)
+ {
+ throw Exception("Internal cube size exception.");
+ }
+
+ // Set to a fixed 6 decimal precision
+ ostream.setf(std::ios::fixed, std::ios::floatfield);
+ ostream.precision(6);
+ for(int i=0; i<cubeSize*cubeSize*cubeSize; ++i)
+ {
+ float r = cubeData[3*i+0];
+ float g = cubeData[3*i+1];
+ float b = cubeData[3*i+2];
+ ostream << r << " " << g << " " << b << "\n";
+ }
+ ostream << "\n";
+ }
+
+
+ void
+ LocalFileFormat::BuildFileOps(OpRcPtrVec & ops,
+ const Config& /*config*/,
+ const ConstContextRcPtr & /*context*/,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const
+ {
+ LocalCachedFileRcPtr cachedFile = DynamicPtrCast<LocalCachedFile>(untypedCachedFile);
+
+ // This should never happen.
+ if(!cachedFile)
+ {
+ std::ostringstream os;
+ os << "Cannot build Iridas .itx Op. Invalid cache type.";
+ throw Exception(os.str().c_str());
+ }
+
+ TransformDirection newDir = CombineTransformDirections(dir,
+ fileTransform.getDirection());
+ if(newDir == TRANSFORM_DIR_UNKNOWN)
+ {
+ std::ostringstream os;
+ os << "Cannot build file format transform,";
+ os << " unspecified transform direction.";
+ throw Exception(os.str().c_str());
+ }
+
+ // TODO: INTERP_LINEAR should not be hard-coded.
+ // Instead query 'highest' interpolation?
+ // (right now, it's linear). If cubic is added, consider
+ // using it
+
+ if(newDir == TRANSFORM_DIR_FORWARD)
+ {
+ CreateLut3DOp(ops, cachedFile->lut3D,
+ fileTransform.getInterpolation(), newDir);
+ }
+ else if(newDir == TRANSFORM_DIR_INVERSE)
+ {
+ CreateLut3DOp(ops, cachedFile->lut3D,
+ fileTransform.getInterpolation(), newDir);
+ }
+ }
+ }
+
+ FileFormat * CreateFileFormatIridasItx()
+ {
+ return new LocalFileFormat();
+ }
+}
+OCIO_NAMESPACE_EXIT
+
+
+///////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/FileFormatIridasLook.cpp b/src/core/FileFormatIridasLook.cpp
new file mode 100644
index 0000000..d53c641
--- /dev/null
+++ b/src/core/FileFormatIridasLook.cpp
@@ -0,0 +1,1356 @@
+/*
+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 <cstdio>
+#include <cstring>
+#include <iterator>
+
+#include <tinyxml.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "FileTransform.h"
+#include "Lut1DOp.h"
+#include "Lut3DOp.h"
+#include "ParseUtils.h"
+#include "pystring/pystring.h"
+
+/*
+
+Iridas .look format
+
+An XML format containing <shaders>, a series of layers describing the
+operations and their parameters (irrelevant to us in this context).
+
+This series of shaders is baked into the <LUT> section.
+
+<?xml version="1.0" ?>
+<look>
+ <shaders>
+ # anything in here is useless to us
+ </shaders>
+ <LUT>
+ <size>"8"</size> # Size of 3D LUT
+ <data>"
+ 0000008000000080000000802CF52E3D2DF52E3D2DF52E3D2CF5AE3D2DF5AE3D
+ # ...cut...
+ 5A216A3F5A216A3FAD10753FAD10753FAD10753F0000803F0000803F0000803F"
+ </data>
+ </LUT>
+</look>
+
+The LUT data contains a 3D LUT, as a hex-encoded series of 32-bit
+floats, with little-endian bit-ordering. LUT value ordering is
+LUT3DORDER_FAST_RED (red index incrementing fastest, then green, then
+blue)
+
+The LUT data is parsed by removing all whitespace and quotes. Taking 8
+characters at a time and intepreting as little-endian float, as follows:
+
+Given the string "0000003F0000803FAD10753F":
+
+ >>> import binascii, struct
+ >>> struct.unpack("<f", binascii.unhexlify("0000003F"))[0]
+ 0.5
+ >>> struct.unpack("<f", binascii.unhexlify("0000803F"))[0]
+ 1.0
+ >>> struct.unpack("<f", binascii.unhexlify("AD10753F"))[0]
+ 0.9572857022285461
+
+ */
+
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ // convert hex ascii to int
+ // return true on success, false on failure
+ bool hexasciitoint(char& ival, char character)
+ {
+ if(character>=48 && character<=57) // [0-9]
+ {
+ ival = static_cast<char>(character-48);
+ return true;
+ }
+ else if(character>=65 && character<=70) // [A-F]
+ {
+ ival = static_cast<char>(10+character-65);
+ return true;
+ }
+ else if(character>=97 && character<=102) // [a-f]
+ {
+ ival = static_cast<char>(10+character-97);
+ return true;
+ }
+
+ ival = 0;
+ return false;
+ }
+
+ // convert array of 8 hex ascii to f32
+ // The input hexascii is required to be a little-endian representation
+ // as used in the iridas file format
+ // "AD10753F" -> 0.9572857022285461f on ALL architectures
+
+ bool hexasciitofloat(float& fval, const char * ascii)
+ {
+ // Convert all ASCII numbers to their numerical representations
+ char asciinums[8];
+ for(unsigned int i=0; i<8; ++i)
+ {
+ if(!hexasciitoint(asciinums[i], ascii[i]))
+ {
+ return false;
+ }
+ }
+
+ unsigned char * fvalbytes = reinterpret_cast<unsigned char *>(&fval);
+
+#if OCIO_LITTLE_ENDIAN
+ // Since incoming values are little endian, and we're on little endian
+ // preserve the byte order
+ fvalbytes[0] = (unsigned char) (asciinums[1] | (asciinums[0] << 4));
+ fvalbytes[1] = (unsigned char) (asciinums[3] | (asciinums[2] << 4));
+ fvalbytes[2] = (unsigned char) (asciinums[5] | (asciinums[4] << 4));
+ fvalbytes[3] = (unsigned char) (asciinums[7] | (asciinums[6] << 4));
+#else
+ // Since incoming values are little endian, and we're on big endian
+ // flip the byte order
+ fvalbytes[3] = (unsigned char) (asciinums[1] | (asciinums[0] << 4));
+ fvalbytes[2] = (unsigned char) (asciinums[3] | (asciinums[2] << 4));
+ fvalbytes[1] = (unsigned char) (asciinums[5] | (asciinums[4] << 4));
+ fvalbytes[0] = (unsigned char) (asciinums[7] | (asciinums[6] << 4));
+#endif
+ return true;
+ }
+ }
+
+ namespace
+ {
+ class LocalCachedFile : public CachedFile
+ {
+ public:
+ LocalCachedFile ()
+ {
+ lut3D = Lut3D::Create();
+ };
+ ~LocalCachedFile() {};
+
+ Lut3DRcPtr lut3D;
+ };
+
+ typedef OCIO_SHARED_PTR<LocalCachedFile> LocalCachedFileRcPtr;
+ typedef OCIO_SHARED_PTR<TiXmlDocument> TiXmlDocumentRcPtr;
+
+
+ class LocalFileFormat : public FileFormat
+ {
+ public:
+
+ ~LocalFileFormat() {};
+
+ virtual void GetFormatInfo(FormatInfoVec & formatInfoVec) const;
+
+ virtual CachedFileRcPtr Read(std::istream & istream) const;
+
+ virtual void BuildFileOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const;
+ };
+
+ void LocalFileFormat::GetFormatInfo(FormatInfoVec & formatInfoVec) const
+ {
+ FormatInfo info;
+ info.name = "iridas_look";
+ info.extension = "look";
+ info.capabilities = FORMAT_CAPABILITY_READ;
+ formatInfoVec.push_back(info);
+ }
+
+ CachedFileRcPtr
+ LocalFileFormat::Read(std::istream & istream) const
+ {
+
+ // Get root element from XML file
+ TiXmlDocumentRcPtr doc;
+ TiXmlElement* rootElement;
+
+ {
+ std::ostringstream rawdata;
+ rawdata << istream.rdbuf();
+
+ doc = TiXmlDocumentRcPtr(new TiXmlDocument());
+ doc->Parse(rawdata.str().c_str());
+
+ if(doc->Error())
+ {
+ std::ostringstream os;
+ os << "XML Parse Error. ";
+ os << doc->ErrorDesc() << " (line ";
+ os << doc->ErrorRow() << ", character ";
+ os << doc->ErrorCol() << ")";
+ throw Exception(os.str().c_str());
+ }
+
+ // Check for blank file
+ rootElement = doc->RootElement();
+ if(!rootElement)
+ {
+ std::ostringstream os;
+ os << "Error loading xml. Null root element.";
+ throw Exception(os.str().c_str());
+ }
+ }
+
+ // Check root element is <look>
+ if(std::string(rootElement->Value()) != "look")
+ {
+ std::ostringstream os;
+ os << "Error loading .look LUT. ";
+ os << "Root element is type '" << rootElement->Value() << "', ";
+ os << "expected 'look'.";
+ throw Exception(os.str().c_str());
+ }
+
+ // Fail to load file if it contains a <mask> section
+ if(rootElement->FirstChild("mask") && rootElement->FirstChild("mask")->FirstChild())
+ {
+ // If root element contains "mask" child, and it is
+ // not empty, throw exception
+ std::ostringstream os;
+ os << "Cannot load .look LUT containing mask";
+ throw Exception(os.str().c_str());
+ }
+
+ // Get <LUT> section
+
+ // TODO: There is a LUT1D section in some .look files,
+ // which we could use if available. Need to check
+ // assumption that it is only written for 1D transforms,
+ // and it matches the desired output
+ TiXmlNode* lutsection = rootElement->FirstChild("LUT");
+
+ if(!lutsection)
+ {
+ std::ostringstream os;
+ os << "Error loading .look LUT. ";
+ os << "Could not find required 'LUT' section.";
+ throw Exception(os.str().c_str());
+ }
+
+ // Get 3D LUT size
+ int size_3d = -1;
+
+ {
+ // Get size from <look><LUT><size>'123'</size></LUT></look>
+ TiXmlNode* elemsize = lutsection->FirstChild("size");
+ if(!elemsize)
+ {
+ std::ostringstream os;
+ os << "Error loading .look LUT. ";
+ os << "LUT section did not contain 'size'.";
+ throw Exception(os.str().c_str());
+ }
+
+ std::string size_raw = std::string(elemsize->ToElement()->GetText());
+ std::string size_clean = pystring::strip(size_raw, "'\" "); // strip quotes and space
+
+ char* endptr = 0;
+ size_3d = static_cast<int>(strtol(size_clean.c_str(), &endptr, 10));
+
+ if(*endptr)
+ {
+ // strtol didn't consume entire string, there was
+ // remaining data, thus did not contain a single interger
+ std::ostringstream os;
+ os << "Invalid LUT size value: '" << size_raw;
+ os << "'. Expected quoted integer.";
+ throw Exception(os.str().c_str());
+ }
+ }
+
+ // Grab raw 3D data
+ std::vector<float> raw;
+ {
+ TiXmlNode* dataelem = lutsection->FirstChild("data");
+ if(!dataelem)
+ {
+ std::ostringstream os;
+ os << "Error loading .look LUT. ";
+ os << "LUT section did not contain 'data'.";
+ throw Exception(os.str().c_str());
+ }
+
+ raw.reserve(3*(size_3d*size_3d*size_3d));
+
+ std::string what = dataelem->ToElement()->GetText();
+
+ // Remove spaces, quotes and newlines
+ what = pystring::replace(what, " ", "");
+ what = pystring::replace(what, "\"", "");
+ what = pystring::replace(what, "'", "");
+ what = pystring::replace(what, "\n", "");
+
+ if(what.size() % 8 != 0)
+ {
+ std::ostringstream os;
+ os << "Error loading .look LUT. ";
+ os << "Number of characters in 'data' must be multiple of 8. ";
+ os << what.size() << " elements found.";
+ throw Exception(os.str().c_str());
+ }
+
+ const char * ascii = what.c_str();
+ float fval = 0.0f;
+ for(unsigned int i=0; i<what.size()/8; ++i)
+ {
+ if(!hexasciitofloat(fval, &ascii[8*i]))
+ {
+ std::ostringstream os;
+ os << "Error loading .look LUT. ";
+ os << "Non-hex characters found in 'data' block ";
+ os << "at index '" << (8*i) << "'.";
+ throw Exception(os.str().c_str());
+ }
+ raw.push_back(fval);
+ }
+ }
+
+
+ // Validate LUT sizes, and create cached file object
+ LocalCachedFileRcPtr cachedFile = LocalCachedFileRcPtr(new LocalCachedFile());
+
+ if((size_3d*size_3d*size_3d)*3 != static_cast<int>(raw.size()))
+ {
+ std::ostringstream os;
+ os << "Parse error in Iridas .look lut. ";
+ os << "Incorrect number of lut3d entries. ";
+ os << "Found " << raw.size() << " values, expected " << (size_3d*size_3d*size_3d)*3 << ".";
+ throw Exception(os.str().c_str());
+ }
+
+ // Reformat 3D data
+ cachedFile->lut3D->size[0] = size_3d;
+ cachedFile->lut3D->size[1] = size_3d;
+ cachedFile->lut3D->size[2] = size_3d;
+ cachedFile->lut3D->lut = raw;
+
+ return cachedFile;
+ }
+
+
+ void
+ LocalFileFormat::BuildFileOps(OpRcPtrVec & ops,
+ const Config& /*config*/,
+ const ConstContextRcPtr & /*context*/,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const
+ {
+ LocalCachedFileRcPtr cachedFile = DynamicPtrCast<LocalCachedFile>(untypedCachedFile);
+
+ // This should never happen.
+ if(!cachedFile)
+ {
+ std::ostringstream os;
+ os << "Cannot build Iridas .look Op. Invalid cache type.";
+ throw Exception(os.str().c_str());
+ }
+
+ TransformDirection newDir = CombineTransformDirections(dir,
+ fileTransform.getDirection());
+ if(newDir == TRANSFORM_DIR_UNKNOWN)
+ {
+ std::ostringstream os;
+ os << "Cannot build file format transform,";
+ os << " unspecified transform direction.";
+ throw Exception(os.str().c_str());
+ }
+
+ CreateLut3DOp(ops, cachedFile->lut3D,
+ fileTransform.getInterpolation(), newDir);
+ }
+ }
+
+ FileFormat * CreateFileFormatIridasLook()
+ {
+ return new LocalFileFormat();
+ }
+}
+OCIO_NAMESPACE_EXIT
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef OCIO_UNIT_TEST
+
+#include "UnitTest.h"
+
+OCIO_NAMESPACE_USING
+
+
+
+OIIO_ADD_TEST(FileFormatIridasLook, hexasciitoint)
+{
+ {
+ char ival = 0;
+ bool success = hexasciitoint(ival, 'a');
+ OIIO_CHECK_EQUAL(success, true); OIIO_CHECK_EQUAL(ival, 10);
+ }
+
+ {
+ char ival = 0;
+ bool success = hexasciitoint(ival, 'A');
+ OIIO_CHECK_EQUAL(success, true); OIIO_CHECK_EQUAL(ival, 10);
+ }
+
+ {
+ char ival = 0;
+ bool success = hexasciitoint(ival, 'f');
+ OIIO_CHECK_EQUAL(success, true); OIIO_CHECK_EQUAL(ival, 15);
+ }
+
+ {
+ char ival = 0;
+ bool success = hexasciitoint(ival, 'F');
+ OIIO_CHECK_EQUAL(success, true); OIIO_CHECK_EQUAL(ival, 15);
+ }
+
+ {
+ char ival = 0;
+ bool success = hexasciitoint(ival, '0');
+ OIIO_CHECK_EQUAL(success, true); OIIO_CHECK_EQUAL(ival, 0);
+ }
+
+ {
+ char ival = 0;
+ bool success = hexasciitoint(ival, '0');
+ OIIO_CHECK_EQUAL(success, true); OIIO_CHECK_EQUAL(ival, 0);
+ }
+
+ {
+ char ival = 0;
+ bool success = hexasciitoint(ival, '9');
+ OIIO_CHECK_EQUAL(success, true); OIIO_CHECK_EQUAL(ival, 9);
+ }
+
+ {
+ char ival = 0;
+ bool success = hexasciitoint(ival, '\n');
+ OIIO_CHECK_EQUAL(success, false);
+ }
+
+ {
+ char ival = 0;
+ bool success = hexasciitoint(ival, 'j');
+ OIIO_CHECK_EQUAL(success, false);
+ }
+
+ {
+ char ival = 0;
+ bool success = hexasciitoint(ival, 'x');
+ OIIO_CHECK_EQUAL(success, false);
+ }
+}
+
+
+OIIO_ADD_TEST(FileFormatIridasLook, hexasciitofloat)
+{
+ //>>> import binascii, struct
+ //>> struct.unpack("<f", binascii.unhexlify("AD10753F"))[0]
+ //0.9572857022285461
+
+ {
+ float fval = 0.0f;
+ bool success = hexasciitofloat(fval, "0000003F");
+ OIIO_CHECK_EQUAL(success, true); OIIO_CHECK_EQUAL(fval, 0.5f);
+ }
+
+ {
+ float fval = 0.0f;
+ bool success = hexasciitofloat(fval, "0000803F");
+ OIIO_CHECK_EQUAL(success, true); OIIO_CHECK_EQUAL(fval, 1.0f);
+ }
+
+ {
+ float fval = 0.0f;
+ bool success = hexasciitofloat(fval, "AD10753F");
+ OIIO_CHECK_EQUAL(success, true); OIIO_CHECK_EQUAL(fval, 0.9572857022285461f);
+ }
+
+ {
+ float fval = 0.0f;
+ bool success = hexasciitofloat(fval, "AD10X53F");
+ OIIO_CHECK_EQUAL(success, false);
+ }
+}
+
+
+OIIO_ADD_TEST(FileFormatIridasLook, simple3d)
+{
+ std::ostringstream strebuf;
+ strebuf << "<?xml version=\"1.0\" ?>" << "\n";
+ strebuf << "<look>" << "\n";
+ strebuf << " <shaders>" << "\n";
+ strebuf << " <base>" << "\n";
+ strebuf << " <visible>\"1\"</visible>" << "\n";
+ strebuf << " <sublayer0>" << "\n";
+ strebuf << " <opacity>\"1\"</opacity>" << "\n";
+ strebuf << " <parameters>" << "\n";
+ strebuf << " <Secondary1>\"1\"</Secondary1>" << "\n";
+ strebuf << " <Secondary5>\"0\"</Secondary5>" << "\n";
+ strebuf << " <Secondary4>\"0\"</Secondary4>" << "\n";
+ strebuf << " <Secondary2>\"0\"</Secondary2>" << "\n";
+ strebuf << " <Secondary6>\"0\"</Secondary6>" << "\n";
+ strebuf << " <Secondary3>\"0\"</Secondary3>" << "\n";
+ strebuf << " <Blur>\"0\"</Blur>" << "\n";
+ strebuf << " <saturation>\"0\"</saturation>" << "\n";
+ strebuf << " </parameters>" << "\n";
+ strebuf << " </sublayer0>" << "\n";
+ strebuf << " </base>" << "\n";
+ strebuf << " </shaders>" << "\n";
+ strebuf << " <LUT>" << "\n";
+ strebuf << " <size>\"8\"</size>" << "\n";
+ strebuf << " <data>\"" << "\n";
+ strebuf << " 0000008000000080000000802CF52E3D2DF52E3D2DF52E3D2CF5AE3D2DF5AE3D" << "\n";
+ strebuf << " 2DF5AE3DE237033EE237033EE237033E2CF52E3E2DF52E3E2DF52E3E78B25A3E" << "\n";
+ strebuf << " 78B25A3E78B25A3EE037833EE137833EE137833E8616993E8716993E8716993E" << "\n";
+ strebuf << " 4BBDAB3D4BBDAB3D4BBDAB3DF09B013EF09B013EF09B013E3C592D3E3C592D3E" << "\n";
+ strebuf << " 3C592D3E8716593E8716593E8716593EE969823EE969823EE969823E8E48983E" << "\n";
+ strebuf << " 8E48983E8E48983E3227AE3E3327AE3E3327AE3ED805C43ED905C43ED905C43E" << "\n";
+ strebuf << " 4BBD2B3E4BBD2B3E4BBD2B3E967A573E967A573E967A573EF09B813EF09B813E" << "\n";
+ strebuf << " F09B813E967A973E967A973E967A973E3C59AD3E3C59AD3E3C59AD3EE137C33E" << "\n";
+ strebuf << " E137C33EE137C33E8616D93E8616D93E8616D93E2CF5EE3E2CF5EE3E2CF5EE3E" << "\n";
+ strebuf << " F9CD803EF9CD803EF9CD803E9EAC963E9EAC963E9EAC963E448BAC3E448BAC3E" << "\n";
+ strebuf << " 448BAC3EEA69C23EEA69C23EEA69C23E8F48D83E8F48D83E8F48D83E3527EE3E" << "\n";
+ strebuf << " 3527EE3E3527EE3EED02023FED02023FED02023F40F20C3F40F20C3F40F20C3F" << "\n";
+ strebuf << " 4BBDAB3E4BBDAB3E4BBDAB3EF09BC13EF09BC13EF09BC13E967AD73E967AD73E" << "\n";
+ strebuf << " 967AD73E3C59ED3E3C59ED3E3C59ED3EF09B013FF09B013FF09B013F438B0C3F" << "\n";
+ strebuf << " 438B0C3F438B0C3F967A173F967A173F967A173FE969223FE969223FE969223F" << "\n";
+ strebuf << " 9EACD63E9EACD63E9EACD63E428BEC3E438BEC3E438BEC3EF434013FF434013F" << "\n";
+ strebuf << " F434013F47240C3F47240C3F47240C3F9A13173F9A13173F9A13173FED02223F" << "\n";
+ strebuf << " ED02223FED02223F3FF22C3F3FF22C3F3FF22C3F92E1373F92E1373F92E1373F" << "\n";
+ strebuf << " F8CD003FF8CD003FF8CD003F49BD0B3F4ABD0B3F4ABD0B3F9DAC163F9DAC163F" << "\n";
+ strebuf << " 9DAC163FF09B213FF09B213FF09B213F438B2C3F438B2C3F438B2C3F967A373F" << "\n";
+ strebuf << " 967A373F967A373FE869423FE869423FE869423F3B594D3F3B594D3F3B594D3F" << "\n";
+ strebuf << " A245163FA245163FA245163FF334213FF434213FF434213F47242C3F47242C3F" << "\n";
+ strebuf << " 47242C3F9A13373F9A13373F9A13373FED02423FED02423FED02423F40F24C3F" << "\n";
+ strebuf << " 40F24C3F40F24C3F92E1573F92E1573F92E1573FE5D0623FE5D0623FE5D0623F" << "\n";
+ strebuf << " 9E69853C9E69853C9869853CFCA9713DFCA9713DFCA9713D944FD03D944FD03D" << "\n";
+ strebuf << " 944FD03D14E5133E15E5133E15E5133E60A23F3E60A23F3E60A23F3EAA5F6B3E" << "\n";
+ strebuf << " AB5F6B3EAB5F6B3E7A8E8B3E7A8E8B3E7A8E8B3E206DA13E206DA13E206DA13E" << "\n";
+ strebuf << " B217CD3DB217CD3DB217CD3D2449123E2449123E2449123E6F063E3E6F063E3E" << "\n";
+ strebuf << " 6F063E3EBAC3693EBAC3693EBAC3693E82C08A3E82C08A3E82C08A3E289FA03E" << "\n";
+ strebuf << " 289FA03E289FA03ECC7DB63ECC7DB63ECC7DB63E725CCC3E715CCC3E715CCC3E" << "\n";
+ strebuf << " 7E6A3C3E7E6A3C3E7E6A3C3ECA27683ECA27683ECA27683E8AF2893E8AF2893E" << "\n";
+ strebuf << " 8AF2893E30D19F3E30D19F3E30D19F3ED5AFB53ED5AFB53ED5AFB53E7B8ECB3E" << "\n";
+ strebuf << " 7B8ECB3E7A8ECB3E1F6DE13E1F6DE13E1E6DE13EC44BF73EC54BF73EC44BF73E" << "\n";
+ strebuf << " 9224893E9224893E9224893E38039F3E38039F3E38039F3EDEE1B43EDEE1B43E" << "\n";
+ strebuf << " DEE1B43E83C0CA3E83C0CA3E82C0CA3E299FE03E299FE03E289FE03ECE7DF63E" << "\n";
+ strebuf << " CE7DF63ECD7DF63E392E063F392E063F382E063F8C1D113F8C1D113F8B1D113F" << "\n";
+ strebuf << " E413B43EE413B43EE413B43E89F2C93E8AF2C93E89F2C93E30D1DF3E30D1DF3E" << "\n";
+ strebuf << " 2FD1DF3ED5AFF53ED5AFF53ED4AFF53E3DC7053F3DC7053F3CC7053F90B6103F" << "\n";
+ strebuf << " 90B6103F8FB6103FE2A51B3FE2A51B3FE1A51B3F3595263F3595263F3495263F" << "\n";
+ strebuf << " 3703DF3E3703DF3E3603DF3EDCE1F43EDDE1F43EDCE1F43E4160053F4160053F" << "\n";
+ strebuf << " 4060053F944F103F944F103F934F103FE73E1B3FE73E1B3FE63E1B3F392E263F" << "\n";
+ strebuf << " 392E263F382E263F8C1D313F8C1D313F8B1D313FDF0C3C3FDF0C3C3FDE0C3C3F" << "\n";
+ strebuf << " 44F9043F44F9043F43F9043F96E80F3F97E80F3F96E80F3FEAD71A3FEAD71A3F" << "\n";
+ strebuf << " E9D71A3F3DC7253F3DC7253F3CC7253F90B6303F90B6303F8FB6303FE2A53B3F" << "\n";
+ strebuf << " E2A53B3FE1A53B3F3595463F3595463F3495463F8884513F8884513F8784513F" << "\n";
+ strebuf << " EE701A3FEE701A3FED701A3F4060253F4160253F4060253F944F303F944F303F" << "\n";
+ strebuf << " 934F303FE73E3B3FE73E3B3FE63E3B3F3A2E463F3A2E463F392E463F8C1D513F" << "\n";
+ strebuf << " 8C1D513F8B1D513FDF0C5C3FDF0C5C3FDE0C5C3F32FC663F32FC663F31FC663F" << "\n";
+ strebuf << " 9E69053D9E69053D9869053D652F9A3D652F9A3D642F9A3DFCA9F13DFCA9F13D" << "\n";
+ strebuf << " FCA9F13D4892243E4992243E4992243E944F503E944F503E944F503EDE0C7C3E" << "\n";
+ strebuf << " DF0C7C3EDF0C7C3E14E5933E14E5933E14E5933EBAC3A93EBAC3A93EBAC3A93E" << "\n";
+ strebuf << " 1A72EE3D1A72EE3D1A72EE3D58F6223E58F6223E58F6223EA3B34E3EA3B34E3E" << "\n";
+ strebuf << " A3B34E3EEE707A3EEE707A3EEE707A3E1C17933E1C17933E1C17933EC2F5A83E" << "\n";
+ strebuf << " C2F5A83EC2F5A83E66D4BE3E66D4BE3E66D4BE3E0CB3D43E0BB3D43E0CB3D43E" << "\n";
+ strebuf << " B2174D3EB2174D3EB2174D3EFDD4783EFDD4783EFDD4783E2449923E2449923E" << "\n";
+ strebuf << " 2449923ECA27A83ECA27A83ECA27A83E6F06BE3E6F06BE3E6F06BE3E15E5D33E" << "\n";
+ strebuf << " 15E5D33E15E5D33EB9C3E93EB9C3E93EB9C3E93E5EA2FF3E5FA2FF3E5FA2FF3E" << "\n";
+ strebuf << " 2C7B913E2C7B913E2C7B913ED259A73ED259A73ED259A73E7838BD3E7838BD3E" << "\n";
+ strebuf << " 7838BD3E1D17D33E1D17D33E1D17D33EC3F5E83EC3F5E83EC3F5E83E68D4FE3E" << "\n";
+ strebuf << " 68D4FE3E68D4FE3E86590A3F86590A3F86590A3FD948153FD948153FD948153F" << "\n";
+ strebuf << " 7E6ABC3E7E6ABC3E7E6ABC3E2349D23E2449D23E2449D23ECA27E83ECA27E83E" << "\n";
+ strebuf << " CA27E83E6F06FE3E6F06FE3E6F06FE3E8AF2093F8AF2093F8AF2093FDDE1143F" << "\n";
+ strebuf << " DDE1143FDDE1143F2FD11F3F2FD11F3F2FD11F3F82C02A3F82C02A3F82C02A3F" << "\n";
+ strebuf << " D159E73ED159E73ED159E73E7638FD3E7738FD3E7738FD3E8E8B093F8E8B093F" << "\n";
+ strebuf << " 8E8B093FE17A143FE17A143FE17A143F346A1F3F346A1F3F346A1F3F86592A3F" << "\n";
+ strebuf << " 86592A3F86592A3FD948353FD948353FD948353F2C38403F2C38403F2C38403F" << "\n";
+ strebuf << " 9124093F9124093F9124093FE313143FE413143FE413143F37031F3F37031F3F" << "\n";
+ strebuf << " 37031F3F8AF2293F8AF2293F8AF2293FDDE1343FDDE1343FDDE1343F2FD13F3F" << "\n";
+ strebuf << " 2FD13F3F2FD13F3F82C04A3F82C04A3F81C04A3FD5AF553FD5AF553FD4AF553F" << "\n";
+ strebuf << " 3B9C1E3F3B9C1E3F3B9C1E3F8D8B293F8E8B293F8E8B293FE17A343FE17A343F" << "\n";
+ strebuf << " E17A343F346A3F3F346A3F3F346A3F3F87594A3F87594A3F86594A3FD948553F" << "\n";
+ strebuf << " D948553FD848553F2C38603F2C38603F2B38603F7F276B3F7F276B3F7E276B3F" << "\n";
+ strebuf << " 6E1E483D6E1E483D681E483DCD89BB3DCD89BB3DCC89BB3D3282093E3282093E" << "\n";
+ strebuf << " 3282093E7C3F353E7D3F353E7C3F353EC8FC603EC8FC603EC8FC603E095D863E" << "\n";
+ strebuf << " 095D863E095D863EAE3B9C3EAE3B9C3EAE3B9C3E541AB23E541AB23E541AB23E" << "\n";
+ strebuf << " 41E6073E41E6073E40E6073E8CA3333E8CA3333E8CA3333ED7605F3ED7605F3E" << "\n";
+ strebuf << " D7605F3E118F853E118F853E118F853EB66D9B3EB66D9B3EB66D9B3E5B4CB13E" << "\n";
+ strebuf << " 5B4CB13E5B4CB13E002BC73E002BC73E002BC73EA609DD3EA509DD3EA609DD3E" << "\n";
+ strebuf << " E6C45D3EE6C45D3EE6C45D3E18C1843E18C1843E18C1843EBE9F9A3EBE9F9A3E" << "\n";
+ strebuf << " BE9F9A3E647EB03E647EB03E647EB03E095DC63E095DC63E095DC63EAE3BDC3E" << "\n";
+ strebuf << " AE3BDC3EAE3BDC3E531AF23E531AF23E531AF23E7CFC033F7CFC033F7CFC033F" << "\n";
+ strebuf << " C6D1993EC6D1993EC6D1993E6CB0AF3E6CB0AF3E6CB0AF3E128FC53E128FC53E" << "\n";
+ strebuf << " 128FC53EB76DDB3EB76DDB3EB76DDB3E5D4CF13E5D4CF13E5D4CF13E8195033F" << "\n";
+ strebuf << " 8195033F8195033FD3840E3FD3840E3FD3840E3F2674193F2674193F2674193F" << "\n";
+ strebuf << " 18C1C43E18C1C43E18C1C43EBD9FDA3EBE9FDA3EBE9FDA3E647EF03E647EF03E" << "\n";
+ strebuf << " 647EF03E842E033F842E033F842E033FD71D0E3FD71D0E3FD71D0E3F2A0D193F" << "\n";
+ strebuf << " 2A0D193F2A0D193F7CFC233F7CFC233F7CFC233FCFEB2E3FCFEB2E3FCFEB2E3F" << "\n";
+ strebuf << " 6BB0EF3E6BB0EF3E6BB0EF3E87C7023F88C7023F88C7023FDBB60D3FDBB60D3F" << "\n";
+ strebuf << " DBB60D3F2EA6183F2EA6183F2EA6183F8195233F8195233F8195233FD3842E3F" << "\n";
+ strebuf << " D3842E3FD3842E3F2674393F2674393F2674393F7963443F7963443F7963443F" << "\n";
+ strebuf << " DE4F0D3FDE4F0D3FDE4F0D3F303F183F313F183F313F183F842E233F842E233F" << "\n";
+ strebuf << " 842E233FD71D2E3FD71D2E3FD71D2E3F2A0D393F2A0D393F2A0D393F7CFC433F" << "\n";
+ strebuf << " 7CFC433F7CFC433FCFEB4E3FCFEB4E3FCFEB4E3F22DB593F22DB593F22DB593F" << "\n";
+ strebuf << " 88C7223F88C7223F88C7223FDAB62D3FDBB62D3FDBB62D3F2EA6383F2EA6383F" << "\n";
+ strebuf << " 2EA6383F8195433F8195433F8195433FD4844E3FD4844E3FD4844E3F2674593F" << "\n";
+ strebuf << " 2674593F2674593F7963643F7963643F7963643FCC526F3FCC526F3FCC526F3F" << "\n";
+ strebuf << " 9E69853D9E69853D9869853D34E4DC3D34E4DC3D34E4DC3D652F1A3E652F1A3E" << "\n";
+ strebuf << " 642F1A3EB1EC453EB1EC453EB0EC453EFCA9713EFCA9713EFCA9713EA3B38E3E" << "\n";
+ strebuf << " A3B38E3EA3B38E3E4892A43E4892A43E4892A43EEE70BA3EEE70BA3EEE70BA3E" << "\n";
+ strebuf << " 7493183E7493183E7493183EBF50443EBF50443EBE50443E0A0E703E0A0E703E" << "\n";
+ strebuf << " 0A0E703EABE58D3EABE58D3EABE58D3E50C4A33E50C4A33E50C4A33EF5A2B93E" << "\n";
+ strebuf << " F5A2B93EF5A2B93E9A81CF3E9981CF3E9A81CF3E4060E53E3F60E53E4060E53E" << "\n";
+ strebuf << " 1A726E3E1A726E3E1A726E3EB2178D3EB2178D3EB2178D3E58F6A23E58F6A23E" << "\n";
+ strebuf << " 58F6A23EFED4B83EFED4B83EFED4B83EA3B3CE3EA3B3CE3EA3B3CE3E4892E43E" << "\n";
+ strebuf << " 4892E43E4892E43EED70FA3EED70FA3EED70FA3EC927083FC927083FC927083F" << "\n";
+ strebuf << " 6028A23E6028A23E6028A23E0607B83E0607B83E0607B83EABE5CD3EABE5CD3E" << "\n";
+ strebuf << " ABE5CD3E51C4E33E51C4E33E51C4E33EF7A2F93EF7A2F93EF7A2F93ECEC0073F" << "\n";
+ strebuf << " CEC0073FCEC0073F20B0123F20B0123F20B0123F739F1D3F739F1D3F739F1D3F" << "\n";
+ strebuf << " B217CD3EB217CD3EB217CD3E57F6E23E58F6E23E58F6E23EFDD4F83EFDD4F83E" << "\n";
+ strebuf << " FDD4F83ED159073FD159073FD159073F2449123F2449123F2449123F77381D3F" << "\n";
+ strebuf << " 77381D3F77381D3FC927283FC927283FC927283F1C17333F1C17333F1C17333F" << "\n";
+ strebuf << " 0507F83E0507F83E0507F83ED4F2063FD5F2063FD5F2063F28E2113F28E2113F" << "\n";
+ strebuf << " 28E2113F7BD11C3F7BD11C3F7BD11C3FCEC0273FCEC0273FCEC0273F20B0323F" << "\n";
+ strebuf << " 20B0323F20B0323F739F3D3F739F3D3F739F3D3FC68E483FC68E483FC68E483F" << "\n";
+ strebuf << " 2B7B113F2B7B113F2B7B113F7D6A1C3F7E6A1C3F7E6A1C3FD159273FD159273F" << "\n";
+ strebuf << " D159273F2449323F2449323F2449323F77383D3F77383D3F77383D3FC927483F" << "\n";
+ strebuf << " C927483FC927483F1C17533F1C17533F1C17533F6F065E3F6F065E3F6F065E3F" << "\n";
+ strebuf << " D5F2263FD5F2263FD5F2263F27E2313F28E2313F28E2313F7BD13C3F7BD13C3F" << "\n";
+ strebuf << " 7BD13C3FCEC0473FCEC0473FCEC0473F21B0523F21B0523F21B0523F739F5D3F" << "\n";
+ strebuf << " 739F5D3F739F5D3FC68E683FC68E683FC68E683F197E733F197E733F197E733F" << "\n";
+ strebuf << " 06C4A63D06C4A63D00C4A63D9C3EFE3D9C3EFE3D983EFE3D99DC2A3E99DC2A3E" << "\n";
+ strebuf << " 98DC2A3EE599563EE599563EE499563E982B813E982B813E982B813E3D0A973E" << "\n";
+ strebuf << " 3D0A973E3D0A973EE2E8AC3EE2E8AC3EE2E8AC3E88C7C23E88C7C23E88C7C23E" << "\n";
+ strebuf << " A840293EA840293EA840293EF3FD543EF3FD543EF0FD543E9F5D803E9F5D803E" << "\n";
+ strebuf << " 9F5D803E453C963E453C963E453C963EEA1AAC3EEA1AAC3EEA1AAC3E8FF9C13E" << "\n";
+ strebuf << " 8FF9C13E8FF9C13E34D8D73E33D8D73E34D8D73EDAB6ED3ED9B6ED3EDAB6ED3E" << "\n";
+ strebuf << " 4E1F7F3E4E1F7F3E4E1F7F3E4C6E953E4C6E953E4C6E953EF24CAB3EF24CAB3E" << "\n";
+ strebuf << " F24CAB3E982BC13E982BC13E982BC13E3D0AD73E3D0AD73E3D0AD73EE2E8EC3E" << "\n";
+ strebuf << " E2E8EC3EE2E8EC3EC363013FC363013FC363013F16530C3F16530C3F16530C3F" << "\n";
+ strebuf << " FA7EAA3EFA7EAA3EFA7EAA3EA05DC03EA05DC03EA05DC03E453CD63E453CD63E" << "\n";
+ strebuf << " 453CD63EEB1AEC3EEB1AEC3EEB1AEC3EC8FC003FC8FC003FC8FC003F1BEC0B3F" << "\n";
+ strebuf << " 1BEC0B3F1BEC0B3F6DDB163F6DDB163F6DDB163FC0CA213FC0CA213FC0CA213F" << "\n";
+ strebuf << " 4C6ED53E4C6ED53E4C6ED53EF14CEB3EF24CEB3EF24CEB3ECB95003FCB95003F" << "\n";
+ strebuf << " CB95003F1E850B3F1E850B3F1E850B3F7174163F7174163F7174163FC463213F" << "\n";
+ strebuf << " C463213FC463213F16532C3F16532C3F16532C3F6942373F6942373F6942373F" << "\n";
+ strebuf << " CF2E003FCF2E003FCF2E003F211E0B3F221E0B3F221E0B3F750D163F750D163F" << "\n";
+ strebuf << " 750D163FC8FC203FC8FC203FC8FC203F1BEC2B3F1BEC2B3F1BEC2B3F6DDB363F" << "\n";
+ strebuf << " 6DDB363F6DDB363FC0CA413FC0CA413FC0CA413F13BA4C3F13BA4C3F13BA4C3F" << "\n";
+ strebuf << " 78A6153F78A6153F78A6153FCA95203FCB95203FCB95203F1E852B3F1E852B3F" << "\n";
+ strebuf << " 1E852B3F7174363F7174363F7174363FC463413FC463413FC463413F16534C3F" << "\n";
+ strebuf << " 16534C3F16534C3F6942573F6942573F6942573FBC31623FBC31623FBC31623F" << "\n";
+ strebuf << " 221E2B3F221E2B3F221E2B3F740D363F750D363F750D363FC8FC403FC8FC403F" << "\n";
+ strebuf << " C8FC403F1BEC4B3F1BEC4B3F1BEC4B3F6EDB563F6EDB563F6EDB563FC0CA613F" << "\n";
+ strebuf << " C0CA613FC0CA613F13BA6C3F13BA6C3F13BA6C3F66A9773F66A9773F66A9773F" << "\n";
+ strebuf << " 6D1EC83D6D1EC83D681EC83D81CC0F3E81CC0F3E80CC0F3ECD893B3ECD893B3E" << "\n";
+ strebuf << " CC893B3E1847673E1847673E1847673E3182893E3182893E3082893ED7609F3E" << "\n";
+ strebuf << " D7609F3ED6609F3E7C3FB53E7C3FB53E7C3FB53E221ECB3E221ECB3E221ECB3E" << "\n";
+ strebuf << " DCED393EDCED393EDCED393E26AB653E26AB653E24AB653E39B4883E39B4883E" << "\n";
+ strebuf << " 38B4883EDE929E3EDE929E3EDE929E3E8371B43E8371B43E8271B43E2950CA3E" << "\n";
+ strebuf << " 2850CA3E2950CA3ECE2EE03ECD2EE03ECE2EE03E740DF63E730DF63E740DF63E" << "\n";
+ strebuf << " 40E6873E40E6873E40E6873EE6C49D3EE6C49D3EE6C49D3E8CA3B33E8CA3B33E" << "\n";
+ strebuf << " 8CA3B33E3182C93E3182C93E3182C93ED660DF3ED660DF3ED660DF3E7C3FF53E" << "\n";
+ strebuf << " 7C3FF53E7C3FF53E108F053F108F053F108F053F637E103F637E103F637E103F" << "\n";
+ strebuf << " 94D5B23E94D5B23E94D5B23E39B4C83E39B4C83E39B4C83EDF92DE3EDF92DE3E" << "\n";
+ strebuf << " DF92DE3E8571F43E8571F43E8571F43E1528053F1528053F1528053F6817103F" << "\n";
+ strebuf << " 6817103F6817103FBA061B3FBA061B3FBA061B3F0DF6253F0DF6253F0DF6253F" << "\n";
+ strebuf << " E6C4DD3EE6C4DD3EE6C4DD3E8AA3F33E8BA3F33E8BA3F33E18C1043F18C1043F" << "\n";
+ strebuf << " 18C1043F6BB00F3F6BB00F3F6BB00F3FBE9F1A3FBE9F1A3FBE9F1A3F118F253F" << "\n";
+ strebuf << " 118F253F118F253F637E303F637E303F637E303FB66D3B3FB66D3B3FB66D3B3F" << "\n";
+ strebuf << " 1C5A043F1C5A043F1C5A043F6E490F3F6F490F3F6F490F3FC2381A3FC2381A3F" << "\n";
+ strebuf << " C2381A3F1528253F1528253F1528253F6717303F6717303F6717303FBA063B3F" << "\n";
+ strebuf << " BA063B3FBA063B3F0DF6453F0DF6453F0DF6453F60E5503F60E5503F60E5503F" << "\n";
+ strebuf << " C5D1193FC5D1193FC5D1193F17C1243F18C1243F18C1243F6BB02F3F6BB02F3F" << "\n";
+ strebuf << " 6BB02F3FBE9F3A3FBE9F3A3FBE9F3A3F108F453F108F453F108F453F637E503F" << "\n";
+ strebuf << " 637E503F637E503FB66D5B3FB66D5B3FB66D5B3F095D663F095D663F095D663F" << "\n";
+ strebuf << " 6F492F3F6F492F3F6F492F3FC1383A3FC2383A3FC2383A3F1528453F1528453F" << "\n";
+ strebuf << " 1528453F6817503F6817503F6817503FBA065B3FBA065B3FBA065B3F0DF6653F" << "\n";
+ strebuf << " 0DF6653F0DF6653F60E5703F60E5703F60E5703FB3D47B3FB3D47B3FB3D47B3F" << "\n";
+ strebuf << " D578E93DD578E93DD078E93DB579203EB579203EB479203E01374C3E01374C3E" << "\n";
+ strebuf << " 00374C3E4CF4773E4CF4773E4CF4773ECBD8913ECBD8913ECAD8913E71B7A73E" << "\n";
+ strebuf << " 71B7A73E70B7A73E1696BD3E1696BD3E1696BD3EBC74D33EBC74D33EBC74D33E" << "\n";
+ strebuf << " 109B4A3E109B4A3E109B4A3E5A58763E5A58763E5858763ED30A913ED30A913E" << "\n";
+ strebuf << " D20A913E78E9A63E78E9A63E78E9A63E1DC8BC3E1DC8BC3E1CC8BC3EC3A6D23E" << "\n";
+ strebuf << " C2A6D23EC2A6D23E6885E83E6785E83E6885E83E0E64FE3E0D64FE3E0E64FE3E" << "\n";
+ strebuf << " DA3C903EDA3C903EDA3C903E801BA63E801BA63E801BA63E26FABB3E26FABB3E" << "\n";
+ strebuf << " 26FABB3ECBD8D13ECBD8D13ECAD8D13E70B7E73E70B7E73E70B7E73E1696FD3E" << "\n";
+ strebuf << " 1696FD3E1696FD3E5DBA093F5DBA093F5DBA093FB0A9143FB0A9143FB0A9143F" << "\n";
+ strebuf << " 2E2CBB3E2E2CBB3E2E2CBB3ED20AD13ED30AD13ED20AD13E79E9E63E79E9E63E" << "\n";
+ strebuf << " 78E9E63E1FC8FC3E1FC8FC3E1EC8FC3E6253093F6253093F6253093FB542143F" << "\n";
+ strebuf << " B542143FB542143F07321F3F07321F3F07321F3F5A212A3F5A212A3F5A212A3F" << "\n";
+ strebuf << " 801BE63E801BE63E801BE63E24FAFB3E25FAFB3E24FAFB3E65EC083F65EC083F" << "\n";
+ strebuf << " 65EC083FB8DB133FB8DB133FB8DB133F0BCB1E3F0BCB1E3F0BCB1E3F5EBA293F" << "\n";
+ strebuf << " 5EBA293F5EBA293FB0A9343FB0A9343FB0A9343F03993F3F03993F3F03993F3F" << "\n";
+ strebuf << " 6985083F6985083F6985083FBB74133FBC74133FBC74133F0F641E3F0F641E3F" << "\n";
+ strebuf << " 0F641E3F6253293F6253293F6253293FB442343FB442343FB442343F07323F3F" << "\n";
+ strebuf << " 07323F3F07323F3F5A214A3F5A214A3F5A214A3FAD10553FAD10553FAD10553F" << "\n";
+ strebuf << " 12FD1D3F12FD1D3F12FD1D3F64EC283F65EC283F65EC283FB8DB333FB8DB333F" << "\n";
+ strebuf << " B8DB333F0BCB3E3F0BCB3E3F0BCB3E3F5DBA493F5DBA493F5DBA493FB0A9543F" << "\n";
+ strebuf << " B0A9543FB0A9543F03995F3F03995F3F03995F3F56886A3F56886A3F56886A3F" << "\n";
+ strebuf << " BC74333FBC74333FBC74333F0E643E3F0F643E3F0F643E3F6153493F6253493F" << "\n";
+ strebuf << " 6253493FB542543FB542543FB542543F07325F3F07325F3F07325F3F5A216A3F" << "\n";
+ strebuf << " 5A216A3F5A216A3FAD10753FAD10753FAD10753F0000803F0000803F0000803F\"" << "\n";
+ strebuf << " </data>" << "\n";
+ strebuf << " </LUT>" << "\n";
+ strebuf << "</look>" << "\n";
+
+ std::istringstream simple1D;
+ simple1D.str(strebuf.str());
+
+ // Read file
+ LocalFileFormat tester;
+ CachedFileRcPtr cachedFile = tester.Read(simple1D);
+ LocalCachedFileRcPtr looklut = DynamicPtrCast<LocalCachedFile>(cachedFile);
+
+ // Check LUT size is correct
+ OIIO_CHECK_EQUAL(looklut->lut3D->size[0], 8);
+ OIIO_CHECK_EQUAL(looklut->lut3D->size[1], 8);
+ OIIO_CHECK_EQUAL(looklut->lut3D->size[2], 8);
+
+ // Check LUT values
+ OIIO_CHECK_EQUAL(looklut->lut3D->lut.size(), 8*8*8*3);
+
+ double cube[8 * 8 * 8 * 3] = {
+ -0.00000, -0.00000, -0.00000,
+ 0.04271, 0.04271, 0.04271,
+ 0.08543, 0.08543, 0.08543,
+ 0.12814, 0.12814, 0.12814,
+ 0.17086, 0.17086, 0.17086,
+ 0.21357, 0.21357, 0.21357,
+ 0.25629, 0.25629, 0.25629,
+ 0.29900, 0.29900, 0.29900,
+ 0.08386, 0.08386, 0.08386,
+ 0.12657, 0.12657, 0.12657,
+ 0.16929, 0.16929, 0.16929,
+ 0.21200, 0.21200, 0.21200,
+ 0.25471, 0.25471, 0.25471,
+ 0.29743, 0.29743, 0.29743,
+ 0.34014, 0.34014, 0.34014,
+ 0.38286, 0.38286, 0.38286,
+ 0.16771, 0.16771, 0.16771,
+ 0.21043, 0.21043, 0.21043,
+ 0.25314, 0.25314, 0.25314,
+ 0.29586, 0.29586, 0.29586,
+ 0.33857, 0.33857, 0.33857,
+ 0.38129, 0.38129, 0.38129,
+ 0.42400, 0.42400, 0.42400,
+ 0.46671, 0.46671, 0.46671,
+ 0.25157, 0.25157, 0.25157,
+ 0.29429, 0.29429, 0.29429,
+ 0.33700, 0.33700, 0.33700,
+ 0.37971, 0.37971, 0.37971,
+ 0.42243, 0.42243, 0.42243,
+ 0.46514, 0.46514, 0.46514,
+ 0.50786, 0.50786, 0.50786,
+ 0.55057, 0.55057, 0.55057,
+ 0.33543, 0.33543, 0.33543,
+ 0.37814, 0.37814, 0.37814,
+ 0.42086, 0.42086, 0.42086,
+ 0.46357, 0.46357, 0.46357,
+ 0.50629, 0.50629, 0.50629,
+ 0.54900, 0.54900, 0.54900,
+ 0.59171, 0.59171, 0.59171,
+ 0.63443, 0.63443, 0.63443,
+ 0.41929, 0.41929, 0.41929,
+ 0.46200, 0.46200, 0.46200,
+ 0.50471, 0.50471, 0.50471,
+ 0.54743, 0.54743, 0.54743,
+ 0.59014, 0.59014, 0.59014,
+ 0.63286, 0.63286, 0.63286,
+ 0.67557, 0.67557, 0.67557,
+ 0.71829, 0.71829, 0.71829,
+ 0.50314, 0.50314, 0.50314,
+ 0.54586, 0.54586, 0.54586,
+ 0.58857, 0.58857, 0.58857,
+ 0.63129, 0.63129, 0.63129,
+ 0.67400, 0.67400, 0.67400,
+ 0.71671, 0.71671, 0.71671,
+ 0.75943, 0.75943, 0.75943,
+ 0.80214, 0.80214, 0.80214,
+ 0.58700, 0.58700, 0.58700,
+ 0.62971, 0.62971, 0.62971,
+ 0.67243, 0.67243, 0.67243,
+ 0.71514, 0.71514, 0.71514,
+ 0.75786, 0.75786, 0.75786,
+ 0.80057, 0.80057, 0.80057,
+ 0.84329, 0.84329, 0.84329,
+ 0.88600, 0.88600, 0.88600,
+ 0.01629, 0.01629, 0.01629,
+ 0.05900, 0.05900, 0.05900,
+ 0.10171, 0.10171, 0.10171,
+ 0.14443, 0.14443, 0.14443,
+ 0.18714, 0.18714, 0.18714,
+ 0.22986, 0.22986, 0.22986,
+ 0.27257, 0.27257, 0.27257,
+ 0.31529, 0.31529, 0.31529,
+ 0.10014, 0.10014, 0.10014,
+ 0.14286, 0.14286, 0.14286,
+ 0.18557, 0.18557, 0.18557,
+ 0.22829, 0.22829, 0.22829,
+ 0.27100, 0.27100, 0.27100,
+ 0.31371, 0.31371, 0.31371,
+ 0.35643, 0.35643, 0.35643,
+ 0.39914, 0.39914, 0.39914,
+ 0.18400, 0.18400, 0.18400,
+ 0.22671, 0.22671, 0.22671,
+ 0.26943, 0.26943, 0.26943,
+ 0.31214, 0.31214, 0.31214,
+ 0.35486, 0.35486, 0.35486,
+ 0.39757, 0.39757, 0.39757,
+ 0.44029, 0.44029, 0.44029,
+ 0.48300, 0.48300, 0.48300,
+ 0.26786, 0.26786, 0.26786,
+ 0.31057, 0.31057, 0.31057,
+ 0.35329, 0.35329, 0.35329,
+ 0.39600, 0.39600, 0.39600,
+ 0.43871, 0.43871, 0.43871,
+ 0.48143, 0.48143, 0.48143,
+ 0.52414, 0.52414, 0.52414,
+ 0.56686, 0.56686, 0.56686,
+ 0.35171, 0.35171, 0.35171,
+ 0.39443, 0.39443, 0.39443,
+ 0.43714, 0.43714, 0.43714,
+ 0.47986, 0.47986, 0.47986,
+ 0.52257, 0.52257, 0.52257,
+ 0.56529, 0.56529, 0.56529,
+ 0.60800, 0.60800, 0.60800,
+ 0.65071, 0.65071, 0.65071,
+ 0.43557, 0.43557, 0.43557,
+ 0.47829, 0.47829, 0.47829,
+ 0.52100, 0.52100, 0.52100,
+ 0.56371, 0.56371, 0.56371,
+ 0.60643, 0.60643, 0.60643,
+ 0.64914, 0.64914, 0.64914,
+ 0.69186, 0.69186, 0.69186,
+ 0.73457, 0.73457, 0.73457,
+ 0.51943, 0.51943, 0.51943,
+ 0.56214, 0.56214, 0.56214,
+ 0.60486, 0.60486, 0.60486,
+ 0.64757, 0.64757, 0.64757,
+ 0.69029, 0.69029, 0.69029,
+ 0.73300, 0.73300, 0.73300,
+ 0.77571, 0.77571, 0.77571,
+ 0.81843, 0.81843, 0.81843,
+ 0.60329, 0.60329, 0.60329,
+ 0.64600, 0.64600, 0.64600,
+ 0.68871, 0.68871, 0.68871,
+ 0.73143, 0.73143, 0.73143,
+ 0.77414, 0.77414, 0.77414,
+ 0.81686, 0.81686, 0.81686,
+ 0.85957, 0.85957, 0.85957,
+ 0.90229, 0.90229, 0.90229,
+ 0.03257, 0.03257, 0.03257,
+ 0.07529, 0.07529, 0.07529,
+ 0.11800, 0.11800, 0.11800,
+ 0.16071, 0.16071, 0.16071,
+ 0.20343, 0.20343, 0.20343,
+ 0.24614, 0.24614, 0.24614,
+ 0.28886, 0.28886, 0.28886,
+ 0.33157, 0.33157, 0.33157,
+ 0.11643, 0.11643, 0.11643,
+ 0.15914, 0.15914, 0.15914,
+ 0.20186, 0.20186, 0.20186,
+ 0.24457, 0.24457, 0.24457,
+ 0.28729, 0.28729, 0.28729,
+ 0.33000, 0.33000, 0.33000,
+ 0.37271, 0.37271, 0.37271,
+ 0.41543, 0.41543, 0.41543,
+ 0.20029, 0.20029, 0.20029,
+ 0.24300, 0.24300, 0.24300,
+ 0.28571, 0.28571, 0.28571,
+ 0.32843, 0.32843, 0.32843,
+ 0.37114, 0.37114, 0.37114,
+ 0.41386, 0.41386, 0.41386,
+ 0.45657, 0.45657, 0.45657,
+ 0.49929, 0.49929, 0.49929,
+ 0.28414, 0.28414, 0.28414,
+ 0.32686, 0.32686, 0.32686,
+ 0.36957, 0.36957, 0.36957,
+ 0.41229, 0.41229, 0.41229,
+ 0.45500, 0.45500, 0.45500,
+ 0.49771, 0.49771, 0.49771,
+ 0.54043, 0.54043, 0.54043,
+ 0.58314, 0.58314, 0.58314,
+ 0.36800, 0.36800, 0.36800,
+ 0.41071, 0.41071, 0.41071,
+ 0.45343, 0.45343, 0.45343,
+ 0.49614, 0.49614, 0.49614,
+ 0.53886, 0.53886, 0.53886,
+ 0.58157, 0.58157, 0.58157,
+ 0.62429, 0.62429, 0.62429,
+ 0.66700, 0.66700, 0.66700,
+ 0.45186, 0.45186, 0.45186,
+ 0.49457, 0.49457, 0.49457,
+ 0.53729, 0.53729, 0.53729,
+ 0.58000, 0.58000, 0.58000,
+ 0.62271, 0.62271, 0.62271,
+ 0.66543, 0.66543, 0.66543,
+ 0.70814, 0.70814, 0.70814,
+ 0.75086, 0.75086, 0.75086,
+ 0.53571, 0.53571, 0.53571,
+ 0.57843, 0.57843, 0.57843,
+ 0.62114, 0.62114, 0.62114,
+ 0.66386, 0.66386, 0.66386,
+ 0.70657, 0.70657, 0.70657,
+ 0.74929, 0.74929, 0.74929,
+ 0.79200, 0.79200, 0.79200,
+ 0.83471, 0.83471, 0.83471,
+ 0.61957, 0.61957, 0.61957,
+ 0.66229, 0.66229, 0.66229,
+ 0.70500, 0.70500, 0.70500,
+ 0.74771, 0.74771, 0.74771,
+ 0.79043, 0.79043, 0.79043,
+ 0.83314, 0.83314, 0.83314,
+ 0.87586, 0.87586, 0.87586,
+ 0.91857, 0.91857, 0.91857,
+ 0.04886, 0.04886, 0.04886,
+ 0.09157, 0.09157, 0.09157,
+ 0.13429, 0.13429, 0.13429,
+ 0.17700, 0.17700, 0.17700,
+ 0.21971, 0.21971, 0.21971,
+ 0.26243, 0.26243, 0.26243,
+ 0.30514, 0.30514, 0.30514,
+ 0.34786, 0.34786, 0.34786,
+ 0.13271, 0.13271, 0.13271,
+ 0.17543, 0.17543, 0.17543,
+ 0.21814, 0.21814, 0.21814,
+ 0.26086, 0.26086, 0.26086,
+ 0.30357, 0.30357, 0.30357,
+ 0.34629, 0.34629, 0.34629,
+ 0.38900, 0.38900, 0.38900,
+ 0.43171, 0.43171, 0.43171,
+ 0.21657, 0.21657, 0.21657,
+ 0.25929, 0.25929, 0.25929,
+ 0.30200, 0.30200, 0.30200,
+ 0.34471, 0.34471, 0.34471,
+ 0.38743, 0.38743, 0.38743,
+ 0.43014, 0.43014, 0.43014,
+ 0.47286, 0.47286, 0.47286,
+ 0.51557, 0.51557, 0.51557,
+ 0.30043, 0.30043, 0.30043,
+ 0.34314, 0.34314, 0.34314,
+ 0.38586, 0.38586, 0.38586,
+ 0.42857, 0.42857, 0.42857,
+ 0.47129, 0.47129, 0.47129,
+ 0.51400, 0.51400, 0.51400,
+ 0.55671, 0.55671, 0.55671,
+ 0.59943, 0.59943, 0.59943,
+ 0.38429, 0.38429, 0.38429,
+ 0.42700, 0.42700, 0.42700,
+ 0.46971, 0.46971, 0.46971,
+ 0.51243, 0.51243, 0.51243,
+ 0.55514, 0.55514, 0.55514,
+ 0.59786, 0.59786, 0.59786,
+ 0.64057, 0.64057, 0.64057,
+ 0.68329, 0.68329, 0.68329,
+ 0.46814, 0.46814, 0.46814,
+ 0.51086, 0.51086, 0.51086,
+ 0.55357, 0.55357, 0.55357,
+ 0.59629, 0.59629, 0.59629,
+ 0.63900, 0.63900, 0.63900,
+ 0.68171, 0.68171, 0.68171,
+ 0.72443, 0.72443, 0.72443,
+ 0.76714, 0.76714, 0.76714,
+ 0.55200, 0.55200, 0.55200,
+ 0.59471, 0.59471, 0.59471,
+ 0.63743, 0.63743, 0.63743,
+ 0.68014, 0.68014, 0.68014,
+ 0.72286, 0.72286, 0.72286,
+ 0.76557, 0.76557, 0.76557,
+ 0.80829, 0.80829, 0.80829,
+ 0.85100, 0.85100, 0.85100,
+ 0.63586, 0.63586, 0.63586,
+ 0.67857, 0.67857, 0.67857,
+ 0.72129, 0.72129, 0.72129,
+ 0.76400, 0.76400, 0.76400,
+ 0.80671, 0.80671, 0.80671,
+ 0.84943, 0.84943, 0.84943,
+ 0.89214, 0.89214, 0.89214,
+ 0.93486, 0.93486, 0.93486,
+ 0.06514, 0.06514, 0.06514,
+ 0.10786, 0.10786, 0.10786,
+ 0.15057, 0.15057, 0.15057,
+ 0.19329, 0.19329, 0.19329,
+ 0.23600, 0.23600, 0.23600,
+ 0.27871, 0.27871, 0.27871,
+ 0.32143, 0.32143, 0.32143,
+ 0.36414, 0.36414, 0.36414,
+ 0.14900, 0.14900, 0.14900,
+ 0.19171, 0.19171, 0.19171,
+ 0.23443, 0.23443, 0.23443,
+ 0.27714, 0.27714, 0.27714,
+ 0.31986, 0.31986, 0.31986,
+ 0.36257, 0.36257, 0.36257,
+ 0.40529, 0.40529, 0.40529,
+ 0.44800, 0.44800, 0.44800,
+ 0.23286, 0.23286, 0.23286,
+ 0.27557, 0.27557, 0.27557,
+ 0.31829, 0.31829, 0.31829,
+ 0.36100, 0.36100, 0.36100,
+ 0.40371, 0.40371, 0.40371,
+ 0.44643, 0.44643, 0.44643,
+ 0.48914, 0.48914, 0.48914,
+ 0.53186, 0.53186, 0.53186,
+ 0.31671, 0.31671, 0.31671,
+ 0.35943, 0.35943, 0.35943,
+ 0.40214, 0.40214, 0.40214,
+ 0.44486, 0.44486, 0.44486,
+ 0.48757, 0.48757, 0.48757,
+ 0.53029, 0.53029, 0.53029,
+ 0.57300, 0.57300, 0.57300,
+ 0.61571, 0.61571, 0.61571,
+ 0.40057, 0.40057, 0.40057,
+ 0.44329, 0.44329, 0.44329,
+ 0.48600, 0.48600, 0.48600,
+ 0.52871, 0.52871, 0.52871,
+ 0.57143, 0.57143, 0.57143,
+ 0.61414, 0.61414, 0.61414,
+ 0.65686, 0.65686, 0.65686,
+ 0.69957, 0.69957, 0.69957,
+ 0.48443, 0.48443, 0.48443,
+ 0.52714, 0.52714, 0.52714,
+ 0.56986, 0.56986, 0.56986,
+ 0.61257, 0.61257, 0.61257,
+ 0.65529, 0.65529, 0.65529,
+ 0.69800, 0.69800, 0.69800,
+ 0.74071, 0.74071, 0.74071,
+ 0.78343, 0.78343, 0.78343,
+ 0.56829, 0.56829, 0.56829,
+ 0.61100, 0.61100, 0.61100,
+ 0.65371, 0.65371, 0.65371,
+ 0.69643, 0.69643, 0.69643,
+ 0.73914, 0.73914, 0.73914,
+ 0.78186, 0.78186, 0.78186,
+ 0.82457, 0.82457, 0.82457,
+ 0.86729, 0.86729, 0.86729,
+ 0.65214, 0.65214, 0.65214,
+ 0.69486, 0.69486, 0.69486,
+ 0.73757, 0.73757, 0.73757,
+ 0.78029, 0.78029, 0.78029,
+ 0.82300, 0.82300, 0.82300,
+ 0.86571, 0.86571, 0.86571,
+ 0.90843, 0.90843, 0.90843,
+ 0.95114, 0.95114, 0.95114,
+ 0.08143, 0.08143, 0.08143,
+ 0.12414, 0.12414, 0.12414,
+ 0.16686, 0.16686, 0.16686,
+ 0.20957, 0.20957, 0.20957,
+ 0.25229, 0.25229, 0.25229,
+ 0.29500, 0.29500, 0.29500,
+ 0.33771, 0.33771, 0.33771,
+ 0.38043, 0.38043, 0.38043,
+ 0.16529, 0.16529, 0.16529,
+ 0.20800, 0.20800, 0.20800,
+ 0.25071, 0.25071, 0.25071,
+ 0.29343, 0.29343, 0.29343,
+ 0.33614, 0.33614, 0.33614,
+ 0.37886, 0.37886, 0.37886,
+ 0.42157, 0.42157, 0.42157,
+ 0.46429, 0.46429, 0.46429,
+ 0.24914, 0.24914, 0.24914,
+ 0.29186, 0.29186, 0.29186,
+ 0.33457, 0.33457, 0.33457,
+ 0.37729, 0.37729, 0.37729,
+ 0.42000, 0.42000, 0.42000,
+ 0.46271, 0.46271, 0.46271,
+ 0.50543, 0.50543, 0.50543,
+ 0.54814, 0.54814, 0.54814,
+ 0.33300, 0.33300, 0.33300,
+ 0.37571, 0.37571, 0.37571,
+ 0.41843, 0.41843, 0.41843,
+ 0.46114, 0.46114, 0.46114,
+ 0.50386, 0.50386, 0.50386,
+ 0.54657, 0.54657, 0.54657,
+ 0.58929, 0.58929, 0.58929,
+ 0.63200, 0.63200, 0.63200,
+ 0.41686, 0.41686, 0.41686,
+ 0.45957, 0.45957, 0.45957,
+ 0.50229, 0.50229, 0.50229,
+ 0.54500, 0.54500, 0.54500,
+ 0.58771, 0.58771, 0.58771,
+ 0.63043, 0.63043, 0.63043,
+ 0.67314, 0.67314, 0.67314,
+ 0.71586, 0.71586, 0.71586,
+ 0.50071, 0.50071, 0.50071,
+ 0.54343, 0.54343, 0.54343,
+ 0.58614, 0.58614, 0.58614,
+ 0.62886, 0.62886, 0.62886,
+ 0.67157, 0.67157, 0.67157,
+ 0.71429, 0.71429, 0.71429,
+ 0.75700, 0.75700, 0.75700,
+ 0.79971, 0.79971, 0.79971,
+ 0.58457, 0.58457, 0.58457,
+ 0.62729, 0.62729, 0.62729,
+ 0.67000, 0.67000, 0.67000,
+ 0.71271, 0.71271, 0.71271,
+ 0.75543, 0.75543, 0.75543,
+ 0.79814, 0.79814, 0.79814,
+ 0.84086, 0.84086, 0.84086,
+ 0.88357, 0.88357, 0.88357,
+ 0.66843, 0.66843, 0.66843,
+ 0.71114, 0.71114, 0.71114,
+ 0.75386, 0.75386, 0.75386,
+ 0.79657, 0.79657, 0.79657,
+ 0.83929, 0.83929, 0.83929,
+ 0.88200, 0.88200, 0.88200,
+ 0.92471, 0.92471, 0.92471,
+ 0.96743, 0.96743, 0.96743,
+ 0.09771, 0.09771, 0.09771,
+ 0.14043, 0.14043, 0.14043,
+ 0.18314, 0.18314, 0.18314,
+ 0.22586, 0.22586, 0.22586,
+ 0.26857, 0.26857, 0.26857,
+ 0.31129, 0.31129, 0.31129,
+ 0.35400, 0.35400, 0.35400,
+ 0.39671, 0.39671, 0.39671,
+ 0.18157, 0.18157, 0.18157,
+ 0.22429, 0.22429, 0.22429,
+ 0.26700, 0.26700, 0.26700,
+ 0.30971, 0.30971, 0.30971,
+ 0.35243, 0.35243, 0.35243,
+ 0.39514, 0.39514, 0.39514,
+ 0.43786, 0.43786, 0.43786,
+ 0.48057, 0.48057, 0.48057,
+ 0.26543, 0.26543, 0.26543,
+ 0.30814, 0.30814, 0.30814,
+ 0.35086, 0.35086, 0.35086,
+ 0.39357, 0.39357, 0.39357,
+ 0.43629, 0.43629, 0.43629,
+ 0.47900, 0.47900, 0.47900,
+ 0.52171, 0.52171, 0.52171,
+ 0.56443, 0.56443, 0.56443,
+ 0.34929, 0.34929, 0.34929,
+ 0.39200, 0.39200, 0.39200,
+ 0.43471, 0.43471, 0.43471,
+ 0.47743, 0.47743, 0.47743,
+ 0.52014, 0.52014, 0.52014,
+ 0.56286, 0.56286, 0.56286,
+ 0.60557, 0.60557, 0.60557,
+ 0.64829, 0.64829, 0.64829,
+ 0.43314, 0.43314, 0.43314,
+ 0.47586, 0.47586, 0.47586,
+ 0.51857, 0.51857, 0.51857,
+ 0.56129, 0.56129, 0.56129,
+ 0.60400, 0.60400, 0.60400,
+ 0.64671, 0.64671, 0.64671,
+ 0.68943, 0.68943, 0.68943,
+ 0.73214, 0.73214, 0.73214,
+ 0.51700, 0.51700, 0.51700,
+ 0.55971, 0.55971, 0.55971,
+ 0.60243, 0.60243, 0.60243,
+ 0.64514, 0.64514, 0.64514,
+ 0.68786, 0.68786, 0.68786,
+ 0.73057, 0.73057, 0.73057,
+ 0.77329, 0.77329, 0.77329,
+ 0.81600, 0.81600, 0.81600,
+ 0.60086, 0.60086, 0.60086,
+ 0.64357, 0.64357, 0.64357,
+ 0.68629, 0.68629, 0.68629,
+ 0.72900, 0.72900, 0.72900,
+ 0.77171, 0.77171, 0.77171,
+ 0.81443, 0.81443, 0.81443,
+ 0.85714, 0.85714, 0.85714,
+ 0.89986, 0.89986, 0.89986,
+ 0.68471, 0.68471, 0.68471,
+ 0.72743, 0.72743, 0.72743,
+ 0.77014, 0.77014, 0.77014,
+ 0.81286, 0.81286, 0.81286,
+ 0.85557, 0.85557, 0.85557,
+ 0.89829, 0.89829, 0.89829,
+ 0.94100, 0.94100, 0.94100,
+ 0.98371, 0.98371, 0.98371,
+ 0.11400, 0.11400, 0.11400,
+ 0.15671, 0.15671, 0.15671,
+ 0.19943, 0.19943, 0.19943,
+ 0.24214, 0.24214, 0.24214,
+ 0.28486, 0.28486, 0.28486,
+ 0.32757, 0.32757, 0.32757,
+ 0.37029, 0.37029, 0.37029,
+ 0.41300, 0.41300, 0.41300,
+ 0.19786, 0.19786, 0.19786,
+ 0.24057, 0.24057, 0.24057,
+ 0.28329, 0.28329, 0.28329,
+ 0.32600, 0.32600, 0.32600,
+ 0.36871, 0.36871, 0.36871,
+ 0.41143, 0.41143, 0.41143,
+ 0.45414, 0.45414, 0.45414,
+ 0.49686, 0.49686, 0.49686,
+ 0.28171, 0.28171, 0.28171,
+ 0.32443, 0.32443, 0.32443,
+ 0.36714, 0.36714, 0.36714,
+ 0.40986, 0.40986, 0.40986,
+ 0.45257, 0.45257, 0.45257,
+ 0.49529, 0.49529, 0.49529,
+ 0.53800, 0.53800, 0.53800,
+ 0.58071, 0.58071, 0.58071,
+ 0.36557, 0.36557, 0.36557,
+ 0.40829, 0.40829, 0.40829,
+ 0.45100, 0.45100, 0.45100,
+ 0.49371, 0.49371, 0.49371,
+ 0.53643, 0.53643, 0.53643,
+ 0.57914, 0.57914, 0.57914,
+ 0.62186, 0.62186, 0.62186,
+ 0.66457, 0.66457, 0.66457,
+ 0.44943, 0.44943, 0.44943,
+ 0.49214, 0.49214, 0.49214,
+ 0.53486, 0.53486, 0.53486,
+ 0.57757, 0.57757, 0.57757,
+ 0.62029, 0.62029, 0.62029,
+ 0.66300, 0.66300, 0.66300,
+ 0.70571, 0.70571, 0.70571,
+ 0.74843, 0.74843, 0.74843,
+ 0.53329, 0.53329, 0.53329,
+ 0.57600, 0.57600, 0.57600,
+ 0.61871, 0.61871, 0.61871,
+ 0.66143, 0.66143, 0.66143,
+ 0.70414, 0.70414, 0.70414,
+ 0.74686, 0.74686, 0.74686,
+ 0.78957, 0.78957, 0.78957,
+ 0.83229, 0.83229, 0.83229,
+ 0.61714, 0.61714, 0.61714,
+ 0.65986, 0.65986, 0.65986,
+ 0.70257, 0.70257, 0.70257,
+ 0.74529, 0.74529, 0.74529,
+ 0.78800, 0.78800, 0.78800,
+ 0.83071, 0.83071, 0.83071,
+ 0.87343, 0.87343, 0.87343,
+ 0.91614, 0.91614, 0.91614,
+ 0.70100, 0.70100, 0.70100,
+ 0.74371, 0.74371, 0.74371,
+ 0.78643, 0.78643, 0.78643,
+ 0.82914, 0.82914, 0.82914,
+ 0.87186, 0.87186, 0.87186,
+ 0.91457, 0.91457, 0.91457,
+ 0.95729, 0.95729, 0.95729,
+ 1.00000, 1.00000, 1.00000
+ };
+
+ // check cube data
+ for(unsigned int i = 0; i < looklut->lut3D->lut.size(); ++i) {
+ OIIO_CHECK_CLOSE(cube[i], looklut->lut3D->lut[i], 1e-4);
+ }
+}
+
+
+OIIO_ADD_TEST(FileFormatIridasLook, fail_on_mask)
+{
+ std::ostringstream strebuf;
+ strebuf << "<?xml version=\"1.0\" ?>" << "\n";
+ strebuf << "<look>" << "\n";
+ strebuf << " <shaders>" << "\n";
+ strebuf << " <base>" << "\n";
+ strebuf << " <rangeversion>\"2\"</rangeversion>" << "\n";
+ strebuf << " <visible>\"1\"</visible>" << "\n";
+ strebuf << " <sublayer0>" << "\n";
+ strebuf << " <opacity>\"1\"</opacity>" << "\n";
+ strebuf << " <parameters>" << "\n";
+ strebuf << " <LogPrinterLights>\"N1\"</LogPrinterLights>" << "\n";
+ strebuf << " </parameters>" << "\n";
+ strebuf << " </sublayer0>" << "\n";
+ strebuf << " <sublayer3>" << "\n";
+ strebuf << " <opacity>\"1\"</opacity>" << "\n";
+ strebuf << " <parameters>" << "\n";
+ strebuf << " <gamma.Z>\"0.49967\"</gamma.Z>" << "\n";
+ strebuf << " <gain.Z>\"0.28739\"</gain.Z>" << "\n";
+ strebuf << " <gamma.Y>\"0.49179\"</gamma.Y>" << "\n";
+ strebuf << " <gain.Y>\"0.22243\"</gain.Y>" << "\n";
+ strebuf << " <gain.X>\"0.34531\"</gain.X>" << "\n";
+ strebuf << " <gamma.X>\"0.39388\"</gamma.X>" << "\n";
+ strebuf << " </parameters>" << "\n";
+ strebuf << " </sublayer3>" << "\n";
+ strebuf << " </base>" << "\n";
+ strebuf << " </shaders>" << "\n";
+ strebuf << " <mask>" << "\n";
+ strebuf << " <name>\"Untitled00_00_00_00\"</name>" << "\n";
+ strebuf << " <activecontour>\"0\"</activecontour>" << "\n";
+ strebuf << " <width>\"1024\"</width>" << "\n";
+ strebuf << " <height>\"778\"</height>" << "\n";
+ strebuf << " <contour>" << "\n";
+ strebuf << " <positive>\"1\"</positive>" << "\n";
+ strebuf << " <point>" << "\n";
+ strebuf << " <inner>\"catmull-rom,value:317.5,583.5@0\"</inner>" << "\n";
+ strebuf << " <innerprevtangent>\"catmull-rom,value:0,0@0\"</innerprevtangent>" << "\n";
+ strebuf << " <innernexttangent>\"catmull-rom,value:0,0@0\"</innernexttangent>" << "\n";
+ strebuf << " <falloffexponent>\"catmull-rom,value:1@0\"</falloffexponent>" << "\n";
+ strebuf << " <falloffweight>\"catmull-rom,value:0.5@0\"</falloffweight>" << "\n";
+ strebuf << " <detached>linear,value:0@0</detached>" << "\n";
+ strebuf << " <outer>\"catmull-rom,value:317.5,583.5@0\"</outer>" << "\n";
+ strebuf << " <outerprevtangent>\"catmull-rom,value:0,0@0\"</outerprevtangent>" << "\n";
+ strebuf << " <outernexttangent>\"catmull-rom,value:0,0@0\"</outernexttangent>" << "\n";
+ strebuf << " <spline>\"linear,value:0@0\"</spline>" << "\n";
+ strebuf << " <smooth>\"linear,value:0@0\"</smooth>" << "\n";
+ strebuf << " </point>" << "\n";
+ strebuf << " </contour>" << "\n";
+ strebuf << " </mask>" << "\n";
+ strebuf << " <LUT>" << "\n";
+ strebuf << " <size>\"8\"</size>" << "\n";
+ strebuf << " <data>\"" << "\n";
+ strebuf << " 000000000000000000000000878B933D000000000000000057BC563E00000000" << "\n";
+ strebuf << " ...truncated, should never be parsed due to mask section\"" << "\n";
+ strebuf << " </data>" << "\n";
+ strebuf << " </LUT>" << "\n";
+ strebuf << "</look>" << "\n";
+
+ std::istringstream infile;
+ infile.str(strebuf.str());
+
+ // Read file
+ LocalFileFormat tester;
+ try
+ {
+ CachedFileRcPtr cachedFile = tester.Read(infile);
+ OIIO_CHECK_ASSERT(false); // Fail test if previous line doesn't throw Exception
+ }
+ catch(Exception& e)
+ {
+ // Check exception message is correct error (not something
+ // like "cannot parse LUT data")
+ std::string expected_error = "Cannot load .look LUT containing mask";
+ OIIO_CHECK_EQUAL(e.what(), expected_error);
+ }
+
+}
+#endif // OCIO_UNIT_TEST
diff --git a/src/core/FileFormatPandora.cpp b/src/core/FileFormatPandora.cpp
new file mode 100644
index 0000000..eef68d2
--- /dev/null
+++ b/src/core/FileFormatPandora.cpp
@@ -0,0 +1,286 @@
+/*
+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 <cstdio>
+#include <iostream>
+#include <iterator>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "FileTransform.h"
+#include "Lut1DOp.h"
+#include "Lut3DOp.h"
+#include "ParseUtils.h"
+#include "pystring/pystring.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ class LocalCachedFile : public CachedFile
+ {
+ public:
+ LocalCachedFile ()
+ {
+ lut3D = Lut3D::Create();
+ };
+ ~LocalCachedFile() {};
+
+ Lut3DRcPtr lut3D;
+ };
+
+ typedef OCIO_SHARED_PTR<LocalCachedFile> LocalCachedFileRcPtr;
+
+
+
+ class LocalFileFormat : public FileFormat
+ {
+ public:
+
+ ~LocalFileFormat() {};
+
+ virtual void GetFormatInfo(FormatInfoVec & formatInfoVec) const;
+
+ virtual CachedFileRcPtr Read(std::istream & istream) const;
+
+ virtual void BuildFileOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const;
+ };
+
+ void LocalFileFormat::GetFormatInfo(FormatInfoVec & formatInfoVec) const
+ {
+ FormatInfo info;
+ info.name = "pandora_mga";
+ info.extension = "mga";
+ info.capabilities = FORMAT_CAPABILITY_READ;
+ formatInfoVec.push_back(info);
+
+ FormatInfo info2;
+ info2.name = "pandora_m3d";
+ info2.extension = "m3d";
+ info2.capabilities = FORMAT_CAPABILITY_READ;
+ formatInfoVec.push_back(info2);
+ }
+
+ CachedFileRcPtr
+ LocalFileFormat::Read(std::istream & istream) const
+ {
+ // this shouldn't happen
+ if(!istream)
+ {
+ throw Exception ("File stream empty when trying to read Pandora lut");
+ }
+
+ // Validate the file type
+ std::string line;
+
+ // Parse the file
+ std::string format;
+ int lutEdgeLen = 0;
+ int outputBitDepthMaxValue = 0;
+ std::vector<int> raw3d;
+
+ {
+ std::vector<std::string> parts;
+ std::vector<int> tmpints;
+ bool inLut3d = false;
+
+ while(nextline(istream, line))
+ {
+ // Strip, lowercase, and split the line
+ pystring::split(pystring::lower(pystring::strip(line)), parts);
+ if(parts.empty()) continue;
+
+ // Skip all lines starting with '#'
+ if(pystring::startswith(parts[0],"#")) continue;
+
+ if(parts[0] == "channel")
+ {
+ if(parts.size() != 2 || pystring::lower(parts[1]) != "3d")
+ {
+ throw Exception("Parse error in Pandora lut. Only 3d luts are currently supported. (channel: 3d).");
+ }
+ }
+ else if(parts[0] == "in")
+ {
+ int inval = 0;
+ if(parts.size() != 2 || !StringToInt( &inval, parts[1].c_str()))
+ {
+ throw Exception("Malformed 'in' tag in Pandora lut.");
+ }
+ raw3d.reserve(inval*3);
+ lutEdgeLen = Get3DLutEdgeLenFromNumPixels(inval);
+ }
+ else if(parts[0] == "out")
+ {
+ if(parts.size() != 2 || !StringToInt( &outputBitDepthMaxValue, parts[1].c_str()))
+ {
+ throw Exception("Malformed 'out' tag in Pandora lut.");
+ }
+ }
+ else if(parts[0] == "format")
+ {
+ if(parts.size() != 2 || pystring::lower(parts[1]) != "lut")
+ {
+ throw Exception("Parse error in Pandora lut. Only luts are currently supported. (format: lut).");
+ }
+ }
+ else if(parts[0] == "values")
+ {
+ if(parts.size() != 4 ||
+ pystring::lower(parts[1]) != "red" ||
+ pystring::lower(parts[2]) != "green" ||
+ pystring::lower(parts[3]) != "blue")
+ {
+ throw Exception("Parse error in Pandora lut. Only rgb luts are currently supported. (values: red green blue).");
+ }
+
+ inLut3d = true;
+ }
+ else if(inLut3d)
+ {
+ if(!StringVecToIntVec(tmpints, parts) || tmpints.size() != 4)
+ {
+ std::ostringstream os;
+ os << "Parse error in Pandora lut. Expected to find 4 integers. Instead found '"
+ << line << "'";
+ throw Exception(os.str().c_str());
+ }
+
+ raw3d.push_back(tmpints[1]);
+ raw3d.push_back(tmpints[2]);
+ raw3d.push_back(tmpints[3]);
+ }
+ }
+ }
+
+ // Interpret the parsed data, validate lut sizes
+ if(lutEdgeLen*lutEdgeLen*lutEdgeLen != static_cast<int>(raw3d.size()/3))
+ {
+ std::ostringstream os;
+ os << "Parse error in Pandora lut. ";
+ os << "Incorrect number of lut3d entries. ";
+ os << "Found " << raw3d.size()/3 << ", expected " << lutEdgeLen*lutEdgeLen*lutEdgeLen << ".";
+ throw Exception(os.str().c_str());
+ }
+
+ if(lutEdgeLen*lutEdgeLen*lutEdgeLen == 0)
+ {
+ std::ostringstream os;
+ os << "Parse error in Pandora lut. ";
+ os << "No 3D Lut entries found.";
+ throw Exception(os.str().c_str());
+ }
+
+ if(outputBitDepthMaxValue <= 0)
+ {
+ std::ostringstream os;
+ os << "Parse error in Pandora lut. ";
+ os << "A valid 'out' tag was not found.";
+ throw Exception(os.str().c_str());
+ }
+
+ LocalCachedFileRcPtr cachedFile = LocalCachedFileRcPtr(new LocalCachedFile());
+
+ // Reformat 3D data
+ cachedFile->lut3D->size[0] = lutEdgeLen;
+ cachedFile->lut3D->size[1] = lutEdgeLen;
+ cachedFile->lut3D->size[2] = lutEdgeLen;
+ cachedFile->lut3D->lut.reserve(raw3d.size());
+
+ float scale = 1.0f / ((float)outputBitDepthMaxValue - 1.0f);
+
+ for(int rIndex=0; rIndex<lutEdgeLen; ++rIndex)
+ {
+ for(int gIndex=0; gIndex<lutEdgeLen; ++gIndex)
+ {
+ for(int bIndex=0; bIndex<lutEdgeLen; ++bIndex)
+ {
+ int i = GetLut3DIndex_B(rIndex, gIndex, bIndex,
+ lutEdgeLen, lutEdgeLen, lutEdgeLen);
+ cachedFile->lut3D->lut.push_back(static_cast<float>(raw3d[i+0]) * scale);
+ cachedFile->lut3D->lut.push_back(static_cast<float>(raw3d[i+1]) * scale);
+ cachedFile->lut3D->lut.push_back(static_cast<float>(raw3d[i+2]) * scale);
+ }
+ }
+ }
+
+ return cachedFile;
+ }
+
+ void
+ LocalFileFormat::BuildFileOps(OpRcPtrVec & ops,
+ const Config& /*config*/,
+ const ConstContextRcPtr & /*context*/,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const
+ {
+ LocalCachedFileRcPtr cachedFile = DynamicPtrCast<LocalCachedFile>(untypedCachedFile);
+
+ // This should never happen.
+ if(!cachedFile)
+ {
+ std::ostringstream os;
+ os << "Cannot build Truelight .cub Op. Invalid cache type.";
+ throw Exception(os.str().c_str());
+ }
+
+ TransformDirection newDir = CombineTransformDirections(dir,
+ fileTransform.getDirection());
+ if(newDir == TRANSFORM_DIR_UNKNOWN)
+ {
+ std::ostringstream os;
+ os << "Cannot build file format transform,";
+ os << " unspecified transform direction.";
+ throw Exception(os.str().c_str());
+ }
+
+ if(newDir == TRANSFORM_DIR_FORWARD)
+ {
+ CreateLut3DOp(ops, cachedFile->lut3D,
+ fileTransform.getInterpolation(), newDir);
+ }
+ else if(newDir == TRANSFORM_DIR_INVERSE)
+ {
+ CreateLut3DOp(ops, cachedFile->lut3D,
+ fileTransform.getInterpolation(), newDir);
+ }
+ }
+ }
+
+ FileFormat * CreateFileFormatPandora()
+ {
+ return new LocalFileFormat();
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/FileFormatSpi1D.cpp b/src/core/FileFormatSpi1D.cpp
new file mode 100644
index 0000000..2835c50
--- /dev/null
+++ b/src/core/FileFormatSpi1D.cpp
@@ -0,0 +1,261 @@
+/*
+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 "FileTransform.h"
+#include "Lut1DOp.h"
+#include "pystring/pystring.h"
+
+#include <cstdio>
+#include <sstream>
+
+/*
+Version 1
+From -7.5 3.7555555555555555
+Components 1
+Length 4096
+{
+ 0.031525943963232252
+ 0.045645604561056156
+ ...
+}
+
+*/
+
+
+OCIO_NAMESPACE_ENTER
+{
+ ////////////////////////////////////////////////////////////////
+
+ namespace
+ {
+ class LocalCachedFile : public CachedFile
+ {
+ public:
+ LocalCachedFile()
+ {
+ lut = Lut1D::Create();
+ };
+ ~LocalCachedFile() {};
+
+ Lut1DRcPtr lut;
+ };
+
+ typedef OCIO_SHARED_PTR<LocalCachedFile> LocalCachedFileRcPtr;
+
+
+ class LocalFileFormat : public FileFormat
+ {
+ public:
+
+ ~LocalFileFormat() {};
+
+ virtual void GetFormatInfo(FormatInfoVec & formatInfoVec) const;
+
+ virtual CachedFileRcPtr Read(std::istream & istream) const;
+
+ virtual void BuildFileOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const;
+ };
+
+ void LocalFileFormat::GetFormatInfo(FormatInfoVec & formatInfoVec) const
+ {
+ FormatInfo info;
+ info.name = "spi1d";
+ info.extension = "spi1d";
+ info.capabilities = FORMAT_CAPABILITY_READ;
+ formatInfoVec.push_back(info);
+ }
+
+ // Try and load the format
+ // Raise an exception if it can't be loaded.
+
+ CachedFileRcPtr LocalFileFormat::Read(std::istream & istream) const
+ {
+ Lut1DRcPtr lut1d = Lut1D::Create();
+
+ // Parse Header Info
+ int lut_size = -1;
+ float from_min = 0.0;
+ float from_max = 1.0;
+ int version = -1;
+ int components = -1;
+
+ const int MAX_LINE_SIZE = 4096;
+ char lineBuffer[MAX_LINE_SIZE];
+
+ // PARSE HEADER INFO
+ {
+ std::string headerLine("");
+ do
+ {
+ istream.getline(lineBuffer, MAX_LINE_SIZE);
+ headerLine = std::string(lineBuffer);
+ if(pystring::startswith(headerLine, "Version"))
+ {
+ if(sscanf(lineBuffer, "Version %d", &version)!=1)
+ throw Exception("Invalid 'Version' Tag");
+ }
+ else if(pystring::startswith(headerLine, "From"))
+ {
+ if(sscanf(lineBuffer, "From %f %f", &from_min, &from_max)!=2)
+ throw Exception("Invalid 'From' Tag");
+ }
+ else if(pystring::startswith(headerLine, "Components"))
+ {
+ if(sscanf(lineBuffer, "Components %d", &components)!=1)
+ throw Exception("Invalid 'Components' Tag");
+ }
+ else if(pystring::startswith(headerLine, "Length"))
+ {
+ if(sscanf(lineBuffer, "Length %d", &lut_size)!=1)
+ throw Exception("Invalid 'Length' Tag");
+ }
+ }
+ while (istream.good() && !pystring::startswith(headerLine,"{"));
+ }
+
+ if(version == -1)
+ throw Exception("Could not find 'Version' Tag");
+ if(version != 1)
+ throw Exception("Only format version 1 supported.");
+ if (lut_size == -1)
+ throw Exception("Could not find 'Length' Tag");
+ if (components == -1)
+ throw Exception("Could not find 'Components' Tag");
+ if (components<0 || components>3)
+ throw Exception("Components must be [1,2,3]");
+
+
+
+ for(int i=0; i<3; ++i)
+ {
+ lut1d->from_min[i] = from_min;
+ lut1d->from_max[i] = from_max;
+ lut1d->luts[i].clear();
+ lut1d->luts[i].reserve(lut_size);
+ }
+
+ {
+ istream.getline(lineBuffer, MAX_LINE_SIZE);
+
+ int lineCount=0;
+ float values[4];
+
+ while (istream.good())
+ {
+ // If 1 component is specificed, use x1 x1 x1 defaultA
+ if(components==1 && sscanf(lineBuffer,"%f",&values[0])==1)
+ {
+ lut1d->luts[0].push_back(values[0]);
+ lut1d->luts[1].push_back(values[0]);
+ lut1d->luts[2].push_back(values[0]);
+ ++lineCount;
+ }
+ // If 2 components are specificed, use x1 x2 0.0
+ else if(components==2 && sscanf(lineBuffer,"%f %f",&values[0],&values[1])==2)
+ {
+ lut1d->luts[0].push_back(values[0]);
+ lut1d->luts[1].push_back(values[1]);
+ lut1d->luts[2].push_back(0.0);
+ ++lineCount;
+ }
+ // If 3 component is specificed, use x1 x2 x3 defaultA
+ else if(components==3 && sscanf(lineBuffer,"%f %f %f",&values[0],&values[1],&values[2])==3)
+ {
+ lut1d->luts[0].push_back(values[0]);
+ lut1d->luts[1].push_back(values[1]);
+ lut1d->luts[2].push_back(values[2]);
+ ++lineCount;
+ }
+
+ if(lineCount == lut_size) break;
+
+ istream.getline(lineBuffer, MAX_LINE_SIZE);
+ }
+
+ if(lineCount!=lut_size)
+ throw Exception("Not enough entries found.");
+ }
+
+ // 1e-5 rel error is a good threshold when float numbers near 0
+ // are written out with 6 decimal places of precision. This is
+ // a bit aggressive, I.e., changes in the 6th decimal place will
+ // be considered roundoff error, but changes in the 5th decimal
+ // will be considered lut 'intent'.
+ // 1.0
+ // 1.000005 equal to 1.0
+ // 1.000007 equal to 1.0
+ // 1.000010 not equal
+ // 0.0
+ // 0.000001 not equal
+ lut1d->maxerror = 1e-5f;
+ lut1d->errortype = ERROR_RELATIVE;
+
+ LocalCachedFileRcPtr cachedFile = LocalCachedFileRcPtr(new LocalCachedFile());
+ cachedFile->lut = lut1d;
+ return cachedFile;
+ }
+
+ void LocalFileFormat::BuildFileOps(OpRcPtrVec & ops,
+ const Config& /*config*/,
+ const ConstContextRcPtr & /*context*/,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const
+ {
+ LocalCachedFileRcPtr cachedFile = DynamicPtrCast<LocalCachedFile>(untypedCachedFile);
+
+ if(!cachedFile) // This should never happen.
+ {
+ std::ostringstream os;
+ os << "Cannot build Spi1D Op. Invalid cache type.";
+ throw Exception(os.str().c_str());
+ }
+
+ TransformDirection newDir = CombineTransformDirections(dir,
+ fileTransform.getDirection());
+
+ CreateLut1DOp(ops,
+ cachedFile->lut,
+ fileTransform.getInterpolation(),
+ newDir);
+ }
+ }
+
+ FileFormat * CreateFileFormatSpi1D()
+ {
+ return new LocalFileFormat();
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/FileFormatSpi3D.cpp b/src/core/FileFormatSpi3D.cpp
new file mode 100644
index 0000000..b1d8c69
--- /dev/null
+++ b/src/core/FileFormatSpi3D.cpp
@@ -0,0 +1,209 @@
+/*
+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 "FileTransform.h"
+#include "Lut3DOp.h"
+#include "pystring/pystring.h"
+
+#include <cstdio>
+#include <sstream>
+
+/*
+SPILUT 1.0
+3 3
+32 32 32
+0 0 0 0.0132509 0.0158522 0.0156622
+0 0 1 0.0136178 0.018843 0.033921
+0 0 2 0.0136487 0.0240918 0.0563014
+0 0 3 0.015706 0.0303061 0.0774135
+
+... entries can be in any order
+... after the expected number of entries is found, file can contain anything
+*/
+
+
+OCIO_NAMESPACE_ENTER
+{
+ ////////////////////////////////////////////////////////////////
+
+ namespace
+ {
+ class LocalCachedFile : public CachedFile
+ {
+ public:
+ LocalCachedFile()
+ {
+ lut = Lut3D::Create();
+ };
+ ~LocalCachedFile() {};
+
+ Lut3DRcPtr lut;
+ };
+
+ typedef OCIO_SHARED_PTR<LocalCachedFile> LocalCachedFileRcPtr;
+
+
+
+ class LocalFileFormat : public FileFormat
+ {
+ public:
+
+ ~LocalFileFormat() {};
+
+ virtual void GetFormatInfo(FormatInfoVec & formatInfoVec) const;
+
+ virtual CachedFileRcPtr Read(std::istream & istream) const;
+
+ virtual void BuildFileOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const;
+ };
+
+
+ void LocalFileFormat::GetFormatInfo(FormatInfoVec & formatInfoVec) const
+ {
+ FormatInfo info;
+ info.name = "spi3d";
+ info.extension = "spi3d";
+ info.capabilities = FORMAT_CAPABILITY_READ;
+ formatInfoVec.push_back(info);
+ }
+
+ CachedFileRcPtr
+ LocalFileFormat::Read(std::istream & istream) const
+ {
+ const int MAX_LINE_SIZE = 4096;
+ char lineBuffer[MAX_LINE_SIZE];
+
+ Lut3DRcPtr lut3d = Lut3D::Create();
+
+ // Read header information
+ istream.getline(lineBuffer, MAX_LINE_SIZE);
+ if(!pystring::startswith(pystring::lower(lineBuffer), "spilut"))
+ {
+ std::ostringstream os;
+ os << "Lut does not appear to be valid spilut format. ";
+ os << "Expected 'SPILUT'. Found, '" << lineBuffer << "'.";
+ throw Exception(os.str().c_str());
+ }
+
+ // TODO: Assert 2nd line is 3 3
+ istream.getline(lineBuffer, MAX_LINE_SIZE);
+
+ // Get LUT Size
+ // TODO: Error handling
+ int rSize, gSize, bSize;
+ istream.getline(lineBuffer, MAX_LINE_SIZE);
+ sscanf(lineBuffer, "%d %d %d", &rSize, &gSize, &bSize);
+
+ lut3d->size[0] = rSize;
+ lut3d->size[1] = gSize;
+ lut3d->size[2] = bSize;
+ lut3d->lut.resize(rSize * gSize * bSize * 3);
+
+ // Parse table
+ int index = 0;
+ int rIndex, gIndex, bIndex;
+ float redValue, greenValue, blueValue;
+
+ int entriesRemaining = rSize * gSize * bSize;
+
+ while (istream.good() && entriesRemaining > 0)
+ {
+ istream.getline(lineBuffer, MAX_LINE_SIZE);
+
+ if (sscanf(lineBuffer, "%d %d %d %f %f %f",
+ &rIndex, &gIndex, &bIndex,
+ &redValue, &greenValue, &blueValue) == 6)
+ {
+ index = GetLut3DIndex_B(rIndex, gIndex, bIndex,
+ rSize, gSize, bSize);
+ if(index < 0 || index >= (int) lut3d->lut.size())
+ {
+ std::ostringstream os;
+ os << "Cannot load .spi3d lut, data is invalid. ";
+ os << "A lut entry is specified (";
+ os << rIndex << " " << gIndex << " " << bIndex;
+ os << " that falls outside of the cube.";
+ throw Exception(os.str().c_str());
+ }
+
+ lut3d->lut[index+0] = redValue;
+ lut3d->lut[index+1] = greenValue;
+ lut3d->lut[index+2] = blueValue;
+
+ entriesRemaining--;
+ }
+ }
+
+ // Have we fully populated the table?
+ if (entriesRemaining>0)
+ throw Exception("Not enough entries found.");
+
+ LocalCachedFileRcPtr cachedFile = LocalCachedFileRcPtr(new LocalCachedFile());
+ cachedFile->lut = lut3d;
+ return cachedFile;
+ }
+
+ void LocalFileFormat::BuildFileOps(OpRcPtrVec & ops,
+ const Config& /*config*/,
+ const ConstContextRcPtr & /*context*/,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const
+ {
+ LocalCachedFileRcPtr cachedFile = DynamicPtrCast<LocalCachedFile>(untypedCachedFile);
+
+ if(!cachedFile) // This should never happen.
+ {
+ std::ostringstream os;
+ os << "Cannot build Spi3D Op. Invalid cache type.";
+ throw Exception(os.str().c_str());
+ }
+
+ TransformDirection newDir = CombineTransformDirections(dir,
+ fileTransform.getDirection());
+
+ CreateLut3DOp(ops,
+ cachedFile->lut,
+ fileTransform.getInterpolation(),
+ newDir);
+ }
+ }
+
+ FileFormat * CreateFileFormatSpi3D()
+ {
+ return new LocalFileFormat();
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/FileFormatSpiMtx.cpp b/src/core/FileFormatSpiMtx.cpp
new file mode 100644
index 0000000..e14f557
--- /dev/null
+++ b/src/core/FileFormatSpiMtx.cpp
@@ -0,0 +1,195 @@
+/*
+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 "FileTransform.h"
+#include "MatrixOps.h"
+#include "ParseUtils.h"
+#include "pystring/pystring.h"
+
+#include <cstdio>
+#include <cstring>
+#include <sstream>
+
+
+OCIO_NAMESPACE_ENTER
+{
+ ////////////////////////////////////////////////////////////////
+
+ namespace
+ {
+ class LocalCachedFile : public CachedFile
+ {
+ public:
+ LocalCachedFile()
+ {
+ memset(m44, 0, 16*sizeof(float));
+ memset(offset4, 0, 4*sizeof(float));
+ };
+ ~LocalCachedFile() {};
+
+ float m44[16];
+ float offset4[4];
+ };
+
+ typedef OCIO_SHARED_PTR<LocalCachedFile> LocalCachedFileRcPtr;
+
+
+
+ class LocalFileFormat : public FileFormat
+ {
+ public:
+
+ ~LocalFileFormat() {};
+
+ virtual void GetFormatInfo(FormatInfoVec & formatInfoVec) const;
+
+ virtual CachedFileRcPtr Read(std::istream & istream) const;
+
+ virtual void BuildFileOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const;
+ };
+
+ void LocalFileFormat::GetFormatInfo(FormatInfoVec & formatInfoVec) const
+ {
+ FormatInfo info;
+ info.name = "spimtx";
+ info.extension = "spimtx";
+ info.capabilities = FORMAT_CAPABILITY_READ;
+ formatInfoVec.push_back(info);
+ }
+
+ CachedFileRcPtr
+ LocalFileFormat::Read(std::istream & istream) const
+ {
+
+ // Read the entire file.
+ std::ostringstream fileStream;
+
+ {
+ const int MAX_LINE_SIZE = 4096;
+ char lineBuffer[MAX_LINE_SIZE];
+
+ while (istream.good())
+ {
+ istream.getline(lineBuffer, MAX_LINE_SIZE);
+ fileStream << std::string(lineBuffer) << " ";
+ }
+ }
+
+ // Turn it into parts
+ std::vector<std::string> lineParts;
+ pystring::split(pystring::strip(fileStream.str()), lineParts);
+ if(lineParts.size() != 12)
+ {
+ std::ostringstream os;
+ os << "Error parsing .spimtx file. ";
+ os << "File must contain 12 float entries. ";
+ os << lineParts.size() << " found.";
+ throw Exception(os.str().c_str());
+ }
+
+ // Turn the parts into floats
+ std::vector<float> floatArray;
+ if(!StringVecToFloatVec(floatArray, lineParts))
+ {
+ std::ostringstream os;
+ os << "Error parsing .spimtx file. ";
+ os << "File must contain all float entries. ";
+ throw Exception(os.str().c_str());
+ }
+
+
+ // Put the bits in the right place
+ LocalCachedFileRcPtr cachedFile = LocalCachedFileRcPtr(new LocalCachedFile());
+
+ cachedFile->m44[0] = floatArray[0];
+ cachedFile->m44[1] = floatArray[1];
+ cachedFile->m44[2] = floatArray[2];
+ cachedFile->m44[3] = 0.0f;
+
+ cachedFile->m44[4] = floatArray[4];
+ cachedFile->m44[5] = floatArray[5];
+ cachedFile->m44[6] = floatArray[6];
+ cachedFile->m44[7] = 0.0f;
+
+ cachedFile->m44[8] = floatArray[8];
+ cachedFile->m44[9] = floatArray[9];
+ cachedFile->m44[10] = floatArray[10];
+ cachedFile->m44[11] = 0.0f;
+
+ cachedFile->m44[12] = 0.0f;
+ cachedFile->m44[13] = 0.0f;
+ cachedFile->m44[14] = 0.0f;
+ cachedFile->m44[15] = 1.0f;
+
+ cachedFile->offset4[0] = floatArray[3] / 65535.0f;
+ cachedFile->offset4[1] = floatArray[7] / 65535.0f;
+ cachedFile->offset4[2] = floatArray[11] / 65535.0f;
+ cachedFile->offset4[3] = 0.0f;
+
+ return cachedFile;
+ }
+
+ void LocalFileFormat::BuildFileOps(OpRcPtrVec & ops,
+ const Config& /*config*/,
+ const ConstContextRcPtr & /*context*/,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const
+ {
+ LocalCachedFileRcPtr cachedFile = DynamicPtrCast<LocalCachedFile>(untypedCachedFile);
+
+ if(!cachedFile) // This should never happen.
+ {
+ std::ostringstream os;
+ os << "Cannot build SpiMtx Ops. Invalid cache type.";
+ throw Exception(os.str().c_str());
+ }
+
+ TransformDirection newDir = CombineTransformDirections(dir,
+ fileTransform.getDirection());
+
+ CreateMatrixOffsetOp(ops,
+ cachedFile->m44,
+ cachedFile->offset4,
+ newDir);
+ }
+ }
+
+ FileFormat * CreateFileFormatSpiMtx()
+ {
+ return new LocalFileFormat();
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/FileFormatTruelight.cpp b/src/core/FileFormatTruelight.cpp
new file mode 100644
index 0000000..a7ccc48
--- /dev/null
+++ b/src/core/FileFormatTruelight.cpp
@@ -0,0 +1,620 @@
+/*
+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 <cstdio>
+#include <iostream>
+#include <iterator>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "FileTransform.h"
+#include "Lut1DOp.h"
+#include "Lut3DOp.h"
+#include "ParseUtils.h"
+#include "pystring/pystring.h"
+
+// This implements the spec for:
+// Per http://www.filmlight.ltd.uk/resources/documents/truelight/white-papers_tl.php
+// FL-TL-TN-0388-TLCubeFormat2.0.pdf
+//
+// Known deficiency in implementation:
+// 1D shaper luts (InputLUT) using integer encodings (vs float) are not supported.
+// How to we determine if the input is integer? MaxVal? Or do we look for a decimal-point?
+// How about scientific notation? (which is explicitly allowed?)
+
+/*
+The input LUT is used to interpolate a higher precision LUT matched to the particular image
+format. For integer formats, the range 0-1 is mapped onto the integer range. Floating point
+values outside the 0-1 range are allowed but may be truncated for integer formats.
+*/
+
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ class LocalCachedFile : public CachedFile
+ {
+ public:
+ LocalCachedFile () :
+ has1D(false),
+ has3D(false)
+ {
+ lut1D = Lut1D::Create();
+ lut3D = Lut3D::Create();
+ };
+ ~LocalCachedFile() {};
+
+ bool has1D;
+ bool has3D;
+ Lut1DRcPtr lut1D;
+ Lut3DRcPtr lut3D;
+ };
+
+ typedef OCIO_SHARED_PTR<LocalCachedFile> LocalCachedFileRcPtr;
+
+
+
+ class LocalFileFormat : public FileFormat
+ {
+ public:
+
+ ~LocalFileFormat() {};
+
+ virtual void GetFormatInfo(FormatInfoVec & formatInfoVec) const;
+
+ virtual CachedFileRcPtr Read(std::istream & istream) const;
+
+ virtual void BuildFileOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const;
+ };
+
+ void LocalFileFormat::GetFormatInfo(FormatInfoVec & formatInfoVec) const
+ {
+ FormatInfo info;
+ info.name = "truelight";
+ info.extension = "cub";
+ info.capabilities = FORMAT_CAPABILITY_READ;
+ formatInfoVec.push_back(info);
+ }
+
+ CachedFileRcPtr
+ LocalFileFormat::Read(std::istream & istream) const
+ {
+ // this shouldn't happen
+ if(!istream)
+ {
+ throw Exception ("File stream empty when trying to read Truelight .cub lut");
+ }
+
+ // Validate the file type
+ std::string line;
+ if(!nextline(istream, line) ||
+ !pystring::startswith(pystring::lower(line), "# truelight cube"))
+ {
+ throw Exception("Lut doesn't seem to be a Truelight .cub lut.");
+ }
+
+ // Parse the file
+ std::vector<float> raw1d;
+ std::vector<float> raw3d;
+ int size3d[] = { 0, 0, 0 };
+ int size1d = 0;
+ {
+ std::vector<std::string> parts;
+ std::vector<float> tmpfloats;
+
+ bool in1d = false;
+ bool in3d = false;
+
+ while(nextline(istream, line))
+ {
+ // Strip, lowercase, and split the line
+ pystring::split(pystring::lower(pystring::strip(line)), parts);
+
+ if(parts.empty()) continue;
+
+ // Parse header metadata (which starts with #)
+ if(pystring::startswith(parts[0],"#"))
+ {
+ if(parts.size() < 2) continue;
+
+ if(parts[1] == "width")
+ {
+ if(parts.size() != 5 ||
+ !StringToInt( &size3d[0], parts[2].c_str()) ||
+ !StringToInt( &size3d[1], parts[3].c_str()) ||
+ !StringToInt( &size3d[2], parts[4].c_str()))
+ {
+ throw Exception("Malformed width tag in Truelight .cub lut.");
+ }
+
+ raw3d.reserve(3*size3d[0]*size3d[1]*size3d[2]);
+ }
+ else if(parts[1] == "lutlength")
+ {
+ if(parts.size() != 3 ||
+ !StringToInt( &size1d, parts[2].c_str()))
+ {
+ throw Exception("Malformed lutlength tag in Truelight .cub lut.");
+ }
+ raw1d.reserve(3*size1d);
+ }
+ else if(parts[1] == "inputlut")
+ {
+ in1d = true;
+ in3d = false;
+ }
+ else if(parts[1] == "cube")
+ {
+ in3d = true;
+ in1d = false;
+ }
+ else if(parts[1] == "end")
+ {
+ in3d = false;
+ in1d = false;
+
+ // If we hit the end tag, don't bother searching further in the file.
+ break;
+ }
+ }
+
+
+ if(in1d || in3d)
+ {
+ if(StringVecToFloatVec(tmpfloats, parts) && (tmpfloats.size() == 3))
+ {
+ if(in1d)
+ {
+ raw1d.push_back(tmpfloats[0]);
+ raw1d.push_back(tmpfloats[1]);
+ raw1d.push_back(tmpfloats[2]);
+ }
+ else if(in3d)
+ {
+ raw3d.push_back(tmpfloats[0]);
+ raw3d.push_back(tmpfloats[1]);
+ raw3d.push_back(tmpfloats[2]);
+ }
+ }
+ }
+ }
+ }
+
+ // Interpret the parsed data, validate lut sizes
+
+ if(size1d != static_cast<int>(raw1d.size()/3))
+ {
+ std::ostringstream os;
+ os << "Parse error in Truelight .cub lut. ";
+ os << "Incorrect number of lut1d entries. ";
+ os << "Found " << raw1d.size()/3 << ", expected " << size1d << ".";
+ throw Exception(os.str().c_str());
+ }
+
+ if(size3d[0]*size3d[1]*size3d[2] != static_cast<int>(raw3d.size()/3))
+ {
+ std::ostringstream os;
+ os << "Parse error in Truelight .cub lut. ";
+ os << "Incorrect number of lut3d entries. ";
+ os << "Found " << raw3d.size()/3 << ", expected " << size3d[0]*size3d[1]*size3d[2] << ".";
+ throw Exception(os.str().c_str());
+ }
+
+
+ LocalCachedFileRcPtr cachedFile = LocalCachedFileRcPtr(new LocalCachedFile());
+
+ cachedFile->has1D = (size1d>0);
+ cachedFile->has3D = (size3d[0]*size3d[1]*size3d[2]>0);
+
+ // Reformat 1D data
+ if(cachedFile->has1D)
+ {
+ for(int channel=0; channel<3; ++channel)
+ {
+ // Determine the scale factor for the 1d lut. Example:
+ // The inputlut feeding a 6x6x6 3dlut should be scaled from 0.0-5.0.
+ // Beware: Nuke Truelight Writer (at least 6.3 and before) is busted
+ // and does this scaling incorrectly.
+
+ float descale = 1.0f;
+ if(cachedFile->has3D)
+ {
+ descale = 1.0f / static_cast<float>(size3d[channel]-1);
+ }
+
+ cachedFile->lut1D->luts[channel].resize(size1d);
+ for(int i=0; i<size1d; ++i)
+ {
+ cachedFile->lut1D->luts[channel][i] = raw1d[3*i+channel] * descale;
+ }
+ }
+
+ // 1e-5 rel error is a good threshold when float numbers near 0
+ // are written out with 6 decimal places of precision. This is
+ // a bit aggressive, I.e., changes in the 6th decimal place will
+ // be considered roundoff error, but changes in the 5th decimal
+ // will be considered lut 'intent'.
+ // 1.0
+ // 1.000005 equal to 1.0
+ // 1.000007 equal to 1.0
+ // 1.000010 not equal
+ // 0.0
+ // 0.000001 not equal
+
+ cachedFile->lut1D->maxerror = 1e-5f;
+ cachedFile->lut1D->errortype = ERROR_RELATIVE;
+ }
+
+ // Reformat 3D data
+ if(cachedFile->has3D)
+ {
+ cachedFile->lut3D->size[0] = size3d[0];
+ cachedFile->lut3D->size[1] = size3d[1];
+ cachedFile->lut3D->size[2] = size3d[2];
+ cachedFile->lut3D->lut = raw3d;
+ }
+
+ return cachedFile;
+ }
+
+ void
+ LocalFileFormat::BuildFileOps(OpRcPtrVec & ops,
+ const Config& /*config*/,
+ const ConstContextRcPtr & /*context*/,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const
+ {
+ LocalCachedFileRcPtr cachedFile = DynamicPtrCast<LocalCachedFile>(untypedCachedFile);
+
+ // This should never happen.
+ if(!cachedFile)
+ {
+ std::ostringstream os;
+ os << "Cannot build Truelight .cub Op. Invalid cache type.";
+ throw Exception(os.str().c_str());
+ }
+
+ TransformDirection newDir = CombineTransformDirections(dir,
+ fileTransform.getDirection());
+ if(newDir == TRANSFORM_DIR_UNKNOWN)
+ {
+ std::ostringstream os;
+ os << "Cannot build file format transform,";
+ os << " unspecified transform direction.";
+ throw Exception(os.str().c_str());
+ }
+
+ // TODO: INTERP_LINEAR should not be hard-coded.
+ // Instead query 'highest' interpolation?
+ // (right now, it's linear). If cubic is added, consider
+ // using it
+
+ if(newDir == TRANSFORM_DIR_FORWARD)
+ {
+ if(cachedFile->has1D)
+ {
+ CreateLut1DOp(ops, cachedFile->lut1D,
+ INTERP_LINEAR, newDir);
+ }
+
+ CreateLut3DOp(ops, cachedFile->lut3D,
+ fileTransform.getInterpolation(), newDir);
+ }
+ else if(newDir == TRANSFORM_DIR_INVERSE)
+ {
+ CreateLut3DOp(ops, cachedFile->lut3D,
+ fileTransform.getInterpolation(), newDir);
+
+ if(cachedFile->has1D)
+ {
+ CreateLut1DOp(ops, cachedFile->lut1D,
+ INTERP_LINEAR, newDir);
+ }
+ }
+ }
+ }
+
+ FileFormat * CreateFileFormatTruelight()
+ {
+ return new LocalFileFormat();
+ }
+}
+OCIO_NAMESPACE_EXIT
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef OCIO_UNIT_TEST
+
+namespace OCIO = OCIO_NAMESPACE;
+#include "UnitTest.h"
+
+OIIO_ADD_TEST(FileFormatTruelight, ShaperAndLut3D)
+{
+ // This lowers the red channel by 0.5, other channels are unaffected.
+ const char * luttext = "# Truelight Cube v2.0\n"
+ "# iDims 3\n"
+ "# oDims 3\n"
+ "# width 3 3 3\n"
+ "# lutLength 5\n"
+ "# InputLUT\n"
+ " 0.000000 0.000000 0.000000\n"
+ " 0.500000 0.500000 0.500000\n"
+ " 1.000000 1.000000 1.000000\n"
+ " 1.500000 1.500000 1.500000\n"
+ " 2.000000 2.000000 2.000000\n"
+ "\n"
+ "# Cube\n"
+ " 0.000000 0.000000 0.000000\n"
+ " 0.250000 0.000000 0.000000\n"
+ " 0.500000 0.000000 0.000000\n"
+ " 0.000000 0.500000 0.000000\n"
+ " 0.250000 0.500000 0.000000\n"
+ " 0.500000 0.500000 0.000000\n"
+ " 0.000000 1.000000 0.000000\n"
+ " 0.250000 1.000000 0.000000\n"
+ " 0.500000 1.000000 0.000000\n"
+ " 0.000000 0.000000 0.500000\n"
+ " 0.250000 0.000000 0.500000\n"
+ " 0.500000 0.000000 0.500000\n"
+ " 0.000000 0.500000 0.500000\n"
+ " 0.250000 0.500000 0.500000\n"
+ " 0.500000 0.500000 0.500000\n"
+ " 0.000000 1.000000 0.500000\n"
+ " 0.250000 1.000000 0.500000\n"
+ " 0.500000 1.000000 0.500000\n"
+ " 0.000000 0.000000 1.000000\n"
+ " 0.250000 0.000000 1.000000\n"
+ " 0.500000 0.000000 1.000000\n"
+ " 0.000000 0.500000 1.000000\n"
+ " 0.250000 0.500000 1.000000\n"
+ " 0.500000 0.500000 1.000000\n"
+ " 0.000000 1.000000 1.000000\n"
+ " 0.250000 1.000000 1.000000\n"
+ " 0.500000 1.000000 1.000000\n"
+ "\n"
+ "# end\n"
+ "\n"
+ "# Truelight profile\n"
+ "title{madeup on some display}\n"
+ "print{someprint}\n"
+ "display{some}\n"
+ "cubeFile{madeup.cube}\n"
+ "\n"
+ " # This last line confirms 'end' tag is obeyed\n"
+ " 1.23456 1.23456 1.23456\n";
+
+ std::istringstream lutIStream;
+ lutIStream.str(luttext);
+
+ // Read file
+ OCIO::LocalFileFormat tester;
+ OCIO::CachedFileRcPtr cachedFile;
+ OIIO_CHECK_NO_THOW(cachedFile = tester.Read(lutIStream));
+ OCIO::LocalCachedFileRcPtr lut = OCIO::DynamicPtrCast<OCIO::LocalCachedFile>(cachedFile);
+
+ OIIO_CHECK_ASSERT(lut->has1D);
+ OIIO_CHECK_ASSERT(lut->has3D);
+
+ float data[4*3] = { 0.1f, 0.2f, 0.3f, 0.0f,
+ 1.0f, 0.5f, 0.123456f, 0.0f,
+ -1.0f, 1.5f, 0.5f, 0.0f };
+
+ float result[4*3] = { 0.05f, 0.2f, 0.3f, 0.0f,
+ 0.50f, 0.5f, 0.123456f, 0.0f,
+ 0.0f, 1.5f, 0.5f, 0.0f };
+
+ OCIO::OpRcPtrVec ops;
+ if(lut->has1D)
+ {
+ CreateLut1DOp(ops, lut->lut1D,
+ OCIO::INTERP_LINEAR, OCIO::TRANSFORM_DIR_FORWARD);
+ }
+ if(lut->has3D)
+ {
+ CreateLut3DOp(ops, lut->lut3D,
+ OCIO::INTERP_LINEAR, OCIO::TRANSFORM_DIR_FORWARD);
+ }
+ FinalizeOpVec(ops);
+
+
+ // Apply the result
+ for(OCIO::OpRcPtrVec::size_type i = 0, size = ops.size(); i < size; ++i)
+ {
+ ops[i]->apply(data, 3);
+ }
+
+ for(int i=0; i<3; ++i)
+ {
+ OIIO_CHECK_CLOSE( data[i], result[i], 1.0e-6 );
+ }
+}
+
+OIIO_ADD_TEST(FileFormatTruelight, Shaper)
+{
+ const char * luttext = "# Truelight Cube v2.0\n"
+ "# lutLength 11\n"
+ "# iDims 3\n"
+ "\n"
+ "\n"
+ "# InputLUT\n"
+ " 0.000 0.000 -0.000\n"
+ " 0.200 0.010 -0.100\n"
+ " 0.400 0.040 -0.200\n"
+ " 0.600 0.090 -0.300\n"
+ " 0.800 0.160 -0.400\n"
+ " 1.000 0.250 -0.500\n"
+ " 1.200 0.360 -0.600\n"
+ " 1.400 0.490 -0.700\n"
+ " 1.600 0.640 -0.800\n"
+ " 1.800 0.820 -0.900\n"
+ " 2.000 1.000 -1.000\n"
+ "\n\n\n"
+ "# end\n";
+
+ std::istringstream lutIStream;
+ lutIStream.str(luttext);
+
+ // Read file
+ OCIO::LocalFileFormat tester;
+ OCIO::CachedFileRcPtr cachedFile;
+ OIIO_CHECK_NO_THOW(cachedFile = tester.Read(lutIStream));
+
+ OCIO::LocalCachedFileRcPtr lut = OCIO::DynamicPtrCast<OCIO::LocalCachedFile>(cachedFile);
+
+ OIIO_CHECK_ASSERT(lut->has1D);
+ OIIO_CHECK_ASSERT(!lut->has3D);
+
+ float data[4*3] = { 0.1f, 0.2f, 0.3f, 0.0f,
+ 1.0f, 0.5f, 0.123456f, 0.0f,
+ -1.0f, 1.5f, 0.5f, 0.0f };
+
+ float result[4*3] = { 0.2f, 0.04f, -0.3f, 0.0f,
+ 2.0f, 0.25f, -0.123456f, 0.0f,
+ 0.0f, 1.0f, -0.5f, 0.0f };
+
+ OCIO::OpRcPtrVec ops;
+ if(lut->has1D)
+ {
+ CreateLut1DOp(ops, lut->lut1D,
+ OCIO::INTERP_LINEAR, OCIO::TRANSFORM_DIR_FORWARD);
+ }
+ if(lut->has3D)
+ {
+ CreateLut3DOp(ops, lut->lut3D,
+ OCIO::INTERP_LINEAR, OCIO::TRANSFORM_DIR_FORWARD);
+ }
+ FinalizeOpVec(ops);
+
+
+ // Apply the result
+ for(OCIO::OpRcPtrVec::size_type i = 0, size = ops.size(); i < size; ++i)
+ {
+ ops[i]->apply(data, 3);
+ }
+
+ for(int i=0; i<3; ++i)
+ {
+ OIIO_CHECK_CLOSE( data[i], result[i], 1.0e-6 );
+ }
+}
+
+
+OIIO_ADD_TEST(FileFormatTruelight, Lut3D)
+{
+ // This lowers the red channel by 0.5, other channels are unaffected.
+ const char * luttext = "# Truelight Cube v2.0\n"
+ "# iDims 3\n"
+ "# oDims 3\n"
+ "# width 3 3 3\n"
+ "\n\n\n"
+ "# Cube\n"
+ " 0.000000 0.000000 0.000000\n"
+ " 0.250000 0.000000 0.000000\n"
+ " 0.500000 0.000000 0.000000\n"
+ " 0.000000 0.500000 0.000000\n"
+ " 0.250000 0.500000 0.000000\n"
+ " 0.500000 0.500000 0.000000\n"
+ " 0.000000 1.000000 0.000000\n"
+ " 0.250000 1.000000 0.000000\n"
+ " 0.500000 1.000000 0.000000\n"
+ " 0.000000 0.000000 0.500000\n"
+ " 0.250000 0.000000 0.500000\n"
+ " 0.500000 0.000000 0.500000\n"
+ " 0.000000 0.500000 0.500000\n"
+ " 0.250000 0.500000 0.500000\n"
+ " 0.500000 0.500000 0.500000\n"
+ " 0.000000 1.000000 0.500000\n"
+ " 0.250000 1.000000 0.500000\n"
+ " 0.500000 1.000000 0.500000\n"
+ " 0.000000 0.000000 1.000000\n"
+ " 0.250000 0.000000 1.000000\n"
+ " 0.500000 0.000000 1.000000\n"
+ " 0.000000 0.500000 1.000000\n"
+ " 0.250000 0.500000 1.000000\n"
+ " 0.500000 0.500000 1.000000\n"
+ " 0.000000 1.000000 1.000000\n"
+ " 0.250000 1.000000 1.000000\n"
+ " 0.500000 1.000000 1.000000\n"
+ "\n"
+ "# end\n";
+
+ std::istringstream lutIStream;
+ lutIStream.str(luttext);
+
+ // Read file
+ OCIO::LocalFileFormat tester;
+ OCIO::CachedFileRcPtr cachedFile;
+ OIIO_CHECK_NO_THOW(cachedFile = tester.Read(lutIStream));
+ OCIO::LocalCachedFileRcPtr lut = OCIO::DynamicPtrCast<OCIO::LocalCachedFile>(cachedFile);
+
+ OIIO_CHECK_ASSERT(!lut->has1D);
+ OIIO_CHECK_ASSERT(lut->has3D);
+
+ float data[4*3] = { 0.1f, 0.2f, 0.3f, 0.0f,
+ 1.0f, 0.5f, 0.123456f, 0.0f,
+ -1.0f, 1.5f, 0.5f, 0.0f };
+
+ float result[4*3] = { 0.05f, 0.2f, 0.3f, 0.0f,
+ 0.50f, 0.5f, 0.123456f, 0.0f,
+ 0.0f, 1.5f, 0.5f, 0.0f };
+
+ OCIO::OpRcPtrVec ops;
+ if(lut->has1D)
+ {
+ CreateLut1DOp(ops, lut->lut1D,
+ OCIO::INTERP_LINEAR, OCIO::TRANSFORM_DIR_FORWARD);
+ }
+ if(lut->has3D)
+ {
+ CreateLut3DOp(ops, lut->lut3D,
+ OCIO::INTERP_LINEAR, OCIO::TRANSFORM_DIR_FORWARD);
+ }
+ FinalizeOpVec(ops);
+
+
+ // Apply the result
+ for(OCIO::OpRcPtrVec::size_type i = 0, size = ops.size(); i < size; ++i)
+ {
+ ops[i]->apply(data, 3);
+ }
+
+ for(int i=0; i<3; ++i)
+ {
+ OIIO_CHECK_CLOSE( data[i], result[i], 1.0e-6 );
+ }
+}
+
+#endif // OCIO_UNIT_TEST
diff --git a/src/core/FileFormatVF.cpp b/src/core/FileFormatVF.cpp
new file mode 100644
index 0000000..cb46ef0
--- /dev/null
+++ b/src/core/FileFormatVF.cpp
@@ -0,0 +1,297 @@
+/*
+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 <cstdio>
+#include <cstring>
+#include <iostream>
+#include <iterator>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "FileTransform.h"
+#include "Lut3DOp.h"
+#include "MatrixOps.h"
+#include "ParseUtils.h"
+#include "pystring/pystring.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ class LocalCachedFile : public CachedFile
+ {
+ public:
+ LocalCachedFile () :
+ useMatrix(false)
+ {
+ lut3D = Lut3D::Create();
+ memset(m44, 0, 16*sizeof(float));
+ };
+ ~LocalCachedFile() {};
+
+ Lut3DRcPtr lut3D;
+ float m44[16];
+ bool useMatrix;
+ };
+
+ typedef OCIO_SHARED_PTR<LocalCachedFile> LocalCachedFileRcPtr;
+
+
+
+ class LocalFileFormat : public FileFormat
+ {
+ public:
+
+ ~LocalFileFormat() {};
+
+ virtual void GetFormatInfo(FormatInfoVec & formatInfoVec) const;
+
+ virtual CachedFileRcPtr Read(std::istream & istream) const;
+
+ virtual void BuildFileOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const;
+ };
+
+ void LocalFileFormat::GetFormatInfo(FormatInfoVec & formatInfoVec) const
+ {
+ FormatInfo info;
+ info.name = "nukevf";
+ info.extension = "vf";
+ info.capabilities = FORMAT_CAPABILITY_READ;
+ formatInfoVec.push_back(info);
+ }
+
+ CachedFileRcPtr
+ LocalFileFormat::Read(std::istream & istream) const
+ {
+ // this shouldn't happen
+ if(!istream)
+ {
+ throw Exception ("File stream empty when trying to read .vf lut");
+ }
+
+ // Validate the file type
+ std::string line;
+ if(!nextline(istream, line) ||
+ !pystring::startswith(pystring::lower(line), "#inventor"))
+ {
+ throw Exception("Lut doesn't seem to be a .vf lut. Expecting '#Inventor V2.1 ascii'.");
+ }
+
+ // Parse the file
+ std::vector<float> raw3d;
+ int size3d[] = { 0, 0, 0 };
+ std::vector<float> global_transform;
+
+ {
+ std::vector<std::string> parts;
+ std::vector<float> tmpfloats;
+
+ bool in3d = false;
+
+ while(nextline(istream, line))
+ {
+ // Strip, lowercase, and split the line
+ pystring::split(pystring::lower(pystring::strip(line)), parts);
+
+ if(parts.empty()) continue;
+
+ if(pystring::startswith(parts[0],"#")) continue;
+
+ if(!in3d)
+ {
+ if(parts[0] == "grid_size")
+ {
+ if(parts.size() != 4 ||
+ !StringToInt( &size3d[0], parts[1].c_str()) ||
+ !StringToInt( &size3d[1], parts[2].c_str()) ||
+ !StringToInt( &size3d[2], parts[3].c_str()))
+ {
+ throw Exception("Malformed grid_size tag in .vf lut.");
+ }
+
+ raw3d.reserve(3*size3d[0]*size3d[1]*size3d[2]);
+ }
+ else if(parts[0] == "global_transform")
+ {
+ if(parts.size() != 17)
+ {
+ throw Exception("Malformed global_transform tag. 16 floats expected.");
+ }
+
+ parts.erase(parts.begin()); // Drop the 1st entry. (the tag)
+ if(!StringVecToFloatVec(global_transform, parts) || global_transform.size() != 16)
+ {
+ throw Exception("Malformed global_transform tag. Could not convert to float array.");
+ }
+ }
+ // TODO: element_size (aka scale3)
+ // TODO: world_origin (aka translate3)
+ else if(parts[0] == "data")
+ {
+ in3d = true;
+ }
+ }
+ else // (in3d)
+ {
+ if(StringVecToFloatVec(tmpfloats, parts) && (tmpfloats.size() == 3))
+ {
+ raw3d.push_back(tmpfloats[0]);
+ raw3d.push_back(tmpfloats[1]);
+ raw3d.push_back(tmpfloats[2]);
+ }
+ }
+ }
+ }
+
+ // Interpret the parsed data, validate lut sizes
+ if(size3d[0]*size3d[1]*size3d[2] != static_cast<int>(raw3d.size()/3))
+ {
+ std::ostringstream os;
+ os << "Parse error in .vf lut. ";
+ os << "Incorrect number of lut3d entries. ";
+ os << "Found " << raw3d.size()/3 << ", expected " << size3d[0]*size3d[1]*size3d[2] << ".";
+ throw Exception(os.str().c_str());
+ }
+
+ if(size3d[0]*size3d[1]*size3d[2] == 0)
+ {
+ std::ostringstream os;
+ os << "Parse error in .vf lut. ";
+ os << "No 3D Lut entries found.";
+ throw Exception(os.str().c_str());
+ }
+
+ LocalCachedFileRcPtr cachedFile = LocalCachedFileRcPtr(new LocalCachedFile());
+
+ // Setup the global matrix.
+ // (Nuke pre-scales this by the 3dlut size, so we must undo that here)
+ if(global_transform.size() == 16)
+ {
+ for(int i=0; i<4; ++i)
+ {
+ global_transform[4*i+0] *= static_cast<float>(size3d[0]);
+ global_transform[4*i+1] *= static_cast<float>(size3d[1]);
+ global_transform[4*i+2] *= static_cast<float>(size3d[2]);
+ }
+
+ memcpy(cachedFile->m44, &global_transform[0], 16*sizeof(float));
+ cachedFile->useMatrix = true;
+ }
+
+ // Reformat 3D data
+ cachedFile->lut3D->size[0] = size3d[0];
+ cachedFile->lut3D->size[1] = size3d[1];
+ cachedFile->lut3D->size[2] = size3d[2];
+ cachedFile->lut3D->lut.reserve(raw3d.size());
+
+ for(int rIndex=0; rIndex<size3d[0]; ++rIndex)
+ {
+ for(int gIndex=0; gIndex<size3d[1]; ++gIndex)
+ {
+ for(int bIndex=0; bIndex<size3d[2]; ++bIndex)
+ {
+ int i = GetLut3DIndex_B(rIndex, gIndex, bIndex,
+ size3d[0], size3d[1], size3d[2]);
+
+ cachedFile->lut3D->lut.push_back(static_cast<float>(raw3d[i+0]));
+ cachedFile->lut3D->lut.push_back(static_cast<float>(raw3d[i+1]));
+ cachedFile->lut3D->lut.push_back(static_cast<float>(raw3d[i+2]));
+ }
+ }
+ }
+
+ return cachedFile;
+ }
+
+ void
+ LocalFileFormat::BuildFileOps(OpRcPtrVec & ops,
+ const Config& /*config*/,
+ const ConstContextRcPtr & /*context*/,
+ CachedFileRcPtr untypedCachedFile,
+ const FileTransform& fileTransform,
+ TransformDirection dir) const
+ {
+ LocalCachedFileRcPtr cachedFile = DynamicPtrCast<LocalCachedFile>(untypedCachedFile);
+
+ // This should never happen.
+ if(!cachedFile)
+ {
+ std::ostringstream os;
+ os << "Cannot build .vf Op. Invalid cache type.";
+ throw Exception(os.str().c_str());
+ }
+
+ TransformDirection newDir = CombineTransformDirections(dir,
+ fileTransform.getDirection());
+ if(newDir == TRANSFORM_DIR_UNKNOWN)
+ {
+ std::ostringstream os;
+ os << "Cannot build file format transform,";
+ os << " unspecified transform direction.";
+ throw Exception(os.str().c_str());
+ }
+
+ if(newDir == TRANSFORM_DIR_FORWARD)
+ {
+ if(cachedFile->useMatrix)
+ {
+ CreateMatrixOp(ops, cachedFile->m44, newDir);
+ }
+
+ CreateLut3DOp(ops, cachedFile->lut3D,
+ fileTransform.getInterpolation(), newDir);
+ }
+ else if(newDir == TRANSFORM_DIR_INVERSE)
+ {
+ CreateLut3DOp(ops, cachedFile->lut3D,
+ fileTransform.getInterpolation(), newDir);
+
+ if(cachedFile->useMatrix)
+ {
+ CreateMatrixOp(ops, cachedFile->m44, newDir);
+ }
+ }
+ }
+ }
+
+ FileFormat * CreateFileFormatVF()
+ {
+ return new LocalFileFormat();
+ }
+}
+OCIO_NAMESPACE_EXIT
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+// TODO: Unit test
diff --git a/src/core/FileTransform.cpp b/src/core/FileTransform.cpp
new file mode 100644
index 0000000..45b5a3e
--- /dev/null
+++ b/src/core/FileTransform.cpp
@@ -0,0 +1,579 @@
+/*
+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 "FileTransform.h"
+#include "Logging.h"
+#include "Mutex.h"
+#include "NoOps.h"
+#include "PathUtils.h"
+#include "pystring/pystring.h"
+
+#include <fstream>
+#include <map>
+#include <sstream>
+
+OCIO_NAMESPACE_ENTER
+{
+ FileTransformRcPtr FileTransform::Create()
+ {
+ return FileTransformRcPtr(new FileTransform(), &deleter);
+ }
+
+ void FileTransform::deleter(FileTransform* t)
+ {
+ delete t;
+ }
+
+
+ class FileTransform::Impl
+ {
+ public:
+ TransformDirection dir_;
+ std::string src_;
+ std::string cccid_;
+ Interpolation interp_;
+
+ Impl() :
+ dir_(TRANSFORM_DIR_FORWARD),
+ interp_(INTERP_UNKNOWN)
+ { }
+
+ ~Impl()
+ { }
+
+ Impl& operator= (const Impl & rhs)
+ {
+ dir_ = rhs.dir_;
+ src_ = rhs.src_;
+ cccid_ = rhs.cccid_;
+ interp_ = rhs.interp_;
+ return *this;
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ FileTransform::FileTransform()
+ : m_impl(new FileTransform::Impl)
+ {
+ }
+
+ TransformRcPtr FileTransform::createEditableCopy() const
+ {
+ FileTransformRcPtr transform = FileTransform::Create();
+ *(transform->m_impl) = *m_impl;
+ return transform;
+ }
+
+ FileTransform::~FileTransform()
+ {
+ delete m_impl;
+ m_impl = NULL;
+ }
+
+ FileTransform& FileTransform::operator= (const FileTransform & rhs)
+ {
+ *m_impl = *rhs.m_impl;
+ return *this;
+ }
+
+ TransformDirection FileTransform::getDirection() const
+ {
+ return getImpl()->dir_;
+ }
+
+ void FileTransform::setDirection(TransformDirection dir)
+ {
+ getImpl()->dir_ = dir;
+ }
+
+ const char * FileTransform::getSrc() const
+ {
+ return getImpl()->src_.c_str();
+ }
+
+ void FileTransform::setSrc(const char * src)
+ {
+ getImpl()->src_ = src;
+ }
+
+ const char * FileTransform::getCCCId() const
+ {
+ return getImpl()->cccid_.c_str();
+ }
+
+ void FileTransform::setCCCId(const char * cccid)
+ {
+ getImpl()->cccid_ = cccid;
+ }
+
+ Interpolation FileTransform::getInterpolation() const
+ {
+ return getImpl()->interp_;
+ }
+
+ void FileTransform::setInterpolation(Interpolation interp)
+ {
+ getImpl()->interp_ = interp;
+ }
+
+ int FileTransform::getNumFormats()
+ {
+ return FormatRegistry::GetInstance().getNumFormats(FORMAT_CAPABILITY_READ);
+ }
+
+ const char * FileTransform::getFormatNameByIndex(int index)
+ {
+ return FormatRegistry::GetInstance().getFormatNameByIndex(FORMAT_CAPABILITY_READ, index);
+ }
+
+ const char * FileTransform::getFormatExtensionByIndex(int index)
+ {
+ return FormatRegistry::GetInstance().getFormatExtensionByIndex(FORMAT_CAPABILITY_READ, index);
+ }
+
+ std::ostream& operator<< (std::ostream& os, const FileTransform& t)
+ {
+ os << "<FileTransform ";
+ os << "direction=" << TransformDirectionToString(t.getDirection()) << ", ";
+ os << "interpolation=" << InterpolationToString(t.getInterpolation()) << ", ";
+ os << "src='" << t.getSrc() << "', ";
+ os << "cccid='" << t.getCCCId() << "'";
+ os << ">";
+
+ return os;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ // NOTE: You must be mindful when editing this function.
+ // to be resiliant to the static initialization order 'fiasco'
+ //
+ // See
+ // http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14
+ // http://stackoverflow.com/questions/335369/finding-c-static-initialization-order-problems
+ // for more info.
+
+ namespace
+ {
+ FormatRegistry* g_formatRegistry = NULL;
+ Mutex g_formatRegistryLock;
+ }
+
+ FormatRegistry & FormatRegistry::GetInstance()
+ {
+ AutoMutex lock(g_formatRegistryLock);
+
+ if(!g_formatRegistry)
+ {
+ g_formatRegistry = new FormatRegistry();
+ }
+
+ return *g_formatRegistry;
+ }
+
+ FormatRegistry::FormatRegistry()
+ {
+ registerFileFormat(CreateFileFormat3DL());
+ registerFileFormat(CreateFileFormatCCC());
+ registerFileFormat(CreateFileFormatCC());
+ registerFileFormat(CreateFileFormatCSP());
+ registerFileFormat(CreateFileFormatHDL());
+ registerFileFormat(CreateFileFormatIridasItx());
+ registerFileFormat(CreateFileFormatIridasCube());
+ registerFileFormat(CreateFileFormatIridasLook());
+ registerFileFormat(CreateFileFormatPandora());
+ registerFileFormat(CreateFileFormatSpi1D());
+ registerFileFormat(CreateFileFormatSpi3D());
+ registerFileFormat(CreateFileFormatSpiMtx());
+ registerFileFormat(CreateFileFormatTruelight());
+ registerFileFormat(CreateFileFormatVF());
+ }
+
+ FormatRegistry::~FormatRegistry()
+ {
+ }
+
+ FileFormat* FormatRegistry::getFileFormatByName(const std::string & name) const
+ {
+ FileFormatMap::const_iterator iter = m_formatsByName.find(
+ pystring::lower(name));
+ if(iter != m_formatsByName.end())
+ return iter->second;
+ return NULL;
+ }
+
+ FileFormat* FormatRegistry::getFileFormatForExtension(const std::string & extension) const
+ {
+ FileFormatMap::const_iterator iter = m_formatsByExtension.find(
+ pystring::lower(extension));
+ if(iter != m_formatsByExtension.end())
+ return iter->second;
+ return NULL;
+ }
+
+ void FormatRegistry::registerFileFormat(FileFormat* format)
+ {
+ FormatInfoVec formatInfoVec;
+ format->GetFormatInfo(formatInfoVec);
+
+ if(formatInfoVec.empty())
+ {
+ std::ostringstream os;
+ os << "FileFormat Registry error. ";
+ os << "A file format did not provide the required format info.";
+ throw Exception(os.str().c_str());
+ }
+
+ for(unsigned int i=0; i<formatInfoVec.size(); ++i)
+ {
+ if(formatInfoVec[i].capabilities == FORMAT_CAPABILITY_NONE)
+ {
+ std::ostringstream os;
+ os << "FileFormat Registry error. ";
+ os << "A file format does not define either reading or writing.";
+ throw Exception(os.str().c_str());
+ }
+
+ if(getFileFormatByName(formatInfoVec[i].name))
+ {
+ std::ostringstream os;
+ os << "Cannot register multiple file formats named, '";
+ os << formatInfoVec[i].name << "'.";
+ throw Exception(os.str().c_str());
+ }
+
+ m_formatsByName[formatInfoVec[i].name] = format;
+
+ // For now, dont worry if multiple formats register the same extension
+ // TODO: keep track of all of em! (make the value a vector)
+ m_formatsByExtension[formatInfoVec[i].extension] = format;
+
+ if(formatInfoVec[i].capabilities & FORMAT_CAPABILITY_READ)
+ {
+ m_readFormatNames.push_back(formatInfoVec[i].name);
+ m_readFormatExtensions.push_back(formatInfoVec[i].extension);
+ }
+
+ if(formatInfoVec[i].capabilities & FORMAT_CAPABILITY_WRITE)
+ {
+ m_writeFormatNames.push_back(formatInfoVec[i].name);
+ m_writeFormatExtensions.push_back(formatInfoVec[i].extension);
+ }
+ }
+
+ m_rawFormats.push_back(format);
+ }
+
+ int FormatRegistry::getNumRawFormats() const
+ {
+ return static_cast<int>(m_rawFormats.size());
+ }
+
+ FileFormat* FormatRegistry::getRawFormatByIndex(int index) const
+ {
+ if(index<0 || index>=getNumRawFormats())
+ {
+ return NULL;
+ }
+
+ return m_rawFormats[index];
+ }
+
+ int FormatRegistry::getNumFormats(int capability) const
+ {
+ if(capability == FORMAT_CAPABILITY_READ)
+ {
+ return static_cast<int>(m_readFormatNames.size());
+ }
+ else if(capability == FORMAT_CAPABILITY_WRITE)
+ {
+ return static_cast<int>(m_writeFormatNames.size());
+ }
+ return 0;
+ }
+
+ const char * FormatRegistry::getFormatNameByIndex(int capability, int index) const
+ {
+ if(capability == FORMAT_CAPABILITY_READ)
+ {
+ if(index<0 || index>=static_cast<int>(m_readFormatNames.size()))
+ {
+ return "";
+ }
+ return m_readFormatNames[index].c_str();
+ }
+ else if(capability == FORMAT_CAPABILITY_WRITE)
+ {
+ if(index<0 || index>=static_cast<int>(m_readFormatNames.size()))
+ {
+ return "";
+ }
+ return m_writeFormatNames[index].c_str();
+ }
+ return "";
+ }
+
+ const char * FormatRegistry::getFormatExtensionByIndex(int capability, int index) const
+ {
+ if(capability == FORMAT_CAPABILITY_READ)
+ {
+ if(index<0 || index>=static_cast<int>(m_readFormatExtensions.size()))
+ {
+ return "";
+ }
+ return m_readFormatExtensions[index].c_str();
+ }
+ else if(capability == FORMAT_CAPABILITY_WRITE)
+ {
+ if(index<0 || index>=static_cast<int>(m_writeFormatExtensions.size()))
+ {
+ return "";
+ }
+ return m_writeFormatExtensions[index].c_str();
+ }
+ return "";
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ FileFormat::~FileFormat()
+ {
+
+ }
+
+ std::string FileFormat::getName() const
+ {
+ FormatInfoVec infoVec;
+ GetFormatInfo(infoVec);
+ if(infoVec.size()>0)
+ {
+ return infoVec[0].name;
+ }
+ return "Unknown Format";
+ }
+
+
+
+ void FileFormat::Write(const Baker & /*baker*/,
+ const std::string & formatName,
+ std::ostream & /*ostream*/) const
+ {
+ std::ostringstream os;
+ os << "Format " << formatName << " does not support writing.";
+ throw Exception(os.str().c_str());
+ }
+
+ namespace
+ {
+ typedef std::pair<FileFormat*, CachedFileRcPtr> FileCachePair;
+ typedef std::map<std::string, FileCachePair> FileCacheMap;
+
+ FileCacheMap g_fileCache;
+ Mutex g_fileCacheLock;
+
+ // Get the FileFormat, CachedFilePtr
+ // or throw an exception.
+
+ FileCachePair GetFile(const std::string & filepath)
+ {
+ // Acquire fileCache mutex
+ AutoMutex lock(g_fileCacheLock);
+
+ FileCacheMap::iterator iter = g_fileCache.find(filepath);
+ if(iter != g_fileCache.end())
+ {
+ return iter->second;
+ }
+
+ // We did not find the file in the cache; let's read it.
+ {
+ std::ostringstream os;
+ os << "Opening " << filepath;
+ LogDebug(os.str());
+ }
+
+ // Open the filePath
+ std::ifstream filestream;
+ filestream.open(filepath.c_str(), std::ios_base::in);
+ if (!filestream.good())
+ {
+ std::ostringstream os;
+ os << "The specified FileTransform srcfile, '";
+ os << filepath <<"', could not be opened. ";
+ os << "Please confirm the file exists with appropriate read";
+ os << " permissions.";
+ throw Exception(os.str().c_str());
+ }
+
+
+ // Try the initial format.
+ std::string primaryErrorText;
+ std::string root, extension;
+ pystring::os::path::splitext(root, extension, filepath);
+ extension = pystring::replace(extension,".","",1); // remove the leading '.'
+
+ FileFormat * primaryFormat = FormatRegistry::GetInstance().getFileFormatForExtension(extension);
+
+ if(primaryFormat)
+ {
+ try
+ {
+ CachedFileRcPtr cachedFile = primaryFormat->Read(filestream);
+
+ // Add the result to our cache, return it.
+ FileCachePair pair = std::make_pair(primaryFormat, cachedFile);
+ g_fileCache[filepath] = pair;
+
+ if(IsDebugLoggingEnabled())
+ {
+ std::ostringstream os;
+ os << " Loaded primary format ";
+ os << primaryFormat->getName();
+ LogDebug(os.str());
+ }
+
+ return pair;
+ }
+ catch(std::exception & e)
+ {
+ primaryErrorText = e.what();
+ filestream.clear();
+ filestream.seekg( std::ifstream::beg );
+
+ if(IsDebugLoggingEnabled())
+ {
+ std::ostringstream os;
+ os << " Failed primary format ";
+ os << primaryFormat->getName();
+ os << ": " << e.what();
+ LogDebug(os.str());
+ }
+ }
+ }
+
+ // If this fails, try all other formats
+ FormatRegistry & formats = FormatRegistry::GetInstance();
+ for(int findex = 0; findex<formats.getNumRawFormats(); ++findex)
+ {
+ FileFormat * altFormat = formats.getRawFormatByIndex(findex);
+
+ // Dont bother trying the primaryFormat twice.
+ if(altFormat == primaryFormat) continue;
+
+ try
+ {
+ CachedFileRcPtr cachedFile = altFormat->Read(filestream);
+
+ // Add the result to our cache, return it.
+ FileCachePair pair = std::make_pair(altFormat, cachedFile);
+ g_fileCache[filepath] = pair;
+
+ if(IsDebugLoggingEnabled())
+ {
+ std::ostringstream os;
+ os << " Loaded alt format ";
+ os << altFormat->getName();
+ LogDebug(os.str());
+ }
+
+ return pair;
+ }
+ catch(std::exception & e)
+ {
+ filestream.clear();
+ filestream.seekg( std::ifstream::beg );
+
+ if(IsDebugLoggingEnabled())
+ {
+ std::ostringstream os;
+ os << " Failed alt format ";
+ os << altFormat->getName();
+ os << ": " << e.what();
+ LogDebug(os.str());
+ }
+ }
+ }
+
+ // No formats succeeded. Error out with a sensible message.
+ if(primaryFormat)
+ {
+ std::ostringstream os;
+ os << "The specified transform file '";
+ os << filepath <<"' could not be loaded. ";
+ os << primaryErrorText;
+
+ throw Exception(os.str().c_str());
+ }
+ else
+ {
+ std::ostringstream os;
+ os << "The specified transform file '";
+ os << filepath <<"' does not appear to be a valid, known LUT file format.";
+ throw Exception(os.str().c_str());
+ }
+ }
+ }
+
+ void ClearFileTransformCaches()
+ {
+ AutoMutex lock(g_fileCacheLock);
+ g_fileCache.clear();
+ }
+
+ void BuildFileOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ const FileTransform& fileTransform,
+ TransformDirection dir)
+ {
+ std::string src = fileTransform.getSrc();
+ if(src.empty())
+ {
+ std::ostringstream os;
+ os << "The transform file has not been specified.";
+ throw Exception(os.str().c_str());
+ }
+
+ std::string filepath = context->resolveFileLocation(src.c_str());
+ CreateFileNoOp(ops, filepath);
+
+ FileCachePair cachePair = GetFile(filepath);
+ FileFormat* format = cachePair.first;
+ CachedFileRcPtr cachedFile = cachePair.second;
+
+ format->BuildFileOps(ops,
+ config, context,
+ cachedFile, fileTransform,
+ dir);
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/FileTransform.h b/src/core/FileTransform.h
new file mode 100644
index 0000000..3c8f070
--- /dev/null
+++ b/src/core/FileTransform.h
@@ -0,0 +1,156 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_FILETRANSFORM_H
+#define INCLUDED_OCIO_FILETRANSFORM_H
+
+#include <map>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "Op.h"
+#include "Processor.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ void ClearFileTransformCaches();
+
+ class CachedFile
+ {
+ public:
+ CachedFile() {};
+ virtual ~CachedFile() {};
+ };
+
+ typedef OCIO_SHARED_PTR<CachedFile> CachedFileRcPtr;
+
+ const int FORMAT_CAPABILITY_NONE = 0;
+ const int FORMAT_CAPABILITY_READ = 1;
+ const int FORMAT_CAPABILITY_WRITE = 2;
+ const int FORMAT_CAPABILITY_ALL = (FORMAT_CAPABILITY_READ | FORMAT_CAPABILITY_WRITE);
+
+ struct FormatInfo
+ {
+ std::string name; // name must be globally unique
+ std::string extension; // extension does not need to be unique
+ int capabilities;
+
+ FormatInfo():
+ capabilities(FORMAT_CAPABILITY_NONE)
+ { }
+ };
+
+ typedef std::vector<FormatInfo> FormatInfoVec;
+
+ class FileFormat
+ {
+ public:
+ virtual ~FileFormat();
+
+ virtual void GetFormatInfo(FormatInfoVec & formatInfoVec) const = 0;
+
+ virtual CachedFileRcPtr Read(std::istream & istream) const = 0;
+
+ virtual void Write(const Baker & baker,
+ const std::string & formatName,
+ std::ostream & ostream) const;
+
+ virtual void BuildFileOps(OpRcPtrVec & ops,
+ const Config & config,
+ const ConstContextRcPtr & context,
+ CachedFileRcPtr cachedFile,
+ const FileTransform & fileTransform,
+ TransformDirection dir) const = 0;
+
+ // For logging purposes
+ std::string getName() const;
+ private:
+ FileFormat& operator= (const FileFormat &);
+ };
+
+ typedef std::map<std::string, FileFormat*> FileFormatMap;
+ typedef std::vector<FileFormat*> FileFormatVector;
+
+ // TODO: This interface is ugly. What private API is actually appropriate?
+ // Maybe, instead of exposing the raw formats, we wrap it?
+ // FileCachePair GetFile(const std::string & filepath) and all
+ // lookups will move internal
+
+ class FormatRegistry
+ {
+ public:
+ static FormatRegistry & GetInstance();
+
+ // TODO: Make these return a vector of possible formats
+ FileFormat* getFileFormatByName(const std::string & name) const;
+ FileFormat* getFileFormatForExtension(const std::string & extension) const;
+
+ int getNumRawFormats() const;
+ FileFormat* getRawFormatByIndex(int index) const;
+
+ int getNumFormats(int capability) const;
+ const char * getFormatNameByIndex(int capability, int index) const;
+ const char * getFormatExtensionByIndex(int capability, int index) const;
+ private:
+ FormatRegistry();
+ ~FormatRegistry();
+
+ void registerFileFormat(FileFormat* format);
+
+ FileFormatMap m_formatsByName;
+ FileFormatMap m_formatsByExtension;
+ FileFormatVector m_rawFormats;
+
+ typedef std::vector<std::string> StringVec;
+ StringVec m_readFormatNames;
+ StringVec m_readFormatExtensions;
+ StringVec m_writeFormatNames;
+ StringVec m_writeFormatExtensions;
+ };
+
+ // Registry Builders
+ FileFormat * CreateFileFormat3DL();
+ FileFormat * CreateFileFormatCCC();
+ FileFormat * CreateFileFormatCC();
+ FileFormat * CreateFileFormatCSP();
+ FileFormat * CreateFileFormatHDL();
+ FileFormat * CreateFileFormatIridasItx();
+ FileFormat * CreateFileFormatIridasCube();
+ FileFormat * CreateFileFormatIridasLook();
+ FileFormat * CreateFileFormatPandora();
+ FileFormat * CreateFileFormatSpi1D();
+ FileFormat * CreateFileFormatSpi3D();
+ FileFormat * CreateFileFormatSpiMtx();
+ FileFormat * CreateFileFormatTruelight();
+ FileFormat * CreateFileFormatVF();
+
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/GpuShaderDesc.cpp b/src/core/GpuShaderDesc.cpp
new file mode 100644
index 0000000..3b20845
--- /dev/null
+++ b/src/core/GpuShaderDesc.cpp
@@ -0,0 +1,131 @@
+/*
+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 <sstream>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "Mutex.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ class GpuShaderDesc::Impl
+ {
+ public:
+ GpuLanguage language_;
+ std::string functionName_;
+ int lut3DEdgeLen_;
+
+ mutable std::string cacheID_;
+ mutable Mutex cacheIDMutex_;
+
+ Impl() :
+ language_(GPU_LANGUAGE_UNKNOWN),
+ lut3DEdgeLen_(0)
+ {
+ }
+
+ ~Impl()
+ { }
+
+ Impl& operator= (const Impl & rhs)
+ {
+ language_ = rhs.language_;
+ functionName_ = rhs.functionName_;
+ lut3DEdgeLen_ = rhs.lut3DEdgeLen_;
+ cacheID_ = rhs.cacheID_;
+ return *this;
+ }
+ };
+
+
+ GpuShaderDesc::GpuShaderDesc()
+ : m_impl(new GpuShaderDesc::Impl)
+ {
+ }
+
+ GpuShaderDesc::~GpuShaderDesc()
+ {
+ delete m_impl;
+ m_impl = NULL;
+ }
+
+
+ void GpuShaderDesc::setLanguage(GpuLanguage lang)
+ {
+ AutoMutex lock(getImpl()->cacheIDMutex_);
+ getImpl()->language_ = lang;
+ getImpl()->cacheID_ = "";
+ }
+
+ GpuLanguage GpuShaderDesc::getLanguage() const
+ {
+ return getImpl()->language_;
+ }
+
+ void GpuShaderDesc::setFunctionName(const char * name)
+ {
+ AutoMutex lock(getImpl()->cacheIDMutex_);
+ getImpl()->functionName_ = name;
+ getImpl()->cacheID_ = "";
+ }
+
+ const char * GpuShaderDesc::getFunctionName() const
+ {
+ return getImpl()->functionName_.c_str();
+ }
+
+ void GpuShaderDesc::setLut3DEdgeLen(int len)
+ {
+ AutoMutex lock(getImpl()->cacheIDMutex_);
+ getImpl()->lut3DEdgeLen_ = len;
+ getImpl()->cacheID_ = "";
+ }
+
+ int GpuShaderDesc::getLut3DEdgeLen() const
+ {
+ return getImpl()->lut3DEdgeLen_;
+ }
+
+ const char * GpuShaderDesc::getCacheID() const
+ {
+ AutoMutex lock(getImpl()->cacheIDMutex_);
+
+ if(getImpl()->cacheID_.empty())
+ {
+ std::ostringstream os;
+ os << GpuLanguageToString(getImpl()->language_) << " ";
+ os << getImpl()->functionName_ << " ";
+ os << getImpl()->lut3DEdgeLen_;
+ getImpl()->cacheID_ = os.str();
+ }
+
+ return getImpl()->cacheID_.c_str();
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/GpuShaderUtils.cpp b/src/core/GpuShaderUtils.cpp
new file mode 100644
index 0000000..cb8d67b
--- /dev/null
+++ b/src/core/GpuShaderUtils.cpp
@@ -0,0 +1,193 @@
+/*
+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 "GpuShaderUtils.h"
+#include "MathUtils.h"
+
+#include <cmath>
+#include <sstream>
+
+OCIO_NAMESPACE_ENTER
+{
+ void Write_half4x4(std::ostream & os, const float * m44, GpuLanguage lang)
+ {
+ if(lang == GPU_LANGUAGE_CG)
+ {
+ os << "half4x4(";
+ for(int i=0; i<16; i++)
+ {
+ if(i!=0) os << ", ";
+ os << ClampToNormHalf(m44[i]);
+ }
+ os << ")";
+ }
+ else if(lang == GPU_LANGUAGE_GLSL_1_0 || lang == GPU_LANGUAGE_GLSL_1_3)
+ {
+ os << "mat4(";
+ for(int i=0; i<16; i++)
+ {
+ if(i!=0) os << ", ";
+ os << m44[i]; // Clamping to half is not necessary
+ }
+ os << ")";
+ }
+ else
+ {
+ throw Exception("Unsupported shader language.");
+ }
+ }
+
+ void Write_half4(std::ostream & os, const float * v4, GpuLanguage lang)
+ {
+ if(lang == GPU_LANGUAGE_CG)
+ {
+ os << "half4(";
+ for(int i=0; i<4; i++)
+ {
+ if(i!=0) os << ", ";
+ os << ClampToNormHalf(v4[i]);
+ }
+ os << ")";
+ }
+ else if(lang == GPU_LANGUAGE_GLSL_1_0 || lang == GPU_LANGUAGE_GLSL_1_3)
+ {
+ os << "vec4(";
+ for(int i=0; i<4; i++)
+ {
+ if(i!=0) os << ", ";
+ os << v4[i]; // Clamping to half is not necessary
+ }
+ os << ")";
+ }
+ else
+ {
+ throw Exception("Unsupported shader language.");
+ }
+ }
+
+ void Write_half3(std::ostream & os, const float * v3, GpuLanguage lang)
+ {
+ if(lang == GPU_LANGUAGE_CG)
+ {
+ os << "half3(";
+ for(int i=0; i<3; i++)
+ {
+ if(i!=0) os << ", ";
+ os << ClampToNormHalf(v3[i]);
+ }
+ os << ")";
+ }
+ else if(lang == GPU_LANGUAGE_GLSL_1_0 || lang == GPU_LANGUAGE_GLSL_1_3)
+ {
+ os << "vec3(";
+ for(int i=0; i<3; i++)
+ {
+ if(i!=0) os << ", ";
+ os << v3[i]; // Clamping to half is not necessary
+ }
+ os << ")";
+ }
+ else
+ {
+ throw Exception("Unsupported shader language.");
+ }
+ }
+
+
+
+
+ std::string GpuTextHalf4x4(const float * m44, GpuLanguage lang)
+ {
+ std::ostringstream os;
+ Write_half4x4(os, m44, lang);
+ return os.str();
+ }
+
+ std::string GpuTextHalf4(const float * v4, GpuLanguage lang)
+ {
+ std::ostringstream os;
+ Write_half4(os, v4, lang);
+ return os.str();
+ }
+
+ std::string GpuTextHalf3(const float * v3, GpuLanguage lang)
+ {
+ std::ostringstream os;
+ Write_half3(os, v3, lang);
+ return os.str();
+ }
+
+ // Note that Cg and GLSL have opposite ordering for vec/mtx multiplication
+ void Write_mtx_x_vec(std::ostream & os,
+ const std::string & mtx, const std::string & vec,
+ GpuLanguage lang)
+ {
+ if(lang == GPU_LANGUAGE_CG)
+ {
+ os << "mul( " << mtx << ", " << vec << ")";
+ }
+ else if(lang == GPU_LANGUAGE_GLSL_1_0 || lang == GPU_LANGUAGE_GLSL_1_3)
+ {
+ os << vec << " * " << mtx;
+ }
+ else
+ {
+ throw Exception("Unsupported shader language.");
+ }
+ }
+
+
+ void Write_sampleLut3D_rgb(std::ostream & os, const std::string& variableName,
+ const std::string& lutName, int lut3DEdgeLen,
+ GpuLanguage lang)
+ {
+ float m = ((float) lut3DEdgeLen-1.0f) / (float) lut3DEdgeLen;
+ float b = 1.0f / (2.0f * (float) lut3DEdgeLen);
+
+ if(lang == GPU_LANGUAGE_CG)
+ {
+ os << "tex3D(";
+ os << lutName << ", ";
+ os << m << " * " << variableName << ".rgb + " << b << ").rgb;" << std::endl;
+ }
+ else if(lang == GPU_LANGUAGE_GLSL_1_0 || lang == GPU_LANGUAGE_GLSL_1_3)
+ {
+ os << "texture3D(";
+ os << lutName << ", ";
+ os << m << " * " << variableName << ".rgb + " << b << ").rgb;" << std::endl;
+ }
+ else
+ {
+ throw Exception("Unsupported shader language.");
+ }
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/GpuShaderUtils.h b/src/core/GpuShaderUtils.h
new file mode 100644
index 0000000..43d16a4
--- /dev/null
+++ b/src/core/GpuShaderUtils.h
@@ -0,0 +1,58 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_GPUSHADERUTILS_H
+#define INCLUDED_OCIO_GPUSHADERUTILS_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include <sstream>
+
+OCIO_NAMESPACE_ENTER
+{
+ std::string GpuTextHalf4x4(const float * m44, GpuLanguage lang);
+ std::string GpuTextHalf4(const float * v4, GpuLanguage lang);
+ std::string GpuTextHalf3(const float * v3, GpuLanguage lang);
+
+ void Write_mtx_x_vec(std::ostream & os,
+ const std::string & mtx, const std::string & vec,
+ GpuLanguage lang);
+
+ void Write_half4x4(std::ostream & os, const float * m44, GpuLanguage lang);
+ void Write_half4(std::ostream & os, const float * v4, GpuLanguage lang);
+ void Write_half3(std::ostream & os, const float * v3, GpuLanguage lang);
+
+ // returns vec3
+ void Write_sampleLut3D_rgb(std::ostream & os, const std::string & variableName,
+ const std::string & lutName, int lut3DEdgeLen,
+ GpuLanguage lang);
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/GroupTransform.cpp b/src/core/GroupTransform.cpp
new file mode 100644
index 0000000..344714a
--- /dev/null
+++ b/src/core/GroupTransform.cpp
@@ -0,0 +1,196 @@
+/*
+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 "OpBuilders.h"
+
+#include <sstream>
+
+OCIO_NAMESPACE_ENTER
+{
+ GroupTransformRcPtr GroupTransform::Create()
+ {
+ return GroupTransformRcPtr(new GroupTransform(), &deleter);
+ }
+
+ void GroupTransform::deleter(GroupTransform* t)
+ {
+ delete t;
+ }
+
+ namespace
+ {
+ typedef std::vector<TransformRcPtr> TransformRcPtrVec;
+ }
+
+ class GroupTransform::Impl
+ {
+ public:
+ TransformDirection dir_;
+ TransformRcPtrVec vec_;
+
+ Impl() :
+ dir_(TRANSFORM_DIR_FORWARD)
+ { }
+
+ ~Impl()
+ {
+ vec_.clear();
+ }
+
+ Impl& operator= (const Impl & rhs)
+ {
+ dir_ = rhs.dir_;
+
+ vec_.clear();
+
+ for(unsigned int i=0; i<rhs.vec_.size(); ++i)
+ {
+ vec_.push_back(rhs.vec_[i]->createEditableCopy());
+ }
+
+ return *this;
+ }
+ };
+
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+
+ GroupTransform::GroupTransform()
+ : m_impl(new GroupTransform::Impl)
+ {
+ }
+
+ TransformRcPtr GroupTransform::createEditableCopy() const
+ {
+ GroupTransformRcPtr transform = GroupTransform::Create();
+ *(transform->m_impl) = *m_impl;
+ return transform;
+ }
+
+ GroupTransform::~GroupTransform()
+ {
+ delete m_impl;
+ m_impl = NULL;
+ }
+
+ GroupTransform& GroupTransform::operator= (const GroupTransform & rhs)
+ {
+ *m_impl = *rhs.m_impl;
+ return *this;
+ }
+
+ TransformDirection GroupTransform::getDirection() const
+ {
+ return getImpl()->dir_;
+ }
+
+ void GroupTransform::setDirection(TransformDirection dir)
+ {
+ getImpl()->dir_ = dir;
+ }
+
+ int GroupTransform::size() const
+ {
+ return static_cast<int>(getImpl()->vec_.size());
+ }
+
+ ConstTransformRcPtr GroupTransform::getTransform(int index) const
+ {
+ if(index < 0 || index >= (int)getImpl()->vec_.size())
+ {
+ std::ostringstream os;
+ os << "Invalid transform index " << index << ".";
+ throw Exception(os.str().c_str());
+ }
+
+ return getImpl()->vec_[index];
+ }
+
+ void GroupTransform::push_back(const ConstTransformRcPtr& transform)
+ {
+ getImpl()->vec_.push_back(transform->createEditableCopy());
+ }
+
+ void GroupTransform::clear()
+ {
+ getImpl()->vec_.clear();
+ }
+
+ bool GroupTransform::empty() const
+ {
+ return getImpl()->vec_.empty();
+ }
+
+ std::ostream& operator<< (std::ostream& os, const GroupTransform& groupTransform)
+ {
+ for(int i=0; i<groupTransform.size(); ++i)
+ {
+ if(i!=groupTransform.size()-1) os << "\n";
+ ConstTransformRcPtr transform = groupTransform.getTransform(i);
+ os << "\t" << *transform;
+ }
+ return os;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ void BuildGroupOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ const GroupTransform& groupTransform,
+ TransformDirection dir)
+ {
+ TransformDirection combinedDir = CombineTransformDirections(dir,
+ groupTransform.getDirection());
+
+ if(combinedDir == TRANSFORM_DIR_FORWARD)
+ {
+ for(int i=0; i<groupTransform.size(); ++i)
+ {
+ ConstTransformRcPtr childTransform = groupTransform.getTransform(i);
+ BuildOps(ops, config, context, childTransform, TRANSFORM_DIR_FORWARD);
+ }
+ }
+ else if(combinedDir == TRANSFORM_DIR_INVERSE)
+ {
+ for(int i=groupTransform.size()-1; i>=0; --i)
+ {
+ ConstTransformRcPtr childTransform = groupTransform.getTransform(i);
+ BuildOps(ops, config, context, childTransform, TRANSFORM_DIR_INVERSE);
+ }
+ }
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/HashUtils.cpp b/src/core/HashUtils.cpp
new file mode 100644
index 0000000..5b9acd1
--- /dev/null
+++ b/src/core/HashUtils.cpp
@@ -0,0 +1,71 @@
+/*
+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 "HashUtils.h"
+#include "md5/md5.h"
+
+#include <sstream>
+#include <iostream>
+
+OCIO_NAMESPACE_ENTER
+{
+ std::string CacheIDHash(const char * array, int size)
+ {
+ md5_state_t state;
+ md5_byte_t digest[16];
+
+ md5_init(&state);
+ md5_append(&state, (const md5_byte_t *)array, size);
+ md5_finish(&state, digest);
+
+ return GetPrintableHash(digest);
+ }
+
+ std::string GetPrintableHash(const md5_byte_t * digest)
+ {
+ static char charmap[] = "0123456789abcdef";
+
+ char printableResult[34];
+ char *ptr = printableResult;
+
+ // build a printable string from unprintable chars. first character
+ // of hashed cache IDs is '$', to later check if it's already been hashed
+ *ptr++ = '$';
+ for (int i=0;i<16;++i)
+ {
+ *ptr++ = charmap[(digest[i] & 0x0F)];
+ *ptr++ = charmap[(digest[i] >> 4)];
+ }
+ *ptr++ = 0;
+
+ return std::string(printableResult);
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/HashUtils.h b/src/core/HashUtils.h
new file mode 100644
index 0000000..58481db
--- /dev/null
+++ b/src/core/HashUtils.h
@@ -0,0 +1,48 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_HASHUTILS_H
+#define INCLUDED_OCIO_HASHUTILS_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "md5/md5.h"
+#include <string>
+
+OCIO_NAMESPACE_ENTER
+{
+ std::string CacheIDHash(const char * array, int size);
+
+ // TODO: get rid of md5.h include, make this a generic byte array
+ std::string GetPrintableHash(const md5_byte_t * digest);
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
+
diff --git a/src/core/ImageDesc.cpp b/src/core/ImageDesc.cpp
new file mode 100644
index 0000000..63156c8
--- /dev/null
+++ b/src/core/ImageDesc.cpp
@@ -0,0 +1,392 @@
+/*
+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 <cstdlib>
+#include <sstream>
+
+#include "ImagePacking.h"
+
+OCIO_NAMESPACE_ENTER
+{
+
+ std::ostream& operator<< (std::ostream& os, const ImageDesc& img)
+ {
+ if(const PackedImageDesc * packedImg = dynamic_cast<const PackedImageDesc*>(&img))
+ {
+ os << "<PackedImageDesc ";
+ os << "data=" << packedImg->getData() << ", ";
+ os << "width=" << packedImg->getWidth() << ", ";
+ os << "height=" << packedImg->getHeight() << ", ";
+ os << "numChannels=" << packedImg->getNumChannels() << ", ";
+ os << "chanStrideBytes=" << packedImg->getChanStrideBytes() << ", ";
+ os << "xStrideBytes=" << packedImg->getXStrideBytes() << ", ";
+ os << "yStrideBytes=" << packedImg->getYStrideBytes() << "";
+ os << ">";
+ }
+ else if(const PlanarImageDesc * planarImg = dynamic_cast<const PlanarImageDesc*>(&img))
+ {
+ os << "<PlanarImageDesc ";
+ os << "rData=" << planarImg->getRData() << ", ";
+ os << "gData=" << planarImg->getGData() << ", ";
+ os << "bData=" << planarImg->getBData() << ", ";
+ os << "aData=" << planarImg->getAData() << ", ";
+ os << "width=" << packedImg->getWidth() << ", ";
+ os << "height=" << packedImg->getHeight() << ", ";
+ os << "yStrideBytes=" << planarImg->getYStrideBytes() << "";
+ os << ">";
+ }
+ else
+ {
+ os << "<UnknownImageDesc>";
+ }
+
+ return os;
+ }
+
+ ImageDesc::~ImageDesc()
+ {
+
+ }
+
+
+
+ GenericImageDesc::GenericImageDesc():
+ width(0),
+ height(0),
+ xStrideBytes(0),
+ yStrideBytes(0),
+ rData(NULL),
+ gData(NULL),
+ bData(NULL),
+ aData(NULL)
+ { };
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ GenericImageDesc::~GenericImageDesc()
+ { };
+
+ void GenericImageDesc::init(const ImageDesc& img)
+ {
+ if(const PackedImageDesc * packedImg = dynamic_cast<const PackedImageDesc*>(&img))
+ {
+ width = packedImg->getWidth();
+ height = packedImg->getHeight();
+ long numChannels = packedImg->getNumChannels();
+
+ ptrdiff_t chanStrideBytes = packedImg->getChanStrideBytes();
+ xStrideBytes = packedImg->getXStrideBytes();
+ yStrideBytes = packedImg->getYStrideBytes();
+
+ // AutoStrides will already be resolved by here, in the constructor of the ImageDesc
+ if(chanStrideBytes == AutoStride ||
+ xStrideBytes == AutoStride ||
+ yStrideBytes == AutoStride)
+ {
+ throw Exception("Malformed PackedImageDesc: Unresolved AutoStride.");
+ }
+
+ rData = packedImg->getData();
+ gData = reinterpret_cast<float*>( reinterpret_cast<char*>(rData)
+ + chanStrideBytes );
+ bData = reinterpret_cast<float*>( reinterpret_cast<char*>(rData)
+ + 2*chanStrideBytes );
+ if(numChannels >= 4)
+ {
+ aData = reinterpret_cast<float*>( reinterpret_cast<char*>(rData)
+ + 3*chanStrideBytes );
+ }
+
+ if(rData == NULL)
+ {
+ std::ostringstream os;
+ os << "PackedImageDesc Error: A null image ptr was specified.";
+ throw Exception(os.str().c_str());
+ }
+
+ if(width <= 0 || height <= 0)
+ {
+ std::ostringstream os;
+ os << "PackedImageDesc Error: Image dimensions must be positive for both x,y. '";
+ os << width << "x" << height << "' is not allowed.";
+ throw Exception(os.str().c_str());
+ }
+
+ if(numChannels < 3)
+ {
+ std::ostringstream os;
+ os << "PackedImageDesc Error: Image numChannels must be three (or more) (rgb+). '";
+ os << numChannels << "' is not allowed.";
+ throw Exception(os.str().c_str());
+ }
+ }
+ else if(const PlanarImageDesc * planarImg = dynamic_cast<const PlanarImageDesc*>(&img))
+ {
+ width = planarImg->getWidth();
+ height = planarImg->getHeight();
+ xStrideBytes = sizeof(float);
+ yStrideBytes = planarImg->getYStrideBytes();
+
+ // AutoStrides will already be resolved by here, in the constructor of the ImageDesc
+ if(yStrideBytes == AutoStride)
+ {
+ throw Exception("Malformed PlanarImageDesc: Unresolved AutoStride.");
+ }
+
+ rData = planarImg->getRData();
+ gData = planarImg->getGData();
+ bData = planarImg->getBData();
+ aData = planarImg->getAData();
+
+ if(width <= 0 || height <= 0)
+ {
+ std::ostringstream os;
+ os << "PlanarImageDesc Error: Image dimensions must be positive for both x,y. '";
+ os << width << "x" << height << "' is not allowed.";
+ throw Exception(os.str().c_str());
+ }
+
+ if(rData == NULL || gData == NULL || bData == NULL)
+ {
+ std::ostringstream os;
+ os << "PlanarImageDesc Error: Valid ptrs must be passed for all 3 image rgb color channels.";
+ throw Exception(os.str().c_str());
+ }
+ }
+ else
+ {
+ throw Exception("Unknown ImageDesc type.");
+ }
+ }
+
+ bool GenericImageDesc::isPackedRGBA() const
+ {
+ char* rPtr = reinterpret_cast<char*>(rData);
+ char* gPtr = reinterpret_cast<char*>(gData);
+ char* bPtr = reinterpret_cast<char*>(bData);
+ char* aPtr = reinterpret_cast<char*>(aData);
+
+ if(gPtr-rPtr != sizeof(float)) return false;
+ if(bPtr-gPtr != sizeof(float)) return false;
+ if(aPtr && (aPtr-bPtr != sizeof(float))) return false;
+
+ // Confirm xStrideBytes is a pure float-sized packing
+ // (I.e., it will divide evenly)
+ if(xStrideBytes <= 0) return false;
+ div_t result = div((int) xStrideBytes, (int)sizeof(float));
+ if(result.rem != 0) return false;
+
+ int implicitChannels = result.quot;
+ if(implicitChannels != 4) return false;
+
+ return true;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ class PackedImageDesc::Impl
+ {
+ public:
+ float * data_;
+ long width_;
+ long height_;
+ long numChannels_;
+ ptrdiff_t chanStrideBytes_;
+ ptrdiff_t xStrideBytes_;
+ ptrdiff_t yStrideBytes_;
+
+ Impl() :
+ data_(NULL),
+ width_(0),
+ height_(0),
+ numChannels_(0),
+ chanStrideBytes_(0),
+ xStrideBytes_(0),
+ yStrideBytes_(0)
+ {
+ }
+
+ ~Impl()
+ { }
+ };
+
+ PackedImageDesc::PackedImageDesc(float * data,
+ long width, long height,
+ long numChannels,
+ ptrdiff_t chanStrideBytes,
+ ptrdiff_t xStrideBytes,
+ ptrdiff_t yStrideBytes)
+ : m_impl(new PackedImageDesc::Impl)
+ {
+ getImpl()->data_ = data;
+ getImpl()->width_ = width;
+ getImpl()->height_ = height;
+ getImpl()->numChannels_ = numChannels;
+ getImpl()->chanStrideBytes_ = (chanStrideBytes == AutoStride)
+ ? sizeof(float) : chanStrideBytes;
+ getImpl()->xStrideBytes_ = (xStrideBytes == AutoStride)
+ ? sizeof(float)*numChannels : xStrideBytes;
+ getImpl()->yStrideBytes_ = (yStrideBytes == AutoStride)
+ ? sizeof(float)*width*numChannels : yStrideBytes;
+ }
+
+ PackedImageDesc::~PackedImageDesc()
+ {
+ delete m_impl;
+ m_impl = NULL;
+ }
+
+ float * PackedImageDesc::getData() const
+ {
+ return getImpl()->data_;
+ }
+
+ long PackedImageDesc::getWidth() const
+ {
+ return getImpl()->width_;
+ }
+
+ long PackedImageDesc::getHeight() const
+ {
+ return getImpl()->height_;
+ }
+
+ long PackedImageDesc::getNumChannels() const
+ {
+ return getImpl()->numChannels_;
+ }
+
+ ptrdiff_t PackedImageDesc::getChanStrideBytes() const
+ {
+ return getImpl()->chanStrideBytes_;
+ }
+
+ ptrdiff_t PackedImageDesc::getXStrideBytes() const
+ {
+ return getImpl()->xStrideBytes_;
+ }
+
+ ptrdiff_t PackedImageDesc::getYStrideBytes() const
+ {
+ return getImpl()->yStrideBytes_;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+
+ class PlanarImageDesc::Impl
+ {
+ public:
+ float * rData_;
+ float * gData_;
+ float * bData_;
+ float * aData_;
+ long width_;
+ long height_;
+ ptrdiff_t yStrideBytes_;
+
+ Impl() :
+ rData_(NULL),
+ gData_(NULL),
+ bData_(NULL),
+ aData_(NULL),
+ width_(0),
+ height_(0),
+ yStrideBytes_(0)
+ { }
+
+ ~Impl()
+ { }
+ };
+
+
+ PlanarImageDesc::PlanarImageDesc(float * rData, float * gData, float * bData, float * aData,
+ long width, long height,
+ ptrdiff_t yStrideBytes)
+ : m_impl(new PlanarImageDesc::Impl())
+ {
+ getImpl()->rData_ = rData;
+ getImpl()->gData_ = gData;
+ getImpl()->bData_ = bData;
+ getImpl()->aData_ = aData;
+ getImpl()->width_ = width;
+ getImpl()->height_ = height;
+ getImpl()->yStrideBytes_ = (yStrideBytes == AutoStride)
+ ? sizeof(float)*width : yStrideBytes;
+ }
+
+ PlanarImageDesc::~PlanarImageDesc()
+ {
+ delete m_impl;
+ m_impl = NULL;
+ }
+
+ float* PlanarImageDesc::getRData() const
+ {
+ return getImpl()->rData_;
+ }
+
+ float* PlanarImageDesc::getGData() const
+ {
+ return getImpl()->gData_;
+ }
+
+ float* PlanarImageDesc::getBData() const
+ {
+ return getImpl()->bData_;
+ }
+
+ float* PlanarImageDesc::getAData() const
+ {
+ return getImpl()->aData_;
+ }
+
+ long PlanarImageDesc::getWidth() const
+ {
+ return getImpl()->width_;
+ }
+
+ long PlanarImageDesc::getHeight() const
+ {
+ return getImpl()->height_;
+ }
+
+ ptrdiff_t PlanarImageDesc::getYStrideBytes() const
+ {
+ return getImpl()->yStrideBytes_;
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/ImagePacking.cpp b/src/core/ImagePacking.cpp
new file mode 100644
index 0000000..256d25c
--- /dev/null
+++ b/src/core/ImagePacking.cpp
@@ -0,0 +1,407 @@
+/*
+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 <sstream>
+#include <iostream>
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+
+#include "ImagePacking.h"
+
+OCIO_NAMESPACE_ENTER
+{
+
+ namespace
+ {
+ // GENERIC CASE, SLOW BUT ALWAYS WORKS
+
+ void PackRGBAFromImageDesc_Generic(const GenericImageDesc& srcImg,
+ float* outputBuffer,
+ int* numPixelsCopied,
+ int outputBufferSize,
+ long imagePixelStartIndex)
+ {
+ assert(outputBuffer);
+ assert(numPixelsCopied);
+
+ long imgWidth = srcImg.width;
+ long imgHeight = srcImg.height;
+ long imgPixels = imgWidth * imgHeight;
+
+ if(imagePixelStartIndex<0 || imagePixelStartIndex>=imgPixels)
+ {
+ *numPixelsCopied = 0;
+ return;
+ }
+
+ ptrdiff_t xStrideBytes = srcImg.xStrideBytes;
+ ptrdiff_t yStrideBytes = srcImg.yStrideBytes;
+ long yIndex = imagePixelStartIndex / imgWidth;
+ long xIndex = imagePixelStartIndex % imgWidth;
+
+ // Figure out our initial ptr positions
+ char* rRow = reinterpret_cast<char*>(srcImg.rData) +
+ yStrideBytes * yIndex;
+ char* gRow = reinterpret_cast<char*>(srcImg.gData) +
+ yStrideBytes * yIndex;
+ char* bRow = reinterpret_cast<char*>(srcImg.bData) +
+ yStrideBytes * yIndex;
+ char* aRow = NULL;
+
+ float* rPtr = reinterpret_cast<float*>(rRow + xStrideBytes*xIndex);
+ float* gPtr = reinterpret_cast<float*>(gRow + xStrideBytes*xIndex);
+ float* bPtr = reinterpret_cast<float*>(bRow + xStrideBytes*xIndex);
+ float* aPtr = NULL;
+
+ if(srcImg.aData)
+ {
+ aRow = reinterpret_cast<char*>(srcImg.aData) + yStrideBytes * yIndex;
+ aPtr = reinterpret_cast<float*>(aRow + xStrideBytes*xIndex);
+ }
+
+ if(aPtr)
+ {
+ int pixelsCopied = 0;
+ while(pixelsCopied < outputBufferSize)
+ {
+ outputBuffer[4*pixelsCopied] = *rPtr;
+ outputBuffer[4*pixelsCopied+1] = *gPtr;
+ outputBuffer[4*pixelsCopied+2] = *bPtr;
+ outputBuffer[4*pixelsCopied+3] = *aPtr;
+ pixelsCopied++;
+ xIndex++;
+
+ // Jump to the next scanline
+ if(xIndex == imgWidth)
+ {
+ yIndex += 1;
+ if(yIndex == imgHeight)
+ {
+ *numPixelsCopied = pixelsCopied;
+ return;
+ }
+
+ xIndex = 0;
+ rRow += yStrideBytes;
+ gRow += yStrideBytes;
+ bRow += yStrideBytes;
+ aRow += yStrideBytes;
+
+ rPtr = reinterpret_cast<float*>(rRow);
+ gPtr = reinterpret_cast<float*>(gRow);
+ bPtr = reinterpret_cast<float*>(bRow);
+ aPtr = reinterpret_cast<float*>(aRow);
+ }
+ // Jump to the next pixel
+ else
+ {
+ rPtr = reinterpret_cast<float*>(
+ reinterpret_cast<char*>(rPtr) + xStrideBytes);
+ gPtr = reinterpret_cast<float*>(
+ reinterpret_cast<char*>(gPtr) + xStrideBytes);
+ bPtr = reinterpret_cast<float*>(
+ reinterpret_cast<char*>(bPtr) + xStrideBytes);
+ aPtr = reinterpret_cast<float*>(
+ reinterpret_cast<char*>(aPtr) + xStrideBytes);
+ }
+ }
+
+ *numPixelsCopied = pixelsCopied;
+ }
+ else
+ {
+ int pixelsCopied = 0;
+ while(pixelsCopied < outputBufferSize)
+ {
+ outputBuffer[4*pixelsCopied] = *rPtr;
+ outputBuffer[4*pixelsCopied+1] = *gPtr;
+ outputBuffer[4*pixelsCopied+2] = *bPtr;
+ outputBuffer[4*pixelsCopied+3] = 0.0;
+ pixelsCopied++;
+ xIndex++;
+
+ // Jump to the next scanline
+ if(xIndex == imgWidth)
+ {
+ yIndex += 1;
+ if(yIndex == imgHeight)
+ {
+ *numPixelsCopied = pixelsCopied;
+ return;
+ }
+
+ xIndex = 0;
+ rRow += yStrideBytes;
+ gRow += yStrideBytes;
+ bRow += yStrideBytes;
+
+ rPtr = reinterpret_cast<float*>(rRow);
+ gPtr = reinterpret_cast<float*>(gRow);
+ bPtr = reinterpret_cast<float*>(bRow);
+ }
+ // Jump to the next pixel
+ else
+ {
+ rPtr = reinterpret_cast<float*>(
+ reinterpret_cast<char*>(rPtr) + xStrideBytes);
+ gPtr = reinterpret_cast<float*>(
+ reinterpret_cast<char*>(gPtr) + xStrideBytes);
+ bPtr = reinterpret_cast<float*>(
+ reinterpret_cast<char*>(bPtr) + xStrideBytes);
+ }
+ }
+
+ *numPixelsCopied = pixelsCopied;
+ }
+ }
+
+ void UnpackRGBAToImageDesc_Generic(GenericImageDesc& dstImg,
+ float* inputBuffer,
+ int numPixelsToUnpack,
+ long imagePixelStartIndex)
+ {
+ assert(inputBuffer);
+
+ long imgWidth = dstImg.width;
+ long imgHeight = dstImg.height;
+ long imgPixels = imgWidth * imgHeight;
+
+ if(imagePixelStartIndex<0 || imagePixelStartIndex>=imgPixels)
+ {
+ return;
+ }
+
+ ptrdiff_t xStrideBytes = dstImg.xStrideBytes;
+ ptrdiff_t yStrideBytes = dstImg.yStrideBytes;
+ long yIndex = imagePixelStartIndex / imgWidth;
+ long xIndex = imagePixelStartIndex % imgWidth;
+
+ // Figure out our initial ptr positions
+ char* rRow = reinterpret_cast<char*>(dstImg.rData) +
+ yStrideBytes * yIndex;
+ char* gRow = reinterpret_cast<char*>(dstImg.gData) +
+ yStrideBytes * yIndex;
+ char* bRow = reinterpret_cast<char*>(dstImg.bData) +
+ yStrideBytes * yIndex;
+ char* aRow = NULL;
+
+ float* rPtr = reinterpret_cast<float*>(rRow + xStrideBytes*xIndex);
+ float* gPtr = reinterpret_cast<float*>(gRow + xStrideBytes*xIndex);
+ float* bPtr = reinterpret_cast<float*>(bRow + xStrideBytes*xIndex);
+ float* aPtr = NULL;
+
+ if(dstImg.aData)
+ {
+ aRow = reinterpret_cast<char*>(dstImg.aData) + yStrideBytes * yIndex;
+ aPtr = reinterpret_cast<float*>(aRow + xStrideBytes*xIndex);
+ }
+
+ if(aPtr)
+ {
+ int pixelsCopied = 0;
+ while(pixelsCopied < numPixelsToUnpack)
+ {
+ *rPtr = inputBuffer[4*pixelsCopied];
+ *gPtr = inputBuffer[4*pixelsCopied+1];
+ *bPtr = inputBuffer[4*pixelsCopied+2];
+ *aPtr = inputBuffer[4*pixelsCopied+3];
+
+ pixelsCopied++;
+ xIndex++;
+
+ // Jump to the next scanline
+ if(xIndex == imgWidth)
+ {
+ yIndex += 1;
+ if(yIndex == imgHeight)
+ {
+ return;
+ }
+
+ xIndex = 0;
+ rRow += yStrideBytes;
+ gRow += yStrideBytes;
+ bRow += yStrideBytes;
+ aRow += yStrideBytes;
+
+ rPtr = reinterpret_cast<float*>(rRow);
+ gPtr = reinterpret_cast<float*>(gRow);
+ bPtr = reinterpret_cast<float*>(bRow);
+ aPtr = reinterpret_cast<float*>(aRow);
+ }
+ // Jump to the next pixel
+ else
+ {
+ rPtr = reinterpret_cast<float*>(
+ reinterpret_cast<char*>(rPtr) + xStrideBytes);
+ gPtr = reinterpret_cast<float*>(
+ reinterpret_cast<char*>(gPtr) + xStrideBytes);
+ bPtr = reinterpret_cast<float*>(
+ reinterpret_cast<char*>(bPtr) + xStrideBytes);
+ aPtr = reinterpret_cast<float*>(
+ reinterpret_cast<char*>(aPtr) + xStrideBytes);
+ }
+ }
+ }
+ else
+ {
+ int pixelsCopied = 0;
+ while(pixelsCopied < numPixelsToUnpack)
+ {
+ *rPtr = inputBuffer[4*pixelsCopied];
+ *gPtr = inputBuffer[4*pixelsCopied+1];
+ *bPtr = inputBuffer[4*pixelsCopied+2];
+
+ pixelsCopied++;
+ xIndex++;
+
+ // Jump to the next scanline
+ if(xIndex == imgWidth)
+ {
+ yIndex += 1;
+ if(yIndex == imgHeight)
+ {
+ return;
+ }
+
+ xIndex = 0;
+ rRow += yStrideBytes;
+ gRow += yStrideBytes;
+ bRow += yStrideBytes;
+
+ rPtr = reinterpret_cast<float*>(rRow);
+ gPtr = reinterpret_cast<float*>(gRow);
+ bPtr = reinterpret_cast<float*>(bRow);
+ }
+ // Jump to the next pixel
+ else
+ {
+ rPtr = reinterpret_cast<float*>(
+ reinterpret_cast<char*>(rPtr) + xStrideBytes);
+ gPtr = reinterpret_cast<float*>(
+ reinterpret_cast<char*>(gPtr) + xStrideBytes);
+ bPtr = reinterpret_cast<float*>(
+ reinterpret_cast<char*>(bPtr) + xStrideBytes);
+ }
+ }
+ }
+ }
+
+ }
+
+
+ /*
+ namespace
+ {
+
+ void PackRGBAFromImageDesc_RGBAMemcpy(const GenericImageDesc& srcImg,
+ float* outputBuffer,
+ int* numPixelsCopied,
+ int outputBufferSize,
+ int imagePixelStartIndex)
+ {
+ assert(outputBuffer);
+ assert(numPixelsCopied);
+
+ long imgWidth = srcImg.getWidth();
+ long imgHeight = srcImg.getHeight();
+ long imgPixels = srcImg.getNumPixels();
+
+ if(imagePixelStartIndex<0 || imagePixelStartIndex>=imgPixels)
+ {
+ *numPixelsCopied = 0;
+ return;
+ }
+
+ ptrdiff_t xStrideBytes = srcImg.getXStrideBytes();
+ ptrdiff_t yStrideBytes = srcImg.getYStrideBytes();
+ int yIndex = imagePixelStartIndex / imgWidth;
+ int xIndex = imagePixelStartIndex % imgWidth;
+
+ // Figure out our initial ptr positions
+ char* imgRow = reinterpret_cast<char*>(srcImg.getRData()) +
+ yStrideBytes * yIndex;
+
+ char* imgPtr = imgRow + xStrideBytes*xIndex;
+
+ int totalPixelsCopied = 0;
+ int pixelsRemainingToCopy = outputBufferSize;
+
+ while(pixelsRemainingToCopy>0 && yIndex < imgHeight)
+ {
+ int imgScanlinePixels = imgWidth - xIndex;
+ int numPixels = std::min(imgScanlinePixels,
+ pixelsRemainingToCopy);
+ memcpy(outputBuffer+totalPixelsCopied,
+ imgPtr, numPixels);
+
+ yIndex += 1;
+ xIndex = 0;
+
+ imgRow += yStrideBytes;
+ imgPtr = imgRow;
+ totalPixelsCopied += numPixels;
+ pixelsRemainingToCopy -= numPixels;
+ }
+
+ if(numPixelsCopied) *numPixelsCopied = totalPixelsCopied;
+ }
+ }
+ */
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ // TODO: Add optimized codepaths to image packing / unpacking
+
+ void PackRGBAFromImageDesc(const GenericImageDesc& srcImg,
+ float* outputBuffer,
+ int* numPixelsCopied,
+ int outputBufferSize,
+ long imagePixelStartIndex)
+ {
+ PackRGBAFromImageDesc_Generic(srcImg, outputBuffer,
+ numPixelsCopied,
+ outputBufferSize,
+ imagePixelStartIndex);
+ }
+
+
+ void UnpackRGBAToImageDesc(GenericImageDesc& dstImg,
+ float* inputBuffer,
+ int numPixelsToUnpack,
+ long imagePixelStartIndex)
+ {
+ UnpackRGBAToImageDesc_Generic(dstImg, inputBuffer,
+ numPixelsToUnpack,
+ imagePixelStartIndex);
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/ImagePacking.h b/src/core/ImagePacking.h
new file mode 100644
index 0000000..a03d1ea
--- /dev/null
+++ b/src/core/ImagePacking.h
@@ -0,0 +1,71 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_IMAGEPACKING_H
+#define INCLUDED_OCIO_IMAGEPACKING_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+OCIO_NAMESPACE_ENTER
+{
+ struct GenericImageDesc
+ {
+ long width;
+ long height;
+ ptrdiff_t xStrideBytes;
+ ptrdiff_t yStrideBytes;
+
+ float* rData;
+ float* gData;
+ float* bData;
+ float* aData;
+
+ GenericImageDesc();
+ ~GenericImageDesc();
+
+ // Resolves all AutoStride
+ void init(const ImageDesc& img);
+
+ bool isPackedRGBA() const;
+ };
+
+ void PackRGBAFromImageDesc(const GenericImageDesc& srcImg,
+ float* outputBuffer,
+ int* numPixelsCopied,
+ int outputBufferSize,
+ long imagePixelStartIndex);
+
+ void UnpackRGBAToImageDesc(GenericImageDesc& dstImg,
+ float* inputBuffer,
+ int numPixelsToUnpack,
+ long imagePixelStartIndex);
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/LogOps.cpp b/src/core/LogOps.cpp
new file mode 100644
index 0000000..bc3174e
--- /dev/null
+++ b/src/core/LogOps.cpp
@@ -0,0 +1,499 @@
+/*
+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 <cmath>
+#include <cstring>
+#include <iostream>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "GpuShaderUtils.h"
+#include "LogOps.h"
+#include "MathUtils.h"
+
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ const float FLTMIN = std::numeric_limits<float>::min();
+
+ const int FLOAT_DECIMALS = 7;
+
+ // k * log(mx+b, base) + kb
+ // the caller is responsible for base != 1.0
+ // TODO: pull the precomputation into the caller?
+
+ void ApplyLinToLog(float* rgbaBuffer, long numPixels,
+ const float * k,
+ const float * m,
+ const float * b,
+ const float * base,
+ const float * kb)
+ {
+ // We account for the change of base by rolling the multiplier
+ // in with 'k'
+
+ float knew[3] = { k[0] / logf(base[0]),
+ k[1] / logf(base[1]),
+ k[2] / logf(base[0]) };
+
+ for(long pixelIndex=0; pixelIndex<numPixels; ++pixelIndex)
+ {
+ rgbaBuffer[0] = knew[0] * logf(std::max(m[0]*rgbaBuffer[0] + b[0], FLTMIN)) + kb[0];
+ rgbaBuffer[1] = knew[1] * logf(std::max(m[1]*rgbaBuffer[1] + b[1], FLTMIN)) + kb[1];
+ rgbaBuffer[2] = knew[2] * logf(std::max(m[2]*rgbaBuffer[2] + b[2], FLTMIN)) + kb[2];
+
+ rgbaBuffer += 4;
+ }
+ }
+
+ // the caller is responsible for m != 0
+ // the caller is responsible for k != 0
+ // TODO: pull the precomputation into the caller?
+
+ void ApplyLogToLin(float* rgbaBuffer, long numPixels,
+ const float * k,
+ const float * m,
+ const float * b,
+ const float * base,
+ const float * kb)
+ {
+ float kinv[3] = { 1.0f / k[0],
+ 1.0f / k[1],
+ 1.0f / k[2] };
+
+ float minv[3] = { 1.0f / m[0],
+ 1.0f / m[1],
+ 1.0f / m[2] };
+
+ for(long pixelIndex=0; pixelIndex<numPixels; ++pixelIndex)
+ {
+ rgbaBuffer[0] = minv[0] * (powf(base[0], kinv[0]*(rgbaBuffer[0]-kb[0])) - b[0]);
+ rgbaBuffer[1] = minv[1] * (powf(base[1], kinv[1]*(rgbaBuffer[1]-kb[1])) - b[1]);
+ rgbaBuffer[2] = minv[2] * (powf(base[2], kinv[2]*(rgbaBuffer[2]-kb[2])) - b[2]);
+
+ rgbaBuffer += 4;
+ }
+ }
+
+ }
+
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ namespace
+ {
+ class LogOp : public Op
+ {
+ public:
+ LogOp(const float * k,
+ const float * m,
+ const float * b,
+ const float * base,
+ const float * kb,
+ TransformDirection direction);
+ virtual ~LogOp();
+
+ virtual OpRcPtr clone() const;
+
+ virtual std::string getInfo() const;
+ virtual std::string getCacheID() const;
+
+ virtual bool isNoOp() const;
+ virtual bool isSameType(const OpRcPtr & op) const;
+ virtual bool isInverse(const OpRcPtr & op) const;
+ virtual bool hasChannelCrosstalk() const;
+ virtual void finalize();
+ virtual void apply(float* rgbaBuffer, long numPixels) const;
+
+ virtual bool supportsGpuShader() const;
+ virtual void writeGpuShader(std::ostream & shader,
+ const std::string & pixelName,
+ const GpuShaderDesc & shaderDesc) const;
+
+ private:
+ float m_k[3];
+ float m_m[3];
+ float m_b[3];
+ float m_base[3];
+ float m_kb[3];
+ TransformDirection m_direction;
+
+ std::string m_cacheID;
+ };
+
+ typedef OCIO_SHARED_PTR<LogOp> LogOpRcPtr;
+
+ LogOp::LogOp(const float * k,
+ const float * m,
+ const float * b,
+ const float * base,
+ const float * kb,
+ TransformDirection direction):
+ Op(),
+ m_direction(direction)
+ {
+ if(m_direction == TRANSFORM_DIR_UNKNOWN)
+ {
+ throw Exception("Cannot apply LogOp op, unspecified transform direction.");
+ }
+
+ memcpy(m_k, k, sizeof(float)*3);
+ memcpy(m_m, m, sizeof(float)*3);
+ memcpy(m_b, b, sizeof(float)*3);
+ memcpy(m_base, base, sizeof(float)*3);
+ memcpy(m_kb, kb, sizeof(float)*3);
+ }
+
+ OpRcPtr LogOp::clone() const
+ {
+ OpRcPtr op = OpRcPtr(new LogOp(m_k, m_m, m_b, m_base, m_kb, m_direction));
+ return op;
+ }
+
+ LogOp::~LogOp()
+ { }
+
+ std::string LogOp::getInfo() const
+ {
+ return "<LogOp>";
+ }
+
+ std::string LogOp::getCacheID() const
+ {
+ return m_cacheID;
+ }
+
+ bool LogOp::isNoOp() const
+ {
+ return false;
+ }
+
+ bool LogOp::isSameType(const OpRcPtr & op) const
+ {
+ LogOpRcPtr typedRcPtr = DynamicPtrCast<LogOp>(op);
+ if(!typedRcPtr) return false;
+ return true;
+ }
+
+ bool LogOp::isInverse(const OpRcPtr & op) const
+ {
+ LogOpRcPtr typedRcPtr = DynamicPtrCast<LogOp>(op);
+ if(!typedRcPtr) return false;
+
+ if(GetInverseTransformDirection(m_direction) != typedRcPtr->m_direction)
+ return false;
+
+ float error = std::numeric_limits<float>::min();
+ if(!VecsEqualWithRelError(m_k, 3, typedRcPtr->m_k, 3, error))
+ return false;
+ if(!VecsEqualWithRelError(m_m, 3, typedRcPtr->m_m, 3, error))
+ return false;
+ if(!VecsEqualWithRelError(m_b, 3, typedRcPtr->m_b, 3, error))
+ return false;
+ if(!VecsEqualWithRelError(m_base, 3, typedRcPtr->m_base, 3, error))
+ return false;
+ if(!VecsEqualWithRelError(m_kb, 3, typedRcPtr->m_kb, 3, error))
+ return false;
+
+ return true;
+ }
+
+ bool LogOp::hasChannelCrosstalk() const
+ {
+ return false;
+ }
+
+ void LogOp::finalize()
+ {
+ if(m_direction == TRANSFORM_DIR_FORWARD)
+ {
+ if(VecContainsOne(m_base, 3))
+ throw Exception("LogOp Exception, base cannot be 1.");
+ }
+ else if(m_direction == TRANSFORM_DIR_INVERSE)
+ {
+ if(VecContainsZero(m_m, 3))
+ throw Exception("LogOp Exception, m (slope) cannot be 0.");
+ if(VecContainsZero(m_k, 3))
+ throw Exception("LogOp Exception, k (multiplier) cannot be 0.");
+ }
+
+ std::ostringstream cacheIDStream;
+ cacheIDStream << "<LogOp ";
+ cacheIDStream.precision(FLOAT_DECIMALS);
+ for(int i=0; i<3; ++i)
+ {
+ cacheIDStream << m_k[i] << " ";
+ cacheIDStream << m_m[i] << " ";
+ cacheIDStream << m_b[i] << " ";
+ cacheIDStream << m_base[i] << " ";
+ cacheIDStream << m_kb[i] << " ";
+ }
+
+ cacheIDStream << TransformDirectionToString(m_direction) << " ";
+ cacheIDStream << ">";
+
+ m_cacheID = cacheIDStream.str();
+ }
+
+ void LogOp::apply(float* rgbaBuffer, long numPixels) const
+ {
+ if(m_direction == TRANSFORM_DIR_FORWARD)
+ {
+ ApplyLinToLog(rgbaBuffer, numPixels,
+ m_k, m_m, m_b, m_base, m_kb);
+ }
+ else if(m_direction == TRANSFORM_DIR_INVERSE)
+ {
+ ApplyLogToLin(rgbaBuffer, numPixels,
+ m_k, m_m, m_b, m_base, m_kb);
+ }
+ } // Op::process
+
+ bool LogOp::supportsGpuShader() const
+ {
+ return true;
+ }
+
+ void LogOp::writeGpuShader(std::ostream & shader,
+ const std::string & pixelName,
+ const GpuShaderDesc & shaderDesc) const
+ {
+ GpuLanguage lang = shaderDesc.getLanguage();
+
+ if(m_direction == TRANSFORM_DIR_FORWARD)
+ {
+ // Lin To Log
+ // k * log(mx+b, base) + kb
+
+ // We account for the change of base by rolling the multiplier
+ // in with 'k'
+
+ float knew[3] = { m_k[0] / logf(m_base[0]),
+ m_k[1] / logf(m_base[1]),
+ m_k[2] / logf(m_base[0]) };
+
+ float clampMin[3] = { FLTMIN, FLTMIN, FLTMIN };
+
+ // TODO: Switch to f32 for internal Cg processing?
+ if(lang == GPU_LANGUAGE_CG)
+ {
+ clampMin[0] = static_cast<float>(GetHalfNormMin());
+ clampMin[1] = static_cast<float>(GetHalfNormMin());
+ clampMin[2] = static_cast<float>(GetHalfNormMin());
+ }
+
+ // Decompose into 2 steps
+ // 1) clamp(mx+b)
+ // 2) knew * log(x) + kb
+
+ shader << pixelName << ".rgb = ";
+ shader << "max(" << GpuTextHalf3(clampMin,lang) << ", ";
+ shader << GpuTextHalf3(m_m,lang) << " * ";
+ shader << pixelName << ".rgb + ";
+ shader << GpuTextHalf3(m_b,lang) << ");\n";
+
+ shader << pixelName << ".rgb = ";
+ shader << GpuTextHalf3(knew,lang) << " * ";
+ shader << "log(" << pixelName << ".rgb) + ";
+ shader << GpuTextHalf3(m_kb,lang) << ";\n";
+ }
+ else if(m_direction == TRANSFORM_DIR_INVERSE)
+ {
+ float kinv[3] = { 1.0f / m_k[0],
+ 1.0f / m_k[1],
+ 1.0f / m_k[2] };
+
+ float minv[3] = { 1.0f / m_m[0],
+ 1.0f / m_m[1],
+ 1.0f / m_m[2] };
+
+ // Decompose into 3 steps
+ // 1) kinv * ( x - kb)
+ // 2) pow(base, x)
+ // 3) minv * (x - b)
+
+ shader << pixelName << ".rgb = ";
+ shader << GpuTextHalf3(kinv,lang) << " * (";
+ shader << pixelName << ".rgb - ";
+ shader << GpuTextHalf3(m_kb,lang) << ");\n";
+
+ shader << pixelName << ".rgb = pow(";
+ shader << GpuTextHalf3(m_base,lang) << ", ";
+ shader << pixelName << ".rgb);\n";
+
+ shader << pixelName << ".rgb = ";
+ shader << GpuTextHalf3(minv,lang) << " * (";
+ shader << pixelName << ".rgb - ";
+ shader << GpuTextHalf3(m_b,lang) << ");\n";
+ }
+ }
+
+ } // Anon namespace
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ void CreateLogOp(OpRcPtrVec & ops,
+ const float * k,
+ const float * m,
+ const float * b,
+ const float * base,
+ const float * kb,
+ TransformDirection direction)
+ {
+ ops.push_back( LogOpRcPtr(new LogOp(k, m, b, base, kb, direction)) );
+ }
+}
+OCIO_NAMESPACE_EXIT
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef OCIO_UNIT_TEST
+
+namespace OCIO = OCIO_NAMESPACE;
+#include "UnitTest.h"
+
+OIIO_ADD_TEST(LogOps, LinToLog)
+{
+ float k[3] = { 0.18f, 0.18f, 0.18f };
+ float m[3] = { 2.0f, 2.0f, 2.0f };
+ float b[3] = { 0.1f, 0.1f, 0.1f };
+ float base[3] = { 10.0f, 10.0f, 10.0f };
+ float kb[3] = { 1.0f, 1.0f, 1.0f };
+
+
+ float data[8] = { 0.01f, 0.1f, 1.0f, 1.0f,
+ 10.0f, 100.0f, 1000.0f, 1.0f, };
+
+ float result[8] = { 0.8342526242885725f,
+ 0.90588182584953925f,
+ 1.057999473052105462f,
+ 1.0f,
+ 1.23457529033568797f,
+ 1.41422447595451795f,
+ 1.59418930777214063f,
+ 1.0f };
+
+ OCIO::OpRcPtrVec ops;
+ CreateLogOp(ops, k, m, b, base, kb, OCIO::TRANSFORM_DIR_FORWARD);
+
+ FinalizeOpVec(ops);
+
+ // Apply the result
+ for(OCIO::OpRcPtrVec::size_type i = 0, size = ops.size(); i < size; ++i)
+ {
+ ops[i]->apply(data, 2);
+ }
+
+ for(int i=0; i<8; ++i)
+ {
+ OIIO_CHECK_CLOSE( data[i], result[i], 1.0e-3 );
+ }
+}
+
+OIIO_ADD_TEST(LogOps, LogToLin)
+{
+ float k[3] = { 0.18f, 0.18f, 0.18f };
+ float m[3] = { 2.0f, 2.0f, 2.0f };
+ float b[3] = { 0.1f, 0.1f, 0.1f };
+ float base[3] = { 10.0f, 10.0f, 10.0f };
+ float kb[3] = { 1.0f, 1.0f, 1.0f };
+
+ float data[8] = { 0.8342526242885725f,
+ 0.90588182584953925f,
+ 1.057999473052105462f,
+ 1.0f,
+ 1.23457529033568797f,
+ 1.41422447595451795f,
+ 1.59418930777214063f,
+ 1.0f };
+
+ float result[8] = { 0.01f, 0.1f, 1.0f, 1.0f,
+ 10.0f, 100.0f, 1000.0f, 1.0f, };
+
+ OCIO::OpRcPtrVec ops;
+ CreateLogOp(ops, k, m, b, base, kb, OCIO::TRANSFORM_DIR_INVERSE);
+
+ FinalizeOpVec(ops);
+
+ // Apply the result
+ for(OCIO::OpRcPtrVec::size_type i = 0, size = ops.size(); i < size; ++i)
+ {
+ ops[i]->apply(data, 2);
+ }
+
+ for(int i=0; i<8; ++i)
+ {
+ OIIO_CHECK_CLOSE( data[i], result[i], 1.0e-3 );
+ }
+}
+
+OIIO_ADD_TEST(LogOps, Inverse)
+{
+ float k[3] = { 0.18f, 0.18f, 0.18f };
+ float m[3] = { 2.0f, 2.0f, 2.0f };
+ float b[3] = { 0.1f, 0.1f, 0.1f };
+ float base[3] = { 10.0f, 10.0f, 10.0f };
+ float kb[3] = { 1.0f, 1.0f, 1.0f };
+
+ OCIO::OpRcPtrVec ops;
+ CreateLogOp(ops, k, m, b, base, kb, OCIO::TRANSFORM_DIR_FORWARD);
+
+ CreateLogOp(ops, k, m, b, base, kb, OCIO::TRANSFORM_DIR_INVERSE);
+
+ base[0] += 1e-5f;
+ CreateLogOp(ops, k, m, b, base, kb, OCIO::TRANSFORM_DIR_INVERSE);
+ CreateLogOp(ops, k, m, b, base, kb, OCIO::TRANSFORM_DIR_FORWARD);
+
+ OIIO_CHECK_EQUAL(ops.size(), 4);
+
+ OIIO_CHECK_ASSERT(ops[0]->isSameType(ops[1]));
+ OIIO_CHECK_ASSERT(ops[0]->isSameType(ops[2]));
+ OIIO_CHECK_ASSERT(ops[0]->isSameType(ops[3]->clone()));
+
+ OIIO_CHECK_EQUAL(ops[0]->isInverse(ops[0]), false);
+ OIIO_CHECK_EQUAL(ops[0]->isInverse(ops[1]), true);
+ OIIO_CHECK_EQUAL(ops[0]->isInverse(ops[2]), false);
+ OIIO_CHECK_EQUAL(ops[0]->isInverse(ops[3]), false);
+
+ OIIO_CHECK_EQUAL(ops[1]->isInverse(ops[0]), true);
+ OIIO_CHECK_EQUAL(ops[1]->isInverse(ops[2]), false);
+ OIIO_CHECK_EQUAL(ops[1]->isInverse(ops[3]), false);
+
+ OIIO_CHECK_EQUAL(ops[2]->isInverse(ops[2]), false);
+ OIIO_CHECK_EQUAL(ops[2]->isInverse(ops[3]), true);
+
+ OIIO_CHECK_EQUAL(ops[3]->isInverse(ops[3]), false);
+}
+
+#endif // OCIO_UNIT_TEST
diff --git a/src/core/LogOps.h b/src/core/LogOps.h
new file mode 100644
index 0000000..0356fd8
--- /dev/null
+++ b/src/core/LogOps.h
@@ -0,0 +1,57 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_LOGOPS_H
+#define INCLUDED_OCIO_LOGOPS_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "Op.h"
+
+#include <vector>
+
+OCIO_NAMESPACE_ENTER
+{
+ // output = k * log(mx+b, base) + kb
+ // This does not affect alpha
+ // In the forward direction this is lin->log
+ // All input vectors are size 3 (including base)
+
+ void CreateLogOp(OpRcPtrVec & ops,
+ const float * k,
+ const float * m,
+ const float * b,
+ const float * base,
+ const float * kb,
+ TransformDirection direction);
+
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/LogTransform.cpp b/src/core/LogTransform.cpp
new file mode 100644
index 0000000..8ed7bb0
--- /dev/null
+++ b/src/core/LogTransform.cpp
@@ -0,0 +1,157 @@
+/*
+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 <cstring>
+#include <sstream>
+#include <vector>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "LogOps.h"
+#include "OpBuilders.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ LogTransformRcPtr LogTransform::Create()
+ {
+ return LogTransformRcPtr(new LogTransform(), &deleter);
+ }
+
+ void LogTransform::deleter(LogTransform* t)
+ {
+ delete t;
+ }
+
+
+ class LogTransform::Impl
+ {
+ public:
+ TransformDirection dir_;
+ float base_;
+
+ Impl() :
+ dir_(TRANSFORM_DIR_FORWARD),
+ base_(2.0)
+ { }
+
+ ~Impl()
+ { }
+
+ Impl& operator= (const Impl & rhs)
+ {
+ dir_ = rhs.dir_;
+ base_ = rhs.base_;
+ return *this;
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ LogTransform::LogTransform()
+ : m_impl(new LogTransform::Impl)
+ {
+ }
+
+ TransformRcPtr LogTransform::createEditableCopy() const
+ {
+ LogTransformRcPtr transform = LogTransform::Create();
+ *(transform->m_impl) = *m_impl;
+ return transform;
+ }
+
+ LogTransform::~LogTransform()
+ {
+ delete m_impl;
+ m_impl = NULL;
+ }
+
+ LogTransform& LogTransform::operator= (const LogTransform & rhs)
+ {
+ *m_impl = *rhs.m_impl;
+ return *this;
+ }
+
+ TransformDirection LogTransform::getDirection() const
+ {
+ return getImpl()->dir_;
+ }
+
+ void LogTransform::setDirection(TransformDirection dir)
+ {
+ getImpl()->dir_ = dir;
+ }
+
+
+ float LogTransform::getBase() const
+ {
+ return getImpl()->base_;
+ }
+
+ void LogTransform::setBase(float val)
+ {
+ getImpl()->base_ = val;
+ }
+
+ std::ostream& operator<< (std::ostream& os, const LogTransform& t)
+ {
+ os << "<LogTransform ";
+ os << "base=" << t.getBase() << ", ";
+ os << "direction=" << TransformDirectionToString(t.getDirection()) << ", ";
+ os << ">\n";
+
+ return os;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ void BuildLogOps(OpRcPtrVec & ops,
+ const Config& /*config*/,
+ const LogTransform& transform,
+ TransformDirection dir)
+ {
+ TransformDirection combinedDir = CombineTransformDirections(dir,
+ transform.getDirection());
+
+ float basescalar = transform.getBase();
+ float base[3] = { basescalar, basescalar, basescalar };
+
+ float k[3] = { 1.0f, 1.0f, 1.0f };
+ float m[3] = { 1.0f, 1.0f, 1.0f };
+ float b[3] = { 0.0f, 0.0f, 0.0f };
+ float kb[3] = { 0.0f, 0.0f, 0.0f };
+
+ // output = k * log(mx+b, base) + kb
+ CreateLogOp(ops,
+ k, m, b, base, kb,
+ combinedDir);
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/Logging.cpp b/src/core/Logging.cpp
new file mode 100644
index 0000000..7846ac2
--- /dev/null
+++ b/src/core/Logging.cpp
@@ -0,0 +1,156 @@
+/*
+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 <cstdlib>
+#include <iostream>
+#include <sstream>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "Logging.h"
+#include "Mutex.h"
+#include "pystring/pystring.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ const char * OCIO_LOGGING_LEVEL_ENVVAR = "OCIO_LOGGING_LEVEL";
+ const LoggingLevel OCIO_DEFAULT_LOGGING_LEVEL = LOGGING_LEVEL_INFO;
+
+ Mutex g_logmutex;
+ LoggingLevel g_logginglevel = LOGGING_LEVEL_UNKNOWN;
+ bool g_initialized = false;
+ bool g_loggingOverride = false;
+
+ // You must manually acquire the logging mutex before calling this.
+ // This will set g_logginglevel, g_initialized, g_loggingOverride
+ void InitLogging()
+ {
+ if(g_initialized) return;
+
+ g_initialized = true;
+
+ char* levelstr = std::getenv(OCIO_LOGGING_LEVEL_ENVVAR);
+ if(levelstr)
+ {
+ g_loggingOverride = true;
+ g_logginglevel = LoggingLevelFromString(levelstr);
+
+ if(g_logginglevel == LOGGING_LEVEL_UNKNOWN)
+ {
+ std::cerr << "[OpenColorIO Warning]: Invalid $OCIO_LOGGING_LEVEL specified. ";
+ std::cerr << "Options: none (0), warning (1), info (2), debug (3)" << std::endl;
+ g_logginglevel = OCIO_DEFAULT_LOGGING_LEVEL;
+ }
+ }
+ else
+ {
+ g_logginglevel = OCIO_DEFAULT_LOGGING_LEVEL;
+ }
+ }
+ }
+
+ LoggingLevel GetLoggingLevel()
+ {
+ AutoMutex lock(g_logmutex);
+ InitLogging();
+
+ return g_logginglevel;
+ }
+
+ void SetLoggingLevel(LoggingLevel level)
+ {
+ AutoMutex lock(g_logmutex);
+ InitLogging();
+
+ // Calls to SetLoggingLevel are ignored if OCIO_LOGGING_LEVEL_ENVVAR
+ // is specified. This is to allow users to optionally debug OCIO at
+ // runtime even in applications that disable logging.
+
+ if(!g_loggingOverride)
+ {
+ g_logginglevel = level;
+ }
+ }
+
+ void LogWarning(const std::string & text)
+ {
+ AutoMutex lock(g_logmutex);
+ InitLogging();
+
+ if(g_logginglevel<LOGGING_LEVEL_WARNING) return;
+
+ std::vector<std::string> parts;
+ pystring::split( pystring::rstrip(text), parts, "\n");
+
+ for(unsigned int i=0; i<parts.size(); ++i)
+ {
+ std::cerr << "[OpenColorIO Warning]: " << parts[i] << std::endl;
+ }
+ }
+
+ void LogInfo(const std::string & text)
+ {
+ AutoMutex lock(g_logmutex);
+ InitLogging();
+
+ if(g_logginglevel<LOGGING_LEVEL_INFO) return;
+
+ std::vector<std::string> parts;
+ pystring::split( pystring::rstrip(text), parts, "\n");
+
+ for(unsigned int i=0; i<parts.size(); ++i)
+ {
+ std::cerr << "[OpenColorIO Info]: " << parts[i] << std::endl;
+ }
+ }
+
+ void LogDebug(const std::string & text)
+ {
+ AutoMutex lock(g_logmutex);
+ InitLogging();
+
+ if(g_logginglevel<LOGGING_LEVEL_DEBUG) return;
+
+ std::vector<std::string> parts;
+ pystring::split( pystring::rstrip(text), parts, "\n");
+
+ for(unsigned int i=0; i<parts.size(); ++i)
+ {
+ std::cerr << "[OpenColorIO Debug]: " << parts[i] << std::endl;
+ }
+ }
+
+ bool IsDebugLoggingEnabled()
+ {
+ return (GetLoggingLevel()>=LOGGING_LEVEL_DEBUG);
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/Logging.h b/src/core/Logging.h
new file mode 100644
index 0000000..173e642
--- /dev/null
+++ b/src/core/Logging.h
@@ -0,0 +1,47 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_LOGGING_H
+#define INCLUDED_OCIO_LOGGING_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include <string>
+
+OCIO_NAMESPACE_ENTER
+{
+ void LogWarning(const std::string & text);
+ void LogInfo(const std::string & text);
+ void LogDebug(const std::string & text);
+
+ bool IsDebugLoggingEnabled();
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/Look.cpp b/src/core/Look.cpp
new file mode 100644
index 0000000..fd1bfe7
--- /dev/null
+++ b/src/core/Look.cpp
@@ -0,0 +1,163 @@
+/*
+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 <cstring>
+#include <sstream>
+#include <vector>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+OCIO_NAMESPACE_ENTER
+{
+ LookRcPtr Look::Create()
+ {
+ return LookRcPtr(new Look(), &deleter);
+ }
+
+ void Look::deleter(Look* c)
+ {
+ delete c;
+ }
+
+ class Look::Impl
+ {
+ public:
+ std::string name_;
+ std::string processSpace_;
+ TransformRcPtr transform_;
+ TransformRcPtr inverseTransform_;
+
+ Impl()
+ { }
+
+ ~Impl()
+ { }
+
+ Impl& operator= (const Impl & rhs)
+ {
+ name_ = rhs.name_;
+ processSpace_ = rhs.processSpace_;
+
+ transform_ = rhs.transform_;
+ if(transform_) transform_ = transform_->createEditableCopy();
+
+ inverseTransform_ = rhs.inverseTransform_;
+ if(inverseTransform_) inverseTransform_ = inverseTransform_->createEditableCopy();
+
+ return *this;
+ }
+ };
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+
+ Look::Look()
+ : m_impl(new Look::Impl)
+ {
+ }
+
+ Look::~Look()
+ {
+ delete m_impl;
+ m_impl = NULL;
+ }
+
+ LookRcPtr Look::createEditableCopy() const
+ {
+ LookRcPtr cs = Look::Create();
+ *cs->m_impl = *m_impl;
+ return cs;
+ }
+
+ const char * Look::getName() const
+ {
+ return getImpl()->name_.c_str();
+ }
+
+ void Look::setName(const char * name)
+ {
+ getImpl()->name_ = name;
+ }
+
+ const char * Look::getProcessSpace() const
+ {
+ return getImpl()->processSpace_.c_str();
+ }
+
+ void Look::setProcessSpace(const char * processSpace)
+ {
+ getImpl()->processSpace_ = processSpace;
+ }
+
+ ConstTransformRcPtr Look::getTransform() const
+ {
+ return getImpl()->transform_;
+ }
+
+ void Look::setTransform(const ConstTransformRcPtr & transform)
+ {
+ getImpl()->transform_ = transform->createEditableCopy();
+ }
+
+ ConstTransformRcPtr Look::getInverseTransform() const
+ {
+ return getImpl()->inverseTransform_;
+ }
+
+ void Look::setInverseTransform(const ConstTransformRcPtr & transform)
+ {
+ getImpl()->inverseTransform_ = transform->createEditableCopy();
+ }
+
+
+ std::ostream& operator<< (std::ostream& os, const Look& look)
+ {
+ os << "<Look ";
+ os << "name=" << look.getName() << ", ";
+ os << "processSpace=" << look.getProcessSpace() << ", ";
+
+ if(look.getTransform())
+ {
+ os << "\tTransform: ";
+ os << *look.getTransform();
+ }
+
+ if(look.getInverseTransform())
+ {
+ os << "\tInverseTransform: ";
+ os << *look.getInverseTransform();
+ }
+
+ os << ">";
+
+ return os;
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/LookParse.cpp b/src/core/LookParse.cpp
new file mode 100644
index 0000000..3c6db03
--- /dev/null
+++ b/src/core/LookParse.cpp
@@ -0,0 +1,309 @@
+/*
+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 "LookParse.h"
+#include "ParseUtils.h"
+#include "pystring/pystring.h"
+#include <iostream>
+
+OCIO_NAMESPACE_ENTER
+{
+ void LookParseResult::Token::parse(const std::string & str)
+ {
+ // Assert no commas, colons, or | in str.
+
+ if(pystring::startswith(str, "+"))
+ {
+ name = pystring::lstrip(str, "+");
+ dir = TRANSFORM_DIR_FORWARD;
+ }
+ // TODO: Handle --
+ else if(pystring::startswith(str, "-"))
+ {
+ name = pystring::lstrip(str, "-");
+ dir = TRANSFORM_DIR_INVERSE;
+ }
+ else
+ {
+ name = str;
+ dir = TRANSFORM_DIR_FORWARD;
+ }
+ }
+
+ void LookParseResult::Token::serialize(std::ostream & os) const
+ {
+ if(dir==TRANSFORM_DIR_FORWARD)
+ {
+ os << name;
+ }
+ else if(dir==TRANSFORM_DIR_INVERSE)
+ {
+ os << "-" << name;
+ }
+ else
+ {
+ os << "?" << name;
+ }
+ }
+
+ void LookParseResult::serialize(std::ostream & os, const Tokens & tokens)
+ {
+ for(unsigned int i=0; i<tokens.size(); ++i)
+ {
+ if(i!=0) os << ", ";
+ tokens[i].serialize(os);
+ }
+ }
+
+ const LookParseResult::Options & LookParseResult::parse(const std::string & looksstr)
+ {
+ m_options.clear();
+
+ std::string strippedlooks = pystring::strip(looksstr);
+ if(strippedlooks.empty())
+ {
+ return m_options;
+ }
+
+ std::vector<std::string> options;
+ pystring::split(strippedlooks, options, "|");
+
+ std::vector<std::string> vec;
+
+ for(unsigned int optionsindex=0;
+ optionsindex<options.size();
+ ++optionsindex)
+ {
+ LookParseResult::Tokens tokens;
+
+ vec.clear();
+ SplitStringEnvStyle(vec, options[optionsindex].c_str());
+ for(unsigned int i=0; i<vec.size(); ++i)
+ {
+ LookParseResult::Token t;
+ t.parse(vec[i]);
+ tokens.push_back(t);
+ }
+
+ m_options.push_back(tokens);
+ }
+
+ return m_options;
+ }
+
+ const LookParseResult::Options & LookParseResult::getOptions() const
+ {
+ return m_options;
+ }
+
+ bool LookParseResult::empty() const
+ {
+ return m_options.empty();
+ }
+
+ void LookParseResult::reverse()
+ {
+ // m_options itself should NOT be reversed.
+ // The individual looks
+ // need to be applied in the inverse direction. But, the precedence
+ // for which option to apply is to be maintained!
+
+ for(unsigned int optionindex=0;
+ optionindex<m_options.size();
+ ++optionindex)
+ {
+ std::reverse(m_options[optionindex].begin(), m_options[optionindex].end());
+
+ for(unsigned int tokenindex=0;
+ tokenindex<m_options[optionindex].size();
+ ++tokenindex)
+ {
+ m_options[optionindex][tokenindex].dir =
+ GetInverseTransformDirection(
+ m_options[optionindex][tokenindex].dir);
+ }
+ }
+ }
+}
+OCIO_NAMESPACE_EXIT
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef OCIO_UNIT_TEST
+
+OCIO_NAMESPACE_USING
+
+#include "UnitTest.h"
+
+OIIO_ADD_TEST(LookParse, Parse)
+{
+ LookParseResult r;
+
+ {
+ const LookParseResult::Options & options = r.parse("");
+ OIIO_CHECK_EQUAL(options.size(), 0);
+ OIIO_CHECK_EQUAL(options.empty(), true);
+ }
+
+ {
+ const LookParseResult::Options & options = r.parse(" ");
+ OIIO_CHECK_EQUAL(options.size(), 0);
+ OIIO_CHECK_EQUAL(options.empty(), true);
+ }
+
+ {
+ const LookParseResult::Options & options = r.parse("cc");
+ OIIO_CHECK_EQUAL(options.size(), 1);
+ OIIO_CHECK_EQUAL(options[0][0].name, "cc");
+ OIIO_CHECK_EQUAL(options[0][0].dir, TRANSFORM_DIR_FORWARD);
+ OIIO_CHECK_EQUAL(options.empty(), false);
+ }
+
+ {
+ const LookParseResult::Options & options = r.parse("+cc");
+ OIIO_CHECK_EQUAL(options.size(), 1);
+ OIIO_CHECK_EQUAL(options[0][0].name, "cc");
+ OIIO_CHECK_EQUAL(options[0][0].dir, TRANSFORM_DIR_FORWARD);
+ OIIO_CHECK_EQUAL(options.empty(), false);
+ }
+
+ {
+ const LookParseResult::Options & options = r.parse(" +cc");
+ OIIO_CHECK_EQUAL(options.size(), 1);
+ OIIO_CHECK_EQUAL(options[0][0].name, "cc");
+ OIIO_CHECK_EQUAL(options[0][0].dir, TRANSFORM_DIR_FORWARD);
+ OIIO_CHECK_EQUAL(options.empty(), false);
+ }
+
+ {
+ const LookParseResult::Options & options = r.parse(" +cc ");
+ OIIO_CHECK_EQUAL(options.size(), 1);
+ OIIO_CHECK_EQUAL(options[0][0].name, "cc");
+ OIIO_CHECK_EQUAL(options[0][0].dir, TRANSFORM_DIR_FORWARD);
+ OIIO_CHECK_EQUAL(options.empty(), false);
+ }
+
+ {
+ const LookParseResult::Options & options = r.parse("+cc,-di");
+ OIIO_CHECK_EQUAL(options.size(), 1);
+ OIIO_CHECK_EQUAL(options[0].size(), 2);
+ OIIO_CHECK_EQUAL(options[0][0].name, "cc");
+ OIIO_CHECK_EQUAL(options[0][0].dir, TRANSFORM_DIR_FORWARD);
+ OIIO_CHECK_EQUAL(options[0][1].name, "di");
+ OIIO_CHECK_EQUAL(options[0][1].dir, TRANSFORM_DIR_INVERSE);
+ OIIO_CHECK_EQUAL(options.empty(), false);
+ }
+
+ {
+ const LookParseResult::Options & options = r.parse(" +cc , -di");
+ OIIO_CHECK_EQUAL(options.size(), 1);
+ OIIO_CHECK_EQUAL(options[0].size(), 2);
+ OIIO_CHECK_EQUAL(options[0][0].name, "cc");
+ OIIO_CHECK_EQUAL(options[0][0].dir, TRANSFORM_DIR_FORWARD);
+ OIIO_CHECK_EQUAL(options[0][1].name, "di");
+ OIIO_CHECK_EQUAL(options[0][1].dir, TRANSFORM_DIR_INVERSE);
+ OIIO_CHECK_EQUAL(options.empty(), false);
+ }
+
+ {
+ const LookParseResult::Options & options = r.parse(" +cc : -di");
+ OIIO_CHECK_EQUAL(options.size(), 1);
+ OIIO_CHECK_EQUAL(options[0].size(), 2);
+ OIIO_CHECK_EQUAL(options[0][0].name, "cc");
+ OIIO_CHECK_EQUAL(options[0][0].dir, TRANSFORM_DIR_FORWARD);
+ OIIO_CHECK_EQUAL(options[0][1].name, "di");
+ OIIO_CHECK_EQUAL(options[0][1].dir, TRANSFORM_DIR_INVERSE);
+ OIIO_CHECK_EQUAL(options.empty(), false);
+ }
+
+ {
+ const LookParseResult::Options & options = r.parse("+cc, -di |-cc");
+ OIIO_CHECK_EQUAL(options.size(), 2);
+ OIIO_CHECK_EQUAL(options[0].size(), 2);
+ OIIO_CHECK_EQUAL(options[0][0].name, "cc");
+ OIIO_CHECK_EQUAL(options[0][0].dir, TRANSFORM_DIR_FORWARD);
+ OIIO_CHECK_EQUAL(options[0][1].name, "di");
+ OIIO_CHECK_EQUAL(options[0][1].dir, TRANSFORM_DIR_INVERSE);
+ OIIO_CHECK_EQUAL(options[1].size(), 1);
+ OIIO_CHECK_EQUAL(options.empty(), false);
+ OIIO_CHECK_EQUAL(options[1][0].name, "cc");
+ OIIO_CHECK_EQUAL(options[1][0].dir, TRANSFORM_DIR_INVERSE);
+ }
+
+ {
+ const LookParseResult::Options & options = r.parse("+cc, -di |-cc| ");
+ OIIO_CHECK_EQUAL(options.size(), 3);
+ OIIO_CHECK_EQUAL(options[0].size(), 2);
+ OIIO_CHECK_EQUAL(options[0][0].name, "cc");
+ OIIO_CHECK_EQUAL(options[0][0].dir, TRANSFORM_DIR_FORWARD);
+ OIIO_CHECK_EQUAL(options[0][1].name, "di");
+ OIIO_CHECK_EQUAL(options[0][1].dir, TRANSFORM_DIR_INVERSE);
+ OIIO_CHECK_EQUAL(options[1].size(), 1);
+ OIIO_CHECK_EQUAL(options.empty(), false);
+ OIIO_CHECK_EQUAL(options[1][0].name, "cc");
+ OIIO_CHECK_EQUAL(options[1][0].dir, TRANSFORM_DIR_INVERSE);
+ OIIO_CHECK_EQUAL(options[2].size(), 1);
+ OIIO_CHECK_EQUAL(options[2][0].name, "");
+ OIIO_CHECK_EQUAL(options[2][0].dir, TRANSFORM_DIR_FORWARD);
+ }
+}
+
+OIIO_ADD_TEST(LookParse, Reverse)
+{
+ LookParseResult r;
+
+ {
+ r.parse("+cc, -di |-cc| ");
+ r.reverse();
+ const LookParseResult::Options & options = r.getOptions();
+
+ OIIO_CHECK_EQUAL(options.size(), 3);
+ OIIO_CHECK_EQUAL(options[0].size(), 2);
+ OIIO_CHECK_EQUAL(options[0][1].name, "cc");
+ OIIO_CHECK_EQUAL(options[0][1].dir, TRANSFORM_DIR_INVERSE);
+ OIIO_CHECK_EQUAL(options[0][0].name, "di");
+ OIIO_CHECK_EQUAL(options[0][0].dir, TRANSFORM_DIR_FORWARD);
+ OIIO_CHECK_EQUAL(options[1].size(), 1);
+ OIIO_CHECK_EQUAL(options.empty(), false);
+ OIIO_CHECK_EQUAL(options[1][0].name, "cc");
+ OIIO_CHECK_EQUAL(options[1][0].dir, TRANSFORM_DIR_FORWARD);
+ OIIO_CHECK_EQUAL(options[2].size(), 1);
+ OIIO_CHECK_EQUAL(options[2][0].name, "");
+ OIIO_CHECK_EQUAL(options[2][0].dir, TRANSFORM_DIR_INVERSE);
+ }
+
+
+}
+
+#endif // OCIO_UNIT_TEST
diff --git a/src/core/LookParse.h b/src/core/LookParse.h
new file mode 100644
index 0000000..e867ce7
--- /dev/null
+++ b/src/core/LookParse.h
@@ -0,0 +1,79 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_PARSED_LOOK_H
+#define INCLUDED_OCIO_PARSED_LOOK_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include <vector>
+
+OCIO_NAMESPACE_ENTER
+{
+ // Looks parse structures
+ // This is contains a list, where each option entry corresponds to
+ // an "or" separated looks token list.
+ // I.e, " +cc,-onset | +cc " parses to TWO options: (+cc,-onset), (+cc)
+
+ class LookParseResult
+ {
+ public:
+ struct Token
+ {
+ std::string name;
+ TransformDirection dir;
+
+ Token():
+ dir(TRANSFORM_DIR_FORWARD) {}
+
+ void parse(const std::string & str);
+ void serialize(std::ostream & os) const;
+ };
+
+ typedef std::vector<Token> Tokens;
+
+ static void serialize(std::ostream & os, const Tokens & tokens);
+
+ typedef std::vector<Tokens> Options;
+
+ const Options & parse(const std::string & looksstr);
+
+ const Options & getOptions() const;
+ bool empty() const;
+
+ void reverse();
+
+ private:
+ Options m_options;
+ };
+
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
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
diff --git a/src/core/Lut1DOp.cpp b/src/core/Lut1DOp.cpp
new file mode 100644
index 0000000..8363536
--- /dev/null
+++ b/src/core/Lut1DOp.cpp
@@ -0,0 +1,1038 @@
+/*
+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 "HashUtils.h"
+#include "Lut1DOp.h"
+#include "MathUtils.h"
+#include "SSE.h"
+
+#include <algorithm>
+#include <cmath>
+#include <sstream>
+#include <iostream>
+
+OCIO_NAMESPACE_ENTER
+{
+ Lut1D::Lut1D() :
+ maxerror(std::numeric_limits<float>::min()),
+ errortype(ERROR_RELATIVE)
+ {
+ for(int i=0; i<3; ++i)
+ {
+ from_min[i] = 0.0f;
+ from_max[i] = 1.0f;
+ }
+ }
+
+ Lut1DRcPtr Lut1D::Create()
+ {
+ return Lut1DRcPtr(new Lut1D());
+ }
+
+
+ namespace
+ {
+ bool IsLut1DNoOp(const Lut1D & lut,
+ float maxerror,
+ ErrorType errortype)
+ {
+ // If tolerance not positive, skip the check.
+ if(!(maxerror > 0.0)) return false;
+
+ for(int channel = 0; channel<3; ++channel)
+ {
+ if(lut.luts[channel].size() == 0) continue;
+
+ float inorm = 1.0f / (static_cast<float>(lut.luts[channel].size()) - 1.0f);
+
+ float m = lut.from_max[channel] - lut.from_min[channel];
+ float b = lut.from_min[channel];
+
+ for(unsigned int i=0; i<lut.luts[channel].size(); ++i)
+ {
+ float x = static_cast<float>(i) * inorm;
+ float identval = m*x+b;
+ float lutval = lut.luts[channel][i];
+
+ if(errortype == ERROR_ABSOLUTE)
+ {
+ if(!equalWithAbsError(identval, lutval, maxerror))
+ {
+ return false;
+ }
+ }
+ else if(errortype == ERROR_RELATIVE)
+ {
+ if(!equalWithRelError(identval, lutval, maxerror))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ throw Exception("Unknown error type.");
+ }
+ }
+ }
+
+ return true;
+ }
+ }
+
+ std::string Lut1D::getCacheID() const
+ {
+ AutoMutex lock(m_mutex);
+
+ if(luts[0].empty() || luts[1].empty() || luts[2].empty())
+ throw Exception("Cannot compute cacheID of invalid Lut1D");
+
+ if(!m_cacheID.empty())
+ return m_cacheID;
+
+ finalize();
+ return m_cacheID;
+ }
+
+ bool Lut1D::isNoOp() const
+ {
+ AutoMutex lock(m_mutex);
+
+ if(luts[0].empty() || luts[1].empty() || luts[2].empty())
+ throw Exception("Cannot compute noOp of invalid Lut1D");
+
+ if(!m_cacheID.empty())
+ return m_isNoOp;
+
+ finalize();
+
+ return m_isNoOp;
+ }
+
+ void Lut1D::unfinalize()
+ {
+ AutoMutex lock(m_mutex);
+ m_cacheID = "";
+ m_isNoOp = false;
+ }
+
+ void Lut1D::finalize() const
+ {
+ m_isNoOp = IsLut1DNoOp(*this, maxerror, errortype);
+
+ if(m_isNoOp)
+ {
+ m_cacheID = "<NULL 1D>";
+ }
+ else
+ {
+ md5_state_t state;
+ md5_byte_t digest[16];
+
+ md5_init(&state);
+ md5_append(&state, (const md5_byte_t *)from_min, 3*sizeof(float));
+ md5_append(&state, (const md5_byte_t *)from_max, 3*sizeof(float));
+
+ for(int i=0; i<3; ++i)
+ {
+ md5_append( &state, (const md5_byte_t *)&(luts[i][0]),
+ (int) (luts[i].size()*sizeof(float)) );
+ }
+
+ md5_finish(&state, digest);
+
+ m_cacheID = GetPrintableHash(digest);
+ }
+ }
+
+
+ namespace
+ {
+ // Note: This function assumes that minVal is less than maxVal
+ inline int clamp(float k, float minVal, float maxVal)
+ {
+ return static_cast<int>(roundf(std::max(std::min(k, maxVal), minVal)));
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////
+ // Nearest Forward
+
+ inline float lookupNearest_1D(float index, float maxIndex, const float * simple_lut)
+ {
+ return simple_lut[clamp(index, 0.0f, maxIndex)];
+ }
+
+ void Lut1D_Nearest(float* rgbaBuffer, long numPixels, const Lut1D & lut)
+ {
+ float maxIndex[3];
+ float mInv[3];
+ float b[3];
+ float mInv_x_maxIndex[3];
+ const float* startPos[3];
+
+ for(int i=0; i<3; ++i)
+ {
+ maxIndex[i] = (float) (lut.luts[i].size() - 1);
+ mInv[i] = 1.0f / (lut.from_max[i] - lut.from_min[i]);
+ b[i] = lut.from_min[i];
+ mInv_x_maxIndex[i] = (float) (mInv[i] * maxIndex[i]);
+ startPos[i] = &(lut.luts[i][0]);
+ }
+
+ for(long pixelIndex=0; pixelIndex<numPixels; ++pixelIndex)
+ {
+ if(!isnan(rgbaBuffer[0]))
+ rgbaBuffer[0] = lookupNearest_1D(mInv_x_maxIndex[0] * (rgbaBuffer[0] - b[0]), maxIndex[0], startPos[0]);
+ if(!isnan(rgbaBuffer[1]))
+ rgbaBuffer[1] = lookupNearest_1D(mInv_x_maxIndex[1] * (rgbaBuffer[1] - b[1]), maxIndex[1], startPos[1]);
+ if(!isnan(rgbaBuffer[2]))
+ rgbaBuffer[2] = lookupNearest_1D(mInv_x_maxIndex[2] * (rgbaBuffer[2] - b[2]), maxIndex[2], startPos[2]);
+
+ rgbaBuffer += 4;
+ }
+ }
+#ifdef USE_SSE
+ void Lut1D_Nearest_SSE(float* rgbaBuffer, long numPixels, const Lut1D & lut)
+ {
+ // orig: 546 ms
+ // curr: 91 ms
+
+ // These are all sized 4, to allow simpler sse loading
+ float maxIndex[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float mInv[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float b[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float mInv_x_maxIndex[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ const float* startPos[3];
+
+ for(int i=0; i<3; ++i)
+ {
+ maxIndex[i] = (float) (lut.luts[i].size() - 1);
+ mInv[i] = 1.0f / (lut.from_max[i] - lut.from_min[i]);
+ b[i] = lut.from_min[i];
+ mInv_x_maxIndex[i] = (float) (mInv[i] * maxIndex[i]);
+ startPos[i] = &(lut.luts[i][0]);
+ }
+
+ const __m128 _zero = _mm_setzero_ps();
+ const __m128 _mInv_x_maxIndex = _mm_loadu_ps(mInv_x_maxIndex);
+ const __m128 _b = _mm_loadu_ps(b);
+ const __m128 _maxIndex = _mm_loadu_ps(maxIndex);
+ const __m128 _half = _mm_set1_ps(0.5f);
+
+ float result[4];
+
+ for(long pixelIndex=0; pixelIndex<numPixels; ++pixelIndex)
+ {
+ // TODO: SSE Optimized nancheck
+
+ __m128 p = _mm_loadu_ps(rgbaBuffer);
+
+ // mInv_x_maxIndex * (p - b)
+ p = _mm_sub_ps(p, _b);
+ p = _mm_mul_ps(p, _mInv_x_maxIndex);
+
+ // clamp _zero <= b <= _maxIndex
+ p = _mm_max_ps(p, _zero);
+ p = _mm_min_ps(p, _maxIndex);
+
+ // add 0.5f for rounding
+ p = _mm_add_ps(p, _half);
+
+ _mm_storeu_ps(result, p);
+
+
+ // TODO: use native SSE to convert to an int?
+ // _mm_cvttss_si32
+ // Converts the lower single-precision, floating-point value of
+ // a to a 32-bit integer with truncation
+ //
+ // _mm_cvttps_pi32 converts 2 floats to 2 32-bit packed ints,
+ // with truncation
+
+ if(!isnan(result[0]))
+ rgbaBuffer[0] = startPos[0][(int)(result[0])];
+ if(!isnan(result[1]))
+ rgbaBuffer[1] = startPos[1][(int)(result[1])];
+ if(!isnan(result[2]))
+ rgbaBuffer[2] = startPos[2][(int)(result[2])];
+
+ rgbaBuffer += 4;
+ }
+ }
+#endif
+
+
+ ///////////////////////////////////////////////////////////////////////
+ // Linear Forward
+
+ inline float lookupLinear_1D(float index, float maxIndex, const float * simple_lut)
+ {
+ int indexLow = clamp(std::floor(index), 0.0f, maxIndex);
+ int indexHigh = clamp(std::ceil(index), 0.0f, maxIndex);
+ float delta = index - (float)indexLow;
+ return (1.0f-delta) * simple_lut[indexLow] + delta * simple_lut[indexHigh];
+ }
+
+ void Lut1D_Linear(float* rgbaBuffer, long numPixels, const Lut1D & lut)
+ {
+ float maxIndex[3];
+ float mInv[3];
+ float b[3];
+ float mInv_x_maxIndex[3];
+ const float* startPos[3];
+
+ for(int i=0; i<3; ++i)
+ {
+ maxIndex[i] = (float) (lut.luts[i].size() - 1);
+ mInv[i] = 1.0f / (lut.from_max[i] - lut.from_min[i]);
+ b[i] = lut.from_min[i];
+ mInv_x_maxIndex[i] = (float) (mInv[i] * maxIndex[i]);
+ startPos[i] = &(lut.luts[i][0]);
+ }
+
+ for(long pixelIndex=0; pixelIndex<numPixels; ++pixelIndex)
+ {
+ if(!isnan(rgbaBuffer[0]))
+ rgbaBuffer[0] = lookupLinear_1D(mInv_x_maxIndex[0] * (rgbaBuffer[0] - b[0]), maxIndex[0], startPos[0]);
+ if(!isnan(rgbaBuffer[1]))
+ rgbaBuffer[1] = lookupLinear_1D(mInv_x_maxIndex[1] * (rgbaBuffer[1] - b[1]), maxIndex[1], startPos[1]);
+ if(!isnan(rgbaBuffer[2]))
+ rgbaBuffer[2] = lookupLinear_1D(mInv_x_maxIndex[2] * (rgbaBuffer[2] - b[2]), maxIndex[2], startPos[2]);
+
+ rgbaBuffer += 4;
+ }
+ }
+
+
+
+ ///////////////////////////////////////////////////////////////////////
+ // Nearest Inverse
+
+ inline float reverseLookupNearest_1D(const float v, const float *start, const float *end)
+ {
+ const float *lowbound = std::lower_bound(start, end, v);
+ if (lowbound != start) --lowbound;
+
+ const float *highbound = lowbound;
+ if (highbound < end - 1) ++highbound;
+
+ // NOTE: Not dividing result by /(size-1) anymore
+ if (fabsf(v - *lowbound) < fabsf(v - *highbound))
+ {
+ return (float)(lowbound-start);
+ }
+ else
+ {
+ return (float)(highbound-start);
+ }
+ }
+
+ void Lut1D_NearestInverse(float* rgbaBuffer, long numPixels, const Lut1D & lut)
+ {
+ float m[3];
+ float b[3];
+ const float* startPos[3];
+ const float* endPos[3];
+
+ for(int i=0; i<3; ++i)
+ {
+ m[i] = (lut.from_max[i] - lut.from_min[i]);
+ b[i] = lut.from_min[i];
+
+ startPos[i] = &(lut.luts[i][0]);
+ endPos[i] = startPos[i] + lut.luts[i].size();
+
+ // Roll the size division into m as an optimization
+ m[i] /= (float) (lut.luts[i].size() - 1);
+ }
+
+ for(long pixelIndex=0; pixelIndex<numPixels; ++pixelIndex)
+ {
+ if(!isnan(rgbaBuffer[0]))
+ rgbaBuffer[0] = m[0] * reverseLookupNearest_1D(rgbaBuffer[0], startPos[0], endPos[0]) + b[0];
+ if(!isnan(rgbaBuffer[1]))
+ rgbaBuffer[1] = m[1] * reverseLookupNearest_1D(rgbaBuffer[1], startPos[1], endPos[1]) + b[1];
+ if(!isnan(rgbaBuffer[2]))
+ rgbaBuffer[2] = m[2] * reverseLookupNearest_1D(rgbaBuffer[2], startPos[2], endPos[2]) + b[2];
+
+ rgbaBuffer += 4;
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // Linear Inverse
+
+ inline float reverseLookupLinear_1D(const float v, const float *start, const float *end, float invMaxIndex)
+ {
+ const float *lowbound = std::lower_bound(start, end, v);
+ if (lowbound != start) --lowbound;
+
+ const float *highbound = lowbound;
+ if (highbound < end - 1) ++highbound;
+
+ // lowbound is the lower bound, highbound is the upper bound.
+ float delta = 0.0;
+ if (*highbound > *lowbound)
+ {
+ delta = (v - *lowbound) / (*highbound - *lowbound);
+ }
+
+ return ((float)(lowbound - start) + delta) * invMaxIndex;
+ }
+
+ void Lut1D_LinearInverse(float* rgbaBuffer, long numPixels, const Lut1D & lut)
+ {
+ float m[3];
+ float b[3];
+ const float* startPos[3];
+ const float* endPos[3];
+ float invMaxIndex[3];
+
+ for(int i=0; i<3; ++i)
+ {
+ m[i] = (lut.from_max[i] - lut.from_min[i]);
+ b[i] = lut.from_min[i];
+
+ startPos[i] = &(lut.luts[i][0]);
+ endPos[i] = startPos[i] + lut.luts[i].size();
+
+ invMaxIndex[i] = 1.0f / (float) (lut.luts[i].size() - 1);
+ }
+
+ for(long pixelIndex=0; pixelIndex<numPixels; ++pixelIndex)
+ {
+ if(!isnan(rgbaBuffer[0]))
+ rgbaBuffer[0] = m[0] * reverseLookupLinear_1D(rgbaBuffer[0], startPos[0], endPos[0], invMaxIndex[0]) + b[0];
+ if(!isnan(rgbaBuffer[1]))
+ rgbaBuffer[1] = m[1] * reverseLookupLinear_1D(rgbaBuffer[1], startPos[1], endPos[1], invMaxIndex[0]) + b[1];
+ if(!isnan(rgbaBuffer[2]))
+ rgbaBuffer[2] = m[2] * reverseLookupLinear_1D(rgbaBuffer[2], startPos[2], endPos[2], invMaxIndex[0]) + b[2];
+
+ rgbaBuffer += 4;
+ }
+ }
+
+
+ }
+
+ namespace
+ {
+ class Lut1DOp : public Op
+ {
+ public:
+ Lut1DOp(const Lut1DRcPtr & lut,
+ Interpolation interpolation,
+ TransformDirection direction);
+ virtual ~Lut1DOp();
+
+ virtual OpRcPtr clone() const;
+
+ virtual std::string getInfo() const;
+ virtual std::string getCacheID() const;
+
+ virtual bool isNoOp() const;
+ virtual bool isSameType(const OpRcPtr & op) const;
+ virtual bool isInverse(const OpRcPtr & op) const;
+ virtual bool hasChannelCrosstalk() const;
+ virtual void finalize();
+ virtual void apply(float* rgbaBuffer, long numPixels) const;
+
+ virtual bool supportsGpuShader() const;
+ virtual void writeGpuShader(std::ostream & shader,
+ const std::string & pixelName,
+ const GpuShaderDesc & shaderDesc) const;
+
+ private:
+ const Lut1DRcPtr m_lut;
+ Interpolation m_interpolation;
+ TransformDirection m_direction;
+
+ std::string m_cacheID;
+ };
+
+ typedef OCIO_SHARED_PTR<Lut1DOp> Lut1DOpRcPtr;
+
+
+ Lut1DOp::Lut1DOp(const Lut1DRcPtr & lut,
+ Interpolation interpolation,
+ TransformDirection direction):
+ Op(),
+ m_lut(lut),
+ m_interpolation(interpolation),
+ m_direction(direction)
+ {
+ }
+
+ OpRcPtr Lut1DOp::clone() const
+ {
+ OpRcPtr op = OpRcPtr(new Lut1DOp(m_lut, m_interpolation, m_direction));
+ return op;
+ }
+
+ Lut1DOp::~Lut1DOp()
+ { }
+
+ std::string Lut1DOp::getInfo() const
+ {
+ return "<Lut1DOp>";
+ }
+
+ std::string Lut1DOp::getCacheID() const
+ {
+ return m_cacheID;
+ }
+
+ // TODO: compute real value for isNoOp
+ bool Lut1DOp::isNoOp() const
+ {
+ return false;
+ }
+
+ bool Lut1DOp::isSameType(const OpRcPtr & op) const
+ {
+ Lut1DOpRcPtr typedRcPtr = DynamicPtrCast<Lut1DOp>(op);
+ if(!typedRcPtr) return false;
+ return true;
+ }
+
+ bool Lut1DOp::isInverse(const OpRcPtr & op) const
+ {
+ Lut1DOpRcPtr typedRcPtr = DynamicPtrCast<Lut1DOp>(op);
+ if(!typedRcPtr) return false;
+
+ if(GetInverseTransformDirection(m_direction) != typedRcPtr->m_direction)
+ return false;
+
+ return (m_lut->getCacheID() == typedRcPtr->m_lut->getCacheID());
+ }
+
+ bool Lut1DOp::hasChannelCrosstalk() const
+ {
+ return false;
+ }
+
+ void Lut1DOp::finalize()
+ {
+ if(m_direction == TRANSFORM_DIR_UNKNOWN)
+ {
+ throw Exception("Cannot apply lut1d op, unspecified transform direction.");
+ }
+
+ // Validate the requested interpolation type
+ switch(m_interpolation)
+ {
+ // These are the allowed values.
+ case INTERP_NEAREST:
+ case INTERP_LINEAR:
+ break;
+ case INTERP_BEST:
+ m_interpolation = INTERP_LINEAR;
+ break;
+ case INTERP_UNKNOWN:
+ throw Exception("Cannot apply Lut1DOp, unspecified interpolation.");
+ break;
+ case INTERP_TETRAHEDRAL:
+ throw Exception("Cannot apply Lut1DOp, tetrahedral interpolation is not allowed for 1d luts.");
+ break;
+ default:
+ throw Exception("Cannot apply Lut1DOp, invalid interpolation specified.");
+ }
+
+ if(m_lut->luts[0].empty() || m_lut->luts[1].empty() || m_lut->luts[2].empty())
+ {
+ throw Exception("Cannot apply lut1d op, no lut data provided.");
+ }
+
+ // Create the cacheID
+ std::ostringstream cacheIDStream;
+ cacheIDStream << "<Lut1DOp ";
+ cacheIDStream << m_lut->getCacheID() << " ";
+ cacheIDStream << InterpolationToString(m_interpolation) << " ";
+ cacheIDStream << TransformDirectionToString(m_direction) << " ";
+ cacheIDStream << ">";
+ m_cacheID = cacheIDStream.str();
+ }
+
+ void Lut1DOp::apply(float* rgbaBuffer, long numPixels) const
+ {
+ if(m_direction == TRANSFORM_DIR_FORWARD)
+ {
+ if(m_interpolation == INTERP_NEAREST)
+ {
+#ifdef USE_SSE
+ Lut1D_Nearest_SSE(rgbaBuffer, numPixels, *m_lut);
+#else
+ Lut1D_Nearest(rgbaBuffer, numPixels, *m_lut);
+#endif
+ }
+ else if(m_interpolation == INTERP_LINEAR)
+ {
+ Lut1D_Linear(rgbaBuffer, numPixels, *m_lut);
+ }
+ }
+ else if(m_direction == TRANSFORM_DIR_INVERSE)
+ {
+ if(m_interpolation == INTERP_NEAREST)
+ {
+ Lut1D_NearestInverse(rgbaBuffer, numPixels, *m_lut);
+ }
+ else if(m_interpolation == INTERP_LINEAR)
+ {
+ Lut1D_LinearInverse(rgbaBuffer, numPixels, *m_lut);
+ }
+ }
+ }
+
+ bool Lut1DOp::supportsGpuShader() const
+ {
+ return false;
+ }
+
+ void Lut1DOp::writeGpuShader(std::ostream & /*shader*/,
+ const std::string & /*pixelName*/,
+ const GpuShaderDesc & /*shaderDesc*/) const
+ {
+ throw Exception("Lut1DOp does not support analytical shader generation.");
+ }
+ }
+
+ void CreateLut1DOp(OpRcPtrVec & ops,
+ const Lut1DRcPtr & lut,
+ Interpolation interpolation,
+ TransformDirection direction)
+ {
+ if(lut->isNoOp()) return;
+
+ // TODO: Detect if lut1d can be exactly approximated as y = mx + b
+ // If so, return a mtx instead.
+
+ ops.push_back( OpRcPtr(new Lut1DOp(lut, interpolation, direction)) );
+ }
+
+
+ void GenerateIdentityLut1D(float* img, int numElements, int numChannels)
+ {
+ if(!img) return;
+ int numChannelsToFill = std::min(3, numChannels);
+
+ float scale = 1.0f / ((float) numElements - 1.0f);
+ for(int i=0; i<numElements; i++)
+ {
+ for(int c=0; c<numChannelsToFill; ++c)
+ {
+ img[numChannels*i+c] = scale * (float)(i);
+ }
+ }
+ }
+}
+OCIO_NAMESPACE_EXIT
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef OCIO_UNIT_TEST
+
+#include <cstring>
+
+namespace OCIO = OCIO_NAMESPACE;
+#include "UnitTest.h"
+
+OIIO_ADD_TEST(Lut1DOp, NoOp)
+{
+ // Make an identity lut
+ OCIO::Lut1DRcPtr lut = OCIO::Lut1D::Create();
+ lut->from_min[0] = 0.0f;
+ lut->from_min[1] = 0.0f;
+ lut->from_min[2] = 0.0f;
+
+ lut->from_max[0] = 1.0f;
+ lut->from_max[1] = 1.0f;
+ lut->from_max[2] = 1.0f;
+
+ int size = 256;
+ for(int i=0; i<size; ++i)
+ {
+ float x = (float)i / (float)(size-1);
+ for(int c=0; c<3; ++c)
+ {
+ lut->luts[c].push_back(x);
+ }
+ }
+
+ lut->maxerror = 1e-5f;
+ lut->errortype = OCIO::ERROR_RELATIVE;
+ OIIO_CHECK_EQUAL(lut->isNoOp(), true);
+
+ lut->unfinalize();
+ lut->maxerror = 1e-5f;
+ lut->errortype = OCIO::ERROR_ABSOLUTE;
+ OIIO_CHECK_EQUAL(lut->isNoOp(), true);
+
+ // Edit the lut
+ // These should NOT be identity
+ lut->unfinalize();
+ lut->luts[0][125] += 1e-3f;
+ lut->maxerror = 1e-5f;
+ lut->errortype = OCIO::ERROR_RELATIVE;
+ OIIO_CHECK_EQUAL(lut->isNoOp(), false);
+
+ lut->unfinalize();
+ lut->maxerror = 1e-5f;
+ lut->errortype = OCIO::ERROR_ABSOLUTE;
+ OIIO_CHECK_EQUAL(lut->isNoOp(), false);
+}
+
+
+OIIO_ADD_TEST(Lut1DOp, FiniteValue)
+{
+ // Make a lut that squares the input
+ OCIO::Lut1DRcPtr lut = OCIO::Lut1D::Create();
+ lut->from_min[0] = 0.0f;
+ lut->from_min[1] = 0.0f;
+ lut->from_min[2] = 0.0f;
+
+ lut->from_max[0] = 1.0f;
+ lut->from_max[1] = 1.0f;
+ lut->from_max[2] = 1.0f;
+
+ int size = 256;
+ for(int i=0; i<size; ++i)
+ {
+ float x = (float)i / (float)(size-1);
+ float x2 = x*x;
+
+ for(int c=0; c<3; ++c)
+ {
+ lut->luts[c].push_back(x2);
+ }
+ }
+
+ lut->maxerror = 1e-5f;
+ lut->errortype = OCIO::ERROR_RELATIVE;
+ OIIO_CHECK_EQUAL(lut->isNoOp(), false);
+
+ float inputBuffer_linearforward[4] = { 0.5f, 0.6f, 0.7f, 0.5f };
+ float outputBuffer_linearforward[4] = { 0.25f, 0.36f, 0.49f, 0.5f };
+ OCIO::Lut1D_Linear(inputBuffer_linearforward, 1, *lut);
+ for(int i=0; i <4; ++i)
+ {
+ OIIO_CHECK_CLOSE(inputBuffer_linearforward[i], outputBuffer_linearforward[i], 1e-5f);
+ }
+
+ float inputBuffer_nearestforward[4] = { 0.5f, 0.6f, 0.7f, 0.5f };
+ float outputBuffer_nearestforward[4] = { 0.25f, 0.36f, 0.49f, 0.5f };
+ OCIO::Lut1D_Nearest(inputBuffer_nearestforward, 1, *lut);
+ for(int i=0; i <4; ++i)
+ {
+ OIIO_CHECK_CLOSE(inputBuffer_nearestforward[i], outputBuffer_nearestforward[i], 1e-2f);
+ }
+
+ float inputBuffer_linearinverse[4] = { 0.5f, 0.6f, 0.7f, 0.5f };
+ float outputBuffer_linearinverse[4] = { 0.25f, 0.36f, 0.49f, 0.5f };
+ OCIO::Lut1D_LinearInverse(outputBuffer_linearinverse, 1, *lut);
+ for(int i=0; i <4; ++i)
+ {
+ OIIO_CHECK_CLOSE(inputBuffer_linearinverse[i], outputBuffer_linearinverse[i], 1e-5f);
+ }
+
+ float inputBuffer_nearestinverse[4] = { 0.5f, 0.6f, 0.7f, 0.5f };
+ float outputBuffer_nearestinverse[4] = { 0.25f, 0.36f, 0.49f, 0.5f };
+ OCIO::Lut1D_NearestInverse(outputBuffer_nearestinverse, 1, *lut);
+ for(int i=0; i <4; ++i)
+ {
+ OIIO_CHECK_CLOSE(inputBuffer_nearestinverse[i], outputBuffer_nearestinverse[i], 1e-2f);
+ }
+}
+
+
+OIIO_ADD_TEST(Lut1DOp, Inverse)
+{
+ // Make a lut that squares the input
+ OCIO::Lut1DRcPtr lut_a = OCIO::Lut1D::Create();
+ {
+ lut_a->from_min[0] = 0.0f;
+ lut_a->from_min[1] = 0.0f;
+ lut_a->from_min[2] = 0.0f;
+ lut_a->from_max[0] = 1.0f;
+ lut_a->from_max[1] = 1.0f;
+ lut_a->from_max[2] = 1.0f;
+ int size = 256;
+ for(int i=0; i<size; ++i)
+ {
+ float x = (float)i / (float)(size-1);
+ float x2 = x*x;
+
+ for(int c=0; c<3; ++c)
+ {
+ lut_a->luts[c].push_back(x2);
+ }
+ }
+ lut_a->maxerror = 1e-5f;
+ lut_a->errortype = OCIO::ERROR_RELATIVE;
+ }
+
+ // Make another lut
+ OCIO::Lut1DRcPtr lut_b = OCIO::Lut1D::Create();
+ {
+ lut_b->from_min[0] = 0.5f;
+ lut_b->from_min[1] = 0.6f;
+ lut_b->from_min[2] = 0.7f;
+ lut_b->from_max[0] = 1.0f;
+ lut_b->from_max[1] = 1.0f;
+ lut_b->from_max[2] = 1.0f;
+ int size = 256;
+ for(int i=0; i<size; ++i)
+ {
+ float x = (float)i / (float)(size-1);
+ float x2 = x*x;
+
+ for(int c=0; c<3; ++c)
+ {
+ lut_b->luts[c].push_back(x2);
+ }
+ }
+ lut_b->maxerror = 1e-5f;
+ lut_b->errortype = OCIO::ERROR_RELATIVE;
+ }
+
+ OCIO::OpRcPtrVec ops;
+ CreateLut1DOp(ops, lut_a, OCIO::INTERP_NEAREST, OCIO::TRANSFORM_DIR_FORWARD);
+ CreateLut1DOp(ops, lut_a, OCIO::INTERP_LINEAR, OCIO::TRANSFORM_DIR_INVERSE);
+ CreateLut1DOp(ops, lut_b, OCIO::INTERP_LINEAR, OCIO::TRANSFORM_DIR_FORWARD);
+ CreateLut1DOp(ops, lut_b, OCIO::INTERP_LINEAR, OCIO::TRANSFORM_DIR_INVERSE);
+
+ OIIO_CHECK_EQUAL(ops.size(), 4);
+
+ OIIO_CHECK_ASSERT(ops[0]->isSameType(ops[1]));
+ OIIO_CHECK_ASSERT(ops[0]->isSameType(ops[2]));
+ OIIO_CHECK_ASSERT(ops[0]->isSameType(ops[3]->clone()));
+
+ OIIO_CHECK_EQUAL( ops[0]->isInverse(ops[1]), true);
+ OIIO_CHECK_EQUAL( ops[0]->isInverse(ops[2]), false);
+ OIIO_CHECK_EQUAL( ops[0]->isInverse(ops[2]), false);
+ OIIO_CHECK_EQUAL( ops[0]->isInverse(ops[3]), false);
+ OIIO_CHECK_EQUAL( ops[2]->isInverse(ops[3]), true);
+}
+
+
+#ifdef USE_SSE
+OIIO_ADD_TEST(Lut1DOp, SSE)
+{
+ // Make a lut that squares the input
+ OCIO::Lut1DRcPtr lut = OCIO::Lut1D::Create();
+ lut->from_min[0] = 0.0f;
+ lut->from_min[1] = 0.0f;
+ lut->from_min[2] = 0.0f;
+
+ lut->from_max[0] = 1.0f;
+ lut->from_max[1] = 1.0f;
+ lut->from_max[2] = 1.0f;
+
+ int size = 256;
+ for(int i=0; i<size; ++i)
+ {
+ float x = (float)i / (float)(size-1);
+ float x2 = x*x;
+
+ for(int c=0; c<3; ++c)
+ {
+ lut->luts[c].push_back(x2);
+ }
+ }
+
+ lut->maxerror = 1e-5f;
+ lut->errortype = OCIO::ERROR_RELATIVE;
+ OIIO_CHECK_EQUAL(lut->isNoOp(), false);
+
+ int NUM_TEST_PIXELS = 1024;
+ std::vector<float> testValues(NUM_TEST_PIXELS*4);
+ std::vector<float> outputBuffer_cpu(NUM_TEST_PIXELS*4);
+ std::vector<float> outputBuffer_sse(NUM_TEST_PIXELS*4);
+
+ float val = -1.0f;
+ float delta = 0.00123456789f;
+
+ for(int i=0; i<NUM_TEST_PIXELS*4; ++i)
+ {
+ testValues[i] = val;
+ val += delta;
+ }
+
+ memcpy(&outputBuffer_cpu[0], &testValues[0], testValues.size()*sizeof(float));
+ memcpy(&outputBuffer_sse[0], &testValues[0], testValues.size()*sizeof(float));
+
+ OCIO::Lut1D_Nearest(&outputBuffer_cpu[0], NUM_TEST_PIXELS, *lut);
+ OCIO::Lut1D_Nearest_SSE(&outputBuffer_sse[0], NUM_TEST_PIXELS, *lut);
+
+ for(int i=0; i<NUM_TEST_PIXELS*4; ++i)
+ {
+ OIIO_CHECK_CLOSE(outputBuffer_cpu[i], outputBuffer_sse[i], 1e-7f);
+ //OIIO_CHECK_EQUAL(outputBuffer_cpu[i], outputBuffer_sse[i]);
+ }
+
+
+ // Test special values
+ /*
+ NUM_TEST_PIXELS = 2;
+ testValues.resize(NUM_TEST_PIXELS*4);
+ outputBuffer_cpu.resize(NUM_TEST_PIXELS*4);
+ outputBuffer_sse.resize(NUM_TEST_PIXELS*4);
+
+ testValues[0] = std::numeric_limits<float>::signaling_NaN();
+ testValues[1] = std::numeric_limits<float>::quiet_NaN();
+ testValues[2] = -std::numeric_limits<float>::signaling_NaN();
+ testValues[3] = -std::numeric_limits<float>::signaling_NaN();
+
+ testValues[4] = std::numeric_limits<float>::infinity();
+ testValues[5] = -std::numeric_limits<float>::infinity();
+ testValues[6] = 0.0f;
+
+
+ memcpy(&outputBuffer_cpu[0], &testValues[0], testValues.size()*sizeof(float));
+ memcpy(&outputBuffer_sse[0], &testValues[0], testValues.size()*sizeof(float));
+
+ OCIO::Lut1D_Nearest(&outputBuffer_cpu[0], NUM_TEST_PIXELS, lut);
+ OCIO::Lut1D_Nearest_SSE(&outputBuffer_sse[0], NUM_TEST_PIXELS, lut);
+
+ for(int i=0; i<NUM_TEST_PIXELS*4; ++i)
+ {
+ //OIIO_CHECK_CLOSE(outputBuffer_cpu[i], outputBuffer_sse[i], 1e-7f);
+ OIIO_CHECK_EQUAL(outputBuffer_cpu[i], outputBuffer_sse[i]);
+ }
+
+ */
+}
+#endif
+
+
+OIIO_ADD_TEST(Lut1DOp, NanInf)
+{
+ // Make a lut that squares the input
+ OCIO::Lut1DRcPtr lut = OCIO::Lut1D::Create();
+ lut->from_min[0] = 0.0f;
+ lut->from_min[1] = 0.0f;
+ lut->from_min[2] = 0.0f;
+
+ lut->from_max[0] = 1.0f;
+ lut->from_max[1] = 1.0f;
+ lut->from_max[2] = 1.0f;
+
+ int size = 256;
+ for(int i=0; i<size; ++i)
+ {
+ float x = (float)i / (float)(size-1);
+ float x2 = x*x;
+
+ for(int c=0; c<3; ++c)
+ {
+ lut->luts[c].push_back(x2);
+ }
+ }
+
+ lut->maxerror = 1e-5f;
+ lut->errortype = OCIO::ERROR_RELATIVE;
+ OIIO_CHECK_EQUAL(lut->isNoOp(), false);
+
+ const float reference[4] = { std::numeric_limits<float>::signaling_NaN(),
+ std::numeric_limits<float>::quiet_NaN(),
+ std::numeric_limits<float>::infinity(),
+ -std::numeric_limits<float>::infinity() };
+ /*
+ float output[4] = { std::numeric_limits<float>::signaling_NaN(),
+ std::numeric_limits<float>::quiet_NaN(),
+ 1.0f,
+ -std::numeric_limits<float>::infinity() };
+ */
+ float color[4];
+
+ memcpy(color, reference, 4*sizeof(float));
+ OCIO::Lut1D_Linear(color, 1, *lut);
+ /*
+ for(int i=0; i<4; ++i)
+ {
+ if(isnan(color[i]))
+ {
+ std::cerr << color[i] << " " << output[i] << std::endl;
+ OIIO_CHECK_EQUAL(isnan(color[i]), isnan(output[i]));
+ }
+ else
+ {
+ OIIO_CHECK_EQUAL(color[i], output[i]);
+ }
+ }
+ */
+ memcpy(color, reference, 4*sizeof(float));
+ OCIO::Lut1D_Nearest(color, 1, *lut);
+ /*
+ for(int i=0; i <4; ++i)
+ {
+ if(isnan(color[i]))
+ {
+ OIIO_CHECK_EQUAL(isnan(color[i]), isnan(output[i]));
+ }
+ else
+ {
+ OIIO_CHECK_EQUAL(color[i], output[i]);
+ }
+ }
+ */
+ memcpy(color, reference, 4*sizeof(float));
+ OCIO::Lut1D_LinearInverse(color, 1, *lut);
+ /*
+ for(int i=0; i <4; ++i)
+ {
+ if(isnan(color[i]))
+ {
+ OIIO_CHECK_EQUAL(isnan(color[i]), isnan(output[i]));
+ }
+ else
+ {
+ OIIO_CHECK_EQUAL(color[i], output[i]);
+ }
+ }
+ */
+ memcpy(color, reference, 4*sizeof(float));
+ OCIO::Lut1D_NearestInverse(color, 1, *lut);
+ /*
+ for(int i=0; i <4; ++i)
+ {
+ if(isnan(color[i]))
+ {
+ OIIO_CHECK_EQUAL(isnan(color[i]), isnan(output[i]));
+ }
+ else
+ {
+ OIIO_CHECK_EQUAL(color[i], output[i]);
+ }
+ }
+ */
+}
+
+#endif // OCIO_UNIT_TEST
diff --git a/src/core/Lut1DOp.h b/src/core/Lut1DOp.h
new file mode 100644
index 0000000..d4d96c1
--- /dev/null
+++ b/src/core/Lut1DOp.h
@@ -0,0 +1,107 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_LUT1DOP_H
+#define INCLUDED_OCIO_LUT1DOP_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "Mutex.h"
+#include "Op.h"
+
+#include <vector>
+
+OCIO_NAMESPACE_ENTER
+{
+ // TODO: turn into a class instead of a struct?
+
+ enum ErrorType
+ {
+ ERROR_ABSOLUTE = 1,
+ ERROR_RELATIVE
+ };
+
+
+ struct Lut1D;
+ typedef OCIO_SHARED_PTR<Lut1D> Lut1DRcPtr;
+
+ struct Lut1D
+ {
+ static Lut1DRcPtr Create();
+
+ // This will compute the cacheid, and also
+ // determine if the lut is a no-op.
+ // If this lut is being read in from float ASCII text
+ // a value of 1e-5 is preferable.
+ // If this lut is being read in from integer ASCII
+ // representation, the value will depend on the LSB
+ // at the specified integer precision.
+ // Example: reading 10-bit ints? Use 2/1023.0
+ // If you dont want to do the noop computation,
+ // specify a 0.0 tolerance.
+ //
+ // TODO: Instead of having each user compute the error
+ // individually, maybe they should specify the original file bitdepth?
+ // (with appropriate precision tokens?)
+ float maxerror;
+ ErrorType errortype;
+
+ float from_min[3];
+ float from_max[3];
+
+ typedef std::vector<float> fv_t;
+ fv_t luts[3];
+
+ std::string getCacheID() const;
+ bool isNoOp() const;
+
+ void unfinalize();
+ private:
+ Lut1D();
+
+ mutable std::string m_cacheID;
+ mutable bool m_isNoOp;
+ mutable Mutex m_mutex;
+
+ void finalize() const;
+ };
+
+ typedef OCIO_SHARED_PTR<Lut1D> Lut1DRcPtr;
+
+ // This generates an identity 1d lut, from 0.0 to 1.0
+ void GenerateIdentityLut1D(float* img, int numElements, int numChannels);
+
+ void CreateLut1DOp(OpRcPtrVec & ops,
+ const Lut1DRcPtr & lut,
+ Interpolation interpolation,
+ TransformDirection direction);
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/Lut3DOp.cpp b/src/core/Lut3DOp.cpp
new file mode 100644
index 0000000..d64d451
--- /dev/null
+++ b/src/core/Lut3DOp.cpp
@@ -0,0 +1,982 @@
+/*
+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 "HashUtils.h"
+#include "Lut3DOp.h"
+#include "MathUtils.h"
+
+#include <cmath>
+#include <limits>
+#include <sstream>
+
+OCIO_NAMESPACE_ENTER
+{
+ Lut3D::Lut3D()
+ {
+ for(int i=0; i<3; ++i)
+ {
+ from_min[i] = 0.0f;
+ from_max[i] = 1.0f;
+ size[i] = 0;
+ }
+ }
+
+ Lut3DRcPtr Lut3D::Create()
+ {
+ return Lut3DRcPtr(new Lut3D());
+ }
+
+ std::string Lut3D::getCacheID() const
+ {
+ AutoMutex lock(m_cacheidMutex);
+
+ if(lut.empty())
+ throw Exception("Cannot compute cacheID of invalid Lut3D");
+
+ if(!m_cacheID.empty())
+ return m_cacheID;
+
+ md5_state_t state;
+ md5_byte_t digest[16];
+
+ md5_init(&state);
+
+ md5_append(&state, (const md5_byte_t *)from_min, 3*sizeof(float));
+ md5_append(&state, (const md5_byte_t *)from_max, 3*sizeof(float));
+ md5_append(&state, (const md5_byte_t *)size, 3*sizeof(int));
+ md5_append(&state, (const md5_byte_t *)&lut[0], (int) (lut.size()*sizeof(float)));
+
+ md5_finish(&state, digest);
+
+ m_cacheID = GetPrintableHash(digest);
+
+ return m_cacheID;
+ }
+
+
+ namespace
+ {
+ // Linear
+ inline float lerp(float a, float b, float z)
+ { return (b - a) * z + a; }
+
+ inline void lerp_rgb(float* out, float* a, float* b, float* z)
+ {
+ out[0] = (b[0] - a[0]) * z[0] + a[0];
+ out[1] = (b[1] - a[1]) * z[1] + a[1];
+ out[2] = (b[2] - a[2]) * z[2] + a[2];
+ }
+
+ // Bilinear
+ inline float lerp(float a, float b, float c, float d, float y, float z)
+ { return lerp(lerp(a, b, z), lerp(c, d, z), y); }
+
+ inline void lerp_rgb(float* out, float* a, float* b, float* c,
+ float* d, float* y, float* z)
+ {
+ float v1[3];
+ float v2[3];
+
+ lerp_rgb(v1, a, b, z);
+ lerp_rgb(v2, c, d, z);
+ lerp_rgb(out, v1, v2, y);
+ }
+
+ // Trilinear
+ inline float lerp(float a, float b, float c, float d,
+ float e, float f, float g, float h,
+ float x, float y, float z)
+ { return lerp(lerp(a,b,c,d,y,z), lerp(e,f,g,h,y,z), x); }
+
+ inline void lerp_rgb(float* out, float* a, float* b, float* c, float* d,
+ float* e, float* f, float* g, float* h,
+ float* x, float* y, float* z)
+ {
+ float v1[3];
+ float v2[3];
+
+ lerp_rgb(v1, a,b,c,d,y,z);
+ lerp_rgb(v2, e,f,g,h,y,z);
+ lerp_rgb(out, v1, v2, x);
+ }
+
+ inline float lookupNearest_3D(int rIndex, int gIndex, int bIndex,
+ int size_red, int size_green, int size_blue,
+ const float* simple_rgb_lut, int channelIndex)
+ {
+ return simple_rgb_lut[ GetLut3DIndex_B(rIndex, gIndex, bIndex,
+ size_red, size_green, size_blue) + channelIndex];
+ }
+
+ inline void lookupNearest_3D_rgb(float* rgb,
+ int rIndex, int gIndex, int bIndex,
+ int size_red, int size_green, int size_blue,
+ const float* simple_rgb_lut)
+ {
+ int offset = GetLut3DIndex_B(rIndex, gIndex, bIndex, size_red, size_green, size_blue);
+ rgb[0] = simple_rgb_lut[offset];
+ rgb[1] = simple_rgb_lut[offset+1];
+ rgb[2] = simple_rgb_lut[offset+2];
+ }
+
+ // Note: This function assumes that minVal is less than maxVal
+ inline int clamp(float k, float minVal, float maxVal)
+ {
+ return static_cast<int>(roundf(std::max(std::min(k, maxVal), minVal)));
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // Nearest Forward
+
+ void Lut3D_Nearest(float* rgbaBuffer, long numPixels, const Lut3D & lut)
+ {
+ float maxIndex[3];
+ float mInv[3];
+ float b[3];
+ float mInv_x_maxIndex[3];
+ int lutSize[3];
+ const float* startPos = &(lut.lut[0]);
+
+ for(int i=0; i<3; ++i)
+ {
+ maxIndex[i] = (float) (lut.size[i] - 1);
+ mInv[i] = 1.0f / (lut.from_max[i] - lut.from_min[i]);
+ b[i] = lut.from_min[i];
+ mInv_x_maxIndex[i] = (float) (mInv[i] * maxIndex[i]);
+
+ lutSize[i] = lut.size[i];
+ }
+
+ int localIndex[3];
+
+ for(long pixelIndex=0; pixelIndex<numPixels; ++pixelIndex)
+ {
+ if(isnan(rgbaBuffer[0]) || isnan(rgbaBuffer[1]) || isnan(rgbaBuffer[2]))
+ {
+ rgbaBuffer[0] = std::numeric_limits<float>::quiet_NaN();
+ rgbaBuffer[1] = std::numeric_limits<float>::quiet_NaN();
+ rgbaBuffer[2] = std::numeric_limits<float>::quiet_NaN();
+ }
+ else
+ {
+ localIndex[0] = clamp(mInv_x_maxIndex[0] * (rgbaBuffer[0] - b[0]), 0.0f, maxIndex[0]);
+ localIndex[1] = clamp(mInv_x_maxIndex[1] * (rgbaBuffer[1] - b[1]), 0.0f, maxIndex[1]);
+ localIndex[2] = clamp(mInv_x_maxIndex[2] * (rgbaBuffer[2] - b[2]), 0.0f, maxIndex[2]);
+
+ lookupNearest_3D_rgb(rgbaBuffer, localIndex[0], localIndex[1], localIndex[2],
+ lutSize[0], lutSize[1], lutSize[2], startPos);
+ }
+
+ rgbaBuffer += 4;
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // Linear Forward
+
+ void Lut3D_Linear(float* rgbaBuffer, long numPixels, const Lut3D & lut)
+ {
+ float maxIndex[3];
+ float mInv[3];
+ float b[3];
+ float mInv_x_maxIndex[3];
+ int lutSize[3];
+ const float* startPos = &(lut.lut[0]);
+
+ for(int i=0; i<3; ++i)
+ {
+ maxIndex[i] = (float) (lut.size[i] - 1);
+ mInv[i] = 1.0f / (lut.from_max[i] - lut.from_min[i]);
+ b[i] = lut.from_min[i];
+ mInv_x_maxIndex[i] = (float) (mInv[i] * maxIndex[i]);
+
+ lutSize[i] = lut.size[i];
+ }
+
+ for(long pixelIndex=0; pixelIndex<numPixels; ++pixelIndex)
+ {
+
+ if(isnan(rgbaBuffer[0]) || isnan(rgbaBuffer[1]) || isnan(rgbaBuffer[2]))
+ {
+ rgbaBuffer[0] = std::numeric_limits<float>::quiet_NaN();
+ rgbaBuffer[1] = std::numeric_limits<float>::quiet_NaN();
+ rgbaBuffer[2] = std::numeric_limits<float>::quiet_NaN();
+ }
+ else
+ {
+ float localIndex[3];
+ int indexLow[3];
+ int indexHigh[3];
+ float delta[3];
+ float a[3];
+ float b_[3];
+ float c[3];
+ float d[3];
+ float e[3];
+ float f[3];
+ float g[3];
+ float h[4];
+ float x[4];
+ float y[4];
+ float z[4];
+
+ localIndex[0] = std::max(std::min(mInv_x_maxIndex[0] * (rgbaBuffer[0] - b[0]), maxIndex[0]), 0.0f);
+ localIndex[1] = std::max(std::min(mInv_x_maxIndex[1] * (rgbaBuffer[1] - b[1]), maxIndex[1]), 0.0f);
+ localIndex[2] = std::max(std::min(mInv_x_maxIndex[2] * (rgbaBuffer[2] - b[2]), maxIndex[2]), 0.0f);
+
+ indexLow[0] = static_cast<int>(std::floor(localIndex[0]));
+ indexLow[1] = static_cast<int>(std::floor(localIndex[1]));
+ indexLow[2] = static_cast<int>(std::floor(localIndex[2]));
+
+ indexHigh[0] = static_cast<int>(std::ceil(localIndex[0]));
+ indexHigh[1] = static_cast<int>(std::ceil(localIndex[1]));
+ indexHigh[2] = static_cast<int>(std::ceil(localIndex[2]));
+
+ delta[0] = localIndex[0] - static_cast<float>(indexLow[0]);
+ delta[1] = localIndex[1] - static_cast<float>(indexLow[1]);
+ delta[2] = localIndex[2] - static_cast<float>(indexLow[2]);
+
+ // Lookup 8 corners of cube
+ lookupNearest_3D_rgb(a, indexLow[0], indexLow[1], indexLow[2], lutSize[0], lutSize[1], lutSize[2], startPos);
+ lookupNearest_3D_rgb(b_, indexLow[0], indexLow[1], indexHigh[2], lutSize[0], lutSize[1], lutSize[2], startPos);
+ lookupNearest_3D_rgb(c, indexLow[0], indexHigh[1], indexLow[2], lutSize[0], lutSize[1], lutSize[2], startPos);
+ lookupNearest_3D_rgb(d, indexLow[0], indexHigh[1], indexHigh[2], lutSize[0], lutSize[1], lutSize[2], startPos);
+ lookupNearest_3D_rgb(e, indexHigh[0], indexLow[1], indexLow[2], lutSize[0], lutSize[1], lutSize[2], startPos);
+ lookupNearest_3D_rgb(f, indexHigh[0], indexLow[1], indexHigh[2], lutSize[0], lutSize[1], lutSize[2], startPos);
+ lookupNearest_3D_rgb(g, indexHigh[0], indexHigh[1], indexLow[2], lutSize[0], lutSize[1], lutSize[2], startPos);
+ lookupNearest_3D_rgb(h, indexHigh[0], indexHigh[1], indexHigh[2], lutSize[0], lutSize[1], lutSize[2], startPos);
+
+ // Also store the 3d interpolation coordinates
+ x[0] = delta[0]; x[1] = delta[0]; x[2] = delta[0];
+ y[0] = delta[1]; y[1] = delta[1]; y[2] = delta[1];
+ z[0] = delta[2]; z[1] = delta[2]; z[2] = delta[2];
+
+ // Do a trilinear interpolation of the 8 corners
+ // 4726.8 scanlines/sec
+
+ lerp_rgb(rgbaBuffer, a, b_, c, d, e, f, g, h,
+ x, y, z);
+ }
+
+ rgbaBuffer += 4;
+ }
+ }
+ }
+
+
+ void Lut3D_Tetrahedral(float* rgbaBuffer, long numPixels, const Lut3D & lut)
+ {
+ // Tetrahedral interoplation, as described by:
+ // http://www.filmlight.ltd.uk/pdf/whitepapers/FL-TL-TN-0057-SoftwareLib.pdf
+ // http://blogs.mathworks.com/steve/2006/11/24/tetrahedral-interpolation-for-colorspace-conversion/
+ // http://www.hpl.hp.com/techreports/98/HPL-98-95.html
+
+ float maxIndex[3];
+ float mInv[3];
+ float b[3];
+ float mInv_x_maxIndex[3];
+ int lutSize[3];
+ const float* startPos = &(lut.lut[0]);
+
+ for(int i=0; i<3; ++i)
+ {
+ maxIndex[i] = (float) (lut.size[i] - 1);
+ mInv[i] = 1.0f / (lut.from_max[i] - lut.from_min[i]);
+ b[i] = lut.from_min[i];
+ mInv_x_maxIndex[i] = (float) (mInv[i] * maxIndex[i]);
+
+ lutSize[i] = lut.size[i];
+ }
+
+ for(long pixelIndex=0; pixelIndex<numPixels; ++pixelIndex)
+ {
+
+ if(isnan(rgbaBuffer[0]) || isnan(rgbaBuffer[1]) || isnan(rgbaBuffer[2]))
+ {
+ rgbaBuffer[0] = std::numeric_limits<float>::quiet_NaN();
+ rgbaBuffer[1] = std::numeric_limits<float>::quiet_NaN();
+ rgbaBuffer[2] = std::numeric_limits<float>::quiet_NaN();
+ }
+ else
+ {
+ float localIndex[3];
+ int indexLow[3];
+ int indexHigh[3];
+ float delta[3];
+
+ // Same index/delta calculation as linear interpolation
+ localIndex[0] = std::max(std::min(mInv_x_maxIndex[0] * (rgbaBuffer[0] - b[0]), maxIndex[0]), 0.0f);
+ localIndex[1] = std::max(std::min(mInv_x_maxIndex[1] * (rgbaBuffer[1] - b[1]), maxIndex[1]), 0.0f);
+ localIndex[2] = std::max(std::min(mInv_x_maxIndex[2] * (rgbaBuffer[2] - b[2]), maxIndex[2]), 0.0f);
+
+ indexLow[0] = static_cast<int>(std::floor(localIndex[0]));
+ indexLow[1] = static_cast<int>(std::floor(localIndex[1]));
+ indexLow[2] = static_cast<int>(std::floor(localIndex[2]));
+
+ indexHigh[0] = static_cast<int>(std::ceil(localIndex[0]));
+ indexHigh[1] = static_cast<int>(std::ceil(localIndex[1]));
+ indexHigh[2] = static_cast<int>(std::ceil(localIndex[2]));
+
+ delta[0] = localIndex[0] - static_cast<float>(indexLow[0]);
+ delta[1] = localIndex[1] - static_cast<float>(indexLow[1]);
+ delta[2] = localIndex[2] - static_cast<float>(indexLow[2]);
+
+ // Rebind for consistency with Truelight paper
+ float fx = delta[0];
+ float fy = delta[1];
+ float fz = delta[2];
+
+ // Compute index into LUT for surrounding corners
+ const int n000 = GetLut3DIndex_B(indexLow[0], indexLow[1], indexLow[2],
+ lutSize[0], lutSize[1], lutSize[2]);
+ const int n100 = GetLut3DIndex_B(indexHigh[0], indexLow[1], indexLow[2],
+ lutSize[0], lutSize[1], lutSize[2]);
+ const int n010 = GetLut3DIndex_B(indexLow[0], indexHigh[1], indexLow[2],
+ lutSize[0], lutSize[1], lutSize[2]);
+ const int n001 = GetLut3DIndex_B(indexLow[0], indexLow[1], indexHigh[2],
+ lutSize[0], lutSize[1], lutSize[2]);
+ const int n110 = GetLut3DIndex_B(indexHigh[0], indexHigh[1], indexLow[2],
+ lutSize[0], lutSize[1], lutSize[2]);
+ const int n101 = GetLut3DIndex_B(indexHigh[0], indexLow[1], indexHigh[2],
+ lutSize[0], lutSize[1], lutSize[2]);
+ const int n011 = GetLut3DIndex_B(indexLow[0], indexHigh[1], indexHigh[2],
+ lutSize[0], lutSize[1], lutSize[2]);
+ const int n111 = GetLut3DIndex_B(indexHigh[0], indexHigh[1], indexHigh[2],
+ lutSize[0], lutSize[1], lutSize[2]);
+
+ if (fx > fy) {
+ if (fy > fz) {
+ rgbaBuffer[0] =
+ (1-fx) * startPos[n000] +
+ (fx-fy) * startPos[n100] +
+ (fy-fz) * startPos[n110] +
+ (fz) * startPos[n111];
+
+ rgbaBuffer[1] =
+ (1-fx) * startPos[n000+1] +
+ (fx-fy) * startPos[n100+1] +
+ (fy-fz) * startPos[n110+1] +
+ (fz) * startPos[n111+1];
+
+ rgbaBuffer[2] =
+ (1-fx) * startPos[n000+2] +
+ (fx-fy) * startPos[n100+2] +
+ (fy-fz) * startPos[n110+2] +
+ (fz) * startPos[n111+2];
+ }
+ else if (fx > fz)
+ {
+ rgbaBuffer[0] =
+ (1-fx) * startPos[n000] +
+ (fx-fz) * startPos[n100] +
+ (fz-fy) * startPos[n101] +
+ (fy) * startPos[n111];
+
+ rgbaBuffer[1] =
+ (1-fx) * startPos[n000+1] +
+ (fx-fz) * startPos[n100+1] +
+ (fz-fy) * startPos[n101+1] +
+ (fy) * startPos[n111+1];
+
+ rgbaBuffer[2] =
+ (1-fx) * startPos[n000+2] +
+ (fx-fz) * startPos[n100+2] +
+ (fz-fy) * startPos[n101+2] +
+ (fy) * startPos[n111+2];
+ }
+ else
+ {
+ rgbaBuffer[0] =
+ (1-fz) * startPos[n000] +
+ (fz-fx) * startPos[n001] +
+ (fx-fy) * startPos[n101] +
+ (fy) * startPos[n111];
+
+ rgbaBuffer[1] =
+ (1-fz) * startPos[n000+1] +
+ (fz-fx) * startPos[n001+1] +
+ (fx-fy) * startPos[n101+1] +
+ (fy) * startPos[n111+1];
+
+ rgbaBuffer[2] =
+ (1-fz) * startPos[n000+2] +
+ (fz-fx) * startPos[n001+2] +
+ (fx-fy) * startPos[n101+2] +
+ (fy) * startPos[n111+2];
+ }
+ }
+ else
+ {
+ if (fz > fy)
+ {
+ rgbaBuffer[0] =
+ (1-fz) * startPos[n000] +
+ (fz-fy) * startPos[n001] +
+ (fy-fx) * startPos[n011] +
+ (fx) * startPos[n111];
+
+ rgbaBuffer[1] =
+ (1-fz) * startPos[n000+1] +
+ (fz-fy) * startPos[n001+1] +
+ (fy-fx) * startPos[n011+1] +
+ (fx) * startPos[n111+1];
+
+ rgbaBuffer[2] =
+ (1-fz) * startPos[n000+2] +
+ (fz-fy) * startPos[n001+2] +
+ (fy-fx) * startPos[n011+2] +
+ (fx) * startPos[n111+2];
+ }
+ else if (fz > fx)
+ {
+ rgbaBuffer[0] =
+ (1-fy) * startPos[n000] +
+ (fy-fz) * startPos[n010] +
+ (fz-fx) * startPos[n011] +
+ (fx) * startPos[n111];
+
+ rgbaBuffer[1] =
+ (1-fy) * startPos[n000+1] +
+ (fy-fz) * startPos[n010+1] +
+ (fz-fx) * startPos[n011+1] +
+ (fx) * startPos[n111+1];
+
+ rgbaBuffer[2] =
+ (1-fy) * startPos[n000+2] +
+ (fy-fz) * startPos[n010+2] +
+ (fz-fx) * startPos[n011+2] +
+ (fx) * startPos[n111+2];
+ }
+ else
+ {
+ rgbaBuffer[0] =
+ (1-fy) * startPos[n000] +
+ (fy-fx) * startPos[n010] +
+ (fx-fz) * startPos[n110] +
+ (fz) * startPos[n111];
+
+ rgbaBuffer[1] =
+ (1-fy) * startPos[n000+1] +
+ (fy-fx) * startPos[n010+1] +
+ (fx-fz) * startPos[n110+1] +
+ (fz) * startPos[n111+1];
+
+ rgbaBuffer[2] =
+ (1-fy) * startPos[n000+2] +
+ (fy-fx) * startPos[n010+2] +
+ (fx-fz) * startPos[n110+2] +
+ (fz) * startPos[n111+2];
+ }
+ }
+ } // !isnan
+
+ rgbaBuffer += 4;
+ }
+ }
+
+
+ void GenerateIdentityLut3D(float* img, int edgeLen, int numChannels, Lut3DOrder lut3DOrder)
+ {
+ if(!img) return;
+ if(numChannels < 3)
+ {
+ throw Exception("Cannot generate idenitity 3d lut with less than 3 channels.");
+ }
+
+ float c = 1.0f / ((float)edgeLen - 1.0f);
+
+ if(lut3DOrder == LUT3DORDER_FAST_RED)
+ {
+ for(int i=0; i<edgeLen*edgeLen*edgeLen; i++)
+ {
+ img[numChannels*i+0] = (float)(i%edgeLen) * c;
+ img[numChannels*i+1] = (float)((i/edgeLen)%edgeLen) * c;
+ img[numChannels*i+2] = (float)((i/edgeLen/edgeLen)%edgeLen) * c;
+ }
+ }
+ else if(lut3DOrder == LUT3DORDER_FAST_BLUE)
+ {
+ for(int i=0; i<edgeLen*edgeLen*edgeLen; i++)
+ {
+ img[numChannels*i+0] = (float)((i/edgeLen/edgeLen)%edgeLen) * c;
+ img[numChannels*i+1] = (float)((i/edgeLen)%edgeLen) * c;
+ img[numChannels*i+2] = (float)(i%edgeLen) * c;
+ }
+ }
+ else
+ {
+ throw Exception("Unknown Lut3DOrder.");
+ }
+ }
+
+
+ int Get3DLutEdgeLenFromNumPixels(int numPixels)
+ {
+ int dim = static_cast<int>(roundf(powf((float) numPixels, 1.0f/3.0f)));
+
+ if(dim*dim*dim != numPixels)
+ {
+ std::ostringstream os;
+ os << "Cannot infer 3D Lut size. ";
+ os << numPixels << " element(s) does not correspond to a ";
+ os << "unform cube edge length. (nearest edge length is ";
+ os << dim << ").";
+ throw Exception(os.str().c_str());
+ }
+
+ return dim;
+ }
+
+ namespace
+ {
+ class Lut3DOp : public Op
+ {
+ public:
+ Lut3DOp(Lut3DRcPtr lut,
+ Interpolation interpolation,
+ TransformDirection direction);
+ virtual ~Lut3DOp();
+
+ virtual OpRcPtr clone() const;
+
+ virtual std::string getInfo() const;
+ virtual std::string getCacheID() const;
+
+ virtual bool isNoOp() const;
+ virtual bool isSameType(const OpRcPtr & op) const;
+ virtual bool isInverse(const OpRcPtr & op) const;
+ virtual bool hasChannelCrosstalk() const;
+ virtual void finalize();
+ virtual void apply(float* rgbaBuffer, long numPixels) const;
+
+ virtual bool supportsGpuShader() const;
+ virtual void writeGpuShader(std::ostream & shader,
+ const std::string & pixelName,
+ const GpuShaderDesc & shaderDesc) const;
+
+ private:
+ Lut3DRcPtr m_lut;
+ Interpolation m_interpolation;
+ TransformDirection m_direction;
+
+ // Set in finalize
+ std::string m_cacheID;
+ };
+
+ typedef OCIO_SHARED_PTR<Lut3DOp> Lut3DOpRcPtr;
+
+
+ Lut3DOp::Lut3DOp(Lut3DRcPtr lut,
+ Interpolation interpolation,
+ TransformDirection direction):
+ Op(),
+ m_lut(lut),
+ m_interpolation(interpolation),
+ m_direction(direction)
+ {
+ }
+
+ OpRcPtr Lut3DOp::clone() const
+ {
+ OpRcPtr op = OpRcPtr(new Lut3DOp(m_lut, m_interpolation, m_direction));
+ return op;
+ }
+
+ Lut3DOp::~Lut3DOp()
+ { }
+
+ std::string Lut3DOp::getInfo() const
+ {
+ return "<Lut3DOp>";
+ }
+
+ std::string Lut3DOp::getCacheID() const
+ {
+ return m_cacheID;
+ }
+
+ // TODO: compute real value for isNoOp
+ bool Lut3DOp::isNoOp() const
+ {
+ return false;
+ }
+
+ bool Lut3DOp::isSameType(const OpRcPtr & op) const
+ {
+ Lut3DOpRcPtr typedRcPtr = DynamicPtrCast<Lut3DOp>(op);
+ if(!typedRcPtr) return false;
+ return true;
+ }
+
+ bool Lut3DOp::isInverse(const OpRcPtr & op) const
+ {
+ Lut3DOpRcPtr typedRcPtr = DynamicPtrCast<Lut3DOp>(op);
+ if(!typedRcPtr) return false;
+
+ if(GetInverseTransformDirection(m_direction) != typedRcPtr->m_direction)
+ return false;
+
+ return (m_lut->getCacheID() == typedRcPtr->m_lut->getCacheID());
+ }
+
+ // TODO: compute real value for hasChannelCrosstalk
+ bool Lut3DOp::hasChannelCrosstalk() const
+ {
+ return true;
+ }
+
+ void Lut3DOp::finalize()
+ {
+ if(m_direction != TRANSFORM_DIR_FORWARD)
+ {
+ std::ostringstream os;
+ os << "3D Luts can only be applied in the forward direction. ";
+ os << "(" << TransformDirectionToString(m_direction) << ")";
+ os << " specified.";
+ throw Exception(os.str().c_str());
+ }
+
+ // Validate the requested interpolation type
+ switch(m_interpolation)
+ {
+ // These are the allowed values.
+ case INTERP_NEAREST:
+ case INTERP_LINEAR:
+ case INTERP_TETRAHEDRAL:
+ break;
+ case INTERP_BEST:
+ m_interpolation = INTERP_LINEAR;
+ break;
+ case INTERP_UNKNOWN:
+ throw Exception("Cannot apply Lut3DOp, unspecified interpolation.");
+ break;
+ default:
+ throw Exception("Cannot apply Lut3DOp, invalid interpolation specified.");
+ }
+
+ for(int i=0; i<3; ++i)
+ {
+ if(m_lut->size[i] == 0)
+ {
+ throw Exception("Cannot apply Lut3DOp, lut object is empty.");
+ }
+ // TODO if from_min[i] == from_max[i]
+ }
+
+ if(m_lut->size[0]*m_lut->size[1]*m_lut->size[2] * 3 != (int)m_lut->lut.size())
+ {
+ throw Exception("Cannot apply Lut3DOp, specified size does not match data.");
+ }
+
+ // Create the cacheID
+ std::ostringstream cacheIDStream;
+ cacheIDStream << "<Lut3DOp ";
+ cacheIDStream << m_lut->getCacheID() << " ";
+ cacheIDStream << InterpolationToString(m_interpolation) << " ";
+ cacheIDStream << TransformDirectionToString(m_direction) << " ";
+ cacheIDStream << ">";
+ m_cacheID = cacheIDStream.str();
+ }
+
+ void Lut3DOp::apply(float* rgbaBuffer, long numPixels) const
+ {
+ if(m_interpolation == INTERP_NEAREST)
+ {
+ Lut3D_Nearest(rgbaBuffer, numPixels, *m_lut);
+ }
+ else if(m_interpolation == INTERP_LINEAR)
+ {
+ Lut3D_Linear(rgbaBuffer, numPixels, *m_lut);
+ }
+ else if(m_interpolation == INTERP_TETRAHEDRAL)
+ {
+ Lut3D_Tetrahedral(rgbaBuffer, numPixels, *m_lut);
+ }
+ }
+
+ bool Lut3DOp::supportsGpuShader() const
+ {
+ return false;
+ }
+
+ void Lut3DOp::writeGpuShader(std::ostream & /*shader*/,
+ const std::string & /*pixelName*/,
+ const GpuShaderDesc & /*shaderDesc*/) const
+ {
+ throw Exception("Lut3DOp does not support analytical shader generation.");
+ }
+ }
+
+ void CreateLut3DOp(OpRcPtrVec & ops,
+ Lut3DRcPtr lut,
+ Interpolation interpolation,
+ TransformDirection direction)
+ {
+ ops.push_back( Lut3DOpRcPtr(new Lut3DOp(lut, interpolation, direction)) );
+ }
+}
+OCIO_NAMESPACE_EXIT
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef OCIO_UNIT_TEST
+
+#include <cstring>
+#include <cstdlib>
+#include <sys/time.h>
+
+namespace OCIO = OCIO_NAMESPACE;
+#include "UnitTest.h"
+
+OIIO_ADD_TEST(Lut3DOp, NanInfValueCheck)
+{
+ OCIO::Lut3DRcPtr lut = OCIO::Lut3D::Create();
+
+ lut->from_min[0] = 0.0f;
+ lut->from_min[1] = 0.0f;
+ lut->from_min[2] = 0.0f;
+
+ lut->from_max[0] = 1.0f;
+ lut->from_max[1] = 1.0f;
+ lut->from_max[2] = 1.0f;
+
+ lut->size[0] = 3;
+ lut->size[1] = 3;
+ lut->size[2] = 3;
+
+ lut->lut.resize(lut->size[0]*lut->size[1]*lut->size[2]*3);
+
+ GenerateIdentityLut3D(&lut->lut[0], lut->size[0], 3, OCIO::LUT3DORDER_FAST_RED);
+ for(unsigned int i=0; i<lut->lut.size(); ++i)
+ {
+ lut->lut[i] = powf(lut->lut[i], 2.0f);
+ }
+
+ const float reference[4] = { std::numeric_limits<float>::signaling_NaN(),
+ std::numeric_limits<float>::quiet_NaN(),
+ std::numeric_limits<float>::infinity(),
+ -std::numeric_limits<float>::infinity() };
+ float color[4];
+
+ memcpy(color, reference, 4*sizeof(float));
+ OCIO::Lut3D_Nearest(color, 1, *lut);
+
+ memcpy(color, reference, 4*sizeof(float));
+ OCIO::Lut3D_Linear(color, 1, *lut);
+}
+
+
+OIIO_ADD_TEST(Lut3DOp, ValueCheck)
+{
+ OCIO::Lut3DRcPtr lut = OCIO::Lut3D::Create();
+
+ lut->from_min[0] = 0.0f;
+ lut->from_min[1] = 0.0f;
+ lut->from_min[2] = 0.0f;
+
+ lut->from_max[0] = 1.0f;
+ lut->from_max[1] = 1.0f;
+ lut->from_max[2] = 1.0f;
+
+ lut->size[0] = 32;
+ lut->size[1] = 32;
+ lut->size[2] = 32;
+
+ lut->lut.resize(lut->size[0]*lut->size[1]*lut->size[2]*3);
+ GenerateIdentityLut3D(&lut->lut[0], lut->size[0], 3, OCIO::LUT3DORDER_FAST_RED);
+ for(unsigned int i=0; i<lut->lut.size(); ++i)
+ {
+ lut->lut[i] = powf(lut->lut[i], 2.0f);
+ }
+
+ const float reference[] = { 0.0f, 0.2f, 0.3f, 1.0f,
+ 0.1234f, 0.4567f, 0.9876f, 1.0f,
+ 11.0f, -0.5f, 0.5010f, 1.0f
+ };
+ const float nearest[] = { 0.0f, 0.03746097535f, 0.0842871964f, 1.0f,
+ 0.01664932258f, 0.2039542049f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 0.2663891613f, 1.0f
+ };
+ const float linear[] = { 0.0f, 0.04016649351f, 0.09021852165f, 1.0f,
+ 0.01537752338f, 0.2087130845f, 0.9756000042f, 1.0f,
+ 1.0f, 0.0f, 0.2512601018f, 1.0f
+ };
+ float color[12];
+
+ // Check nearest
+ memcpy(color, reference, 12*sizeof(float));
+ OCIO::Lut3D_Nearest(color, 3, *lut);
+ for(unsigned int i=0; i<12; ++i)
+ {
+ OIIO_CHECK_CLOSE(color[i], nearest[i], 1e-8);
+ }
+
+ // Check linear
+ memcpy(color, reference, 12*sizeof(float));
+ OCIO::Lut3D_Linear(color, 3, *lut);
+ for(unsigned int i=0; i<12; ++i)
+ {
+ OIIO_CHECK_CLOSE(color[i], linear[i], 1e-8);
+ }
+
+ // Check tetrahedral
+ memcpy(color, reference, 12*sizeof(float));
+ OCIO::Lut3D_Tetrahedral(color, 3, *lut);
+ for(unsigned int i=0; i<12; ++i)
+ {
+ OIIO_CHECK_CLOSE(color[i], linear[i], 1e-7); // Note, max delta lowered from 1e-8
+ }
+}
+
+
+
+OIIO_ADD_TEST(Lut3DOp, InverseComparisonCheck)
+{
+ OCIO::Lut3DRcPtr lut_a = OCIO::Lut3D::Create();
+ lut_a->from_min[0] = 0.0f;
+ lut_a->from_min[1] = 0.0f;
+ lut_a->from_min[2] = 0.0f;
+ lut_a->from_max[0] = 1.0f;
+ lut_a->from_max[1] = 1.0f;
+ lut_a->from_max[2] = 1.0f;
+ lut_a->size[0] = 32;
+ lut_a->size[1] = 32;
+ lut_a->size[2] = 32;
+ lut_a->lut.resize(lut_a->size[0]*lut_a->size[1]*lut_a->size[2]*3);
+ GenerateIdentityLut3D(&lut_a->lut[0], lut_a->size[0], 3, OCIO::LUT3DORDER_FAST_RED);
+
+ OCIO::Lut3DRcPtr lut_b = OCIO::Lut3D::Create();
+ lut_b->from_min[0] = 0.5f;
+ lut_b->from_min[1] = 0.5f;
+ lut_b->from_min[2] = 0.5f;
+ lut_b->from_max[0] = 1.0f;
+ lut_b->from_max[1] = 1.0f;
+ lut_b->from_max[2] = 1.0f;
+ lut_b->size[0] = 32;
+ lut_b->size[1] = 32;
+ lut_b->size[2] = 32;
+ lut_b->lut.resize(lut_b->size[0]*lut_b->size[1]*lut_b->size[2]*3);
+ GenerateIdentityLut3D(&lut_b->lut[0], lut_b->size[0], 3, OCIO::LUT3DORDER_FAST_RED);
+
+ OCIO::OpRcPtrVec ops;
+ CreateLut3DOp(ops, lut_a, OCIO::INTERP_NEAREST, OCIO::TRANSFORM_DIR_FORWARD);
+ CreateLut3DOp(ops, lut_a, OCIO::INTERP_LINEAR, OCIO::TRANSFORM_DIR_INVERSE);
+ CreateLut3DOp(ops, lut_b, OCIO::INTERP_LINEAR, OCIO::TRANSFORM_DIR_FORWARD);
+ CreateLut3DOp(ops, lut_b, OCIO::INTERP_LINEAR, OCIO::TRANSFORM_DIR_INVERSE);
+
+ OIIO_CHECK_EQUAL(ops.size(), 4);
+
+ OIIO_CHECK_ASSERT(ops[0]->isSameType(ops[1]));
+ OIIO_CHECK_ASSERT(ops[0]->isSameType(ops[2]));
+ OIIO_CHECK_ASSERT(ops[0]->isSameType(ops[3]->clone()));
+
+ OIIO_CHECK_EQUAL( ops[0]->isInverse(ops[1]), true);
+ OIIO_CHECK_EQUAL( ops[0]->isInverse(ops[2]), false);
+ OIIO_CHECK_EQUAL( ops[0]->isInverse(ops[2]), false);
+ OIIO_CHECK_EQUAL( ops[0]->isInverse(ops[3]), false);
+ OIIO_CHECK_EQUAL( ops[2]->isInverse(ops[3]), true);
+}
+
+
+OIIO_ADD_TEST(Lut3DOp, PerformanceCheck)
+{
+ /*
+ OCIO::Lut3D lut;
+
+ lut.from_min[0] = 0.0f;
+ lut.from_min[1] = 0.0f;
+ lut.from_min[2] = 0.0f;
+
+ lut.from_max[0] = 1.0f;
+ lut.from_max[1] = 1.0f;
+ lut.from_max[2] = 1.0f;
+
+ lut.size[0] = 32;
+ lut.size[1] = 32;
+ lut.size[2] = 32;
+
+ lut.lut.resize(lut.size[0]*lut.size[1]*lut.size[2]*3);
+ GenerateIdentityLut3D(&lut.lut[0], lut.size[0], 3, OCIO::LUT3DORDER_FAST_RED);
+
+ std::vector<float> img;
+ int xres = 2048;
+ int yres = 1;
+ int channels = 4;
+ img.resize(xres*yres*channels);
+
+ srand48(0);
+
+ // create random values from -0.05 to 1.05
+ // (To simulate clipping performance)
+
+ for(unsigned int i=0; i<img.size(); ++i)
+ {
+ float uniform = (float)drand48();
+ img[i] = uniform*1.1f - 0.05f;
+ }
+
+ timeval t;
+ gettimeofday(&t, 0);
+ double starttime = (double) t.tv_sec + (double) t.tv_usec / 1000000.0;
+
+ int numloops = 1024;
+ for(int i=0; i<numloops; ++i)
+ {
+ //OCIO::Lut3D_Nearest(&img[0], xres*yres, lut);
+ OCIO::Lut3D_Linear(&img[0], xres*yres, lut);
+ }
+
+ gettimeofday(&t, 0);
+ double endtime = (double) t.tv_sec + (double) t.tv_usec / 1000000.0;
+ double totaltime_a = (endtime-starttime)/numloops;
+
+ printf("Linear: %0.1f ms - %0.1f fps\n", totaltime_a*1000.0, 1.0/totaltime_a);
+
+
+ // Tetrahedral
+ gettimeofday(&t, 0);
+ starttime = (double) t.tv_sec + (double) t.tv_usec / 1000000.0;
+
+ for(int i=0; i<numloops; ++i)
+ {
+ OCIO::Lut3D_Tetrahedral(&img[0], xres*yres, lut);
+ }
+
+ gettimeofday(&t, 0);
+ endtime = (double) t.tv_sec + (double) t.tv_usec / 1000000.0;
+ double totaltime_b = (endtime-starttime)/numloops;
+
+ printf("Tetra: %0.1f ms - %0.1f fps\n", totaltime_b*1000.0, 1.0/totaltime_b);
+
+ double speed_diff = totaltime_a/totaltime_b;
+ printf("Tetra is %.04f speed of Linear\n", speed_diff);
+ */
+}
+#endif // OCIO_UNIT_TEST
diff --git a/src/core/Lut3DOp.h b/src/core/Lut3DOp.h
new file mode 100644
index 0000000..bba532b
--- /dev/null
+++ b/src/core/Lut3DOp.h
@@ -0,0 +1,114 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_LUT3DOP_H
+#define INCLUDED_OCIO_LUT3DOP_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "Mutex.h"
+#include "Op.h"
+
+#include <vector>
+
+OCIO_NAMESPACE_ENTER
+{
+ // TODO: turn into a class instead of a struct?
+
+ struct Lut3D;
+ typedef OCIO_SHARED_PTR<Lut3D> Lut3DRcPtr;
+
+ struct Lut3D
+ {
+ static Lut3DRcPtr Create();
+
+ float from_min[3];
+ float from_max[3];
+ int size[3];
+
+ typedef std::vector<float> fv_t;
+ fv_t lut;
+
+ std::string getCacheID() const;
+
+ private:
+ Lut3D();
+ mutable std::string m_cacheID;
+ mutable Mutex m_cacheidMutex;
+ };
+
+ // RGB channel ordering.
+ // Pixels ordered in such a way that the blue coordinate changes fastest,
+ // then the green coordinate, and finally, the red coordinate changes slowest
+
+ inline int GetLut3DIndex_B(int indexR, int indexG, int indexB,
+ int sizeR, int sizeG, int /*sizeB*/)
+ {
+ return 3 * (indexR + sizeR * (indexG + sizeG * indexB));
+ }
+
+
+ // RGB channel ordering.
+ // Pixels ordered in such a way that the red coordinate changes fastest,
+ // then the green coordinate, and finally, the blue coordinate changes slowest
+
+ inline int GetLut3DIndex_R(int indexR, int indexG, int indexB,
+ int /*sizeR*/, int sizeG, int sizeB)
+ {
+ return 3 * (indexB + sizeB * (indexG + sizeG * indexR));
+ }
+
+ // What is the preferred order for the lut3d?
+ // I.e., are the first two entries change along
+ // the blue direction, or the red direction?
+ // OpenGL expects 'red'
+
+ enum Lut3DOrder
+ {
+ LUT3DORDER_FAST_RED = 0,
+ LUT3DORDER_FAST_BLUE
+ };
+
+ void GenerateIdentityLut3D(float* img, int edgeLen, int numChannels,
+ Lut3DOrder lut3DOrder);
+
+ // Essentially the cube root, but will throw an exception if the
+ // cuberoot is not exact.
+ int Get3DLutEdgeLenFromNumPixels(int numPixels);
+
+
+
+ void CreateLut3DOp(OpRcPtrVec & ops,
+ Lut3DRcPtr lut,
+ Interpolation interpolation,
+ TransformDirection direction);
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/MathUtils.cpp b/src/core/MathUtils.cpp
new file mode 100644
index 0000000..19691d7
--- /dev/null
+++ b/src/core/MathUtils.cpp
@@ -0,0 +1,603 @@
+/*
+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 <cstring>
+
+#include "MathUtils.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ const float FLTMIN = std::numeric_limits<float>::min();
+ }
+
+ bool IsScalarEqualToZero(float v)
+ {
+ return equalWithAbsError(v, 0.0f, FLTMIN);
+ }
+
+ bool IsScalarEqualToOne(float v)
+ {
+ return equalWithAbsError(v, 1.0f, FLTMIN);
+ }
+
+ float GetSafeScalarInverse(float v, float defaultValue)
+ {
+ if(IsScalarEqualToZero(v)) return defaultValue;
+ return 1.0f / v;
+ }
+
+ bool IsVecEqualToZero(const float* v, int size)
+ {
+ for(int i=0; i<size; ++i)
+ {
+ if(!IsScalarEqualToZero(v[i])) return false;
+ }
+ return true;
+ }
+
+ bool IsVecEqualToOne(const float* v, int size)
+ {
+ for(int i=0; i<size; ++i)
+ {
+ if(!IsScalarEqualToOne(v[i])) return false;
+ }
+ return true;
+ }
+
+ bool VecContainsZero(const float* v, int size)
+ {
+ for(int i=0; i<size; ++i)
+ {
+ if(IsScalarEqualToZero(v[i])) return true;
+ }
+ return false;
+ }
+
+ bool VecContainsOne(const float* v, int size)
+ {
+ for(int i=0; i<size; ++i)
+ {
+ if(IsScalarEqualToOne(v[i])) return true;
+ }
+ return false;
+ }
+
+ bool VecsEqualWithRelError(const float* v1, int size1,
+ const float* v2, int size2,
+ float e)
+ {
+ if(size1 != size2) return false;
+ for(int i=0; i<size1; ++i)
+ {
+ if(!equalWithRelError(v1[i], v2[i], e)) return false;
+ }
+
+ return true;
+ }
+
+ double ClampToNormHalf(double val)
+ {
+ if(val < -GetHalfMax())
+ {
+ return -GetHalfMax();
+ }
+
+ if(val > -GetHalfNormMin() && val<GetHalfNormMin())
+ {
+ return 0.0;
+ }
+
+ if(val > GetHalfMax())
+ {
+ return GetHalfMax();
+ }
+
+ return val;
+ }
+
+ bool IsM44Identity(const float* m44)
+ {
+ int index=0;
+
+ for(unsigned int j=0; j<4; ++j)
+ {
+ for(unsigned int i=0; i<4; ++i)
+ {
+ index = 4*j+i;
+
+ if(i==j)
+ {
+ if(!IsScalarEqualToOne(m44[index])) return false;
+ }
+ else
+ {
+ if(!IsScalarEqualToZero(m44[index])) return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ bool IsM44Diagonal(const float* m44)
+ {
+ for(int i=0; i<16; ++i)
+ {
+ if((i%5)==0) continue; // If we're on the diagonal, skip it
+ if(!IsScalarEqualToZero(m44[i])) return false;
+ }
+
+ return true;
+ }
+
+ void GetM44Diagonal(float* out4, const float* m44)
+ {
+ for(int i=0; i<4; ++i)
+ {
+ out4[i] = m44[i*5];
+ }
+ }
+
+ // We use an intermediate double representation to make sure
+ // there is minimal float precision error on the determinant's computation
+ // (We have seen IsScalarEqualToZero sensitivities here on 32-bit
+ // virtual machines)
+
+ bool GetM44Inverse(float* inverse_out, const float* m_)
+ {
+ double m[16];
+ for(unsigned int i=0; i<16; ++i) m[i] = (double)m_[i];
+
+ double d10_21 = m[4]*m[9] - m[5]*m[8];
+ double d10_22 = m[4]*m[10] - m[6]*m[8];
+ double d10_23 = m[4]*m[11] - m[7]*m[8];
+ double d11_22 = m[5]*m[10] - m[6]*m[9];
+ double d11_23 = m[5]*m[11] - m[7]*m[9];
+ double d12_23 = m[6]*m[11] - m[7]*m[10];
+
+ double a00 = m[13]*d12_23 - m[14]*d11_23 + m[15]*d11_22;
+ double a10 = m[14]*d10_23 - m[15]*d10_22 - m[12]*d12_23;
+ double a20 = m[12]*d11_23 - m[13]*d10_23 + m[15]*d10_21;
+ double a30 = m[13]*d10_22 - m[14]*d10_21 - m[12]*d11_22;
+
+ double det = a00*m[0] + a10*m[1] + a20*m[2] + a30*m[3];
+
+ if(IsScalarEqualToZero((float)det)) return false;
+
+ det = 1.0/det;
+
+ double d00_31 = m[0]*m[13] - m[1]*m[12];
+ double d00_32 = m[0]*m[14] - m[2]*m[12];
+ double d00_33 = m[0]*m[15] - m[3]*m[12];
+ double d01_32 = m[1]*m[14] - m[2]*m[13];
+ double d01_33 = m[1]*m[15] - m[3]*m[13];
+ double d02_33 = m[2]*m[15] - m[3]*m[14];
+
+ double a01 = m[9]*d02_33 - m[10]*d01_33 + m[11]*d01_32;
+ double a11 = m[10]*d00_33 - m[11]*d00_32 - m[8]*d02_33;
+ double a21 = m[8]*d01_33 - m[9]*d00_33 + m[11]*d00_31;
+ double a31 = m[9]*d00_32 - m[10]*d00_31 - m[8]*d01_32;
+
+ double a02 = m[6]*d01_33 - m[7]*d01_32 - m[5]*d02_33;
+ double a12 = m[4]*d02_33 - m[6]*d00_33 + m[7]*d00_32;
+ double a22 = m[5]*d00_33 - m[7]*d00_31 - m[4]*d01_33;
+ double a32 = m[4]*d01_32 - m[5]*d00_32 + m[6]*d00_31;
+
+ double a03 = m[2]*d11_23 - m[3]*d11_22 - m[1]*d12_23;
+ double a13 = m[0]*d12_23 - m[2]*d10_23 + m[3]*d10_22;
+ double a23 = m[1]*d10_23 - m[3]*d10_21 - m[0]*d11_23;
+ double a33 = m[0]*d11_22 - m[1]*d10_22 + m[2]*d10_21;
+
+ inverse_out[0] = (float) (a00*det);
+ inverse_out[1] = (float) (a01*det);
+ inverse_out[2] = (float) (a02*det);
+ inverse_out[3] = (float) (a03*det);
+ inverse_out[4] = (float) (a10*det);
+ inverse_out[5] = (float) (a11*det);
+ inverse_out[6] = (float) (a12*det);
+ inverse_out[7] = (float) (a13*det);
+ inverse_out[8] = (float) (a20*det);
+ inverse_out[9] = (float) (a21*det);
+ inverse_out[10] = (float) (a22*det);
+ inverse_out[11] = (float) (a23*det);
+ inverse_out[12] = (float) (a30*det);
+ inverse_out[13] = (float) (a31*det);
+ inverse_out[14] = (float) (a32*det);
+ inverse_out[15] = (float) (a33*det);
+
+ return true;
+ }
+
+ void GetM44M44Product(float* mout, const float* m1_, const float* m2_)
+ {
+ float m1[16];
+ float m2[16];
+ memcpy(m1, m1_, 16*sizeof(float));
+ memcpy(m2, m2_, 16*sizeof(float));
+
+ mout[ 0] = m1[ 0]*m2[0] + m1[ 1]*m2[4] + m1[ 2]*m2[ 8] + m1[ 3]*m2[12];
+ mout[ 1] = m1[ 0]*m2[1] + m1[ 1]*m2[5] + m1[ 2]*m2[ 9] + m1[ 3]*m2[13];
+ mout[ 2] = m1[ 0]*m2[2] + m1[ 1]*m2[6] + m1[ 2]*m2[10] + m1[ 3]*m2[14];
+ mout[ 3] = m1[ 0]*m2[3] + m1[ 1]*m2[7] + m1[ 2]*m2[11] + m1[ 3]*m2[15];
+ mout[ 4] = m1[ 4]*m2[0] + m1[ 5]*m2[4] + m1[ 6]*m2[ 8] + m1[ 7]*m2[12];
+ mout[ 5] = m1[ 4]*m2[1] + m1[ 5]*m2[5] + m1[ 6]*m2[ 9] + m1[ 7]*m2[13];
+ mout[ 6] = m1[ 4]*m2[2] + m1[ 5]*m2[6] + m1[ 6]*m2[10] + m1[ 7]*m2[14];
+ mout[ 7] = m1[ 4]*m2[3] + m1[ 5]*m2[7] + m1[ 6]*m2[11] + m1[ 7]*m2[15];
+ mout[ 8] = m1[ 8]*m2[0] + m1[ 9]*m2[4] + m1[10]*m2[ 8] + m1[11]*m2[12];
+ mout[ 9] = m1[ 8]*m2[1] + m1[ 9]*m2[5] + m1[10]*m2[ 9] + m1[11]*m2[13];
+ mout[10] = m1[ 8]*m2[2] + m1[ 9]*m2[6] + m1[10]*m2[10] + m1[11]*m2[14];
+ mout[11] = m1[ 8]*m2[3] + m1[ 9]*m2[7] + m1[10]*m2[11] + m1[11]*m2[15];
+ mout[12] = m1[12]*m2[0] + m1[13]*m2[4] + m1[14]*m2[ 8] + m1[15]*m2[12];
+ mout[13] = m1[12]*m2[1] + m1[13]*m2[5] + m1[14]*m2[ 9] + m1[15]*m2[13];
+ mout[14] = m1[12]*m2[2] + m1[13]*m2[6] + m1[14]*m2[10] + m1[15]*m2[14];
+ mout[15] = m1[12]*m2[3] + m1[13]*m2[7] + m1[14]*m2[11] + m1[15]*m2[15];
+ }
+
+ namespace
+ {
+
+ void GetM44V4Product(float* vout, const float* m, const float* v_)
+ {
+ float v[4];
+ memcpy(v, v_, 4*sizeof(float));
+
+ vout[0] = m[ 0]*v[0] + m[ 1]*v[1] + m[ 2]*v[2] + m[ 3]*v[3];
+ vout[1] = m[ 4]*v[0] + m[ 5]*v[1] + m[ 6]*v[2] + m[ 7]*v[3];
+ vout[2] = m[ 8]*v[0] + m[ 9]*v[1] + m[10]*v[2] + m[11]*v[3];
+ vout[3] = m[12]*v[0] + m[13]*v[1] + m[14]*v[2] + m[15]*v[3];
+ }
+
+ void GetV4Sum(float* vout, const float* v1, const float* v2)
+ {
+ for(int i=0; i<4; ++i)
+ {
+ vout[i] = v1[i] + v2[i];
+ }
+ }
+
+ } // anon namespace
+
+ // All m(s) are 4x4. All v(s) are size 4 vectors.
+ // Return mout, vout, where mout*x+vout == m2*(m1*x+v1)+v2
+ // mout = m2*m1
+ // vout = m2*v1 + v2
+ void GetMxbCombine(float* mout, float* vout,
+ const float* m1_, const float* v1_,
+ const float* m2_, const float* v2_)
+ {
+ float m1[16];
+ float v1[4];
+ float m2[16];
+ float v2[4];
+ memcpy(m1, m1_, 16*sizeof(float));
+ memcpy(v1, v1_, 4*sizeof(float));
+ memcpy(m2, m2_, 16*sizeof(float));
+ memcpy(v2, v2_, 4*sizeof(float));
+
+ GetM44M44Product(mout, m2, m1);
+ GetM44V4Product(vout, m2, v1);
+ GetV4Sum(vout, vout, v2);
+ }
+
+ namespace
+ {
+
+ void GetMxbResult(float* vout, float* m, float* x, float* v)
+ {
+ GetM44V4Product(vout, m, x);
+ GetV4Sum(vout, vout, v);
+ }
+
+ } // anon namespace
+
+ bool GetMxbInverse(float* mout, float* vout,
+ const float* m_, const float* v_)
+ {
+ float m[16];
+ float v[4];
+ memcpy(m, m_, 16*sizeof(float));
+ memcpy(v, v_, 4*sizeof(float));
+
+ if(!GetM44Inverse(mout, m)) return false;
+
+ for(int i=0; i<4; ++i)
+ {
+ v[i] = -v[i];
+ }
+ GetM44V4Product(vout, mout, v);
+
+ return true;
+ }
+
+}
+
+OCIO_NAMESPACE_EXIT
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef OCIO_UNIT_TEST
+
+OCIO_NAMESPACE_USING
+
+#include "UnitTest.h"
+
+OIIO_ADD_TEST(MathUtils, M44_is_diagonal)
+{
+ {
+ float m44[] = { 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f };
+ bool isdiag = IsM44Diagonal(m44);
+ OIIO_CHECK_EQUAL(isdiag, true);
+
+ m44[1] += 1e-8f;
+ isdiag = IsM44Diagonal(m44);
+ OIIO_CHECK_EQUAL(isdiag, false);
+ }
+}
+
+
+OIIO_ADD_TEST(MathUtils, IsScalarEqualToZero)
+{
+ OIIO_CHECK_EQUAL(IsScalarEqualToZero(0.0f), true);
+ OIIO_CHECK_EQUAL(IsScalarEqualToZero(-0.0f), true);
+
+ OIIO_CHECK_EQUAL(IsScalarEqualToZero(-1.072883670794056e-09f), false);
+ OIIO_CHECK_EQUAL(IsScalarEqualToZero(1.072883670794056e-09f), false);
+
+ OIIO_CHECK_EQUAL(IsScalarEqualToZero(-1.072883670794056e-03f), false);
+ OIIO_CHECK_EQUAL(IsScalarEqualToZero(1.072883670794056e-03f), false);
+
+ OIIO_CHECK_EQUAL(IsScalarEqualToZero(-1.072883670794056e-01f), false);
+ OIIO_CHECK_EQUAL(IsScalarEqualToZero(1.072883670794056e-01f), false);
+}
+
+OIIO_ADD_TEST(MathUtils, GetM44Inverse)
+{
+ // This is a degenerate matrix, and shouldnt be invertible.
+ float m[] = { 0.3f, 0.3f, 0.3f, 0.0f,
+ 0.3f, 0.3f, 0.3f, 0.0f,
+ 0.3f, 0.3f, 0.3f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f };
+
+ float mout[16];
+ bool invertsuccess = GetM44Inverse(mout, m);
+ OIIO_CHECK_EQUAL(invertsuccess, false);
+}
+
+
+OIIO_ADD_TEST(MathUtils, M44_M44_product)
+{
+ {
+ float mout[16];
+ float m1[] = { 1.0f, 2.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 1.0f, 0.0f,
+ 1.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 3.0f, 1.0f };
+ float m2[] = { 1.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 2.0f, 0.0f, 0.0f, 1.0f };
+ GetM44M44Product(mout, m1, m2);
+
+ float mcorrect[] = { 1.0f, 3.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 1.0f, 0.0f,
+ 1.0f, 1.0f, 1.0f, 0.0f,
+ 2.0f, 1.0f, 3.0f, 1.0f };
+
+ for(int i=0; i<16; ++i)
+ {
+ OIIO_CHECK_EQUAL(mout[i], mcorrect[i]);
+ }
+ }
+}
+
+OIIO_ADD_TEST(MathUtils, M44_V4_product)
+{
+ {
+ float vout[4];
+ float m[] = { 1.0f, 2.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 1.0f, 0.0f,
+ 1.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 3.0f, 1.0f };
+ float v[] = { 1.0f, 2.0f, 3.0f, 4.0f };
+ GetM44V4Product(vout, m, v);
+
+ float vcorrect[] = { 5.0f, 5.0f, 4.0f, 15.0f };
+
+ for(int i=0; i<4; ++i)
+ {
+ OIIO_CHECK_EQUAL(vout[i], vcorrect[i]);
+ }
+ }
+}
+
+OIIO_ADD_TEST(MathUtils, V4_add)
+{
+ {
+ float vout[4];
+ float v1[] = { 1.0f, 2.0f, 3.0f, 4.0f };
+ float v2[] = { 3.0f, 1.0f, 4.0f, 1.0f };
+ GetV4Sum(vout, v1, v2);
+
+ float vcorrect[] = { 4.0f, 3.0f, 7.0f, 5.0f };
+
+ for(int i=0; i<4; ++i)
+ {
+ OIIO_CHECK_EQUAL(vout[i], vcorrect[i]);
+ }
+ }
+}
+
+OIIO_ADD_TEST(MathUtils, mxb_eval)
+{
+ {
+ float vout[4];
+ float m[] = { 1.0f, 2.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 1.0f, 0.0f,
+ 1.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 3.0f, 1.0f };
+ float x[] = { 1.0f, 1.0f, 1.0f, 1.0f };
+ float v[] = { 1.0f, 2.0f, 3.0f, 4.0f };
+ GetMxbResult(vout, m, x, v);
+
+ float vcorrect[] = { 4.0f, 4.0f, 5.0f, 9.0f };
+
+ for(int i=0; i<4; ++i)
+ {
+ OIIO_CHECK_EQUAL(vout[i], vcorrect[i]);
+ }
+ }
+}
+
+OIIO_ADD_TEST(MathUtils, Combine_two_mxb)
+{
+ float m1[] = { 1.0f, 0.0f, 2.0f, 0.0f,
+ 2.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 2.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f };
+ float v1[] = { 1.0f, 2.0f, 3.0f, 4.0f };
+ float m2[] = { 2.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 3.0f, 0.0f,
+ 1.0f,1.0f, 1.0f, 1.0f };
+ float v2[] = { 0.0f, 2.0f, 1.0f, 0.0f };
+ float tolerance = 1e-9f;
+
+ {
+ float x[] = { 1.0f, 1.0f, 1.0f, 1.0f };
+ float vout[4];
+
+ // Combine two mx+b operations, and apply to test point
+ float mout[16];
+ float vcombined[4];
+ GetMxbCombine(mout, vout, m1, v1, m2, v2);
+ GetMxbResult(vcombined, mout, x, vout);
+
+ // Sequentially apply the two mx+b operations.
+ GetMxbResult(vout, m1, x, v1);
+ GetMxbResult(vout, m2, vout, v2);
+
+ // Compare outputs
+ for(int i=0; i<4; ++i)
+ {
+ OIIO_CHECK_CLOSE(vcombined[i], vout[i], tolerance);
+ }
+ }
+
+ {
+ float x[] = { 6.0f, 0.5f, -2.0f, -0.1f };
+ float vout[4];
+
+ float mout[16];
+ float vcombined[4];
+ GetMxbCombine(mout, vout, m1, v1, m2, v2);
+ GetMxbResult(vcombined, mout, x, vout);
+
+ GetMxbResult(vout, m1, x, v1);
+ GetMxbResult(vout, m2, vout, v2);
+
+ for(int i=0; i<4; ++i)
+ {
+ OIIO_CHECK_CLOSE(vcombined[i], vout[i], tolerance);
+ }
+ }
+
+ {
+ float x[] = { 26.0f, -0.5f, 0.005f, 12.1f };
+ float vout[4];
+
+ float mout[16];
+ float vcombined[4];
+ GetMxbCombine(mout, vout, m1, v1, m2, v2);
+ GetMxbResult(vcombined, mout, x, vout);
+
+ GetMxbResult(vout, m1, x, v1);
+ GetMxbResult(vout, m2, vout, v2);
+
+ // We pick a not so small tolerance, as we're dealing with
+ // large numbers, and the error for CHECK_CLOSE is absolute.
+ for(int i=0; i<4; ++i)
+ {
+ OIIO_CHECK_CLOSE(vcombined[i], vout[i], 1e-3);
+ }
+ }
+}
+
+OIIO_ADD_TEST(MathUtils, mxb_invert)
+{
+ {
+ float m[] = { 1.0f, 2.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 1.0f, 0.0f,
+ 1.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 3.0f, 1.0f };
+ float x[] = { 1.0f, 0.5f, -1.0f, 60.0f };
+ float v[] = { 1.0f, 2.0f, 3.0f, 4.0f };
+
+ float vresult[4];
+ float mout[16];
+ float vout[4];
+
+ GetMxbResult(vresult, m, x, v);
+ bool invertsuccess = GetMxbInverse(mout, vout, m, v);
+ OIIO_CHECK_EQUAL(invertsuccess, true);
+
+ GetMxbResult(vresult, mout, vresult, vout);
+
+ float tolerance = 1e-9f;
+ for(int i=0; i<4; ++i)
+ {
+ OIIO_CHECK_CLOSE(vresult[i], x[i], tolerance);
+ }
+ }
+
+ {
+ float m[] = { 0.3f, 0.3f, 0.3f, 0.0f,
+ 0.3f, 0.3f, 0.3f, 0.0f,
+ 0.3f, 0.3f, 0.3f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f };
+ float v[] = { 0.0f, 0.0f, 0.0f, 0.0f };
+
+ float mout[16];
+ float vout[4];
+
+ bool invertsuccess = GetMxbInverse(mout, vout, m, v);
+ OIIO_CHECK_EQUAL(invertsuccess, false);
+ }
+}
+
+#endif
+
diff --git a/src/core/MathUtils.h b/src/core/MathUtils.h
new file mode 100644
index 0000000..ffe66f3
--- /dev/null
+++ b/src/core/MathUtils.h
@@ -0,0 +1,186 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_MATHUTILS_H
+#define INCLUDED_OCIO_MATHUTILS_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include <cmath>
+#include <vector>
+
+#include "Op.h"
+#include "Platform.h"
+
+#ifdef WINDOWS
+#include <float.h>
+#endif
+
+OCIO_NAMESPACE_ENTER
+{
+ // From Imath
+ //--------------------------------------------------------------------------
+ // Compare two numbers and test if they are "approximately equal":
+ //
+ // equalWithAbsError (x1, x2, e)
+ //
+ // Returns true if x1 is the same as x2 with an absolute error of
+ // no more than e,
+ //
+ // abs (x1 - x2) <= e
+ //
+ // equalWithRelError (x1, x2, e)
+ //
+ // Returns true if x1 is the same as x2 with an relative error of
+ // no more than e,
+ //
+ // abs (x1 - x2) <= e * x1
+ //
+ //--------------------------------------------------------------------------
+
+ inline bool equalWithAbsError (float x1, float x2, float e)
+ {
+ return ((x1 > x2)? x1 - x2: x2 - x1) <= e;
+ }
+
+ inline bool equalWithRelError (float x1, float x2, float e)
+ {
+ return ((x1 > x2)? x1 - x2: x2 - x1) <= e * ((x1 > 0)? x1: -x1);
+ }
+
+ inline float lerpf(float a, float b, float z)
+ {
+ return (b - a) * z + a;
+ }
+
+#ifdef WINDOWS
+ inline double
+ round (float val) {
+ return floor (val + 0.5);
+ }
+
+ inline float
+ roundf (float val) {
+ return static_cast<float>(round (val));
+ }
+
+ inline int
+ isnan (float val) {
+ // Windows uses a non-standard version of 'isnan'
+ return _isnan (val);
+ }
+#else
+
+#ifdef ANDROID
+// support std::isnan - needs to be tested as it might not be part of the NDK
+#define _GLIBCXX_USE_C99_MATH 1
+#endif
+
+ // This lets all platforms just use isnan, within the OCIO namespace,
+ // across all platforms. (Windows defines the function above).
+ using std::isnan;
+#endif
+
+ // Checks within fltmin tolerance
+ bool IsScalarEqualToZero(float v);
+ bool IsScalarEqualToOne(float v);
+
+ // Are all the vector components the specified value?
+ bool IsVecEqualToZero(const float* v, int size);
+ bool IsVecEqualToOne(const float* v, int size);
+
+ // Is at least one of the specified components equal to 0?
+ bool VecContainsZero(const float* v, int size);
+ bool VecContainsOne(const float* v, int size);
+
+ // Are two vectors equal? (Same size, same values?)
+ bool VecsEqualWithRelError(const float* v1, int size1,
+ const float* v2, int size2,
+ float e);
+
+ inline double GetHalfMax()
+ {
+ return 65504.0; // Largest positive half
+ }
+
+ inline double GetHalfMin()
+ {
+ return 5.96046448e-08; // Smallest positive half;
+ }
+
+ inline double GetHalfNormMin()
+ {
+ return 6.10351562e-05; // Smallest positive normalized half
+ }
+
+ //! Clamp the specified value to the valid range of normalized half.
+ // (can be either positive or negative though
+
+ double ClampToNormHalf(double val);
+
+ float GetSafeScalarInverse(float v, float defaultValue = 1.0);
+
+
+ // All matrix / vector operations use the following sizing...
+ //
+ // m : 4x4 matrix
+ // v : 4 column vector
+
+ // Return the 4x4 inverse, and whether the inverse has succeeded.
+ // Supports in-place operations
+ bool GetM44Inverse(float* mout, const float* m);
+
+ // Is an identity matrix? (with fltmin tolerance)
+ bool IsM44Identity(const float* m);
+
+ // Is this a purely diagonal matrix?
+ bool IsM44Diagonal(const float* m);
+
+ // Extract the diagonal
+ void GetM44Diagonal(float* vout, const float* m);
+
+ // Get the product, out = m1*m2
+ // Supports in-place operations
+ void GetM44Product(float* mout, const float* m1, const float* m2);
+
+ // Combine two transforms in the mx+b form, into a single transform
+ // mout*x+vout == m2*(m1*x+v1)+v2
+ // Supports in-place operations
+ void GetMxbCombine(float* mout, float* vout,
+ const float* m1, const float* v1,
+ const float* m2, const float* v2);
+
+ // Supports in-place operations
+ bool GetMxbInverse(float* mout, float* vout,
+ const float* m, const float* v);
+
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/MatrixOps.cpp b/src/core/MatrixOps.cpp
new file mode 100644
index 0000000..a0d4ef3
--- /dev/null
+++ b/src/core/MatrixOps.cpp
@@ -0,0 +1,788 @@
+/*
+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 "GpuShaderUtils.h"
+#include "HashUtils.h"
+#include "MatrixOps.h"
+#include "MathUtils.h"
+
+#include <cstring>
+#include <sstream>
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ void ApplyScale(float* rgbaBuffer, long numPixels,
+ const float* scale4)
+ {
+ for(long pixelIndex=0; pixelIndex<numPixels; ++pixelIndex)
+ {
+ rgbaBuffer[0] *= scale4[0];
+ rgbaBuffer[1] *= scale4[1];
+ rgbaBuffer[2] *= scale4[2];
+ rgbaBuffer[3] *= scale4[3];
+
+ rgbaBuffer += 4;
+ }
+ }
+
+ void ApplyOffset(float* rgbaBuffer, long numPixels,
+ const float* offset4)
+ {
+ for(long pixelIndex=0; pixelIndex<numPixels; ++pixelIndex)
+ {
+ rgbaBuffer[0] += offset4[0];
+ rgbaBuffer[1] += offset4[1];
+ rgbaBuffer[2] += offset4[2];
+ rgbaBuffer[3] += offset4[3];
+
+ rgbaBuffer += 4;
+ }
+ }
+
+ void ApplyMatrix(float* rgbaBuffer, long numPixels,
+ const float* mat44)
+ {
+ float r,g,b,a;
+
+ for(long pixelIndex=0; pixelIndex<numPixels; ++pixelIndex)
+ {
+ r = rgbaBuffer[0];
+ g = rgbaBuffer[1];
+ b = rgbaBuffer[2];
+ a = rgbaBuffer[3];
+
+ rgbaBuffer[0] = r*mat44[0] + g*mat44[1] + b*mat44[2] + a*mat44[3];
+ rgbaBuffer[1] = r*mat44[4] + g*mat44[5] + b*mat44[6] + a*mat44[7];
+ rgbaBuffer[2] = r*mat44[8] + g*mat44[9] + b*mat44[10] + a*mat44[11];
+ rgbaBuffer[3] = r*mat44[12] + g*mat44[13] + b*mat44[14] + a*mat44[15];
+
+ rgbaBuffer += 4;
+ }
+ }
+ }
+
+
+
+
+
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+
+
+ namespace
+ {
+ class MatrixOffsetOp : public Op
+ {
+ public:
+ MatrixOffsetOp(const float * m44,
+ const float * offset4,
+ TransformDirection direction);
+ virtual ~MatrixOffsetOp();
+
+ virtual OpRcPtr clone() const;
+
+ virtual std::string getInfo() const;
+ virtual std::string getCacheID() const;
+
+ virtual bool isNoOp() const;
+ virtual bool isSameType(const OpRcPtr & op) const;
+ virtual bool isInverse(const OpRcPtr & op) const;
+ virtual bool canCombineWith(const OpRcPtr & op) const;
+ virtual void combineWith(OpRcPtrVec & ops, const OpRcPtr & secondOp) const;
+
+ virtual bool hasChannelCrosstalk() const;
+ virtual void finalize();
+ virtual void apply(float* rgbaBuffer, long numPixels) const;
+
+ virtual bool supportsGpuShader() const;
+ virtual void writeGpuShader(std::ostream & shader,
+ const std::string & pixelName,
+ const GpuShaderDesc & shaderDesc) const;
+
+ private:
+ bool m_isNoOp;
+ float m_m44[16];
+ float m_offset4[4];
+ TransformDirection m_direction;
+
+ // Set in finalize
+ bool m_m44IsIdentity;
+ bool m_m44IsDiagonal;
+ bool m_offset4IsIdentity;
+ float m_m44_inv[16];
+ std::string m_cacheID;
+ };
+
+
+ typedef OCIO_SHARED_PTR<MatrixOffsetOp> MatrixOffsetOpRcPtr;
+
+
+ MatrixOffsetOp::MatrixOffsetOp(const float * m44,
+ const float * offset4,
+ TransformDirection direction):
+ Op(),
+ m_isNoOp(false),
+ m_direction(direction),
+ m_m44IsIdentity(false),
+ m_offset4IsIdentity(false)
+ {
+ if(m_direction == TRANSFORM_DIR_UNKNOWN)
+ {
+ throw Exception("Cannot apply MatrixOffsetOp op, unspecified transform direction.");
+ }
+
+ memcpy(m_m44, m44, 16*sizeof(float));
+ memcpy(m_offset4, offset4, 4*sizeof(float));
+
+ memset(m_m44_inv, 0, 16*sizeof(float));
+
+ // This Op will be a NoOp if and old if both the offset and matrix
+ // are identity. This hold true no matter what the direction is,
+ // so we can compute this ahead of time.
+ m_isNoOp = (IsVecEqualToZero(m_offset4, 4) && IsM44Identity(m_m44));
+ }
+
+ OpRcPtr MatrixOffsetOp::clone() const
+ {
+ OpRcPtr op = OpRcPtr(new MatrixOffsetOp(m_m44, m_offset4, m_direction));
+ return op;
+ }
+
+ MatrixOffsetOp::~MatrixOffsetOp()
+ { }
+
+ std::string MatrixOffsetOp::getInfo() const
+ {
+ return "<MatrixOffsetOp>";
+ }
+
+ std::string MatrixOffsetOp::getCacheID() const
+ {
+ return m_cacheID;
+ }
+
+ bool MatrixOffsetOp::isNoOp() const
+ {
+ return m_isNoOp;
+ }
+
+ bool MatrixOffsetOp::isSameType(const OpRcPtr & op) const
+ {
+ MatrixOffsetOpRcPtr typedRcPtr = DynamicPtrCast<MatrixOffsetOp>(op);
+ if(!typedRcPtr) return false;
+ return true;
+ }
+
+ bool MatrixOffsetOp::isInverse(const OpRcPtr & op) const
+ {
+ MatrixOffsetOpRcPtr typedRcPtr = DynamicPtrCast<MatrixOffsetOp>(op);
+ if(!typedRcPtr) return false;
+
+ if(GetInverseTransformDirection(m_direction) != typedRcPtr->m_direction)
+ return false;
+
+ float error = std::numeric_limits<float>::min();
+ if(!VecsEqualWithRelError(m_m44, 16, typedRcPtr->m_m44, 16, error))
+ return false;
+ if(!VecsEqualWithRelError(m_offset4, 4,typedRcPtr->m_offset4, 4, error))
+ return false;
+
+ return true;
+ }
+
+ bool MatrixOffsetOp::canCombineWith(const OpRcPtr & op) const
+ {
+ return isSameType(op);
+ }
+
+ void MatrixOffsetOp::combineWith(OpRcPtrVec & ops, const OpRcPtr & secondOp) const
+ {
+ MatrixOffsetOpRcPtr typedRcPtr = DynamicPtrCast<MatrixOffsetOp>(secondOp);
+ if(!typedRcPtr)
+ {
+ std::ostringstream os;
+ os << "MatrixOffsetOp can only be combined with other ";
+ os << "MatrixOffsetOps. secondOp:" << secondOp->getInfo();
+ throw Exception(os.str().c_str());
+ }
+
+ float mout[16];
+ float vout[4];
+
+ if(m_direction == TRANSFORM_DIR_FORWARD &&
+ typedRcPtr->m_direction == TRANSFORM_DIR_FORWARD)
+ {
+ GetMxbCombine(mout, vout,
+ m_m44, m_offset4,
+ typedRcPtr->m_m44, typedRcPtr->m_offset4);
+ }
+ else if(m_direction == TRANSFORM_DIR_FORWARD &&
+ typedRcPtr->m_direction == TRANSFORM_DIR_INVERSE)
+ {
+ float minv2[16];
+ float vinv2[4];
+
+ if(!GetMxbInverse(minv2, vinv2, typedRcPtr->m_m44, typedRcPtr->m_offset4))
+ {
+ std::ostringstream os;
+ os << "Cannot invert second MatrixOffsetOp op. ";
+ os << "Matrix inverse does not exist for (";
+ for(int i=0; i<16; ++i)
+ {
+ os << typedRcPtr->m_m44[i] << " ";
+ }
+ os << ").";
+ throw Exception(os.str().c_str());
+ }
+
+ GetMxbCombine(mout, vout,
+ m_m44, m_offset4,
+ minv2, vinv2);
+ }
+ else if(m_direction == TRANSFORM_DIR_INVERSE &&
+ typedRcPtr->m_direction == TRANSFORM_DIR_FORWARD)
+ {
+ float minv1[16];
+ float vinv1[4];
+
+ if(!GetMxbInverse(minv1, vinv1, m_m44, m_offset4))
+ {
+ std::ostringstream os;
+ os << "Cannot invert primary MatrixOffsetOp op. ";
+ os << "Matrix inverse does not exist for (";
+ for(int i=0; i<16; ++i)
+ {
+ os << m_m44[i] << " ";
+ }
+ os << ").";
+ throw Exception(os.str().c_str());
+ }
+
+ GetMxbCombine(mout, vout,
+ minv1, vinv1,
+ typedRcPtr->m_m44, typedRcPtr->m_offset4);
+
+ }
+ else if(m_direction == TRANSFORM_DIR_INVERSE &&
+ typedRcPtr->m_direction == TRANSFORM_DIR_INVERSE)
+ {
+ float minv1[16];
+ float vinv1[4];
+ float minv2[16];
+ float vinv2[4];
+
+ if(!GetMxbInverse(minv1, vinv1, m_m44, m_offset4))
+ {
+ std::ostringstream os;
+ os << "Cannot invert primary MatrixOffsetOp op. ";
+ os << "Matrix inverse does not exist for (";
+ for(int i=0; i<16; ++i)
+ {
+ os << m_m44[i] << " ";
+ }
+ os << ").";
+ throw Exception(os.str().c_str());
+ }
+
+ if(!GetMxbInverse(minv2, vinv2, typedRcPtr->m_m44, typedRcPtr->m_offset4))
+ {
+ std::ostringstream os;
+ os << "Cannot invert second MatrixOffsetOp op. ";
+ os << "Matrix inverse does not exist for (";
+ for(int i=0; i<16; ++i)
+ {
+ os << typedRcPtr->m_m44[i] << " ";
+ }
+ os << ").";
+ throw Exception(os.str().c_str());
+ }
+
+ GetMxbCombine(mout, vout,
+ minv1, vinv1,
+ minv2, vinv2);
+ }
+ else
+ {
+ std::ostringstream os;
+ os << "MatrixOffsetOp cannot combine ops with unspecified ";
+ os << "directions. First op: " << m_direction << " ";
+ os << "secondOp:" << typedRcPtr->m_direction;
+ throw Exception(os.str().c_str());
+ }
+
+ CreateMatrixOffsetOp(ops,
+ mout, vout,
+ TRANSFORM_DIR_FORWARD);
+ }
+
+ bool MatrixOffsetOp::hasChannelCrosstalk() const
+ {
+ return (!m_m44IsDiagonal);
+ }
+
+ void MatrixOffsetOp::finalize()
+ {
+ m_offset4IsIdentity = IsVecEqualToZero(m_offset4, 4);
+ m_m44IsIdentity = IsM44Identity(m_m44);
+ m_m44IsDiagonal = IsM44Diagonal(m_m44);
+
+ if(m_direction == TRANSFORM_DIR_INVERSE)
+ {
+ if(!GetM44Inverse(m_m44_inv, m_m44))
+ {
+ std::ostringstream os;
+ os << "Cannot apply MatrixOffsetOp op. ";
+ os << "Matrix inverse does not exist for m44 (";
+ for(int i=0; i<16; ++i) os << m_m44[i] << " ";
+ os << ").";
+ throw Exception(os.str().c_str());
+ }
+ }
+
+ // Create the cacheID
+ md5_state_t state;
+ md5_byte_t digest[16];
+ md5_init(&state);
+ md5_append(&state, (const md5_byte_t *)m_m44, 16*sizeof(float));
+ md5_append(&state, (const md5_byte_t *)m_offset4, 4*sizeof(float));
+ md5_finish(&state, digest);
+
+ std::ostringstream cacheIDStream;
+ cacheIDStream << "<MatrixOffsetOp ";
+ cacheIDStream << GetPrintableHash(digest) << " ";
+ cacheIDStream << TransformDirectionToString(m_direction) << " ";
+ cacheIDStream << ">";
+
+ m_cacheID = cacheIDStream.str();
+ }
+
+ void MatrixOffsetOp::apply(float* rgbaBuffer, long numPixels) const
+ {
+ if(m_direction == TRANSFORM_DIR_FORWARD)
+ {
+ if(!m_m44IsIdentity)
+ {
+ if(m_m44IsDiagonal)
+ {
+ float scale[4];
+ GetM44Diagonal(scale, m_m44);
+ ApplyScale(rgbaBuffer, numPixels, scale);
+ }
+ else
+ {
+ ApplyMatrix(rgbaBuffer, numPixels, m_m44);
+ }
+ }
+
+ if(!m_offset4IsIdentity)
+ {
+ ApplyOffset(rgbaBuffer, numPixels, m_offset4);
+ }
+ }
+ else if(m_direction == TRANSFORM_DIR_INVERSE)
+ {
+ if(!m_offset4IsIdentity)
+ {
+ float offset_inv[] = { -m_offset4[0],
+ -m_offset4[1],
+ -m_offset4[2],
+ -m_offset4[3] };
+
+ ApplyOffset(rgbaBuffer, numPixels, offset_inv);
+ }
+
+ if(!m_m44IsIdentity)
+ {
+ if(m_m44IsDiagonal)
+ {
+ float scale[4];
+ GetM44Diagonal(scale, m_m44_inv);
+ ApplyScale(rgbaBuffer, numPixels, scale);
+ }
+ else
+ {
+ ApplyMatrix(rgbaBuffer, numPixels, m_m44_inv);
+ }
+ }
+ }
+ } // Op::process
+
+ bool MatrixOffsetOp::supportsGpuShader() const
+ {
+ return true;
+ }
+
+ void MatrixOffsetOp::writeGpuShader(std::ostream & shader,
+ const std::string & pixelName,
+ const GpuShaderDesc & shaderDesc) const
+ {
+ GpuLanguage lang = shaderDesc.getLanguage();
+
+ // TODO: This should not act upon alpha,
+ // since we dont apply it on the CPU?
+
+ if(m_direction == TRANSFORM_DIR_FORWARD)
+ {
+ if(!m_m44IsIdentity)
+ {
+ if(m_m44IsDiagonal)
+ {
+ shader << pixelName << " = ";
+ float scale[4];
+ GetM44Diagonal(scale, m_m44);
+ Write_half4(shader, scale, lang);
+ shader << " * " << pixelName << ";\n";
+ }
+ else
+ {
+ shader << pixelName << " = ";
+ Write_mtx_x_vec(shader,
+ GpuTextHalf4x4(m_m44, lang), pixelName,
+ lang);
+ shader << ";\n";
+ }
+ }
+
+ if(!m_offset4IsIdentity)
+ {
+ shader << pixelName << " = ";
+ Write_half4(shader, m_offset4, lang);
+ shader << " + " << pixelName << ";\n";
+ }
+ }
+ else if(m_direction == TRANSFORM_DIR_INVERSE)
+ {
+ if(!m_offset4IsIdentity)
+ {
+ float offset_inv[] = { -m_offset4[0],
+ -m_offset4[1],
+ -m_offset4[2],
+ -m_offset4[3] };
+
+ shader << pixelName << " = ";
+ Write_half4(shader, offset_inv, lang);
+ shader << " + " << pixelName << ";\n";
+ }
+
+ if(!m_m44IsIdentity)
+ {
+ if(m_m44IsDiagonal)
+ {
+ shader << pixelName << " = ";
+ float scale[4];
+ GetM44Diagonal(scale, m_m44_inv);
+ Write_half4(shader, scale, lang);
+ shader << " * " << pixelName << ";\n";
+ }
+ else
+ {
+ shader << pixelName << " = ";
+ Write_mtx_x_vec(shader,
+ GpuTextHalf4x4(m_m44_inv, lang), pixelName,
+ lang);
+ shader << ";\n";
+ }
+ }
+ }
+ }
+
+ } // Anon namespace
+
+
+
+
+
+
+
+
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+
+
+
+ void CreateScaleOp(OpRcPtrVec & ops,
+ const float * scale4,
+ TransformDirection direction)
+ {
+ float offset4[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ CreateScaleOffsetOp(ops, scale4, offset4, direction);
+ }
+
+ void CreateMatrixOp(OpRcPtrVec & ops,
+ const float * m44,
+ TransformDirection direction)
+ {
+ float offset4[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ CreateMatrixOffsetOp(ops, m44, offset4, direction);
+ }
+
+ void CreateOffsetOp(OpRcPtrVec & ops,
+ const float * offset4,
+ TransformDirection direction)
+ {
+ float scale4[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
+ CreateScaleOffsetOp(ops, scale4, offset4, direction);
+ }
+
+ void CreateScaleOffsetOp(OpRcPtrVec & ops,
+ const float * scale4, const float * offset4,
+ TransformDirection direction)
+ {
+ float m44[16];
+ memset(m44, 0, 16*sizeof(float));
+
+ m44[0] = scale4[0];
+ m44[5] = scale4[1];
+ m44[10] = scale4[2];
+ m44[15] = scale4[3];
+
+ CreateMatrixOffsetOp(ops,
+ m44, offset4,
+ direction);
+ }
+
+ void CreateSaturationOp(OpRcPtrVec & ops,
+ float sat,
+ const float * lumaCoef3,
+ TransformDirection direction)
+ {
+ float matrix[16];
+ float offset[4];
+ MatrixTransform::Sat(matrix, offset,
+ sat, lumaCoef3);
+
+ CreateMatrixOffsetOp(ops, matrix, offset, direction);
+ }
+
+ void CreateMatrixOffsetOp(OpRcPtrVec & ops,
+ const float * m44, const float * offset4,
+ TransformDirection direction)
+ {
+ bool mtxIsIdentity = IsM44Identity(m44);
+ bool offsetIsIdentity = IsVecEqualToZero(offset4, 4);
+ if(mtxIsIdentity && offsetIsIdentity) return;
+
+ ops.push_back( MatrixOffsetOpRcPtr(new MatrixOffsetOp(m44,
+ offset4, direction)) );
+ }
+
+ void CreateFitOp(OpRcPtrVec & ops,
+ const float * oldmin4, const float * oldmax4,
+ const float * newmin4, const float * newmax4,
+ TransformDirection direction)
+ {
+ float matrix[16];
+ float offset[4];
+ MatrixTransform::Fit(matrix, offset,
+ oldmin4, oldmax4,
+ newmin4, newmax4);
+
+ CreateMatrixOffsetOp(ops, matrix, offset, direction);
+ }
+
+}
+OCIO_NAMESPACE_EXIT
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+#ifdef OCIO_UNIT_TEST
+
+namespace OCIO = OCIO_NAMESPACE;
+#include "UnitTest.h"
+
+OCIO_NAMESPACE_USING
+
+OIIO_ADD_TEST(MatrixOps, Combining)
+{
+ float m1[16] = { 1.1f, 0.2f, 0.3f, 0.4f,
+ 0.5f, 1.6f, 0.7f, 0.8f,
+ 0.2f, 0.1f, 1.1f, 0.2f,
+ 0.3f, 0.4f, 0.5f, 1.6f };
+
+ float v1[4] = { -0.5f, -0.25f, 0.25f, 0.0f };
+
+ float m2[16] = { 1.1f, -0.1f, -0.1f, 0.0f,
+ 0.1f, 0.9f, -0.2f, 0.0f,
+ 0.05f, 0.0f, 1.1f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f };
+ float v2[4] = { -0.2f, -0.1f, -0.1f, -0.2f };
+
+ const float source[] = { 0.1f, 0.2f, 0.3f, 0.4f,
+ -0.1f, -0.2f, 50.0f, 123.4f,
+ 1.0f, 1.0f, 1.0f, 1.0f };
+ float error = 1e-4f;
+
+ {
+ OpRcPtrVec ops;
+ CreateMatrixOffsetOp(ops, m1, v1, TRANSFORM_DIR_FORWARD);
+ CreateMatrixOffsetOp(ops, m2, v2, TRANSFORM_DIR_FORWARD);
+ OIIO_CHECK_EQUAL(ops.size(), 2);
+ ops[0]->finalize();
+ ops[1]->finalize();
+
+ OpRcPtrVec combined;
+ ops[0]->combineWith(combined, ops[1]);
+ OIIO_CHECK_EQUAL(combined.size(), 1);
+ combined[0]->finalize();
+
+ for(int test=0; test<3; ++test)
+ {
+ float tmp[4];
+ memcpy(tmp, &source[4*test], 4*sizeof(float));
+ ops[0]->apply(tmp, 1);
+ ops[1]->apply(tmp, 1);
+
+ float tmp2[4];
+ memcpy(tmp2, &source[4*test], 4*sizeof(float));
+ combined[0]->apply(tmp2, 1);
+
+ for(unsigned int i=0; i<4; ++i)
+ {
+ OIIO_CHECK_CLOSE(tmp2[i], tmp[i], error);
+ }
+ }
+ }
+
+
+ {
+ OpRcPtrVec ops;
+ CreateMatrixOffsetOp(ops, m1, v1, TRANSFORM_DIR_FORWARD);
+ CreateMatrixOffsetOp(ops, m2, v2, TRANSFORM_DIR_INVERSE);
+ OIIO_CHECK_EQUAL(ops.size(), 2);
+ ops[0]->finalize();
+ ops[1]->finalize();
+
+ OpRcPtrVec combined;
+ ops[0]->combineWith(combined, ops[1]);
+ OIIO_CHECK_EQUAL(combined.size(), 1);
+ combined[0]->finalize();
+
+
+ for(int test=0; test<3; ++test)
+ {
+ float tmp[4];
+ memcpy(tmp, &source[4*test], 4*sizeof(float));
+ ops[0]->apply(tmp, 1);
+ ops[1]->apply(tmp, 1);
+
+ float tmp2[4];
+ memcpy(tmp2, &source[4*test], 4*sizeof(float));
+ combined[0]->apply(tmp2, 1);
+
+ for(unsigned int i=0; i<4; ++i)
+ {
+ OIIO_CHECK_CLOSE(tmp2[i], tmp[i], error);
+ }
+ }
+ }
+
+ {
+ OpRcPtrVec ops;
+ CreateMatrixOffsetOp(ops, m1, v1, TRANSFORM_DIR_INVERSE);
+ CreateMatrixOffsetOp(ops, m2, v2, TRANSFORM_DIR_FORWARD);
+ OIIO_CHECK_EQUAL(ops.size(), 2);
+ ops[0]->finalize();
+ ops[1]->finalize();
+
+ OpRcPtrVec combined;
+ ops[0]->combineWith(combined, ops[1]);
+ OIIO_CHECK_EQUAL(combined.size(), 1);
+ combined[0]->finalize();
+
+ for(int test=0; test<3; ++test)
+ {
+ float tmp[4];
+ memcpy(tmp, &source[4*test], 4*sizeof(float));
+ ops[0]->apply(tmp, 1);
+ ops[1]->apply(tmp, 1);
+
+ float tmp2[4];
+ memcpy(tmp2, &source[4*test], 4*sizeof(float));
+ combined[0]->apply(tmp2, 1);
+
+ for(unsigned int i=0; i<4; ++i)
+ {
+ OIIO_CHECK_CLOSE(tmp2[i], tmp[i], error);
+ }
+ }
+ }
+
+ {
+ OpRcPtrVec ops;
+ CreateMatrixOffsetOp(ops, m1, v1, TRANSFORM_DIR_INVERSE);
+ CreateMatrixOffsetOp(ops, m2, v2, TRANSFORM_DIR_INVERSE);
+ OIIO_CHECK_EQUAL(ops.size(), 2);
+ ops[0]->finalize();
+ ops[1]->finalize();
+
+ OpRcPtrVec combined;
+ ops[0]->combineWith(combined, ops[1]);
+ OIIO_CHECK_EQUAL(combined.size(), 1);
+ combined[0]->finalize();
+
+ for(int test=0; test<3; ++test)
+ {
+ float tmp[4];
+ memcpy(tmp, &source[4*test], 4*sizeof(float));
+ ops[0]->apply(tmp, 1);
+ ops[1]->apply(tmp, 1);
+
+ float tmp2[4];
+ memcpy(tmp2, &source[4*test], 4*sizeof(float));
+ combined[0]->apply(tmp2, 1);
+
+ for(unsigned int i=0; i<4; ++i)
+ {
+ OIIO_CHECK_CLOSE(tmp2[i], tmp[i], error);
+ }
+ }
+ }
+}
+
+#endif
diff --git a/src/core/MatrixOps.h b/src/core/MatrixOps.h
new file mode 100644
index 0000000..e462706
--- /dev/null
+++ b/src/core/MatrixOps.h
@@ -0,0 +1,75 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_MATRIXOFFSETOP_H
+#define INCLUDED_OCIO_MATRIXOFFSETOP_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "Op.h"
+
+#include <vector>
+
+OCIO_NAMESPACE_ENTER
+{
+ // Use whichever is most convenient; they are equally efficient
+
+ void CreateScaleOp(OpRcPtrVec & ops,
+ const float * scale4,
+ TransformDirection direction);
+
+ void CreateMatrixOp(OpRcPtrVec & ops,
+ const float * m44,
+ TransformDirection direction);
+
+ void CreateOffsetOp(OpRcPtrVec & ops,
+ const float * offset4,
+ TransformDirection direction);
+
+ void CreateMatrixOffsetOp(OpRcPtrVec & ops,
+ const float * m44, const float * offset4,
+ TransformDirection direction);
+
+ void CreateScaleOffsetOp(OpRcPtrVec & ops,
+ const float * scale4, const float * offset4,
+ TransformDirection direction);
+
+ void CreateFitOp(OpRcPtrVec & ops,
+ const float * oldmin4, const float * oldmax4,
+ const float * newmin4, const float * newmax4,
+ TransformDirection direction);
+
+ void CreateSaturationOp(OpRcPtrVec & ops,
+ float sat,
+ const float * lumaCoef3,
+ TransformDirection direction);
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/MatrixTransform.cpp b/src/core/MatrixTransform.cpp
new file mode 100644
index 0000000..cb88327
--- /dev/null
+++ b/src/core/MatrixTransform.cpp
@@ -0,0 +1,386 @@
+/*
+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 <cstring>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "OpBuilders.h"
+#include "MatrixOps.h"
+#include "MathUtils.h"
+
+
+OCIO_NAMESPACE_ENTER
+{
+ MatrixTransformRcPtr MatrixTransform::Create()
+ {
+ return MatrixTransformRcPtr(new MatrixTransform(), &deleter);
+ }
+
+ void MatrixTransform::deleter(MatrixTransform* t)
+ {
+ delete t;
+ }
+
+ class MatrixTransform::Impl
+ {
+ public:
+ TransformDirection dir_;
+ float matrix_[16];
+ float offset_[4];
+
+ Impl() :
+ dir_(TRANSFORM_DIR_FORWARD)
+ {
+ Identity(matrix_, offset_);
+ }
+
+ ~Impl()
+ { }
+
+ Impl& operator= (const Impl & rhs)
+ {
+ dir_ = rhs.dir_;
+ memcpy(matrix_, rhs.matrix_, 16*sizeof(float));
+ memcpy(offset_, rhs.offset_, 4*sizeof(float));
+ return *this;
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+
+ MatrixTransform::MatrixTransform()
+ : m_impl(new MatrixTransform::Impl)
+ {
+ }
+
+ TransformRcPtr MatrixTransform::createEditableCopy() const
+ {
+ MatrixTransformRcPtr transform = MatrixTransform::Create();
+ *(transform->m_impl) = *m_impl;
+ return transform;
+ }
+
+ MatrixTransform::~MatrixTransform()
+ {
+ delete m_impl;
+ m_impl = NULL;
+ }
+
+ MatrixTransform& MatrixTransform::operator= (const MatrixTransform & rhs)
+ {
+ *m_impl = *rhs.m_impl;
+ return *this;
+ }
+
+ TransformDirection MatrixTransform::getDirection() const
+ {
+ return getImpl()->dir_;
+ }
+
+ void MatrixTransform::setDirection(TransformDirection dir)
+ {
+ getImpl()->dir_ = dir;
+ }
+
+ bool MatrixTransform::equals(const MatrixTransform & other) const
+ {
+ const float abserror = 1e-9f;
+
+ for(int i=0; i<16; ++i)
+ {
+ if(!equalWithAbsError(getImpl()->matrix_[i],
+ other.getImpl()->matrix_[i], abserror))
+ {
+ return false;
+ }
+ }
+
+ for(int i=0; i<4; ++i)
+ {
+ if(!equalWithAbsError(getImpl()->offset_[i],
+ other.getImpl()->offset_[i], abserror))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ void MatrixTransform::getValue(float * m44, float * offset4) const
+ {
+ if(m44) memcpy(m44, getImpl()->matrix_, 16*sizeof(float));
+ if(offset4) memcpy(offset4, getImpl()->offset_, 4*sizeof(float));
+ }
+
+ void MatrixTransform::setValue(const float * m44, const float * offset4)
+ {
+ if(m44) memcpy(getImpl()->matrix_, m44, 16*sizeof(float));
+ if(offset4) memcpy(getImpl()->offset_, offset4, 4*sizeof(float));
+ }
+
+ void MatrixTransform::setMatrix(const float * m44)
+ {
+ if(m44) memcpy(getImpl()->matrix_, m44, 16*sizeof(float));
+ }
+
+ void MatrixTransform::getMatrix(float * m44) const
+ {
+ if(m44) memcpy(m44, getImpl()->matrix_, 16*sizeof(float));
+ }
+
+ void MatrixTransform::setOffset(const float * offset4)
+ {
+ if(offset4) memcpy(getImpl()->offset_, offset4, 4*sizeof(float));
+ }
+
+ void MatrixTransform::getOffset(float * offset4) const
+ {
+ if(offset4) memcpy(offset4, getImpl()->offset_, 4*sizeof(float));
+ }
+
+ /*
+ Fit is canonically formulated as:
+ out = newmin + ((value-oldmin)/(oldmax-oldmin)*(newmax-newmin))
+ I.e., subtract the old offset, descale into the [0,1] range,
+ scale into the new range, and add the new offset
+
+ We algebraiclly manipulate the terms into y = mx + b form as:
+ m = (newmax-newmin)/(oldmax-oldmin)
+ b = (newmin*oldmax - newmax*oldmin) / (oldmax-oldmin)
+ */
+
+ void MatrixTransform::Fit(float * m44, float * offset4,
+ const float * oldmin4, const float * oldmax4,
+ const float * newmin4, const float * newmax4)
+ {
+ if(!oldmin4 || !oldmax4) return;
+ if(!newmin4 || !newmax4) return;
+
+ if(m44) memset(m44, 0, 16*sizeof(float));
+ if(offset4) memset(offset4, 0, 4*sizeof(float));
+
+ for(int i=0; i<4; ++i)
+ {
+ float denom = oldmax4[i] - oldmin4[i];
+ if(IsScalarEqualToZero(denom))
+ {
+ std::ostringstream os;
+ os << "Cannot create Fit operator. ";
+ os << "Max value equals min value '";
+ os << oldmax4[i] << "' in channel index ";
+ os << i << ".";
+ throw Exception(os.str().c_str());
+ }
+
+ if(m44) m44[5*i] = (newmax4[i]-newmin4[i]) / denom;
+ if(offset4) offset4[i] = (newmin4[i]*oldmax4[i] - newmax4[i]*oldmin4[i]) / denom;
+ }
+ }
+
+
+ void MatrixTransform::Identity(float * m44, float * offset4)
+ {
+ if(m44)
+ {
+ memset(m44, 0, 16*sizeof(float));
+ m44[0] = 1.0f;
+ m44[5] = 1.0f;
+ m44[10] = 1.0f;
+ m44[15] = 1.0f;
+ }
+
+ if(offset4)
+ {
+ offset4[0] = 0.0f;
+ offset4[1] = 0.0f;
+ offset4[2] = 0.0f;
+ offset4[3] = 0.0f;
+ }
+ }
+
+ void MatrixTransform::Sat(float * m44, float * offset4,
+ float sat, const float * lumaCoef3)
+ {
+ if(!lumaCoef3) return;
+
+ if(m44)
+ {
+ m44[0] = (1 - sat) * lumaCoef3[0] + sat;
+ m44[1] = (1 - sat) * lumaCoef3[1];
+ m44[2] = (1 - sat) * lumaCoef3[2];
+ m44[3] = 0.0f;
+
+ m44[4] = (1 - sat) * lumaCoef3[0];
+ m44[5] = (1 - sat) * lumaCoef3[1] + sat;
+ m44[6] = (1 - sat) * lumaCoef3[2];
+ m44[7] = 0.0f;
+
+ m44[8] = (1 - sat) * lumaCoef3[0];
+ m44[9] = (1 - sat) * lumaCoef3[1];
+ m44[10] = (1 - sat) * lumaCoef3[2] + sat;
+ m44[11] = 0.0f;
+
+ m44[12] = 0.0f;
+ m44[13] = 0.0f;
+ m44[14] = 0.0f;
+ m44[15] = 1.0f;
+ }
+
+ if(offset4)
+ {
+ offset4[0] = 0.0f;
+ offset4[1] = 0.0f;
+ offset4[2] = 0.0f;
+ offset4[3] = 0.0f;
+ }
+ }
+
+ void MatrixTransform::Scale(float * m44, float * offset4,
+ const float * scale4)
+ {
+ if(!scale4) return;
+
+ if(m44)
+ {
+ memset(m44, 0, 16*sizeof(float));
+ m44[0] = scale4[0];
+ m44[5] = scale4[1];
+ m44[10] = scale4[2];
+ m44[15] = scale4[3];
+ }
+
+ if(offset4)
+ {
+ offset4[0] = 0.0f;
+ offset4[1] = 0.0f;
+ offset4[2] = 0.0f;
+ offset4[3] = 0.0f;
+ }
+ }
+
+ void MatrixTransform::View(float * m44, float * offset4,
+ int * channelHot4,
+ const float * lumaCoef3)
+ {
+ if(!channelHot4 || !lumaCoef3) return;
+
+ if(offset4)
+ {
+ offset4[0] = 0.0f;
+ offset4[1] = 0.0f;
+ offset4[2] = 0.0f;
+ offset4[3] = 0.0f;
+ }
+
+ if(m44)
+ {
+ memset(m44, 0, 16*sizeof(float));
+
+ // All channels are hot, return identity
+ if(channelHot4[0] && channelHot4[1] &&
+ channelHot4[2] && channelHot4[3])
+ {
+ Identity(m44, 0x0);
+ }
+ // If not all the channels are hot, but alpha is,
+ // just show it.
+ else if(channelHot4[3])
+ {
+ for(int i=0; i<4; ++i)
+ {
+ m44[4*i+3] = 1.0f;
+ }
+ }
+ // Blend rgb as specified, place it in all 3 output
+ // channels (to make a grayscale final image)
+ else
+ {
+ float values[3] = { 0.0f, 0.0f, 0.0f };
+
+ for(int i = 0; i < 3; ++i)
+ {
+ values[i] += lumaCoef3[i] * (channelHot4[i] ? 1.0f : 0.0f);
+ }
+
+ float sum = values[0] + values[1] + values[2];
+ if(!IsScalarEqualToZero(sum))
+ {
+ values[0] /= sum;
+ values[1] /= sum;
+ values[2] /= sum;
+ }
+
+ // Copy rgb into rgb rows
+ for(int row=0; row<3; ++row)
+ {
+ for(int i=0; i<3; i++)
+ {
+ m44[4*row+i] = values[i];
+ }
+ }
+
+ // Preserve alpha
+ m44[15] = 1.0f;
+ }
+ }
+ }
+
+ std::ostream& operator<< (std::ostream& os, const MatrixTransform& t)
+ {
+ os << "<MatrixTransform ";
+ os << "direction=" << TransformDirectionToString(t.getDirection()) << ", ";
+ os << ">\n";
+ return os;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ void BuildMatrixOps(OpRcPtrVec & ops,
+ const Config& /*config*/,
+ const MatrixTransform & transform,
+ TransformDirection dir)
+ {
+ TransformDirection combinedDir = CombineTransformDirections(dir,
+ transform.getDirection());
+
+ float matrix[16];
+ float offset[4];
+ transform.getValue(matrix, offset);
+
+ CreateMatrixOffsetOp(ops,
+ matrix, offset,
+ combinedDir);
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/Mutex.h b/src/core/Mutex.h
new file mode 100644
index 0000000..421ad29
--- /dev/null
+++ b/src/core/Mutex.h
@@ -0,0 +1,115 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_MUTEX_H
+#define INCLUDED_OCIO_MUTEX_H
+
+/*
+PTEX SOFTWARE
+Copyright 2009 Disney Enterprises, Inc. 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.
+
+ * The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
+ Studios" or the names of its contributors may NOT be used to
+ endorse or promote products derived from this software without
+ specific prior written permission from Walt Disney Pictures.
+
+Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
+CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
+IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER 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 BASED 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 DAMAGES.
+*/
+
+#include "Platform.h"
+
+// #define DEBUG_THREADING
+
+/** For internal use only */
+
+OCIO_NAMESPACE_ENTER
+{
+
+#ifndef NDEBUG
+ template <class T>
+ class DebugLock : public T {
+ public:
+ DebugLock() : _locked(0) {}
+ void lock() { T::lock(); _locked = 1; }
+ void unlock() { assert(_locked); _locked = 0; T::unlock(); }
+ bool locked() { return _locked != 0; }
+ private:
+ int _locked;
+ };
+#endif
+
+ /** Automatically acquire and release lock within enclosing scope. */
+ template <class T>
+ class AutoLock {
+ public:
+ AutoLock(T& m) : _m(m) { _m.lock(); }
+ ~AutoLock() { _m.unlock(); }
+ private:
+ T& _m;
+ };
+
+#ifndef NDEBUG
+ // add debug wrappers to mutex and spinlock
+ typedef DebugLock<_Mutex> Mutex;
+ typedef DebugLock<_SpinLock> SpinLock;
+#else
+ typedef _Mutex Mutex;
+ typedef _SpinLock SpinLock;
+#endif
+
+ typedef AutoLock<Mutex> AutoMutex;
+ typedef AutoLock<SpinLock> AutoSpin;
+
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/NoOps.cpp b/src/core/NoOps.cpp
new file mode 100644
index 0000000..101324e
--- /dev/null
+++ b/src/core/NoOps.cpp
@@ -0,0 +1,641 @@
+/*
+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 <sstream>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "AllocationOp.h"
+#include "NoOps.h"
+#include "OpBuilders.h"
+#include "Op.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ class AllocationNoOp : public Op
+ {
+ public:
+ AllocationNoOp(const AllocationData & allocationData):
+ m_allocationData(allocationData) {}
+ virtual ~AllocationNoOp() {}
+
+ virtual OpRcPtr clone() const;
+
+ virtual std::string getInfo() const { return "<AllocationNoOp>"; }
+ virtual std::string getCacheID() const { return ""; }
+
+ virtual bool isNoOp() const { return true; }
+ virtual bool isSameType(const OpRcPtr & op) const;
+ virtual bool isInverse(const OpRcPtr & op) const;
+ virtual bool hasChannelCrosstalk() const { return false; }
+ virtual void finalize() { }
+ virtual void apply(float* /*rgbaBuffer*/, long /*numPixels*/) const { }
+
+ virtual bool supportsGpuShader() const { return true; }
+ virtual void writeGpuShader(std::ostream & /*shader*/,
+ const std::string & /*pixelName*/,
+ const GpuShaderDesc & /*shaderDesc*/) const
+ { }
+
+ void getGpuAllocation(AllocationData & allocation) const;
+
+ private:
+ AllocationData m_allocationData;
+ };
+
+ typedef OCIO_SHARED_PTR<AllocationNoOp> AllocationNoOpRcPtr;
+
+ OpRcPtr AllocationNoOp::clone() const
+ {
+ OpRcPtr op = OpRcPtr(new AllocationNoOp(m_allocationData));
+ return op;
+ }
+
+ bool AllocationNoOp::isSameType(const OpRcPtr & op) const
+ {
+ AllocationNoOpRcPtr typedRcPtr = DynamicPtrCast<AllocationNoOp>(op);
+ if(!typedRcPtr) return false;
+ return true;
+ }
+
+ bool AllocationNoOp::isInverse(const OpRcPtr & op) const
+ {
+ if(!isSameType(op)) return false;
+ return true;
+ }
+
+ void AllocationNoOp::getGpuAllocation(AllocationData & allocation) const
+ {
+ allocation = m_allocationData;
+ }
+
+ // Return whether the op defines an Allocation
+ bool DefinesGpuAllocation(const OpRcPtr & op)
+ {
+ AllocationNoOpRcPtr allocationNoOpRcPtr =
+ DynamicPtrCast<AllocationNoOp>(op);
+
+ if(allocationNoOpRcPtr) return true;
+ return false;
+ }
+ }
+
+ void CreateGpuAllocationNoOp(OpRcPtrVec & ops,
+ const AllocationData & allocationData)
+ {
+ ops.push_back( AllocationNoOpRcPtr(new AllocationNoOp(allocationData)) );
+ }
+
+
+ namespace
+ {
+ // Find the minimal index range in the opVec that does not support
+ // shader text generation. The endIndex *is* inclusive.
+ //
+ // I.e., if the entire opVec does not support GPUShaders, the
+ // result will be startIndex = 0, endIndex = opVec.size() - 1
+ //
+ // If the entire opVec supports GPU generation, both the
+ // startIndex and endIndex will equal -1
+
+ void GetGpuUnsupportedIndexRange(int * startIndex, int * endIndex,
+ const OpRcPtrVec & opVec)
+ {
+ int start = -1;
+ int end = -1;
+
+ for(unsigned int i=0; i<opVec.size(); ++i)
+ {
+ // We've found a gpu unsupported op.
+ // If it's the first, save it as our start.
+ // Otherwise, update the end.
+
+ if(!opVec[i]->supportsGpuShader())
+ {
+ if(start<0)
+ {
+ start = i;
+ end = i;
+ }
+ else end = i;
+ }
+ }
+
+ // Now that we've found a startIndex, walk back until we find
+ // one that defines a GpuAllocation. (we can only upload to
+ // the gpu at a location are tagged with an allocation)
+
+ while(start>0)
+ {
+ if(DefinesGpuAllocation(opVec[start])) break;
+ --start;
+ }
+
+ if(startIndex) *startIndex = start;
+ if(endIndex) *endIndex = end;
+ }
+
+
+ bool GetGpuAllocation(AllocationData & allocation,
+ const OpRcPtr & op)
+ {
+ AllocationNoOpRcPtr allocationNoOpRcPtr =
+ DynamicPtrCast<AllocationNoOp>(op);
+
+ if(!allocationNoOpRcPtr)
+ {
+ return false;
+ }
+
+ allocationNoOpRcPtr->getGpuAllocation(allocation);
+ return true;
+ }
+ }
+
+
+ void PartitionGPUOps(OpRcPtrVec & gpuPreOps,
+ OpRcPtrVec & gpuLatticeOps,
+ OpRcPtrVec & gpuPostOps,
+ const OpRcPtrVec & ops)
+ {
+ //
+ // Partition the original, raw opvec into 3 segments for GPU Processing
+ //
+ // gpuLatticeOps need not support analytical gpu shader generation
+ // the pre and post ops must support analytical generation.
+ // Additional ops will be inserted to take into account allocations
+ // transformations.
+
+
+ // This is used to bound our analytical shader text generation
+ // start index and end index are inclusive.
+
+ int gpuLut3DOpStartIndex = 0;
+ int gpuLut3DOpEndIndex = 0;
+ GetGpuUnsupportedIndexRange(&gpuLut3DOpStartIndex,
+ &gpuLut3DOpEndIndex,
+ ops);
+
+ // Write the entire shader using only shader text (3d lut is unused)
+ if(gpuLut3DOpStartIndex == -1 && gpuLut3DOpEndIndex == -1)
+ {
+ for(unsigned int i=0; i<ops.size(); ++i)
+ {
+ gpuPreOps.push_back( ops[i]->clone() );
+ }
+ }
+ // Analytical -> 3dlut -> analytical
+ else
+ {
+ // Handle analytical shader block before start index.
+ for(int i=0; i<gpuLut3DOpStartIndex; ++i)
+ {
+ gpuPreOps.push_back( ops[i]->clone() );
+ }
+
+ // Get the GPU Allocation at the cross-over point
+ // Create 2 symmetrically canceling allocation ops,
+ // where the shader text moves to a nicely allocated LDR
+ // (low dynamic range color space), and the lattice processing
+ // does the inverse (making the overall operation a no-op
+ // color-wise
+
+ AllocationData allocation;
+ if(gpuLut3DOpStartIndex<0 || gpuLut3DOpStartIndex>=(int)ops.size())
+ {
+ std::ostringstream error;
+ error << "Invalid GpuUnsupportedIndexRange: ";
+ error << "gpuLut3DOpStartIndex: " << gpuLut3DOpStartIndex << " ";
+ error << "gpuLut3DOpEndIndex: " << gpuLut3DOpEndIndex << " ";
+ error << "cpuOps.size: " << ops.size();
+ throw Exception(error.str().c_str());
+ }
+
+ // If the specified location defines an allocation, use it.
+ // It's possible that this index wont define an allocation.
+ // (For example in the case of getProcessor(FileTransform)
+ if(GetGpuAllocation(allocation, ops[gpuLut3DOpStartIndex]))
+ {
+ CreateAllocationOps(gpuPreOps, allocation,
+ TRANSFORM_DIR_FORWARD);
+ CreateAllocationOps(gpuLatticeOps, allocation,
+ TRANSFORM_DIR_INVERSE);
+ }
+
+ // Handle cpu lattice processing
+ for(int i=gpuLut3DOpStartIndex; i<=gpuLut3DOpEndIndex; ++i)
+ {
+ gpuLatticeOps.push_back( ops[i]->clone() );
+ }
+
+ // And then handle the gpu post processing
+ for(int i=gpuLut3DOpEndIndex+1; i<(int)ops.size(); ++i)
+ {
+ gpuPostOps.push_back( ops[i]->clone() );
+ }
+ }
+ }
+
+ void AssertPartitionIntegrity(OpRcPtrVec & gpuPreOps,
+ OpRcPtrVec & gpuLatticeOps,
+ OpRcPtrVec & gpuPostOps)
+ {
+ // All gpu pre ops must support analytical gpu shader generation
+ for(unsigned int i=0; i<gpuPreOps.size(); ++i)
+ {
+ if(!gpuPreOps[i]->supportsGpuShader())
+ {
+ throw Exception("Patition failed check. gpuPreOps");
+ }
+ }
+
+ // If there are any lattice ops, at lease one must NOT support GPU
+ // shaders (otherwise this block isnt necessary!)
+ if(gpuLatticeOps.size()>0)
+ {
+ bool requireslattice = false;
+ for(unsigned int i=0; i<gpuLatticeOps.size(); ++i)
+ {
+ if(!gpuLatticeOps[i]->supportsGpuShader()) requireslattice = true;
+ }
+
+ if(!requireslattice)
+ {
+ throw Exception("Patition failed check. gpuLatticeOps");
+ }
+ }
+
+ // All gpu post ops must support analytical gpu shader generation
+ for(unsigned int i=0; i<gpuPostOps.size(); ++i)
+ {
+ if(!gpuPostOps[i]->supportsGpuShader())
+ {
+ throw Exception("Patition failed check. gpuPostOps");
+ }
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ namespace
+ {
+ class FileNoOp : public Op
+ {
+ public:
+ FileNoOp(const std::string & fileReference):
+ m_fileReference(fileReference) {}
+ virtual ~FileNoOp() {}
+
+ virtual OpRcPtr clone() const;
+
+ virtual std::string getInfo() const { return "<FileNoOp>"; }
+ virtual std::string getCacheID() const { return ""; }
+
+ virtual bool isNoOp() const { return true; }
+ virtual bool isSameType(const OpRcPtr & op) const;
+ virtual bool isInverse(const OpRcPtr & op) const;
+ virtual bool hasChannelCrosstalk() const { return false; }
+ virtual void dumpMetadata(ProcessorMetadataRcPtr & metadata) const;
+
+ virtual void finalize() {}
+ virtual void apply(float* /*rgbaBuffer*/, long /*numPixels*/) const {}
+
+ virtual bool supportsGpuShader() const { return true; }
+ virtual void writeGpuShader(std::ostream & /*shader*/,
+ const std::string & /*pixelName*/,
+ const GpuShaderDesc & /*shaderDesc*/) const
+ { }
+
+ private:
+ std::string m_fileReference;
+ };
+
+ typedef OCIO_SHARED_PTR<FileNoOp> FileNoOpRcPtr;
+
+ OpRcPtr FileNoOp::clone() const
+ {
+ OpRcPtr op = OpRcPtr(new FileNoOp(m_fileReference));
+ return op;
+ }
+
+ bool FileNoOp::isSameType(const OpRcPtr & op) const
+ {
+ FileNoOpRcPtr typedRcPtr = DynamicPtrCast<FileNoOp>(op);
+ if(!typedRcPtr) return false;
+ return true;
+ }
+
+ bool FileNoOp::isInverse(const OpRcPtr & op) const
+ {
+ return isSameType(op);
+ }
+
+ void FileNoOp::dumpMetadata(ProcessorMetadataRcPtr & metadata) const
+ {
+ metadata->addFile(m_fileReference.c_str());
+ }
+ }
+
+ void CreateFileNoOp(OpRcPtrVec & ops,
+ const std::string & fileReference)
+ {
+ ops.push_back( FileNoOpRcPtr(new FileNoOp(fileReference)) );
+ }
+
+
+
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ namespace
+ {
+ class LookNoOp : public Op
+ {
+ public:
+ LookNoOp(const std::string & look):
+ m_look(look) {}
+ virtual ~LookNoOp() {}
+
+ virtual OpRcPtr clone() const;
+
+ virtual std::string getInfo() const { return "<LookNoOp>"; }
+ virtual std::string getCacheID() const { return ""; }
+
+ virtual bool isNoOp() const { return true; }
+ virtual bool isSameType(const OpRcPtr & op) const;
+ virtual bool isInverse(const OpRcPtr & op) const;
+ virtual bool hasChannelCrosstalk() const { return false; }
+ virtual void dumpMetadata(ProcessorMetadataRcPtr & metadata) const;
+
+ virtual void finalize() {}
+ virtual void apply(float* /*rgbaBuffer*/, long /*numPixels*/) const {}
+
+ virtual bool supportsGpuShader() const { return true; }
+ virtual void writeGpuShader(std::ostream & /*shader*/,
+ const std::string & /*pixelName*/,
+ const GpuShaderDesc & /*shaderDesc*/) const
+ { }
+
+ private:
+ std::string m_look;
+ };
+
+ typedef OCIO_SHARED_PTR<LookNoOp> LookNoOpRcPtr;
+
+ OpRcPtr LookNoOp::clone() const
+ {
+ OpRcPtr op = OpRcPtr(new FileNoOp(m_look));
+ return op;
+ }
+
+ bool LookNoOp::isSameType(const OpRcPtr & op) const
+ {
+ FileNoOpRcPtr typedRcPtr = DynamicPtrCast<FileNoOp>(op);
+ if(!typedRcPtr) return false;
+ return true;
+ }
+
+ bool LookNoOp::isInverse(const OpRcPtr & op) const
+ {
+ return isSameType(op);
+ }
+
+ void LookNoOp::dumpMetadata(ProcessorMetadataRcPtr & metadata) const
+ {
+ metadata->addLook(m_look.c_str());
+ }
+ }
+
+ void CreateLookNoOp(OpRcPtrVec & ops,
+ const std::string & look)
+ {
+ ops.push_back( LookNoOpRcPtr(new LookNoOp(look)) );
+ }
+
+}
+OCIO_NAMESPACE_EXIT
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef OCIO_UNIT_TEST
+
+OCIO_NAMESPACE_USING
+
+#include "UnitTest.h"
+#include "Lut1DOp.h"
+#include "MatrixOps.h"
+
+void CreateGenericAllocationOp(OpRcPtrVec & ops)
+{
+ AllocationData srcAllocation;
+ srcAllocation.allocation = ALLOCATION_LG2;
+ srcAllocation.vars.push_back(-8.0f);
+ srcAllocation.vars.push_back(8.0f);
+ CreateGpuAllocationNoOp(ops, srcAllocation);
+}
+
+void CreateGenericScaleOp(OpRcPtrVec & ops)
+{
+ float scale4[4] = { 1.04f, 1.05f, 1.06f, 1.0f };
+ CreateScaleOp(ops, scale4, TRANSFORM_DIR_FORWARD);
+}
+
+void CreateGenericLutOp(OpRcPtrVec & ops)
+{
+ // Make a lut that squares the input
+ Lut1DRcPtr lut = Lut1D::Create();
+ {
+ lut->from_min[0] = 0.0f;
+ lut->from_min[1] = 0.0f;
+ lut->from_min[2] = 0.0f;
+ lut->from_max[0] = 1.0f;
+ lut->from_max[1] = 1.0f;
+ lut->from_max[2] = 1.0f;
+ int size = 256;
+ for(int i=0; i<size; ++i)
+ {
+ float x = (float)i / (float)(size-1);
+ float x2 = x*x;
+
+ for(int c=0; c<3; ++c)
+ {
+ lut->luts[c].push_back(x2);
+ }
+ }
+ }
+
+ CreateLut1DOp(ops, lut, INTERP_LINEAR, TRANSFORM_DIR_FORWARD);
+}
+
+OIIO_ADD_TEST(NoOps, PartitionGPUOps)
+{
+ {
+ OpRcPtrVec ops;
+
+ OpRcPtrVec gpuPreOps, gpuLatticeOps, gpuPostOps;
+ PartitionGPUOps(gpuPreOps, gpuLatticeOps, gpuPostOps, ops);
+
+ OIIO_CHECK_EQUAL(gpuPreOps.size(), 0);
+ OIIO_CHECK_EQUAL(gpuLatticeOps.size(), 0);
+ OIIO_CHECK_EQUAL(gpuPostOps.size(), 0);
+
+ OIIO_CHECK_NO_THOW( AssertPartitionIntegrity(gpuPreOps,
+ gpuLatticeOps,
+ gpuPostOps) );
+ }
+
+ {
+ OpRcPtrVec ops;
+ CreateGenericAllocationOp(ops);
+
+ OpRcPtrVec gpuPreOps, gpuLatticeOps, gpuPostOps;
+ PartitionGPUOps(gpuPreOps, gpuLatticeOps, gpuPostOps, ops);
+
+ OIIO_CHECK_EQUAL(gpuPreOps.size(), 1);
+ OIIO_CHECK_EQUAL(gpuLatticeOps.size(), 0);
+ OIIO_CHECK_EQUAL(gpuPostOps.size(), 0);
+
+ OIIO_CHECK_NO_THOW( AssertPartitionIntegrity(gpuPreOps,
+ gpuLatticeOps,
+ gpuPostOps) );
+ }
+
+ {
+ OpRcPtrVec ops;
+
+ CreateGenericAllocationOp(ops);
+ CreateGenericScaleOp(ops);
+
+ OpRcPtrVec gpuPreOps, gpuLatticeOps, gpuPostOps;
+ PartitionGPUOps(gpuPreOps, gpuLatticeOps, gpuPostOps, ops);
+
+ OIIO_CHECK_EQUAL(gpuPreOps.size(), 2);
+ OIIO_CHECK_EQUAL(gpuLatticeOps.size(), 0);
+ OIIO_CHECK_EQUAL(gpuPostOps.size(), 0);
+
+ OIIO_CHECK_NO_THOW( AssertPartitionIntegrity(gpuPreOps,
+ gpuLatticeOps,
+ gpuPostOps) );
+ }
+
+ {
+ OpRcPtrVec ops;
+
+ CreateGenericAllocationOp(ops);
+ CreateGenericLutOp(ops);
+ CreateGenericScaleOp(ops);
+
+ OpRcPtrVec gpuPreOps, gpuLatticeOps, gpuPostOps;
+ PartitionGPUOps(gpuPreOps, gpuLatticeOps, gpuPostOps, ops);
+
+ OIIO_CHECK_EQUAL(gpuPreOps.size(), 2);
+ OIIO_CHECK_EQUAL(gpuLatticeOps.size(), 4);
+ OIIO_CHECK_EQUAL(gpuPostOps.size(), 1);
+
+ OIIO_CHECK_NO_THOW( AssertPartitionIntegrity(gpuPreOps,
+ gpuLatticeOps,
+ gpuPostOps) );
+ }
+
+ {
+ OpRcPtrVec ops;
+
+ CreateGenericLutOp(ops);
+
+ OpRcPtrVec gpuPreOps, gpuLatticeOps, gpuPostOps;
+ PartitionGPUOps(gpuPreOps, gpuLatticeOps, gpuPostOps, ops);
+
+ OIIO_CHECK_EQUAL(gpuPreOps.size(), 0);
+ OIIO_CHECK_EQUAL(gpuLatticeOps.size(), 1);
+ OIIO_CHECK_EQUAL(gpuPostOps.size(), 0);
+
+ OIIO_CHECK_NO_THOW( AssertPartitionIntegrity(gpuPreOps,
+ gpuLatticeOps,
+ gpuPostOps) );
+ }
+
+ {
+ OpRcPtrVec ops;
+
+ CreateGenericLutOp(ops);
+ CreateGenericScaleOp(ops);
+ CreateGenericAllocationOp(ops);
+ CreateGenericLutOp(ops);
+ CreateGenericScaleOp(ops);
+ CreateGenericAllocationOp(ops);
+
+ OpRcPtrVec gpuPreOps, gpuLatticeOps, gpuPostOps;
+ PartitionGPUOps(gpuPreOps, gpuLatticeOps, gpuPostOps, ops);
+
+ OIIO_CHECK_EQUAL(gpuPreOps.size(), 0);
+ OIIO_CHECK_EQUAL(gpuLatticeOps.size(), 4);
+ OIIO_CHECK_EQUAL(gpuPostOps.size(), 2);
+
+ OIIO_CHECK_NO_THOW( AssertPartitionIntegrity(gpuPreOps,
+ gpuLatticeOps,
+ gpuPostOps) );
+ }
+
+ {
+ OpRcPtrVec ops;
+
+ CreateGenericAllocationOp(ops);
+ CreateGenericScaleOp(ops);
+ CreateGenericLutOp(ops);
+ CreateGenericScaleOp(ops);
+ CreateGenericAllocationOp(ops);
+ CreateGenericLutOp(ops);
+ CreateGenericScaleOp(ops);
+ CreateGenericAllocationOp(ops);
+
+ OpRcPtrVec gpuPreOps, gpuLatticeOps, gpuPostOps;
+ PartitionGPUOps(gpuPreOps, gpuLatticeOps, gpuPostOps, ops);
+
+ OIIO_CHECK_EQUAL(gpuPreOps.size(), 2);
+ OIIO_CHECK_EQUAL(gpuLatticeOps.size(), 8);
+ OIIO_CHECK_EQUAL(gpuPostOps.size(), 2);
+
+ OIIO_CHECK_NO_THOW( AssertPartitionIntegrity(gpuPreOps,
+ gpuLatticeOps,
+ gpuPostOps) );
+ /*
+ std::cerr << "gpuPreOps" << std::endl;
+ std::cerr << SerializeOpVec(gpuPreOps, 4) << std::endl;
+ std::cerr << "gpuLatticeOps" << std::endl;
+ std::cerr << SerializeOpVec(gpuLatticeOps, 4) << std::endl;
+ std::cerr << "gpuPostOps" << std::endl;
+ std::cerr << SerializeOpVec(gpuPostOps, 4) << std::endl;
+ */
+ }
+} // PartitionGPUOps
+
+#endif // OCIO_UNIT_TEST
diff --git a/src/core/NoOps.h b/src/core/NoOps.h
new file mode 100644
index 0000000..dcc93e8
--- /dev/null
+++ b/src/core/NoOps.h
@@ -0,0 +1,67 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_GPUALLOCATIONNOOP_H
+#define INCLUDED_OCIO_GPUALLOCATIONNOOP_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "Op.h"
+
+#include <vector>
+
+OCIO_NAMESPACE_ENTER
+{
+ void CreateGpuAllocationNoOp(OpRcPtrVec & ops,
+ const AllocationData & allocationData);
+
+
+ // Partition an opvec into 3 segments for GPU Processing
+ //
+ // gpuLatticeOps need not support analytical gpu shader generation
+ // the pre and post ops must support analytical generation.
+ //
+ // Additional ops will optinally be inserted to take into account
+ // allocation transformations
+
+ void PartitionGPUOps(OpRcPtrVec & gpuPreOps,
+ OpRcPtrVec & gpuLatticeOps,
+ OpRcPtrVec & gpuPostOps,
+ const OpRcPtrVec & ops);
+
+ void CreateFileNoOp(OpRcPtrVec & ops,
+ const std::string & fname);
+
+ void CreateLookNoOp(OpRcPtrVec & ops,
+ const std::string & lookName);
+
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/OCIOYaml.cpp b/src/core/OCIOYaml.cpp
new file mode 100644
index 0000000..7089318
--- /dev/null
+++ b/src/core/OCIOYaml.cpp
@@ -0,0 +1,1218 @@
+/*
+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 <cstring>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "Logging.h"
+#include "MathUtils.h"
+#include "OCIOYaml.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ ///////////////////////////////////////////////////////////////////////////
+ // Core
+
+ void LogUnknownKeyWarning(const std::string & name, const YAML::Node& tag)
+ {
+ std::string key;
+ tag >> key;
+
+ std::ostringstream os;
+ os << "Unknown key in " << name << ": ";
+ os << "'" << key << "'. (line ";
+ os << (tag.GetMark().line+1) << ", column "; // (yaml line numbers start at 0)
+ os << tag.GetMark().column << ")";
+ LogWarning(os.str());
+ }
+
+ void operator >> (const YAML::Node& node, ColorSpaceRcPtr& cs)
+ {
+ if(node.Tag() != "ColorSpace")
+ return; // not a !<ColorSpace> tag
+
+ std::string key, stringval;
+ bool boolval;
+
+ for (YAML::Iterator iter = node.begin();
+ iter != node.end();
+ ++iter)
+ {
+ iter.first() >> key;
+
+ if(key == "name")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ cs->setName(stringval.c_str());
+ }
+ else if(key == "description")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ cs->setDescription(stringval.c_str());
+ }
+ else if(key == "family")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ cs->setFamily(stringval.c_str());
+ }
+ else if(key == "equalitygroup")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ cs->setEqualityGroup(stringval.c_str());
+ }
+ else if(key == "bitdepth")
+ {
+ BitDepth ret;
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<BitDepth>(ret))
+ cs->setBitDepth(ret);
+ }
+ else if(key == "isdata")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<bool>(boolval))
+ cs->setIsData(boolval);
+ }
+ else if(key == "allocation")
+ {
+ Allocation val;
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<Allocation>(val))
+ cs->setAllocation(val);
+ }
+ else if(key == "allocationvars")
+ {
+ std::vector<float> val;
+ if (iter.second().Type() != YAML::NodeType::Null)
+ {
+ iter.second() >> val;
+ if(!val.empty())
+ {
+ cs->setAllocationVars(static_cast<int>(val.size()), &val[0]);
+ }
+ }
+ }
+ else if(key == "to_reference")
+ {
+ TransformRcPtr val;
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<TransformRcPtr>(val))
+ cs->setTransform(val, COLORSPACE_DIR_TO_REFERENCE);
+ }
+ else if(key == "from_reference")
+ {
+ TransformRcPtr val;
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<TransformRcPtr>(val))
+ cs->setTransform(val, COLORSPACE_DIR_FROM_REFERENCE);
+ }
+ else
+ {
+ LogUnknownKeyWarning(node.Tag(), iter.first());
+ }
+ }
+ }
+
+ YAML::Emitter& operator << (YAML::Emitter& out, ColorSpaceRcPtr cs)
+ {
+ out << YAML::VerbatimTag("ColorSpace");
+ out << YAML::BeginMap;
+
+ out << YAML::Key << "name" << YAML::Value << cs->getName();
+ out << YAML::Key << "family" << YAML::Value << cs->getFamily();
+ out << YAML::Key << "equalitygroup" << YAML::Value << cs->getEqualityGroup();
+ out << YAML::Key << "bitdepth" << YAML::Value << cs->getBitDepth();
+ if(strlen(cs->getDescription()) > 0)
+ {
+ out << YAML::Key << "description";
+ out << YAML::Value << YAML::Literal << cs->getDescription();
+ }
+ out << YAML::Key << "isdata" << YAML::Value << cs->isData();
+
+ out << YAML::Key << "allocation" << YAML::Value << cs->getAllocation();
+ if(cs->getAllocationNumVars() > 0)
+ {
+ std::vector<float> allocationvars(cs->getAllocationNumVars());
+ cs->getAllocationVars(&allocationvars[0]);
+ out << YAML::Key << "allocationvars";
+ out << YAML::Flow << YAML::Value << allocationvars;
+ }
+
+ ConstTransformRcPtr toref = \
+ cs->getTransform(COLORSPACE_DIR_TO_REFERENCE);
+ if(toref)
+ out << YAML::Key << "to_reference" << YAML::Value << toref;
+
+ ConstTransformRcPtr fromref = \
+ cs->getTransform(COLORSPACE_DIR_FROM_REFERENCE);
+ if(fromref)
+ out << YAML::Key << "from_reference" << YAML::Value << fromref;
+
+ out << YAML::EndMap;
+ out << YAML::Newline;
+
+ return out;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ // Look. (not the transform, the top-level class)
+
+ void operator >> (const YAML::Node& node, LookRcPtr& look)
+ {
+ if(node.Tag() != "Look")
+ return;
+
+ std::string key, stringval;
+
+ for (YAML::Iterator iter = node.begin();
+ iter != node.end();
+ ++iter)
+ {
+ iter.first() >> key;
+
+ if(key == "name")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ look->setName(stringval.c_str());
+ }
+ else if(key == "process_space")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ look->setProcessSpace(stringval.c_str());
+ }
+ else if(key == "transform")
+ {
+ TransformRcPtr val;
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<TransformRcPtr>(val))
+ look->setTransform(val);
+ }
+ else if(key == "inverse_transform")
+ {
+ TransformRcPtr val;
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<TransformRcPtr>(val))
+ look->setInverseTransform(val);
+ }
+ else
+ {
+ LogUnknownKeyWarning(node.Tag(), iter.first());
+ }
+ }
+ }
+
+ YAML::Emitter& operator << (YAML::Emitter& out, LookRcPtr look)
+ {
+ out << YAML::VerbatimTag("Look");
+ out << YAML::BeginMap;
+ out << YAML::Key << "name" << YAML::Value << look->getName();
+ out << YAML::Key << "process_space" << YAML::Value << look->getProcessSpace();
+
+ if(look->getTransform())
+ {
+ out << YAML::Key << "transform";
+ out << YAML::Value << look->getTransform();
+ }
+
+ if(look->getInverseTransform())
+ {
+ out << YAML::Key << "inverse_transform";
+ out << YAML::Value << look->getInverseTransform();
+ }
+
+ out << YAML::EndMap;
+ out << YAML::Newline;
+
+ return out;
+ }
+
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ namespace
+ {
+ void EmitBaseTransformKeyValues(YAML::Emitter & out,
+ const ConstTransformRcPtr & t)
+ {
+ if(t->getDirection() != TRANSFORM_DIR_FORWARD)
+ {
+ out << YAML::Key << "direction";
+ out << YAML::Value << YAML::Flow << t->getDirection();
+ }
+ }
+ }
+
+ void operator >> (const YAML::Node& node, TransformRcPtr& t)
+ {
+ if(node.Type() != YAML::NodeType::Map)
+ {
+ std::ostringstream os;
+ os << "Unsupported Transform type encountered: (" << node.Type() << ") in OCIO profile. ";
+ os << "Only Mapping types supported. (line ";
+ os << (node.GetMark().line+1) << ", column "; // (yaml line numbers start at 0)
+ os << node.GetMark().column << ")";
+ throw Exception(os.str().c_str());
+ }
+
+ std::string type = node.Tag();
+
+ if(type == "AllocationTransform") {
+ AllocationTransformRcPtr temp;
+ node.Read<AllocationTransformRcPtr>(temp);
+ t = temp;
+ }
+ else if(type == "CDLTransform") {
+ CDLTransformRcPtr temp;
+ node.Read<CDLTransformRcPtr>(temp);
+ t = temp;
+ }
+ else if(type == "ColorSpaceTransform") {
+ ColorSpaceTransformRcPtr temp;
+ node.Read<ColorSpaceTransformRcPtr>(temp);
+ t = temp;
+ }
+ // TODO: DisplayTransform
+ else if(type == "ExponentTransform") {
+ ExponentTransformRcPtr temp;
+ node.Read<ExponentTransformRcPtr>(temp);
+ t = temp;
+ }
+ else if(type == "FileTransform") {
+ FileTransformRcPtr temp;
+ node.Read<FileTransformRcPtr>(temp);
+ t = temp;
+ }
+ else if(type == "GroupTransform") {
+ GroupTransformRcPtr temp;
+ node.Read<GroupTransformRcPtr>(temp);
+ t = temp;
+ }
+ else if(type == "LogTransform") {
+ LogTransformRcPtr temp;
+ node.Read<LogTransformRcPtr>(temp);
+ t = temp;
+ }
+ else if(type == "LookTransform") {
+ LookTransformRcPtr temp;
+ node.Read<LookTransformRcPtr>(temp);
+ t = temp;
+ }
+ else if(type == "MatrixTransform") {
+ MatrixTransformRcPtr temp;
+ node.Read<MatrixTransformRcPtr>(temp);
+ t = temp;
+ }
+ else if(type == "TruelightTransform") {
+ TruelightTransformRcPtr temp;
+ node.Read<TruelightTransformRcPtr>(temp);
+ t = temp;
+ }
+ else
+ {
+ // TODO: add a new empty (better name?) aka passthru Transform()
+ // which does nothing. This is so upsupported !<tag> types don't
+ // throw an exception. Alternativly this could be caught in the
+ // GroupTransformRcPtr >> operator with some type of
+ // supported_tag() method
+
+ // TODO: consider the forwards-compatibility implication of
+ // throwing an exception. Should this be a warning, instead?
+
+ // t = EmptyTransformRcPtr(new EmptyTransform(), &deleter);
+ std::ostringstream os;
+ os << "Unsupported transform type !<" << type << "> in OCIO profile. ";
+ os << " (line ";
+ os << (node.GetMark().line+1) << ", column "; // (yaml line numbers start at 0)
+ os << node.GetMark().column << ")";
+ throw Exception(os.str().c_str());
+ }
+ }
+
+ YAML::Emitter& operator << (YAML::Emitter& out, ConstTransformRcPtr t)
+ {
+ if(ConstAllocationTransformRcPtr Allocation_tran = \
+ DynamicPtrCast<const AllocationTransform>(t))
+ out << Allocation_tran;
+ else if(ConstCDLTransformRcPtr CDL_tran = \
+ DynamicPtrCast<const CDLTransform>(t))
+ out << CDL_tran;
+ else if(ConstColorSpaceTransformRcPtr ColorSpace_tran = \
+ DynamicPtrCast<const ColorSpaceTransform>(t))
+ out << ColorSpace_tran;
+ else if(ConstExponentTransformRcPtr Exponent_tran = \
+ DynamicPtrCast<const ExponentTransform>(t))
+ out << Exponent_tran;
+ else if(ConstFileTransformRcPtr File_tran = \
+ DynamicPtrCast<const FileTransform>(t))
+ out << File_tran;
+ else if(ConstGroupTransformRcPtr Group_tran = \
+ DynamicPtrCast<const GroupTransform>(t))
+ out << Group_tran;
+ else if(ConstLogTransformRcPtr Log_tran = \
+ DynamicPtrCast<const LogTransform>(t))
+ out << Log_tran;
+ else if(ConstLookTransformRcPtr Look_tran = \
+ DynamicPtrCast<const LookTransform>(t))
+ out << Look_tran;
+ else if(ConstMatrixTransformRcPtr Matrix_tran = \
+ DynamicPtrCast<const MatrixTransform>(t))
+ out << Matrix_tran;
+ else if(ConstTruelightTransformRcPtr Truelight_tran = \
+ DynamicPtrCast<const TruelightTransform>(t))
+ out << Truelight_tran;
+ else
+ throw Exception("Unsupported Transform() type for serialization.");
+
+ return out;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Transforms
+
+ void operator >> (const YAML::Node& node, GroupTransformRcPtr& t)
+ {
+ t = GroupTransform::Create();
+
+ std::string key;
+
+ for (YAML::Iterator iter = node.begin();
+ iter != node.end();
+ ++iter)
+ {
+ iter.first() >> key;
+
+ if(key == "children")
+ {
+ const YAML::Node & children = iter.second();
+ for(unsigned i = 0; i <children.size(); ++i)
+ {
+ TransformRcPtr childTransform;
+ children[i].Read<TransformRcPtr>(childTransform);
+
+ // TODO: consider the forwards-compatibility implication of
+ // throwing an exception. Should this be a warning, instead?
+ if(!childTransform)
+ {
+ throw Exception("Child transform could not be parsed.");
+ }
+
+ t->push_back(childTransform);
+ }
+ }
+ else if(key == "direction")
+ {
+ TransformDirection val;
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<TransformDirection>(val))
+ t->setDirection(val);
+ }
+ else
+ {
+ LogUnknownKeyWarning(node.Tag(), iter.first());
+ }
+ }
+ }
+
+ YAML::Emitter& operator << (YAML::Emitter& out, ConstGroupTransformRcPtr t)
+ {
+ out << YAML::VerbatimTag("GroupTransform");
+ out << YAML::BeginMap;
+ EmitBaseTransformKeyValues(out, t);
+
+ out << YAML::Key << "children";
+ out << YAML::Value;
+
+ out << YAML::BeginSeq;
+ for(int i = 0; i < t->size(); ++i)
+ {
+ out << t->getTransform(i);
+ }
+ out << YAML::EndSeq;
+
+ out << YAML::EndMap;
+
+ return out;
+ }
+
+
+
+ void operator >> (const YAML::Node& node, FileTransformRcPtr& t)
+ {
+ t = FileTransform::Create();
+
+ std::string key, stringval;
+
+ for (YAML::Iterator iter = node.begin();
+ iter != node.end();
+ ++iter)
+ {
+ iter.first() >> key;
+
+ if(key == "src")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ t->setSrc(stringval.c_str());
+ }
+ else if(key == "cccid")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ t->setCCCId(stringval.c_str());
+ }
+ else if(key == "interpolation")
+ {
+ Interpolation val;
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<Interpolation>(val))
+ t->setInterpolation(val);
+ }
+ else if(key == "direction")
+ {
+ TransformDirection val;
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<TransformDirection>(val))
+ t->setDirection(val);
+ }
+ else
+ {
+ LogUnknownKeyWarning(node.Tag(), iter.first());
+ }
+ }
+ }
+
+ YAML::Emitter& operator << (YAML::Emitter& out, ConstFileTransformRcPtr t)
+ {
+ out << YAML::VerbatimTag("FileTransform");
+ out << YAML::Flow << YAML::BeginMap;
+ out << YAML::Key << "src" << YAML::Value << t->getSrc();
+ const char * cccid = t->getCCCId();
+ if(cccid && *cccid)
+ {
+ out << YAML::Key << "cccid" << YAML::Value << t->getCCCId();
+ }
+ out << YAML::Key << "interpolation";
+ out << YAML::Value << t->getInterpolation();
+
+ EmitBaseTransformKeyValues(out, t);
+ out << YAML::EndMap;
+ return out;
+ }
+
+ void operator >> (const YAML::Node& node, ColorSpaceTransformRcPtr& t)
+ {
+ t = ColorSpaceTransform::Create();
+
+ std::string key, stringval;
+
+ for (YAML::Iterator iter = node.begin();
+ iter != node.end();
+ ++iter)
+ {
+ iter.first() >> key;
+
+ if(key == "src")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ t->setSrc(stringval.c_str());
+ }
+ else if(key == "dst")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ t->setDst(stringval.c_str());
+ }
+ else if(key == "direction")
+ {
+ TransformDirection val;
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<TransformDirection>(val))
+ t->setDirection(val);
+ }
+ else
+ {
+ LogUnknownKeyWarning(node.Tag(), iter.first());
+ }
+ }
+ }
+
+ YAML::Emitter& operator << (YAML::Emitter& out, ConstColorSpaceTransformRcPtr t)
+ {
+ out << YAML::VerbatimTag("ColorSpaceTransform");
+ out << YAML::Flow << YAML::BeginMap;
+ out << YAML::Key << "src" << YAML::Value << t->getSrc();
+ out << YAML::Key << "dst" << YAML::Value << t->getDst();
+ EmitBaseTransformKeyValues(out, t);
+ out << YAML::EndMap;
+ return out;
+ }
+
+ void operator >> (const YAML::Node& node, LookTransformRcPtr& t)
+ {
+ t = LookTransform::Create();
+
+ std::string key, stringval;
+
+ for (YAML::Iterator iter = node.begin();
+ iter != node.end();
+ ++iter)
+ {
+ iter.first() >> key;
+
+ if(key == "src")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ t->setSrc(stringval.c_str());
+ }
+ else if(key == "dst")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ t->setDst(stringval.c_str());
+ }
+ else if(key == "looks")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ t->setLooks(stringval.c_str());
+ }
+ else if(key == "direction")
+ {
+ TransformDirection val;
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<TransformDirection>(val))
+ t->setDirection(val);
+ }
+ else
+ {
+ LogUnknownKeyWarning(node.Tag(), iter.first());
+ }
+ }
+ }
+
+ YAML::Emitter& operator << (YAML::Emitter& out, ConstLookTransformRcPtr t)
+ {
+ out << YAML::VerbatimTag("LookTransform");
+ out << YAML::Flow << YAML::BeginMap;
+ out << YAML::Key << "src" << YAML::Value << t->getSrc();
+ out << YAML::Key << "dst" << YAML::Value << t->getDst();
+ out << YAML::Key << "looks" << YAML::Value << t->getLooks();
+ EmitBaseTransformKeyValues(out, t);
+ out << YAML::EndMap;
+ return out;
+ }
+
+ void operator >> (const YAML::Node& node, ExponentTransformRcPtr& t)
+ {
+ t = ExponentTransform::Create();
+
+ std::string key;
+
+ for (YAML::Iterator iter = node.begin();
+ iter != node.end();
+ ++iter)
+ {
+ iter.first() >> key;
+
+ if(key == "value")
+ {
+ std::vector<float> val;
+ if (iter.second().Type() != YAML::NodeType::Null)
+ {
+ iter.second() >> val;
+ if(val.size() != 4)
+ {
+ std::ostringstream os;
+ os << "ExponentTransform parse error, value field must be 4 ";
+ os << "floats. Found '" << val.size() << "'.";
+ throw Exception(os.str().c_str());
+ }
+ t->setValue(&val[0]);
+ }
+ }
+ else if(key == "direction")
+ {
+ TransformDirection val;
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<TransformDirection>(val))
+ t->setDirection(val);
+ }
+ else
+ {
+ LogUnknownKeyWarning(node.Tag(), iter.first());
+ }
+ }
+ }
+
+ YAML::Emitter& operator << (YAML::Emitter& out, ConstExponentTransformRcPtr t)
+ {
+ out << YAML::VerbatimTag("ExponentTransform");
+ out << YAML::Flow << YAML::BeginMap;
+
+ std::vector<float> value(4, 0.0);
+ t->getValue(&value[0]);
+ out << YAML::Key << "value";
+ out << YAML::Value << YAML::Flow << value;
+ EmitBaseTransformKeyValues(out, t);
+ out << YAML::EndMap;
+ return out;
+ }
+
+ void operator >> (const YAML::Node& node, LogTransformRcPtr& t)
+ {
+ t = LogTransform::Create();
+
+ std::string key;
+
+ for (YAML::Iterator iter = node.begin();
+ iter != node.end();
+ ++iter)
+ {
+ iter.first() >> key;
+
+ if(key == "base")
+ {
+ float val = 0.0f;
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<float>(val))
+ t->setBase(val);
+ }
+ else if(key == "direction")
+ {
+ TransformDirection val;
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<TransformDirection>(val))
+ t->setDirection(val);
+ }
+ else
+ {
+ LogUnknownKeyWarning(node.Tag(), iter.first());
+ }
+ }
+ }
+
+ YAML::Emitter& operator << (YAML::Emitter& out, ConstLogTransformRcPtr t)
+ {
+ out << YAML::VerbatimTag("LogTransform");
+ out << YAML::Flow << YAML::BeginMap;
+ out << YAML::Key << "base" << YAML::Value << t->getBase();
+ EmitBaseTransformKeyValues(out, t);
+ out << YAML::EndMap;
+ return out;
+ }
+
+ void operator >> (const YAML::Node& node, MatrixTransformRcPtr& t)
+ {
+ t = MatrixTransform::Create();
+
+ std::string key;
+
+ for (YAML::Iterator iter = node.begin();
+ iter != node.end();
+ ++iter)
+ {
+ iter.first() >> key;
+
+ if(key == "matrix")
+ {
+ std::vector<float> val;
+ if (iter.second().Type() != YAML::NodeType::Null)
+ {
+ iter.second() >> val;
+ if(val.size() != 16)
+ {
+ std::ostringstream os;
+ os << "MatrixTransform parse error, matrix field must be 16 ";
+ os << "floats. Found '" << val.size() << "'.";
+ throw Exception(os.str().c_str());
+ }
+ t->setMatrix(&val[0]);
+ }
+ }
+ else if(key == "offset")
+ {
+ std::vector<float> val;
+ if (iter.second().Type() != YAML::NodeType::Null)
+ {
+ iter.second() >> val;
+ if(val.size() != 4)
+ {
+ std::ostringstream os;
+ os << "MatrixTransform parse error, offset field must be 4 ";
+ os << "floats. Found '" << val.size() << "'.";
+ throw Exception(os.str().c_str());
+ }
+ t->setOffset(&val[0]);
+ }
+ }
+ else if(key == "direction")
+ {
+ TransformDirection val;
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<TransformDirection>(val))
+ t->setDirection(val);
+ }
+ else
+ {
+ LogUnknownKeyWarning(node.Tag(), iter.first());
+ }
+ }
+ }
+
+ YAML::Emitter& operator << (YAML::Emitter& out, ConstMatrixTransformRcPtr t)
+ {
+ out << YAML::VerbatimTag("MatrixTransform");
+ out << YAML::Flow << YAML::BeginMap;
+
+ std::vector<float> matrix(16, 0.0);
+ t->getMatrix(&matrix[0]);
+ if(!IsM44Identity(&matrix[0]))
+ {
+ out << YAML::Key << "matrix";
+ out << YAML::Value << YAML::Flow << matrix;
+ }
+
+ std::vector<float> offset(4, 0.0);
+ t->getOffset(&offset[0]);
+ if(!IsVecEqualToZero(&offset[0],4))
+ {
+ out << YAML::Key << "offset";
+ out << YAML::Value << YAML::Flow << offset;
+ }
+
+ EmitBaseTransformKeyValues(out, t);
+ out << YAML::EndMap;
+ return out;
+ }
+
+ void operator >> (const YAML::Node& node, CDLTransformRcPtr& t)
+ {
+ t = CDLTransform::Create();
+
+ std::string key;
+ std::vector<float> floatvecval;
+
+ for (YAML::Iterator iter = node.begin();
+ iter != node.end();
+ ++iter)
+ {
+ iter.first() >> key;
+
+ if(key == "slope")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null)
+ {
+ iter.second() >> floatvecval;
+ if(floatvecval.size() != 3)
+ {
+ std::ostringstream os;
+ os << "CDLTransform parse error, 'slope' field must be 3 ";
+ os << "floats. Found '" << floatvecval.size() << "'.";
+ throw Exception(os.str().c_str());
+ }
+ t->setSlope(&floatvecval[0]);
+ }
+ }
+ else if(key == "offset")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null)
+ {
+ iter.second() >> floatvecval;
+ if(floatvecval.size() != 3)
+ {
+ std::ostringstream os;
+ os << "CDLTransform parse error, 'offset' field must be 3 ";
+ os << "floats. Found '" << floatvecval.size() << "'.";
+ throw Exception(os.str().c_str());
+ }
+ t->setOffset(&floatvecval[0]);
+ }
+ }
+ else if(key == "power")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null)
+ {
+ iter.second() >> floatvecval;
+ if(floatvecval.size() != 3)
+ {
+ std::ostringstream os;
+ os << "CDLTransform parse error, 'power' field must be 3 ";
+ os << "floats. Found '" << floatvecval.size() << "'.";
+ throw Exception(os.str().c_str());
+ }
+ t->setPower(&floatvecval[0]);
+ }
+ }
+ else if(key == "saturation" || key == "sat")
+ {
+ float val = 0.0f;
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<float>(val))
+ t->setSat(val);
+ }
+ else if(key == "direction")
+ {
+ TransformDirection val;
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<TransformDirection>(val))
+ t->setDirection(val);
+ }
+ else
+ {
+ LogUnknownKeyWarning(node.Tag(), iter.first());
+ }
+ }
+ }
+
+ YAML::Emitter& operator << (YAML::Emitter& out, ConstCDLTransformRcPtr t)
+ {
+ out << YAML::VerbatimTag("CDLTransform");
+ out << YAML::Flow << YAML::BeginMap;
+
+ std::vector<float> slope(3);
+ t->getSlope(&slope[0]);
+ if(!IsVecEqualToOne(&slope[0], 3))
+ {
+ out << YAML::Key << "slope";
+ out << YAML::Value << YAML::Flow << slope;
+ }
+
+ std::vector<float> offset(3);
+ t->getOffset(&offset[0]);
+ if(!IsVecEqualToZero(&offset[0], 3))
+ {
+ out << YAML::Key << "offset";
+ out << YAML::Value << YAML::Flow << offset;
+ }
+
+ std::vector<float> power(3);
+ t->getPower(&power[0]);
+ if(!IsVecEqualToOne(&power[0], 3))
+ {
+ out << YAML::Key << "power";
+ out << YAML::Value << YAML::Flow << power;
+ }
+
+ if(!IsScalarEqualToOne(t->getSat()))
+ {
+ out << YAML::Key << "sat" << YAML::Value << t->getSat();
+ }
+
+ EmitBaseTransformKeyValues(out, t);
+ out << YAML::EndMap;
+ return out;
+ }
+
+ void operator >> (const YAML::Node& node, AllocationTransformRcPtr& t)
+ {
+ t = AllocationTransform::Create();
+
+ std::string key;
+
+ for (YAML::Iterator iter = node.begin();
+ iter != node.end();
+ ++iter)
+ {
+ iter.first() >> key;
+
+ if(key == "allocation")
+ {
+ Allocation val;
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<Allocation>(val))
+ t->setAllocation(val);
+ }
+ else if(key == "vars")
+ {
+ std::vector<float> val;
+ if (iter.second().Type() != YAML::NodeType::Null)
+ {
+ iter.second() >> val;
+ if(!val.empty())
+ {
+ t->setVars(static_cast<int>(val.size()), &val[0]);
+ }
+ }
+ }
+ else if(key == "direction")
+ {
+ TransformDirection val;
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<TransformDirection>(val))
+ t->setDirection(val);
+ }
+ else
+ {
+ LogUnknownKeyWarning(node.Tag(), iter.first());
+ }
+ }
+ }
+
+ YAML::Emitter& operator << (YAML::Emitter& out, ConstAllocationTransformRcPtr t)
+ {
+ out << YAML::VerbatimTag("AllocationTransform");
+ out << YAML::Flow << YAML::BeginMap;
+
+ out << YAML::Key << "allocation";
+ out << YAML::Value << YAML::Flow << t->getAllocation();
+
+ if(t->getNumVars() > 0)
+ {
+ std::vector<float> vars(t->getNumVars());
+ t->getVars(&vars[0]);
+ out << YAML::Key << "vars";
+ out << YAML::Flow << YAML::Value << vars;
+ }
+
+ EmitBaseTransformKeyValues(out, t);
+ out << YAML::EndMap;
+ return out;
+ }
+
+ void operator >> (const YAML::Node& node, TruelightTransformRcPtr& t)
+ {
+ t = TruelightTransform::Create();
+
+ std::string key, stringval;
+
+ for (YAML::Iterator iter = node.begin();
+ iter != node.end();
+ ++iter)
+ {
+ iter.first() >> key;
+
+ if(key == "config_root")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ t->setConfigRoot(stringval.c_str());
+ }
+ else if(key == "profile")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ t->setProfile(stringval.c_str());
+ }
+ else if(key == "camera")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ t->setCamera(stringval.c_str());
+ }
+ else if(key == "input_display")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ t->setInputDisplay(stringval.c_str());
+ }
+ else if(key == "recorder")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ t->setRecorder(stringval.c_str());
+ }
+ else if(key == "print")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ t->setPrint(stringval.c_str());
+ }
+ else if(key == "lamp")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ t->setLamp(stringval.c_str());
+ }
+ else if(key == "output_camera")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ t->setOutputCamera(stringval.c_str());
+ }
+ else if(key == "display")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ t->setDisplay(stringval.c_str());
+ }
+ else if(key == "cube_input")
+ {
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<std::string>(stringval))
+ t->setCubeInput(stringval.c_str());
+ }
+ else if(key == "direction")
+ {
+ TransformDirection val;
+ if (iter.second().Type() != YAML::NodeType::Null &&
+ iter.second().Read<TransformDirection>(val))
+ t->setDirection(val);
+ }
+ else
+ {
+ LogUnknownKeyWarning(node.Tag(), iter.first());
+ }
+ }
+ }
+
+ YAML::Emitter& operator << (YAML::Emitter& out, ConstTruelightTransformRcPtr t)
+ {
+
+ out << YAML::VerbatimTag("TruelightTransform");
+ out << YAML::Flow << YAML::BeginMap;
+ if(strcmp(t->getConfigRoot(), "") != 0)
+ {
+ out << YAML::Key << "config_root";
+ out << YAML::Value << YAML::Flow << t->getConfigRoot();
+ }
+ if(strcmp(t->getProfile(), "") != 0)
+ {
+ out << YAML::Key << "profile";
+ out << YAML::Value << YAML::Flow << t->getProfile();
+ }
+ if(strcmp(t->getCamera(), "") != 0)
+ {
+ out << YAML::Key << "camera";
+ out << YAML::Value << YAML::Flow << t->getCamera();
+ }
+ if(strcmp(t->getInputDisplay(), "") != 0)
+ {
+ out << YAML::Key << "input_display";
+ out << YAML::Value << YAML::Flow << t->getInputDisplay();
+ }
+ if(strcmp(t->getRecorder(), "") != 0)
+ {
+ out << YAML::Key << "recorder";
+ out << YAML::Value << YAML::Flow << t->getRecorder();
+ }
+ if(strcmp(t->getPrint(), "") != 0)
+ {
+ out << YAML::Key << "print";
+ out << YAML::Value << YAML::Flow << t->getPrint();
+ }
+ if(strcmp(t->getLamp(), "") != 0)
+ {
+ out << YAML::Key << "lamp";
+ out << YAML::Value << YAML::Flow << t->getLamp();
+ }
+ if(strcmp(t->getOutputCamera(), "") != 0)
+ {
+ out << YAML::Key << "output_camera";
+ out << YAML::Value << YAML::Flow << t->getOutputCamera();
+ }
+ if(strcmp(t->getDisplay(), "") != 0)
+ {
+ out << YAML::Key << "display";
+ out << YAML::Value << YAML::Flow << t->getDisplay();
+ }
+ if(strcmp(t->getCubeInput(), "") != 0)
+ {
+ out << YAML::Key << "cube_input";
+ out << YAML::Value << YAML::Flow << t->getCubeInput();
+ }
+
+ EmitBaseTransformKeyValues(out, t);
+
+ out << YAML::EndMap;
+ return out;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Enums
+
+ YAML::Emitter& operator << (YAML::Emitter& out, BitDepth depth) {
+ out << BitDepthToString(depth);
+ return out;
+ }
+
+ void operator >> (const YAML::Node& node, BitDepth& depth) {
+ std::string str;
+ node.Read<std::string>(str);
+ depth = BitDepthFromString(str.c_str());
+ }
+
+ YAML::Emitter& operator << (YAML::Emitter& out, Allocation alloc) {
+ out << AllocationToString(alloc);
+ return out;
+ }
+
+ void operator >> (const YAML::Node& node, Allocation& alloc) {
+ std::string str;
+ node.Read<std::string>(str);
+ alloc = AllocationFromString(str.c_str());
+ }
+
+ YAML::Emitter& operator << (YAML::Emitter& out, ColorSpaceDirection dir) {
+ out << ColorSpaceDirectionToString(dir);
+ return out;
+ }
+
+ void operator >> (const YAML::Node& node, ColorSpaceDirection& dir) {
+ std::string str;
+ node.Read<std::string>(str);
+ dir = ColorSpaceDirectionFromString(str.c_str());
+ }
+
+ YAML::Emitter& operator << (YAML::Emitter& out, TransformDirection dir) {
+ out << TransformDirectionToString(dir);
+ return out;
+ }
+
+ void operator >> (const YAML::Node& node, TransformDirection& dir) {
+ std::string str;
+ node.Read<std::string>(str);
+ dir = TransformDirectionFromString(str.c_str());
+ }
+
+ YAML::Emitter& operator << (YAML::Emitter& out, Interpolation interp) {
+ out << InterpolationToString(interp);
+ return out;
+ }
+
+ void operator >> (const YAML::Node& node, Interpolation& interp) {
+ std::string str;
+ node.Read<std::string>(str);
+ interp = InterpolationFromString(str.c_str());
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/OCIOYaml.h b/src/core/OCIOYaml.h
new file mode 100644
index 0000000..7104123
--- /dev/null
+++ b/src/core/OCIOYaml.h
@@ -0,0 +1,125 @@
+/*
+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 "Platform.h"
+
+#ifndef WINDOWS
+
+// fwd declare yaml-cpp visibility
+#pragma GCC visibility push(hidden)
+namespace YAML {
+ class Exception;
+ class BadDereference;
+ class RepresentationException;
+ class EmitterException;
+ class ParserException;
+ class InvalidScalar;
+ class KeyNotFound;
+ template <typename T> class TypedKeyNotFound;
+ template <> class TypedKeyNotFound<OCIO_NAMESPACE::ColorSpace>;
+ template <> class TypedKeyNotFound<OCIO_NAMESPACE::Config>;
+ template <> class TypedKeyNotFound<OCIO_NAMESPACE::Exception>;
+ template <> class TypedKeyNotFound<OCIO_NAMESPACE::GpuShaderDesc>;
+ template <> class TypedKeyNotFound<OCIO_NAMESPACE::ImageDesc>;
+ template <> class TypedKeyNotFound<OCIO_NAMESPACE::Look>;
+ template <> class TypedKeyNotFound<OCIO_NAMESPACE::Processor>;
+
+ template <> class TypedKeyNotFound<OCIO_NAMESPACE::Transform>;
+ template <> class TypedKeyNotFound<OCIO_NAMESPACE::AllocationTransform>;
+ template <> class TypedKeyNotFound<OCIO_NAMESPACE::CDLTransform>;
+ template <> class TypedKeyNotFound<OCIO_NAMESPACE::ColorSpaceTransform>;
+ template <> class TypedKeyNotFound<OCIO_NAMESPACE::DisplayTransform>;
+ template <> class TypedKeyNotFound<OCIO_NAMESPACE::ExponentTransform>;
+ template <> class TypedKeyNotFound<OCIO_NAMESPACE::FileTransform>;
+ template <> class TypedKeyNotFound<OCIO_NAMESPACE::GroupTransform>;
+ template <> class TypedKeyNotFound<OCIO_NAMESPACE::LogTransform>;
+ template <> class TypedKeyNotFound<OCIO_NAMESPACE::LookTransform>;
+ template <> class TypedKeyNotFound<OCIO_NAMESPACE::MatrixTransform>;
+ template <> class TypedKeyNotFound<OCIO_NAMESPACE::TruelightTransform>;
+}
+#pragma GCC visibility pop
+
+#endif
+
+#include <yaml-cpp/yaml.h>
+
+#ifndef INCLUDED_OCIO_YAML_H
+#define INCLUDED_OCIO_YAML_H
+
+OCIO_NAMESPACE_ENTER
+{
+
+ // Core
+ OCIOHIDDEN void operator >> (const YAML::Node& node, ColorSpaceRcPtr& cs);
+ OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ColorSpaceRcPtr cs);
+ OCIOHIDDEN void operator >> (const YAML::Node& node, GroupTransformRcPtr& t);
+ OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstGroupTransformRcPtr t);
+ OCIOHIDDEN void operator >> (const YAML::Node& node, TransformRcPtr& t);
+ OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstTransformRcPtr t);
+ OCIOHIDDEN void operator >> (const YAML::Node& node, LookRcPtr& cs);
+ OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, LookRcPtr cs);
+
+ // Transforms
+ OCIOHIDDEN void operator >> (const YAML::Node& node, AllocationTransformRcPtr& t);
+ OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstAllocationTransformRcPtr t);
+ OCIOHIDDEN void operator >> (const YAML::Node& node, CDLTransformRcPtr& t);
+ OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstCDLTransformRcPtr t);
+ OCIOHIDDEN void operator >> (const YAML::Node& node, ColorSpaceTransformRcPtr& t);
+ OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstColorSpaceTransformRcPtr t);
+ OCIOHIDDEN void operator >> (const YAML::Node& node, ExponentTransformRcPtr& t);
+ OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstExponentTransformRcPtr t);
+ OCIOHIDDEN void operator >> (const YAML::Node& node, FileTransformRcPtr& t);
+ OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstFileTransformRcPtr t);
+ OCIOHIDDEN void operator >> (const YAML::Node& node, LogTransformRcPtr& t);
+ OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstLogTransformRcPtr t);
+ OCIOHIDDEN void operator >> (const YAML::Node& node, LookTransformRcPtr& t);
+ OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstLookTransformRcPtr t);
+ OCIOHIDDEN void operator >> (const YAML::Node& node, MatrixTransformRcPtr& t);
+ OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstMatrixTransformRcPtr t);
+ OCIOHIDDEN void operator >> (const YAML::Node& node, TruelightTransformRcPtr& t);
+ OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstTruelightTransformRcPtr t);
+
+ // Enums
+ OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, BitDepth depth);
+ OCIOHIDDEN void operator >> (const YAML::Node& node, BitDepth& depth);
+ OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, Allocation alloc);
+ OCIOHIDDEN void operator >> (const YAML::Node& node, Allocation& alloc);
+ OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ColorSpaceDirection dir);
+ OCIOHIDDEN void operator >> (const YAML::Node& node, ColorSpaceDirection& dir);
+ OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, TransformDirection dir);
+ OCIOHIDDEN void operator >> (const YAML::Node& node, TransformDirection& dir);
+ OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, Interpolation iterp);
+ OCIOHIDDEN void operator >> (const YAML::Node& node, Interpolation& iterp);
+
+ void LogUnknownKeyWarning(const std::string & name, const YAML::Node& tag);
+}
+OCIO_NAMESPACE_EXIT
+
+#endif // INCLUDED_OCIO_YAML_H
diff --git a/src/core/Op.cpp b/src/core/Op.cpp
new file mode 100644
index 0000000..e4e9da2
--- /dev/null
+++ b/src/core/Op.cpp
@@ -0,0 +1,126 @@
+/*
+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 "Op.h"
+#include "pystring/pystring.h"
+
+#include <sstream>
+
+OCIO_NAMESPACE_ENTER
+{
+ Op::~Op()
+ { }
+
+ bool Op::canCombineWith(const OpRcPtr & /*op*/) const
+ {
+ return false;
+ }
+
+ void Op::combineWith(OpRcPtrVec & /*ops*/,
+ const OpRcPtr & /*secondOp*/) const
+ {
+ std::ostringstream os;
+ os << "Op: " << getInfo() << " cannot be combined. ";
+ os << "A type-specific combining function is not defined.";
+ throw Exception(os.str().c_str());
+ }
+
+ std::ostream& operator<< (std::ostream & os, const Op & op)
+ {
+ os << op.getInfo();
+ return os;
+ }
+
+ namespace
+ {
+ const int FLOAT_DECIMALS = 7;
+ }
+
+ std::string AllocationData::getCacheID() const
+ {
+ std::ostringstream os;
+ os.precision(FLOAT_DECIMALS);
+ os << AllocationToString(allocation) << " ";
+
+ for(unsigned int i=0; i<vars.size(); ++i)
+ {
+ os << vars[i] << " ";
+ }
+
+ return os.str();
+ }
+
+ std::ostream& operator<< (std::ostream & os, const AllocationData & allocation)
+ {
+ os << allocation.getCacheID();
+ return os;
+ }
+
+ std::string SerializeOpVec(const OpRcPtrVec & ops, int indent)
+ {
+ std::ostringstream os;
+
+ for(OpRcPtrVec::size_type i = 0, size = ops.size(); i < size; ++i)
+ {
+ os << pystring::mul(" ", indent);
+ os << "Op " << i << ": " << *ops[i] << " ";
+ os << ops[i]->getCacheID() << " supports_gpu:" << ops[i]->supportsGpuShader();
+ os << "\n";
+ }
+
+ return os.str();
+ }
+
+ bool IsOpVecNoOp(const OpRcPtrVec & ops)
+ {
+ for(OpRcPtrVec::size_type i = 0, size = ops.size(); i < size; ++i)
+ {
+ if(!ops[i]->isNoOp()) return false;
+ }
+
+ return true;
+ }
+
+ void FinalizeOpVec(OpRcPtrVec & ops, bool optimize)
+ {
+ // TODO: Add envvar to force disable optimizations
+
+ if(optimize)
+ {
+ OptimizeOpVec(ops);
+ }
+
+ for(OpRcPtrVec::size_type i = 0, size = ops.size(); i < size; ++i)
+ {
+ ops[i]->finalize();
+ }
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/Op.h b/src/core/Op.h
new file mode 100644
index 0000000..831c072
--- /dev/null
+++ b/src/core/Op.h
@@ -0,0 +1,136 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_OP_H
+#define INCLUDED_OCIO_OP_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include <sstream>
+#include <vector>
+
+OCIO_NAMESPACE_ENTER
+{
+ struct AllocationData
+ {
+ Allocation allocation;
+ std::vector<float> vars;
+
+ AllocationData():
+ allocation(ALLOCATION_UNIFORM)
+ {};
+
+ std::string getCacheID() const;
+ };
+
+ std::ostream& operator<< (std::ostream&, const AllocationData&);
+
+ class Op;
+ typedef OCIO_SHARED_PTR<Op> OpRcPtr;
+ typedef std::vector<OpRcPtr> OpRcPtrVec;
+
+ std::string SerializeOpVec(const OpRcPtrVec & ops, int indent=0);
+ bool IsOpVecNoOp(const OpRcPtrVec & ops);
+
+ void FinalizeOpVec(OpRcPtrVec & opVec, bool optimize=true);
+
+ void OptimizeOpVec(OpRcPtrVec & result);
+
+ class Op
+ {
+ public:
+ virtual ~Op();
+
+ virtual OpRcPtr clone() const = 0;
+
+ //! Something short, and printable.
+ // The type of stuff you'd want to see in debugging.
+ virtual std::string getInfo() const = 0;
+
+ //! This should yield a string of not unreasonable length.
+ //! It can only be called after finalize()
+ virtual std::string getCacheID() const = 0;
+
+ //! Is the processing a noop? I.e, does apply do nothing.
+ //! (Even no-ops may define Allocation though.)
+ //! This must be implmented in a manner where its valid to call
+ //! *prior* to finalize. (Optimizers may make use of it)
+ virtual bool isNoOp() const = 0;
+
+ virtual bool isSameType(const OpRcPtr & op) const = 0;
+
+ virtual bool isInverse(const OpRcPtr & op) const = 0;
+
+ virtual bool canCombineWith(const OpRcPtr & op) const;
+
+ // Return a vector of result ops, which correspond to
+ // THIS combinedWith secondOp.
+ //
+ // If the result is a noOp, it is valid for the resulting opsVec
+ // to be empty.
+
+ virtual void combineWith(OpRcPtrVec & ops, const OpRcPtr & secondOp) const;
+
+ virtual bool hasChannelCrosstalk() const = 0;
+
+ virtual void dumpMetadata(ProcessorMetadataRcPtr & /*metadata*/) const
+ { }
+
+ // This is called a single time after construction.
+ // Final pre-processing and safety checks should happen here,
+ // rather than in the constructor.
+
+ virtual void finalize() = 0;
+
+ // Render the specified pixels.
+ //
+ // This must be safe to call in a multi-threaded context.
+ // Ops that have mutable data internally, or rely on external
+ // caching, must thus be appropriately mutexed.
+
+ virtual void apply(float* rgbaBuffer, long numPixels) const = 0;
+
+
+ //! Does this op support gpu shader text generation
+ virtual bool supportsGpuShader() const = 0;
+
+ // TODO: If temp variables are ever needed, also pass tempvar prefix.
+ virtual void writeGpuShader(std::ostream & shader,
+ const std::string & pixelName,
+ const GpuShaderDesc & shaderDesc) const = 0;
+
+ private:
+ Op& operator= (const Op &);
+ };
+
+ std::ostream& operator<< (std::ostream&, const Op&);
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/OpBuilders.h b/src/core/OpBuilders.h
new file mode 100644
index 0000000..f981478
--- /dev/null
+++ b/src/core/OpBuilders.h
@@ -0,0 +1,125 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_OPBUILDERS_H
+#define INCLUDED_OCIO_OPBUILDERS_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "Op.h"
+#include "LookParse.h"
+#include "PrivateTypes.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ void BuildOps(OpRcPtrVec & ops,
+ const Config & config,
+ const ConstContextRcPtr & context,
+ const ConstTransformRcPtr & transform,
+ TransformDirection dir);
+
+
+ ////////////////////////////////////////////////////////////////////////
+
+ void BuildAllocationOps(OpRcPtrVec & ops,
+ const Config & config,
+ const AllocationTransform & transform,
+ TransformDirection dir);
+
+ void BuildCDLOps(OpRcPtrVec & ops,
+ const Config & config,
+ const CDLTransform & transform,
+ TransformDirection dir);
+
+ void BuildColorSpaceOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ const ColorSpaceTransform & transform,
+ TransformDirection dir);
+
+ void BuildColorSpaceOps(OpRcPtrVec & ops,
+ const Config & config,
+ const ConstContextRcPtr & context,
+ const ConstColorSpaceRcPtr & srcColorSpace,
+ const ConstColorSpaceRcPtr & dstColorSpace);
+
+ void BuildDisplayOps(OpRcPtrVec & ops,
+ const Config & config,
+ const ConstContextRcPtr & context,
+ const DisplayTransform & transform,
+ TransformDirection dir);
+
+ void BuildExponentOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ExponentTransform & transform,
+ TransformDirection dir);
+
+ void BuildFileOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ const FileTransform & transform,
+ TransformDirection dir);
+
+ void BuildGroupOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ const GroupTransform & transform,
+ TransformDirection dir);
+
+ void BuildLogOps(OpRcPtrVec & ops,
+ const Config& config,
+ const LogTransform& transform,
+ TransformDirection dir);
+
+ void BuildLookOps(OpRcPtrVec & ops,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ const LookTransform & lookTransform,
+ TransformDirection dir);
+
+ void BuildLookOps(OpRcPtrVec & ops,
+ ConstColorSpaceRcPtr & currentColorSpace,
+ bool skipColorSpaceConversions,
+ const Config& config,
+ const ConstContextRcPtr & context,
+ const LookParseResult & looks);
+
+ void BuildMatrixOps(OpRcPtrVec & ops,
+ const Config& config,
+ const MatrixTransform & transform,
+ TransformDirection dir);
+
+ void BuildTruelightOps(OpRcPtrVec & ops,
+ const Config & config,
+ const TruelightTransform & transform,
+ TransformDirection dir);
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/OpOptimizers.cpp b/src/core/OpOptimizers.cpp
new file mode 100644
index 0000000..6e975eb
--- /dev/null
+++ b/src/core/OpOptimizers.cpp
@@ -0,0 +1,364 @@
+/*
+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 "Logging.h"
+#include "Op.h"
+
+#include <iterator>
+#include <sstream>
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ const int MAX_OPTIMIZATION_PASSES = 8;
+
+ int RemoveNoOps(OpRcPtrVec & opVec)
+ {
+ int count = 0;
+
+ OpRcPtrVec::iterator iter = opVec.begin();
+ while(iter != opVec.end())
+ {
+ if((*iter)->isNoOp())
+ {
+ iter = opVec.erase(iter);
+ ++count;
+ }
+ else
+ {
+ ++iter;
+ }
+ }
+
+ return count;
+ }
+
+ int RemoveInverseOps(OpRcPtrVec & opVec)
+ {
+ int count = 0;
+ int firstindex = 0; // this must be a signed int
+
+ while(firstindex < static_cast<int>(opVec.size()-1))
+ {
+ const OpRcPtr & first = opVec[firstindex];
+ const OpRcPtr & second = opVec[firstindex+1];
+
+ // The common case of inverse ops is to have a deep nesting:
+ // ..., A, B, B', A', ...
+ //
+ // Consider the above, when firstindex reaches B:
+ //
+ // |
+ // ..., A, B, B', A', ...
+ //
+ // We will remove B and B'.
+ // Firstindex remains pointing at the original location:
+ //
+ // |
+ // ..., A, A', ...
+ //
+ // We then decrement firstindex by 1,
+ // to backstep and reconsider the A, A' case:
+ //
+ // | <-- firstindex decremented
+ // ..., A, A', ...
+ //
+
+ if(first->isSameType(second) && first->isInverse(second))
+ {
+ opVec.erase(opVec.begin() + firstindex,
+ opVec.begin() + firstindex + 2);
+ ++count;
+
+ firstindex = std::max(0, firstindex-1);
+ }
+ else
+ {
+ ++firstindex;
+ }
+ }
+
+ return count;
+ }
+
+ int CombineOps(OpRcPtrVec & opVec)
+ {
+ int count = 0;
+ int firstindex = 0; // this must be a signed int
+
+ OpRcPtrVec tmpops;
+
+ while(firstindex < static_cast<int>(opVec.size()-1))
+ {
+ const OpRcPtr & first = opVec[firstindex];
+ const OpRcPtr & second = opVec[firstindex+1];
+
+ if(first->canCombineWith(second))
+ {
+ tmpops.clear();
+ first->combineWith(tmpops, second);
+
+ // tmpops may have any number of ops in it. (0, 1, 2, ...)
+ // (size 0 would occur potentially iff the combination
+ // results in a no-op)
+ //
+ // No matter the number, we need to swap them in for the
+ // original ops
+
+ // Erase the initial two ops we've combined
+ opVec.erase(opVec.begin() + firstindex,
+ opVec.begin() + firstindex + 2);
+
+ // Insert the new ops (which may be empty) at
+ // this location
+ std::copy(tmpops.begin(), tmpops.end(),
+ std::inserter(opVec, opVec.begin() + firstindex));
+
+ // Decrement firstindex by 1,
+ // to backstep and reconsider the A, A' case.
+ // See RemoveInverseOps for the full discussion of
+ // why this is appropriate
+ firstindex = std::max(0, firstindex-1);
+
+ // We've done something so increment the count!
+ ++count;
+ }
+ else
+ {
+ ++firstindex;
+ }
+ }
+
+ return count;
+ }
+ }
+
+ void OptimizeOpVec(OpRcPtrVec & ops)
+ {
+ if(ops.empty()) return;
+
+
+ if(IsDebugLoggingEnabled())
+ {
+ LogDebug("Optimizing Op Vec...");
+ LogDebug(SerializeOpVec(ops, 4));
+ }
+
+ OpRcPtrVec::size_type originalSize = ops.size();
+ int total_noops = 0;
+ int total_inverseops = 0;
+ int total_combines = 0;
+ int passes = 0;
+
+ while(passes<=MAX_OPTIMIZATION_PASSES)
+ {
+ int noops = RemoveNoOps(ops);
+ int inverseops = RemoveInverseOps(ops);
+ int combines = CombineOps(ops);
+
+ if(noops == 0 && inverseops==0 && combines==0)
+ {
+ // No optimization progress was made, so stop trying.
+ break;
+ }
+
+ total_noops += noops;
+ total_inverseops += inverseops;
+ total_combines += combines;
+
+ ++passes;
+ }
+
+ OpRcPtrVec::size_type finalSize = ops.size();
+
+ if(passes == MAX_OPTIMIZATION_PASSES)
+ {
+ std::ostringstream os;
+ os << "The max number of passes, " << passes << ", ";
+ os << "was reached during optimization. This is likely a sign ";
+ os << "that either the complexity of the color transform is ";
+ os << "very high, or that some internal optimizers are in conflict ";
+ os << "(undo-ing / redo-ing the other's results).";
+ LogDebug(os.str().c_str());
+ }
+
+ if(IsDebugLoggingEnabled())
+ {
+ std::ostringstream os;
+ os << "Optimized ";
+ os << originalSize << "->" << finalSize << ", ";
+ os << passes << " passes, ";
+ os << total_noops << " noops removed, ";
+ os << total_inverseops << " inverse ops removed\n";
+ os << total_combines << " ops combines\n";
+ os << SerializeOpVec(ops, 4);
+ LogDebug(os.str());
+ }
+ }
+}
+OCIO_NAMESPACE_EXIT
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef OCIO_UNIT_TEST
+
+namespace OCIO = OCIO_NAMESPACE;
+#include "UnitTest.h"
+
+#include "ExponentOps.h"
+#include "LogOps.h"
+#include "Lut1DOp.h"
+#include "Lut3DOp.h"
+#include "MatrixOps.h"
+
+OIIO_ADD_TEST(OpOptimizers, RemoveInverseOps)
+{
+ OCIO::OpRcPtrVec ops;
+
+ float exp[4] = { 1.2f, 1.3f, 1.4f, 1.5f };
+
+
+ float k[3] = { 0.18f, 0.18f, 0.18f };
+ float m[3] = { 2.0f, 2.0f, 2.0f };
+ float b[3] = { 0.1f, 0.1f, 0.1f };
+ float base[3] = { 10.0f, 10.0f, 10.0f };
+ float kb[3] = { 1.0f, 1.0f, 1.0f };
+
+ OCIO::CreateExponentOp(ops, exp, OCIO::TRANSFORM_DIR_FORWARD);
+ OCIO::CreateLogOp(ops, k, m, b, base, kb, OCIO::TRANSFORM_DIR_FORWARD);
+ OCIO::CreateLogOp(ops, k, m, b, base, kb, OCIO::TRANSFORM_DIR_INVERSE);
+ OCIO::CreateExponentOp(ops, exp, OCIO::TRANSFORM_DIR_INVERSE);
+
+ OIIO_CHECK_EQUAL(ops.size(), 4);
+ OCIO::RemoveInverseOps(ops);
+ OIIO_CHECK_EQUAL(ops.size(), 0);
+
+
+ ops.clear();
+ OCIO::CreateExponentOp(ops, exp, OCIO::TRANSFORM_DIR_FORWARD);
+ OCIO::CreateExponentOp(ops, exp, OCIO::TRANSFORM_DIR_INVERSE);
+ OCIO::CreateLogOp(ops, k, m, b, base, kb, OCIO::TRANSFORM_DIR_INVERSE);
+ OCIO::CreateLogOp(ops, k, m, b, base, kb, OCIO::TRANSFORM_DIR_FORWARD);
+ OCIO::CreateExponentOp(ops, exp, OCIO::TRANSFORM_DIR_FORWARD);
+
+ OIIO_CHECK_EQUAL(ops.size(), 5);
+ OCIO::RemoveInverseOps(ops);
+ OIIO_CHECK_EQUAL(ops.size(), 1);
+}
+
+
+OIIO_ADD_TEST(OpOptimizers, CombineOps)
+{
+ float m1[4] = { 2.0f, 2.0f, 2.0f, 1.0f };
+ float m2[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
+ float m3[4] = { 0.6f, 0.6f, 0.6f, 1.0f };
+ float m4[4] = { 0.7f, 0.7f, 0.7f, 1.0f };
+
+ float exp[4] = { 1.2f, 1.3f, 1.4f, 1.5f };
+
+ {
+ OCIO::OpRcPtrVec ops;
+ OCIO::CreateScaleOp(ops, m1, OCIO::TRANSFORM_DIR_FORWARD);
+
+ OIIO_CHECK_EQUAL(ops.size(), 1);
+ OCIO::CombineOps(ops);
+ OIIO_CHECK_EQUAL(ops.size(), 1);
+ }
+
+ {
+ OCIO::OpRcPtrVec ops;
+ OCIO::CreateScaleOp(ops, m1, OCIO::TRANSFORM_DIR_FORWARD);
+ OCIO::CreateScaleOp(ops, m3, OCIO::TRANSFORM_DIR_FORWARD);
+
+ OIIO_CHECK_EQUAL(ops.size(), 2);
+ OCIO::CombineOps(ops);
+ OIIO_CHECK_EQUAL(ops.size(), 1);
+ }
+
+ {
+ OCIO::OpRcPtrVec ops;
+ OCIO::CreateScaleOp(ops, m1, OCIO::TRANSFORM_DIR_FORWARD);
+ OCIO::CreateScaleOp(ops, m3, OCIO::TRANSFORM_DIR_FORWARD);
+ OCIO::CreateScaleOp(ops, m4, OCIO::TRANSFORM_DIR_FORWARD);
+
+ OIIO_CHECK_EQUAL(ops.size(), 3);
+ OCIO::CombineOps(ops);
+ OIIO_CHECK_EQUAL(ops.size(), 1);
+ }
+
+ {
+ OCIO::OpRcPtrVec ops;
+ OCIO::CreateScaleOp(ops, m1, OCIO::TRANSFORM_DIR_FORWARD);
+ OCIO::CreateScaleOp(ops, m2, OCIO::TRANSFORM_DIR_FORWARD);
+
+ OIIO_CHECK_EQUAL(ops.size(), 2);
+ OCIO::CombineOps(ops);
+ OIIO_CHECK_EQUAL(ops.size(), 0);
+ }
+
+ {
+ OCIO::OpRcPtrVec ops;
+ OCIO::CreateScaleOp(ops, m1, OCIO::TRANSFORM_DIR_FORWARD);
+ OCIO::CreateScaleOp(ops, m1, OCIO::TRANSFORM_DIR_INVERSE);
+
+ OIIO_CHECK_EQUAL(ops.size(), 2);
+ OCIO::CombineOps(ops);
+ OIIO_CHECK_EQUAL(ops.size(), 0);
+ }
+
+ {
+ OCIO::OpRcPtrVec ops;
+ OCIO::CreateScaleOp(ops, m1, OCIO::TRANSFORM_DIR_FORWARD);
+ OCIO::CreateScaleOp(ops, m1, OCIO::TRANSFORM_DIR_FORWARD);
+ OCIO::CreateScaleOp(ops, m1, OCIO::TRANSFORM_DIR_FORWARD);
+ OCIO::CreateScaleOp(ops, m1, OCIO::TRANSFORM_DIR_FORWARD);
+ OCIO::CreateScaleOp(ops, m1, OCIO::TRANSFORM_DIR_FORWARD);
+
+ OIIO_CHECK_EQUAL(ops.size(), 5);
+ OCIO::CombineOps(ops);
+ OIIO_CHECK_EQUAL(ops.size(), 1);
+ }
+
+ {
+ OCIO::OpRcPtrVec ops;
+ OCIO::CreateExponentOp(ops, exp, OCIO::TRANSFORM_DIR_FORWARD);
+ OCIO::CreateScaleOp(ops, m1, OCIO::TRANSFORM_DIR_FORWARD);
+ OCIO::CreateScaleOp(ops, m2, OCIO::TRANSFORM_DIR_FORWARD);
+ OCIO::CreateExponentOp(ops, exp, OCIO::TRANSFORM_DIR_INVERSE);
+
+ OIIO_CHECK_EQUAL(ops.size(), 4);
+ OCIO::CombineOps(ops);
+ OIIO_CHECK_EQUAL(ops.size(), 0);
+ }
+}
+
+#endif // OCIO_UNIT_TEST
diff --git a/src/core/ParseUtils.cpp b/src/core/ParseUtils.cpp
new file mode 100644
index 0000000..9110161
--- /dev/null
+++ b/src/core/ParseUtils.cpp
@@ -0,0 +1,438 @@
+/*
+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 <iostream>
+#include <set>
+#include <sstream>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "ParseUtils.h"
+#include "pystring/pystring.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ const char * BoolToString(bool val)
+ {
+ if(val) return "true";
+ return "false";
+ }
+
+ bool BoolFromString(const char * s)
+ {
+ std::string str = pystring::lower(s);
+ if((str == "true") || (str=="yes")) return true;
+ return false;
+ }
+
+ const char * LoggingLevelToString(LoggingLevel level)
+ {
+ if(level == LOGGING_LEVEL_NONE) return "none";
+ else if(level == LOGGING_LEVEL_WARNING) return "warning";
+ else if(level == LOGGING_LEVEL_INFO) return "info";
+ else if(level == LOGGING_LEVEL_DEBUG) return "debug";
+ return "unknown";
+ }
+
+ LoggingLevel LoggingLevelFromString(const char * s)
+ {
+ std::string str = pystring::lower(s);
+ if(str == "0" || str == "none") return LOGGING_LEVEL_NONE;
+ else if(str == "1" || str == "warning") return LOGGING_LEVEL_WARNING;
+ else if(str == "2" || str == "info") return LOGGING_LEVEL_INFO;
+ else if(str == "3" || str == "debug") return LOGGING_LEVEL_DEBUG;
+ return LOGGING_LEVEL_UNKNOWN;
+ }
+
+ const char * TransformDirectionToString(TransformDirection dir)
+ {
+ if(dir == TRANSFORM_DIR_FORWARD) return "forward";
+ else if(dir == TRANSFORM_DIR_INVERSE) return "inverse";
+ return "unknown";
+ }
+
+ TransformDirection TransformDirectionFromString(const char * s)
+ {
+ std::string str = pystring::lower(s);
+ if(str == "forward") return TRANSFORM_DIR_FORWARD;
+ else if(str == "inverse") return TRANSFORM_DIR_INVERSE;
+ return TRANSFORM_DIR_UNKNOWN;
+ }
+
+ TransformDirection CombineTransformDirections(TransformDirection d1,
+ TransformDirection d2)
+ {
+ // Any unknowns always combine to be unknown.
+ if(d1 == TRANSFORM_DIR_UNKNOWN || d2 == TRANSFORM_DIR_UNKNOWN)
+ return TRANSFORM_DIR_UNKNOWN;
+
+ if(d1 == TRANSFORM_DIR_FORWARD && d2 == TRANSFORM_DIR_FORWARD)
+ return TRANSFORM_DIR_FORWARD;
+
+ if(d1 == TRANSFORM_DIR_INVERSE && d2 == TRANSFORM_DIR_INVERSE)
+ return TRANSFORM_DIR_FORWARD;
+
+ return TRANSFORM_DIR_INVERSE;
+ }
+
+ TransformDirection GetInverseTransformDirection(TransformDirection dir)
+ {
+ if(dir == TRANSFORM_DIR_FORWARD) return TRANSFORM_DIR_INVERSE;
+ else if(dir == TRANSFORM_DIR_INVERSE) return TRANSFORM_DIR_FORWARD;
+ return TRANSFORM_DIR_UNKNOWN;
+ }
+
+ const char * ColorSpaceDirectionToString(ColorSpaceDirection dir)
+ {
+ if(dir == COLORSPACE_DIR_TO_REFERENCE) return "to_reference";
+ else if(dir == COLORSPACE_DIR_FROM_REFERENCE) return "from_reference";
+ return "unknown";
+ }
+
+ ColorSpaceDirection ColorSpaceDirectionFromString(const char * s)
+ {
+ std::string str = pystring::lower(s);
+ if(str == "to_reference") return COLORSPACE_DIR_TO_REFERENCE;
+ else if(str == "from_reference") return COLORSPACE_DIR_FROM_REFERENCE;
+ return COLORSPACE_DIR_UNKNOWN;
+ }
+
+ const char * BitDepthToString(BitDepth bitDepth)
+ {
+ if(bitDepth == BIT_DEPTH_UINT8) return "8ui";
+ else if(bitDepth == BIT_DEPTH_UINT10) return "10ui";
+ else if(bitDepth == BIT_DEPTH_UINT12) return "12ui";
+ else if(bitDepth == BIT_DEPTH_UINT14) return "14ui";
+ else if(bitDepth == BIT_DEPTH_UINT16) return "16ui";
+ else if(bitDepth == BIT_DEPTH_UINT32) return "32ui";
+ else if(bitDepth == BIT_DEPTH_F16) return "16f";
+ else if(bitDepth == BIT_DEPTH_F32) return "32f";
+ return "unknown";
+ }
+
+ BitDepth BitDepthFromString(const char * s)
+ {
+ std::string str = pystring::lower(s);
+ if(str == "8ui") return BIT_DEPTH_UINT8;
+ else if(str == "10ui") return BIT_DEPTH_UINT10;
+ else if(str == "12ui") return BIT_DEPTH_UINT12;
+ else if(str == "14ui") return BIT_DEPTH_UINT14;
+ else if(str == "16ui") return BIT_DEPTH_UINT16;
+ else if(str == "32ui") return BIT_DEPTH_UINT32;
+ else if(str == "16f") return BIT_DEPTH_F16;
+ else if(str == "32f") return BIT_DEPTH_F32;
+ return BIT_DEPTH_UNKNOWN;
+ }
+
+ bool BitDepthIsFloat(BitDepth bitDepth)
+ {
+ if(bitDepth == BIT_DEPTH_F16) return true;
+ else if(bitDepth == BIT_DEPTH_F32) return true;
+ return false;
+ }
+
+ int BitDepthToInt(BitDepth bitDepth)
+ {
+ if(bitDepth == BIT_DEPTH_UINT8) return 8;
+ else if(bitDepth == BIT_DEPTH_UINT10) return 10;
+ else if(bitDepth == BIT_DEPTH_UINT12) return 12;
+ else if(bitDepth == BIT_DEPTH_UINT14) return 14;
+ else if(bitDepth == BIT_DEPTH_UINT16) return 16;
+ else if(bitDepth == BIT_DEPTH_UINT32) return 32;
+
+ return 0;
+ }
+
+ const char * AllocationToString(Allocation alloc)
+ {
+ if(alloc == ALLOCATION_UNIFORM) return "uniform";
+ else if(alloc == ALLOCATION_LG2) return "lg2";
+ return "unknown";
+ }
+
+ Allocation AllocationFromString(const char * s)
+ {
+ std::string str = pystring::lower(s);
+ if(str == "uniform") return ALLOCATION_UNIFORM;
+ else if(str == "lg2") return ALLOCATION_LG2;
+ return ALLOCATION_UNKNOWN;
+ }
+
+ const char * InterpolationToString(Interpolation interp)
+ {
+ if(interp == INTERP_NEAREST) return "nearest";
+ else if(interp == INTERP_LINEAR) return "linear";
+ else if(interp == INTERP_TETRAHEDRAL) return "tetrahedral";
+ else if(interp == INTERP_BEST) return "best";
+ return "unknown";
+ }
+
+ Interpolation InterpolationFromString(const char * s)
+ {
+ std::string str = pystring::lower(s);
+ if(str == "nearest") return INTERP_NEAREST;
+ else if(str == "linear") return INTERP_LINEAR;
+ else if(str == "tetrahedral") return INTERP_TETRAHEDRAL;
+ else if(str == "best") return INTERP_BEST;
+ return INTERP_UNKNOWN;
+ }
+
+ const char * GpuLanguageToString(GpuLanguage language)
+ {
+ if(language == GPU_LANGUAGE_CG) return "cg";
+ else if(language == GPU_LANGUAGE_GLSL_1_0) return "glsl_1.0";
+ else if(language == GPU_LANGUAGE_GLSL_1_3) return "glsl_1.3";
+ return "unknown";
+ }
+
+ GpuLanguage GpuLanguageFromString(const char * s)
+ {
+ std::string str = pystring::lower(s);
+ if(str == "cg") return GPU_LANGUAGE_CG;
+ else if(str == "glsl_1.0") return GPU_LANGUAGE_GLSL_1_0;
+ else if(str == "glsl_1.3") return GPU_LANGUAGE_GLSL_1_3;
+ return GPU_LANGUAGE_UNKNOWN;
+ }
+
+
+ const char * ROLE_DEFAULT = "default";
+ const char * ROLE_REFERENCE = "reference";
+ const char * ROLE_DATA = "data";
+ const char * ROLE_COLOR_PICKING = "color_picking";
+ const char * ROLE_SCENE_LINEAR = "scene_linear";
+ const char * ROLE_COMPOSITING_LOG = "compositing_log";
+ const char * ROLE_COLOR_TIMING = "color_timing";
+ const char * ROLE_TEXTURE_PAINT = "texture_paint";
+ const char * ROLE_MATTE_PAINT = "matte_paint";
+
+ namespace
+ {
+ const int FLOAT_DECIMALS = 7;
+ const int DOUBLE_DECIMALS = 16;
+ }
+
+ std::string FloatToString(float value)
+ {
+ std::ostringstream pretty;
+ pretty.precision(FLOAT_DECIMALS);
+ pretty << value;
+ return pretty.str();
+ }
+
+ std::string FloatVecToString(const float * fval, unsigned int size)
+ {
+ if(size<=0) return "";
+
+ std::ostringstream pretty;
+ pretty.precision(FLOAT_DECIMALS);
+ for(unsigned int i=0; i<size; ++i)
+ {
+ if(i!=0) pretty << " ";
+ pretty << fval[i];
+ }
+
+ return pretty.str();
+ }
+
+ bool StringToFloat(float * fval, const char * str)
+ {
+ if(!str) return false;
+
+ std::istringstream inputStringstream(str);
+ float x;
+ if(!(inputStringstream >> x))
+ {
+ return false;
+ }
+
+ if(fval) *fval = x;
+ return true;
+ }
+
+ bool StringToInt(int * ival, const char * str)
+ {
+ if(!str) return false;
+
+ std::istringstream inputStringstream(str);
+ int x;
+ if(!(inputStringstream >> x))
+ {
+ return false;
+ }
+
+ if(ival) *ival = x;
+ return true;
+ }
+
+
+ std::string DoubleToString(double value)
+ {
+ std::ostringstream pretty;
+ pretty.precision(DOUBLE_DECIMALS);
+ pretty << value;
+ return pretty.str();
+ }
+
+
+ bool StringVecToFloatVec(std::vector<float> &floatArray,
+ const std::vector<std::string> &lineParts)
+ {
+ floatArray.resize(lineParts.size());
+
+ for(unsigned int i=0; i<lineParts.size(); i++)
+ {
+ std::istringstream inputStringstream(lineParts[i]);
+ float x;
+ if(!(inputStringstream >> x))
+ {
+ return false;
+ }
+ floatArray[i] = x;
+ }
+
+ return true;
+ }
+
+
+ bool StringVecToIntVec(std::vector<int> &intArray,
+ const std::vector<std::string> &lineParts)
+ {
+ intArray.resize(lineParts.size());
+
+ for(unsigned int i=0; i<lineParts.size(); i++)
+ {
+ std::istringstream inputStringstream(lineParts[i]);
+ int x;
+ if(!(inputStringstream >> x))
+ {
+ return false;
+ }
+ intArray[i] = x;
+ }
+
+ return true;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ // read the next non empty line, and store it in 'line'
+ // return 'true' on success
+
+ bool nextline(std::istream &istream, std::string &line)
+ {
+ while ( istream.good() )
+ {
+ std::getline(istream, line);
+ if(!pystring::strip(line).empty())
+ {
+ return true;
+ }
+ }
+
+ line = "";
+ return false;
+ }
+
+
+ bool StrEqualsCaseIgnore(const std::string & a, const std::string & b)
+ {
+ return (pystring::lower(a) == pystring::lower(b));
+ }
+
+ // If a ',' is in the string, split on it
+ // If a ':' is in the string, split on it
+ // Otherwise, assume a single string.
+ // Also, strip whitespace from all parts.
+
+ void SplitStringEnvStyle(std::vector<std::string> & outputvec, const char * str)
+ {
+ if(!str) return;
+
+ std::string s = pystring::strip(str);
+ if(pystring::find(s, ",") > -1)
+ {
+ pystring::split(s, outputvec, ",");
+ }
+ else if(pystring::find(s, ":") > -1)
+ {
+ pystring::split(s, outputvec, ":");
+ }
+ else
+ {
+ outputvec.push_back(s);
+ }
+
+ for(unsigned int i=0; i<outputvec.size(); ++i)
+ {
+ outputvec[i] = pystring::strip(outputvec[i]);
+ }
+ }
+
+ std::string JoinStringEnvStyle(const std::vector<std::string> & outputvec)
+ {
+ return pystring::join(", ", outputvec);
+ }
+
+ // Ordering and capitalization from vec1 is preserved
+ std::vector<std::string> IntersectStringVecsCaseIgnore(const std::vector<std::string> & vec1,
+ const std::vector<std::string> & vec2)
+ {
+ std::vector<std::string> newvec;
+ std::set<std::string> allvalues;
+
+ // Seed the set with all values from vec2
+ for(unsigned int i=0; i<vec2.size(); ++i)
+ {
+ allvalues.insert(pystring::lower(vec2[i]));
+ }
+
+ for(unsigned int i=0; i<vec1.size(); ++i)
+ {
+ std::string key = pystring::lower(vec1[i]);
+ if(allvalues.find(key) != allvalues.end())
+ {
+ newvec.push_back(vec1[i]);
+ }
+ }
+
+ return newvec;
+ }
+
+
+ int FindInStringVecCaseIgnore(const std::vector<std::string> & vec, const std::string & str)
+ {
+ std::string teststr = pystring::lower(str);
+ for(unsigned int i=0; i<vec.size(); ++i)
+ {
+ if(pystring::lower(vec[i]) == teststr) return static_cast<int>(i);
+ }
+
+ return -1;
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/ParseUtils.h b/src/core/ParseUtils.h
new file mode 100644
index 0000000..efc07d4
--- /dev/null
+++ b/src/core/ParseUtils.h
@@ -0,0 +1,89 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_PARSEUTILS_H
+#define INCLUDED_OCIO_PARSEUTILS_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "PrivateTypes.h"
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+OCIO_NAMESPACE_ENTER
+{
+
+ std::string FloatToString(float fval);
+ std::string FloatVecToString(const float * fval, unsigned int size);
+
+ std::string DoubleToString(double value);
+
+ bool StringToFloat(float * fval, const char * str);
+ bool StringToInt(int * ival, const char * str);
+
+ bool StringVecToFloatVec(std::vector<float> & floatArray,
+ const std::vector<std::string> & lineParts);
+
+ bool StringVecToIntVec(std::vector<int> & intArray,
+ const std::vector<std::string> & lineParts);
+
+ //////////////////////////////////////////////////////////////////////////
+
+ // read the next non empty line, and store it in 'line'
+ // return 'true' on success
+
+ bool nextline(std::istream &istream, std::string &line);
+
+ bool StrEqualsCaseIgnore(const std::string & a, const std::string & b);
+
+ // If a ',' is in the string, split on it
+ // If a ':' is in the string, split on it
+ // Otherwise, assume a single string.
+ // Also, strip whitespace from all parts.
+
+ void SplitStringEnvStyle(std::vector<std::string> & outputvec, const char * str);
+
+ // Join on ','
+ std::string JoinStringEnvStyle(const std::vector<std::string> & outputvec);
+
+ // Ordering and capitalization from vec1 is preserved
+ std::vector<std::string> IntersectStringVecsCaseIgnore(const std::vector<std::string> & vec1,
+ const std::vector<std::string> & vec2);
+
+ // Find the index of the specified string, ignoring case.
+ // return -1 if not found.
+
+ int FindInStringVecCaseIgnore(const std::vector<std::string> & vec, const std::string & str);
+
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/PathUtils.cpp b/src/core/PathUtils.cpp
new file mode 100644
index 0000000..a04ecee
--- /dev/null
+++ b/src/core/PathUtils.cpp
@@ -0,0 +1,229 @@
+/*
+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 <cstdlib>
+#include <fstream>
+#include <iostream>
+#include <limits>
+#include <sstream>
+#include <sys/stat.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "Mutex.h"
+#include "PathUtils.h"
+#include "Platform.h"
+#include "pystring/pystring.h"
+
+#if !defined(WINDOWS)
+#include <sys/param.h>
+#else
+#include <direct.h>
+#define MAXPATHLEN 4096
+#endif
+
+#if defined(__APPLE__) && !defined(__IPHONE__)
+#include <crt_externs.h> // _NSGetEnviron()
+#elif !defined(WINDOWS)
+#include <unistd.h>
+extern char **environ;
+#endif
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ typedef std::map<std::string, std::string> StringMap;
+
+ StringMap g_fastFileHashCache;
+ Mutex g_fastFileHashCache_mutex;
+
+ std::string ComputeHash(const std::string & filename)
+ {
+ struct stat results;
+ if (stat(filename.c_str(), &results) == 0)
+ {
+ // Treat the mtime + inode as a proxy for the contents
+ std::ostringstream fasthash;
+ fasthash << results.st_ino << ":";
+ fasthash << results.st_mtime;
+ return fasthash.str();
+ }
+
+ return "";
+ }
+ }
+
+ std::string GetFastFileHash(const std::string & filename)
+ {
+ AutoMutex lock(g_fastFileHashCache_mutex);
+
+ StringMap::iterator iter = g_fastFileHashCache.find(filename);
+ if(iter != g_fastFileHashCache.end())
+ {
+ return iter->second;
+ }
+
+ std::string hash = ComputeHash(filename);
+ g_fastFileHashCache[filename] = hash;
+
+ return hash;
+ }
+
+ bool FileExists(const std::string & filename)
+ {
+ std::string hash = GetFastFileHash(filename);
+ return (!hash.empty());
+ }
+
+ void ClearPathCaches()
+ {
+ AutoMutex lock(g_fastFileHashCache_mutex);
+ g_fastFileHashCache.clear();
+ }
+
+ namespace pystring
+ {
+ namespace os
+ {
+ std::string getcwd()
+ {
+#ifdef WINDOWS
+ char path[MAXPATHLEN];
+ _getcwd(path, MAXPATHLEN);
+ return path;
+#else
+ char path[MAXPATHLEN];
+ ::getcwd(path, MAXPATHLEN);
+ return path;
+#endif
+ }
+
+ namespace path
+ {
+ std::string abspath(const std::string & path)
+ {
+ std::string p = path;
+ if(!isabs(p)) p = join(getcwd(), p);
+ return normpath(p);
+ }
+ } // namespace path
+ } // namespace os
+ }
+
+ namespace
+ {
+ inline char** GetEnviron()
+ {
+#if __IPHONE__
+ // TODO: fix this
+ return NULL;
+#elif __APPLE__
+ return (*_NSGetEnviron());
+#else
+ return environ;
+#endif
+ }
+
+ const int MAX_PATH_LENGTH = 4096;
+ }
+
+ void LoadEnvironment(EnvMap & map)
+ {
+ for (char **env = GetEnviron(); *env != NULL; ++env)
+ {
+ // split environment up into std::map[name] = value
+ std::string env_str = (char*)*env;
+ int pos = static_cast<int>(env_str.find_first_of('='));
+ map.insert(
+ EnvMap::value_type(env_str.substr(0, pos),
+ env_str.substr(pos+1, env_str.length()))
+ );
+ }
+ }
+
+ std::string EnvExpand(const std::string & str, const EnvMap & map)
+ {
+ // Early exit if no magic characters are found.
+ if(pystring::find(str, "$") == -1 &&
+ pystring::find(str, "%") == -1) return str;
+
+ std::string orig = str;
+ std::string newstr = str;
+
+ // This walks through the envmap in key order,
+ // from longest to shortest to handle envvars which are
+ // substrings.
+ // ie. '$TEST_$TESTING_$TE' will expand in this order '2 1 3'
+
+ for (EnvMap::const_iterator iter = map.begin();
+ iter != map.end(); ++iter)
+ {
+ newstr = pystring::replace(newstr,
+ ("${"+iter->first+"}"), iter->second);
+ newstr = pystring::replace(newstr,
+ ("$"+iter->first), iter->second);
+ newstr = pystring::replace(newstr,
+ ("%"+iter->first+"%"), iter->second);
+ }
+
+ // recursively call till string doesn't expand anymore
+ if(newstr != orig)
+ {
+ return EnvExpand(newstr, map);
+ }
+
+ return orig;
+ }
+}
+OCIO_NAMESPACE_EXIT
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef OCIO_UNIT_TEST
+
+namespace OCIO = OCIO_NAMESPACE;
+#include "UnitTest.h"
+
+OIIO_ADD_TEST(PathUtils, EnvExpand)
+{
+ // build env by hand for unit test
+ OCIO::EnvMap env_map; // = OCIO::GetEnvMap();
+
+ // add some fake env vars so the test runs
+ env_map.insert(OCIO::EnvMap::value_type("TEST1", "foo.bar"));
+ env_map.insert(OCIO::EnvMap::value_type("TEST1NG", "bar.foo"));
+ env_map.insert(OCIO::EnvMap::value_type("FOO_foo.bar", "cheese"));
+
+ //
+ std::string foo = "/a/b/${TEST1}/${TEST1NG}/$TEST1/$TEST1NG/${FOO_${TEST1}}/";
+ std::string foo_result = "/a/b/foo.bar/bar.foo/foo.bar/bar.foo/cheese/";
+ std::string testresult = OCIO::EnvExpand(foo, env_map);
+ OIIO_CHECK_ASSERT( testresult == foo_result );
+}
+
+#endif // OCIO_BUILD_TESTS
diff --git a/src/core/PathUtils.h b/src/core/PathUtils.h
new file mode 100644
index 0000000..649f52c
--- /dev/null
+++ b/src/core/PathUtils.h
@@ -0,0 +1,95 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_PATHUTILS_H
+#define INCLUDED_OCIO_PATHUTILS_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include <map>
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace pystring
+ {
+ namespace os
+ {
+ namespace path
+ {
+ // This is not currently included in pystring, but we need it
+ // So let's define it locally for now
+
+ std::string abspath(const std::string & path);
+ }
+ }
+ }
+
+ // The EnvMap is ordered by the length of the keys (long -> short). This
+ // is so that recursive string expansion will deal with similar prefixed
+ // keys as expected.
+ // ie. '$TEST_$TESTING_$TE' will expand in this order '2 1 3'
+ template <class T>
+ struct EnvMapKey : std::binary_function <T, T, bool>
+ {
+ bool
+ operator() (const T &x, const T &y) const
+ {
+ // If the lengths are unequal, sort by length
+ if(x.length() != y.length())
+ {
+ return (x.length() > y.length());
+ }
+ // Otherwise, use the standard string sort comparison
+ else
+ {
+ return (x<y);
+ }
+ }
+ };
+ typedef std::map< std::string, std::string, EnvMapKey< std::string > > EnvMap;
+
+ // Get map of current env key = value,
+ void LoadEnvironment(EnvMap & map);
+
+ // Expand a string with $VAR, ${VAR} or %VAR% with the keys passed
+ // in the EnvMap.
+ std::string EnvExpand(const std::string & str, const EnvMap & map);
+
+ // Check if a file exists
+ bool FileExists(const std::string & filename);
+
+ // Get a fast hash for a file, without reading all the contents.
+ // Currently, this checks the mtime and the inode number.
+ std::string GetFastFileHash(const std::string & filename);
+
+ void ClearPathCaches();
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/Platform.h b/src/core/Platform.h
new file mode 100644
index 0000000..56d0971
--- /dev/null
+++ b/src/core/Platform.h
@@ -0,0 +1,202 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_PLATFORM_H
+#define INCLUDED_OCIO_PLATFORM_H
+
+/*
+PTEX SOFTWARE
+Copyright 2009 Disney Enterprises, Inc. 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.
+
+ * The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
+ Studios" or the names of its contributors may NOT be used to
+ endorse or promote products derived from this software without
+ specific prior written permission from Walt Disney Pictures.
+
+Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
+CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
+IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER 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 BASED 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 DAMAGES.
+*/
+
+// platform-specific includes
+#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS) || defined(_MSC_VER)
+#ifndef WINDOWS
+#define WINDOWS
+#endif
+#define _CRT_NONSTDC_NO_DEPRECATE 1
+#define _CRT_SECURE_NO_DEPRECATE 1
+#define NOMINMAX 1
+
+// windows - defined for both Win32 and Win64
+#include <Windows.h>
+#include <malloc.h>
+#include <io.h>
+#include <tchar.h>
+#include <process.h>
+
+#else
+
+// linux/unix/posix
+#include <stdlib.h>
+#include <alloca.h>
+#include <string.h>
+#include <pthread.h>
+// OS for spinlock
+#ifdef __APPLE__
+#include <libkern/OSAtomic.h>
+#include <sys/types.h>
+#endif
+#endif
+
+// general includes
+#include <stdio.h>
+#include <math.h>
+#include <assert.h>
+
+// missing functions on Windows
+#ifdef WINDOWS
+#define snprintf sprintf_s
+#define strtok_r strtok_s
+typedef __int64 FilePos;
+#define fseeko _fseeki64
+#define ftello _ftelli64
+
+inline double log2(double x) {
+ return log(x) * 1.4426950408889634;
+}
+
+#else
+typedef off_t FilePos;
+#endif
+
+
+OCIO_NAMESPACE_ENTER
+{
+
+// TODO: Add proper endian detection using architecture / compiler mojo
+// In the meantime, hardcode to x86
+#define OCIO_LITTLE_ENDIAN 1 // This is correct on x86
+
+ /*
+ * Mutex/SpinLock classes
+ */
+
+#ifdef WINDOWS
+
+ class _Mutex {
+ public:
+ _Mutex() { _mutex = CreateMutex(NULL, FALSE, NULL); }
+ ~_Mutex() { CloseHandle(_mutex); }
+ void lock() { WaitForSingleObject(_mutex, INFINITE); }
+ void unlock() { ReleaseMutex(_mutex); }
+ private:
+ HANDLE _mutex;
+ };
+
+ class _SpinLock {
+ public:
+ _SpinLock() { InitializeCriticalSection(&_spinlock); }
+ ~_SpinLock() { DeleteCriticalSection(&_spinlock); }
+ void lock() { EnterCriticalSection(&_spinlock); }
+ void unlock() { LeaveCriticalSection(&_spinlock); }
+ private:
+ CRITICAL_SECTION _spinlock;
+ };
+
+#else
+ // assume linux/unix/posix
+
+ class _Mutex {
+ public:
+ _Mutex() { pthread_mutex_init(&_mutex, 0); }
+ ~_Mutex() { pthread_mutex_destroy(&_mutex); }
+ void lock() { pthread_mutex_lock(&_mutex); }
+ void unlock() { pthread_mutex_unlock(&_mutex); }
+ private:
+ pthread_mutex_t _mutex;
+ };
+
+#if __APPLE__
+ class _SpinLock {
+ public:
+ _SpinLock() { _spinlock = 0; }
+ ~_SpinLock() { }
+ void lock() { OSSpinLockLock(&_spinlock); }
+ void unlock() { OSSpinLockUnlock(&_spinlock); }
+ private:
+ OSSpinLock _spinlock;
+ };
+#elif ANDROID
+ // we don't have access to pthread on andriod so we just make an empty
+ // class that does nothing.
+ class _SpinLock {
+ public:
+ _SpinLock() { }
+ ~_SpinLock() { }
+ void lock() { }
+ void unlock() { }
+ };
+#else
+ class _SpinLock {
+ public:
+ _SpinLock() { pthread_spin_init(&_spinlock, PTHREAD_PROCESS_PRIVATE); }
+ ~_SpinLock() { pthread_spin_destroy(&_spinlock); }
+ void lock() { pthread_spin_lock(&_spinlock); }
+ void unlock() { pthread_spin_unlock(&_spinlock); }
+ private:
+ pthread_spinlock_t _spinlock;
+ };
+#endif // __APPLE__
+#endif // WINDOWS
+
+}
+OCIO_NAMESPACE_EXIT
+
+#endif // INCLUDED_OCIO_PLATFORM_H
diff --git a/src/core/PrivateTypes.h b/src/core/PrivateTypes.h
new file mode 100644
index 0000000..4f0b1ee
--- /dev/null
+++ b/src/core/PrivateTypes.h
@@ -0,0 +1,54 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_PRIVATE_TYPES_H
+#define INCLUDED_OCIO_PRIVATE_TYPES_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include <map>
+#include <set>
+#include <vector>
+
+OCIO_NAMESPACE_ENTER
+{
+ // Stl types of OCIO classes
+ typedef std::map<std::string, std::string> StringMap;
+ typedef std::vector<std::string> StringVec;
+ typedef std::set<std::string> StringSet;
+
+ typedef std::vector<ConstTransformRcPtr> ConstTransformVec;
+ typedef std::vector<ColorSpaceRcPtr> ColorSpaceVec;
+ typedef std::vector<LookRcPtr> LookVec;
+
+ typedef std::vector<TransformDirection> TransformDirectionVec;
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/Processor.cpp b/src/core/Processor.cpp
new file mode 100644
index 0000000..06b08d2
--- /dev/null
+++ b/src/core/Processor.cpp
@@ -0,0 +1,640 @@
+/*
+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 "AllocationOp.h"
+#include "GpuShaderUtils.h"
+#include "HashUtils.h"
+#include "Logging.h"
+#include "Lut3DOp.h"
+#include "NoOps.h"
+#include "OpBuilders.h"
+#include "Processor.h"
+#include "ScanlineHelper.h"
+
+#include <algorithm>
+#include <cstring>
+#include <sstream>
+
+OCIO_NAMESPACE_ENTER
+{
+
+
+
+ //////////////////////////////////////////////////////////////////////////
+
+ class ProcessorMetadata::Impl
+ {
+ public:
+ StringSet files;
+ StringVec looks;
+
+ Impl()
+ { }
+
+ ~Impl()
+ { }
+ };
+
+ ProcessorMetadataRcPtr ProcessorMetadata::Create()
+ {
+ return ProcessorMetadataRcPtr(new ProcessorMetadata(), &deleter);
+ }
+
+ ProcessorMetadata::ProcessorMetadata()
+ : m_impl(new ProcessorMetadata::Impl)
+ { }
+
+ ProcessorMetadata::~ProcessorMetadata()
+ {
+ delete m_impl;
+ m_impl = NULL;
+ }
+
+ void ProcessorMetadata::deleter(ProcessorMetadata* c)
+ {
+ delete c;
+ }
+
+ int ProcessorMetadata::getNumFiles() const
+ {
+ return static_cast<int>(getImpl()->files.size());
+ }
+
+ const char * ProcessorMetadata::getFile(int index) const
+ {
+ if(index < 0 ||
+ index >= (static_cast<int>(getImpl()->files.size())))
+ {
+ return "";
+ }
+
+ StringSet::const_iterator iter = getImpl()->files.begin();
+ std::advance( iter, index );
+
+ return iter->c_str();
+ }
+
+ void ProcessorMetadata::addFile(const char * fname)
+ {
+ getImpl()->files.insert(fname);
+ }
+
+
+
+ int ProcessorMetadata::getNumLooks() const
+ {
+ return static_cast<int>(getImpl()->looks.size());
+ }
+
+ const char * ProcessorMetadata::getLook(int index) const
+ {
+ if(index < 0 ||
+ index >= (static_cast<int>(getImpl()->looks.size())))
+ {
+ return "";
+ }
+
+ return getImpl()->looks[index].c_str();
+ }
+
+ void ProcessorMetadata::addLook(const char * look)
+ {
+ getImpl()->looks.push_back(look);
+ }
+
+
+
+ //////////////////////////////////////////////////////////////////////////
+
+
+ ProcessorRcPtr Processor::Create()
+ {
+ return ProcessorRcPtr(new Processor(), &deleter);
+ }
+
+ void Processor::deleter(Processor* c)
+ {
+ delete c;
+ }
+
+ Processor::Processor()
+ : m_impl(new Processor::Impl)
+ {
+ }
+
+ Processor::~Processor()
+ {
+ delete m_impl;
+ m_impl = NULL;
+ }
+
+ bool Processor::isNoOp() const
+ {
+ return getImpl()->isNoOp();
+ }
+
+ bool Processor::hasChannelCrosstalk() const
+ {
+ return getImpl()->hasChannelCrosstalk();
+ }
+
+ ConstProcessorMetadataRcPtr Processor::getMetadata() const
+ {
+ return getImpl()->getMetadata();
+ }
+
+ void Processor::apply(ImageDesc& img) const
+ {
+ getImpl()->apply(img);
+ }
+ void Processor::applyRGB(float * pixel) const
+ {
+ getImpl()->applyRGB(pixel);
+ }
+
+ void Processor::applyRGBA(float * pixel) const
+ {
+ getImpl()->applyRGBA(pixel);
+ }
+
+ const char * Processor::getCpuCacheID() const
+ {
+ return getImpl()->getCpuCacheID();
+ }
+
+ const char * Processor::getGpuShaderText(const GpuShaderDesc & shaderDesc) const
+ {
+ return getImpl()->getGpuShaderText(shaderDesc);
+ }
+
+ const char * Processor::getGpuShaderTextCacheID(const GpuShaderDesc & shaderDesc) const
+ {
+ return getImpl()->getGpuShaderTextCacheID(shaderDesc);
+ }
+
+ void Processor::getGpuLut3D(float* lut3d, const GpuShaderDesc & shaderDesc) const
+ {
+ return getImpl()->getGpuLut3D(lut3d, shaderDesc);
+ }
+
+ const char * Processor::getGpuLut3DCacheID(const GpuShaderDesc & shaderDesc) const
+ {
+ return getImpl()->getGpuLut3DCacheID(shaderDesc);
+ }
+
+
+
+ //////////////////////////////////////////////////////////////////////////
+
+
+
+ namespace
+ {
+ void WriteShaderHeader(std::ostream & shader,
+ const std::string & pixelName,
+ const GpuShaderDesc & shaderDesc)
+ {
+ if(!shader) return;
+
+ std::string lut3dName = "lut3d";
+
+ shader << "\n// Generated by OpenColorIO\n\n";
+
+ GpuLanguage lang = shaderDesc.getLanguage();
+
+ std::string fcnName = shaderDesc.getFunctionName();
+
+ if(lang == GPU_LANGUAGE_CG)
+ {
+ shader << "half4 " << fcnName << "(in half4 inPixel," << "\n";
+ shader << " const uniform sampler3D " << lut3dName << ") \n";
+ }
+ else if(lang == GPU_LANGUAGE_GLSL_1_0)
+ {
+ shader << "vec4 " << fcnName << "(vec4 inPixel, \n";
+ shader << " sampler3D " << lut3dName << ") \n";
+ }
+ else if(lang == GPU_LANGUAGE_GLSL_1_3)
+ {
+ shader << "vec4 " << fcnName << "(in vec4 inPixel, \n";
+ shader << " const sampler3D " << lut3dName << ") \n";
+ }
+ else throw Exception("Unsupported shader language.");
+
+ shader << "{" << "\n";
+
+ if(lang == GPU_LANGUAGE_CG)
+ {
+ shader << "half4 " << pixelName << " = inPixel; \n";
+ }
+ else if(lang == GPU_LANGUAGE_GLSL_1_0 || lang == GPU_LANGUAGE_GLSL_1_3)
+ {
+ shader << "vec4 " << pixelName << " = inPixel; \n";
+ }
+ else throw Exception("Unsupported shader language.");
+ }
+
+
+ void WriteShaderFooter(std::ostream & shader,
+ const std::string & pixelName,
+ const GpuShaderDesc & /*shaderDesc*/)
+ {
+ shader << "return " << pixelName << ";\n";
+ shader << "}" << "\n\n";
+ }
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+
+
+ Processor::Impl::Impl():
+ m_metadata(ProcessorMetadata::Create())
+ {
+ }
+
+ Processor::Impl::~Impl()
+ { }
+
+ bool Processor::Impl::isNoOp() const
+ {
+ return IsOpVecNoOp(m_cpuOps);
+ }
+
+ bool Processor::Impl::hasChannelCrosstalk() const
+ {
+ for(OpRcPtrVec::size_type i=0, size = m_cpuOps.size(); i<size; ++i)
+ {
+ if(m_cpuOps[i]->hasChannelCrosstalk()) return true;
+ }
+
+ return false;
+ }
+
+ ConstProcessorMetadataRcPtr Processor::Impl::getMetadata() const
+ {
+ return m_metadata;
+ }
+
+ void Processor::Impl::apply(ImageDesc& img) const
+ {
+ if(m_cpuOps.empty()) return;
+
+ ScanlineHelper scanlineHelper(img);
+ float * rgbaBuffer = 0;
+ long numPixels = 0;
+
+ while(true)
+ {
+ scanlineHelper.prepRGBAScanline(&rgbaBuffer, &numPixels);
+ if(numPixels == 0) break;
+ if(!rgbaBuffer)
+ throw Exception("Cannot apply transform; null image.");
+
+ for(OpRcPtrVec::size_type i=0, size = m_cpuOps.size(); i<size; ++i)
+ {
+ m_cpuOps[i]->apply(rgbaBuffer, numPixels);
+ }
+
+ scanlineHelper.finishRGBAScanline();
+ }
+ }
+
+ void Processor::Impl::applyRGB(float * pixel) const
+ {
+ if(m_cpuOps.empty()) return;
+
+ // We need to allocate a temp array as the pixel must be 4 floats in size
+ // (otherwise, sse loads will potentially fail)
+
+ float rgbaBuffer[4] = { pixel[0], pixel[1], pixel[2], 0.0f };
+
+ for(OpRcPtrVec::size_type i=0, size = m_cpuOps.size(); i<size; ++i)
+ {
+ m_cpuOps[i]->apply(rgbaBuffer, 1);
+ }
+
+ pixel[0] = rgbaBuffer[0];
+ pixel[1] = rgbaBuffer[1];
+ pixel[2] = rgbaBuffer[2];
+ }
+
+ void Processor::Impl::applyRGBA(float * pixel) const
+ {
+ for(OpRcPtrVec::size_type i=0, size = m_cpuOps.size(); i<size; ++i)
+ {
+ m_cpuOps[i]->apply(pixel, 1);
+ }
+ }
+
+ const char * Processor::Impl::getCpuCacheID() const
+ {
+ AutoMutex lock(m_resultsCacheMutex);
+
+ if(!m_cpuCacheID.empty()) return m_cpuCacheID.c_str();
+
+ if(m_cpuOps.empty())
+ {
+ m_cpuCacheID = "<NOOP>";
+ }
+ else
+ {
+ std::ostringstream cacheid;
+ for(OpRcPtrVec::size_type i=0, size = m_cpuOps.size(); i<size; ++i)
+ {
+ cacheid << m_cpuOps[i]->getCacheID() << " ";
+ }
+ std::string fullstr = cacheid.str();
+
+ m_cpuCacheID = CacheIDHash(fullstr.c_str(), (int)fullstr.size());
+ }
+
+ return m_cpuCacheID.c_str();
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+
+
+ const char * Processor::Impl::getGpuShaderText(const GpuShaderDesc & shaderDesc) const
+ {
+ AutoMutex lock(m_resultsCacheMutex);
+
+ if(m_lastShaderDesc != shaderDesc.getCacheID())
+ {
+ m_lastShaderDesc = shaderDesc.getCacheID();
+ m_shader = "";
+ m_shaderCacheID = "";
+ m_lut3D.clear();
+ m_lut3DCacheID = "";
+ }
+
+ if(m_shader.empty())
+ {
+ std::ostringstream shader;
+ calcGpuShaderText(shader, shaderDesc);
+ m_shader = shader.str();
+
+ if(IsDebugLoggingEnabled())
+ {
+ LogDebug("GPU Shader");
+ LogDebug(m_shader);
+ }
+ }
+
+ return m_shader.c_str();
+ }
+
+ const char * Processor::Impl::getGpuShaderTextCacheID(const GpuShaderDesc & shaderDesc) const
+ {
+ AutoMutex lock(m_resultsCacheMutex);
+
+ if(m_lastShaderDesc != shaderDesc.getCacheID())
+ {
+ m_lastShaderDesc = shaderDesc.getCacheID();
+ m_shader = "";
+ m_shaderCacheID = "";
+ m_lut3D.clear();
+ m_lut3DCacheID = "";
+ }
+
+ if(m_shader.empty())
+ {
+ std::ostringstream shader;
+ calcGpuShaderText(shader, shaderDesc);
+ m_shader = shader.str();
+ }
+
+ if(m_shaderCacheID.empty())
+ {
+ m_shaderCacheID = CacheIDHash(m_shader.c_str(), (int)m_shader.size());
+ }
+
+ return m_shaderCacheID.c_str();
+ }
+
+
+ const char * Processor::Impl::getGpuLut3DCacheID(const GpuShaderDesc & shaderDesc) const
+ {
+ AutoMutex lock(m_resultsCacheMutex);
+
+ if(m_lastShaderDesc != shaderDesc.getCacheID())
+ {
+ m_lastShaderDesc = shaderDesc.getCacheID();
+ m_shader = "";
+ m_shaderCacheID = "";
+ m_lut3D.clear();
+ m_lut3DCacheID = "";
+ }
+
+ if(m_lut3DCacheID.empty())
+ {
+ if(m_gpuOpsCpuLatticeProcess.empty())
+ {
+ m_lut3DCacheID = "<NULL>";
+ }
+ else
+ {
+ std::ostringstream cacheid;
+ for(OpRcPtrVec::size_type i=0, size = m_gpuOpsCpuLatticeProcess.size(); i<size; ++i)
+ {
+ cacheid << m_gpuOpsCpuLatticeProcess[i]->getCacheID() << " ";
+ }
+ // Also, add a hash of the shader description
+ cacheid << shaderDesc.getCacheID();
+ std::string fullstr = cacheid.str();
+ m_lut3DCacheID = CacheIDHash(fullstr.c_str(), (int)fullstr.size());
+ }
+ }
+
+ return m_lut3DCacheID.c_str();
+ }
+
+ void Processor::Impl::getGpuLut3D(float* lut3d, const GpuShaderDesc & shaderDesc) const
+ {
+ if(!lut3d) return;
+
+ AutoMutex lock(m_resultsCacheMutex);
+
+ if(m_lastShaderDesc != shaderDesc.getCacheID())
+ {
+ m_lastShaderDesc = shaderDesc.getCacheID();
+ m_shader = "";
+ m_shaderCacheID = "";
+ m_lut3D.clear();
+ m_lut3DCacheID = "";
+ }
+
+ int lut3DEdgeLen = shaderDesc.getLut3DEdgeLen();
+ int lut3DNumPixels = lut3DEdgeLen*lut3DEdgeLen*lut3DEdgeLen;
+
+ // Can we write the entire shader using only shader text?
+ // If so, the lut3D is not needed so clear it.
+ // This is preferable to identity, as it lets people notice if
+ // it's accidentally being used.
+ if(m_gpuOpsCpuLatticeProcess.empty())
+ {
+ memset(lut3d, 0, sizeof(float) * 3 * lut3DNumPixels);
+ return;
+ }
+
+ if(m_lut3D.empty())
+ {
+ // Allocate 3dlut image, RGBA
+ m_lut3D.resize(lut3DNumPixels*4);
+ GenerateIdentityLut3D(&m_lut3D[0], lut3DEdgeLen, 4, LUT3DORDER_FAST_RED);
+
+ // Apply the lattice ops to it
+ for(int i=0; i<(int)m_gpuOpsCpuLatticeProcess.size(); ++i)
+ {
+ m_gpuOpsCpuLatticeProcess[i]->apply(&m_lut3D[0], lut3DNumPixels);
+ }
+
+ // Convert the RGBA image to an RGB image, in place.
+ // Of course, this only works because we're doing it from left to right
+ // so old pixels are read before they're written over
+ // TODO: is this bad for memory access patterns?
+ // see if this is faster with a 2nd temp float array
+
+ for(int i=1; i<lut3DNumPixels; ++i) // skip the 1st pixel, it's ok.
+ {
+ m_lut3D[3*i+0] = m_lut3D[4*i+0];
+ m_lut3D[3*i+1] = m_lut3D[4*i+1];
+ m_lut3D[3*i+2] = m_lut3D[4*i+2];
+ }
+ }
+
+ // Copy to the destination
+ memcpy(lut3d, &m_lut3D[0], sizeof(float) * 3 * lut3DNumPixels);
+ }
+
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+
+ void Processor::Impl::addColorSpaceConversion(const Config & config,
+ const ConstContextRcPtr & context,
+ const ConstColorSpaceRcPtr & srcColorSpace,
+ const ConstColorSpaceRcPtr & dstColorSpace)
+ {
+ BuildColorSpaceOps(m_cpuOps, config, context, srcColorSpace, dstColorSpace);
+ }
+
+
+ void Processor::Impl::addTransform(const Config & config,
+ const ConstContextRcPtr & context,
+ const ConstTransformRcPtr& transform,
+ TransformDirection direction)
+ {
+ BuildOps(m_cpuOps, config, context, transform, direction);
+ }
+
+ void Processor::Impl::finalize()
+ {
+ // Pull out metadata, before the no-ops are removed.
+ for(unsigned int i=0; i<m_cpuOps.size(); ++i)
+ {
+ m_cpuOps[i]->dumpMetadata(m_metadata);
+ }
+
+ // GPU Process setup
+ //
+ // Partition the original, raw opvec into 3 segments for GPU Processing
+ //
+ // Interior index range does not support the gpu shader.
+ // This is used to bound our analytical shader text generation
+ // start index and end index are inclusive.
+
+ PartitionGPUOps(m_gpuOpsHwPreProcess,
+ m_gpuOpsCpuLatticeProcess,
+ m_gpuOpsHwPostProcess,
+ m_cpuOps);
+
+ LogDebug("GPU Ops: Pre-3DLUT");
+ FinalizeOpVec(m_gpuOpsHwPreProcess);
+
+ LogDebug("GPU Ops: 3DLUT");
+ FinalizeOpVec(m_gpuOpsCpuLatticeProcess);
+
+ LogDebug("GPU Ops: Post-3DLUT");
+ FinalizeOpVec(m_gpuOpsHwPostProcess);
+
+ LogDebug("CPU Ops");
+ FinalizeOpVec(m_cpuOps);
+ }
+
+ void Processor::Impl::calcGpuShaderText(std::ostream & shader,
+ const GpuShaderDesc & shaderDesc) const
+ {
+ std::string pixelName = "out_pixel";
+ std::string lut3dName = "lut3d";
+
+ WriteShaderHeader(shader, pixelName, shaderDesc);
+
+
+ for(unsigned int i=0; i<m_gpuOpsHwPreProcess.size(); ++i)
+ {
+ m_gpuOpsHwPreProcess[i]->writeGpuShader(shader, pixelName, shaderDesc);
+ }
+
+ if(!m_gpuOpsCpuLatticeProcess.empty())
+ {
+ // Sample the 3D LUT.
+ int lut3DEdgeLen = shaderDesc.getLut3DEdgeLen();
+ shader << pixelName << ".rgb = ";
+ Write_sampleLut3D_rgb(shader, pixelName,
+ lut3dName, lut3DEdgeLen,
+ shaderDesc.getLanguage());
+ }
+#ifdef __APPLE__
+ else
+ {
+ // Force a no-op sampling of the 3d lut on OSX to work around a segfault.
+ int lut3DEdgeLen = shaderDesc.getLut3DEdgeLen();
+ shader << "// OSX segfault work-around: Force a no-op sampling of the 3d lut.\n";
+ Write_sampleLut3D_rgb(shader, pixelName,
+ lut3dName, lut3DEdgeLen,
+ shaderDesc.getLanguage());
+ }
+#endif // __APPLE__
+ for(unsigned int i=0; i<m_gpuOpsHwPostProcess.size(); ++i)
+ {
+ m_gpuOpsHwPostProcess[i]->writeGpuShader(shader, pixelName, shaderDesc);
+ }
+
+ WriteShaderFooter(shader, pixelName, shaderDesc);
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/Processor.h b/src/core/Processor.h
new file mode 100644
index 0000000..c0bdb51
--- /dev/null
+++ b/src/core/Processor.h
@@ -0,0 +1,132 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_PROCESSOR_H
+#define INCLUDED_OCIO_PROCESSOR_H
+
+#include <sstream>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "Mutex.h"
+#include "Op.h"
+#include "PrivateTypes.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ class Processor::Impl
+ {
+ private:
+ ProcessorMetadataRcPtr m_metadata;
+
+ OpRcPtrVec m_cpuOps;
+
+ // These 3 op vecs represent the 3 stages in our gpu pipe.
+ // 1) preprocess shader text
+ // 2) 3d lut process lookup
+ // 3) postprocess shader text
+
+ OpRcPtrVec m_gpuOpsHwPreProcess;
+ OpRcPtrVec m_gpuOpsCpuLatticeProcess;
+ OpRcPtrVec m_gpuOpsHwPostProcess;
+
+ mutable std::string m_cpuCacheID;
+
+ // Cache the last last queried value,
+ // for the specified shader description
+ mutable std::string m_lastShaderDesc;
+ mutable std::string m_shader;
+ mutable std::string m_shaderCacheID;
+ mutable std::vector<float> m_lut3D;
+ mutable std::string m_lut3DCacheID;
+
+ mutable Mutex m_resultsCacheMutex;
+
+ public:
+ Impl();
+ ~Impl();
+
+ bool isNoOp() const;
+ bool hasChannelCrosstalk() const;
+
+ ConstProcessorMetadataRcPtr getMetadata() const;
+
+ void apply(ImageDesc& img) const;
+
+ void applyRGB(float * pixel) const;
+ void applyRGBA(float * pixel) const;
+ const char * getCpuCacheID() const;
+
+ const char * getGpuShaderText(const GpuShaderDesc & gpuDesc) const;
+ const char * getGpuShaderTextCacheID(const GpuShaderDesc & shaderDesc) const;
+
+ void getGpuLut3D(float* lut3d, const GpuShaderDesc & shaderDesc) const;
+ const char * getGpuLut3DCacheID(const GpuShaderDesc & shaderDesc) const;
+
+ ////////////////////////////////////////////
+ //
+ // Builder functions, Not exposed
+
+ void addColorSpaceConversion(const Config & config,
+ const ConstContextRcPtr & context,
+ const ConstColorSpaceRcPtr & srcColorSpace,
+ const ConstColorSpaceRcPtr & dstColorSpace);
+
+ void addTransform(const Config & config,
+ const ConstContextRcPtr & context,
+ const ConstTransformRcPtr& transform,
+ TransformDirection direction);
+
+ void finalize();
+
+ void calcGpuShaderText(std::ostream & shader,
+ const GpuShaderDesc & shaderDesc) const;
+
+ };
+
+ // TODO: Move these!
+ // TODO: Its not ideal that buildops requires a config to be passed around
+ // but the only alternative is to make build ops a function on it?
+ // and even if it were, what about the build calls it dispatches to...
+
+ // TODO: all of the build op functions shouldnt take a LocalProcessor class
+ // Instead, they should take an abstract interface class that defines
+ // registerOp(OpRcPtr op), annotateColorSpace, finalizeOps, etc.
+ // of which LocalProcessor happens to be one example.
+ // Then the only location in the codebase that knows of LocalProcessor is
+ // in Config.cpp, which creates one.
+
+ void BuildOps(OpRcPtrVec & ops,
+ const Config & config,
+ const ConstTransformRcPtr & transform,
+ TransformDirection dir);
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/SSE.h b/src/core/SSE.h
new file mode 100644
index 0000000..5b825e2
--- /dev/null
+++ b/src/core/SSE.h
@@ -0,0 +1,37 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_SSE_H
+#define INCLUDED_OCIO_SSE_H
+
+#ifdef USE_SSE
+#include <xmmintrin.h>
+#endif
+
+#endif
diff --git a/src/core/ScanlineHelper.cpp b/src/core/ScanlineHelper.cpp
new file mode 100644
index 0000000..b090ae7
--- /dev/null
+++ b/src/core/ScanlineHelper.cpp
@@ -0,0 +1,123 @@
+/*
+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 "ScanlineHelper.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <sstream>
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ const int PIXELS_PER_LINE = 4096;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ ScanlineHelper::ScanlineHelper(ImageDesc& img):
+ m_buffer(0),
+ m_imagePixelIndex(0),
+ m_numPixelsCopied(0),
+ m_yIndex(0),
+ m_inPlaceMode(false)
+ {
+ m_img.init(img);
+
+ if(m_img.isPackedRGBA())
+ {
+ m_inPlaceMode = true;
+ }
+ else
+ {
+ // TODO: Re-use memory from thread-safe memory pool, rather
+ // than doing a new allocation each time.
+
+ m_buffer = (float*)malloc(sizeof(float)*PIXELS_PER_LINE*4);
+ }
+ }
+
+ ScanlineHelper::~ScanlineHelper()
+ {
+ free(m_buffer);
+ }
+
+ // Copy from the src image to our scanline, in our preferred
+ // pixel layout.
+
+ void ScanlineHelper::prepRGBAScanline(float** buffer, long* numPixels)
+ {
+ if(m_inPlaceMode)
+ {
+ // TODO: what if scanline is too short, or too long?
+ if(m_yIndex >= m_img.height)
+ {
+ *numPixels = 0;
+ return;
+ }
+
+ char* rowPtr = reinterpret_cast<char*>(m_img.rData);
+ rowPtr += m_img.yStrideBytes*m_yIndex;
+
+ *buffer = reinterpret_cast<float*>(rowPtr);
+ *numPixels = m_img.width;
+ }
+ else
+ {
+ PackRGBAFromImageDesc(m_img, m_buffer,
+ &m_numPixelsCopied,
+ PIXELS_PER_LINE,
+ m_imagePixelIndex);
+ *buffer = m_buffer;
+ *numPixels = m_numPixelsCopied;
+ }
+ }
+
+ // Write back the result of our work, from the scanline to our
+ // destination image.
+
+ void ScanlineHelper::finishRGBAScanline()
+ {
+ if(m_inPlaceMode)
+ {
+ m_yIndex += 1;
+ }
+ else
+ {
+ UnpackRGBAToImageDesc(m_img,
+ m_buffer,
+ m_numPixelsCopied,
+ m_imagePixelIndex);
+ m_imagePixelIndex += m_numPixelsCopied;
+ }
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/ScanlineHelper.h b/src/core/ScanlineHelper.h
new file mode 100644
index 0000000..016f1d9
--- /dev/null
+++ b/src/core/ScanlineHelper.h
@@ -0,0 +1,78 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_OCIO_SCANLINEHELPER_H
+#define INCLUDED_OCIO_SCANLINEHELPER_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "ImagePacking.h"
+
+OCIO_NAMESPACE_ENTER
+{
+
+ class ScanlineHelper
+ {
+ public:
+
+ ScanlineHelper(ImageDesc& img);
+
+ ~ScanlineHelper();
+
+ // Copy from the src image to our scanline, in our preferred
+ // pixel layout. Return the number of pixels to process;
+
+ void prepRGBAScanline(float** buffer, long* numPixels);
+
+ // Write back the result of our work, from the scanline to our
+ // destination image.
+
+ void finishRGBAScanline();
+
+ private:
+ GenericImageDesc m_img;
+
+ // Copy mode
+ float* m_buffer;
+ long m_imagePixelIndex;
+ int m_numPixelsCopied;
+
+ // In place mode
+ int m_yIndex;
+
+ bool m_inPlaceMode;
+
+ ScanlineHelper(const ScanlineHelper &);
+ ScanlineHelper& operator= (const ScanlineHelper &);
+ };
+
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core/Transform.cpp b/src/core/Transform.cpp
new file mode 100644
index 0000000..2f4bf7f
--- /dev/null
+++ b/src/core/Transform.cpp
@@ -0,0 +1,175 @@
+/*
+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 "FileTransform.h"
+#include "OpBuilders.h"
+#include "Processor.h"
+
+#include <sstream>
+
+OCIO_NAMESPACE_ENTER
+{
+ Transform::~Transform()
+ { }
+
+
+ void BuildOps(OpRcPtrVec & ops,
+ const Config & config,
+ const ConstContextRcPtr & context,
+ const ConstTransformRcPtr & transform,
+ TransformDirection dir)
+ {
+ // A null transform is valid, and corresponds to a no-op.
+ if(!transform)
+ return;
+
+ if(ConstAllocationTransformRcPtr allocationTransform = \
+ DynamicPtrCast<const AllocationTransform>(transform))
+ {
+ BuildAllocationOps(ops, config, *allocationTransform, dir);
+ }
+ else if(ConstCDLTransformRcPtr cdlTransform = \
+ DynamicPtrCast<const CDLTransform>(transform))
+ {
+ BuildCDLOps(ops, config, *cdlTransform, dir);
+ }
+ else if(ConstColorSpaceTransformRcPtr colorSpaceTransform = \
+ DynamicPtrCast<const ColorSpaceTransform>(transform))
+ {
+ BuildColorSpaceOps(ops, config, context, *colorSpaceTransform, dir);
+ }
+ else if(ConstDisplayTransformRcPtr displayTransform = \
+ DynamicPtrCast<const DisplayTransform>(transform))
+ {
+ BuildDisplayOps(ops, config, context, *displayTransform, dir);
+ }
+ else if(ConstExponentTransformRcPtr exponentTransform = \
+ DynamicPtrCast<const ExponentTransform>(transform))
+ {
+ BuildExponentOps(ops, config, *exponentTransform, dir);
+ }
+ else if(ConstFileTransformRcPtr fileTransform = \
+ DynamicPtrCast<const FileTransform>(transform))
+ {
+ BuildFileOps(ops, config, context, *fileTransform, dir);
+ }
+ else if(ConstGroupTransformRcPtr groupTransform = \
+ DynamicPtrCast<const GroupTransform>(transform))
+ {
+ BuildGroupOps(ops, config, context, *groupTransform, dir);
+ }
+ else if(ConstLogTransformRcPtr logTransform = \
+ DynamicPtrCast<const LogTransform>(transform))
+ {
+ BuildLogOps(ops, config, *logTransform, dir);
+ }
+ else if(ConstLookTransformRcPtr lookTransform = \
+ DynamicPtrCast<const LookTransform>(transform))
+ {
+ BuildLookOps(ops, config, context, *lookTransform, dir);
+ }
+ else if(ConstMatrixTransformRcPtr matrixTransform = \
+ DynamicPtrCast<const MatrixTransform>(transform))
+ {
+ BuildMatrixOps(ops, config, *matrixTransform, dir);
+ }
+ else if(ConstTruelightTransformRcPtr truelightTransform = \
+ DynamicPtrCast<const TruelightTransform>(transform))
+ {
+ BuildTruelightOps(ops, config, *truelightTransform, dir);
+ }
+ else
+ {
+ std::ostringstream os;
+ os << "Unknown transform type for Op Creation.";
+ throw Exception(os.str().c_str());
+ }
+ }
+
+ std::ostream& operator<< (std::ostream & os, const Transform & transform)
+ {
+ const Transform* t = &transform;
+
+ if(const AllocationTransform * allocationTransform = \
+ dynamic_cast<const AllocationTransform*>(t))
+ {
+ os << *allocationTransform;
+ }
+ else if(const CDLTransform * cdlTransform = \
+ dynamic_cast<const CDLTransform*>(t))
+ {
+ os << *cdlTransform;
+ }
+ else if(const ColorSpaceTransform * colorSpaceTransform = \
+ dynamic_cast<const ColorSpaceTransform*>(t))
+ {
+ os << *colorSpaceTransform;
+ }
+ else if(const DisplayTransform * displayTransform = \
+ dynamic_cast<const DisplayTransform*>(t))
+ {
+ os << *displayTransform;
+ }
+ else if(const ExponentTransform * exponentTransform = \
+ dynamic_cast<const ExponentTransform*>(t))
+ {
+ os << *exponentTransform;
+ }
+ else if(const FileTransform * fileTransform = \
+ dynamic_cast<const FileTransform*>(t))
+ {
+ os << *fileTransform;
+ }
+ else if(const GroupTransform * groupTransform = \
+ dynamic_cast<const GroupTransform*>(t))
+ {
+ os << *groupTransform;
+ }
+ else if(const MatrixTransform * matrixTransform = \
+ dynamic_cast<const MatrixTransform*>(t))
+ {
+ os << *matrixTransform;
+ }
+ else if(const TruelightTransform * truelightTransform = \
+ dynamic_cast<const TruelightTransform*>(t))
+ {
+ os << *truelightTransform;
+ }
+ else
+ {
+ std::ostringstream error;
+ os << "Unknown transform type for serialization.";
+ throw Exception(error.str().c_str());
+ }
+
+ return os;
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/TruelightOp.cpp b/src/core/TruelightOp.cpp
new file mode 100644
index 0000000..50f3915
--- /dev/null
+++ b/src/core/TruelightOp.cpp
@@ -0,0 +1,395 @@
+/*
+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 <iostream>
+
+#ifdef OCIO_TRUELIGHT_SUPPORT
+#include <truelight.h>
+#else
+#define TL_INPUT_LOG 0
+#define TL_INPUT_LIN 1
+#define TL_INPUT_VID 2
+#endif // OCIO_TRUELIGHT_SUPPORT
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "TruelightOp.h"
+#include "pystring/pystring.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ class TruelightOp : public Op
+ {
+ public:
+ TruelightOp(const char * configroot,
+ const char * profile,
+ const char * camera,
+ const char * inputdisplay,
+ const char * recorder,
+ const char * print,
+ const char * lamp,
+ const char * outputcamera,
+ const char * display,
+ const char * cubeinput,
+ TransformDirection direction);
+ virtual ~TruelightOp();
+
+ virtual OpRcPtr clone() const;
+
+ virtual std::string getInfo() const;
+ virtual std::string getCacheID() const;
+
+ virtual bool isNoOp() const;
+ virtual bool isSameType(const OpRcPtr & op) const;
+ virtual bool isInverse(const OpRcPtr & op) const;
+ virtual bool hasChannelCrosstalk() const;
+
+ virtual void finalize();
+ virtual void apply(float* rgbaBuffer, long numPixels) const;
+
+ virtual bool supportsGpuShader() const;
+ virtual void writeGpuShader(std::ostream & shader,
+ const std::string & pixelName,
+ const GpuShaderDesc & shaderDesc) const;
+
+ private:
+ TransformDirection m_direction;
+ void *m_truelight;
+ std::string m_configroot;
+ std::string m_profile;
+ std::string m_camera;
+ std::string m_inputdisplay;
+ std::string m_recorder;
+ std::string m_print;
+ std::string m_lamp;
+ std::string m_outputcamera;
+ std::string m_display;
+ int m_cubeinput;
+ std::string m_cacheID;
+ };
+
+ TruelightOp::TruelightOp(const char * configroot,
+ const char * profile,
+ const char * camera,
+ const char * inputdisplay,
+ const char * recorder,
+ const char * print,
+ const char * lamp,
+ const char * outputcamera,
+ const char * display,
+ const char * cubeinput,
+ TransformDirection direction):
+ Op(),
+ m_direction(direction),
+ m_configroot(configroot),
+ m_profile(profile),
+ m_camera(camera),
+ m_inputdisplay(inputdisplay),
+ m_recorder(recorder),
+ m_print(print),
+ m_lamp(lamp),
+ m_outputcamera(outputcamera),
+ m_display(display)
+ {
+
+ if(m_direction == TRANSFORM_DIR_UNKNOWN)
+ {
+ throw Exception("Cannot apply TruelightOp op, unspecified transform direction.");
+ }
+
+ std::string _tmp = pystring::lower(cubeinput);
+ if(_tmp == "log") m_cubeinput = TL_INPUT_LOG;
+ else if(_tmp == "linear") m_cubeinput = TL_INPUT_LIN;
+ else if(_tmp == "video") m_cubeinput = TL_INPUT_VID;
+ else
+ {
+ std::ostringstream err;
+ err << "we don't support cubeinput of type " << cubeinput;
+ err << " try log, linear or video.";
+ throw Exception(err.str().c_str());
+ }
+
+#ifdef OCIO_TRUELIGHT_SUPPORT
+
+ if((TruelightBegin("")) == 0)
+ {
+ std::ostringstream err;
+ err << "Error: " << TruelightGetErrorString();
+ throw Exception(err.str().c_str());
+ }
+
+ m_truelight = TruelightCreateInstance();
+ if(!m_truelight)
+ {
+ std::ostringstream err;
+ err << "Error: '" << TruelightGetErrorString();
+ throw Exception(err.str().c_str());
+ }
+
+ // floating point
+ TruelightInstanceSetMax(m_truelight, 1);
+
+ // where too look for the profiles, prints etc
+ TruelightSetRoot(m_configroot.c_str());
+
+ // invert the transform depending on direction
+ if(m_direction == TRANSFORM_DIR_FORWARD)
+ {
+ TruelightInstanceSetInvertFlag(m_truelight, 0);
+ }
+ else if(m_direction == TRANSFORM_DIR_INVERSE)
+ {
+ TruelightInstanceSetInvertFlag(m_truelight, 1);
+ }
+
+#endif // OCIO_TRUELIGHT_SUPPORT
+
+ }
+
+ OpRcPtr TruelightOp::clone() const
+ {
+ std::string _cubeinput = "unknown";
+ if(m_cubeinput == TL_INPUT_LOG) _cubeinput = "log";
+ else if(m_cubeinput == TL_INPUT_LIN) _cubeinput = "linear";
+ else if(m_cubeinput == TL_INPUT_VID) _cubeinput = "video";
+ OpRcPtr op = OpRcPtr(new TruelightOp(m_configroot.c_str(),
+ m_profile.c_str(),
+ m_camera.c_str(),
+ m_inputdisplay.c_str(),
+ m_recorder.c_str(),
+ m_print.c_str(),
+ m_lamp.c_str(),
+ m_outputcamera.c_str(),
+ m_display.c_str(),
+ _cubeinput.c_str(),
+ m_direction));
+ return op;
+ }
+
+ TruelightOp::~TruelightOp()
+ {
+#ifdef OCIO_TRUELIGHT_SUPPORT
+ if(m_truelight) TruelightDestroyInstance(m_truelight);
+#endif // OCIO_TRUELIGHT_SUPPORT
+ }
+
+ std::string TruelightOp::getInfo() const
+ {
+ return "<TruelightOp>";
+ }
+
+ std::string TruelightOp::getCacheID() const
+ {
+ return m_cacheID;
+ }
+
+ bool TruelightOp::isNoOp() const
+ {
+ return false;
+ }
+ bool TruelightOp::isSameType(const OpRcPtr & /*op*/) const
+ {
+ // TODO: TruelightOp::isSameType
+ return false;
+ }
+
+ bool TruelightOp::isInverse(const OpRcPtr & /*op*/) const
+ {
+ // TODO: TruelightOp::isInverse
+ return false;
+ }
+
+ bool TruelightOp::hasChannelCrosstalk() const
+ {
+ return true;
+ }
+
+ void TruelightOp::finalize()
+ {
+#ifndef OCIO_TRUELIGHT_SUPPORT
+ std::ostringstream err;
+ err << "OCIO has been built without Truelight support";
+ throw Exception(err.str().c_str());
+#else
+ if(m_profile != "")
+ {
+ if(TruelightInstanceSetProfile(m_truelight, m_profile.c_str()) == 0)
+ {
+ std::ostringstream err;
+ err << "Error: " << TruelightGetErrorString();
+ throw Exception(err.str().c_str());
+ }
+ }
+
+ if(m_camera != "")
+ {
+ if(TruelightInstanceSetCamera(m_truelight, m_camera.c_str()) == 0)
+ {
+ std::ostringstream err;
+ err << "Error: " << TruelightGetErrorString();
+ throw Exception(err.str().c_str());
+ }
+ }
+
+ if(m_inputdisplay != "")
+ {
+ if(TruelightInstanceSetInputDisplay(m_truelight, m_inputdisplay.c_str()) == 0)
+ {
+ std::ostringstream err;
+ err << "Error: " << TruelightGetErrorString();
+ throw Exception(err.str().c_str());
+ }
+ }
+
+ if(m_recorder != "")
+ {
+ if(TruelightInstanceSetRecorder(m_truelight, m_recorder.c_str()) == 0)
+ {
+ std::ostringstream err;
+ err << "Error: " << TruelightGetErrorString();
+ throw Exception(err.str().c_str());
+ }
+ }
+
+ if(m_print != "")
+ {
+ if(TruelightInstanceSetPrint(m_truelight, m_print.c_str()) == 0)
+ {
+ std::ostringstream err;
+ err << "Error: " << TruelightGetErrorString();
+ throw Exception(err.str().c_str());
+ }
+ }
+
+ if(m_lamp != "")
+ {
+ if(TruelightInstanceSetLamp(m_truelight, m_lamp.c_str()) == 0)
+ {
+ std::ostringstream err;
+ err << "Error: " << TruelightGetErrorString();
+ throw Exception(err.str().c_str());
+ }
+ }
+
+ if(m_outputcamera != "")
+ {
+ if(TruelightInstanceSetOutputCamera(m_truelight, m_outputcamera.c_str()) == 0)
+ {
+ std::ostringstream err;
+ err << "Error: " << TruelightGetErrorString();
+ throw Exception(err.str().c_str());
+ }
+ }
+
+ if(m_display != "")
+ {
+ if(TruelightInstanceSetDisplay(m_truelight, m_display.c_str()) == 0)
+ {
+ std::ostringstream err;
+ err << "Error: " << TruelightGetErrorString();
+ throw Exception(err.str().c_str());
+ }
+ }
+
+ if(TruelightInstanceSetCubeInput(m_truelight, m_cubeinput) == 0)
+ {
+ std::ostringstream err;
+ err << "Error: " << TruelightGetErrorString();
+ throw Exception(err.str().c_str());
+ }
+
+ if(TruelightInstanceSetUp(m_truelight) == 0)
+ {
+ std::ostringstream err;
+ err << "Error: " << TruelightGetErrorString();
+ throw Exception(err.str().c_str());
+ }
+#endif // OCIO_TRUELIGHT_SUPPORT
+
+ // build cache id
+ std::ostringstream cacheIDStream;
+ cacheIDStream << "<TruelightOp ";
+ cacheIDStream << m_profile << " ";
+ cacheIDStream << m_camera << " ";
+ cacheIDStream << m_inputdisplay << " ";
+ cacheIDStream << m_recorder << " ";
+ cacheIDStream << m_print << " ";
+ cacheIDStream << m_lamp << " ";
+ cacheIDStream << m_outputcamera << " ";
+ cacheIDStream << m_display << " ";
+ cacheIDStream << m_cubeinput << " ";
+ cacheIDStream << TransformDirectionToString(m_direction) << " ";
+ cacheIDStream << ">";
+ m_cacheID = cacheIDStream.str();
+ }
+
+ void TruelightOp::apply(float* rgbaBuffer, long numPixels) const
+ {
+ for(long pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex)
+ {
+#ifdef OCIO_TRUELIGHT_SUPPORT
+ TruelightInstanceTransformF(m_truelight, rgbaBuffer);
+#endif // OCIO_TRUELIGHT_SUPPORT
+ rgbaBuffer += 4; // skip alpha
+ }
+ }
+
+ bool TruelightOp::supportsGpuShader() const
+ {
+ return false;
+ }
+
+ void TruelightOp::writeGpuShader(std::ostream & /*shader*/,
+ const std::string & /*pixelName*/,
+ const GpuShaderDesc & /*shaderDesc*/) const
+ {
+ throw Exception("TruelightOp does not define an gpu shader.");
+ }
+
+ } // anonymous namespace
+
+ void CreateTruelightOps(OpRcPtrVec & ops,
+ const TruelightTransform & data,
+ TransformDirection direction)
+ {
+ ops.push_back(OpRcPtr(new TruelightOp(data.getConfigRoot(),
+ data.getProfile(),
+ data.getCamera(),
+ data.getInputDisplay(),
+ data.getRecorder(),
+ data.getPrint(),
+ data.getLamp(),
+ data.getOutputCamera(),
+ data.getDisplay(),
+ data.getCubeInput(),
+ direction)));
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/TruelightOp.h b/src/core/TruelightOp.h
new file mode 100644
index 0000000..fe78b6a
--- /dev/null
+++ b/src/core/TruelightOp.h
@@ -0,0 +1,44 @@
+/*
+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.
+*/
+
+#ifndef INCLUDED_OCIO_TRUELIGHTOP_H
+#define INCLUDED_OCIO_TRUELIGHTOP_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "Op.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ void CreateTruelightOps(OpRcPtrVec & ops,
+ const TruelightTransform & data,
+ TransformDirection dir);
+}
+OCIO_NAMESPACE_EXIT
+
+#endif // INCLUDED_OCIO_TRUELIGHTOP_H
diff --git a/src/core/TruelightTransform.cpp b/src/core/TruelightTransform.cpp
new file mode 100644
index 0000000..7e95875
--- /dev/null
+++ b/src/core/TruelightTransform.cpp
@@ -0,0 +1,365 @@
+/*
+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 <iostream>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "OpBuilders.h"
+#include "TruelightOp.h"
+#include "pystring/pystring.h"
+
+OCIO_NAMESPACE_ENTER
+{
+
+ TruelightTransformRcPtr TruelightTransform::Create()
+ {
+ return TruelightTransformRcPtr(new TruelightTransform(), &deleter);
+ }
+
+ void TruelightTransform::deleter(TruelightTransform* t)
+ {
+ delete t;
+ }
+
+ class TruelightTransform::Impl
+ {
+ public:
+ TransformDirection dir_;
+ std::string configroot_;
+ std::string profile_;
+ std::string camera_;
+ std::string inputdisplay_;
+ std::string recorder_;
+ std::string print_;
+ std::string lamp_;
+ std::string outputcamera_;
+ std::string display_;
+ std::string cubeinput_;
+
+ Impl() : dir_(TRANSFORM_DIR_FORWARD)
+ { }
+
+ ~Impl()
+ { }
+
+ Impl& operator= (const Impl & rhs)
+ {
+ dir_ = rhs.dir_;
+ configroot_ = rhs.configroot_;
+ profile_ = rhs.profile_;
+ camera_ = rhs.camera_;
+ inputdisplay_ = rhs.inputdisplay_;
+ recorder_ = rhs.recorder_;
+ print_ = rhs.print_;
+ lamp_ = rhs.lamp_;
+ outputcamera_ = rhs.outputcamera_;
+ display_ = rhs.display_;
+ cubeinput_ = rhs.cubeinput_;
+ return *this;
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ TruelightTransform::TruelightTransform()
+ : m_impl(new TruelightTransform::Impl)
+ {
+ getImpl()->configroot_ = "/usr/fl/truelight";
+ getImpl()->profile_ = "";
+ getImpl()->camera_ = "";
+ getImpl()->inputdisplay_ = "";
+ getImpl()->recorder_ = "";
+ getImpl()->print_ = "";
+ getImpl()->lamp_ = "";
+ getImpl()->outputcamera_ = "";
+ getImpl()->display_ = "";
+ getImpl()->cubeinput_ = "log";
+ }
+
+ TransformRcPtr TruelightTransform::createEditableCopy() const
+ {
+ TruelightTransformRcPtr transform = TruelightTransform::Create();
+ *(transform->m_impl) = *m_impl;
+ return transform;
+ }
+
+ TruelightTransform::~TruelightTransform()
+ {
+ delete m_impl;
+ m_impl = NULL;
+ }
+
+ TruelightTransform& TruelightTransform::operator= (const TruelightTransform & rhs)
+ {
+ *m_impl = *rhs.m_impl;
+ return *this;
+ }
+
+ TransformDirection TruelightTransform::getDirection() const
+ {
+ return getImpl()->dir_;
+ }
+
+ void TruelightTransform::setDirection(TransformDirection dir)
+ {
+ getImpl()->dir_ = dir;
+ }
+
+ void TruelightTransform::setConfigRoot(const char * configroot)
+ {
+ getImpl()->configroot_ = configroot;
+ }
+
+ const char * TruelightTransform::getConfigRoot() const
+ {
+ return getImpl()->configroot_.c_str();
+ }
+
+ void TruelightTransform::setProfile(const char * profile)
+ {
+ getImpl()->profile_ = profile;
+ }
+
+ const char * TruelightTransform::getProfile() const
+ {
+ return getImpl()->profile_.c_str();
+ }
+
+ void TruelightTransform::setCamera(const char * camera)
+ {
+ getImpl()->camera_ = camera;
+ }
+
+ const char * TruelightTransform::getCamera() const
+ {
+ return getImpl()->camera_.c_str();
+ }
+
+ void TruelightTransform::setInputDisplay(const char * display)
+ {
+ getImpl()->inputdisplay_ = display;
+ }
+
+ const char * TruelightTransform::getInputDisplay() const
+ {
+ return getImpl()->inputdisplay_.c_str();
+ }
+
+ void TruelightTransform::setRecorder(const char * recorder)
+ {
+ getImpl()->recorder_ = recorder;
+ }
+
+ const char * TruelightTransform::getRecorder() const
+ {
+ return getImpl()->recorder_.c_str();
+ }
+
+ void TruelightTransform::setPrint(const char * print)
+ {
+ getImpl()->print_ = print;
+ }
+
+ const char * TruelightTransform::getPrint() const
+ {
+ return getImpl()->print_.c_str();
+ }
+
+ void TruelightTransform::setLamp(const char * lamp)
+ {
+ getImpl()->lamp_ = lamp;
+ }
+
+ const char * TruelightTransform::getLamp() const
+ {
+ return getImpl()->lamp_.c_str();
+ }
+
+ void TruelightTransform::setOutputCamera(const char * camera)
+ {
+ getImpl()->outputcamera_ = camera;
+ }
+
+ const char * TruelightTransform::getOutputCamera() const
+ {
+ return getImpl()->outputcamera_.c_str();
+ }
+
+ void TruelightTransform::setDisplay(const char * display)
+ {
+ getImpl()->display_ = display;
+ }
+
+ const char * TruelightTransform::getDisplay() const
+ {
+ return getImpl()->display_.c_str();
+ }
+
+ void TruelightTransform::setCubeInput(const char * cubeinput)
+ {
+ getImpl()->cubeinput_ = pystring::lower(cubeinput);
+ }
+
+ const char * TruelightTransform::getCubeInput() const
+ {
+ return getImpl()->cubeinput_.c_str();
+ }
+
+ std::ostream& operator<< (std::ostream& os, const TruelightTransform& t)
+ {
+ os << "<TruelightTransform ";
+ os << "direction=" << TransformDirectionToString(t.getDirection()) << ", ";
+ os << ">\n";
+ return os;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ void BuildTruelightOps(OpRcPtrVec & ops,
+ const Config& /*config*/,
+ const TruelightTransform & transform,
+ TransformDirection dir)
+ {
+ TransformDirection combinedDir = CombineTransformDirections(dir,
+ transform.getDirection());
+ CreateTruelightOps(ops, transform, combinedDir);
+ }
+
+}
+OCIO_NAMESPACE_EXIT
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef OCIO_UNIT_TEST
+
+namespace OCIO = OCIO_NAMESPACE;
+#include "UnitTest.h"
+
+OIIO_ADD_TEST(TruelightTransform, simpletest)
+{
+
+ OCIO::ConfigRcPtr config = OCIO::Config::Create();
+ {
+ OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create();
+ cs->setName("log");
+ cs->setFamily("log");
+ config->addColorSpace(cs);
+ config->setRole(OCIO::ROLE_COMPOSITING_LOG, cs->getName());
+ }
+ {
+ OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create();
+ cs->setName("sRGB");
+ cs->setFamily("srgb");
+ OCIO::TruelightTransformRcPtr transform1 = OCIO::TruelightTransform::Create();
+ transform1->setConfigRoot("/usr/fl/truelight");
+ transform1->setPrint("internal-LowContrast");
+ //transform1->setInputDisplay("DCIrgb");
+ transform1->setDisplay("sRGB");
+ transform1->setCubeInput("log");
+ cs->setTransform(transform1, OCIO::COLORSPACE_DIR_FROM_REFERENCE);
+ config->addColorSpace(cs);
+ }
+
+ // check the transform round trip
+ OCIO::ConstProcessorRcPtr tosrgb;
+ OCIO::ConstProcessorRcPtr tolog;
+
+#ifdef OCIO_TRUELIGHT_SUPPORT
+ OIIO_CHECK_NO_THOW(tosrgb = config->getProcessor("log", "sRGB"));
+ OIIO_CHECK_NO_THOW(tolog = config->getProcessor("sRGB", "log"));
+#else
+ OIIO_CHECK_THOW(tosrgb = config->getProcessor("log", "sRGB"), OCIO::Exception);
+ OIIO_CHECK_THOW(tolog = config->getProcessor("sRGB", "log"), OCIO::Exception);
+#endif
+
+#ifdef OCIO_TRUELIGHT_SUPPORT
+ float input[3] = {0.5f, 0.5f, 0.5f};
+ float output[3] = {0.500098f, 0.500317f, 0.501134f};
+ OIIO_CHECK_NO_THOW(tosrgb->applyRGB(input));
+ OIIO_CHECK_NO_THOW(tolog->applyRGB(input));
+ OIIO_CHECK_CLOSE(input[0], output[0], 1e-4);
+ OIIO_CHECK_CLOSE(input[1], output[1], 1e-4);
+ OIIO_CHECK_CLOSE(input[2], output[2], 1e-4);
+#endif
+
+ std::ostringstream os;
+ OIIO_CHECK_NO_THOW(config->serialize(os));
+
+ std::string referenceconfig =
+ "ocio_profile_version: 1\n"
+ "\n"
+ "search_path: \"\"\n"
+ "strictparsing: true\n"
+ "luma: [0.2126, 0.7152, 0.0722]\n"
+ "\n"
+ "roles:\n"
+ " compositing_log: log\n"
+ "\n"
+ "displays:\n"
+ " {}\n"
+ "\n"
+ "active_displays: []\n"
+ "active_views: []\n"
+ "\n"
+ "colorspaces:\n"
+ " - !<ColorSpace>\n"
+ " name: log\n"
+ " family: log\n"
+ " equalitygroup: \"\"\n"
+ " bitdepth: unknown\n"
+ " isdata: false\n"
+ " allocation: uniform\n"
+ "\n"
+ " - !<ColorSpace>\n"
+ " name: sRGB\n"
+ " family: srgb\n"
+ " equalitygroup: \"\"\n"
+ " bitdepth: unknown\n"
+ " isdata: false\n"
+ " allocation: uniform\n"
+ " from_reference: !<TruelightTransform> {config_root: /usr/fl/truelight, print: internal-LowContrast, display: sRGB, cube_input: log}\n";
+
+
+ std::vector<std::string> osvec;
+ OCIO::pystring::splitlines(os.str(), osvec);
+ std::vector<std::string> referenceconfigvec;
+ OCIO::pystring::splitlines(referenceconfig, referenceconfigvec);
+
+ OIIO_CHECK_EQUAL(osvec.size(), referenceconfigvec.size());
+ for(unsigned int i = 0; i < referenceconfigvec.size(); ++i)
+ OIIO_CHECK_EQUAL(osvec[i], referenceconfigvec[i]);
+
+ std::istringstream is;
+ is.str(referenceconfig);
+ OCIO::ConstConfigRcPtr rtconfig;
+ OIIO_CHECK_NO_THOW(rtconfig = OCIO::Config::CreateFromStream(is));
+
+}
+
+#endif // OCIO_BUILD_TESTS
diff --git a/src/core/UnitTest.cpp b/src/core/UnitTest.cpp
new file mode 100644
index 0000000..8b1270d
--- /dev/null
+++ b/src/core/UnitTest.cpp
@@ -0,0 +1,39 @@
+/*
+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.
+*/
+
+#ifndef INCLUDED_OCIO_UNITTEST_H
+#define INCLUDED_OCIO_UNITTEST_H
+
+#ifdef OCIO_UNIT_TEST
+#pragma GCC visibility push(default)
+#include <unittest.h> // OIIO unit tests header
+OIIO_TEST_APP(OpenColorIO_Core_Unit_Tests)
+#pragma GCC visibility pop
+#endif // OCIO_UNIT_TEST
+
+#endif // INCLUDED_OCIO_UNITTEST_H
diff --git a/src/core/UnitTest.h b/src/core/UnitTest.h
new file mode 100644
index 0000000..33625c5
--- /dev/null
+++ b/src/core/UnitTest.h
@@ -0,0 +1,38 @@
+/*
+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.
+*/
+
+#ifndef INCLUDED_OCIO_UNITTEST_H
+#define INCLUDED_OCIO_UNITTEST_H
+
+#ifdef OCIO_UNIT_TEST
+#pragma GCC visibility push(default)
+#include <unittest.h> // OIIO unit tests header
+#pragma GCC visibility pop
+#endif // OCIO_UNIT_TEST
+
+#endif // INCLUDED_OCIO_UNITTEST_H
diff --git a/src/core/md5/md5.cpp b/src/core/md5/md5.cpp
new file mode 100644
index 0000000..3eb5673
--- /dev/null
+++ b/src/core/md5/md5.cpp
@@ -0,0 +1,391 @@
+/*
+ Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost@aladdin.com
+
+ */
+/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.c is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+ either statically or dynamically; added missing #include <string.h>
+ in library.
+ 2002-03-11 lpd Corrected argument list for main(), and added int return
+ type, in test program and T value program.
+ 2002-02-21 lpd Added missing #include <stdio.h> in test program.
+ 2000-07-03 lpd Patched to eliminate warnings about "constant is
+ unsigned in ANSI C, signed in traditional"; made test program
+ self-checking.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+ 1999-05-03 lpd Original version.
+ */
+
+// This file was altered for OCIO compilation purposes
+
+#include "md5.h"
+#include <cstring>
+
+
+OCIO_NAMESPACE_ENTER
+{
+
+
+#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#ifdef ARCH_IS_BIG_ENDIAN
+# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#else
+# define BYTE_ORDER 0
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3 0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6 0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9 0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13 0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16 0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19 0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22 0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25 0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28 0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31 0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35 0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38 0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41 0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44 0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47 0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50 0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53 0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57 0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60 0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63 0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+
+static void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+ md5_word_t
+ a = pms->abcd[0], b = pms->abcd[1],
+ c = pms->abcd[2], d = pms->abcd[3];
+ md5_word_t t;
+#if BYTE_ORDER > 0
+ /* Define storage only for big-endian CPUs. */
+ md5_word_t X[16];
+#else
+ /* Define storage for little-endian or both types of CPUs. */
+ md5_word_t xbuf[16];
+ const md5_word_t *X;
+#endif
+
+ {
+#if BYTE_ORDER == 0
+ /*
+ * Determine dynamically whether this is a big-endian or
+ * little-endian machine, since we can use a more efficient
+ * algorithm on the latter.
+ */
+ static const int w = 1;
+
+ if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0 /* little-endian */
+ {
+ /*
+ * On little-endian machines, we can process properly aligned
+ * data without copying it.
+ */
+ if (!((data - (const md5_byte_t *)0) & 3)) {
+ /* data are properly aligned */
+ X = (const md5_word_t *)data;
+ } else {
+ /* not aligned */
+ memcpy(xbuf, data, 64);
+ X = xbuf;
+ }
+ }
+#endif
+#if BYTE_ORDER == 0
+ else /* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0 /* big-endian */
+ {
+ /*
+ * On big-endian machines, we must arrange the bytes in the
+ * right order.
+ */
+ const md5_byte_t *xp = data;
+ int i;
+
+# if BYTE_ORDER == 0
+ X = xbuf; /* (dynamic only) */
+# else
+# define xbuf X /* (static only) */
+# endif
+ for (i = 0; i < 16; ++i, xp += 4)
+ xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+ }
+#endif
+ }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + F(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 7, T1);
+ SET(d, a, b, c, 1, 12, T2);
+ SET(c, d, a, b, 2, 17, T3);
+ SET(b, c, d, a, 3, 22, T4);
+ SET(a, b, c, d, 4, 7, T5);
+ SET(d, a, b, c, 5, 12, T6);
+ SET(c, d, a, b, 6, 17, T7);
+ SET(b, c, d, a, 7, 22, T8);
+ SET(a, b, c, d, 8, 7, T9);
+ SET(d, a, b, c, 9, 12, T10);
+ SET(c, d, a, b, 10, 17, T11);
+ SET(b, c, d, a, 11, 22, T12);
+ SET(a, b, c, d, 12, 7, T13);
+ SET(d, a, b, c, 13, 12, T14);
+ SET(c, d, a, b, 14, 17, T15);
+ SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + G(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 1, 5, T17);
+ SET(d, a, b, c, 6, 9, T18);
+ SET(c, d, a, b, 11, 14, T19);
+ SET(b, c, d, a, 0, 20, T20);
+ SET(a, b, c, d, 5, 5, T21);
+ SET(d, a, b, c, 10, 9, T22);
+ SET(c, d, a, b, 15, 14, T23);
+ SET(b, c, d, a, 4, 20, T24);
+ SET(a, b, c, d, 9, 5, T25);
+ SET(d, a, b, c, 14, 9, T26);
+ SET(c, d, a, b, 3, 14, T27);
+ SET(b, c, d, a, 8, 20, T28);
+ SET(a, b, c, d, 13, 5, T29);
+ SET(d, a, b, c, 2, 9, T30);
+ SET(c, d, a, b, 7, 14, T31);
+ SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + H(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 5, 4, T33);
+ SET(d, a, b, c, 8, 11, T34);
+ SET(c, d, a, b, 11, 16, T35);
+ SET(b, c, d, a, 14, 23, T36);
+ SET(a, b, c, d, 1, 4, T37);
+ SET(d, a, b, c, 4, 11, T38);
+ SET(c, d, a, b, 7, 16, T39);
+ SET(b, c, d, a, 10, 23, T40);
+ SET(a, b, c, d, 13, 4, T41);
+ SET(d, a, b, c, 0, 11, T42);
+ SET(c, d, a, b, 3, 16, T43);
+ SET(b, c, d, a, 6, 23, T44);
+ SET(a, b, c, d, 9, 4, T45);
+ SET(d, a, b, c, 12, 11, T46);
+ SET(c, d, a, b, 15, 16, T47);
+ SET(b, c, d, a, 2, 23, T48);
+#undef SET
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + I(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 6, T49);
+ SET(d, a, b, c, 7, 10, T50);
+ SET(c, d, a, b, 14, 15, T51);
+ SET(b, c, d, a, 5, 21, T52);
+ SET(a, b, c, d, 12, 6, T53);
+ SET(d, a, b, c, 3, 10, T54);
+ SET(c, d, a, b, 10, 15, T55);
+ SET(b, c, d, a, 1, 21, T56);
+ SET(a, b, c, d, 8, 6, T57);
+ SET(d, a, b, c, 15, 10, T58);
+ SET(c, d, a, b, 6, 15, T59);
+ SET(b, c, d, a, 13, 21, T60);
+ SET(a, b, c, d, 4, 6, T61);
+ SET(d, a, b, c, 11, 10, T62);
+ SET(c, d, a, b, 2, 15, T63);
+ SET(b, c, d, a, 9, 21, T64);
+#undef SET
+
+ /* Then perform the following additions. (That is increment each
+ of the four registers by the value it had before this block
+ was started.) */
+ pms->abcd[0] += a;
+ pms->abcd[1] += b;
+ pms->abcd[2] += c;
+ pms->abcd[3] += d;
+}
+
+void
+md5_init(md5_state_t *pms)
+{
+ pms->count[0] = pms->count[1] = 0;
+ pms->abcd[0] = 0x67452301;
+ pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+ pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+ pms->abcd[3] = 0x10325476;
+}
+
+void
+md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
+{
+ const md5_byte_t *p = data;
+ int left = nbytes;
+ int offset = (pms->count[0] >> 3) & 63;
+ md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+ if (nbytes <= 0)
+ return;
+
+ /* Update the message length. */
+ pms->count[1] += nbytes >> 29;
+ pms->count[0] += nbits;
+ if (pms->count[0] < nbits)
+ pms->count[1]++;
+
+ /* Process an initial partial block. */
+ if (offset) {
+ int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcpy(pms->buf + offset, p, copy);
+ if (offset + copy < 64)
+ return;
+ p += copy;
+ left -= copy;
+ md5_process(pms, pms->buf);
+ }
+
+ /* Process full blocks. */
+ for (; left >= 64; p += 64, left -= 64)
+ md5_process(pms, p);
+
+ /* Process a final partial block. */
+ if (left)
+ memcpy(pms->buf, p, left);
+}
+
+void
+md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+ static const md5_byte_t pad[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ md5_byte_t data[8];
+ int i;
+
+ /* Save the length before padding. */
+ for (i = 0; i < 8; ++i)
+ data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+ /* Pad to 56 bytes mod 64. */
+ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+ /* Append the length. */
+ md5_append(pms, data, 8);
+ for (i = 0; i < 16; ++i)
+ digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/md5/md5.h b/src/core/md5/md5.h
new file mode 100644
index 0000000..cb36edb
--- /dev/null
+++ b/src/core/md5/md5.h
@@ -0,0 +1,97 @@
+/*
+ Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost@aladdin.com
+
+ */
+/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.h is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Removed support for non-ANSI compilers; removed
+ references to Ghostscript; clarified derivation from RFC 1321;
+ now handles byte order either statically or dynamically.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+ added conditionalization for C++ compilation from Martin
+ Purschke <purschke@bnl.gov>.
+ 1999-05-03 lpd Original version.
+ */
+
+// This file was altered for OCIO compilation purposes
+
+#ifndef INCLUDED_OCIO_md5_INCLUDED
+#define INCLUDED_OCIO_md5_INCLUDED
+
+
+#include <OpenColorIO/OpenColorIO.h>
+
+OCIO_NAMESPACE_ENTER
+{
+
+// Note: the md5 functions should not be wrapped in extern "C', otherwise
+// the symbols will not be appropriately wrapped in the OCIO namespace
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+ md5_word_t count[2]; /* message length in bits, lsw first */
+ md5_word_t abcd[4]; /* digest buffer */
+ md5_byte_t buf[64]; /* accumulate block */
+} md5_state_t;
+
+/* Initialize the algorithm. */
+void md5_init(md5_state_t *pms);
+
+/* Append a string to the message. */
+void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
+
+/* Finish the message and return the digest. */
+void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+
+
+}
+OCIO_NAMESPACE_EXIT
+
+#endif /* md5_INCLUDED */
diff --git a/src/core/pystring/pystring.cpp b/src/core/pystring/pystring.cpp
new file mode 100644
index 0000000..7805162
--- /dev/null
+++ b/src/core/pystring/pystring.cpp
@@ -0,0 +1,1658 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2008-2010, Sony Pictures Imageworks Inc
+// 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 the organization 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 "pystring.h"
+
+#include <algorithm>
+#include <cctype>
+#include <cstring>
+#include <iostream>
+#include <sstream>
+
+OCIO_NAMESPACE_ENTER
+{
+
+namespace pystring
+{
+
+#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS) || defined(_MSC_VER)
+#ifndef WINDOWS
+#define WINDOWS
+#endif
+#endif
+
+// This definition codes from configure.in in the python src.
+// Strictly speaking this limits us to str sizes of 2**31.
+// Should we wish to handle this limit, we could use an architecture
+// specific #defines and read from ssize_t (unistd.h) if the header exists.
+// But in the meantime, the use of int assures maximum arch compatibility.
+// This must also equal the size used in the end = MAX_32BIT_INT default arg.
+
+typedef int Py_ssize_t;
+
+/* helper macro to fixup start/end slice values */
+#define ADJUST_INDICES(start, end, len) \
+ if (end > len) \
+ end = len; \
+ else if (end < 0) { \
+ end += len; \
+ if (end < 0) \
+ end = 0; \
+ } \
+ if (start < 0) { \
+ start += len; \
+ if (start < 0) \
+ start = 0; \
+ }
+
+
+ namespace {
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// why doesn't the std::reverse work?
+ ///
+ void reverse_strings( std::vector< std::string > & result)
+ {
+ for (std::vector< std::string >::size_type i = 0; i < result.size() / 2; i++ )
+ {
+ std::swap(result[i], result[result.size() - 1 - i]);
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ void split_whitespace( const std::string & str, std::vector< std::string > & result, int maxsplit )
+ {
+ std::string::size_type i, j, len = str.size();
+ for (i = j = 0; i < len; )
+ {
+
+ while ( i < len && ::isspace( str[i] ) ) i++;
+ j = i;
+
+ while ( i < len && ! ::isspace( str[i]) ) i++;
+
+
+
+ if (j < i)
+ {
+ if ( maxsplit-- <= 0 ) break;
+
+ result.push_back( str.substr( j, i - j ));
+
+ while ( i < len && ::isspace( str[i])) i++;
+ j = i;
+ }
+ }
+ if (j < len)
+ {
+ result.push_back( str.substr( j, len - j ));
+ }
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ void rsplit_whitespace( const std::string & str, std::vector< std::string > & result, int maxsplit )
+ {
+ std::string::size_type len = str.size();
+ std::string::size_type i, j;
+ for (i = j = len; i > 0; )
+ {
+
+ while ( i > 0 && ::isspace( str[i - 1] ) ) i--;
+ j = i;
+
+ while ( i > 0 && ! ::isspace( str[i - 1]) ) i--;
+
+
+
+ if (j > i)
+ {
+ if ( maxsplit-- <= 0 ) break;
+
+ result.push_back( str.substr( i, j - i ));
+
+ while ( i > 0 && ::isspace( str[i - 1])) i--;
+ j = i;
+ }
+ }
+ if (j > 0)
+ {
+ result.push_back( str.substr( 0, j ));
+ }
+ //std::reverse( result, result.begin(), result.end() );
+ reverse_strings( result );
+ }
+
+ } //anonymous namespace
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ void split( const std::string & str, std::vector< std::string > & result, const std::string & sep, int maxsplit )
+ {
+ result.clear();
+
+ if ( maxsplit < 0 ) maxsplit = MAX_32BIT_INT;//result.max_size();
+
+
+ if ( sep.size() == 0 )
+ {
+ split_whitespace( str, result, maxsplit );
+ return;
+ }
+
+ std::string::size_type i,j, len = str.size(), n = sep.size();
+
+ i = j = 0;
+
+ while ( i+n <= len )
+ {
+ if ( str[i] == sep[0] && str.substr( i, n ) == sep )
+ {
+ if ( maxsplit-- <= 0 ) break;
+
+ result.push_back( str.substr( j, i - j ) );
+ i = j = i + n;
+ }
+ else
+ {
+ i++;
+ }
+ }
+
+ result.push_back( str.substr( j, len-j ) );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ void rsplit( const std::string & str, std::vector< std::string > & result, const std::string & sep, int maxsplit )
+ {
+ if ( maxsplit < 0 )
+ {
+ split( str, result, sep, 0 );
+ return;
+ }
+
+ result.clear();
+
+ if ( sep.size() == 0 )
+ {
+ rsplit_whitespace( str, result, maxsplit );
+ return;
+ }
+
+ std::string::size_type i,j, len = str.size(), n = sep.size();
+
+ i = j = len;
+
+ while ( i > n )
+ {
+ if ( str[i - 1] == sep[n - 1] && str.substr( i - n, n ) == sep )
+ {
+ if ( maxsplit-- <= 0 ) break;
+
+ result.push_back( str.substr( i, j - i ) );
+ i = j = i - n;
+ }
+ else
+ {
+ i--;
+ }
+ }
+
+ result.push_back( str.substr( 0, j ) );
+ reverse_strings( result );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ #define LEFTSTRIP 0
+ #define RIGHTSTRIP 1
+ #define BOTHSTRIP 2
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string do_strip( const std::string & str, int striptype, const std::string & chars )
+ {
+ Py_ssize_t len = (Py_ssize_t) str.size(), i, j, charslen = (Py_ssize_t) chars.size();
+
+ if ( charslen == 0 )
+ {
+ i = 0;
+ if ( striptype != RIGHTSTRIP )
+ {
+ while ( i < len && ::isspace( str[i] ) )
+ {
+ i++;
+ }
+ }
+
+ j = len;
+ if ( striptype != LEFTSTRIP )
+ {
+ do
+ {
+ j--;
+ }
+ while (j >= i && ::isspace(str[j]));
+
+ j++;
+ }
+
+
+ }
+ else
+ {
+ const char * sep = chars.c_str();
+
+ i = 0;
+ if ( striptype != RIGHTSTRIP )
+ {
+ while ( i < len && memchr(sep, str[i], charslen) )
+ {
+ i++;
+ }
+ }
+
+ j = len;
+ if (striptype != LEFTSTRIP)
+ {
+ do
+ {
+ j--;
+ }
+ while (j >= i && memchr(sep, str[j], charslen) );
+ j++;
+ }
+
+
+ }
+
+ if ( i == 0 && j == len )
+ {
+ return str;
+ }
+ else
+ {
+ return str.substr( i, j - i );
+ }
+
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ void partition( const std::string & str, const std::string & sep, std::vector< std::string > & result )
+ {
+ result.resize(3);
+ int index = find( str, sep );
+ if ( index < 0 )
+ {
+ result[0] = str;
+ result[1] = "";
+ result[2] = "";
+ }
+ else
+ {
+ result[0] = str.substr( 0, index );
+ result[1] = sep;
+ result[2] = str.substr( index + sep.size(), str.size() );
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ void rpartition( const std::string & str, const std::string & sep, std::vector< std::string > & result )
+ {
+ result.resize(3);
+ int index = rfind( str, sep );
+ if ( index < 0 )
+ {
+ result[0] = "";
+ result[1] = "";
+ result[2] = str;
+ }
+ else
+ {
+ result[0] = str.substr( 0, index );
+ result[1] = sep;
+ result[2] = str.substr( index + sep.size(), str.size() );
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string strip( const std::string & str, const std::string & chars )
+ {
+ return do_strip( str, BOTHSTRIP, chars );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string lstrip( const std::string & str, const std::string & chars )
+ {
+ return do_strip( str, LEFTSTRIP, chars );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string rstrip( const std::string & str, const std::string & chars )
+ {
+ return do_strip( str, RIGHTSTRIP, chars );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string join( const std::string & str, const std::vector< std::string > & seq )
+ {
+ std::vector< std::string >::size_type seqlen = seq.size(), i;
+
+ if ( seqlen == 0 ) return "";
+ if ( seqlen == 1 ) return seq[0];
+
+ std::string result( seq[0] );
+
+ for ( i = 1; i < seqlen; ++i )
+ {
+ result += str + seq[i];
+
+ }
+
+
+ return result;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+
+ namespace
+ {
+ /* Matches the end (direction >= 0) or start (direction < 0) of self
+ * against substr, using the start and end arguments. Returns
+ * -1 on error, 0 if not found and 1 if found.
+ */
+
+ int _string_tailmatch(const std::string & self, const std::string & substr,
+ Py_ssize_t start, Py_ssize_t end,
+ int direction)
+ {
+ Py_ssize_t len = (Py_ssize_t) self.size();
+ Py_ssize_t slen = (Py_ssize_t) substr.size();
+
+ const char* sub = substr.c_str();
+ const char* str = self.c_str();
+
+ ADJUST_INDICES(start, end, len);
+
+ if (direction < 0) {
+ // startswith
+ if (start+slen > len)
+ return 0;
+ } else {
+ // endswith
+ if (end-start < slen || start > len)
+ return 0;
+ if (end-slen > start)
+ start = end - slen;
+ }
+ if (end-start >= slen)
+ return (!std::memcmp(str+start, sub, slen));
+
+ return 0;
+ }
+ }
+
+ bool endswith( const std::string & str, const std::string & suffix, int start, int end )
+ {
+ int result = _string_tailmatch(str, suffix,
+ (Py_ssize_t) start, (Py_ssize_t) end, +1);
+ //if (result == -1) // TODO: Error condition
+
+ return static_cast<bool>(result);
+ }
+
+
+ bool startswith( const std::string & str, const std::string & prefix, int start, int end )
+ {
+ int result = _string_tailmatch(str, prefix,
+ (Py_ssize_t) start, (Py_ssize_t) end, -1);
+ //if (result == -1) // TODO: Error condition
+
+ return static_cast<bool>(result);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+
+ bool isalnum( const std::string & str )
+ {
+ std::string::size_type len = str.size(), i;
+ if ( len == 0 ) return false;
+
+
+ if( len == 1 )
+ {
+ return ::isalnum( str[0] );
+ }
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( !::isalnum( str[i] ) ) return false;
+ }
+ return true;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ bool isalpha( const std::string & str )
+ {
+ std::string::size_type len = str.size(), i;
+ if ( len == 0 ) return false;
+ if( len == 1 ) return ::isalpha( (int) str[0] );
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( !::isalpha( (int) str[i] ) ) return false;
+ }
+ return true;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ bool isdigit( const std::string & str )
+ {
+ std::string::size_type len = str.size(), i;
+ if ( len == 0 ) return false;
+ if( len == 1 ) return ::isdigit( str[0] );
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( ! ::isdigit( str[i] ) ) return false;
+ }
+ return true;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ bool islower( const std::string & str )
+ {
+ std::string::size_type len = str.size(), i;
+ if ( len == 0 ) return false;
+ if( len == 1 ) return ::islower( str[0] );
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( !::islower( str[i] ) ) return false;
+ }
+ return true;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ bool isspace( const std::string & str )
+ {
+ std::string::size_type len = str.size(), i;
+ if ( len == 0 ) return false;
+ if( len == 1 ) return ::isspace( str[0] );
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( !::isspace( str[i] ) ) return false;
+ }
+ return true;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ bool istitle( const std::string & str )
+ {
+ std::string::size_type len = str.size(), i;
+
+ if ( len == 0 ) return false;
+ if ( len == 1 ) return ::isupper( str[0] );
+
+ bool cased = false, previous_is_cased = false;
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( ::isupper( str[i] ) )
+ {
+ if ( previous_is_cased )
+ {
+ return false;
+ }
+
+ previous_is_cased = true;
+ cased = true;
+ }
+ else if ( ::islower( str[i] ) )
+ {
+ if (!previous_is_cased)
+ {
+ return false;
+ }
+
+ previous_is_cased = true;
+ cased = true;
+
+ }
+ else
+ {
+ previous_is_cased = false;
+ }
+ }
+
+ return cased;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ bool isupper( const std::string & str )
+ {
+ std::string::size_type len = str.size(), i;
+ if ( len == 0 ) return false;
+ if( len == 1 ) return ::isupper( str[0] );
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( !::isupper( str[i] ) ) return false;
+ }
+ return true;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string capitalize( const std::string & str )
+ {
+ std::string s( str );
+ std::string::size_type len = s.size(), i;
+
+ if ( len > 0)
+ {
+ if (::islower(s[0])) s[0] = (char) ::toupper( s[0] );
+ }
+
+ for ( i = 1; i < len; ++i )
+ {
+ if (::isupper(s[i])) s[i] = (char) ::tolower( s[i] );
+ }
+
+ return s;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string lower( const std::string & str )
+ {
+ std::string s( str );
+ std::string::size_type len = s.size(), i;
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( ::isupper( s[i] ) ) s[i] = (char) ::tolower( s[i] );
+ }
+
+ return s;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string upper( const std::string & str )
+ {
+ std::string s( str ) ;
+ std::string::size_type len = s.size(), i;
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( ::islower( s[i] ) ) s[i] = (char) ::toupper( s[i] );
+ }
+
+ return s;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string swapcase( const std::string & str )
+ {
+ std::string s( str );
+ std::string::size_type len = s.size(), i;
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( ::islower( s[i] ) ) s[i] = (char) ::toupper( s[i] );
+ else if (::isupper( s[i] ) ) s[i] = (char) ::tolower( s[i] );
+ }
+
+ return s;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string title( const std::string & str )
+ {
+ std::string s( str );
+ std::string::size_type len = s.size(), i;
+ bool previous_is_cased = false;
+
+ for ( i = 0; i < len; ++i )
+ {
+ int c = s[i];
+ if ( ::islower(c) )
+ {
+ if ( !previous_is_cased )
+ {
+ s[i] = (char) ::toupper(c);
+ }
+ previous_is_cased = true;
+ }
+ else if ( ::isupper(c) )
+ {
+ if ( previous_is_cased )
+ {
+ s[i] = (char) ::tolower(c);
+ }
+ previous_is_cased = true;
+ }
+ else
+ {
+ previous_is_cased = false;
+ }
+ }
+
+ return s;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string translate( const std::string & str, const std::string & table, const std::string & deletechars )
+ {
+ std::string s;
+ std::string::size_type len = str.size(), dellen = deletechars.size();
+
+ if ( table.size() != 256 )
+ {
+ // TODO : raise exception instead
+ return str;
+ }
+
+ //if nothing is deleted, use faster code
+ if ( dellen == 0 )
+ {
+ s = str;
+ for ( std::string::size_type i = 0; i < len; ++i )
+ {
+ s[i] = table[ s[i] ];
+ }
+ return s;
+ }
+
+
+ int trans_table[256];
+ for ( int i = 0; i < 256; i++)
+ {
+ trans_table[i] = table[i];
+ }
+
+ for ( std::string::size_type i = 0; i < dellen; i++)
+ {
+ trans_table[(int) deletechars[i] ] = -1;
+ }
+
+ for ( std::string::size_type i = 0; i < len; ++i )
+ {
+ if ( trans_table[ (int) str[i] ] != -1 )
+ {
+ s += table[ str[i] ];
+ }
+ }
+
+ return s;
+
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string zfill( const std::string & str, int width )
+ {
+ int len = (int)str.size();
+
+ if ( len >= width )
+ {
+ return str;
+ }
+
+ std::string s( str );
+
+ int fill = width - len;
+
+ s = std::string( fill, '0' ) + s;
+
+
+ if ( s[fill] == '+' || s[fill] == '-' )
+ {
+ s[0] = s[fill];
+ s[fill] = '0';
+ }
+
+ return s;
+
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string ljust( const std::string & str, int width )
+ {
+ std::string::size_type len = str.size();
+ if ( (( int ) len ) >= width ) return str;
+ return str + std::string( width - len, ' ' );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string rjust( const std::string & str, int width )
+ {
+ std::string::size_type len = str.size();
+ if ( (( int ) len ) >= width ) return str;
+ return std::string( width - len, ' ' ) + str;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string center( const std::string & str, int width )
+ {
+ int len = (int) str.size();
+ int marg, left;
+
+ if ( len >= width ) return str;
+
+ marg = width - len;
+ left = marg / 2 + (marg & width & 1);
+
+ return std::string( left, ' ' ) + str + std::string( marg - left, ' ' );
+
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string slice( const std::string & str, int start, int end )
+ {
+ ADJUST_INDICES(start, end, (int) str.size());
+ if ( start >= end ) return "";
+ return str.substr( start, end - start );
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ int find( const std::string & str, const std::string & sub, int start, int end )
+ {
+ ADJUST_INDICES(start, end, (int) str.size());
+
+ std::string::size_type result = str.find( sub, start );
+
+ // If we cannot find the string, or if the end-point of our found substring is past
+ // the allowed end limit, return that it can't be found.
+ if( result == std::string::npos ||
+ (result + sub.size() > (std::string::size_type)end) )
+ {
+ return -1;
+ }
+
+ return (int) result;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ int index( const std::string & str, const std::string & sub, int start, int end )
+ {
+ return find( str, sub, start, end );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ int rfind( const std::string & str, const std::string & sub, int start, int end )
+ {
+ ADJUST_INDICES(start, end, (int) str.size());
+
+ std::string::size_type result = str.rfind( sub, end );
+
+ if( result == std::string::npos ||
+ result < (std::string::size_type)start ||
+ (result + sub.size() > (std::string::size_type)end))
+ return -1;
+
+ return (int)result;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ int rindex( const std::string & str, const std::string & sub, int start, int end )
+ {
+ return rfind( str, sub, start, end );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string expandtabs( const std::string & str, int tabsize )
+ {
+ std::string s( str );
+
+ std::string::size_type len = str.size(), i = 0;
+ int offset = 0;
+
+ int j = 0;
+
+ for ( i = 0; i < len; ++i )
+ {
+ if ( str[i] == '\t' )
+ {
+
+ if ( tabsize > 0 )
+ {
+ int fillsize = tabsize - (j % tabsize);
+ j += fillsize;
+ s.replace( i + offset, 1, std::string( fillsize, ' ' ));
+ offset += fillsize - 1;
+ }
+ else
+ {
+ s.replace( i + offset, 1, "" );
+ offset -= 1;
+ }
+
+ }
+ else
+ {
+ j++;
+
+ if (str[i] == '\n' || str[i] == '\r')
+ {
+ j = 0;
+ }
+ }
+ }
+
+ return s;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ int count( const std::string & str, const std::string & substr, int start, int end )
+ {
+ int nummatches = 0;
+ int cursor = start;
+
+ while ( 1 )
+ {
+ cursor = find( str, substr, cursor, end );
+
+ if ( cursor < 0 ) break;
+
+ cursor += (int) substr.size();
+ nummatches += 1;
+ }
+
+ return nummatches;
+
+
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string replace( const std::string & str, const std::string & oldstr, const std::string & newstr, int count )
+ {
+ int sofar = 0;
+ int cursor = 0;
+ std::string s( str );
+
+ std::string::size_type oldlen = oldstr.size(), newlen = newstr.size();
+
+ while ( ( cursor = find( s, oldstr, cursor ) ) != -1 )
+ {
+ if ( count > -1 && sofar >= count )
+ {
+ break;
+ }
+
+ s.replace( cursor, oldlen, newstr );
+
+ cursor += (int) newlen;
+ ++sofar;
+ }
+
+ return s;
+
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ void splitlines( const std::string & str, std::vector< std::string > & result, bool keepends )
+ {
+ result.clear();
+ std::string::size_type len = str.size(), i, j, eol;
+
+ for (i = j = 0; i < len; )
+ {
+ while (i < len && str[i] != '\n' && str[i] != '\r') i++;
+
+ eol = i;
+ if (i < len)
+ {
+ if (str[i] == '\r' && i + 1 < len && str[i+1] == '\n')
+ {
+ i += 2;
+ }
+ else
+ {
+ i++;
+ }
+ if (keepends)
+ eol = i;
+
+ }
+
+ result.push_back( str.substr( j, eol - j ) );
+ j = i;
+
+ }
+
+ if (j < len)
+ {
+ result.push_back( str.substr( j, len - j ) );
+ }
+
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ std::string mul( const std::string & str, int n )
+ {
+ // Early exits
+ if (n <= 0) return "";
+ if (n == 1) return str;
+
+ std::ostringstream os;
+ for(int i=0; i<n; ++i)
+ {
+ os << str;
+ }
+ return os.str();
+ }
+
+
+
+namespace os
+{
+namespace path
+{
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+ /// These functions are C++ ports of the python2.6 versions of os.path,
+ /// and come from genericpath.py, ntpath.py, posixpath.py
+
+ /// Split a pathname into drive and path specifiers.
+ /// Returns drivespec, pathspec. Either part may be empty.
+ void splitdrive_nt(std::string & drivespec, std::string & pathspec,
+ const std::string & p)
+ {
+ if(pystring::slice(p, 1, 2) == ":")
+ {
+ std::string path = p; // In case drivespec == p
+ drivespec = pystring::slice(path, 0, 2);
+ pathspec = pystring::slice(path, 2);
+ }
+ else
+ {
+ drivespec = "";
+ pathspec = p;
+ }
+ }
+
+ // On Posix, drive is always empty
+ void splitdrive_posix(std::string & drivespec, std::string & pathspec,
+ const std::string & path)
+ {
+ drivespec = "";
+ pathspec = path;
+ }
+
+ void splitdrive(std::string & drivespec, std::string & pathspec,
+ const std::string & path)
+ {
+#ifdef WINDOWS
+ return splitdrive_nt(drivespec, pathspec, path);
+#else
+ return splitdrive_posix(drivespec, pathspec, path);
+#endif
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+
+ // Test whether a path is absolute
+ // In windows, if the character to the right of the colon
+ // is a forward or backslash it's absolute.
+ bool isabs_nt(const std::string & path)
+ {
+ std::string drivespec, pathspec;
+ splitdrive_nt(drivespec, pathspec, path);
+ if(pathspec.empty()) return false;
+ return ((pathspec[0] == '/') || (pathspec[0] == '\\'));
+ }
+
+ bool isabs_posix(const std::string & s)
+ {
+ return pystring::startswith(s, "/");
+ }
+
+ bool isabs(const std::string & path)
+ {
+#ifdef WINDOWS
+ return isabs_nt(path);
+#else
+ return isabs_posix(path);
+#endif
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+
+ std::string abspath_nt(const std::string & path, const std::string & cwd)
+ {
+ std::string p = path;
+ if(!isabs_nt(p)) p = join_nt(cwd, p);
+ return normpath_nt(p);
+ }
+
+ std::string abspath_posix(const std::string & path, const std::string & cwd)
+ {
+ std::string p = path;
+ if(!isabs_posix(p)) p = join_posix(cwd, p);
+ return normpath_posix(p);
+ }
+
+ std::string abspath(const std::string & path, const std::string & cwd)
+ {
+#ifdef WINDOWS
+ return abspath_nt(path, cwd);
+#else
+ return abspath_posix(path, cwd);
+#endif
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+
+ std::string join_nt(const std::vector< std::string > & paths)
+ {
+ if(paths.empty()) return "";
+ if(paths.size() == 1) return paths[0];
+
+ std::string path = paths[0];
+
+ for(unsigned int i=1; i<paths.size(); ++i)
+ {
+ std::string b = paths[i];
+
+ bool b_nts = false;
+ if(path.empty())
+ {
+ b_nts = true;
+ }
+ else if(isabs_nt(b))
+ {
+ // This probably wipes out path so far. However, it's more
+ // complicated if path begins with a drive letter:
+ // 1. join('c:', '/a') == 'c:/a'
+ // 2. join('c:/', '/a') == 'c:/a'
+ // But
+ // 3. join('c:/a', '/b') == '/b'
+ // 4. join('c:', 'd:/') = 'd:/'
+ // 5. join('c:/', 'd:/') = 'd:/'
+
+ if( (pystring::slice(path, 1, 2) != ":") ||
+ (pystring::slice(b, 1, 2) == ":") )
+ {
+ // Path doesnt start with a drive letter
+ b_nts = true;
+ }
+ // Else path has a drive letter, and b doesn't but is absolute.
+ else if((path.size()>3) ||
+ ((path.size()==3) && !pystring::endswith(path, "/") && !pystring::endswith(path, "\\")))
+ {
+ b_nts = true;
+ }
+ }
+
+ if(b_nts)
+ {
+ path = b;
+ }
+ else
+ {
+ // Join, and ensure there's a separator.
+ // assert len(path) > 0
+ if( pystring::endswith(path, "/") || pystring::endswith(path, "\\"))
+ {
+ if(pystring::startswith(b,"/") || pystring::startswith(b,"\\"))
+ {
+ path += pystring::slice(b, 1);
+ }
+ else
+ {
+ path += b;
+ }
+ }
+ else if(pystring::endswith(path, ":"))
+ {
+ path += b;
+ }
+ else if(!b.empty())
+ {
+ if(pystring::startswith(b,"/") || pystring::startswith(b,"\\"))
+ {
+ path += b;
+ }
+ else
+ {
+ path += "\\" + b;
+ }
+ }
+ else
+ {
+ // path is not empty and does not end with a backslash,
+ // but b is empty; since, e.g., split('a/') produces
+ // ('a', ''), it's best if join() adds a backslash in
+ // this case.
+ path += "\\";
+ }
+ }
+ }
+
+ return path;
+ }
+
+ // Join two or more pathname components, inserting "\\" as needed.
+ std::string join_nt(const std::string & a, const std::string & b)
+ {
+ std::vector< std::string > paths(2);
+ paths[0] = a;
+ paths[1] = b;
+ return join_nt(paths);
+ }
+
+ // Join pathnames.
+ // If any component is an absolute path, all previous path components
+ // will be discarded.
+ // Ignore the previous parts if a part is absolute.
+ // Insert a '/' unless the first part is empty or already ends in '/'.
+
+ std::string join_posix(const std::vector< std::string > & paths)
+ {
+ if(paths.empty()) return "";
+ if(paths.size() == 1) return paths[0];
+
+ std::string path = paths[0];
+
+ for(unsigned int i=1; i<paths.size(); ++i)
+ {
+ std::string b = paths[i];
+ if(pystring::startswith(b, "/"))
+ {
+ path = b;
+ }
+ else if(path.empty() || pystring::endswith(path, "/"))
+ {
+ path += b;
+ }
+ else
+ {
+ path += "/" + b;
+ }
+ }
+
+ return path;
+ }
+
+ std::string join_posix(const std::string & a, const std::string & b)
+ {
+ std::vector< std::string > paths(2);
+ paths[0] = a;
+ paths[1] = b;
+ return join_posix(paths);
+ }
+
+ std::string join(const std::string & path1, const std::string & path2)
+ {
+#ifdef WINDOWS
+ return join_nt(path1, path2);
+#else
+ return join_posix(path1, path2);
+#endif
+ }
+
+
+ std::string join(const std::vector< std::string > & paths)
+ {
+#ifdef WINDOWS
+ return join_nt(paths);
+#else
+ return join_posix(paths);
+#endif
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+
+
+ // Split a pathname.
+ // Return (head, tail) where tail is everything after the final slash.
+ // Either part may be empty
+
+ void split_nt(std::string & head, std::string & tail, const std::string & path)
+ {
+ std::string d, p;
+ splitdrive_nt(d, p, path);
+
+ // set i to index beyond p's last slash
+ int i = (int)p.size();
+
+ while(i>0 && (p[i-1] != '\\') && (p[i-1] != '/'))
+ {
+ i = i - 1;
+ }
+
+ head = pystring::slice(p,0,i);
+ tail = pystring::slice(p,i); // now tail has no slashes
+
+ // remove trailing slashes from head, unless it's all slashes
+ std::string head2 = head;
+ while(!head2.empty() && ((pystring::slice(head2,-1) == "/") ||
+ (pystring::slice(head2,-1) == "\\")))
+ {
+ head2 = pystring::slice(head,0,-1);
+ }
+
+ if(!head2.empty()) head = head2;
+ head = d + head;
+ }
+
+
+ // Split a path in head (everything up to the last '/') and tail (the
+ // rest). If the path ends in '/', tail will be empty. If there is no
+ // '/' in the path, head will be empty.
+ // Trailing '/'es are stripped from head unless it is the root.
+
+ void split_posix(std::string & head, std::string & tail, const std::string & p)
+ {
+ int i = pystring::rfind(p, "/") + 1;
+
+ head = pystring::slice(p,0,i);
+ tail = pystring::slice(p,i);
+
+ if(!head.empty() && (head != pystring::mul("/", (int) head.size())))
+ {
+ head = pystring::rstrip(head, "/");
+ }
+ }
+
+ void split(std::string & head, std::string & tail, const std::string & path)
+ {
+#ifdef WINDOWS
+ return split_nt(head, tail, path);
+#else
+ return split_posix(head, tail, path);
+#endif
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+
+ std::string basename_nt(const std::string & path)
+ {
+ std::string head, tail;
+ split_nt(head, tail, path);
+ return tail;
+ }
+
+ std::string basename_posix(const std::string & path)
+ {
+ std::string head, tail;
+ split_posix(head, tail, path);
+ return tail;
+ }
+
+ std::string basename(const std::string & path)
+ {
+#ifdef WINDOWS
+ return basename_nt(path);
+#else
+ return basename_posix(path);
+#endif
+ }
+
+ std::string dirname_nt(const std::string & path)
+ {
+ std::string head, tail;
+ split_nt(head, tail, path);
+ return head;
+ }
+
+ std::string dirname_posix(const std::string & path)
+ {
+ std::string head, tail;
+ split_posix(head, tail, path);
+ return head;
+ }
+
+ std::string dirname(const std::string & path)
+ {
+#ifdef WINDOWS
+ return dirname_nt(path);
+#else
+ return dirname_posix(path);
+#endif
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+
+ // Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B.
+ std::string normpath_nt(const std::string & p)
+ {
+ std::string path = p;
+ path = pystring::replace(path, "/","\\");
+
+ std::string prefix;
+ splitdrive_nt(prefix, path, path);
+
+ // We need to be careful here. If the prefix is empty, and the path starts
+ // with a backslash, it could either be an absolute path on the current
+ // drive (\dir1\dir2\file) or a UNC filename (\\server\mount\dir1\file). It
+ // is therefore imperative NOT to collapse multiple backslashes blindly in
+ // that case.
+ // The code below preserves multiple backslashes when there is no drive
+ // letter. This means that the invalid filename \\\a\b is preserved
+ // unchanged, where a\\\b is normalised to a\b. It's not clear that there
+ // is any better behaviour for such edge cases.
+
+ if(prefix.empty())
+ {
+ // No drive letter - preserve initial backslashes
+ while(pystring::slice(path,0,1) == "\\")
+ {
+ prefix = prefix + "\\";
+ path = pystring::slice(path,1);
+ }
+ }
+ else
+ {
+ // We have a drive letter - collapse initial backslashes
+ if(pystring::startswith(path, "\\"))
+ {
+ prefix = prefix + "\\";
+ path = pystring::lstrip(path, "\\");
+ }
+ }
+
+ std::vector<std::string> comps;
+ pystring::split(path, comps, "\\");
+
+ int i = 0;
+
+ while(i<(int)comps.size())
+ {
+ if(comps[i].empty() || comps[i] == ".")
+ {
+ comps.erase(comps.begin()+i);
+ }
+ else if(comps[i] == "..")
+ {
+ if(i>0 && comps[i-1] != "..")
+ {
+ comps.erase(comps.begin()+i-1, comps.begin()+i+1);
+ i -= 1;
+ }
+ else if(i == 0 && pystring::endswith(prefix, "\\"))
+ {
+ comps.erase(comps.begin()+i);
+ }
+ else
+ {
+ i += 1;
+ }
+ }
+ else
+ {
+ i += 1;
+ }
+ }
+
+ // If the path is now empty, substitute '.'
+ if(prefix.empty() && comps.empty())
+ {
+ comps.push_back(".");
+ }
+
+ return prefix + pystring::join("\\", comps);
+ }
+
+ // Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
+ // It should be understood that this may change the meaning of the path
+ // if it contains symbolic links!
+ // Normalize path, eliminating double slashes, etc.
+
+ std::string normpath_posix(const std::string & p)
+ {
+ if(p.empty()) return ".";
+
+ std::string path = p;
+
+ int initial_slashes = pystring::startswith(path,"/") ? 1 : 0;
+
+ // POSIX allows one or two initial slashes, but treats three or more
+ // as single slash.
+
+ if (initial_slashes && pystring::startswith(path,"//")
+ && !pystring::startswith(path,"///"))
+ initial_slashes = 2;
+
+ std::vector<std::string> comps, new_comps;
+ pystring::split(path, comps, "/");
+
+ for(unsigned int i=0; i<comps.size(); ++i)
+ {
+ std::string comp = comps[i];
+ if(comp.empty() || comp == ".")
+ continue;
+
+ if( (comp != "..") || ((initial_slashes == 0) && new_comps.empty()) ||
+ (!new_comps.empty() && new_comps[new_comps.size()-1] == ".."))
+ {
+ new_comps.push_back(comp);
+ }
+ else if (!new_comps.empty())
+ {
+ new_comps.pop_back();
+ }
+ }
+
+ path = pystring::join("/", new_comps);
+
+ if (initial_slashes > 0)
+ path = pystring::mul("/",initial_slashes) + path;
+
+ if(path.empty()) return ".";
+ return path;
+ }
+
+ std::string normpath(const std::string & path)
+ {
+#ifdef WINDOWS
+ return normpath_nt(path);
+#else
+ return normpath_posix(path);
+#endif
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ ///
+ ///
+
+ // Split the extension from a pathname.
+ // Extension is everything from the last dot to the end, ignoring
+ // leading dots. Returns "(root, ext)"; ext may be empty.
+ // It is always true that root + ext == p
+
+ void splitext_generic(std::string & root, std::string & ext,
+ const std::string & p,
+ const std::string & sep,
+ const std::string & altsep,
+ const std::string & extsep)
+ {
+ int sepIndex = pystring::rfind(p, sep);
+ if(!altsep.empty())
+ {
+ int altsepIndex = pystring::rfind(p, altsep);
+ sepIndex = std::max(sepIndex, altsepIndex);
+ }
+
+ int dotIndex = pystring::rfind(p, extsep);
+ if(dotIndex > sepIndex)
+ {
+ // Skip all leading dots
+ int filenameIndex = sepIndex + 1;
+
+ while(filenameIndex < dotIndex)
+ {
+ if(pystring::slice(p,filenameIndex) != extsep)
+ {
+ root = pystring::slice(p, 0, dotIndex);
+ ext = pystring::slice(p, dotIndex);
+ return;
+ }
+
+ filenameIndex += 1;
+ }
+ }
+
+ root = p;
+ ext = "";
+ }
+
+ void splitext_nt(std::string & root, std::string & ext, const std::string & path)
+ {
+ return splitext_generic(root, ext, path,
+ "\\", "/", ".");
+ }
+
+ void splitext_posix(std::string & root, std::string & ext, const std::string & path)
+ {
+ return splitext_generic(root, ext, path,
+ "/", "", ".");
+ }
+
+ void splitext(std::string & root, std::string & ext, const std::string & path)
+ {
+#ifdef WINDOWS
+ return splitext_nt(root, ext, path);
+#else
+ return splitext_posix(root, ext, path);
+#endif
+ }
+
+} // namespace path
+} // namespace os
+
+
+}//namespace pystring
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/core/pystring/pystring.h b/src/core/pystring/pystring.h
new file mode 100644
index 0000000..f0729db
--- /dev/null
+++ b/src/core/pystring/pystring.h
@@ -0,0 +1,438 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2008-2010, Sony Pictures Imageworks Inc
+// 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 the organization 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.
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDED_OCIO_PYSTRING_H
+#define INCLUDED_OCIO_PYSTRING_H
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include <string>
+#include <vector>
+
+OCIO_NAMESPACE_ENTER
+{
+// Version 1.1.2
+// https://github.com/imageworks/pystring/tarball/v1.1.2
+
+namespace pystring
+{
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @mainpage pystring
+ ///
+ /// This is a set of functions matching the interface and behaviors of python string methods
+ /// (as of python 2.3) using std::string.
+ ///
+ /// Overlapping functionality ( such as index and slice/substr ) of std::string is included
+ /// to match python interfaces.
+ ///
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @defgroup functions pystring
+ /// @{
+
+
+ #define MAX_32BIT_INT 2147483647
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string with only its first character capitalized.
+ ///
+ std::string capitalize( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return centered in a string of length width. Padding is done using spaces.
+ ///
+ std::string center( const std::string & str, int width );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return the number of occurrences of substring sub in string S[start:end]. Optional
+ /// arguments start and end are interpreted as in slice notation.
+ ///
+ int count( const std::string & str, const std::string & substr, int start = 0, int end = MAX_32BIT_INT);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return True if the string ends with the specified suffix, otherwise return False. With
+ /// optional start, test beginning at that position. With optional end, stop comparing at that position.
+ ///
+ bool endswith( const std::string & str, const std::string & suffix, int start = 0, int end = MAX_32BIT_INT );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string where all tab characters are expanded using spaces. If tabsize
+ /// is not given, a tab size of 8 characters is assumed.
+ ///
+ std::string expandtabs( const std::string & str, int tabsize = 8);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return the lowest index in the string where substring sub is found, such that sub is
+ /// contained in the range [start, end). Optional arguments start and end are interpreted as
+ /// in slice notation. Return -1 if sub is not found.
+ ///
+ int find( const std::string & str, const std::string & sub, int start = 0, int end = MAX_32BIT_INT );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Synonym of find right now. Python version throws exceptions. This one currently doesn't
+ ///
+ int index( const std::string & str, const std::string & sub, int start = 0, int end = MAX_32BIT_INT );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return true if all characters in the string are alphanumeric and there is at least one
+ /// character, false otherwise.
+ ///
+ bool isalnum( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return true if all characters in the string are alphabetic and there is at least one
+ /// character, false otherwise
+ ///
+ bool isalpha( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return true if all characters in the string are digits and there is at least one
+ /// character, false otherwise.
+ ///
+ bool isdigit( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return true if all cased characters in the string are lowercase and there is at least one
+ /// cased character, false otherwise.
+ ///
+ bool islower( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return true if there are only whitespace characters in the string and there is at least
+ /// one character, false otherwise.
+ ///
+ bool isspace( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return true if the string is a titlecased string and there is at least one character,
+ /// i.e. uppercase characters may only follow uncased characters and lowercase characters only
+ /// cased ones. Return false otherwise.
+ ///
+ bool istitle( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return true if all cased characters in the string are uppercase and there is at least one
+ /// cased character, false otherwise.
+ ///
+ bool isupper( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a string which is the concatenation of the strings in the sequence seq.
+ /// The separator between elements is the str argument
+ ///
+ std::string join( const std::string & str, const std::vector< std::string > & seq );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return the string left justified in a string of length width. Padding is done using
+ /// spaces. The original string is returned if width is less than str.size().
+ ///
+ std::string ljust( const std::string & str, int width );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string converted to lowercase.
+ ///
+ std::string lower( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string with leading characters removed. If chars is omitted or None,
+ /// whitespace characters are removed. If given and not "", chars must be a string; the
+ /// characters in the string will be stripped from the beginning of the string this method
+ /// is called on (argument "str" ).
+ ///
+ std::string lstrip( const std::string & str, const std::string & chars = "" );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string, concatenated N times, together.
+ /// Corresponds to the __mul__ operator.
+ ///
+ std::string mul( const std::string & str, int n);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Split the string around first occurance of sep.
+ /// Three strings will always placed into result. If sep is found, the strings will
+ /// be the text before sep, sep itself, and the remaining text. If sep is
+ /// not found, the original string will be returned with two empty strings.
+ ///
+ void partition( const std::string & str, const std::string & sep, std::vector< std::string > & result );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string with all occurrences of substring old replaced by new. If
+ /// the optional argument count is given, only the first count occurrences are replaced.
+ ///
+ std::string replace( const std::string & str, const std::string & oldstr, const std::string & newstr, int count = -1);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return the highest index in the string where substring sub is found, such that sub is
+ /// contained within s[start,end]. Optional arguments start and end are interpreted as in
+ /// slice notation. Return -1 on failure.
+ ///
+ int rfind( const std::string & str, const std::string & sub, int start = 0, int end = MAX_32BIT_INT );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Currently a synonym of rfind. The python version raises exceptions. This one currently
+ /// does not
+ ///
+ int rindex( const std::string & str, const std::string & sub, int start = 0, int end = MAX_32BIT_INT );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return the string right justified in a string of length width. Padding is done using
+ /// spaces. The original string is returned if width is less than str.size().
+ ///
+ std::string rjust( const std::string & str, int width);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Split the string around last occurance of sep.
+ /// Three strings will always placed into result. If sep is found, the strings will
+ /// be the text before sep, sep itself, and the remaining text. If sep is
+ /// not found, the original string will be returned with two empty strings.
+ ///
+ void rpartition( const std::string & str, const std::string & sep, std::vector< std::string > & result );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string with trailing characters removed. If chars is "", whitespace
+ /// characters are removed. If not "", the characters in the string will be stripped from the
+ /// end of the string this method is called on.
+ ///
+ std::string rstrip( const std::string & str, const std::string & chars = "" );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Fills the "result" list with the words in the string, using sep as the delimiter string.
+ /// If maxsplit is > -1, at most maxsplit splits are done. If sep is "",
+ /// any whitespace string is a separator.
+ ///
+ void split( const std::string & str, std::vector< std::string > & result, const std::string & sep = "", int maxsplit = -1);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Fills the "result" list with the words in the string, using sep as the delimiter string.
+ /// Does a number of splits starting at the end of the string, the result still has the
+ /// split strings in their original order.
+ /// If maxsplit is > -1, at most maxsplit splits are done. If sep is "",
+ /// any whitespace string is a separator.
+ ///
+ void rsplit( const std::string & str, std::vector< std::string > & result, const std::string & sep = "", int maxsplit = -1);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a list of the lines in the string, breaking at line boundaries. Line breaks
+ /// are not included in the resulting list unless keepends is given and true.
+ ///
+ void splitlines( const std::string & str, std::vector< std::string > & result, bool keepends = false );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return True if string starts with the prefix, otherwise return False. With optional start,
+ /// test string beginning at that position. With optional end, stop comparing string at that
+ /// position
+ ///
+ bool startswith( const std::string & str, const std::string & prefix, int start = 0, int end = MAX_32BIT_INT );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string with leading and trailing characters removed. If chars is "",
+ /// whitespace characters are removed. If given not "", the characters in the string will be
+ /// stripped from the both ends of the string this method is called on.
+ ///
+ std::string strip( const std::string & str, const std::string & chars = "" );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string with uppercase characters converted to lowercase and vice versa.
+ ///
+ std::string swapcase( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a titlecased version of the string: words start with uppercase characters,
+ /// all remaining cased characters are lowercase.
+ ///
+ std::string title( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string where all characters occurring in the optional argument
+ /// deletechars are removed, and the remaining characters have been mapped through the given
+ /// translation table, which must be a string of length 256.
+ ///
+ std::string translate( const std::string & str, const std::string & table, const std::string & deletechars = "");
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a copy of the string converted to uppercase.
+ ///
+ std::string upper( const std::string & str );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return the numeric string left filled with zeros in a string of length width. The original
+ /// string is returned if width is less than str.size().
+ ///
+ std::string zfill( const std::string & str, int width );
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief function matching python's slice functionality.
+ ///
+ std::string slice( const std::string & str, int start = 0, int end = MAX_32BIT_INT);
+
+ ///
+ /// @ }
+ ///
+
+
+namespace os
+{
+namespace path
+{
+ // All of the function below have three versions.
+ // Example:
+ // join(...)
+ // join_nt(...)
+ // join_posix(...)
+ //
+ // The regular function dispatches to the other versions - based on the OS
+ // at compile time - to match the result you'd get from the python
+ // interepreter on the same operating system
+ //
+ // Should you want to 'lock off' to a particular version of the string
+ // manipulation across *all* operating systems, use the version with the
+ // _OS you are interested in. I.e., you can use posix style path joining,
+ // even on Windows, with join_posix.
+ //
+ // The naming, (nt, posix) matches the cpython source implementation.
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @defgroup functions pystring::os::path
+ /// @{
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return the base name of pathname path. This is the second half of the pair returned
+ /// by split(path). Note that the result of this function is different from the Unix basename
+ /// program; where basename for '/foo/bar/' returns 'bar', the basename() function returns an
+ /// empty string ('').
+
+ std::string basename(const std::string & path);
+ std::string basename_nt(const std::string & path);
+ std::string basename_posix(const std::string & path);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return the directory name of pathname path. This is the first half of the pair
+ /// returned by split(path).
+
+ std::string dirname(const std::string & path);
+ std::string dirname_nt(const std::string & path);
+ std::string dirname_posix(const std::string & path);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return True if path is an absolute pathname. On Unix, that means it begins with a
+ /// slash, on Windows that it begins with a (back)slash after chopping off a potential drive
+ /// letter.
+
+ bool isabs(const std::string & path);
+ bool isabs_nt(const std::string & path);
+ bool isabs_posix(const std::string & s);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Return a normalized absolutized version of the pathname path.
+ ///
+ /// NOTE: This differs from the interface of the python equivalent in that it requires you
+ /// to pass in the current working directory as an argument.
+
+ std::string abspath(const std::string & path, const std::string & cwd);
+ std::string abspath_nt(const std::string & path, const std::string & cwd);
+ std::string abspath_posix(const std::string & path, const std::string & cwd);
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Join one or more path components intelligently. If any component is an absolute
+ /// path, all previous components (on Windows, including the previous drive letter, if there
+ /// was one) are thrown away, and joining continues. The return value is the concatenation of
+ /// path1, and optionally path2, etc., with exactly one directory separator (os.sep) inserted
+ /// between components, unless path2 is empty. Note that on Windows, since there is a current
+ /// directory for each drive, os.path.join("c:", "foo") represents a path relative to the
+ /// current directory on drive C: (c:foo), not c:\foo.
+
+ /// This dispatches based on the compilation OS
+ std::string join(const std::string & path1, const std::string & path2);
+ std::string join_nt(const std::string & path1, const std::string & path2);
+ std::string join_posix(const std::string & path1, const std::string & path2);
+
+ std::string join(const std::vector< std::string > & paths);
+ std::string join_nt(const std::vector< std::string > & paths);
+ std::string join_posix(const std::vector< std::string > & paths);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Normalize a pathname. This collapses redundant separators and up-level references
+ /// so that A//B, A/B/, A/./B and A/foo/../B all become A/B. It does not normalize the case
+ /// (use normcase() for that). On Windows, it converts forward slashes to backward slashes.
+ /// It should be understood that this may change the meaning of the path if it contains
+ /// symbolic links!
+
+ std::string normpath(const std::string & path);
+ std::string normpath_nt(const std::string & path);
+ std::string normpath_posix(const std::string & path);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Split the pathname path into a pair, (head, tail) where tail is the last pathname
+ /// component and head is everything leading up to that. The tail part will never contain a
+ /// slash; if path ends in a slash, tail will be empty. If there is no slash in path, head
+ /// will be empty. If path is empty, both head and tail are empty. Trailing slashes are
+ /// stripped from head unless it is the root (one or more slashes only). In all cases,
+ /// join(head, tail) returns a path to the same location as path (but the strings may
+ /// differ).
+
+ void split(std::string & head, std::string & tail, const std::string & path);
+ void split_nt(std::string & head, std::string & tail, const std::string & path);
+ void split_posix(std::string & head, std::string & tail, const std::string & path);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Split the pathname path into a pair (drive, tail) where drive is either a drive
+ /// specification or the empty string. On systems which do not use drive specifications,
+ /// drive will always be the empty string. In all cases, drive + tail will be the same as
+ /// path.
+
+ void splitdrive(std::string & drivespec, std::string & pathspec, const std::string & path);
+ void splitdrive_nt(std::string & drivespec, std::string & pathspec, const std::string & p);
+ void splitdrive_posix(std::string & drivespec, std::string & pathspec, const std::string & path);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /// @brief Split the pathname path into a pair (root, ext) such that root + ext == path, and
+ /// ext is empty or begins with a period and contains at most one period. Leading periods on
+ /// the basename are ignored; splitext('.cshrc') returns ('.cshrc', '').
+
+ void splitext(std::string & root, std::string & ext, const std::string & path);
+ void splitext_nt(std::string & root, std::string & ext, const std::string & path);
+ void splitext_posix(std::string & root, std::string & ext, const std::string & path);
+
+ ///
+ /// @ }
+ ///
+} // namespace path
+} // namespace os
+
+} // namespace pystring
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/core_tests/CMakeLists.txt b/src/core_tests/CMakeLists.txt
new file mode 100644
index 0000000..de56210
--- /dev/null
+++ b/src/core_tests/CMakeLists.txt
@@ -0,0 +1,51 @@
+###############################################################################
+### CORE UNIT TESTS ###
+
+add_definitions("-DOCIO_UNIT_TEST")
+
+include_directories(
+ ${CMAKE_SOURCE_DIR}/export/
+ ${CMAKE_BINARY_DIR}/export/
+ ${EXTERNAL_INCLUDE_DIRS}
+ ${CMAKE_SOURCE_DIR}/ext/oiio/src/include
+ )
+
+file( GLOB_RECURSE core_test_src_files "${CMAKE_SOURCE_DIR}/src/core/*.cpp" )
+
+add_executable(ocio_core_tests ${core_test_src_files})
+
+if(USE_EXTERNAL_TINYXML)
+ target_link_libraries(ocio_core_tests ${TINYXML_LIBRARIES})
+else(USE_EXTERNAL_TINYXML)
+ add_dependencies(ocio_core_tests tinyxml)
+endif(USE_EXTERNAL_TINYXML)
+
+if(USE_EXTERNAL_YAML)
+ target_link_libraries(ocio_core_tests ${YAML_CPP_LIBRARIES})
+else(USE_EXTERNAL_YAML)
+ add_dependencies(ocio_core_tests YAML_CPP_LOCAL)
+endif(USE_EXTERNAL_YAML)
+
+set_target_properties(ocio_core_tests PROPERTIES
+ COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}"
+ LINK_FLAGS "${EXTERNAL_LINK_FLAGS}")
+if(WIN32)
+ target_link_libraries(ocio_core_tests
+ debug ${EXTERNAL_DEBUG_LIBRARIES}
+ optimized ${EXTERNAL_OPTIMIZED_LIBRARIES}
+ general ${EXTERNAL_GENERAL_LIBRARIES})
+else()
+ target_link_libraries(ocio_core_tests ${EXTERNAL_GENERAL_LIBRARIES})
+endif()
+
+###############################################################################
+### CTEST ###
+
+set(OCIO_TEST_AREA ${CMAKE_CURRENT_BINARY_DIR})
+
+message(STATUS "Create ocio_core_tests.sh.in from ocio_core_tests.sh")
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ocio_core_tests.sh.in
+ ${CMAKE_CURRENT_BINARY_DIR}/ocio_core_tests.sh @ONLY)
+
+add_test(NAME ocio_core_tests
+ COMMAND /bin/sh ${CMAKE_CURRENT_BINARY_DIR}/ocio_core_tests.sh)
diff --git a/src/core_tests/ocio_core_tests.sh.in b/src/core_tests/ocio_core_tests.sh.in
new file mode 100644
index 0000000..5667a42
--- /dev/null
+++ b/src/core_tests/ocio_core_tests.sh.in
@@ -0,0 +1,8 @@
+#!/bin/sh
+OCIO_TEST_AREA=@OCIO_TEST_AREA@ \
+OCIO_DATA_ROOT=@OCIO_TEST_AREA@/test_search \
+OCIO_TEST1=foobar \
+OCIO_JOB=meatballs \
+OCIO_SEQ=cheesecake \
+OCIO_SHOT=mb-cc-001 \
+@CMAKE_CURRENT_BINARY_DIR@/ocio_core_tests --log_level=test_suite; \ No newline at end of file
diff --git a/src/jniglue/CMakeLists.txt b/src/jniglue/CMakeLists.txt
new file mode 100644
index 0000000..aedb514
--- /dev/null
+++ b/src/jniglue/CMakeLists.txt
@@ -0,0 +1,92 @@
+
+include_directories(
+ ${JNI_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/export/
+ ${CMAKE_BINARY_DIR}/export/
+)
+
+set(JNIOCIO_CLASSES
+ # Core
+ org.OpenColorIO.ExceptionBase
+ org.OpenColorIO.ExceptionMissingFile
+ org.OpenColorIO.Globals
+ org.OpenColorIO.Config
+ org.OpenColorIO.ColorSpace
+ org.OpenColorIO.Processor
+ org.OpenColorIO.GpuShaderDesc
+ org.OpenColorIO.Context
+ org.OpenColorIO.Look
+ org.OpenColorIO.ImageDesc
+ org.OpenColorIO.Transform
+ org.OpenColorIO.PackedImageDesc
+ org.OpenColorIO.PlanarImageDesc
+ org.OpenColorIO.Baker
+ # Enums
+ org.OpenColorIO.LoggingLevel
+ org.OpenColorIO.ColorSpaceDirection
+ org.OpenColorIO.TransformDirection
+ org.OpenColorIO.Interpolation
+ org.OpenColorIO.BitDepth
+ org.OpenColorIO.Allocation
+ org.OpenColorIO.GpuLanguage
+ # Transforms
+ org.OpenColorIO.AllocationTransform
+ org.OpenColorIO.CDLTransform
+ org.OpenColorIO.ColorSpaceTransform
+ org.OpenColorIO.DisplayTransform
+ org.OpenColorIO.ExponentTransform
+ org.OpenColorIO.FileTransform
+ org.OpenColorIO.GroupTransform
+ org.OpenColorIO.LogTransform
+ org.OpenColorIO.LookTransform
+ org.OpenColorIO.MatrixTransform
+ org.OpenColorIO.TruelightTransform
+)
+
+file(GLOB JNIOCIO_JAVAS "org/OpenColorIO/*.java")
+
+message(STATUS "Creating Jar Manifest.txt")
+configure_file(${CMAKE_SOURCE_DIR}/src/jniglue/Manifest.txt.in
+ ${CMAKE_CURRENT_BINARY_DIR}/Manifest.txt @ONLY)
+
+message(STATUS "Creating LoadLibrary.java")
+configure_file(${CMAKE_SOURCE_DIR}/src/jniglue/LoadLibrary.java.in
+ ${CMAKE_CURRENT_BINARY_DIR}/LoadLibrary.java @ONLY)
+list(APPEND JNIOCIO_JAVAS ${CMAKE_CURRENT_BINARY_DIR}/LoadLibrary.java)
+
+set(JNIOCIO_HEADERS)
+set(JNIOCIO_H_INCLUDE "/* DO NOT EDIT THIS FILE - it is machine generated */\n\n")
+foreach(_CLASS ${JNIOCIO_CLASSES})
+ string(REPLACE "." "_" _CLASS_H ${_CLASS})
+ set(_CLASS_H "${_CLASS_H}.h")
+ set(JNIOCIO_HEADERS ${JNIOCIO_HEADERS} "${_CLASS_H}")
+ set(JNIOCIO_H_INCLUDE "${JNIOCIO_H_INCLUDE}#include \"${_CLASS_H}\"\n")
+endforeach()
+message(STATUS "Creating OpenColorIOJNI.h that includes all the ocio jni headers")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/OpenColorIOJNI.h" "${JNIOCIO_H_INCLUDE}")
+
+set(JNIOCIO_JAR "${CMAKE_CURRENT_BINARY_DIR}/OpenColorIO-${OCIO_VERSION}.jar")
+add_custom_command(OUTPUT ${JNIOCIO_HEADERS}
+ COMMAND cmake -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/org/OpenColorIO
+ COMMAND ${Java_JAVAC_EXECUTABLE} -cp ${CMAKE_CURRENT_BINARY_DIR} -d ${CMAKE_CURRENT_BINARY_DIR} ${JNIOCIO_JAVAS}
+ COMMAND ${Java_JAVAH_EXECUTABLE} -jni -force ${JNIOCIO_CLASSES}
+ COMMAND ${Java_JAR_EXECUTABLE} vcfm ${JNIOCIO_JAR} Manifest.txt org
+ IMPLICIT_DEPENDS ${JNIOCIO_JAVAS}
+ COMMENT "Compiling .java files, packaged .jar and creating jni C headers")
+
+file(GLOB JNIOCIO_SRC "*.cpp")
+add_library(OpenColorIO-JNI SHARED ${JNIOCIO_SRC} ${JNIOCIO_HEADERS})
+set_target_properties(OpenColorIO-JNI PROPERTIES
+ VERSION ${OCIO_VERSION}
+ SOVERSION ${SOVERSION})
+if(OCIO_STATIC_JNIGLUE)
+ target_link_libraries(OpenColorIO-JNI OpenColorIO_STATIC)
+else()
+ target_link_libraries(OpenColorIO-JNI OpenColorIO)
+endif()
+
+add_subdirectory(tests)
+
+install(TARGETS OpenColorIO-JNI DESTINATION ${CMAKE_INSTALL_EXEC_PREFIX}/lib${LIB_SUFFIX})
+install(FILES ${JNIOCIO_JAR} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/ocio/)
diff --git a/src/jniglue/JNIBaker.cpp b/src/jniglue/JNIBaker.cpp
new file mode 100644
index 0000000..c838b70
--- /dev/null
+++ b/src/jniglue/JNIBaker.cpp
@@ -0,0 +1,264 @@
+/*
+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 <string>
+#include <sstream>
+
+#include "OpenColorIO/OpenColorIO.h"
+#include "OpenColorIOJNI.h"
+#include "JNIUtil.h"
+OCIO_NAMESPACE_USING
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Baker_dispose(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ DisposeJOCIO<BakerJNI>(env, self);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Baker_Create(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJObject<BakerRcPtr, BakerJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Baker"), Baker::Create());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Baker_createEditableCopy(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstBakerRcPtr bake = GetConstJOCIO<ConstBakerRcPtr, BakerJNI>(env, self);
+ return BuildJObject<BakerRcPtr, BakerJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Baker"), bake->createEditableCopy());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Baker_setConfig(JNIEnv * env, jobject self, jobject config)
+{
+ OCIO_JNITRY_ENTER()
+ BakerRcPtr bake = GetEditableJOCIO<BakerRcPtr, BakerJNI>(env, self);
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, config);
+ bake->setConfig(cfg);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Baker_getConfig(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstBakerRcPtr bake = GetConstJOCIO<ConstBakerRcPtr, BakerJNI>(env, self);
+ return BuildJConstObject<ConstConfigRcPtr, ConfigJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Config"), bake->getConfig());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Baker_setFormat(JNIEnv * env, jobject self, jstring formatName)
+{
+ OCIO_JNITRY_ENTER()
+ BakerRcPtr bake = GetEditableJOCIO<BakerRcPtr, BakerJNI>(env, self);
+ bake->setFormat(GetJStringValue(env, formatName)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Baker_getFormat(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstBakerRcPtr bake = GetConstJOCIO<ConstBakerRcPtr, BakerJNI>(env, self);
+ return env->NewStringUTF(bake->getFormat());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Baker_setType(JNIEnv * env, jobject self, jstring type)
+{
+ OCIO_JNITRY_ENTER()
+ BakerRcPtr bake = GetEditableJOCIO<BakerRcPtr, BakerJNI>(env, self);
+ bake->setType(GetJStringValue(env, type)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Baker_getType(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstBakerRcPtr bake = GetConstJOCIO<ConstBakerRcPtr, BakerJNI>(env, self);
+ return env->NewStringUTF(bake->getType());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Baker_setMetadata(JNIEnv * env, jobject self, jstring metadata)
+{
+ OCIO_JNITRY_ENTER()
+ BakerRcPtr bake = GetEditableJOCIO<BakerRcPtr, BakerJNI>(env, self);
+ bake->setMetadata(GetJStringValue(env, metadata)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Baker_getMetadata(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstBakerRcPtr bake = GetConstJOCIO<ConstBakerRcPtr, BakerJNI>(env, self);
+ return env->NewStringUTF(bake->getMetadata());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Baker_setInputSpace(JNIEnv * env, jobject self, jstring inputSpace)
+{
+ OCIO_JNITRY_ENTER()
+ BakerRcPtr bake = GetEditableJOCIO<BakerRcPtr, BakerJNI>(env, self);
+ bake->setInputSpace(GetJStringValue(env, inputSpace)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Baker_getInputSpace(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstBakerRcPtr bake = GetConstJOCIO<ConstBakerRcPtr, BakerJNI>(env, self);
+ return env->NewStringUTF(bake->getInputSpace());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Baker_setShaperSpace(JNIEnv * env, jobject self, jstring shaperSpace)
+{
+ OCIO_JNITRY_ENTER()
+ BakerRcPtr bake = GetEditableJOCIO<BakerRcPtr, BakerJNI>(env, self);
+ bake->setShaperSpace(GetJStringValue(env, shaperSpace)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Baker_getShaperSpace(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstBakerRcPtr bake = GetConstJOCIO<ConstBakerRcPtr, BakerJNI>(env, self);
+ return env->NewStringUTF(bake->getShaperSpace());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Baker_setTargetSpace(JNIEnv * env, jobject self, jstring targetSpace)
+{
+ OCIO_JNITRY_ENTER()
+ BakerRcPtr bake = GetEditableJOCIO<BakerRcPtr, BakerJNI>(env, self);
+ bake->setTargetSpace(GetJStringValue(env, targetSpace)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Baker_getTargetSpace(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstBakerRcPtr bake = GetConstJOCIO<ConstBakerRcPtr, BakerJNI>(env, self);
+ return env->NewStringUTF(bake->getTargetSpace());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Baker_setShaperSize(JNIEnv * env, jobject self, jint shapersize)
+{
+ OCIO_JNITRY_ENTER()
+ BakerRcPtr bake = GetEditableJOCIO<BakerRcPtr, BakerJNI>(env, self);
+ return bake->setShaperSize((int)shapersize);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jint JNICALL
+Java_org_OpenColorIO_Baker_getShaperSize(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstBakerRcPtr bake = GetConstJOCIO<ConstBakerRcPtr, BakerJNI>(env, self);
+ return (jint)bake->getShaperSize();
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Baker_setCubeSize(JNIEnv * env, jobject self, jint cubesize)
+{
+ OCIO_JNITRY_ENTER()
+ BakerRcPtr bake = GetEditableJOCIO<BakerRcPtr, BakerJNI>(env, self);
+ return bake->setCubeSize((int)cubesize);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jint JNICALL
+Java_org_OpenColorIO_Baker_getCubeSize(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstBakerRcPtr bake = GetConstJOCIO<ConstBakerRcPtr, BakerJNI>(env, self);
+ return (jint)bake->getCubeSize();
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Baker_bake(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstBakerRcPtr bake = GetConstJOCIO<ConstBakerRcPtr, BakerJNI>(env, self);
+ std::ostringstream os;
+ bake->bake(os);
+ return env->NewStringUTF(os.str().c_str());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jint JNICALL
+Java_org_OpenColorIO_Baker_getNumFormats(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstBakerRcPtr bake = GetConstJOCIO<ConstBakerRcPtr, BakerJNI>(env, self);
+ return (jint)bake->getNumFormats();
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Baker_getFormatNameByIndex(JNIEnv * env, jobject self, jint index)
+{
+ OCIO_JNITRY_ENTER()
+ ConstBakerRcPtr bake = GetConstJOCIO<ConstBakerRcPtr, BakerJNI>(env, self);
+ return env->NewStringUTF(bake->getFormatNameByIndex((int)index));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Baker_getFormatExtensionByIndex(JNIEnv * env, jobject self, jint index)
+{
+ OCIO_JNITRY_ENTER()
+ ConstBakerRcPtr bake = GetConstJOCIO<ConstBakerRcPtr, BakerJNI>(env, self);
+ return env->NewStringUTF(bake->getFormatExtensionByIndex((int)index));
+ OCIO_JNITRY_EXIT(NULL)
+}
diff --git a/src/jniglue/JNIColorSpace.cpp b/src/jniglue/JNIColorSpace.cpp
new file mode 100644
index 0000000..e540ad2
--- /dev/null
+++ b/src/jniglue/JNIColorSpace.cpp
@@ -0,0 +1,239 @@
+/*
+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 <string>
+#include <sstream>
+#include <vector>
+
+#include "OpenColorIO/OpenColorIO.h"
+#include "OpenColorIOJNI.h"
+#include "JNIUtil.h"
+OCIO_NAMESPACE_USING
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_ColorSpace_dispose(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ DisposeJOCIO<ColorSpaceJNI>(env, self);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_ColorSpace_Create(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJObject<ColorSpaceRcPtr, ColorSpaceJNI>(env, self,
+ env->FindClass("org/OpenColorIO/ColorSpace"), ColorSpace::Create());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_ColorSpace_createEditableCopy(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstColorSpaceRcPtr col = GetConstJOCIO<ConstColorSpaceRcPtr, ColorSpaceJNI>(env, self);
+ return BuildJObject<ColorSpaceRcPtr, ColorSpaceJNI>(env, self,
+ env->FindClass("org/OpenColorIO/ColorSpace"), col->createEditableCopy());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_ColorSpace_getName(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstColorSpaceRcPtr col = GetConstJOCIO<ConstColorSpaceRcPtr, ColorSpaceJNI>(env, self);
+ return env->NewStringUTF(col->getName());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_ColorSpace_setName(JNIEnv * env, jobject self, jstring name)
+{
+ OCIO_JNITRY_ENTER()
+ ColorSpaceRcPtr col = GetEditableJOCIO<ColorSpaceRcPtr, ColorSpaceJNI>(env, self);
+ col->setName(GetJStringValue(env, name)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_ColorSpace_getFamily(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstColorSpaceRcPtr col = GetConstJOCIO<ConstColorSpaceRcPtr, ColorSpaceJNI>(env, self);
+ return env->NewStringUTF(col->getFamily());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_ColorSpace_setFamily(JNIEnv * env, jobject self, jstring family)
+{
+ OCIO_JNITRY_ENTER()
+ ColorSpaceRcPtr col = GetEditableJOCIO<ColorSpaceRcPtr, ColorSpaceJNI>(env, self);
+ col->setFamily(GetJStringValue(env, family)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_ColorSpace_getEqualityGroup(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstColorSpaceRcPtr col = GetConstJOCIO<ConstColorSpaceRcPtr, ColorSpaceJNI>(env, self);
+ return env->NewStringUTF(col->getEqualityGroup());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_ColorSpace_setEqualityGroup(JNIEnv * env, jobject self, jstring equalityGroup)
+{
+ OCIO_JNITRY_ENTER()
+ ColorSpaceRcPtr col = GetEditableJOCIO<ColorSpaceRcPtr, ColorSpaceJNI>(env, self);
+ col->setEqualityGroup(GetJStringValue(env, equalityGroup)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_ColorSpace_getDescription(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstColorSpaceRcPtr col = GetConstJOCIO<ConstColorSpaceRcPtr, ColorSpaceJNI>(env, self);
+ return env->NewStringUTF(col->getDescription());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_ColorSpace_setDescription(JNIEnv * env, jobject self, jstring description)
+{
+ OCIO_JNITRY_ENTER()
+ ColorSpaceRcPtr col = GetEditableJOCIO<ColorSpaceRcPtr, ColorSpaceJNI>(env, self);
+ col->setDescription(GetJStringValue(env, description)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_ColorSpace_getBitDepth(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstColorSpaceRcPtr col = GetConstJOCIO<ConstColorSpaceRcPtr, ColorSpaceJNI>(env, self);
+ return BuildJEnum(env, "org/OpenColorIO/BitDepth", col->getBitDepth());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_ColorSpace_setBitDepth(JNIEnv * env, jobject self, jobject bitDepth)
+{
+ OCIO_JNITRY_ENTER()
+ ColorSpaceRcPtr col = GetEditableJOCIO<ColorSpaceRcPtr, ColorSpaceJNI>(env, self);
+ col->setBitDepth(GetJEnum<BitDepth>(env, bitDepth));
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_OpenColorIO_ColorSpace_isData(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstColorSpaceRcPtr col = GetConstJOCIO<ConstColorSpaceRcPtr, ColorSpaceJNI>(env, self);
+ return (jboolean)col->isData();
+ OCIO_JNITRY_EXIT(false)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_ColorSpace_setIsData(JNIEnv * env, jobject self, jboolean isData)
+{
+ OCIO_JNITRY_ENTER()
+ ColorSpaceRcPtr col = GetEditableJOCIO<ColorSpaceRcPtr, ColorSpaceJNI>(env, self);
+ col->setIsData((bool)isData);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_ColorSpace_getAllocation(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstColorSpaceRcPtr col = GetConstJOCIO<ConstColorSpaceRcPtr, ColorSpaceJNI>(env, self);
+ return BuildJEnum(env, "org/OpenColorIO/Allocation", col->getAllocation());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_ColorSpace_setAllocation(JNIEnv * env, jobject self, jobject allocation)
+{
+ OCIO_JNITRY_ENTER()
+ ColorSpaceRcPtr col = GetEditableJOCIO<ColorSpaceRcPtr, ColorSpaceJNI>(env, self);
+ col->setAllocation(GetJEnum<Allocation>(env, allocation));
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jint JNICALL
+Java_org_OpenColorIO_ColorSpace_getAllocationNumVars(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstColorSpaceRcPtr col = GetConstJOCIO<ConstColorSpaceRcPtr, ColorSpaceJNI>(env, self);
+ return (jint)col->getAllocationNumVars();
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_ColorSpace_getAllocationVars(JNIEnv * env, jobject self, jfloatArray vars)
+{
+ OCIO_JNITRY_ENTER()
+ ConstColorSpaceRcPtr col = GetConstJOCIO<ConstColorSpaceRcPtr, ColorSpaceJNI>(env, self);
+ col->getAllocationVars(SetJFloatArrayValue(env, vars, "vars", col->getAllocationNumVars())());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_ColorSpace_setAllocationVars(JNIEnv * env, jobject self, jint numvars, jfloatArray vars)
+{
+ OCIO_JNITRY_ENTER()
+ ColorSpaceRcPtr col = GetEditableJOCIO<ColorSpaceRcPtr, ColorSpaceJNI>(env, self);
+ col->setAllocationVars((int)numvars, GetJFloatArrayValue(env, vars, "vars", numvars)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_ColorSpace_getTransform(JNIEnv * env, jobject self, jobject dir)
+{
+ OCIO_JNITRY_ENTER()
+ ConstColorSpaceRcPtr col = GetConstJOCIO<ConstColorSpaceRcPtr, ColorSpaceJNI>(env, self);
+ ColorSpaceDirection cd = GetJEnum<ColorSpaceDirection>(env, dir);
+ ConstTransformRcPtr tr = col->getTransform(cd);
+ return BuildJConstObject<ConstTransformRcPtr, TransformJNI>(env, self,
+ env->FindClass(GetOCIOTClass(tr)), tr);
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_ColorSpace_setTransform(JNIEnv * env, jobject self, jobject transform, jobject dir)
+{
+ OCIO_JNITRY_ENTER()
+ ColorSpaceRcPtr col = GetEditableJOCIO<ColorSpaceRcPtr, ColorSpaceJNI>(env, self);
+ ColorSpaceDirection cd = GetJEnum<ColorSpaceDirection>(env, dir);
+ ConstTransformRcPtr tran = GetConstJOCIO<ConstTransformRcPtr, TransformJNI>(env, transform);
+ col->setTransform(tran, cd);
+ OCIO_JNITRY_EXIT()
+}
diff --git a/src/jniglue/JNIConfig.cpp b/src/jniglue/JNIConfig.cpp
new file mode 100644
index 0000000..fa3873a
--- /dev/null
+++ b/src/jniglue/JNIConfig.cpp
@@ -0,0 +1,607 @@
+/*
+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 <string>
+#include <sstream>
+#include <vector>
+
+#include "OpenColorIO/OpenColorIO.h"
+#include "OpenColorIOJNI.h"
+#include "JNIUtil.h"
+OCIO_NAMESPACE_USING
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Config_dispose(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ DisposeJOCIO<ConfigJNI>(env, self);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Config_Create(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJObject<ConfigRcPtr, ConfigJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Config"), Config::Create());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Config_CreateFromEnv(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJConstObject<ConstConfigRcPtr, ConfigJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Config"), Config::CreateFromEnv());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Config_CreateFromFile(JNIEnv * env, jobject self, jstring filename)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJConstObject<ConstConfigRcPtr, ConfigJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Config"),
+ Config::CreateFromFile(GetJStringValue(env, filename)()));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Config_CreateFromStream(JNIEnv * env, jobject self, jstring istream)
+{
+ OCIO_JNITRY_ENTER()
+ std::istringstream is;
+ is.str(std::string(GetJStringValue(env, istream)()));
+ return BuildJConstObject<ConstConfigRcPtr, ConfigJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Config"), Config::CreateFromStream(is));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Config_createEditableCopy(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return BuildJObject<ConfigRcPtr, ConfigJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Config"), cfg->createEditableCopy());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Config_sanityCheck(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ cfg->sanityCheck();
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Config_getDescription(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return env->NewStringUTF(cfg->getDescription());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Config_setDescription(JNIEnv * env, jobject self, jstring description)
+{
+ OCIO_JNITRY_ENTER()
+ ConfigRcPtr cfg = GetEditableJOCIO<ConfigRcPtr, ConfigJNI>(env, self);
+ cfg->setDescription(GetJStringValue(env, description)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Config_serialize(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ std::ostringstream os;
+ cfg->serialize(os);
+ return env->NewStringUTF(os.str().c_str());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Config_getCacheID__(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return env->NewStringUTF(cfg->getCacheID());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Config_getCacheID__Lorg_OpenColorIO_Context_2(JNIEnv * env, jobject self, jobject context)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ ConstContextRcPtr con = GetConstJOCIO<ConstContextRcPtr, ContextJNI>(env, context);
+ return env->NewStringUTF(cfg->getCacheID(con));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Config_getCurrentContext(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return BuildJConstObject<ConstContextRcPtr, ContextJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Context"), cfg->getCurrentContext());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Config_getSearchPath(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return env->NewStringUTF(cfg->getSearchPath());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Config_setSearchPath(JNIEnv * env, jobject self, jstring path)
+{
+ OCIO_JNITRY_ENTER()
+ ConfigRcPtr cfg = GetEditableJOCIO<ConfigRcPtr, ConfigJNI>(env, self);
+ cfg->setSearchPath(GetJStringValue(env, path)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Config_getWorkingDir(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return env->NewStringUTF(cfg->getWorkingDir());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Config_setWorkingDir(JNIEnv * env, jobject self, jstring dirname)
+{
+ OCIO_JNITRY_ENTER()
+ ConfigRcPtr cfg = GetEditableJOCIO<ConfigRcPtr, ConfigJNI>(env, self);
+ cfg->setWorkingDir(GetJStringValue(env, dirname)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jint JNICALL
+Java_org_OpenColorIO_Config_getNumColorSpaces(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return (jint)cfg->getNumColorSpaces();
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Config_getColorSpaceNameByIndex(JNIEnv * env, jobject self, jint index)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return env->NewStringUTF(cfg->getColorSpaceNameByIndex((int)index));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Config_getColorSpace(JNIEnv * env, jobject self, jstring name)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return BuildJConstObject<ConstColorSpaceRcPtr, ColorSpaceJNI>(env, self,
+ env->FindClass("org/OpenColorIO/ColorSpace"),
+ cfg->getColorSpace(GetJStringValue(env, name)()));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jint JNICALL
+Java_org_OpenColorIO_Config_getIndexForColorSpace(JNIEnv * env, jobject self, jstring name)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return (jint)cfg->getIndexForColorSpace(GetJStringValue(env, name)());
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Config_addColorSpace(JNIEnv * env, jobject self, jobject cs)
+{
+ OCIO_JNITRY_ENTER()
+ ConfigRcPtr cfg = GetEditableJOCIO<ConfigRcPtr, ConfigJNI>(env, self);
+ ConstColorSpaceRcPtr space = GetConstJOCIO<ConstColorSpaceRcPtr, ColorSpaceJNI>(env, cs);
+ cfg->addColorSpace(space);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Config_clearColorSpaces(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConfigRcPtr cfg = GetEditableJOCIO<ConfigRcPtr, ConfigJNI>(env, self);
+ cfg->clearColorSpaces();
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Config_parseColorSpaceFromString(JNIEnv * env, jobject self, jstring str)
+{
+ OCIO_JNITRY_ENTER()
+ ConfigRcPtr cfg = GetEditableJOCIO<ConfigRcPtr, ConfigJNI>(env, self);
+ return env->NewStringUTF(cfg->parseColorSpaceFromString(GetJStringValue(env, str)()));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_OpenColorIO_Config_isStrictParsingEnabled(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return (jboolean)cfg->isStrictParsingEnabled();
+ OCIO_JNITRY_EXIT(false)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Config_setStrictParsingEnabled(JNIEnv * env, jobject self, jboolean enabled)
+{
+ OCIO_JNITRY_ENTER()
+ ConfigRcPtr cfg = GetEditableJOCIO<ConfigRcPtr, ConfigJNI>(env, self);
+ cfg->setStrictParsingEnabled((bool)enabled);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Config_setRole(JNIEnv * env, jobject self, jstring role, jstring colorSpaceName)
+{
+ OCIO_JNITRY_ENTER()
+ ConfigRcPtr cfg = GetEditableJOCIO<ConfigRcPtr, ConfigJNI>(env, self);
+ cfg->setRole(GetJStringValue(env, role)(), GetJStringValue(env, colorSpaceName)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jint JNICALL
+Java_org_OpenColorIO_Config_getNumRoles(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return (jint)cfg->getNumRoles();
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_OpenColorIO_Config_hasRole(JNIEnv * env, jobject self, jstring role)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return (jboolean)cfg->hasRole(GetJStringValue(env, role)());
+ OCIO_JNITRY_EXIT(false)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Config_getRoleName(JNIEnv * env, jobject self, jint index)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return env->NewStringUTF(cfg->getRoleName((int)index));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Config_getDefaultDisplay(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return env->NewStringUTF(cfg->getDefaultDisplay());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jint JNICALL
+Java_org_OpenColorIO_Config_getNumDisplays(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return (jint)cfg->getNumDisplays();
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Config_getDisplay(JNIEnv * env, jobject self, jint index)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return env->NewStringUTF(cfg->getDisplay((int)index));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Config_getDefaultView(JNIEnv * env, jobject self, jstring display)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return env->NewStringUTF(cfg->getDefaultView(GetJStringValue(env, display)()));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jint JNICALL
+Java_org_OpenColorIO_Config_getNumViews(JNIEnv * env, jobject self, jstring display)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return (jint)cfg->getNumViews(GetJStringValue(env, display)());
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Config_getView(JNIEnv * env, jobject self, jstring display, jint index)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return env->NewStringUTF(cfg->getView(GetJStringValue(env, display)(), (int)index));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Config_getDisplayColorSpaceName(JNIEnv * env, jobject self, jstring display, jstring view)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return env->NewStringUTF(cfg->getDisplayColorSpaceName(GetJStringValue(env, display)(),
+ GetJStringValue(env, view)()));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Config_getDisplayLooks(JNIEnv * env, jobject self, jstring display, jstring view)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return env->NewStringUTF(cfg->getDisplayLooks(GetJStringValue(env, display)(),
+ GetJStringValue(env, view)()));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+// TODO: seems that 4 string params causes a memory error in the JNI layer?
+/*
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Config_addDisplay(JNIEnv * env, jobject self, jstring display, jstring view, jstring colorSpaceName, jstring looks)
+{
+ OCIO_JNITRY_ENTER()
+ ConfigRcPtr cfg = GetEditableJOCIO<ConfigRcPtr, ConfigJNI>(env, self);
+ cfg->addDisplay(GetJStringValue(env, display)(),
+ GetJStringValue(env, view)(),
+ GetJStringValue(env, colorSpaceName)(),
+ GetJStringValue(env, looks)());
+
+ OCIO_JNITRY_EXIT()
+}
+*/
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Config_clearDisplays(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConfigRcPtr cfg = GetEditableJOCIO<ConfigRcPtr, ConfigJNI>(env, self);
+ cfg->clearDisplays();
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Config_setActiveDisplays(JNIEnv * env, jobject self, jstring displays)
+{
+ OCIO_JNITRY_ENTER()
+ ConfigRcPtr cfg = GetEditableJOCIO<ConfigRcPtr, ConfigJNI>(env, self);
+ cfg->setActiveDisplays(GetJStringValue(env, displays)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Config_getActiveDisplays(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return env->NewStringUTF(cfg->getActiveDisplays());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Config_setActiveViews(JNIEnv * env, jobject self, jstring views)
+{
+ OCIO_JNITRY_ENTER()
+ ConfigRcPtr cfg = GetEditableJOCIO<ConfigRcPtr, ConfigJNI>(env, self);
+ cfg->setActiveViews(GetJStringValue(env, views)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Config_getActiveViews(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return env->NewStringUTF(cfg->getActiveViews());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Config_getDefaultLumaCoefs(JNIEnv * env, jobject self, jfloatArray rgb)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ cfg->getDefaultLumaCoefs(SetJFloatArrayValue(env, rgb, "rgb", 3)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Config_setDefaultLumaCoefs(JNIEnv * env, jobject self, jfloatArray rgb)
+{
+ OCIO_JNITRY_ENTER()
+ ConfigRcPtr cfg = GetEditableJOCIO<ConfigRcPtr, ConfigJNI>(env, self);
+ cfg->setDefaultLumaCoefs(GetJFloatArrayValue(env, rgb, "rgb", 3)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Config_getLook(JNIEnv * env, jobject self, jstring name)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return BuildJConstObject<ConstLookRcPtr, LookJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Look"), cfg->getLook(GetJStringValue(env, name)()));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jint JNICALL
+Java_org_OpenColorIO_Config_getNumLooks(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return (jint)cfg->getNumLooks();
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Config_getLookNameByIndex(JNIEnv * env, jobject self, jint index)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return env->NewStringUTF(cfg->getLookNameByIndex((int)index));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Config_addLook(JNIEnv * env, jobject self, jobject look)
+{
+ OCIO_JNITRY_ENTER()
+ ConfigRcPtr cfg = GetEditableJOCIO<ConfigRcPtr, ConfigJNI>(env, self);
+ ConstLookRcPtr lok = GetConstJOCIO<ConstLookRcPtr, LookJNI>(env, look);
+ cfg->addLook(lok);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Config_clearLooks(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConfigRcPtr cfg = GetEditableJOCIO<ConfigRcPtr, ConfigJNI>(env, self);
+ cfg->clearLooks();
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Config_getProcessor__Lorg_OpenColorIO_Context_2Lorg_OpenColorIO_ColorSpace_2Lorg_OpenColorIO_ColorSpace_2
+ (JNIEnv * env, jobject self, jobject context, jobject srcColorSpace, jobject dstColorSpace)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ ConstContextRcPtr con = GetConstJOCIO<ConstContextRcPtr, ContextJNI>(env, context);
+ ConstColorSpaceRcPtr src = GetConstJOCIO<ConstColorSpaceRcPtr, ColorSpaceJNI>(env, srcColorSpace);
+ ConstColorSpaceRcPtr dst = GetConstJOCIO<ConstColorSpaceRcPtr, ColorSpaceJNI>(env, dstColorSpace);
+ return BuildJConstObject<ConstProcessorRcPtr, ProcessorJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Processor"), cfg->getProcessor(con, src, dst));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Config_getProcessor__Lorg_OpenColorIO_ColorSpace_2Lorg_OpenColorIO_ColorSpace_2
+ (JNIEnv * env, jobject self, jobject srcColorSpace, jobject dstColorSpace)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ ConstColorSpaceRcPtr src = GetConstJOCIO<ConstColorSpaceRcPtr, ColorSpaceJNI>(env, srcColorSpace);
+ ConstColorSpaceRcPtr dst = GetConstJOCIO<ConstColorSpaceRcPtr, ColorSpaceJNI>(env, dstColorSpace);
+ return BuildJConstObject<ConstProcessorRcPtr, ProcessorJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Processor"), cfg->getProcessor(src, dst));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Config_getProcessor__Ljava_lang_String_2Ljava_lang_String_2
+ (JNIEnv * env, jobject self, jstring srcName, jstring dstName)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return BuildJConstObject<ConstProcessorRcPtr, ProcessorJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Processor"), cfg->getProcessor(
+ GetJStringValue(env, srcName)(), GetJStringValue(env, dstName)()));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Config_getProcessor__Lorg_OpenColorIO_Context_2Ljava_lang_String_2Ljava_lang_String_2
+ (JNIEnv * env, jobject self, jobject context, jstring srcName, jstring dstName)
+{
+ OCIO_JNITRY_ENTER()
+ ConstContextRcPtr con = GetConstJOCIO<ConstContextRcPtr, ContextJNI>(env, context);
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ return BuildJConstObject<ConstProcessorRcPtr, ProcessorJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Processor"), cfg->getProcessor(con,
+ GetJStringValue(env, srcName)(), GetJStringValue(env, dstName)()));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Config_getProcessor__Lorg_OpenColorIO_Transform_2
+ (JNIEnv * env, jobject self, jobject transform)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ ConstTransformRcPtr tran = GetConstJOCIO<ConstTransformRcPtr, TransformJNI>(env, transform);
+ return BuildJConstObject<ConstProcessorRcPtr, ProcessorJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Processor"), cfg->getProcessor(tran));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Config_getProcessor__Lorg_OpenColorIO_Transform_2Lorg_OpenColorIO_TransformDirection_2
+ (JNIEnv * env, jobject self, jobject transform, jobject direction)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ ConstTransformRcPtr tran = GetConstJOCIO<ConstTransformRcPtr, TransformJNI>(env, transform);
+ TransformDirection dir = GetJEnum<TransformDirection>(env, direction);
+ return BuildJConstObject<ConstProcessorRcPtr, ProcessorJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Processor"), cfg->getProcessor(tran, dir));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Config_getProcessor__Lorg_OpenColorIO_Context_2Lorg_OpenColorIO_Transform_2Lorg_OpenColorIO_TransformDirection_2
+ (JNIEnv * env, jobject self, jobject context, jobject transform, jobject direction)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, self);
+ ConstContextRcPtr con = GetConstJOCIO<ConstContextRcPtr, ContextJNI>(env, context);
+ ConstTransformRcPtr tran = GetConstJOCIO<ConstTransformRcPtr, TransformJNI>(env, transform);
+ TransformDirection dir = GetJEnum<TransformDirection>(env, direction);
+ return BuildJConstObject<ConstProcessorRcPtr, ProcessorJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Processor"), cfg->getProcessor(con, tran, dir));
+ OCIO_JNITRY_EXIT(NULL)
+}
diff --git a/src/jniglue/JNIContext.cpp b/src/jniglue/JNIContext.cpp
new file mode 100644
index 0000000..e1fcffd
--- /dev/null
+++ b/src/jniglue/JNIContext.cpp
@@ -0,0 +1,170 @@
+/*
+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 <string>
+#include <sstream>
+
+#include "OpenColorIO/OpenColorIO.h"
+#include "OpenColorIOJNI.h"
+#include "JNIUtil.h"
+OCIO_NAMESPACE_USING
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Context_dispose(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ DisposeJOCIO<ContextJNI>(env, self);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Context_Create(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJObject<ContextRcPtr, ContextJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Context"), Context::Create());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Context_createEditableCopy(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstContextRcPtr con = GetConstJOCIO<ConstContextRcPtr, ContextJNI>(env, self);
+ return BuildJObject<ContextRcPtr, ContextJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Context"), con->createEditableCopy());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Context_getCacheID(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstContextRcPtr con = GetConstJOCIO<ConstContextRcPtr, ContextJNI>(env, self);
+ return env->NewStringUTF(con->getCacheID());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Context_setSearchPath(JNIEnv * env, jobject self, jstring path)
+{
+ OCIO_JNITRY_ENTER()
+ ContextRcPtr con = GetEditableJOCIO<ContextRcPtr, ContextJNI>(env, self);
+ con->setSearchPath(GetJStringValue(env, path)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Context_getSearchPath(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstContextRcPtr con = GetConstJOCIO<ConstContextRcPtr, ContextJNI>(env, self);
+ return env->NewStringUTF(con->getSearchPath());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Context_setWorkingDir(JNIEnv * env, jobject self, jstring dirname)
+{
+ OCIO_JNITRY_ENTER()
+ ContextRcPtr con = GetEditableJOCIO<ContextRcPtr, ContextJNI>(env, self);
+ con->setWorkingDir(GetJStringValue(env, dirname)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Context_getWorkingDir(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstContextRcPtr con = GetConstJOCIO<ConstContextRcPtr, ContextJNI>(env, self);
+ return env->NewStringUTF(con->getWorkingDir());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Context_setStringVar(JNIEnv * env, jobject self, jstring name, jstring var)
+{
+ OCIO_JNITRY_ENTER()
+ ContextRcPtr con = GetEditableJOCIO<ContextRcPtr, ContextJNI>(env, self);
+ con->setStringVar(GetJStringValue(env, name)(), GetJStringValue(env, var)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Context_getStringVar(JNIEnv * env, jobject self, jstring name)
+{
+ OCIO_JNITRY_ENTER()
+ ConstContextRcPtr con = GetConstJOCIO<ConstContextRcPtr, ContextJNI>(env, self);
+ return env->NewStringUTF(con->getStringVar(GetJStringValue(env, name)()));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jint JNICALL
+Java_org_OpenColorIO_Context_getNumStringVars(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstContextRcPtr con = GetConstJOCIO<ConstContextRcPtr, ContextJNI>(env, self);
+ return (jint)con->getNumStringVars();
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Context_getStringVarNameByIndex(JNIEnv * env, jobject self, jint index)
+{
+ OCIO_JNITRY_ENTER()
+ ConstContextRcPtr con = GetConstJOCIO<ConstContextRcPtr, ContextJNI>(env, self);
+ return env->NewStringUTF(con->getStringVarNameByIndex((int)index));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Context_loadEnvironment(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ContextRcPtr con = GetEditableJOCIO<ContextRcPtr, ContextJNI>(env, self);
+ con->loadEnvironment();
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Context_resolveStringVar(JNIEnv * env, jobject self, jstring val)
+{
+ OCIO_JNITRY_ENTER()
+ ConstContextRcPtr con = GetConstJOCIO<ConstContextRcPtr, ContextJNI>(env, self);
+ return env->NewStringUTF(con->resolveStringVar(GetJStringValue(env, val)()));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Context_resolveFileLocation(JNIEnv * env, jobject self, jstring filename)
+{
+ OCIO_JNITRY_ENTER()
+ ConstContextRcPtr con = GetConstJOCIO<ConstContextRcPtr, ContextJNI>(env, self);
+ return env->NewStringUTF(con->resolveFileLocation(GetJStringValue(env, filename)()));
+ OCIO_JNITRY_EXIT(NULL)
+}
diff --git a/src/jniglue/JNIGlobals.cpp b/src/jniglue/JNIGlobals.cpp
new file mode 100644
index 0000000..9d57c84
--- /dev/null
+++ b/src/jniglue/JNIGlobals.cpp
@@ -0,0 +1,417 @@
+/*
+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 "OpenColorIOJNI.h"
+#include "JNIUtil.h"
+OCIO_NAMESPACE_USING
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Globals_create(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ jfieldID fid;
+ jclass wclass = env->GetObjectClass(self);
+ fid = env->GetFieldID(wclass, "ROLE_DEFAULT", "Ljava/lang/String;");
+ env->SetObjectField(self, fid, env->NewStringUTF(ROLE_DEFAULT));
+ fid = env->GetFieldID(wclass, "ROLE_REFERENCE", "Ljava/lang/String;");
+ env->SetObjectField(self, fid, env->NewStringUTF(ROLE_REFERENCE));
+ fid = env->GetFieldID(wclass, "ROLE_DATA", "Ljava/lang/String;");
+ env->SetObjectField(self, fid, env->NewStringUTF(ROLE_DATA));
+ fid = env->GetFieldID(wclass, "ROLE_COLOR_PICKING", "Ljava/lang/String;");
+ env->SetObjectField(self, fid, env->NewStringUTF(ROLE_COLOR_PICKING));
+ fid = env->GetFieldID(wclass, "ROLE_SCENE_LINEAR", "Ljava/lang/String;");
+ env->SetObjectField(self, fid, env->NewStringUTF(ROLE_SCENE_LINEAR));
+ fid = env->GetFieldID(wclass, "ROLE_COMPOSITING_LOG", "Ljava/lang/String;");
+ env->SetObjectField(self, fid, env->NewStringUTF(ROLE_COMPOSITING_LOG));
+ fid = env->GetFieldID(wclass, "ROLE_COLOR_TIMING", "Ljava/lang/String;");
+ env->SetObjectField(self, fid, env->NewStringUTF(ROLE_COLOR_TIMING));
+ fid = env->GetFieldID(wclass, "ROLE_TEXTURE_PAINT", "Ljava/lang/String;");
+ env->SetObjectField(self, fid, env->NewStringUTF(ROLE_TEXTURE_PAINT));
+ fid = env->GetFieldID(wclass, "ROLE_MATTE_PAINT", "Ljava/lang/String;");
+ env->SetObjectField(self, fid, env->NewStringUTF(ROLE_MATTE_PAINT));
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Globals_ClearAllCaches(JNIEnv * env, jobject)
+{
+ OCIO_JNITRY_ENTER()
+ ClearAllCaches();
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Globals_GetVersion(JNIEnv * env, jobject)
+{
+ OCIO_JNITRY_ENTER()
+ return env->NewStringUTF(GetVersion());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jint JNICALL
+Java_org_OpenColorIO_Globals_GetVersionHex(JNIEnv * env, jobject)
+{
+ OCIO_JNITRY_ENTER()
+ return (jint)GetVersionHex();
+ OCIO_JNITRY_EXIT(-1)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Globals_GetLoggingLevel(JNIEnv * env, jobject)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJEnum(env, "org/OpenColorIO/LoggingLevel", GetLoggingLevel());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Globals_SetLoggingLevel(JNIEnv * env, jobject, jobject level)
+{
+ OCIO_JNITRY_ENTER()
+ SetLoggingLevel(GetJEnum<LoggingLevel>(env, level));
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Globals_GetCurrentConfig(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ jobject obj = BuildJConstObject<ConstConfigRcPtr, ConfigJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Config"), GetCurrentConfig());
+ return obj;
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Globals_SetCurrentConfig(JNIEnv * env, jobject, jobject config)
+{
+ OCIO_JNITRY_ENTER()
+ ConstConfigRcPtr cfg = GetConstJOCIO<ConstConfigRcPtr, ConfigJNI>(env, config);
+ SetCurrentConfig(cfg);
+ OCIO_JNITRY_EXIT()
+}
+
+// Bool
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Globals_BoolToString(JNIEnv * env, jobject, jboolean val)
+{
+ OCIO_JNITRY_ENTER()
+ return env->NewStringUTF(BoolToString((bool)val));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_OpenColorIO_Globals_BoolFromString(JNIEnv * env, jobject, jstring s)
+{
+ OCIO_JNITRY_ENTER()
+ return (jboolean)BoolFromString(GetJStringValue(env, s)());
+ OCIO_JNITRY_EXIT(false)
+}
+
+// LoggingLevel
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_LoggingLevel_toString(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ return env->NewStringUTF(
+ LoggingLevelToString(GetJEnum<LoggingLevel>(env, self)));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_OpenColorIO_LoggingLevel_equals(JNIEnv * env, jobject self, jobject obj)
+{
+ OCIO_JNITRY_ENTER()
+ return GetJEnum<LoggingLevel>(env, self)
+ == GetJEnum<LoggingLevel>(env, obj);
+ OCIO_JNITRY_EXIT(false)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Globals_LoggingLevelToString(JNIEnv * env, jobject, jobject level)
+{
+ OCIO_JNITRY_ENTER()
+ return env->NewStringUTF(
+ LoggingLevelToString(GetJEnum<LoggingLevel>(env, level)));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Globals_LoggingLevelFromString(JNIEnv * env, jobject, jstring s)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJEnum(env, "org/OpenColorIO/LoggingLevel",
+ LoggingLevelFromString(GetJStringValue(env, s)()));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+// TransformDirection
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_TransformDirection_toString(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ return env->NewStringUTF(
+ TransformDirectionToString(GetJEnum<TransformDirection>(env, self)));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_OpenColorIO_TransformDirection_equals(JNIEnv * env, jobject self, jobject obj)
+{
+ OCIO_JNITRY_ENTER()
+ return GetJEnum<TransformDirection>(env, self)
+ == GetJEnum<TransformDirection>(env, obj);
+ OCIO_JNITRY_EXIT(false)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Globals_TransformDirectionToString(JNIEnv * env, jobject,
+ jobject dir)
+{
+ OCIO_JNITRY_ENTER()
+ return env->NewStringUTF(
+ TransformDirectionToString(GetJEnum<TransformDirection>(env, dir)));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Globals_TransformDirectionFromString(JNIEnv * env, jobject,
+ jstring s)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJEnum(env, "org/OpenColorIO/TransformDirection",
+ TransformDirectionFromString(GetJStringValue(env, s)()));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Globals_GetInverseTransformDirection(JNIEnv * env, jobject,
+ jobject dir) {
+ OCIO_JNITRY_ENTER()
+ return BuildJEnum(env, "org/OpenColorIO/TransformDirection",
+ GetInverseTransformDirection(GetJEnum<TransformDirection>(env, dir)));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Globals_CombineTransformDirections(JNIEnv * env, jobject,
+ jobject d1, jobject d2) {
+ OCIO_JNITRY_ENTER()
+ return BuildJEnum(env, "org/OpenColorIO/TransformDirection",
+ CombineTransformDirections(GetJEnum<TransformDirection>(env, d1),
+ GetJEnum<TransformDirection>(env, d2)));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+// ColorSpaceDirection
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_ColorSpaceDirection_toString(JNIEnv * env, jobject self) {
+ OCIO_JNITRY_ENTER()
+ return env->NewStringUTF(
+ ColorSpaceDirectionToString(GetJEnum<ColorSpaceDirection>(env, self)));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_OpenColorIO_ColorSpaceDirection_equals(JNIEnv * env, jobject self, jobject obj) {
+ OCIO_JNITRY_ENTER()
+ return GetJEnum<ColorSpaceDirection>(env, self)
+ == GetJEnum<ColorSpaceDirection>(env, obj);
+ OCIO_JNITRY_EXIT(false)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Globals_ColorSpaceDirectionToString(JNIEnv * env, jobject, jobject dir) {
+ OCIO_JNITRY_ENTER()
+ return env->NewStringUTF(
+ ColorSpaceDirectionToString(GetJEnum<ColorSpaceDirection>(env, dir)));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Globals_ColorSpaceDirectionFromString(JNIEnv * env, jobject, jstring s) {
+ OCIO_JNITRY_ENTER()
+ return BuildJEnum(env, "org/OpenColorIO/ColorSpaceDirection",
+ ColorSpaceDirectionFromString(GetJStringValue(env, s)()));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+// BitDepth
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_BitDepth_toString(JNIEnv * env, jobject self) {
+ OCIO_JNITRY_ENTER()
+ return env->NewStringUTF(
+ BitDepthToString(GetJEnum<BitDepth>(env, self)));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_OpenColorIO_BitDepth_equals(JNIEnv * env, jobject self, jobject obj) {
+ OCIO_JNITRY_ENTER()
+ return GetJEnum<BitDepth>(env, self)
+ == GetJEnum<BitDepth>(env, obj);
+ OCIO_JNITRY_EXIT(false)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Globals_BitDepthToString(JNIEnv * env, jobject, jobject bitDepth) {
+ OCIO_JNITRY_ENTER()
+ return env->NewStringUTF(
+ BitDepthToString(GetJEnum<BitDepth>(env, bitDepth)));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Globals_BitDepthFromString(JNIEnv * env, jobject, jstring s) {
+ OCIO_JNITRY_ENTER()
+ return BuildJEnum(env, "org/OpenColorIO/BitDepth",
+ BitDepthFromString(GetJStringValue(env, s)()));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_OpenColorIO_Globals_BitDepthIsFloat(JNIEnv * env, jobject, jobject bitDepth) {
+ OCIO_JNITRY_ENTER()
+ return (jboolean)BitDepthIsFloat(GetJEnum<BitDepth>(env, bitDepth));
+ OCIO_JNITRY_EXIT(false)
+}
+
+JNIEXPORT jint JNICALL
+Java_org_OpenColorIO_Globals_BitDepthToInt(JNIEnv * env, jobject, jobject bitDepth) {
+ OCIO_JNITRY_ENTER()
+ return (jint) BitDepthToInt(GetJEnum<BitDepth>(env, bitDepth));
+ OCIO_JNITRY_EXIT(-1)
+}
+
+// Allocation
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Allocation_toString(JNIEnv * env, jobject self) {
+ OCIO_JNITRY_ENTER()
+ return env->NewStringUTF(
+ AllocationToString(GetJEnum<Allocation>(env, self)));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_OpenColorIO_Allocation_equals(JNIEnv * env, jobject self, jobject obj) {
+ OCIO_JNITRY_ENTER()
+ return GetJEnum<Allocation>(env, self)
+ == GetJEnum<Allocation>(env, obj);
+ OCIO_JNITRY_EXIT(false)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Globals_AllocationToString(JNIEnv * env, jobject, jobject allocation) {
+ OCIO_JNITRY_ENTER()
+ return env->NewStringUTF(
+ AllocationToString(GetJEnum<Allocation>(env, allocation)));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Globals_AllocationFromString(JNIEnv * env, jobject, jstring s) {
+ OCIO_JNITRY_ENTER()
+ return BuildJEnum(env, "org/OpenColorIO/Allocation",
+ AllocationFromString(GetJStringValue(env, s)()));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+// Interpolation
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Interpolation_toString(JNIEnv * env, jobject self) {
+ OCIO_JNITRY_ENTER()
+ return env->NewStringUTF(
+ InterpolationToString(GetJEnum<Interpolation>(env, self)));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_OpenColorIO_Interpolation_equals(JNIEnv * env, jobject self, jobject obj) {
+ OCIO_JNITRY_ENTER()
+ return GetJEnum<Interpolation>(env, self)
+ == GetJEnum<Interpolation>(env, obj);
+ OCIO_JNITRY_EXIT(false)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Globals_InterpolationToString(JNIEnv * env, jobject, jobject interp) {
+ OCIO_JNITRY_ENTER()
+ return env->NewStringUTF(
+ InterpolationToString(GetJEnum<Interpolation>(env, interp)));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Globals_InterpolationFromString(JNIEnv * env, jobject, jstring s) {
+ OCIO_JNITRY_ENTER()
+ return BuildJEnum(env, "org/OpenColorIO/Interpolation",
+ InterpolationFromString(GetJStringValue(env, s)()));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+// GpuLanguage
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_GpuLanguage_toString(JNIEnv * env, jobject self) {
+ OCIO_JNITRY_ENTER()
+ return env->NewStringUTF(
+ GpuLanguageToString(GetJEnum<GpuLanguage>(env, self)));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_OpenColorIO_GpuLanguage_equals(JNIEnv * env, jobject self, jobject obj) {
+ OCIO_JNITRY_ENTER()
+ return GetJEnum<GpuLanguage>(env, self)
+ == GetJEnum<GpuLanguage>(env, obj);
+ OCIO_JNITRY_EXIT(false)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Globals_GpuLanguageToString(JNIEnv * env, jobject, jobject language) {
+ OCIO_JNITRY_ENTER()
+ return env->NewStringUTF(
+ GpuLanguageToString(GetJEnum<GpuLanguage>(env, language)));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Globals_GpuLanguageFromString(JNIEnv * env, jobject, jstring s) {
+ OCIO_JNITRY_ENTER()
+ return BuildJEnum(env, "org/OpenColorIO/GpuLanguage",
+ GpuLanguageFromString(GetJStringValue(env, s)()));
+ OCIO_JNITRY_EXIT(NULL)
+}
diff --git a/src/jniglue/JNIGpuShaderDesc.cpp b/src/jniglue/JNIGpuShaderDesc.cpp
new file mode 100644
index 0000000..21a57ea
--- /dev/null
+++ b/src/jniglue/JNIGpuShaderDesc.cpp
@@ -0,0 +1,125 @@
+/*
+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 <string>
+#include <sstream>
+
+#include "OpenColorIO/OpenColorIO.h"
+#include "OpenColorIOJNI.h"
+#include "JNIUtil.h"
+OCIO_NAMESPACE_USING
+
+namespace
+{
+
+void GpuShaderDesc_deleter(GpuShaderDesc* d)
+{
+ delete d;
+}
+
+}; // end anon namespace
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_GpuShaderDesc_create(JNIEnv * env, jobject self) {
+ OCIO_JNITRY_ENTER()
+ GpuShaderDescJNI * jnistruct = new GpuShaderDescJNI();
+ jnistruct->back_ptr = env->NewGlobalRef(self);
+ jnistruct->constcppobj = new ConstGpuShaderDescRcPtr();
+ jnistruct->cppobj = new GpuShaderDescRcPtr();
+ *jnistruct->cppobj = GpuShaderDescRcPtr(new GpuShaderDesc(), &GpuShaderDesc_deleter);
+ jnistruct->isconst = false;
+ jclass wclass = env->GetObjectClass(self);
+ jfieldID fid = env->GetFieldID(wclass, "m_impl", "J");
+ env->SetLongField(self, fid, (jlong)jnistruct);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_GpuShaderDesc_dispose(JNIEnv * env, jobject self) {
+ OCIO_JNITRY_ENTER()
+ DisposeJOCIO<GpuShaderDescJNI>(env, self);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_GpuShaderDesc_setLanguage(JNIEnv * env, jobject self, jobject lang) {
+ OCIO_JNITRY_ENTER()
+ GpuShaderDescRcPtr ptr = GetEditableJOCIO<GpuShaderDescRcPtr, GpuShaderDescJNI>(env, self);
+ ptr->setLanguage(GetJEnum<GpuLanguage>(env, lang));
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_GpuShaderDesc_getLanguage(JNIEnv * env, jobject self) {
+ OCIO_JNITRY_ENTER()
+ ConstGpuShaderDescRcPtr ptr = GetConstJOCIO<ConstGpuShaderDescRcPtr, GpuShaderDescJNI>(env, self);
+ return BuildJEnum(env, "org/OpenColorIO/GpuLanguage", ptr->getLanguage());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_GpuShaderDesc_setFunctionName(JNIEnv * env, jobject self, jstring name) {
+ OCIO_JNITRY_ENTER()
+ const char *_name = env->GetStringUTFChars(name, 0);
+ GpuShaderDescRcPtr ptr = GetEditableJOCIO<GpuShaderDescRcPtr, GpuShaderDescJNI>(env, self);
+ ptr->setFunctionName(_name);
+ env->ReleaseStringUTFChars(name, _name);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_GpuShaderDesc_getFunctionName(JNIEnv * env, jobject self) {
+ OCIO_JNITRY_ENTER()
+ ConstGpuShaderDescRcPtr ptr = GetConstJOCIO<ConstGpuShaderDescRcPtr, GpuShaderDescJNI>(env, self);
+ return env->NewStringUTF(ptr->getFunctionName());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_GpuShaderDesc_setLut3DEdgeLen(JNIEnv * env, jobject self, jint len) {
+ OCIO_JNITRY_ENTER()
+ GpuShaderDescRcPtr ptr = GetEditableJOCIO<GpuShaderDescRcPtr, GpuShaderDescJNI>(env, self);
+ ptr->setLut3DEdgeLen((int)len);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jint JNICALL
+Java_org_OpenColorIO_GpuShaderDesc_getLut3DEdgeLen(JNIEnv * env, jobject self) {
+ OCIO_JNITRY_ENTER()
+ ConstGpuShaderDescRcPtr ptr = GetConstJOCIO<ConstGpuShaderDescRcPtr, GpuShaderDescJNI>(env, self);
+ return (jint)ptr->getLut3DEdgeLen();
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_GpuShaderDesc_getCacheID(JNIEnv * env, jobject self) {
+ OCIO_JNITRY_ENTER()
+ ConstGpuShaderDescRcPtr ptr = GetConstJOCIO<ConstGpuShaderDescRcPtr, GpuShaderDescJNI>(env, self);
+ return env->NewStringUTF(ptr->getCacheID());
+ OCIO_JNITRY_EXIT(NULL)
+}
diff --git a/src/jniglue/JNIImageDesc.cpp b/src/jniglue/JNIImageDesc.cpp
new file mode 100644
index 0000000..c307984
--- /dev/null
+++ b/src/jniglue/JNIImageDesc.cpp
@@ -0,0 +1,309 @@
+/*
+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 "OpenColorIOJNI.h"
+#include "JNIUtil.h"
+OCIO_NAMESPACE_USING
+
+namespace
+{
+void ImageDesc_deleter(ImageDesc* d)
+{
+ delete d;
+}
+
+void ImageDesc_dispose(JNIEnv * env, jobject self)
+{
+ DisposeJOCIO<ImageDescJNI>(env, self);
+}
+
+}; // end anon namespace
+
+// PackedImageDesc
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_PackedImageDesc_create__Ljava_nio_FloatBuffer_2JJJ(JNIEnv * env,
+ jobject self, jobject data, jlong width, jlong height, jlong numChannels)
+{
+ OCIO_JNITRY_ENTER()
+ float* _data = GetJFloatBuffer(env, data, width * height * numChannels);
+ if(!_data) throw Exception("Could not find direct buffer address for data");
+ ImageDescJNI * jnistruct = new ImageDescJNI();
+ jnistruct->back_ptr = env->NewGlobalRef(self);
+ jnistruct->constcppobj = new ConstImageDescRcPtr();
+ jnistruct->cppobj = new ImageDescRcPtr();
+ *jnistruct->cppobj = ImageDescRcPtr(new PackedImageDesc(_data, (long)width,
+ (long)height, (long)numChannels), &ImageDesc_deleter);
+ jnistruct->isconst = false;
+ jclass wclass = env->GetObjectClass(self);
+ jfieldID fid = env->GetFieldID(wclass, "m_impl", "J");
+ env->SetLongField(self, fid, (jlong)jnistruct);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_PackedImageDesc_create__Ljava_nio_FloatBuffer_2JJJJJJ(JNIEnv * env,
+ jobject self, jobject data, jlong width, jlong height, jlong numChannels,
+ jlong chanStrideBytes, jlong xStrideBytes, jlong yStrideBytes)
+{
+ OCIO_JNITRY_ENTER()
+ float* _data = GetJFloatBuffer(env, data, width * height * numChannels);
+ if(!_data) throw Exception("Could not find direct buffer address for data");
+ ImageDescJNI * jnistruct = new ImageDescJNI();
+ jnistruct->back_ptr = env->NewGlobalRef(self);
+ jnistruct->constcppobj = new ConstImageDescRcPtr();
+ jnistruct->cppobj = new ImageDescRcPtr();
+ *jnistruct->cppobj = ImageDescRcPtr(new PackedImageDesc(_data, (long)width,
+ (long)height, (long)numChannels, (long)chanStrideBytes, (long) xStrideBytes,
+ (long)yStrideBytes), &ImageDesc_deleter);
+ jnistruct->isconst = false;
+ jclass wclass = env->GetObjectClass(self);
+ jfieldID fid = env->GetFieldID(wclass, "m_impl", "J");
+ env->SetLongField(self, fid, (jlong)jnistruct);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_PackedImageDesc_dispose(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ImageDesc_dispose(env, self);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_PackedImageDesc_getData(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstImageDescRcPtr img = GetConstJOCIO<ConstImageDescRcPtr, ImageDescJNI>(env, self);
+ ConstPackedImageDescRcPtr ptr = DynamicPtrCast<const PackedImageDesc>(img);
+ int size = ptr->getWidth() * ptr->getHeight() * ptr->getNumChannels();
+ return NewJFloatBuffer(env, ptr->getData(), size);
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_OpenColorIO_PackedImageDesc_getWidth(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstImageDescRcPtr img = GetConstJOCIO<ConstImageDescRcPtr, ImageDescJNI>(env, self);
+ ConstPackedImageDescRcPtr ptr = DynamicPtrCast<const PackedImageDesc>(img);
+ return (jlong)ptr->getWidth();
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_OpenColorIO_PackedImageDesc_getHeight(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstImageDescRcPtr img = GetConstJOCIO<ConstImageDescRcPtr, ImageDescJNI>(env, self);
+ ConstPackedImageDescRcPtr ptr = DynamicPtrCast<const PackedImageDesc>(img);
+ return (jlong)ptr->getHeight();
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_OpenColorIO_PackedImageDesc_getNumChannels(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstImageDescRcPtr img = GetConstJOCIO<ConstImageDescRcPtr, ImageDescJNI>(env, self);
+ ConstPackedImageDescRcPtr ptr = DynamicPtrCast<const PackedImageDesc>(img);
+ return (jlong)ptr->getNumChannels();
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_OpenColorIO_PackedImageDesc_getChanStrideBytes(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstImageDescRcPtr img = GetConstJOCIO<ConstImageDescRcPtr, ImageDescJNI>(env, self);
+ ConstPackedImageDescRcPtr ptr = DynamicPtrCast<const PackedImageDesc>(img);
+ return (jlong)ptr->getChanStrideBytes();
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_OpenColorIO_PackedImageDesc_getXStrideBytes(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstImageDescRcPtr img = GetConstJOCIO<ConstImageDescRcPtr, ImageDescJNI>(env, self);
+ ConstPackedImageDescRcPtr ptr = DynamicPtrCast<const PackedImageDesc>(img);
+ return (jlong)ptr->getXStrideBytes();
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_OpenColorIO_PackedImageDesc_getYStrideBytes(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstImageDescRcPtr img = GetConstJOCIO<ConstImageDescRcPtr, ImageDescJNI>(env, self);
+ ConstPackedImageDescRcPtr ptr = DynamicPtrCast<const PackedImageDesc>(img);
+ return (jlong)ptr->getYStrideBytes();
+ OCIO_JNITRY_EXIT(0)
+}
+
+// PlanarImageDesc
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_PlanarImageDesc_dispose(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ImageDesc_dispose(env, self);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_PlanarImageDesc_create__Ljava_nio_FloatBuffer_2Ljava_nio_FloatBuffer_2Ljava_nio_FloatBuffer_2Ljava_nio_FloatBuffer_2JJ
+ (JNIEnv * env, jobject self, jobject rData, jobject gData, jobject bData,
+ jobject aData, jlong width, jlong height)
+{
+ OCIO_JNITRY_ENTER()
+ int32_t size = width * height;
+ float* _rdata = GetJFloatBuffer(env, rData, size);
+ if(!_rdata) throw Exception("Could not find direct buffer address for rData");
+ float* _gdata = GetJFloatBuffer(env, gData, size);
+ if(!_gdata) throw Exception("Could not find direct buffer address for gData");
+ float* _bdata = GetJFloatBuffer(env, bData, size);
+ if(!_bdata) throw Exception("Could not find direct buffer address for bData");
+ float* _adata = GetJFloatBuffer(env, aData, size);
+ if(!_adata) throw Exception("Could not find direct buffer address for aData");
+ ImageDescJNI * jnistruct = new ImageDescJNI();
+ jnistruct->back_ptr = env->NewGlobalRef(self);
+ jnistruct->constcppobj = new ConstImageDescRcPtr();
+ jnistruct->cppobj = new ImageDescRcPtr();
+ *jnistruct->cppobj = ImageDescRcPtr(new PlanarImageDesc(_rdata, _gdata,
+ _bdata, _adata, (long)width, (long)height), &ImageDesc_deleter);
+ jnistruct->isconst = false;
+ jclass wclass = env->GetObjectClass(self);
+ jfieldID fid = env->GetFieldID(wclass, "m_impl", "J");
+ env->SetLongField(self, fid, (jlong)jnistruct);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void
+JNICALL Java_org_OpenColorIO_PlanarImageDesc_create__Ljava_nio_FloatBuffer_2Ljava_nio_FloatBuffer_2Ljava_nio_FloatBuffer_2Ljava_nio_FloatBuffer_2JJJ
+ (JNIEnv * env, jobject self, jobject rData, jobject gData, jobject bData,
+ jobject aData, jlong width, jlong height, jlong yStrideBytes)
+{
+ OCIO_JNITRY_ENTER()
+ int32_t size = width * height;
+ float* _rdata = GetJFloatBuffer(env, rData, size);
+ if(!_rdata) throw Exception("Could not find direct buffer address for rData");
+ float* _gdata = GetJFloatBuffer(env, gData, size);
+ if(!_gdata) throw Exception("Could not find direct buffer address for gData");
+ float* _bdata = GetJFloatBuffer(env, bData, size);
+ if(!_bdata) throw Exception("Could not find direct buffer address for bData");
+ float* _adata = GetJFloatBuffer(env, aData, size);
+ if(!_adata) throw Exception("Could not find direct buffer address for aData");
+ ImageDescJNI * jnistruct = new ImageDescJNI();
+ jnistruct->back_ptr = env->NewGlobalRef(self);
+ jnistruct->constcppobj = new ConstImageDescRcPtr();
+ jnistruct->cppobj = new ImageDescRcPtr();
+ *jnistruct->cppobj = ImageDescRcPtr(new PlanarImageDesc(_rdata, _gdata, _bdata,
+ _adata, (long)width, (long)height, (long)yStrideBytes), &ImageDesc_deleter);
+ jnistruct->isconst = false;
+ jclass wclass = env->GetObjectClass(self);
+ jfieldID fid = env->GetFieldID(wclass, "m_impl", "J");
+ env->SetLongField(self, fid, (jlong)jnistruct);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_PlanarImageDesc_getRData(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstImageDescRcPtr img = GetConstJOCIO<ConstImageDescRcPtr, ImageDescJNI>(env, self);
+ ConstPlanarImageDescRcPtr ptr = DynamicPtrCast<const PlanarImageDesc>(img);
+ int size = ptr->getWidth() * ptr->getHeight();
+ return NewJFloatBuffer(env, ptr->getRData(), size);
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_PlanarImageDesc_getGData(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstImageDescRcPtr img = GetConstJOCIO<ConstImageDescRcPtr, ImageDescJNI>(env, self);
+ ConstPlanarImageDescRcPtr ptr = DynamicPtrCast<const PlanarImageDesc>(img);
+ int size = ptr->getWidth() * ptr->getHeight();
+ return NewJFloatBuffer(env, ptr->getGData(), size);
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_PlanarImageDesc_getBData(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstImageDescRcPtr img = GetConstJOCIO<ConstImageDescRcPtr, ImageDescJNI>(env, self);
+ ConstPlanarImageDescRcPtr ptr = DynamicPtrCast<const PlanarImageDesc>(img);
+ int size = ptr->getWidth() * ptr->getHeight();
+ return NewJFloatBuffer(env, ptr->getBData(), size);
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_PlanarImageDesc_getAData(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstImageDescRcPtr img = GetConstJOCIO<ConstImageDescRcPtr, ImageDescJNI>(env, self);
+ ConstPlanarImageDescRcPtr ptr = DynamicPtrCast<const PlanarImageDesc>(img);
+ int size = ptr->getWidth() * ptr->getHeight();
+ return NewJFloatBuffer(env, ptr->getAData(), size);
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_OpenColorIO_PlanarImageDesc_getWidth(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstImageDescRcPtr img = GetConstJOCIO<ConstImageDescRcPtr, ImageDescJNI>(env, self);
+ ConstPlanarImageDescRcPtr ptr = DynamicPtrCast<const PlanarImageDesc>(img);
+ return (jlong)ptr->getWidth();
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_OpenColorIO_PlanarImageDesc_getHeight(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstImageDescRcPtr img = GetConstJOCIO<ConstImageDescRcPtr, ImageDescJNI>(env, self);
+ ConstPlanarImageDescRcPtr ptr = DynamicPtrCast<const PlanarImageDesc>(img);
+ return (jlong)ptr->getHeight();
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_OpenColorIO_PlanarImageDesc_getYStrideBytes(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstImageDescRcPtr img = GetConstJOCIO<ConstImageDescRcPtr, ImageDescJNI>(env, self);
+ ConstPlanarImageDescRcPtr ptr = DynamicPtrCast<const PlanarImageDesc>(img);
+ return (jlong)ptr->getYStrideBytes();
+ OCIO_JNITRY_EXIT(0)
+}
diff --git a/src/jniglue/JNILook.cpp b/src/jniglue/JNILook.cpp
new file mode 100644
index 0000000..ebd7731
--- /dev/null
+++ b/src/jniglue/JNILook.cpp
@@ -0,0 +1,131 @@
+/*
+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 <string>
+#include <sstream>
+#include <vector>
+
+#include "OpenColorIO/OpenColorIO.h"
+#include "OpenColorIOJNI.h"
+#include "JNIUtil.h"
+OCIO_NAMESPACE_USING
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Look_dispose(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ DisposeJOCIO<LookJNI>(env, self);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Look_Create(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJObject<LookRcPtr, LookJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Look"), Look::Create());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Look_getName(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstLookRcPtr lok = GetConstJOCIO<ConstLookRcPtr, LookJNI>(env, self);
+ return env->NewStringUTF(lok->getName());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Look_setName(JNIEnv * env, jobject self, jstring name)
+{
+ OCIO_JNITRY_ENTER()
+ LookRcPtr lok = GetEditableJOCIO<LookRcPtr, LookJNI>(env, self);
+ lok->setName(GetJStringValue(env, name)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Look_getProcessSpace(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstLookRcPtr lok = GetConstJOCIO<ConstLookRcPtr, LookJNI>(env, self);
+ return env->NewStringUTF(lok->getProcessSpace());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Look_setProcessSpace(JNIEnv * env, jobject self, jstring processSpace)
+{
+ OCIO_JNITRY_ENTER()
+ LookRcPtr lok = GetEditableJOCIO<LookRcPtr, LookJNI>(env, self);
+ lok->setProcessSpace(GetJStringValue(env, processSpace)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Look_getTransform(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstLookRcPtr lok = GetConstJOCIO<ConstLookRcPtr, LookJNI>(env, self);
+ ConstTransformRcPtr tr = lok->getTransform();
+ return BuildJConstObject<ConstTransformRcPtr, TransformJNI>(env, self,
+ env->FindClass(GetOCIOTClass(tr)), tr);
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Look_setTransform(JNIEnv * env, jobject self, jobject transform)
+{
+ OCIO_JNITRY_ENTER()
+ LookRcPtr lok = GetEditableJOCIO<LookRcPtr, LookJNI>(env, self);
+ ConstTransformRcPtr tran = GetConstJOCIO<ConstTransformRcPtr, TransformJNI>(env, transform);
+ lok->setTransform(tran);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Look_getInverseTransform(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstLookRcPtr lok = GetConstJOCIO<ConstLookRcPtr, LookJNI>(env, self);
+ ConstTransformRcPtr tr = lok->getInverseTransform();
+ return BuildJConstObject<ConstTransformRcPtr, TransformJNI>(env, self,
+ env->FindClass(GetOCIOTClass(tr)), tr);
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Look_setInverseTransform(JNIEnv * env, jobject self, jobject transform)
+{
+ OCIO_JNITRY_ENTER()
+ LookRcPtr lok = GetEditableJOCIO<LookRcPtr, LookJNI>(env, self);
+ ConstTransformRcPtr tran = GetConstJOCIO<ConstTransformRcPtr, TransformJNI>(env, transform);
+ lok->setInverseTransform(tran);
+ OCIO_JNITRY_EXIT()
+}
diff --git a/src/jniglue/JNIProcessor.cpp b/src/jniglue/JNIProcessor.cpp
new file mode 100644
index 0000000..ada897a
--- /dev/null
+++ b/src/jniglue/JNIProcessor.cpp
@@ -0,0 +1,133 @@
+/*
+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 <string>
+#include <sstream>
+#include <vector>
+
+#include "OpenColorIO/OpenColorIO.h"
+#include "OpenColorIOJNI.h"
+#include "JNIUtil.h"
+OCIO_NAMESPACE_USING
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Processor_Create(JNIEnv * env, jobject self) {
+ OCIO_JNITRY_ENTER()
+ jobject obj = BuildJConstObject<ConstProcessorRcPtr, ProcessorJNI>(env, self,
+ env->FindClass("org/OpenColorIO/Processor"), Processor::Create());
+ return obj;
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_OpenColorIO_Processor_isNoOp(JNIEnv * env, jobject self) {
+ OCIO_JNITRY_ENTER()
+ ConstProcessorRcPtr ptr = GetConstJOCIO<ConstProcessorRcPtr, ProcessorJNI>(env, self);
+ return (jboolean)ptr->isNoOp();
+ OCIO_JNITRY_EXIT(false)
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_OpenColorIO_Processor_hasChannelCrosstalk(JNIEnv * env, jobject self) {
+ OCIO_JNITRY_ENTER()
+ ConstProcessorRcPtr ptr = GetConstJOCIO<ConstProcessorRcPtr, ProcessorJNI>(env, self);
+ return (jboolean)ptr->hasChannelCrosstalk();
+ OCIO_JNITRY_EXIT(false)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Processor_apply(JNIEnv * env, jobject self, jobject img) {
+ OCIO_JNITRY_ENTER()
+ ConstProcessorRcPtr ptr = GetConstJOCIO<ConstProcessorRcPtr, ProcessorJNI>(env, self);
+ ImageDescRcPtr _img = GetEditableJOCIO<ImageDescRcPtr, ImageDescJNI>(env, img);
+ ptr->apply(*_img.get());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Processor_applyRGB(JNIEnv * env, jobject self, jfloatArray pixel) {
+ OCIO_JNITRY_ENTER()
+ ConstProcessorRcPtr ptr = GetConstJOCIO<ConstProcessorRcPtr, ProcessorJNI>(env, self);
+ ptr->applyRGB(GetJFloatArrayValue(env, pixel, "pixel", 3)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Processor_applyRGBA(JNIEnv * env, jobject self, jfloatArray pixel) {
+ OCIO_JNITRY_ENTER()
+ ConstProcessorRcPtr ptr = GetConstJOCIO<ConstProcessorRcPtr, ProcessorJNI>(env, self);
+ ptr->applyRGBA(GetJFloatArrayValue(env, pixel, "pixel", 4)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Processor_getCpuCacheID(JNIEnv * env, jobject self) {
+ OCIO_JNITRY_ENTER()
+ ConstProcessorRcPtr ptr = GetConstJOCIO<ConstProcessorRcPtr, ProcessorJNI>(env, self);
+ return env->NewStringUTF(ptr->getCpuCacheID());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Processor_getGpuShaderText(JNIEnv * env, jobject self, jobject shaderDesc) {
+ OCIO_JNITRY_ENTER()
+ ConstProcessorRcPtr ptr = GetConstJOCIO<ConstProcessorRcPtr, ProcessorJNI>(env, self);
+ ConstGpuShaderDescRcPtr desc = GetConstJOCIO<ConstGpuShaderDescRcPtr, GpuShaderDescJNI>(env, shaderDesc);
+ return env->NewStringUTF(ptr->getGpuShaderText(*desc.get()));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Processor_getGpuShaderTextCacheID(JNIEnv * env, jobject self, jobject shaderDesc) {
+ OCIO_JNITRY_ENTER()
+ ConstProcessorRcPtr ptr = GetConstJOCIO<ConstProcessorRcPtr, ProcessorJNI>(env, self);
+ ConstGpuShaderDescRcPtr desc = GetConstJOCIO<ConstGpuShaderDescRcPtr, GpuShaderDescJNI>(env, shaderDesc);
+ return env->NewStringUTF(ptr->getGpuShaderTextCacheID(*desc.get()));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Processor_getGpuLut3D(JNIEnv * env, jobject self, jobject lut3d, jobject shaderDesc) {
+ OCIO_JNITRY_ENTER()
+ ConstProcessorRcPtr ptr = GetConstJOCIO<ConstProcessorRcPtr, ProcessorJNI>(env, self);
+ ConstGpuShaderDescRcPtr desc = GetConstJOCIO<ConstGpuShaderDescRcPtr, GpuShaderDescJNI>(env, shaderDesc);
+ int len = desc->getLut3DEdgeLen();
+ int size = 3*len*len*len;
+ float* _lut3d = GetJFloatBuffer(env, lut3d, size);
+ ptr->getGpuLut3D(_lut3d, *desc.get());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_Processor_getGpuLut3DCacheID(JNIEnv * env, jobject self, jobject shaderDesc) {
+ OCIO_JNITRY_ENTER()
+ ConstProcessorRcPtr ptr = GetConstJOCIO<ConstProcessorRcPtr, ProcessorJNI>(env, self);
+ ConstGpuShaderDescRcPtr desc = GetConstJOCIO<ConstGpuShaderDescRcPtr, GpuShaderDescJNI>(env, shaderDesc);
+ return env->NewStringUTF(ptr->getGpuLut3DCacheID(*desc.get()));
+ OCIO_JNITRY_EXIT(NULL)
+}
diff --git a/src/jniglue/JNITransforms.cpp b/src/jniglue/JNITransforms.cpp
new file mode 100644
index 0000000..6e2fe26
--- /dev/null
+++ b/src/jniglue/JNITransforms.cpp
@@ -0,0 +1,1151 @@
+/*
+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 "OpenColorIOJNI.h"
+#include "JNIUtil.h"
+OCIO_NAMESPACE_USING
+
+// Transform
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Transform_dispose(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ DisposeJOCIO<TransformJNI>(env, self);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Transform_createEditableCopy(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstTransformRcPtr ctran = GetConstJOCIO<ConstTransformRcPtr, TransformJNI>(env, self);
+ return BuildJObject<TransformRcPtr, TransformJNI>(env, self,
+ env->FindClass(GetOCIOTClass(ctran)), ctran->createEditableCopy());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_Transform_getDirection(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstTransformRcPtr ptr = GetConstJOCIO<ConstTransformRcPtr, TransformJNI>(env, self);
+ return BuildJEnum(env, "org/OpenColorIO/TransformDirection", ptr->getDirection());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_Transform_setDirection(JNIEnv * env, jobject self, jobject dir)
+{
+ OCIO_JNITRY_ENTER()
+ TransformRcPtr ptr = GetEditableJOCIO<TransformRcPtr, TransformJNI>(env, self);
+ ptr->setDirection(GetJEnum<TransformDirection>(env, dir));
+ OCIO_JNITRY_EXIT()
+}
+
+// AllocationTransform
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_AllocationTransform_Create(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJObject<AllocationTransformRcPtr, AllocationTransformJNI>(env, self,
+ env->FindClass("org/OpenColorIO/AllocationTransform"), AllocationTransform::Create());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_AllocationTransform_getAllocation(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstAllocationTransformRcPtr alctran = GetConstJOCIO<ConstAllocationTransformRcPtr, AllocationTransformJNI>(env, self);
+ return BuildJEnum(env, "org/OpenColorIO/Allocation", alctran->getAllocation());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_AllocationTransform_setAllocation(JNIEnv * env, jobject self, jobject allocation)
+{
+ OCIO_JNITRY_ENTER()
+ AllocationTransformRcPtr alctran = GetEditableJOCIO<AllocationTransformRcPtr, AllocationTransformJNI>(env, self);
+ alctran->setAllocation(GetJEnum<Allocation>(env, allocation));
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jint JNICALL
+Java_org_OpenColorIO_AllocationTransform_getNumVars(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstAllocationTransformRcPtr alctran = GetConstJOCIO<ConstAllocationTransformRcPtr, AllocationTransformJNI>(env, self);
+ return (jint)alctran->getNumVars();
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_AllocationTransform_getVars(JNIEnv * env, jobject self, jfloatArray vars)
+{
+ OCIO_JNITRY_ENTER()
+ ConstAllocationTransformRcPtr alctran = GetConstJOCIO<ConstAllocationTransformRcPtr, AllocationTransformJNI>(env, self);
+ alctran->getVars(SetJFloatArrayValue(env, vars, "vars", alctran->getNumVars())());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_AllocationTransform_setVars(JNIEnv * env, jobject self, jint numvars, jfloatArray vars)
+{
+ OCIO_JNITRY_ENTER()
+ AllocationTransformRcPtr alctran = GetEditableJOCIO<AllocationTransformRcPtr, AllocationTransformJNI>(env, self);
+ alctran->setVars((int)numvars, GetJFloatArrayValue(env, vars, "vars", numvars)());
+ OCIO_JNITRY_EXIT()
+}
+
+// CDLTransform
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_CDLTransform_Create(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJObject<CDLTransformRcPtr, CDLTransformJNI>(env, self,
+ env->FindClass("org/OpenColorIO/CDLTransform"), CDLTransform::Create());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_CDLTransform_CreateFromFile(JNIEnv * env, jobject self, jstring src, jstring cccid)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJObject<CDLTransformRcPtr, CDLTransformJNI>(env, self,
+ env->FindClass("org/OpenColorIO/CDLTransform"),
+ CDLTransform::CreateFromFile(GetJStringValue(env, src)(), GetJStringValue(env, cccid)()));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_OpenColorIO_CDLTransform_equals(JNIEnv * env, jobject self, jobject obj)
+{
+ OCIO_JNITRY_ENTER()
+ ConstCDLTransformRcPtr left = GetConstJOCIO<ConstCDLTransformRcPtr, CDLTransformJNI>(env, self);
+ ConstCDLTransformRcPtr right = GetConstJOCIO<ConstCDLTransformRcPtr, CDLTransformJNI>(env, obj);
+ return (jboolean)left->equals(right);
+ OCIO_JNITRY_EXIT(false)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_CDLTransform_getXML(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstCDLTransformRcPtr cdltran = GetConstJOCIO<ConstCDLTransformRcPtr, CDLTransformJNI>(env, self);
+ return env->NewStringUTF(cdltran->getXML());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_CDLTransform_setXML(JNIEnv * env, jobject self, jstring xml)
+{
+ OCIO_JNITRY_ENTER()
+ CDLTransformRcPtr cdltran = GetEditableJOCIO<CDLTransformRcPtr, CDLTransformJNI>(env, self);
+ cdltran->setXML(GetJStringValue(env, xml)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_CDLTransform_setSlope(JNIEnv * env, jobject self, jfloatArray rgb)
+{
+ OCIO_JNITRY_ENTER()
+ CDLTransformRcPtr cdltran = GetEditableJOCIO<CDLTransformRcPtr, CDLTransformJNI>(env, self);
+ cdltran->setSlope(GetJFloatArrayValue(env, rgb, "rgb", 3)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_CDLTransform_getSlope(JNIEnv * env, jobject self, jfloatArray rgb)
+{
+ OCIO_JNITRY_ENTER()
+ ConstCDLTransformRcPtr cdltran = GetConstJOCIO<ConstCDLTransformRcPtr, CDLTransformJNI>(env, self);
+ cdltran->getSlope(SetJFloatArrayValue(env, rgb, "rgb", 3)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_CDLTransform_setOffset(JNIEnv * env, jobject self, jfloatArray rgb)
+{
+ OCIO_JNITRY_ENTER()
+ CDLTransformRcPtr cdltran = GetEditableJOCIO<CDLTransformRcPtr, CDLTransformJNI>(env, self);
+ cdltran->setOffset(GetJFloatArrayValue(env, rgb, "rgb", 3)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_CDLTransform_getOffset(JNIEnv * env, jobject self, jfloatArray rgb)
+{
+ OCIO_JNITRY_ENTER()
+ ConstCDLTransformRcPtr cdltran = GetConstJOCIO<ConstCDLTransformRcPtr, CDLTransformJNI>(env, self);
+ cdltran->getOffset(SetJFloatArrayValue(env, rgb, "rgb", 3)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_CDLTransform_setPower(JNIEnv * env, jobject self, jfloatArray rgb)
+{
+ OCIO_JNITRY_ENTER()
+ CDLTransformRcPtr cdltran = GetEditableJOCIO<CDLTransformRcPtr, CDLTransformJNI>(env, self);
+ cdltran->setPower(GetJFloatArrayValue(env, rgb, "rgb", 3)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_CDLTransform_getPower(JNIEnv * env, jobject self, jfloatArray rgb)
+{
+ OCIO_JNITRY_ENTER()
+ ConstCDLTransformRcPtr cdltran = GetConstJOCIO<ConstCDLTransformRcPtr, CDLTransformJNI>(env, self);
+ cdltran->getPower(SetJFloatArrayValue(env, rgb, "rgb", 3)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_CDLTransform_setSOP(JNIEnv * env, jobject self, jfloatArray vec9)
+{
+ OCIO_JNITRY_ENTER()
+ CDLTransformRcPtr cdltran = GetEditableJOCIO<CDLTransformRcPtr, CDLTransformJNI>(env, self);
+ cdltran->setSOP(GetJFloatArrayValue(env, vec9, "vec9", 9)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_CDLTransform_getSOP(JNIEnv * env, jobject self, jfloatArray vec9)
+{
+ OCIO_JNITRY_ENTER()
+ ConstCDLTransformRcPtr cdltran = GetConstJOCIO<ConstCDLTransformRcPtr, CDLTransformJNI>(env, self);
+ cdltran->getSOP(SetJFloatArrayValue(env, vec9, "vec9", 9)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_CDLTransform_setSat(JNIEnv * env, jobject self, jfloat sat)
+{
+ OCIO_JNITRY_ENTER()
+ CDLTransformRcPtr cdltran = GetEditableJOCIO<CDLTransformRcPtr, CDLTransformJNI>(env, self);
+ cdltran->setSat((float)sat);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jfloat JNICALL
+Java_org_OpenColorIO_CDLTransform_getSat(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstCDLTransformRcPtr cdltran = GetConstJOCIO<ConstCDLTransformRcPtr, CDLTransformJNI>(env, self);
+ return (jfloat)cdltran->getSat();
+ OCIO_JNITRY_EXIT(1.f)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_CDLTransform_getSatLumaCoefs(JNIEnv * env, jobject self, jfloatArray rgb)
+{
+ OCIO_JNITRY_ENTER()
+ ConstCDLTransformRcPtr cdltran = GetConstJOCIO<ConstCDLTransformRcPtr, CDLTransformJNI>(env, self);
+ cdltran->getSatLumaCoefs(SetJFloatArrayValue(env, rgb, "rgb", 3)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_CDLTransform_setID(JNIEnv * env, jobject self, jstring id)
+{
+ OCIO_JNITRY_ENTER()
+ CDLTransformRcPtr cdltran = GetEditableJOCIO<CDLTransformRcPtr, CDLTransformJNI>(env, self);
+ cdltran->setID(GetJStringValue(env, id)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_CDLTransform_getID(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstCDLTransformRcPtr cdltran = GetConstJOCIO<ConstCDLTransformRcPtr, CDLTransformJNI>(env, self);
+ return env->NewStringUTF(cdltran->getID());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_CDLTransform_setDescription(JNIEnv * env, jobject self, jstring desc)
+{
+ OCIO_JNITRY_ENTER()
+ CDLTransformRcPtr cdltran = GetEditableJOCIO<CDLTransformRcPtr, CDLTransformJNI>(env, self);
+ cdltran->setDescription(GetJStringValue(env, desc)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_CDLTransform_getDescription(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstCDLTransformRcPtr cdltran = GetConstJOCIO<ConstCDLTransformRcPtr, CDLTransformJNI>(env, self);
+ return env->NewStringUTF(cdltran->getDescription());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+// ColorSpaceTransform
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_ColorSpaceTransform_Create(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJObject<ColorSpaceTransformRcPtr, ColorSpaceTransformJNI>(env, self,
+ env->FindClass("org/OpenColorIO/ColorSpaceTransform"), ColorSpaceTransform::Create());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_ColorSpaceTransform_getSrc(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstColorSpaceTransformRcPtr coltran = GetConstJOCIO<ConstColorSpaceTransformRcPtr, ColorSpaceTransformJNI>(env, self);
+ return env->NewStringUTF(coltran->getSrc());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_ColorSpaceTransform_setSrc(JNIEnv * env, jobject self, jstring src)
+{
+ OCIO_JNITRY_ENTER()
+ ColorSpaceTransformRcPtr coltran = GetEditableJOCIO<ColorSpaceTransformRcPtr, ColorSpaceTransformJNI>(env, self);
+ coltran->setSrc(GetJStringValue(env, src)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_ColorSpaceTransform_getDst(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstColorSpaceTransformRcPtr coltran = GetConstJOCIO<ConstColorSpaceTransformRcPtr, ColorSpaceTransformJNI>(env, self);
+ return env->NewStringUTF(coltran->getDst());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_ColorSpaceTransform_setDst(JNIEnv * env, jobject self, jstring dst)
+{
+ OCIO_JNITRY_ENTER()
+ ColorSpaceTransformRcPtr coltran = GetEditableJOCIO<ColorSpaceTransformRcPtr, ColorSpaceTransformJNI>(env, self);
+ coltran->setDst(GetJStringValue(env, dst)());
+ OCIO_JNITRY_EXIT()
+}
+
+// DisplayTransform
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_DisplayTransform_Create(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJObject<DisplayTransformRcPtr, DisplayTransformJNI>(env, self,
+ env->FindClass("org/OpenColorIO/DisplayTransform"), DisplayTransform::Create());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_DisplayTransform_setInputColorSpaceName(JNIEnv * env, jobject self, jstring name)
+{
+ OCIO_JNITRY_ENTER()
+ DisplayTransformRcPtr dtran = GetEditableJOCIO<DisplayTransformRcPtr, DisplayTransformJNI>(env, self);
+ dtran->setInputColorSpaceName(GetJStringValue(env, name)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_DisplayTransform_getInputColorSpaceName(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstDisplayTransformRcPtr dtran = GetConstJOCIO<ConstDisplayTransformRcPtr, DisplayTransformJNI>(env, self);
+ return env->NewStringUTF(dtran->getInputColorSpaceName());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_DisplayTransform_setLinearCC(JNIEnv * env, jobject self, jobject cc)
+{
+ OCIO_JNITRY_ENTER()
+ DisplayTransformRcPtr dtran = GetEditableJOCIO<DisplayTransformRcPtr, DisplayTransformJNI>(env, self);
+ ConstTransformRcPtr ptr = GetConstJOCIO<ConstTransformRcPtr, TransformJNI>(env, cc);
+ dtran->setLinearCC(ptr);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_DisplayTransform_getLinearCC(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstDisplayTransformRcPtr dtran = GetConstJOCIO<ConstDisplayTransformRcPtr, DisplayTransformJNI>(env, self);
+ ConstTransformRcPtr cctran = dtran->getLinearCC();
+ return BuildJObject<TransformRcPtr, TransformJNI>(env, self,
+ env->FindClass(GetOCIOTClass(cctran)), cctran->createEditableCopy());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_DisplayTransform_setColorTimingCC(JNIEnv * env, jobject self, jobject cc)
+{
+ OCIO_JNITRY_ENTER()
+ DisplayTransformRcPtr dtran = GetEditableJOCIO<DisplayTransformRcPtr, DisplayTransformJNI>(env, self);
+ ConstTransformRcPtr ptr = GetConstJOCIO<ConstTransformRcPtr, TransformJNI>(env, cc);
+ dtran->setColorTimingCC(ptr);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_DisplayTransform_getColorTimingCC(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstDisplayTransformRcPtr dtran = GetConstJOCIO<ConstDisplayTransformRcPtr, DisplayTransformJNI>(env, self);
+ ConstTransformRcPtr cctran = dtran->getColorTimingCC();
+ return BuildJObject<TransformRcPtr, TransformJNI>(env, self,
+ env->FindClass(GetOCIOTClass(cctran)), cctran->createEditableCopy());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_DisplayTransform_setChannelView(JNIEnv * env, jobject self, jobject transform)
+{
+ OCIO_JNITRY_ENTER()
+ DisplayTransformRcPtr dtran = GetEditableJOCIO<DisplayTransformRcPtr, DisplayTransformJNI>(env, self);
+ ConstTransformRcPtr ptr = GetConstJOCIO<ConstTransformRcPtr, TransformJNI>(env, transform);
+ dtran->setChannelView(ptr);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_DisplayTransform_getChannelView(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstDisplayTransformRcPtr dtran = GetConstJOCIO<ConstDisplayTransformRcPtr, DisplayTransformJNI>(env, self);
+ ConstTransformRcPtr cvtran = dtran->getChannelView();
+ return BuildJObject<TransformRcPtr, TransformJNI>(env, self,
+ env->FindClass(GetOCIOTClass(cvtran)), cvtran->createEditableCopy());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_DisplayTransform_setDisplay(JNIEnv * env, jobject self, jstring display)
+{
+ OCIO_JNITRY_ENTER()
+ DisplayTransformRcPtr dtran = GetEditableJOCIO<DisplayTransformRcPtr, DisplayTransformJNI>(env, self);
+ dtran->setDisplay(GetJStringValue(env, display)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_DisplayTransform_getDisplay(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstDisplayTransformRcPtr dtran = GetConstJOCIO<ConstDisplayTransformRcPtr, DisplayTransformJNI>(env, self);
+ return env->NewStringUTF(dtran->getDisplay());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_DisplayTransform_setView(JNIEnv * env, jobject self, jstring view)
+{
+ OCIO_JNITRY_ENTER()
+ DisplayTransformRcPtr dtran = GetEditableJOCIO<DisplayTransformRcPtr, DisplayTransformJNI>(env, self);
+ dtran->setView(GetJStringValue(env, view)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_DisplayTransform_getView(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstDisplayTransformRcPtr dtran = GetConstJOCIO<ConstDisplayTransformRcPtr, DisplayTransformJNI>(env, self);
+ return env->NewStringUTF(dtran->getView());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_DisplayTransform_setDisplayCC(JNIEnv * env, jobject self, jobject cc)
+{
+ OCIO_JNITRY_ENTER()
+ DisplayTransformRcPtr dtran = GetEditableJOCIO<DisplayTransformRcPtr, DisplayTransformJNI>(env, self);
+ ConstTransformRcPtr ptr = GetConstJOCIO<ConstTransformRcPtr, TransformJNI>(env, cc);
+ dtran->setDisplayCC(ptr);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_DisplayTransform_getDisplayCC(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstDisplayTransformRcPtr dtran = GetConstJOCIO<ConstDisplayTransformRcPtr, DisplayTransformJNI>(env, self);
+ ConstTransformRcPtr cctran = dtran->getDisplayCC();
+ return BuildJObject<TransformRcPtr, TransformJNI>(env, self,
+ env->FindClass(GetOCIOTClass(cctran)), cctran->createEditableCopy());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_DisplayTransform_setLooksOverride(JNIEnv * env, jobject self, jstring looks)
+{
+ OCIO_JNITRY_ENTER()
+ DisplayTransformRcPtr dtran = GetEditableJOCIO<DisplayTransformRcPtr, DisplayTransformJNI>(env, self);
+ dtran->setLooksOverride(GetJStringValue(env, looks)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_DisplayTransform_getLooksOverride(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstDisplayTransformRcPtr dtran = GetConstJOCIO<ConstDisplayTransformRcPtr, DisplayTransformJNI>(env, self);
+ return env->NewStringUTF(dtran->getLooksOverride());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_DisplayTransform_setLooksOverrideEnabled(JNIEnv * env, jobject self, jboolean enabled)
+{
+ OCIO_JNITRY_ENTER()
+ DisplayTransformRcPtr dtran = GetEditableJOCIO<DisplayTransformRcPtr, DisplayTransformJNI>(env, self);
+ dtran->setLooksOverrideEnabled((bool)enabled);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_OpenColorIO_DisplayTransform_getLooksOverrideEnabled(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstDisplayTransformRcPtr dtran = GetConstJOCIO<ConstDisplayTransformRcPtr, DisplayTransformJNI>(env, self);
+ return (jboolean)dtran->getLooksOverrideEnabled();
+ OCIO_JNITRY_EXIT(false)
+}
+
+// ExponentTransform
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_ExponentTransform_Create(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJObject<TransformRcPtr, TransformJNI>(env, self,
+ env->FindClass("org/OpenColorIO/ExponentTransform"), ExponentTransform::Create());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_ExponentTransform_setValue(JNIEnv * env, jobject self, jfloatArray vec4)
+{
+ OCIO_JNITRY_ENTER()
+ ExponentTransformRcPtr exptran = GetEditableJOCIO<ExponentTransformRcPtr, ExponentTransformJNI>(env, self);
+ exptran->setValue(GetJFloatArrayValue(env, vec4, "vec4", 4)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_ExponentTransform_getValue(JNIEnv * env, jobject self, jfloatArray vec4)
+{
+ OCIO_JNITRY_ENTER()
+ ConstExponentTransformRcPtr exptran = GetConstJOCIO<ConstExponentTransformRcPtr, ExponentTransformJNI>(env, self);
+ exptran->getValue(SetJFloatArrayValue(env, vec4, "vec4", 4)());
+ OCIO_JNITRY_EXIT()
+}
+
+// FileTransform
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_FileTransform_Create(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJObject<FileTransformRcPtr, FileTransformJNI>(env, self,
+ env->FindClass("org/OpenColorIO/FileTransform"), FileTransform::Create());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_FileTransform_getSrc(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstFileTransformRcPtr filetran = GetConstJOCIO<ConstFileTransformRcPtr, FileTransformJNI>(env, self);
+ return env->NewStringUTF(filetran->getSrc());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_FileTransform_setSrc(JNIEnv * env, jobject self, jstring src)
+{
+ OCIO_JNITRY_ENTER()
+ FileTransformRcPtr filetran = GetEditableJOCIO<FileTransformRcPtr, FileTransformJNI>(env, self);
+ filetran->setSrc(GetJStringValue(env, src)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_FileTransform_getCCCId(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstFileTransformRcPtr filetran = GetConstJOCIO<ConstFileTransformRcPtr, FileTransformJNI>(env, self);
+ return env->NewStringUTF(filetran->getCCCId());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_FileTransform_setCCCId(JNIEnv * env, jobject self, jstring id)
+{
+ OCIO_JNITRY_ENTER()
+ FileTransformRcPtr filetran = GetEditableJOCIO<FileTransformRcPtr, FileTransformJNI>(env, self);
+ filetran->setCCCId(GetJStringValue(env, id)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_FileTransform_getInterpolation(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstFileTransformRcPtr filetran = GetConstJOCIO<ConstFileTransformRcPtr, FileTransformJNI>(env, self);
+ return BuildJEnum(env, "org/OpenColorIO/Interpolation", filetran->getInterpolation());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_FileTransform_setInterpolation(JNIEnv * env, jobject self, jobject interp)
+{
+ OCIO_JNITRY_ENTER()
+ FileTransformRcPtr filetran = GetEditableJOCIO<FileTransformRcPtr, FileTransformJNI>(env, self);
+ filetran->setInterpolation(GetJEnum<Interpolation>(env, interp));
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jint JNICALL
+Java_org_OpenColorIO_FileTransform_getNumFormats(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstFileTransformRcPtr filetran = GetConstJOCIO<ConstFileTransformRcPtr, FileTransformJNI>(env, self);
+ return (jint)filetran->getNumFormats();
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_FileTransform_getFormatNameByIndex(JNIEnv * env, jobject self, jint index)
+{
+ OCIO_JNITRY_ENTER()
+ ConstFileTransformRcPtr filetran = GetConstJOCIO<ConstFileTransformRcPtr, FileTransformJNI>(env, self);
+ return env->NewStringUTF(filetran->getFormatNameByIndex((int)index));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_FileTransform_getFormatExtensionByIndex(JNIEnv * env, jobject self, jint index)
+{
+ OCIO_JNITRY_ENTER()
+ ConstFileTransformRcPtr filetran = GetConstJOCIO<ConstFileTransformRcPtr, FileTransformJNI>(env, self);
+ return env->NewStringUTF(filetran->getFormatExtensionByIndex((int)index));
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+// GroupTransform
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_GroupTransform_Create(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJObject<GroupTransformRcPtr, GroupTransformJNI>(env, self,
+ env->FindClass("org/OpenColorIO/GroupTransform"), GroupTransform::Create());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_GroupTransform_getTransform(JNIEnv * env, jobject self, jint index)
+{
+ OCIO_JNITRY_ENTER()
+ ConstGroupTransformRcPtr gtran = GetConstJOCIO<ConstGroupTransformRcPtr, GroupTransformJNI>(env, self);
+ ConstTransformRcPtr ctran = gtran->getTransform((int)index);
+ return BuildJObject<TransformRcPtr, TransformJNI>(env, self,
+ env->FindClass(GetOCIOTClass(ctran)), ctran->createEditableCopy());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jint JNICALL
+Java_org_OpenColorIO_GroupTransform_size(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstGroupTransformRcPtr gtran = GetConstJOCIO<ConstGroupTransformRcPtr, GroupTransformJNI>(env, self);
+ return (jint)gtran->size();
+ OCIO_JNITRY_EXIT(0)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_GroupTransform_push_1back(JNIEnv * env, jobject self, jobject transform)
+{
+ OCIO_JNITRY_ENTER()
+ GroupTransformRcPtr gtran = GetEditableJOCIO<GroupTransformRcPtr, GroupTransformJNI>(env, self);
+ ConstTransformRcPtr ptr = GetConstJOCIO<ConstTransformRcPtr, TransformJNI>(env, transform);
+ gtran->push_back(ptr);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_GroupTransform_clear(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ GroupTransformRcPtr gtran = GetEditableJOCIO<GroupTransformRcPtr, GroupTransformJNI>(env, self);
+ gtran->clear();
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_OpenColorIO_GroupTransform_empty(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstGroupTransformRcPtr gtran = GetConstJOCIO<ConstGroupTransformRcPtr, GroupTransformJNI>(env, self);
+ return (jboolean)gtran->empty();
+ OCIO_JNITRY_EXIT(false)
+}
+
+// LogTransform
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_LogTransform_Create(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJObject<LogTransformRcPtr, LogTransformJNI>(env, self,
+ env->FindClass("org/OpenColorIO/LogTransform"), LogTransform::Create());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_LogTransform_setBase(JNIEnv * env, jobject self, jfloat val)
+{
+ OCIO_JNITRY_ENTER()
+ LogTransformRcPtr ltran = GetEditableJOCIO<LogTransformRcPtr, LogTransformJNI>(env, self);
+ ltran->setBase((float)val);
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jfloat JNICALL
+Java_org_OpenColorIO_LogTransform_getBase(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstLogTransformRcPtr ltran = GetConstJOCIO<ConstLogTransformRcPtr, LogTransformJNI>(env, self);
+ return (jfloat)ltran->getBase();
+ OCIO_JNITRY_EXIT(0.f)
+}
+
+// LookTransform
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_LookTransform_Create(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJObject<LookTransformRcPtr, LookTransformJNI>(env, self,
+ env->FindClass("org/OpenColorIO/LookTransform"), LookTransform::Create());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_LookTransform_getSrc(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstLookTransformRcPtr lktran = GetConstJOCIO<ConstLookTransformRcPtr, LookTransformJNI>(env, self);
+ return env->NewStringUTF(lktran->getSrc());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_LookTransform_setSrc(JNIEnv * env, jobject self, jstring src)
+{
+ OCIO_JNITRY_ENTER()
+ LookTransformRcPtr lktran = GetEditableJOCIO<LookTransformRcPtr, LookTransformJNI>(env, self);
+ lktran->setSrc(GetJStringValue(env, src)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_LookTransform_getDst(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstLookTransformRcPtr lktran = GetConstJOCIO<ConstLookTransformRcPtr, LookTransformJNI>(env, self);
+ return env->NewStringUTF(lktran->getDst());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_LookTransform_setDst(JNIEnv * env, jobject self, jstring dst)
+{
+ OCIO_JNITRY_ENTER()
+ LookTransformRcPtr lktran = GetEditableJOCIO<LookTransformRcPtr, LookTransformJNI>(env, self);
+ lktran->setDst(GetJStringValue(env, dst)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_LookTransform_setLooks(JNIEnv * env, jobject self, jstring looks)
+{
+ OCIO_JNITRY_ENTER()
+ LookTransformRcPtr lktran = GetEditableJOCIO<LookTransformRcPtr, LookTransformJNI>(env, self);
+ lktran->setLooks(GetJStringValue(env, looks)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_LookTransform_getLooks(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstLookTransformRcPtr lktran = GetConstJOCIO<ConstLookTransformRcPtr, LookTransformJNI>(env, self);
+ return env->NewStringUTF(lktran->getLooks());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+// MatrixTransform
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_MatrixTransform_Create(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJObject<MatrixTransformRcPtr, MatrixTransformJNI>(env, self,
+ env->FindClass("org/OpenColorIO/MatrixTransform"), MatrixTransform::Create());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_OpenColorIO_MatrixTransform_equals(JNIEnv * env, jobject self, jobject obj)
+{
+ OCIO_JNITRY_ENTER()
+ ConstMatrixTransformRcPtr left = GetConstJOCIO<ConstMatrixTransformRcPtr, MatrixTransformJNI>(env, self);
+ ConstMatrixTransformRcPtr right = GetConstJOCIO<ConstMatrixTransformRcPtr, MatrixTransformJNI>(env, obj);
+ return (jboolean)left->equals(*right.get());
+ OCIO_JNITRY_EXIT(false)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_MatrixTransform_setValue(JNIEnv * env, jobject self, jfloatArray m44, jfloatArray offset4)
+{
+ OCIO_JNITRY_ENTER()
+ MatrixTransformRcPtr mtran = GetEditableJOCIO<MatrixTransformRcPtr, MatrixTransformJNI>(env, self);
+ mtran->setValue(GetJFloatArrayValue(env, m44, "m44", 16)(),
+ GetJFloatArrayValue(env, offset4, "offset4", 4)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_MatrixTransform_getValue(JNIEnv * env, jobject self, jfloatArray m44, jfloatArray offset4)
+{
+ OCIO_JNITRY_ENTER()
+ ConstMatrixTransformRcPtr mtran = GetConstJOCIO<ConstMatrixTransformRcPtr, MatrixTransformJNI>(env, self);
+ mtran->getValue(SetJFloatArrayValue(env, m44, "m44", 16)(),
+ SetJFloatArrayValue(env, offset4, "offset4", 4)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_MatrixTransform_setMatrix(JNIEnv * env, jobject self, jfloatArray m44)
+{
+ OCIO_JNITRY_ENTER()
+ MatrixTransformRcPtr mtran = GetEditableJOCIO<MatrixTransformRcPtr, MatrixTransformJNI>(env, self);
+ mtran->setMatrix(GetJFloatArrayValue(env, m44, "m44", 16)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_MatrixTransform_getMatrix(JNIEnv * env, jobject self, jfloatArray m44)
+{
+ OCIO_JNITRY_ENTER()
+ ConstMatrixTransformRcPtr mtran = GetConstJOCIO<ConstMatrixTransformRcPtr, MatrixTransformJNI>(env, self);
+ mtran->getMatrix(SetJFloatArrayValue(env, m44, "m44", 16)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_MatrixTransform_setOffset(JNIEnv * env, jobject self, jfloatArray offset4)
+{
+ OCIO_JNITRY_ENTER()
+ MatrixTransformRcPtr mtran = GetEditableJOCIO<MatrixTransformRcPtr, MatrixTransformJNI>(env, self);
+ mtran->setOffset(GetJFloatArrayValue(env, offset4, "offset4", 4)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_MatrixTransform_getOffset(JNIEnv * env, jobject self, jfloatArray offset4)
+{
+ OCIO_JNITRY_ENTER()
+ ConstMatrixTransformRcPtr mtran = GetConstJOCIO<ConstMatrixTransformRcPtr, MatrixTransformJNI>(env, self);
+ mtran->getOffset(SetJFloatArrayValue(env, offset4, "offset4", 4)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_MatrixTransform_Fit(JNIEnv * env, jobject self,
+ jfloatArray m44, jfloatArray offset4, jfloatArray oldmin4,
+ jfloatArray oldmax4, jfloatArray newmin4, jfloatArray newmax4)
+{
+ OCIO_JNITRY_ENTER()
+ ConstMatrixTransformRcPtr mtran = GetConstJOCIO<ConstMatrixTransformRcPtr, MatrixTransformJNI>(env, self);
+ mtran->Fit(GetJFloatArrayValue(env, m44, "m44", 16)(),
+ GetJFloatArrayValue(env, offset4, "offset4", 4)(),
+ GetJFloatArrayValue(env, oldmin4, "oldmin4", 4)(),
+ GetJFloatArrayValue(env, oldmax4, "oldmax4", 4)(),
+ GetJFloatArrayValue(env, newmin4, "newmin4", 4)(),
+ GetJFloatArrayValue(env, newmax4, "newmax4", 4)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_MatrixTransform_Identity(JNIEnv * env, jobject self,
+ jfloatArray m44, jfloatArray offset4)
+{
+ OCIO_JNITRY_ENTER()
+ ConstMatrixTransformRcPtr mtran = GetConstJOCIO<ConstMatrixTransformRcPtr, MatrixTransformJNI>(env, self);
+ mtran->Identity(GetJFloatArrayValue(env, m44, "m44", 16)(),
+ GetJFloatArrayValue(env, offset4, "offset4", 4)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_MatrixTransform_Sat(JNIEnv * env, jobject self,
+ jfloatArray m44, jfloatArray offset4, jfloat sat,
+ jfloatArray lumaCoef3)
+{
+ OCIO_JNITRY_ENTER()
+ ConstMatrixTransformRcPtr mtran = GetConstJOCIO<ConstMatrixTransformRcPtr, MatrixTransformJNI>(env, self);
+ mtran->Sat(GetJFloatArrayValue(env, m44, "m44", 16)(),
+ GetJFloatArrayValue(env, offset4, "offset4", 4)(),
+ (float)sat,
+ GetJFloatArrayValue(env, lumaCoef3, "lumaCoef3", 3)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_MatrixTransform_Scale(JNIEnv * env, jobject self,
+ jfloatArray m44, jfloatArray offset4, jfloatArray scale4)
+{
+ OCIO_JNITRY_ENTER()
+ ConstMatrixTransformRcPtr mtran = GetConstJOCIO<ConstMatrixTransformRcPtr, MatrixTransformJNI>(env, self);
+ mtran->Scale(GetJFloatArrayValue(env, m44, "m44", 16)(),
+ GetJFloatArrayValue(env, offset4, "offset4", 4)(),
+ GetJFloatArrayValue(env, scale4, "scale4", 4)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_MatrixTransform_View(JNIEnv * env, jobject self,
+ jfloatArray m44, jfloatArray offset4, jintArray channelHot4,
+ jfloatArray lumaCoef3)
+{
+ OCIO_JNITRY_ENTER()
+ ConstMatrixTransformRcPtr mtran = GetConstJOCIO<ConstMatrixTransformRcPtr, MatrixTransformJNI>(env, self);
+ mtran->View(GetJFloatArrayValue(env, m44, "m44", 16)(),
+ GetJFloatArrayValue(env, offset4, "offset4", 4)(),
+ GetJIntArrayValue(env, channelHot4, "channelHot4", 4)(),
+ GetJFloatArrayValue(env, lumaCoef3, "lumaCoef3", 3)());
+ OCIO_JNITRY_EXIT()
+}
+
+// TruelightTransform
+
+JNIEXPORT jobject JNICALL
+Java_org_OpenColorIO_TruelightTransform_Create(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ return BuildJObject<TruelightTransformRcPtr, TruelightTransformJNI>(env, self,
+ env->FindClass("org/OpenColorIO/TruelightTransform"), TruelightTransform::Create());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_TruelightTransform_setConfigRoot(JNIEnv * env, jobject self, jstring configroot)
+{
+ OCIO_JNITRY_ENTER()
+ TruelightTransformRcPtr ttran = GetEditableJOCIO<TruelightTransformRcPtr, TruelightTransformJNI>(env, self);
+ ttran->setConfigRoot(GetJStringValue(env, configroot)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_TruelightTransform_getConfigRoot(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstTruelightTransformRcPtr ttran = GetConstJOCIO<ConstTruelightTransformRcPtr, TruelightTransformJNI>(env, self);
+ return env->NewStringUTF(ttran->getConfigRoot());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_TruelightTransform_setProfile(JNIEnv * env, jobject self, jstring profile)
+{
+ OCIO_JNITRY_ENTER()
+ TruelightTransformRcPtr ttran = GetEditableJOCIO<TruelightTransformRcPtr, TruelightTransformJNI>(env, self);
+ ttran->setProfile(GetJStringValue(env, profile)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_TruelightTransform_getProfile(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstTruelightTransformRcPtr ttran = GetConstJOCIO<ConstTruelightTransformRcPtr, TruelightTransformJNI>(env, self);
+ return env->NewStringUTF(ttran->getProfile());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_TruelightTransform_setCamera(JNIEnv * env, jobject self, jstring camera)
+{
+ OCIO_JNITRY_ENTER()
+ TruelightTransformRcPtr ttran = GetEditableJOCIO<TruelightTransformRcPtr, TruelightTransformJNI>(env, self);
+ ttran->setCamera(GetJStringValue(env, camera)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_TruelightTransform_getCamera(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstTruelightTransformRcPtr ttran = GetConstJOCIO<ConstTruelightTransformRcPtr, TruelightTransformJNI>(env, self);
+ return env->NewStringUTF(ttran->getCamera());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_TruelightTransform_setInputDisplay(JNIEnv * env, jobject self, jstring display)
+{
+ OCIO_JNITRY_ENTER()
+ TruelightTransformRcPtr ttran = GetEditableJOCIO<TruelightTransformRcPtr, TruelightTransformJNI>(env, self);
+ ttran->setInputDisplay(GetJStringValue(env, display)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_TruelightTransform_getInputDisplay(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstTruelightTransformRcPtr ttran = GetConstJOCIO<ConstTruelightTransformRcPtr, TruelightTransformJNI>(env, self);
+ return env->NewStringUTF(ttran->getInputDisplay());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_TruelightTransform_setRecorder(JNIEnv * env, jobject self, jstring recorder)
+{
+ OCIO_JNITRY_ENTER()
+ TruelightTransformRcPtr ttran = GetEditableJOCIO<TruelightTransformRcPtr, TruelightTransformJNI>(env, self);
+ ttran->setRecorder(GetJStringValue(env, recorder)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_TruelightTransform_getRecorder(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstTruelightTransformRcPtr ttran = GetConstJOCIO<ConstTruelightTransformRcPtr, TruelightTransformJNI>(env, self);
+ return env->NewStringUTF(ttran->getRecorder());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_TruelightTransform_setPrint(JNIEnv * env, jobject self, jstring print)
+{
+ OCIO_JNITRY_ENTER()
+ TruelightTransformRcPtr ttran = GetEditableJOCIO<TruelightTransformRcPtr, TruelightTransformJNI>(env, self);
+ ttran->setPrint(GetJStringValue(env, print)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_TruelightTransform_getPrint(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstTruelightTransformRcPtr ttran = GetConstJOCIO<ConstTruelightTransformRcPtr, TruelightTransformJNI>(env, self);
+ return env->NewStringUTF(ttran->getPrint());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_TruelightTransform_setLamp(JNIEnv * env, jobject self, jstring lamp)
+{
+ OCIO_JNITRY_ENTER()
+ TruelightTransformRcPtr ttran = GetEditableJOCIO<TruelightTransformRcPtr, TruelightTransformJNI>(env, self);
+ ttran->setLamp(GetJStringValue(env, lamp)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_TruelightTransform_getLamp(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstTruelightTransformRcPtr ttran = GetConstJOCIO<ConstTruelightTransformRcPtr, TruelightTransformJNI>(env, self);
+ return env->NewStringUTF(ttran->getLamp());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_TruelightTransform_setOutputCamera(JNIEnv * env, jobject self, jstring camera)
+{
+ OCIO_JNITRY_ENTER()
+ TruelightTransformRcPtr ttran = GetEditableJOCIO<TruelightTransformRcPtr, TruelightTransformJNI>(env, self);
+ ttran->setOutputCamera(GetJStringValue(env, camera)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_TruelightTransform_getOutputCamera(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstTruelightTransformRcPtr ttran = GetConstJOCIO<ConstTruelightTransformRcPtr, TruelightTransformJNI>(env, self);
+ return env->NewStringUTF(ttran->getOutputCamera());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_TruelightTransform_setDisplay(JNIEnv * env, jobject self, jstring display)
+{
+ OCIO_JNITRY_ENTER()
+ TruelightTransformRcPtr ttran = GetEditableJOCIO<TruelightTransformRcPtr, TruelightTransformJNI>(env, self);
+ ttran->setDisplay(GetJStringValue(env, display)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_TruelightTransform_getDisplay(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstTruelightTransformRcPtr ttran = GetConstJOCIO<ConstTruelightTransformRcPtr, TruelightTransformJNI>(env, self);
+ return env->NewStringUTF(ttran->getDisplay());
+ OCIO_JNITRY_EXIT(NULL)
+}
+
+JNIEXPORT void JNICALL
+Java_org_OpenColorIO_TruelightTransform_setCubeInput(JNIEnv * env, jobject self, jstring type)
+{
+ OCIO_JNITRY_ENTER()
+ TruelightTransformRcPtr ttran = GetEditableJOCIO<TruelightTransformRcPtr, TruelightTransformJNI>(env, self);
+ ttran->setCubeInput(GetJStringValue(env, type)());
+ OCIO_JNITRY_EXIT()
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_OpenColorIO_TruelightTransform_getCubeInput(JNIEnv * env, jobject self)
+{
+ OCIO_JNITRY_ENTER()
+ ConstTruelightTransformRcPtr ttran = GetConstJOCIO<ConstTruelightTransformRcPtr, TruelightTransformJNI>(env, self);
+ return env->NewStringUTF(ttran->getCubeInput());
+ OCIO_JNITRY_EXIT(NULL)
+}
diff --git a/src/jniglue/JNIUtil.cpp b/src/jniglue/JNIUtil.cpp
new file mode 100644
index 0000000..b893098
--- /dev/null
+++ b/src/jniglue/JNIUtil.cpp
@@ -0,0 +1,122 @@
+/*
+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 "JNIUtil.h"
+
+OCIO_NAMESPACE_ENTER
+{
+
+jobject NewJFloatBuffer(JNIEnv * env, float* ptr, int32_t len) {
+ jobject byte_buf = env->NewDirectByteBuffer(ptr, len * sizeof(float));
+ jmethodID mid = env->GetMethodID(env->GetObjectClass(byte_buf),
+ "asFloatBuffer", "()Ljava/nio/FloatBuffer;");
+ if (mid == 0) throw Exception("Could not find asFloatBuffer() method");
+ return env->CallObjectMethod(byte_buf, mid);
+}
+
+float* GetJFloatBuffer(JNIEnv * env, jobject buffer, int32_t len) {
+ jmethodID mid = env->GetMethodID(env->GetObjectClass(buffer), "isDirect", "()Z");
+ if (mid == 0) throw Exception("Could not find isDirect() method");
+ if(!env->CallBooleanMethod(buffer, mid)) {
+ std::ostringstream err;
+ err << "the FloatBuffer object is not 'direct' it needs to be created ";
+ err << "from a ByteBuffer.allocateDirect(..).asFloatBuffer() call.";
+ throw Exception(err.str().c_str());
+ }
+ if(env->GetDirectBufferCapacity(buffer) != len) {
+ std::ostringstream err;
+ err << "the FloatBuffer object is not allocated correctly it needs to ";
+ err << "of size " << len << " but is ";
+ err << env->GetDirectBufferCapacity(buffer) << ".";
+ throw Exception(err.str().c_str());
+ }
+ return (float*)env->GetDirectBufferAddress(buffer);
+}
+
+const char* GetOCIOTClass(ConstTransformRcPtr tran) {
+ if(ConstAllocationTransformRcPtr at = DynamicPtrCast<const AllocationTransform>(tran))
+ return "org/OpenColorIO/AllocationTransform";
+ else if(ConstCDLTransformRcPtr ct = DynamicPtrCast<const CDLTransform>(tran))
+ return "org/OpenColorIO/CDLTransform";
+ else if(ConstColorSpaceTransformRcPtr cst = DynamicPtrCast<const ColorSpaceTransform>(tran))
+ return "org/OpenColorIO/ColorSpaceTransform";
+ else if(ConstDisplayTransformRcPtr dt = DynamicPtrCast<const DisplayTransform>(tran))
+ return "org/OpenColorIO/DisplayTransform";
+ else if(ConstExponentTransformRcPtr et = DynamicPtrCast<const ExponentTransform>(tran))
+ return "org/OpenColorIO/ExponentTransform";
+ else if(ConstFileTransformRcPtr ft = DynamicPtrCast<const FileTransform>(tran))
+ return "org/OpenColorIO/FileTransform";
+ else if(ConstGroupTransformRcPtr gt = DynamicPtrCast<const GroupTransform>(tran))
+ return "org/OpenColorIO/GroupTransform";
+ else if(ConstLogTransformRcPtr lt = DynamicPtrCast<const LogTransform>(tran))
+ return "org/OpenColorIO/LogTransform";
+ else if(ConstLookTransformRcPtr lkt = DynamicPtrCast<const LookTransform>(tran))
+ return "org/OpenColorIO/LookTransform";
+ else if(ConstMatrixTransformRcPtr mt = DynamicPtrCast<const MatrixTransform>(tran))
+ return "org/OpenColorIO/MatrixTransform";
+ else if(ConstTruelightTransformRcPtr tt = DynamicPtrCast<const TruelightTransform>(tran))
+ return "org/OpenColorIO/TruelightTransform";
+ else return "org/OpenColorIO/Transform";
+}
+
+void JNI_Handle_Exception(JNIEnv * env)
+{
+ try
+ {
+ throw;
+ }
+ catch (ExceptionMissingFile & e)
+ {
+ jclass je = env->FindClass("org/OpenColorIO/ExceptionMissingFile");
+ env->ThrowNew(je, e.what());
+ env->DeleteLocalRef(je);
+ }
+ catch (Exception & e)
+ {
+ jclass je = env->FindClass("org/OpenColorIO/ExceptionBase");
+ env->ThrowNew(je, e.what());
+ env->DeleteLocalRef(je);
+ }
+ catch (std::exception& e)
+ {
+ jclass je = env->FindClass("java/lang/Exception");
+ env->ThrowNew(je, e.what());
+ env->DeleteLocalRef(je);
+ }
+ catch (...)
+ {
+ jclass je = env->FindClass("java/lang/Exception");
+ env->ThrowNew(je, "Unknown C++ exception caught.");
+ env->DeleteLocalRef(je);
+ }
+}
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/jniglue/JNIUtil.h b/src/jniglue/JNIUtil.h
new file mode 100644
index 0000000..cf9381c
--- /dev/null
+++ b/src/jniglue/JNIUtil.h
@@ -0,0 +1,282 @@
+/*
+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.
+*/
+
+#ifndef INCLUDED_OCIO_JNIUTIL_H
+#define INCLUDED_OCIO_JNIUTIL_H
+
+#include <sstream>
+#include <vector>
+#include "OpenColorIOJNI.h"
+
+OCIO_NAMESPACE_ENTER
+{
+
+template<typename C, typename E>
+struct JObject
+{
+ jobject back_ptr;
+ C * constcppobj;
+ E * cppobj;
+ bool isconst;
+};
+
+typedef OCIO_SHARED_PTR<const GpuShaderDesc> ConstGpuShaderDescRcPtr;
+typedef OCIO_SHARED_PTR<GpuShaderDesc> GpuShaderDescRcPtr;
+typedef OCIO_SHARED_PTR<const ImageDesc> ConstImageDescRcPtr;
+typedef OCIO_SHARED_PTR<ImageDesc> ImageDescRcPtr;
+typedef OCIO_SHARED_PTR<const PackedImageDesc> ConstPackedImageDescRcPtr;
+typedef OCIO_SHARED_PTR<PackedImageDesc> PackedImageDescRcPtr;
+typedef OCIO_SHARED_PTR<const PlanarImageDesc> ConstPlanarImageDescRcPtr;
+typedef OCIO_SHARED_PTR<PlanarImageDesc> PlanarImageDescRcPtr;
+
+typedef JObject <ConstConfigRcPtr, ConfigRcPtr> ConfigJNI;
+typedef JObject <ConstContextRcPtr, ContextRcPtr> ContextJNI;
+typedef JObject <ConstProcessorRcPtr, ProcessorRcPtr> ProcessorJNI;
+typedef JObject <ConstColorSpaceRcPtr, ColorSpaceRcPtr> ColorSpaceJNI;
+typedef JObject <ConstLookRcPtr, LookRcPtr> LookJNI;
+typedef JObject <ConstBakerRcPtr, BakerRcPtr> BakerJNI;
+typedef JObject <ConstGpuShaderDescRcPtr, GpuShaderDescRcPtr> GpuShaderDescJNI;
+typedef JObject <ConstImageDescRcPtr, ImageDescRcPtr> ImageDescJNI;
+typedef JObject <ConstTransformRcPtr, TransformRcPtr> TransformJNI;
+typedef JObject <ConstAllocationTransformRcPtr, AllocationTransformRcPtr> AllocationTransformJNI;
+typedef JObject <ConstCDLTransformRcPtr, CDLTransformRcPtr> CDLTransformJNI;
+typedef JObject <ConstColorSpaceTransformRcPtr, ColorSpaceTransformRcPtr> ColorSpaceTransformJNI;
+typedef JObject <ConstDisplayTransformRcPtr, DisplayTransformRcPtr> DisplayTransformJNI;
+typedef JObject <ConstExponentTransformRcPtr, ExponentTransformRcPtr> ExponentTransformJNI;
+typedef JObject <ConstFileTransformRcPtr, FileTransformRcPtr> FileTransformJNI;
+typedef JObject <ConstGroupTransformRcPtr, GroupTransformRcPtr> GroupTransformJNI;
+typedef JObject <ConstLogTransformRcPtr, LogTransformRcPtr> LogTransformJNI;
+typedef JObject <ConstLookTransformRcPtr, LookTransformRcPtr> LookTransformJNI;
+typedef JObject <ConstMatrixTransformRcPtr, MatrixTransformRcPtr> MatrixTransformJNI;
+typedef JObject <ConstTruelightTransformRcPtr, TruelightTransformRcPtr> TruelightTransformJNI;
+
+template<typename T, typename S>
+inline jobject BuildJConstObject(JNIEnv * env, jobject self, jclass cls, T ptr)
+{
+ S * jnistruct = new S ();
+ jnistruct->back_ptr = env->NewGlobalRef(self);
+ jnistruct->constcppobj = new T ();
+ *jnistruct->constcppobj = ptr;
+ jnistruct->isconst = true;
+ jmethodID mid = env->GetMethodID(cls, "<init>", "(J)V");
+ return env->NewObject(cls, mid, (jlong)jnistruct);
+}
+
+template<typename T, typename S>
+inline jobject BuildJObject(JNIEnv * env, jobject self, jclass cls, T ptr)
+{
+ S * jnistruct = new S ();
+ jnistruct->back_ptr = env->NewGlobalRef(self);
+ jnistruct->cppobj = new T ();
+ *jnistruct->cppobj = ptr;
+ jnistruct->isconst = false;
+ jmethodID mid = env->GetMethodID(cls, "<init>", "(J)V");
+ return env->NewObject(cls, mid, (jlong)jnistruct);
+}
+
+template<typename S>
+inline void DisposeJOCIO(JNIEnv * env, jobject self)
+{
+ jclass wclass = env->GetObjectClass(self);
+ jfieldID fid = env->GetFieldID(wclass, "m_impl", "J");
+ jlong m_impl = env->GetLongField(self, fid);
+ if(m_impl == 0) return; // nothing to do
+ S * jni = reinterpret_cast<S *> (m_impl);
+ delete jni->constcppobj;
+ delete jni->cppobj;
+ env->DeleteGlobalRef(jni->back_ptr);
+ delete jni;
+ env->SetLongField(self, fid, 0);
+ return;
+}
+
+template<typename T, typename S>
+inline T GetConstJOCIO(JNIEnv * env, jobject self)
+{
+ jclass wclass = env->GetObjectClass(self);
+ jfieldID fid = env->GetFieldID(wclass, "m_impl", "J");
+ jlong m_impl = env->GetLongField(self, fid);
+ if(m_impl == 0) {
+ throw Exception("Java object doesn't point to a OCIO object");
+ }
+ S * jni = reinterpret_cast<S *> (m_impl);
+ if(jni->isconst && jni->constcppobj) {
+ return *jni->constcppobj;
+ }
+ if(!jni->isconst && jni->cppobj) {
+ return *jni->cppobj;
+ }
+ throw Exception("Could not get a const OCIO object");
+}
+
+template<typename T, typename S>
+inline T GetEditableJOCIO(JNIEnv * env, jobject self)
+{
+ jclass wclass = env->GetObjectClass(self);
+ jfieldID fid = env->GetFieldID(wclass, "m_impl", "J");
+ jlong m_impl = env->GetLongField(self, fid);
+ if(m_impl == 0) {
+ throw Exception("Java object doesn't point to a OCIO object");
+ }
+ S * jni = reinterpret_cast<S *> (m_impl);
+ if(!jni->isconst && jni->cppobj) {
+ return *jni->cppobj;
+ }
+ throw Exception("Could not get an editable OCIO object");
+}
+
+template<typename T>
+inline T GetJEnum(JNIEnv * env, jobject j_enum)
+{
+ jclass cls = env->GetObjectClass(j_enum);
+ jfieldID fid = env->GetFieldID(cls, "m_enum", "I");
+ return (T)env->GetIntField(j_enum, fid);
+}
+
+template<typename T>
+inline jobject BuildJEnum(JNIEnv * env, const char* ociotype, T val)
+{
+ jclass cls = env->FindClass(ociotype);
+ jmethodID mid = env->GetMethodID(cls, "<init>", "(I)V");
+ return env->NewObject(cls, mid, (int)val);
+}
+
+template<typename T>
+inline void CheckArrayLength(JNIEnv * env, const char* name, T ptr, int32_t length) {
+ if(ptr == NULL) return;
+ if(env->GetArrayLength(ptr) < length) {
+ std::ostringstream err;
+ err << name << " needs to have " << length;
+ err << " elements but found only " << env->GetArrayLength(ptr);
+ throw Exception(err.str().c_str());
+ }
+}
+
+class GetJFloatArrayValue
+{
+public:
+ GetJFloatArrayValue(JNIEnv* env, jfloatArray val, const char* name, int32_t len) {
+ CheckArrayLength(env, name, val, len);
+ m_env = env;
+ m_val = val;
+ if(val != NULL) m_ptr = env->GetFloatArrayElements(val, JNI_FALSE);
+ }
+ ~GetJFloatArrayValue() {
+ if(m_val != NULL) m_env->ReleaseFloatArrayElements(m_val, m_ptr, JNI_FALSE);
+ m_val = NULL;
+ m_ptr = NULL;
+ }
+ jfloat* operator() () {
+ return m_ptr;
+ }
+private:
+ JNIEnv* m_env;
+ jfloat* m_ptr;
+ jfloatArray m_val;
+};
+
+class SetJFloatArrayValue
+{
+public:
+ SetJFloatArrayValue(JNIEnv* env, jfloatArray val, const char* name, int32_t len) {
+ CheckArrayLength(env, name, val, len);
+ m_env = env;
+ m_val = val;
+ if(val != NULL) m_tmp.resize(len);
+ }
+ ~SetJFloatArrayValue() {
+ if(m_val != NULL) m_env->SetFloatArrayRegion(m_val, 0, m_tmp.size(), &m_tmp[0]);
+ m_val = NULL;
+ m_tmp.clear();
+ }
+ float* operator() () {
+ return &m_tmp[0];
+ }
+private:
+ JNIEnv* m_env;
+ std::vector<float> m_tmp;
+ jfloatArray m_val;
+};
+
+class GetJIntArrayValue
+{
+public:
+ GetJIntArrayValue(JNIEnv* env, jintArray val, const char* name, int32_t len) {
+ CheckArrayLength(env, name, val, len);
+ m_env = env;
+ m_val = val;
+ if(val != NULL) m_ptr = env->GetIntArrayElements(val, JNI_FALSE);
+ }
+ ~GetJIntArrayValue() {
+ if(m_val != NULL) m_env->ReleaseIntArrayElements(m_val, m_ptr, JNI_FALSE);
+ m_val = NULL;
+ m_ptr = NULL;
+ }
+ jint* operator() () {
+ return m_ptr;
+ }
+private:
+ JNIEnv* m_env;
+ jint* m_ptr;
+ jintArray m_val;
+};
+
+class GetJStringValue
+{
+public:
+ GetJStringValue(JNIEnv* env, jstring val) {
+ m_env = env;
+ m_val = val;
+ if(val != NULL) m_tmp = env->GetStringUTFChars(m_val, 0);
+ }
+ ~GetJStringValue() {
+ if(m_val != NULL) m_env->ReleaseStringUTFChars(m_val, m_tmp);
+ m_val = NULL;
+ m_tmp = NULL;
+ }
+ const char* operator() () {
+ return m_tmp;
+ }
+private:
+ JNIEnv* m_env;
+ const char* m_tmp;
+ jstring m_val;
+};
+
+jobject NewJFloatBuffer(JNIEnv * env, float* ptr, int32_t len);
+float* GetJFloatBuffer(JNIEnv * env, jobject buffer, int32_t len);
+const char* GetOCIOTClass(ConstTransformRcPtr tran);
+void JNI_Handle_Exception(JNIEnv * env);
+
+#define OCIO_JNITRY_ENTER() try {
+#define OCIO_JNITRY_EXIT(ret) } catch(...) { JNI_Handle_Exception(env); return ret; }
+
+}
+OCIO_NAMESPACE_EXIT
+
+#endif // INCLUDED_OCIO_JNIUTIL_H
diff --git a/src/jniglue/LoadLibrary.java.in b/src/jniglue/LoadLibrary.java.in
new file mode 100644
index 0000000..41818d6
--- /dev/null
+++ b/src/jniglue/LoadLibrary.java.in
@@ -0,0 +1,40 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+
+public class LoadLibrary
+{
+ public LoadLibrary() { }
+ protected LoadLibrary(long impl) { m_impl = impl; }
+ public long m_impl = 0;
+ static
+ {
+ System.loadLibrary("OpenColorIO-JNI.@OCIO_VERSION@");
+ }
+}
diff --git a/src/jniglue/Manifest.txt.in b/src/jniglue/Manifest.txt.in
new file mode 100644
index 0000000..71a5142
--- /dev/null
+++ b/src/jniglue/Manifest.txt.in
@@ -0,0 +1,7 @@
+Name: org/OpenColorIO/
+Specification-Title: OpenColorIO - Open Source Color Management
+Specification-Version: @OCIO_VERSION@
+Specification-Vendor: Sony Pictures Imageworks Inc., et al.
+Implementation-Title: org.OpenColorIO
+Implementation-Version: @OCIO_VERSION@
+Implementation-Vendor: Sony Pictures Imageworks Inc., et al. \ No newline at end of file
diff --git a/src/jniglue/org/OpenColorIO/Allocation.java b/src/jniglue/org/OpenColorIO/Allocation.java
new file mode 100644
index 0000000..3d80251
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/Allocation.java
@@ -0,0 +1,44 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class Allocation extends LoadLibrary
+{
+ private final int m_enum;
+ protected Allocation(int type) { super(); m_enum = type; }
+ public native String toString();
+ public native boolean equals(Object obj);
+ public static final Allocation
+ ALLOCATION_UNKNOWN = new Allocation(0);
+ public static final Allocation
+ ALLOCATION_UNIFORM = new Allocation(1);
+ public static final Allocation
+ ALLOCATION_LG2 = new Allocation(2);
+}
diff --git a/src/jniglue/org/OpenColorIO/AllocationTransform.java b/src/jniglue/org/OpenColorIO/AllocationTransform.java
new file mode 100644
index 0000000..b116d18
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/AllocationTransform.java
@@ -0,0 +1,42 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class AllocationTransform extends Transform
+{
+ public AllocationTransform() { super(); }
+ protected AllocationTransform(long impl) { super(impl); }
+ public native AllocationTransform Create();
+ public native Allocation getAllocation();
+ public native void setAllocation(Allocation allocation);
+ public native int getNumVars();
+ public native void getVars(float[] vars);
+ public native void setVars(int numvars, float[] vars);
+}
diff --git a/src/jniglue/org/OpenColorIO/Baker.java b/src/jniglue/org/OpenColorIO/Baker.java
new file mode 100644
index 0000000..0464753
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/Baker.java
@@ -0,0 +1,62 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class Baker extends LoadLibrary
+{
+ public Baker() { super(); }
+ protected Baker(long impl) { super(impl); }
+ public native void dispose();
+ protected void finalize() { dispose(); }
+ public native Baker Create();
+ public native Baker createEditableCopy();
+ public native void setConfig(Config config);
+ public native Config getConfig();
+ public native void setFormat(String formatName);
+ public native String getFormat();
+ public native void setType(String type);
+ public native String getType();
+ public native void setMetadata(String metadata);
+ public native String getMetadata();
+ public native void setInputSpace(String inputSpace);
+ public native String getInputSpace();
+ public native void setShaperSpace(String shaperSpace);
+ public native String getShaperSpace();
+ public native void setTargetSpace(String targetSpace);
+ public native String getTargetSpace();
+ public native void setShaperSize(int shapersize);
+ public native int getShaperSize();
+ public native void setCubeSize(int cubesize);
+ public native int getCubeSize();
+ public native String bake();
+ public native int getNumFormats();
+ public native String getFormatNameByIndex(int index);
+ public native String getFormatExtensionByIndex(int index);
+}
diff --git a/src/jniglue/org/OpenColorIO/BitDepth.java b/src/jniglue/org/OpenColorIO/BitDepth.java
new file mode 100644
index 0000000..afa0543
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/BitDepth.java
@@ -0,0 +1,56 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class BitDepth extends LoadLibrary
+{
+ private final int m_enum;
+ protected BitDepth(int type) { super(); m_enum = type; }
+ public native String toString();
+ public native boolean equals(Object obj);
+ public static final BitDepth
+ BIT_DEPTH_UNKNOWN = new BitDepth(0);
+ public static final BitDepth
+ BIT_DEPTH_UINT8 = new BitDepth(1);
+ public static final BitDepth
+ BIT_DEPTH_UINT10 = new BitDepth(2);
+ public static final BitDepth
+ BIT_DEPTH_UINT12 = new BitDepth(3);
+ public static final BitDepth
+ BIT_DEPTH_UINT14 = new BitDepth(4);
+ public static final BitDepth
+ BIT_DEPTH_UINT16 = new BitDepth(5);
+ public static final BitDepth
+ BIT_DEPTH_UINT32 = new BitDepth(6);
+ public static final BitDepth
+ BIT_DEPTH_F16 = new BitDepth(7);
+ public static final BitDepth
+ BIT_DEPTH_F32 = new BitDepth(8);
+}
diff --git a/src/jniglue/org/OpenColorIO/CDLTransform.java b/src/jniglue/org/OpenColorIO/CDLTransform.java
new file mode 100644
index 0000000..ce0fd00
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/CDLTransform.java
@@ -0,0 +1,56 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class CDLTransform extends Transform
+{
+ public CDLTransform() { super(); }
+ protected CDLTransform(long impl) { super(impl); }
+ public native CDLTransform Create();
+ public native CDLTransform CreateFromFile(String src, String cccid);
+ public native boolean equals(CDLTransform obj);
+ public native String getXML();
+ public native void setXML(String xml);
+ public native void setSlope(float[] rgb);
+ public native void getSlope(float[] rgb);
+ public native void setOffset(float[] rgb);
+ public native void getOffset(float[] rgb);
+ public native void setPower(float[] rgb);
+ public native void getPower(float[] rgb);
+ public native void setSOP(float[] vec9);
+ public native void getSOP(float[] vec9);
+ public native void setSat(float sat);
+ public native float getSat();
+ public native void getSatLumaCoefs(float[] rgb);
+ public native void setID(String id);
+ public native String getID();
+ public native void setDescription(String desc);
+ public native String getDescription();
+}
diff --git a/src/jniglue/org/OpenColorIO/ColorSpace.java b/src/jniglue/org/OpenColorIO/ColorSpace.java
new file mode 100644
index 0000000..11e7198
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/ColorSpace.java
@@ -0,0 +1,59 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class ColorSpace extends LoadLibrary
+{
+ public ColorSpace() { super(); }
+ protected ColorSpace(long impl) { super(impl); }
+ public native void dispose();
+ protected void finalize() { dispose(); }
+ public native ColorSpace Create();
+ public native ColorSpace createEditableCopy();
+ public native String getName();
+ public native void setName(String name);
+ public native String getFamily();
+ public native void setFamily(String family);
+ public native String getEqualityGroup();
+ public native void setEqualityGroup(String equalityGroup);
+ public native String getDescription();
+ public native void setDescription(String description);
+ public native BitDepth getBitDepth();
+ public native void setBitDepth(BitDepth bitDepth);
+ public native boolean isData();
+ public native void setIsData(boolean isData);
+ public native Allocation getAllocation();
+ public native void setAllocation(Allocation allocation);
+ public native int getAllocationNumVars();
+ public native void getAllocationVars(float[] vars);
+ public native void setAllocationVars(int numvars, float[] vars);
+ public native Transform getTransform(ColorSpaceDirection dir);
+ public native void setTransform(Transform transform, ColorSpaceDirection dir);
+}
diff --git a/src/jniglue/org/OpenColorIO/ColorSpaceDirection.java b/src/jniglue/org/OpenColorIO/ColorSpaceDirection.java
new file mode 100644
index 0000000..a822f6e
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/ColorSpaceDirection.java
@@ -0,0 +1,44 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class ColorSpaceDirection extends LoadLibrary
+{
+ private final int m_enum;
+ protected ColorSpaceDirection(int type) { super(); m_enum = type; }
+ public native String toString();
+ public native boolean equals(Object obj);
+ public static final ColorSpaceDirection
+ COLORSPACE_DIR_UNKNOWN = new ColorSpaceDirection(0);
+ public static final ColorSpaceDirection
+ COLORSPACE_DIR_TO_REFERENCE = new ColorSpaceDirection(1);
+ public static final ColorSpaceDirection
+ COLORSPACE_DIR_FROM_REFERENCE = new ColorSpaceDirection(2);
+}
diff --git a/src/jniglue/org/OpenColorIO/ColorSpaceTransform.java b/src/jniglue/org/OpenColorIO/ColorSpaceTransform.java
new file mode 100644
index 0000000..ffc856b
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/ColorSpaceTransform.java
@@ -0,0 +1,41 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class ColorSpaceTransform extends Transform
+{
+ public ColorSpaceTransform() { super(); }
+ protected ColorSpaceTransform(long impl) { super(impl); }
+ public native ColorSpaceTransform Create();
+ public native String getSrc();
+ public native void setSrc(String src);
+ public native String getDst();
+ public native void setDst(String dst);
+}
diff --git a/src/jniglue/org/OpenColorIO/Config.java b/src/jniglue/org/OpenColorIO/Config.java
new file mode 100644
index 0000000..f35ca65
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/Config.java
@@ -0,0 +1,96 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class Config extends LoadLibrary
+{
+ public Config() { super(); }
+ protected Config(long impl) { super(impl); }
+ public native void dispose();
+ protected void finalize() { dispose(); }
+ public native Config Create();
+ public native Config CreateFromEnv();
+ public native Config CreateFromFile(String filename);
+ public native Config CreateFromStream(String istream);
+ public native Config createEditableCopy();
+ public native void sanityCheck();
+ public native String getDescription();
+ public native void setDescription(String description);
+ public native String serialize();
+ public native String getCacheID();
+ public native String getCacheID(Context context);
+ public native Context getCurrentContext();
+ public native String getSearchPath();
+ public native void setSearchPath(String path);
+ public native String getWorkingDir();
+ public native void setWorkingDir(String dirname);
+ public native int getNumColorSpaces();
+ public native String getColorSpaceNameByIndex(int index);
+ public native ColorSpace getColorSpace(String name);
+ public native int getIndexForColorSpace(String name);
+ public native void addColorSpace(ColorSpace cs);
+ public native void clearColorSpaces();
+ public native String parseColorSpaceFromString(String str);
+ public native boolean isStrictParsingEnabled();
+ public native void setStrictParsingEnabled(boolean enabled);
+ public native void setRole(String role, String colorSpaceName);
+ public native int getNumRoles();
+ public native boolean hasRole(String role);
+ public native String getRoleName(int index);
+ public native String getDefaultDisplay();
+ public native int getNumDisplays();
+ public native String getDisplay(int index);
+ public native String getDefaultView(String display);
+ public native int getNumViews(String display);
+ public native String getView(String display, int index);
+ public native String getDisplayColorSpaceName(String display, String view);
+ public native String getDisplayLooks(String display, String view);
+ // TODO: seems that 4 string params causes a memory error in the JNI layer?
+ // public native void addDisplay(String display, String view, String colorSpaceName, int looks);
+ public native void clearDisplays();
+ public native void setActiveDisplays(String displays);
+ public native String getActiveDisplays();
+ public native void setActiveViews(String views);
+ public native String getActiveViews();
+ public native void getDefaultLumaCoefs(float[] rgb);
+ public native void setDefaultLumaCoefs(float[] rgb);
+ public native Look getLook(String name);
+ public native int getNumLooks();
+ public native String getLookNameByIndex(int index);
+ public native void addLook(Look look);
+ public native void clearLooks();
+ public native Processor getProcessor(Context context, ColorSpace srcColorSpace, ColorSpace dstColorSpace);
+ public native Processor getProcessor(ColorSpace srcColorSpace, ColorSpace dstColorSpace);
+ public native Processor getProcessor(String srcName, String dstName);
+ public native Processor getProcessor(Context context, String srcName, String dstName);
+ public native Processor getProcessor(Transform transform);
+ public native Processor getProcessor(Transform transform, TransformDirection direction);
+ public native Processor getProcessor(Context context, Transform transform, TransformDirection direction);
+}
diff --git a/src/jniglue/org/OpenColorIO/Context.java b/src/jniglue/org/OpenColorIO/Context.java
new file mode 100644
index 0000000..eaec345
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/Context.java
@@ -0,0 +1,52 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class Context extends LoadLibrary
+{
+ public Context() { super(); }
+ protected Context(long impl) { super(impl); }
+ public native void dispose();
+ protected void finalize() { dispose(); }
+ public native Context Create();
+ public native Context createEditableCopy();
+ public native String getCacheID();
+ public native void setSearchPath(String path);
+ public native String getSearchPath();
+ public native void setWorkingDir(String dirname);
+ public native String getWorkingDir();
+ public native void setStringVar(String name, String value);
+ public native String getStringVar(String name);
+ public native int getNumStringVars();
+ public native String getStringVarNameByIndex(int index);
+ public native void loadEnvironment();
+ public native String resolveStringVar(String val);
+ public native String resolveFileLocation(String filename) throws ExceptionMissingFile;
+}
diff --git a/src/jniglue/org/OpenColorIO/DisplayTransform.java b/src/jniglue/org/OpenColorIO/DisplayTransform.java
new file mode 100644
index 0000000..0867029
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/DisplayTransform.java
@@ -0,0 +1,55 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class DisplayTransform extends Transform
+{
+ public DisplayTransform() { super(); }
+ protected DisplayTransform(long impl) { super(impl); }
+ public native DisplayTransform Create();
+ public native void setInputColorSpaceName(String name);
+ public native String getInputColorSpaceName();
+ public native void setLinearCC(Transform cc);
+ public native Transform getLinearCC();
+ public native void setColorTimingCC(Transform cc);
+ public native Transform getColorTimingCC();
+ public native void setChannelView(Transform transform);
+ public native Transform getChannelView();
+ public native void setDisplay(String display);
+ public native String getDisplay();
+ public native void setView(String view);
+ public native String getView();
+ public native void setDisplayCC(Transform cc);
+ public native Transform getDisplayCC();
+ public native void setLooksOverride(String looks);
+ public native String getLooksOverride();
+ public native void setLooksOverrideEnabled(boolean enabled);
+ public native boolean getLooksOverrideEnabled();
+}
diff --git a/src/jniglue/org/OpenColorIO/ExceptionBase.java b/src/jniglue/org/OpenColorIO/ExceptionBase.java
new file mode 100644
index 0000000..ba8639f
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/ExceptionBase.java
@@ -0,0 +1,37 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class ExceptionBase extends java.lang.Exception
+{
+ public ExceptionBase(String msg) {
+ super(msg);
+ }
+}
diff --git a/src/jniglue/org/OpenColorIO/ExceptionMissingFile.java b/src/jniglue/org/OpenColorIO/ExceptionMissingFile.java
new file mode 100644
index 0000000..a0c79ef
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/ExceptionMissingFile.java
@@ -0,0 +1,37 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class ExceptionMissingFile extends ExceptionBase
+{
+ public ExceptionMissingFile(String msg) {
+ super(msg);
+ }
+}
diff --git a/src/jniglue/org/OpenColorIO/ExponentTransform.java b/src/jniglue/org/OpenColorIO/ExponentTransform.java
new file mode 100644
index 0000000..4f763a9
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/ExponentTransform.java
@@ -0,0 +1,39 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class ExponentTransform extends Transform
+{
+ public ExponentTransform() { super(); }
+ protected ExponentTransform(long impl) { super(impl); }
+ public native ExponentTransform Create();
+ public native void setValue(float[] vec4);
+ public native void getValue(float[] vec4);
+}
diff --git a/src/jniglue/org/OpenColorIO/FileTransform.java b/src/jniglue/org/OpenColorIO/FileTransform.java
new file mode 100644
index 0000000..bfe55cc
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/FileTransform.java
@@ -0,0 +1,46 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class FileTransform extends Transform
+{
+ public FileTransform() { super(); }
+ protected FileTransform(long impl) { super(impl); }
+ public native FileTransform Create();
+ public native String getSrc();
+ public native void setSrc(String src);
+ public native String getCCCId();
+ public native void setCCCId(String id);
+ public native Interpolation getInterpolation();
+ public native void setInterpolation(Interpolation interp);
+ public native int getNumFormats();
+ public native String getFormatNameByIndex(int index);
+ public native String getFormatExtensionByIndex(int index);
+}
diff --git a/src/jniglue/org/OpenColorIO/Globals.java b/src/jniglue/org/OpenColorIO/Globals.java
new file mode 100644
index 0000000..5273bd7
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/Globals.java
@@ -0,0 +1,78 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class Globals extends LoadLibrary
+{
+ public native void ClearAllCaches();
+ public native String GetVersion();
+ public native int GetVersionHex();
+ public native LoggingLevel GetLoggingLevel();
+ public native void SetLoggingLevel(LoggingLevel level);
+ public native Config GetCurrentConfig();
+ public native void SetCurrentConfig(Config config);
+
+ // Types
+ public native String BoolToString(boolean val);
+ public native boolean BoolFromString(String s);
+ public native String LoggingLevelToString(LoggingLevel level);
+ public native LoggingLevel LoggingLevelFromString(String s);
+ public native String TransformDirectionToString(TransformDirection dir);
+ public native TransformDirection TransformDirectionFromString(String s);
+ public native TransformDirection GetInverseTransformDirection(TransformDirection dir);
+ public native TransformDirection CombineTransformDirections(TransformDirection d1, TransformDirection d2);
+ public native String ColorSpaceDirectionToString(ColorSpaceDirection dir);
+ public native ColorSpaceDirection ColorSpaceDirectionFromString(String s);
+ public native String BitDepthToString(BitDepth bitDepth);
+ public native BitDepth BitDepthFromString(String s);
+ public native boolean BitDepthIsFloat(BitDepth bitDepth);
+ public native int BitDepthToInt(BitDepth bitDepth);
+ public native String AllocationToString(Allocation allocation);
+ public native Allocation AllocationFromString(String s);
+ public native String InterpolationToString(Interpolation interp);
+ public native Interpolation InterpolationFromString(String s);
+ public native String GpuLanguageToString(GpuLanguage language);
+ public native GpuLanguage GpuLanguageFromString(String s);
+
+ // Roles
+ public String ROLE_DEFAULT;
+ public String ROLE_REFERENCE;
+ public String ROLE_DATA;
+ public String ROLE_COLOR_PICKING;
+ public String ROLE_SCENE_LINEAR;
+ public String ROLE_COMPOSITING_LOG;
+ public String ROLE_COLOR_TIMING;
+ public String ROLE_TEXTURE_PAINT;
+ public String ROLE_MATTE_PAINT;
+
+ //
+ public Globals() { super(); create(); }
+ private native void create();
+}
diff --git a/src/jniglue/org/OpenColorIO/GpuLanguage.java b/src/jniglue/org/OpenColorIO/GpuLanguage.java
new file mode 100644
index 0000000..3368a88
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/GpuLanguage.java
@@ -0,0 +1,46 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class GpuLanguage extends LoadLibrary
+{
+ private final int m_enum;
+ protected GpuLanguage(int type) { super(); m_enum = type; }
+ public native String toString();
+ public native boolean equals(Object obj);
+ public static final GpuLanguage
+ GPU_LANGUAGE_UNKNOWN = new GpuLanguage(0);
+ public static final GpuLanguage
+ GPU_LANGUAGE_CG = new GpuLanguage(1);
+ public static final GpuLanguage
+ GPU_LANGUAGE_GLSL_1_0 = new GpuLanguage(2);
+ public static final GpuLanguage
+ GPU_LANGUAGE_GLSL_1_3 = new GpuLanguage(3);
+}
diff --git a/src/jniglue/org/OpenColorIO/GpuShaderDesc.java b/src/jniglue/org/OpenColorIO/GpuShaderDesc.java
new file mode 100644
index 0000000..bdaf855
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/GpuShaderDesc.java
@@ -0,0 +1,46 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class GpuShaderDesc extends LoadLibrary
+{
+ public GpuShaderDesc() { super(); create(); }
+ protected GpuShaderDesc(long impl) { super(impl); }
+ private native void create();
+ public native void dispose();
+ protected void finalize() { dispose(); }
+ public native void setLanguage(GpuLanguage lang);
+ public native GpuLanguage getLanguage();
+ public native void setFunctionName(String name);
+ public native String getFunctionName();
+ public native void setLut3DEdgeLen(int len);
+ public native int getLut3DEdgeLen();
+ public native String getCacheID();
+};
diff --git a/src/jniglue/org/OpenColorIO/GroupTransform.java b/src/jniglue/org/OpenColorIO/GroupTransform.java
new file mode 100644
index 0000000..b0a24e6
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/GroupTransform.java
@@ -0,0 +1,42 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class GroupTransform extends Transform
+{
+ public GroupTransform() { super(); }
+ protected GroupTransform(long impl) { super(impl); }
+ public native GroupTransform Create();
+ public native Transform getTransform(int index);
+ public native int size();
+ public native void push_back(Transform transform);
+ public native void clear();
+ public native boolean empty();
+}
diff --git a/src/jniglue/org/OpenColorIO/ImageDesc.java b/src/jniglue/org/OpenColorIO/ImageDesc.java
new file mode 100644
index 0000000..f442ca1
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/ImageDesc.java
@@ -0,0 +1,36 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class ImageDesc extends LoadLibrary
+{
+ public ImageDesc() { super(); }
+ protected ImageDesc(long impl) { super(impl); }
+};
diff --git a/src/jniglue/org/OpenColorIO/Interpolation.java b/src/jniglue/org/OpenColorIO/Interpolation.java
new file mode 100644
index 0000000..f807d99
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/Interpolation.java
@@ -0,0 +1,48 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class Interpolation extends LoadLibrary
+{
+ private final int m_enum;
+ protected Interpolation(int type) { super(); m_enum = type; }
+ public native String toString();
+ public native boolean equals(Object obj);
+ public static final Interpolation
+ INTERP_UNKNOWN = new Interpolation(0);
+ public static final Interpolation
+ INTERP_NEAREST = new Interpolation(1);
+ public static final Interpolation
+ INTERP_LINEAR = new Interpolation(2);
+ public static final Interpolation
+ INTERP_TETRAHEDRAL = new Interpolation(3);
+ public static final Interpolation
+ INTERP_BEST = new Interpolation(255);
+}
diff --git a/src/jniglue/org/OpenColorIO/LogTransform.java b/src/jniglue/org/OpenColorIO/LogTransform.java
new file mode 100644
index 0000000..0f5b435
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/LogTransform.java
@@ -0,0 +1,39 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class LogTransform extends Transform
+{
+ public LogTransform() { super(); }
+ protected LogTransform(long impl) { super(impl); }
+ public native LogTransform Create();
+ public native void setBase(float val);
+ public native float getBase();
+}
diff --git a/src/jniglue/org/OpenColorIO/LoggingLevel.java b/src/jniglue/org/OpenColorIO/LoggingLevel.java
new file mode 100644
index 0000000..a8106e4
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/LoggingLevel.java
@@ -0,0 +1,48 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class LoggingLevel extends LoadLibrary
+{
+ private final int m_enum;
+ protected LoggingLevel(int type) { super(); m_enum = type; }
+ public native String toString();
+ public native boolean equals(Object obj);
+ public static final LoggingLevel
+ LOGGING_LEVEL_NONE = new LoggingLevel(0);
+ public static final LoggingLevel
+ LOGGING_LEVEL_WARNING = new LoggingLevel(1);
+ public static final LoggingLevel
+ LOGGING_LEVEL_INFO = new LoggingLevel(2);
+ public static final LoggingLevel
+ LOGGING_LEVEL_DEBUG = new LoggingLevel(3);
+ public static final LoggingLevel
+ LOGGING_LEVEL_UNKNOWN = new LoggingLevel(255);
+}
diff --git a/src/jniglue/org/OpenColorIO/Look.java b/src/jniglue/org/OpenColorIO/Look.java
new file mode 100644
index 0000000..c2fb0ef
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/Look.java
@@ -0,0 +1,48 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class Look extends LoadLibrary
+{
+ public Look() { super(); }
+ protected Look(long impl) { super(impl); }
+ public native void dispose();
+ protected void finalize() { dispose(); }
+ public native Look Create();
+ public native String getName();
+ public native void setName(String name);
+ public native String getProcessSpace();
+ public native void setProcessSpace(String processSpace);
+ public native Transform getTransform();
+ public native void setTransform(Transform transform);
+ public native Transform getInverseTransform();
+ public native void setInverseTransform(Transform transform);
+};
+
diff --git a/src/jniglue/org/OpenColorIO/LookTransform.java b/src/jniglue/org/OpenColorIO/LookTransform.java
new file mode 100644
index 0000000..a6ca6b3
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/LookTransform.java
@@ -0,0 +1,43 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class LookTransform extends Transform
+{
+ public LookTransform() { super(); }
+ protected LookTransform(long impl) { super(impl); }
+ public native LookTransform Create();
+ public native String getSrc();
+ public native void setSrc(String src);
+ public native String getDst();
+ public native void setDst(String dst);
+ public native void setLooks(String looks);
+ public native String getLooks();
+}
diff --git a/src/jniglue/org/OpenColorIO/MatrixTransform.java b/src/jniglue/org/OpenColorIO/MatrixTransform.java
new file mode 100644
index 0000000..d4560f1
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/MatrixTransform.java
@@ -0,0 +1,54 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class MatrixTransform extends Transform
+{
+ public MatrixTransform() { super(); }
+ protected MatrixTransform(long impl) { super(impl); }
+ public native MatrixTransform Create();
+ public native boolean equals(MatrixTransform obj);
+ public native void setValue(float[] m44, float[] offset4);
+ public native void getValue(float[] m44, float[] offset4);
+ public native void setMatrix(float[] m44);
+ public native void getMatrix(float[] m44);
+ public native void setOffset(float[] offset4);
+ public native void getOffset(float[] offset4);
+ public native void Fit(float[] m44, float[] offset4,
+ float[] oldmin4, float[] oldmax4,
+ float[] newmin4, float[] newmax4);
+ public native void Identity(float[] m44, float[] offset4);
+ public native void Sat(float[] m44, float[] offset4,
+ float sat, float[] lumaCoef3);
+ public native void Scale(float[] m44, float[] offset4,
+ float[] scale4);
+ public native void View(float[] m44, float[] offset4,
+ int[] channelHot4, float[] lumaCoef3);
+}
diff --git a/src/jniglue/org/OpenColorIO/PackedImageDesc.java b/src/jniglue/org/OpenColorIO/PackedImageDesc.java
new file mode 100644
index 0000000..8cc6932
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/PackedImageDesc.java
@@ -0,0 +1,59 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+import java.nio.FloatBuffer;
+
+public class PackedImageDesc extends ImageDesc
+{
+ public PackedImageDesc(FloatBuffer data, long width, long height, long numChannels)
+ {
+ super();
+ create(data, width, height, numChannels);
+ }
+ public PackedImageDesc(FloatBuffer data, long width, long height, long numChannels,
+ long chanStrideBytes, long xStrideBytes, long yStrideBytes)
+ {
+ super();
+ create(data, width, height, numChannels, chanStrideBytes, xStrideBytes, yStrideBytes);
+ }
+ protected PackedImageDesc(long impl) { super(impl); }
+ protected native void create(FloatBuffer data, long width, long height, long numChannels);
+ protected native void create(FloatBuffer data, long width, long height, long numChannels,
+ long chanStrideBytes, long xStrideBytes, long yStrideBytes);
+ public native void dispose();
+ protected void finalize() { dispose(); }
+ public native FloatBuffer getData();
+ public native long getWidth();
+ public native long getHeight();
+ public native long getNumChannels();
+ public native long getChanStrideBytes();
+ public native long getXStrideBytes();
+ public native long getYStrideBytes();
+};
diff --git a/src/jniglue/org/OpenColorIO/PlanarImageDesc.java b/src/jniglue/org/OpenColorIO/PlanarImageDesc.java
new file mode 100644
index 0000000..86fc5de
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/PlanarImageDesc.java
@@ -0,0 +1,63 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+import java.nio.FloatBuffer;
+
+public class PlanarImageDesc extends ImageDesc
+{
+ public PlanarImageDesc(FloatBuffer rData, FloatBuffer gData, FloatBuffer bData,
+ FloatBuffer aData, long width, long height)
+ {
+ super();
+ create(rData, gData, bData, aData, width, height);
+ }
+ public PlanarImageDesc(FloatBuffer rData, FloatBuffer gData, FloatBuffer bData,
+ FloatBuffer aData, long width, long height,
+ long yStrideBytes)
+ {
+ super();
+ create(rData, gData, bData, aData, width, height, yStrideBytes);
+ }
+ protected PlanarImageDesc(long impl) { super(impl); }
+ public native void dispose();
+ protected void finalize() { dispose(); }
+ protected native void create(FloatBuffer rData, FloatBuffer gData, FloatBuffer bData,
+ FloatBuffer aData, long width, long height);
+ protected native void create(FloatBuffer rData, FloatBuffer gData, FloatBuffer bData,
+ FloatBuffer aData, long width, long height,
+ long yStrideBytes);
+ public native FloatBuffer getRData();
+ public native FloatBuffer getGData();
+ public native FloatBuffer getBData();
+ public native FloatBuffer getAData();
+ public native long getWidth();
+ public native long getHeight();
+ public native long getYStrideBytes();
+};
diff --git a/src/jniglue/org/OpenColorIO/Processor.java b/src/jniglue/org/OpenColorIO/Processor.java
new file mode 100644
index 0000000..a999992
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/Processor.java
@@ -0,0 +1,51 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+import java.nio.FloatBuffer;
+
+public class Processor extends LoadLibrary
+{
+ public Processor() { super(); }
+ protected Processor(long impl) { super(impl); }
+ public native void dispose();
+ protected void finalize() { dispose(); }
+ public native Processor Create();
+ public native boolean isNoOp();
+ public native boolean hasChannelCrosstalk();
+ public native void apply(ImageDesc img);
+ public native void applyRGB(float[] pixel);
+ public native void applyRGBA(float[] pixel);
+ public native String getCpuCacheID();
+ public native String getGpuShaderText(GpuShaderDesc shaderDesc);
+ public native String getGpuShaderTextCacheID(GpuShaderDesc shaderDesc);
+ public native void getGpuLut3D(FloatBuffer lut3d, GpuShaderDesc shaderDesc);
+ public native String getGpuLut3DCacheID(GpuShaderDesc shaderDesc);
+};
+
diff --git a/src/jniglue/org/OpenColorIO/Transform.java b/src/jniglue/org/OpenColorIO/Transform.java
new file mode 100644
index 0000000..52c6fb5
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/Transform.java
@@ -0,0 +1,41 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class Transform extends LoadLibrary
+{
+ public Transform() { super(); }
+ protected Transform(long impl) { super(impl); }
+ public native void dispose();
+ protected void finalize() { dispose(); }
+ public native Transform createEditableCopy();
+ public native TransformDirection getDirection();
+ public native void setDirection(TransformDirection dir);
+}
diff --git a/src/jniglue/org/OpenColorIO/TransformDirection.java b/src/jniglue/org/OpenColorIO/TransformDirection.java
new file mode 100644
index 0000000..b034b5a
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/TransformDirection.java
@@ -0,0 +1,44 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class TransformDirection extends LoadLibrary
+{
+ private final int m_enum;
+ protected TransformDirection(int type) { super(); m_enum = type; }
+ public native String toString();
+ public native boolean equals(Object obj);
+ public static final TransformDirection
+ TRANSFORM_DIR_UNKNOWN = new TransformDirection(0);
+ public static final TransformDirection
+ TRANSFORM_DIR_FORWARD = new TransformDirection(1);
+ public static final TransformDirection
+ TRANSFORM_DIR_INVERSE = new TransformDirection(2);
+}
diff --git a/src/jniglue/org/OpenColorIO/TruelightTransform.java b/src/jniglue/org/OpenColorIO/TruelightTransform.java
new file mode 100644
index 0000000..1d966e9
--- /dev/null
+++ b/src/jniglue/org/OpenColorIO/TruelightTransform.java
@@ -0,0 +1,58 @@
+/*
+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.
+*/
+
+package org.OpenColorIO;
+import org.OpenColorIO.*;
+
+public class TruelightTransform extends Transform
+{
+ public TruelightTransform() { super(); }
+ protected TruelightTransform(long impl) { super(impl); }
+ public native TruelightTransform Create();
+ public native void setConfigRoot(String configroot);
+ public native String getConfigRoot();
+ public native void setProfile(String profile);
+ public native String getProfile();
+ public native void setCamera(String camera);
+ public native String getCamera();
+ public native void setInputDisplay(String display);
+ public native String getInputDisplay();
+ public native void setRecorder(String recorder);
+ public native String getRecorder();
+ public native void setPrint(String print);
+ public native String getPrint();
+ public native void setLamp(String lamp);
+ public native String getLamp();
+ public native void setOutputCamera(String camera);
+ public native String getOutputCamera();
+ public native void setDisplay(String display);
+ public native String getDisplay();
+ public native void setCubeInput(String type);
+ public native String getCubeInput();
+}
+
diff --git a/src/jniglue/tests/CMakeLists.txt b/src/jniglue/tests/CMakeLists.txt
new file mode 100644
index 0000000..e201749
--- /dev/null
+++ b/src/jniglue/tests/CMakeLists.txt
@@ -0,0 +1,17 @@
+###############################################################################
+### JNI JUNIT TESTS ###
+
+
+file(GLOB _TESTS_FILES "org/OpenColorIO/*.java")
+set(_JCLASS_PATH "${CMAKE_CURRENT_BINARY_DIR}:${CMAKE_CURRENT_BINARY_DIR}/..:${CMAKE_SOURCE_DIR}/ext/junit-4.9b4.jar")
+set(_JLIB_PATH "${CMAKE_CURRENT_BINARY_DIR}/..")
+
+add_custom_target(JNITests
+ COMMAND javac -cp ${_JCLASS_PATH}
+ -d ${CMAKE_CURRENT_BINARY_DIR} ${_TESTS_FILES}
+ COMMAND java -cp ${_JCLASS_PATH}
+ -Djava.library.path=${_JLIB_PATH} junit.textui.TestRunner
+ OpenColorIOTestSuite
+ DEPENDS OpenColorIO-JNI
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Setting Up and Running JNI OCIO JUNIT tests")
diff --git a/src/jniglue/tests/org/OpenColorIO/BakerTest.java b/src/jniglue/tests/org/OpenColorIO/BakerTest.java
new file mode 100644
index 0000000..63f540a
--- /dev/null
+++ b/src/jniglue/tests/org/OpenColorIO/BakerTest.java
@@ -0,0 +1,84 @@
+
+import junit.framework.TestCase;
+import org.OpenColorIO.*;
+
+public class BakerTest extends TestCase {
+
+ String SIMPLE_PROFILE = ""
+ + "ocio_profile_version: 1\n"
+ + "\n"
+ + "strictparsing: false\n"
+ + "\n"
+ + "colorspaces:\n"
+ + "\n"
+ + " - !<ColorSpace>\n"
+ + " name: lnh\n"
+ + " bitdepth: 16f\n"
+ + " isdata: false\n"
+ + " allocation: lg2\n"
+ + "\n"
+ + " - !<ColorSpace>\n"
+ + " name: test\n"
+ + " bitdepth: 8ui\n"
+ + " isdata: false\n"
+ + " allocation: uniform\n"
+ + " to_reference: !<ExponentTransform> {value: [2.2, 2.2, 2.2, 1]}\n";
+
+ String EXPECTED_LUT = ""
+ + "CSPLUTV100\n"
+ + "3D\n"
+ + "BEGIN METADATA\n"
+ + "this is some metadata!\n"
+ + "END METADATA\n"
+ + "\n"
+ + "4\n"
+ + "0.000977 0.039373 1.587401 64.000000\n"
+ + "0.000000 0.333333 0.666667 1.000000\n"
+ + "4\n"
+ + "0.000977 0.039373 1.587401 64.000000\n"
+ + "0.000000 0.333333 0.666667 1.000000\n"
+ + "4\n"
+ + "0.000977 0.039373 1.587401 64.000000\n"
+ + "0.000000 0.333333 0.666667 1.000000\n"
+ + "\n"
+ + "2 2 2\n"
+ + "0.042823 0.042823 0.042823\n"
+ + "6.622026 0.042823 0.042823\n"
+ + "0.042823 6.622026 0.042823\n"
+ + "6.622026 6.622026 0.042823\n"
+ + "0.042823 0.042823 6.622026\n"
+ + "6.622026 0.042823 6.622026\n"
+ + "0.042823 6.622026 6.622026\n"
+ + "6.622026 6.622026 6.622026\n"
+ + "\n";
+
+ protected void setUp() {
+ }
+
+ protected void tearDown() {
+ }
+
+ public void test_interface() {
+ Baker bake = new Baker().Create();
+ Baker bakee = bake.createEditableCopy();
+ Config cfg = new Config().CreateFromStream(SIMPLE_PROFILE);
+ bakee.setConfig(cfg);
+ bakee.setFormat("cinespace");
+ assertEquals("cinespace", bakee.getFormat());
+ bakee.setType("3D");
+ assertEquals("3D", bakee.getType());
+ bakee.setMetadata("this is some metadata!");
+ assertEquals("this is some metadata!", bakee.getMetadata());
+ bakee.setInputSpace("lnh");
+ assertEquals("lnh", bakee.getInputSpace());
+ bakee.setTargetSpace("test");
+ assertEquals("test", bakee.getTargetSpace());
+ bakee.setShaperSize(4);
+ assertEquals(4, bakee.getShaperSize());
+ bakee.setCubeSize(2);
+ assertEquals(2, bakee.getCubeSize());
+ String output = bakee.bake();
+ assertEquals(EXPECTED_LUT, output);
+ }
+
+}
diff --git a/src/jniglue/tests/org/OpenColorIO/ColorSpaceTest.java b/src/jniglue/tests/org/OpenColorIO/ColorSpaceTest.java
new file mode 100644
index 0000000..f49e582
--- /dev/null
+++ b/src/jniglue/tests/org/OpenColorIO/ColorSpaceTest.java
@@ -0,0 +1,41 @@
+
+import junit.framework.TestCase;
+import org.OpenColorIO.*;
+
+public class ColorSpaceTest extends TestCase {
+
+ protected void setUp() {
+ }
+
+ protected void tearDown() {
+ }
+
+ public void test_interface() {
+ ColorSpace cs = new ColorSpace().Create();
+ cs.setName("mynewcolspace");
+ assertEquals("mynewcolspace", cs.getName());
+ cs.setFamily("fam1");
+ assertEquals("fam1", cs.getFamily());
+ cs.setEqualityGroup("match1");
+ assertEquals("match1", cs.getEqualityGroup());
+ cs.setDescription("this is a test");
+ assertEquals("this is a test", cs.getDescription());
+ cs.setBitDepth(BitDepth.BIT_DEPTH_F16);
+ assertEquals(BitDepth.BIT_DEPTH_F16, cs.getBitDepth());
+ cs.setIsData(false);
+ assertEquals(false, cs.isData());
+ cs.setAllocation(Allocation.ALLOCATION_LG2);
+ assertEquals(Allocation.ALLOCATION_LG2, cs.getAllocation());
+ float test[] = new float[]{0.1f, 0.2f, 0.3f};
+ cs.setAllocationVars(3, test);
+ assertEquals(3, cs.getAllocationNumVars());
+ float out[] = new float[3];
+ cs.getAllocationVars(out);
+ LogTransform lt = new LogTransform().Create();
+ lt.setBase(10.f);
+ cs.setTransform(lt, ColorSpaceDirection.COLORSPACE_DIR_TO_REFERENCE);
+ LogTransform ott = (LogTransform)cs.getTransform(ColorSpaceDirection.COLORSPACE_DIR_TO_REFERENCE);
+ assertEquals(10.f, ott.getBase());
+ }
+
+}
diff --git a/src/jniglue/tests/org/OpenColorIO/ConfigTest.java b/src/jniglue/tests/org/OpenColorIO/ConfigTest.java
new file mode 100644
index 0000000..a676bae
--- /dev/null
+++ b/src/jniglue/tests/org/OpenColorIO/ConfigTest.java
@@ -0,0 +1,220 @@
+
+import junit.framework.TestCase;
+import org.OpenColorIO.*;
+import java.nio.*;
+
+public class ConfigTest extends TestCase {
+
+ String SIMPLE_PROFILE = ""
+ + "ocio_profile_version: 1\n"
+ + "\n"
+ + "search_path: luts\n"
+ + "strictparsing: false\n"
+ + "luma: [0.2126, 0.7152, 0.0722]\n"
+ + "\n"
+ + "roles:\n"
+ + " default: raw\n"
+ + " scene_linear: lnh\n"
+ + "\n"
+ + "displays:\n"
+ + " sRGB:\n"
+ + " - !<View> {name: Film1D, colorspace: vd8}\n"
+ + " - !<View> {name: Raw, colorspace: raw}\n"
+ + "\n"
+ + "active_displays: []\n"
+ + "active_views: []\n"
+ + "\n"
+ + "colorspaces:\n"
+ + " - !<ColorSpace>\n"
+ + " name: raw\n"
+ + " family: raw\n"
+ + " bitdepth: 32f\n"
+ + " description: |\n"
+ + " A raw color space. Conversions to and from this space are no-ops.\n"
+ + " \n"
+ + " isdata: true\n"
+ + " allocation: uniform\n"
+ + "\n"
+ + " - !<ColorSpace>\n"
+ + " name: lnh\n"
+ + " family: ln\n"
+ + " bitdepth: 16f\n"
+ + " description: |\n"
+ + " The show reference space. This is a sensor referred linear\n"
+ + " representation of the scene with primaries that correspond to\n"
+ + " scanned film. 0.18 in this space corresponds to a properly\n"
+ + " exposed 18% grey card.\n"
+ + " \n"
+ + " isdata: false\n"
+ + " allocation: lg2\n"
+ + "\n"
+ + " - !<ColorSpace>\n"
+ + " name: vd8\n"
+ + " family: vd8\n"
+ + " bitdepth: 8ui\n"
+ + " description: |\n"
+ + " how many transforms can we use?\n"
+ + " \n"
+ + " isdata: false\n"
+ + " allocation: uniform\n"
+ + " to_reference: !<GroupTransform>\n"
+ + " children:\n"
+ + " - !<ExponentTransform> {value: [2.2, 2.2, 2.2, 1]}\n"
+ + " - !<MatrixTransform> {matrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], offset: [0, 0, 0, 0]}\n"
+ + " - !<CDLTransform> {slope: [1, 1, 1], offset: [0.1, 0.3, 0.4], power: [1.1, 1.1, 1.1], saturation: 0.9}\n";
+
+ String GLSLResult = ""
+ + "\n"
+ + "// Generated by OpenColorIO\n"
+ + "\n"
+ + "vec4 jnitestocio(in vec4 inPixel, \n"
+ + " const sampler3D lut3d) \n"
+ + "{\n"
+ + "vec4 out_pixel = inPixel; \n"
+ + "out_pixel = out_pixel * mat4(1.08749, -0.0794667, -0.00802222, 0, -0.0236222, 1.03164, -0.00802222, 0, -0.0236222, -0.0794667, 1.10309, 0, 0, 0, 0, 1);\n"
+ + "out_pixel = pow(max(out_pixel, vec4(0, 0, 0, 0)), vec4(0.909091, 0.909091, 0.909091, 1));\n"
+ + "out_pixel = vec4(-0.1, -0.3, -0.4, -0) + out_pixel;\n"
+ + "out_pixel = pow(max(out_pixel, vec4(0, 0, 0, 0)), vec4(0.454545, 0.454545, 0.454545, 1));\n"
+ + "// OSX segfault work-around: Force a no-op sampling of the 3d lut.\n"
+ + "texture3D(lut3d, -inf * out_pixel.rgb + inf).rgb;\n"
+ + "return out_pixel;\n"
+ + "}\n"
+ + "\n";
+
+ protected void setUp() {
+ }
+
+ protected void tearDown() {
+ }
+
+ public void test_interface() {
+
+ Config _cfg = new Config().CreateFromStream(SIMPLE_PROFILE);
+ Config _cfge = _cfg.createEditableCopy();
+ assertEquals("luts", _cfge.getSearchPath());
+ _cfge.setSearchPath("otherdir");
+ assertEquals("otherdir", _cfge.getSearchPath());
+ _cfge.sanityCheck();
+ _cfge.setDescription("testdesc");
+ assertEquals("testdesc", _cfge.getDescription());
+ //assertEquals(SIMPLE_PROFILE, _cfg.serialize());
+ //assertEquals("$07d1fb1509eeae1837825fd4242f8a69:$885ad1683add38a11f7bbe34e8bf9ac0",
+ // _cfg.getCacheID());
+ Context con = _cfg.getCurrentContext();
+ assertNotSame(0, con.getNumStringVars());
+ //assertEquals("", _cfg.getCacheID(con)); // test env makes this fail
+ //assertEquals("", _cfge.getWorkingDir());
+ _cfge.setWorkingDir("/foobar");
+ assertEquals("/foobar", _cfge.getWorkingDir());
+ assertEquals(3, _cfge.getNumColorSpaces());
+ assertEquals("lnh", _cfge.getColorSpaceNameByIndex(1));
+ //public native ColorSpace getColorSpace(String name);
+ assertEquals(0, _cfge.getIndexForColorSpace("foobar"));
+ //public native void addColorSpace(ColorSpace cs);
+ //public native void clearColorSpaces();
+ //public native String parseColorSpaceFromString(String str);
+ if(_cfg.isStrictParsingEnabled()) fail("strict parsing should be off");
+ _cfge.setStrictParsingEnabled(true);
+ if(!_cfge.isStrictParsingEnabled()) fail("strict parsing should be on");
+ assertEquals(2, _cfge.getNumRoles());
+ if(_cfg.hasRole("foo")) fail("shouldn't have role foo");
+ _cfge.setRole("foo", "dfadfadf");
+ assertEquals(3, _cfge.getNumRoles());
+ if(!_cfge.hasRole("foo")) fail("should have role foo");
+ assertEquals("foo", _cfge.getRoleName(1));
+ assertEquals("sRGB", _cfge.getDefaultDisplay());
+ assertEquals(1, _cfge.getNumDisplays());
+ assertEquals("sRGB", _cfge.getDisplay(0));
+ assertEquals("Film1D", _cfge.getDefaultView("sRGB"));
+ assertEquals(2, _cfge.getNumViews("sRGB"));
+ assertEquals("Raw", _cfge.getView("sRGB", 1));
+ assertEquals("vd8", _cfge.getDisplayColorSpaceName("sRGB", "Film1D"));
+ assertEquals("", _cfg.getDisplayLooks("sRGB", "Film1D"));
+
+ // TODO: seems that 4 string params causes a memory error in the JNI layer?
+ //_cfge.addDisplay("foo", "bar", "foo", 0);
+
+ _cfge.clearDisplays();
+ _cfge.setActiveDisplays("sRGB");
+ assertEquals("sRGB", _cfge.getActiveDisplays());
+ _cfge.setActiveViews("Film1D");
+ assertEquals("Film1D", _cfge.getActiveViews());
+ float luma[] = new float[3];
+ _cfge.getDefaultLumaCoefs(luma);
+ assertEquals(0.2126, luma[0], 1e-8);
+ float[] newluma = new float[]{0.1f, 0.2f, 0.3f};
+ _cfge.setDefaultLumaCoefs(newluma);
+ float tnewluma[] = new float[3];
+ _cfge.getDefaultLumaCoefs(tnewluma);
+ assertEquals(0.1f, tnewluma[0], 1e-8);
+ assertEquals(0, _cfge.getNumLooks());
+ Look lk = new Look().Create();
+ lk.setName("coollook");
+ lk.setProcessSpace("somespace");
+ ExponentTransform et = new ExponentTransform().Create();
+ et.setValue(new float[]{0.1f, 0.2f, 0.3f, 0.4f});
+ lk.setTransform(et);
+ ExponentTransform iet = new ExponentTransform().Create();
+ iet.setValue(new float[]{-0.1f, -0.2f, -0.3f, -0.4f});
+ lk.setInverseTransform(iet);
+ _cfge.addLook(lk);
+ assertEquals(1, _cfge.getNumLooks());
+ assertEquals("coollook", _cfge.getLookNameByIndex(0));
+ Look glk = _cfge.getLook("coollook");
+ assertEquals("somespace", glk.getProcessSpace());
+ _cfge.clearLooks();
+ assertEquals(0, _cfge.getNumLooks());
+
+ //public native Processor getProcessor(Context context, ColorSpace srcColorSpace, ColorSpace dstColorSpace);
+
+ Processor _proc = _cfg.getProcessor("lnh", "vd8");
+ assertEquals(false, _proc.isNoOp());
+ assertEquals(true, _proc.hasChannelCrosstalk());
+ float packedpix[] = new float[]{0.48f, 0.18f, 0.9f, 1.0f,
+ 0.48f, 0.18f, 0.18f, 1.0f,
+ 0.48f, 0.18f, 0.18f, 1.0f,
+ 0.48f, 0.18f, 0.18f, 1.0f };
+ FloatBuffer buf = ByteBuffer.allocateDirect(2 * 2 * 4 * Float.SIZE / 8).asFloatBuffer();
+ buf.put(packedpix);
+ PackedImageDesc foo = new PackedImageDesc(buf, 2, 2, 4);
+ _proc.apply(foo);
+ FloatBuffer wee = foo.getData();
+ assertEquals(-2.4307251581696764E-35f, wee.get(2), 1e-8);
+ float rgbfoo[] = new float[]{0.48f, 0.18f, 0.18f};
+ _proc.applyRGB(rgbfoo);
+ assertEquals(0.6875247f, rgbfoo[0], 1e-8);
+ float rgbafoo[] = new float[]{0.48f, 0.18f, 0.18f, 1.f};
+ _proc.applyRGBA(rgbafoo);
+ assertEquals(1.f, rgbafoo[3], 1e-8);
+ //assertEquals("$a92ef63abd9edf61ad5a7855da064648", _proc.getCpuCacheID());
+ GpuShaderDesc desc = new GpuShaderDesc();
+ desc.setLanguage(GpuLanguage.GPU_LANGUAGE_GLSL_1_3);
+ desc.setFunctionName("jnitestocio");
+ desc.setLut3DEdgeLen(32);
+ String glsl = _proc.getGpuShaderText(desc);
+ //assertEquals(GLSLResult, glsl);
+ //assertEquals("$1dead2bf42974cd1769164e45a0c9e40", _proc.getGpuShaderTextCacheID(desc));
+ int len = desc.getLut3DEdgeLen();
+ int size = 3 * len * len * len;
+ FloatBuffer lut3d = ByteBuffer.allocateDirect(size * Float.SIZE / 8).asFloatBuffer();
+ _proc.getGpuLut3D(lut3d, desc);
+ assertEquals(0.0f, lut3d.get(size-1));
+ assertEquals("<NULL>", _proc.getGpuLut3DCacheID(desc));
+
+ //public native Processor getProcessor(Context context, String srcName, String dstName);
+ //public native Processor getProcessor(Transform transform);
+ //public native Processor getProcessor(Transform transform, TransformDirection direction);
+ //public native Processor getProcessor(Context context, Transform transform, TransformDirection direction);
+
+ _cfge.dispose();
+ _cfg.dispose();
+
+ //System.out.println(_cfge.serialize());
+ //_cfge.sanityCheck();
+ //System.out.println(_cfge.getNumColorSpaces());
+ //System.out.println(_cfg.getCacheID());
+ //System.out.println(_cfge.serialize());
+
+ }
+
+}
diff --git a/src/jniglue/tests/org/OpenColorIO/ContextTest.java b/src/jniglue/tests/org/OpenColorIO/ContextTest.java
new file mode 100644
index 0000000..87579e3
--- /dev/null
+++ b/src/jniglue/tests/org/OpenColorIO/ContextTest.java
@@ -0,0 +1,38 @@
+
+import junit.framework.TestCase;
+import org.OpenColorIO.*;
+
+public class ContextTest extends TestCase {
+
+ protected void setUp() {
+ }
+
+ protected void tearDown() {
+ }
+
+ public void test_interface() {
+ Context cont = new Context().Create();
+ cont.setSearchPath("testing123");
+ cont.setWorkingDir("/dir/123");
+ assertEquals("$af84c0ff921e48843d711a761e05b80f", cont.getCacheID());
+ assertEquals("testing123", cont.getSearchPath());
+ assertEquals("/dir/123", cont.getWorkingDir());
+ cont.setStringVar("TeSt", "foobar");
+ assertEquals("foobar", cont.getStringVar("TeSt"));
+ assertEquals(1, cont.getNumStringVars());
+ assertEquals("TeSt", cont.getStringVarNameByIndex(0));
+ cont.loadEnvironment();
+ assertNotSame(0, cont.getNumStringVars());
+ cont.setStringVar("TEST1", "foobar");
+ assertEquals("/foo/foobar/bar",
+ cont.resolveStringVar("/foo/${TEST1}/bar"));
+ try {
+ cont.setSearchPath("testing123");
+ String foo = cont.resolveFileLocation("test.lut");
+ System.out.println(foo);
+ } catch (ExceptionMissingFile e) {
+ //System.out.println(e);
+ }
+ }
+
+}
diff --git a/src/jniglue/tests/org/OpenColorIO/GlobalsTest.java b/src/jniglue/tests/org/OpenColorIO/GlobalsTest.java
new file mode 100644
index 0000000..72f92f8
--- /dev/null
+++ b/src/jniglue/tests/org/OpenColorIO/GlobalsTest.java
@@ -0,0 +1,150 @@
+
+import junit.framework.TestCase;
+import org.OpenColorIO.*;
+
+public class GlobalsTest extends TestCase {
+
+ String FOO = ""
+ + "ocio_profile_version: 1\n"
+ + "\n"
+ + "search_path: \n"
+ + "strictparsing: false\n"
+ + "luma: [0.2126, 0.7152, 0.0722]\n"
+ + "\n"
+ + "roles:\n"
+ + " default: raw\n"
+ + "\n"
+ + "displays:\n"
+ + " sRGB:\n"
+ + " - !<View> {name: Raw, colorspace: raw}\n"
+ + "\n"
+ + "active_displays: []\n"
+ + "active_views: []\n"
+ + "\n"
+ + "colorspaces:\n"
+ + " - !<ColorSpace>\n"
+ + " name: raw\n"
+ + " family: raw\n"
+ + " equalitygroup: \n"
+ + " bitdepth: 32f\n"
+ + " description: |\n"
+ + " A raw color space. Conversions to and from this space are no-ops.\n"
+ + " isdata: true\n"
+ + " allocation: uniform\n";
+
+ protected void setUp() {
+ }
+
+ public void test_interface() {
+
+ Globals globals = new Globals();
+
+ // Globals
+ globals.ClearAllCaches();
+ //assertEquals("1.0.1", globals.GetVersion());
+ //assertEquals(16777472, globals.GetVersionHex());
+ assertEquals(LoggingLevel.LOGGING_LEVEL_INFO, globals.GetLoggingLevel());
+ globals.SetLoggingLevel(LoggingLevel.LOGGING_LEVEL_NONE);
+ assertEquals(LoggingLevel.LOGGING_LEVEL_NONE, globals.GetLoggingLevel());
+ Config foo = globals.GetCurrentConfig();
+ assertEquals(FOO, foo.serialize());
+ globals.SetLoggingLevel(LoggingLevel.LOGGING_LEVEL_INFO);
+ Config bar = new Config().CreateFromStream(foo.serialize());
+ globals.SetCurrentConfig(bar);
+ Config wee = globals.GetCurrentConfig();
+
+ // LoggingLevel
+ assertEquals(globals.LoggingLevelToString(LoggingLevel.LOGGING_LEVEL_NONE), "none");
+ assertEquals(globals.LoggingLevelFromString("none"), LoggingLevel.LOGGING_LEVEL_NONE);
+ assertEquals(globals.LoggingLevelToString(LoggingLevel.LOGGING_LEVEL_WARNING), "warning");
+ assertEquals(globals.LoggingLevelFromString("warning"), LoggingLevel.LOGGING_LEVEL_WARNING);
+ assertEquals(globals.LoggingLevelToString(LoggingLevel.LOGGING_LEVEL_INFO), "info");
+ assertEquals(globals.LoggingLevelFromString("info"), LoggingLevel.LOGGING_LEVEL_INFO);
+ assertEquals(globals.LoggingLevelToString(LoggingLevel.LOGGING_LEVEL_DEBUG), "debug");
+ assertEquals(globals.LoggingLevelFromString("debug"), LoggingLevel.LOGGING_LEVEL_DEBUG);
+ assertEquals(globals.LoggingLevelToString(LoggingLevel.LOGGING_LEVEL_UNKNOWN), "unknown");
+ assertEquals(globals.LoggingLevelFromString("unknown"), LoggingLevel.LOGGING_LEVEL_UNKNOWN);
+
+ // TransformDirection
+ assertEquals(globals.TransformDirectionToString(TransformDirection.TRANSFORM_DIR_UNKNOWN), "unknown");
+ assertEquals(globals.TransformDirectionFromString("unknown"), TransformDirection.TRANSFORM_DIR_UNKNOWN);
+ assertEquals(globals.TransformDirectionToString(TransformDirection.TRANSFORM_DIR_FORWARD), "forward");
+ assertEquals(globals.TransformDirectionFromString("forward"), TransformDirection.TRANSFORM_DIR_FORWARD);
+ assertEquals(globals.TransformDirectionToString(TransformDirection.TRANSFORM_DIR_INVERSE), "inverse");
+ assertEquals(globals.TransformDirectionFromString("inverse"), TransformDirection.TRANSFORM_DIR_INVERSE);
+ assertEquals(globals.GetInverseTransformDirection(TransformDirection.TRANSFORM_DIR_UNKNOWN), TransformDirection.TRANSFORM_DIR_UNKNOWN);
+ assertEquals(globals.GetInverseTransformDirection(TransformDirection.TRANSFORM_DIR_FORWARD), TransformDirection.TRANSFORM_DIR_INVERSE);
+ assertEquals(globals.GetInverseTransformDirection(TransformDirection.TRANSFORM_DIR_INVERSE), TransformDirection.TRANSFORM_DIR_FORWARD);
+
+ // ColorSpaceDirection
+ assertEquals(globals.ColorSpaceDirectionToString(ColorSpaceDirection.COLORSPACE_DIR_UNKNOWN), "unknown");
+ assertEquals(globals.ColorSpaceDirectionFromString("unknown"), ColorSpaceDirection.COLORSPACE_DIR_UNKNOWN);
+ assertEquals(globals.ColorSpaceDirectionToString(ColorSpaceDirection.COLORSPACE_DIR_TO_REFERENCE), "to_reference");
+ assertEquals(globals.ColorSpaceDirectionFromString("to_reference"), ColorSpaceDirection.COLORSPACE_DIR_TO_REFERENCE);
+ assertEquals(globals.ColorSpaceDirectionToString(ColorSpaceDirection.COLORSPACE_DIR_FROM_REFERENCE), "from_reference");
+ assertEquals(globals.ColorSpaceDirectionFromString("from_reference"), ColorSpaceDirection.COLORSPACE_DIR_FROM_REFERENCE);
+
+ // BitDepth
+ assertEquals(globals.BitDepthToString(BitDepth.BIT_DEPTH_UNKNOWN), "unknown");
+ assertEquals(globals.BitDepthFromString("unknown"), BitDepth.BIT_DEPTH_UNKNOWN);
+ assertEquals(globals.BitDepthToString(BitDepth.BIT_DEPTH_UINT8), "8ui");
+ assertEquals(globals.BitDepthFromString("8ui"), BitDepth.BIT_DEPTH_UINT8);
+ assertEquals(globals.BitDepthToString(BitDepth.BIT_DEPTH_UINT10), "10ui");
+ assertEquals(globals.BitDepthFromString("10ui"), BitDepth.BIT_DEPTH_UINT10);
+ assertEquals(globals.BitDepthToString(BitDepth.BIT_DEPTH_UINT12), "12ui");
+ assertEquals(globals.BitDepthFromString("12ui"), BitDepth.BIT_DEPTH_UINT12);
+ assertEquals(globals.BitDepthToString(BitDepth.BIT_DEPTH_UINT14), "14ui");
+ assertEquals(globals.BitDepthFromString("14ui"), BitDepth.BIT_DEPTH_UINT14);
+ assertEquals(globals.BitDepthToString(BitDepth.BIT_DEPTH_UINT16), "16ui");
+ assertEquals(globals.BitDepthFromString("16ui"), BitDepth.BIT_DEPTH_UINT16);
+ assertEquals(globals.BitDepthToString(BitDepth.BIT_DEPTH_UINT32), "32ui");
+ assertEquals(globals.BitDepthFromString("32ui"), BitDepth.BIT_DEPTH_UINT32);
+ assertEquals(globals.BitDepthToString(BitDepth.BIT_DEPTH_F16), "16f");
+ assertEquals(globals.BitDepthFromString("16f"), BitDepth.BIT_DEPTH_F16);
+ assertEquals(globals.BitDepthToString(BitDepth.BIT_DEPTH_F32), "32f");
+ assertEquals(globals.BitDepthFromString("32f"), BitDepth.BIT_DEPTH_F32);
+
+ // Allocation
+ assertEquals(globals.AllocationToString(Allocation.ALLOCATION_UNKNOWN), "unknown");
+ assertEquals(globals.AllocationFromString("unknown"), Allocation.ALLOCATION_UNKNOWN);
+ assertEquals(globals.AllocationToString(Allocation.ALLOCATION_UNIFORM), "uniform");
+ assertEquals(globals.AllocationFromString("uniform"), Allocation.ALLOCATION_UNIFORM);
+ assertEquals(globals.AllocationToString(Allocation.ALLOCATION_LG2), "lg2");
+ assertEquals(globals.AllocationFromString("lg2"), Allocation.ALLOCATION_LG2);
+
+ // Interpolation
+ assertEquals(globals.InterpolationToString(Interpolation.INTERP_UNKNOWN), "unknown");
+ assertEquals(globals.InterpolationFromString("unknown"), Interpolation.INTERP_UNKNOWN);
+ assertEquals(globals.InterpolationToString(Interpolation.INTERP_NEAREST), "nearest");
+ assertEquals(globals.InterpolationFromString("nearest"), Interpolation.INTERP_NEAREST);
+ assertEquals(globals.InterpolationToString(Interpolation.INTERP_LINEAR), "linear");
+ assertEquals(globals.InterpolationFromString("linear"), Interpolation.INTERP_LINEAR);
+ assertEquals(globals.InterpolationToString(Interpolation.INTERP_TETRAHEDRAL), "tetrahedral");
+ assertEquals(globals.InterpolationFromString("tetrahedral"), Interpolation.INTERP_TETRAHEDRAL);
+ assertEquals(globals.InterpolationToString(Interpolation.INTERP_BEST), "best");
+ assertEquals(globals.InterpolationFromString("best"), Interpolation.INTERP_BEST);
+
+ // GpuLanguage
+ assertEquals(globals.GpuLanguageToString(GpuLanguage.GPU_LANGUAGE_UNKNOWN), "unknown");
+ assertEquals(globals.GpuLanguageFromString("unknown"), GpuLanguage.GPU_LANGUAGE_UNKNOWN);
+ assertEquals(globals.GpuLanguageToString(GpuLanguage.GPU_LANGUAGE_CG), "cg");
+ assertEquals(globals.GpuLanguageFromString("cg"), GpuLanguage.GPU_LANGUAGE_CG);
+ assertEquals(globals.GpuLanguageToString(GpuLanguage.GPU_LANGUAGE_GLSL_1_0), "glsl_1.0");
+ assertEquals(globals.GpuLanguageFromString("glsl_1.0"), GpuLanguage.GPU_LANGUAGE_GLSL_1_0);
+ assertEquals(globals.GpuLanguageToString(GpuLanguage.GPU_LANGUAGE_GLSL_1_3), "glsl_1.3");
+ assertEquals(globals.GpuLanguageFromString("glsl_1.3"), GpuLanguage.GPU_LANGUAGE_GLSL_1_3);
+
+ // Roles
+ assertEquals(globals.ROLE_DEFAULT, "default");
+ assertEquals(globals.ROLE_REFERENCE, "reference");
+ assertEquals(globals.ROLE_DATA, "data");
+ assertEquals(globals.ROLE_COLOR_PICKING, "color_picking");
+ assertEquals(globals.ROLE_SCENE_LINEAR, "scene_linear");
+ assertEquals(globals.ROLE_COMPOSITING_LOG, "compositing_log");
+ assertEquals(globals.ROLE_COLOR_TIMING, "color_timing");
+ assertEquals(globals.ROLE_TEXTURE_PAINT, "texture_paint");
+ assertEquals(globals.ROLE_MATTE_PAINT, "matte_paint");
+
+ }
+
+}
diff --git a/src/jniglue/tests/org/OpenColorIO/GpuShaderDescTest.java b/src/jniglue/tests/org/OpenColorIO/GpuShaderDescTest.java
new file mode 100644
index 0000000..08b0a16
--- /dev/null
+++ b/src/jniglue/tests/org/OpenColorIO/GpuShaderDescTest.java
@@ -0,0 +1,24 @@
+
+import junit.framework.TestCase;
+import org.OpenColorIO.*;
+
+public class GpuShaderDescTest extends TestCase {
+
+ protected void setUp() {
+ }
+
+ protected void tearDown() {
+ }
+
+ public void test_interface() {
+ GpuShaderDesc desc = new GpuShaderDesc();
+ desc.setLanguage(GpuLanguage.GPU_LANGUAGE_GLSL_1_3);
+ assertEquals(GpuLanguage.GPU_LANGUAGE_GLSL_1_3, desc.getLanguage());
+ desc.setFunctionName("foo123");
+ assertEquals("foo123", desc.getFunctionName());
+ desc.setLut3DEdgeLen(32);
+ assertEquals(32, desc.getLut3DEdgeLen());
+ assertEquals("glsl_1.3 foo123 32", desc.getCacheID());
+ }
+
+}
diff --git a/src/jniglue/tests/org/OpenColorIO/LookTest.java b/src/jniglue/tests/org/OpenColorIO/LookTest.java
new file mode 100644
index 0000000..778c124
--- /dev/null
+++ b/src/jniglue/tests/org/OpenColorIO/LookTest.java
@@ -0,0 +1,35 @@
+
+import junit.framework.TestCase;
+import org.OpenColorIO.*;
+
+public class LookTest extends TestCase {
+
+ protected void setUp() {
+ }
+
+ protected void tearDown() {
+ }
+
+ public void test_interface() {
+ Look lk = new Look().Create();
+ lk.setName("coollook");
+ assertEquals("coollook", lk.getName());
+ lk.setProcessSpace("somespace");
+ assertEquals("somespace", lk.getProcessSpace());
+ ExponentTransform et = new ExponentTransform().Create();
+ et.setValue(new float[]{0.1f, 0.2f, 0.3f, 0.4f});
+ lk.setTransform(et);
+ ExponentTransform oet = (ExponentTransform)lk.getTransform();
+ float vals[] = new float[4];
+ oet.getValue(vals);
+ assertEquals(0.2f, vals[1], 1e-8);
+ ExponentTransform iet = new ExponentTransform().Create();
+ iet.setValue(new float[]{-0.1f, -0.2f, -0.3f, -0.4f});
+ lk.setInverseTransform(iet);
+ ExponentTransform ioet = (ExponentTransform)lk.getInverseTransform();
+ float vals2[] = new float[4];
+ ioet.getValue(vals2);
+ assertEquals(-0.2f, vals2[1], 1e-8);
+ }
+
+}
diff --git a/src/jniglue/tests/org/OpenColorIO/OpenColorIOTestSuite.java b/src/jniglue/tests/org/OpenColorIO/OpenColorIOTestSuite.java
new file mode 100644
index 0000000..b847d96
--- /dev/null
+++ b/src/jniglue/tests/org/OpenColorIO/OpenColorIOTestSuite.java
@@ -0,0 +1,30 @@
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class OpenColorIOTestSuite {
+
+ public static Test suite() {
+
+ TestSuite suite = new TestSuite();
+
+ // Core
+ suite.addTestSuite(GlobalsTest.class);
+ suite.addTestSuite(ConfigTest.class);
+ suite.addTestSuite(ColorSpaceTest.class);
+ suite.addTestSuite(LookTest.class);
+ suite.addTestSuite(BakerTest.class);
+ suite.addTestSuite(PackedImageDescTest.class);
+ suite.addTestSuite(PlanarImageDescTest.class);
+ suite.addTestSuite(GpuShaderDescTest.class);
+ suite.addTestSuite(ContextTest.class);
+ suite.addTestSuite(TransformsTest.class);
+
+ return suite;
+ }
+
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+}
diff --git a/src/jniglue/tests/org/OpenColorIO/PackedImageDescTest.java b/src/jniglue/tests/org/OpenColorIO/PackedImageDescTest.java
new file mode 100644
index 0000000..741a13d
--- /dev/null
+++ b/src/jniglue/tests/org/OpenColorIO/PackedImageDescTest.java
@@ -0,0 +1,39 @@
+
+import junit.framework.TestCase;
+import org.OpenColorIO.*;
+import java.nio.*;
+
+public class PackedImageDescTest extends TestCase {
+
+ protected void setUp() {
+ }
+
+ protected void tearDown() {
+ }
+
+ public void test_interface() {
+
+ int width = 2;
+ int height = 2;
+ int channels = 4;
+ float packedpix[] = new float[]{0.1f, 0.1f, 0.1f, 1.0f,
+ 0.2f, 0.2f, 0.2f, 1.0f,
+ 0.3f, 0.3f, 0.3f, 1.0f,
+ 0.4f, 0.4f, 0.4f, 1.0f };
+ FloatBuffer buf = ByteBuffer.allocateDirect(width * height * channels
+ * Float.SIZE / 8).asFloatBuffer();
+ buf.put(packedpix);
+ //
+ PackedImageDesc foo = new PackedImageDesc(buf, width, height, channels);
+ FloatBuffer wee = foo.getData();
+ assertEquals(0.3f, wee.get(10));
+ assertEquals(2, foo.getWidth());
+ assertEquals(2, foo.getHeight());
+ assertEquals(4, foo.getNumChannels());
+ assertEquals(4, foo.getChanStrideBytes());
+ assertEquals(16, foo.getXStrideBytes());
+ assertEquals(32, foo.getYStrideBytes());
+
+ }
+
+}
diff --git a/src/jniglue/tests/org/OpenColorIO/PlanarImageDescTest.java b/src/jniglue/tests/org/OpenColorIO/PlanarImageDescTest.java
new file mode 100644
index 0000000..e0d4deb
--- /dev/null
+++ b/src/jniglue/tests/org/OpenColorIO/PlanarImageDescTest.java
@@ -0,0 +1,51 @@
+
+import junit.framework.TestCase;
+import org.OpenColorIO.*;
+import java.nio.*;
+
+public class PlanarImageDescTest extends TestCase {
+
+ protected void setUp() {
+ }
+
+ protected void tearDown() {
+ }
+
+ public void test_interface() {
+
+ int width = 2;
+ int height = 2;
+ int channels = 4;
+ //
+ float rpix[] = new float[]{0.1f, 0.2f, 0.3f, 0.4f};
+ float gpix[] = new float[]{0.1f, 0.2f, 0.3f, 0.4f};
+ float bpix[] = new float[]{0.1f, 0.2f, 0.3f, 0.4f};
+ float apix[] = new float[]{1.0f, 1.0f, 1.0f, 1.0f};
+ int alloc = width * height * Float.SIZE / 8;
+ //
+ FloatBuffer rbuf = ByteBuffer.allocateDirect(alloc).asFloatBuffer();
+ rbuf.put(rpix);
+ FloatBuffer gbuf = ByteBuffer.allocateDirect(alloc).asFloatBuffer();
+ gbuf.put(gpix);
+ FloatBuffer bbuf = ByteBuffer.allocateDirect(alloc).asFloatBuffer();
+ bbuf.put(bpix);
+ FloatBuffer abuf = ByteBuffer.allocateDirect(alloc).asFloatBuffer();
+ abuf.put(apix);
+ //
+ PlanarImageDesc foo = new PlanarImageDesc(rbuf, gbuf, bbuf, abuf,
+ width, height);
+ FloatBuffer trb = foo.getRData();
+ FloatBuffer tgb = foo.getGData();
+ FloatBuffer tbb = foo.getBData();
+ FloatBuffer tab = foo.getAData();
+ assertEquals(0.1f, trb.get(0));
+ assertEquals(0.2f, tgb.get(1));
+ assertEquals(0.3f, tbb.get(2));
+ assertEquals(1.0f, tab.get(3));
+ assertEquals(2, foo.getWidth());
+ assertEquals(2, foo.getHeight());
+ assertEquals(8, foo.getYStrideBytes());
+
+ }
+
+}
diff --git a/src/jniglue/tests/org/OpenColorIO/TransformsTest.java b/src/jniglue/tests/org/OpenColorIO/TransformsTest.java
new file mode 100644
index 0000000..6300079
--- /dev/null
+++ b/src/jniglue/tests/org/OpenColorIO/TransformsTest.java
@@ -0,0 +1,237 @@
+
+import junit.framework.TestCase;
+import org.OpenColorIO.*;
+
+public class TransformsTest extends TestCase {
+
+ protected void setUp() {
+ }
+
+ protected void tearDown() {
+ }
+
+ public void test_interface() {
+
+ //// AllocationTransform ////
+ AllocationTransform at = new AllocationTransform().Create();
+ assertEquals(Allocation.ALLOCATION_UNIFORM, at.getAllocation());
+ at.setAllocation(Allocation.ALLOCATION_LG2);
+ assertEquals(Allocation.ALLOCATION_LG2, at.getAllocation());
+ assertEquals(0, at.getNumVars());
+ float[] vars = new float[]{0.1f, 0.2f, 0.3f};
+ at.setVars(3, vars);
+ assertEquals(3, at.getNumVars());
+ float newvars[] = new float[3];
+ at.getVars(newvars);
+ assertEquals(0.2f, newvars[1], 1e-8);
+
+ // Base Transform method tests
+ assertEquals(TransformDirection.TRANSFORM_DIR_FORWARD, at.getDirection());
+ at.setDirection(TransformDirection.TRANSFORM_DIR_UNKNOWN);
+ assertEquals(TransformDirection.TRANSFORM_DIR_UNKNOWN, at.getDirection());
+
+ //// CDLTransform ////
+ CDLTransform cdl = new CDLTransform().Create();
+ String CC = ""
+ +"<ColorCorrection id=\"foo\">"
+ +"<SOPNode>"
+ +"<Description>this is a descipt</Description>"
+ +"<Slope>1.1 1.2 1.3</Slope>"
+ +"<Offset>2.1 2.2 2.3</Offset>"
+ +"<Power>3.1 3.2 3.3</Power>"
+ +"</SOPNode>"
+ +"<SatNode><Saturation>0.7</Saturation></SatNode>"
+ +"</ColorCorrection>";
+ // Don't want to deal with getting the correct path so this runs
+ //CDLTransform cdlfile = new CDLTransform().CreateFromFile("../OpenColorIO/src/jniglue/tests/org/OpenColorIO/test.cc", "foo");
+ //assertEquals(CC, cdlfile.getXML());
+ cdl.setXML(CC);
+ assertEquals(CC, cdl.getXML());
+ //CDLTransform match = new CDLTransform().Create();
+ CDLTransform match = (CDLTransform)cdl.createEditableCopy();
+ match.setOffset(new float[]{1.0f, 1.0f, 1.f});
+ assertEquals(false, cdl.equals(match));
+ cdl.setSlope(new float[]{0.1f, 0.2f, 0.3f});
+ cdl.setOffset(new float[]{1.1f, 1.2f, 1.3f});
+ cdl.setPower(new float[]{2.1f, 2.2f, 2.3f});
+ cdl.setSat(0.5f);
+ String CC2 = ""
+ +"<ColorCorrection id=\"foo\">"
+ +"<SOPNode>"
+ +"<Description>this is a descipt</Description>"
+ +"<Slope>0.1 0.2 0.3</Slope>"
+ +"<Offset>1.1 1.2 1.3</Offset>"
+ +"<Power>2.1 2.2 2.3</Power>"
+ +"</SOPNode>"
+ +"<SatNode><Saturation>0.5</Saturation></SatNode>"
+ +"</ColorCorrection>";
+ assertEquals(CC2, cdl.getXML());
+ cdl.setSOP(new float[]{1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f});
+ float newsop[] = new float[9];
+ cdl.getSOP(newsop);
+ assertEquals(1.5f, newsop[4], 1e-8);
+ float slope[] = new float[3];
+ cdl.getSlope(slope);
+ assertEquals(1.2f, slope[1], 1e-8);
+ float offset[] = new float[3];
+ cdl.getOffset(offset);
+ assertEquals(1.6f, offset[2], 1e-8);
+ float power[] = new float[3];
+ cdl.getPower(power);
+ assertEquals(1.7f, power[0], 1e-8);
+ assertEquals(0.5f, cdl.getSat(), 1e-8);
+ float luma[] = new float[3];
+ cdl.getSatLumaCoefs(luma);
+ assertEquals(0.2126f, luma[0], 1e-8);
+ assertEquals(0.7152f, luma[1], 1e-8);
+ assertEquals(0.0722f, luma[2], 1e-8);
+ cdl.setID("foobar123");
+ assertEquals("foobar123", cdl.getID());
+ cdl.setDescription("bar");
+ assertEquals("bar", cdl.getDescription());
+
+ //// ColorSpaceTransform ////
+ ColorSpaceTransform ct = new ColorSpaceTransform().Create();
+ ct.setSrc("foo");
+ assertEquals("foo", ct.getSrc());
+ ct.setDst("bar");
+ assertEquals("bar", ct.getDst());
+
+ //// DisplayTransform ////
+ DisplayTransform dt = new DisplayTransform().Create();
+ dt.setInputColorSpaceName("lin18");
+ assertEquals("lin18", dt.getInputColorSpaceName());
+ //public native void setLinearCC(Transform cc);
+ //public native Transform getLinearCC();
+ //public native void setColorTimingCC(Transform cc);
+ //public native Transform getColorTimingCC();
+ //public native void setChannelView(Transform transform);
+ //public native Transform getChannelView();
+ dt.setDisplay("sRGB");
+ assertEquals("sRGB", dt.getDisplay());
+ dt.setView("foobar");
+ assertEquals("foobar", dt.getView());
+ cdl.setXML(CC);
+ dt.setDisplayCC(cdl);
+ CDLTransform cdldt = (CDLTransform)dt.getDisplayCC();
+ assertEquals(CC, cdldt.getXML());
+ dt.setLooksOverride("darkgrade");
+ assertEquals("darkgrade", dt.getLooksOverride());
+ dt.setLooksOverrideEnabled(true);
+ assertEquals(true, dt.getLooksOverrideEnabled());
+
+ //// ExponentTransform ////
+ ExponentTransform et = new ExponentTransform().Create();
+ et.setValue(new float[]{0.1f, 0.2f, 0.3f, 0.4f});
+ float evals[] = new float[4];
+ et.getValue(evals);
+ assertEquals(0.3f, evals[2], 1e-8);
+
+ //// FileTransform ////
+ FileTransform ft = new FileTransform().Create();
+ ft.setSrc("foo");
+ assertEquals("foo", ft.getSrc());
+ ft.setCCCId("foobar");
+ assertEquals("foobar", ft.getCCCId());
+ ft.setInterpolation(Interpolation.INTERP_NEAREST);
+ assertEquals(Interpolation.INTERP_NEAREST, ft.getInterpolation());
+ assertEquals(15, ft.getNumFormats());
+ assertEquals("flame", ft.getFormatNameByIndex(0));
+ assertEquals("3dl", ft.getFormatExtensionByIndex(0));
+
+ //// GroupTransform ////
+ GroupTransform gt = new GroupTransform().Create();
+ gt.push_back(et);
+ gt.push_back(ft);
+ assertEquals(2, gt.size());
+ assertEquals(false, gt.empty());
+ Transform foo = gt.getTransform(0);
+ assertEquals(TransformDirection.TRANSFORM_DIR_FORWARD, foo.getDirection());
+ gt.clear();
+ assertEquals(0, gt.size());
+
+ //// LogTransform ////
+ LogTransform lt = new LogTransform().Create();
+ lt.setBase(10.f);
+ assertEquals(10.f, lt.getBase());
+
+ //// LookTransform ////
+ LookTransform lkt = new LookTransform().Create();
+ lkt.setSrc("foo");
+ assertEquals("foo", lkt.getSrc());
+ lkt.setDst("bar");
+ assertEquals("bar", lkt.getDst());
+ lkt.setLooks("bar;foo");
+ assertEquals("bar;foo", lkt.getLooks());
+
+ //// MatrixTransform ////
+ MatrixTransform mt = new MatrixTransform().Create();
+ MatrixTransform mmt = (MatrixTransform)mt.createEditableCopy();
+ mt.setValue(new float[]{0.1f, 0.2f, 0.3f, 0.4f,
+ 0.5f, 0.6f, 0.7f, 0.8f,
+ 0.9f, 1.0f, 1.1f, 1.2f,
+ 1.3f, 1.4f, 1.5f, 1.6f},
+ new float[]{0.1f, 0.2f, 0.3f, 0.4f});
+ assertEquals(false, mt.equals(mmt));
+ float m44_1[] = new float[16];
+ float offset_1[] = new float[4];
+ mt.getValue(m44_1, offset_1);
+ assertEquals(0.3f, m44_1[2]);
+ assertEquals(0.2f, offset_1[1]);
+ mt.setMatrix(new float[]{1.1f, 1.2f, 1.3f, 1.4f,
+ 1.5f, 1.6f, 1.7f, 1.8f,
+ 1.9f, 2.0f, 2.1f, 2.2f,
+ 2.3f, 2.4f, 2.5f, 2.6f});
+ float m44_2[] = new float[16];
+ mt.getMatrix(m44_2);
+ assertEquals(1.3f, m44_2[2]);
+ mt.setOffset(new float[]{1.1f, 1.2f, 1.3f, 1.4f});
+ float offset_2[] = new float[4];
+ mt.getOffset(offset_2);
+ assertEquals(1.4f, offset_2[3]);
+ mt.Fit(m44_2, offset_2,
+ new float[]{0.1f, 0.1f, 0.1f, 0.1f},
+ new float[]{0.9f, 0.9f, 0.9f, 0.9f},
+ new float[]{0.0f, 0.0f, 0.0f, 0.0f},
+ new float[]{1.1f, 1.1f, 1.1f, 1.1f});
+ float m44_3[] = new float[16];
+ mt.getMatrix(m44_3);
+ assertEquals(1.3f, m44_3[2]);
+ mt.Identity(m44_3, offset_2);
+ assertEquals(0.f, m44_3[1]);
+ mt.Sat(m44_2, offset_2, 0.5f, new float[]{0.2126f, 0.7152f, 0.0722f});
+ assertEquals(0.3576f, m44_2[1]);
+ mt.Scale(m44_2, offset_2, new float[]{0.9f, 0.8f, 0.7f, 1.f});
+ assertEquals(0.9f, m44_2[0]);
+ mt.View(m44_2, null, new int[]{1, 1, 1, 0}, new float[]{0.2126f, 0.7152f, 0.0722f});
+ assertEquals(0.0722f, m44_2[2]);
+
+ //// TruelightTransform ////
+ TruelightTransform tt = new TruelightTransform().Create();
+ tt.setConfigRoot("/some/path");
+ assertEquals("/some/path", tt.getConfigRoot());
+ tt.setProfile("profileA");
+ assertEquals("profileA", tt.getProfile());
+ tt.setCamera("incam");
+ assertEquals("incam", tt.getCamera());
+ tt.setInputDisplay("dellmon");
+ assertEquals("dellmon", tt.getInputDisplay());
+ tt.setRecorder("blah");
+ assertEquals("blah", tt.getRecorder());
+ tt.setPrint("kodasomething");
+ assertEquals("kodasomething", tt.getPrint());
+ tt.setLamp("foobar");
+ assertEquals("foobar", tt.getLamp());
+ tt.setOutputCamera("somecam");
+ assertEquals("somecam", tt.getOutputCamera());
+ tt.setDisplay("sRGB");
+ assertEquals("sRGB", tt.getDisplay());
+ tt.setCubeInput("log");
+ assertEquals("log", tt.getCubeInput());
+
+ try {
+ } catch (Exception e) { System.out.println(e); }
+
+ }
+
+} \ No newline at end of file
diff --git a/src/jniglue/tests/org/OpenColorIO/test.cc b/src/jniglue/tests/org/OpenColorIO/test.cc
new file mode 100644
index 0000000..121bf42
--- /dev/null
+++ b/src/jniglue/tests/org/OpenColorIO/test.cc
@@ -0,0 +1,11 @@
+<ColorCorrection id="foo">
+ <SOPNode>
+ <Description>this is a descipt</Description>
+ <Slope>1.1 1.2 1.3</Slope>
+ <Offset>2.1 2.2 2.3</Offset>
+ <Power>3.1 3.2 3.3</Power>
+ </SOPNode>
+ <SatNode>
+ <Saturation>0.7</Saturation>
+ </SatNode>
+</ColorCorrection> \ No newline at end of file
diff --git a/src/mari/1.4v1/README b/src/mari/1.4v1/README
new file mode 100644
index 0000000..ecfdf18
--- /dev/null
+++ b/src/mari/1.4v1/README
@@ -0,0 +1,10 @@
+These files ship with Mari, and are *not* required to be manually installed.
+
+They are provided as a reference example of using the OCIO API to create a GPU
+monitor implementation in python.
+
+Media/Scripts/mari/utils/ocio.py
+Media/Scripts/mari/system/_ocio_toolbar.py
+Media/Scripts/mari/system/_ocio_filter.py
+
+All code in these examples is Copyright (c) 2011 The Foundry Visionmongers Ltd.
diff --git a/src/mari/1.4v1/_ocio_filter.py b/src/mari/1.4v1/_ocio_filter.py
new file mode 100755
index 0000000..e3c3bf3
--- /dev/null
+++ b/src/mari/1.4v1/_ocio_filter.py
@@ -0,0 +1,127 @@
+#-------------------------------------------------------------------------------
+# Post processing (color management) related Mari scripts
+# coding: utf-8
+# Copyright (c) 2011 The Foundry Visionmongers Ltd. All Rights Reserved.
+#-------------------------------------------------------------------------------
+
+import mari, time, PythonQt, os, math
+ocio = mari.utils.ocio
+
+##############################################################################################
+
+filter = None
+
+class OcioFilter():
+
+ #-----------------------------------------------------------------------------------------
+
+ def __init__(self):
+ # Default all members...
+ self._config_file_list = mari.FileList(ocio.config_file_list_default)
+ self._config = ocio.config_default
+ self._input_color_space = ocio.color_space_default
+ self._output_color_space = ocio.color_space_default
+ self._filter = mari.gl_render.createQuickApplyGLSL('Color Correction', '', '', 'ColorManager.png')
+ self._filter_cache_id = None
+ self._texture_cache_id = None
+ self._sampler_name = None
+
+ self._filter.setMetadata('ConfigPath', self._config_file_list)
+ self._filter.setMetadataDisplayName('ConfigPath', 'Configuration File')
+ self._filter.setMetadataDefault('ConfigPath', ocio.CONFIG_FILE_LIST_RESET)
+ self._filter.setMetadataFlags('ConfigPath', self._filter.METADATA_VISIBLE | self._filter.METADATA_EDITABLE)
+
+ color_spaces = [color_space.getName() for color_space in self._config.getColorSpaces()]
+
+ color_space_reset = ocio.COLOR_SPACE_RESET
+ if color_spaces.count(color_space_reset) == 0:
+ color_space_reset = color_spaces[0]
+
+ self._filter.setMetadata('InputColorSpace', self._input_color_space)
+ self._filter.setMetadataDisplayName('InputColorSpace', 'Input Color Space')
+ self._filter.setMetadataDefault('InputColorSpace', color_space_reset)
+ self._filter.setMetadataItemList('InputColorSpace', color_spaces)
+ self._filter.setMetadataFlags('InputColorSpace', self._filter.METADATA_VISIBLE | self._filter.METADATA_EDITABLE)
+
+ self._filter.setMetadata('OutputColorSpace', self._output_color_space)
+ self._filter.setMetadataDisplayName('OutputColorSpace', 'Output Color Space')
+ self._filter.setMetadataDefault('OutputColorSpace', color_space_reset)
+ self._filter.setMetadataItemList('OutputColorSpace', color_spaces)
+ self._filter.setMetadataFlags('OutputColorSpace', self._filter.METADATA_VISIBLE | self._filter.METADATA_EDITABLE)
+
+ mari.utils.connect(self._filter.metadataValueChanged, self._metadataValueChanged)
+
+ self._rebuildFilter()
+
+ #-----------------------------------------------------------------------------------------
+
+ def _metadataValueChanged(self, name, value):
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Metadata \'%s\' changed to \'%s\'' % (name, value))
+
+ if name == 'ConfigPath':
+ if value == self._config_file_list:
+ return
+ self._config_file_list = mari.FileList(value)
+ self._config = ocio.loadConfig(self._config_file_list.at(0), False)
+
+ color_spaces = [color_space.getName() for color_space in self._config.getColorSpaces()]
+
+ color_space_reset = ocio.COLOR_SPACE_RESET
+ if color_spaces.count(color_space_reset) == 0:
+ color_space_reset = color_spaces[0]
+
+ if color_spaces.count(self._input_color_space) == 0:
+ self._input_color_space = color_space_reset
+
+ if color_spaces.count(self._output_color_space) == 0:
+ self._output_color_space = color_space_reset
+
+ self._filter.setMetadataItemList('InputColorSpace', color_spaces)
+ self._filter.setMetadataItemList('OutputColorSpace', color_spaces)
+ self._filter.setMetadataDefault('InputColorSpace', color_space_reset)
+ self._filter.setMetadataDefault('OutputColorSpace', color_space_reset)
+ self._filter.setMetadata('InputColorSpace', self._input_color_space )
+ self._filter.setMetadata('OutputColorSpace', self._output_color_space)
+
+ elif name == 'InputColorSpace':
+ if value == self._input_color_space:
+ return
+ self._input_color_space = value
+
+ elif name == 'OutputColorSpace':
+ if value == self._output_color_space:
+ return
+ self._output_color_space = value
+
+ else:
+ return
+
+ self._rebuildFilter()
+
+ #-----------------------------------------------------------------------------------------
+
+ def _rebuildFilter(self):
+ input_color_space = self._config.getColorSpace(self._input_color_space)
+ if input_color_space is not None:
+ output_color_space = self._config.getColorSpace(self._output_color_space)
+ if output_color_space is not None:
+ processor = self._config.getProcessor(input_color_space, output_color_space)
+
+ self._filter_cache_id, self._texture_cache_id, self._sampler_name = ocio.buildProcessorFilter(
+ processor,
+ self._filter,
+ self._filter_cache_id,
+ self._texture_cache_id)
+
+ current_canvas = mari.canvases.current()
+ if current_canvas is not None:
+ current_canvas.repaint()
+
+##############################################################################################
+
+if mari.app.isRunning():
+ if not hasattr(mari.gl_render, 'createQuickApplyGLSL'):
+ printMessage(MessageType.ERROR, 'This version of Mari does not support the mari.gl_render.createQuickApplyGLSL API')
+
+ elif ocio is not None:
+ filter = OcioFilter()
diff --git a/src/mari/1.4v1/_ocio_toolbar.py b/src/mari/1.4v1/_ocio_toolbar.py
new file mode 100755
index 0000000..84afb68
--- /dev/null
+++ b/src/mari/1.4v1/_ocio_toolbar.py
@@ -0,0 +1,1279 @@
+#-------------------------------------------------------------------------------
+# Post processing (color management) related Mari scripts
+# coding: utf-8
+# Copyright (c) 2011 The Foundry Visionmongers Ltd. All Rights Reserved.
+#-------------------------------------------------------------------------------
+
+import mari, time, PythonQt, os, math
+QtGui = PythonQt.QtGui
+QtCore = PythonQt.QtCore
+ocio = mari.utils.ocio
+
+##############################################################################################
+
+GAIN_GROUP_MAX_WIDTH = 312
+FSTOP_MAX_WIDTH = 50
+EXPOSURE_MAX_WIDTH = 102
+GAIN_MAX_WIDTH = 80
+GAMMA_MAX_WIDTH = 200
+TOOLBAR_SPACING = 3
+
+toolbar = None
+
+class OcioToolBar():
+
+ #-----------------------------------------------------------------------------------------
+
+ def __init__(self):
+ # Default all members...
+ self._config_file_list = mari.FileList(ocio.config_file_list_default)
+ self._config = ocio.config_default
+ self._lut_file_list = mari.FileList(ocio.lut_file_list_default)
+ self._lut_extrapolate = ocio.lut_extrapolate_default
+ self._color_space = ocio.color_space_default
+ self._display = ocio.display_default
+ self._view = ocio.view_default
+ self._swizzle = ocio.swizzle_default
+ self._gain = ocio.gain_default
+ self._gamma = ocio.gamma_default
+
+ self._lut_filter = None
+ self._lut_filter_cache_id = None
+ self._lut_texture_cache_id = None
+ self._lut_sampler_name = None
+
+ self._display_filter = None
+ self._display_filter_cache_id = None
+ self._display_texture_cache_id = None
+ self._display_sampler_name = None
+
+ self._lut_extrapolate_widget = None
+ self._color_space_widget = None
+ self._display_widget = None
+ self._view_widget = None
+ self._swizzle_widget = None
+ self._fstop_widget = None
+ self._fstop_decrement_widget = None
+ self._fstop_increment_widget = None
+ self._gain_widget = None
+ self._exposure_widget = None
+ self._gain_reset_widget = None
+ self._gamma_widget = None
+ self._gamma_reset_widget = None
+
+ self._buildWidgets()
+ self._toggle_color_management_action.setEnabled(False)
+ self._enableWidgets(False)
+
+ # Enable/disable color management.
+ mari.gl_render.setPostProcessingEnabled(self.isColorManagementEnabled())
+
+ # *** IMPORTANT *** The post filter collection used to be called 'OpenColorIO' but was renamed to hide the fact
+ # we use OpenColorIO from our users. So as a temporary workaround we need to check for the old filter collection
+ # on startup and remove it if found.
+ delete_filter_collection = mari.gl_render.findPostFilterCollection('OpenColorIO')
+ if delete_filter_collection is not None:
+ mari.gl_render.deletePostFilterCollection(delete_filter_collection)
+
+ # Create the OCIO post filter collection if not present.
+ self._filter_collection = mari.gl_render.findPostFilterCollection('Color Space')
+ if self._filter_collection is None:
+ self._filter_collection = mari.gl_render.createPostFilterCollection('Color Space')
+ else:
+ self._filter_collection.clear()
+ self._filter_collection.setReadOnly(True)
+
+ self._lut_filter = self._filter_collection.createGLSL('LUT Transform')
+ if not self._lut_file_list.isEmpty() and not self._rebuildLUTFilter(self._lut_file_list.at(0)):
+ self._lut_file_list.clear()
+
+ self._display_filter = self._filter_collection.createGLSL('Display Transform')
+ self._rebuildDisplayFilter()
+
+ self._buildMetadata()
+
+ # Set the color management filter stack as the current.
+ mari.gl_render.setPostFilterCollection(self._filter_collection)
+
+ # Attach ourselves to the applications toolbar created signal so we can rebuild the toolbar when it's been
+ # destoyed.
+ mari.utils.connect(mari.app.toolBarsCreated, self._toolBarsCreated)
+
+ # Attach ourselves to the appropriate GL signals so we can enable and disable widgets.
+ mari.utils.connect(mari.gl_render.postProcessingEnabled, self._postProcessingEnabled)
+ mari.utils.connect(mari.gl_render.setCurrentPostFilterCollection, self._setCurrentPostFilterCollection)
+
+ # Attach ourselves to the appropriate project signals so we can load and save settings.
+ mari.utils.connect(mari.projects.openedProject, self._openedProject)
+ mari.utils.connect(mari.projects.aboutToSaveProject, self._aboutToSaveProject)
+ mari.utils.connect(mari.projects.projectClosed, self._closedProject)
+
+ # Update the UI to match the current project, if we have one.
+ current_project = mari.projects.current()
+ if current_project is not None:
+ self._openedProject(current_project)
+
+ #-----------------------------------------------------------------------------------------
+
+ def isColorManagementEnabled(self):
+ return self._toggle_color_management_action.isChecked()
+
+ #-----------------------------------------------------------------------------------------
+
+ def setLUTPath(self, value, update_metadata = True, force_shader_build = False):
+ if (self._lut_file_list.isEmpty() and value != '') or \
+ (not self._lut_file_list.isEmpty() and value == '') or \
+ (not self._lut_file_list.isEmpty() and value != self._lut_file_list.at(0)) \
+ :
+ if self._rebuildLUTFilter(value, force_shader_build):
+ self._lut_file_list.clear()
+ if value != '':
+ self._lut_file_list.append(value)
+ self._lut_file_list.setPickedFile(value)
+
+ self._clear_lut_action.setEnabled(True)
+ self._lut_extrapolate_widget.setEnabled(True)
+ self._lut_filter.setEnabled(True)
+ else:
+ self._clear_lut_action.setEnabled(False)
+ self._lut_extrapolate_widget.setEnabled(False)
+ self._lut_filter.setEnabled(False)
+
+ if update_metadata:
+ mari.utils.disconnect(self._lut_filter.metadataValueChanged, lutMetadataValueChanged)
+ self._lut_filter.setMetadata('File', self._lut_file_list)
+ mari.utils.connect(self._lut_filter.metadataValueChanged, lutMetadataValueChanged)
+
+ else:
+ # If this was a request via the metadata system we will need to put the value back to what it was
+ # before.
+ if not update_metadata:
+ mari.utils.disconnect(self._lut_filter.metadataValueChanged, lutMetadataValueChanged)
+ self._lut_filter.setMetadata('File', self._lut_file_list)
+ mari.utils.connect(self._lut_filter.metadataValueChanged, lutMetadataValueChanged)
+
+ return False
+
+ return True
+
+ #-----------------------------------------------------------------------------------------
+
+ def resetLUT(self):
+ if ocio.lut_file_list_default.isEmpty() or not self.setLUTPath(ocio.lut_file_list_default.at(0)):
+ self.setLUTPath('')
+
+ #-----------------------------------------------------------------------------------------
+
+ def selectLUT(self):
+ lut_path = mari.utils.misc.getOpenFileName(None,
+ 'Select LUT File',
+ '' if self._lut_file_list.isEmpty() else self._lut_file_list.at(0),
+ ocio.lutFileFilter(),
+ None,
+ 0)
+ if os.path.isfile(lut_path):
+ self.setLUTPath(lut_path)
+
+ #-----------------------------------------------------------------------------------------
+
+ def setExtrapolateEnabled(self, value, update_widget = True, update_metadata = True):
+ if value != self._lut_extrapolate:
+ self._lut_extrapolate = value
+
+ if update_widget:
+ block = self._lut_extrapolate_widget.blockSignals(True)
+ self._lut_extrapolate_widget.setChecked(self._lut_extrapolate)
+ self._lut_extrapolate_widget.blockSignals(block)
+
+ if update_metadata:
+ mari.utils.disconnect(self._lut_filter.metadataValueChanged, lutMetadataValueChanged)
+ self._lut_filter.setMetadata('Extrapolate', self._lut_extrapolate)
+ mari.utils.connect(self._lut_filter.metadataValueChanged, lutMetadataValueChanged)
+
+ if not self._rebuildLUTFilter(lut_path = '' if self._lut_file_list.isEmpty() else self._lut_file_list.at(0),
+ force_shader_build = True):
+ self.resetLUT()
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Changed extrapolate to \'%s\'' % self._lut_extrapolate)
+
+ #-----------------------------------------------------------------------------------------
+
+ def setConfigPath(self, value, update_metadata = True):
+ if self._config_file_list.isEmpty() or value != self._config_file_list.at(0):
+ config = ocio.loadConfig(value, True)
+ if config is not None:
+ self._config_file_list.clear()
+ self._config_file_list.append(value)
+ self._config_file_list.setPickedFile(value)
+
+ self._config = config
+
+ self._updateDisplayWidgets()
+ self._updateDisplayMetadata()
+
+ self._rebuildDisplayFilter()
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Changed config to \'%s\'' % self._config_file_list.at(0))
+
+ else:
+ # If this was a request via the metadata system we will need to put the value back to what it was
+ # before.
+ if not update_metadata:
+ mari.utils.disconnect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+ self._display_filter.setMetadata('ConfigPath', self._config_file_list)
+ mari.utils.connect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+
+ return False
+
+ return True
+
+ #-----------------------------------------------------------------------------------------
+
+ def selectConfig(self):
+ config_path = mari.utils.misc.getOpenFileName(None,
+ 'Select Configuration File',
+ '' if self._config_file_list.isEmpty() else self._config_file_list.at(0),
+ ocio.configFileFilter(),
+ None,
+ 0)
+ if os.path.isfile(config_path):
+ self.setConfigPath(config_path)
+
+ #-----------------------------------------------------------------------------------------
+
+ def setColorSpace(self, value, update_widget = True, update_metadata = True):
+ if value != self._color_space:
+ self._color_space = value
+
+ if update_widget:
+ block = self._color_space_widget.blockSignals(True)
+ index = self._color_space_widget.findText(self._color_space)
+ self._color_space_widget.setCurrentIndex(index)
+ self._color_space_widget.blockSignals(block)
+
+ if update_metadata:
+ mari.utils.disconnect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+ self._display_filter.setMetadata('InputColorSpace', self._color_space)
+ mari.utils.connect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+
+ self._rebuildDisplayFilter()
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Changed input color space to \'%s\'' % self._color_space)
+
+ #-----------------------------------------------------------------------------------------
+
+ def setDisplay(self, value, update_widget = True, update_metadata = True):
+ if value != self._display:
+ self._display = value
+
+ if update_widget:
+ block = self._display_widget.blockSignals(True)
+ index = self._display_widget.findText(self._display)
+ self._display_widget.setCurrentIndex(index)
+ self._display_widget.blockSignals(block)
+
+ if update_metadata:
+ mari.utils.disconnect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+ self._display_filter.setMetadata('Display', self._display)
+ mari.utils.connect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+
+ self.setView(self._config.getDefaultView(self._display), update_widget, update_metadata)
+
+ self._rebuildDisplayFilter()
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Changed display to \'%s\'' % self._display)
+
+ #-----------------------------------------------------------------------------------------
+
+ def setView(self, value, update_widget = True, update_metadata = True):
+ if value != self._view:
+ self._view = value
+
+ if update_widget:
+ block = self._view_widget.blockSignals(True)
+ index = self._view_widget.findText(self._view)
+ self._view_widget.setCurrentIndex(index)
+ self._view_widget.blockSignals(block)
+
+ if update_metadata:
+ mari.utils.disconnect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+ self._display_filter.setMetadata('View', self._view)
+ mari.utils.connect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+
+ self._rebuildDisplayFilter()
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Changed view to \'%s\'' % self._view)
+
+ #-----------------------------------------------------------------------------------------
+
+ def setSwizzle(self, value, update_widget = True, update_metadata = True):
+ if value != self._swizzle:
+ self._swizzle = value
+
+ if update_widget:
+ block = self._swizzle_widget.blockSignals(True)
+ index = self._swizzle_widget.findText(self._swizzle)
+ self._swizzle_widget.setCurrentIndex(index)
+ self._swizzle_widget.blockSignals(block)
+
+ if update_metadata:
+ mari.utils.disconnect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+ self._display_filter.setMetadata('Swizzle', self._swizzle)
+ mari.utils.connect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+
+ self._rebuildDisplayFilter()
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Changed swizzle to \'%s\'' % self._swizzle)
+
+ #-----------------------------------------------------------------------------------------
+
+ def setGain(self, value, update_widget = True, update_metadata = True):
+ if value != self._gain:
+ self._gain = value
+
+ if update_widget:
+ self._updateGainWidgets()
+
+ if update_metadata:
+ mari.utils.disconnect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+ self._display_filter.setMetadata('Gain', self._gain)
+ mari.utils.connect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+
+ self._rebuildDisplayFilter()
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Changed gain to \'%s\'' % self._gain)
+
+ #-----------------------------------------------------------------------------------------
+
+ def setGamma(self, value, update_widget = True, update_metadata = True):
+ if value != self._gamma:
+ self._gamma = value
+
+ if update_widget:
+ block = self._gamma_widget.blockSignals(True)
+ self._gamma_widget.setValue(self._gamma)
+ self._gamma_widget.blockSignals(block)
+
+ if update_metadata:
+ mari.utils.disconnect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+ self._display_filter.setMetadata('Gamma', self._gamma)
+ mari.utils.connect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+
+ self._rebuildDisplayFilter()
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Changed gamma to \'%s\'' % self._gamma)
+
+ #-----------------------------------------------------------------------------------------
+
+ def updateLUTSize(self):
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Updating LUT size...')
+
+ # Rebuild the LUT filter.
+ if self._lut_sampler_name is not None:
+ self._lut_filter.deleteTexture(self._lut_sampler_name)
+ self._lut_sampler_name = None
+
+ self._lut_filter_cache_id = None
+ self._lut_texture_cache_id = None
+
+ if not self._rebuildLUTFilter(lut_path = '' if self._lut_file_list.isEmpty() else self._lut_file_list.at(0),
+ force_shader_build = True):
+ self.resetLUT()
+
+ # Rebuild the display filter.
+ if self._display_sampler_name is not None:
+ self._display_filter.deleteTexture(self._display_sampler_name)
+ self._display_sampler_name = None
+
+ self._display_filter_cache_id = None
+ self._display_texture_cache_id = None
+
+ self._rebuildDisplayFilter()
+
+ #-----------------------------------------------------------------------------------------
+
+ def updateFStopCenter(self):
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Updating f-stop center...')
+
+ fstop = ocio.convertGainToFStop(self._gain)
+ self._updateFStopWidgetText(fstop)
+
+ #-----------------------------------------------------------------------------------------
+ # Widgets:
+ #-----------------------------------------------------------------------------------------
+
+ def _buildWidgets(self):
+ action_list = list()
+
+ self._toggle_color_management_action = self._addAction(
+ '/Mari/OpenColorIO/&Toggle Color Management',
+ 'mari.system._ocio_toolbar.toolbar._toggleColorManagement()',
+ 'ColorManager.png',
+ 'Toggle on/off color management',
+ 'Toggle color management')
+ self._toggle_color_management_action.setCheckable(True)
+ self._toggle_color_management_action.setChecked(ocio.enabled_default)
+ action_list.append('/Mari/OpenColorIO/&Toggle Color Management')
+
+ self._select_config_action = self._addAction(
+ '/Mari/OpenColorIO/&Select Config',
+ 'mari.system._ocio_toolbar.toolbar.selectConfig()',
+ 'LoadColorConfig.png',
+ 'Select color space configuration file',
+ 'Select config')
+ action_list.append('/Mari/OpenColorIO/&Select Config')
+
+ self._select_lut_action = self._addAction(
+ '/Mari/OpenColorIO/&Select LUT',
+ 'mari.system._ocio_toolbar.toolbar.selectLUT()',
+ 'LoadLookupTable.png',
+ 'Select LUT file',
+ 'Select LUT')
+ action_list.append('/Mari/OpenColorIO/&Select LUT')
+
+ self._clear_lut_action = self._addAction(
+ '/Mari/OpenColorIO/&Clear LUT',
+ 'mari.system._ocio_toolbar.toolbar._clearLUT()',
+ 'ClearLookupTable.png',
+ 'Clear current LUT',
+ 'Clear LUT')
+ action_list.append('/Mari/OpenColorIO/&Clear LUT')
+
+ mari.app.deleteToolBar('Color Space')
+ self._toolbar = mari.app.createToolBar('Color Space', True)
+ self._toolbar.addActionList(action_list, False)
+ self._toolbar.setLockedSlot(True)
+ self._toolbar.setSpacing(TOOLBAR_SPACING)
+
+ self._toolbar.insertSeparator('/Mari/OpenColorIO/&Select LUT')
+
+ # Extrapolate:
+ self._toolbar.addWidget(QtGui.QLabel('Extrapolate'))
+ self._lut_extrapolate_widget = QtGui.QCheckBox()
+ self._lut_extrapolate_widget.setToolTip('Extrapolate if outside LUT range');
+ self._lut_extrapolate_widget.setChecked(self._lut_extrapolate)
+ self._lut_extrapolate_widget.connect(
+ QtCore.SIGNAL('toggled(bool)'),
+ lambda value: self.setExtrapolateEnabled(value = value, update_widget = False, update_metadata = True))
+ self._toolbar.addWidget(self._lut_extrapolate_widget)
+
+ self._toolbar.addSeparator()
+
+ color_spaces = [color_space.getName() for color_space in self._config.getColorSpaces()]
+
+ # Color-Space:
+ self._color_space_widget = self._addComboBox(
+ 'Input Color Space',
+ color_spaces,
+ self._color_space,
+ ocio.color_space_default,
+ lambda value: self.setColorSpace(value = value, update_widget = False, update_metadata = True))
+ self._color_space = self._color_space_widget.currentText
+
+ # Display:
+ self._display_widget = self._addComboBox(
+ 'Display Device',
+ self._config.getDisplays(),
+ self._display,
+ ocio.display_default,
+ lambda value: self.setDisplay(value = value, update_widget = False, update_metadata = True))
+ self._display = self._display_widget.currentText
+
+ # View:
+ self._view_widget = self._addComboBox(
+ 'View Transform',
+ self._config.getViews(self._display),
+ self._view,
+ ocio.view_default,
+ lambda value: self.setView(value = value, update_widget = False, update_metadata = True))
+ self._view = self._view_widget.currentText
+
+ # Swizzle:
+ self._swizzle_widget = self._addComboBox(
+ 'Component',
+ ocio.SWIZZLE_TYPES,
+ self._swizzle,
+ ocio.swizzle_default,
+ lambda value: self.setSwizzle(value = value, update_widget = False, update_metadata = True))
+ self._swizzle = self._swizzle_widget.currentText
+
+ # Gain Group:
+ group_widget, layout = self._addWidgetGroup()
+ group_widget.setMaximumWidth(GAIN_GROUP_MAX_WIDTH)
+
+ layout.addWidget(QtGui.QLabel('Gain'))
+
+ # F-Stop:
+ subgroup_widget = QtGui.QWidget()
+ layout.addWidget(subgroup_widget)
+
+ sublayout = QtGui.QHBoxLayout()
+ sublayout.setSpacing(0)
+ sublayout.setMargin(0)
+ subgroup_widget.setLayout(sublayout)
+
+ exposure = ocio.convertGainToExposure(self._gain)
+ fstop = ocio.convertExposureToFStop(exposure)
+ scale = (exposure - ocio.EXPOSURE_MIN) / ocio.EXPOSURE_DELTA
+ widget_max = int(math.ceil(ocio.EXPOSURE_DELTA / ocio.FSTOP_STEP_SIZE))
+ widget_value = scale * widget_max
+ self._fstop_widget = mari.LineEdit()
+ self._fstop_widget.setRange(widget_max)
+ self._fstop_widget.setMaximumWidth(FSTOP_MAX_WIDTH)
+ self._fstop_widget.setReadOnly(True)
+ self._updateFStopWidgetText(fstop)
+ self._fstop_widget.setValue(widget_value)
+ mari.utils.connect(self._fstop_widget.movedMouse, self._fstopMovedMouse)
+ self._fstop_widget.addToLayout(sublayout)
+
+ self._fstop_decrement_widget = self._addSmallButtom(
+ sublayout,
+ '-',
+ 'Decrease gain 1/2 stop',
+ lambda: self.setGain(ocio.convertExposureToGain(ocio.convertGainToExposure(self._gain) - 0.5)))
+ self._fstop_increment_widget = self._addSmallButtom(
+ sublayout,
+ '+',
+ 'Increase gain 1/2 stop',
+ lambda: self.setGain(ocio.convertExposureToGain(ocio.convertGainToExposure(self._gain) + 0.5)))
+
+ ocio.registerLUTSizeChanged(self.updateLUTSize)
+ ocio.registerFStopCenterChanged(self.updateFStopCenter)
+
+ # Gain:
+ subgroup_widget = QtGui.QWidget()
+ layout.addWidget(subgroup_widget)
+
+ sublayout = QtGui.QHBoxLayout()
+ sublayout.setSpacing(3)
+ sublayout.setMargin(0)
+ subgroup_widget.setLayout(sublayout)
+
+ widget_max = int(math.ceil(ocio.EXPOSURE_DELTA / ocio.EXPOSURE_STEP_SIZE))
+ widget_value = scale * widget_max
+ self._gain_widget = mari.LineEdit()
+ self._gain_widget.setRange(widget_max)
+ self._gain_widget.addFloatValidator(ocio.GAIN_MIN, ocio.GAIN_MAX, ocio.GAIN_PRECISION)
+ self._gain_widget.setMaximumWidth(GAIN_MAX_WIDTH)
+ self._updateGainWidgetText()
+ self._gain_widget.setValue(widget_value)
+ mari.utils.connect(
+ self._gain_widget.lostFocus,
+ lambda: self.setGain(max(min(float(self._gain_widget.text()), ocio.GAIN_MAX), ocio.GAIN_MIN)))
+ mari.utils.connect(self._gain_widget.movedMouse, self._gainMovedMouse)
+ self._gain_widget.addToLayout(sublayout)
+
+ # Exposure:
+ self._exposure_widget = QtGui.QSlider()
+ self._exposure_widget.orientation = 1
+ self._exposure_widget.setMaximum(widget_max)
+ self._exposure_widget.setValue(widget_value)
+ self._exposure_widget.setMinimumWidth(EXPOSURE_MAX_WIDTH)
+ self._exposure_widget.setMaximumWidth(EXPOSURE_MAX_WIDTH)
+ mari.utils.connect(self._exposure_widget.valueChanged, self._exposureChanged)
+ sublayout.addWidget(self._exposure_widget)
+
+ self._gain_reset_widget = self._addSmallButtom(
+ layout,
+ 'R',
+ 'Reset gain to default',
+ lambda: self.setGain(value = ocio.GAIN_RESET, update_widget = True, update_metadata = True))
+
+ # Gamma:
+ group_widget, layout = self._addWidgetGroup()
+ group_widget.setMaximumWidth(GAMMA_MAX_WIDTH)
+
+ layout.addWidget(QtGui.QLabel('Gamma'))
+
+ self._gamma_widget = mari.FloatSlider()
+ self._gamma_widget.setRange(ocio.GAMMA_MIN, ocio.GAMMA_MAX)
+ self._gamma_widget.setStepSize(ocio.GAMMA_STEP_SIZE)
+ self._gamma_widget.setPrecision(ocio.GAMMA_PRECISION)
+ self._gamma_widget.setValue(self._gamma)
+ mari.utils.connect(
+ self._gamma_widget.valueChanged,
+ lambda value: self.setGamma(value = value, update_widget = False, update_metadata = True))
+ self._gamma_widget.addToLayout(layout)
+
+ self._gamma_reset_widget = self._addSmallButtom(
+ layout,
+ 'R',
+ 'Reset gamma to default',
+ lambda: self.setGamma(value = ocio.GAMMA_RESET, update_widget = True, update_metadata = True))
+
+ #-----------------------------------------------------------------------------------------
+
+ def _updateDisplayWidgets(self):
+ color_spaces = [color_space.getName() for color_space in self._config.getColorSpaces()]
+
+ self._updateComboBox(self._color_space_widget, color_spaces, self._color_space, ocio.color_space_default)
+ self._color_space = self._color_space_widget.currentText
+
+ self._updateComboBox(self._display_widget, self._config.getDisplays(), self._display, ocio.display_default)
+ self._display = self._display_widget.currentText
+
+ self._updateComboBox(self._view_widget, self._config.getViews(self._display), self._view, ocio.view_default)
+ self._view = self._view_widget.currentText
+
+ self._updateComboBox(self._swizzle_widget, ocio.SWIZZLE_TYPES, self._swizzle, ocio.swizzle_default)
+ self._swizzle = self._swizzle_widget.currentText
+
+ self._updateGainWidgets()
+
+ self._gamma_widget.setValue(self._gamma)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _enableWidgets(self, enable):
+ self._select_config_action.setEnabled(enable)
+ self._select_lut_action.setEnabled(enable)
+ lut_enable = enable and not self._lut_file_list.isEmpty()
+ self._clear_lut_action.setEnabled(lut_enable)
+ self._lut_extrapolate_widget.setEnabled(lut_enable)
+
+ self._color_space_widget.setEnabled(enable)
+ self._display_widget.setEnabled(enable)
+ self._view_widget.setEnabled(enable)
+ self._swizzle_widget.setEnabled(enable)
+
+ self._fstop_widget.setEnabled(enable)
+ self._fstop_decrement_widget.setEnabled(enable)
+ self._fstop_increment_widget.setEnabled(enable)
+ self._gain_widget.setEnabled(enable)
+ self._exposure_widget.setEnabled(enable)
+ self._gain_reset_widget.setEnabled(enable)
+
+ self._gamma_widget.setEnabled(enable)
+ self._gamma_reset_widget.setEnabled(enable)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _addAction(self, identifier, command, icon_filename, tip, whats_this):
+ action = mari.actions.find(identifier)
+ if action is None:
+ action = mari.actions.create(identifier, command)
+
+ icon_path = mari.resources.path(mari.resources.ICONS) + '/' + icon_filename
+ action.setIconPath(icon_path)
+
+ action.setStatusTip(tip)
+ action.setToolTip(tip)
+ action.setWhatsThis(whats_this)
+
+ return action
+
+ #-----------------------------------------------------------------------------------------
+
+ def _addWidgetGroup(self):
+ group_widget = QtGui.QWidget()
+ self._toolbar.addWidget(group_widget)
+
+ layout = QtGui.QHBoxLayout()
+ layout.setSpacing(1)
+ layout.setMargin(1)
+ group_widget.setLayout(layout)
+
+ return (group_widget, layout)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _addComboBox(self, label, items, value, default, value_changed, *args):
+ group_widget, layout = self._addWidgetGroup()
+
+ layout.addWidget(QtGui.QLabel(label))
+
+ widget = QtGui.QComboBox()
+ self._updateComboBox(widget, items, value, default)
+ widget.connect(QtCore.SIGNAL('currentIndexChanged(const QString &)'), value_changed)
+ layout.addWidget(widget)
+
+ return widget
+
+ #-----------------------------------------------------------------------------------------
+
+ def _updateComboBox(self, widget, items, value, default):
+ block = widget.blockSignals(True)
+
+ widget.clear()
+ for item in items:
+ widget.addItem(item)
+
+ if items.count(value) != 0:
+ widget.setCurrentIndex(items.index(value))
+ elif items.count(default) != 0:
+ widget.setCurrentIndex(items.index(default))
+
+ widget.blockSignals(block)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _addSmallButtom(self, layout, label, tool_tip, value_changed, *args):
+ widget = QtGui.QPushButton(label);
+ widget.setToolTip(tool_tip);
+ widget.setFixedHeight(16);
+ widget.setFixedWidth(16);
+ widget.connect(QtCore.SIGNAL('released()'), value_changed)
+ layout.addWidget(widget);
+
+ return widget
+
+ #-----------------------------------------------------------------------------------------
+
+ def _convertFStopWidgetValueToGain(self, value):
+ widget_max = int(math.ceil(ocio.EXPOSURE_DELTA / ocio.FSTOP_STEP_SIZE))
+ scale = float(value) / float(widget_max)
+ exposure = ocio.EXPOSURE_MIN + scale * ocio.EXPOSURE_DELTA
+ return ocio.convertExposureToGain(exposure)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _convertExposureWidgetValueToGain(self, value):
+ widget_max = int(math.ceil(ocio.EXPOSURE_DELTA / ocio.EXPOSURE_STEP_SIZE))
+ scale = float(value) / float(widget_max)
+ exposure = ocio.EXPOSURE_MIN + scale * ocio.EXPOSURE_DELTA
+ return ocio.convertExposureToGain(exposure)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _updateFStopWidgetText(self, fstop):
+ block = self._fstop_widget.blockSignals(True)
+ if fstop < 10.0:
+ # Floor the value to one decimal place and only display the decimal point if necessary
+ text = '%f' % fstop
+ index = text.index('.')
+ if text[index + 1] == '0':
+ text = text[:index]
+ else:
+ text = text[:index + 2]
+ self._fstop_widget.setText('f/%s' % text)
+ else:
+ self._fstop_widget.setText('f/%d' % int(fstop))
+ self._fstop_widget.blockSignals(block)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _updateGainWidgetText(self):
+ block = self._gain_widget.blockSignals(True)
+ self._gain_widget.setText(('%.' + ('%d' % ocio.GAIN_PRECISION) + 'f') % self._gain)
+ self._gain_widget.home(False)
+ self._gain_widget.blockSignals(block)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _updateGainWidgets(self):
+ exposure = ocio.convertGainToExposure(self._gain)
+ fstop = ocio.convertExposureToFStop(exposure)
+ self._updateFStopWidgetText(fstop)
+
+ scale = (exposure - ocio.EXPOSURE_MIN) / ocio.EXPOSURE_DELTA
+ widget_max = int(math.ceil(ocio.EXPOSURE_DELTA / ocio.FSTOP_STEP_SIZE))
+ widget_value = int(round(scale * float(widget_max)))
+ block = self._fstop_widget.blockSignals(True)
+ self._fstop_widget.setValue(widget_value)
+ self._fstop_widget.blockSignals(block)
+
+ self._updateGainWidgetText()
+
+ widget_max = int(math.ceil(ocio.EXPOSURE_DELTA / ocio.EXPOSURE_STEP_SIZE))
+ widget_value = int(round(scale * float(widget_max)))
+ block = self._gain_widget.blockSignals(True)
+ self._gain_widget.setValue(widget_value)
+ self._gain_widget.blockSignals(block)
+ block = self._exposure_widget.blockSignals(True)
+ self._exposure_widget.setValue(widget_value)
+ self._exposure_widget.blockSignals(block)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _toggleColorManagement(self):
+ enabled = self.isColorManagementEnabled()
+ mari.gl_render.setPostProcessingEnabled(enabled)
+ self._enableWidgets(enabled)
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Toggled color management to \'%s\'' % ('on' if enabled else 'off'))
+
+ #-----------------------------------------------------------------------------------------
+
+ def _clearLUT(self):
+ self.setLUTPath('')
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Cleared lut')
+
+ #-----------------------------------------------------------------------------------------
+
+ def _fstopMovedMouse(self, value):
+ self.setGain(self._convertFStopWidgetValueToGain(float(value)), False)
+
+ exposure = ocio.convertGainToExposure(self._gain)
+ fstop = ocio.convertExposureToFStop(exposure)
+ self._updateFStopWidgetText(fstop)
+
+ self._updateGainWidgetText()
+
+ widget_max = int(math.ceil(ocio.EXPOSURE_DELTA / ocio.EXPOSURE_STEP_SIZE))
+ scale = (exposure - ocio.EXPOSURE_MIN) / ocio.EXPOSURE_DELTA
+ value = int(round(scale * float(widget_max)))
+ self._gain_widget.setValue(value)
+
+ value = max(min(value, widget_max), 0)
+ self._exposure_widget.setValue(value)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _gainMovedMouse(self, value):
+ self.setGain(self._convertExposureWidgetValueToGain(float(value)), False)
+
+ self._updateGainWidgetText()
+
+ widget_max = int(math.ceil(ocio.EXPOSURE_DELTA / ocio.EXPOSURE_STEP_SIZE))
+ value = max(min(value, widget_max), 0)
+ self._exposure_widget.setValue(value)
+
+ exposure = ocio.convertGainToExposure(self._gain)
+ fstop = ocio.convertExposureToFStop(exposure)
+ self._updateFStopWidgetText(fstop)
+
+ scale = (exposure - ocio.EXPOSURE_MIN) / ocio.EXPOSURE_DELTA
+ widget_max = int(math.ceil(ocio.EXPOSURE_DELTA / ocio.FSTOP_STEP_SIZE))
+ value = int(round(scale * float(widget_max)))
+ self._fstop_widget.setValue(value)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _exposureChanged(self, value):
+ self.setGain(value = self._convertExposureWidgetValueToGain(float(value)),
+ update_widget = False,
+ update_metadata = True)
+
+ self._updateGainWidgetText()
+
+ self._gain_widget.setValue(value)
+
+ exposure = ocio.convertGainToExposure(self._gain)
+ fstop = ocio.convertExposureToFStop(exposure)
+ self._updateFStopWidgetText(fstop)
+
+ scale = (exposure - ocio.EXPOSURE_MIN) / ocio.EXPOSURE_DELTA
+ widget_max = int(math.ceil(ocio.EXPOSURE_DELTA / ocio.FSTOP_STEP_SIZE))
+ value = int(round(scale * float(widget_max)))
+ self._fstop_widget.setValue(value)
+
+ #-----------------------------------------------------------------------------------------
+ # Metadata:
+ #-----------------------------------------------------------------------------------------
+
+ def _buildMetadata(self):
+ # LUT:
+ # ---
+ mari.utils.connect(self._lut_filter.metadataValueChanged, lutMetadataValueChanged)
+ self._updateLUTMetadata()
+
+ flags = self._lut_filter.METADATA_VISIBLE | self._lut_filter.METADATA_EDITABLE
+ self._lut_filter.setMetadataFlags('File', flags)
+
+ self._lut_filter.setMetadataFlags('Extrapolate', flags)
+
+ # Display:
+ # -------
+ mari.utils.connect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+ self._updateDisplayMetadata()
+
+ self._display_filter.setMetadataDisplayName('ConfigPath', 'Configuration File')
+ flags = self._display_filter.METADATA_VISIBLE | self._display_filter.METADATA_EDITABLE
+ self._display_filter.setMetadataFlags('ConfigPath', flags)
+
+ self._display_filter.setMetadataDisplayName('InputColorSpace', 'Input Color Space')
+ self._display_filter.setMetadataFlags('InputColorSpace', flags)
+
+ self._display_filter.setMetadataDisplayName('Display', 'Display Device')
+ self._display_filter.setMetadataFlags('Display', flags)
+
+ self._display_filter.setMetadataDisplayName('View', 'View Transform')
+ self._display_filter.setMetadataFlags('View', flags)
+
+ self._display_filter.setMetadataDisplayName('Swizzle', 'Component')
+ self._display_filter.setMetadataFlags('Swizzle', flags)
+
+ self._display_filter.setMetadataDefault('Gain', ocio.GAIN_RESET)
+ self._display_filter.setMetadataRange('Gain', ocio.GAIN_MIN, ocio.GAIN_MAX)
+ self._display_filter.setMetadataStep('Gain', ocio.GAIN_STEP_SIZE)
+ self._display_filter.setMetadataFlags('Gain', flags)
+
+ self._display_filter.setMetadataDefault('Gamma', ocio.GAMMA_RESET)
+ self._display_filter.setMetadataRange('Gamma', ocio.GAMMA_MIN, ocio.GAMMA_MAX)
+ self._display_filter.setMetadataStep('Gamma', ocio.GAMMA_STEP_SIZE)
+ self._display_filter.setMetadataFlags('Gamma', flags)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _updateLUTMetadata(self):
+ mari.utils.disconnect(self._lut_filter.metadataValueChanged, lutMetadataValueChanged)
+
+ self._lut_filter.setMetadata('File', self._lut_file_list)
+
+ self._lut_filter.setMetadata('Extrapolate', self._lut_extrapolate)
+
+ mari.utils.connect(self._lut_filter.metadataValueChanged, lutMetadataValueChanged)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _updateDisplayMetadata(self):
+ mari.utils.disconnect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+
+ self._display_filter.setMetadata('ConfigPath', self._config_file_list)
+
+ color_spaces = [color_space.getName() for color_space in self._config.getColorSpaces()]
+
+ self._display_filter.setMetadata('InputColorSpace', self._color_space)
+ self._display_filter.setMetadataItemList('InputColorSpace', color_spaces)
+
+ self._display_filter.setMetadata('Display', self._display)
+ self._display_filter.setMetadataItemList('Display', self._config.getDisplays())
+
+ self._display_filter.setMetadata('View', self._view)
+ self._display_filter.setMetadataItemList('View', self._config.getViews(self._display))
+
+ self._display_filter.setMetadata('Swizzle', self._swizzle)
+ self._display_filter.setMetadataItemList('Swizzle', ocio.SWIZZLE_TYPES)
+
+ self._display_filter.setMetadata('Gain', self._gain)
+
+ self._display_filter.setMetadata('Gamma', self._gain)
+
+ mari.utils.connect(self._display_filter.metadataValueChanged, displayMetadataValueChanged)
+
+
+ #-----------------------------------------------------------------------------------------
+ # External Connections:
+ #-----------------------------------------------------------------------------------------
+
+ def _openedProject(self, project):
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Loading settings for project \'%s\'' % project.name())
+
+ # Load the settings stored as metadata on the project...
+
+ # General:
+ # -------
+
+ self._toggle_color_management_action.setEnabled(True)
+ self._toggle_color_management_action.setChecked(project.metadata('ColorEnabled') if project.hasMetadata('ColorEnabled') else ocio.enabled_default)
+
+ # Enable/disable color management (MUST be done after modifications to 'self._toggle_color_management_action'.
+ mari.gl_render.setPostProcessingEnabled(self.isColorManagementEnabled())
+
+ filter_collection = None
+ if project.hasMetadata('ColorProfile'):
+ # *** IMPORTANT *** The post filter collection used to be called 'OpenColorIO' but was renamed to hide the
+ # fact we use OpenColorIO from our users. So as a temporary workaround we need to check for the old filter
+ # collection correct for it.
+ name = project.metadata('ColorProfile')
+ if name == 'OpenColorIO':
+ name = 'Color Space'
+ filter_collection = mari.gl_render.findPostFilterCollection(name)
+
+ # Default the color management filter stack if the working one doesn't exist.
+ if filter_collection is None:
+ filter_collection = mari.gl_render.findPostFilterCollection(ocio.profile_default)
+
+ mari.gl_render.setPostFilterCollection(filter_collection)
+
+ # LUT:
+ # ---
+
+ lut_extrapolate = project.metadata('OcioLutExtrapolate') if project.hasMetadata('OcioLutExtrapolate') else ocio.lut_extrapolate_default
+ force_shader_build = lut_extrapolate != self._lut_extrapolate
+ self._lut_extrapolate = lut_extrapolate
+ self._lut_extrapolate_widget.setChecked(self._lut_extrapolate)
+
+ if project.hasMetadata('OcioLutPath'):
+ lut_path = ocio.buildLoadPath(project.metadata('OcioLutPath'))
+ if not self.setLUTPath(value = lut_path, update_metadata = True, force_shader_build = force_shader_build):
+ self.resetLUT()
+ else:
+ self.resetLUT()
+
+ # Display:
+ # -------
+
+ self._color_space = project.metadata( 'OcioColorSpace') if project.hasMetadata('OcioColorSpace') else ocio.color_space_default
+ self._display = project.metadata( 'OcioDisplay') if project.hasMetadata( 'OcioDisplay') else ocio.display_default
+ self._view = project.metadata( 'OcioView') if project.hasMetadata( 'OcioView') else ocio.view_default
+ self._swizzle = project.metadata( 'OcioSwizzle') if project.hasMetadata( 'OcioSwizzle') else ocio.swizzle_default
+ self._gain = max(min(project.metadata('OcioGain'),
+ ocio.GAIN_MAX),
+ ocio.GAIN_MIN) if project.hasMetadata( 'OcioGain') else ocio.gain_default
+ self._gamma = project.metadata( 'OcioGamma') if project.hasMetadata( 'OcioGamma') else ocio.gamma_default
+
+ # Attempt to load a configuration file...
+ self._config_file_list.clear()
+ self._config = None
+
+ # 1. Environment variable.
+ config_path = os.getenv('OCIO')
+ if config_path is not None:
+ self.setConfigPath(config_path)
+
+ # 2. Project setting.
+ if self._config is None and project.hasMetadata('OcioConfigPath'):
+ self.setConfigPath(ocio.buildLoadPath(project.metadata('OcioConfigPath')))
+
+ # 3. Use the default if nothing was found.
+ if self._config is None:
+ self._config_file_list = mari.FileList(ocio.config_file_list_default)
+ self._config = ocio.config_default
+
+ self._updateDisplayWidgets()
+ self._rebuildDisplayFilter()
+
+ self._enableWidgets(filter_collection.name() == 'Color Space' and self._toggle_color_management_action.isChecked())
+ self._updateLUTMetadata()
+ self._updateDisplayMetadata()
+
+ self._printLog()
+
+ #-----------------------------------------------------------------------------------------
+
+ def _aboutToSaveProject(self, project):
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Saving settings for project \'%s\'' % project.name())
+
+ # Store the settings as metadata on the project.
+ project.setMetadata( 'ColorEnabled', self.isColorManagementEnabled())
+ filter_collection = mari.gl_render.currentPostFilterCollection()
+ if filter_collection is not None:
+ project.setMetadata( 'ColorProfile', filter_collection.name())
+ project.setMetadata('OcioLutExtrapolate', self._lut_extrapolate)
+ project.setMetadata( 'OcioLutPath', '' if self._lut_file_list.isEmpty() else ocio.buildSavePath(self._lut_file_list.at(0)))
+ if os.getenv('OCIO') is None:
+ project.setMetadata('OcioConfigPath', '' if self._config_file_list.isEmpty() else ocio.buildSavePath(self._config_file_list.at(0)))
+ project.setMetadata( 'OcioColorSpace', self._color_space)
+ project.setMetadata( 'OcioDisplay', self._display)
+ project.setMetadata( 'OcioView', self._view)
+ project.setMetadata( 'OcioSwizzle', self._swizzle)
+ project.setMetadata( 'OcioGain', self._gain)
+ project.setMetadata( 'OcioGamma', self._gamma)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _closedProject(self):
+ self._toggle_color_management_action.setEnabled(False)
+ self._enableWidgets(False)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _toolBarsCreated(self):
+ # Things like deleting Mari's configuration file and reseting the layout to the default will destroy the toolbar
+ # so we need to detect if this is the case and rebuild it!
+ toolbar = mari.app.findToolBar('Color Space')
+ if toolbar is None:
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Rebuilding missing toolbar...')
+ self._buildWidgets()
+
+ #-----------------------------------------------------------------------------------------
+
+ def _postProcessingEnabled(self, enabled):
+ self._toggle_color_management_action.setChecked(enabled)
+
+ # Only enable or disable UI if we have a current project.
+ current_project = mari.projects.current()
+ if current_project is not None:
+ self._enableWidgets(enabled)
+
+ #-----------------------------------------------------------------------------------------
+
+ def _setCurrentPostFilterCollection(self):
+ # Only enable or disable UI if we have a current project.
+ current_project = mari.projects.current()
+ if current_project is not None:
+ filter_collection = mari.gl_render.currentPostFilterCollection()
+ if filter_collection is None or filter_collection.name() != 'Color Space':
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Disabling OpenColorIO')
+ self._enableWidgets(False)
+ else:
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Enabling OpenColorIO')
+ self._enableWidgets(True)
+
+ #-----------------------------------------------------------------------------------------
+ # Filter:
+ #-----------------------------------------------------------------------------------------
+
+ def _rebuildLUTFilter(self, lut_path, force_shader_build = False):
+ if lut_path == '':
+ self._lut_filter.setDefinitionsSnippet('')
+ self._lut_filter.setBodySnippet('')
+
+ if self._lut_sampler_name is not None:
+ self._lut_filter.deleteTexture(self._lut_sampler_name)
+ self._lut_sampler_name = None
+
+ self._lut_filter_cache_id = None
+ self._lut_texture_cache_id = None
+
+ else:
+ # There is a chance this is a bad file so we need to guard against it.
+ try:
+ self._lut_filter_cache_id, self._lut_texture_cache_id, self._lut_sampler_name = ocio.buildLUTFilter(
+ self._config,
+ lut_path,
+ self._lut_filter,
+ self._lut_filter_cache_id,
+ self._lut_texture_cache_id,
+ self._lut_extrapolate,
+ force_shader_build)
+
+ except Exception, e:
+ message = 'Failed to load LUT file \'%s\' due to \'%s\'' % (lut_path, e)
+ ocio.printMessage(ocio.MessageType.ERROR, '%s' % message)
+ if not mari.app.inTerminalMode():
+ mari.utils.misc.message(message, 'Color Space', 1024, 2)
+
+ return False
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Changed LUT to \'%s\'' % lut_path)
+
+ return True
+
+ #-----------------------------------------------------------------------------------------
+
+ def _rebuildDisplayFilter(self):
+ display_transform = ocio.PyOpenColorIO.DisplayTransform()
+ display_transform.setInputColorSpaceName(self._color_space)
+
+ if hasattr(display_transform, 'setDisplay'):
+ # OCIO 1.0+
+ display_transform.setDisplay(self._display)
+ display_transform.setView(self._view)
+ else:
+ # OCIO 0.8.X
+ display_color_space = self._config.getDisplayColorSpaceName(self._display, self._view)
+ display_transform.setDisplayColorSpaceName(display_color_space)
+
+ # Add the channel sizzle.
+ luma_coefs = self._config.getDefaultLumaCoefs()
+ mtx, offset = ocio.PyOpenColorIO.MatrixTransform.View(ocio.SWIZZLE_VALUES[self._swizzle], luma_coefs)
+
+ transform = ocio.PyOpenColorIO.MatrixTransform()
+ transform.setValue(mtx, offset)
+ display_transform.setChannelView(transform)
+
+ # Add the linear gain.
+ transform = ocio.PyOpenColorIO.CDLTransform()
+ transform.setSlope((self._gain, self._gain, self._gain))
+ display_transform.setLinearCC(transform)
+
+ # Add the post-display CC.
+ transform = ocio.PyOpenColorIO.ExponentTransform()
+ transform.setValue([1.0 / max(1e-6, v) for v in (self._gamma, self._gamma, self._gamma, self._gamma)])
+ display_transform.setDisplayCC(transform)
+
+ processor = self._config.getProcessor(display_transform)
+
+ self._display_filter_cache_id, self._display_texture_cache_id, self._display_sampler_name = ocio.buildProcessorFilter(
+ processor,
+ self._display_filter,
+ self._display_filter_cache_id,
+ self._display_texture_cache_id)
+
+ current_canvas = mari.canvases.current()
+ if current_canvas is not None:
+ current_canvas.repaint()
+
+ #-----------------------------------------------------------------------------------------
+ # Debugging:
+ #-----------------------------------------------------------------------------------------
+
+ def _printLog(self):
+ ocio.printMessage( ocio.MessageType.INFO, '==============================================================')
+ ocio.printMessage( ocio.MessageType.INFO, 'Configuration:')
+ ocio.printMessage( ocio.MessageType.INFO, '==============================================================')
+ ocio.printMessage( ocio.MessageType.INFO, ' Enabled: %s; Default: %s' % (mari.gl_render.isPostProcessingEnabled(),
+ ocio.enabled_default))
+ filter_collection = mari.gl_render.currentPostFilterCollection()
+ if filter_collection is not None:
+ ocio.printMessage(ocio.MessageType.INFO, ' Profile: %s; Default: %s' % (filter_collection.name(),
+ ocio.profile_default))
+ else:
+ ocio.printMessage(ocio.MessageType.INFO, ' Profile: None; Default: %s' % (ocio.profile_default))
+ ocio.printMessage( ocio.MessageType.INFO, ' LUT Path: %s; Default: %s' % ('' if self._lut_file_list.isEmpty() else self._lut_file_list.at(0),
+ '' if ocio.lut_file_list_default.isEmpty() else ocio.lut_file_list_default.at(0)))
+ ocio.printMessage( ocio.MessageType.INFO, ' Extrapolate: %s; Default: %s' % (self._lut_extrapolate,
+ ocio.lut_extrapolate_default))
+ ocio.printMessage( ocio.MessageType.INFO, ' Config Path: %s; Default: %s' % ('' if self._config_file_list.isEmpty() else self._config_file_list.at(0),
+ '' if ocio.config_file_list_default.isEmpty() else ocio.config_file_list_default.at(0)))
+ ocio.printMessage( ocio.MessageType.INFO, ' Color Space: %s; Default: %s' % (self._color_space,
+ ocio.color_space_default))
+ ocio.printMessage( ocio.MessageType.INFO, ' Display: %s; Default: %s' % (self._display,
+ ocio.display_default))
+ ocio.printMessage( ocio.MessageType.INFO, ' View: %s; Default: %s' % (self._view,
+ ocio.view_default))
+ ocio.printMessage( ocio.MessageType.INFO, ' Swizzle: %s; Default: %s' % (self._swizzle,
+ ocio.swizzle_default))
+ ocio.printMessage( ocio.MessageType.INFO, ' F-Stop: %f; Default: %f; Center: %f' % (ocio.convertGainToFStop(self._gain),
+ ocio.convertGainToFStop(ocio.gain_default),
+ ocio.fstop_center))
+ ocio.printMessage( ocio.MessageType.INFO, ' Gain: %f; Default: %f' % (self._gain,
+ ocio.gain_default))
+ ocio.printMessage( ocio.MessageType.INFO, ' Gamma: %f; Default: %f' % (self._gamma,
+ ocio.gamma_default))
+ ocio.printMessage( ocio.MessageType.INFO, '==============================================================')
+
+##############################################################################################
+# The following functions CAN'T be part of the toolbar class as a potential bug in PythonQt
+# causes the disconnect function to fail
+
+def lutMetadataValueChanged(name, value):
+ global toolbar
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'LUT metadata \'%s\' changed to \'%s\'' % (name, value))
+
+ if name == 'File':
+ toolbar.setLUTPath(value = '' if value.isEmpty() else value.at(0),
+ update_metadata = False,
+ force_shader_build = False)
+
+ elif name == 'Extrapolate':
+ toolbar.setExtrapolateEnabled(value = value, update_widget = True, update_metadata = False)
+
+#-----------------------------------------------------------------------------------------
+
+def displayMetadataValueChanged(name, value):
+ global toolbar
+
+ ocio.printMessage(ocio.MessageType.DEBUG, 'Display metadata \'%s\' changed to \'%s\'' % (name, value))
+
+ if name == 'ConfigPath':
+ toolbar.setConfigPath(value = '' if value.isEmpty() else value.at(0), update_metadata = False)
+
+ elif name == 'InputColorSpace':
+ toolbar.setColorSpace(value = value, update_widget = True, update_metadata = False)
+
+ elif name == 'Display':
+ toolbar.setDisplay(value = value, update_widget = True, update_metadata = False)
+
+ elif name == 'View':
+ toolbar.setView(value = value, update_widget = True, update_metadata = False)
+
+ elif name == 'Swizzle':
+ toolbar.setSwizzle(value = value, update_widget = True, update_metadata = False)
+
+ elif name == 'Gain':
+ toolbar.setGain(value = value, update_widget = True, update_metadata = False)
+
+ elif name == 'Gamma':
+ toolbar.setGamma(value = value, update_widget = True, update_metadata = False)
+
+##############################################################################################
+
+if mari.app.isRunning():
+ if not hasattr(mari.gl_render, 'createPostFilterCollection'):
+ ocio.printMessage(ocio.MessageType.ERROR, 'This version of Mari does not support the mari.gl_render.createPostFilterCollection API')
+
+ else:
+ if ocio.config_default is not None:
+ toolbar = OcioToolBar()
+
+ else:
+ # Destroy the OCIO post filter collection if present to prevent the user trying to use it.
+ filter_collection = mari.gl_render.findPostFilterCollection('Color Space')
+ if filter_collection is not None:
+ mari.gl_render.deletePostFilterCollection(filter_collection)
+
+ # Destroy the toolbar to prevent the user trying to use it.
+ mari.app.deleteToolBar('Color Space')
diff --git a/src/mari/1.4v1/ocio.py b/src/mari/1.4v1/ocio.py
new file mode 100755
index 0000000..4f0f61e
--- /dev/null
+++ b/src/mari/1.4v1/ocio.py
@@ -0,0 +1,789 @@
+#-------------------------------------------------------------------------------
+# OpenColorIO (color management) related Mari scripts
+# coding: utf-8
+# Copyright (c) 2011 The Foundry Visionmongers Ltd. All Rights Reserved.
+#-------------------------------------------------------------------------------
+
+import mari, time, PythonQt, os, math
+
+##############################################################################################
+
+# Enable to output extended debugging messages.
+VERBOSE_ENABLED = False
+
+# Message type identifiers.
+class MessageType:
+ DEBUG = 1
+ INFO = 2
+ WARNING = 3
+ ERROR = 4
+
+def printMessage(type, message):
+ if type == MessageType.DEBUG:
+ if VERBOSE_ENABLED:
+ mari.app.log('[ OpenColorIO ] %s' % message)
+ elif type == MessageType.INFO:
+ mari.app.log('[ OpenColorIO ] %s' % message)
+ elif type == MessageType.WARNING:
+ mari.app.log('[ OpenColorIO ] [ WARNING ] %s' % message)
+ elif type == MessageType.ERROR:
+ mari.app.log('[ OpenColorIO ] [ ERROR ] %s' % message)
+
+##############################################################################################
+
+def configFileFilter():
+ return 'OpenColorIO Configuration (*.ocio)'
+
+#---------------------------------------------------------------------------------------------
+
+def lutFileFilter():
+ result = 'All LUT Files (*.3dl *.ccc *.cc *.csp *.cub *.cube *.hdl *.m3d *.mga *.spi1d *.spi3d *.spimtx *.vf);;'
+ result += 'Autodesk LUT (*.3dl);;'
+ result += 'ASC CDL Color Correction Collection LUT (*.ccc);;'
+ result += 'ASC CDL Color Correction LUT (*.cc);;'
+ result += 'Cinespace LUT (*.csp);;'
+ result += 'Truelight LUT (*.cub);;'
+ result += 'Iridas LUT (*.cube);;'
+ result += 'Houdini LUT (*.hdl);;'
+ result += 'Pandora LUT (*.m3d *.mga);;'
+ result += 'Imageworks LUT (*.spi1d *.spi3d *.spimtx);;'
+ result += 'Inventor LUT (*.vf)'
+ return result
+
+##############################################################################################
+
+# Make sure the OpenColorIO python bindings are okay.
+try:
+ import PyOpenColorIO
+ printMessage(MessageType.INFO, 'Loaded Python bindings \'%s\' successfully' % PyOpenColorIO.__file__)
+except ImportError, e:
+ PyOpenColorIO = None
+ printMessage(MessageType.ERROR, 'Failed to load Python bindings \'%s\'' % e)
+
+LUT_FILE_LIST_RESET = mari.FileList(mari.FileList.TYPE_SINGLE_FILE)
+LUT_FILE_LIST_RESET.setAcceptNonExisting(True)
+LUT_FILE_LIST_RESET.setFilter(lutFileFilter())
+
+CONFIG_FILE_LIST_RESET = mari.FileList(mari.FileList.TYPE_SINGLE_FILE)
+if mari.app.isRunning():
+ CONFIG_FILE_LIST_RESET.append(mari.resources.path(mari.resources.COLOR) + '/OpenColorIO/nuke-default/config.ocio')
+else:
+ CONFIG_FILE_LIST_RESET.append('/OpenColorIO/nuke-default/config.ocio')
+CONFIG_FILE_LIST_RESET.setPickedFile(CONFIG_FILE_LIST_RESET.at(0))
+CONFIG_FILE_LIST_RESET.setAcceptNonExisting(True)
+CONFIG_FILE_LIST_RESET.setFilter(configFileFilter())
+
+SQRT_TWO = math.sqrt(2.0)
+LUT_SIZE_TYPES = ['Small', 'Medium', 'Large']
+LUT_SIZE_VALUES = {'Small': 16,
+ 'Medium': 32,
+ 'Large': 64}
+LUT_SIZE_RESET = LUT_SIZE_TYPES[1]
+ENABLED_RESET = True
+PROFILE_RESET = 'Color Space'
+LUT_EXTRAPOLATE_RESET = True
+COLOR_SPACE_RESET = 'sRGB'
+DISPLAY_RESET = 'default'
+VIEW_RESET = 'sRGB'
+SWIZZLE_TYPES = ['Luminance', 'RGB', 'R', 'G', 'B', 'A']
+SWIZZLE_VALUES = {'Luminance': ( True, True, True, False),
+ 'RGB': ( True, True, True, True),
+ 'R': ( True, False, False, False),
+ 'G': (False, True, False, False),
+ 'B': (False, False, True, False),
+ 'A': (False, False, False, True)}
+SWIZZLE_RESET = SWIZZLE_TYPES[1]
+FSTOP_STEP_SIZE = 0.5
+FSTOP_CENTER_MIN = 1.0
+FSTOP_CENTER_MAX = 64.0
+FSTOP_CENTER_STEP_SIZE = 0.001
+FSTOP_CENTER_RESET = 8.0
+EXPOSURE_MIN = -6.0
+EXPOSURE_MAX = +6.0
+EXPOSURE_DELTA = EXPOSURE_MAX - EXPOSURE_MIN
+EXPOSURE_STEP_SIZE = 0.1
+GAIN_RESET = 1.0
+GAIN_MIN = 2.0 ** EXPOSURE_MIN
+GAIN_MAX = 2.0 ** EXPOSURE_MAX
+GAIN_STEP_SIZE = 0.000001
+GAIN_PRECISION = 6
+GAMMA_RESET = 1.0
+GAMMA_MIN = 0.0
+GAMMA_MAX = 4.0
+GAMMA_STEP_SIZE = 0.01
+GAMMA_PRECISION = 2
+
+enabled_default = ENABLED_RESET
+profile_default = PROFILE_RESET
+lut_file_list_default = mari.FileList(LUT_FILE_LIST_RESET)
+lut_extrapolate_default = LUT_EXTRAPOLATE_RESET
+config_file_list_default = mari.FileList(CONFIG_FILE_LIST_RESET)
+color_space_default = COLOR_SPACE_RESET
+display_default = DISPLAY_RESET
+view_default = VIEW_RESET
+swizzle_default = SWIZZLE_RESET
+gain_default = GAIN_RESET
+gamma_default = GAMMA_RESET
+lut_size = LUT_SIZE_RESET
+fstop_center = FSTOP_CENTER_RESET
+
+config_default = None
+
+lut_size_functions = []
+fstop_center_functions = []
+
+##############################################################################################
+
+def registerLUTSizeChanged(function):
+ global lut_size_functions
+ lut_size_functions.append(function)
+
+#---------------------------------------------------------------------------------------------
+
+def registerFStopCenterChanged(function):
+ global fstop_center_functions
+ fstop_center_functions.append(function)
+
+#---------------------------------------------------------------------------------------------
+
+def _enabledDefaultChanged():
+ global enabled_default
+ enabled_default = mari.prefs.get('/Color/Color Management Defaults/colorEnabledDefault')
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _profileDefaultChanged():
+ global profile_default
+ profile_default = mari.prefs.get('/Color/Color Management Defaults/colorProfileDefault')
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _postFilterCollectionAdded(filter_collection):
+ mari.prefs.setItemList('/Color/Color Management Defaults/colorProfileDefault', mari.gl_render.postFilterCollectionNames())
+
+#---------------------------------------------------------------------------------------------
+
+def _postFilterCollectionRemoved(name):
+ collection_names = mari.gl_render.postFilterCollectionNames()
+ mari.prefs.setItemList('/Color/Color Management Defaults/colorProfileDefault', collection_names)
+
+ global PROFILE_RESET
+ if name == PROFILE_RESET:
+ PROFILE_RESET = collection_names[0]
+ mari.prefs.setDefault('/Color/Color Management Defaults/colorProfileDefault', PROFILE_RESET)
+
+ global profile_default
+ if name == profile_default:
+ profile_default = PROFILE_RESET
+ mari.prefs.set('/Color/Color Management Defaults/colorProfileDefault', profile_default)
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _lutPathDefaultChanged():
+ global lut_file_list_default
+ lut_file_list_default = mari.FileList(mari.prefs.get('/Color/LUT Defaults/lutPathDefault'))
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _lutExtrapolateDefaultChanged():
+ global lut_extrapolate_default
+ lut_extrapolate_default = mari.prefs.get('/Color/LUT Defaults/lutExtrapolateDefault')
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _configPathDefaultChanged():
+ global config_file_list_default
+
+ # Only replace the existing configuration file if the new one is valid!
+ config_file_list = mari.FileList(mari.prefs.get('/Color/Display Defaults/displayConfigPathDefault'))
+
+ if not config_file_list.isEmpty():
+ config = loadConfig(config_file_list.at(0), True)
+ if config is not None:
+ config_file_list_default = config_file_list
+
+ global config_default
+ config_default = config
+
+ _updateColorSpaceDefault()
+ _updateDisplayDefault()
+ _updateViewDefault()
+
+ _savePreferences()
+
+ else:
+ # Put back the existing configuration file that works...
+ mari.prefs.set('/Color/Display Defaults/displayConfigPathDefault', config_file_list_default)
+ else:
+ # Put back the existing configuration file that works...
+ mari.prefs.set('/Color/Display Defaults/displayConfigPathDefault', config_file_list_default)
+
+#---------------------------------------------------------------------------------------------
+
+def _colorSpaceDefaultChanged():
+ global color_space_default
+ color_space_default = mari.prefs.get('/Color/Display Defaults/displayColorSpaceDefault')
+ _updateDisplayDefault()
+ _updateViewDefault()
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _displayDefaultChanged():
+ global display_default
+ display_default = mari.prefs.get('/Color/Display Defaults/displayDisplayDefault')
+ _updateViewDefault()
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _viewDefaultChanged():
+ global view_default
+ view_default = mari.prefs.get('/Color/Display Defaults/displayViewDefault')
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _swizzleDefaultChanged():
+ global swizzle_default
+ swizzle_default = mari.prefs.get('/Color/Display Defaults/displaySwizzleDefault')
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _gainDefaultChanged():
+ global gain_default
+ gain_default = mari.prefs.get('/Color/Display Defaults/displayGainDefault')
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _gammaDefaultChanged():
+ global gamma_default
+ gamma_default = mari.prefs.get('/Color/Display Defaults/displayGammaDefault')
+ _savePreferences()
+
+#---------------------------------------------------------------------------------------------
+
+def _lutSizeChanged():
+ global lut_size
+ global lut_size_functions
+ lut_size = mari.prefs.get('/Color/Display General/displayLutSize')
+ _savePreferences()
+ for function in lut_size_functions:
+ function()
+
+#---------------------------------------------------------------------------------------------
+
+def _fstopCenterChanged():
+ global fstop_center
+ global fstop_center_functions
+ fstop_center = mari.prefs.get('/Color/Display General/displayFStopCenter')
+ _savePreferences()
+ for function in fstop_center_functions:
+ function()
+
+#---------------------------------------------------------------------------------------------
+
+def _registerPreferences():
+ global enabled_default
+ mari.prefs.set('/Color/Color Management Defaults/colorEnabledDefault', enabled_default)
+ mari.prefs.setChangedScript('/Color/Color Management Defaults/colorEnabledDefault', 'mari.utils.ocio._enabledDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/Color Management Defaults/colorEnabledDefault', 'Enabled')
+ mari.prefs.setDefault('/Color/Color Management Defaults/colorEnabledDefault', ENABLED_RESET)
+
+ global profile_default
+ mari.prefs.set('/Color/Color Management Defaults/colorProfileDefault', profile_default)
+ mari.prefs.setChangedScript('/Color/Color Management Defaults/colorProfileDefault', 'mari.utils.ocio._profileDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/Color Management Defaults/colorProfileDefault', 'Color Profile')
+ mari.prefs.setDefault('/Color/Color Management Defaults/colorProfileDefault', PROFILE_RESET)
+ mari.prefs.setItemList('/Color/Color Management Defaults/colorProfileDefault', mari.gl_render.postFilterCollectionNames())
+
+ global lut_file_list_default
+ if not lut_file_list_default.isEmpty() and not os.path.isfile(lut_file_list_default.at(0)):
+ message = 'LUT file \'%s\' does not exist' % lut_file_list_default.at(0)
+ printMessage(MessageType.ERROR, '%s' % message)
+ lut_file_list_default = mari.FileList(LUT_FILE_LIST_RESET)
+
+ mari.prefs.set('/Color/LUT Defaults/lutPathDefault', lut_file_list_default)
+ mari.prefs.setChangedScript('/Color/LUT Defaults/lutPathDefault', 'mari.utils.ocio._lutPathDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/LUT Defaults/lutPathDefault', 'File')
+ mari.prefs.setDefault('/Color/LUT Defaults/lutPathDefault', LUT_FILE_LIST_RESET)
+
+ global lut_extrapolate_default
+ mari.prefs.set('/Color/LUT Defaults/lutExtrapolateDefault', lut_extrapolate_default)
+ mari.prefs.setChangedScript('/Color/LUT Defaults/lutExtrapolateDefault', 'mari.utils.ocio._lutExtrapolateDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/LUT Defaults/lutExtrapolateDefault', 'Extrapolate')
+ mari.prefs.setDefault('/Color/LUT Defaults/lutExtrapolateDefault', LUT_EXTRAPOLATE_RESET)
+
+ global config_file_list_default
+ global config_default
+ if not config_file_list_default.isEmpty():
+ config = loadConfig(config_file_list_default.at(0), False)
+ if config is not None:
+ config_default = config
+ else:
+ config_file_list_default = mari.FileList(CONFIG_FILE_LIST_RESET)
+ else:
+ config_file_list_default = mari.FileList(CONFIG_FILE_LIST_RESET)
+
+ mari.prefs.set('/Color/Display Defaults/displayConfigPathDefault', config_file_list_default)
+ mari.prefs.setChangedScript('/Color/Display Defaults/displayConfigPathDefault', 'mari.utils.ocio._configPathDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/Display Defaults/displayConfigPathDefault', 'Configuration File')
+ mari.prefs.setDefault('/Color/Display Defaults/displayConfigPathDefault', CONFIG_FILE_LIST_RESET)
+
+ color_spaces = [color_space.getName() for color_space in config_default.getColorSpaces()]
+
+ color_space_reset = COLOR_SPACE_RESET
+ if color_spaces.count(color_space_reset) == 0:
+ color_space_reset = color_spaces[0]
+
+ global color_space_default
+ if color_spaces.count(color_space_default) == 0:
+ color_space_default = color_space_reset
+
+ mari.prefs.set('/Color/Display Defaults/displayColorSpaceDefault', color_space_default)
+ mari.prefs.setChangedScript('/Color/Display Defaults/displayColorSpaceDefault', 'mari.utils.ocio._colorSpaceDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/Display Defaults/displayColorSpaceDefault', 'Input Color Space')
+ mari.prefs.setDefault('/Color/Display Defaults/displayColorSpaceDefault', color_space_reset)
+ mari.prefs.setItemList('/Color/Display Defaults/displayColorSpaceDefault', color_spaces)
+
+ displays = config_default.getDisplays()
+
+ display_reset = DISPLAY_RESET
+ if displays.count(display_reset) == 0:
+ display_reset = config_default.getDefaultDisplay()
+
+ global display_default
+ if displays.count(display_default) == 0:
+ display_default = display_reset
+
+ mari.prefs.set('/Color/Display Defaults/displayDisplayDefault', display_default)
+ mari.prefs.setChangedScript('/Color/Display Defaults/displayDisplayDefault', 'mari.utils.ocio._displayDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/Display Defaults/displayDisplayDefault', 'Display')
+ mari.prefs.setDefault('/Color/Display Defaults/displayDisplayDefault', display_reset)
+ mari.prefs.setItemList('/Color/Display Defaults/displayDisplayDefault', displays)
+
+ views = config_default.getViews(display_default)
+
+ view_reset = VIEW_RESET
+ if views.count(view_reset) == 0:
+ view_reset = config_default.getDefaultView(display_default)
+
+ global view_default
+ if views.count(view_default) == 0:
+ view_default = view_reset
+
+ mari.prefs.set('/Color/Display Defaults/displayViewDefault', view_default)
+ mari.prefs.setChangedScript('/Color/Display Defaults/displayViewDefault', 'mari.utils.ocio._viewDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/Display Defaults/displayViewDefault', 'View')
+ mari.prefs.setDefault('/Color/Display Defaults/displayViewDefault', view_reset)
+ mari.prefs.setItemList('/Color/Display Defaults/displayViewDefault', views)
+
+ global swizzle_default
+ if SWIZZLE_TYPES.count(swizzle_default) == 0:
+ swizzle_default = SWIZZLE_RESET
+
+ mari.prefs.set('/Color/Display Defaults/displaySwizzleDefault', swizzle_default)
+ mari.prefs.setChangedScript('/Color/Display Defaults/displaySwizzleDefault', 'mari.utils.ocio._swizzleDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/Display Defaults/displaySwizzleDefault', 'Component')
+ mari.prefs.setDefault('/Color/Display Defaults/displaySwizzleDefault', SWIZZLE_RESET)
+ mari.prefs.setItemList('/Color/Display Defaults/displaySwizzleDefault', SWIZZLE_TYPES)
+
+ global gain_default
+ mari.prefs.set('/Color/Display Defaults/displayGainDefault', gain_default)
+ mari.prefs.setChangedScript('/Color/Display Defaults/displayGainDefault', 'mari.utils.ocio._gainDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/Display Defaults/displayGainDefault', 'Gain')
+ mari.prefs.setDefault('/Color/Display Defaults/displayGainDefault', GAIN_RESET)
+ mari.prefs.setRange('/Color/Display Defaults/displayGainDefault', GAIN_MIN, GAIN_MAX)
+ mari.prefs.setStep('/Color/Display Defaults/displayGainDefault', GAIN_STEP_SIZE)
+
+ global gamma_default
+ mari.prefs.set('/Color/Display Defaults/displayGammaDefault', gamma_default)
+ mari.prefs.setChangedScript('/Color/Display Defaults/displayGammaDefault', 'mari.utils.ocio._gammaDefaultChanged()')
+ mari.prefs.setDisplayName('/Color/Display Defaults/displayGammaDefault', 'Gamma')
+ mari.prefs.setDefault('/Color/Display Defaults/displayGammaDefault', GAMMA_RESET)
+ mari.prefs.setRange('/Color/Display Defaults/displayGammaDefault', GAMMA_MIN, GAMMA_MAX)
+ mari.prefs.setStep('/Color/Display Defaults/displayGammaDefault', GAMMA_STEP_SIZE)
+
+ global lut_size
+ mari.prefs.set('/Color/Display General/displayLutSize', lut_size)
+ mari.prefs.setChangedScript('/Color/Display General/displayLutSize', 'mari.utils.ocio._lutSizeChanged()')
+ mari.prefs.setDisplayName('/Color/Display General/displayLutSize', 'LUT Size')
+ mari.prefs.setDefault('/Color/Display General/displayLutSize', LUT_SIZE_RESET)
+ mari.prefs.setItemList('/Color/Display General/displayLutSize', LUT_SIZE_TYPES)
+
+ global fstop_center
+ mari.prefs.set('/Color/Display General/displayFStopCenter', fstop_center)
+ mari.prefs.setChangedScript('/Color/Display General/displayFStopCenter', 'mari.utils.ocio._fstopCenterChanged()')
+ mari.prefs.setDisplayName('/Color/Display General/displayFStopCenter', 'Center F-Stop')
+ mari.prefs.setDefault('/Color/Display General/displayFStopCenter', FSTOP_CENTER_RESET)
+ mari.prefs.setRange('/Color/Display General/displayFStopCenter', FSTOP_CENTER_MIN, FSTOP_CENTER_MAX)
+ mari.prefs.setStep('/Color/Display General/displayFStopCenter', FSTOP_CENTER_STEP_SIZE)
+
+ # Attach ourselves to the appropriate project signals so we can update widgets.
+ PythonQt.QtCore.QObject.connect(mari.gl_render.postFilterCollectionAdded.__self__,
+ mari.gl_render.postFilterCollectionAdded.__name__,
+ _postFilterCollectionAdded)
+ PythonQt.QtCore.QObject.connect(mari.gl_render.postFilterCollectionRemoved.__self__,
+ mari.gl_render.postFilterCollectionRemoved.__name__,
+ _postFilterCollectionRemoved)
+
+#---------------------------------------------------------------------------------------------
+
+def _updateColorSpaceDefault():
+ global config_default
+ global color_space_default
+
+ color_spaces = [color_space.getName() for color_space in config_default.getColorSpaces()]
+
+ color_space_reset = COLOR_SPACE_RESET
+ if color_spaces.count(color_space_reset) == 0:
+ color_space_reset = color_spaces[0]
+
+ if color_spaces.count(color_space_default) == 0:
+ color_space_default = color_space_reset
+
+ mari.prefs.setItemList('/Color/Display Defaults/displayColorSpaceDefault', color_spaces)
+ mari.prefs.set('/Color/Display Defaults/displayColorSpaceDefault', color_space_default)
+ mari.prefs.setDefault('/Color/Display Defaults/displayColorSpaceDefault', color_space_reset)
+
+
+#---------------------------------------------------------------------------------------------
+
+def _updateDisplayDefault():
+ global config_default
+ global display_default
+
+ displays = config_default.getDisplays()
+
+ display_reset = DISPLAY_RESET
+ if displays.count(display_reset) == 0:
+ display_reset = config_default.getDefaultDisplay()
+
+ if displays.count(display_default) == 0:
+ display_default = display_reset
+
+ mari.prefs.setItemList('/Color/Display Defaults/displayDisplayDefault', displays)
+ mari.prefs.set('/Color/Display Defaults/displayDisplayDefault', display_default)
+ mari.prefs.setDefault('/Color/Display Defaults/displayDisplayDefault', display_reset)
+
+#---------------------------------------------------------------------------------------------
+
+def _updateViewDefault():
+ global config_default
+ global display_default
+ global view_default
+
+ views = config_default.getViews(display_default)
+
+ view_reset = VIEW_RESET
+ if views.count(view_reset) == 0:
+ view_reset = config_default.getDefaultView(display_default)
+
+ if views.count(view_default) == 0:
+ view_default = view_reset
+
+ mari.prefs.setItemList('/Color/Display Defaults/displayViewDefault', views)
+ mari.prefs.set('/Color/Display Defaults/displayViewDefault', view_default)
+ mari.prefs.setDefault('/Color/Display Defaults/displayViewDefault', view_reset)
+
+#---------------------------------------------------------------------------------------------
+
+def _loadPreferences():
+ settings = mari.Settings()
+ settings.beginGroup('OpenColorIO')
+
+ try:
+ global enabled_default
+ global profile_default
+ global lut_file_list_default
+ global lut_extrapolate_default
+ global config_file_list_default
+ global color_space_default
+ global display_default
+ global view_default
+ global swizzle_default
+ global gain_default
+ global gamma_default
+ global lut_size
+ global fstop_center
+
+ enabled_default = False if int(settings.value('enabledDefault', ENABLED_RESET)) == 0 else True
+ profile_default = str(settings.value('profileDefault', PROFILE_RESET))
+ lut_path = buildLoadPath(str(settings.value('lutPathDefault', '' if LUT_FILE_LIST_RESET.isEmpty() else LUT_FILE_LIST_RESET.at(0))))
+ lut_extrapolate_default = False if int(settings.value('lutExtrapolateDefault', LUT_EXTRAPOLATE_RESET)) == 0 else True
+ config_path = buildLoadPath(str(settings.value('configPathDefault', '' if CONFIG_FILE_LIST_RESET.isEmpty() else CONFIG_FILE_LIST_RESET.at(0))))
+ color_space_default = str(settings.value('colorSpaceDefault', COLOR_SPACE_RESET))
+ display_default = str(settings.value('displayDefault', DISPLAY_RESET))
+ view_default = str(settings.value('viewDefault', VIEW_RESET))
+ swizzle_default = str(settings.value('swizzleDefault', SWIZZLE_RESET))
+ gain_default = max(min(float(settings.value('gainDefault', GAIN_RESET)), GAIN_MAX), GAIN_MIN)
+ gamma_default = max(min(float(settings.value('gammaDefault', GAMMA_RESET)), GAMMA_MAX), GAMMA_MIN)
+ lut_size = str(settings.value('lutSize', LUT_SIZE_RESET))
+ fstop_center = max(min(float(settings.value('fstopCenter', FSTOP_CENTER_RESET)), FSTOP_CENTER_MAX), FSTOP_CENTER_MIN)
+
+ if os.path.isfile(lut_path):
+ lut_file_list_default.clear()
+ lut_file_list_default.append(lut_path)
+ lut_file_list_default.setPickedFile(lut_path)
+
+ if os.path.isfile(config_path):
+ config_file_list_default.clear()
+ config_file_list_default.append(config_path)
+ config_file_list_default.setPickedFile(config_path)
+
+ except ValueError, e:
+ printMessage(MessageType.ERROR, 'Failed to load preferences \'%s\'' % e)
+
+ settings.endGroup()
+
+ _printPreferences(MessageType.DEBUG, 'Loaded Preferences:')
+
+#---------------------------------------------------------------------------------------------
+
+def _savePreferences():
+ settings = mari.Settings()
+ settings.beginGroup('OpenColorIO')
+
+ global enabled_default
+ global profile_default
+ global lut_file_list_default
+ global lut_extrapolate_default
+ global config_file_list_default
+ global color_space_default
+ global display_default
+ global view_default
+ global swizzle_default
+ global gain_default
+ global gamma_default
+ global lut_size
+ global fstop_center
+
+ settings.setValue( 'enabledDefault', 1 if enabled_default else 0)
+ settings.setValue( 'profileDefault', profile_default)
+ settings.setValue( 'lutPathDefault', '' if lut_file_list_default.isEmpty() else buildSavePath(lut_file_list_default.at(0)))
+ settings.setValue('lutExtrapolateDefault', 1 if lut_extrapolate_default else 0)
+ settings.setValue( 'configPathDefault', '' if config_file_list_default.isEmpty() else buildSavePath(config_file_list_default.at(0)))
+ settings.setValue( 'colorSpaceDefault', color_space_default)
+ settings.setValue( 'displayDefault', display_default)
+ settings.setValue( 'viewDefault', view_default)
+ settings.setValue( 'swizzleDefault', swizzle_default)
+ settings.setValue( 'gainDefault', gain_default)
+ settings.setValue( 'gammaDefault', gamma_default)
+ settings.setValue( 'lutSize', lut_size)
+ settings.setValue( 'fstopCenter', fstop_center)
+
+ settings.endGroup()
+
+ _printPreferences(MessageType.DEBUG, 'Saved Preferences:')
+
+#---------------------------------------------------------------------------------------------
+
+def _printPreferences(type, title):
+ global enabled_default
+ global profile_default
+ global lut_file_list_default
+ global lut_extrapolate_default
+ global config_file_list_default
+ global color_space_default
+ global display_default
+ global view_default
+ global swizzle_default
+ global gain_default
+ global fstop_center
+ global lut_size
+ global gamma_default
+
+ printMessage(type, '==============================================================')
+ printMessage(type, title)
+ printMessage(type, '==============================================================')
+ printMessage(type, ' Enabled: %s' % enabled_default)
+ printMessage(type, ' Profile: %s' % profile_default)
+ printMessage(type, ' LUT Path: %s' % '' if lut_file_list_default.isEmpty() else lut_file_list_default.at(0))
+ printMessage(type, ' Extrapolate: %s' % lut_extrapolate_default)
+ printMessage(type, ' Config Path: %s' % '' if config_file_list_default.isEmpty() else config_file_list_default.at(0))
+ printMessage(type, ' Color Space: %s' % color_space_default)
+ printMessage(type, ' Display: %s' % display_default)
+ printMessage(type, ' View: %s' % view_default)
+ printMessage(type, ' Swizzle: %s' % swizzle_default)
+ printMessage(type, ' F-Stop: %f; Center: %f' % (convertGainToFStop(gain_default), fstop_center))
+ printMessage(type, ' Gain: %f' % gain_default)
+ printMessage(type, ' Gamma: %f' % gamma_default)
+ printMessage(type, ' LUT Size: %s' % lut_size)
+ printMessage(type, '==============================================================')
+
+##############################################################################################
+
+def convertExposureToGain(exposure):
+ return 2.0 ** exposure
+
+#---------------------------------------------------------------------------------------------
+
+def convertGainToExposure(gain):
+ return math.log(gain, 2.0)
+
+#---------------------------------------------------------------------------------------------
+
+def convertExposureToFStop(exposure):
+ global fstop_center
+ exposure_center = math.log(fstop_center, SQRT_TWO)
+ return math.pow(SQRT_TWO, exposure_center - exposure)
+
+#---------------------------------------------------------------------------------------------
+
+def convertGainToFStop(gain):
+ exposure = convertGainToExposure(gain)
+ return convertExposureToFStop(exposure)
+
+#---------------------------------------------------------------------------------------------
+
+def buildProcessorFilter(processor, filter, filter_cache_id, texture_cache_id, extrapolate = False, force_shader_build = False):
+ # Create a name, using the filter's name, that can be used in uniquely naming parameters and functions.
+ name = filter.name();
+ name = name.lower()
+ name = name.replace(' ', '_')
+
+ sampler_name = 'ocio_' + name + '_lut_$ID_'
+ function_name = 'ocio_' + name + '_$ID_'
+
+ global lut_size
+ shader_desc = { 'language': PyOpenColorIO.Constants.GPU_LANGUAGE_GLSL_1_3,
+ 'functionName': function_name,
+ 'lut3DEdgeLen': LUT_SIZE_VALUES[lut_size]}
+
+ cache_id = processor.getGpuShaderTextCacheID(shader_desc)
+ if cache_id != filter_cache_id or force_shader_build:
+ filter_cache_id = cache_id
+ printMessage(MessageType.DEBUG, 'Creating new GLSL filter...')
+
+ desc = 'uniform sampler3D ' + sampler_name + ';\n'
+ desc += processor.getGpuShaderText(shader_desc)
+ body = ''
+ if extrapolate:
+ # The following code was taken from Nuke's 'LUT3D::Extrapolate' functionality. It attempts to estimate what
+ # the corresponding color value would be when the incoming color value is outside the normal range of [0-1],
+ # such as the case with HDR images.
+ rcp_lut_edge_length = 1.0 / float(LUT_SIZE_VALUES[lut_size])
+
+ body += '{\n'
+ body += ' if( 1.0 < Out.r || 1.0 < Out.g || 1.0 < Out.b )\n'
+ body += ' {\n'
+ body += ' vec4 closest;\n'
+ body += ' closest.rgb = clamp(Out.rgb, vec3(0.0), vec3(1.0));\n'
+ body += ' closest.a = Out.a;\n'
+ body += '\n'
+ body += ' vec3 offset = Out.rgb - closest.rgb;\n'
+ body += ' float offset_distance = length(offset);\n'
+ body += ' offset = normalize(offset);\n'
+ body += '\n'
+ body += ' vec4 nbr_position;\n'
+ body += ' nbr_position.rgb = closest.rgb - %f * offset;\n' % rcp_lut_edge_length
+ body += ' nbr_position.a = Out.a;\n'
+ body += '\n'
+ body += ' Out = ' + function_name + '(closest, ' + sampler_name + ');\n'
+ body += ' Out.rgb += (Out.rgb - ' + function_name + '(nbr_position, ' + sampler_name + ').rgb) / %f * offset_distance;\n' % rcp_lut_edge_length
+ body += ' }\n'
+ body += ' else\n'
+ body += ' {\n'
+ body += ' Out = ' + function_name + '(Out, ' + sampler_name + ');\n'
+ body += ' }\n'
+ body += '}\n'
+ else:
+ body += '{ Out = ' + function_name + '(Out, ' + sampler_name + '); }\n'
+
+ filter.setDefinitionsSnippet(desc)
+ filter.setBodySnippet(body)
+ else:
+ printMessage(MessageType.DEBUG, 'No GLSL filter update required')
+
+ cache_id = processor.getGpuLut3DCacheID(shader_desc)
+ if cache_id != texture_cache_id:
+ lut = processor.getGpuLut3D(shader_desc)
+
+ printMessage(MessageType.DEBUG, 'Updating LUT...')
+
+ if texture_cache_id is None:
+ filter.setTexture3D(sampler_name,
+ LUT_SIZE_VALUES[lut_size],
+ LUT_SIZE_VALUES[lut_size],
+ LUT_SIZE_VALUES[lut_size],
+ filter.FORMAT_RGB,
+ lut)
+ else:
+ filter.updateTexture3D(sampler_name, lut)
+
+ texture_cache_id = cache_id
+ else:
+ printMessage(MessageType.DEBUG, 'No LUT update required')
+
+ return (filter_cache_id, texture_cache_id, sampler_name)
+
+#---------------------------------------------------------------------------------------------
+
+def buildLUTFilter(config, path, filter, filter_cache_id, texture_cache_id, extrapolate, force_shader_build = False):
+ file_transform = PyOpenColorIO.FileTransform()
+ file_transform.setSrc(path)
+ file_transform.setInterpolation('linear')
+
+ processor = config.getProcessor(file_transform)
+
+ return buildProcessorFilter(processor, filter, filter_cache_id, texture_cache_id, extrapolate, force_shader_build)
+
+#---------------------------------------------------------------------------------------------
+
+def loadConfig(path, display_message_box = True):
+ try:
+ config = PyOpenColorIO.Config.CreateFromFile(path)
+ return config
+
+ except Exception, e:
+ message = 'Failed to load configuration file \'%s\' due to \'%s\'' % (path, e)
+ printMessage(MessageType.ERROR, '%s' % message)
+ if display_message_box and not mari.app.inTerminalMode():
+ mari.utils.misc.message(message, 'Color Space', 1024, 2)
+
+ return None
+
+#---------------------------------------------------------------------------------------------
+
+# This converts a path into a form which can be shared among different platforms and installations.
+def buildSavePath(path):
+ result = path.replace(mari.resources.path(mari.resources.COLOR), '$MARI_COLOR_PATH', 1)
+ return result
+
+#---------------------------------------------------------------------------------------------
+
+# This converts a path saved out to disk back into a form which can used by the application.
+def buildLoadPath(path):
+ result = path.replace('$MARI_COLOR_PATH', mari.resources.path(mari.resources.COLOR), 1)
+ return result
+
+##############################################################################################
+
+if mari.app.isRunning():
+ if PyOpenColorIO is not None:
+ # Attempt to load the default configuration file... without it we can't do nothing!
+ config_file_lists = [config_file_list_default, CONFIG_FILE_LIST_RESET]
+ for config_file_list in config_file_lists:
+ if not config_file_list.isEmpty():
+ config_default = loadConfig(config_file_list.at(0), False)
+ if config_default is not None:
+ config_file_list_default = mari.FileList(config_file_list)
+ break
+
+ if config_default is not None:
+ _loadPreferences()
+ _registerPreferences()
+ _savePreferences()
+
+ else:
+ message = 'Failed to find a working configuration file. OpenColorIO will be disabled!'
+ printMessage(MessageType.ERROR, message)
+ if not mari.app.inTerminalMode():
+ mari.utils.misc.message(message, 'OpenColorIO', 1024, 3)
diff --git a/src/mari/prototype/README b/src/mari/prototype/README
new file mode 100644
index 0000000..514cd65
--- /dev/null
+++ b/src/mari/prototype/README
@@ -0,0 +1,3 @@
+This is a prototype implemetation for a python display integration, which worked
+in early Mari versions. It's provided as a simple example of how to use the
+OCIO python API to query the GPU interface functions.
diff --git a/src/mari/prototype/ociodisplay.py b/src/mari/prototype/ociodisplay.py
new file mode 100644
index 0000000..5b0b949
--- /dev/null
+++ b/src/mari/prototype/ociodisplay.py
@@ -0,0 +1,242 @@
+"""
+This script allows the use of OpenColorIO display transforms (3d luts) in
+the Mari Viewer. Requires Mari 1.3v2+.
+
+This example is not represntative of the final Mari OCIO workflow, merely
+an API demonstration. This code is a work in progress, to demonstrate the
+integration of OpenColorIO and Mari. The APIs this code relies on are subject
+to change at any time, and as such should not be relied on for production use
+(yet).
+
+LINUX testing instructions:
+
+* Build OCIO
+mkdir -p dist_mari
+mkdir -p build_mari && cd build_mari
+cmake -D CMAKE_BUILD_TYPE=Release \
+ -D CMAKE_INSTALL_PREFIX=../dist_mari \
+ -D PYTHON=/usr/bin/python2.6 \
+ -D OCIO_NAMESPACE=OpenColorIO_Mari \
+ ../
+make install -j8
+
+* Set $OCIO color environment
+setenv OCIO setenv OCIO <YOURDIR>/ocio.configs/spi-vfx/config.ocio
+(Profiles available for download from opencolorio.org)
+
+* Run Mari with OpenColorIO added to the LD_LIBRARY_PATH, and Python
+env LD_LIBRARY_PATH=<YOURDIR>/dist_mari/lib/ PYTHONPATH=<YOURDIR>/dist_mari/lib/python2.6 mari
+
+* Source this script in the python console.
+Also - IMPORTANT - you must enable 'Use Color Correction' in the Color Manager.
+
+"""
+
+import mari, time, PythonQt
+QtGui = PythonQt.QtGui
+QtCore = PythonQt.QtCore
+
+try:
+ import PyOpenColorIO as OCIO
+ mari.app.log("OCIODisplay: %s" % OCIO.__file__)
+except Exception,e:
+ OCIO = None
+ mari.app.log("OCIODisplay: Error: Could not import OpenColorIO python bindings.")
+ mari.app.log("OCIODisplay: Please confirm PYTHONPATH has dir containing PyOpenColorIO.so")
+
+__all__ = [ 'OCIO', 'CreateOCIODisplayTransform', 'OCIODisplayUI']
+
+LUT3D_SIZE = 32
+WINDOW_NAME = "OpenColorIO Display Manager"
+CREATE_FLOATING = True
+
+
+class OCIODisplayUI(QtGui.QWidget):
+ def __init__(self):
+ QtGui.QWidget.__init__(self)
+ QtGui.QGridLayout(self)
+ self.setWindowTitle(WINDOW_NAME)
+ self.setMinimumWidth(300)
+
+ config = OCIO.GetCurrentConfig()
+
+ self.__inputColorSpace = OCIO.Constants.ROLE_DEFAULT
+ inputColorSpaces = [ OCIO.Constants.ROLE_TEXTURE_PAINT,
+ 'dt8',
+ OCIO.Constants.ROLE_SCENE_LINEAR ]
+ for cs in inputColorSpaces:
+ if config.getColorSpace(cs) is None: continue
+ self.__inputColorSpace = cs
+ break
+
+ self.__fStopOffset = 0.0
+ self.__viewGamma = 1.0
+ self.__swizzle = (True, True, True, True)
+
+ self.__filter_cacheID = None
+ self.__filter = None
+ self.__texture3d_cacheID = None
+ self.__counter_hack = 0
+
+ self.__buildUI()
+ self.__rebuildFilter()
+
+ def __buildUI(self):
+ config = OCIO.GetCurrentConfig()
+
+ self.layout().addWidget( QtGui.QLabel("Input Color Space", self), 0, 0)
+ csWidget = QtGui.QComboBox(self)
+ self.layout().addWidget( csWidget, 0, 1)
+ csIndex = None
+ for name in (cs.getName() for cs in config.getColorSpaces()):
+ csWidget.addItem(name)
+ if name == self.__inputColorSpace:
+ csIndex = csWidget.count - 1
+ if csIndex is not None:
+ csWidget.setCurrentIndex(csIndex)
+ csWidget.connect( QtCore.SIGNAL('currentIndexChanged(const QString &)'), self.__csChanged)
+
+
+ # This doesnt work until the Horizontal enum is exposed.
+ """
+ self.__fstopWidget_numStops = 3.0
+ self.__fstopWidget_ticksPerStop = 4
+
+ self.layout().addWidget( QtGui.QLabel("FStop", self), 1, 0)
+ fstopWidget = QtGui.QSlider(Horizontal, self)
+ self.layout().addWidget( fstopWidget, 1, 1)
+ fstopWidget.setMinimum(int(-self.__fstopWidget_numStops*self.__fstopWidget_ticksPerStop))
+ fstopWidget.setMaximum(int(self.__fstopWidget_numStops*self.__fstopWidget_ticksPerStop))
+ fstopWidget.setTickInterval(self.__fstopWidget_ticksPerStop)
+ """
+
+
+ def __csChanged(self, text):
+ text = str(text)
+ if text != self.__inputColorSpace:
+ self.__inputColorSpace = text
+ self.__rebuildFilter()
+
+ def __rebuildFilter(self):
+ config = OCIO.GetCurrentConfig()
+ display = config.getDefaultDisplay()
+ view = config.getDefaultView(display)
+ transform = CreateOCIODisplayTransform(config, self.__inputColorSpace,
+ display, view,
+ self.__swizzle,
+ self.__fStopOffset, self.__viewGamma)
+
+ processor = config.getProcessor(transform)
+
+ shaderDesc = dict( [('language', OCIO.Constants.GPU_LANGUAGE_GLSL_1_3),
+ ('functionName', 'display_ocio_$ID_'),
+ ('lut3DEdgeLen', LUT3D_SIZE)] )
+
+ filterCacheID = processor.getGpuShaderTextCacheID(shaderDesc)
+ if filterCacheID != self.__filter_cacheID:
+ self.__filter_cacheID = filterCacheID
+ mari.app.log("OCIODisplay: Creating filter %s" % self.__filter_cacheID)
+
+ desc = "sampler3D lut3d_ocio_$ID_;\n"
+ desc += processor.getGpuShaderText(shaderDesc)
+ body = "{ Out = display_ocio_$ID_(Out, lut3d_ocio_$ID_); }"
+
+ # Clear the existing color managment filter stack and create a new filter
+ # HACK: Increment a counter by 1 each time to force a refresh
+ #self.__counter_hack += 1
+ #name = "OCIO %s %s %s v%d" % (display, view, self.__inputColorSpace, self.__counter_hack)
+ name = "OCIO %s %s %s" % (display, view, self.__inputColorSpace)
+
+ self.__filter = None
+ self.__texture3d_cacheID = None
+
+ mari.gl_render.clearPostFilterStack()
+ self.__filter = mari.gl_render.createPostFilter(name, desc, body)
+ mari.gl_render.appendPostFilter(self.__filter)
+ else:
+ mari.app.log('OCIODisplay: no shader text update required')
+
+ texture3d_cacheID = processor.getGpuLut3DCacheID(shaderDesc)
+ if texture3d_cacheID != self.__texture3d_cacheID:
+ lut3d = processor.getGpuLut3D(shaderDesc)
+
+ mari.app.log("OCIODisplay: Updating 3dlut %s" % texture3d_cacheID)
+
+ if self.__texture3d_cacheID is None:
+ self.__filter.setTexture3D("lut3d_ocio_$ID_",
+ LUT3D_SIZE, LUT3D_SIZE, LUT3D_SIZE,
+ self.__filter.FORMAT_RGB, lut3d)
+ else:
+ self.__filter.updateTexture3D( "lut3d_ocio_$ID_", lut3d)
+
+ self.__texture3d_cacheID = texture3d_cacheID
+ else:
+ mari.app.log("OCIODisplay: No lut3d update required")
+
+
+
+def CreateOCIODisplayTransform(config,
+ inputColorSpace,
+ display, view,
+ swizzle,
+ fstopOffset, viewGamma):
+
+ displayTransform = OCIO.DisplayTransform()
+ displayTransform.setInputColorSpaceName( inputColorSpace )
+
+ displayColorSpace = config.getDisplayColorSpaceName(display, view)
+ displayTransform.setDisplayColorSpaceName( displayColorSpace )
+
+ # Add the channel sizzle
+ lumacoef = config.getDefaultLumaCoefs()
+ mtx, offset = OCIO.MatrixTransform.View(swizzle, lumacoef)
+
+ transform = OCIO.MatrixTransform()
+ transform.setValue(mtx, offset)
+ displayTransform.setChannelView(transform)
+
+ # Add the linear fstop gain
+ gain = 2**fstopOffset
+ mtx, offset = OCIO.MatrixTransform.Scale((gain,gain,gain,gain))
+ transform = OCIO.MatrixTransform()
+ transform.setValue(mtx, offset)
+ displayTransform.setLinearCC(transform)
+
+ # Add the post-display CC
+ transform = OCIO.ExponentTransform()
+ transform.setValue([1.0 / max(1e-6, v) for v in \
+ (viewGamma, viewGamma, viewGamma, viewGamma)])
+ displayTransform.setDisplayCC(transform)
+
+ return displayTransform
+
+"""
+SWIZZLE_COLOR = (True, True, True, True)
+SWIZZLE_RED = (True, False, False, False)
+SWIZZLE_GREEN = (False, True, False, False)
+SWIZZLE_BLUE = (False, False, True, False)
+SWIZZLE_ALPHA = (False, False, False, True)
+SWIZZLE_LUMA = (True, True, True, False)
+
+Timings
+
+OCIO Setup: 0.5 ms
+OCIO 3D Lut creation: 14.7 ms
+Mari Setup: 21.3 ms
+Mari Texture Upload: 44.2 ms
+"""
+
+
+if __name__ == '__main__':
+ if not hasattr(mari.gl_render,"createPostFilter"):
+ mari.app.log("OCIODisplay: Error: This version of Mari does not support the mari.gl_render.createPostFilter API")
+ else:
+ if OCIO is not None:
+ if CREATE_FLOATING:
+ w = OCIODisplayUI()
+ w.show()
+ else:
+ if WINDOW_NAME in mari.app.tabNames():
+ mari.app.removeTab(WINDOW_NAME)
+ w = OCIODisplayUI()
+ mari.app.addTab(WINDOW_NAME, w)
diff --git a/src/mari/prototype/ociofiletransform.py b/src/mari/prototype/ociofiletransform.py
new file mode 100644
index 0000000..318c656
--- /dev/null
+++ b/src/mari/prototype/ociofiletransform.py
@@ -0,0 +1,93 @@
+"""
+This script allows the loading of a specied lut (1d/3d/mtx) in
+the Mari Viewer. Requires Mari 1.3v2+.
+
+This example is not represntative of the final Mari OCIO workflow, merely
+an API demonstration. This code is a work in progress, to demonstrate the
+integration of OpenColorIO and Mari. The APIs this code relies on are subject
+to change at any time, and as such should not be relied on for production use
+(yet).
+
+LINUX testing instructions:
+
+* Build OCIO
+mkdir -p dist_mari
+mkdir -p build_mari && cd build_mari
+cmake -D CMAKE_BUILD_TYPE=Release \
+ -D CMAKE_INSTALL_PREFIX=../dist_mari \
+ -D PYTHON=/usr/bin/python2.6 \
+ -D OCIO_NAMESPACE=OpenColorIO_Mari \
+ ../
+make install -j8
+
+* Edit this file to point to use viewer lut you want to use
+
+* Run Mari with OpenColorIO added to the LD_LIBRARY_PATH, and Python
+env LD_LIBRARY_PATH=<YOURDIR>/dist_mari/lib/ PYTHONPATH=<YOURDIR>/dist_mari/lib/python2.6 mari
+
+* Source this script in the python console.
+Also - IMPORTANT - you must enable 'Use Color Correction' in the Color Manager.
+
+"""
+
+# YOU MUST CHANGE THIS TO MODIFY WHICH LUT TO USE
+LUT_FILENAME = "/shots/spi/home/lib/lut/dev/v29/luts/LC3DL_Kodak2383_Sony_GDM.3dl"
+LUT3D_SIZE = 32
+
+import mari, time, os
+
+try:
+ import PyOpenColorIO as OCIO
+ print OCIO.__file__
+except Exception,e:
+ print "Error: Could not import OpenColorIO python bindings."
+ print "Please confirm PYTHONPATH has dir containing PyOpenColorIO.so"
+
+def RegisterOCIOLut():
+ if not hasattr(mari.gl_render,"createPostFilter"):
+ print "Error: This version of Mari does not support the mari.gl_render.createPostFilter API"
+ return
+
+ config = OCIO.Config()
+ transform = OCIO.FileTransform(src = os.path.realpath(LUT_FILENAME),
+ interpolation = OCIO.Constants.INTERP_LINEAR,
+ direction = OCIO.Constants.TRANSFORM_DIR_FORWARD)
+ processor = config.getProcessor(transform)
+
+ shaderDesc = dict( [('language', OCIO.Constants.GPU_LANGUAGE_GLSL_1_3),
+ ('functionName', 'display_ocio_$ID_'),
+ ('lut3DEdgeLen', LUT3D_SIZE)] )
+ shaderText = processor.getGpuShaderText(shaderDesc)
+
+ lut3d = processor.getGpuLut3D(shaderDesc)
+
+ # Clear the existing color managment filter stack
+ mari.gl_render.clearPostFilterStack()
+
+ # Create variable pre-declarations
+ desc = "sampler3D lut3d_ocio_$ID_;\n"
+ desc += shaderText
+
+ # Set the body of the filter
+ body = "{ Out = display_ocio_$ID_(Out, lut3d_ocio_$ID_); }"
+
+ # HACK: Increment a counter by 1 each time to force a refresh
+ if not hasattr(mari, "ocio_lut_counter_hack"):
+ mari.ocio_lut_counter_hack = 0
+ else:
+ mari.ocio_lut_counter_hack += 1
+ ocio_lut_counter_hack = mari.ocio_lut_counter_hack
+
+ # Create a new filter
+ name = "OCIO %s v%d" % (os.path.basename(LUT_FILENAME), ocio_lut_counter_hack)
+ postfilter = mari.gl_render.createPostFilter(name, desc, body)
+
+ # Set the texture to use for the given sampler on this filter
+ postfilter.setTexture3D("lut3d_ocio_$ID_",
+ LUT3D_SIZE, LUT3D_SIZE, LUT3D_SIZE,
+ postfilter.FORMAT_RGB, lut3d)
+
+ # Append the filter to the end of the current list of filters
+ mari.gl_render.appendPostFilter(postfilter)
+
+RegisterOCIOLut()
diff --git a/src/nuke/CMakeLists.txt b/src/nuke/CMakeLists.txt
new file mode 100644
index 0000000..81b2cd5
--- /dev/null
+++ b/src/nuke/CMakeLists.txt
@@ -0,0 +1,138 @@
+if(APPLE)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -undefined dynamic_lookup")
+endif()
+
+include_directories(
+ ${CMAKE_SOURCE_DIR}/export/
+ ${CMAKE_BINARY_DIR}/export/
+ ${Nuke_INCLUDE_DIR}
+)
+
+###############################################################################
+### NukeOCIOColorSpace ###
+
+add_library(NukeOCIOColorSpace MODULE
+ OCIOColorSpace/OCIOColorSpace.cpp
+)
+target_link_libraries(NukeOCIOColorSpace
+ OpenColorIO
+ #${Nuke_LIBRARIES}
+)
+set_target_properties(NukeOCIOColorSpace
+ PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME "OCIOColorSpace"
+)
+
+###############################################################################
+### NukeOCIODisplay ###
+
+add_library(NukeOCIODisplay MODULE
+ OCIODisplay/OCIODisplay.cpp
+)
+target_link_libraries(NukeOCIODisplay
+ OpenColorIO
+ #${Nuke_LIBRARIES}
+)
+set_target_properties(NukeOCIODisplay
+ PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME "OCIODisplay"
+)
+
+###############################################################################
+### NukeOCIOFileTransform ###
+
+add_library(NukeOCIOFileTransform MODULE
+ OCIOFileTransform/OCIOFileTransform.cpp
+)
+target_link_libraries(NukeOCIOFileTransform
+ OpenColorIO
+ #${Nuke_LIBRARIES}
+)
+set_target_properties(NukeOCIOFileTransform
+ PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME "OCIOFileTransform"
+)
+
+###############################################################################
+### NukeOCIOLogConvert ###
+
+add_library(NukeOCIOLogConvert MODULE
+ OCIOLogConvert/OCIOLogConvert.cpp
+)
+target_link_libraries(NukeOCIOLogConvert
+ OpenColorIO
+ #${Nuke_LIBRARIES}
+)
+set_target_properties(NukeOCIOLogConvert
+ PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME "OCIOLogConvert"
+)
+
+###############################################################################
+### NukeOCIOLookTransform ###
+
+add_library(NukeOCIOLookTransform MODULE
+ OCIOLookTransform/OCIOLookTransform.cpp
+)
+target_link_libraries(NukeOCIOLookTransform
+ OpenColorIO
+ #${Nuke_LIBRARIES}
+)
+set_target_properties(NukeOCIOLookTransform
+ PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME "OCIOLookTransform"
+)
+
+###############################################################################
+### NukeOCIOCDLTransform ###
+
+add_library(NukeOCIOCDLTransform MODULE
+ OCIOCDLTransform/OCIOCDLTransform.cpp
+)
+target_link_libraries(NukeOCIOCDLTransform
+ OpenColorIO
+ #${Nuke_LIBRARIES}
+)
+set_target_properties(NukeOCIOCDLTransform
+ PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME "OCIOCDLTransform"
+)
+
+###############################################################################
+### Nuke Targets ###
+
+add_custom_target(Nuke
+ DEPENDS NukeOCIOColorSpace
+ DEPENDS NukeOCIODisplay
+ DEPENDS NukeOCIOFileTransform
+ DEPENDS NukeOCIOLogConvert
+ DEPENDS NukeOCIOCDLTransform
+)
+
+install(TARGETS NukeOCIOColorSpace
+ DESTINATION ${CMAKE_INSTALL_EXEC_PREFIX}/lib/nuke${Nuke_API_VERSION})
+
+install(TARGETS NukeOCIODisplay
+ DESTINATION ${CMAKE_INSTALL_EXEC_PREFIX}/lib/nuke${Nuke_API_VERSION})
+
+install(TARGETS NukeOCIOLogConvert
+ DESTINATION ${CMAKE_INSTALL_EXEC_PREFIX}/lib/nuke${Nuke_API_VERSION})
+
+install(TARGETS NukeOCIOFileTransform
+ DESTINATION ${CMAKE_INSTALL_EXEC_PREFIX}/lib/nuke${Nuke_API_VERSION})
+
+install(TARGETS NukeOCIOLookTransform
+ DESTINATION ${CMAKE_INSTALL_EXEC_PREFIX}/lib/nuke${Nuke_API_VERSION})
+
+install(TARGETS NukeOCIOCDLTransform
+ DESTINATION ${CMAKE_INSTALL_EXEC_PREFIX}/lib/nuke${Nuke_API_VERSION})
+
+install(DIRECTORY ${CMAKE_SOURCE_DIR}/share/nuke
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/share/
+ PATTERN .svn EXCLUDE)
diff --git a/src/nuke/OCIOCDLTransform/OCIOCDLTransform.cpp b/src/nuke/OCIOCDLTransform/OCIOCDLTransform.cpp
new file mode 100644
index 0000000..51ec866
--- /dev/null
+++ b/src/nuke/OCIOCDLTransform/OCIOCDLTransform.cpp
@@ -0,0 +1,387 @@
+/**
+ * OpenColorIO conversion Iop.
+ */
+
+#include "OCIOCDLTransform.h"
+
+namespace OCIO = OCIO_NAMESPACE;
+
+#include <string>
+#include <sstream>
+#include <stdexcept>
+
+#include <DDImage/Channel.h>
+#include <DDImage/PixelIop.h>
+#include <DDImage/NukeWrapper.h>
+#include <DDImage/Row.h>
+#include <DDImage/Knobs.h>
+
+
+const char* OCIOCDLTransform::dirs[] = { "forward", "inverse", 0 };
+
+OCIOCDLTransform::OCIOCDLTransform(Node *n) : DD::Image::PixelIop(n)
+{
+ for (int i = 0; i < 3; i++){
+ m_slope[i] = 1.0;
+ m_offset[i] = 0.0;
+ m_power[i] = 1.0;
+ }
+
+ m_saturation = 1.0;
+ m_readFromFile = false;
+ m_dirindex = 0;
+ m_file = NULL;
+ m_reload_version = 1;
+
+ m_slopeKnob = NULL;
+ m_offsetKnob = NULL;
+ m_powerKnob = NULL;
+ m_saturationKnob = NULL;
+ m_fileKnob = NULL;
+ m_cccidKnob = NULL;
+
+ m_firstLoad = true;
+}
+
+OCIOCDLTransform::~OCIOCDLTransform()
+{
+
+}
+
+void OCIOCDLTransform::knobs(DD::Image::Knob_Callback f)
+{
+ // ASC CDL grade numbers
+ m_slopeKnob = DD::Image::Color_knob(f, m_slope, DD::Image::IRange(0, 4.0), "slope");
+ m_offsetKnob = DD::Image::Color_knob(f, m_offset, DD::Image::IRange(-0.2, 0.2), "offset");
+ m_powerKnob = DD::Image::Color_knob(f, m_power, DD::Image::IRange(0.0, 4.0), "power");
+ m_saturationKnob = DD::Image::Float_knob(f, &m_saturation, DD::Image::IRange(0, 4.0), "saturation");
+
+ Enumeration_knob(f, &m_dirindex, dirs, "direction", "direction");
+ DD::Image::Tooltip(f, "Specify the transform direction.");
+
+ DD::Image::Divider(f);
+
+ DD::Image::Bool_knob(f, &m_readFromFile, "read_from_file", "read from file");
+ DD::Image::SetFlags(f, DD::Image::Knob::EARLY_STORE);
+ DD::Image::Tooltip(f, "Load color correction information from the .cc or .ccc file.");
+
+ m_fileKnob = File_knob(f, &m_file, "file", "file");
+ const char * filehelp = "Specify the src ASC CDL file, on disk, to use for this transform. "
+ "This can be either a .cc or .ccc file. If .ccc is specified, the cccid is required.";
+ DD::Image::Tooltip(f, filehelp);
+
+ // Reload button, and hidden "version" knob to invalidate cache on reload
+ Button(f, "reload", "reload");
+ DD::Image::Tooltip(f, "Reloads specified files");
+ Int_knob(f, &m_reload_version, "version");
+ DD::Image::SetFlags(f, DD::Image::Knob::HIDDEN);
+
+ DD::Image::SetFlags(f, DD::Image::Knob::ENDLINE);
+
+ m_cccidKnob = String_knob(f, &m_cccid, "cccid");
+ const char * ccchelp = "If the source file is an ASC CDL CCC (color correction collection), "
+ "this specifies the id to lookup. OpenColorIO::Contexts (envvars) are obeyed.";
+ DD::Image::Tooltip(f, ccchelp);
+
+ /* TODO:
+ These scripts should be updated to make use of native OCIO APIs, rather than convenience functions
+ exposed in ocionuke. Ideally, ocionuke would be a minimal module (essentially only ui code) that makes
+ use of OCIO for all heavy lifting.
+ */
+
+ DD::Image::PyScript_knob(f, "import ocionuke.cdl; ocionuke.cdl.select_cccid_for_filetransform()", "select_cccid", "select cccid");
+
+ // Import/export buttons
+ DD::Image::PyScript_knob(f, "import ocionuke.cdl; ocionuke.cdl.export_as_cc()", "export_cc", "export grade as .cc");
+ DD::Image::Tooltip(f, "Export this grade as a ColorCorrection XML file, which can be loaded with the OCIOFileTransform, or using a FileTransform in an OCIO config");
+
+ DD::Image::PyScript_knob(f, "import ocionuke.cdl; ocionuke.cdl.import_cc_from_xml()", "import_cc", "import from .cc");
+ DD::Image::Tooltip(f, "Import grade from a ColorCorrection XML file");
+
+
+ DD::Image::Divider(f);
+
+ /*
+ TODO: One thing thats sucks is that we dont apparently have a mechansism to call refreshKnobEnabledState
+ after the knobs have been loaded, but before scripts have a chance to run. I'd love to have a post-knob
+ finalize callback opportunity to reload the cdl from file, if needed. The current system will only do the
+ initial file refresh when either the ui is loaded, or a render is triggered.
+ */
+
+ if(!f.makeKnobs() && m_firstLoad)
+ {
+ m_firstLoad = false;
+ refreshKnobEnabledState();
+ if(m_readFromFile) loadCDLFromFile();
+ }
+}
+
+void OCIOCDLTransform::refreshKnobEnabledState()
+{
+ if(m_readFromFile)
+ {
+ m_slopeKnob->disable();
+ m_offsetKnob->disable();
+ m_powerKnob->disable();
+ m_saturationKnob->disable();
+
+ // We leave these active to allow knob re-use with the import/export buttons
+ //m_fileKnob->enable();
+ //m_cccidKnob->enable();
+
+ loadCDLFromFile();
+ }
+ else
+ {
+ m_slopeKnob->enable();
+ m_offsetKnob->enable();
+ m_powerKnob->enable();
+ m_saturationKnob->enable();
+
+ // We leave these active to allow knob re-use with the import/export buttons
+ //m_fileKnob->disable();
+ //m_cccidKnob->disable();
+ }
+}
+
+void OCIOCDLTransform::append(DD::Image::Hash& nodehash)
+{
+ // There is a bug where in Nuke <6.3 the String_knob (used for
+ // cccid) is not included in the node's hash. Include it manually
+ // so the node correctly redraws. Appears fixed in in 6.3
+ nodehash.append(m_cccid.c_str());
+
+ // Incremented to force reloading after rereading the LUT file
+ nodehash.append(m_reload_version);
+}
+
+int OCIOCDLTransform::knob_changed(DD::Image::Knob* k)
+{
+ // return true if you want to continue to receive changes for this knob
+ std::string knobname = k->name();
+
+ if(knobname == "read_from_file")
+ {
+ refreshKnobEnabledState();
+
+ if(m_readFromFile)
+ {
+ loadCDLFromFile();
+ }
+ return true;
+ }
+ else if(knobname == "file")
+ {
+ if(m_readFromFile)
+ {
+ loadCDLFromFile();
+ }
+ return true;
+ }
+
+ else if(knobname == "reload")
+ {
+ knob("version")->set_value(m_reload_version+1);
+ OCIO::ClearAllCaches();
+ m_firstLoad = true;
+
+ return true; // ensure callback is triggered again
+ }
+
+ return false;
+}
+
+// Check to see if file exists
+// read from file
+// set knob values
+// throw an error if anything goes wrong
+
+void OCIOCDLTransform::loadCDLFromFile()
+{
+ OCIO::CDLTransformRcPtr transform;
+
+ try
+ {
+ // This is inexpensive to call multiple times, as OCIO caches results
+ // internally.
+ transform = OCIO::CDLTransform::CreateFromFile(m_file, m_cccid.c_str());
+ }
+ catch(OCIO::Exception &e)
+ {
+ error(e.what());
+ return;
+ }
+
+
+ float sop[9];
+ transform->getSOP(sop);
+
+ m_slopeKnob->clear_animated(-1);
+ m_slopeKnob->set_value(sop[0], 0);
+ m_slopeKnob->set_value(sop[1], 1);
+ m_slopeKnob->set_value(sop[2], 2);
+
+ m_offsetKnob->clear_animated(-1);
+ m_offsetKnob->set_value(sop[3], 0);
+ m_offsetKnob->set_value(sop[4], 1);
+ m_offsetKnob->set_value(sop[5], 2);
+
+ m_powerKnob->clear_animated(-1);
+ m_powerKnob->set_value(sop[6], 0);
+ m_powerKnob->set_value(sop[7], 1);
+ m_powerKnob->set_value(sop[8], 2);
+
+ m_saturationKnob->clear_animated(-1);
+ m_saturationKnob->set_value(transform->getSat());
+}
+
+void OCIOCDLTransform::_validate(bool for_real)
+{
+ if(m_firstLoad)
+ {
+ m_firstLoad = false;
+ if(m_readFromFile) loadCDLFromFile();
+ }
+
+ // We must explicitly refresh the enable state here as well,
+ // as there are some changes (such as expressioned knob updates)
+ // that wont trigger the knob_changed callback. This allows
+ // us to catch these here.
+
+ refreshKnobEnabledState();
+
+ try
+ {
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+
+ OCIO::CDLTransformRcPtr cc = OCIO::CDLTransform::Create();
+ cc->setSlope(m_slope);
+ cc->setOffset(m_offset);
+ cc->setPower(m_power);
+ cc->setSat(m_saturation);
+
+ if(m_dirindex == 0) cc->setDirection(OCIO::TRANSFORM_DIR_FORWARD);
+ else cc->setDirection(OCIO::TRANSFORM_DIR_INVERSE);
+
+ m_processor = config->getProcessor(cc);
+ }
+ catch(OCIO::Exception &e)
+ {
+ error(e.what());
+ return;
+ }
+
+ if(m_processor->isNoOp())
+ {
+ set_out_channels(DD::Image::Mask_None); // prevents engine() from being called
+ } else {
+ set_out_channels(DD::Image::Mask_All);
+ }
+
+ DD::Image::PixelIop::_validate(for_real);
+}
+
+// Note that this is copied by others (OCIODisplay)
+void OCIOCDLTransform::in_channels(int /* n unused */, DD::Image::ChannelSet& mask) const
+{
+ DD::Image::ChannelSet done;
+ foreach(c, mask)
+ {
+ if (DD::Image::colourIndex(c) < 3 && !(done & c))
+ {
+ done.addBrothers(c, 3);
+ }
+ }
+ mask += done;
+}
+
+// See Saturation::pixel_engine for a well-commented example.
+// Note that this is copied by others (OCIODisplay)
+void OCIOCDLTransform::pixel_engine(
+ const DD::Image::Row& in,
+ int /* rowY unused */, int rowX, int rowXBound,
+ DD::Image::ChannelMask outputChannels,
+ DD::Image::Row& out)
+{
+ int rowWidth = rowXBound - rowX;
+
+ DD::Image::ChannelSet done;
+ foreach (requestedChannel, outputChannels)
+ {
+ // Skip channels which had their trios processed already,
+ if (done & requestedChannel)
+ {
+ continue;
+ }
+
+ // Pass through channels which are not selected for processing
+ // and non-rgb channels.
+ if (colourIndex(requestedChannel) >= 3)
+ {
+ out.copy(in, requestedChannel, rowX, rowXBound);
+ continue;
+ }
+
+ DD::Image::Channel rChannel = DD::Image::brother(requestedChannel, 0);
+ DD::Image::Channel gChannel = DD::Image::brother(requestedChannel, 1);
+ DD::Image::Channel bChannel = DD::Image::brother(requestedChannel, 2);
+
+ done += rChannel;
+ done += gChannel;
+ done += bChannel;
+
+ const float *rIn = in[rChannel] + rowX;
+ const float *gIn = in[gChannel] + rowX;
+ const float *bIn = in[bChannel] + rowX;
+
+ float *rOut = out.writable(rChannel) + rowX;
+ float *gOut = out.writable(gChannel) + rowX;
+ float *bOut = out.writable(bChannel) + rowX;
+
+ // OCIO modifies in-place
+ // Note: xOut can equal xIn in some circumstances, such as when the
+ // 'Black' (throwaway) scanline is uses. We thus must guard memcpy,
+ // which does not allow for overlapping regions.
+ if (rOut != rIn) memcpy(rOut, rIn, sizeof(float)*rowWidth);
+ if (gOut != gIn) memcpy(gOut, gIn, sizeof(float)*rowWidth);
+ if (bOut != bIn) memcpy(bOut, bIn, sizeof(float)*rowWidth);
+
+ try
+ {
+ OCIO::PlanarImageDesc img(rOut, gOut, bOut, NULL, rowWidth, /*height*/ 1);
+ m_processor->apply(img);
+ }
+ catch(OCIO::Exception &e)
+ {
+ error(e.what());
+ }
+ }
+}
+
+const DD::Image::Op::Description OCIOCDLTransform::description("OCIOCDLTransform", build);
+
+const char* OCIOCDLTransform::Class() const
+{
+ return description.name;
+}
+
+const char* OCIOCDLTransform::displayName() const
+{
+ return description.name;
+}
+
+const char* OCIOCDLTransform::node_help() const
+{
+ // TODO more detailed help text
+ return "Use OpenColorIO to apply an ASC CDL grade. Applied using:\n\n"\
+ "out = (i * s + o)^p\n\nWhere i is the input value, s is slope, "\
+ "o is offset and p is power";
+}
+
+
+DD::Image::Op* build(Node *node)
+{
+ DD::Image::NukeWrapper *op = new DD::Image::NukeWrapper(new OCIOCDLTransform(node));
+ op->channels(DD::Image::Mask_RGB);
+ return op;
+}
diff --git a/src/nuke/OCIOCDLTransform/OCIOCDLTransform.h b/src/nuke/OCIOCDLTransform/OCIOCDLTransform.h
new file mode 100644
index 0000000..6b7cc66
--- /dev/null
+++ b/src/nuke/OCIOCDLTransform/OCIOCDLTransform.h
@@ -0,0 +1,137 @@
+#ifndef INCLUDED_OCIO_NUKE_CDLTRANSFORM_H_
+#define INCLUDED_OCIO_NUKE_CDLTRANSFORM_H_
+
+// Include these early, for Nuke's headers under gcc 4.4.2.
+#include <memory>
+#include <cstdarg>
+
+#include <DDImage/PixelIop.h>
+#include <DDImage/Row.h>
+#include <DDImage/Knob.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+namespace OCIO = OCIO_NAMESPACE;
+
+
+/*!
+ * Iop that uses OpenColorIO to apply an ASC CDL transform
+ */
+class OCIOCDLTransform : public DD::Image::PixelIop {
+
+ protected:
+
+ // ASC CDL grade numbers
+ float m_slope[3];
+ float m_offset[3];
+ float m_power[3];
+ float m_saturation;
+
+ static const char* dirs[];
+ int m_dirindex;
+
+ bool m_readFromFile;
+
+ // ID used for exporting grades into .cc/.ccc files
+ const char* m_file;
+ std::string m_cccid;
+
+ DD::Image::Knob* m_slopeKnob;
+ DD::Image::Knob* m_offsetKnob;
+ DD::Image::Knob* m_powerKnob;
+ DD::Image::Knob* m_saturationKnob;
+ DD::Image::Knob* m_fileKnob;
+ DD::Image::Knob* m_cccidKnob;
+
+ OCIO::ConstProcessorRcPtr m_processor;
+ bool m_firstLoad;
+
+ /*! Controlled by hidden "version" knob, incremented to redraw image */
+ int m_reload_version;
+
+ public:
+ OCIOCDLTransform(Node *node);
+
+ virtual ~OCIOCDLTransform();
+
+ static const DD::Image::Op::Description description;
+
+ /*! Return the command name that will be stored in Nuke scripts. */
+ virtual const char *Class() const;
+
+ /*!
+ * Return a name for this class that will be shown to the user. The
+ * default implementation returns Class(). You can return a different
+ * (ie more user-friendly) name instead here, and there is no need for
+ * this to be unique.
+ *
+ * Nuke currently will remove any trailing digits and underscores from
+ * this and add a new number to make a unique name for the new node.
+ *
+ * \return "OCIOCDLTransform"
+ */
+ virtual const char *displayName() const;
+
+ /*!
+ * Return help information for this node. This information is in the
+ * pop-up window that the user gets when they hit the [?] button in
+ * the lower-left corner of the control panel.
+ */
+ virtual const char *node_help() const;
+
+ /*!
+ * Define the knobs that will be presented in the control panel.
+ */
+ virtual void knobs(DD::Image::Knob_Callback f);
+
+ //! The will handle the knob changes.
+ virtual int knob_changed(DD::Image::Knob*);
+
+ void refreshKnobEnabledState();
+ void loadCDLFromFile();
+
+
+ /*!
+ * Specify the channels required from input n to produce the channels
+ * in mask by modifying mask in-place. (At least one channel in the
+ * input is assumed.)
+ *
+ * Since OCIOCDLTransform conversions can have channel cross-talk, any rgb
+ * output channel requires all its rgb bretheren. (Non-rgb
+ * are passed through.)
+ */
+ virtual void in_channels(int n, DD::Image::ChannelSet& mask) const;
+
+ /*!
+ * Calculate the output pixel data.
+ * \param rowY vertical line number
+ * \param rowX inclusive left bound
+ * \param rowXBound exclusive right bound
+ * \param outputChannels a subset of out_channels(), the required channels to be produced
+ */
+ virtual void pixel_engine(
+ const DD::Image::Row& in,
+ int rowY, int rowX, int rowXBound,
+ DD::Image::ChannelMask outputChannels,
+ DD::Image::Row& out);
+
+
+ protected:
+
+ /*!
+ * Check that colorspaces are available, and that the transform
+ * is not a noop. (As OCIO whether a given transform is a noop, since it
+ * can do more analysis than just name matching.)
+ */
+ virtual void _validate(bool for_real);
+
+ /*!
+ * Ensure Node hash is reflects all parameters
+ */
+ void append(DD::Image::Hash& nodehash);
+
+};
+
+
+static DD::Image::Op* build(Node *node);
+
+#endif // INCLUDED_OCIO_NUKE_CDLTRANSFORM_H_
diff --git a/src/nuke/OCIOColorSpace/OCIOColorSpace.cpp b/src/nuke/OCIOColorSpace/OCIOColorSpace.cpp
new file mode 100644
index 0000000..091c1ef
--- /dev/null
+++ b/src/nuke/OCIOColorSpace/OCIOColorSpace.cpp
@@ -0,0 +1,376 @@
+/**
+ * OpenColorIO ColorSpace Iop.
+ */
+
+#include "OCIOColorSpace.h"
+
+namespace OCIO = OCIO_NAMESPACE;
+
+#include <string>
+#include <sstream>
+#include <stdexcept>
+
+#include <DDImage/Channel.h>
+#include <DDImage/PixelIop.h>
+#include <DDImage/NukeWrapper.h>
+#include <DDImage/Row.h>
+#include <DDImage/Knobs.h>
+#include <DDImage/ddImageVersionNumbers.h>
+
+// Should we use cascasing ColorSpace menus
+#if defined kDDImageVersionInteger && (kDDImageVersionInteger>=62300)
+#define OCIO_CASCADE
+#endif
+
+OCIOColorSpace::OCIOColorSpace(Node *n) : DD::Image::PixelIop(n)
+{
+ m_hasColorSpaces = false;
+
+ m_inputColorSpaceIndex = 0;
+ m_outputColorSpaceIndex = 0;
+
+ // Query the color space names from the current config
+ // TODO (when to) re-grab the list of available color spaces? How to save/load?
+
+ try
+ {
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+
+ OCIO::ConstColorSpaceRcPtr defaultcs = config->getColorSpace(OCIO::ROLE_SCENE_LINEAR);
+ if(!defaultcs) throw std::runtime_error("ROLE_SCENE_LINEAR not defined.");
+ std::string defaultColorSpaceName = defaultcs->getName();
+
+ for(int i = 0; i < config->getNumColorSpaces(); i++)
+ {
+ std::string csname = config->getColorSpaceNameByIndex(i);
+
+#ifdef OCIO_CASCADE
+ std::string family = config->getColorSpace(csname.c_str())->getFamily();
+ if(family.empty())
+ m_colorSpaceNames.push_back(csname.c_str());
+ else
+ m_colorSpaceNames.push_back(family + "/" + csname);
+#else
+ m_colorSpaceNames.push_back(csname);
+#endif
+
+ if(csname == defaultColorSpaceName)
+ {
+ m_inputColorSpaceIndex = i;
+ m_outputColorSpaceIndex = i;
+ }
+ }
+ }
+ catch (OCIO::Exception& e)
+ {
+ std::cerr << "OCIOColorSpace: " << e.what() << std::endl;
+ }
+ catch (...)
+ {
+ std::cerr << "OCIOColorSpace: Unknown exception during OCIO setup." << std::endl;
+ }
+
+ // Then, create a cstr array for passing to Nuke
+ // This must be done in a second pass, lest the original m_colorSpaceNames
+ // std::string be reallocated in the interim
+ for(unsigned int i=0; i<m_colorSpaceNames.size(); ++i)
+ {
+ m_inputColorSpaceCstrNames.push_back(m_colorSpaceNames[i].c_str());
+ m_outputColorSpaceCstrNames.push_back(m_colorSpaceNames[i].c_str());
+ }
+
+ m_inputColorSpaceCstrNames.push_back(NULL);
+ m_outputColorSpaceCstrNames.push_back(NULL);
+
+ m_hasColorSpaces = (!m_colorSpaceNames.empty());
+
+ if(!m_hasColorSpaces)
+ {
+ std::cerr << "OCIOColorSpace: No color spaces available for input and/or output." << std::endl;
+ }
+}
+
+OCIOColorSpace::~OCIOColorSpace()
+{
+
+}
+
+void OCIOColorSpace::knobs(DD::Image::Knob_Callback f)
+{
+#ifdef OCIO_CASCADE
+ DD::Image::CascadingEnumeration_knob(f,
+ &m_inputColorSpaceIndex, &m_inputColorSpaceCstrNames[0], "in_colorspace", "in");
+ DD::Image::Tooltip(f, "Input data is taken to be in this color space.");
+ DD::Image::SetFlags(f, DD::Image::Knob::ALWAYS_SAVE);
+
+ DD::Image::CascadingEnumeration_knob(f,
+ &m_outputColorSpaceIndex, &m_outputColorSpaceCstrNames[0], "out_colorspace", "out");
+ DD::Image::Tooltip(f, "Image data is converted to this color space for output.");
+ DD::Image::SetFlags(f, DD::Image::Knob::ALWAYS_SAVE);
+#else
+ DD::Image::Enumeration_knob(f,
+ &m_inputColorSpaceIndex, &m_inputColorSpaceCstrNames[0], "in_colorspace", "in");
+ DD::Image::Tooltip(f, "Input data is taken to be in this color space.");
+ DD::Image::SetFlags(f, DD::Image::Knob::ALWAYS_SAVE);
+
+ DD::Image::Enumeration_knob(f,
+ &m_outputColorSpaceIndex, &m_outputColorSpaceCstrNames[0], "out_colorspace", "out");
+ DD::Image::Tooltip(f, "Image data is converted to this color space for output.");
+ DD::Image::SetFlags(f, DD::Image::Knob::ALWAYS_SAVE);
+#endif
+
+}
+
+OCIO::ConstContextRcPtr OCIOColorSpace::getLocalContext()
+{
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+ OCIO::ConstContextRcPtr context = config->getCurrentContext();
+ OCIO::ContextRcPtr mutableContext;
+
+ if(!m_contextKey1.empty())
+ {
+ if(!mutableContext) mutableContext = context->createEditableCopy();
+ mutableContext->setStringVar(m_contextKey1.c_str(), m_contextValue1.c_str());
+ }
+ if(!m_contextKey2.empty())
+ {
+ if(!mutableContext) mutableContext = context->createEditableCopy();
+ mutableContext->setStringVar(m_contextKey2.c_str(), m_contextValue2.c_str());
+ }
+ if(!m_contextKey3.empty())
+ {
+ if(!mutableContext) mutableContext = context->createEditableCopy();
+ mutableContext->setStringVar(m_contextKey3.c_str(), m_contextValue3.c_str());
+ }
+ if(!m_contextKey4.empty())
+ {
+ if(!mutableContext) mutableContext = context->createEditableCopy();
+ mutableContext->setStringVar(m_contextKey4.c_str(), m_contextValue4.c_str());
+ }
+
+ if(mutableContext) context = mutableContext;
+ return context;
+}
+
+void OCIOColorSpace::append(DD::Image::Hash& localhash)
+{
+ // TODO: Hang onto the context, what if getting it
+ // (and querying getCacheID) is expensive?
+ try
+ {
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+ OCIO::ConstContextRcPtr context = getLocalContext();
+ std::string configCacheID = config->getCacheID(context);
+ localhash.append(configCacheID);
+ }
+ catch(OCIO::Exception &e)
+ {
+ error(e.what());
+ return;
+ }
+}
+
+void OCIOColorSpace::_validate(bool for_real)
+{
+ if(!m_hasColorSpaces)
+ {
+ error("No color spaces available for input and/or output.");
+ return;
+ }
+
+ int inputColorSpaceCount = static_cast<int>(m_inputColorSpaceCstrNames.size()) - 1;
+ if(m_inputColorSpaceIndex < 0 || m_inputColorSpaceIndex >= inputColorSpaceCount)
+ {
+ std::ostringstream err;
+ err << "Input color space index (" << m_inputColorSpaceIndex << ") out of range.";
+ error(err.str().c_str());
+ return;
+ }
+
+ int outputColorSpaceCount = static_cast<int>(m_outputColorSpaceCstrNames.size()) - 1;
+ if(m_outputColorSpaceIndex < 0 || m_outputColorSpaceIndex >= outputColorSpaceCount)
+ {
+ std::ostringstream err;
+ err << "Output color space index (" << m_outputColorSpaceIndex << ") out of range.";
+ error(err.str().c_str());
+ return;
+ }
+
+ try
+ {
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+
+ const char * inputName = config->getColorSpaceNameByIndex(m_inputColorSpaceIndex);
+ const char * outputName = config->getColorSpaceNameByIndex(m_outputColorSpaceIndex);
+
+ OCIO::ConstContextRcPtr context = getLocalContext();
+ m_processor = config->getProcessor(context, inputName, outputName);
+ }
+ catch(OCIO::Exception &e)
+ {
+ error(e.what());
+ return;
+ }
+
+ if(m_processor->isNoOp())
+ {
+ set_out_channels(DD::Image::Mask_None); // prevents engine() from being called
+ } else {
+ set_out_channels(DD::Image::Mask_All);
+ }
+
+ DD::Image::PixelIop::_validate(for_real);
+}
+
+// Note that this is copied by others (OCIODisplay)
+void OCIOColorSpace::in_channels(int /* n unused */, DD::Image::ChannelSet& mask) const
+{
+ DD::Image::ChannelSet done;
+ foreach(c, mask)
+ {
+ if (DD::Image::colourIndex(c) < 3 && !(done & c))
+ {
+ done.addBrothers(c, 3);
+ }
+ }
+ mask += done;
+}
+
+// See Saturation::pixel_engine for a well-commented example.
+// Note that this is copied by others (OCIODisplay)
+void OCIOColorSpace::pixel_engine(
+ const DD::Image::Row& in,
+ int /* rowY unused */, int rowX, int rowXBound,
+ DD::Image::ChannelMask outputChannels,
+ DD::Image::Row& out)
+{
+ int rowWidth = rowXBound - rowX;
+
+ DD::Image::ChannelSet done;
+ foreach (requestedChannel, outputChannels)
+ {
+ // Skip channels which had their trios processed already,
+ if (done & requestedChannel)
+ {
+ continue;
+ }
+
+ // Pass through channels which are not selected for processing
+ // and non-rgb channels.
+ if (colourIndex(requestedChannel) >= 3)
+ {
+ out.copy(in, requestedChannel, rowX, rowXBound);
+ continue;
+ }
+
+ DD::Image::Channel rChannel = DD::Image::brother(requestedChannel, 0);
+ DD::Image::Channel gChannel = DD::Image::brother(requestedChannel, 1);
+ DD::Image::Channel bChannel = DD::Image::brother(requestedChannel, 2);
+
+ done += rChannel;
+ done += gChannel;
+ done += bChannel;
+
+ const float *rIn = in[rChannel] + rowX;
+ const float *gIn = in[gChannel] + rowX;
+ const float *bIn = in[bChannel] + rowX;
+
+ float *rOut = out.writable(rChannel) + rowX;
+ float *gOut = out.writable(gChannel) + rowX;
+ float *bOut = out.writable(bChannel) + rowX;
+
+ // OCIO modifies in-place
+ // Note: xOut can equal xIn in some circumstances, such as when the
+ // 'Black' (throwaway) scanline is uses. We thus must guard memcpy,
+ // which does not allow for overlapping regions.
+ if (rOut != rIn) memcpy(rOut, rIn, sizeof(float)*rowWidth);
+ if (gOut != gIn) memcpy(gOut, gIn, sizeof(float)*rowWidth);
+ if (bOut != bIn) memcpy(bOut, bIn, sizeof(float)*rowWidth);
+
+ try
+ {
+ OCIO::PlanarImageDesc img(rOut, gOut, bOut, NULL, rowWidth, /*height*/ 1);
+ m_processor->apply(img);
+ }
+ catch(OCIO::Exception &e)
+ {
+ error(e.what());
+ }
+ }
+}
+
+const DD::Image::Op::Description OCIOColorSpace::description("OCIOColorSpace", build);
+
+const char* OCIOColorSpace::Class() const
+{
+ return description.name;
+}
+
+const char* OCIOColorSpace::displayName() const
+{
+ return description.name;
+}
+
+const char* OCIOColorSpace::node_help() const
+{
+ // TODO more detailed help text
+ return "Use OpenColorIO to convert from one color space to another.";
+}
+
+// This class is necessary in order to call knobsAtTheEnd(). Otherwise, the NukeWrapper knobs
+// will be added to the Context tab instead of the primary tab.
+class OCIOColorSpaceNukeWrapper : public DD::Image::NukeWrapper
+{
+public:
+ OCIOColorSpaceNukeWrapper(DD::Image::PixelIop* op) : DD::Image::NukeWrapper(op)
+ {
+ }
+
+ virtual void attach()
+ {
+ wrapped_iop()->attach();
+ }
+
+ virtual void detach()
+ {
+ wrapped_iop()->detach();
+ }
+
+ virtual void knobs(DD::Image::Knob_Callback f)
+ {
+ OCIOColorSpace* csIop = dynamic_cast<OCIOColorSpace*>(wrapped_iop());
+ if(!csIop) return;
+
+ DD::Image::NukeWrapper::knobs(f);
+
+ DD::Image::Tab_knob(f, "Context");
+ {
+ DD::Image::String_knob(f, &csIop->m_contextKey1, "key1");
+ DD::Image::Spacer(f, 10);
+ DD::Image::String_knob(f, &csIop->m_contextValue1, "value1");
+ DD::Image::ClearFlags(f, DD::Image::Knob::STARTLINE);
+
+ DD::Image::String_knob(f, &csIop->m_contextKey2, "key2");
+ DD::Image::Spacer(f, 10);
+ DD::Image::String_knob(f, &csIop->m_contextValue2, "value2");
+ DD::Image::ClearFlags(f, DD::Image::Knob::STARTLINE);
+
+ DD::Image::String_knob(f, &csIop->m_contextKey3, "key3");
+ DD::Image::Spacer(f, 10);
+ DD::Image::String_knob(f, &csIop->m_contextValue3, "value3");
+ DD::Image::ClearFlags(f, DD::Image::Knob::STARTLINE);
+
+ DD::Image::String_knob(f, &csIop->m_contextKey4, "key4");
+ DD::Image::Spacer(f, 10);
+ DD::Image::String_knob(f, &csIop->m_contextValue4, "value4");
+ DD::Image::ClearFlags(f, DD::Image::Knob::STARTLINE);
+ }
+ }
+};
+
+static DD::Image::Op* build(Node *node)
+{
+ DD::Image::NukeWrapper *op = (new OCIOColorSpaceNukeWrapper(new OCIOColorSpace(node)));
+ op->channels(DD::Image::Mask_RGB);
+ return op;
+}
diff --git a/src/nuke/OCIOColorSpace/OCIOColorSpace.h b/src/nuke/OCIOColorSpace/OCIOColorSpace.h
new file mode 100644
index 0000000..12b243b
--- /dev/null
+++ b/src/nuke/OCIOColorSpace/OCIOColorSpace.h
@@ -0,0 +1,120 @@
+#ifndef INCLUDED_OCIO_NUKE_COLORSPACECONVERSION_H_
+#define INCLUDED_OCIO_NUKE_COLORSPACECONVERSION_H_
+
+// Include these early, for Nuke's headers under gcc 4.4.2.
+#include <memory>
+#include <cstdarg>
+
+#include <DDImage/PixelIop.h>
+#include <DDImage/Row.h>
+#include <DDImage/Knob.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+namespace OCIO = OCIO_NAMESPACE;
+
+
+/*!
+ * Iop that uses OpenColorIO to perform colorspace conversions
+ */
+class OCIOColorSpace : public DD::Image::PixelIop {
+
+ protected:
+
+ bool m_hasColorSpaces; //!< Were colorspaces found for both input and output? If not, always error.
+ int m_inputColorSpaceIndex; //!< index of input colorspace selection from the pulldown list knob
+ int m_outputColorSpaceIndex;
+ std::vector<std::string> m_colorSpaceNames; //!< list of input and output colorspace names (memory for const char* s below)
+ std::vector<const char*> m_inputColorSpaceCstrNames; //!< list for the pulldown list knob (used raw)
+ std::vector<const char*> m_outputColorSpaceCstrNames;
+
+ OCIO::ConstContextRcPtr getLocalContext();
+
+ OCIO::ConstProcessorRcPtr m_processor;
+ public:
+
+ OCIOColorSpace(Node *node);
+
+ virtual ~OCIOColorSpace();
+
+ // These are public so the nuke wrapper can introspect into it
+ // TODO: use 'friend' instead
+ std::string m_contextKey1;
+ std::string m_contextValue1;
+ std::string m_contextKey2;
+ std::string m_contextValue2;
+ std::string m_contextKey3;
+ std::string m_contextValue3;
+ std::string m_contextKey4;
+ std::string m_contextValue4;
+
+ static const DD::Image::Op::Description description;
+
+ /*! Return the command name that will be stored in Nuke scripts. */
+ virtual const char *Class() const;
+
+ /*!
+ * Return a name for this class that will be shown to the user. The
+ * default implementation returns Class(). You can return a different
+ * (ie more user-friendly) name instead here, and there is no need for
+ * this to be unique.
+ *
+ * Nuke currently will remove any trailing digits and underscores from
+ * this and add a new number to make a unique name for the new node.
+ *
+ * \return "OCIOColorSpace"
+ */
+ virtual const char *displayName() const;
+
+ /*!
+ * Return help information for this node. This information is in the
+ * pop-up window that the user gets when they hit the [?] button in
+ * the lower-left corner of the control panel.
+ */
+ virtual const char *node_help() const;
+
+ /*!
+ * Define the knobs that will be presented in the control panel.
+ */
+ virtual void knobs(DD::Image::Knob_Callback f);
+
+ /*!
+ * Specify the channels required from input n to produce the channels
+ * in mask by modifying mask in-place. (At least one channel in the
+ * input is assumed.)
+ *
+ * Since colorspace conversions can have channel cross-talk, any rgb
+ * output channel requires all its rgb bretheren. (Non-rgb
+ * are passed through.)
+ */
+ virtual void in_channels(int n, DD::Image::ChannelSet& mask) const;
+
+ /*!
+ * Calculate the output pixel data.
+ * \param rowY vertical line number
+ * \param rowX inclusive left bound
+ * \param rowXBound exclusive right bound
+ * \param outputChannels a subset of out_channels(), the required channels to be produced
+ */
+ virtual void pixel_engine(
+ const DD::Image::Row& in,
+ int rowY, int rowX, int rowXBound,
+ DD::Image::ChannelMask outputChannels,
+ DD::Image::Row& out);
+
+ virtual void append(DD::Image::Hash& hash);
+
+ protected:
+
+ /*!
+ * Check that colorspaces are available, and that the transform
+ * is not a noop. (As OCIO whether a given transform is a noop, since it
+ * can do more analysis than just name matching.)
+ */
+ virtual void _validate(bool for_real);
+
+};
+
+
+static DD::Image::Op* build(Node *node);
+
+#endif // INCLUDED_OCIO_NUKE_COLORSPACECONVERSION_H_
diff --git a/src/nuke/OCIODisplay/OCIODisplay.cpp b/src/nuke/OCIODisplay/OCIODisplay.cpp
new file mode 100644
index 0000000..bf82ab8
--- /dev/null
+++ b/src/nuke/OCIODisplay/OCIODisplay.cpp
@@ -0,0 +1,561 @@
+/**
+ * OpenColorIO Display Iop.
+ */
+
+#include "OCIODisplay.h"
+
+namespace OCIO = OCIO_NAMESPACE;
+
+#include <algorithm>
+#include <string>
+#include <sstream>
+#include <stdexcept>
+
+#include <DDImage/Channel.h>
+#include <DDImage/PixelIop.h>
+#include <DDImage/NukeWrapper.h>
+#include <DDImage/Row.h>
+#include <DDImage/Knobs.h>
+#include <DDImage/Enumeration_KnobI.h>
+#include <DDImage/ddImageVersionNumbers.h>
+
+// Should we use cascasing ColorSpace menus
+#if defined kDDImageVersionInteger && (kDDImageVersionInteger>=62300)
+#define OCIO_CASCADE
+#endif
+
+OCIODisplay::OCIODisplay(Node *n) : DD::Image::PixelIop(n)
+{
+ m_layersToProcess = DD::Image::Mask_RGBA;
+ m_hasLists = false;
+ m_colorSpaceIndex = m_displayIndex = m_viewIndex = 0;
+ m_displayKnob = m_viewKnob = NULL;
+ m_gain = 1.0;
+ m_gamma = 1.0;
+ m_channel = 2;
+ m_transform = OCIO::DisplayTransform::Create();
+
+ try
+ {
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+
+ OCIO::ConstColorSpaceRcPtr defaultcs = config->getColorSpace(OCIO::ROLE_SCENE_LINEAR);
+ if(!defaultcs) throw std::runtime_error("ROLE_SCENE_LINEAR not defined.");
+ std::string defaultColorSpaceName = defaultcs->getName();
+
+ for(int i=0; i<config->getNumColorSpaces(); ++i)
+ {
+ std::string csname = config->getColorSpaceNameByIndex(i);
+
+#ifdef OCIO_CASCADE
+ std::string family = config->getColorSpace(csname.c_str())->getFamily();
+ if(family.empty())
+ m_colorSpaceNames.push_back(csname.c_str());
+ else
+ m_colorSpaceNames.push_back(family + "/" + csname);
+#else
+ m_colorSpaceNames.push_back(csname);
+#endif
+
+ if(defaultColorSpaceName == csname)
+ {
+ m_colorSpaceIndex = i;
+ }
+ }
+
+ std::string defaultDisplay = config->getDefaultDisplay();
+
+ for(int i=0; i<config->getNumDisplays(); ++i)
+ {
+ std::string display = config->getDisplay(i);
+ m_displayNames.push_back(display);
+
+ if(display == defaultDisplay)
+ {
+ m_displayIndex = i;
+ }
+ }
+ }
+ catch(OCIO::Exception& e)
+ {
+ std::cerr << "OCIODisplay: " << e.what() << std::endl;
+ }
+ catch(...)
+ {
+ std::cerr << "OCIODisplay: Unknown exception during OCIO setup." << std::endl;
+ }
+
+ // Build the cstr vectors on our second pass
+ for(unsigned int i=0; i<m_colorSpaceNames.size(); ++i)
+ {
+ m_colorSpaceCstrNames.push_back(m_colorSpaceNames[i].c_str());
+ }
+ m_colorSpaceCstrNames.push_back(NULL);
+
+ for(unsigned int i=0; i<m_displayNames.size(); ++i)
+ {
+ m_displayCstrNames.push_back(m_displayNames[i].c_str());
+ }
+ m_displayCstrNames.push_back(NULL);
+
+ refreshDisplayTransforms();
+
+ m_hasLists = !(m_colorSpaceNames.empty() || m_displayNames.empty() || m_viewNames.empty());
+
+ if(!m_hasLists)
+ {
+ std::cerr << "OCIODisplay: Missing one or more of colorspaces, display devices, or display transforms." << std::endl;
+ }
+}
+
+OCIODisplay::~OCIODisplay()
+{
+
+}
+
+void OCIODisplay::knobs(DD::Image::Knob_Callback f)
+{
+#ifdef OCIO_CASCADE
+ DD::Image::CascadingEnumeration_knob(f,
+ &m_colorSpaceIndex, &m_colorSpaceCstrNames[0], "colorspace", "input colorspace");
+#else
+ DD::Image::Enumeration_knob(f,
+ &m_colorSpaceIndex, &m_colorSpaceCstrNames[0], "colorspace", "input colorspace");
+#endif
+ DD::Image::SetFlags(f, DD::Image::Knob::ALWAYS_SAVE);
+ DD::Image::Tooltip(f, "Input data is taken to be in this colorspace.");
+
+ m_displayKnob = DD::Image::Enumeration_knob(f,
+ &m_displayIndex, &m_displayCstrNames[0], "display", "display device");
+ DD::Image::SetFlags(f, DD::Image::Knob::ALWAYS_SAVE);
+ DD::Image::Tooltip(f, "Display device for output.");
+
+ m_viewKnob = DD::Image::Enumeration_knob(f,
+ &m_viewIndex, &m_viewCstrNames[0], "view", "view transform");
+ DD::Image::SetFlags(f, DD::Image::Knob::ALWAYS_SAVE);
+ DD::Image::Tooltip(f, "Display transform for output.");
+
+ DD::Image::Float_knob(f, &m_gain, DD::Image::IRange(1.0 / 64.0f, 64.0f), "gain");
+ DD::Image::SetFlags(f, DD::Image::Knob::NO_ANIMATION | DD::Image::Knob::NO_UNDO | DD::Image::Knob::LOG_SLIDER);
+ DD::Image::Tooltip(f, "Exposure adjustment, in scene-linear, prior to the display transform.");
+
+ DD::Image::Float_knob(f, &m_gamma, DD::Image::IRange(0, 4), "gamma");
+ DD::Image::SetFlags(f, DD::Image::Knob::NO_ANIMATION | DD::Image::Knob::NO_UNDO | DD::Image::Knob::LOG_SLIDER);
+ DD::Image::Tooltip(f, "Gamma correction applied after the display transform.");
+
+ static const char* const channelvalues[] = {
+ "Luminance",
+ "Matte overlay",
+ "RGB",
+ "R",
+ "G",
+ "B",
+ "A",
+ 0
+ };
+ DD::Image::Enumeration_knob(f, &m_channel, channelvalues, "channel_selector", "channel view");
+ DD::Image::SetFlags(f, DD::Image::Knob::NO_ANIMATION | DD::Image::Knob::NO_UNDO);
+ DD::Image::Tooltip(f, "Specify which channels to view (prior to the display transform).");
+
+ DD::Image::Divider(f);
+
+ DD::Image::Input_ChannelSet_knob(f, &m_layersToProcess, 0, "layer", "layer");
+ // DD::Image::SetFlags(f, DD::Image::Knob::NO_CHECKMARKS | DD::Image::Knob::NO_ALPHA_PULLDOWN);
+ DD::Image::Tooltip(f, "Set which layer to process. This should be a layer with rgb data.");
+
+ DD::Image::Tab_knob(f, "Context");
+ {
+ DD::Image::String_knob(f, &m_contextKey1, "key1");
+ DD::Image::Spacer(f, 10);
+ DD::Image::String_knob(f, &m_contextValue1, "value1");
+ DD::Image::ClearFlags(f, DD::Image::Knob::STARTLINE);
+
+ DD::Image::String_knob(f, &m_contextKey2, "key2");
+ DD::Image::Spacer(f, 10);
+ DD::Image::String_knob(f, &m_contextValue2, "value2");
+ DD::Image::ClearFlags(f, DD::Image::Knob::STARTLINE);
+
+ DD::Image::String_knob(f, &m_contextKey3, "key3");
+ DD::Image::Spacer(f, 10);
+ DD::Image::String_knob(f, &m_contextValue3, "value3");
+ DD::Image::ClearFlags(f, DD::Image::Knob::STARTLINE);
+
+ DD::Image::String_knob(f, &m_contextKey4, "key4");
+ DD::Image::Spacer(f, 10);
+ DD::Image::String_knob(f, &m_contextValue4, "value4");
+ DD::Image::ClearFlags(f, DD::Image::Knob::STARTLINE);
+ }
+}
+
+OCIO::ConstContextRcPtr OCIODisplay::getLocalContext()
+{
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+ OCIO::ConstContextRcPtr context = config->getCurrentContext();
+ OCIO::ContextRcPtr mutableContext;
+
+ if(!m_contextKey1.empty())
+ {
+ if(!mutableContext) mutableContext = context->createEditableCopy();
+ mutableContext->setStringVar(m_contextKey1.c_str(), m_contextValue1.c_str());
+ }
+ if(!m_contextKey2.empty())
+ {
+ if(!mutableContext) mutableContext = context->createEditableCopy();
+ mutableContext->setStringVar(m_contextKey2.c_str(), m_contextValue2.c_str());
+ }
+ if(!m_contextKey3.empty())
+ {
+ if(!mutableContext) mutableContext = context->createEditableCopy();
+ mutableContext->setStringVar(m_contextKey3.c_str(), m_contextValue3.c_str());
+ }
+ if(!m_contextKey4.empty())
+ {
+ if(!mutableContext) mutableContext = context->createEditableCopy();
+ mutableContext->setStringVar(m_contextKey4.c_str(), m_contextValue4.c_str());
+ }
+
+ if(mutableContext) context = mutableContext;
+
+ return context;
+}
+
+void OCIODisplay::append(DD::Image::Hash& localhash)
+{
+ // TODO: Hang onto the context, what if getting it
+ // (and querying getCacheID) is expensive?
+ try
+ {
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+ OCIO::ConstContextRcPtr context = getLocalContext();
+ std::string configCacheID = config->getCacheID(context);
+ localhash.append(configCacheID);
+
+ // This is required due to our custom channel overlay mode post-processing
+ localhash.append(m_channel);
+ }
+ catch(OCIO::Exception &e)
+ {
+ error(e.what());
+ return;
+ }
+}
+
+void OCIODisplay::_validate(bool for_real)
+{
+ input0().validate(for_real);
+
+ if(!m_hasLists)
+ {
+ error("Missing one or more of colorspaces, display devices, or display transforms.");
+ return;
+ }
+
+ int nColorSpaces = static_cast<int>(m_colorSpaceNames.size());
+ if(m_colorSpaceIndex < 0 || m_colorSpaceIndex >= nColorSpaces)
+ {
+ std::ostringstream err;
+ err << "ColorSpace index (" << m_colorSpaceIndex << ") out of range.";
+ error(err.str().c_str());
+ return;
+ }
+
+ try
+ {
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+
+ m_transform->setInputColorSpaceName(config->getColorSpaceNameByIndex(m_colorSpaceIndex));
+ m_transform->setDisplay(m_displayCstrNames[m_displayIndex]);
+ m_transform->setView(m_viewCstrNames[m_viewIndex]);
+
+ // Specify an (optional) linear color correction
+ {
+ float m44[16];
+ float offset4[4];
+
+ const float slope4f[] = { m_gain, m_gain, m_gain, m_gain };
+ OCIO::MatrixTransform::Scale(m44, offset4, slope4f);
+
+ OCIO::MatrixTransformRcPtr mtx = OCIO::MatrixTransform::Create();
+ mtx->setValue(m44, offset4);
+
+ m_transform->setLinearCC(mtx);
+ }
+
+ // Specify an (optional) post-display transform.
+ {
+ float exponent = 1.0f/std::max(1e-6f, m_gamma);
+ const float exponent4f[] = { exponent, exponent, exponent, exponent };
+ OCIO::ExponentTransformRcPtr cc = OCIO::ExponentTransform::Create();
+ cc->setValue(exponent4f);
+ m_transform->setDisplayCC(cc);
+ }
+
+ // Add Channel swizzling
+ {
+ int channelHot[4] = { 0, 0, 0, 0};
+
+ switch(m_channel)
+ {
+ case 0: // Luma
+ channelHot[0] = 1;
+ channelHot[1] = 1;
+ channelHot[2] = 1;
+ break;
+ case 1: // Channel overlay mode. Do rgb, and then swizzle later
+ channelHot[0] = 1;
+ channelHot[1] = 1;
+ channelHot[2] = 1;
+ channelHot[3] = 1;
+ break;
+ case 2: // RGB
+ channelHot[0] = 1;
+ channelHot[1] = 1;
+ channelHot[2] = 1;
+ channelHot[3] = 1;
+ break;
+ case 3: // R
+ channelHot[0] = 1;
+ break;
+ case 4: // G
+ channelHot[1] = 1;
+ break;
+ case 5: // B
+ channelHot[2] = 1;
+ break;
+ case 6: // A
+ channelHot[3] = 1;
+ break;
+ default:
+ break;
+ }
+
+ float lumacoef[3];
+ config->getDefaultLumaCoefs(lumacoef);
+ float m44[16];
+ float offset[4];
+ OCIO::MatrixTransform::View(m44, offset, channelHot, lumacoef);
+ OCIO::MatrixTransformRcPtr swizzle = OCIO::MatrixTransform::Create();
+ swizzle->setValue(m44, offset);
+ m_transform->setChannelView(swizzle);
+ }
+
+ OCIO::ConstContextRcPtr context = getLocalContext();
+ m_processor = config->getProcessor(context,
+ m_transform,
+ OCIO::TRANSFORM_DIR_FORWARD);
+ }
+ catch(OCIO::Exception &e)
+ {
+ error(e.what());
+ return;
+ }
+
+ if(m_processor->isNoOp())
+ {
+ set_out_channels(DD::Image::Mask_None); // prevents engine() from being called
+ } else {
+ set_out_channels(DD::Image::Mask_All);
+ }
+
+ DD::Image::PixelIop::_validate(for_real);
+}
+
+// Note: Same as OCIO ColorSpace::in_channels.
+void OCIODisplay::in_channels(int /* n unused */, DD::Image::ChannelSet& mask) const
+{
+ DD::Image::ChannelSet done;
+ foreach(c, mask)
+ {
+ if ((m_layersToProcess & c) && DD::Image::colourIndex(c) < 4 && !(done & c))
+ {
+ done.addBrothers(c, 4);
+ }
+ }
+ mask += done;
+}
+
+// Note: Same as OCIO ColorSpace::pixel_engine.
+void OCIODisplay::pixel_engine(
+ const DD::Image::Row& in,
+ int /* rowY unused */, int rowX, int rowXBound,
+ DD::Image::ChannelMask outputChannels,
+ DD::Image::Row& out)
+{
+ int rowWidth = rowXBound - rowX;
+
+ DD::Image::ChannelSet done;
+ foreach (requestedChannel, outputChannels)
+ {
+ // Skip channels which had their trios processed already,
+ if (done & requestedChannel)
+ {
+ continue;
+ }
+
+ // Pass through channels which are not selected for processing
+ // and non-rgb channels.
+ if (!(m_layersToProcess & requestedChannel))
+ {
+ out.copy(in, requestedChannel, rowX, rowXBound);
+ continue;
+ }
+
+ DD::Image::Channel rChannel = DD::Image::brother(requestedChannel, 0);
+ DD::Image::Channel gChannel = DD::Image::brother(requestedChannel, 1);
+ DD::Image::Channel bChannel = DD::Image::brother(requestedChannel, 2);
+ DD::Image::Channel aChannel = outputChannels.next(bChannel);
+
+ done += rChannel;
+ done += gChannel;
+ done += bChannel;
+ done += aChannel;
+
+ const float *rIn = in[rChannel] + rowX;
+ const float *gIn = in[gChannel] + rowX;
+ const float *bIn = in[bChannel] + rowX;
+ const float *aIn = in[aChannel] + rowX;
+
+ float *rOut = out.writable(rChannel) + rowX;
+ float *gOut = out.writable(gChannel) + rowX;
+ float *bOut = out.writable(bChannel) + rowX;
+ float *aOut = out.writable(aChannel) + rowX;
+
+ // OCIO modifies in-place
+ // Note: xOut can equal xIn in some circumstances, such as when the
+ // 'Black' (throwaway) scanline is uses. We thus must guard memcpy,
+ // which does not allow for overlapping regions.
+ if (rOut != rIn) memcpy(rOut, rIn, sizeof(float)*rowWidth);
+ if (gOut != gIn) memcpy(gOut, gIn, sizeof(float)*rowWidth);
+ if (bOut != bIn) memcpy(bOut, bIn, sizeof(float)*rowWidth);
+ if (aOut != aIn) memcpy(aOut, aIn, sizeof(float)*rowWidth);
+
+ try
+ {
+ OCIO::PlanarImageDesc img(rOut, gOut, bOut, aOut, rowWidth, /*height*/ 1);
+ m_processor->apply(img);
+ }
+ catch(OCIO::Exception &e)
+ {
+ error(e.what());
+ }
+
+ // Hack to emulate Channel overlay mode
+ if(m_channel == 1)
+ {
+ for(int i=0; i<rowWidth; ++i)
+ {
+ rOut[i] = rOut[i] + (1.0f - rOut[i]) * (0.5f * aOut[i]);
+ gOut[i] = gOut[i] - gOut[i] * (0.5f * aOut[i]);
+ bOut[i] = bOut[i] - bOut[i] * (0.5f * aOut[i]);
+ }
+ }
+ }
+}
+
+void OCIODisplay::refreshDisplayTransforms()
+{
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+
+ if (m_displayIndex < 0 || m_displayIndex >= static_cast<int>(m_displayNames.size()))
+ {
+ std::ostringstream err;
+ err << "No or invalid display specified (index " << m_displayIndex << ").";
+ std::cerr << err.str(); // This can't set an error, as it's called in the constructor
+ return;
+ }
+
+ const char * display = m_displayCstrNames[m_displayIndex];
+ int numViews = config->getNumViews(display);
+ std::string defaultViewName = config->getDefaultView(display);
+
+ // Try to maintain an old transform name, or use the default.
+ bool hasOldViewName = false;
+ std::string oldViewName = "";
+ if (m_viewIndex >= 0 && m_viewIndex < static_cast<int>(m_viewNames.size()))
+ {
+ hasOldViewName = true;
+ oldViewName = m_viewNames[m_viewIndex];
+ }
+ int defaultViewIndex = 0, newViewIndex = -1;
+
+ m_viewCstrNames.clear();
+ m_viewNames.clear();
+
+ for(int i = 0; i < numViews; i++)
+ {
+ std::string view = config->getView(display, i);
+ m_viewNames.push_back(view);
+ if (hasOldViewName && view == oldViewName)
+ {
+ newViewIndex = i;
+ }
+ if (view == defaultViewName)
+ {
+ defaultViewIndex = i;
+ }
+ }
+
+ for(unsigned int i=0; i<m_viewNames.size(); ++i)
+ {
+ m_viewCstrNames.push_back(m_viewNames[i].c_str());
+ }
+ m_viewCstrNames.push_back(NULL);
+
+ if (newViewIndex == -1)
+ {
+ newViewIndex = defaultViewIndex;
+ }
+
+ if (m_viewKnob == NULL)
+ {
+ m_viewIndex = newViewIndex;
+ }
+ else
+ {
+ DD::Image::Enumeration_KnobI *enumKnob = m_viewKnob->enumerationKnob();
+ enumKnob->menu(m_viewNames);
+ m_viewKnob->set_value(newViewIndex);
+ }
+}
+
+int OCIODisplay::knob_changed(DD::Image::Knob *k)
+{
+ if (k == m_displayKnob && m_displayKnob != NULL)
+ {
+ refreshDisplayTransforms();
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+const DD::Image::Op::Description OCIODisplay::description("OCIODisplay", build);
+
+const char* OCIODisplay::Class() const
+{
+ return description.name;
+}
+
+const char* OCIODisplay::displayName() const
+{
+ return description.name;
+}
+
+const char* OCIODisplay::node_help() const
+{
+ // TODO more detailed help text
+ return "Use OpenColorIO to convert for a display device.";
+}
+
+
+DD::Image::Op* build(Node *node)
+{
+ DD::Image::NukeWrapper *op = new DD::Image::NukeWrapper(new OCIODisplay(node));
+ op->noMix();
+ op->noMask();
+ op->noChannels(); // prefer our own channels control without checkboxes / alpha
+ op->noUnpremult();
+ return op;
+}
diff --git a/src/nuke/OCIODisplay/OCIODisplay.h b/src/nuke/OCIODisplay/OCIODisplay.h
new file mode 100644
index 0000000..a4521cf
--- /dev/null
+++ b/src/nuke/OCIODisplay/OCIODisplay.h
@@ -0,0 +1,133 @@
+#ifndef INCLUDED_OCIO_NUKE_DISPLAY_H_
+#define INCLUDED_OCIO_NUKE_DISPLAY_H_
+
+// Include these early, for Nuke's headers under gcc 4.4.2.
+#include <memory>
+#include <cstdarg>
+
+#include <DDImage/PixelIop.h>
+#include <DDImage/Row.h>
+#include <DDImage/Knob.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+namespace OCIO = OCIO_NAMESPACE;
+
+
+/*!
+ * Use OpenColorIO to convert for display output.
+ */
+class OCIODisplay : public DD::Image::PixelIop {
+ protected:
+
+ bool m_hasLists; //!< Were colorspaces, OCIODisplay devices, and transform names found? If not, always error.
+ DD::Image::ChannelSet m_layersToProcess; //!< layers (rgb channel groups) to process
+ int m_colorSpaceIndex; //!< index of colorspace selection from the pulldown list knob
+ int m_displayIndex, m_viewIndex;
+ std::vector<std::string> m_colorSpaceNames; //!< list of colorspace names (memory for const char* s below)
+ std::vector<std::string> m_displayNames, m_viewNames;
+ std::vector<const char*> m_colorSpaceCstrNames; //!< list for the pulldown list knob (used raw)
+ std::vector<const char*> m_displayCstrNames, m_viewCstrNames;
+ float m_gain;
+ float m_gamma;
+ int m_channel;
+
+ std::string m_contextKey1;
+ std::string m_contextValue1;
+ std::string m_contextKey2;
+ std::string m_contextValue2;
+ std::string m_contextKey3;
+ std::string m_contextValue3;
+ std::string m_contextKey4;
+ std::string m_contextValue4;
+ OCIO::ConstContextRcPtr getLocalContext();
+
+ OCIO::DisplayTransformRcPtr m_transform;
+ OCIO::ConstProcessorRcPtr m_processor;
+
+ DD::Image::Knob *m_displayKnob, *m_viewKnob;
+ void refreshDisplayTransforms();
+
+ public:
+
+ OCIODisplay(Node *node);
+
+ virtual ~OCIODisplay();
+
+ static const DD::Image::Op::Description description;
+
+ /*! Return the command name that will be stored in Nuke scripts. */
+ virtual const char *Class() const;
+
+ /*!
+ * Return a name for this class that will be shown to the user. The
+ * default implementation returns Class(). You can return a different
+ * (ie more user-friendly) name instead here, and there is no need for
+ * this to be unique.
+ *
+ * Nuke currently will remove any trailing digits and underscores from
+ * this and add a new number to make a unique name for the new node.
+ *
+ * \return "OCIODisplay"
+ */
+ virtual const char *displayName() const;
+
+ /*!
+ * Return help information for this node. This information is in the
+ * pop-up window that the user gets when they hit the [?] button in
+ * the lower-left corner of the control panel.
+ */
+ virtual const char *node_help() const;
+
+ /*!
+ * Define the knobs that will be presented in the control panel.
+ */
+ virtual void knobs(DD::Image::Knob_Callback f);
+
+ /*!
+ * Specify the channels required from input n to produce the channels
+ * in mask by modifying mask in-place. (At least one channel in the
+ * input is assumed.)
+ *
+ * Since colorspace conversions can have channel cross-talk, any rgb
+ * output channel requires all its rgb bretheren. (Non-rgb
+ * are passed through.)
+ */
+ virtual void in_channels(int n, DD::Image::ChannelSet& mask) const;
+
+ /*!
+ * Calculate the output pixel data.
+ * \param rowY vertical line number
+ * \param rowX inclusive left bound
+ * \param rowXBound exclusive right bound
+ * \param outputChannels a subset of out_channels(), the required channels to be produced
+ */
+ virtual void pixel_engine(
+ const DD::Image::Row& in,
+ int rowY, int rowX, int rowXBound,
+ DD::Image::ChannelMask outputChannels,
+ DD::Image::Row& out);
+
+ /*!
+ * When the display device changes,
+ * regenerate the display transform list.
+ */
+ virtual int knob_changed(DD::Image::Knob *k);
+
+ virtual void append(DD::Image::Hash& hash);
+
+
+ protected:
+
+ /*!
+ * Check that colorspaces are available, and that the transform
+ * is not a noop. (As OCIO whether a given transform is a noop, since it
+ * can do more analysis than just name matching.)
+ */
+ virtual void _validate(bool for_real);
+
+};
+
+
+static DD::Image::Op* build(Node *node);
+
+#endif // INCLUDED_OCIO_NUKE_DISPLAY_H_
diff --git a/src/nuke/OCIOFileTransform/OCIOFileTransform.cpp b/src/nuke/OCIOFileTransform/OCIOFileTransform.cpp
new file mode 100644
index 0000000..ff18f74
--- /dev/null
+++ b/src/nuke/OCIOFileTransform/OCIOFileTransform.cpp
@@ -0,0 +1,287 @@
+/**
+ * OpenColorIO FileTransform Iop.
+ */
+
+#include "OCIOFileTransform.h"
+
+namespace OCIO = OCIO_NAMESPACE;
+
+#include <string>
+#include <sstream>
+#include <stdexcept>
+
+#include <DDImage/Channel.h>
+#include <DDImage/PixelIop.h>
+#include <DDImage/NukeWrapper.h>
+#include <DDImage/Row.h>
+#include <DDImage/Knobs.h>
+
+OCIOFileTransform::OCIOFileTransform(Node *n) : DD::Image::PixelIop(n)
+{
+ m_file = NULL;
+ m_dirindex = 0;
+ m_interpindex = 1;
+ m_reload_version = 1;
+}
+
+OCIOFileTransform::~OCIOFileTransform()
+{
+
+}
+
+const char* OCIOFileTransform::dirs[] = { "forward", "inverse", 0 };
+
+const char* OCIOFileTransform::interp[] = { "nearest", "linear", "tetrahedral", "best", 0 };
+
+void OCIOFileTransform::knobs(DD::Image::Knob_Callback f)
+{
+ File_knob(f, &m_file, "file", "file");
+ DD::Image::Tooltip(f, "Specify the file, on disk, to use for this transform. See the node help for the list of supported formats.");
+
+ // Reload button, and hidden "version" knob to invalidate cache on reload
+ Button(f, "reload", "reload");
+ DD::Image::Tooltip(f, "Reloads specified files");
+ Int_knob(f, &m_reload_version, "version");
+ DD::Image::SetFlags(f, DD::Image::Knob::HIDDEN);
+
+ String_knob(f, &m_cccid, "cccid");
+ const char * srchelp2 = "If the source file is an ASC CDL CCC (color correction collection), "
+ "this specifys the id to lookup. OpenColorIO::Contexts (envvars) are obeyed.";
+ DD::Image::Tooltip(f, srchelp2);
+
+ DD::Image::PyScript_knob(f, "import ocionuke.cdl; ocionuke.cdl.select_cccid_for_filetransform(fileknob='file', cccidknob = 'cccid')", "select_cccid", "select cccid");
+
+ Enumeration_knob(f, &m_dirindex, dirs, "direction", "direction");
+ DD::Image::Tooltip(f, "Specify the transform direction.");
+
+ Enumeration_knob(f, &m_interpindex, interp, "interpolation", "interpolation");
+ DD::Image::Tooltip(f, "Specify the interpolation method. For files that are not LUTs (mtx, etc) this is ignored.");
+}
+
+void OCIOFileTransform::_validate(bool for_real)
+{
+ if(!m_file)
+ {
+ error("The source file must be specified.");
+ return;
+ }
+
+ try
+ {
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+
+ OCIO::FileTransformRcPtr transform = OCIO::FileTransform::Create();
+ transform->setSrc(m_file);
+
+ transform->setCCCId(m_cccid.c_str());
+
+ if(m_dirindex == 0) transform->setDirection(OCIO::TRANSFORM_DIR_FORWARD);
+ else transform->setDirection(OCIO::TRANSFORM_DIR_INVERSE);
+
+ if(m_interpindex == 0) transform->setInterpolation(OCIO::INTERP_NEAREST);
+ else if(m_interpindex == 1) transform->setInterpolation(OCIO::INTERP_LINEAR);
+ else if(m_interpindex == 2) transform->setInterpolation(OCIO::INTERP_TETRAHEDRAL);
+ else if(m_interpindex == 3) transform->setInterpolation(OCIO::INTERP_BEST);
+ else
+ {
+ // Should never happen
+ error("Interpolation value out of bounds");
+ return;
+ }
+
+ m_processor = config->getProcessor(transform, OCIO::TRANSFORM_DIR_FORWARD);
+ }
+ catch(OCIO::Exception &e)
+ {
+ error(e.what());
+ return;
+ }
+
+ if(m_processor->isNoOp())
+ {
+ set_out_channels(DD::Image::Mask_None); // prevents engine() from being called
+ } else {
+ set_out_channels(DD::Image::Mask_All);
+ }
+
+ DD::Image::PixelIop::_validate(for_real);
+}
+
+// Note that this is copied by others (OCIODisplay)
+void OCIOFileTransform::in_channels(int /* n unused */, DD::Image::ChannelSet& mask) const
+{
+ DD::Image::ChannelSet done;
+ foreach(c, mask)
+ {
+ if (DD::Image::colourIndex(c) < 3 && !(done & c))
+ {
+ done.addBrothers(c, 3);
+ }
+ }
+ mask += done;
+}
+
+void OCIOFileTransform::append(DD::Image::Hash& nodehash)
+{
+ // There is a bug where in Nuke <6.3 the String_knob (used for
+ // cccid) is not included in the node's hash. Include it manually
+ // so the node correctly redraws. Appears fixed in in 6.3
+ nodehash.append(m_cccid.c_str());
+
+ // Incremented to force reloading after rereading the LUT file
+ nodehash.append(m_reload_version);
+}
+
+int OCIOFileTransform::knob_changed(DD::Image::Knob* k)
+{
+ // Only show the cccid knob when loading a .cc/.ccc file. Set
+ // hidden state when the src is changed, or the node properties
+ // are shown
+ if(k->is("file") | k->is("showPanel"))
+ {
+ // Convoluted equiv to pysting::endswith(m_file, ".ccc")
+ // TODO: Could this be queried from the processor?
+ const std::string srcstring = m_file;
+ const std::string cccext = "ccc";
+ const std::string ccext = "cc";
+ if(std::equal(cccext.rbegin(), cccext.rend(), srcstring.rbegin()) ||
+ std::equal(ccext.rbegin(), ccext.rend(), srcstring.rbegin()))
+ {
+ knob("cccid")->show();
+ knob("select_cccid")->show();
+ }
+ else
+ {
+ knob("cccid")->hide();
+ knob("select_cccid")->hide();
+ }
+
+ // Ensure this callback is always triggered (for src knob)
+ return true;
+ }
+
+ if(k->is("reload"))
+ {
+ knob("version")->set_value(m_reload_version+1);
+ OCIO::ClearAllCaches();
+
+ return true; // ensure callback is triggered again
+ }
+
+ // Return zero to avoid callbacks for other knobs
+ return false;
+}
+
+// See Saturation::pixel_engine for a well-commented example.
+// Note that this is copied by others (OCIODisplay)
+void OCIOFileTransform::pixel_engine(
+ const DD::Image::Row& in,
+ int /* rowY unused */, int rowX, int rowXBound,
+ DD::Image::ChannelMask outputChannels,
+ DD::Image::Row& out)
+{
+ int rowWidth = rowXBound - rowX;
+
+ DD::Image::ChannelSet done;
+ foreach (requestedChannel, outputChannels)
+ {
+ // Skip channels which had their trios processed already,
+ if (done & requestedChannel)
+ {
+ continue;
+ }
+
+ // Pass through channels which are not selected for processing
+ // and non-rgb channels.
+ if (colourIndex(requestedChannel) >= 3)
+ {
+ out.copy(in, requestedChannel, rowX, rowXBound);
+ continue;
+ }
+
+ DD::Image::Channel rChannel = DD::Image::brother(requestedChannel, 0);
+ DD::Image::Channel gChannel = DD::Image::brother(requestedChannel, 1);
+ DD::Image::Channel bChannel = DD::Image::brother(requestedChannel, 2);
+
+ done += rChannel;
+ done += gChannel;
+ done += bChannel;
+
+ const float *rIn = in[rChannel] + rowX;
+ const float *gIn = in[gChannel] + rowX;
+ const float *bIn = in[bChannel] + rowX;
+
+ float *rOut = out.writable(rChannel) + rowX;
+ float *gOut = out.writable(gChannel) + rowX;
+ float *bOut = out.writable(bChannel) + rowX;
+
+ // OCIO modifies in-place
+ // Note: xOut can equal xIn in some circumstances, such as when the
+ // 'Black' (throwaway) scanline is uses. We thus must guard memcpy,
+ // which does not allow for overlapping regions.
+ if (rOut != rIn) memcpy(rOut, rIn, sizeof(float)*rowWidth);
+ if (gOut != gIn) memcpy(gOut, gIn, sizeof(float)*rowWidth);
+ if (bOut != bIn) memcpy(bOut, bIn, sizeof(float)*rowWidth);
+
+ try
+ {
+ OCIO::PlanarImageDesc img(rOut, gOut, bOut, NULL, rowWidth, /*height*/ 1);
+ m_processor->apply(img);
+ }
+ catch(OCIO::Exception &e)
+ {
+ error(e.what());
+ }
+ }
+}
+
+const DD::Image::Op::Description OCIOFileTransform::description("OCIOFileTransform", build);
+
+const char* OCIOFileTransform::Class() const
+{
+ return description.name;
+}
+
+const char* OCIOFileTransform::displayName() const
+{
+ return description.name;
+}
+
+const char* OCIOFileTransform::node_help() const
+{
+ if(m_nodehelp.empty())
+ {
+ const char * helptext =
+ "Use OpenColorIO to apply a transform loaded from the given "
+ "file.\n\n"
+ "This is usually a 1D or 3D LUT file, but can be other file-based "
+ "transform, for example an ASC ColorCorrection XML file.\n\n"
+ "Note that the file's transform is applied with no special "
+ "input/output colorspace handling - so if the file expects "
+ "log-encoded pixels, but you apply the node to a linear "
+ "image, you will get incorrect results.\n\n";
+
+ std::ostringstream os;
+ os << helptext;
+
+ os << "Supported formats:\n";
+ for(int i=0; i<OCIO::FileTransform::getNumFormats(); ++i)
+ {
+ const char* name = OCIO::FileTransform::getFormatNameByIndex(i);
+ const char* exten = OCIO::FileTransform::getFormatExtensionByIndex(i);
+ os << "\n." << exten << " (" << name << ")";
+ }
+
+ m_nodehelp = os.str();
+ }
+
+ return m_nodehelp.c_str();
+}
+
+
+DD::Image::Op* build(Node *node)
+{
+ DD::Image::NukeWrapper *op = new DD::Image::NukeWrapper(new OCIOFileTransform(node));
+ op->channels(DD::Image::Mask_RGB);
+ return op;
+}
diff --git a/src/nuke/OCIOFileTransform/OCIOFileTransform.h b/src/nuke/OCIOFileTransform/OCIOFileTransform.h
new file mode 100644
index 0000000..0a848c5
--- /dev/null
+++ b/src/nuke/OCIOFileTransform/OCIOFileTransform.h
@@ -0,0 +1,128 @@
+#ifndef INCLUDED_OCIO_NUKE_FILETRANSFORM_H_
+#define INCLUDED_OCIO_NUKE_FILETRANSFORM_H_
+
+// Include these early, for Nuke's headers under gcc 4.4.2.
+#include <memory>
+#include <cstdarg>
+
+#include <DDImage/PixelIop.h>
+#include <DDImage/Row.h>
+#include <DDImage/Knob.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+namespace OCIO = OCIO_NAMESPACE;
+
+
+/*!
+ * Iop that uses OpenColorIO to perform colorspace conversions
+ */
+class OCIOFileTransform : public DD::Image::PixelIop {
+
+ protected:
+ const char* m_file;
+ std::string m_cccid;
+
+ /*! Transform direction dropdown index */
+ int m_dirindex;
+
+ /*! Interpolation dropdown index */
+ int m_interpindex;
+
+ /*! Processor used to apply the FileTransform */
+ OCIO::ConstProcessorRcPtr m_processor;
+
+ /*! Holds computed help string */
+ mutable std::string m_nodehelp;
+
+ /*! Controlled by hidden "version" knob, incremented to redraw image */
+ int m_reload_version;
+
+ public:
+ static const char* dirs[];
+ static const char* interp[];
+
+ OCIOFileTransform(Node *node);
+
+ virtual ~OCIOFileTransform();
+
+ static const DD::Image::Op::Description description;
+
+ /*! Return the command name that will be stored in Nuke scripts. */
+ virtual const char *Class() const;
+
+ /*!
+ * Return a name for this class that will be shown to the user. The
+ * default implementation returns Class(). You can return a different
+ * (ie more user-friendly) name instead here, and there is no need for
+ * this to be unique.
+ *
+ * Nuke currently will remove any trailing digits and underscores from
+ * this and add a new number to make a unique name for the new node.
+ *
+ * \return "OCIOFileTransform"
+ */
+ virtual const char *displayName() const;
+
+ /*!
+ * Return help information for this node. This information is in the
+ * pop-up window that the user gets when they hit the [?] button in
+ * the lower-left corner of the control panel.
+ */
+ virtual const char *node_help() const;
+
+ /*!
+ * Define the knobs that will be presented in the control panel.
+ */
+ virtual void knobs(DD::Image::Knob_Callback f);
+
+ /*!
+ * Specify the channels required from input n to produce the channels
+ * in mask by modifying mask in-place. (At least one channel in the
+ * input is assumed.)
+ *
+ * Since OCIOFileTransform conversions can have channel cross-talk, any rgb
+ * output channel requires all its rgb bretheren. (Non-rgb
+ * are passed through.)
+ */
+ virtual void in_channels(int n, DD::Image::ChannelSet& mask) const;
+
+ /*!
+ * Calculate the output pixel data.
+ * \param rowY vertical line number
+ * \param rowX inclusive left bound
+ * \param rowXBound exclusive right bound
+ * \param outputChannels a subset of out_channels(), the required channels to be produced
+ */
+ virtual void pixel_engine(
+ const DD::Image::Row& in,
+ int rowY, int rowX, int rowXBound,
+ DD::Image::ChannelMask outputChannels,
+ DD::Image::Row& out);
+
+
+ protected:
+
+ /*!
+ * Check that colorspaces are available, and that the transform
+ * is not a noop. (As OCIO whether a given transform is a noop, since it
+ * can do more analysis than just name matching.)
+ */
+ virtual void _validate(bool for_real);
+
+ /*!
+ * Ensure Node hash is reflects all parameters
+ */
+ virtual void append(DD::Image::Hash& nodehash);
+
+ /*!
+ * Hide and show UI elements based on other parameters.
+ Also handles reload button
+ */
+ virtual int knob_changed(DD::Image::Knob* k);
+
+};
+
+
+static DD::Image::Op* build(Node *node);
+
+#endif // INCLUDED_OCIO_NUKE_FILETRANSFORM_H_
diff --git a/src/nuke/OCIOLogConvert/OCIOLogConvert.cpp b/src/nuke/OCIOLogConvert/OCIOLogConvert.cpp
new file mode 100644
index 0000000..521847f
--- /dev/null
+++ b/src/nuke/OCIOLogConvert/OCIOLogConvert.cpp
@@ -0,0 +1,179 @@
+/**
+ * OpenColorIO LogConvert Iop.
+ */
+
+#include "OCIOLogConvert.h"
+
+namespace OCIO = OCIO_NAMESPACE;
+
+#include <string>
+#include <sstream>
+#include <stdexcept>
+
+#include <DDImage/Channel.h>
+#include <DDImage/PixelIop.h>
+#include <DDImage/NukeWrapper.h>
+#include <DDImage/Row.h>
+#include <DDImage/Knobs.h>
+
+const char* OCIOLogConvert::modes[] = {
+ "log to lin", "lin to log", 0
+};
+
+OCIOLogConvert::OCIOLogConvert(Node *n) : DD::Image::PixelIop(n)
+{
+ modeindex = 0;
+}
+
+OCIOLogConvert::~OCIOLogConvert()
+{
+
+}
+
+void OCIOLogConvert::knobs(DD::Image::Knob_Callback f)
+{
+
+ Enumeration_knob(f, &modeindex, modes, "operation", "operation");
+ DD::Image::SetFlags(f, DD::Image::Knob::ALWAYS_SAVE);
+}
+
+void OCIOLogConvert::_validate(bool for_real)
+{
+ try
+ {
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+
+ const char * src = 0;
+ const char * dst = 0;
+
+ if(modeindex == 0)
+ {
+ src = OCIO::ROLE_COMPOSITING_LOG;
+ dst = OCIO::ROLE_SCENE_LINEAR;
+ }
+ else
+ {
+ src = OCIO::ROLE_SCENE_LINEAR;
+ dst = OCIO::ROLE_COMPOSITING_LOG;
+ }
+
+ processor = config->getProcessor(src, dst);
+ }
+ catch(OCIO::Exception &e)
+ {
+ error(e.what());
+ return;
+ }
+
+ if(processor->isNoOp())
+ {
+ set_out_channels(DD::Image::Mask_None); // prevents engine() from being called
+ } else {
+ set_out_channels(DD::Image::Mask_All);
+ }
+
+ DD::Image::PixelIop::_validate(for_real);
+}
+
+// Note that this is copied by others (OCIODisplay)
+void OCIOLogConvert::in_channels(int /* n unused */, DD::Image::ChannelSet& mask) const
+{
+ DD::Image::ChannelSet done;
+ foreach(c, mask)
+ {
+ if (DD::Image::colourIndex(c) < 3 && !(done & c))
+ {
+ done.addBrothers(c, 3);
+ }
+ }
+ mask += done;
+}
+
+// See Saturation::pixel_engine for a well-commented example.
+// Note that this is copied by others (OCIODisplay)
+void OCIOLogConvert::pixel_engine(
+ const DD::Image::Row& in,
+ int /* rowY unused */, int rowX, int rowXBound,
+ DD::Image::ChannelMask outputChannels,
+ DD::Image::Row& out)
+{
+ int rowWidth = rowXBound - rowX;
+
+ DD::Image::ChannelSet done;
+ foreach (requestedChannel, outputChannels)
+ {
+ // Skip channels which had their trios processed already,
+ if (done & requestedChannel)
+ {
+ continue;
+ }
+
+ // Pass through channels which are not selected for processing
+ // and non-rgb channels.
+ if (colourIndex(requestedChannel) >= 3)
+ {
+ out.copy(in, requestedChannel, rowX, rowXBound);
+ continue;
+ }
+
+ DD::Image::Channel rChannel = DD::Image::brother(requestedChannel, 0);
+ DD::Image::Channel gChannel = DD::Image::brother(requestedChannel, 1);
+ DD::Image::Channel bChannel = DD::Image::brother(requestedChannel, 2);
+
+ done += rChannel;
+ done += gChannel;
+ done += bChannel;
+
+ const float *rIn = in[rChannel] + rowX;
+ const float *gIn = in[gChannel] + rowX;
+ const float *bIn = in[bChannel] + rowX;
+
+ float *rOut = out.writable(rChannel) + rowX;
+ float *gOut = out.writable(gChannel) + rowX;
+ float *bOut = out.writable(bChannel) + rowX;
+
+ // OCIO modifies in-place
+ // Note: xOut can equal xIn in some circumstances, such as when the
+ // 'Black' (throwaway) scanline is uses. We thus must guard memcpy,
+ // which does not allow for overlapping regions.
+ if (rOut != rIn) memcpy(rOut, rIn, sizeof(float)*rowWidth);
+ if (gOut != gIn) memcpy(gOut, gIn, sizeof(float)*rowWidth);
+ if (bOut != bIn) memcpy(bOut, bIn, sizeof(float)*rowWidth);
+
+ try
+ {
+ OCIO::PlanarImageDesc img(rOut, gOut, bOut, NULL, rowWidth, /*height*/ 1);
+ processor->apply(img);
+ }
+ catch(OCIO::Exception &e)
+ {
+ error(e.what());
+ }
+ }
+}
+
+const DD::Image::Op::Description OCIOLogConvert::description("OCIOLogConvert", build);
+
+const char* OCIOLogConvert::Class() const
+{
+ return description.name;
+}
+
+const char* OCIOLogConvert::displayName() const
+{
+ return description.name;
+}
+
+const char* OCIOLogConvert::node_help() const
+{
+ // TODO more detailed help text
+ return "Use OpenColorIO to convert from SCENE_LINEAR to COMPOSITING_LOG (or back).";
+}
+
+
+DD::Image::Op* build(Node *node)
+{
+ DD::Image::NukeWrapper *op = new DD::Image::NukeWrapper(new OCIOLogConvert(node));
+ op->channels(DD::Image::Mask_RGB);
+ return op;
+}
diff --git a/src/nuke/OCIOLogConvert/OCIOLogConvert.h b/src/nuke/OCIOLogConvert/OCIOLogConvert.h
new file mode 100644
index 0000000..0ce6aa8
--- /dev/null
+++ b/src/nuke/OCIOLogConvert/OCIOLogConvert.h
@@ -0,0 +1,101 @@
+#ifndef INCLUDED_OCIO_NUKE_LOGCONVERT_H_
+#define INCLUDED_OCIO_NUKE_LOGCONVERT_H_
+
+// Include these early, for Nuke's headers under gcc 4.4.2.
+#include <memory>
+#include <cstdarg>
+
+#include <DDImage/PixelIop.h>
+#include <DDImage/Row.h>
+#include <DDImage/Knob.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+namespace OCIO = OCIO_NAMESPACE;
+
+
+/*!
+ * Iop that uses OpenColorIO to perform colorspace conversions
+ */
+class OCIOLogConvert : public DD::Image::PixelIop {
+
+ protected:
+ int modeindex;
+
+ OCIO::ConstProcessorRcPtr processor;
+ public:
+ static const char* modes[];
+
+ OCIOLogConvert(Node *node);
+
+ virtual ~OCIOLogConvert();
+
+ static const DD::Image::Op::Description description;
+
+ /*! Return the command name that will be stored in Nuke scripts. */
+ virtual const char *Class() const;
+
+ /*!
+ * Return a name for this class that will be shown to the user. The
+ * default implementation returns Class(). You can return a different
+ * (ie more user-friendly) name instead here, and there is no need for
+ * this to be unique.
+ *
+ * Nuke currently will remove any trailing digits and underscores from
+ * this and add a new number to make a unique name for the new node.
+ *
+ * \return "OCIOLogConvert"
+ */
+ virtual const char *displayName() const;
+
+ /*!
+ * Return help information for this node. This information is in the
+ * pop-up window that the user gets when they hit the [?] button in
+ * the lower-left corner of the control panel.
+ */
+ virtual const char *node_help() const;
+
+ /*!
+ * Define the knobs that will be presented in the control panel.
+ */
+ virtual void knobs(DD::Image::Knob_Callback f);
+
+ /*!
+ * Specify the channels required from input n to produce the channels
+ * in mask by modifying mask in-place. (At least one channel in the
+ * input is assumed.)
+ *
+ * Since OCIOLogConvert conversions can have channel cross-talk, any rgb
+ * output channel requires all its rgb bretheren. (Non-rgb
+ * are passed through.)
+ */
+ virtual void in_channels(int n, DD::Image::ChannelSet& mask) const;
+
+ /*!
+ * Calculate the output pixel data.
+ * \param rowY vertical line number
+ * \param rowX inclusive left bound
+ * \param rowXBound exclusive right bound
+ * \param outputChannels a subset of out_channels(), the required channels to be produced
+ */
+ virtual void pixel_engine(
+ const DD::Image::Row& in,
+ int rowY, int rowX, int rowXBound,
+ DD::Image::ChannelMask outputChannels,
+ DD::Image::Row& out);
+
+
+ protected:
+
+ /*!
+ * Check that colorspaces are available, and that the transform
+ * is not a noop. (As OCIO whether a given transform is a noop, since it
+ * can do more analysis than just name matching.)
+ */
+ virtual void _validate(bool for_real);
+
+};
+
+
+static DD::Image::Op* build(Node *node);
+
+#endif // INCLUDED_OCIO_NUKE_LOGCONVERT_H_
diff --git a/src/nuke/OCIOLookTransform/OCIOLookTransform.cpp b/src/nuke/OCIOLookTransform/OCIOLookTransform.cpp
new file mode 100644
index 0000000..9dfac56
--- /dev/null
+++ b/src/nuke/OCIOLookTransform/OCIOLookTransform.cpp
@@ -0,0 +1,533 @@
+/**
+ * OpenColorIO ColorSpace Iop.
+ */
+
+#include "OCIOLookTransform.h"
+
+namespace OCIO = OCIO_NAMESPACE;
+
+#include <string>
+#include <sstream>
+#include <stdexcept>
+
+#include <DDImage/Channel.h>
+#include <DDImage/PixelIop.h>
+#include <DDImage/NukeWrapper.h>
+#include <DDImage/Row.h>
+#include <DDImage/Knobs.h>
+#include <DDImage/ddImageVersionNumbers.h>
+
+// Should we use cascasing ColorSpace menus
+#if defined kDDImageVersionInteger && (kDDImageVersionInteger>=62300)
+#define OCIO_CASCADE
+#endif
+
+OCIOLookTransform::OCIOLookTransform(Node *n) : DD::Image::PixelIop(n)
+{
+ m_hasColorSpaces = false;
+
+ m_inputColorSpaceIndex = 0;
+ m_outputColorSpaceIndex = 0;
+ m_dirIndex = 0;
+ m_ignoreErrors = false;
+ m_reload_version = 1;
+
+ // Query the colorspace names from the current config
+ // TODO (when to) re-grab the list of available colorspaces? How to save/load?
+
+ OCIO::ConstConfigRcPtr config;
+ std::string linear;
+
+ try
+ {
+ config = OCIO::GetCurrentConfig();
+
+ OCIO::ConstColorSpaceRcPtr linearcs = config->getColorSpace(OCIO::ROLE_SCENE_LINEAR);
+ if(!linearcs) throw std::runtime_error("ROLE_SCENE_LINEAR not defined.");
+ linear = linearcs->getName();
+
+ if(config->getNumLooks()>0)
+ {
+ m_look = config->getLookNameByIndex(0);
+ }
+
+ std::ostringstream os;
+ os << "Specify the look(s) to apply, as predefined in the OpenColorIO ";
+ os << "configuration. This may be the name of a single look, or a ";
+ os << "combination of looks using the 'look syntax' (outlined below)\n\n";
+
+ std::string firstlook = "a";
+ std::string secondlook = "b";
+ if(config->getNumLooks()>0)
+ {
+ os << "Looks: ";
+ for(int i = 0; i<config->getNumLooks(); ++i)
+ {
+ if(i!=0) os << ", ";
+ const char * lookname = config->getLookNameByIndex(i);
+ os << lookname;
+ if(i==0) firstlook = lookname;
+ if(i==1) secondlook = lookname;
+ }
+ os << "\n\n";
+ }
+ else
+ {
+ os << "NO LOOKS DEFINED -- ";
+ os << "This node cannot be used until looks are added to the OCIO Configuration. ";
+ os << "See opencolorio.org for examples.\n\n";
+ }
+
+ os << "Look Syntax:\n";
+ os << "Multiple looks are combined with commas: '";
+ os << firstlook << ", " << secondlook << "'\n";
+ os << "Direction is specified with +/- prefixes: '";
+ os << "+" << firstlook << ", -" << secondlook << "'\n";
+ os << "Missing look 'fallbacks' specified with |: '";
+ os << firstlook << ", -" << secondlook << " | -" << secondlook << "'";
+ m_lookhelp = os.str();
+ }
+ catch (const OCIO::Exception& e)
+ {
+ std::cerr << "OCIOLookTransform: " << e.what() << std::endl;
+ }
+ catch (...)
+ {
+ std::cerr << "OCIOLookTransform: Unknown exception during OCIO setup." << std::endl;
+ }
+
+ if(!config)
+ {
+ m_hasColorSpaces = false;
+ return;
+ }
+
+ for(int i = 0; i < config->getNumColorSpaces(); i++)
+ {
+ std::string csname = config->getColorSpaceNameByIndex(i);
+
+#ifdef OCIO_CASCADE
+ std::string family = config->getColorSpace(csname.c_str())->getFamily();
+ if(family.empty())
+ m_colorSpaceNames.push_back(csname.c_str());
+ else
+ m_colorSpaceNames.push_back(family + "/" + csname);
+#else
+ m_colorSpaceNames.push_back(csname);
+#endif
+ if(csname == linear)
+ {
+ m_inputColorSpaceIndex = i;
+ m_outputColorSpaceIndex = i;
+ }
+ }
+
+
+ // Step 2: Create a cstr array for passing to Nuke
+ // (This must be done in a second pass, lest the original strings be reallocated)
+
+ for(unsigned int i=0; i<m_colorSpaceNames.size(); ++i)
+ {
+ m_inputColorSpaceCstrNames.push_back(m_colorSpaceNames[i].c_str());
+ m_outputColorSpaceCstrNames.push_back(m_colorSpaceNames[i].c_str());
+ }
+
+ m_inputColorSpaceCstrNames.push_back(NULL);
+ m_outputColorSpaceCstrNames.push_back(NULL);
+
+ m_hasColorSpaces = (!m_colorSpaceNames.empty());
+
+ if(!m_hasColorSpaces)
+ {
+ std::cerr << "OCIOLookTransform: No ColorSpaces available for input and/or output." << std::endl;
+ }
+}
+
+OCIOLookTransform::~OCIOLookTransform()
+{
+
+}
+
+namespace
+{
+ static const char * directions[] = { "forward", "inverse", 0 };
+}
+
+void OCIOLookTransform::knobs(DD::Image::Knob_Callback f)
+{
+#ifdef OCIO_CASCADE
+ DD::Image::CascadingEnumeration_knob(f,
+ &m_inputColorSpaceIndex, &m_inputColorSpaceCstrNames[0], "in_colorspace", "in");
+#else
+ DD::Image::Enumeration_knob(f,
+ &m_inputColorSpaceIndex, &m_inputColorSpaceCstrNames[0], "in_colorspace", "in");
+#endif
+ DD::Image::SetFlags(f, DD::Image::Knob::ALWAYS_SAVE);
+ DD::Image::Tooltip(f, "Input data is taken to be in this colorspace.");
+
+ DD::Image::String_knob(f, &m_look, "look");
+ DD::Image::Tooltip(f, m_lookhelp.c_str());
+ DD::Image::SetFlags(f, DD::Image::Knob::ALWAYS_SAVE);
+
+ DD::Image::Spacer(f, 8);
+
+ Enumeration_knob(f, &m_dirIndex, directions, "direction", "direction");
+ DD::Image::Tooltip(f, "Specify the look transform direction. in/out colorspace handling is not affected.");
+ DD::Image::ClearFlags(f, DD::Image::Knob::STARTLINE );
+
+ // Reload button, and hidden "version" knob to invalidate cache on reload
+ DD::Image::Spacer(f, 8);
+
+ Button(f, "reload", "reload");
+ DD::Image::Tooltip(f, "Reload all files used in the underlying Look(s).");
+ Int_knob(f, &m_reload_version, "version");
+ DD::Image::SetFlags(f, DD::Image::Knob::HIDDEN);
+
+#ifdef OCIO_CASCADE
+ DD::Image::CascadingEnumeration_knob(f,
+ &m_outputColorSpaceIndex, &m_outputColorSpaceCstrNames[0], "out_colorspace", "out");
+#else
+ DD::Image::Enumeration_knob(f,
+ &m_outputColorSpaceIndex, &m_outputColorSpaceCstrNames[0], "out_colorspace", "out");
+#endif
+ DD::Image::SetFlags(f, DD::Image::Knob::ALWAYS_SAVE);
+ DD::Image::Tooltip(f, "Image data is converted to this colorspace for output.");
+
+
+ DD::Image::Bool_knob(f, &m_ignoreErrors, "ignore_errors", "ignore errors");
+ DD::Image::Tooltip(f, "If enabled, looks that cannot find the specified correction"
+ " are treated as a normal ColorSpace conversion instead of triggering a render error.");
+ DD::Image::SetFlags(f, DD::Image::Knob::STARTLINE );
+
+}
+
+OCIO::ConstContextRcPtr OCIOLookTransform::getLocalContext()
+{
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+ OCIO::ConstContextRcPtr context = config->getCurrentContext();
+ OCIO::ContextRcPtr mutableContext;
+
+ if(!m_contextKey1.empty())
+ {
+ if(!mutableContext) mutableContext = context->createEditableCopy();
+ mutableContext->setStringVar(m_contextKey1.c_str(), m_contextValue1.c_str());
+ }
+ if(!m_contextKey2.empty())
+ {
+ if(!mutableContext) mutableContext = context->createEditableCopy();
+ mutableContext->setStringVar(m_contextKey2.c_str(), m_contextValue2.c_str());
+ }
+ if(!m_contextKey3.empty())
+ {
+ if(!mutableContext) mutableContext = context->createEditableCopy();
+ mutableContext->setStringVar(m_contextKey3.c_str(), m_contextValue3.c_str());
+ }
+ if(!m_contextKey4.empty())
+ {
+ if(!mutableContext) mutableContext = context->createEditableCopy();
+ mutableContext->setStringVar(m_contextKey4.c_str(), m_contextValue4.c_str());
+ }
+
+ if(mutableContext) context = mutableContext;
+ return context;
+}
+
+void OCIOLookTransform::append(DD::Image::Hash& nodehash)
+{
+ // Incremented to force reloading after rereading the LUT file
+ nodehash.append(m_reload_version);
+
+ // TODO: Hang onto the context, what if getting it
+ // (and querying getCacheID) is expensive?
+ try
+ {
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+ OCIO::ConstContextRcPtr context = getLocalContext();
+ std::string configCacheID = config->getCacheID(context);
+ nodehash.append(configCacheID);
+ }
+ catch(const OCIO::Exception &e)
+ {
+ error(e.what());
+ }
+ catch (...)
+ {
+ error("OCIOLookTransform: Unknown exception during hash generation.");
+ }
+}
+
+
+int OCIOLookTransform::knob_changed(DD::Image::Knob* k)
+{
+ if(k->is("reload"))
+ {
+ knob("version")->set_value(m_reload_version+1);
+ OCIO::ClearAllCaches();
+
+ return true; // ensure callback is triggered again
+ }
+
+ // Return zero to avoid callbacks for other knobs
+ return false;
+}
+
+
+void OCIOLookTransform::_validate(bool for_real)
+{
+ if(!m_hasColorSpaces)
+ {
+ error("No colorspaces available for input and/or output.");
+ return;
+ }
+
+ int inputColorSpaceCount = static_cast<int>(m_inputColorSpaceCstrNames.size()) - 1;
+ if(m_inputColorSpaceIndex < 0 || m_inputColorSpaceIndex >= inputColorSpaceCount)
+ {
+ std::ostringstream err;
+ err << "Input colorspace index (" << m_inputColorSpaceIndex << ") out of range.";
+ error(err.str().c_str());
+ return;
+ }
+
+ int outputColorSpaceCount = static_cast<int>(m_outputColorSpaceCstrNames.size()) - 1;
+ if(m_outputColorSpaceIndex < 0 || m_outputColorSpaceIndex >= outputColorSpaceCount)
+ {
+ std::ostringstream err;
+ err << "Output colorspace index (" << m_outputColorSpaceIndex << ") out of range.";
+ error(err.str().c_str());
+ return;
+ }
+
+ try
+ {
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+
+ const char * inputName = config->getColorSpaceNameByIndex(m_inputColorSpaceIndex);
+ const char * outputName = config->getColorSpaceNameByIndex(m_outputColorSpaceIndex);
+
+ OCIO::LookTransformRcPtr transform = OCIO::LookTransform::Create();
+ transform->setLooks(m_look.c_str());
+
+ OCIO::ConstContextRcPtr context = getLocalContext();
+ OCIO::TransformDirection direction = OCIO::TRANSFORM_DIR_UNKNOWN;
+ bool invertTransform = (m_dirIndex == 0) ? false : true;
+
+ // Forward
+ if(!invertTransform)
+ {
+ transform->setSrc(inputName);
+ transform->setDst(outputName);
+ direction = OCIO::TRANSFORM_DIR_FORWARD;
+ }
+ else
+ {
+ // The TRANSFORM_DIR_INVERSE applies an inverse for the end-to-end transform,
+ // which would otherwise do dst->inv look -> src.
+ // This is an unintuitive result for the artist (who would expect in, out to
+ // remain unchanged), so we account for that here by flipping src/dst
+
+ transform->setSrc(outputName);
+ transform->setDst(inputName);
+ direction = OCIO::TRANSFORM_DIR_INVERSE;
+ }
+
+ try
+ {
+ m_processor = config->getProcessor(context, transform, direction);
+ }
+ // We only catch the exceptions for missing files, and try to succeed
+ // in this case. All other errors represent more serious problems and
+ // should fail through.
+ catch(const OCIO::ExceptionMissingFile &e)
+ {
+ if(!m_ignoreErrors) throw;
+ m_processor = config->getProcessor(context, inputName, outputName);
+ }
+ }
+ catch(const OCIO::Exception &e)
+ {
+ error(e.what());
+ return;
+ }
+ catch (...)
+ {
+ error("OCIOLookTransform: Unknown exception during _validate.");
+ return;
+ }
+
+ if(m_processor->isNoOp())
+ {
+ set_out_channels(DD::Image::Mask_None); // prevents engine() from being called
+ } else {
+ set_out_channels(DD::Image::Mask_All);
+ }
+
+ DD::Image::PixelIop::_validate(for_real);
+}
+
+// Note that this is copied by others (OCIODisplay)
+void OCIOLookTransform::in_channels(int /* n unused */, DD::Image::ChannelSet& mask) const
+{
+ DD::Image::ChannelSet done;
+ foreach(c, mask)
+ {
+ if (DD::Image::colourIndex(c) < 3 && !(done & c))
+ {
+ done.addBrothers(c, 3);
+ }
+ }
+ mask += done;
+}
+
+// See Saturation::pixel_engine for a well-commented example.
+// Note that this is copied by others (OCIODisplay)
+void OCIOLookTransform::pixel_engine(
+ const DD::Image::Row& in,
+ int /* rowY unused */, int rowX, int rowXBound,
+ DD::Image::ChannelMask outputChannels,
+ DD::Image::Row& out)
+{
+ int rowWidth = rowXBound - rowX;
+
+ DD::Image::ChannelSet done;
+ foreach (requestedChannel, outputChannels)
+ {
+ // Skip channels which had their trios processed already,
+ if (done & requestedChannel)
+ {
+ continue;
+ }
+
+ // Pass through channels which are not selected for processing
+ // and non-rgb channels.
+ if (colourIndex(requestedChannel) >= 3)
+ {
+ out.copy(in, requestedChannel, rowX, rowXBound);
+ continue;
+ }
+
+ DD::Image::Channel rChannel = DD::Image::brother(requestedChannel, 0);
+ DD::Image::Channel gChannel = DD::Image::brother(requestedChannel, 1);
+ DD::Image::Channel bChannel = DD::Image::brother(requestedChannel, 2);
+
+ done += rChannel;
+ done += gChannel;
+ done += bChannel;
+
+ const float *rIn = in[rChannel] + rowX;
+ const float *gIn = in[gChannel] + rowX;
+ const float *bIn = in[bChannel] + rowX;
+
+ float *rOut = out.writable(rChannel) + rowX;
+ float *gOut = out.writable(gChannel) + rowX;
+ float *bOut = out.writable(bChannel) + rowX;
+
+ // OCIO modifies in-place
+ // Note: xOut can equal xIn in some circumstances, such as when the
+ // 'Black' (throwaway) scanline is uses. We thus must guard memcpy,
+ // which does not allow for overlapping regions.
+ if (rOut != rIn) memcpy(rOut, rIn, sizeof(float)*rowWidth);
+ if (gOut != gIn) memcpy(gOut, gIn, sizeof(float)*rowWidth);
+ if (bOut != bIn) memcpy(bOut, bIn, sizeof(float)*rowWidth);
+
+ try
+ {
+ OCIO::PlanarImageDesc img(rOut, gOut, bOut, NULL, rowWidth, /*height*/ 1);
+ m_processor->apply(img);
+ }
+ catch(const OCIO::Exception &e)
+ {
+ error(e.what());
+ }
+ catch (...)
+ {
+ error("OCIOLookTransform: Unknown exception during pixel_engine.");
+ }
+ }
+}
+
+const DD::Image::Op::Description OCIOLookTransform::description("OCIOLookTransform", build);
+
+const char* OCIOLookTransform::Class() const
+{
+ return description.name;
+}
+
+const char* OCIOLookTransform::displayName() const
+{
+ return description.name;
+}
+
+const char* OCIOLookTransform::node_help() const
+{
+ static const char * help = "OpenColorIO LookTransform\n\n"
+ "A 'look' is a named color transform, intended to modify the look of an "
+ "image in a 'creative' manner (as opposed to a colorspace definion which "
+ "tends to be technically/mathematically defined).\n\n"
+ "Examples of looks may be a neutral grade, to be applied to film scans "
+ "prior to VFX work, or a per-shot DI grade decided on by the director, "
+ "to be applied just before the viewing transform.\n\n"
+ "OCIOLooks must be predefined in the OpenColorIO configuration before usage, "
+ "and often reference per-shot/sequence LUTs/CCs.\n\n"
+ "See the look knob for further syntax details.\n\n"
+ "See opencolorio.org for look configuration customization examples.";
+ return help;
+}
+
+// This class is necessary in order to call knobsAtTheEnd(). Otherwise, the NukeWrapper knobs
+// will be added to the Context tab instead of the primary tab.
+class OCIOLookTransformNukeWrapper : public DD::Image::NukeWrapper
+{
+public:
+ OCIOLookTransformNukeWrapper(DD::Image::PixelIop* op) : DD::Image::NukeWrapper(op)
+ {
+ }
+
+ virtual void attach()
+ {
+ wrapped_iop()->attach();
+ }
+
+ virtual void detach()
+ {
+ wrapped_iop()->detach();
+ }
+
+ virtual void knobs(DD::Image::Knob_Callback f)
+ {
+ OCIOLookTransform* lookIop = dynamic_cast<OCIOLookTransform*>(wrapped_iop());
+ if(!lookIop) return;
+
+ DD::Image::NukeWrapper::knobs(f);
+
+ DD::Image::Tab_knob(f, "Context");
+ {
+ DD::Image::String_knob(f, &lookIop->m_contextKey1, "key1");
+ DD::Image::Spacer(f, 10);
+ DD::Image::String_knob(f, &lookIop->m_contextValue1, "value1");
+ DD::Image::ClearFlags(f, DD::Image::Knob::STARTLINE);
+
+ DD::Image::String_knob(f, &lookIop->m_contextKey2, "key2");
+ DD::Image::Spacer(f, 10);
+ DD::Image::String_knob(f, &lookIop->m_contextValue2, "value2");
+ DD::Image::ClearFlags(f, DD::Image::Knob::STARTLINE);
+
+ DD::Image::String_knob(f, &lookIop->m_contextKey3, "key3");
+ DD::Image::Spacer(f, 10);
+ DD::Image::String_knob(f, &lookIop->m_contextValue3, "value3");
+ DD::Image::ClearFlags(f, DD::Image::Knob::STARTLINE);
+
+ DD::Image::String_knob(f, &lookIop->m_contextKey4, "key4");
+ DD::Image::Spacer(f, 10);
+ DD::Image::String_knob(f, &lookIop->m_contextValue4, "value4");
+ DD::Image::ClearFlags(f, DD::Image::Knob::STARTLINE);
+ }
+ }
+};
+
+static DD::Image::Op* build(Node *node)
+{
+ DD::Image::NukeWrapper *op = (new OCIOLookTransformNukeWrapper(new OCIOLookTransform(node)));
+ op->channels(DD::Image::Mask_RGB);
+ return op;
+}
diff --git a/src/nuke/OCIOLookTransform/OCIOLookTransform.h b/src/nuke/OCIOLookTransform/OCIOLookTransform.h
new file mode 100644
index 0000000..9526bfa
--- /dev/null
+++ b/src/nuke/OCIOLookTransform/OCIOLookTransform.h
@@ -0,0 +1,140 @@
+#ifndef INCLUDED_OCIO_NUKE_COLORSPACECONVERSION_H_
+#define INCLUDED_OCIO_NUKE_COLORSPACECONVERSION_H_
+
+// Include these early, for Nuke's headers under gcc 4.4.2.
+#include <memory>
+#include <cstdarg>
+
+#include <DDImage/PixelIop.h>
+#include <DDImage/Row.h>
+#include <DDImage/Knob.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+namespace OCIO = OCIO_NAMESPACE;
+
+
+/*!
+ * Iop that uses OpenColorIO to perform colorspace conversions
+ */
+class OCIOLookTransform : public DD::Image::PixelIop {
+
+ protected:
+
+ bool m_hasColorSpaces; //!< Were colorspaces found for both input and output? If not, always error.
+
+ std::string m_look;
+ std::string m_lookhelp;
+
+ int m_dirIndex;
+ int m_inputColorSpaceIndex;
+ int m_outputColorSpaceIndex;
+
+ std::vector<std::string> m_colorSpaceNames; //!< list of input and output colorspace names (memory for const char* s below)
+ std::vector<const char*> m_inputColorSpaceCstrNames; //!< list for the pulldown list knob (used raw)
+ std::vector<const char*> m_outputColorSpaceCstrNames;
+
+ bool m_ignoreErrors;
+
+ OCIO::ConstContextRcPtr getLocalContext();
+
+ OCIO::ConstProcessorRcPtr m_processor;
+
+ /*! Controlled by hidden "version" knob, incremented to redraw image */
+ int m_reload_version;
+ public:
+
+ OCIOLookTransform(Node *node);
+
+ virtual ~OCIOLookTransform();
+
+ // These are public so the nuke wrapper can introspect into it
+ // TODO: use 'friend' instead
+ std::string m_contextKey1;
+ std::string m_contextValue1;
+ std::string m_contextKey2;
+ std::string m_contextValue2;
+ std::string m_contextKey3;
+ std::string m_contextValue3;
+ std::string m_contextKey4;
+ std::string m_contextValue4;
+
+ static const DD::Image::Op::Description description;
+
+ /*! Return the command name that will be stored in Nuke scripts. */
+ virtual const char *Class() const;
+
+ /*!
+ * Return a name for this class that will be shown to the user. The
+ * default implementation returns Class(). You can return a different
+ * (ie more user-friendly) name instead here, and there is no need for
+ * this to be unique.
+ *
+ * Nuke currently will remove any trailing digits and underscores from
+ * this and add a new number to make a unique name for the new node.
+ *
+ * \return "OCIOLookTransform"
+ */
+ virtual const char *displayName() const;
+
+ /*!
+ * Return help information for this node. This information is in the
+ * pop-up window that the user gets when they hit the [?] button in
+ * the lower-left corner of the control panel.
+ */
+ virtual const char *node_help() const;
+
+ /*!
+ * Define the knobs that will be presented in the control panel.
+ */
+ virtual void knobs(DD::Image::Knob_Callback f);
+
+ /*!
+ * Specify the channels required from input n to produce the channels
+ * in mask by modifying mask in-place. (At least one channel in the
+ * input is assumed.)
+ *
+ * Since colorspace conversions can have channel cross-talk, any rgb
+ * output channel requires all its rgb bretheren. (Non-rgb
+ * are passed through.)
+ */
+ virtual void in_channels(int n, DD::Image::ChannelSet& mask) const;
+
+ /*!
+ * Calculate the output pixel data.
+ * \param rowY vertical line number
+ * \param rowX inclusive left bound
+ * \param rowXBound exclusive right bound
+ * \param outputChannels a subset of out_channels(), the required channels to be produced
+ */
+ virtual void pixel_engine(
+ const DD::Image::Row& in,
+ int rowY, int rowX, int rowXBound,
+ DD::Image::ChannelMask outputChannels,
+ DD::Image::Row& out);
+
+ protected:
+
+ /*!
+ * Check that colorspaces are available, and that the transform
+ * is not a noop. (As OCIO whether a given transform is a noop, since it
+ * can do more analysis than just name matching.)
+ */
+ virtual void _validate(bool for_real);
+
+ /*!
+ * Ensure Node hash is reflects all parameters
+ */
+ virtual void append(DD::Image::Hash& nodehash);
+
+ /*!
+ * Hide and show UI elements based on other parameters.
+ Also handles reload button
+ */
+ virtual int knob_changed(DD::Image::Knob* k);
+
+};
+
+
+static DD::Image::Op* build(Node *node);
+
+#endif // INCLUDED_OCIO_NUKE_COLORSPACECONVERSION_H_
diff --git a/src/pyglue/CMakeLists.txt b/src/pyglue/CMakeLists.txt
new file mode 100644
index 0000000..07188ea
--- /dev/null
+++ b/src/pyglue/CMakeLists.txt
@@ -0,0 +1,106 @@
+if(CMAKE_FIRST_RUN)
+ message(STATUS "Python library to include 'lib' prefix: ${OCIO_PYGLUE_LIB_PREFIX}")
+endif()
+
+if(CMAKE_FIRST_RUN)
+ message(STATUS "Python ${PYTHON_VERSION} okay (UCS: ${PYTHON_UCS}), will build the Python bindings against ${PYTHON_INCLUDE}")
+ message(STATUS "Python variant path is ${PYTHON_VARIANT_PATH}")
+endif()
+
+if(CMAKE_COMPILER_IS_GNUCXX)
+ # Python breaks strict-aliasing rules. Disable the warning here.
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-strict-aliasing")
+endif()
+
+if(NOT WIN32)
+ find_package(PythonLibs)
+ if(NOT PYTHONLIBS_FOUND)
+ message(FATAL "Python libraries were not found, exiting.")
+ endif()
+ SET(PYTHON_INCLUDES ${PYTHON_INCLUDE_DIRS})
+endif()
+
+add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/src/pyglue/PyDoc.h
+ COMMAND ${PYTHON} ${CMAKE_SOURCE_DIR}/src/pyglue/createPyDocH.py ${CMAKE_BINARY_DIR}/src/pyglue/PyDoc.h
+ COMMENT "Creating PyDoc.h")
+
+file( GLOB pyglue_src_files "${CMAKE_SOURCE_DIR}/src/pyglue/*.cpp" )
+
+add_library(PyOpenColorIO MODULE ${pyglue_src_files} ${CMAKE_BINARY_DIR}/src/pyglue/PyDoc.h)
+
+if(OCIO_USE_BOOST_PTR)
+ include_directories(
+ ${PYTHON_INCLUDE}
+ ${Boost_INCLUDE_DIR}
+ ${CMAKE_SOURCE_DIR}/export/
+ ${CMAKE_BINARY_DIR}/export/
+ ${CMAKE_CURRENT_BINARY_DIR}
+ )
+else()
+ include_directories(
+ ${PYTHON_INCLUDE}
+ ${CMAKE_SOURCE_DIR}/export/
+ ${CMAKE_BINARY_DIR}/export/
+ ${CMAKE_CURRENT_BINARY_DIR}
+ )
+endif()
+
+# Exclude the 'lib' prefix from the name.
+if(NOT OCIO_PYGLUE_LIB_PREFIX)
+ set_property(TARGET PyOpenColorIO
+ PROPERTY PREFIX ""
+ )
+endif()
+
+if(WIN32)
+ if(OCIO_PYGLUE_LINK)
+ target_link_libraries(PyOpenColorIO OpenColorIO
+ debug ${PYTHON_LIB}/python26_d.lib
+ optimized ${PYTHON_LIB}/python26.lib)
+ else()
+ target_link_libraries(PyOpenColorIO OpenColorIO)
+ endif(OCIO_PYGLUE_LINK)
+else()
+ if(OCIO_PYGLUE_LINK)
+ message(STATUS "Linking python bindings against: ${PYTHON_LIBRARY}")
+ message(STATUS "Python library dirs: ${PYTHON_LIBRARY_DIRS}")
+ link_directories(${PYTHON_LIBRARY})
+ target_link_libraries(PyOpenColorIO OpenColorIO
+ ${PYTHON_LIBRARIES})
+ else()
+ target_link_libraries(PyOpenColorIO OpenColorIO)
+ endif(OCIO_PYGLUE_LINK)
+endif()
+
+# PyOpenColorIO so serves dual roles:
+# - First, to provide the C API function necessary to act as a cpython module,
+# (extern "C" PyMODINIT_FUNC initPyOpenColorIO(void)
+# - Second, to act as a normal shared library, providing the C++ API functions
+# to convert between C++ and python representation of the OCIO object.
+#
+# To fulfill this second role, as a shared libary, we must continue to define
+# so version.
+#
+# TODO: This wont let the normal shared library symbols work on OSX.
+# We should explore whether this should be built as a normal dylib, instead
+# of as a bundle. See https://github.com/imageworks/OpenColorIO/pull/175
+
+if(OCIO_PYGLUE_SONAME)
+ message(STATUS "Setting PyOCIO SOVERSION to: ${SOVERSION}")
+ set_target_properties(PyOpenColorIO PROPERTIES
+ VERSION ${OCIO_VERSION}
+ SOVERSION ${SOVERSION}
+ )
+endif()
+
+if(APPLE)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -undefined dynamic_lookup")
+endif()
+
+
+message("PYTHON_VARIANT_PATH: ${PYTHON_VARIANT_PATH}")
+
+install(TARGETS PyOpenColorIO DESTINATION ${CMAKE_INSTALL_EXEC_PREFIX}/${PYTHON_VARIANT_PATH})
+
+install(FILES ${CMAKE_SOURCE_DIR}/export/PyOpenColorIO/PyOpenColorIO.h
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/include/PyOpenColorIO/)
diff --git a/src/pyglue/DocStrings/AllocationTransform.py b/src/pyglue/DocStrings/AllocationTransform.py
new file mode 100644
index 0000000..26bdaa2
--- /dev/null
+++ b/src/pyglue/DocStrings/AllocationTransform.py
@@ -0,0 +1,54 @@
+
+class AllocationTransform:
+ """
+ Respans the 'expanded' range into the specified (often compressed) range.
+
+ Performs both squeeze (offset) and log transforms.
+ """
+ def __init__(self):
+ pass
+
+ def getAllocation(self):
+ """
+ getAllocation()
+
+ Returns the allocation specified in the transform. Allocation is an
+ enum, defined in Constants.
+
+ :return: Allocation
+ :rtype: string
+ """
+ pass
+
+ def setAllocation(self, hwalloc):
+ """
+ setAllocation(hwalloc)
+
+ Sets the allocation of the transform.
+
+ :param hwalloc: Allocation
+ :type hwalloc: object
+ """
+ pass
+
+ def getVars(self):
+ """
+ getVars()
+
+ Returns the allocation values specified in the transform.
+
+ :return: allocation values
+ :rtype: list of floats
+ """
+ pass
+
+ def setVars(self, vars):
+ """
+ setVars(pyvars)
+
+ Sets the allocation in the transform.
+
+ :param pyvars: list of floats
+ :type pyvars: object
+ """
+ pass
diff --git a/src/pyglue/DocStrings/CDLTransform.py b/src/pyglue/DocStrings/CDLTransform.py
new file mode 100644
index 0000000..63acbd2
--- /dev/null
+++ b/src/pyglue/DocStrings/CDLTransform.py
@@ -0,0 +1,141 @@
+
+class CDLTransform:
+ """
+ CDLTransform
+ """
+ def __init__(self):
+ pass
+
+ def equals(self):
+ pass
+
+ def getXML(self):
+ pass
+
+ def setXML(self, xmltext):
+ pass
+
+ def getSlope(self):
+ pass
+
+ def getOffset(self):
+ pass
+
+ def getPower(self):
+ pass
+
+ def getSOP(self):
+ pass
+
+ def getSat(self):
+ pass
+
+ def setSlope(self, slope):
+ """
+ setSlope(pyData)
+
+ Sets the slope ('S' part of SOP) in :py:class:`PyOpenColorIO.CDLTransform`.
+
+ :param pyData:
+ :type pyData: object
+ """
+ pass
+
+ def setOffset(self, offset):
+ """
+ setOffset(pyData)
+
+ Sets the offset ('O' part of SOP) in :py:class:`PyOpenColorIO.CDLTransform`.
+
+ :param pyData: list of three floats
+ :type pyData: object
+ """
+ pass
+
+ def setPower(self, power):
+ """
+ setPower(pyData)
+
+ Sets the power ('P' part of SOP) in :py:class:`PyOpenColorIO.CDLTransform`.
+
+ :param pyData: list of three floats
+ :type pyData: object
+ """
+ pass
+
+ def setSOP(self, sop):
+ """
+ setSOP(pyData)
+
+ Sets SOP in :py:class:`PyOpenColorIO.CDLTransform`.
+
+ :param pyData: list of nine floats
+ :type pyData: object
+ """
+ pass
+
+ def setSat(self, sat):
+ """
+ setSAT(pyData)
+
+ Sets SAT (saturation) in :py:class:`PyOpenColorIO.CDLTransform`.
+
+ :param pyData: saturation
+ :type pyData: float
+ """
+ pass
+
+ def getSatLumaCoefs(self):
+ """
+ getSatLumaCoefs(pyData)
+
+ Returns the SAT (saturation) and luma coefficients in :py:class:`CDLTransform`.
+
+ :return: saturation and luma coefficients
+ :rtype: list of floats
+ """
+ pass
+
+ def getID(self):
+ """
+ getID()
+
+ Returns the ID from :py:class:`PyOpenColorIO.CDLTransform`.
+
+ :return: ID
+ :rtype: string
+ """
+ pass
+
+ def setID(self, id):
+ """
+ setID(str)
+
+ Sets the ID in :py:class:`PyOpenColorIO.CDLTransform`.
+
+ :param str: ID
+ :type str: string
+ """
+ pass
+
+ def getDescription(self):
+ """
+ getDescription()
+
+ Returns the description of :py:class:`PyOpenColorIO.CDLTransform`.
+
+ :return: description
+ :rtype: string
+ """
+ pass
+
+ def setDescription(self, desc):
+ """
+ setDescription(str)
+
+ Sets the description of :py:class:`PyOpenColorIO.CDLTransform`.
+
+ :param str: description
+ :type str: string
+ """
+ pass
diff --git a/src/pyglue/DocStrings/ColorSpace.py b/src/pyglue/DocStrings/ColorSpace.py
new file mode 100644
index 0000000..caf351b
--- /dev/null
+++ b/src/pyglue/DocStrings/ColorSpace.py
@@ -0,0 +1,103 @@
+
+class ColorSpace:
+ """
+ A color space is the state of an image in terms of colorimetry and color
+ encoding. I.e., it defines how an image's color information needs to be
+ interpreted.
+
+ Transforming images between different color spaces is the primary
+ motivation for the OCIO library.
+
+ While a complete discussion of color spaces is beyond the scope of this
+ documentation, traditional uses would be to have color spaces describing
+ image capture devices, such as cameras and scanners, and internal
+ 'convenience' spaces, such as scene-linear and logarithmic.
+
+ Color spaces are specific to a particular image precision
+ (float32, uint8, etc.). The set of color spaces that provide equivalent
+ mappings (at different precisions) are referred to as a 'family'.
+
+ .. code-block:: python
+
+ import PyOpenColorIO as OCIO
+ config = OCIO.Config()
+
+ """
+ def __init__(self):
+ pass
+
+ def isEditable(self):
+ pass
+
+ def createEditableCopy(self):
+ pass
+
+ def getName(self):
+ pass
+
+ def setName(self, name):
+ pass
+
+ def getFamily(self):
+ pass
+
+ def setFamily(self, family):
+ pass
+
+ def getEqualityGroup(self):
+ pass
+
+ def setEqualityGroup(self, equalityGroup):
+ pass
+
+ def getDescription(self):
+ pass
+
+ def setDescription(self, desc):
+ pass
+
+ def getBitDepth(self):
+ pass
+
+ def setBitDepth(self, bitDepth):
+ pass
+
+ def isData(self):
+ """
+ ColorSpaces that are data are treated a bit special. Basically, any
+ colorspace transforms you try to apply to them are ignored. (Think
+ of applying a gamut mapping transform to an ID pass). Also, the
+ :py:class:`PyOpenColorIO.DisplayTransform` process obeys special
+ 'data min' and 'data max' args.
+
+ This is traditionally used for pixel data that represents non-color
+ pixel data, such as normals, point positions, ID information, etc.
+ """
+ pass
+
+ def setIsData(self, isData):
+ pass
+
+ def getAllocation(self):
+ """
+ If this colorspace needs to be transferred to a limited dynamic
+ range coding space (such as during display with a GPU path), use this
+ allocation to maximize bit efficiency.
+ """
+ pass
+
+ def setAllocation(self, allocation):
+ pass
+
+ def getAllocationVars(self):
+ pass
+
+ def setAllocationVars(self, vars):
+ pass
+
+ def getTransform(self):
+ pass
+
+ def setTransform(self, transform, direction):
+ pass
+
diff --git a/src/pyglue/DocStrings/ColorSpaceTransform.py b/src/pyglue/DocStrings/ColorSpaceTransform.py
new file mode 100644
index 0000000..a4de30b
--- /dev/null
+++ b/src/pyglue/DocStrings/ColorSpaceTransform.py
@@ -0,0 +1,51 @@
+
+class ColorSpaceTransform:
+ """
+ ColorSpaceTransform
+ """
+ def __init__(self):
+ pass
+
+ def getSrc(self):
+ """
+ getSrc()
+
+ Returns the name of the source ColorSpace in this transform.
+
+ :return: ColorSpace
+ :rtype: string
+ """
+ pass
+
+ def setSrc(self, srcname):
+ """
+ setSrc(srcname)
+
+ Sets the source ColorSpace in this transform.
+
+ :param str: source ColorSpace
+ :type str: string
+ """
+ pass
+
+ def getDst(self):
+ """
+ getDst()
+
+ Returns the name of the destination ColorSpace in this transform.
+
+ :return: ColorSpace
+ :rtype: string
+ """
+ pass
+
+ def setDst(self, dstname):
+ """
+ setDst(dstname)
+
+ Sets the destination ColorSpace in this transform.
+
+ :param str: destination ColorSpace
+ :type str: string
+ """
+ pass
diff --git a/src/pyglue/DocStrings/Config.py b/src/pyglue/DocStrings/Config.py
new file mode 100644
index 0000000..688e822
--- /dev/null
+++ b/src/pyglue/DocStrings/Config.py
@@ -0,0 +1,527 @@
+
+class Config:
+ """
+ Config
+ """
+
+ def __init__(self):
+ pass
+
+ def CreateFromEnv(self):
+ """
+ CreateFromEnv()
+
+ Create a :py:class:`PyOpenColorIO.Config` object using the environment variable.
+
+ :returns: Config object
+ """
+ pass
+
+ def CreateFromFile(self):
+ """
+ CreateFromFile(filename)
+
+ Create a :py:class:`PyOpenColorIO.Config` object using the information in a file.
+
+ :param filename: name of file
+ :type filename: string
+ :return: Config object
+ """
+ pass
+
+ def isEditable(self):
+ """
+ isEditable()
+
+ Returns whether Config is editable.
+
+ The configurations returned from
+ :py:function:`PyOpenColorIO.GetCurrentConfig` are not editable, and if
+ you want to edit them you can use
+ :py:method:`PyOpenColorIO.Config.createEditableCopy`.
+
+ If you attempt to call any of the set functions on a noneditable
+ Config, an exception will be thrown.
+
+ :return: state of :py:class:`PyOpenColorIO.Config`'s editability
+ :rtype: bool
+ """
+ pass
+
+ def createEditableCopy(self):
+ """
+ createEditableCopy()
+
+ Returns an editable copy of :py:class:`PyOpenColorIO.Config`.
+
+ :return: editable copy of :py:class:`PyOpenColorIO.Config`
+ :rtype: Config object
+ """
+ pass
+
+ def sanityCheck(self):
+ """
+ sanityCheck()
+
+ This will throw an exception if :py:class:`PyOpenColorIO.Config` is
+ malformed. The most common error occurs when references are made to
+ colorspaces that do not exist.
+ """
+ pass
+
+ def getDescription(self):
+ """
+ getDescription()
+
+ Returns the stored description of :py:class:`PyOpenColorIO.Config`.
+
+ :return: stored description of :py:class:`PyOpenColorIO.Config`
+ :rtype: string
+ """
+ pass
+
+ def setDescription(self, desc):
+ """
+ setDescription(desc)
+
+ Sets the description of :py:class:`PyOpenColorIO.Config`.
+
+ :param desc: description of :py:class:`PyOpenColorIO.Config`
+ :type desc: string
+ """
+ pass
+
+ def serialize(self):
+ """
+ serialize()
+
+ Returns the string representation of :py:class:`PyOpenColorIO.Config`
+ in YAML text form. This is typically stored on disk in a file with the
+ .ocio extension.
+
+ :return: :py:class:`PyOpenColorIO.Config` in YAML text form
+ :rtype: string
+ """
+ pass
+
+ def getCacheID(self, pycontext=None):
+ """
+ getCacheID([, pycontext])
+
+ This will produce a hash of the all colorspace definitions, etc.
+
+ All external references, such as files used in FileTransforms, etc.,
+ will be incorporated into the cacheID. While the contents of the files
+ are not read, the file system is queried for relavent information
+ (mtime, inode) so that the :py:class:`PyOpenColorIO.Config`'s cacheID
+ will change when the underlying luts are updated.
+
+ If a context is not provided, the current Context will be used. If a
+ null context is provided, file references will not be taken into
+ account (this is essentially a hash of :py:method:`PyOpenColorIO.Config.serialize`).
+
+ :param pycontext: optional
+ :type pycontext: object
+ :return: hash of :py:class:`PyOpenColorIO.Config`
+ :rtype: string
+ """
+ pass
+
+ def getCurrentContext(self):
+ """
+ getCurrentContext()
+
+ Return the current context, which is essentially a record of all
+ the environment variables that are available for use in file path
+ lookups.
+
+ :return: context
+ :rtype: pycontext
+ """
+ pass
+
+ def getSearchPath(self):
+ """
+ getSearchPath()
+
+ Returns the search path.
+
+ :return: search path
+ :rtype: string
+ """
+ pass
+
+ def setSearchPath(self, searchpath):
+ """
+ setSearchPath(path)
+
+ Sets the search path.
+
+ :param path: the search path
+ :type path: string
+ """
+ pass
+
+ def getWorkingDir(self):
+ """
+ getWorkingDir()
+
+ Returns the working directory.
+
+ :return: the working directory
+ :rtype path: string
+ """
+ pass
+
+ def setWorkingDir(self, dirname):
+ """
+ setWorkingDir(path)
+
+ Sets the working directory.
+
+ :param path: the working directory
+ :type path: string
+ """
+ pass
+
+ def getColorSpaces(self):
+ """
+ getColorSpaces()
+
+ Returns all the ColorSpaces defined in :py:class:`Config`.
+
+ :return: ColorSpaces in :py:class:`PyOpenColorIO.Config`
+ :rtype: tuple
+ """
+ pass
+
+ def getColorSpace(self, name):
+ """
+ getColorSpace(name)
+
+ Returns the data for the specified color space in :py:class:`Config`.
+
+ This will return null if the specified name is not found.
+
+ :param name: name of color space
+ :type name: string
+ :return: data for specified color space
+ :rtype: pyColorSpace object
+ """
+ pass
+
+ def addColorSpace(self, colorSpace):
+ """
+ addColorSpace(pyColorSpace)
+
+ Add a specified color space to :py:class:`PyOpenColorIO.Config`.
+
+ :param pyColorSpace: color space
+ :type pyColorSpace: object
+
+ .. note::
+ If another color space is already registered with the same name,
+ this will overwrite it.
+ """
+ pass
+
+ def clearColorSpaces(self):
+ """
+ clearColorSpaces()
+
+ Clear the color spaces in :py:class:`PyOpenColorIO.Config`.
+ """
+ pass
+
+ def parseColorSpaceFromString(self, str):
+ """
+ parseColorSpaceFromString(str)
+
+ Parses out the color space from a string.
+
+ Given the specified string, gets the longest, right-most color space substring.
+ * If strict parsing is enabled, and no color space is found, return an empty string.
+ * If strict parsing is disabled, return the default role, if defined.
+ * If the default role is not defined, return an empty string.
+
+ :param str: ColorSpace data
+ :type str: string
+ :return: parsed data
+ :rtype: string
+ """
+ pass
+
+ def setRole(self, role, csname):
+ """
+ setRole(role, csname)
+
+ Set a role's ColorSpace.
+
+ Setting the colorSpaceName name to a null string unsets it.
+
+ :param role: role whose ColorSpace will be set
+ :type role: string
+ :param csname: name of ColorSpace
+ :type csname: string
+ """
+ pass
+
+ def getDefaultDisplay(self):
+ """
+ getDefaultDisplay()
+
+ Returns the default display set in :py:class:`PyOpenColorIO.Config`.
+
+ :return: default display
+ :rtype: string
+ """
+ pass
+
+ def getDisplays(self):
+ """
+ getDisplays()
+
+ Returns all the displays defined in :py:class:`PyOpenColorIO.Config`.
+
+ :return: displays in :py:class:`Config`
+ :rtype: list of strings
+ """
+ pass
+
+ def getDefaultView(self, display):
+ """
+ getDefaultView(display)
+
+ Returns the default view of :py:class:`PyOpenColorIO.Config`.
+
+ :param display: default view
+ :type display: string
+ :return: view
+ :rtype: string
+ """
+ pass
+
+ def getViews(self, display):
+ """
+ getViews(display)
+
+ Returns all the views defined in :py:class:`PyOpenColorIO.Config`.
+
+ :param display: views in :py:class:`Config`
+ :type display: string
+ :return: views in :py:class:`Config`.
+ :rtype: list of strings
+ """
+ pass
+
+ def getDisplayColorSpaceName(self, display, view):
+ """
+ getDisplayColorSpaceName(display, view)
+
+ Returns the ColorSpace name corresponding to the display and view
+ combination in :py:class:`PyOpenColorIO.Config`.
+
+ :param display: display
+ :type display: string
+ :param view: view
+ :type view: string
+ :return: display color space name
+ :rtype: string
+ """
+ pass
+
+ def getDisplayLooks(self, display, view):
+ """
+ getDisplayLooks(display, view)
+
+ Returns the looks corresponding to the display and view combination in
+ :py:class:`PyOpenColorIO.Config`.
+
+ :param display: display
+ :type display: string
+ :param view: view
+ :type view: string
+ :return: looks
+ :rtype: string
+ """
+ pass
+
+ def addDisplay(self, display, view, csname, looks=None):
+ """
+ addDisplay(display, view, colorSpaceName[, looks])
+
+ NEEDS WORK
+
+ :param display:
+ :type display: string
+ :param view:
+ :type view: string
+ :param colorSpaceName:
+ :type colorSpaceName: string
+ :param looks: optional
+ :type looks: string
+ """
+ pass
+
+ def clearDisplays(self):
+ """
+ clearDisplays()
+ """
+ pass
+
+ def setActiveDisplays(self, dislpays):
+ """
+ setActiveDisplays(displays)
+
+ Sets the active displays in :py:class:`PyOpenColorIO.Config`.
+
+ :param displays: active displays
+ :type displays: string
+ """
+ pass
+
+ def getActiveDisplays(self):
+ """
+ getActiveDisplays()
+
+ Returns the active displays in :py:class:`PyOpenColorIO.Config`.
+
+ :return: active displays
+ :rtype: string
+ """
+ pass
+
+ def setActiveViews(self, views):
+ """
+ setActiveViews(views)
+
+ Sets the active views in :py:class:`PyOpenColorIO.Config`.
+
+ :param views: active views
+ :type views: string
+ """
+ pass
+
+ def getActiveViews(self):
+ """
+ getActiveViews()
+
+ Returns the active views in :py:class:`PyOpenColorIO.Config`.
+
+ :return: active views
+ :rtype: string
+ """
+ pass
+
+ def getDefaultLumaCoefs(self):
+ """
+ getDefaultLumaCoefs()
+
+ Returns the default luma coefficients in :py:class:`PyOpenColorIO.Config`.
+
+ :return: luma coefficients
+ :rtype: list of floats
+ """
+ pass
+
+ def setDefaultLumaCoefs(self, coefficients):
+ """
+ setDefaultLumaCoefs(pyCoef)
+
+ Sets the default luma coefficients in :py:class:`PyOpenColorIO.Config`.
+
+ :param pyCoef: luma coefficients
+ :type pyCoef: object
+ """
+ pass
+
+ def getLook(self, lookname):
+ """
+ getLook(str)
+
+ Returns the information of a specified look in
+ :py:class:`PyOpenColorIO.Config`.
+
+ :param str: look
+ :type str: string
+ :return: specified look
+ :rtype: look object
+ """
+ pass
+
+ def getLooks(self):
+ """
+ getLooks()
+
+ Returns a list of all the looks defined in
+ :py:class:`PyOpenColorIO.Config`.
+
+ :return: looks
+ :rtype: tuple of look objects
+ """
+ pass
+
+ def addLook(self, look):
+ """
+ addLook(pylook)
+
+ Adds a look to :py:class:`PyOpenColorIO.Config`.
+
+ :param pylook: look
+ :type pylook: look object
+ """
+ pass
+
+ def clearLooks(self):
+ """
+ clearLooks()
+
+ Clear looks in :py:class:`PyOpenColorIO.Config`.
+ """
+ pass
+
+ def getProcessor(self, arg1, arg2=None, direction=None, context=None):
+ """
+ getProcessor(arg1[, arg2[, direction[, context]])
+
+ Returns a processor for a specified transform.
+
+ Although this is not often needed, it allows for the reuse of atomic
+ OCIO functionality, such as applying an individual LUT file.
+
+ There are two canonical ways of creating a
+ :py:class:`PyOpenColorIO.Processor`:
+
+ #. Pass a transform into arg1, in which case arg2 will be ignored.
+ #. Set arg1 as the source and arg2 as the destination. These can be
+ ColorSpace names, objects, or roles.
+
+ Both arguments, ``direction`` (of transform) and ``context``, are
+ optional and respected for both methods of
+ :py:class:`PyOpenColorIO.Processor` creation.
+
+ This will fail if either the source or destination color space is null.
+
+ See Python: Processor for more details.
+
+ .. note::
+ This may provide higher fidelity than anticipated due to internal
+ optimizations. For example, if inputColorSpace and outputColorSpace
+ are members of the same family, no conversion will be applied, even
+ though, strictly speaking, quantization should be added.
+
+ If you wish to test these calls for quantization characteristics,
+ apply in two steps; the image must contain RGB triples (though
+ arbitrary numbers of additional channels can be optionally
+ supported using the pixelStrideBytes arg). ???
+
+ :param arg1:
+ :type arg1: object
+ :param arg2: ignored if arg1 is a transform
+ :type arg2: object
+ :param direction: optional
+ :type direction: string
+ :param context: optional
+ :type context: object
+ """
+ pass
diff --git a/src/pyglue/DocStrings/Constants.py b/src/pyglue/DocStrings/Constants.py
new file mode 100644
index 0000000..a58a38c
--- /dev/null
+++ b/src/pyglue/DocStrings/Constants.py
@@ -0,0 +1,43 @@
+
+class Constants:
+
+ def __init__(self):
+ pass
+
+ def GetInverseTransformDirection(self, direction):
+ """
+ GetInverseTransformDirection(direction)
+
+ :param s:
+ :param type: string
+ """
+ pass
+
+ def CombineTransformDirections(self, dir1, dir2):
+ """
+ CombineTransformDirections(dir1, dir2)
+
+ :param s1:
+ :param type: string
+ :param s2:
+ :param type: string
+ """
+ pass
+
+ def BitDepthIsFloat(self, bitDepth):
+ """
+ BitDepthIsFloat(bitDepth)
+
+ :param s:
+ :param type: string
+ """
+ pass
+
+ def BitDepthToInt(self, bitDepth):
+ """
+ BitDepthToInt(bitDepth)
+
+ :param s:
+ :param type: string
+ """
+ pass
diff --git a/src/pyglue/DocStrings/Context.py b/src/pyglue/DocStrings/Context.py
new file mode 100644
index 0000000..ff73dbf
--- /dev/null
+++ b/src/pyglue/DocStrings/Context.py
@@ -0,0 +1,32 @@
+
+class Context:
+ """
+ Context
+ """
+ def __init__(self):
+ pass
+ def isEditable(self):
+ pass
+ def createEditableCopy(self):
+ pass
+ def getCacheID(self):
+ pass
+ def getSearchPath(self):
+ pass
+ def setSearchPath(self, searchPath):
+ pass
+ def getWorkingDir(self):
+ pass
+ def setWorkingDir(self, workingDir):
+ pass
+ def getStringVar(self):
+ pass
+ def setStringVar(self, stringVar):
+ pass
+ def loadEnvironment(self):
+ pass
+ def resolveStringVar(self, stringVar):
+ pass
+ def resolveFileLocation(self, fileLocation):
+ pass
+
diff --git a/src/pyglue/DocStrings/DisplayTransform.py b/src/pyglue/DocStrings/DisplayTransform.py
new file mode 100644
index 0000000..2d68ac3
--- /dev/null
+++ b/src/pyglue/DocStrings/DisplayTransform.py
@@ -0,0 +1,222 @@
+
+class DisplayTransform:
+ """
+ Used to create transforms for displays.
+ """
+ def __init__(self):
+ pass
+
+ def getInputColorSpaceName(self):
+ """
+ getInputColorSpaceName()
+
+ Returns the name of the input ColorSpace of
+ :py:class:`PyOpenColorIO.DisplayTransform`.
+
+ :return: name of input ColorSpace
+ :rtype: string
+ """
+ pass
+
+ def setInputColorSpaceName(self, name):
+ """
+ setInputColorSpaceName(name)
+
+ Sets the name of the input ColorSpace of
+ :py:class:`PyOpenColorIO.DisplayTransform`.
+
+ :param name: name of input ColorSpace
+ :type name: string
+ """
+ pass
+
+ def getLinearCC(self):
+ """
+ getLinearCC()
+
+ Returns the linear CC transform of
+ :py:class:`PyOpenColorIO.DisplayTransform`.
+
+ :return: linear CC transform
+ :rtype: object
+ """
+ pass
+
+ def setLinearCC(self, transform):
+ """
+ setLinearCC(pyCC)
+
+ Sets the linear CC transform of
+ :py:class:`PyOpenColorIO.DisplayTransform`.
+
+ :param pyCC: linear CC
+ :type pyCC: object
+ """
+ pass
+
+ def getColorTimingCC(self):
+ """
+ getColorTimingCC()
+
+ Returns the color timing CC transform of
+ :py:class:`PyOpenColorIO.DisplayTransform`.
+
+ :return: color timing CC transform
+ :rtype: object
+ """
+ pass
+
+ def setColorTimingCC(self, transform):
+ """
+ setColorTimingCC(pyCC)
+
+ Sets the color timing CC transform of
+ :py:class:`PyOpenColorIO.DisplayTransform`.
+
+ :param pyCC: color timing CC
+ :type pyCC: object
+ """
+ pass
+
+ def getChannelView(self):
+ """
+ getChannelView()
+
+ Returns the channel view of
+ :py:class:`PyOpenColorIO.DisplayTransform`.
+
+ :return: channel view
+ :rtype: object
+ """
+ pass
+
+ def setChannelView(self, transform):
+ """
+ setChannelView(pyCC)
+
+ Sets the channel view transform of
+ :py:class:`PyOpenColorIO.DisplayTransform`.
+
+ :param pyCC: channel view transform
+ :type pyCC: object
+ """
+ pass
+
+ def getDisplay(self):
+ """
+ getDisplay()
+
+ Returns the display of
+ :py:class:`PyOpenColorIO.DisplayTransform`.
+
+ :return: display
+ :rtype: string
+ """
+ pass
+
+ def setDisplay(self, displayName):
+ """
+ setDisplay(str)
+
+ Sets the display of
+ :py:class:`PyOpenColorIO.DisplayTransform`.
+
+ :param str: display
+ :type str: string
+ """
+ pass
+
+ def getView(self):
+ """
+ getView()
+
+ Returns the view of
+ :py:class:`PyOpenColorIO.DisplayTransform`.
+
+ :return: view
+ :rtype: string
+ """
+ pass
+
+ def setView(self, viewName):
+ """
+ setView(str)
+
+ Sets the view of
+ :py:class:`PyOpenColorIO.DisplayTransform`.
+
+ :param str: view
+ :type str: string
+ """
+ pass
+
+ def getDisplayCC(self):
+ """
+ getDisplayCC()
+
+ Returns the display CC transform of
+ :py:class:`PyOpenColorIO.DisplayTransform`.
+
+ :return: display CC
+ :rtype: object
+ """
+ pass
+
+ def setDisplayCC(self, transform):
+ """
+ setDisplayCC(pyCC)
+
+ Sets the display CC transform of
+ :py:class:`PyOpenColorIO.DisplayTransform`.
+
+ :param pyCC: display CC
+ :type pyCC: object
+ """
+ pass
+
+ def getLooksOverride(self):
+ """
+ getLooksOverride()
+
+ Returns the looks in :py:class:`PyOpenColorIO.DisplayTransform` that's
+ overriding :py:class:`PyOpenColorIO.Config`'s.
+
+ :return: looks override
+ :rtype: string
+ """
+ pass
+
+ def setLooksOverride(self, looksStr):
+ """
+ setLooksOverride(str)
+
+ Sets the looks override of :py:class:`PyOpenColorIO.DisplayTransform`.
+
+ :param str: looks override
+ :type str: string
+ """
+ pass
+
+ def getLooksOverrideEnabled(self):
+ """
+ getLooksOverrideEnabled()
+
+ Returns whether the looks override of
+ :py:class:`PyOpenColorIO.DisplayTransform` is enabled.
+
+ :return: looks override enabling
+ :rtype: bool
+ """
+ pass
+
+ def setLooksOverrideEnabled(self, enabled):
+ """
+ setLooksOverrideEnabled(enabled)
+
+ Sets the looks override enabling of
+ :py:class:`PyOpenColorIO.DisplayTransform`.
+
+ :param enabled: looks override enabling
+ :type enabled: object
+ """
+ pass
diff --git a/src/pyglue/DocStrings/Exception.py b/src/pyglue/DocStrings/Exception.py
new file mode 100644
index 0000000..75bba8e
--- /dev/null
+++ b/src/pyglue/DocStrings/Exception.py
@@ -0,0 +1,11 @@
+
+class Exception:
+ """
+ An exception class to throw for errors detected at runtime.
+
+ .. warning::
+ All functions in the Config class can potentially throw this exception.
+ """
+ def __init__(self):
+ pass
+
diff --git a/src/pyglue/DocStrings/ExceptionMissingFile.py b/src/pyglue/DocStrings/ExceptionMissingFile.py
new file mode 100644
index 0000000..6aa102a
--- /dev/null
+++ b/src/pyglue/DocStrings/ExceptionMissingFile.py
@@ -0,0 +1,11 @@
+
+class ExceptionMissingFile:
+ """
+ An exception class for errors detected at runtime, thrown when OCIO cannot
+ find a file that is expected to exist. This is provided as a custom type to
+ distinguish cases where one wants to continue looking for missing files,
+ but wants to properly fail for other error conditions.
+ """
+ def __init__(self):
+ pass
+
diff --git a/src/pyglue/DocStrings/ExponentTransform.py b/src/pyglue/DocStrings/ExponentTransform.py
new file mode 100644
index 0000000..930bb39
--- /dev/null
+++ b/src/pyglue/DocStrings/ExponentTransform.py
@@ -0,0 +1,31 @@
+
+class ExponentTransform:
+ """
+ ExponentTransform
+ """
+ def __init__(self):
+ pass
+
+ def getValue(self):
+ """
+ getValue()
+
+ Returns the values in the exponent transform of
+ :py:class:`PyOpenColorIO.ExponentTransform`.
+
+ :return: exponent transform values
+ :rtype: list of floats
+ """
+ pass
+
+ def setValue(self, value):
+ """
+ setValue()
+
+ Sets the values in the exponent transform of
+ :py:class:`PyOpenColorIO.ExponentTransform`.
+
+ :param pyData: exponent transform values
+ :type pyData: list of 4 floats
+ """
+ pass
diff --git a/src/pyglue/DocStrings/FileTransform.py b/src/pyglue/DocStrings/FileTransform.py
new file mode 100644
index 0000000..05a7026
--- /dev/null
+++ b/src/pyglue/DocStrings/FileTransform.py
@@ -0,0 +1,19 @@
+
+class FileTransform:
+ """
+ FileTransform
+ """
+ def __init__(self):
+ pass
+ def getSrc(self):
+ pass
+ def setSrc(self, src):
+ pass
+ def getCCCId(self):
+ pass
+ def setCCCId(self, cccid):
+ pass
+ def getInterpolation(self):
+ pass
+ def setInterpolation(self, interp):
+ pass
diff --git a/src/pyglue/DocStrings/GroupTransform.py b/src/pyglue/DocStrings/GroupTransform.py
new file mode 100644
index 0000000..80a5bf8
--- /dev/null
+++ b/src/pyglue/DocStrings/GroupTransform.py
@@ -0,0 +1,21 @@
+
+class GroupTransform:
+ """
+ GroupTransform
+ """
+ def __init__(self):
+ pass
+ def getTransform(self):
+ pass
+ def getTransforms(self):
+ pass
+ def setTransforms(self, transforms):
+ pass
+ def size(self):
+ pass
+ def push_back(self, transform):
+ pass
+ def clear(self):
+ pass
+ def empty(self):
+ pass
diff --git a/src/pyglue/DocStrings/LogTransform.py b/src/pyglue/DocStrings/LogTransform.py
new file mode 100644
index 0000000..ee823bb
--- /dev/null
+++ b/src/pyglue/DocStrings/LogTransform.py
@@ -0,0 +1,26 @@
+
+class LogTransform:
+ """
+ LogTransform
+ """
+ def __init__(self):
+ pass
+
+ def getBase(self):
+ """
+ getBase()
+
+ Returns the base of :py:class:`PyOpenColorIO.LogTransform`.
+ """
+ pass
+
+ def setBase(self, base):
+ """
+ setBase(base)
+
+ Sets the base in :py:class:`PyOpenColorIO.LogTransform`.
+
+ :param base: base of log transform
+ :type base: float
+ """
+ pass
diff --git a/src/pyglue/DocStrings/Look.py b/src/pyglue/DocStrings/Look.py
new file mode 100644
index 0000000..787fb5c
--- /dev/null
+++ b/src/pyglue/DocStrings/Look.py
@@ -0,0 +1,35 @@
+
+class Look:
+ """
+ The *Look* is an 'artistic' image modification, in a specified image state.
+
+ The processSpace defines the ColorSpace the image is required to be in, for
+ the math to apply correctly.
+ """
+ def __init__(self):
+ pass
+
+ def isEditable(self):
+ pass
+
+ def createEditableCopy(self):
+ pass
+
+ def getName(self):
+ pass
+
+ def setName(self, name):
+ pass
+
+ def getProcessSpace(self):
+ pass
+
+ def setProcessSpace(self, csname):
+ pass
+
+ def getTransform(self):
+ pass
+
+ def setTransform(self, transform):
+ pass
+
diff --git a/src/pyglue/DocStrings/LookTransform.py b/src/pyglue/DocStrings/LookTransform.py
new file mode 100644
index 0000000..9b0c62a
--- /dev/null
+++ b/src/pyglue/DocStrings/LookTransform.py
@@ -0,0 +1,19 @@
+
+class LookTransform:
+ """
+ LookTransform
+ """
+ def __init__(self):
+ pass
+ def getSrc(self):
+ pass
+ def setSrc(self, srcname):
+ pass
+ def getDst(self):
+ pass
+ def setDst(self, dstname):
+ pass
+ def getLooks(self):
+ pass
+ def setLooks(self, looks):
+ pass
diff --git a/src/pyglue/DocStrings/MatrixTransform.py b/src/pyglue/DocStrings/MatrixTransform.py
new file mode 100644
index 0000000..8b89ca5
--- /dev/null
+++ b/src/pyglue/DocStrings/MatrixTransform.py
@@ -0,0 +1,29 @@
+
+class MatrixTransform:
+ """
+ MatrixTransfom
+ """
+ def __init__(self):
+ pass
+ def getValue(self):
+ pass
+ def setValue(self, value):
+ pass
+ def getMatrix(self):
+ pass
+ def setMatrix(self, matrix):
+ pass
+ def getOffset(self):
+ pass
+ def setOffset(self, offset):
+ pass
+ def Identity(self):
+ pass
+ def Fit(self):
+ pass
+ def Sat(self):
+ pass
+ def Scale(self):
+ pass
+ def View(self):
+ pass
diff --git a/src/pyglue/DocStrings/OpenColorIO.py b/src/pyglue/DocStrings/OpenColorIO.py
new file mode 100644
index 0000000..0b7e376
--- /dev/null
+++ b/src/pyglue/DocStrings/OpenColorIO.py
@@ -0,0 +1,17 @@
+
+class OpenColorIO:
+ """
+ OpenColorIO API
+ """
+ def __init__(self):
+ pass
+ def ClearAllCaches(self):
+ pass
+ def GetLoggingLevel(self):
+ pass
+ def SetLoggingLevel(self, level):
+ pass
+ def GetCurrentConfig(self):
+ pass
+ def SetCurrentConfig(self, config):
+ pass
diff --git a/src/pyglue/DocStrings/Processor.py b/src/pyglue/DocStrings/Processor.py
new file mode 100644
index 0000000..7ce02bf
--- /dev/null
+++ b/src/pyglue/DocStrings/Processor.py
@@ -0,0 +1,141 @@
+
+class Processor:
+ """
+ Processor is the baked representation of a particular color transform.
+ Once you have a process for a particular transform created, you can hang
+ onto it to efficiently transform pixels.
+
+ Processors can only be created from the `PyOpenColorIO.Config`
+ getProcessor(...) call.
+ """
+
+ def __init__(self):
+ pass
+
+ def isNoOp(self):
+ """
+ isNoOp()
+
+ Returns whether the actual transformation represented by
+ :py:class:`PyOpenColorIO.Processor` is a no-op.
+
+ :return: whether transform is a no-op
+ :rtype: bool
+ """
+ pass
+
+ def hasChannelCrosstalk(self):
+ """
+ hasChannelCrosstalk()
+
+ Returns whether the transformation of
+ :py:class:`PyOpenColorIO.Processor` introduces crosstalk between the
+ image channels.
+
+ :return: whether there's crosstalk between channels
+ :rtype: bool
+ """
+ pass
+
+ def getMetadata(self):
+ """
+ getMetadata()
+
+ Returns information about the process that generated this processor.
+
+ :return: processor metadata
+ :rtype: `PyOpenColorIO.ProcessorMetadata`
+ """
+ pass
+
+ def applyRGB(self, pixeldata):
+ """
+ applyRGB(pixeldata)
+
+ Apply the RGB part of the transform represented by
+ :py:class:`PyOpenColorIO.Processor` to an image.
+
+ :param pixeldata: rgbrgb... array (length % 3 == 0)
+ :type pixeldata: object
+ :return: color converted pixeldata
+ :rtype: list
+ """
+ pass
+
+ def applyRGBA(self, pixeldata):
+ """
+ applyRGBA(pixeldata)
+
+ Apply the RGB and alpha part of the transform represented by
+ :py:class:`PyOpenColorIO.Processor` to an image.
+
+ :param pixeldata: rgbargba... array (length % 4 == 0)
+ :type pixeldata: object
+ :return: color converted pixeldata
+ :rtype: list
+ """
+ pass
+
+ def getCpuCacheID(self):
+ """
+ getCpuCacheID()
+
+ Returns the cache ID of the CPU that :py:class:`PyOpenColorIO.Processor`
+ will run on.
+
+ :return: CPU cache ID
+ :rtype: string
+ """
+ pass
+
+ def getGpuShaderText(self, shaderDesc):
+ """
+ getGpuShaderText(shaderDesc)
+
+ Returns the GPU shader text.
+
+ :param shaderDesc: define 'language','functionName','lut3DEdgeLen'
+ :type shaderDesc: dict
+ :return: GPU shader text
+ :rtype: string
+ """
+ pass
+
+ def getGpuShaderTextCacheID(self, shaderDesc):
+ """
+ getGpuShaderTextCacheID(shaderDesc)
+
+ Returns the GPU shader text cache ID.
+
+ :param shaderDesc: define 'language','functionName','lut3DEdgeLen'
+ :type shaderDesc: dict
+ :return: GPU shader text cache ID
+ :rtype: string
+ """
+ pass
+
+ def getGpuLut3D(self, shaderDesc):
+ """
+ getGpuLut3D(shaderDesc)
+
+ Returns the GPU LUT 3D.
+
+ :param shaderDesc: define 'language','functionName','lut3DEdgeLen'
+ :type shaderDesc: dict
+ :return: GPU LUT 3D
+ :rtype: list
+ """
+ pass
+
+ def getGpuLut3DCacheID(self, shaderDesc):
+ """
+ getGpuLut3DCacheID(shaderDesc)
+
+ Returns the GPU 3D LUT cache ID.
+
+ :param shaderDesc: two params
+ :type shaderDesc: dict
+ :return: GPU 3D LUT cache ID
+ :rtype: string
+ """
+ pass
diff --git a/src/pyglue/DocStrings/ProcessorMetadata.py b/src/pyglue/DocStrings/ProcessorMetadata.py
new file mode 100644
index 0000000..2e1d21a
--- /dev/null
+++ b/src/pyglue/DocStrings/ProcessorMetadata.py
@@ -0,0 +1,34 @@
+
+class ProcessorMetadata:
+ """
+ ProcessorMetadata
+
+ This contains meta information about the process that generated
+ this processor. The results of these functions do not
+ impact the pixel processing.
+
+ """
+ def __init__(self):
+ pass
+
+ def getFiles(self):
+ """
+ getFiles()
+
+ Returns a list of file references used internally by this processor
+
+ :return: list of filenames
+ :rtype: list
+ """
+ pass
+
+ def getLooks(self):
+ """
+ getLooks()
+
+ Returns a list of looks used internally by this processor
+
+ :return: list of look names
+ :rtype: list
+ """
+ pass
diff --git a/src/pyglue/DocStrings/Transform.py b/src/pyglue/DocStrings/Transform.py
new file mode 100644
index 0000000..b0819be
--- /dev/null
+++ b/src/pyglue/DocStrings/Transform.py
@@ -0,0 +1,19 @@
+
+class Transform:
+ """
+ These are typically only needed when creating or manipulating configurations.
+ """
+ def __init__(self):
+ pass
+
+ def isEditable(self):
+ pass
+
+ def createEditableCopy(self):
+ pass
+
+ def getDirection(self):
+ pass
+
+ def setDirection(self):
+ pass
diff --git a/src/pyglue/DocStrings/__init__.py b/src/pyglue/DocStrings/__init__.py
new file mode 100644
index 0000000..6afe720
--- /dev/null
+++ b/src/pyglue/DocStrings/__init__.py
@@ -0,0 +1,23 @@
+
+from Exception import *
+from ExceptionMissingFile import *
+from OpenColorIO import *
+from Constants import *
+from Config import *
+from ColorSpace import *
+from Processor import *
+from ProcessorMetadata import *
+from Context import *
+from Look import *
+from Transform import *
+
+from AllocationTransform import *
+from CDLTransform import *
+from ColorSpaceTransform import *
+from DisplayTransform import *
+from ExponentTransform import *
+from FileTransform import *
+from GroupTransform import *
+from LogTransform import *
+from LookTransform import *
+from MatrixTransform import *
diff --git a/src/pyglue/PyAllocationTransform.cpp b/src/pyglue/PyAllocationTransform.cpp
new file mode 100644
index 0000000..a977274
--- /dev/null
+++ b/src/pyglue/PyAllocationTransform.cpp
@@ -0,0 +1,300 @@
+/*
+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 <Python.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "PyTransform.h"
+#include "PyUtil.h"
+#include "PyDoc.h"
+
+//Rarely used. could use a log transform instead. This can sample by log when doing the offset to make best use of the data.
+
+OCIO_NAMESPACE_ENTER
+{
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ bool AddAllocationTransformObjectToModule( PyObject* m )
+ {
+ PyOCIO_AllocationTransformType.tp_new = PyType_GenericNew;
+ if ( PyType_Ready(&PyOCIO_AllocationTransformType) < 0 ) return false;
+
+ Py_INCREF( &PyOCIO_AllocationTransformType );
+ PyModule_AddObject(m, "AllocationTransform",
+ (PyObject *)&PyOCIO_AllocationTransformType);
+
+ return true;
+ }
+
+ /*
+ bool IsPyAllocationTransform(PyObject * pyobject)
+ {
+ if(!pyobject) return false;
+ return PyObject_TypeCheck(pyobject, &PyOCIO_AllocationTransformType);
+ }
+ */
+
+ ConstAllocationTransformRcPtr GetConstAllocationTransform(PyObject * pyobject, bool allowCast)
+ {
+ ConstAllocationTransformRcPtr transform = \
+ DynamicPtrCast<const AllocationTransform>(GetConstTransform(pyobject, allowCast));
+ if(!transform)
+ {
+ throw Exception("PyObject must be a valid OCIO.AllocationTransform.");
+ }
+ return transform;
+ }
+
+ AllocationTransformRcPtr GetEditableAllocationTransform(PyObject * pyobject)
+ {
+ AllocationTransformRcPtr transform = \
+ DynamicPtrCast<AllocationTransform>(GetEditableTransform(pyobject));
+ if(!transform)
+ {
+ throw Exception("PyObject must be a valid OCIO.AllocationTransform.");
+ }
+ return transform;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ int PyOCIO_AllocationTransform_init( PyOCIO_Transform * self, PyObject * args, PyObject * kwds );
+
+ PyObject * PyOCIO_AllocationTransform_equals( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_AllocationTransform_getAllocation( PyObject * self );
+ PyObject * PyOCIO_AllocationTransform_setAllocation( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_AllocationTransform_getVars( PyObject * self );
+ PyObject * PyOCIO_AllocationTransform_setVars( PyObject * self, PyObject *args );
+
+ ///////////////////////////////////////////////////////////////////////
+ ///
+
+ PyMethodDef PyOCIO_AllocationTransform_methods[] = {
+ {"getAllocation",
+ (PyCFunction) PyOCIO_AllocationTransform_getAllocation, METH_NOARGS, ALLOCATIONTRANSFORM_GETALLOCATION__DOC__ },
+ {"setAllocation",
+ PyOCIO_AllocationTransform_setAllocation, METH_VARARGS, ALLOCATIONTRANSFORM_SETALLOCATION__DOC__ },
+ {"getVars",
+ (PyCFunction) PyOCIO_AllocationTransform_getVars, METH_NOARGS, ALLOCATIONTRANSFORM_GETVARS__DOC__ },
+ {"setVars",
+ PyOCIO_AllocationTransform_setVars, METH_VARARGS, ALLOCATIONTRANSFORM_SETVARS__DOC__ },
+ {NULL, NULL, 0, NULL}
+ };
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyTypeObject PyOCIO_AllocationTransformType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, //ob_size
+ "OCIO.AllocationTransform", //tp_name
+ sizeof(PyOCIO_Transform), //tp_basicsize
+ 0, //tp_itemsize
+ 0, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ 0, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
+ ALLOCATIONTRANSFORM__DOC__, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ PyOCIO_AllocationTransform_methods, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ &PyOCIO_TransformType, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ (initproc) PyOCIO_AllocationTransform_init, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0, //tp_del
+ #if PY_VERSION_HEX > 0x02060000
+ 0, //tp_version_tag
+ #endif
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+
+ ///////////////////////////////////////////////////////////////////////
+ ///
+
+ int PyOCIO_AllocationTransform_init( PyOCIO_Transform *self, PyObject * /*args*/, PyObject * /*kwds*/ )
+ {
+ ///////////////////////////////////////////////////////////////////
+ /// init pyobject fields
+
+ self->constcppobj = new ConstTransformRcPtr();
+ self->cppobj = new TransformRcPtr();
+ self->isconst = true;
+
+ try
+ {
+ *self->cppobj = AllocationTransform::Create();
+ self->isconst = false;
+ return 0;
+ }
+ catch ( const std::exception & e )
+ {
+ std::string message = "Cannot create AllocationTransform: ";
+ message += e.what();
+ PyErr_SetString( PyExc_RuntimeError, message.c_str() );
+ return -1;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_AllocationTransform_getAllocation( PyObject * self )
+ {
+ try
+ {
+ ConstAllocationTransformRcPtr transform = GetConstAllocationTransform(self, true);
+ return PyString_FromString( AllocationToString( transform->getAllocation()) );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_AllocationTransform_setAllocation( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ Allocation hwalloc;
+ if (!PyArg_ParseTuple(args,"O&:setAllocation",
+ ConvertPyObjectToAllocation, &hwalloc)) return NULL;
+
+ AllocationTransformRcPtr transform = GetEditableAllocationTransform(self);
+ transform->setAllocation( hwalloc );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_AllocationTransform_getVars( PyObject * self )
+ {
+ try
+ {
+ ConstAllocationTransformRcPtr transform = GetConstAllocationTransform(self, true);
+
+ std::vector<float> vars(transform->getNumVars());
+ if(!vars.empty())
+ {
+ transform->getVars(&vars[0]);
+ }
+
+ return CreatePyListFromFloatVector(vars);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_AllocationTransform_setVars( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyvars = 0;
+ if (!PyArg_ParseTuple(args,"O:setVars", &pyvars)) return NULL;
+
+ std::vector<float> vars;
+ if(!FillFloatVectorFromPySequence(pyvars, vars))
+ {
+ PyErr_SetString(PyExc_TypeError, "First argument must be a float array.");
+ return 0;
+ }
+
+ AllocationTransformRcPtr transform = GetEditableAllocationTransform(self);
+ if(!vars.empty())
+ {
+ transform->setVars(static_cast<int>(vars.size()), &vars[0]);
+ }
+
+ Py_RETURN_NONE;
+
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/pyglue/PyCDLTransform.cpp b/src/pyglue/PyCDLTransform.cpp
new file mode 100644
index 0000000..5702940
--- /dev/null
+++ b/src/pyglue/PyCDLTransform.cpp
@@ -0,0 +1,611 @@
+/*
+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 <Python.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "PyTransform.h"
+#include "PyUtil.h"
+#include "PyDoc.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ bool AddCDLTransformObjectToModule( PyObject* m )
+ {
+ PyOCIO_CDLTransformType.tp_new = PyType_GenericNew;
+ if ( PyType_Ready(&PyOCIO_CDLTransformType) < 0 ) return false;
+
+ Py_INCREF( &PyOCIO_CDLTransformType );
+ PyModule_AddObject(m, "CDLTransform",
+ (PyObject *)&PyOCIO_CDLTransformType);
+
+ return true;
+ }
+
+ bool IsPyCDLTransform(PyObject * pyobject)
+ {
+ if(!pyobject) return false;
+ return PyObject_TypeCheck(pyobject, &PyOCIO_CDLTransformType);
+ }
+
+ ConstCDLTransformRcPtr GetConstCDLTransform(PyObject * pyobject, bool allowCast)
+ {
+ ConstCDLTransformRcPtr transform = \
+ DynamicPtrCast<const CDLTransform>(GetConstTransform(pyobject, allowCast));
+ if(!transform)
+ {
+ throw Exception("PyObject must be a valid OCIO.CDLTransform.");
+ }
+ return transform;
+ }
+
+ CDLTransformRcPtr GetEditableCDLTransform(PyObject * pyobject)
+ {
+ CDLTransformRcPtr transform = \
+ DynamicPtrCast<CDLTransform>(GetEditableTransform(pyobject));
+ if(!transform)
+ {
+ throw Exception("PyObject must be a valid OCIO.CDLTransform.");
+ }
+ return transform;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ int PyOCIO_CDLTransform_init( PyOCIO_Transform * self, PyObject * args, PyObject * kwds );
+
+ PyObject * PyOCIO_CDLTransform_equals( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_CDLTransform_getXML( PyObject * self );
+ PyObject * PyOCIO_CDLTransform_setXML( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_CDLTransform_getSlope( PyObject * self );
+ PyObject * PyOCIO_CDLTransform_getOffset( PyObject * self );
+ PyObject * PyOCIO_CDLTransform_getPower( PyObject * self );
+ PyObject * PyOCIO_CDLTransform_getSOP( PyObject * self );
+ PyObject * PyOCIO_CDLTransform_getSat( PyObject * self );
+
+ PyObject * PyOCIO_CDLTransform_setSlope( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_CDLTransform_setOffset( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_CDLTransform_setPower( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_CDLTransform_setSOP( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_CDLTransform_setSat( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_CDLTransform_getSatLumaCoefs( PyObject * self );
+
+ PyObject * PyOCIO_CDLTransform_getID( PyObject * self );
+ PyObject * PyOCIO_CDLTransform_setID( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_CDLTransform_getDescription( PyObject * self );
+ PyObject * PyOCIO_CDLTransform_setDescription( PyObject * self, PyObject *args );
+
+ ///////////////////////////////////////////////////////////////////////
+ ///
+
+ PyMethodDef PyOCIO_CDLTransform_methods[] = {
+ {"equals",
+ PyOCIO_CDLTransform_equals, METH_VARARGS, CDLTRANSFORM_EQUALS__DOC__ },
+ {"getXML",
+ (PyCFunction) PyOCIO_CDLTransform_getXML, METH_NOARGS, CDLTRANSFORM_GETXML__DOC__ },
+ {"setXML",
+ PyOCIO_CDLTransform_setXML, METH_VARARGS, CDLTRANSFORM_SETXML__DOC__ },
+ {"getSlope",
+ (PyCFunction) PyOCIO_CDLTransform_getSlope, METH_NOARGS, CDLTRANSFORM_GETSLOPE__DOC__ },
+ {"getOffset",
+ (PyCFunction) PyOCIO_CDLTransform_getOffset, METH_NOARGS, CDLTRANSFORM_GETOFFSET__DOC__ },
+ {"getPower",
+ (PyCFunction) PyOCIO_CDLTransform_getPower, METH_NOARGS, CDLTRANSFORM_GETPOWER__DOC__ },
+ {"getSOP",
+ (PyCFunction) PyOCIO_CDLTransform_getSOP, METH_NOARGS, CDLTRANSFORM_GETSOP__DOC__ },
+ {"getSat",
+ (PyCFunction) PyOCIO_CDLTransform_getSat, METH_NOARGS, CDLTRANSFORM_GETSAT__DOC__ },
+ {"setSlope",
+ PyOCIO_CDLTransform_setSlope, METH_VARARGS, CDLTRANSFORM_SETSLOPE__DOC__ },
+ {"setOffset",
+ PyOCIO_CDLTransform_setOffset, METH_VARARGS, CDLTRANSFORM_SETOFFSET__DOC__ },
+ {"setPower",
+ PyOCIO_CDLTransform_setPower, METH_VARARGS, CDLTRANSFORM_SETPOWER__DOC__ },
+ {"setSOP",
+ PyOCIO_CDLTransform_setSOP, METH_VARARGS, CDLTRANSFORM_SETSOP__DOC__ },
+ {"setSat",
+ PyOCIO_CDLTransform_setSat, METH_VARARGS, CDLTRANSFORM_SETSAT__DOC__ },
+ {"getSatLumaCoefs",
+ (PyCFunction) PyOCIO_CDLTransform_getSatLumaCoefs, METH_NOARGS, CDLTRANSFORM_GETSATLUMACOEFS__DOC__ },
+ {"getID",
+ (PyCFunction) PyOCIO_CDLTransform_getID, METH_NOARGS, CDLTRANSFORM_GETID__DOC__ },
+ {"setID",
+ PyOCIO_CDLTransform_setID, METH_VARARGS, CDLTRANSFORM_SETID__DOC__ },
+ {"getDescription",
+ (PyCFunction) PyOCIO_CDLTransform_getDescription, METH_NOARGS, CDLTRANSFORM_GETDESCRIPTION__DOC__ },
+ {"setDescription",
+ PyOCIO_CDLTransform_setDescription, METH_VARARGS, CDLTRANSFORM_SETDESCRIPTION__DOC__ },
+ {NULL, NULL, 0, NULL}
+ };
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyTypeObject PyOCIO_CDLTransformType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, //ob_size
+ "OCIO.CDLTransform", //tp_name
+ sizeof(PyOCIO_Transform), //tp_basicsize
+ 0, //tp_itemsize
+ 0, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ 0, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
+ CDLTRANSFORM__DOC__, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ PyOCIO_CDLTransform_methods, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ &PyOCIO_TransformType, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ (initproc) PyOCIO_CDLTransform_init, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0, //tp_del
+ #if PY_VERSION_HEX > 0x02060000
+ 0, //tp_version_tag
+ #endif
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ ///////////////////////////////////////////////////////////////////////
+ ///
+ int PyOCIO_CDLTransform_init( PyOCIO_Transform *self, PyObject * /*args*/, PyObject * /*kwds*/ )
+ {
+ ///////////////////////////////////////////////////////////////////
+ /// init pyobject fields
+
+ self->constcppobj = new ConstTransformRcPtr();
+ self->cppobj = new TransformRcPtr();
+ self->isconst = true;
+
+ try
+ {
+ *self->cppobj = CDLTransform::Create();
+ self->isconst = false;
+ return 0;
+ }
+ catch ( const std::exception & e )
+ {
+ std::string message = "Cannot create CDLTransform: ";
+ message += e.what();
+ PyErr_SetString( PyExc_RuntimeError, message.c_str() );
+ return -1;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_CDLTransform_equals( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyother = 0;
+
+ if (!PyArg_ParseTuple(args,"O:equals",
+ &pyother)) return NULL;
+
+ ConstCDLTransformRcPtr transform = GetConstCDLTransform(self, true);
+ if(!IsPyCDLTransform(pyother))
+ {
+ return PyBool_FromLong(false);
+ }
+
+ ConstCDLTransformRcPtr other = GetConstCDLTransform(pyother, true);
+
+ return PyBool_FromLong(transform->equals(other));
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_CDLTransform_getXML( PyObject * self )
+ {
+ try
+ {
+ ConstCDLTransformRcPtr transform = GetConstCDLTransform(self, true);
+ return PyString_FromString( transform->getXML() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_CDLTransform_setXML( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ const char * str = 0;
+ if (!PyArg_ParseTuple(args,"s:setXML",
+ &str)) return NULL;
+
+ CDLTransformRcPtr transform = GetEditableCDLTransform(self);
+ transform->setXML( str );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_CDLTransform_getSlope( PyObject * self )
+ {
+ try
+ {
+ ConstCDLTransformRcPtr transform = GetConstCDLTransform(self, true);
+ std::vector<float> data(3);
+ transform->getSlope(&data[0]);
+ return CreatePyListFromFloatVector(data);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_CDLTransform_getOffset( PyObject * self )
+ {
+ try
+ {
+ ConstCDLTransformRcPtr transform = GetConstCDLTransform(self, true);
+ std::vector<float> data(3);
+ transform->getOffset(&data[0]);
+ return CreatePyListFromFloatVector(data);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_CDLTransform_getPower( PyObject * self )
+ {
+ try
+ {
+ ConstCDLTransformRcPtr transform = GetConstCDLTransform(self, true);
+ std::vector<float> data(3);
+ transform->getPower(&data[0]);
+ return CreatePyListFromFloatVector(data);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_CDLTransform_getSOP( PyObject * self )
+ {
+ try
+ {
+ ConstCDLTransformRcPtr transform = GetConstCDLTransform(self, true);
+ std::vector<float> data(9);
+ transform->getSOP(&data[0]);
+ return CreatePyListFromFloatVector(data);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_CDLTransform_getSat( PyObject * self )
+ {
+ try
+ {
+ ConstCDLTransformRcPtr transform = GetConstCDLTransform(self, true);
+ return PyFloat_FromDouble(transform->getSat());
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_CDLTransform_setSlope( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyData = 0;
+ if (!PyArg_ParseTuple(args,"O:setSlope", &pyData)) return NULL;
+ CDLTransformRcPtr transform = GetEditableCDLTransform(self);
+
+ std::vector<float> data;
+ if(!FillFloatVectorFromPySequence(pyData, data) || (data.size() != 3))
+ {
+ PyErr_SetString(PyExc_TypeError, "First argument must be a float array, size 3");
+ return 0;
+ }
+
+ transform->setSlope( &data[0] );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_CDLTransform_setOffset( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyData = 0;
+ if (!PyArg_ParseTuple(args,"O:setOffset", &pyData)) return NULL;
+ CDLTransformRcPtr transform = GetEditableCDLTransform(self);
+
+ std::vector<float> data;
+ if(!FillFloatVectorFromPySequence(pyData, data) || (data.size() != 3))
+ {
+ PyErr_SetString(PyExc_TypeError, "First argument must be a float array, size 3");
+ return 0;
+ }
+
+ transform->setOffset( &data[0] );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_CDLTransform_setPower( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyData = 0;
+ if (!PyArg_ParseTuple(args,"O:setPower", &pyData)) return NULL;
+ CDLTransformRcPtr transform = GetEditableCDLTransform(self);
+
+ std::vector<float> data;
+ if(!FillFloatVectorFromPySequence(pyData, data) || (data.size() != 3))
+ {
+ PyErr_SetString(PyExc_TypeError, "First argument must be a float array, size 3");
+ return 0;
+ }
+
+ transform->setPower( &data[0] );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_CDLTransform_setSOP( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyData = 0;
+ if (!PyArg_ParseTuple(args,"O:setSOP", &pyData)) return NULL;
+ CDLTransformRcPtr transform = GetEditableCDLTransform(self);
+
+ std::vector<float> data;
+ if(!FillFloatVectorFromPySequence(pyData, data) || (data.size() != 9))
+ {
+ PyErr_SetString(PyExc_TypeError, "First argument must be a float array, size 9");
+ return 0;
+ }
+
+ transform->setSOP( &data[0] );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_CDLTransform_setSat( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ float sat;
+ if (!PyArg_ParseTuple(args,"f:setSat", &sat)) return NULL;
+ CDLTransformRcPtr transform = GetEditableCDLTransform(self);
+
+ transform->setSat( sat );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_CDLTransform_getSatLumaCoefs( PyObject * self )
+ {
+ try
+ {
+ ConstCDLTransformRcPtr transform = GetConstCDLTransform(self, true);
+ std::vector<float> data(3);
+ transform->getSatLumaCoefs(&data[0]);
+ return CreatePyListFromFloatVector(data);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+
+ PyObject * PyOCIO_CDLTransform_getID( PyObject * self )
+ {
+ try
+ {
+ ConstCDLTransformRcPtr transform = GetConstCDLTransform(self, true);
+ return PyString_FromString( transform->getID() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_CDLTransform_setID( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ const char * str = 0;
+ if (!PyArg_ParseTuple(args,"s:setID",
+ &str)) return NULL;
+
+ CDLTransformRcPtr transform = GetEditableCDLTransform(self);
+ transform->setID( str );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_CDLTransform_getDescription( PyObject * self )
+ {
+ try
+ {
+ ConstCDLTransformRcPtr transform = GetConstCDLTransform(self, true);
+ return PyString_FromString( transform->getDescription() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_CDLTransform_setDescription( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ const char * str = 0;
+ if (!PyArg_ParseTuple(args,"s:setDescription",
+ &str)) return NULL;
+
+ CDLTransformRcPtr transform = GetEditableCDLTransform(self);
+ transform->setDescription( str );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/pyglue/PyColorSpace.cpp b/src/pyglue/PyColorSpace.cpp
new file mode 100644
index 0000000..f169ad6
--- /dev/null
+++ b/src/pyglue/PyColorSpace.cpp
@@ -0,0 +1,756 @@
+/*
+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 <Python.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "PyColorSpace.h"
+#include "PyTransform.h"
+#include "PyUtil.h"
+#include "PyDoc.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ bool AddColorSpaceObjectToModule( PyObject* m )
+ {
+ PyOCIO_ColorSpaceType.tp_new = PyType_GenericNew;
+ if ( PyType_Ready(&PyOCIO_ColorSpaceType) < 0 ) return false;
+
+ Py_INCREF( &PyOCIO_ColorSpaceType );
+ PyModule_AddObject(m, "ColorSpace",
+ (PyObject *)&PyOCIO_ColorSpaceType);
+
+ return true;
+ }
+
+ PyObject * BuildConstPyColorSpace(ConstColorSpaceRcPtr colorSpace)
+ {
+ if (!colorSpace)
+ {
+ Py_RETURN_NONE;
+ }
+
+ PyOCIO_ColorSpace * pycolorSpace = PyObject_New(
+ PyOCIO_ColorSpace, (PyTypeObject * ) &PyOCIO_ColorSpaceType);
+
+ pycolorSpace->constcppobj = new ConstColorSpaceRcPtr();
+ *pycolorSpace->constcppobj = colorSpace;
+
+ pycolorSpace->cppobj = new ColorSpaceRcPtr();
+ pycolorSpace->isconst = true;
+
+ return ( PyObject * ) pycolorSpace;
+ }
+
+ PyObject * BuildEditablePyColorSpace(ColorSpaceRcPtr colorSpace)
+ {
+ if (!colorSpace)
+ {
+ Py_RETURN_NONE;
+ }
+
+ PyOCIO_ColorSpace * pycolorSpace = PyObject_New(
+ PyOCIO_ColorSpace, (PyTypeObject * ) &PyOCIO_ColorSpaceType);
+
+ pycolorSpace->constcppobj = new ConstColorSpaceRcPtr();
+ pycolorSpace->cppobj = new ColorSpaceRcPtr();
+ *pycolorSpace->cppobj = colorSpace;
+
+ pycolorSpace->isconst = false;
+
+ return ( PyObject * ) pycolorSpace;
+ }
+
+ bool IsPyColorSpace(PyObject * pyobject)
+ {
+ if(!pyobject) return false;
+ return (PyObject_Type(pyobject) == (PyObject *) (&PyOCIO_ColorSpaceType));
+ }
+
+ bool IsPyColorSpaceEditable(PyObject * pyobject)
+ {
+ if(!IsPyColorSpace(pyobject))
+ {
+ throw Exception("PyObject must be an OCIO.ColorSpace.");
+ }
+
+ PyOCIO_ColorSpace * pycolorSpace = reinterpret_cast<PyOCIO_ColorSpace *> (pyobject);
+ return (!pycolorSpace->isconst);
+ }
+
+ ConstColorSpaceRcPtr GetConstColorSpace(PyObject * pyobject, bool allowCast)
+ {
+ if(!IsPyColorSpace(pyobject))
+ {
+ throw Exception("PyObject must be an OCIO.ColorSpace.");
+ }
+
+ PyOCIO_ColorSpace * pycolorspace = reinterpret_cast<PyOCIO_ColorSpace *> (pyobject);
+ if(pycolorspace->isconst && pycolorspace->constcppobj)
+ {
+ return *pycolorspace->constcppobj;
+ }
+
+ if(allowCast && !pycolorspace->isconst && pycolorspace->cppobj)
+ {
+ return *pycolorspace->cppobj;
+ }
+
+ throw Exception("PyObject must be a valid OCIO.ColorSpace.");
+ }
+
+ ColorSpaceRcPtr GetEditableColorSpace(PyObject * pyobject)
+ {
+ if(!IsPyColorSpace(pyobject))
+ {
+ throw Exception("PyObject must be an OCIO.ColorSpace.");
+ }
+
+ PyOCIO_ColorSpace * pycolorspace = reinterpret_cast<PyOCIO_ColorSpace *> (pyobject);
+ if(!pycolorspace->isconst && pycolorspace->cppobj)
+ {
+ return *pycolorspace->cppobj;
+ }
+
+ throw Exception("PyObject must be an editable OCIO.ColorSpace.");
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ int PyOCIO_ColorSpace_init( PyOCIO_ColorSpace * self, PyObject * args, PyObject * kwds );
+ void PyOCIO_ColorSpace_delete( PyOCIO_ColorSpace * self, PyObject * args );
+ PyObject * PyOCIO_ColorSpace_isEditable( PyObject * self );
+ PyObject * PyOCIO_ColorSpace_createEditableCopy( PyObject * self );
+
+ PyObject * PyOCIO_ColorSpace_getName( PyObject * self );
+ PyObject * PyOCIO_ColorSpace_setName( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_ColorSpace_getFamily( PyObject * self );
+ PyObject * PyOCIO_ColorSpace_setFamily( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_ColorSpace_getEqualityGroup( PyObject * self );
+ PyObject * PyOCIO_ColorSpace_setEqualityGroup( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_ColorSpace_getDescription( PyObject * self );
+ PyObject * PyOCIO_ColorSpace_setDescription( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_ColorSpace_getBitDepth( PyObject * self );
+ PyObject * PyOCIO_ColorSpace_setBitDepth( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_ColorSpace_isData( PyObject * self );
+ PyObject * PyOCIO_ColorSpace_setIsData( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_ColorSpace_getAllocation( PyObject * self );
+ PyObject * PyOCIO_ColorSpace_setAllocation( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_ColorSpace_getAllocationVars( PyObject * self );
+ PyObject * PyOCIO_ColorSpace_setAllocationVars( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_ColorSpace_getTransform( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_ColorSpace_setTransform( PyObject * self, PyObject *args );
+
+ ///////////////////////////////////////////////////////////////////////
+ ///
+
+ PyMethodDef PyOCIO_ColorSpace_methods[] = {
+ {"isEditable",
+ (PyCFunction) PyOCIO_ColorSpace_isEditable, METH_NOARGS, COLORSPACE_ISEDITABLE__DOC__ },
+ {"createEditableCopy",
+ (PyCFunction) PyOCIO_ColorSpace_createEditableCopy, METH_NOARGS, COLORSPACE_CREATEEDITABLECOPY__DOC__ },
+ {"getName",
+ (PyCFunction) PyOCIO_ColorSpace_getName, METH_NOARGS, COLORSPACE_GETNAME__DOC__ },
+ {"setName",
+ PyOCIO_ColorSpace_setName, METH_VARARGS, COLORSPACE_SETNAME__DOC__ },
+ {"getFamily",
+ (PyCFunction) PyOCIO_ColorSpace_getFamily, METH_NOARGS, COLORSPACE_GETFAMILY__DOC__ },
+ {"setFamily",
+ PyOCIO_ColorSpace_setFamily, METH_VARARGS, COLORSPACE_SETFAMILY__DOC__ },
+ {"getEqualityGroup",
+ (PyCFunction) PyOCIO_ColorSpace_getEqualityGroup, METH_NOARGS, COLORSPACE_GETEQUALITYGROUP__DOC__ },
+ {"setEqualityGroup",
+ PyOCIO_ColorSpace_setEqualityGroup, METH_VARARGS, COLORSPACE_SETEQUALITYGROUP__DOC__ },
+ {"getDescription",
+ (PyCFunction) PyOCIO_ColorSpace_getDescription, METH_NOARGS, COLORSPACE_GETDESCRIPTION__DOC__ },
+ {"setDescription",
+ PyOCIO_ColorSpace_setDescription, METH_VARARGS, COLORSPACE_SETDESCRIPTION__DOC__ },
+ {"getBitDepth",
+ (PyCFunction) PyOCIO_ColorSpace_getBitDepth, METH_NOARGS, COLORSPACE_GETBITDEPTH__DOC__ },
+ {"setBitDepth",
+ PyOCIO_ColorSpace_setBitDepth, METH_VARARGS, COLORSPACE_SETBITDEPTH__DOC__ },
+ {"isData",
+ (PyCFunction) PyOCIO_ColorSpace_isData, METH_NOARGS, COLORSPACE_ISDATA__DOC__ },
+ {"setIsData",
+ PyOCIO_ColorSpace_setIsData, METH_VARARGS, COLORSPACE_SETISDATA__DOC__ },
+ {"getAllocation",
+ (PyCFunction) PyOCIO_ColorSpace_getAllocation, METH_NOARGS, COLORSPACE_GETALLOCATION__DOC__ },
+ {"setAllocation",
+ PyOCIO_ColorSpace_setAllocation, METH_VARARGS, COLORSPACE_SETALLOCATION__DOC__ },
+ {"getAllocationVars",
+ (PyCFunction) PyOCIO_ColorSpace_getAllocationVars, METH_NOARGS, COLORSPACE_GETALLOCATIONVARS__DOC__ },
+ {"setAllocationVars",
+ PyOCIO_ColorSpace_setAllocationVars, METH_VARARGS, COLORSPACE_SETALLOCATIONVARS__DOC__ },
+ {"getTransform",
+ PyOCIO_ColorSpace_getTransform, METH_VARARGS, COLORSPACE_GETTRANSFORM__DOC__ },
+ {"setTransform",
+ PyOCIO_ColorSpace_setTransform, METH_VARARGS, COLORSPACE_SETTRANSFORM__DOC__ },
+ {NULL, NULL, 0, NULL}
+ };
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyTypeObject PyOCIO_ColorSpaceType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, //ob_size
+ "OCIO.ColorSpace", //tp_name
+ sizeof(PyOCIO_ColorSpace), //tp_basicsize
+ 0, //tp_itemsize
+ (destructor)PyOCIO_ColorSpace_delete, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ 0, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
+ COLORSPACE__DOC__, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ PyOCIO_ColorSpace_methods, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ 0, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ (initproc) PyOCIO_ColorSpace_init, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0, //tp_del
+ #if PY_VERSION_HEX > 0x02060000
+ 0, //tp_version_tag
+ #endif
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ ///////////////////////////////////////////////////////////////////////
+ ///
+ int PyOCIO_ColorSpace_init( PyOCIO_ColorSpace *self, PyObject * args, PyObject * kwds )
+ {
+ ///////////////////////////////////////////////////////////////////
+ /// init pyobject fields
+
+ self->constcppobj = new ConstColorSpaceRcPtr();
+ self->cppobj = new ColorSpaceRcPtr();
+ self->isconst = true;
+
+ // Parse optional kwargs
+ char * name = NULL;
+ char * family = NULL;
+ char * equalityGroup = NULL;
+ char * description = NULL;
+ char * bitDepth = NULL;
+ bool isData = false; // TODO: Do not rely on the default value
+ char * allocation = NULL;
+ PyObject * allocationVars = NULL;
+ PyObject * toRefTransform = NULL;
+ PyObject * fromRefTransform = NULL;
+
+
+ const char * toRefStr =
+ ColorSpaceDirectionToString(COLORSPACE_DIR_TO_REFERENCE);
+ const char * fromRefStr =
+ ColorSpaceDirectionToString(COLORSPACE_DIR_FROM_REFERENCE);
+ const char *kwlist[] = {
+ "name", "family", "equalityGroup",
+ "description", "bitDepth",
+ "isData",
+ "allocation", "allocationVars",
+ toRefStr, fromRefStr,
+ NULL
+ };
+
+ if(!PyArg_ParseTupleAndKeywords(args, kwds, "|sssssO&sOOO",
+ const_cast<char **>(kwlist),
+ &name, &family, &equalityGroup, &description, &bitDepth,
+ ConvertPyObjectToBool, &isData,
+ &allocation, &allocationVars,
+ &toRefTransform, &fromRefTransform)) return -1;
+
+ try
+ {
+ ColorSpaceRcPtr colorSpace = ColorSpace::Create();
+ *self->cppobj = colorSpace;
+ self->isconst = false;
+
+ if(name) colorSpace->setName(name);
+ if(family) colorSpace->setFamily(family);
+ if(equalityGroup) colorSpace->setEqualityGroup(equalityGroup);
+ if(description) colorSpace->setDescription(description);
+ if(bitDepth) colorSpace->setBitDepth(BitDepthFromString(bitDepth));
+ colorSpace->setIsData(isData); // TODO: Do not rely on the default value
+ if(allocation) colorSpace->setAllocation(AllocationFromString(allocation));
+ if(allocationVars)
+ {
+ std::vector<float> vars;
+ if(!FillFloatVectorFromPySequence(allocationVars, vars))
+ {
+ PyErr_SetString(PyExc_TypeError, "allocationVars kwarg must be a float array.");
+ return -1;
+ }
+ colorSpace->setAllocationVars(static_cast<int>(vars.size()), &vars[0]);
+ }
+ if(toRefTransform)
+ {
+ ConstTransformRcPtr transform = GetConstTransform(toRefTransform, true);
+ colorSpace->setTransform(transform, COLORSPACE_DIR_TO_REFERENCE);
+ }
+ if(fromRefTransform)
+ {
+ ConstTransformRcPtr transform = GetConstTransform(fromRefTransform, true);
+ colorSpace->setTransform(transform, COLORSPACE_DIR_FROM_REFERENCE);
+ }
+
+ return 0;
+ }
+ catch ( const std::exception & e )
+ {
+ std::string message = "Cannot create colorSpace: ";
+ message += e.what();
+ PyErr_SetString( PyExc_RuntimeError, message.c_str() );
+ return -1;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+
+ void PyOCIO_ColorSpace_delete( PyOCIO_ColorSpace *self, PyObject * /*args*/ )
+ {
+ delete self->constcppobj;
+ delete self->cppobj;
+
+ self->ob_type->tp_free((PyObject*)self);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+
+ PyObject * PyOCIO_ColorSpace_isEditable( PyObject * self )
+ {
+ return PyBool_FromLong(IsPyColorSpaceEditable(self));
+ }
+
+ PyObject * PyOCIO_ColorSpace_createEditableCopy( PyObject * self )
+ {
+ try
+ {
+ ConstColorSpaceRcPtr colorSpace = GetConstColorSpace(self, true);
+ ColorSpaceRcPtr copy = colorSpace->createEditableCopy();
+ return BuildEditablePyColorSpace( copy );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+
+ PyObject * PyOCIO_ColorSpace_getName( PyObject * self )
+ {
+ try
+ {
+ ConstColorSpaceRcPtr colorSpace = GetConstColorSpace(self, true);
+ return PyString_FromString( colorSpace->getName() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_ColorSpace_setName( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * name = 0;
+ if (!PyArg_ParseTuple(args,"s:setName", &name)) return NULL;
+
+ ColorSpaceRcPtr colorSpace = GetEditableColorSpace(self);
+ colorSpace->setName( name );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+
+ PyObject * PyOCIO_ColorSpace_getFamily( PyObject * self )
+ {
+ try
+ {
+ ConstColorSpaceRcPtr colorSpace = GetConstColorSpace(self, true);
+ return PyString_FromString( colorSpace->getFamily() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_ColorSpace_setFamily( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * name = 0;
+ if (!PyArg_ParseTuple(args,"s:setFamily", &name)) return NULL;
+
+ ColorSpaceRcPtr colorSpace = GetEditableColorSpace(self);
+ colorSpace->setFamily( name );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+
+ PyObject * PyOCIO_ColorSpace_getEqualityGroup( PyObject * self )
+ {
+ try
+ {
+ ConstColorSpaceRcPtr colorSpace = GetConstColorSpace(self, true);
+ return PyString_FromString( colorSpace->getEqualityGroup() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_ColorSpace_setEqualityGroup( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * name = 0;
+ if (!PyArg_ParseTuple(args,"s:setEqualityGroup", &name)) return NULL;
+
+ ColorSpaceRcPtr colorSpace = GetEditableColorSpace(self);
+ colorSpace->setEqualityGroup( name );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+
+ PyObject * PyOCIO_ColorSpace_getDescription( PyObject * self )
+ {
+ try
+ {
+ ConstColorSpaceRcPtr colorSpace = GetConstColorSpace(self, true);
+ return PyString_FromString( colorSpace->getDescription() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_ColorSpace_setDescription( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * name = 0;
+ if (!PyArg_ParseTuple(args,"s:setDescription", &name)) return NULL;
+
+ ColorSpaceRcPtr colorSpace = GetEditableColorSpace(self);
+ colorSpace->setDescription( name );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+
+ PyObject * PyOCIO_ColorSpace_getBitDepth( PyObject * self )
+ {
+ try
+ {
+ ConstColorSpaceRcPtr colorSpace = GetConstColorSpace(self, true);
+ return PyString_FromString( BitDepthToString( colorSpace->getBitDepth()) );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_ColorSpace_setBitDepth( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * name = 0;
+ if (!PyArg_ParseTuple(args,"s:setBitDepth", &name)) return NULL;
+
+ ColorSpaceRcPtr colorSpace = GetEditableColorSpace(self);
+ colorSpace->setBitDepth( BitDepthFromString( name ) );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+
+ PyObject * PyOCIO_ColorSpace_isData( PyObject * self )
+ {
+ try
+ {
+ ConstColorSpaceRcPtr colorSpace = GetConstColorSpace(self, true);
+ return PyBool_FromLong( colorSpace->isData() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_ColorSpace_setIsData( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ bool isData = false;
+ if (!PyArg_ParseTuple(args,"O&:setIsData",
+ ConvertPyObjectToBool, &isData)) return NULL;
+
+ ColorSpaceRcPtr colorSpace = GetEditableColorSpace(self);
+ colorSpace->setIsData( isData );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+
+ PyObject * PyOCIO_ColorSpace_getAllocation( PyObject * self )
+ {
+ try
+ {
+ ConstColorSpaceRcPtr colorSpace = GetConstColorSpace(self, true);
+ return PyString_FromString( AllocationToString( colorSpace->getAllocation()) );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_ColorSpace_setAllocation( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ Allocation hwalloc;
+ if (!PyArg_ParseTuple(args,"O&:setAllocation",
+ ConvertPyObjectToAllocation, &hwalloc)) return NULL;
+
+ ColorSpaceRcPtr colorSpace = GetEditableColorSpace(self);
+ colorSpace->setAllocation( hwalloc );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+
+ PyObject * PyOCIO_ColorSpace_getAllocationVars( PyObject * self )
+ {
+ try
+ {
+ ConstColorSpaceRcPtr colorSpace = GetConstColorSpace(self, true);
+
+ std::vector<float> allocationvars(colorSpace->getAllocationNumVars());
+ if(!allocationvars.empty())
+ {
+ colorSpace->getAllocationVars(&allocationvars[0]);
+ }
+
+ return CreatePyListFromFloatVector(allocationvars);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_ColorSpace_setAllocationVars( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyvars = 0;
+ if (!PyArg_ParseTuple(args,"O:setAllocationVars", &pyvars)) return NULL;
+
+ std::vector<float> vars;
+ if(!FillFloatVectorFromPySequence(pyvars, vars))
+ {
+ PyErr_SetString(PyExc_TypeError, "First argument must be a float array.");
+ return 0;
+ }
+
+ ColorSpaceRcPtr colorSpace = GetEditableColorSpace(self);
+ if(!vars.empty())
+ {
+ colorSpace->setAllocationVars(static_cast<int>(vars.size()), &vars[0]);
+ }
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+
+ PyObject * PyOCIO_ColorSpace_getTransform( PyObject * self, PyObject *args )
+ {
+ try
+ {
+ ColorSpaceDirection dir;
+ if (!PyArg_ParseTuple(args,"O&:getTransform",
+ ConvertPyObjectToColorSpaceDirection, &dir)) return NULL;
+
+ ConstColorSpaceRcPtr colorSpace = GetConstColorSpace(self, true);
+ ConstTransformRcPtr transform = colorSpace->getTransform(dir);
+ return BuildConstPyTransform(transform);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+
+ PyObject * PyOCIO_ColorSpace_setTransform( PyObject * self, PyObject *args )
+ {
+
+ try
+ {
+ PyObject * pytransform = 0;
+ ColorSpaceDirection dir;
+ if (!PyArg_ParseTuple(args,"OO&:setTransform", &pytransform,
+ ConvertPyObjectToColorSpaceDirection, &dir)) return NULL;
+
+ ConstTransformRcPtr transform = GetConstTransform(pytransform, true);
+ ColorSpaceRcPtr colorSpace = GetEditableColorSpace(self);
+ colorSpace->setTransform(transform, dir);
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/pyglue/PyColorSpace.h b/src/pyglue/PyColorSpace.h
new file mode 100644
index 0000000..ae7d7d0
--- /dev/null
+++ b/src/pyglue/PyColorSpace.h
@@ -0,0 +1,52 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_PYOCIO_PYCOLORSPACE_H
+#define INCLUDED_PYOCIO_PYCOLORSPACE_H
+
+#include <PyOpenColorIO/PyOpenColorIO.h>
+
+OCIO_NAMESPACE_ENTER
+{
+ // TODO: Maybe put this in a pyinternal namespace?
+
+ typedef struct {
+ PyObject_HEAD
+ ConstColorSpaceRcPtr * constcppobj;
+ ColorSpaceRcPtr * cppobj;
+ bool isconst;
+ } PyOCIO_ColorSpace;
+
+ extern PyTypeObject PyOCIO_ColorSpaceType;
+
+ bool AddColorSpaceObjectToModule( PyObject* m );
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/pyglue/PyColorSpaceTransform.cpp b/src/pyglue/PyColorSpaceTransform.cpp
new file mode 100644
index 0000000..a4dc0fa
--- /dev/null
+++ b/src/pyglue/PyColorSpaceTransform.cpp
@@ -0,0 +1,294 @@
+/*
+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 <Python.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "PyTransform.h"
+#include "PyUtil.h"
+#include "PyDoc.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ bool AddColorSpaceTransformObjectToModule( PyObject* m )
+ {
+ PyOCIO_ColorSpaceTransformType.tp_new = PyType_GenericNew;
+ if ( PyType_Ready(&PyOCIO_ColorSpaceTransformType) < 0 ) return false;
+
+ Py_INCREF( &PyOCIO_ColorSpaceTransformType );
+ PyModule_AddObject(m, "ColorSpaceTransform",
+ (PyObject *)&PyOCIO_ColorSpaceTransformType);
+
+ return true;
+ }
+
+ bool IsPyColorSpaceTransform(PyObject * pyobject)
+ {
+ if(!pyobject) return false;
+ return PyObject_TypeCheck(pyobject, &PyOCIO_ColorSpaceTransformType);
+ }
+
+ ConstColorSpaceTransformRcPtr GetConstColorSpaceTransform(PyObject * pyobject, bool allowCast)
+ {
+ ConstColorSpaceTransformRcPtr transform = \
+ DynamicPtrCast<const ColorSpaceTransform>(GetConstTransform(pyobject, allowCast));
+ if(!transform)
+ {
+ throw Exception("PyObject must be a valid OCIO.ColorSpaceTransform.");
+ }
+ return transform;
+ }
+
+ ColorSpaceTransformRcPtr GetEditableColorSpaceTransform(PyObject * pyobject)
+ {
+ ColorSpaceTransformRcPtr transform = \
+ DynamicPtrCast<ColorSpaceTransform>(GetEditableTransform(pyobject));
+ if(!transform)
+ {
+ throw Exception("PyObject must be a valid OCIO.ColorSpaceTransform.");
+ }
+ return transform;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ int PyOCIO_ColorSpaceTransform_init( PyOCIO_Transform * self, PyObject * args, PyObject * kwds );
+
+ PyObject * PyOCIO_ColorSpaceTransform_getSrc( PyObject * self );
+ PyObject * PyOCIO_ColorSpaceTransform_setSrc( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_ColorSpaceTransform_getDst( PyObject * self );
+ PyObject * PyOCIO_ColorSpaceTransform_setDst( PyObject * self, PyObject *args );
+
+ ///////////////////////////////////////////////////////////////////////
+ ///
+
+ PyMethodDef PyOCIO_ColorSpaceTransform_methods[] = {
+ {"getSrc",
+ (PyCFunction) PyOCIO_ColorSpaceTransform_getSrc, METH_NOARGS, COLORSPACETRANSFORM_GETSRC__DOC__ },
+ {"setSrc",
+ PyOCIO_ColorSpaceTransform_setSrc, METH_VARARGS, COLORSPACETRANSFORM_SETSRC__DOC__ },
+ {"getDst",
+ (PyCFunction) PyOCIO_ColorSpaceTransform_getDst, METH_NOARGS, COLORSPACETRANSFORM_GETDST__DOC__ },
+ {"setDst",
+ PyOCIO_ColorSpaceTransform_setDst, METH_VARARGS, COLORSPACETRANSFORM_SETDST__DOC__ },
+ {NULL, NULL, 0, NULL}
+ };
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyTypeObject PyOCIO_ColorSpaceTransformType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, //ob_size
+ "OCIO.ColorSpaceTransform", //tp_name
+ sizeof(PyOCIO_Transform), //tp_basicsize
+ 0, //tp_itemsize
+ 0, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ 0, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
+ COLORSPACETRANSFORM__DOC__, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ PyOCIO_ColorSpaceTransform_methods, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ &PyOCIO_TransformType, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ (initproc) PyOCIO_ColorSpaceTransform_init, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0, //tp_del
+ #if PY_VERSION_HEX > 0x02060000
+ 0, //tp_version_tag
+ #endif
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ ///////////////////////////////////////////////////////////////////////
+ ///
+ int PyOCIO_ColorSpaceTransform_init( PyOCIO_Transform *self,
+ PyObject * args, PyObject * kwds )
+ {
+ ///////////////////////////////////////////////////////////////////
+ /// init pyobject fields
+
+ self->constcppobj = new ConstTransformRcPtr();
+ self->cppobj = new TransformRcPtr();
+ self->isconst = true;
+
+ // Parse optional kwargs
+ char * src = NULL;
+ char * dst = NULL;
+ char * direction = NULL;
+
+ static const char *kwlist[] = {
+ "src",
+ "dst",
+ "direction",
+ NULL
+ };
+
+ if(!PyArg_ParseTupleAndKeywords(args, kwds, "|sss",
+ const_cast<char **>(kwlist),
+ &src, &dst, &direction )) return -1;
+
+ try
+ {
+ ColorSpaceTransformRcPtr transform = ColorSpaceTransform::Create();
+ *self->cppobj = transform;
+ self->isconst = false;
+
+ if(src) transform->setSrc(src);
+ if(dst) transform->setDst(dst);
+ if(direction) transform->setDirection(TransformDirectionFromString(direction));
+
+ return 0;
+ }
+ catch ( const std::exception & e )
+ {
+ std::string message = "Cannot create ColorSpaceTransform: ";
+ message += e.what();
+ PyErr_SetString( PyExc_RuntimeError, message.c_str() );
+ return -1;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_ColorSpaceTransform_getSrc( PyObject * self )
+ {
+ try
+ {
+ ConstColorSpaceTransformRcPtr transform = GetConstColorSpaceTransform(self, true);
+ return PyString_FromString( transform->getSrc() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_ColorSpaceTransform_setSrc( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ const char * str = 0;
+ if (!PyArg_ParseTuple(args,"s:setSrc",
+ &str)) return NULL;
+
+ ColorSpaceTransformRcPtr transform = GetEditableColorSpaceTransform(self);
+ transform->setSrc( str );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_ColorSpaceTransform_getDst( PyObject * self )
+ {
+ try
+ {
+ ConstColorSpaceTransformRcPtr transform = GetConstColorSpaceTransform(self, true);
+ return PyString_FromString( transform->getDst() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_ColorSpaceTransform_setDst( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ const char * str = 0;
+ if (!PyArg_ParseTuple(args,"s:setDst",
+ &str)) return NULL;
+
+ ColorSpaceTransformRcPtr transform = GetEditableColorSpaceTransform(self);
+ transform->setDst( str );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/pyglue/PyConfig.cpp b/src/pyglue/PyConfig.cpp
new file mode 100644
index 0000000..2c6339d
--- /dev/null
+++ b/src/pyglue/PyConfig.cpp
@@ -0,0 +1,1220 @@
+/*
+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 <Python.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "PyColorSpace.h"
+#include "PyConfig.h"
+#include "PyUtil.h"
+#include "PyDoc.h"
+
+#include <sstream>
+
+OCIO_NAMESPACE_ENTER
+{
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+ bool AddConfigObjectToModule( PyObject* m )
+ {
+ PyOCIO_ConfigType.tp_new = PyType_GenericNew;
+ if ( PyType_Ready(&PyOCIO_ConfigType) < 0 ) return false;
+
+ Py_INCREF( &PyOCIO_ConfigType );
+ PyModule_AddObject(m, "Config",
+ (PyObject *)&PyOCIO_ConfigType);
+
+ return true;
+ }
+
+ PyObject * BuildConstPyConfig(ConstConfigRcPtr config)
+ {
+ if (!config.get())
+ {
+ Py_RETURN_NONE;
+ }
+
+ PyOCIO_Config * pyconfig = PyObject_New(
+ PyOCIO_Config, (PyTypeObject * ) &PyOCIO_ConfigType);
+
+ pyconfig->constcppobj = new ConstConfigRcPtr();
+ *pyconfig->constcppobj = config;
+
+ pyconfig->cppobj = new ConfigRcPtr();
+ pyconfig->isconst = true;
+
+ return ( PyObject * ) pyconfig;
+ }
+
+ PyObject * BuildEditablePyConfig(ConfigRcPtr config)
+ {
+ if (!config)
+ {
+ Py_RETURN_NONE;
+ }
+
+ PyOCIO_Config * pyconfig = PyObject_New(
+ PyOCIO_Config, (PyTypeObject * ) &PyOCIO_ConfigType);
+
+ pyconfig->constcppobj = new ConstConfigRcPtr();
+ pyconfig->cppobj = new ConfigRcPtr();
+ *pyconfig->cppobj = config;
+
+ pyconfig->isconst = false;
+
+ return ( PyObject * ) pyconfig;
+ }
+
+ bool IsPyConfig(PyObject * pyobject)
+ {
+ if(!pyobject) return false;
+ return (PyObject_Type(pyobject) == (PyObject *) (&PyOCIO_ConfigType));
+ }
+
+ bool IsPyConfigEditable(PyObject * pyobject)
+ {
+ if(!IsPyConfig(pyobject))
+ {
+ throw Exception("PyObject must be an OCIO.Config.");
+ }
+
+ PyOCIO_Config * pyconfig = reinterpret_cast<PyOCIO_Config *> (pyobject);
+ return (!pyconfig->isconst);
+ }
+
+ ConstConfigRcPtr GetConstConfig(PyObject * pyobject, bool allowCast)
+ {
+ if(!IsPyConfig(pyobject))
+ {
+ throw Exception("PyObject must be an OCIO.Config.");
+ }
+
+ PyOCIO_Config * pyconfig = reinterpret_cast<PyOCIO_Config *> (pyobject);
+ if(pyconfig->isconst && pyconfig->constcppobj)
+ {
+ return *pyconfig->constcppobj;
+ }
+
+ if(allowCast && !pyconfig->isconst && pyconfig->cppobj)
+ {
+ return *pyconfig->cppobj;
+ }
+
+ throw Exception("PyObject must be a valid OCIO.Config.");
+ }
+
+ ConfigRcPtr GetEditableConfig(PyObject * pyobject)
+ {
+ if(!IsPyConfig(pyobject))
+ {
+ throw Exception("PyObject must be an OCIO.Config.");
+ }
+
+ PyOCIO_Config * pyconfig = reinterpret_cast<PyOCIO_Config *> (pyobject);
+ if(!pyconfig->isconst && pyconfig->cppobj)
+ {
+ return *pyconfig->cppobj;
+ }
+
+ throw Exception("PyObject must be an editable OCIO.Config.");
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ PyObject * PyOCIO_Config_CreateFromEnv( PyObject * cls );
+ PyObject * PyOCIO_Config_CreateFromFile( PyObject * cls, PyObject * args );
+
+ int PyOCIO_Config_init( PyOCIO_Config * self, PyObject * args, PyObject * kwds );
+ void PyOCIO_Config_delete( PyOCIO_Config * self, PyObject * args );
+
+ PyObject * PyOCIO_Config_isEditable( PyObject * self );
+ PyObject * PyOCIO_Config_createEditableCopy( PyObject * self );
+
+ PyObject * PyOCIO_Config_sanityCheck( PyObject * self );
+
+ PyObject * PyOCIO_Config_getDescription( PyObject * self );
+ PyObject * PyOCIO_Config_setDescription( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_Config_serialize( PyObject * self );
+ PyObject * PyOCIO_Config_getCacheID( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_Config_getCurrentContext( PyObject * self );
+
+ PyObject * PyOCIO_Config_getSearchPath( PyObject * self );
+ PyObject * PyOCIO_Config_setSearchPath( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_Config_getWorkingDir( PyObject * self );
+ PyObject * PyOCIO_Config_setWorkingDir( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_Config_getColorSpaces( PyObject * self );
+ PyObject * PyOCIO_Config_getColorSpace( PyObject * self, PyObject * args );
+ PyObject * PyOCIO_Config_addColorSpace( PyObject * self, PyObject * args );
+ PyObject * PyOCIO_Config_clearColorSpaces( PyObject * self );
+ PyObject * PyOCIO_Config_parseColorSpaceFromString( PyObject * self, PyObject * args );
+ PyObject * PyOCIO_Config_setRole( PyObject * self, PyObject * args );
+
+ PyObject * PyOCIO_Config_getDefaultDisplay( PyObject * self );
+ PyObject * PyOCIO_Config_getDisplays( PyObject * self );
+ PyObject * PyOCIO_Config_getDefaultView( PyObject * self, PyObject * args );
+ PyObject * PyOCIO_Config_getViews( PyObject * self, PyObject * args );
+ PyObject * PyOCIO_Config_getDisplayColorSpaceName( PyObject * self, PyObject * args );
+ PyObject * PyOCIO_Config_getDisplayLooks( PyObject * self, PyObject * args );
+ PyObject * PyOCIO_Config_addDisplay( PyObject * self, PyObject * args, PyObject * kwargs );
+ PyObject * PyOCIO_Config_clearDisplays( PyObject * self );
+ PyObject * PyOCIO_Config_setActiveDisplays( PyObject * self, PyObject * args );
+ PyObject * PyOCIO_Config_getActiveDisplays( PyObject * self );
+ PyObject * PyOCIO_Config_setActiveViews( PyObject * self, PyObject * args );
+ PyObject * PyOCIO_Config_getActiveViews( PyObject * self );
+
+ PyObject * PyOCIO_Config_getDefaultLumaCoefs( PyObject * self );
+ PyObject * PyOCIO_Config_setDefaultLumaCoefs( PyObject * self, PyObject * args );
+
+ PyObject * PyOCIO_Config_getLook( PyObject * self, PyObject * args );
+ PyObject * PyOCIO_Config_getLooks( PyObject * self );
+ PyObject * PyOCIO_Config_addLook( PyObject * self, PyObject * args );
+ PyObject * PyOCIO_Config_clearLooks( PyObject * self );
+
+ PyObject * PyOCIO_Config_getProcessor( PyObject * self, PyObject * args, PyObject * kwargs );
+
+ ///////////////////////////////////////////////////////////////////////
+ ///
+
+ PyMethodDef PyOCIO_Config_methods[] = {
+ {"CreateFromEnv",
+ (PyCFunction) PyOCIO_Config_CreateFromEnv, METH_NOARGS | METH_CLASS, CONFIG_CREATEFROMENV__DOC__ },
+ {"CreateFromFile",
+ PyOCIO_Config_CreateFromFile, METH_VARARGS | METH_CLASS, CONFIG_CREATEFROMFILE__DOC__ },
+ {"isEditable",
+ (PyCFunction) PyOCIO_Config_isEditable, METH_NOARGS, CONFIG_ISEDITABLE__DOC__ },
+ {"createEditableCopy",
+ (PyCFunction) PyOCIO_Config_createEditableCopy, METH_NOARGS, CONFIG_CREATEEDITABLECOPY__DOC__ },
+ {"sanityCheck",
+ (PyCFunction) PyOCIO_Config_sanityCheck, METH_NOARGS, CONFIG_SANITYCHECK__DOC__ },
+ {"getDescription",
+ (PyCFunction) PyOCIO_Config_getDescription, METH_NOARGS, CONFIG_GETDESCRIPTION__DOC__ },
+ {"setDescription",
+ PyOCIO_Config_setDescription, METH_VARARGS, CONFIG_SETDESCRIPTION__DOC__ },
+ {"serialize",
+ (PyCFunction) PyOCIO_Config_serialize, METH_NOARGS, CONFIG_SERIALIZE__DOC__ },
+ {"getCacheID",
+ PyOCIO_Config_getCacheID, METH_VARARGS, CONFIG_GETCACHEID__DOC__ },
+ {"getCurrentContext",
+ (PyCFunction) PyOCIO_Config_getCurrentContext, METH_NOARGS, CONFIG_GETCURRENTCONTEXT__DOC__ },
+ {"getSearchPath",
+ (PyCFunction) PyOCIO_Config_getSearchPath, METH_NOARGS, CONFIG_GETSEARCHPATH__DOC__ },
+ {"setSearchPath",
+ PyOCIO_Config_setSearchPath, METH_VARARGS, CONFIG_SETSEARCHPATH__DOC__ },
+ {"getWorkingDir",
+ (PyCFunction) PyOCIO_Config_getWorkingDir, METH_NOARGS, CONFIG_GETWORKINGDIR__DOC__ },
+ {"setWorkingDir",
+ PyOCIO_Config_setWorkingDir, METH_VARARGS, CONFIG_SETWORKINGDIR__DOC__ },
+ {"getColorSpaces",
+ (PyCFunction) PyOCIO_Config_getColorSpaces, METH_NOARGS, CONFIG_GETCOLORSPACES__DOC__ },
+ {"getColorSpace",
+ PyOCIO_Config_getColorSpace, METH_VARARGS, CONFIG_GETCOLORSPACE__DOC__ },
+ {"addColorSpace",
+ PyOCIO_Config_addColorSpace, METH_VARARGS, CONFIG_ADDCOLORSPACE__DOC__ },
+ {"clearColorSpaces",
+ (PyCFunction) PyOCIO_Config_clearColorSpaces, METH_NOARGS, CONFIG_CLEARCOLORSPACES__DOC__ },
+ {"parseColorSpaceFromString",
+ PyOCIO_Config_parseColorSpaceFromString, METH_VARARGS, CONFIG_PARSECOLORSPACEFROMSTRING__DOC__ },
+ {"setRole",
+ PyOCIO_Config_setRole, METH_VARARGS, CONFIG_SETROLE__DOC__ },
+ {"getDefaultDisplay",
+ (PyCFunction) PyOCIO_Config_getDefaultDisplay, METH_NOARGS, CONFIG_GETDEFAULTDISPLAY__DOC__ },
+ {"getDisplays",
+ (PyCFunction) PyOCIO_Config_getDisplays, METH_NOARGS, CONFIG_GETDISPLAYS__DOC__ },
+ {"getDefaultView",
+ PyOCIO_Config_getDefaultView, METH_VARARGS, CONFIG_GETDEFAULTVIEW__DOC__ },
+ {"getViews",
+ PyOCIO_Config_getViews, METH_VARARGS, CONFIG_GETVIEWS__DOC__ },
+ {"getDisplayColorSpaceName",
+ PyOCIO_Config_getDisplayColorSpaceName, METH_VARARGS, CONFIG_GETDISPLAYCOLORSPACENAME__DOC__ },
+ {"getDisplayLooks",
+ PyOCIO_Config_getDisplayLooks, METH_VARARGS, CONFIG_GETDISPLAYLOOKS__DOC__ },
+ {"addDisplay",
+ (PyCFunction) PyOCIO_Config_addDisplay, METH_KEYWORDS, CONFIG_ADDDISPLAY__DOC__ },
+ {"clearDisplays",
+ (PyCFunction) PyOCIO_Config_clearDisplays, METH_NOARGS, CONFIG_CLEARDISPLAYS__DOC__ },
+ {"setActiveDisplays",
+ PyOCIO_Config_setActiveDisplays, METH_VARARGS, CONFIG_SETACTIVEDISPLAYS__DOC__ },
+ {"getActiveDisplays",
+ (PyCFunction) PyOCIO_Config_getActiveDisplays, METH_NOARGS, CONFIG_GETACTIVEDISPLAYS__DOC__ },
+ {"setActiveViews",
+ PyOCIO_Config_setActiveViews, METH_VARARGS, CONFIG_SETACTIVEVIEWS__DOC__ },
+ {"getActiveViews",
+ (PyCFunction) PyOCIO_Config_getActiveViews, METH_NOARGS, CONFIG_GETACTIVEVIEWS__DOC__ },
+ {"getDefaultLumaCoefs",
+ (PyCFunction) PyOCIO_Config_getDefaultLumaCoefs, METH_NOARGS, CONFIG_GETDEFAULTLUMACOEFS__DOC__ },
+ {"setDefaultLumaCoefs",
+ PyOCIO_Config_setDefaultLumaCoefs, METH_VARARGS, CONFIG_SETDEFAULTLUMACOEFS__DOC__ },
+ {"getLook",
+ PyOCIO_Config_getLook, METH_VARARGS, CONFIG_GETLOOK__DOC__ },
+ {"getLooks",
+ (PyCFunction) PyOCIO_Config_getLooks, METH_NOARGS, CONFIG_GETLOOKS__DOC__ },
+ {"addLook",
+ PyOCIO_Config_addLook, METH_VARARGS, CONFIG_ADDLOOK__DOC__ },
+ {"clearLook", // THIS SHOULD BE REMOVED IN THE NEXT BINARY INCOMPATIBLE VERSION
+ (PyCFunction) PyOCIO_Config_clearLooks, METH_NOARGS, CONFIG_CLEARLOOKS__DOC__ },
+ {"clearLooks",
+ (PyCFunction) PyOCIO_Config_clearLooks, METH_NOARGS, CONFIG_CLEARLOOKS__DOC__ },
+ {"getProcessor",
+ (PyCFunction) PyOCIO_Config_getProcessor, METH_KEYWORDS, CONFIG_GETPROCESSOR__DOC__ },
+ {NULL, NULL, 0, NULL}
+ };
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyTypeObject PyOCIO_ConfigType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, //ob_size
+ "OCIO.Config", //tp_name
+ sizeof(PyOCIO_Config), //tp_basicsize
+ 0, //tp_itemsize
+ (destructor)PyOCIO_Config_delete, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ 0, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
+ CONFIG__DOC__, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ PyOCIO_Config_methods, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ 0, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ (initproc) PyOCIO_Config_init, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0, //tp_del
+ #if PY_VERSION_HEX > 0x02060000
+ 0, //tp_version_tag
+ #endif
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// static methods
+
+ namespace
+ {
+ PyObject * PyOCIO_Config_CreateFromEnv( PyObject * /*cls*/ )
+ {
+ try
+ {
+ return BuildConstPyConfig( Config::CreateFromEnv() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_CreateFromFile( PyObject * /*cls*/, PyObject * args )
+ {
+ try
+ {
+ char * filename = 0;
+ if (!PyArg_ParseTuple(args,"s:CreateFromFile", &filename)) return NULL;
+
+ return BuildConstPyConfig( Config::CreateFromFile(filename) );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////
+ // Insert class markup here
+ int PyOCIO_Config_init( PyOCIO_Config *self, PyObject * /*args*/, PyObject * /*kwds*/ )
+ {
+ ///////////////////////////////////////////////////////////////////
+ /// init pyobject fields
+ self->constcppobj = new ConstConfigRcPtr();
+ self->cppobj = new ConfigRcPtr();
+ self->isconst = true;
+
+ try
+ {
+ *self->cppobj = Config::Create();
+ self->isconst = false;
+ return 0;
+ }
+ catch ( const std::exception & e )
+ {
+ std::string message = "Cannot create config: ";
+ message += e.what();
+ PyErr_SetString( PyExc_RuntimeError, message.c_str() );
+ return -1;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ void PyOCIO_Config_delete( PyOCIO_Config *self, PyObject * /*args*/ )
+ {
+ delete self->constcppobj;
+ delete self->cppobj;
+
+ self->ob_type->tp_free((PyObject*)self);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_Config_isEditable( PyObject * self )
+ {
+ return PyBool_FromLong(IsPyConfigEditable(self));
+ }
+
+ PyObject * PyOCIO_Config_createEditableCopy( PyObject * self )
+ {
+ try
+ {
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+ ConfigRcPtr copy = config->createEditableCopy();
+ return BuildEditablePyConfig( copy );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_sanityCheck( PyObject * self )
+ {
+ try
+ {
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+ config->sanityCheck();
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_Config_getDescription( PyObject * self )
+ {
+ try
+ {
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+ return PyString_FromString( config->getDescription() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_setDescription( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * desc = 0;
+ if (!PyArg_ParseTuple(args,"s:setDescription", &desc)) return NULL;
+
+ ConfigRcPtr config = GetEditableConfig(self);
+ config->setDescription( desc );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_serialize( PyObject * self )
+ {
+ try
+ {
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+
+ std::ostringstream os;
+
+ config->serialize(os);
+
+ return PyString_FromString( os.str().c_str() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+
+ }
+
+ PyObject * PyOCIO_Config_getCacheID( PyObject * self, PyObject * args )
+ {
+ try
+ { PyObject * pycontext = NULL;
+ if (!PyArg_ParseTuple(args,"|O:getCacheID", &pycontext)) return NULL;
+
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+
+ // Parse the context
+ ConstContextRcPtr context;
+ if(pycontext != NULL)
+ {
+ context = GetConstContext(pycontext, true);
+ }
+ else
+ {
+ context = config->getCurrentContext();
+ }
+
+ return PyString_FromString( config->getCacheID(context) );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_getCurrentContext( PyObject * self )
+ {
+ try
+ {
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+
+ return BuildConstPyContext(config->getCurrentContext());
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_getSearchPath( PyObject * self )
+ {
+ try
+ {
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+ return PyString_FromString( config->getSearchPath() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_setSearchPath( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * path = 0;
+ if (!PyArg_ParseTuple(args,"s:setSearchPath", &path)) return NULL;
+
+ ConfigRcPtr config = GetEditableConfig(self);
+ config->setSearchPath( path );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_getWorkingDir( PyObject * self )
+ {
+ try
+ {
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+ return PyString_FromString( config->getWorkingDir() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_setWorkingDir( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * path = 0;
+ if (!PyArg_ParseTuple(args,"s:setWorkingDir", &path)) return NULL;
+
+ ConfigRcPtr config = GetEditableConfig(self);
+ config->setWorkingDir( path );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_getColorSpaces( PyObject * self )
+ {
+ try
+ {
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+ int numColorSpaces = config->getNumColorSpaces();
+
+ PyObject* tuple = PyTuple_New( numColorSpaces );
+ for(int i = 0; i<numColorSpaces; ++i)
+ {
+ const char * name = config->getColorSpaceNameByIndex(i);
+ ConstColorSpaceRcPtr cs = config->getColorSpace(name);
+ PyObject * pycs = BuildConstPyColorSpace(cs);
+ PyTuple_SetItem(tuple, i, pycs);
+ }
+
+ return tuple;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_getColorSpace( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+
+ char * name = 0;
+ if (!PyArg_ParseTuple(args,"s:getColorSpace", &name)) return NULL;
+
+ return BuildConstPyColorSpace(config->getColorSpace(name));
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_Config_addColorSpace( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ ConfigRcPtr config = GetEditableConfig(self);
+
+ PyObject * pyColorSpace = 0;
+ if (!PyArg_ParseTuple(args,"O:addColorSpace", &pyColorSpace)) return NULL;
+
+ config->addColorSpace( GetConstColorSpace(pyColorSpace, true) );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_clearColorSpaces( PyObject * self )
+ {
+ try
+ {
+ ConfigRcPtr config = GetEditableConfig(self);
+ config->clearColorSpaces();
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_parseColorSpaceFromString( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+
+ char * str = 0;
+
+ if (!PyArg_ParseTuple(args,"s:parseColorSpaceFromString",
+ &str)) return NULL;
+
+ const char * cs = config->parseColorSpaceFromString(str);
+ if(cs)
+ {
+ return PyString_FromString( cs );
+ }
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_setRole( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ ConfigRcPtr config = GetEditableConfig(self);
+
+ char * role = 0;
+ char * csname = 0;
+
+ if (!PyArg_ParseTuple(args,"ss:setRole",
+ &role, &csname)) return NULL;
+
+ config->setRole(role, csname);
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_Config_getDefaultDisplay( PyObject * self )
+ {
+ try
+ {
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+ return PyString_FromString( config->getDefaultDisplay() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_getDisplays( PyObject * self )
+ {
+ try
+ {
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+
+ std::vector<std::string> data;
+ int numDevices = config->getNumDisplays();
+
+ for(int i=0; i<numDevices; ++i)
+ {
+ data.push_back( config->getDisplay(i) );
+ }
+
+ return CreatePyListFromStringVector(data);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_getDefaultView( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * display = 0;
+ if (!PyArg_ParseTuple(args,"s:getDefaultView",
+ &display)) return NULL;
+
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+ return PyString_FromString( config->getDefaultView(display) );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_getViews( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * display = 0;
+ if (!PyArg_ParseTuple(args,"s:getViews",
+ &display)) return NULL;
+
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+ std::vector<std::string> data;
+ int num = config->getNumViews(display);
+ for(int i=0; i<num; ++i)
+ {
+ data.push_back( config->getView(display, i) );
+ }
+
+ return CreatePyListFromStringVector(data);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_getDisplayColorSpaceName( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * display = 0;
+ char * view = 0;
+ if (!PyArg_ParseTuple(args,"ss:getDisplayColorSpaceName",
+ &display, &view)) return NULL;
+
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+ return PyString_FromString( config->getDisplayColorSpaceName(display, view) );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_getDisplayLooks( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * display = 0;
+ char * view = 0;
+ if (!PyArg_ParseTuple(args,"ss:getDisplayLooks",
+ &display, &view)) return NULL;
+
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+ return PyString_FromString( config->getDisplayLooks(display, view) );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_addDisplay( PyObject * self, PyObject * args, PyObject * kwargs)
+ {
+ try
+ {
+ ConfigRcPtr config = GetEditableConfig(self);
+
+ char * display = 0;
+ char * view = 0;
+ char * colorSpaceName = 0;
+ char * looks = 0;
+
+ const char * kwlist[] = {"display", "view", "colorSpaceName", "looks", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sss|s",
+ const_cast<char**>(kwlist),
+ &display, &view, &colorSpaceName, &looks))
+ return 0;
+
+ std::string lookStr;
+ if(looks) lookStr = looks;
+
+ config->addDisplay(display, view, colorSpaceName, lookStr.c_str());
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_clearDisplays( PyObject * self )
+ {
+ try
+ {
+ ConfigRcPtr config = GetEditableConfig(self);
+ config->clearDisplays();
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_setActiveDisplays( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ ConfigRcPtr config = GetEditableConfig(self);
+
+ char * displays = 0;
+
+ if (!PyArg_ParseTuple(args,"s:setActiveDisplays",
+ &displays)) return NULL;
+
+ config->setActiveDisplays(displays);
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_getActiveDisplays( PyObject * self )
+ {
+ try
+ {
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+ return PyString_FromString( config->getActiveDisplays() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_setActiveViews( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ ConfigRcPtr config = GetEditableConfig(self);
+
+ char * views = 0;
+
+ if (!PyArg_ParseTuple(args,"s:setActiveViews",
+ &views)) return NULL;
+
+ config->setActiveViews(views);
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_getActiveViews( PyObject * self )
+ {
+ try
+ {
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+ return PyString_FromString( config->getActiveViews() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_Config_setDefaultLumaCoefs( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ ConfigRcPtr config = GetEditableConfig(self);
+
+ PyObject* pyCoef = 0;
+ if (!PyArg_ParseTuple(args, "O:setDefaultLumaCoefs", &pyCoef))
+ {
+ return 0;
+ }
+
+ std::vector<float> coef;
+ if(!FillFloatVectorFromPySequence(pyCoef, coef) || (coef.size() != 3))
+ {
+ PyErr_SetString(PyExc_TypeError, "First argument must be a float array, size 3");
+ return 0;
+ }
+
+ config->setDefaultLumaCoefs(&coef[0]);
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_getDefaultLumaCoefs( PyObject * self )
+ {
+ try
+ {
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+
+ std::vector<float> coef(3);
+ config->getDefaultLumaCoefs(&coef[0]);
+
+ return CreatePyListFromFloatVector(coef);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_Config_getLook( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+
+ char * str = 0;
+ if (!PyArg_ParseTuple(args,"s:getLook",
+ &str)) return NULL;
+
+ return BuildConstPyLook(config->getLook(str));
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_getLooks( PyObject * self )
+ {
+ try
+ {
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+ int num = config->getNumLooks();
+
+ PyObject* tuple = PyTuple_New( num );
+ for(int i = 0; i<num; ++i)
+ {
+ const char * name = config->getLookNameByIndex(i);
+ ConstLookRcPtr look = config->getLook(name);
+ PyObject * pylook = BuildConstPyLook(look);
+ PyTuple_SetItem(tuple, i, pylook);
+ }
+
+ return tuple;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_addLook( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ ConfigRcPtr config = GetEditableConfig(self);
+
+ PyObject * pyLook = 0;
+ if (!PyArg_ParseTuple(args,"O:addLook", &pyLook)) return NULL;
+
+ config->addLook( GetConstLook(pyLook, true) );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Config_clearLooks( PyObject * self )
+ {
+ try
+ {
+ ConfigRcPtr config = GetEditableConfig(self);
+ config->clearLooks();
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_Config_getProcessor( PyObject * self, PyObject * args, PyObject * kwargs)
+ {
+ try
+ {
+ // We want this call to be as flexible as possible.
+ // arg1 will either be a PyTransform
+ // or arg1, arg2 will be {str, ColorSpace}
+
+ PyObject * arg1 = Py_None;
+ PyObject * arg2 = Py_None;
+
+ const char * direction = 0;
+ PyObject * pycontext = Py_None;
+
+ const char * kwlist[] = {"arg1", "arg2", "direction", "context", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OsO",
+ const_cast<char**>(kwlist),
+ &arg1, &arg2, &direction, &pycontext))
+ return 0;
+
+ ConstConfigRcPtr config = GetConstConfig(self, true);
+
+ // Parse the direction string
+ TransformDirection dir = TRANSFORM_DIR_FORWARD;
+ if(direction) dir = TransformDirectionFromString( direction );
+
+ // Parse the context
+ ConstContextRcPtr context;
+ if(pycontext != Py_None) context = GetConstContext(pycontext, true);
+ if(!context) context = config->getCurrentContext();
+
+ if(IsPyTransform(arg1))
+ {
+ ConstTransformRcPtr transform = GetConstTransform(arg1, true);
+ return BuildConstPyProcessor(config->getProcessor(context, transform, dir));
+ }
+
+ // Any two (Colorspaces, colorspace name, roles)
+ ConstColorSpaceRcPtr cs1, cs2;
+
+ if(IsPyColorSpace(arg1))
+ {
+ cs1 = GetConstColorSpace(arg1, true);
+ }
+ else if(PyString_Check(arg1))
+ {
+ cs1 = config->getColorSpace(PyString_AsString(arg1));
+ }
+ if(!cs1)
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "Could not parse first arg. Allowed types include ColorSpace, ColorSpace name, Role.");
+ return NULL;
+ }
+
+ if(IsPyColorSpace(arg2))
+ {
+ cs2 = GetConstColorSpace(arg2, true);
+ }
+ else if(PyString_Check(arg2))
+ {
+ cs2 = config->getColorSpace(PyString_AsString(arg2));
+ }
+ if(!cs2)
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "Could not parse second arg. Allowed types include ColorSpace, ColorSpace name, Role.");
+ return NULL;
+ }
+
+ return BuildConstPyProcessor(config->getProcessor(context, cs1, cs2));
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/pyglue/PyConfig.h b/src/pyglue/PyConfig.h
new file mode 100644
index 0000000..05ba954
--- /dev/null
+++ b/src/pyglue/PyConfig.h
@@ -0,0 +1,52 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_PYOCIO_PYCONFIG_H
+#define INCLUDED_PYOCIO_PYCONFIG_H
+
+#include <PyOpenColorIO/PyOpenColorIO.h>
+
+OCIO_NAMESPACE_ENTER
+{
+ // TODO: Maybe put this in a pyinternal namespace?
+
+ typedef struct {
+ PyObject_HEAD
+ ConstConfigRcPtr * constcppobj;
+ ConfigRcPtr * cppobj;
+ bool isconst;
+ } PyOCIO_Config;
+
+ extern PyTypeObject PyOCIO_ConfigType;
+
+ bool AddConfigObjectToModule( PyObject* m );
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/pyglue/PyConstants.cpp b/src/pyglue/PyConstants.cpp
new file mode 100644
index 0000000..ff004bf
--- /dev/null
+++ b/src/pyglue/PyConstants.cpp
@@ -0,0 +1,239 @@
+/*
+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 <Python.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "PyColorSpace.h"
+#include "PyConstants.h"
+#include "PyUtil.h"
+#include "PyDoc.h"
+
+OCIO_NAMESPACE_ENTER
+{
+
+ namespace
+ {
+ PyObject * PyOCIO_Constants_GetInverseTransformDirection( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_Constants_CombineTransformDirections( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_Constants_BitDepthIsFloat( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_Constants_BitDepthToInt( PyObject * self, PyObject *args );
+
+ ///////////////////////////////////////////////////////////////////////
+ ///
+
+ PyMethodDef LocalModuleMethods[] = {
+ {"GetInverseTransformDirection",
+ PyOCIO_Constants_GetInverseTransformDirection, METH_VARARGS, CONSTANTS_GETINVERSETRANSFORMDIRECTION__DOC__ },
+ {"CombineTransformDirections",
+ PyOCIO_Constants_CombineTransformDirections, METH_VARARGS, CONSTANTS_COMBINETRANSFORMDIRECTIONS__DOC__ },
+ {"BitDepthIsFloat",
+ PyOCIO_Constants_BitDepthIsFloat, METH_VARARGS, CONSTANTS_BITDEPTHISFLOAT__DOC__ },
+ {"BitDepthToInt",
+ PyOCIO_Constants_BitDepthToInt, METH_VARARGS, CONSTANTS_BITDEPTHTOINT__DOC__ },
+ {NULL, NULL, 0, NULL} /* Sentinel */
+ };
+
+ }
+
+ void AddConstantsModule(PyObject *enclosingModule)
+ {
+ // Add sub-module
+ std::string moduleName = PyModule_GetName(enclosingModule);
+ moduleName += ".Constants";
+
+ PyObject * m = Py_InitModule3(const_cast<char*>(moduleName.c_str()),
+ LocalModuleMethods, CONSTANTS__DOC__);
+ Py_INCREF(m);
+
+ // Add Module Constants
+ PyModule_AddStringConstant(m, "LOGGING_LEVEL_NONE",
+ const_cast<char*>(LoggingLevelToString(LOGGING_LEVEL_NONE)));
+ PyModule_AddStringConstant(m, "LOGGING_LEVEL_WARNING",
+ const_cast<char*>(LoggingLevelToString(LOGGING_LEVEL_WARNING)));
+ PyModule_AddStringConstant(m, "LOGGING_LEVEL_INFO",
+ const_cast<char*>(LoggingLevelToString(LOGGING_LEVEL_INFO)));
+ PyModule_AddStringConstant(m, "LOGGING_LEVEL_UNKNOWN",
+ const_cast<char*>(LoggingLevelToString(LOGGING_LEVEL_UNKNOWN)));
+
+ PyModule_AddStringConstant(m, "TRANSFORM_DIR_UNKNOWN",
+ const_cast<char*>(TransformDirectionToString(TRANSFORM_DIR_UNKNOWN)));
+ PyModule_AddStringConstant(m, "TRANSFORM_DIR_FORWARD",
+ const_cast<char*>(TransformDirectionToString(TRANSFORM_DIR_FORWARD)));
+ PyModule_AddStringConstant(m, "TRANSFORM_DIR_INVERSE",
+ const_cast<char*>(TransformDirectionToString(TRANSFORM_DIR_INVERSE)));
+
+ PyModule_AddStringConstant(m, "COLORSPACE_DIR_UNKNOWN",
+ const_cast<char*>(ColorSpaceDirectionToString(COLORSPACE_DIR_UNKNOWN)));
+ PyModule_AddStringConstant(m, "COLORSPACE_DIR_TO_REFERENCE",
+ const_cast<char*>(ColorSpaceDirectionToString(COLORSPACE_DIR_TO_REFERENCE)));
+ PyModule_AddStringConstant(m, "COLORSPACE_DIR_FROM_REFERENCE",
+ const_cast<char*>(ColorSpaceDirectionToString(COLORSPACE_DIR_FROM_REFERENCE)));
+
+ PyModule_AddStringConstant(m, "BIT_DEPTH_UNKNOWN",
+ const_cast<char*>(BitDepthToString(BIT_DEPTH_UNKNOWN)));
+ PyModule_AddStringConstant(m, "BIT_DEPTH_UINT8",
+ const_cast<char*>(BitDepthToString(BIT_DEPTH_UINT8)));
+ PyModule_AddStringConstant(m, "BIT_DEPTH_UINT10",
+ const_cast<char*>(BitDepthToString(BIT_DEPTH_UINT10)));
+ PyModule_AddStringConstant(m, "BIT_DEPTH_UINT12",
+ const_cast<char*>(BitDepthToString(BIT_DEPTH_UINT12)));
+ PyModule_AddStringConstant(m, "BIT_DEPTH_UINT14",
+ const_cast<char*>(BitDepthToString(BIT_DEPTH_UINT14)));
+ PyModule_AddStringConstant(m, "BIT_DEPTH_UINT16",
+ const_cast<char*>(BitDepthToString(BIT_DEPTH_UINT16)));
+ PyModule_AddStringConstant(m, "BIT_DEPTH_UINT32",
+ const_cast<char*>(BitDepthToString(BIT_DEPTH_UINT32)));
+ PyModule_AddStringConstant(m, "BIT_DEPTH_F16",
+ const_cast<char*>(BitDepthToString(BIT_DEPTH_F16)));
+ PyModule_AddStringConstant(m, "BIT_DEPTH_F32",
+ const_cast<char*>(BitDepthToString(BIT_DEPTH_F32)));
+
+ PyModule_AddStringConstant(m, "ALLOCATION_UNKNOWN",
+ const_cast<char*>(AllocationToString(ALLOCATION_UNKNOWN)));
+ PyModule_AddStringConstant(m, "ALLOCATION_UNIFORM",
+ const_cast<char*>(AllocationToString(ALLOCATION_UNIFORM)));
+ PyModule_AddStringConstant(m, "ALLOCATION_LG2",
+ const_cast<char*>(AllocationToString(ALLOCATION_LG2)));
+
+ PyModule_AddStringConstant(m, "INTERP_UNKNOWN",
+ const_cast<char*>(InterpolationToString(INTERP_UNKNOWN)));
+ PyModule_AddStringConstant(m, "INTERP_NEAREST",
+ const_cast<char*>(InterpolationToString(INTERP_NEAREST)));
+ PyModule_AddStringConstant(m, "INTERP_LINEAR",
+ const_cast<char*>(InterpolationToString(INTERP_LINEAR)));
+ PyModule_AddStringConstant(m, "INTERP_TETRAHEDRAL",
+ const_cast<char*>(InterpolationToString(INTERP_TETRAHEDRAL)));
+ PyModule_AddStringConstant(m, "INTERP_BEST",
+ const_cast<char*>(InterpolationToString(INTERP_BEST)));
+
+ PyModule_AddStringConstant(m, "GPU_LANGUAGE_UNKNOWN",
+ const_cast<char*>(GpuLanguageToString(GPU_LANGUAGE_UNKNOWN)));
+ PyModule_AddStringConstant(m, "GPU_LANGUAGE_CG",
+ const_cast<char*>(GpuLanguageToString(GPU_LANGUAGE_CG)));
+ PyModule_AddStringConstant(m, "GPU_LANGUAGE_GLSL_1_0",
+ const_cast<char*>(GpuLanguageToString(GPU_LANGUAGE_GLSL_1_0)));
+ PyModule_AddStringConstant(m, "GPU_LANGUAGE_GLSL_1_3",
+ const_cast<char*>(GpuLanguageToString(GPU_LANGUAGE_GLSL_1_3)));
+
+ PyModule_AddStringConstant(m, "ROLE_DEFAULT", const_cast<char*>(ROLE_DEFAULT));
+ PyModule_AddStringConstant(m, "ROLE_REFERENCE", const_cast<char*>(ROLE_REFERENCE));
+ PyModule_AddStringConstant(m, "ROLE_DATA", const_cast<char*>(ROLE_DATA));
+ PyModule_AddStringConstant(m, "ROLE_COLOR_PICKING", const_cast<char*>(ROLE_COLOR_PICKING));
+ PyModule_AddStringConstant(m, "ROLE_SCENE_LINEAR", const_cast<char*>(ROLE_SCENE_LINEAR));
+ PyModule_AddStringConstant(m, "ROLE_COMPOSITING_LOG", const_cast<char*>(ROLE_COMPOSITING_LOG));
+ PyModule_AddStringConstant(m, "ROLE_COLOR_TIMING", const_cast<char*>(ROLE_COLOR_TIMING));
+ PyModule_AddStringConstant(m, "ROLE_TEXTURE_PAINT", const_cast<char*>(ROLE_TEXTURE_PAINT));
+ PyModule_AddStringConstant(m, "ROLE_MATTE_PAINT", const_cast<char*>(ROLE_MATTE_PAINT));
+
+ // Add the module
+ PyModule_AddObject(enclosingModule, "Constants", m);
+ }
+
+
+ namespace
+ {
+
+ PyObject * PyOCIO_Constants_GetInverseTransformDirection( PyObject * /*module*/, PyObject * args )
+ {
+ try
+ {
+ char * s = 0;
+ if (!PyArg_ParseTuple(args,"s:GetInverseTransformDirection", s)) return NULL;
+
+ TransformDirection dir = TransformDirectionFromString(s);
+ dir = GetInverseTransformDirection(dir);
+ return PyString_FromString( TransformDirectionToString(dir) );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Constants_CombineTransformDirections( PyObject * /*module*/, PyObject * args )
+ {
+ try
+ {
+ char * s1 = 0;
+ char * s2 = 0;
+ if (!PyArg_ParseTuple(args,"ss:CombineTransformDirections", &s1, &s2)) return NULL;
+
+ TransformDirection dir1 = TransformDirectionFromString(s1);
+ TransformDirection dir2 = TransformDirectionFromString(s2);
+
+ TransformDirection dir = CombineTransformDirections(dir1, dir2);
+ return PyString_FromString( TransformDirectionToString(dir) );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Constants_BitDepthIsFloat( PyObject * /*module*/, PyObject * args )
+ {
+ try
+ {
+ char * s = 0;
+ if (!PyArg_ParseTuple(args,"s:BitDepthIsFloat", &s)) return NULL;
+
+ BitDepth bitdepth = BitDepthFromString(s);
+ return PyBool_FromLong( BitDepthIsFloat(bitdepth) );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Constants_BitDepthToInt( PyObject * /*module*/, PyObject * args )
+ {
+ try
+ {
+ char * s = 0;
+ if (!PyArg_ParseTuple(args,"s:BitDepthToInt", &s)) return NULL;
+
+ BitDepth bitdepth = BitDepthFromString(s);
+ return PyInt_FromLong( BitDepthToInt(bitdepth) );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/pyglue/PyConstants.h b/src/pyglue/PyConstants.h
new file mode 100644
index 0000000..28b1797
--- /dev/null
+++ b/src/pyglue/PyConstants.h
@@ -0,0 +1,41 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_PYOCIO_PYCONSTANTS_H
+#define INCLUDED_PYOCIO_PYCONSTANTS_H
+
+#include <PyOpenColorIO/PyOpenColorIO.h>
+
+OCIO_NAMESPACE_ENTER
+{
+ void AddConstantsModule(PyObject *enclosingModule);
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/pyglue/PyContext.cpp b/src/pyglue/PyContext.cpp
new file mode 100644
index 0000000..6a97aad
--- /dev/null
+++ b/src/pyglue/PyContext.cpp
@@ -0,0 +1,494 @@
+/*
+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 <Python.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "PyContext.h"
+#include "PyTransform.h"
+#include "PyUtil.h"
+#include "PyDoc.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ bool AddContextObjectToModule( PyObject* m )
+ {
+ PyOCIO_ContextType.tp_new = PyType_GenericNew;
+ if ( PyType_Ready(&PyOCIO_ContextType) < 0 ) return false;
+
+ Py_INCREF( &PyOCIO_ContextType );
+ PyModule_AddObject(m, "Context",
+ (PyObject *)&PyOCIO_ContextType);
+
+ return true;
+ }
+
+ PyObject * BuildConstPyContext(ConstContextRcPtr context)
+ {
+ if (!context)
+ {
+ Py_RETURN_NONE;
+ }
+
+ PyOCIO_Context * pycontext = PyObject_New(
+ PyOCIO_Context, (PyTypeObject * ) &PyOCIO_ContextType);
+
+ pycontext->constcppobj = new ConstContextRcPtr();
+ *pycontext->constcppobj = context;
+
+ pycontext->cppobj = new ContextRcPtr();
+ pycontext->isconst = true;
+
+ return ( PyObject * ) pycontext;
+ }
+
+ PyObject * BuildEditablePyContext(ContextRcPtr context)
+ {
+ if (!context)
+ {
+ Py_RETURN_NONE;
+ }
+
+ PyOCIO_Context * pycontext = PyObject_New(
+ PyOCIO_Context, (PyTypeObject * ) &PyOCIO_ContextType);
+
+ pycontext->constcppobj = new ConstContextRcPtr();
+ pycontext->cppobj = new ContextRcPtr();
+ *pycontext->cppobj = context;
+
+ pycontext->isconst = false;
+
+ return ( PyObject * ) pycontext;
+ }
+
+ bool IsPyContext(PyObject * pyobject)
+ {
+ if(!pyobject) return false;
+ return (PyObject_Type(pyobject) == (PyObject *) (&PyOCIO_ContextType));
+ }
+
+ bool IsPyContextEditable(PyObject * pyobject)
+ {
+ if(!IsPyContext(pyobject))
+ {
+ throw Exception("PyObject must be an OCIO.Context.");
+ }
+
+ PyOCIO_Context * pycontext = reinterpret_cast<PyOCIO_Context *> (pyobject);
+ return (!pycontext->isconst);
+ }
+
+ ConstContextRcPtr GetConstContext(PyObject * pyobject, bool allowCast)
+ {
+ if(!IsPyContext(pyobject))
+ {
+ throw Exception("PyObject must be an OCIO.Context.");
+ }
+
+ PyOCIO_Context * pycontext = reinterpret_cast<PyOCIO_Context *> (pyobject);
+ if(pycontext->isconst && pycontext->constcppobj)
+ {
+ return *pycontext->constcppobj;
+ }
+
+ if(allowCast && !pycontext->isconst && pycontext->cppobj)
+ {
+ return *pycontext->cppobj;
+ }
+
+ throw Exception("PyObject must be a valid OCIO.Context.");
+ }
+
+ ContextRcPtr GetEditableContext(PyObject * pyobject)
+ {
+ if(!IsPyContext(pyobject))
+ {
+ throw Exception("PyObject must be an OCIO.Context.");
+ }
+
+ PyOCIO_Context * pycontext = reinterpret_cast<PyOCIO_Context *> (pyobject);
+ if(!pycontext->isconst && pycontext->cppobj)
+ {
+ return *pycontext->cppobj;
+ }
+
+ throw Exception("PyObject must be an editable OCIO.Context.");
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ int PyOCIO_Context_init( PyOCIO_Context * self, PyObject * args, PyObject * kwds );
+ void PyOCIO_Context_delete( PyOCIO_Context * self, PyObject * args );
+ PyObject * PyOCIO_Context_isEditable( PyObject * self );
+ PyObject * PyOCIO_Context_createEditableCopy( PyObject * self );
+ PyObject * PyOCIO_Context_getCacheID( PyObject * self );
+
+ PyObject * PyOCIO_Context_getSearchPath( PyObject * self );
+ PyObject * PyOCIO_Context_setSearchPath( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_Context_getWorkingDir( PyObject * self );
+ PyObject * PyOCIO_Context_setWorkingDir( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_Context_getStringVar( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_Context_setStringVar( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_Context_loadEnvironment( PyObject * self );
+
+ PyObject * PyOCIO_Context_resolveStringVar( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_Context_resolveFileLocation( PyObject * self, PyObject *args );
+
+ ///////////////////////////////////////////////////////////////////////
+ ///
+
+ PyMethodDef PyOCIO_Context_methods[] = {
+ {"isEditable",
+ (PyCFunction) PyOCIO_Context_isEditable, METH_NOARGS, CONTEXT_ISEDITABLE__DOC__ },
+ {"createEditableCopy",
+ (PyCFunction) PyOCIO_Context_createEditableCopy, METH_NOARGS, CONTEXT_CREATEEDITABLECOPY__DOC__ },
+ {"getCacheID",
+ (PyCFunction) PyOCIO_Context_getCacheID, METH_NOARGS, CONTEXT_GETCACHEID__DOC__ },
+ {"getSearchPath",
+ (PyCFunction) PyOCIO_Context_getSearchPath, METH_NOARGS, CONTEXT_GETSEARCHPATH__DOC__ },
+ {"setSearchPath",
+ PyOCIO_Context_setSearchPath, METH_VARARGS, CONTEXT_SETSEARCHPATH__DOC__ },
+ {"getWorkingDir",
+ (PyCFunction) PyOCIO_Context_getWorkingDir, METH_NOARGS, CONTEXT_GETWORKINGDIR__DOC__ },
+ {"setWorkingDir",
+ PyOCIO_Context_setWorkingDir, METH_VARARGS, CONTEXT_SETWORKINGDIR__DOC__ },
+ {"getStringVar",
+ PyOCIO_Context_getStringVar, METH_VARARGS, CONTEXT_GETSTRINGVAR__DOC__ },
+ {"setStringVar",
+ PyOCIO_Context_setStringVar, METH_VARARGS, CONTEXT_SETSTRINGVAR__DOC__ },
+ {"loadEnvironment",
+ (PyCFunction) PyOCIO_Context_loadEnvironment, METH_NOARGS, CONTEXT_LOADENVIRONMENT__DOC__ },
+ {"resolveStringVar",
+ PyOCIO_Context_resolveStringVar, METH_VARARGS, CONTEXT_RESOLVESTRINGVAR__DOC__ },
+ {"resolveFileLocation",
+ PyOCIO_Context_resolveFileLocation, METH_VARARGS, CONTEXT_RESOLVEFILELOCATION__DOC__ },
+ {NULL, NULL, 0, NULL}
+ };
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyTypeObject PyOCIO_ContextType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, //ob_size
+ "OCIO.Context", //tp_name
+ sizeof(PyOCIO_Context), //tp_basicsize
+ 0, //tp_itemsize
+ (destructor)PyOCIO_Context_delete, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ 0, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
+ CONTEXT__DOC__, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ PyOCIO_Context_methods, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ 0, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ (initproc) PyOCIO_Context_init, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0, //tp_del
+ #if PY_VERSION_HEX > 0x02060000
+ 0, //tp_version_tag
+ #endif
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ ///////////////////////////////////////////////////////////////////////
+ ///
+ int PyOCIO_Context_init( PyOCIO_Context *self, PyObject * /*args*/, PyObject * /*kwds*/ )
+ {
+ ///////////////////////////////////////////////////////////////////
+ /// init pyobject fields
+
+ self->constcppobj = new ConstContextRcPtr();
+ self->cppobj = new ContextRcPtr();
+ self->isconst = true;
+
+ try
+ {
+ *self->cppobj = Context::Create();
+ self->isconst = false;
+ return 0;
+ }
+ catch ( const std::exception & e )
+ {
+ std::string message = "Cannot create context: ";
+ message += e.what();
+ PyErr_SetString( PyExc_RuntimeError, message.c_str() );
+ return -1;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+
+ void PyOCIO_Context_delete( PyOCIO_Context *self, PyObject * /*args*/ )
+ {
+ delete self->constcppobj;
+ delete self->cppobj;
+
+ self->ob_type->tp_free((PyObject*)self);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+
+ PyObject * PyOCIO_Context_isEditable( PyObject * self )
+ {
+ return PyBool_FromLong(IsPyContextEditable(self));
+ }
+
+ PyObject * PyOCIO_Context_createEditableCopy( PyObject * self )
+ {
+ try
+ {
+ ConstContextRcPtr context = GetConstContext(self, true);
+ ContextRcPtr copy = context->createEditableCopy();
+ return BuildEditablePyContext( copy );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Context_getCacheID( PyObject * self )
+ {
+ try
+ {
+ ConstContextRcPtr context = GetConstContext(self, true);
+ return PyString_FromString( context->getCacheID() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+
+ PyObject * PyOCIO_Context_getSearchPath( PyObject * self )
+ {
+ try
+ {
+ ConstContextRcPtr context = GetConstContext(self, true);
+ return PyString_FromString( context->getSearchPath() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Context_setSearchPath( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * path = 0;
+ if (!PyArg_ParseTuple(args,"s:setSearchPath", &path)) return NULL;
+
+ ContextRcPtr context = GetEditableContext(self);
+ context->setSearchPath( path );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Context_getWorkingDir( PyObject * self )
+ {
+ try
+ {
+ ConstContextRcPtr context = GetConstContext(self, true);
+ return PyString_FromString( context->getWorkingDir() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Context_setWorkingDir( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * dirname = 0;
+ if (!PyArg_ParseTuple(args,"s:setWorkingDir", &dirname)) return NULL;
+
+ ContextRcPtr context = GetEditableContext(self);
+ context->setWorkingDir( dirname );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Context_getStringVar( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * name = 0;
+ if (!PyArg_ParseTuple(args,"s:getStringVar", &name)) return NULL;
+
+ ConstContextRcPtr context = GetConstContext(self, true);
+ return PyString_FromString( context->getStringVar(name) );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Context_setStringVar( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * name = 0;
+ char * value = 0;
+ if (!PyArg_ParseTuple(args,"ss:setStringVar", &name, &value)) return NULL;
+
+ ContextRcPtr context = GetEditableContext(self);
+ context->setStringVar( name, value );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Context_loadEnvironment( PyObject * self )
+ {
+ try
+ {
+ ContextRcPtr context = GetEditableContext(self);
+ context->loadEnvironment();
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Context_resolveStringVar( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * str = 0;
+ if (!PyArg_ParseTuple(args,"s:resolveStringVar", &str)) return NULL;
+
+ ConstContextRcPtr context = GetConstContext(self, true);
+ return PyString_FromString( context->resolveStringVar(str) );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Context_resolveFileLocation( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * filename = 0;
+ if (!PyArg_ParseTuple(args,"s:resolveFileLocation", &filename)) return NULL;
+
+ ConstContextRcPtr context = GetConstContext(self, true);
+ return PyString_FromString( context->resolveFileLocation(filename) );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/pyglue/PyContext.h b/src/pyglue/PyContext.h
new file mode 100644
index 0000000..02e5623
--- /dev/null
+++ b/src/pyglue/PyContext.h
@@ -0,0 +1,52 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_PYOCIO_PYCONTEXT_H
+#define INCLUDED_PYOCIO_PYCONTEXT_H
+
+#include <PyOpenColorIO/PyOpenColorIO.h>
+
+OCIO_NAMESPACE_ENTER
+{
+ // TODO: Maybe put this in a pyinternal namespace?
+
+ typedef struct {
+ PyObject_HEAD
+ ConstContextRcPtr * constcppobj;
+ ContextRcPtr * cppobj;
+ bool isconst;
+ } PyOCIO_Context;
+
+ extern PyTypeObject PyOCIO_ContextType;
+
+ bool AddContextObjectToModule( PyObject* m );
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/pyglue/PyDisplayTransform.cpp b/src/pyglue/PyDisplayTransform.cpp
new file mode 100644
index 0000000..6a29153
--- /dev/null
+++ b/src/pyglue/PyDisplayTransform.cpp
@@ -0,0 +1,577 @@
+/*
+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 <Python.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "PyTransform.h"
+#include "PyUtil.h"
+#include "PyDoc.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ bool AddDisplayTransformObjectToModule( PyObject* m )
+ {
+ PyOCIO_DisplayTransformType.tp_new = PyType_GenericNew;
+ if ( PyType_Ready(&PyOCIO_DisplayTransformType) < 0 ) return false;
+
+ Py_INCREF( &PyOCIO_DisplayTransformType );
+ PyModule_AddObject(m, "DisplayTransform",
+ (PyObject *)&PyOCIO_DisplayTransformType);
+
+ return true;
+ }
+
+ bool IsPyDisplayTransform(PyObject * pyobject)
+ {
+ if(!pyobject) return false;
+ return PyObject_TypeCheck(pyobject, &PyOCIO_DisplayTransformType);
+ }
+
+ ConstDisplayTransformRcPtr GetConstDisplayTransform(PyObject * pyobject, bool allowCast)
+ {
+ ConstDisplayTransformRcPtr transform = \
+ DynamicPtrCast<const DisplayTransform>(GetConstTransform(pyobject, allowCast));
+ if(!transform)
+ {
+ throw Exception("PyObject must be a valid OCIO.DisplayTransform.");
+ }
+ return transform;
+ }
+
+ DisplayTransformRcPtr GetEditableDisplayTransform(PyObject * pyobject)
+ {
+ DisplayTransformRcPtr transform = \
+ DynamicPtrCast<DisplayTransform>(GetEditableTransform(pyobject));
+ if(!transform)
+ {
+ throw Exception("PyObject must be a valid OCIO.DisplayTransform.");
+ }
+ return transform;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ int PyOCIO_DisplayTransform_init( PyOCIO_Transform * self, PyObject * args, PyObject * kwds );
+
+ PyObject * PyOCIO_DisplayTransform_getInputColorSpaceName( PyObject * self );
+ PyObject * PyOCIO_DisplayTransform_setInputColorSpaceName( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_DisplayTransform_getLinearCC( PyObject * self );
+ PyObject * PyOCIO_DisplayTransform_setLinearCC( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_DisplayTransform_getColorTimingCC( PyObject * self );
+ PyObject * PyOCIO_DisplayTransform_setColorTimingCC( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_DisplayTransform_getChannelView( PyObject * self );
+ PyObject * PyOCIO_DisplayTransform_setChannelView( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_DisplayTransform_getDisplay( PyObject * self );
+ PyObject * PyOCIO_DisplayTransform_setDisplay( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_DisplayTransform_getView( PyObject * self );
+ PyObject * PyOCIO_DisplayTransform_setView( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_DisplayTransform_getDisplayCC( PyObject * self );
+ PyObject * PyOCIO_DisplayTransform_setDisplayCC( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_DisplayTransform_getLooksOverride( PyObject * self );
+ PyObject * PyOCIO_DisplayTransform_setLooksOverride( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_DisplayTransform_getLooksOverrideEnabled( PyObject * self );
+ PyObject * PyOCIO_DisplayTransform_setLooksOverrideEnabled( PyObject * self, PyObject *args );
+
+ ///////////////////////////////////////////////////////////////////////
+ ///
+
+ PyMethodDef PyOCIO_DisplayTransform_methods[] = {
+ {"getInputColorSpaceName",
+ (PyCFunction) PyOCIO_DisplayTransform_getInputColorSpaceName, METH_NOARGS, DISPLAYTRANSFORM_GETINPUTCOLORSPACENAME__DOC__ },
+ {"setInputColorSpaceName",
+ PyOCIO_DisplayTransform_setInputColorSpaceName, METH_VARARGS, DISPLAYTRANSFORM_SETINPUTCOLORSPACENAME__DOC__ },
+ {"getLinearCC",
+ (PyCFunction) PyOCIO_DisplayTransform_getLinearCC, METH_NOARGS, DISPLAYTRANSFORM_GETLINEARCC__DOC__ },
+ {"setLinearCC",
+ PyOCIO_DisplayTransform_setLinearCC, METH_VARARGS, DISPLAYTRANSFORM_SETLINEARCC__DOC__ },
+ {"getColorTimingCC",
+ (PyCFunction) PyOCIO_DisplayTransform_getColorTimingCC, METH_NOARGS, DISPLAYTRANSFORM_GETCOLORTIMINGCC__DOC__ },
+ {"setColorTimingCC",
+ PyOCIO_DisplayTransform_setColorTimingCC, METH_VARARGS, DISPLAYTRANSFORM_SETCOLORTIMINGCC__DOC__ },
+ {"getChannelView",
+ (PyCFunction) PyOCIO_DisplayTransform_getChannelView, METH_NOARGS, DISPLAYTRANSFORM_GETCHANNELVIEW__DOC__ },
+ {"setChannelView",
+ PyOCIO_DisplayTransform_setChannelView, METH_VARARGS, DISPLAYTRANSFORM_SETCHANNELVIEW__DOC__ },
+ {"getDisplay",
+ (PyCFunction) PyOCIO_DisplayTransform_getDisplay, METH_NOARGS, DISPLAYTRANSFORM_GETDISPLAY__DOC__ },
+ {"setDisplay",
+ PyOCIO_DisplayTransform_setDisplay, METH_VARARGS, DISPLAYTRANSFORM_SETDISPLAY__DOC__ },
+ {"getView",
+ (PyCFunction) PyOCIO_DisplayTransform_getView, METH_NOARGS, DISPLAYTRANSFORM_GETVIEW__DOC__ },
+ {"setView",
+ PyOCIO_DisplayTransform_setView, METH_VARARGS, DISPLAYTRANSFORM_SETVIEW__DOC__ },
+ {"getDisplayCC",
+ (PyCFunction) PyOCIO_DisplayTransform_getDisplayCC, METH_NOARGS, DISPLAYTRANSFORM_GETDISPLAYCC__DOC__ },
+ {"setDisplayCC",
+ PyOCIO_DisplayTransform_setDisplayCC, METH_VARARGS, DISPLAYTRANSFORM_SETDISPLAYCC__DOC__ },
+ {"getLooksOverride",
+ (PyCFunction) PyOCIO_DisplayTransform_getLooksOverride, METH_NOARGS, DISPLAYTRANSFORM_GETLOOKSOVERRIDE__DOC__ },
+ {"setLooksOverride",
+ PyOCIO_DisplayTransform_setLooksOverride, METH_VARARGS, DISPLAYTRANSFORM_SETLOOKSOVERRIDE__DOC__ },
+ {"getLooksOverrideEnabled",
+ (PyCFunction) PyOCIO_DisplayTransform_getLooksOverrideEnabled, METH_NOARGS, DISPLAYTRANSFORM_GETLOOKSOVERRIDEENABLED__DOC__ },
+ {"setLooksOverrideEnabled",
+ PyOCIO_DisplayTransform_setLooksOverrideEnabled, METH_VARARGS, DISPLAYTRANSFORM_SETLOOKSOVERRIDEENABLED__DOC__ },
+ {NULL, NULL, 0, NULL}
+ };
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyTypeObject PyOCIO_DisplayTransformType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, //ob_size
+ "OCIO.DisplayTransform", //tp_name
+ sizeof(PyOCIO_Transform), //tp_basicsize
+ 0, //tp_itemsize
+ 0, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ 0, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
+ DISPLAYTRANSFORM__DOC__, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ PyOCIO_DisplayTransform_methods, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ &PyOCIO_TransformType, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ (initproc) PyOCIO_DisplayTransform_init, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0, //tp_del
+ #if PY_VERSION_HEX > 0x02060000
+ 0, //tp_version_tag
+ #endif
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ ///////////////////////////////////////////////////////////////////////
+ ///
+
+ int PyOCIO_DisplayTransform_init( PyOCIO_Transform *self, PyObject * /*args*/, PyObject * /*kwds*/ )
+ {
+ ///////////////////////////////////////////////////////////////////
+ /// init pyobject fields
+
+ self->constcppobj = new ConstTransformRcPtr();
+ self->cppobj = new TransformRcPtr();
+ self->isconst = true;
+
+ try
+ {
+ *self->cppobj = DisplayTransform::Create();
+ self->isconst = false;
+ return 0;
+ }
+ catch ( const std::exception & e )
+ {
+ std::string message = "Cannot create DisplayTransform: ";
+ message += e.what();
+ PyErr_SetString( PyExc_RuntimeError, message.c_str() );
+ return -1;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_DisplayTransform_getInputColorSpaceName( PyObject * self )
+ {
+ try
+ {
+ ConstDisplayTransformRcPtr transform = GetConstDisplayTransform(self, true);
+ return PyString_FromString( transform->getInputColorSpaceName() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_DisplayTransform_setInputColorSpaceName( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * name = 0;
+ if (!PyArg_ParseTuple(args,"s:setInputColorSpaceName", &name)) return NULL;
+
+ DisplayTransformRcPtr transform = GetEditableDisplayTransform(self);
+ transform->setInputColorSpaceName( name );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_DisplayTransform_getLinearCC( PyObject * self )
+ {
+ try
+ {
+ ConstDisplayTransformRcPtr transform = GetConstDisplayTransform(self, true);
+ return BuildConstPyTransform(transform->getLinearCC());
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_DisplayTransform_setLinearCC( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyCC = 0;
+ if (!PyArg_ParseTuple(args,"O:setLinearCC", &pyCC)) return NULL;
+
+ DisplayTransformRcPtr transform = GetEditableDisplayTransform(self);
+
+ ConstTransformRcPtr cc = GetConstTransform(pyCC, true);
+ transform->setLinearCC(cc);
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_DisplayTransform_getColorTimingCC( PyObject * self )
+ {
+ try
+ {
+ ConstDisplayTransformRcPtr transform = GetConstDisplayTransform(self, true);
+ return BuildConstPyTransform(transform->getColorTimingCC());
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_DisplayTransform_setColorTimingCC( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyCC = 0;
+ if (!PyArg_ParseTuple(args,"O:setColorTimingCC", &pyCC)) return NULL;
+
+ DisplayTransformRcPtr transform = GetEditableDisplayTransform(self);
+
+ ConstTransformRcPtr cc = GetConstTransform(pyCC, true);
+ transform->setColorTimingCC(cc);
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_DisplayTransform_getChannelView( PyObject * self )
+ {
+ try
+ {
+ ConstDisplayTransformRcPtr transform = GetConstDisplayTransform(self, true);
+ return BuildConstPyTransform(transform->getChannelView());
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_DisplayTransform_setChannelView( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyCC = 0;
+ if (!PyArg_ParseTuple(args,"O:setChannelView", &pyCC)) return NULL;
+
+ DisplayTransformRcPtr transform = GetEditableDisplayTransform(self);
+
+ ConstTransformRcPtr t = GetConstTransform(pyCC, true);
+ transform->setChannelView(t);
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_DisplayTransform_getDisplay( PyObject * self )
+ {
+ try
+ {
+ ConstDisplayTransformRcPtr transform = GetConstDisplayTransform(self, true);
+ return PyString_FromString( transform->getDisplay() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_DisplayTransform_setDisplay( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * str = 0;
+ if (!PyArg_ParseTuple(args,"s:setDisplay", &str)) return NULL;
+
+ DisplayTransformRcPtr transform = GetEditableDisplayTransform(self);
+ transform->setDisplay( str );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_DisplayTransform_getView( PyObject * self )
+ {
+ try
+ {
+ ConstDisplayTransformRcPtr transform = GetConstDisplayTransform(self, true);
+ return PyString_FromString( transform->getView() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_DisplayTransform_setView( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * str = 0;
+ if (!PyArg_ParseTuple(args,"s:setView", &str)) return NULL;
+
+ DisplayTransformRcPtr transform = GetEditableDisplayTransform(self);
+ transform->setView( str );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_DisplayTransform_getDisplayCC( PyObject * self )
+ {
+ try
+ {
+ ConstDisplayTransformRcPtr transform = GetConstDisplayTransform(self, true);
+ return BuildConstPyTransform(transform->getDisplayCC());
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_DisplayTransform_setDisplayCC( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyCC = 0;
+ if (!PyArg_ParseTuple(args,"O:setDisplayCC", &pyCC)) return NULL;
+
+ DisplayTransformRcPtr transform = GetEditableDisplayTransform(self);
+
+ ConstTransformRcPtr cc = GetConstTransform(pyCC, true);
+ transform->setDisplayCC(cc);
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_DisplayTransform_getLooksOverride( PyObject * self )
+ {
+ try
+ {
+ ConstDisplayTransformRcPtr transform = GetConstDisplayTransform(self, true);
+ return PyString_FromString( transform->getLooksOverride() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_DisplayTransform_setLooksOverride( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * str = 0;
+ if (!PyArg_ParseTuple(args,"s:setLooksOverride", &str)) return NULL;
+
+ DisplayTransformRcPtr transform = GetEditableDisplayTransform(self);
+ transform->setLooksOverride( str );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_DisplayTransform_getLooksOverrideEnabled( PyObject * self )
+ {
+ try
+ {
+ ConstDisplayTransformRcPtr transform = GetConstDisplayTransform(self, true);
+ return PyBool_FromLong( transform->getLooksOverrideEnabled() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_DisplayTransform_setLooksOverrideEnabled( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ bool enabled = false;
+ if (!PyArg_ParseTuple(args,"O&:setLooksOverrideEnabled",
+ ConvertPyObjectToBool, &enabled)) return NULL;
+
+ DisplayTransformRcPtr transform = GetEditableDisplayTransform(self);
+ transform->setLooksOverrideEnabled( enabled );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/pyglue/PyExponentTransform.cpp b/src/pyglue/PyExponentTransform.cpp
new file mode 100644
index 0000000..2fa7ba3
--- /dev/null
+++ b/src/pyglue/PyExponentTransform.cpp
@@ -0,0 +1,269 @@
+/*
+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 <Python.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "PyTransform.h"
+#include "PyUtil.h"
+#include "PyDoc.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ bool AddExponentTransformObjectToModule( PyObject* m )
+ {
+ PyOCIO_ExponentTransformType.tp_new = PyType_GenericNew;
+ if ( PyType_Ready(&PyOCIO_ExponentTransformType) < 0 ) return false;
+
+ Py_INCREF( &PyOCIO_ExponentTransformType );
+ PyModule_AddObject(m, "ExponentTransform",
+ (PyObject *)&PyOCIO_ExponentTransformType);
+
+ return true;
+ }
+
+ bool IsPyExponentTransform(PyObject * pyobject)
+ {
+ if(!pyobject) return false;
+ return PyObject_TypeCheck(pyobject, &PyOCIO_ExponentTransformType);
+ }
+
+ ConstExponentTransformRcPtr GetConstExponentTransform(PyObject * pyobject, bool allowCast)
+ {
+ ConstExponentTransformRcPtr transform = \
+ DynamicPtrCast<const ExponentTransform>(GetConstTransform(pyobject, allowCast));
+ if(!transform)
+ {
+ throw Exception("PyObject must be a valid OCIO.ExponentTransform.");
+ }
+ return transform;
+ }
+
+ ExponentTransformRcPtr GetEditableExponentTransform(PyObject * pyobject)
+ {
+ ExponentTransformRcPtr transform = \
+ DynamicPtrCast<ExponentTransform>(GetEditableTransform(pyobject));
+ if(!transform)
+ {
+ throw Exception("PyObject must be a valid OCIO.ExponentTransform.");
+ }
+ return transform;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ int PyOCIO_ExponentTransform_init( PyOCIO_Transform * self, PyObject * args, PyObject * kwds );
+
+ PyObject * PyOCIO_ExponentTransform_getValue( PyObject * self );
+ PyObject * PyOCIO_ExponentTransform_setValue( PyObject * self, PyObject *args );
+
+ ///////////////////////////////////////////////////////////////////////
+ ///
+
+ PyMethodDef PyOCIO_ExponentTransform_methods[] = {
+ {"getValue",
+ (PyCFunction) PyOCIO_ExponentTransform_getValue, METH_NOARGS, EXPONENTTRANSFORM_GETVALUE__DOC__ },
+ {"setValue",
+ PyOCIO_ExponentTransform_setValue, METH_VARARGS, EXPONENTTRANSFORM_SETVALUE__DOC__ },
+ {NULL, NULL, 0, NULL}
+ };
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyTypeObject PyOCIO_ExponentTransformType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, //ob_size
+ "OCIO.ExponentTransform", //tp_name
+ sizeof(PyOCIO_Transform), //tp_basicsize
+ 0, //tp_itemsize
+ 0, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ 0, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
+ EXPONENTTRANSFORM__DOC__, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ PyOCIO_ExponentTransform_methods, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ &PyOCIO_TransformType, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ (initproc) PyOCIO_ExponentTransform_init, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0, //tp_del
+ #if PY_VERSION_HEX > 0x02060000
+ 0, //tp_version_tag
+ #endif
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ ///////////////////////////////////////////////////////////////////////
+ ///
+ int PyOCIO_ExponentTransform_init( PyOCIO_Transform *self,
+ PyObject * args, PyObject * kwds )
+ {
+ ///////////////////////////////////////////////////////////////////
+ /// init pyobject fields
+
+ self->constcppobj = new ConstTransformRcPtr();
+ self->cppobj = new TransformRcPtr();
+ self->isconst = true;
+
+ // Parse optional kwargs
+ PyObject * pyvalue = Py_None;
+ char * direction = NULL;
+
+ static const char *kwlist[] = {
+ "value",
+ "direction",
+ NULL
+ };
+
+ if(!PyArg_ParseTupleAndKeywords(args, kwds, "|Os",
+ const_cast<char **>(kwlist),
+ &pyvalue, &direction )) return -1;
+
+ try
+ {
+ ExponentTransformRcPtr transform = ExponentTransform::Create();
+ *self->cppobj = transform;
+ self->isconst = false;
+
+ if(pyvalue != Py_None)
+ {
+ std::vector<float> data;
+ if(!FillFloatVectorFromPySequence(pyvalue, data) || (data.size() != 4))
+ {
+ PyErr_SetString(PyExc_TypeError, "Value argument must be a float array, size 4");
+ return -1;
+ }
+
+ transform->setValue( &data[0] );
+ }
+ if(direction) transform->setDirection(TransformDirectionFromString(direction));
+ return 0;
+ }
+ catch ( const std::exception & e )
+ {
+ std::string message = "Cannot create ExponentTransform: ";
+ message += e.what();
+ PyErr_SetString( PyExc_RuntimeError, message.c_str() );
+ return -1;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_ExponentTransform_getValue( PyObject * self )
+ {
+ try
+ {
+ ConstExponentTransformRcPtr transform = GetConstExponentTransform(self, true);
+ std::vector<float> data(4);
+ transform->getValue(&data[0]);
+ return CreatePyListFromFloatVector(data);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_ExponentTransform_setValue( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyData = 0;
+ if (!PyArg_ParseTuple(args,"O:setValue", &pyData)) return NULL;
+ ExponentTransformRcPtr transform = GetEditableExponentTransform(self);
+
+ std::vector<float> data;
+ if(!FillFloatVectorFromPySequence(pyData, data) || (data.size() != 4))
+ {
+ PyErr_SetString(PyExc_TypeError, "First argument must be a float array, size 4");
+ return 0;
+ }
+
+ transform->setValue( &data[0] );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/pyglue/PyFileTransform.cpp b/src/pyglue/PyFileTransform.cpp
new file mode 100644
index 0000000..2e85232
--- /dev/null
+++ b/src/pyglue/PyFileTransform.cpp
@@ -0,0 +1,344 @@
+/*
+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 <Python.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "PyTransform.h"
+#include "PyUtil.h"
+#include "PyDoc.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ bool AddFileTransformObjectToModule( PyObject* m )
+ {
+ PyOCIO_FileTransformType.tp_new = PyType_GenericNew;
+ if ( PyType_Ready(&PyOCIO_FileTransformType) < 0 ) return false;
+
+ Py_INCREF( &PyOCIO_FileTransformType );
+ PyModule_AddObject(m, "FileTransform",
+ (PyObject *)&PyOCIO_FileTransformType);
+
+ return true;
+ }
+
+ bool IsPyFileTransform(PyObject * pyobject)
+ {
+ if(!pyobject) return false;
+ return PyObject_TypeCheck(pyobject, &PyOCIO_FileTransformType);
+ }
+
+ ConstFileTransformRcPtr GetConstFileTransform(PyObject * pyobject, bool allowCast)
+ {
+ ConstFileTransformRcPtr transform = \
+ DynamicPtrCast<const FileTransform>(GetConstTransform(pyobject, allowCast));
+ if(!transform)
+ {
+ throw Exception("PyObject must be a valid OCIO.FileTransform.");
+ }
+ return transform;
+ }
+
+ FileTransformRcPtr GetEditableFileTransform(PyObject * pyobject)
+ {
+ FileTransformRcPtr transform = \
+ DynamicPtrCast<FileTransform>(GetEditableTransform(pyobject));
+ if(!transform)
+ {
+ throw Exception("PyObject must be a valid OCIO.FileTransform.");
+ }
+ return transform;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ int PyOCIO_FileTransform_init( PyOCIO_Transform * self, PyObject * args, PyObject * kwds );
+
+ PyObject * PyOCIO_FileTransform_getSrc( PyObject * self );
+ PyObject * PyOCIO_FileTransform_setSrc( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_FileTransform_getCCCId( PyObject * self );
+ PyObject * PyOCIO_FileTransform_setCCCId( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_FileTransform_getInterpolation( PyObject * self );
+ PyObject * PyOCIO_FileTransform_setInterpolation( PyObject * self, PyObject *args );
+
+ ///////////////////////////////////////////////////////////////////////
+ ///
+
+ PyMethodDef PyOCIO_FileTransform_methods[] = {
+ {"getSrc",
+ (PyCFunction) PyOCIO_FileTransform_getSrc, METH_NOARGS, FILETRANSFORM_GETSRC__DOC__ },
+ {"setSrc",
+ PyOCIO_FileTransform_setSrc, METH_VARARGS, FILETRANSFORM_SETSRC__DOC__ },
+ {"getCCCId",
+ (PyCFunction) PyOCIO_FileTransform_getCCCId, METH_NOARGS, FILETRANSFORM_GETCCCID__DOC__ },
+ {"setCCCId",
+ PyOCIO_FileTransform_setCCCId, METH_VARARGS, FILETRANSFORM_SETCCCID__DOC__ },
+ {"getInterpolation",
+ (PyCFunction) PyOCIO_FileTransform_getInterpolation, METH_NOARGS, FILETRANSFORM_GETINTERPOLATION__DOC__ },
+ {"setInterpolation",
+ PyOCIO_FileTransform_setInterpolation, METH_VARARGS, FILETRANSFORM_SETINTERPOLATION__DOC__ },
+ {NULL, NULL, 0, NULL}
+ };
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyTypeObject PyOCIO_FileTransformType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, //ob_size
+ "OCIO.FileTransform", //tp_name
+ sizeof(PyOCIO_Transform), //tp_basicsize
+ 0, //tp_itemsize
+ 0, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ 0, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
+ FILETRANSFORM__DOC__, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ PyOCIO_FileTransform_methods, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ &PyOCIO_TransformType, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ (initproc) PyOCIO_FileTransform_init, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0, //tp_del
+ #if PY_VERSION_HEX > 0x02060000
+ 0, //tp_version_tag
+ #endif
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ ///////////////////////////////////////////////////////////////////////
+ ///
+ int PyOCIO_FileTransform_init( PyOCIO_Transform *self,
+ PyObject * args, PyObject * kwds )
+ {
+ ///////////////////////////////////////////////////////////////////
+ /// init pyobject fields
+
+ self->constcppobj = new ConstTransformRcPtr();
+ self->cppobj = new TransformRcPtr();
+ self->isconst = true;
+
+ // Parse optional kwargs
+ char * src = NULL;
+ char * cccid = NULL;
+ char * interpolation = NULL;
+ char * direction = NULL;
+
+ static const char *kwlist[] = {
+ "src",
+ "cccid",
+ "interpolation",
+ "direction",
+ NULL
+ };
+
+ if(!PyArg_ParseTupleAndKeywords(args, kwds, "|ssss",
+ const_cast<char **>(kwlist),
+ &src, &cccid, &interpolation, &direction )) return -1;
+
+ try
+ {
+ FileTransformRcPtr transform = FileTransform::Create();
+ *self->cppobj = transform;
+ self->isconst = false;
+
+ if(src) transform->setSrc(src);
+ if(cccid) transform->setCCCId(cccid);
+ if(interpolation) transform->setInterpolation(InterpolationFromString(interpolation));
+ if(direction) transform->setDirection(TransformDirectionFromString(direction));
+
+ return 0;
+ }
+ catch ( const std::exception & e )
+ {
+ std::string message = "Cannot create FileTransform: ";
+ message += e.what();
+ PyErr_SetString( PyExc_RuntimeError, message.c_str() );
+ return -1;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_FileTransform_getSrc( PyObject * self )
+ {
+ try
+ {
+ ConstFileTransformRcPtr transform = GetConstFileTransform(self, true);
+ return PyString_FromString( transform->getSrc() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_FileTransform_setSrc( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * src = 0;
+ if (!PyArg_ParseTuple(args,"s:setSrc", &src)) return NULL;
+
+ FileTransformRcPtr transform = GetEditableFileTransform(self);
+ transform->setSrc( src );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_FileTransform_getCCCId( PyObject * self )
+ {
+ try
+ {
+ ConstFileTransformRcPtr transform = GetConstFileTransform(self, true);
+ return PyString_FromString( transform->getCCCId() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_FileTransform_setCCCId( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * id = 0;
+ if (!PyArg_ParseTuple(args,"s:setCCCId", &id)) return NULL;
+
+ FileTransformRcPtr transform = GetEditableFileTransform(self);
+ transform->setCCCId( id );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_FileTransform_getInterpolation( PyObject * self )
+ {
+ try
+ {
+ ConstFileTransformRcPtr transform = GetConstFileTransform(self, true);
+ Interpolation interp = transform->getInterpolation();
+ return PyString_FromString( InterpolationToString( interp ) );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_FileTransform_setInterpolation( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ Interpolation interp;
+ if (!PyArg_ParseTuple(args,"O&:setInterpolation",
+ ConvertPyObjectToInterpolation, &interp)) return NULL;
+
+ FileTransformRcPtr transform = GetEditableFileTransform(self);
+ transform->setInterpolation(interp);
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/pyglue/PyGroupTransform.cpp b/src/pyglue/PyGroupTransform.cpp
new file mode 100644
index 0000000..32f5b8d
--- /dev/null
+++ b/src/pyglue/PyGroupTransform.cpp
@@ -0,0 +1,397 @@
+/*
+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 <Python.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "PyTransform.h"
+#include "PyUtil.h"
+#include "PyDoc.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ bool AddGroupTransformObjectToModule( PyObject* m )
+ {
+ PyOCIO_GroupTransformType.tp_new = PyType_GenericNew;
+ if ( PyType_Ready(&PyOCIO_GroupTransformType) < 0 ) return false;
+
+ Py_INCREF( &PyOCIO_GroupTransformType );
+ PyModule_AddObject(m, "GroupTransform",
+ (PyObject *)&PyOCIO_GroupTransformType);
+
+ return true;
+ }
+
+ bool IsPyGroupTransform(PyObject * pyobject)
+ {
+ if(!pyobject) return false;
+ return PyObject_TypeCheck(pyobject, &PyOCIO_GroupTransformType);
+ }
+
+ ConstGroupTransformRcPtr GetConstGroupTransform(PyObject * pyobject, bool allowCast)
+ {
+ ConstGroupTransformRcPtr transform = \
+ DynamicPtrCast<const GroupTransform>(GetConstTransform(pyobject, allowCast));
+ if(!transform)
+ {
+ throw Exception("PyObject must be a valid OCIO.GroupTransform.");
+ }
+ return transform;
+ }
+
+ GroupTransformRcPtr GetEditableGroupTransform(PyObject * pyobject)
+ {
+ GroupTransformRcPtr transform = \
+ DynamicPtrCast<GroupTransform>(GetEditableTransform(pyobject));
+ if(!transform)
+ {
+ throw Exception("PyObject must be a valid OCIO.GroupTransform.");
+ }
+ return transform;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ int PyOCIO_GroupTransform_init( PyOCIO_Transform * self, PyObject * args, PyObject * kwds );
+
+ PyObject * PyOCIO_GroupTransform_getTransform( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_GroupTransform_getTransforms( PyObject * self );
+ PyObject * PyOCIO_GroupTransform_setTransforms( PyObject * self, PyObject *args );
+
+ // TODO: make these appear more like a pysequence. .append, len(), etc
+
+ PyObject * PyOCIO_GroupTransform_size( PyObject * self );
+ PyObject * PyOCIO_GroupTransform_push_back( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_GroupTransform_clear( PyObject * self );
+ PyObject * PyOCIO_GroupTransform_empty( PyObject * self );
+
+ ///////////////////////////////////////////////////////////////////////
+ ///
+
+ PyMethodDef PyOCIO_GroupTransform_methods[] = {
+ {"getTransform",
+ PyOCIO_GroupTransform_getTransform, METH_VARARGS, GROUPTRANSFORM_GETTRANSFORM__DOC__ },
+ {"getTransforms",
+ (PyCFunction) PyOCIO_GroupTransform_getTransforms, METH_NOARGS, GROUPTRANSFORM_GETTRANSFORMS__DOC__ },
+ {"setTransforms",
+ PyOCIO_GroupTransform_setTransforms, METH_VARARGS, GROUPTRANSFORM_SETTRANSFORMS__DOC__ },
+ {"size",
+ (PyCFunction) PyOCIO_GroupTransform_size, METH_NOARGS, GROUPTRANSFORM_SIZE__DOC__ },
+ {"push_back",
+ PyOCIO_GroupTransform_push_back, METH_VARARGS, GROUPTRANSFORM_PUSH_BACK__DOC__ },
+ {"clear",
+ (PyCFunction) PyOCIO_GroupTransform_clear, METH_NOARGS, GROUPTRANSFORM_CLEAR__DOC__ },
+ {"empty",
+ (PyCFunction) PyOCIO_GroupTransform_empty, METH_NOARGS, GROUPTRANSFORM_EMPTY__DOC__ },
+ {NULL, NULL, 0, NULL}
+ };
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyTypeObject PyOCIO_GroupTransformType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, //ob_size
+ "OCIO.GroupTransform", //tp_name
+ sizeof(PyOCIO_Transform), //tp_basicsize
+ 0, //tp_itemsize
+ 0, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ 0, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
+ GROUPTRANSFORM__DOC__, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ PyOCIO_GroupTransform_methods, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ &PyOCIO_TransformType, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ (initproc) PyOCIO_GroupTransform_init, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0, //tp_del
+ #if PY_VERSION_HEX > 0x02060000
+ 0, //tp_version_tag
+ #endif
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ ///////////////////////////////////////////////////////////////////////
+ ///
+ int PyOCIO_GroupTransform_init( PyOCIO_Transform *self,
+ PyObject * args, PyObject * kwds )
+ {
+ ///////////////////////////////////////////////////////////////////
+ /// init pyobject fields
+
+ self->constcppobj = new ConstTransformRcPtr();
+ self->cppobj = new TransformRcPtr();
+ self->isconst = true;
+
+ // Parse optional kwargs
+ PyObject * pytransforms = Py_None;
+ char * direction = NULL;
+
+ static const char *kwlist[] = {
+ "transforms",
+ "direction",
+ NULL
+ };
+
+ if(!PyArg_ParseTupleAndKeywords(args, kwds, "|Os",
+ const_cast<char **>(kwlist),
+ &pytransforms, &direction )) return -1;
+
+ try
+ {
+ GroupTransformRcPtr transform = GroupTransform::Create();
+ *self->cppobj = transform;
+ self->isconst = false;
+
+ if(pytransforms != Py_None)
+ {
+ std::vector<ConstTransformRcPtr> data;
+ if(!FillTransformVectorFromPySequence(pytransforms, data))
+ {
+ PyErr_SetString(PyExc_TypeError, "Kwarg 'transforms' must be a transform array.");
+ return -1;
+ }
+
+ for(unsigned int i=0; i<data.size(); ++i)
+ {
+ transform->push_back( data[i] );
+ }
+ }
+
+ if(direction) transform->setDirection(TransformDirectionFromString(direction));
+
+ return 0;
+ }
+ catch ( const std::exception & e )
+ {
+ std::string message = "Cannot create GroupTransform: ";
+ message += e.what();
+ PyErr_SetString( PyExc_RuntimeError, message.c_str() );
+ return -1;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_GroupTransform_getTransform( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ int index = 0;
+
+ if (!PyArg_ParseTuple(args,"i:getTransform", &index)) return NULL;
+
+ ConstGroupTransformRcPtr transform = GetConstGroupTransform(self, true);
+ ConstTransformRcPtr childTransform = transform->getTransform(index);
+
+ return BuildConstPyTransform(childTransform);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_GroupTransform_getTransforms( PyObject * self)
+ {
+ try
+ {
+ ConstGroupTransformRcPtr transform = GetConstGroupTransform(self, true);
+
+ std::vector<ConstTransformRcPtr> transforms;
+ for(int i=0; i<transform->size(); ++i)
+ {
+ transforms.push_back(transform->getTransform(i));
+ }
+
+ return CreatePyListFromTransformVector(transforms);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_GroupTransform_setTransforms( PyObject * self, PyObject *args )
+ {
+ try
+ {
+ PyObject * pytransforms = 0;
+
+ if (!PyArg_ParseTuple(args,"O:setTransforms", &pytransforms)) return NULL;
+
+ GroupTransformRcPtr transform = GetEditableGroupTransform(self);
+
+ std::vector<ConstTransformRcPtr> data;
+ if(!FillTransformVectorFromPySequence(pytransforms, data))
+ {
+ PyErr_SetString(PyExc_TypeError, "First argument must be a transform array.");
+ return 0;
+ }
+
+ transform->clear();
+
+ for(unsigned int i=0; i<data.size(); ++i)
+ {
+ transform->push_back( data[i] );
+ }
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_GroupTransform_size( PyObject * self )
+ {
+ try
+ {
+ ConstGroupTransformRcPtr transform = GetConstGroupTransform(self, true);
+ return PyInt_FromLong( transform->size() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_GroupTransform_push_back( PyObject * self, PyObject *args )
+ {
+ try
+ {
+ PyObject * pytransform = 0;
+
+ if (!PyArg_ParseTuple(args,"O:push_back", &pytransform)) return NULL;
+
+ GroupTransformRcPtr transform = GetEditableGroupTransform(self);
+
+ if(!IsPyTransform(pytransform))
+ {
+ throw Exception("GroupTransform.push_back requires a transform as the first arg.");
+ }
+
+ transform->push_back( GetConstTransform(pytransform, true) );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_GroupTransform_clear( PyObject * self )
+ {
+ try
+ {
+ GroupTransformRcPtr transform = GetEditableGroupTransform(self);
+ transform->clear();
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_GroupTransform_empty( PyObject * self )
+ {
+ try
+ {
+ ConstGroupTransformRcPtr transform = GetConstGroupTransform(self, true);
+ return PyBool_FromLong( transform->empty() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/pyglue/PyLogTransform.cpp b/src/pyglue/PyLogTransform.cpp
new file mode 100644
index 0000000..e2c1462
--- /dev/null
+++ b/src/pyglue/PyLogTransform.cpp
@@ -0,0 +1,251 @@
+/*
+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 <Python.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "PyTransform.h"
+#include "PyUtil.h"
+#include "PyDoc.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ bool AddLogTransformObjectToModule( PyObject* m )
+ {
+ PyOCIO_LogTransformType.tp_new = PyType_GenericNew;
+ if ( PyType_Ready(&PyOCIO_LogTransformType) < 0 ) return false;
+
+ Py_INCREF( &PyOCIO_LogTransformType );
+ PyModule_AddObject(m, "LogTransform",
+ (PyObject *)&PyOCIO_LogTransformType);
+
+ return true;
+ }
+
+ bool IsPyLogTransform(PyObject * pyobject)
+ {
+ if(!pyobject) return false;
+ return PyObject_TypeCheck(pyobject, &PyOCIO_LogTransformType);
+ }
+
+ ConstLogTransformRcPtr GetConstLogTransform(PyObject * pyobject, bool allowCast)
+ {
+ ConstLogTransformRcPtr transform = \
+ DynamicPtrCast<const LogTransform>(GetConstTransform(pyobject, allowCast));
+ if(!transform)
+ {
+ throw Exception("PyObject must be a valid OCIO.LogTransform.");
+ }
+ return transform;
+ }
+
+ LogTransformRcPtr GetEditableLogTransform(PyObject * pyobject)
+ {
+ LogTransformRcPtr transform = \
+ DynamicPtrCast<LogTransform>(GetEditableTransform(pyobject));
+ if(!transform)
+ {
+ throw Exception("PyObject must be a valid OCIO.LogTransform.");
+ }
+ return transform;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ int PyOCIO_LogTransform_init( PyOCIO_Transform * self, PyObject * args, PyObject * kwds );
+
+ PyObject * PyOCIO_LogTransform_getBase( PyObject * self );
+ PyObject * PyOCIO_LogTransform_setBase( PyObject * self, PyObject *args );
+
+ ///////////////////////////////////////////////////////////////////////
+ ///
+
+ PyMethodDef PyOCIO_LogTransform_methods[] = {
+ {"getBase",
+ (PyCFunction) PyOCIO_LogTransform_getBase, METH_NOARGS, LOGTRANSFORM_GETBASE__DOC__ },
+ {"setBase",
+ PyOCIO_LogTransform_setBase, METH_VARARGS, LOGTRANSFORM_SETBASE__DOC__ },
+ {NULL, NULL, 0, NULL}
+ };
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyTypeObject PyOCIO_LogTransformType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, //ob_size
+ "OCIO.LogTransform", //tp_name
+ sizeof(PyOCIO_Transform), //tp_basicsize
+ 0, //tp_itemsize
+ 0, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ 0, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
+ LOGTRANSFORM__DOC__, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ PyOCIO_LogTransform_methods, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ &PyOCIO_TransformType, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ (initproc) PyOCIO_LogTransform_init, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0, //tp_del
+ #if PY_VERSION_HEX > 0x02060000
+ 0, //tp_version_tag
+ #endif
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ ///////////////////////////////////////////////////////////////////////
+ ///
+ int PyOCIO_LogTransform_init( PyOCIO_Transform *self,
+ PyObject * args, PyObject * kwds )
+ {
+ ///////////////////////////////////////////////////////////////////
+ /// init pyobject fields
+
+ self->constcppobj = new ConstTransformRcPtr();
+ self->cppobj = new TransformRcPtr();
+ self->isconst = true;
+
+ // Parse optional kwargs
+ float base = -1.0f; // -1.0 is an illegal value for log transform base
+ char * direction = NULL;
+
+ static const char *kwlist[] = {
+ "base",
+ "direction",
+ NULL
+ };
+
+ if(!PyArg_ParseTupleAndKeywords(args, kwds, "|fs",
+ const_cast<char **>(kwlist),
+ &base, &direction )) return -1;
+
+ try
+ {
+ LogTransformRcPtr transform = LogTransform::Create();
+ *self->cppobj = transform;
+ self->isconst = false;
+
+ if(base != -1.0f) transform->setBase(base);
+ if(direction) transform->setDirection(TransformDirectionFromString(direction));
+
+ return 0;
+ }
+ catch ( const std::exception & e )
+ {
+ std::string message = "Cannot create LogTransform: ";
+ message += e.what();
+ PyErr_SetString( PyExc_RuntimeError, message.c_str() );
+ return -1;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_LogTransform_getBase( PyObject * self )
+ {
+ try
+ {
+ ConstLogTransformRcPtr transform = GetConstLogTransform(self, true);
+ return PyFloat_FromDouble(transform->getBase());
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_LogTransform_setBase( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ float base;
+ if (!PyArg_ParseTuple(args,"f:setBase", &base)) return NULL;
+ LogTransformRcPtr transform = GetEditableLogTransform(self);
+
+ transform->setBase( base );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/pyglue/PyLook.cpp b/src/pyglue/PyLook.cpp
new file mode 100644
index 0000000..3f1128f
--- /dev/null
+++ b/src/pyglue/PyLook.cpp
@@ -0,0 +1,450 @@
+/*
+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 <Python.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "PyLook.h"
+#include "PyTransform.h"
+#include "PyUtil.h"
+#include "PyDoc.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ bool AddLookObjectToModule( PyObject* m )
+ {
+ PyOCIO_LookType.tp_new = PyType_GenericNew;
+ if ( PyType_Ready(&PyOCIO_LookType) < 0 ) return false;
+
+ Py_INCREF( &PyOCIO_LookType );
+ PyModule_AddObject(m, "Look",
+ (PyObject *)&PyOCIO_LookType);
+
+ return true;
+ }
+
+ PyObject * BuildConstPyLook(ConstLookRcPtr look)
+ {
+ if (!look)
+ {
+ Py_RETURN_NONE;
+ }
+
+ PyOCIO_Look * pyLook = PyObject_New(
+ PyOCIO_Look, (PyTypeObject * ) &PyOCIO_LookType);
+
+ pyLook->constcppobj = new ConstLookRcPtr();
+ *pyLook->constcppobj = look;
+
+ pyLook->cppobj = new LookRcPtr();
+ pyLook->isconst = true;
+
+ return ( PyObject * ) pyLook;
+ }
+
+ PyObject * BuildEditablePyLook(LookRcPtr look)
+ {
+ if (!look)
+ {
+ Py_RETURN_NONE;
+ }
+
+ PyOCIO_Look * pyLook = PyObject_New(
+ PyOCIO_Look, (PyTypeObject * ) &PyOCIO_LookType);
+
+ pyLook->constcppobj = new ConstLookRcPtr();
+ pyLook->cppobj = new LookRcPtr();
+ *pyLook->cppobj = look;
+
+ pyLook->isconst = false;
+
+ return ( PyObject * ) pyLook;
+ }
+
+ bool IsPyLook(PyObject * pyobject)
+ {
+ if(!pyobject) return false;
+ return (PyObject_Type(pyobject) == (PyObject *) (&PyOCIO_LookType));
+ }
+
+ bool IsPyLookEditable(PyObject * pyobject)
+ {
+ if(!IsPyLook(pyobject))
+ {
+ throw Exception("PyObject must be an OCIO.Look.");
+ }
+
+ PyOCIO_Look * pyLook = reinterpret_cast<PyOCIO_Look *> (pyobject);
+ return (!pyLook->isconst);
+ }
+
+ ConstLookRcPtr GetConstLook(PyObject * pyobject, bool allowCast)
+ {
+ if(!IsPyLook(pyobject))
+ {
+ throw Exception("PyObject must be an OCIO.Look.");
+ }
+
+ PyOCIO_Look * pylook = reinterpret_cast<PyOCIO_Look *> (pyobject);
+ if(pylook->isconst && pylook->constcppobj)
+ {
+ return *pylook->constcppobj;
+ }
+
+ if(allowCast && !pylook->isconst && pylook->cppobj)
+ {
+ return *pylook->cppobj;
+ }
+
+ throw Exception("PyObject must be a valid OCIO.Look.");
+ }
+
+ LookRcPtr GetEditableLook(PyObject * pyobject)
+ {
+ if(!IsPyLook(pyobject))
+ {
+ throw Exception("PyObject must be an OCIO.Look.");
+ }
+
+ PyOCIO_Look * pylook = reinterpret_cast<PyOCIO_Look *> (pyobject);
+ if(!pylook->isconst && pylook->cppobj)
+ {
+ return *pylook->cppobj;
+ }
+
+ throw Exception("PyObject must be an editable OCIO.Look.");
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ int PyOCIO_Look_init( PyOCIO_Look * self, PyObject * args, PyObject * kwds );
+ void PyOCIO_Look_delete( PyOCIO_Look * self, PyObject * args );
+ PyObject * PyOCIO_Look_isEditable( PyObject * self );
+ PyObject * PyOCIO_Look_createEditableCopy( PyObject * self );
+
+ PyObject * PyOCIO_Look_getName( PyObject * self );
+ PyObject * PyOCIO_Look_setName( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_Look_getProcessSpace( PyObject * self );
+ PyObject * PyOCIO_Look_setProcessSpace( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_Look_getTransform( PyObject * self );
+ PyObject * PyOCIO_Look_setTransform( PyObject * self, PyObject *args );
+
+ ///////////////////////////////////////////////////////////////////////
+ ///
+
+ PyMethodDef PyOCIO_Look_methods[] = {
+ {"isEditable",
+ (PyCFunction) PyOCIO_Look_isEditable, METH_NOARGS, LOOK_ISEDITABLE__DOC__ },
+ {"createEditableCopy",
+ (PyCFunction) PyOCIO_Look_createEditableCopy, METH_NOARGS, LOOK_CREATEEDITABLECOPY__DOC__ },
+ {"getName",
+ (PyCFunction) PyOCIO_Look_getName, METH_NOARGS, LOOK_GETNAME__DOC__ },
+ {"setName",
+ PyOCIO_Look_setName, METH_VARARGS, LOOK_SETNAME__DOC__ },
+ {"getProcessSpace",
+ (PyCFunction) PyOCIO_Look_getProcessSpace, METH_NOARGS, LOOK_GETPROCESSSPACE__DOC__ },
+ {"setProcessSpace",
+ PyOCIO_Look_setProcessSpace, METH_VARARGS, LOOK_SETPROCESSSPACE__DOC__ },
+ {"getTransform",
+ (PyCFunction) PyOCIO_Look_getTransform, METH_NOARGS, LOOK_GETTRANSFORM__DOC__ },
+ {"setTransform",
+ PyOCIO_Look_setTransform, METH_VARARGS, LOOK_SETTRANSFORM__DOC__ },
+ {NULL, NULL, 0, NULL}
+ };
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyTypeObject PyOCIO_LookType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, //ob_size
+ "OCIO.Look", //tp_name
+ sizeof(PyOCIO_Look), //tp_basicsize
+ 0, //tp_itemsize
+ (destructor)PyOCIO_Look_delete, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ 0, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
+ LOOK__DOC__, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ PyOCIO_Look_methods, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ 0, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ (initproc) PyOCIO_Look_init, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0, //tp_del
+ #if PY_VERSION_HEX > 0x02060000
+ 0, //tp_version_tag
+ #endif
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ ///////////////////////////////////////////////////////////////////////
+ ///
+ int PyOCIO_Look_init( PyOCIO_Look *self, PyObject * args, PyObject * kwds )
+ {
+ ///////////////////////////////////////////////////////////////////
+ /// init pyobject fields
+
+ self->constcppobj = new ConstLookRcPtr();
+ self->cppobj = new LookRcPtr();
+ self->isconst = true;
+
+ // Parse optional kwargs
+ char * name = NULL;
+ char * processSpace = NULL;
+ PyObject * pytransform = NULL;
+
+ const char *kwlist[] = {
+ "name", "processSpace", "transform",
+ NULL
+ };
+
+ if(!PyArg_ParseTupleAndKeywords(args, kwds, "|ssO",
+ const_cast<char **>(kwlist),
+ &name, &processSpace, &pytransform)) return -1;
+
+ try
+ {
+ LookRcPtr look = Look::Create();
+ *self->cppobj = look;
+ self->isconst = false;
+
+ if(name) look->setName(name);
+ if(processSpace) look->setProcessSpace(processSpace);
+
+ if(pytransform)
+ {
+ ConstTransformRcPtr transform = GetConstTransform(pytransform, true);
+ look->setTransform(transform);
+ }
+
+ return 0;
+ }
+ catch ( const std::exception & e )
+ {
+ std::string message = "Cannot create look: ";
+ message += e.what();
+ PyErr_SetString( PyExc_RuntimeError, message.c_str() );
+ return -1;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ void PyOCIO_Look_delete( PyOCIO_Look *self, PyObject * /*args*/ )
+ {
+ delete self->constcppobj;
+ delete self->cppobj;
+
+ self->ob_type->tp_free((PyObject*)self);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_Look_isEditable( PyObject * self )
+ {
+ return PyBool_FromLong(IsPyLookEditable(self));
+ }
+
+ PyObject * PyOCIO_Look_createEditableCopy( PyObject * self )
+ {
+ try
+ {
+ ConstLookRcPtr look = GetConstLook(self, true);
+ LookRcPtr copy = look->createEditableCopy();
+ return BuildEditablePyLook( copy );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_Look_getName( PyObject * self )
+ {
+ try
+ {
+ ConstLookRcPtr look = GetConstLook(self, true);
+ return PyString_FromString( look->getName() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Look_setName( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * name = 0;
+ if (!PyArg_ParseTuple(args,"s:setName", &name)) return NULL;
+
+ LookRcPtr look = GetEditableLook(self);
+ look->setName( name );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_Look_getProcessSpace( PyObject * self )
+ {
+ try
+ {
+ ConstLookRcPtr look = GetConstLook(self, true);
+ return PyString_FromString( look->getProcessSpace() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Look_setProcessSpace( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ char * processSpace = 0;
+ if (!PyArg_ParseTuple(args,"s:setProcessSpace", &processSpace)) return NULL;
+
+ LookRcPtr look = GetEditableLook(self);
+ look->setProcessSpace( processSpace );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_Look_getTransform( PyObject * self )
+ {
+ try
+ {
+ ConstLookRcPtr look = GetConstLook(self, true);
+ ConstTransformRcPtr transform = look->getTransform();
+ return BuildConstPyTransform(transform);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Look_setTransform( PyObject * self, PyObject *args )
+ {
+ try
+ {
+ PyObject * pytransform = 0;
+ if (!PyArg_ParseTuple(args,"O:setTransform", &pytransform))
+ return NULL;
+
+ ConstTransformRcPtr transform = GetConstTransform(pytransform, true);
+ LookRcPtr look = GetEditableLook(self);
+ look->setTransform(transform);
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/pyglue/PyLook.h b/src/pyglue/PyLook.h
new file mode 100644
index 0000000..371eafa
--- /dev/null
+++ b/src/pyglue/PyLook.h
@@ -0,0 +1,50 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_PYOCIO_PYLOOK_H
+#define INCLUDED_PYOCIO_PYLOOK_H
+
+#include <PyOpenColorIO/PyOpenColorIO.h>
+
+OCIO_NAMESPACE_ENTER
+{
+ typedef struct {
+ PyObject_HEAD
+ ConstLookRcPtr * constcppobj;
+ LookRcPtr * cppobj;
+ bool isconst;
+ } PyOCIO_Look;
+
+ extern PyTypeObject PyOCIO_LookType;
+
+ bool AddLookObjectToModule( PyObject* m );
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/pyglue/PyLookTransform.cpp b/src/pyglue/PyLookTransform.cpp
new file mode 100644
index 0000000..6b57afb
--- /dev/null
+++ b/src/pyglue/PyLookTransform.cpp
@@ -0,0 +1,343 @@
+/*
+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 <Python.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "PyTransform.h"
+#include "PyUtil.h"
+#include "PyDoc.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ bool AddLookTransformObjectToModule( PyObject* m )
+ {
+ PyOCIO_LookTransformType.tp_new = PyType_GenericNew;
+ if ( PyType_Ready(&PyOCIO_LookTransformType) < 0 ) return false;
+
+ Py_INCREF( &PyOCIO_LookTransformType );
+ PyModule_AddObject(m, "LookTransform",
+ (PyObject *)&PyOCIO_LookTransformType);
+
+ return true;
+ }
+
+ bool IsPyLookTransform(PyObject * pyobject)
+ {
+ if(!pyobject) return false;
+ return PyObject_TypeCheck(pyobject, &PyOCIO_LookTransformType);
+ }
+
+ ConstLookTransformRcPtr GetConstLookTransform(PyObject * pyobject, bool allowCast)
+ {
+ ConstLookTransformRcPtr transform = \
+ DynamicPtrCast<const LookTransform>(GetConstTransform(pyobject, allowCast));
+ if(!transform)
+ {
+ throw Exception("PyObject must be a valid OCIO.LookTransform.");
+ }
+ return transform;
+ }
+
+ LookTransformRcPtr GetEditableLookTransform(PyObject * pyobject)
+ {
+ LookTransformRcPtr transform = \
+ DynamicPtrCast<LookTransform>(GetEditableTransform(pyobject));
+ if(!transform)
+ {
+ throw Exception("PyObject must be a valid OCIO.LookTransform.");
+ }
+ return transform;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ int PyOCIO_LookTransform_init( PyOCIO_Transform * self, PyObject * args, PyObject * kwds );
+
+ PyObject * PyOCIO_LookTransform_getSrc( PyObject * self );
+ PyObject * PyOCIO_LookTransform_setSrc( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_LookTransform_getDst( PyObject * self );
+ PyObject * PyOCIO_LookTransform_setDst( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_LookTransform_getLooks( PyObject * self );
+ PyObject * PyOCIO_LookTransform_setLooks( PyObject * self, PyObject *args );
+
+ ///////////////////////////////////////////////////////////////////////
+ ///
+
+ PyMethodDef PyOCIO_LookTransform_methods[] = {
+ {"getSrc",
+ (PyCFunction) PyOCIO_LookTransform_getSrc, METH_NOARGS, LOOKTRANSFORM_GETSRC__DOC__ },
+ {"setSrc",
+ PyOCIO_LookTransform_setSrc, METH_VARARGS, LOOKTRANSFORM_SETSRC__DOC__ },
+ {"getDst",
+ (PyCFunction) PyOCIO_LookTransform_getDst, METH_NOARGS, LOOKTRANSFORM_GETDST__DOC__ },
+ {"setDst",
+ PyOCIO_LookTransform_setDst, METH_VARARGS, LOOKTRANSFORM_SETDST__DOC__ },
+ {"getLooks",
+ (PyCFunction) PyOCIO_LookTransform_getLooks, METH_NOARGS, LOOKTRANSFORM_GETLOOKS__DOC__ },
+ {"setLooks",
+ PyOCIO_LookTransform_setLooks, METH_VARARGS, LOOKTRANSFORM_SETLOOKS__DOC__ },
+ {NULL, NULL, 0, NULL}
+ };
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyTypeObject PyOCIO_LookTransformType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, //ob_size
+ "OCIO.LookTransform", //tp_name
+ sizeof(PyOCIO_Transform), //tp_basicsize
+ 0, //tp_itemsize
+ 0, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ 0, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
+ LOOKTRANSFORM__DOC__, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ PyOCIO_LookTransform_methods, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ &PyOCIO_TransformType, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ (initproc) PyOCIO_LookTransform_init, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0, //tp_del
+ #if PY_VERSION_HEX > 0x02060000
+ 0, //tp_version_tag
+ #endif
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ ///////////////////////////////////////////////////////////////////////
+ ///
+ int PyOCIO_LookTransform_init( PyOCIO_Transform *self,
+ PyObject * args, PyObject * kwds )
+ {
+ ///////////////////////////////////////////////////////////////////
+ /// init pyobject fields
+
+ self->constcppobj = new ConstTransformRcPtr();
+ self->cppobj = new TransformRcPtr();
+ self->isconst = true;
+
+ // Parse optional kwargs
+ char * src = NULL;
+ char * dst = NULL;
+ char * looks = NULL;
+ char * direction = NULL;
+
+ static const char *kwlist[] = {
+ "src",
+ "dst",
+ "looks",
+ "direction",
+ NULL
+ };
+
+ if(!PyArg_ParseTupleAndKeywords(args, kwds, "|ssss",
+ const_cast<char **>(kwlist),
+ &src, &dst, &looks, &direction )) return -1;
+
+ try
+ {
+ LookTransformRcPtr transform = LookTransform::Create();
+ *self->cppobj = transform;
+ self->isconst = false;
+
+ if(src) transform->setSrc(src);
+ if(dst) transform->setDst(dst);
+ if(looks) transform->setLooks(looks);
+ if(direction) transform->setDirection(TransformDirectionFromString(direction));
+
+ return 0;
+ }
+ catch ( const std::exception & e )
+ {
+ std::string message = "Cannot create LookTransform: ";
+ message += e.what();
+ PyErr_SetString( PyExc_RuntimeError, message.c_str() );
+ return -1;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_LookTransform_getSrc( PyObject * self )
+ {
+ try
+ {
+ ConstLookTransformRcPtr transform = GetConstLookTransform(self, true);
+ return PyString_FromString( transform->getSrc() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_LookTransform_setSrc( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ const char * str = 0;
+ if (!PyArg_ParseTuple(args,"s:setSrc",
+ &str)) return NULL;
+
+ LookTransformRcPtr transform = GetEditableLookTransform(self);
+ transform->setSrc( str );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_LookTransform_getDst( PyObject * self )
+ {
+ try
+ {
+ ConstLookTransformRcPtr transform = GetConstLookTransform(self, true);
+ return PyString_FromString( transform->getDst() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_LookTransform_setDst( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ const char * str = 0;
+ if (!PyArg_ParseTuple(args,"s:setDst",
+ &str)) return NULL;
+
+ LookTransformRcPtr transform = GetEditableLookTransform(self);
+ transform->setDst( str );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_LookTransform_getLooks( PyObject * self )
+ {
+ try
+ {
+ ConstLookTransformRcPtr transform = GetConstLookTransform(self, true);
+ return PyString_FromString( transform->getLooks() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_LookTransform_setLooks( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ const char * str = 0;
+ if (!PyArg_ParseTuple(args,"s:setLooks",
+ &str)) return NULL;
+
+ LookTransformRcPtr transform = GetEditableLookTransform(self);
+ transform->setLooks( str );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/pyglue/PyMain.cpp b/src/pyglue/PyMain.cpp
new file mode 100644
index 0000000..4feea32
--- /dev/null
+++ b/src/pyglue/PyMain.cpp
@@ -0,0 +1,236 @@
+/*
+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 <Python.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+namespace OCIO = OCIO_NAMESPACE;
+
+#include "PyColorSpace.h"
+#include "PyConfig.h"
+#include "PyContext.h"
+#include "PyConstants.h"
+#include "PyLook.h"
+#include "PyProcessor.h"
+#include "PyProcessorMetadata.h"
+#include "PyTransform.h"
+#include "PyUtil.h"
+#include "PyDoc.h"
+
+namespace
+{
+ PyObject * PyOCIO_ClearAllCaches(PyObject * /* self */)
+ {
+ try
+ {
+ OCIO::ClearAllCaches();
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ OCIO::Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_GetLoggingLevel(PyObject * /* self */)
+ {
+ try
+ {
+ return PyString_FromString(
+ OCIO::LoggingLevelToString(OCIO::GetLoggingLevel()) );
+ }
+ catch(...)
+ {
+ OCIO::Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_SetLoggingLevel(PyObject * /*self*/, PyObject * args)
+ {
+ try
+ {
+ PyObject * pylevel;
+ if (!PyArg_ParseTuple(args, "O:SetLoggingLevel", &pylevel))
+ {
+ return NULL;
+ }
+
+ // We explicitly cast to a str to handle both the str and int cases.
+ PyObject * pystr = PyObject_Str(pylevel);
+ if(!pystr)
+ {
+ throw OCIO::Exception("Fist argument must be a LOGGING_LEVEL");
+ }
+
+ OCIO::LoggingLevel level = OCIO::LoggingLevelFromString(PyString_AsString(pystr));
+ OCIO::SetLoggingLevel(level);
+
+ Py_DECREF(pystr);
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ OCIO::Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_GetCurrentConfig(PyObject * /* self */)
+ {
+ try
+ {
+ return OCIO::BuildConstPyConfig( OCIO::GetCurrentConfig() );
+ }
+ catch(...)
+ {
+ OCIO::Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_SetCurrentConfig(PyObject * /*self*/, PyObject * args)
+ {
+ try
+ {
+ PyObject * pyconfig;
+ if (!PyArg_ParseTuple(args, "O!:SetCurrentConfig",
+ &OCIO::PyOCIO_ConfigType, &pyconfig))
+ {
+ return NULL;
+ }
+
+ OCIO::ConstConfigRcPtr c = OCIO::GetConstConfig(pyconfig, true);
+ OCIO::SetCurrentConfig(c);
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ OCIO::Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyMethodDef PyOCIO_methods[] = {
+ {"ClearAllCaches",
+ (PyCFunction) PyOCIO_ClearAllCaches, METH_NOARGS, OCIO::OPENCOLORIO_CLEARALLCACHES__DOC__ },
+ {"GetLoggingLevel",
+ (PyCFunction) PyOCIO_GetLoggingLevel, METH_NOARGS, OCIO::OPENCOLORIO_GETLOGGINGLEVEL__DOC__ },
+ {"SetLoggingLevel",
+ (PyCFunction) PyOCIO_SetLoggingLevel, METH_VARARGS, OCIO::OPENCOLORIO_SETLOGGINGLEVEL__DOC__ },
+ {"GetCurrentConfig",
+ (PyCFunction) PyOCIO_GetCurrentConfig, METH_NOARGS, OCIO::OPENCOLORIO_GETCURRENTCONFIG__DOC__ },
+ {"SetCurrentConfig",
+ (PyCFunction) PyOCIO_SetCurrentConfig, METH_VARARGS, OCIO::OPENCOLORIO_SETCURRENTCONFIG__DOC__ },
+ {NULL, NULL, 0, NULL} /* Sentinel */
+ };
+}
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ PyObject * g_exceptionType = NULL;
+ PyObject * g_exceptionMissingFileType = NULL;
+ }
+
+ // These are explicitly initialized in the init function
+ // to make sure they're not initialized until after the module is
+
+ PyObject * GetExceptionPyType()
+ {
+ return g_exceptionType;
+ }
+
+ void SetExceptionPyType(PyObject * pytypeobj)
+ {
+ g_exceptionType = pytypeobj;
+ }
+
+ PyObject * GetExceptionMissingFilePyType()
+ {
+ return g_exceptionMissingFileType;
+ }
+
+ void SetExceptionMissingFilePyType(PyObject * pytypeobj)
+ {
+ g_exceptionMissingFileType = pytypeobj;
+ }
+}
+OCIO_NAMESPACE_EXIT
+
+extern "C"
+PyMODINIT_FUNC
+initPyOpenColorIO(void)
+{
+ PyObject * m;
+ m = Py_InitModule3("PyOpenColorIO", PyOCIO_methods, OCIO::OPENCOLORIO__DOC__);
+
+ PyModule_AddStringConstant(m, "version", OCIO::GetVersion());
+ PyModule_AddIntConstant(m, "hexversion", OCIO::GetVersionHex());
+
+ // Create Exceptions, and add to the module
+ // TODO: add support for PyErr_NewExceptionWithDoc for python2.7+
+ OCIO::SetExceptionPyType(
+ PyErr_NewException(const_cast<char*>("PyOpenColorIO.Exception"),
+ PyExc_RuntimeError, NULL));
+ PyModule_AddObject(m, "Exception", OCIO::GetExceptionPyType());
+
+ // TODO: add support for PyErr_NewExceptionWithDoc for python2.7+
+ OCIO::SetExceptionMissingFilePyType(
+ PyErr_NewException(const_cast<char*>("PyOpenColorIO.ExceptionMissingFile"),
+ OCIO::GetExceptionPyType(), NULL));
+ PyModule_AddObject(m, "ExceptionMissingFile", OCIO::GetExceptionMissingFilePyType());
+
+ // Register Classes
+
+ OCIO::AddColorSpaceObjectToModule( m );
+ OCIO::AddConfigObjectToModule( m );
+ OCIO::AddConstantsModule( m );
+ OCIO::AddContextObjectToModule( m );
+ OCIO::AddLookObjectToModule( m );
+ OCIO::AddProcessorObjectToModule( m );
+ OCIO::AddProcessorMetadataObjectToModule( m );
+
+ OCIO::AddTransformObjectToModule( m );
+ {
+ OCIO::AddAllocationTransformObjectToModule( m );
+ OCIO::AddCDLTransformObjectToModule( m );
+ OCIO::AddColorSpaceTransformObjectToModule( m );
+ OCIO::AddDisplayTransformObjectToModule( m );
+ OCIO::AddExponentTransformObjectToModule( m );
+ OCIO::AddFileTransformObjectToModule( m );
+ OCIO::AddGroupTransformObjectToModule( m );
+ OCIO::AddLogTransformObjectToModule( m );
+ OCIO::AddLookTransformObjectToModule( m );
+ OCIO::AddMatrixTransformObjectToModule( m );
+ }
+}
diff --git a/src/pyglue/PyMatrixTransform.cpp b/src/pyglue/PyMatrixTransform.cpp
new file mode 100644
index 0000000..f0a0012
--- /dev/null
+++ b/src/pyglue/PyMatrixTransform.cpp
@@ -0,0 +1,630 @@
+/*
+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 <Python.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "PyTransform.h"
+#include "PyUtil.h"
+#include "PyDoc.h"
+
+OCIO_NAMESPACE_ENTER
+{
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ bool AddMatrixTransformObjectToModule( PyObject* m )
+ {
+ PyOCIO_MatrixTransformType.tp_new = PyType_GenericNew;
+ if ( PyType_Ready(&PyOCIO_MatrixTransformType) < 0 ) return false;
+
+ Py_INCREF( &PyOCIO_MatrixTransformType );
+ PyModule_AddObject(m, "MatrixTransform",
+ (PyObject *)&PyOCIO_MatrixTransformType);
+
+ return true;
+ }
+
+ bool IsPyMatrixTransform(PyObject * pyobject)
+ {
+ if(!pyobject) return false;
+ return PyObject_TypeCheck(pyobject, &PyOCIO_MatrixTransformType);
+ }
+
+ ConstMatrixTransformRcPtr GetConstMatrixTransform(PyObject * pyobject, bool allowCast)
+ {
+ ConstMatrixTransformRcPtr transform = \
+ DynamicPtrCast<const MatrixTransform>(GetConstTransform(pyobject, allowCast));
+ if(!transform)
+ {
+ throw Exception("PyObject must be a valid OCIO.MatrixTransform.");
+ }
+ return transform;
+ }
+
+ MatrixTransformRcPtr GetEditableMatrixTransform(PyObject * pyobject)
+ {
+ MatrixTransformRcPtr transform = \
+ DynamicPtrCast<MatrixTransform>(GetEditableTransform(pyobject));
+ if(!transform)
+ {
+ throw Exception("PyObject must be a valid OCIO.MatrixTransform.");
+ }
+ return transform;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ int PyOCIO_MatrixTransform_init( PyOCIO_Transform * self,
+ PyObject * args, PyObject * kwds );
+
+ PyObject * PyOCIO_MatrixTransform_getValue( PyObject * self );
+ PyObject * PyOCIO_MatrixTransform_setValue( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_MatrixTransform_getMatrix( PyObject * self );
+ PyObject * PyOCIO_MatrixTransform_setMatrix( PyObject * self, PyObject *args );
+ PyObject * PyOCIO_MatrixTransform_getOffset( PyObject * self );
+ PyObject * PyOCIO_MatrixTransform_setOffset( PyObject * self, PyObject *args );
+
+ PyObject * PyOCIO_MatrixTransform_Identity( PyObject * cls );
+ PyObject * PyOCIO_MatrixTransform_Fit( PyObject * cls, PyObject * args );
+ PyObject * PyOCIO_MatrixTransform_Sat( PyObject * cls, PyObject * args );
+ PyObject * PyOCIO_MatrixTransform_Scale( PyObject * cls, PyObject * args );
+ PyObject * PyOCIO_MatrixTransform_View( PyObject * cls, PyObject * args );
+
+ ///////////////////////////////////////////////////////////////////////
+ ///
+
+ PyMethodDef PyOCIO_MatrixTransform_methods[] = {
+ {"getValue",
+ (PyCFunction) PyOCIO_MatrixTransform_getValue, METH_NOARGS, MATRIXTRANSFORM_GETVALUE__DOC__ },
+ {"setValue",
+ PyOCIO_MatrixTransform_setValue, METH_VARARGS, MATRIXTRANSFORM_SETVALUE__DOC__ },
+ {"getMatrix",
+ (PyCFunction) PyOCIO_MatrixTransform_getMatrix, METH_NOARGS, MATRIXTRANSFORM_GETMATRIX__DOC__ },
+ {"setMatrix",
+ PyOCIO_MatrixTransform_setMatrix, METH_VARARGS, MATRIXTRANSFORM_SETMATRIX__DOC__ },
+ {"getOffset",
+ (PyCFunction) PyOCIO_MatrixTransform_getOffset, METH_NOARGS, MATRIXTRANSFORM_GETOFFSET__DOC__ },
+ {"setOffset",
+ PyOCIO_MatrixTransform_setOffset, METH_VARARGS, MATRIXTRANSFORM_SETOFFSET__DOC__ },
+ {"Identity",
+ (PyCFunction) PyOCIO_MatrixTransform_Identity, METH_NOARGS | METH_CLASS, MATRIXTRANSFORM_IDENTITY__DOC__ },
+ {"Fit",
+ PyOCIO_MatrixTransform_Fit, METH_VARARGS | METH_CLASS, MATRIXTRANSFORM_FIT__DOC__ },
+ {"Sat",
+ PyOCIO_MatrixTransform_Sat, METH_VARARGS | METH_CLASS, MATRIXTRANSFORM_SAT__DOC__ },
+ {"Scale",
+ PyOCIO_MatrixTransform_Scale, METH_VARARGS | METH_CLASS, MATRIXTRANSFORM_SCALE__DOC__ },
+ {"View",
+ PyOCIO_MatrixTransform_View, METH_VARARGS | METH_CLASS, MATRIXTRANSFORM_VIEW__DOC__ },
+ {NULL, NULL, 0, NULL}
+ };
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyTypeObject PyOCIO_MatrixTransformType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, //ob_size
+ "OCIO.MatrixTransform", //tp_name
+ sizeof(PyOCIO_Transform), //tp_basicsize
+ 0, //tp_itemsize
+ 0, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ 0, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
+ MATRIXTRANSFORM__DOC__, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ PyOCIO_MatrixTransform_methods, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ &PyOCIO_TransformType, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ (initproc) PyOCIO_MatrixTransform_init, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0, //tp_del
+ #if PY_VERSION_HEX > 0x02060000
+ 0, //tp_version_tag
+ #endif
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ ///////////////////////////////////////////////////////////////////////
+ ///
+ int PyOCIO_MatrixTransform_init( PyOCIO_Transform *self,
+ PyObject * /*args*/, PyObject * /*kwds*/ )
+ {
+ ///////////////////////////////////////////////////////////////////
+ /// init pyobject fields
+
+ self->constcppobj = new ConstTransformRcPtr();
+ self->cppobj = new TransformRcPtr();
+ self->isconst = true;
+
+ try
+ {
+ *self->cppobj = MatrixTransform::Create();
+ self->isconst = false;
+ return 0;
+ }
+ catch ( const std::exception & e )
+ {
+ std::string message = "Cannot create MatrixTransform: ";
+ message += e.what();
+ PyErr_SetString( PyExc_RuntimeError, message.c_str() );
+ return -1;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_MatrixTransform_getValue( PyObject * self )
+ {
+ try
+ {
+ ConstMatrixTransformRcPtr transform = GetConstMatrixTransform(self, true);
+
+ std::vector<float> matrix(16);
+ std::vector<float> offset(4);
+
+ transform->getValue(&matrix[0], &offset[0]);
+
+ PyObject* pymatrix = CreatePyListFromFloatVector(matrix);
+ PyObject* pyoffset = CreatePyListFromFloatVector(offset);
+
+ PyObject* pyreturnval = Py_BuildValue("(OO)", pymatrix, pyoffset);
+ Py_DECREF(pymatrix);
+ Py_DECREF(pyoffset);
+
+ return pyreturnval;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_MatrixTransform_setValue( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pymatrix = 0;
+ PyObject * pyoffset = 0;
+ if (!PyArg_ParseTuple(args,"OO:setValue",
+ &pymatrix, &pyoffset)) return NULL;
+
+ std::vector<float> matrix;
+ std::vector<float> offset;
+
+ if(!FillFloatVectorFromPySequence(pymatrix, matrix) ||
+ (matrix.size() != 16))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "First argument must be a float array, size 16");
+ return 0;
+ }
+
+ if(!FillFloatVectorFromPySequence(pyoffset, offset) ||
+ (offset.size() != 4))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "Second argument must be a float array, size 4");
+ return 0;
+ }
+
+ MatrixTransformRcPtr transform = GetEditableMatrixTransform(self);
+ transform->setValue(&matrix[0], &offset[0]);
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_MatrixTransform_getMatrix( PyObject * self )
+ {
+ try
+ {
+ ConstMatrixTransformRcPtr transform = GetConstMatrixTransform(self, true);
+
+ std::vector<float> matrix(16);
+ transform->getMatrix(&matrix[0]);
+
+ return CreatePyListFromFloatVector(matrix);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_MatrixTransform_setMatrix( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pymatrix = 0;
+ if (!PyArg_ParseTuple(args,"O:setValue", &pymatrix)) return NULL;
+
+ std::vector<float> matrix;
+
+ if(!FillFloatVectorFromPySequence(pymatrix, matrix) ||
+ (matrix.size() != 16))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "First argument must be a float array, size 16");
+ return 0;
+ }
+
+ MatrixTransformRcPtr transform = GetEditableMatrixTransform(self);
+ transform->setMatrix(&matrix[0]);
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_MatrixTransform_getOffset( PyObject * self )
+ {
+ try
+ {
+ ConstMatrixTransformRcPtr transform = GetConstMatrixTransform(self, true);
+
+ std::vector<float> offset(4);
+ transform->getOffset(&offset[0]);
+
+ return CreatePyListFromFloatVector(offset);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_MatrixTransform_setOffset( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyoffset = 0;
+ if (!PyArg_ParseTuple(args,"O:setValue", &pyoffset)) return NULL;
+
+ std::vector<float> offset;
+
+ if(!FillFloatVectorFromPySequence(pyoffset, offset) ||
+ (offset.size() != 4))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "First argument must be a float array, size 4");
+ return 0;
+ }
+
+ MatrixTransformRcPtr transform = GetEditableMatrixTransform(self);
+ transform->setOffset(&offset[0]);
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_MatrixTransform_Identity( PyObject * /*cls*/ )
+ {
+ try
+ {
+ std::vector<float> matrix(16);
+ std::vector<float> offset(4);
+
+ MatrixTransform::Identity(&matrix[0], &offset[0]);
+
+ PyObject* pymatrix = CreatePyListFromFloatVector(matrix);
+ PyObject* pyoffset = CreatePyListFromFloatVector(offset);
+
+ PyObject* pyreturnval = Py_BuildValue("(OO)", pymatrix, pyoffset);
+ Py_DECREF(pymatrix);
+ Py_DECREF(pyoffset);
+
+ return pyreturnval;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_MatrixTransform_Fit( PyObject * /*cls*/, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyoldmin = 0;
+ PyObject * pyoldmax = 0;
+ PyObject * pynewmin = 0;
+ PyObject * pynewmax = 0;
+
+ if (!PyArg_ParseTuple(args,"OOOO:Fit",
+ &pyoldmin, &pyoldmax, &pynewmin, &pynewmax)) return NULL;
+
+ std::vector<float> oldmin;
+ std::vector<float> oldmax;
+ std::vector<float> newmin;
+ std::vector<float> newmax;
+
+ if(!FillFloatVectorFromPySequence(pyoldmin, oldmin) ||
+ (oldmin.size() != 4))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "First argument must be a float array, size 4");
+ return 0;
+ }
+
+ if(!FillFloatVectorFromPySequence(pyoldmax, oldmax) ||
+ (oldmax.size() != 4))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "Second argument must be a float array, size 4");
+ return 0;
+ }
+
+ if(!FillFloatVectorFromPySequence(pynewmin, newmin) ||
+ (newmin.size() != 4))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "Third argument must be a float array, size 4");
+ return 0;
+ }
+
+ if(!FillFloatVectorFromPySequence(pynewmax, newmax) ||
+ (newmax.size() != 4))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "Fourth argument must be a float array, size 4");
+ return 0;
+ }
+
+
+ std::vector<float> matrix(16);
+ std::vector<float> offset(4);
+
+ MatrixTransform::Fit(&matrix[0], &offset[0],
+ &oldmin[0], &oldmax[0],
+ &newmin[0], &newmax[0]);
+
+ PyObject* pymatrix = CreatePyListFromFloatVector(matrix);
+ PyObject* pyoffset = CreatePyListFromFloatVector(offset);
+
+ PyObject* pyreturnval = Py_BuildValue("(OO)", pymatrix, pyoffset);
+ Py_DECREF(pymatrix);
+ Py_DECREF(pyoffset);
+
+ return pyreturnval;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_MatrixTransform_Sat( PyObject * /*cls*/, PyObject * args )
+ {
+ try
+ {
+ float sat = 0.0;
+ PyObject * pyluma = 0;
+
+ if (!PyArg_ParseTuple(args,"fO:Sat",
+ &sat, &pyluma)) return NULL;
+
+ std::vector<float> luma;
+
+ if(!FillFloatVectorFromPySequence(pyluma, luma) ||
+ (luma.size() != 3))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "Second argument must be a float array, size 3");
+ return 0;
+ }
+
+ std::vector<float> matrix(16);
+ std::vector<float> offset(4);
+
+ MatrixTransform::Sat(&matrix[0], &offset[0],
+ sat, &luma[0]);
+
+ PyObject* pymatrix = CreatePyListFromFloatVector(matrix);
+ PyObject* pyoffset = CreatePyListFromFloatVector(offset);
+
+ PyObject* pyreturnval = Py_BuildValue("(OO)", pymatrix, pyoffset);
+ Py_DECREF(pymatrix);
+ Py_DECREF(pyoffset);
+
+ return pyreturnval;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_MatrixTransform_Scale( PyObject * /*cls*/, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyscale = 0;
+
+ if (!PyArg_ParseTuple(args,"O:Scale",
+ &pyscale)) return NULL;
+
+ std::vector<float> scale;
+
+ if(!FillFloatVectorFromPySequence(pyscale, scale) ||
+ (scale.size() != 4))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "Second argument must be a float array, size 4");
+ return 0;
+ }
+
+ std::vector<float> matrix(16);
+ std::vector<float> offset(4);
+
+ MatrixTransform::Scale(&matrix[0], &offset[0],
+ &scale[0]);
+
+ PyObject* pymatrix = CreatePyListFromFloatVector(matrix);
+ PyObject* pyoffset = CreatePyListFromFloatVector(offset);
+
+ PyObject* pyreturnval = Py_BuildValue("(OO)", pymatrix, pyoffset);
+ Py_DECREF(pymatrix);
+ Py_DECREF(pyoffset);
+
+ return pyreturnval;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_MatrixTransform_View( PyObject * /*cls*/, PyObject * args )
+ {
+ try
+ {
+ PyObject * pychannelhot = 0;
+ PyObject * pyluma = 0;
+
+ if (!PyArg_ParseTuple(args,"OO:View",
+ &pychannelhot, &pyluma)) return NULL;
+
+ std::vector<int> channelhot;
+ std::vector<float> luma;
+
+ if(!FillIntVectorFromPySequence(pychannelhot, channelhot) ||
+ (channelhot.size() != 4))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "First argument must be a bool/int array, size 4");
+ return 0;
+ }
+
+ if(!FillFloatVectorFromPySequence(pyluma, luma) ||
+ (luma.size() != 3))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "Second argument must be a float array, size 3");
+ return 0;
+ }
+
+ std::vector<float> matrix(16);
+ std::vector<float> offset(4);
+
+ MatrixTransform::View(&matrix[0], &offset[0],
+ &channelhot[0], &luma[0]);
+
+ PyObject* pymatrix = CreatePyListFromFloatVector(matrix);
+ PyObject* pyoffset = CreatePyListFromFloatVector(offset);
+
+ PyObject* pyreturnval = Py_BuildValue("(OO)", pymatrix, pyoffset);
+ Py_DECREF(pymatrix);
+ Py_DECREF(pyoffset);
+
+ return pyreturnval;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/pyglue/PyProcessor.cpp b/src/pyglue/PyProcessor.cpp
new file mode 100644
index 0000000..e393041
--- /dev/null
+++ b/src/pyglue/PyProcessor.cpp
@@ -0,0 +1,500 @@
+/*
+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 <Python.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "PyProcessor.h"
+#include "PyUtil.h"
+#include "PyDoc.h"
+
+#include <sstream>
+
+OCIO_NAMESPACE_ENTER
+{
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ bool AddProcessorObjectToModule( PyObject* m )
+ {
+ PyOCIO_ProcessorType.tp_new = PyType_GenericNew;
+ if ( PyType_Ready(&PyOCIO_ProcessorType) < 0 ) return false;
+
+ Py_INCREF( &PyOCIO_ProcessorType );
+ PyModule_AddObject(m, "Processor",
+ (PyObject *)&PyOCIO_ProcessorType);
+
+ return true;
+ }
+
+ PyObject * BuildConstPyProcessor(ConstProcessorRcPtr processor)
+ {
+ if (!processor)
+ {
+ Py_RETURN_NONE;
+ }
+
+ PyOCIO_Processor * pyProcessor = PyObject_New(
+ PyOCIO_Processor, (PyTypeObject * ) &PyOCIO_ProcessorType);
+
+ pyProcessor->constcppobj = new ConstProcessorRcPtr();
+ *pyProcessor->constcppobj = processor;
+
+ return ( PyObject * ) pyProcessor;
+ }
+
+ bool IsPyProcessor(PyObject * pyobject)
+ {
+ if(!pyobject) return false;
+ return (PyObject_Type(pyobject) == (PyObject *) (&PyOCIO_ProcessorType));
+ }
+
+ ConstProcessorRcPtr GetConstProcessor(PyObject * pyobject)
+ {
+ if(!IsPyProcessor(pyobject))
+ {
+ throw Exception("PyObject must be an OCIO.Processor.");
+ }
+
+ PyOCIO_Processor * pyProcessor = reinterpret_cast<PyOCIO_Processor *> (pyobject);
+ if(pyProcessor->constcppobj)
+ {
+ return *pyProcessor->constcppobj;
+ }
+
+ throw Exception("PyObject must be a valid OCIO.Processor.");
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ int PyOCIO_Processor_init( PyOCIO_Processor * self, PyObject * args, PyObject * kwds );
+ void PyOCIO_Processor_delete( PyOCIO_Processor * self, PyObject * args );
+
+ PyObject * PyOCIO_Processor_isNoOp( PyObject * self );
+ PyObject * PyOCIO_Processor_hasChannelCrosstalk( PyObject * self );
+ PyObject * PyOCIO_Processor_getMetadata( PyObject * self );
+ PyObject * PyOCIO_Processor_applyRGB( PyObject * self, PyObject * args );
+ PyObject * PyOCIO_Processor_applyRGBA( PyObject * self, PyObject * args );
+ PyObject * PyOCIO_Processor_getCpuCacheID( PyObject * self );
+
+ PyObject * PyOCIO_Processor_getGpuShaderText( PyObject * self, PyObject * args );
+ PyObject * PyOCIO_Processor_getGpuShaderTextCacheID( PyObject * self, PyObject * args );
+ PyObject * PyOCIO_Processor_getGpuLut3D( PyObject * self, PyObject * args );
+ PyObject * PyOCIO_Processor_getGpuLut3DCacheID( PyObject * self, PyObject * args );
+
+ ///////////////////////////////////////////////////////////////////////
+ ///
+
+ PyMethodDef PyOCIO_Processor_methods[] = {
+ {"isNoOp",
+ (PyCFunction) PyOCIO_Processor_isNoOp, METH_NOARGS, PROCESSOR_ISNOOP__DOC__ },
+ {"hasChannelCrosstalk",
+ (PyCFunction) PyOCIO_Processor_hasChannelCrosstalk, METH_NOARGS, PROCESSOR_HASCHANNELCROSSTALK__DOC__ },
+ {"getMetadata",
+ (PyCFunction) PyOCIO_Processor_getMetadata, METH_NOARGS, PROCESSOR_GETMETADATA__DOC__ },
+ {"applyRGB",
+ PyOCIO_Processor_applyRGB, METH_VARARGS, PROCESSOR_APPLYRGB__DOC__ },
+ {"applyRGBA",
+ PyOCIO_Processor_applyRGBA, METH_VARARGS, PROCESSOR_APPLYRGBA__DOC__ },
+ {"getCpuCacheID",
+ (PyCFunction) PyOCIO_Processor_getCpuCacheID, METH_NOARGS, PROCESSOR_GETCPUCACHEID__DOC__ },
+ {"getGpuShaderText",
+ PyOCIO_Processor_getGpuShaderText, METH_VARARGS, PROCESSOR_GETGPUSHADERTEXT__DOC__ },
+ {"getGpuShaderTextCacheID",
+ PyOCIO_Processor_getGpuShaderTextCacheID, METH_VARARGS, PROCESSOR_GETGPUSHADERTEXTCACHEID__DOC__ },
+ {"getGpuLut3D",
+ PyOCIO_Processor_getGpuLut3D, METH_VARARGS, PROCESSOR_GETGPULUT3D__DOC__ },
+ {"getGpuLut3DCacheID",
+ PyOCIO_Processor_getGpuLut3DCacheID, METH_VARARGS, PROCESSOR_GETGPULUT3DCACHEID__DOC__ },
+ {NULL, NULL, 0, NULL}
+ };
+
+ const char initMessage[] =
+ "Processor objects cannot be instantiated directly. "
+ "Please use config.getProcessor() instead.";
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyTypeObject PyOCIO_ProcessorType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, //ob_size
+ "OCIO.Processor", //tp_name
+ sizeof(PyOCIO_Processor), //tp_basicsize
+ 0, //tp_itemsize
+ (destructor)PyOCIO_Processor_delete, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ 0, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
+ PROCESSOR__DOC__, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ PyOCIO_Processor_methods, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ 0, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ (initproc) PyOCIO_Processor_init, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0, //tp_del
+ #if PY_VERSION_HEX > 0x02060000
+ 0, //tp_version_tag
+ #endif
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ // TODO: The use of a dict, rather than a native class is not ideal
+ // in the next API revision, use a native type.
+
+ void FillShaderDescFromPyDict(GpuShaderDesc & shaderDesc,
+ PyObject * dict)
+ {
+ if(!PyDict_Check(dict))
+ {
+ throw Exception("GpuShaderDesc must be a dict type.");
+ }
+
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+
+ while (PyDict_Next(dict, &pos, &key, &value))
+ {
+ std::string keystr;
+ if(!GetStringFromPyObject(key, &keystr))
+ throw Exception("GpuShaderDesc keys must be strings.");
+
+ if(keystr == "language")
+ {
+ GpuLanguage language = GPU_LANGUAGE_UNKNOWN;
+ if(ConvertPyObjectToGpuLanguage(value, &language) == 0)
+ throw Exception("GpuShaderDesc language must be a GpuLanguage.");
+ shaderDesc.setLanguage(language);
+ }
+ else if(keystr == "functionName")
+ {
+ std::string functionName;
+ if(!GetStringFromPyObject(value, &functionName))
+ throw Exception("GpuShaderDesc functionName must be a string.");
+ shaderDesc.setFunctionName(functionName.c_str());
+ }
+ else if(keystr == "lut3DEdgeLen")
+ {
+ int lut3DEdgeLen = 0;
+ if(!GetIntFromPyObject(value, &lut3DEdgeLen))
+ throw Exception("GpuShaderDesc lut3DEdgeLen must be an integer.");
+ shaderDesc.setLut3DEdgeLen(lut3DEdgeLen);
+ }
+ else
+ {
+ std::ostringstream os;
+ os << "Unknown GpuShaderDesc key, '";
+ os << keystr << "'. ";
+ os << "Allowed keys: (";
+ os << "'language', 'functionName', 'lut3DEdgeLen').";
+ throw Exception(os.str().c_str());
+ }
+ }
+ }
+ }
+
+ namespace
+ {
+ ///////////////////////////////////////////////////////////////////////
+ ///
+ int PyOCIO_Processor_init( PyOCIO_Processor */*self*/,
+ PyObject * /*args*/, PyObject * /*kwds*/ )
+ {
+ PyErr_SetString( PyExc_RuntimeError, initMessage);
+ return -1;
+ }
+
+ void PyOCIO_Processor_delete( PyOCIO_Processor *self, PyObject * /*args*/ )
+ {
+ delete self->constcppobj;
+ self->ob_type->tp_free((PyObject*)self);
+ }
+
+ PyObject * PyOCIO_Processor_isNoOp( PyObject * self )
+ {
+ try
+ {
+ ConstProcessorRcPtr processor = GetConstProcessor(self);
+ return PyBool_FromLong( processor->isNoOp() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Processor_hasChannelCrosstalk( PyObject * self )
+ {
+ try
+ {
+ ConstProcessorRcPtr processor = GetConstProcessor(self);
+ return PyBool_FromLong( processor->hasChannelCrosstalk() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Processor_getMetadata( PyObject * self )
+ {
+ try
+ {
+ ConstProcessorRcPtr processor = GetConstProcessor(self);
+ return BuildConstPyProcessorMetadata( processor->getMetadata() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Processor_applyRGB( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyData = 0;
+ if (!PyArg_ParseTuple(args,"O:applyRGB", &pyData)) return NULL;
+
+ ConstProcessorRcPtr processor = GetConstProcessor(self);
+ if(processor->isNoOp())
+ {
+ Py_INCREF(pyData);
+ return pyData;
+ }
+
+ std::vector<float> data;
+ if(!FillFloatVectorFromPySequence(pyData, data) || ((data.size()%3) != 0))
+ {
+ std::ostringstream os;
+ os << "First argument must be a float array, size multiple of 3. ";
+ os << "Size: " << data.size() << ".";
+ PyErr_SetString(PyExc_TypeError, os.str().c_str());
+ return 0;
+ }
+
+ PackedImageDesc img(&data[0], data.size()/3, 1, 3);
+ processor->apply(img);
+
+ return CreatePyListFromFloatVector(data);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Processor_applyRGBA( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyData = 0;
+ if (!PyArg_ParseTuple(args,"O:applyRGBA", &pyData)) return NULL;
+
+ ConstProcessorRcPtr processor = GetConstProcessor(self);
+ if(processor->isNoOp())
+ {
+ Py_INCREF(pyData);
+ return pyData;
+ }
+
+ std::vector<float> data;
+ if(!FillFloatVectorFromPySequence(pyData, data) || ((data.size()%4) != 0))
+ {
+ std::ostringstream os;
+ os << "First argument must be a float array, size multiple of 4. ";
+ os << "Size: " << data.size() << ".";
+ PyErr_SetString(PyExc_TypeError, os.str().c_str());
+ return 0;
+ }
+
+ PackedImageDesc img(&data[0], data.size()/4, 1, 4);
+ processor->apply(img);
+
+ return CreatePyListFromFloatVector(data);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Processor_getCpuCacheID( PyObject * self )
+ {
+ try
+ {
+ ConstProcessorRcPtr processor = GetConstProcessor(self);
+ return PyString_FromString( processor->getCpuCacheID() );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Processor_getGpuShaderText( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyData = 0;
+ if (!PyArg_ParseTuple(args,"O!:getGpuShaderText",
+ &PyDict_Type, &pyData)) return NULL;
+ ConstProcessorRcPtr processor = GetConstProcessor(self);
+
+ GpuShaderDesc shaderDesc;
+ FillShaderDescFromPyDict(shaderDesc, pyData);
+
+ return PyString_FromString( processor->getGpuShaderText(shaderDesc) );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Processor_getGpuShaderTextCacheID( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyData = 0;
+ if (!PyArg_ParseTuple(args,"O!:getGpuShaderTextCacheID",
+ &PyDict_Type, &pyData)) return NULL;
+ ConstProcessorRcPtr processor = GetConstProcessor(self);
+
+ GpuShaderDesc shaderDesc;
+ FillShaderDescFromPyDict(shaderDesc, pyData);
+
+ return PyString_FromString( processor->getGpuShaderTextCacheID(shaderDesc) );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Processor_getGpuLut3D( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyData = 0;
+ if (!PyArg_ParseTuple(args,"O!:getGpuLut3D",
+ &PyDict_Type, &pyData)) return NULL;
+ ConstProcessorRcPtr processor = GetConstProcessor(self);
+
+ GpuShaderDesc shaderDesc;
+ FillShaderDescFromPyDict(shaderDesc, pyData);
+
+ int len = shaderDesc.getLut3DEdgeLen();
+ std::vector<float> lut3d(3*len*len*len);
+
+ // TODO: return more compact binary data? (ex array, ...)
+ processor->getGpuLut3D(&lut3d[0], shaderDesc);
+ return CreatePyListFromFloatVector(lut3d);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Processor_getGpuLut3DCacheID( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ PyObject * pyData = 0;
+ if (!PyArg_ParseTuple(args,"O!:getGpuLut3DCacheID",
+ &PyDict_Type, &pyData)) return NULL;
+ ConstProcessorRcPtr processor = GetConstProcessor(self);
+
+ GpuShaderDesc shaderDesc;
+ FillShaderDescFromPyDict(shaderDesc, pyData);
+
+ return PyString_FromString( processor->getGpuLut3DCacheID(shaderDesc) );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/pyglue/PyProcessor.h b/src/pyglue/PyProcessor.h
new file mode 100644
index 0000000..571847d
--- /dev/null
+++ b/src/pyglue/PyProcessor.h
@@ -0,0 +1,50 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_PYOCIO_PYPROCESSOR_H
+#define INCLUDED_PYOCIO_PYPROCESSOR_H
+
+#include <PyOpenColorIO/PyOpenColorIO.h>
+
+OCIO_NAMESPACE_ENTER
+{
+ // TODO: Maybe put this in a pyinternal namespace?
+
+ typedef struct {
+ PyObject_HEAD
+ ConstProcessorRcPtr * constcppobj;
+ } PyOCIO_Processor;
+
+ extern PyTypeObject PyOCIO_ProcessorType;
+
+ bool AddProcessorObjectToModule( PyObject* m );
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/pyglue/PyProcessorMetadata.cpp b/src/pyglue/PyProcessorMetadata.cpp
new file mode 100644
index 0000000..f8a4a92
--- /dev/null
+++ b/src/pyglue/PyProcessorMetadata.cpp
@@ -0,0 +1,245 @@
+/*
+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 <Python.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "PyProcessorMetadata.h"
+#include "PyUtil.h"
+#include "PyDoc.h"
+
+#include <sstream>
+
+OCIO_NAMESPACE_ENTER
+{
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ bool AddProcessorMetadataObjectToModule( PyObject* m )
+ {
+ PyOCIO_ProcessorMetadataType.tp_new = PyType_GenericNew;
+ if ( PyType_Ready(&PyOCIO_ProcessorMetadataType) < 0 ) return false;
+
+ Py_INCREF( &PyOCIO_ProcessorMetadataType );
+ PyModule_AddObject(m, "ProcessorMetadata",
+ (PyObject *)&PyOCIO_ProcessorMetadataType);
+
+ return true;
+ }
+
+ PyObject * BuildConstPyProcessorMetadata(ConstProcessorMetadataRcPtr metadata)
+ {
+ if (!metadata)
+ {
+ Py_RETURN_NONE;
+ }
+
+ PyOCIO_ProcessorMetadata * pyMetadata = PyObject_New(
+ PyOCIO_ProcessorMetadata, (PyTypeObject * ) &PyOCIO_ProcessorMetadataType);
+
+ pyMetadata->constcppobj = new ConstProcessorMetadataRcPtr();
+ *pyMetadata->constcppobj = metadata;
+
+ return ( PyObject * ) pyMetadata;
+ }
+
+ bool IsPyProcessorMetadata(PyObject * pyobject)
+ {
+ if(!pyobject) return false;
+ return (PyObject_Type(pyobject) == (PyObject *) (&PyOCIO_ProcessorMetadataType));
+ }
+
+ ConstProcessorMetadataRcPtr GetConstProcessorMetadata(PyObject * pyobject)
+ {
+ if(!IsPyProcessorMetadata(pyobject))
+ {
+ throw Exception("PyObject must be an OCIO.ProcessorMetadata.");
+ }
+
+ PyOCIO_ProcessorMetadata * pyMetadata = reinterpret_cast<PyOCIO_ProcessorMetadata *> (pyobject);
+ if(pyMetadata->constcppobj)
+ {
+ return *pyMetadata->constcppobj;
+ }
+
+ throw Exception("PyObject must be a valid OCIO.ProcessorMetadata.");
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ int PyOCIO_ProcessorMetadata_init( PyOCIO_ProcessorMetadata * self, PyObject * args, PyObject * kwds );
+ void PyOCIO_ProcessorMetadata_delete( PyOCIO_ProcessorMetadata * self, PyObject * args );
+
+ PyObject * PyOCIO_ProcessorMetadata_getFiles( PyObject * self );
+ PyObject * PyOCIO_ProcessorMetadata_getLooks( PyObject * self );
+
+ ///////////////////////////////////////////////////////////////////////
+ ///
+
+ PyMethodDef PyOCIO_ProcessorMetadata_methods[] = {
+ {"getFiles",
+ (PyCFunction) PyOCIO_ProcessorMetadata_getFiles, METH_NOARGS,
+ PROCESSORMETADATA_GETFILES__DOC__ },
+ {"getLooks",
+ (PyCFunction) PyOCIO_ProcessorMetadata_getLooks, METH_NOARGS,
+ PROCESSORMETADATA_GETLOOKS__DOC__ },
+ {NULL, NULL, 0, NULL}
+ };
+
+ const char initMessage[] =
+ "ProcessorMetadata objects cannot be instantiated directly. "
+ "Please use processor.getMetadata() instead.";
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyTypeObject PyOCIO_ProcessorMetadataType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, //ob_size
+ "OCIO.ProcessorMetadata", //tp_name
+ sizeof(PyOCIO_ProcessorMetadata), //tp_basicsize
+ 0, //tp_itemsize
+ (destructor)PyOCIO_ProcessorMetadata_delete,//tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ 0, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
+ PROCESSORMETADATA__DOC__, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ PyOCIO_ProcessorMetadata_methods, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ 0, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ (initproc) PyOCIO_ProcessorMetadata_init, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0, //tp_del
+ #if PY_VERSION_HEX > 0x02060000
+ 0, //tp_version_tag
+ #endif
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ ///////////////////////////////////////////////////////////////////////
+ ///
+ int PyOCIO_ProcessorMetadata_init( PyOCIO_ProcessorMetadata */*self*/,
+ PyObject * /*args*/, PyObject * /*kwds*/ )
+ {
+ PyErr_SetString( PyExc_RuntimeError, initMessage);
+ return -1;
+ }
+
+ void PyOCIO_ProcessorMetadata_delete( PyOCIO_ProcessorMetadata *self, PyObject * /*args*/ )
+ {
+ delete self->constcppobj;
+ self->ob_type->tp_free((PyObject*)self);
+ }
+
+ PyObject * PyOCIO_ProcessorMetadata_getFiles( PyObject * self )
+ {
+ try
+ {
+ ConstProcessorMetadataRcPtr metadata = GetConstProcessorMetadata(self);
+
+ std::vector<std::string> data;
+ for(int i=0; i<metadata->getNumFiles(); ++i)
+ {
+ data.push_back(metadata->getFile(i));
+ }
+
+ return CreatePyListFromStringVector(data);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_ProcessorMetadata_getLooks( PyObject * self )
+ {
+ try
+ {
+ ConstProcessorMetadataRcPtr metadata = GetConstProcessorMetadata(self);
+
+ std::vector<std::string> data;
+ for(int i=0; i<metadata->getNumLooks(); ++i)
+ {
+ data.push_back(metadata->getLook(i));
+ }
+
+ return CreatePyListFromStringVector(data);
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+ } // anon namespace
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/pyglue/PyProcessorMetadata.h b/src/pyglue/PyProcessorMetadata.h
new file mode 100644
index 0000000..4aada84
--- /dev/null
+++ b/src/pyglue/PyProcessorMetadata.h
@@ -0,0 +1,50 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_PYOCIO_PYPROCESSORMETADATA_H
+#define INCLUDED_PYOCIO_PYPROCESSORMETADATA_H
+
+#include <PyOpenColorIO/PyOpenColorIO.h>
+
+OCIO_NAMESPACE_ENTER
+{
+ // TODO: Maybe put this in a pyinternal namespace?
+
+ typedef struct {
+ PyObject_HEAD
+ ConstProcessorMetadataRcPtr * constcppobj;
+ } PyOCIO_ProcessorMetadata;
+
+ extern PyTypeObject PyOCIO_ProcessorMetadataType;
+
+ bool AddProcessorMetadataObjectToModule( PyObject* m );
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/pyglue/PyTransform.cpp b/src/pyglue/PyTransform.cpp
new file mode 100644
index 0000000..848e966
--- /dev/null
+++ b/src/pyglue/PyTransform.cpp
@@ -0,0 +1,411 @@
+/*
+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 <Python.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "PyTransform.h"
+#include "PyUtil.h"
+#include "PyDoc.h"
+
+#include <sstream>
+
+OCIO_NAMESPACE_ENTER
+{
+ namespace
+ {
+ PyOCIO_Transform * PyTransform_New(ConstTransformRcPtr transform)
+ {
+ if (!transform)
+ {
+ return 0x0;
+ }
+
+ PyOCIO_Transform * pyobj = 0x0;
+
+ if(ConstAllocationTransformRcPtr allocationTransform = \
+ DynamicPtrCast<const AllocationTransform>(transform))
+ {
+ pyobj = PyObject_New(PyOCIO_Transform,
+ (PyTypeObject * ) &PyOCIO_AllocationTransformType);
+ }
+ else if(ConstCDLTransformRcPtr cdlTransform = \
+ DynamicPtrCast<const CDLTransform>(transform))
+ {
+ pyobj = PyObject_New(PyOCIO_Transform,
+ (PyTypeObject * ) &PyOCIO_CDLTransformType);
+ }
+ else if(ConstColorSpaceTransformRcPtr colorSpaceTransform = \
+ DynamicPtrCast<const ColorSpaceTransform>(transform))
+ {
+ pyobj = PyObject_New(PyOCIO_Transform,
+ (PyTypeObject * ) &PyOCIO_ColorSpaceTransformType);
+ }
+ else if(ConstDisplayTransformRcPtr displayTransform = \
+ DynamicPtrCast<const DisplayTransform>(transform))
+ {
+ pyobj = PyObject_New(PyOCIO_Transform,
+ (PyTypeObject * ) &PyOCIO_DisplayTransformType);
+ }
+ else if(ConstExponentTransformRcPtr exponentTransform = \
+ DynamicPtrCast<const ExponentTransform>(transform))
+ {
+ pyobj = PyObject_New(PyOCIO_Transform,
+ (PyTypeObject * ) &PyOCIO_ExponentTransformType);
+ }
+ else if(ConstFileTransformRcPtr fileTransform = \
+ DynamicPtrCast<const FileTransform>(transform))
+ {
+ pyobj = PyObject_New(PyOCIO_Transform,
+ (PyTypeObject * ) &PyOCIO_FileTransformType);
+ }
+ else if(ConstGroupTransformRcPtr groupTransform = \
+ DynamicPtrCast<const GroupTransform>(transform))
+ {
+ pyobj = PyObject_New(PyOCIO_Transform,
+ (PyTypeObject * ) &PyOCIO_GroupTransformType);
+ }
+ else if(ConstLogTransformRcPtr logTransform = \
+ DynamicPtrCast<const LogTransform>(transform))
+ {
+ pyobj = PyObject_New(PyOCIO_Transform,
+ (PyTypeObject * ) &PyOCIO_LogTransformType);
+ }
+ else if(ConstLookTransformRcPtr lookTransform = \
+ DynamicPtrCast<const LookTransform>(transform))
+ {
+ pyobj = PyObject_New(PyOCIO_Transform,
+ (PyTypeObject * ) &PyOCIO_LookTransformType);
+ }
+ else if(ConstMatrixTransformRcPtr matrixTransform = \
+ DynamicPtrCast<const MatrixTransform>(transform))
+ {
+ pyobj = PyObject_New(PyOCIO_Transform,
+ (PyTypeObject * ) &PyOCIO_MatrixTransformType);
+ }
+
+ return pyobj;
+ }
+ }
+
+ PyObject * BuildConstPyTransform(ConstTransformRcPtr transform)
+ {
+ if (!transform)
+ {
+ Py_RETURN_NONE;
+ }
+
+ PyOCIO_Transform * pyobj = PyTransform_New(transform);
+
+ if(!pyobj)
+ {
+ std::ostringstream os;
+ os << "Unknown transform type for BuildConstPyTransform.";
+ throw Exception(os.str().c_str());
+ }
+
+ pyobj->constcppobj = new ConstTransformRcPtr();
+ pyobj->cppobj = new TransformRcPtr();
+
+ *pyobj->constcppobj = transform;
+ pyobj->isconst = true;
+
+ return (PyObject *) pyobj;
+ }
+
+ PyObject * BuildEditablePyTransform(TransformRcPtr transform)
+ {
+ if (!transform)
+ {
+ Py_RETURN_NONE;
+ }
+
+ PyOCIO_Transform * pyobj = PyTransform_New(transform);
+
+ pyobj->constcppobj = new ConstTransformRcPtr();
+ pyobj->cppobj = new TransformRcPtr();
+
+ *pyobj->cppobj = transform;
+ pyobj->isconst = false;
+
+ return (PyObject *) pyobj;
+ }
+
+ bool IsPyTransform(PyObject * pyobject)
+ {
+ if(!pyobject) return false;
+ return PyObject_TypeCheck(pyobject, &PyOCIO_TransformType);
+ }
+
+ bool IsPyTransformEditable(PyObject * pyobject)
+ {
+ if(!IsPyTransform(pyobject)) return false;
+
+ PyOCIO_Transform * pyobj = reinterpret_cast<PyOCIO_Transform *> (pyobject);
+ return (!pyobj->isconst);
+ }
+
+ TransformRcPtr GetEditableTransform(PyObject * pyobject)
+ {
+ if(!IsPyTransform(pyobject))
+ {
+ throw Exception("PyObject must be an OCIO.Transform.");
+ }
+
+ PyOCIO_Transform * pytransform = reinterpret_cast<PyOCIO_Transform *> (pyobject);
+ if(!pytransform->isconst && pytransform->cppobj)
+ {
+ return *pytransform->cppobj;
+ }
+
+ throw Exception("PyObject must be an editable OCIO.Transform.");
+ }
+
+ ConstTransformRcPtr GetConstTransform(PyObject * pyobject, bool allowCast)
+ {
+ if(!IsPyTransform(pyobject))
+ {
+ throw Exception("PyObject must be an OCIO.Transform.");
+ }
+
+ PyOCIO_Transform * pytransform = reinterpret_cast<PyOCIO_Transform *> (pyobject);
+ if(pytransform->isconst && pytransform->constcppobj)
+ {
+ return *pytransform->constcppobj;
+ }
+
+ if(allowCast && !pytransform->isconst && pytransform->cppobj)
+ {
+ return *pytransform->cppobj;
+ }
+
+ throw Exception("PyObject must be a valid OCIO.Transform.");
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ bool AddTransformObjectToModule( PyObject* m )
+ {
+ PyOCIO_TransformType.tp_new = PyType_GenericNew;
+ if ( PyType_Ready(&PyOCIO_TransformType) < 0 ) return false;
+
+ Py_INCREF( &PyOCIO_TransformType );
+ PyModule_AddObject(m, "Transform",
+ (PyObject *)&PyOCIO_TransformType);
+
+ return true;
+ }
+
+ namespace
+ {
+ int PyOCIO_Transform_init( PyOCIO_Transform * self, PyObject * args, PyObject * kwds );
+ void PyOCIO_Transform_delete( PyOCIO_Transform * self, PyObject * args );
+
+ PyObject * PyOCIO_Transform_isEditable( PyObject * self );
+ PyObject * PyOCIO_Transform_createEditableCopy( PyObject * self );
+ PyObject * PyOCIO_Transform_getDirection( PyObject * self );
+ PyObject * PyOCIO_Transform_setDirection( PyObject * self, PyObject *args );
+
+ ///////////////////////////////////////////////////////////////////////
+ ///
+
+ PyMethodDef PyOCIO_Transform_methods[] = {
+ {"isEditable",
+ (PyCFunction) PyOCIO_Transform_isEditable, METH_NOARGS, TRANSFORM_ISEDITABLE__DOC__ },
+ {"createEditableCopy",
+ (PyCFunction) PyOCIO_Transform_createEditableCopy, METH_NOARGS, TRANSFORM_CREATEEDITABLECOPY__DOC__ },
+ {"getDirection",
+ (PyCFunction) PyOCIO_Transform_getDirection, METH_NOARGS, TRANSFORM_GETDIRECTION__DOC__ },
+ {"setDirection",
+ PyOCIO_Transform_setDirection, METH_VARARGS, TRANSFORM_SETDIRECTION__DOC__ },
+ {NULL, NULL, 0, NULL}
+ };
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyTypeObject PyOCIO_TransformType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, //ob_size
+ "OCIO.Transform", //tp_name
+ sizeof(PyOCIO_Transform), //tp_basicsize
+ 0, //tp_itemsize
+ (destructor) PyOCIO_Transform_delete, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ 0, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
+ TRANSFORM__DOC__, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ PyOCIO_Transform_methods, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ 0, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ (initproc) PyOCIO_Transform_init, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0, //tp_del
+ #if PY_VERSION_HEX > 0x02060000
+ 0, //tp_version_tag
+ #endif
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///
+
+ namespace
+ {
+ ///////////////////////////////////////////////////////////////////////
+ ///
+ int PyOCIO_Transform_init( PyOCIO_Transform *self, PyObject * /*args*/, PyObject * /*kwds*/ )
+ {
+ ///////////////////////////////////////////////////////////////////
+ /// init pyobject fields
+
+ self->constcppobj = new ConstTransformRcPtr();
+ self->cppobj = new TransformRcPtr();
+ self->isconst = true;
+
+ std::string message = "Base Transforms class can not be instantiated.";
+ PyErr_SetString( PyExc_RuntimeError, message.c_str() );
+ return -1;
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ void PyOCIO_Transform_delete( PyOCIO_Transform *self, PyObject * /*args*/ )
+ {
+ delete self->constcppobj;
+ delete self->cppobj;
+
+ self->ob_type->tp_free((PyObject*)self);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_Transform_isEditable( PyObject * self )
+ {
+ return PyBool_FromLong(IsPyTransformEditable(self));
+ }
+
+ PyObject * PyOCIO_Transform_createEditableCopy( PyObject * self )
+ {
+ try
+ {
+ ConstTransformRcPtr transform = GetConstTransform(self, true);
+ TransformRcPtr copy = transform->createEditableCopy();
+
+ PyOCIO_Transform * pycopy = PyTransform_New(copy);
+ pycopy->constcppobj = new ConstTransformRcPtr();
+ pycopy->cppobj = new TransformRcPtr();
+ *pycopy->cppobj = copy;
+ pycopy->isconst = false;
+
+ return (PyObject *) pycopy;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ///
+
+ PyObject * PyOCIO_Transform_getDirection( PyObject * self )
+ {
+ try
+ {
+ ConstTransformRcPtr transform = GetConstTransform(self, true);
+ TransformDirection dir = transform->getDirection();
+ return PyString_FromString( TransformDirectionToString( dir ) );
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+
+ PyObject * PyOCIO_Transform_setDirection( PyObject * self, PyObject * args )
+ {
+ try
+ {
+ TransformDirection dir;
+ if (!PyArg_ParseTuple(args,"O&:setDirection",
+ ConvertPyObjectToTransformDirection, &dir)) return NULL;
+
+ TransformRcPtr transform = GetEditableTransform(self);
+ transform->setDirection( dir );
+
+ Py_RETURN_NONE;
+ }
+ catch(...)
+ {
+ Python_Handle_Exception();
+ return NULL;
+ }
+ }
+ }
+
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/pyglue/PyTransform.h b/src/pyglue/PyTransform.h
new file mode 100644
index 0000000..0ff3e6b
--- /dev/null
+++ b/src/pyglue/PyTransform.h
@@ -0,0 +1,81 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_PYOCIO_PYTRANSFORM_H
+#define INCLUDED_PYOCIO_PYTRANSFORM_H
+
+#include <PyOpenColorIO/PyOpenColorIO.h>
+
+OCIO_NAMESPACE_ENTER
+{
+ // TODO: Maybe put this in a pyinternal namespace?
+
+ typedef struct {
+ PyObject_HEAD
+ ConstTransformRcPtr * constcppobj;
+ TransformRcPtr * cppobj;
+ bool isconst;
+ } PyOCIO_Transform;
+
+ extern PyTypeObject PyOCIO_TransformType;
+ bool AddTransformObjectToModule( PyObject* m );
+
+ extern PyTypeObject PyOCIO_AllocationTransformType;
+ bool AddAllocationTransformObjectToModule( PyObject* m );
+
+ extern PyTypeObject PyOCIO_CDLTransformType;
+ bool AddCDLTransformObjectToModule( PyObject* m );
+
+ extern PyTypeObject PyOCIO_ColorSpaceTransformType;
+ bool AddColorSpaceTransformObjectToModule( PyObject* m );
+
+ extern PyTypeObject PyOCIO_DisplayTransformType;
+ bool AddDisplayTransformObjectToModule( PyObject* m );
+
+ extern PyTypeObject PyOCIO_ExponentTransformType;
+ bool AddExponentTransformObjectToModule( PyObject* m );
+
+ extern PyTypeObject PyOCIO_FileTransformType;
+ bool AddFileTransformObjectToModule( PyObject* m );
+
+ extern PyTypeObject PyOCIO_GroupTransformType;
+ bool AddGroupTransformObjectToModule( PyObject* m );
+
+ extern PyTypeObject PyOCIO_LogTransformType;
+ bool AddLogTransformObjectToModule( PyObject* m );
+
+ extern PyTypeObject PyOCIO_LookTransformType;
+ bool AddLookTransformObjectToModule( PyObject* m );
+
+ extern PyTypeObject PyOCIO_MatrixTransformType;
+ bool AddMatrixTransformObjectToModule( PyObject* m );
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/pyglue/PyUtil.cpp b/src/pyglue/PyUtil.cpp
new file mode 100644
index 0000000..3058c9d
--- /dev/null
+++ b/src/pyglue/PyUtil.cpp
@@ -0,0 +1,742 @@
+/*
+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 <Python.h>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+#include "PyUtil.h"
+
+#include <sstream>
+
+OCIO_NAMESPACE_ENTER
+{
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ // http://docs.python.org/c-api/object.html#PyObject_IsTrue
+ int ConvertPyObjectToBool(PyObject *object, void *valuePtr)
+ {
+ bool *boolPtr = static_cast<bool*>(valuePtr);
+ int status = PyObject_IsTrue(object);
+
+ if (status == -1 || PyErr_Occurred())
+ {
+ if (!PyErr_Occurred())
+ {
+ PyErr_SetString(PyExc_ValueError, "could not convert object to bool.");
+ }
+
+ return 0;
+ }
+
+ *boolPtr = (status == 1) ? true : false;
+
+ return 1;
+ }
+
+ int ConvertPyObjectToAllocation(PyObject *object, void *valuePtr)
+ {
+ Allocation* allocPtr = static_cast<Allocation*>(valuePtr);
+
+ if(!PyString_Check(object))
+ {
+ PyErr_SetString(PyExc_ValueError, "Object is not a string.");
+ return 0;
+ }
+
+ *allocPtr = AllocationFromString(PyString_AsString( object ));
+
+ return 1;
+ }
+
+
+
+ int ConvertPyObjectToInterpolation(PyObject *object, void *valuePtr)
+ {
+ Interpolation* interpPtr = static_cast<Interpolation*>(valuePtr);
+
+ if(!PyString_Check(object))
+ {
+ PyErr_SetString(PyExc_ValueError, "Object is not a string.");
+ return 0;
+ }
+
+ *interpPtr = InterpolationFromString(PyString_AsString( object ));
+
+ return 1;
+ }
+
+ int ConvertPyObjectToTransformDirection(PyObject *object, void *valuePtr)
+ {
+ TransformDirection* dirPtr = static_cast<TransformDirection*>(valuePtr);
+
+ if(!PyString_Check(object))
+ {
+ PyErr_SetString(PyExc_ValueError, "Object is not a string.");
+ return 0;
+ }
+
+ *dirPtr = TransformDirectionFromString(PyString_AsString( object ));
+
+ return 1;
+ }
+
+
+ int ConvertPyObjectToColorSpaceDirection(PyObject *object, void *valuePtr)
+ {
+ ColorSpaceDirection* dirPtr = static_cast<ColorSpaceDirection*>(valuePtr);
+
+ if(!PyString_Check(object))
+ {
+ PyErr_SetString(PyExc_ValueError, "Object is not a string.");
+ return 0;
+ }
+
+ *dirPtr = ColorSpaceDirectionFromString(PyString_AsString( object ));
+
+ return 1;
+ }
+
+
+ int ConvertPyObjectToGpuLanguage(PyObject *object, void *valuePtr)
+ {
+ GpuLanguage* gpuLanguagePtr = static_cast<GpuLanguage*>(valuePtr);
+
+ if(!PyString_Check(object))
+ {
+ PyErr_SetString(PyExc_ValueError, "Object is not a string.");
+ return 0;
+ }
+
+ *gpuLanguagePtr = GpuLanguageFromString(PyString_AsString( object ));
+
+ return 1;
+ }
+
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ bool GetIntFromPyObject(PyObject* object, int* val)
+ {
+ if(!val || !object) return false;
+
+ if( PyInt_Check( object ) )
+ {
+ *val = static_cast<int>( PyInt_AS_LONG( object ) );
+ return true;
+ }
+
+ if( PyFloat_Check( object ) )
+ {
+ *val = static_cast<int>( PyFloat_AS_DOUBLE( object ) );
+ return true;
+ }
+
+ PyObject* intObject = PyNumber_Int(object);
+ if(intObject)
+ {
+ *val = static_cast<int>( PyInt_AS_LONG( intObject ) );
+ Py_DECREF(intObject);
+ return true;
+ }
+
+ PyErr_Clear();
+ return false;
+ }
+
+ bool GetFloatFromPyObject(PyObject* object, float* val)
+ {
+ if(!val || !object) return false;
+
+ if( PyFloat_Check( object ) )
+ {
+ *val = static_cast<float>( PyFloat_AS_DOUBLE( object ) );
+ return true;
+ }
+
+ if( PyInt_Check( object ) )
+ {
+ *val = static_cast<float>( PyInt_AS_LONG( object ) );
+ return true;
+ }
+
+ PyObject* floatObject = PyNumber_Float(object);
+ if(floatObject)
+ {
+ *val = static_cast<float>( PyFloat_AS_DOUBLE( floatObject ) );
+ Py_DECREF(floatObject);
+ return true;
+ }
+
+ PyErr_Clear();
+ return false;
+ }
+
+ bool GetDoubleFromPyObject(PyObject* object, double* val)
+ {
+ if(!val || !object) return false;
+
+ if( PyFloat_Check( object ) )
+ {
+ *val = PyFloat_AS_DOUBLE( object );
+ return true;
+ }
+
+ if( PyInt_Check( object ) )
+ {
+ *val = static_cast<double>( PyInt_AS_LONG( object ) );
+ return true;
+ }
+
+ PyObject* floatObject = PyNumber_Float(object);
+ if(floatObject)
+ {
+ *val = PyFloat_AS_DOUBLE( floatObject );
+ Py_DECREF(floatObject);
+ return true;
+ }
+
+ PyErr_Clear();
+ return false;
+ }
+
+ bool GetStringFromPyObject(PyObject* object, std::string* val)
+ {
+ if(!val || !object) return false;
+
+ if( PyString_Check( object ) )
+ {
+ *val = std::string(PyString_AS_STRING(object));
+ return true;
+ }
+
+ PyObject* strObject = PyObject_Str(object);
+ if(strObject)
+ {
+ *val = std::string(PyString_AS_STRING(strObject));
+ Py_DECREF(strObject);
+ return true;
+ }
+
+ PyErr_Clear();
+ return false;
+ }
+
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ PyObject* CreatePyListFromIntVector(const std::vector<int> &data)
+ {
+ PyObject* returnlist = PyList_New( data.size() );
+ if(!returnlist) return 0;
+
+ for(unsigned int i =0; i<data.size(); ++i)
+ {
+ PyList_SET_ITEM(returnlist, i, PyInt_FromLong(data[i]));
+ }
+
+ return returnlist;
+ }
+
+ PyObject* CreatePyListFromFloatVector(const std::vector<float> &data)
+ {
+ PyObject* returnlist = PyList_New( data.size() );
+ if(!returnlist) return 0;
+
+ for(unsigned int i =0; i<data.size(); ++i)
+ {
+ PyList_SET_ITEM(returnlist, i, PyFloat_FromDouble(data[i]));
+ }
+
+ return returnlist;
+ }
+
+ PyObject* CreatePyListFromDoubleVector(const std::vector<double> &data)
+ {
+ PyObject* returnlist = PyList_New( data.size() );
+ if(!returnlist) return 0;
+
+ for(unsigned int i =0; i<data.size(); ++i)
+ {
+ PyList_SET_ITEM(returnlist, i, PyFloat_FromDouble(data[i]));
+ }
+
+ return returnlist;
+ }
+
+ PyObject* CreatePyListFromStringVector(const std::vector<std::string> &data)
+ {
+ PyObject* returnlist = PyList_New( data.size() );
+ if(!returnlist) return 0;
+
+ for(unsigned int i =0; i<data.size(); ++i)
+ {
+ PyObject *str = PyString_FromString(data[i].c_str());
+ if (str == NULL)
+ {
+ Py_DECREF(returnlist);
+ return NULL;
+ }
+ PyList_SET_ITEM(returnlist, i, str);
+ }
+
+ return returnlist;
+ }
+
+ PyObject* CreatePyListFromTransformVector(const std::vector<ConstTransformRcPtr> &data)
+ {
+ PyObject* returnlist = PyList_New( data.size() );
+ if(!returnlist) return 0;
+
+ for(unsigned int i =0; i<data.size(); ++i)
+ {
+ PyList_SET_ITEM(returnlist, i, BuildConstPyTransform(data[i]));
+ }
+
+ return returnlist;
+ }
+
+
+ namespace
+ {
+ // These are safer than PySequence_Fast, as we can
+ // Confirm that no exceptions will be set in the python runtime.
+
+ inline bool PyListOrTuple_Check(PyObject* pyobj)
+ {
+ return (PyTuple_Check(pyobj) || PyList_Check(pyobj));
+ }
+
+ inline int PyListOrTuple_GET_SIZE(PyObject* pyobj)
+ {
+ if(PyList_Check(pyobj))
+ {
+ return static_cast<int>(PyList_GET_SIZE(pyobj));
+ }
+ else if(PyTuple_Check(pyobj))
+ {
+ return static_cast<int>(PyTuple_GET_SIZE(pyobj));
+ }
+ return -1;
+ }
+
+ // Return a boworrowed reference
+ inline PyObject* PyListOrTuple_GET_ITEM(PyObject* pyobj, int index)
+ {
+ if(PyList_Check(pyobj))
+ {
+ return PyList_GET_ITEM(pyobj, index);
+ }
+ else if(PyTuple_Check(pyobj))
+ {
+ return PyTuple_GET_ITEM(pyobj, index);
+ }
+ return 0;
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ /*
+ A note on why PyErr_Clear is needed in multiple locations...
+
+ Even though it's not immediately apparent, almost every function
+ in the Abstract Objects Layer,
+ http://www.python.org/doc/2.5/api/abstract.html
+ can set a global excpetion under certain circumstances.
+
+ For example, calling the equivalent of int( obj ) will set
+ an exception if the object cannot be casted (such as None),
+ or if it's a custom type that implements the number protocol
+ but throws an exception during the cast.
+
+ During iteration, even an object that implements the sequence
+ protocol can raise an exception if the iteration fails.
+
+ As we want to guarantee that an exception *never* remains on
+ the stack after an internal failure, the simplest way to
+ guarantee this is to always call PyErr_Clear() before
+ returing the failure condition.
+ */
+
+ bool FillIntVectorFromPySequence(PyObject* datalist, std::vector<int> &data)
+ {
+ data.clear();
+
+ // First, try list or tuple iteration (for speed).
+ if(PyListOrTuple_Check(datalist))
+ {
+ int sequenceSize = PyListOrTuple_GET_SIZE(datalist);
+ data.reserve(sequenceSize);
+
+ for(int i=0; i < sequenceSize; i++)
+ {
+ PyObject* item = PyListOrTuple_GET_ITEM(datalist, i);
+
+ int val;
+ if (!GetIntFromPyObject(item, &val))
+ {
+ data.clear();
+ return false;
+ }
+ data.push_back(val);
+ }
+
+ return true;
+ }
+ // As a fallback, try general iteration.
+ else
+ {
+ PyObject *item;
+ PyObject *iter = PyObject_GetIter(datalist);
+ if (iter == NULL)
+ {
+ PyErr_Clear();
+ return false;
+ }
+ while((item = PyIter_Next(iter)) != NULL)
+ {
+ int val;
+ if (!GetIntFromPyObject(item, &val))
+ {
+ Py_DECREF(item);
+ Py_DECREF(iter);
+
+ data.clear();
+ return false;
+ }
+ data.push_back(val);
+ Py_DECREF(item);
+ }
+
+ Py_DECREF(iter);
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ data.clear();
+ return false;
+ }
+ return true;
+ }
+ }
+
+ bool FillFloatVectorFromPySequence(PyObject* datalist, std::vector<float> &data)
+ {
+ data.clear();
+
+ if(PyListOrTuple_Check(datalist))
+ {
+ int sequenceSize = PyListOrTuple_GET_SIZE(datalist);
+ data.reserve(sequenceSize);
+
+ for(int i=0; i < sequenceSize; i++)
+ {
+ PyObject* item = PyListOrTuple_GET_ITEM(datalist, i);
+
+ float val;
+ if (!GetFloatFromPyObject(item, &val))
+ {
+ data.clear();
+ return false;
+ }
+ data.push_back(val);
+ }
+ return true;
+ }
+ else
+ {
+ PyObject *item;
+ PyObject *iter = PyObject_GetIter(datalist);
+ if (iter == NULL)
+ {
+ PyErr_Clear();
+ return false;
+ }
+ while((item = PyIter_Next(iter)) != NULL)
+ {
+ float val;
+ if (!GetFloatFromPyObject(item, &val))
+ {
+ Py_DECREF(item);
+ Py_DECREF(iter);
+
+ data.clear();
+ return false;
+ }
+ data.push_back(val);
+ Py_DECREF(item);
+ }
+ Py_DECREF(iter);
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ data.clear();
+ return false;
+ }
+ return true;
+ }
+ }
+
+ bool FillDoubleVectorFromPySequence(PyObject* datalist, std::vector<double> &data)
+ {
+ data.clear();
+
+ if(PyListOrTuple_Check(datalist))
+ {
+ int sequenceSize = PyListOrTuple_GET_SIZE(datalist);
+ data.reserve(sequenceSize);
+
+ for(int i=0; i < sequenceSize; i++)
+ {
+ PyObject* item = PyListOrTuple_GET_ITEM(datalist, i);
+ double val;
+ if (!GetDoubleFromPyObject(item, &val))
+ {
+ data.clear();
+ return false;
+ }
+ data.push_back( val );
+ }
+ return true;
+ }
+ else
+ {
+ PyObject *item;
+ PyObject *iter = PyObject_GetIter(datalist);
+ if (iter == NULL)
+ {
+ PyErr_Clear();
+ return false;
+ }
+ while((item = PyIter_Next(iter)) != NULL)
+ {
+ double val;
+ if (!GetDoubleFromPyObject(item, &val))
+ {
+ Py_DECREF(item);
+ Py_DECREF(iter);
+
+ data.clear();
+ return false;
+ }
+ data.push_back(val);
+ Py_DECREF(item);
+ }
+
+ Py_DECREF(iter);
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ data.clear();
+ return false;
+ }
+ return true;
+ }
+ }
+
+
+ bool FillStringVectorFromPySequence(PyObject* datalist, std::vector<std::string> &data)
+ {
+ data.clear();
+
+ if(PyListOrTuple_Check(datalist))
+ {
+ int sequenceSize = PyListOrTuple_GET_SIZE(datalist);
+ data.reserve(sequenceSize);
+
+ for(int i=0; i < sequenceSize; i++)
+ {
+ PyObject* item = PyListOrTuple_GET_ITEM(datalist, i);
+ std::string val;
+ if (!GetStringFromPyObject(item, &val))
+ {
+ data.clear();
+ return false;
+ }
+ data.push_back( val );
+ }
+ return true;
+ }
+ else
+ {
+ PyObject *item;
+ PyObject *iter = PyObject_GetIter(datalist);
+ if (iter == NULL)
+ {
+ PyErr_Clear();
+ return false;
+ }
+ while((item = PyIter_Next(iter)) != NULL)
+ {
+ std::string val;
+ if (!GetStringFromPyObject(item, &val))
+ {
+ Py_DECREF(item);
+ Py_DECREF(iter);
+
+ data.clear();
+ return false;
+ }
+ data.push_back(val);
+ Py_DECREF(item);
+ }
+
+ Py_DECREF(iter);
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ data.clear();
+ return false;
+ }
+ return true;
+ }
+ }
+
+
+
+ bool FillTransformVectorFromPySequence(PyObject* datalist, std::vector<ConstTransformRcPtr> &data)
+ {
+ data.clear();
+
+ if(PyListOrTuple_Check(datalist))
+ {
+ int sequenceSize = PyListOrTuple_GET_SIZE(datalist);
+ data.reserve(sequenceSize);
+
+ for(int i=0; i < sequenceSize; i++)
+ {
+ PyObject* item = PyListOrTuple_GET_ITEM(datalist, i);
+ ConstTransformRcPtr val;
+ try
+ {
+ val = GetConstTransform(item, true);
+ }
+ catch(...)
+ {
+ data.clear();
+ return false;
+ }
+
+ data.push_back( val );
+ }
+ return true;
+ }
+ else
+ {
+ PyObject *item;
+ PyObject *iter = PyObject_GetIter(datalist);
+ if (iter == NULL)
+ {
+ PyErr_Clear();
+ return false;
+ }
+ while((item = PyIter_Next(iter)) != NULL)
+ {
+ ConstTransformRcPtr val;
+ try
+ {
+ val = GetConstTransform(item, true);
+ }
+ catch(...)
+ {
+ Py_DECREF(item);
+ Py_DECREF(iter);
+
+ data.clear();
+ return false;
+ }
+
+ data.push_back(val);
+ Py_DECREF(item);
+ }
+
+ Py_DECREF(iter);
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ data.clear();
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ /* See the header for the justification for this function.
+
+ The trick to making this technique work is that we know
+ we've been called from within a catch block, so there
+ is an exception on the stack. We can re-throw this
+ exception, using the throw statement. By doing this
+ inside a try...catch block, it's possible to use the
+ standard catch mechanism to categorize whatever exception
+ was actually caught by the caller.
+ */
+
+ void Python_Handle_Exception()
+ {
+ try
+ {
+ // Re-throw whatever exception is already on the stack.
+ // This will fail horribly if no exception is already
+ // on the stack, so this function must only be called
+ // from inside an exception handler catch block!
+ throw;
+ }
+ catch (ExceptionMissingFile & e)
+ {
+ PyErr_SetString(GetExceptionMissingFilePyType(), e.what());
+ }
+ catch (Exception & e)
+ {
+ PyErr_SetString(GetExceptionPyType(), e.what());
+ }
+ catch (std::exception& e)
+ {
+ PyErr_SetString(PyExc_RuntimeError, e.what());
+ }
+ catch (...)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception caught.");
+ }
+ }
+}
+OCIO_NAMESPACE_EXIT
diff --git a/src/pyglue/PyUtil.h b/src/pyglue/PyUtil.h
new file mode 100644
index 0000000..589a7b8
--- /dev/null
+++ b/src/pyglue/PyUtil.h
@@ -0,0 +1,103 @@
+/*
+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.
+*/
+
+
+#ifndef INCLUDED_PYOCIO_PYUTIL_H
+#define INCLUDED_PYOCIO_PYUTIL_H
+
+#include <PyOpenColorIO/PyOpenColorIO.h>
+
+#include <vector>
+
+OCIO_NAMESPACE_ENTER
+{
+
+ int ConvertPyObjectToBool(PyObject *object, void *valuePtr);
+
+ int ConvertPyObjectToAllocation(PyObject *object, void *valuePtr);
+
+ int ConvertPyObjectToInterpolation(PyObject *object, void *valuePtr);
+
+ int ConvertPyObjectToTransformDirection(PyObject *object, void *valuePtr);
+
+ int ConvertPyObjectToColorSpaceDirection(PyObject *object, void *valuePtr);
+
+ int ConvertPyObjectToGpuLanguage(PyObject *object, void *valuePtr);
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ // Generics.
+ // None of these allow an interpreter error to leak
+
+ //! Use a variety of methods to get the value, as the specified type
+ //! from the specified PyObject. (Return true on success, false on failure)
+ //!
+ //! 1. See if object is PyFloat, return value
+ //! 2. See if object is PyInt, return value
+ //! 3. Attempt to cast to PyFloat / PyInt (equivalent to calling float(obj)/int(obj) in python)
+
+ bool GetIntFromPyObject(PyObject* object, int* val);
+ bool GetFloatFromPyObject(PyObject* object, float* val);
+ bool GetDoubleFromPyObject(PyObject* object, double* val);
+
+ //! 1. See if object is a PyString, return value
+ //! 2. Attempt to cast to a PyString (equivalent to calling str(obj) in python
+ //! Note: This will basically always succeed, even if the object is not string-like
+ //! (such as passing Py_None as val), so you cannot use this to check str type.
+
+ bool GetStringFromPyObject(PyObject* object, std::string* val);
+
+
+ // Can return a null pointer if PyList_New(size) fails.
+ PyObject* CreatePyListFromIntVector(const std::vector<int> &data);
+ PyObject* CreatePyListFromFloatVector(const std::vector<float> &data);
+ PyObject* CreatePyListFromDoubleVector(const std::vector<double> &data);
+ PyObject* CreatePyListFromStringVector(const std::vector<std::string> &data);
+ PyObject* CreatePyListFromTransformVector(const std::vector<ConstTransformRcPtr> &data);
+
+ //! Fill the specified vector type from the given pyobject
+ //! Return true on success, false on failure.
+ //! The PyObject must be a tuple or list, filled with the appropriate data types
+ //! (either PyInt, PyFloat, or something convertible to one)
+
+ bool FillIntVectorFromPySequence(PyObject* datalist, std::vector<int> &data);
+ bool FillFloatVectorFromPySequence(PyObject* datalist, std::vector<float> &data);
+ bool FillDoubleVectorFromPySequence(PyObject* datalist, std::vector<double> &data);
+ bool FillStringVectorFromPySequence(PyObject* datalist, std::vector<std::string> &data);
+ bool FillTransformVectorFromPySequence(PyObject* datalist, std::vector<ConstTransformRcPtr> &data);
+
+
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ void Python_Handle_Exception();
+}
+OCIO_NAMESPACE_EXIT
+
+#endif
diff --git a/src/pyglue/createPyDocH.py b/src/pyglue/createPyDocH.py
new file mode 100644
index 0000000..fd2e795
--- /dev/null
+++ b/src/pyglue/createPyDocH.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+
+"""
+This script contains mock OpenColorIO classes which define the __doc__
+strings that will end up in the final binding. These __doc__ strings are
+also used by sphinx's autodoc extension to also include this documentation
+in the html and pdf formats.
+"""
+
+import re, sys
+
+from DocStrings import *
+
+def DocStringToCString(name, doc_string):
+ _cstr = doc_string
+ _cstr = _cstr.rstrip(' ')
+ _cstr = _cstr.rstrip('\n')
+ _cstr = _cstr.lstrip('\n')
+ _cstr = _cstr.lstrip(' ')
+ _cstr = _cstr.replace("\"", "\\\"")
+ _cstr = _cstr.replace("\n", "\\n")
+ _cstr = _cstr.replace("\r", "\\n")
+ return "const char %s[%d] = \"%s\";" % (name, len(_cstr)+1, _cstr)
+
+def GetDocStrings(inst):
+ _out = ""
+ _cname = inst.__name__
+ _cdoc = inst.__doc__
+ if _cdoc == None:
+ _cdoc = ""
+ _out = "%s\n" % DocStringToCString("%s__DOC__" % _cname.upper(), _cdoc)
+ for mem in dir(inst):
+ if mem[0:2] == "__":
+ continue # skip
+ _doc = eval("inst.%s.__doc__" % mem)
+ if _doc == None:
+ _doc = ""
+ _name = "%s_%s__DOC__" % (_cname.upper(), eval("inst.%s.__name__" % mem).upper())
+ _out += "%s\n" % DocStringToCString(_name, _doc)
+ #print mem
+ return _out
+
+if __name__ == "__main__":
+
+ if len(sys.argv) <= 1:
+ sys.stderr.write("\nYou need to specify an output file\n\n")
+ sys.exit(1)
+
+ fileh = file(sys.argv[1], 'w')
+ fileh.write('\n')
+ fileh.write("/* DO NOT EDIT THIS FILE - it is machine generated */\n")
+ fileh.write("\n")
+ fileh.write("#include <OpenColorIO/OpenColorIO.h>\n")
+ fileh.write("\n")
+ fileh.write("OCIO_NAMESPACE_ENTER\n")
+ fileh.write("{\n")
+ fileh.write("\n")
+ fileh.write("%s\n" % GetDocStrings(Exception))
+ fileh.write("%s\n" % GetDocStrings(ExceptionMissingFile))
+ fileh.write("%s\n" % GetDocStrings(OpenColorIO))
+ fileh.write("%s\n" % GetDocStrings(Constants))
+ fileh.write("%s\n" % GetDocStrings(Config))
+ #fileh.write("%s\n" % GetDocStrings(Baker))
+ fileh.write("%s\n" % GetDocStrings(ColorSpace))
+ fileh.write("%s\n" % GetDocStrings(Processor))
+ fileh.write("%s\n" % GetDocStrings(ProcessorMetadata))
+ fileh.write("%s\n" % GetDocStrings(Context))
+ fileh.write("%s\n" % GetDocStrings(Look))
+ fileh.write("%s\n" % GetDocStrings(Transform))
+ fileh.write("\n")
+ fileh.write("%s\n" % GetDocStrings(AllocationTransform))
+ fileh.write("%s\n" % GetDocStrings(CDLTransform))
+ fileh.write("%s\n" % GetDocStrings(ColorSpaceTransform))
+ fileh.write("%s\n" % GetDocStrings(DisplayTransform))
+ fileh.write("%s\n" % GetDocStrings(ExponentTransform))
+ fileh.write("%s\n" % GetDocStrings(FileTransform))
+ fileh.write("%s\n" % GetDocStrings(GroupTransform))
+ fileh.write("%s\n" % GetDocStrings(LogTransform))
+ fileh.write("%s\n" % GetDocStrings(LookTransform))
+ fileh.write("%s\n" % GetDocStrings(MatrixTransform))
+ fileh.write("\n")
+ fileh.write("}\n")
+ fileh.write("OCIO_NAMESPACE_EXIT\n")
+ fileh.write("\n")
+ fileh.flush()
+ fileh.close()
diff --git a/src/rv/Makefile b/src/rv/Makefile
new file mode 100644
index 0000000..ed68cd3
--- /dev/null
+++ b/src/rv/Makefile
@@ -0,0 +1,6 @@
+.phony:
+all: ociorv.zip
+
+ociorv.zip:
+ mkdir -p Packages
+ zip Packages/ociorv.zip Python/ociorv.py Python/PACKAGE
diff --git a/src/rv/Mu/rvload b/src/rv/Mu/rvload
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/rv/Mu/rvload
@@ -0,0 +1 @@
+1
diff --git a/src/rv/Mu/rvload2 b/src/rv/Mu/rvload2
new file mode 100644
index 0000000..01904d4
--- /dev/null
+++ b/src/rv/Mu/rvload2
@@ -0,0 +1,2 @@
+3
+ociorv,ociorv.zip,nil,nil,nil,true,true,3.12,false
diff --git a/src/rv/Packages/.gitignore b/src/rv/Packages/.gitignore
new file mode 100644
index 0000000..61bce34
--- /dev/null
+++ b/src/rv/Packages/.gitignore
@@ -0,0 +1 @@
+ociorv.zip
diff --git a/src/rv/Packages/rvinstall b/src/rv/Packages/rvinstall
new file mode 100644
index 0000000..501708e
--- /dev/null
+++ b/src/rv/Packages/rvinstall
@@ -0,0 +1 @@
+*ociorv.zip
diff --git a/src/rv/Python/PACKAGE b/src/rv/Python/PACKAGE
new file mode 100644
index 0000000..3a7889f
--- /dev/null
+++ b/src/rv/Python/PACKAGE
@@ -0,0 +1,12 @@
+package: OpenColorIO
+version: 1.0
+rv: 3.12
+requires: ''
+
+modes:
+ - file: ociorv.py
+ load: immediate
+
+description: |
+
+ Integrates OCIO, and that's about it
diff --git a/src/rv/Python/ociorv.py b/src/rv/Python/ociorv.py
new file mode 100644
index 0000000..77e10cf
--- /dev/null
+++ b/src/rv/Python/ociorv.py
@@ -0,0 +1,288 @@
+import time
+import itertools
+import contextlib
+
+import PyOpenColorIO as OCIO
+
+import rv
+from rv.commands import setStringProperty, setIntProperty, setFloatProperty
+
+
+@contextlib.contextmanager
+def timer(msg):
+ start = time.time()
+ yield
+ end = time.time()
+ print "%s: %.02fms" % (msg, (end-start)*1000)
+
+
+def set_lut(proc, nodename):
+ """Given an PyOpenColorIO.Processor instance, create a LUT and
+ sets it for the specified node
+ """
+
+ if proc.isNoOp():
+ return
+
+ if hasattr(proc, "hasChannelCrosstalk"):
+ # Determine if transform has crosstalk, and switch 1D/3D based on this
+ crosstalk = proc.hasChannelCrosstalk()
+ else:
+ # Assume crosstalk in lieu of latest OCIO Python bindings
+ crosstalk = True
+
+ # TODO: Maybe allow configuration of LUT sizes?
+ size_1d = 2048
+ size_3d = 32
+
+ if crosstalk:
+ _set_lut_3d(proc = proc, nodename = nodename, size = size_3d)
+ else:
+ _set_lut_1d(proc = proc, nodename = nodename, size = size_1d)
+
+ # TODO: Can also set nodename.lut.inMatrix - could maybe avoid creating a
+ # 3D LUT for linear transforms
+
+
+def _set_lut_3d(proc, nodename, size = 32):
+ # FIXME: This clips with >1 scene-linear values, use allocation
+ # vars
+
+ # Make noop cube
+ size_minus_one = float(size-1)
+ one_axis = (x/size_minus_one for x in range(size))
+ cube_raw = itertools.product(one_axis, repeat=3)
+
+ # Unpack and fix ordering, by turning [(0, 0, 0), (0, 0, 1), ...]
+ # into [0, 0, 0, 1, 0, 0] as generator
+ cube_raw = (item for sublist in cube_raw for item in sublist[::-1])
+
+ # Apply transform
+ cube_processed = proc.applyRGB(cube_raw)
+
+ # Set LUT type and size, then LUT values
+ setStringProperty("%s.lut.type" % nodename, ["RGB"], False)
+ setIntProperty("%s.lut.size" % nodename, [size, size, size], False)
+ setFloatProperty("%s.lut.lut" % nodename, cube_processed, True)
+
+ # Activate
+ setIntProperty("%s.lut.active" % nodename, [1], False)
+
+
+def _set_lut_1d(proc, nodename, size = 1024):
+ # TODO: Use allocation vars also
+
+ # Make noop ramp
+ def gen_noop_ramp(size):
+ size_minus_one = float(size-1)
+ for x in range(size):
+ val = x/size_minus_one
+ for i in range(3):
+ yield val
+
+ ramp_raw = gen_noop_ramp(size = size)
+
+ # Apply transform
+ # TODO: Make applyRGB accept an iterable, rather than requiring a
+ # list, to avoid making the intermediate list
+ ramp_transformed = proc.applyRGB(ramp_raw)
+
+ # Set LUT type and size, then LUT values
+ setStringProperty("%s.lut.type" % nodename, ["RGB"], False)
+ setIntProperty("%s.lut.size" % nodename, [size], False)
+ setFloatProperty("%s.lut.lut" % nodename, ramp_transformed, True)
+
+ # Activate
+ setIntProperty("%s.lut.active" % nodename, [1], False)
+
+
+def set_noop(nodename):
+ """Just ensure sure the LUT is deactivated, in case source changes
+ from switch from a non-noop to a noop processor
+ """
+
+ is_active = False
+ setIntProperty("%s.lut.active" % nodename, [is_active], False)
+
+
+def view_to_uistr(view):
+ # sRGB/Film
+ return "/".join(view)
+
+
+class PyMyStuffMode(rv.rvtypes.MinorMode):
+
+ def set_display(self, event):
+ avail = self.get_views()
+ cur = self.active_view
+ curindex = avail.index(cur)
+ newindex = (curindex + 1) % len(avail)
+ self.active_view = avail[newindex]
+ rv.extra_commands.displayFeedback(
+ "Changing display to %s" % view_to_uistr(self.active_view),
+ 2.0, # timeout
+ )
+ self.refresh()
+
+ def get_cfg(self):
+ return OCIO.GetCurrentConfig()
+
+ def refresh(self):
+ """Refresh LUT on all sources
+ """
+ for src in rv.commands.nodesOfType("RVSource"):
+ path = rv.commands.getStringProperty(
+ "%s.media.movie" % src,
+ 0, 99999999)[0] # defaultish arguments
+ self._config_source(src = src, srcpath = path)
+
+ def source_setup(self, event):
+ # Event content example:
+ # sourceGroup000001_source;;RVSource;;/path/to/myimg.exr
+ print event.contents()
+ args = event.contents().split(";;")
+ src = args[0]
+ srcpath = args[2]
+
+ self._config_source(src = src, srcpath = srcpath)
+
+ def _config_source(self, src, srcpath):
+ filelut_node = rv.extra_commands.associatedNode("RVColor", src)
+ looklut_node = rv.extra_commands.associatedNode("RVLookLUT", src)
+
+ # Set 3D LUT, and activate
+ cfg = self.get_cfg()
+
+ # FIXME: Need a way to customise this per-facility without
+ # modifying this file (try: import ociorv_custom_stuff ?)
+ inspace = cfg.parseColorSpaceFromString(srcpath)
+
+ test_transform = OCIO.DisplayTransform()
+ test_transform.setInputColorSpaceName(inspace)
+ display, view = self.active_view
+ test_transform.setDisplay(display)
+ test_transform.setView(view)
+
+ try:
+ test_proc = cfg.getProcessor(test_transform)
+ except OCIO.Exception, e:
+ print "INFO: Cannot create test OCIODisplay for %s - display LUT disabled. OCIO message was %s" % (
+ inspace,
+ e)
+ set_noop(nodename = filelut_node)
+ set_noop(nodename = looklut_node)
+ return
+
+ if test_proc.isNoOp():
+ print "Source is NoOp"
+ set_noop(nodename = filelut_node)
+ set_noop(nodename = looklut_node)
+ return
+
+ # Input -> scene-linear processor. Allow grading controls etc
+ # to work as expected
+ try:
+ input_proc = cfg.getProcessor(inspace, OCIO.Constants.ROLE_SCENE_LINEAR)
+ except OCIO.Exception, e:
+ # TODO: This mostly catches "3D Luts can only be applied
+ # in the forward direction.", could handle this better
+ print "INFO: Cannot linearise %s - display LUT disabled. OCIO message was %s" % (
+ inspace,
+ e)
+ set_noop(nodename = filelut_node)
+ set_noop(nodename = looklut_node)
+ return
+
+ # Scene-linear -> output display transform
+ transform = OCIO.DisplayTransform()
+ transform.setDisplay(self.active_view[0])
+ transform.setView(self.active_view[1])
+
+ transform.setInputColorSpaceName(OCIO.Constants.ROLE_SCENE_LINEAR)
+
+ try:
+ output_proc = cfg.getProcessor(transform)
+ except OCIO.Exception, e:
+ print "INFO: Cannot apply scene-linear to %s - OCIO error was %s" % (
+ srcpath,
+ e)
+ set_noop(nodename = filelut_node)
+ set_noop(nodename = looklut_node)
+ return
+
+ # LUT to be applied to input file, before any grading etc
+ set_lut(proc = input_proc, nodename = filelut_node)
+
+ # LUT after grading etc performed
+ set_lut(proc = output_proc, nodename = looklut_node)
+
+ # Update LUT
+ rv.commands.updateLUT()
+
+ def set_view(self, display, view):
+ """Set view, and update all sources
+ """
+ print "display: %s, view: %s" % (display, view)
+ self.active_view = (display, view)
+ self.refresh()
+
+ def get_views(self):
+ """Return [("sRGB", "Film"), ("sRGB", "Log"), ...]
+ """
+ available_views = []
+
+ cfg = self.get_cfg()
+ for a_display in cfg.getDisplays():
+ if a_display not in cfg.getActiveDisplays().split(", "):
+ continue
+
+ for a_view in cfg.getViews(a_display):
+ if a_view not in cfg.getActiveViews():
+ continue
+
+ available_views.append(
+ (a_display, a_view))
+ return available_views
+
+ def __init__(self):
+ rv.rvtypes.MinorMode.__init__(self)
+
+ mode_name = "ociorv-mode"
+
+ global_bindings = [
+ ("key-down--d", self.set_display, "set display"),
+ ("new-source", self.source_setup, "OCIO source setup"),
+ ]
+
+ local_bindings = []
+
+ # Create [("sRGB/Film", self.set_menu(...)), ("sRGB/Log", ...)]
+ views_menu = []
+ for cur_view in self.get_views():
+ def set_view(event, cur_view = cur_view):
+ display, view = cur_view
+ self.set_view(display = display, view = view)
+ mi = (
+ "/".join(cur_view), # label
+ set_view, # actionHook
+ )
+ views_menu.append(mi)
+
+ # Set default view
+ cfg = self.get_cfg()
+ self.active_view = (
+ cfg.getDefaultDisplay(),
+ cfg.getDefaultView(cfg.getDefaultDisplay()))
+
+ # Construct top-level menu
+ menu = [("OCIO", [
+ ("Display/Views", views_menu)])]
+
+ self.init(mode_name,
+ global_bindings,
+ local_bindings,
+ menu)
+
+
+def createMode():
+ return PyMyStuffMode()