In a file called newBright.C, we will first add the routine to set up the UI. When Chalice loads a plugin, it calls a function called upiCreateParameters(), which, as the name suggests, defines the parameters your plugin will present to the user. In our plugin, this would look like
CPIDSOEXPORT void upiCreateParameters( void ) { // First let's add a "Tab": cpiAddTab( "Parameters" ); // Now let's add the brightness parameter cpiAddFloat( "Brightness", 1.0F, 0.0F, 10.0F, P_ANIMATE ); }Notice that the first call is to cpiAddTab(). This should always be the case - you define a tab first, then put parameters into it. Our one parameter is of type float (cpiAddFloat()), but in the next chapter we will see what other kinds of UI inputs we could add.
Next, we need to define what happens when the image is cooked. Whenever a custom node is called on to produce an image, the routine upiProcessImage() is called. This routine has a single argument, which is a pointer to an image (for processing multiple inputs, see Chapter 5).
This is what our routine might look like:
CPIDSOEXPORT int upiProcessImage( CPI_Image *result ) { // First, we get the brightness parameter float brightness; if(cpiGetFloat("Brightness", result->info.time, &brightness) != 0) { cpiError( "Could not get brightness parameter" ); return -1; } // We calculate how many pixels we have int numpix = result->info.sizeX * result->info.sizeY * result->info.channels; // Now we look at what type of image we have and call // the right Brightness switch( result->info.pelType ) { case P_INT8: Brightness( (unsigned char *)result->data, brightness, (float)UCHAR_MAX, numpix ); break; case P_INT16: Brightness( (unsigned short *)result->data, brightness, (float)USHRT_MAX, numpix ); break; case P_FLOAT32: Brightness( (float *)result->data, brightness, 1.0F, numpix ); break; default: cpiError( "Unknown pixel type" ); return -1; } return 0; }Now we need to define the routine Brightness() which we called in upiProcessImage(). By using a C++ template, we only have to do this once, and then let the compiler produce the 3 different versions we actually need (one for each of 8 bit, 16 bit and float image types). Our routine looks like this:
template <class TYPE> void Brightness( TYPE *d, float brightness, float max, int numpix ) { float val; // Go through all pixels while( numpix-- ) { // Apply the brightness val = (float)*d * brightness; // Clip the result to make sure it's within range if( val > max ) val = max; if( val < 0 ) val = 0; // We're done, go to the next pixel *d = val; d++; } }The final file should look like this:
#include <stdlib.h> #include <stdio.h> #include <limits.h> #include <memory.h> #include "cpi.h" CPIDSOEXPORT void upiCreateParameters( void ) { // First let's add a "Tab": cpiAddTab( "Parameters" ); // Now let's add the brightness parameter cpiAddFloat( "Brightness", 1.0F, 0.0F, 10.0F, P_ANIMATE ); } template <class TYPE> void Brightness( TYPE *d, float brightness, float max, int numpix ) { float val; // Go through all pixels while( numpix-- ) { // Apply the brightness val = (float)*d * brightness; // Clip the result to make sure it's within range if( val > max ) val = max; if( val < 0 ) val = 0; // We're done, go to the next pixel *d = val; d++; } } CPIDSOEXPORT int upiProcessImage( CPI_Image *result ) { // First, we get the brightness parameter float brightness; if(cpiGetFloat("Brightness", result->info.time, &brightness) != 0) { cpiError( "Could not get brightness parameter" ); return -1; } // We calculate how many pixels we have int numpix = result->info.sizeX * result->info.sizeY * result->info.channels; // Now we look at what type of image we have and call // the right Brightness switch( result->info.pelType ) { case P_INT8: Brightness( (unsigned char *)result->data, brightness, (float)UCHAR_MAX, numpix ); break; case P_INT16: Brightness( (unsigned short *)result->data, brightness, (float)USHRT_MAX, numpix ); break; case P_FLOAT32: Brightness( (float *)result->data, brightness, 1.0F, numpix ); break; default: cpiError( "Unknown pixel type" ); return -1; } return 0; }This file is provided in the examples, ready to compile. You can now compile, install and run this as per the instructions in Chapter 2: