// 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());
        }
    }
}
// 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 (!(layersToProcess & requestedChannel) || 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
        memcpy(rOut, rIn, sizeof(float)*rowWidth);
        memcpy(gOut, gIn, sizeof(float)*rowWidth);
        memcpy(bOut, bIn, sizeof(float)*rowWidth);

        try
        {
            OCIO::PlanarImageDesc img(rOut, gOut, bOut, rowWidth, /*height*/ 1);
            processor->apply(img);
        }
        catch(OCIO::Exception &e)
        {
            error(e.what());
        }
    }
}
Exemple #3
0
void DisplayIop::engine( int y, int x, int r, const DD::Image::ChannelSet &channels, DD::Image::Row &row )
{
	Channel outputChannels[4] = { Chan_Red, Chan_Green, Chan_Blue, Chan_Alpha };
	const char *inputChannels[] = { "R", "G", "B", "A", nullptr };

	const ImagePrimitive *image = nullptr;
	Box2i inputDataWindow;
	Box2i inputDisplayWindow;
	if( firstDisplayIop()->m_driver )
	{
		image = firstDisplayIop()->m_driver->image().get();
		inputDataWindow = image->getDataWindow();
		inputDisplayWindow = image->getDisplayWindow();
	}

	int i = 0;
	while( inputChannels[i] )
	{
		const FloatVectorData *inputData = image ? image->getChannel<float>( inputChannels[i] ) : nullptr;
		if( inputData )
		{
			float *output = row.writable( outputChannels[i] ) + x;
			// remap coordinate relative to our data window. nuke images have pixel origin at bottom,
			// cortex images have pixel origin at top.
			V2i pDataWindow = V2i( x, inputDisplayWindow.max.y - y ) - inputDataWindow.min;
			const float *input = &((inputData->readable())[pDataWindow.y*(inputDataWindow.size().x+1) + pDataWindow.x]);
			memcpy( output, input, (r-x) * sizeof( float ) );
		}
		else
		{
			row.erase( outputChannels[i] );
		}
		i++;
	}
}
Exemple #4
0
void nuke_ld_3de4_base::engine(int y,int x,int r,DD::Image::ChannelMask channels,DD::Image::Row& outrow)
	{
	if(!input(0))
		{ return; }
	int w = format().w();
	int h = format().h();
	if((w <= 0) | (h <= 0))
		{ return; }
	double inv_w = 1.0 / w;
	double inv_h = 1.0 / h;
// We construct (x_s,y_s) in a way, so that the image area is mapped to the unit interval [0,1]^2,
// which is required by our 3DE4 lens distortion plugin class. Nuke's coordinates are pixel based,
// (0,0) is the left lower corner of the left lower pixel, while (1,1) is the right upper corner
// of that pixel. The center of any pixel (ix,iy) is (ix+0.5,iy+0.5), so we add 0.5 here.
	double y_s = (0.5 + y) * inv_h;
// Determine bounding box and write down results.
	vector<ldpk::vec2d> pos;
// Reserve, so that push_back is performant.
	pos.reserve(r - x);
// Box for "lock the tile".
	DD::Image::Box box;
	for(int i = x;i < r;++i)
		{
// We don't forget shifting by (half,half)!
		double x_s = (0.5 + i) * inv_w;
		double x_d,y_d;
// Image processing, reversed mapping. Weave in 3DE4's field of view.
		if(_knob_direction == undistort)
			{ _ldm->distort(map_in_fov_x(x_s),map_in_fov_y(y_s),x_d,y_d); }
		else
			{ _ldm->undistort(map_in_fov_x(x_s),map_in_fov_y(y_s),x_d,y_d); }
// The result already contains the (half,half) shift. Reformulate in Nuke's coordinates. Weave "out" 3DE4's field of view.
		double px = map_out_fov_x(x_d) * w;
		double py = map_out_fov_y(y_d) * h;
// Build the box for "lock the tile..."
		if(i == x)
			{ box = DD::Image::Box(int(floor(px)),int(floor(py)),int(ceil(px)),int(ceil(py))); }
		else
			{ box.merge(int(floor(px)),int(floor(py)),int(ceil(px)),int(ceil(py))); }
// We store the results.
		pos.push_back(ldpk::vec2d(px,py));
		}
// Add margin for reconstruction filter. Cubic will need two pixels more, others maybe three.
	box.pad(3);

// Transfer the stored result. We set pixels x to r in outrow.
// Begin extension by David Cattermole and Ben Dickson, RSP. Thank you!
// Minor changes added by SDV for version 1.9.1.
	if(_knob_output_mode == OUTPUT_STMAP)
		{
// Output source pixel coordinates in format compatible with STMap
		double inv_w0 = 1.0 / input0().format().width();
		double inv_h0 = 1.0 / input0().format().height();
		for(int i = 0;i < pos.size();++i)
			{
			foreach(z,channels)
				{
				if(z == DD::Image::Chan_Red)
					{ outrow.writable(z)[i + x] = float(pos[i][0] * inv_w0); }
				else if(z == DD::Image::Chan_Green)
					{ outrow.writable(z)[i + x] = float(pos[i][1] * inv_h0); }
				else
					{ outrow.writable(z)[i + x] = 0.0; }
				}
			}
		}