/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2012 Blender Foundation. * All rights reserved. */ #include #include #include #include "BLI_math_color.h" #include "BLI_math_vector.h" #include "MEM_guardedalloc.h" #include "ocio_impl.h" using std::max; #define CONFIG_DEFAULT ((OCIO_ConstConfigRcPtr *)1) enum TransformType { TRANSFORM_LINEAR_TO_SRGB, TRANSFORM_SRGB_TO_LINEAR, TRANSFORM_MATRIX, TRANSFORM_EXPONENT, TRANSFORM_UNKNOWN, }; #define COLORSPACE_LINEAR ((OCIO_ConstColorSpaceRcPtr *)1) #define COLORSPACE_SRGB ((OCIO_ConstColorSpaceRcPtr *)2) typedef struct OCIO_PackedImageDescription { float *data; long width; long height; long numChannels; long chanStrideBytes; long xStrideBytes; long yStrideBytes; } OCIO_PackedImageDescription; struct FallbackTransform { FallbackTransform() : type(TRANSFORM_UNKNOWN), linear_transform(NULL), display_transform(NULL) { } virtual ~FallbackTransform() { delete linear_transform; delete display_transform; } void applyRGB(float *pixel) { if (type == TRANSFORM_LINEAR_TO_SRGB) { applyLinearRGB(pixel); linearrgb_to_srgb_v3_v3(pixel, pixel); applyDisplayRGB(pixel); } else if (type == TRANSFORM_SRGB_TO_LINEAR) { srgb_to_linearrgb_v3_v3(pixel, pixel); } else if (type == TRANSFORM_EXPONENT) { pixel[0] = powf(max(0.0f, pixel[0]), exponent[0]); pixel[1] = powf(max(0.0f, pixel[1]), exponent[1]); pixel[2] = powf(max(0.0f, pixel[2]), exponent[2]); } else if (type == TRANSFORM_MATRIX) { float r = pixel[0]; float g = pixel[1]; float b = pixel[2]; pixel[0] = r * matrix[0] + g * matrix[1] + b * matrix[2]; pixel[1] = r * matrix[4] + g * matrix[5] + b * matrix[6]; pixel[2] = r * matrix[8] + g * matrix[9] + b * matrix[10]; pixel[0] += offset[0]; pixel[1] += offset[1]; pixel[2] += offset[2]; } } void applyRGBA(float *pixel) { if (type == TRANSFORM_LINEAR_TO_SRGB) { applyLinearRGBA(pixel); linearrgb_to_srgb_v4(pixel, pixel); applyDisplayRGBA(pixel); } else if (type == TRANSFORM_SRGB_TO_LINEAR) { srgb_to_linearrgb_v4(pixel, pixel); } else if (type == TRANSFORM_EXPONENT) { pixel[0] = powf(max(0.0f, pixel[0]), exponent[0]); pixel[1] = powf(max(0.0f, pixel[1]), exponent[1]); pixel[2] = powf(max(0.0f, pixel[2]), exponent[2]); pixel[3] = powf(max(0.0f, pixel[3]), exponent[3]); } else if (type == TRANSFORM_MATRIX) { float r = pixel[0]; float g = pixel[1]; float b = pixel[2]; float a = pixel[3]; pixel[0] = r * matrix[0] + g * matrix[1] + b * matrix[2] + a * matrix[3]; pixel[1] = r * matrix[4] + g * matrix[5] + b * matrix[6] + a * matrix[7]; pixel[2] = r * matrix[8] + g * matrix[9] + b * matrix[10] + a * matrix[11]; pixel[3] = r * matrix[12] + g * matrix[13] + b * matrix[14] + a * matrix[15]; pixel[0] += offset[0]; pixel[1] += offset[1]; pixel[2] += offset[2]; pixel[3] += offset[3]; } } void applyLinearRGB(float *pixel) { if (linear_transform != NULL) { linear_transform->applyRGB(pixel); } } void applyLinearRGBA(float *pixel) { if (linear_transform != NULL) { linear_transform->applyRGBA(pixel); } } void applyDisplayRGB(float *pixel) { if (display_transform != NULL) { display_transform->applyRGB(pixel); } } void applyDisplayRGBA(float *pixel) { if (display_transform != NULL) { display_transform->applyRGBA(pixel); } } TransformType type; FallbackTransform *linear_transform; FallbackTransform *display_transform; /* Exponent transform. */ float exponent[4]; /* Matrix transform. */ float matrix[16]; float offset[4]; MEM_CXX_CLASS_ALLOC_FUNCS("FallbackTransform"); }; struct FallbackGroupTransform : FallbackTransform { ~FallbackGroupTransform() { for (auto transform : list) { delete transform; } } std::vector list; }; struct FallbackProcessor { FallbackProcessor() : transform(NULL) { } ~FallbackProcessor() { delete transform; } void applyRGB(float *pixel) { transform->applyRGB(pixel); } void applyRGBA(float *pixel) { transform->applyRGBA(pixel); } FallbackTransform *transform; MEM_CXX_CLASS_ALLOC_FUNCS("FallbackProcessor"); }; OCIO_ConstConfigRcPtr *FallbackImpl::getCurrentConfig(void) { return CONFIG_DEFAULT; } void FallbackImpl::setCurrentConfig(const OCIO_ConstConfigRcPtr * /*config*/) { } OCIO_ConstConfigRcPtr *FallbackImpl::configCreateFromEnv(void) { return NULL; } OCIO_ConstConfigRcPtr *FallbackImpl::configCreateFromFile(const char * /*filename*/) { return CONFIG_DEFAULT; } void FallbackImpl::configRelease(OCIO_ConstConfigRcPtr * /*config*/) { } int FallbackImpl::configGetNumColorSpaces(OCIO_ConstConfigRcPtr * /*config*/) { return 2; } const char *FallbackImpl::configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr * /*config*/, int index) { if (index == 0) return "Linear"; else if (index == 1) return "sRGB"; return NULL; } OCIO_ConstColorSpaceRcPtr *FallbackImpl::configGetColorSpace(OCIO_ConstConfigRcPtr * /*config*/, const char *name) { if (strcmp(name, "scene_linear") == 0) return COLORSPACE_LINEAR; else if (strcmp(name, "color_picking") == 0) return COLORSPACE_SRGB; else if (strcmp(name, "texture_paint") == 0) return COLORSPACE_LINEAR; else if (strcmp(name, "default_byte") == 0) return COLORSPACE_SRGB; else if (strcmp(name, "default_float") == 0) return COLORSPACE_LINEAR; else if (strcmp(name, "default_sequencer") == 0) return COLORSPACE_SRGB; else if (strcmp(name, "Linear") == 0) return COLORSPACE_LINEAR; else if (strcmp(name, "sRGB") == 0) return COLORSPACE_SRGB; return NULL; } int FallbackImpl::configGetIndexForColorSpace(OCIO_ConstConfigRcPtr *config, const char *name) { OCIO_ConstColorSpaceRcPtr *cs = configGetColorSpace(config, name); if (cs == COLORSPACE_LINEAR) { return 0; } else if (cs == COLORSPACE_SRGB) { return 1; } return -1; } const char *FallbackImpl::configGetDefaultDisplay(OCIO_ConstConfigRcPtr * /*config*/) { return "sRGB"; } int FallbackImpl::configGetNumDisplays(OCIO_ConstConfigRcPtr * /*config*/) { return 1; } const char *FallbackImpl::configGetDisplay(OCIO_ConstConfigRcPtr * /*config*/, int index) { if (index == 0) { return "sRGB"; } return NULL; } const char *FallbackImpl::configGetDefaultView(OCIO_ConstConfigRcPtr * /*config*/, const char * /*display*/) { return "Standard"; } int FallbackImpl::configGetNumViews(OCIO_ConstConfigRcPtr * /*config*/, const char * /*display*/) { return 1; } const char *FallbackImpl::configGetView(OCIO_ConstConfigRcPtr * /*config*/, const char * /*display*/, int index) { if (index == 0) { return "Standard"; } return NULL; } const char *FallbackImpl::configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr * /*config*/, const char * /*display*/, const char * /*view*/) { return "sRGB"; } void FallbackImpl::configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr * /*config*/, float *rgb) { /* Here we simply use the older Blender assumed primaries of * ITU-BT.709 / sRGB, or 0.2126729 0.7151522 0.0721750. Brute * force stupid, but only plausible option given no color management * system in place. */ rgb[0] = 0.2126f; rgb[1] = 0.7152f; rgb[2] = 0.0722f; } void FallbackImpl::configGetXYZtoRGB(OCIO_ConstConfigRcPtr * /*config*/, float xyz_to_rgb[3][3]) { /* Default to ITU-BT.709. */ memcpy(xyz_to_rgb, OCIO_XYZ_TO_LINEAR_SRGB, sizeof(OCIO_XYZ_TO_LINEAR_SRGB)); } int FallbackImpl::configGetNumLooks(OCIO_ConstConfigRcPtr * /*config*/) { return 0; } const char *FallbackImpl::configGetLookNameByIndex(OCIO_ConstConfigRcPtr * /*config*/, int /*index*/) { return ""; } OCIO_ConstLookRcPtr *FallbackImpl::configGetLook(OCIO_ConstConfigRcPtr * /*config*/, const char * /*name*/) { return NULL; } const char *FallbackImpl::lookGetProcessSpace(OCIO_ConstLookRcPtr * /*look*/) { return NULL; } void FallbackImpl::lookRelease(OCIO_ConstLookRcPtr * /*look*/) { } int FallbackImpl::colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr * /*cs*/) { return 1; } int FallbackImpl::colorSpaceIsData(OCIO_ConstColorSpaceRcPtr * /*cs*/) { return 0; } void FallbackImpl::colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr * /*config*/, OCIO_ConstColorSpaceRcPtr *cs, bool &is_scene_linear, bool &is_srgb) { if (cs == COLORSPACE_LINEAR) { is_scene_linear = true; is_srgb = false; } else if (cs == COLORSPACE_SRGB) { is_scene_linear = false; is_srgb = true; } else { is_scene_linear = false; is_srgb = false; } } void FallbackImpl::colorSpaceRelease(OCIO_ConstColorSpaceRcPtr * /*cs*/) { } OCIO_ConstProcessorRcPtr *FallbackImpl::configGetProcessorWithNames(OCIO_ConstConfigRcPtr *config, const char *srcName, const char *dstName) { OCIO_ConstColorSpaceRcPtr *cs_src = configGetColorSpace(config, srcName); OCIO_ConstColorSpaceRcPtr *cs_dst = configGetColorSpace(config, dstName); FallbackTransform *transform = new FallbackTransform(); if (cs_src == COLORSPACE_LINEAR && cs_dst == COLORSPACE_SRGB) { transform->type = TRANSFORM_LINEAR_TO_SRGB; } else if (cs_src == COLORSPACE_SRGB && cs_dst == COLORSPACE_LINEAR) { transform->type = TRANSFORM_SRGB_TO_LINEAR; } else { transform->type = TRANSFORM_UNKNOWN; } FallbackProcessor *processor = new FallbackProcessor(); processor->transform = transform; return (OCIO_ConstProcessorRcPtr *)processor; } OCIO_ConstProcessorRcPtr *FallbackImpl::configGetProcessor(OCIO_ConstConfigRcPtr * /*config*/, OCIO_ConstTransformRcPtr *transform) { FallbackProcessor *processor = new FallbackProcessor(); processor->transform = (FallbackTransform *)transform; return (OCIO_ConstProcessorRcPtr *)processor; } void FallbackImpl::processorApply(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img) { /* OCIO_TODO stride not respected, channels must be 3 or 4 */ OCIO_PackedImageDescription *desc = (OCIO_PackedImageDescription *)img; int channels = desc->numChannels; float *pixels = desc->data; int width = desc->width; int height = desc->height; int x, y; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { float *pixel = pixels + channels * (y * width + x); if (channels == 4) processorApplyRGBA(processor, pixel); else if (channels == 3) processorApplyRGB(processor, pixel); } } } void FallbackImpl::processorApply_predivide(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img) { /* OCIO_TODO stride not respected, channels must be 3 or 4 */ OCIO_PackedImageDescription *desc = (OCIO_PackedImageDescription *)img; int channels = desc->numChannels; float *pixels = desc->data; int width = desc->width; int height = desc->height; int x, y; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { float *pixel = pixels + channels * (y * width + x); if (channels == 4) processorApplyRGBA_predivide(processor, pixel); else if (channels == 3) processorApplyRGB(processor, pixel); } } } void FallbackImpl::processorApplyRGB(OCIO_ConstProcessorRcPtr *processor, float *pixel) { ((FallbackProcessor *)processor)->applyRGB(pixel); } void FallbackImpl::processorApplyRGBA(OCIO_ConstProcessorRcPtr *processor, float *pixel) { ((FallbackProcessor *)processor)->applyRGBA(pixel); } void FallbackImpl::processorApplyRGBA_predivide(OCIO_ConstProcessorRcPtr *processor, float *pixel) { if (pixel[3] == 1.0f || pixel[3] == 0.0f) { processorApplyRGBA(processor, pixel); } else { float alpha, inv_alpha; alpha = pixel[3]; inv_alpha = 1.0f / alpha; pixel[0] *= inv_alpha; pixel[1] *= inv_alpha; pixel[2] *= inv_alpha; processorApplyRGBA(processor, pixel); pixel[0] *= alpha; pixel[1] *= alpha; pixel[2] *= alpha; } } void FallbackImpl::processorRelease(OCIO_ConstProcessorRcPtr *processor) { delete (FallbackProcessor *)(processor); } const char *FallbackImpl::colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs) { if (cs == COLORSPACE_LINEAR) { return "Linear"; } else if (cs == COLORSPACE_SRGB) { return "sRGB"; } return NULL; } const char *FallbackImpl::colorSpaceGetDescription(OCIO_ConstColorSpaceRcPtr * /*cs*/) { return ""; } const char *FallbackImpl::colorSpaceGetFamily(OCIO_ConstColorSpaceRcPtr * /*cs*/) { return ""; } OCIO_DisplayTransformRcPtr *FallbackImpl::createDisplayTransform(void) { FallbackTransform *transform = new FallbackTransform(); transform->type = TRANSFORM_LINEAR_TO_SRGB; return (OCIO_DisplayTransformRcPtr *)transform; } void FallbackImpl::displayTransformSetInputColorSpaceName(OCIO_DisplayTransformRcPtr * /*dt*/, const char * /*name*/) { } void FallbackImpl::displayTransformSetDisplay(OCIO_DisplayTransformRcPtr * /*dt*/, const char * /*name*/) { } void FallbackImpl::displayTransformSetView(OCIO_DisplayTransformRcPtr * /*dt*/, const char * /*name*/) { } void FallbackImpl::displayTransformSetDisplayCC(OCIO_DisplayTransformRcPtr *dt, OCIO_ConstTransformRcPtr *et) { FallbackTransform *transform = (FallbackTransform *)dt; transform->display_transform = (FallbackTransform *)et; } void FallbackImpl::displayTransformSetLinearCC(OCIO_DisplayTransformRcPtr *dt, OCIO_ConstTransformRcPtr *et) { FallbackTransform *transform = (FallbackTransform *)dt; transform->linear_transform = (FallbackTransform *)et; } void FallbackImpl::displayTransformSetLooksOverride(OCIO_DisplayTransformRcPtr * /*dt*/, const char * /*looks*/) { } void FallbackImpl::displayTransformSetLooksOverrideEnabled(OCIO_DisplayTransformRcPtr * /*dt*/, bool /*enabled*/) { } void FallbackImpl::displayTransformRelease(OCIO_DisplayTransformRcPtr * /*dt*/) { } OCIO_PackedImageDesc *FallbackImpl::createOCIO_PackedImageDesc(float *data, long width, long height, long numChannels, long chanStrideBytes, long xStrideBytes, long yStrideBytes) { OCIO_PackedImageDescription *desc = (OCIO_PackedImageDescription *)MEM_callocN( sizeof(OCIO_PackedImageDescription), "OCIO_PackedImageDescription"); desc->data = data; desc->width = width; desc->height = height; desc->numChannels = numChannels; desc->chanStrideBytes = chanStrideBytes; desc->xStrideBytes = xStrideBytes; desc->yStrideBytes = yStrideBytes; return (OCIO_PackedImageDesc *)desc; } void FallbackImpl::OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *id) { MEM_freeN(id); } OCIO_GroupTransformRcPtr *FallbackImpl::createGroupTransform(void) { FallbackTransform *transform = new FallbackGroupTransform(); transform->type = TRANSFORM_UNKNOWN; return (OCIO_GroupTransformRcPtr *)transform; } void FallbackImpl::groupTransformSetDirection(OCIO_GroupTransformRcPtr * /*gt*/, const bool /*forward */) { } void FallbackImpl::groupTransformPushBack(OCIO_GroupTransformRcPtr *gt, OCIO_ConstTransformRcPtr *transform) { FallbackGroupTransform *group = (FallbackGroupTransform *)gt; group->list.push_back((FallbackTransform *)transform); } void FallbackImpl::groupTransformRelease(OCIO_GroupTransformRcPtr * /*gt*/) { } OCIO_ColorSpaceTransformRcPtr *FallbackImpl::createColorSpaceTransform(void) { FallbackTransform *transform = new FallbackTransform(); transform->type = TRANSFORM_UNKNOWN; return (OCIO_ColorSpaceTransformRcPtr *)transform; } void FallbackImpl::colorSpaceTransformSetSrc(OCIO_ColorSpaceTransformRcPtr * /*ct*/, const char * /*name*/) { } void FallbackImpl::colorSpaceTransformRelease(OCIO_ColorSpaceTransformRcPtr * /*ct*/) { } OCIO_ExponentTransformRcPtr *FallbackImpl::createExponentTransform(void) { FallbackTransform *transform = new FallbackTransform(); transform->type = TRANSFORM_EXPONENT; return (OCIO_ExponentTransformRcPtr *)transform; } void FallbackImpl::exponentTransformSetValue(OCIO_ExponentTransformRcPtr *et, const float *exponent) { FallbackTransform *transform = (FallbackTransform *)et; copy_v4_v4(transform->exponent, exponent); } void FallbackImpl::exponentTransformRelease(OCIO_ExponentTransformRcPtr * /*et*/) { } OCIO_MatrixTransformRcPtr *FallbackImpl::createMatrixTransform(void) { FallbackTransform *transform = new FallbackTransform(); transform->type = TRANSFORM_MATRIX; return (OCIO_MatrixTransformRcPtr *)transform; } void FallbackImpl::matrixTransformSetValue(OCIO_MatrixTransformRcPtr *mt, const float *m44, const float *offset4) { FallbackTransform *transform = (FallbackTransform *)mt; copy_m4_m4((float(*)[4])transform->matrix, (float(*)[4])m44); copy_v4_v4(transform->offset, offset4); } void FallbackImpl::matrixTransformRelease(OCIO_MatrixTransformRcPtr * /*mt*/) { } void FallbackImpl::matrixTransformScale(float *m44, float *offset4, const float *scale4) { if (scale4 == NULL) { return; } if (m44 != NULL) { memset(m44, 0, 16 * sizeof(float)); m44[0] = scale4[0]; m44[5] = scale4[1]; m44[10] = scale4[2]; m44[15] = scale4[3]; } if (offset4 != NULL) { offset4[0] = 0.0f; offset4[1] = 0.0f; offset4[2] = 0.0f; offset4[3] = 0.0f; } } bool FallbackImpl::supportGLSLDraw(void) { return false; } bool FallbackImpl::setupGLSLDraw(struct OCIO_GLSLDrawState ** /*state_r*/, OCIO_ConstProcessorRcPtr * /*ocio_processor_scene_to_ui*/, OCIO_ConstProcessorRcPtr * /*ocio_processor_ui_to_display*/, OCIO_CurveMappingSettings * /*curve_mapping_settings*/, float /*dither*/, bool /*predivide*/, bool /*overlay*/) { return false; } void FallbackImpl::finishGLSLDraw(OCIO_GLSLDrawState * /*state*/) { } void FallbackImpl::freeGLState(struct OCIO_GLSLDrawState * /*state_r*/) { } const char *FallbackImpl::getVersionString(void) { return "fallback"; } int FallbackImpl::getVersionHex(void) { return 0; }