'+--------------------------------------------------------------------------+
'|                                                                          |
'|                                  ZWP                                     |
'|                                                                          |
'|                         OpenGL + Audio player                            |
'|                                                                          |
'|                BASS 2.4 copyright (c) 1999-2014 Ian Luck.                |
'|                             www.un4seen.com                              |
'|                                                                          |
'|                      Skin Engine for VISTA and XP                        |
'|           with full crystal and blur effect in composited mode           |
'|                                                                          |
'|                Example of what is going on behind the hood.              |
'|                                                                          |
'+--------------------------------------------------------------------------+
'|                                                                          |
'|                         Author Patrice TERRIER                           |
'|                         copyright(c) 2007-2010                           |
'|                           www.zapsolution.com                            |
'|                        pterrier@zapsolution.com                          |
'|                                                                          |
'+--------------------------------------------------------------------------+
'|                  Project started on : 00-06-2007 (MM-DD-YYYY)            |
'|                        Last revised : 11-07-2014 (MM-DD-YYYY)            |
'+--------------------------------------------------------------------------+

#COMPILE EXE "ZWP.exe"

%WM_COPYDATA                                    = 74
%NULL                                           = 0
%WINAPI                                         = 1
%NM_FIRST                                       = 0
%NM_AUDIOCOMPLETION                             = %NM_FIRST - 80
%WM_SETTEXT                                     = &HC
%IDC_ARROW                                      = 32512&
%MAX_PATH                                       = 260
%PFD_TYPE_RGBA                                  = 0
%PFD_DOUBLEBUFFER                               = &H00000001
%PFD_DRAW_TO_WINDOW                             = &H00000004
%PFD_DRAW_TO_BITMAP                             = &H00000008
%PFD_SUPPORT_OPENGL                             = &H00000020
%SW_SHOW                                        = 5
%WM_DESTROY                                     = &H2
%WM_SIZE                                        = &H5
%WM_CLOSE                                       = &H10
%WM_TIMER                                       = &H113
%WM_DEVICECHANGE                                = &H219
%WM_WINDOWPOSCHANGING                           = &H46
%WS_POPUP                                       = &H80000000
%WS_VISIBLE                                     = &H10000000
%WS_EX_TOOLWINDOW                               = &H00000080
%WM_NOTIFY                                      = &H4E
%CS_VREDRAW                                     = &H1
%CS_HREDRAW                                     = &H2
%SM_CXSCREEN                                    = 0
%SM_CYSCREEN                                    = 1
%GL_LIGHTING                                    = &H0B50
%GL_COLOR_MATERIAL                              = &H0B57
%GL_DEPTH_TEST                                  = &H0B71
%GL_NORMALIZE                                   = &H0BA1
%GL_ALPHA_TEST                                  = &H0BC0
%GL_BLEND                                       = &H0BE2
%GL_TEXTURE_2D                                  = &H0DE1
%GL_LIGHT0                                      = &H4000
%GL_LIGHT1                                      = &H4001
%GL_LIGHT2                                      = &H4002
%GL_LIGHT3                                      = &H4003
%GL_LIGHT4                                      = &H4004
%GL_LIGHT5                                      = &H4005
%GL_LIGHT6                                      = &H4006
%GL_LIGHT7                                      = &H4007

type WINDOWPOS
    hWnd as dword
    hWndInsertAfter as dword
    x as long
    y as long
    cx as long
    cy as long
    flags as dword
end type

type RECT
    left as long
    top as long
    right as long
    bottom as long
end type

type POINTAPI
    x as long
    y as long
end type

type tagMSG
    hwnd as dword
    message as dword
    wParam as long
    lParam as long
    time as dword
    pt as POINTAPI
end type

type WNDCLASSEX
    cbSize as dword
    STYLE as dword
    lpfnWndProc as long
    cbClsExtra as long
    cbWndExtra as long
    hInstance as dword
    hIcon as dword
    hCursor as dword
    hbrBackground as dword
    lpszMenuName as asciiz PTR
    lpszClassName as asciiz PTR
    hIconSm as dword
end type

type PIXELFORMATDESCRIPTOR
    nSize as WORD
    nVersion as WORD
    dwFlags as dword
    iPixelType as BYTE
    cColorBits as BYTE
    cRedBits as BYTE
    cRedShift as BYTE
    cGreenBits as BYTE
    cGreenShift as BYTE
    cBlueBits as BYTE
    cBlueShift as BYTE
    cAlphaBits as BYTE
    cAlphaShift as BYTE
    cAccumBits as BYTE
    cAccumRedBits as BYTE
    cAccumGreenBits as BYTE
    cAccumBlueBits as BYTE
    cAccumAlphaBits as BYTE
    cDepthBits as BYTE
    cStencilBits as BYTE
    cAuxBuffers as BYTE
    iLayerType as BYTE
    bReserved as BYTE
    dwLayerMask as dword
    dwVisibleMask as dword
    dwDamageMask as dword
end type

