Writing Advanced Plug-in Effects (APE's)

BOX is a quick and dirty demonstration of basic APE structure and the utilization of AVS features. It takes advantage of AVS's built-in beat detection and easy access to the frame buffer to flash a rectangle onscreen on every beat. We also learn how to set up a configuration screen template, load and save configuration settings, and use the default color selector. There is very little fat, so you can use this as a template for future APEs. You can view the main file below.

BOX Source Code

#include <windows.h>
#include "resource.h"
#include "avs_ape.h"

// this will be the directory and APE name displayed in
// the AVS Editor
#define MOD_NAME "Tutorials / BOX v1.0"

// this is how WVS will recognize this APE internally
#define UNIQUEIDSTRING "Nullsoft Tut0: BOX"


class C_THISCLASS : public C_RBASE
{
 protected:
 public:
  C_THISCLASS();
  virtual ~C_THISCLASS();
  virtual int render(char visdata[2][2][576], int isBeat,
   int *framebuffer, int *fbout, int w, int h);
  virtual HWND conf(HINSTANCE hInstance, HWND hwndParent);
  virtual char *get_desc();
  virtual void load_config(unsigned char *data, int len);
  virtual int  save_config(unsigned char *data);

  int enabled;  // toggles plug-in on and off
                // (a good idea for any APE)
  int color;		// color of rectangle
};

// global configuration dialog pointer
static C_THISCLASS *g_ConfigThis;
// global DLL instance pointer (not needed in this
// example, but is useful)
static HINSTANCE g_hDllInstance;

// this is where we deal with the configuration screen
static BOOL CALLBACK g_DlgProc(HWND hwndDlg, UINT uMsg,
WPARAM wParam,LPARAM lParam)
{
 switch (uMsg)
 {
  case WM_INITDIALOG:
  if (g_ConfigThis->enabled)
  {
   CheckDlgButton(hwndDlg,IDC_CHECK1,BST_CHECKED);
  }
  return 1;

  case WM_DRAWITEM:
  DRAWITEMSTRUCT *di;

  di=(DRAWITEMSTRUCT *)lParam;
  if (di->CtlID == IDC_DEFCOL)
  {
   int w;
   int color;

   w=di->rcItem.right-di->rcItem.left;
   color=g_ConfigThis->color;
   color = ( (color>>16)&0xff) |
   (color&0xff00) |
   ((color<<16)&0xff0000);

   // paint nifty color button
   HBRUSH hBrush,hOldBrush;
   LOGBRUSH lb={BS_SOLID,color,0};
   hBrush = CreateBrushIndirect(&lb);
   hOldBrush=(HBRUSH)SelectObject(di->hDC,hBrush);
   Rectangle(di->hDC,di->rcItem.left,di->rcItem.top,
   di->rcItem.right,di->rcItem.bottom);
   SelectObject(di->hDC,hOldBrush);
   DeleteObject(hBrush);

  }
  return 0;

  case WM_COMMAND:

  // see if enable checkbox is checked
  if (LOWORD(wParam) == IDC_CHECK1)
   {
    g_ConfigThis->enabled=
    (IsDlgButtonChecked(hwndDlg,IDC_CHECK1)?1:0);
   }

   // is colorbox is selected?
  if (LOWORD(wParam) == IDC_DEFCOL)
   {
    static COLORREF custcolors[16];
    int *a;
    CHOOSECOLOR cs;

    a=&g_ConfigThis->color;

    cs.lStructSize = sizeof(cs);
    cs.hwndOwner = hwndDlg;
    cs.hInstance = 0;
    cs.rgbResult = ((*a>>16)&0xff)|
     (*a&0xff00)|
     ((*a<<16)&0xff0000);
    cs.lpCustColors = custcolors;
    cs.Flags = CC_RGBINIT|CC_FULLOPEN;

   // go to windows color selection screen
   if (ChooseColor(&cs))
   {
    *a = ((cs.rgbResult>>16)&0xff)|
    (cs.rgbResult&0xff00)|
    ((cs.rgbResult<<16)&0xff0000);
   }
   InvalidateRect(GetDlgItem(hwndDlg,IDC_DEFCOL),
    NULL,TRUE);
   }
   return 0;
   }
   return 0;
}

// set up default configuration
C_THISCLASS::C_THISCLASS()
{
 //set initial color
 color=RGB(255,0,0);
 enabled=1;
}

// virtual destructor
C_THISCLASS::~C_THISCLASS()
{
}

/* RENDER FUNCTION:
render should return 0 if it only used framebuffer,
or 1 if the new output data  is in fbout.
this is used when you want to do something that you'd otherwise
need to make a copy of the framebuffer.
w and h are the width and height of the screen, in pixels.
isBeat is 1 if a beat has been detected.
visdata is in the format of [spectrum:0,wave:1][channel][band].
*/

int C_THISCLASS::render(char visdata[2][2][576], int isBeat,
		int *framebuffer, int *fbout, int w, int h)
{
 int halfw;
 int halfh;

 // is this effect on?
 if (!enabled)
 {
  return 0;
 }

 // did we just hit a beat?
 if(isBeat)
 {
  // draw our magic box
  halfw=w/2;
  halfh=h/2;

  framebuffer+=(((halfh/2)*w)+ (halfw/2));

  for(int j=0;j<halfh;j++)
   {
    for(int i=0;i<halfw;i++)
    {
     framebuffer[i]=color;
    }
    framebuffer+=w;
    }
  }
  return 0;
}

HWND C_THISCLASS::conf(HINSTANCE hInstance, HWND hwndParent)
// return NULL if no config dialog possible
{
 g_ConfigThis = this;
 return CreateDialog(hInstance,MAKEINTRESOURCE(IDD_CONFIG),
  hwndParent,g_DlgProc);
}


char *C_THISCLASS::get_desc(void)
{
 return MOD_NAME;
}

// load_/save_config are called when saving and loading
// presets (.avs files)

#define GET_INT() (data[pos]|(data[pos+1]<<8)|\
  (data[pos+2]<<16)|(data[pos+3]<<24))
