diff options
Diffstat (limited to 'src')
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, + ¶ms[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;"..\..\..\..\ext\yaml-cpp\include";.\"
+ 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;"..\..\..\..\ext\yaml-cpp\include";.\"
+ 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;"..\..\..\..\ext\yaml-cpp\include";.\"
+ 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;"..\..\..\..\ext\yaml-cpp\include";.\"
+ 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;"..\..\..\..\..\ext\lcms2-2.1\include";"..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Headers";"..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Headers\SP";"..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Headers\Win";"..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Resources";"..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Util";"..\..\..\..\..\ext\glew-1.7.0\include""
+ 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;"..\..\..\..\..\ext\lcms2-2.1\include";"..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Headers";"..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Headers\SP";"..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Headers\Win";"..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Resources";"..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Util";"..\..\..\..\..\ext\glew-1.7.0\include""
+ 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 "$(ProjectDir)..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Headers" /D USE_AE_EFFECT_VERS /EP "..\..\..\$(InputName).r" > "$(IntDir)"\\"$(InputName).rr"
"$(ProjectDir)..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Resources\PiPLTool" "$(IntDir)\$(InputName).rr" "$(IntDir)\$(InputName).rrc"
cl /D "MSWindows" /EP $(IntDir)\$(InputName).rrc > "$(ProjectDir)"\\"$(InputName)".rc
"
+ Outputs="$(ProjectDir)\$(InputName).rc"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Compiling the PiPL"
+ CommandLine="cl /I "$(ProjectDir)..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Headers" /D USE_AE_EFFECT_VERS /EP "..\..\..\$(InputName).r" > "$(IntDir)"\\"$(InputName).rr"
"$(ProjectDir)..\..\..\..\..\ext\Adobe After Effects CS5 SDK\Examples\Resources\PiPLTool" "$(IntDir)\$(InputName).rr" "$(IntDir)\$(InputName).rrc"
cl /D "MSWindows" /EP $(IntDir)\$(InputName).rrc > "$(ProjectDir)"\\"$(InputName)".rc
"
+ 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=""..\..\..\..\..\ext\lcms2-2.1\include""
+ 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=""..\..\..\..\..\ext\lcms2-2.1\include""
+ 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=""..\..\..\..\..\ext\lcms2-2.1\include""
+ 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=""..\..\..\..\..\ext\lcms2-2.1\include""
+ 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=""..\..\..\..\..\ext\yaml-cpp\include""
+ 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=""..\..\..\..\..\ext\yaml-cpp\include""
+ 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=""..\..\..\..\..\ext\yaml-cpp\include""
+ 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=""..\..\..\..\..\ext\yaml-cpp\include""
+ 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", ©right , "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() |