declare function zTrace lib "zTrace.DLL" alias "zTrace" (zMessage as asciiz) as long

declare function GetWindow lib "USER32.DLL" alias "GetWindow" (byval hWnd as dword, byval wCmd as dword) as long
declare function SendMessage lib "USER32.DLL" alias "SendMessageA" (byval hWnd as dword, byval dwMsg as dword, byval wParam as dword, byval lParam as long) as long
declare function PostMessage lib "USER32.DLL" alias "PostMessageA" (byval hWnd as dword, byval dwMsg as dword, byval wParam as dword, byval lParam as long) as long
declare function GetTickCount lib "KERNEL32.DLL" alias "GetTickCount"() as dword
declare function DestroyWindow lib "USER32.DLL" alias "DestroyWindow" (byval hWnd as dword) as long
declare function GetWindowText lib "USER32.DLL" alias "GetWindowTextA" (byval hWnd as dword, lpString as asciiz, byval cch as long) as long
declare function LoadCursor lib "USER32.DLL" alias "LoadCursorA" (byval hInstance as dword, lpCursorName as asciiz) as dword
declare function ChoosePixelFormat lib "GDI32.DLL" alias "ChoosePixelFormat" (byval hDC as dword, pPixelFormatDescriptor as PIXELFORMATDESCRIPTOR) as long
declare function CloseHandle lib "KERNEL32.DLL" alias "CloseHandle" (byval hObject as dword) as long
declare function CreateWindowEx lib "USER32.DLL" alias "CreateWindowExA" (byval dwExStyle as dword, lpClassName as asciiz, lpWindowName as asciiz, byval dwStyle as dword, byval x as long, byval y as long, _
                 byval nWidth as long, byval nHeight as long, byval hWndParent as dword, byval hMenu as dword, byval hInstance as dword, lpParam as ANY) as dword
declare function DefWindowProc lib "USER32.DLL" alias "DefWindowProcA" (byval hWnd as dword, byval uMsg as dword, byval wParam as dword, byval lParam as long) as long
declare function DeleteDC lib "GDI32.DLL" alias "DeleteDC" (byval hdc as dword) as long
declare function DeleteObject lib "GDI32.DLL" alias "DeleteObject" (byval hObject as dword) as long
declare function DispatchMessage lib "USER32.DLL" alias "DispatchMessageA" (lpMsg as tagMSG) as long
declare function FreeLibrary lib "KERNEL32.DLL" alias "FreeLibrary" (byval hLibModule as dword) as long
declare function GetClassInfoEx lib "USER32.DLL" alias "GetClassInfoExA" (byval hInst as dword, lpszClass as asciiz, lpWndClass as WNDCLASSEX) as long
declare function GetClientRect lib "USER32.DLL" alias "GetClientRect" (byval hwnd as dword, lpRect as RECT) as long
declare function GetDC lib "USER32.DLL" alias "GetDC" (byval hWnd as dword) as dword
declare function GetMessage lib "USER32.DLL" alias "GetMessageA" (lpMsg as tagMSG, byval hWnd as dword, byval uMsgFilterMin as dword, byval uMsgFilterMax as dword) as long
declare function GetProcAddress lib "KERNEL32.DLL" alias "GetProcAddress" (byval hModule as dword, lpProcName as asciiz) as long
declare function IsWindowVisible lib "USER32.DLL" alias "IsWindowVisible" (byval hWnd as dword) as long
declare function KillTimer lib "USER32.DLL" alias "KillTimer" (byval hWnd as dword, byval nIDEvent as long) as long
declare function LoadLibrary lib "KERNEL32.DLL" alias "LoadLibraryA" (lpLibFileName as asciiz) as long
declare function RegisterClassEx lib "USER32.DLL" alias "RegisterClassExA" (pcWndClassEx as WNDCLASSEX) as WORD
declare function RegisterWindowMessage lib "USER32.DLL" alias "RegisterWindowMessageA" (lpString as asciiz) as long
declare function ReleaseDC lib "USER32.DLL" alias "ReleaseDC" (byval hWnd as dword, byval hDC as dword) as long
declare function SetPixelFormat lib "GDI32.DLL" alias "SetPixelFormat" (byval hDC as dword, byval n as long, pcPixelFormatDescriptor as PIXELFORMATDESCRIPTOR) as long
declare function SetRect lib "USER32.DLL" alias "SetRect" (lpRect as RECT, byval X1 as long, byval Y1 as long, byval X2 as long, byval Y2 as long) as long
declare function SetTimer lib "USER32.DLL" alias "SetTimer" (byval hWnd as dword, byval nIDEvent as long, byval uElapse as dword, byval lpTimerFunc as long) as long
declare function ShowWindow lib "USER32.DLL" alias "ShowWindow" (byval hWnd as dword, byval nCmdShow as long) as long
declare function SwapBuffers lib "GDI32.DLL" alias "SwapBuffers" (byval hDC as dword) as long
declare function TranslateMessage lib "USER32.DLL" alias "TranslateMessage" (lpMsg as tagMSG) as long
declare function InvalidateRect lib "USER32.DLL" alias "InvalidateRect" (byval hWnd as dword, lpRect as RECT, byval bErase as long) as long
declare function UpdateWindow lib "USER32.DLL" alias "UpdateWindow" (byval hWnd as dword) as long
declare sub      PostQuitMessage lib "USER32.DLL" alias "PostQuitMessage" (byval nExitCode as long)
declare sub      DragAcceptFiles lib "SHELL32.DLL" alias "DragAcceptFiles" (byval hwnd as dword, byval fAccept as long)
declare sub      DragFinish lib "SHELL32.DLL" alias "DragFinish" (byval hDrop as dword)

