Hey all,

So I’m apparently still confused about what (not) to call in Iop::_validate, 
Iop::_request, and Iop::engine when I only need to do things to certain 
channels.

I’ve written a (theoretically) dead-simple Iop that averages the incoming RGB 
channels in place, and passes any other channels through. However, there’s 
either something wrong with my code, or I’m running into a Nuke bug I 
encountered a couple weeks ago with channel requests, because I keep getting 
viewer lock-ups and messages like 'Warning: [node name]: get(channels=0x7), but 
request(channels=0x2000)' in the terminal. I’d like to rule out the "bad user 
code" side of things and get any issues cleaned up on my side, so I’d 
appreciate it if someone could take a look and tell me if I’m doing something 
ass-backwards here.

The rough summary of what the op should be doing is:

1) Only changing rgba.red, .green, and .blue.
2) In engine, aggregating each of those channels into a private double[3] 
array, dividing the aggregated values by the pixel count, and storing those 
averages in another private float[3] array.
3) Unlocking the engine threads and, for any channels not intersecting 
Mask_RGB, copying the input channel straight through; otherwise, writing the 
appropriate component of the average array to the entire output buffer.

Like I said, I seem to still be overlooking something regarding what channels 
to set_out, request, and get(), so there may be some pretty stupid mistakes in 
here (on that note, it would be great if there were some better examples of how 
to use each of those steps somewhere). I’ve tried tweaking various ChannelSets 
and calls in different methods, and there are still a few code optimizations I 
think I could do, but right now I’m having no luck.

CODE TIME:
----------------------------

void _validate(bool for_real)
{
    _firstTime = true;
    copy_info();
    set_out_channels(Mask_RGB);
    Iop::_validate(for_real);
}

void _request(int x, int y, int r, int t, ChannelMask channels, int count)
{
    input0().request(x, y, r, t, channels, count);
}

void engine(int y, int x, int r, ChannelMask channels, Row& out)
{
    ChannelSet opChannels = Mask_RGB;

    {
        Guard g(_engineLock);
        if (_firstTime)
        {
            // Reinitialize value containers
            for (int i = 0; i < 3; i++)
            {
                _avgPix[i] = _pixAggregate[i] = 0.0f;
            }

            Format format = input0().format();
            const int fx = format.x();
            const int fy = format.y();
            const int fr = format.r();
            const int ft = format.t();
            const int height = ft - fy;
            const int width = fr - fx;
            const unsigned long int pixCount = width * height;

            // Allocate cache interest
            // If I uncomment these lines, I will get errors about
            // interest(channels=) instead of get(channels=)
            // Interest interest(input0(), fx, fy, fr, ft, opChannels, true);
            // interest.unlock();

            for (int ry = fy; ry < ft; ry++)
            {
                // Set any progress bars
                progressFraction(ry, ft - fy);

                // Get the corresponding Mask_RGB row from the input
                Row row(fx, fr);
                row.get(input0(), ry, fx, fr, opChannels);

                if (aborted()) return;

                // Aggregate pixel values from Mask_RGB into container array
                int chan = 0;
                foreach(z, opChannels)
                {
                    const float *CUR = row[z] + fx;
                    const float *END = row[z] + fr;
                    while (CUR < END)
                    {
                        _pixAggregate[chan] += (float)*CUR;
                        CUR++;
                    }
                    chan++;
                }
            }

            // Calculate the average for each channel
            for (int c = 0; c < opChannels.size(); c++)
            {
                _avgPix[c] = _pixAggregate[c] / pixCount;
            }

            _firstTime = false;
        }
    } // Lock out of scope

    // Get the full row from the input
    Row in(x, r);
    in.get(input0(), y, x, r, channels);

    if (aborted()) return;

    // Fill all pixels in Mask_RGB from _avgPix
    int outChan = 0;
    foreach(z, channels)
    {
        if (!intersect(z, opChannels))
        {
            // A channel we don't want to modify (may want to
            // change this to a straight memcpy eventually).
            out.copy(in, z, x, r);
        }
        else
        {
            float *CUR = out.writable(z) + x;
            const float *END = out[z] + r;
            while (CUR < END)
            {
                *CUR++ = _avgPix[outChan];
            }
            outChan++;
        }
    }
}

-Nathan

_______________________________________________
Nuke-dev mailing list
Nuke-dev@support.thefoundry.co.uk, http://forums.thefoundry.co.uk/
http://support.thefoundry.co.uk/cgi-bin/mailman/listinfo/nuke-dev

Reply via email to