// read configuration of max length "len" from data.

void C_THISCLASS::load_config(unsigned char *data, int len)
{
 int pos=0;
 // always ensure there is data to be loaded
 if (len-pos >= 4)
  {
   // load activation toggle
   enabled=GET_INT();
   pos+=4;
  }

 if (len-pos >= 4)
  {
   // load the box color
   color=GET_INT();
   pos+=4;
  }
}


// write configuration to data, return length.
// config data should not exceed 64k.
#define PUT_INT(y) data[pos]=(y)&255; data[pos+1]=(y>>8)&255;\
data[pos+2]=(y>>16)&255; data[pos+3]=(y>>24)&255

int  C_THISCLASS::save_config(unsigned char *data)
{
 int pos=0;

 PUT_INT(enabled);
 pos+=4;

 PUT_INT(color);
 pos+=4;

 return pos;
}

/*
export stuff
creates a new effect object if desc is NULL, otherwise
fills in desc with description
*/
C_RBASE *R_RetrFunc(char *desc)
{
 if (desc)
 {
  strcpy(desc,MOD_NAME);
  return NULL;
 }
 return (C_RBASE *) new C_THISCLASS();
}
 // allows AVS to retrieve this APE module
extern "C"
{
 __declspec (dllexport) int _AVS_APE_RetrFunc(HINSTANCE\
  hDllInstance, char **info, int *create)
  // return 0 on failure
 {
  g_hDllInstance=hDllInstance;
  *info=UNIQUEIDSTRING;
  *create=(int)(void*)R_RetrFunc;
  return 1;
 }
};
X
Impressum

Nullsoft, Inc.
22000 AOL Way, Dulles VA 20166
USA
vertreten durch Julie Jacobs und Donald R. Neff

Eingetragen im Company Register von Arizona, USA unter der Nr. 0829063-0

Umsatzsteuer ID: DE251307807

Kontakt: aolmedien@aol.com

Telefon: +1 703 265-0094

Telefax: +1 703 466-9170

AOL Music

Download Winamp, The #1 Free Media Player. Play your MP3, AAC, MPEG, AVI files, and more. Get free MP3 songs, videos, skins and plug-ins. Synch your iPod or Creative Zen, and get mobile music with Winamp Remote.

Copyright © 1999 - 2009 Nullsoft. All Rights Reserved.