declare function wglCreateContext lib "OPENGL32.DLL" alias "wglCreateContext" (byval hdc as dword) as dword
declare function wglDeleteContext lib "OPENGL32.DLL" alias "wglDeleteContext" (byval hglrc as dword) as long
declare function wglMakeCurrent lib "OPENGL32.DLL" alias "wglMakeCurrent" (byval hdc as dword, byval hglrc as dword) as long
declare function glGetError lib "opengl32.dll" alias "glGetError"() as dword
declare sub      glDeleteTextures lib "opengl32.dll" alias "glDeleteTextures" (byval n&, textures as ANY)
declare sub      glDisable lib "opengl32.dll" alias "glDisable" (byval cap as dword)
declare sub      glViewport lib "opengl32.dll" alias "glViewport" (byval x&, byval y&, byval nwidth&, byval height&)
declare sub      MoveMemory lib "KERNEL32.DLL" alias "RtlMoveMemory" (byval Destination as dword, byval Source as dword, byval Length as dword) 

type GdiplusStartupInput
    GdiplusVersion as long             ' Must be 1
    DebugEventCallback as long         ' Ignored on free builds
    SuppressBackgroundThread as long   ' FALSE unless you're prepared to call
                                       ' the hook/unhook functions properly
    SuppressExternalCodecs as long     ' FALSE unless you want GDI+ only to use
                                       ' its internal image codecs.
end type

declare function GdiplusStartup lib "gdiplus.dll" alias "GdiplusStartup" (token as long, inputbuf as GdiplusStartupInput, OPTIONAL byval outputbuf as long) as long
declare function GdiplusShutdown lib "gdiplus.dll" alias "GdiplusShutdown" (byval token as long) as long

%CS_VREDRAW                                     = &H1
%CS_HREDRAW                                     = &H2
%SM_CXSCREEN                                    = 0
%SM_CYSCREEN                                    = 1

%BBP_NO_REGISTRY = 1 ' Disable registry support
%BBP_NO_IOFILE   = 1 ' Disable file I/O support
%BBP_NO_GLFONT   = 1 ' Disable GL font support

%BBP_RENDER      = 1            '// Render the scene.
%BBP_CREATE      = 2            '// Retrieve Title, Name, Version, Render mode.
%BBP_INIT        = 3            '// Init the OpenGL.
%BBP_SIZE        = 4            '// The size of the control has changed.
%BBP_KEYBOARD    = 5            '// All keyborad message.
%BBP_MOUSE       = 6            '// All mouse messages.
%BBP_DESTROY     = 7            '// Free Up resources.

%BBP_GDIPLUS     = 0            '// GDImage GDIPLUS compatible mode.
%BBP_OPENGL      = 1            '// OpenGL mode.
%BBP_DIRECTX     = 2            '// DirectX mode (for future extension).

%BBP_SUCCESS     = 0
%BBP_ERROR       = -1

type BBPLUGIN                   '// 256 bytes
    Msg          as long        '// The plugin's message (see above constant list).
    ParentWindow as long        '// The parent window handle.
    DC           as long        '// The parent window DC (while in play mode).
    RC           as long        '// The parent OpenGL RC (while in play mode).
    Lpeak        as WORD        '// The left audio channel peak value (while in play mode).
    Rpeak        as WORD        '// The right audio channel peak value (while in play mode).
    Title        as asciiz * 32 '// Plugin's name or title.
    Author       as asciiz * 64 '// Plugin's author name.
    Version      as dword       '// LOWRD major, HIWRD minor.
    RenderTo     as long        '// %BBP_GDIPLUS, %BBP_OPENGL, %BBP_DIRECTX.
    BackARGB     as long        '// Default ARGB color background.
    FFTdata      as dword       '// dword pointer to the FFT() as single array.
    FFTsize      as WORD        '// Size of the FFT array.

    WinMsg       as long        '// True Windows message.
    wParam       as long        '// wParam
    lParam       as long        '// lParam

    WIMdata      as dword       '// dword pointer to the wave MM_WIM_DATA.
    MediaLength  as dword       '// Media length.
    MediaPos     as dword       '// Media pos.

    Reserved     as asciiz * 98 '// Reserved for future extension.
end type

