winamp/Src/Plugins/Visualization/vis_avs/apesdk/avstut00.cpp

294 lines
6.4 KiB
C++

/**
Example Winamp AVS plug-in
Copyright (c) 2000, Nullsoft Inc.
Hello, welcome to the first Advanced Visualization
Studio tutorial!
The hope is that together, we can learn to utilize
AVS's powerful features: Namely direct access to the
frame buffer, EZ beat detection, and the ability to
stack plug-ins written by other developers for an
infinite array of possible effects.
I hereby present:
Tutorial 0: BOX-
Simplicity at its finest. Displays a rectangle on
screen on every beat. Oh, and you can change its color
too... Check avstut00.avs for a demonstration of a
spinning rectangle's power!
good luck and have fun!
**/
#include <windows.h>
#include "resource.h"
#include "avs_ape.h"
#define MOD_NAME "Tutorials / BOX v1.0"
#define UNIQUEIDSTRING "Nullsoft Tut0: BOX"
// extended APE api support
APEinfo *g_extinfo;
extern "C"
{
void __declspec(dllexport) _AVS_APE_SetExtInfo(HINSTANCE hDllInstance, APEinfo *ptr)
{
g_extinfo = ptr;
}
}
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
int color; // color of rectangle
};
// global configuration dialog pointer
static C_THISCLASS *g_ConfigThis;
// global DLL instance pointer (not needed in this example, but could be 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))
void C_THISCLASS::load_config(unsigned char *data, int len) // read configuration of max length "len" from data.
{
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
C_RBASE *R_RetrFunc(char *desc) // creates a new effect object if desc is NULL, otherwise fills in desc with description
{
if (desc)
{
strcpy(desc,MOD_NAME);
return NULL;
}
return (C_RBASE *) new C_THISCLASS();
}
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;
}
};
/**
Final Thoughts:
Alright! Hopefully you guys can take the next step
and display more than just a colored rectangle ;) The
exciting thing is, each time you write an AVS plug-in,
you exponentially increase AVS's potential, unlocking
the possibility of an effect you never expected. Good
luck, I hope this has helped!
See you next time!
**/