PageRenderTime 37ms CodeModel.GetById 15ms app.highlight 17ms RepoModel.GetById 2ms app.codeStats 0ms

/src/nuke/OCIOLogConvert/OCIOLogConvert.cpp

http://github.com/imageworks/OpenColorIO
C++ | 179 lines | 133 code | 32 blank | 14 comment | 14 complexity | a469d4327bf9d02d5d4d69ccd3789e77 MD5 | raw file
  1/**
  2 * OpenColorIO LogConvert Iop.
  3 */
  4
  5#include "OCIOLogConvert.h"
  6
  7namespace OCIO = OCIO_NAMESPACE;
  8
  9#include <string>
 10#include <sstream>
 11#include <stdexcept>
 12
 13#include <DDImage/Channel.h>
 14#include <DDImage/PixelIop.h>
 15#include <DDImage/NukeWrapper.h>
 16#include <DDImage/Row.h>
 17#include <DDImage/Knobs.h>
 18
 19const char* OCIOLogConvert::modes[] = {
 20    "log to lin", "lin to log", 0
 21};
 22
 23OCIOLogConvert::OCIOLogConvert(Node *n) : DD::Image::PixelIop(n)
 24{
 25    modeindex = 0;
 26}
 27
 28OCIOLogConvert::~OCIOLogConvert()
 29{
 30
 31}
 32
 33void OCIOLogConvert::knobs(DD::Image::Knob_Callback f)
 34{
 35
 36    Enumeration_knob(f, &modeindex, modes, "operation", "operation");
 37    DD::Image::SetFlags(f, DD::Image::Knob::ALWAYS_SAVE);
 38}
 39
 40void OCIOLogConvert::_validate(bool for_real)
 41{
 42    try
 43    {
 44        OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
 45        
 46        const char * src = 0;
 47        const char * dst = 0;
 48        
 49        if(modeindex == 0)
 50        {
 51            src = OCIO::ROLE_COMPOSITING_LOG;
 52            dst = OCIO::ROLE_SCENE_LINEAR;
 53        }
 54        else
 55        {
 56            src = OCIO::ROLE_SCENE_LINEAR;
 57            dst = OCIO::ROLE_COMPOSITING_LOG;
 58        }
 59        
 60        processor = config->getProcessor(src, dst);
 61    }
 62    catch(OCIO::Exception &e)
 63    {
 64        error(e.what());
 65        return;
 66    }
 67    
 68    if(processor->isNoOp())
 69    {
 70        set_out_channels(DD::Image::Mask_None); // prevents engine() from being called
 71    } else {    
 72        set_out_channels(DD::Image::Mask_All);
 73    }
 74
 75    DD::Image::PixelIop::_validate(for_real);
 76}
 77
 78// Note that this is copied by others (OCIODisplay)
 79void OCIOLogConvert::in_channels(int /* n unused */, DD::Image::ChannelSet& mask) const
 80{
 81    DD::Image::ChannelSet done;
 82    foreach(c, mask)
 83    {
 84        if (DD::Image::colourIndex(c) < 3 && !(done & c))
 85        {
 86            done.addBrothers(c, 3);
 87        }
 88    }
 89    mask += done;
 90}
 91
 92// See Saturation::pixel_engine for a well-commented example.
 93// Note that this is copied by others (OCIODisplay)
 94void OCIOLogConvert::pixel_engine(
 95    const DD::Image::Row& in,
 96    int /* rowY unused */, int rowX, int rowXBound,
 97    DD::Image::ChannelMask outputChannels,
 98    DD::Image::Row& out)
 99{
100    int rowWidth = rowXBound - rowX;
101
102    DD::Image::ChannelSet done;
103    foreach (requestedChannel, outputChannels)
104    {
105        // Skip channels which had their trios processed already,
106        if (done & requestedChannel)
107        {
108            continue;
109        }
110
111        // Pass through channels which are not selected for processing
112        // and non-rgb channels.
113        if (colourIndex(requestedChannel) >= 3)
114        {
115            out.copy(in, requestedChannel, rowX, rowXBound);
116            continue;
117        }
118
119        DD::Image::Channel rChannel = DD::Image::brother(requestedChannel, 0);
120        DD::Image::Channel gChannel = DD::Image::brother(requestedChannel, 1);
121        DD::Image::Channel bChannel = DD::Image::brother(requestedChannel, 2);
122
123        done += rChannel;
124        done += gChannel;
125        done += bChannel;
126
127        const float *rIn = in[rChannel] + rowX;
128        const float *gIn = in[gChannel] + rowX;
129        const float *bIn = in[bChannel] + rowX;
130
131        float *rOut = out.writable(rChannel) + rowX;
132        float *gOut = out.writable(gChannel) + rowX;
133        float *bOut = out.writable(bChannel) + rowX;
134
135        // OCIO modifies in-place
136        // Note: xOut can equal xIn in some circumstances, such as when the
137        // 'Black' (throwaway) scanline is uses. We thus must guard memcpy,
138        // which does not allow for overlapping regions.
139        if (rOut != rIn) memcpy(rOut, rIn, sizeof(float)*rowWidth);
140        if (gOut != gIn) memcpy(gOut, gIn, sizeof(float)*rowWidth);
141        if (bOut != bIn) memcpy(bOut, bIn, sizeof(float)*rowWidth);
142
143        try
144        {
145            OCIO::PlanarImageDesc img(rOut, gOut, bOut, NULL, rowWidth, /*height*/ 1);
146            processor->apply(img);
147        }
148        catch(OCIO::Exception &e)
149        {
150            error(e.what());
151        }
152    }
153}
154
155const DD::Image::Op::Description OCIOLogConvert::description("OCIOLogConvert", build);
156
157const char* OCIOLogConvert::Class() const
158{
159    return description.name;
160}
161
162const char* OCIOLogConvert::displayName() const
163{
164    return description.name;
165}
166
167const char* OCIOLogConvert::node_help() const
168{
169    // TODO more detailed help text
170    return "Use OpenColorIO to convert from SCENE_LINEAR to COMPOSITING_LOG (or back).";
171}
172
173
174DD::Image::Op* build(Node *node)
175{
176    DD::Image::NukeWrapper *op = new DD::Image::NukeWrapper(new OCIOLogConvert(node));
177    op->channels(DD::Image::Mask_RGB);
178    return op;
179}