$Anti                   = "\"
$Dot                    = "."
$BBP_PLUGIN_FOLDER      = "BBplugin\"
$BASSMUSICEXT           = ".mo3.it.xm.s3m.mtm.mod.umx."
$ftp                    = "ftp://"
$http                   = "http://"

%BASS_SYNC_END            = 2
%BASS_SYNC_ONETIME        = &h80000000
%BASS_STREAM_AUTOFREE     = 262144      ' automatically free the stream when it stop/ends
%BASS_STREAM_PRESCAN      = 131072      ' enable pin-point seeking on the MP3/MP2/MP1
%BASS_SAMPLE_3D           = 8           ' 3D functionality enabled
%BASS_STREAM_DECODE       = &H200000    ' don't play the stream, only decode (BASS_ChannelGetData)
%BASS_DATA_AVAILABLE      = 0           ' query how much data is buffered
%BASS_DATA_FFT512         = &H80000000  ' 512 sample FFT
%BASS_DATA_FFT1024        = &H80000001  ' 1024 FFT
%BASS_DATA_FFT2048        = &H80000002  ' 2048 FFT
%BASS_DATA_FFT4096        = &H80000003  ' 4096 FFT
%BASS_DATA_FFT_INDIVIDUAL = &H10        ' FFT flag: FFT for each channel, else all combined
%BASS_DATA_FFT_NOWINDOW   = &H20        ' FFT flag: no Hanning window
%BASS_POS_BYTE            = 0           ' byte position
%BASS_POS_MUSIC_ORDER     = 1           ' order.row position, MAKELONG(order,row)
%BASS_ATTRIB_VOL          = 2           ' Channel volume level
%BASS_ACTIVE_PLAYING      = 1           ' Channel is active
%BASS_CONFIG_MP4_VIDEO    = &H10700     ' play the audio from MP4 videos
%BASS_TAG_MP4             = 7           ' MP4/iTunes metadata
%BASS_AAC_DOWNMATRIX      = &H400000    ' downmatrix to stereo
%BASS_CTYPE_STREAM_AAC    = &H10B00     ' BASS_CHANNELINFO type
%BASS_CTYPE_STREAM_MP4    = &H10B01     ' BASS_CHANNELINFO type
%STREAM                   = 0
%MUSIC                    = 1
%SAMPLE                   = 2
%CDAUDIO                  = 3
%ACCSTREAM                = 4
%WMASTREAM                = 5

declare function BASS_Init lib "bass.dll" alias "BASS_Init" (byval device as long, byval freq as dword, byval flags as dword, byval win as dword, byval dsguid as dword) as long
declare function BASS_ChannelGetLevel lib "bass.dll" alias "BASS_ChannelGetLevel" (byval nChannel as dword) as dword
declare function BASS_ChannelPlay lib "bass.dll" alias "BASS_ChannelPlay" (byval nChannel as dword, byval restart as long) as long
declare function BASS_ChannelStop lib "bass.dll" alias "BASS_ChannelStop" (byval nChannel as dword) as long
declare function BASS_ChannelPause lib "bass.dll" alias "BASS_ChannelPause" (byval nChannel as dword) as long
declare function BASS_Free lib "bass.dll" alias "BASS_Free"() as long
declare function BASS_StreamCreateFile lib "bass.dll" alias "BASS_StreamCreateFile" (byval mem as long, file as asciiz, byval offset as QUAD, byval length as QUAD, byval flags as dword) as long
declare function BASS_MusicLoad lib "bass.dll" alias "BASS_MusicLoad" (byval mem as long, file as asciiz, byval offset as QUAD, byval length as dword, byval flags as dword, byval freq as dword) as long
declare function BASS_StreamFree lib "bass.dll" alias "BASS_StreamFree" (byval nChannel as dword) as long
declare function BASS_MusicFree lib "bass.dll" alias "BASS_MusicFree" (byval nChannel as dword) as long
declare function BASS_ChannelSetSync lib "bass.dll" alias "BASS_ChannelSetSync" (byval nChannel as dword, byval pbType as long, byval param as QUAD, byval proc as long, byval USER as long) as long
declare function BASS_SetVolume lib "bass.dll" alias "BASS_SetVolume" (byval UseVolume as single) as long
declare function BASS_ChannelGetPosition lib "bass.dll" alias "BASS_ChannelGetPosition" (byval nChannel as dword, byval nMode as dword) as dword
declare function BASS_ChannelSetPosition lib "bass.dll" alias "BASS_ChannelSetPosition" (byval nChannel as dword, byval nPos as QUAD) as long
declare function BASS_ChannelGetLength lib "bass.dll" alias "BASS_ChannelGetLength" (byval nChannel as dword, byval nMode as dword) as dword
declare function BASS_MusicGetOrders lib "bass.dll" alias "BASS_MusicGetOrders" (byval nChannel as dword) as dword
declare function BASS_ErrorGetCode lib "bass.dll" alias "BASS_ErrorGetCode"() as long
declare function BASS_ChannelGetData lib "bass.dll" alias "BASS_ChannelGetData" (byval nChannel as dword, byval buffer as dword, byval nlength as long) as long
declare function TAGS_Read lib "BassTags.dll" alias "TAGS_Read" (byval nChannel as dword, zFmt as asciiz) as long
declare function BASS_CD_StreamCreateFile lib "basscd.dll" alias "BASS_CD_StreamCreateFile" (file as asciiz, byval flags as dword) as long
declare function BASS_ChannelBytes2Seconds lib "bass.dll" alias "BASS_ChannelBytes2Seconds" (byval nChannel as dword, byval nPos as QUAD) as DOUBLE
declare function BASS_ChannelSetAttribute lib "bass.dll" alias "BASS_ChannelSetAttribute" (byval nChannel as dword, byval nAtteib as dword, byval nValue as single) as long
declare function BASS_ChannelIsActive lib "bass.dll" alias "BASS_ChannelIsActive" (byval nChannel as dword) as dword
declare function BASS_AAC_StreamCreateFile lib "Bass_AAC.dll" alias "BASS_AAC_StreamCreateFile" (byval mem as long, file as asciiz, byval offset as QUAD, byval length as QUAD, byval flags as dword) as dword
declare function BASS_MP4_StreamCreateFile lib "Bass_AAC.dll" alias "BASS_MP4_StreamCreateFile" (byval mem as long, file as asciiz, byval offset as QUAD, byval length as QUAD, byval flags as dword) as dword

