Effect DLL SDK

(Doesn't work with the Lite version)

Requirements

Use the following information if you want to create your own DLL containing effects for use with Wallpaper Cycler. You need knowledge of programming DLLs in C++ to create your own effects.

The first thing you have to do is to download the Effect DLL SDK and the Anti-Grain Geometry (AGG) drawing library from http://www.antigrain.com/.

The Effect SDK contains the following files:

  • Effects Common.h: Containing some general definitions.
  • Effects.cpp: You should add your effects implementations to this file.
  • Effects.h: This file defines the effects in the DLL.

The first file should not be altered. The two last files will be explained in the following sections.

When you compile the DLL with your compiler, make sure that you have set the preprocessor definition WPC_EFFECTS_EXPORTS.

Effects.h Structure

This section will explain the structure of the effect.h file. The first few lines in the WPC_EFFECTS_DLL namespace allow you to specify some general information about your DLL.

static const TCHAR* g_version = _T("3.0");
static const TCHAR* g_author = _T("NuonSoft (Marc Gregoire)");
static const TCHAR* g_email = _T("marc.gregoire@nuonsoft.com");
static const TCHAR* g_link = _T("http://www.nuonsoft.com/wallpapercycler");
static const TCHAR* g_description = _T("This Effect DLL contains the standard effects that comes with Wallpaper Cycler.");

You should change the above strings to some appropriate values. The next few lines define the following typedefs.

typedef agg::pixfmt_rgba32 pixfmt;
typedef agg::pixfmt_gray8 pixfmtGray;

These typedefs are used in the implementation of your effect. The following few lines in the effects.h file contain some inline helper functions which you need to use in your implementation. The function ColorrefToAgg will convert a COLORREF value into an colorvalue for use by the AGG library. You have to use this inline helper function to do the conversion to make sure the order of the R, G, B and A values is correct. The function "ClampValue" is used to clamp a value between a lower and an upper bound (see example below).

The following section in the effects.h file is the most important section. It defines your effects.

static const EFFECT_INFO g_effects[] = {
  "ApplyTransparency",
  _T("Transparency"),
  _T("Make the image transparent by the given amount."),
  _T("Transparency Percentage=INT=50|0|100=Transparency percentage (100 is 
      fully transparent).;"),
};

Each effect contains the following 4 strings in the g_effects array:

  • Name of the function of your effect.
  • Name of your effect as will be shown in the GUI.
  • A description of this effect.
  • The parameters that your effect accepts (see below).

The first three strings are self-explanatory. The last string contains your parameters and this string has the following well defined syntax:

_T("name1=TYPE=DEFVALUE=DESCRIPTION;name2=TYPE=DEFVALUE=DESCRIPTION")

That string can contain as many parameters as you need. The characters "=" and ";" (without the quotes) are not allowed in the name, type, defvalue and description fields! The different fields are explained below.

nameX is the name of that parameter and will be shown in the GUI. Note: Please make sure that all parameter names are different!

TYPE is the type of the parameter and can be any of the following:

  • STRING: The parameter is a string value. This type is also used if you need a floating point parameter.
  • CHOICE: This parameter will display a dropdown list to the user containing the options you specify in the DEFVALUE field (see below).
  • INT: This parameter is an integer value. The DEFVALUE field can be used to specify a lower- and upperbound for this integer (see below).
  • BOOL: This parameter will display a checkbox to the user.
  • COLOR: This parameter will display a color-selector to the user.
  • FILE: This parameter will allow the user to select a file.

The DEFVALUE field is used to specify a default value for a specific parameter. For example:

_T("aBoolean=BOOL=1=Parameter set to true by default.")

As you can see the DEFVALUE field is set to 1, which will cause the checkbox to be checked by default. The DEFVALUE has a special meaning for the CHOICE and INT types:

  • For the CHOICE type, the default value is what should be added to the dropdown list and the first item will be preselected. The items should be separated with a |. What you get back as parameter is the index of the selected item. For example, the parameter string _T("aChoice=CHOICE=Value 1|Value 2=A choice sample.") will display a dropdown list to user containing the strings "Value 1" and "Value 2" and the first one will be selected by default.
  • For the INT type, the default value can be something like:
    x
    where x is the default value, OR
    x|a
    where x is the default value and a is the minimum value, OR
    x|a|b
    where x is the default value, a is the minimum value and b the maximum value.
    Note: These minimum and maximum values are only used in the GUI to limit the range of the spinner buttons that appear next to the integer entry box. You should still do your own parameter checking when your effect function is called, as will be explained later.

The DESCRIPTION field allows you to specify a little description which will be shown in the GUI when that particular parameter is selected by the user.

The following part of the effects.h file contains some functions definitions that you should not touch.

The last part of the effects.h file is the definition of your effect functions.

WPC_EFFECTS_API bool ApplyTransparency(agg::rendering_buffer& aggbuffBack,
      agg::rendering_buffer& aggbuffFore, agg::rendering_buffer* pAggbuffMask,
      const RECT& rect, const RECT& rectclip, const TCHAR* pszParams);

The meaning of all the parameters will be explained later, but each of your effect functions should have the above signature.

Effects.cpp Structure

The effects.cpp file starts with some includes, the DllMain function, some other functions and the macros PARSE_PARAMETERS_START and PARSE_PARAMETERS_END. All of this shouldn't be touched. After all this, you should implement your effect functions. This is explained in more details in the following example section.

 

Example

The following is an example of an effects function as implemented in a DLL. This particular effect will make the foreground transparent with a certain transparency value.

WPC_EFFECTS_API bool WPC_EFFECTS_DLL::ApplyTransparency(agg::rendering_buffer& aggbuffBack,
          agg::rendering_buffer& aggbuffFore, agg::rendering_buffer* pAggbuffMask,
          const RECT& rect, const RECT& rectclip, const TCHAR* pszParams)
{
  // Create local variables for our effect-specific parameters
  int iTransValue = 0;

  // Parse our effect-specific parameters from pszParams
  PARSE_PARAMETERS_START
    if (!_tcsnicmp(_T("Transparency Percentage"), token, equalsign-token))
      iTransValue = _ttoi(equalsign + 1);
  PARSE_PARAMETERS_END

  // Check parameter range!
  ClampValue<int>(iTransValue, 0, 100);

  // Attach AGG pixel formats to the AGG buffers
  pixfmt pixfF(aggbuffFore);
  pixfmt pixfB(aggbuffBack);
  pixfmtGray pixfMask(*pAggbuffMask);
  // Loop over all rows, keeping into account rectclip!
  for (int y=rectclip.top; y<=rectclip.bottom; ++y)
  {
    // Loop over all columns, keeping into account rectclip!
    for (int x=rectclip.left; x<=rectclip.right; ++x)
    {
      // Take masking into account
      agg::gray8 m(0);
      if (pAggbuffMask)
      {
        // A mask is supplied, check the mask value
        m = pixfMask.pixel(x, y);
        if (m.v == 255)
          continue;
      }

      // Get the color of the pixel in the foreground
      agg::rgba8 pf = pixfF.pixel(x, y);
      // Get the color of the corresponding pixel in the background
      agg::rgba8 pb = pixfB.pixel(x+rect.left, y+rect.top);

      // Calculate new foreground color, based on transparency value
      pf.r = int(((100-iTransValue)*pf.r + iTransValue*pb.r) / 100.0 + 0.5);
      pf.g = int(((100-iTransValue)*pf.g + iTransValue*pb.g) / 100.0 + 0.5);
      pf.b = int(((100-iTransValue)*pf.b + iTransValue*pb.b) / 100.0 + 0.5);
      // Take masking into account
      if (m.v != 0)
      {
        // A mask is supplied and the value is not 0, so
        // apply mask to new foreground color
        pf.r = int(((255-m.v)*pf.r + m.v*pb.r) / 255.0 + 0.5);
        pf.g = int(((255-m.v)*pf.g + m.v*pb.g) / 255.0 + 0.5);
        pf.b = int(((255-m.v)*pf.b + m.v*pb.b) / 255.0 + 0.5);
      }

      // Store new color in foreground buffer
      pixfF.copy_pixel(x, y, pf);
    }
  }

  return true;
}

Each effect function requires the following parameters:

  • aggbuffBack: This is an AGG buffer containing the background.
  • aggbuffFore: This is the AGG buffer on which you need to apply your effect.
  • pAggbuffMask: This is a pointer to an AGG buffer containing a mask. You should keep this mask into account when applying your effect. (Note: This can be a NULL-pointer, so check for NULL pointer!)
  • rect: This is the rectangle that aggbuffFore occupies in aggbuffBack.
  • rectclip: This is the rectangle inside aggbuffFore to which the effect should be applied. You should also keep the mask into account.
  • pszParams: This is a string containing specific parameters for your effect.

The flow of the code is explained with comments in the above piece of code. Don't forget to do parameter validation and correction right after the PARSE_PARAMETERS_START/PARSE_PARAMETERS_END block! In the example above this is done with a simple call to ClampValue to make sure that the iTransValue parameter is between 0 and 100 (0 and 100 inclusive).

Problems?

If you have any trouble with creating effects, ask your questions either via the Wallpaper Cycler SDK sub-forum at http://www.nuonsoft.com/forum/ or via email.

 

Back to Top

Copyright © 2009 NuonSoft
All trademarks and trade names are properties of their respective owners.