Getting Started


Getting Files

First, copy the contents of the directory /usr/class/cs248/assignments/assignment2 to your working directory; then, make a symbolic link to the content directo ry so that you can easily access the images and movies we have assembled for you.

% ln -s /usr/class/cs248/assignments/assignment2/content .
Next, build the skeleton files we have provided for your solutions:

% make
cc -fullwarn -I.. -g -mips3 -n32 -shared -o Blur.efp Blur.c 
cc -fullwarn -I.. -g -mips3 -n32 -shared -o BlurSeparable.efp BlurSeparable.c 
cc -fullwarn -I.. -g -mips3 -n32 -shared -o Magnify.efp Magnify.c 
cc -fullwarn -I.. -g -mips3 -n32 -shared -o Rotate.efp Rotate.c 
cc -fullwarn -I.. -g -mips3 -n32 -shared -o Translate.efp Translate.c 
cc -fullwarn -I.. -g -mips3 -n32 -shared -o Over.efp Over.c 
cc -fullwarn -I.. -g -mips3 -n32 -shared -o Out.efp Out.c 
cc -fullwarn -I.. -g -mips3 -n32 -shared -o Xor.efp Xor.c 
%
Note that an .efp file is built for each source file; this is a compiled form of your program that can be loaded by the effects system. When it starts, the system loads all plug-ins with the suffix .efp in the current directory.


Basic Conventions

When the .efp file is loaded, the pluginStart() function is called first. Note that if you write additional plugins in C++, pluginStart() must be declared extern "C" so that it has C linkage. This function is responsible for initializing the EF_PluginOptions struct that is passed into it with the name of the plugin and a pointer to the function that does the plugin's computation.

Some plugins take one image as input and output one image (e.g. a plugin that makes an image more dim); others take two images as input and produce one image as output. The former kind of plugin should initialize the applyOne field of the option struct to be a pointer to a function with this interface:

void functionName(EF_Image *image, EF_Image *result, float slider)
The latter type should initialize the applyTwo pointer in the options struct to point to a function with this interface:

void functionName(EF_Image *image, EF_Image *image2, EF_Image *result, 
    float slider)
Note that both types of image functions are passed a float slider value; this value is set via the timeline window in the effects system and can be used to have a parameter that is passed to the plugin that has a different value for different frames of an animation.

You may have a plug-in where the single time-varying parameter that is passed to it isn't enough to specify its behavior (for example, a plug-in that translates an input image by some (x,y) amount). So that you don't need to hard-code the translation in your program code, the video editor can call another function in your plug-in whenever the plug-in is hooked into a sequence of operations. To do this, add a function to your plug-in with this prototype:

  void startFunction(void)
and in your pluginInit() function, add a line like this:

  options->pluginStart = startFunction;
The start function will be called when the plug-in is applied to a sequence, and you can use this opportunity to prompt the user for input. For example:

static int gXTrans, gYTrans;

void startFunction()
{
    char buf[1024];

    /* get some parameters */
    fflush(stdin);
    printf ("Translation amount in X: ");
    gets(buf);
    gXTrans = atoi(buf);
    printf ("Translation amount in Y: ");
    gets(buf);
    gYTrans = atoi(buf);
  
    printf ("Setting translation to %d,%d\n", gXTrans, gYTrans);
}

Accessing Pixels In Images

As with the first assignment, we've provided some macros to help you access the pixels in the images that are passed in to your plug-ins. The EF_Image structure's declaration is this:

  typedef struct _EF_Image
  {

    FOUR_BYTES *pixels;
    short       xSize;
    short       ySize;
  
  } EF_Image;
Individual pixels can be extracted or set in an image using the EF_ImageXY(image, x, y) macro:

  int x, y;
  EF_Image *image1, *result;

  EF_ImageXY(result, x, y) = EF_ImageXY(image1, x, y);
There are also some macros to get or change the value of a pixel. First, store the entire pixel in an int:

  int pixel = EF_ImageXY(image, x, y);
Then, individual components can be extracted and set:

  int red = RED(pixel);
  red *= 2;
  RED(pixel) = red;

  EF_ImageXY(image, x, y) = pixel;
Similarly, GREEN(), BLUE(), and ALPHA() are available.


Examples

Now on to a few examples which should clarify all of the above.

First, a plug-in that takes an image as output and inverts the color in each pixel: invert an image. Note that the time varying parameter is ignored.

Next, a plug-in that replaces part of the image with a checkerboard pattern: checkerboard. Here, the time varying parameter can be used to set the size of the checks in the checkerboard; note how the default range of 0 to 1 of the parameter is remapped to a more useful range for the plug-in.

Finally, one that takes two images as input and returns an image that is the average of them: average two images.


CS248: Introduction to Computer Graphics, Pat Hanrahan, Fall 1998