%ID_VISUAL          = -1
%VISUAL_TIMER       = 2

%ZWP_PARENT         = 1
%ZWP_PLUGIN         = 2
%ZWP_AUDIO          = 3
%ZWP_DESTROY        = 4

type COPYDATASTRUCT DWORD
   dwData as DWORD   ' ULONG_PTR
   cbData as DWORD   ' DWORD
   lpData as DWORD   ' PVOID
end type

type ZWP
    file as asciiz * %MAX_PATH
end type

type PROP
    hMain           as dword
    hParent         as dword
    hChannel        as dword
    medialength     as dword
    mediapos        as dword
    glRC            as dword
    bassinit        as long
    mediatype       as long
    audiopause      as long
    ZWPNOTIFICATION as long
    audiofile       as asciiz * %MAX_PATH
end type

global gP as PROP '// Global properties

function GdipStart() as long
    local GpInput as GdiplusStartupInput, hGDIplus as long
    GpInput.GdiplusVersion = 1
    if (GdiplusStartup(hGDIplus, GpInput) = 0) then function = hGDIplus
end function

sub GdipEnd(byval hGDIplus as long)
    if (hGDIplus) then GdiplusShutdown(hGDIplus)
end sub

function BBP_ProcHandle(byval hProc as dword, byval RW as long) as dword
    static WasHproc as dword
    if (RW) then WasHproc = hProc
    function = WasHproc
end function
'// Detached plugin
sub BBP_Detached(byval hWnd as long, BYREF hLib as dword)
    local BBP as BBPLUGIN
    if (hLib) then
        BBP.Msg = %BBP_DESTROY
        BBP.ParentWindow = hWnd
        BBP_Plugin(BBP)
        '// use brute force to delete any existing texture
        local K, Tmax as long
        Tmax = 32
        REDIM DT(1 TO Tmax) as local long
        FOR K = 1 TO Tmax: DT(K) = K: NEXT
        glDeleteTextures(K, DT(1))
        BBP_ProcHandle(0, 1)
        FreeLibrary(hLib): hLib = 0
    end if
end sub
function BBP_ActivePlugin(byval sPluginName as string, byval RW as long) as string
    static sWasPluginName as string
    if (RW) then sWasPluginName = sPluginName
    function = sWasPluginName
end function
'// Load/unload plugin DLL to/from memory
function BBP_LoadPlugin(byval hWnd as long, zPlugin as asciiz) as long
    static hLib as dword, sLastPlugin as string
    local nDone as long, hProc as dword
    if ((len(zPlugin)) and (zPlugin <> sLastPlugin)) then
        if (IsFile(zPlugin)) then
            BBP_Detached(hWnd, hLib)
            hLib = LoadLibrary(zPlugin)
            if (hLib) then
                hProc = GetProcAddress(hLib, "BBProc")
                if (hProc) then
                    BBP_ProcHandle(hProc, 1)
                    sLastPlugin = zPlugin
                    BBP_ActivePlugin(sLastPlugin, 1)
                    '// reset plugin to default
                    BBP_Reset()
                    nDone = -1
                end if
            end if
        end if
    elseif len(zPlugin) = 0 then
        BBP_Detached(hWnd, hLib)
    end if
    function = nDone
end function
'declare function bbPlugin(BYREF BBP as BBPLUGIN) as long
'// Send/recept message to/from plugin
function BBP_Plugin(BYREF BBP as BBPLUGIN) as long
    local hProc as dword, nRet as long
    nRet = %BBP_ERROR
    if (gP.glRC) then
        hProc = BBP_ProcHandle(0, 0)
        if (hProc) then
            CALL DWORD hProc USING BBP_Plugin(BBP) TO nRet
        end if
    end if
    function = nRet
end function
'// Return full qualified path to the plugin folder
function BBP_Path() as string
    function = EXE.Path$ + $BBP_PLUGIN_FOLDER
end function
'// reset OpenGL plugin
sub BBP_Reset()
    local BBP as BBPLUGIN
    BBP.Msg = %BBP_CREATE
    BBP_Plugin(BBP)
    if (BBP.RenderTo = %BBP_OPENGL) then
        glDisable(%GL_BLEND)
        glDisable(%GL_TEXTURE_2D)
        glDisable(%GL_DEPTH_TEST)
        glDisable(%GL_LIGHT0)
        glDisable(%GL_LIGHT1)
        glDisable(%GL_LIGHT2)
        glDisable(%GL_LIGHT3)
        glDisable(%GL_LIGHT4)
        glDisable(%GL_LIGHT5)
        glDisable(%GL_LIGHT6)
        glDisable(%GL_LIGHT7)
        glDisable(%GL_LIGHTING)
        glDisable(%GL_COLOR_MATERIAL)
        glDisable(%GL_ALPHA_TEST)
        glDisable(%GL_NORMALIZE)
        glGetError()
    end if
end sub

function BassChannelGetLevel() as long
    local nRet as long
    if (gP.audiopause = 0) then
        if (gP.hChannel) then
            nRet = BASS_ChannelGetLevel(gP.hChannel)
        end if
    end if
    function = nRet
end function

function BassChannelGetData() as dword
    dim fft(255) as static single
    local nRet as long
    reset fft()
    if (gP.audiopause = 0) then
        if (gP.hChannel) then
            nRet = BASS_ChannelGetData(gP.hChannel, varptr(fft(0)), %BASS_DATA_FFT512)
        end if
    end if
    function = varptr(fft(0))
end function

function BassFree() as long
    if (gP.bassinit) then
        function = BASS_Free()
        gP.bassinit = 0
    end if
end function

function BassCloseChannel() as long
    local nRet as long
    if (gP.hChannel) then
        if (gP.mediatype = %MUSIC) then
            nRet = BASS_MusicFree(gP.hChannel)
        else
            nRet = BASS_StreamFree(gP.hChannel)
        end if
        gP.hChannel = 0: gP.mediatype = 0
    end if
    function = nRet
end function

function BassChannelPause() as long
    function = BASS_ChannelPause(gP.hChannel)
    gP.audiopause = 1
end function

function BassChannelResume() as long
    function = Bass_Channelplay(gP.hChannel, 0)
    gP.audiopause = 0
end function

function BassInit (byval hWnd as long) as long
    if (gP.bassinit = 0) then gP.bassinit = BASS_Init(1, 44100, 0, hWnd, 0)
    function = gP.bassinit
end function

function BassChannelGetPos() as dword
    if (gP.hChannel) then
        function = BASS_ChannelGetPosition(gP.hChannel, 0)
    end if
end function

sub BassStreamEllapsed(nSync as long, nChannel as long, nData as long, nUser as long)
    BassCloseChannel()
    gP.audiopause = 0
    SendMessage(gP.hParent, gP.ZWPNOTIFICATION, %NM_AUDIOCOMPLETION, 0)
end sub

function BassChannelGetLength() as dword
    if (gP.hChannel) then
        function = BASS_ChannelGetLength(gP.hChannel, 0)
    end if
end function

function BassChannelPlay(byval hWnd as long) as long
    local So, IsUrl as long, sLowExt as string
    BassCloseChannel()
    if (BassInit(hWnd)) then
        if ((INSTR(LCASE$(gP.audiofile), $ftp)) or (INSTR(LCASE$(gP.audiofile), $http))) then IsUrl = -1
        So = INSTR(-1, gP.audiofile, $Dot)
        if ((So) and (INSTR($BASSMUSICEXT, LCASE$(MID$(gP.audiofile, So)) + $Dot))) then
            gP.mediatype = %MUSIC
            gP.hChannel = BASS_MusicLoad(0, gP.audiofile, 0, 0, %BASS_STREAM_PRESCAN or %BASS_STREAM_AUTOFREE, 0)
        else
            gP.mediatype = %STREAM
            gP.hChannel = BASS_StreamCreateFile(0, gP.audiofile, 0, 0, %BASS_STREAM_AUTOFREE) ' %BASS_STREAM_PRESCAN)
        end if

        if (gP.hChannel) then
            BASS_ChannelSetSync(gP.hChannel, %BASS_SYNC_END or %BASS_SYNC_ONETIME, 0, CODEPTR(BassStreamEllapsed), 0)
            function = BASS_ChannelPlay(gP.hChannel, 0)
            local nScanChannel as long
            nScanChannel = BASS_StreamCreateFile(0, gP.audiofile, 0, 0, %BASS_STREAM_DECODE)
            gP.audiopause = 0
        else
            BassStreamEllapsed(0, 0, 0, 0)
        end if
    end if
end function

function BassSetChannelVolume(byval nVolume as long) as long
    BASS_ChannelSetAttribute(gP.hChannel, %BASS_ATTRIB_VOL, nVolume / 100)
end function

function BassStreamFree() as long
    if (gP.hChannel) then
        if (gP.mediatype = %MUSIC) then
            function = BASS_MusicFree(gP.hChannel)
        else
            function = BASS_StreamFree(gP.hChannel)
        end if
        gP.hChannel = 0: gP.mediatype = 0
    end if
end function

function BassChannelSetPos(byval nPos as dword) as long
    if (gP.hChannel) then
        function = BASS_ChannelSetPosition(gP.hChannel, MAK(QUAD, nPos, 0))
    end if
end function

function SolvePeak(byval nValue as long, byval nTotal as long) as long
    local nRet as long
    nRet = 0: if nTotal then nRet = (nValue * 100) \ nTotal
    function = nRet
end function

function WINMAIN (byval hInstance     as long, _
                  byval hPrevInstance as long, _
                  byval lpCmdLine     as asciiz PTR, _
                  byval iCmdShow      as long) as long

    local Msg         as tagMsg
    local wcx         as WndClassEx
    local zClass      as asciiz * 16
    local rc          as RECT
    local IsInitialized, hGDIplus as long

    zClass = "ZWALLPAPER"

    wcx.cbSize = sizeof(wcx)
    IsInitialized = GetClassInfoEx(hInstance, zClass, wcx)
    if (IsInitialized    = 0) then
        wcx.cbSize        = sizeof(wcx)
        wcx.style         = %CS_HREDRAW or %CS_VREDRAW
        wcx.lpfnWndProc   = CODEPTR(WndProc)
        wcx.cbWndExtra    = 0
        wcx.hInstance     = hInstance
        wcx.hIcon         = 0
        wcx.hCursor       = LoadCursor(%NULL, byval %IDC_ARROW)
        wcx.hbrBackground = 0
        wcx.lpszMenuName  = 0
        wcx.lpszClassName = varptr(zClass)
        wcx.hIconSm       = 0
        if (RegisterClassEx(wcx)) then IsInitialized = -1
    end if

    if (IsInitialized) then
        hGDIplus = GdipStart() '// Init GDIPLUS
        '// Main window
        gP.hMain = CreateWindowEx(%WS_EX_TOOLWINDOW, zClass, zClass, %WS_POPUP, _
                                  0, 0, 0, 0, 0, 0,  wcx.hInstance, byval %NULL)
        if (gP.hMain) then
            gP.ZWPNOTIFICATION = RegisterWindowMessage("ZWPnotification")

            '// Load plugin based on command line.
            InitOpenGL(gP.hMain)
            '// Create a 66 FPS timer
            SetTimer(gP.hMain, %VISUAL_TIMER, 0, 0)
            '// Main message pump
            while GetMessage(Msg, 0, 0, 0)
                TranslateMessage(Msg)
                DispatchMessage(Msg)
            wend
            '// Clean up everything
            KillTimer(gP.hMain, %VISUAL_TIMER)
            BassCloseChannel()
            BassFree()
            if (gP.glRC) then
                wglMakeCurrent(0, 0)
                wglDeleteContext(gP.glRC): gP.glRC = 0
            end if
            function = msg.wParam

        end if
        GdipEnd(hGDIplus) '// Unload GDIPLUS
    end if
end function

function zSetupPixelFormat(byval hDC as long) as long
    local pfd as PIXELFORMATDESCRIPTOR
    local pixelformat, nRet as long
    nRet = -1
    pfd.nSize      = sizeof(pfd)
    pfd.nVersion   = 1
    pfd.dwFlags    = %PFD_DRAW_TO_WINDOW or %PFD_SUPPORT_OPENGL or %PFD_DOUBLEBUFFER or %PFD_DRAW_TO_BITMAP
    pfd.iPixelType = %PFD_TYPE_RGBA
    pfd.cColorBits = 32
    pfd.cDepthBits = 32
    pixelformat = ChoosePixelFormat(hDC, pfd)
    if (pixelformat) then
        if SetPixelFormat(hDC, pixelformat, pfd) = 0 then nRet = 0
    else
        nRet = 0
    end if
    function = nRet
end function

sub ResizeGLwindow(byval hWnd as long)
    local rc as RECT
    GetClientRect(hWnd, rc)
    glViewport(0, 0, rc.right, rc.bottom)
    local BBP as BBPLUGIN
    BBP.Msg          = %BBP_SIZE
    BBP.ParentWindow = hWnd
    BBP_Plugin(BBP)
end sub

function InitOpenGL(byval hWnd as long) as long
    local glDC, nRet as long, BBP as BBPLUGIN
    glDC = GetDC(hWnd)
    nRet = 0
    if (zSetupPixelFormat(glDC)) then
        gP.glRC = wglCreateContext(glDC)
        if (gP.glRC) then
            if (wglMakeCurrent(glDC, gP.glRC)) then
                ResizeGLwindow(hWnd)
                nRet = -1
            end if
        end if
    end if
    ReleaseDC(hWnd, glDC)
    function = nRet
end function

'// Main window procedure
function WndProc(byval hWnd as dword, byval Msg as long, byval wParam as long, byval lParam as long) as long
    local sMessage, sParam, sCodeID as string
    local wp as WINDOWPOS PTR
    local szFile as asciiz * %MAX_PATH

    dim ptCDS as COPYDATASTRUCT ptr
    local BBP as BBPLUGIN
    dim ptZWP as ZWP ptr

    select case long Msg
    case %WM_WINDOWPOSCHANGING
         if (gP.hParent) then
             wp = lParam
             @wp.hWndInsertAfter = GetWindow(gP.hParent, 2)
             function = 0: exit function
         end if

    case %WM_COPYDATA:
         ptCDS = lParam
         select case long (@ptCDS.dwData)
         case %ZWP_PARENT:
              gP.hParent = wParam
              ptZWP = @ptCDS.lpData
         case %ZWP_PLUGIN:
              ptZWP = @ptCDS.lpData
              MoveMemory(VARPTR(szFile), VARPTR(@ptZWP.file), %MAX_PATH)
              if (BBP_LoadPlugin(hWnd, szFile)) then ' Make sure that a different plugin has been selected
                  BBP.Msg          = %BBP_INIT
                  BBP.ParentWindow = hWnd
                  BBP.DC           = GetDC(BBP.ParentWindow)
                  BBP.RC           = gP.glRC
                  BBP.BackARGB     = 0
                  if (BBP_Plugin(BBP) = %BBP_SUCCESS) then
                      ResizeGLwindow(hWnd)
                  end if
                  ReleaseDC(BBP.ParentWindow, BBP.DC)
              end if
         case %ZWP_AUDIO:
              ptZWP = @ptCDS.lpData
              MoveMemory(VARPTR(szFile), VARPTR(@ptZWP.file), %MAX_PATH)
              if (IsFile(szfile)) then
                  gP.audiofile = szFile
                  BassChannelPlay(hWnd)
              end if
         case %ZWP_DESTROY:
              DestroyWindow(hWnd)             
         end select
         function = 1: EXIT function

    case %WM_CLOSE
         BassCloseChannel()

    case %WM_SIZE
         if (gP.glRC) then
             ResizeGLwindow(hWnd)
             RenderOpenGL(hWnd)
         end if

    case %WM_DESTROY
         '// Detached active plugin
         BBP_LoadPlugin(hWnd, "")
         PostQuitMessage(0)
         function = 0: exit function

    case %WM_TIMER
         if (wParam = %VISUAL_TIMER) then
             RenderOpenGL(hWnd)
             function = 0: exit function
         end if

    end select

    function = DefWindowProc(hWnd, Msg, wParam, lParam)

end function

function BassChannelGetWimData() as dword
    dim fft(255) as static single
    local nRet as long
    reset fft()
    if (gP.audiopause = 0) then
        if (gP.hChannel) then
            nRet = BASS_ChannelGetData(gP.hChannel, varptr(fft(0)), 1024) '// %BASS_DATA_FFT512)
        end if
    end if
    function = varptr(fft(0))
end function

sub RenderOpenGL(byval hWnd as long)

    if (IsWindowVisible(hWnd) = 0) then exit sub

    local nLevel, nLpeak, nRpeak, glDC as long
    local BBP as BBPLUGIN
    static nTempo as long

    if (nTempo < GetTickcount()) then

        glDC = GetDC(hWnd)
        if (gP.glRC) then
            nLevel = BassChannelGetLevel()

            nLpeak = SolvePeak(LO(WORD, nLevel), 128)
            nRpeak = SolvePeak(HI(WORD, nLevel), 128)

            BBP.Msg          = %BBP_RENDER
            BBP.ParentWindow = hWnd
            BBP.DC           = glDC
            BBP.RC           = gP.glRC
            BBP.Lpeak        = nLpeak
            BBP.Rpeak        = nRpeak
            BBP.BackARGB     = 0
            BBP.FFTdata      = BassChannelGetData()
            BBP.FFTsize      = 256
            BBP.MediaLength  = gP.medialength
            BBP.MediaPos     = gP.mediapos
            BBP.WIMdata      = BassChannelGetWimData()

            BBP_PLUGIN(BBP)

            '// Refresh display
            SwapBuffers(glDC)

            InvalidateRect(hWnd, byval %NULL, 0)
            UpdateWindow(hWnd)

        end if
        ReleaseDC(hWnd, glDC)
        nTempo = GetTickCount() + 40 '// 25 FPS = 40 ticks
    end if

end sub
