'//+--------------------------------------------------------------------------+
'//|                                                                          |
'//|                                 Asleep                                   |
'//|                              Version 1.00                                |
'//|                                                                          |
'//|                Culling technic based on z-order sorting                  |
'//|                                                                          |
'//|          The GDImage.dll unregistered version has no limitation,         |
'//|             and all features of the API are fully functional.            |
'//|                                                                          |
'//|       Buying a commercial license removes the copyright nag screen.      |
'//|                                                                          |
'//+--------------------------------------------------------------------------+
'//|                                                                          |
'//|                         Author Patrice TERRIER                           |
'//|                           copyright (c) 2010                             |
'//|                                                                          |
'//|                        pterrier@zapsolution.com                          |
'//|                                                                          |
'//|                          www.zapsolution.com                             |
'//|                                                                          |
'//+--------------------------------------------------------------------------+
'//|                  Project started on : 10-11-2010 (MM-DD-YYYY)            |
'//|                        Last revised : 10-18-2010 (MM-DD-YYYY)            |
'//+--------------------------------------------------------------------------+

#COMPILE EXE "Asleep.exe"

%HWND_TOP                                       = 0
%HWND_BOTTOM                                    = 1
%WINAPI                                         = 1
%FW_BOLD                                        = 700
%TRUE                                           = 1
%FALSE                                          = 0
%NULL                                           = 0
%ERROR_ALREADY_EXISTS                           = 183
%ANSI_VAR_FONT                                  = 12
%SW_RESTORE                                     = 9
%VK_PGUP                                        = &H21
%VK_PGDN                                        = &H22
%VK_LEFT                                        = &H25
%VK_UP                                          = &H26
%VK_RIGHT                                       = &H27
%VK_DOWN                                        = &H28
%GWL_WNDPROC                                    = -4
%GCL_HCURSOR                                    = -12
%WM_DESTROY                                     = &H2
%WM_SIZE                                        = &H5
%WM_ACTIVATE                                    = &H6
%WM_PAINT                                       = &HF
%WM_QUIT                                        = &H12
%WM_SETFONT                                     = &H30
%WM_KEYDOWN                                     = &H100
%WM_COMMAND                                     = &H111
%WM_CLOSE                                       = &H10
%WM_TIMER                                       = &H113
%WM_MOUSEMOVE                                   = &H200
%WM_LBUTTONDOWN                                 = &H201
%WM_LBUTTONUP                                   = &H202
%WM_RBUTTONDOWN                                 = &H204
%WM_RBUTTONUP                                   = &H205
%WS_OVERLAPPED                                  = &H0
%WS_CHILD                                       = &H40000000
%WS_VISIBLE                                     = &H10000000
%WS_CLIPSIBLINGS                                = &H04000000
%WS_CLIPCHILDREN                                = &H02000000
%WS_CAPTION                                     = &H00C00000  ' WS_BORDER OR WS_DLGFRAME
%WS_SYSMENU                                     = &H00080000
%WS_THICKFRAME                                  = &H00040000
%WS_TABSTOP                                     = &H00010000
%WS_MINIMIZEBOX                                 = &H00020000
%WS_MAXIMIZEBOX                                 = &H00010000
%WS_OVERLAPPEDWINDOW                            = %WS_OVERLAPPED OR %WS_CAPTION OR %WS_SYSMENU OR %WS_THICKFRAME OR %WS_MINIMIZEBOX OR %WS_MAXIMIZEBOX
%WS_EX_WINDOWEDGE                               = &H00000100
%WS_EX_STATICEDGE                               = &H00020000
%WS_EX_APPWINDOW                                = &H00040000
%CS_VREDRAW                                     = &H1
%CS_HREDRAW                                     = &H2
%PM_REMOVE                                      = &H0001
%SM_CXSCREEN                                    = 0
%SM_CYSCREEN                                    = 1
%MB_ICONHAND                                    = &H00000010&
%IDC_ARROW                                      = 32512&
%IDC_SIZEALL                                    = 32646&
%IDC_HAND                                       = 32649&
%SS_CENTER                                      = &H00000001
%SS_SUNKEN                                      = &H00001000
%WM_HSCROLL                                     = &H114
%WM_VSCROLL                                     = &H115
%BST_CHECKED                                    = &H01
%BM_GETCHECK                                    = &HF0
%HWND_TOPMOST                                   = &HFFFFFFFF???

%TBS_AUTOTICKS                                  = &H0001
%TBS_VERT                                       = &H0002
%TBS_HORZ                                       = &H0000
%TBS_BOTTOM                                     = &H0000
%TBM_GETPOS                                     = %WM_USER
%TBM_SETPOS                                     = %WM_USER + 5
%TBM_SETRANGE                                   = %WM_USER + 6
%TBM_SETTICFREQ                                 = %WM_USER + 20
%TBM_SETPAGESIZE                                = %WM_USER + 21
%TBM_SETLINESIZE                                = %WM_USER + 23

%GL_TRUE                                        = 1
%GL_FALSE                                       = 0
%GL_LESS                                        = &H0201
%GL_DEPTH_BUFFER_BIT                            = &H00000100
%GL_COLOR_BUFFER_BIT                            = &H00004000
%GL_LINES                                       = &H0001???
%GL_LINE_LOOP                                   = &H0002???
%GL_LINE_STRIP                                  = &H0003???
%GL_QUADS                                       = &H0007
%GL_SRC_ALPHA                                   = &H0302
%GL_ONE_MINUS_SRC_ALPHA                         = &H0303
%GL_ONE_MINUS_SRC_COLOR                         = &H0301???
%GL_ONE_MINUS_DST_ALPHA                         = &H0305???
%GL_SPECULAR                                    = &H1202
%GL_EMISSION                                    = &H1600
%GL_SHININESS                                   = &H1601
%GL_UNSIGNED_BYTE                               = &H1401
%GL_FRONT                                       = &H0404
%GL_LINE_SMOOTH                                 = &H0B20
%GL_LIGHTING                                    = &H0B50
%GL_COLOR_MATERIAL                              = &H0B57
%GL_DEPTH_TEST                                  = &H0B71
%GL_BLEND                                       = &H0BE2
%GL_LIGHT_MODEL_LOCAL_VIEWER                    = &H0B51???
%GL_PERSPECTIVE_CORRECTION_HINT                 = &H0C50
%GL_TEXTURE_2D                                  = &H0DE1
%GL_NICEST                                      = &H1102
%GL_LIGHT0                                      = &H4000
%GL_LIGHT1                                      = &H4001???
%GL_LIGHT2                                      = &H4002???
%GL_LIGHT3                                      = &H4003???
%GL_LIGHT4                                      = &H4004???
%GL_LIGHT5                                      = &H4005???
%GL_LIGHT6                                      = &H4006???
%GL_LIGHT7                                      = &H4007???
%GL_AMBIENT                                     = &H1200
%GL_DIFFUSE                                     = &H1201
%GL_POSITION                                    = &H1203
%GL_COMPILE                                     = &H1300
%GL_AMBIENT_AND_DIFFUSE                         = &H1602
%GL_FRONT_AND_BACK                              = &H0408???
%GL_RGB                                         = &H1907
%GL_SMOOTH                                      = &H1D01
%GL_LINEAR                                      = &H2601
%GL_TEXTURE_MAG_FILTER                          = &H2800
%GL_TEXTURE_MIN_FILTER                          = &H2801
%GLU_SMOOTH                                     = 100000
%GL_RGBA                                        = &H00001908

%GL_CULL_FACE                                   = &H0B44
%GL_CW                                          = &H0900
%GL_CCW                                         = &H0901
%GL_LEQUAL                                      = &H0203
%GL_TEXTURE_GEN_S                               = &H0C60
%GL_TEXTURE_GEN_T                               = &H0C61
%GL_QUAD_STRIP                                  = &H0008
%GL_ONE                                         = 1
%GL_S                                           = &H2000???
%GL_T                                           = &H2001???
%GL_TEXTURE_GEN_MODE                            = &H2500???
%GL_SPHERE_MAP                                  = &H2402???

%GL_NORMALIZE                                   = &H0BA1???
%GL_POINTS                                      = &H0000
%GL_POINT_SPRITE                                = &H08861
%GL_COORD_REPLACE                               = &H08862
%GL_MODELVIEW                                   = &H1700???
%GL_PROJECTION                                  = &H1701???
%GL_TRIANGLE_STRIP                              = &H0005???

%GL_FOG_HINT                    = &H0C54&
%GL_FASTEST                     = &H1101&
%GL_DST_ALPHA                   = &H0304???
%GL_GREATER                     = &H0204&
%GL_ALPHA_TEST                  = &H0BC0&

TYPE RECT
  nLeft AS LONG
  nTop AS LONG
  nRight AS LONG
  nBottom 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 SECURITY_ATTRIBUTES
    nLength AS DWORD
    lpSecurityDescriptor AS LONG
    bInheritHandle AS LONG
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 PAINTSTRUCT
    hDC AS DWORD
    fErase AS LONG
    rcPaint AS RECT
    fRestore AS LONG
    fIncUpdate AS LONG
    rgbReserved(0 TO 31) AS BYTE
END TYPE

DECLARE FUNCTION GetWindowRect LIB "USER32.DLL" ALIAS "GetWindowRect" (BYVAL hWnd AS DWORD, lpRect AS RECT) AS LONG
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 SetWindowLong LIB "USER32.DLL" ALIAS "SetWindowLongA" (BYVAL hWnd AS DWORD, BYVAL nIndex AS LONG, BYVAL lNewLong AS LONG) AS LONG
DECLARE FUNCTION CallWindowProc LIB "USER32.DLL" ALIAS "CallWindowProcA" (BYVAL lpPrevWndFunc AS DWORD, BYVAL hWnd AS DWORD, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG
DECLARE FUNCTION AdjustWindowRectEx LIB "USER32.DLL" ALIAS "AdjustWindowRectEx" (lpRect AS RECT, BYVAL dsStyle AS LONG, BYVAL bMenu AS LONG, BYVAL dwEsStyle AS DWORD) AS LONG
DECLARE FUNCTION BeginPaint LIB "USER32.DLL" ALIAS "BeginPaint" (BYVAL hWnd AS DWORD, lpPaint AS PAINTSTRUCT) AS LONG
DECLARE FUNCTION CloseHandle LIB "KERNEL32.DLL" ALIAS "CloseHandle" (BYVAL hObject AS DWORD) AS LONG
DECLARE FUNCTION CreateMutex LIB "KERNEL32.DLL" ALIAS "CreateMutexA" (lpMutexAttributes AS SECURITY_ATTRIBUTES, BYVAL bInitialOwner AS LONG, lpName AS ASCIIZ) 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 DispatchMessage LIB "USER32.DLL" ALIAS "DispatchMessageA" (lpMsg AS tagMSG) AS LONG
DECLARE FUNCTION EndPaint LIB "USER32.DLL" ALIAS "EndPaint" (BYVAL hWnd AS DWORD, lpPaint AS PAINTSTRUCT) AS LONG
DECLARE FUNCTION FindWindow LIB "USER32.DLL" ALIAS "FindWindowA" (lpClassName AS ASCIIZ, lpWindowName AS ASCIIZ) 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 GetDlgItem LIB "USER32.DLL" ALIAS "GetDlgItem" (BYVAL hDlg AS DWORD, BYVAL nIDDlgItem AS LONG) AS DWORD
DECLARE FUNCTION GetFocus LIB "USER32.DLL" ALIAS "GetFocus" () AS DWORD
DECLARE FUNCTION GetForegroundWindow LIB "USER32.DLL" ALIAS "GetForegroundWindow" () AS DWORD
DECLARE FUNCTION GetLastError LIB "KERNEL32.DLL" ALIAS "GetLastError" () AS LONG
DECLARE FUNCTION GetProcAddress LIB "KERNEL32.DLL" ALIAS "GetProcAddress" (BYVAL hModule AS DWORD, lpProcName AS ASCIIZ) AS LONG
DECLARE FUNCTION GetStockObject LIB "GDI32.DLL" ALIAS "GetStockObject" (BYVAL nIndex AS LONG) AS DWORD
DECLARE FUNCTION GetSystemMetrics LIB "USER32.DLL" ALIAS "GetSystemMetrics" (BYVAL nIndex AS LONG) 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 glGenLists LIB "opengl32.dll" ALIAS "glGenLists" (BYVAL range&) AS DWORD
DECLARE FUNCTION glGetError LIB "opengl32.dll" ALIAS "glGetError" () AS DWORD
DECLARE FUNCTION gluNewQuadric  LIB "glu32.dll" ALIAS "gluNewQuadric"  () AS LONG
DECLARE FUNCTION IsIconic LIB "USER32.DLL" ALIAS "IsIconic" (BYVAL hWnd AS DWORD) AS LONG
DECLARE FUNCTION LoadCursor LIB "USER32.DLL" ALIAS "LoadCursorA" (BYVAL hInstance AS DWORD, lpCursorName AS ASCIIZ) AS DWORD
DECLARE FUNCTION LoadIcon LIB "USER32.DLL" ALIAS "LoadIconA" (BYVAL hInstance AS DWORD, lpIconName AS ASCIIZ) AS DWORD
DECLARE FUNCTION LoadLibrary LIB "KERNEL32.DLL" ALIAS "LoadLibraryA" (lpLibFileName AS ASCIIZ) AS LONG
DECLARE FUNCTION MessageBox LIB "USER32.DLL" ALIAS "MessageBoxA" (BYVAL hWnd AS DWORD, lpText AS ASCIIZ, lpCaption AS ASCIIZ, BYVAL dwType AS DWORD) AS LONG
DECLARE FUNCTION PeekMessage LIB "USER32.DLL" ALIAS "PeekMessageA" (lpMsg AS tagMSG, BYVAL hWnd AS DWORD, BYVAL dwMsgFilterMin AS DWORD, BYVAL dwMsgFilterMax AS DWORD, BYVAL dwRemoveMsg AS DWORD) AS LONG
DECLARE FUNCTION RegisterClassEx LIB "USER32.DLL" ALIAS "RegisterClassExA" (pcWndClassEx AS WNDCLASSEX) AS WORD
DECLARE FUNCTION ScreenToClient LIB "USER32.DLL" ALIAS "ScreenToClient" (BYVAL hWnd AS DWORD, lpPoint AS POINTAPI) 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 SetClassLong LIB "USER32.DLL" ALIAS "SetClassLongA" (BYVAL hWnd AS DWORD, BYVAL nIndex AS LONG, BYVAL dwNewLong AS DWORD) AS LONG
DECLARE FUNCTION SetFocus LIB "USER32.DLL" ALIAS "SetFocus" (BYVAL hWnd AS DWORD) AS LONG
DECLARE FUNCTION SetForegroundWindow LIB "USER32.DLL" ALIAS "SetForegroundWindow" (BYVAL hWnd AS DWORD) 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 ShowWindow LIB "USER32.DLL" ALIAS "ShowWindow" (BYVAL hWnd AS DWORD, BYVAL nCmdShow AS LONG) AS LONG
DECLARE FUNCTION TranslateMessage LIB "USER32.DLL" ALIAS "TranslateMessage" (lpMsg AS tagMSG) AS LONG
DECLARE FUNCTION WindowFromPoint LIB "USER32.DLL" ALIAS "WindowFromPoint" (BYVAL xPoint AS LONG, BYVAL yPoint AS LONG) AS LONG
DECLARE FUNCTION GetDlgCtrlID LIB "USER32.DLL" ALIAS "GetDlgCtrlID" (BYVAL hWnd AS DWORD) AS LONG
DECLARE FUNCTION GetTickCount LIB "KERNEL32.DLL" ALIAS "GetTickCount" () AS DWORD
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 KillTimer LIB "USER32.DLL" ALIAS "KillTimer" (BYVAL hWnd AS DWORD, BYVAL nIDEvent AS LONG) AS LONG
DECLARE SUB MoveMemory LIB "KERNEL32.DLL" ALIAS "RtlMoveMemory" (BYREF Dest AS ANY, BYREF Srce AS ANY, BYVAL Length AS DWORD)

DECLARE SUB glBegin LIB "opengl32.dll" ALIAS "glBegin" (BYVAL MODE AS DWORD)
DECLARE SUB glBindTexture LIB "opengl32.dll" ALIAS "glBindTexture" (BYVAL ntarget AS DWORD, BYVAL texture AS DWORD)
DECLARE SUB glBlendFunc LIB "opengl32.dll" ALIAS "glBlendFunc" (BYVAL sfactor AS DWORD, BYVAL dfactor AS DWORD)
DECLARE SUB glCallList LIB "opengl32.dll" ALIAS "glCallList" (BYVAL list AS DWORD)
DECLARE SUB glClear LIB "opengl32.dll" ALIAS "glClear" (BYVAL mask AS DWORD)
DECLARE SUB glClearColor LIB "opengl32.dll" ALIAS "glClearColor" (BYVAL red AS SINGLE, BYVAL green AS SINGLE, BYVAL blue AS SINGLE, BYVAL alpha AS SINGLE)
DECLARE SUB glClearDepth LIB "opengl32.dll" ALIAS "glClearDepth" (BYVAL depth AS DOUBLE)
DECLARE SUB glColor4fv LIB "opengl32.dll" ALIAS "glColor4fv" (v AS ANY)
DECLARE SUB glColorMaterial LIB "opengl32.dll" ALIAS "glColorMaterial" (BYVAL face AS DWORD, BYVAL MODE AS DWORD)
DECLARE SUB glDepthFunc LIB "opengl32.dll" ALIAS "glDepthFunc" (BYVAL func AS DWORD)
DECLARE SUB glEnable LIB "opengl32.dll" ALIAS "glEnable" (BYVAL cap AS DWORD)
DECLARE SUB glLightModeli LIB "OPENGL32.DLL" ALIAS "glLightModeli" (BYVAL pname AS DWORD, BYVAL param AS LONG)
DECLARE SUB glDisable LIB "opengl32.dll" ALIAS "glDisable" (BYVAL cap AS DWORD)
DECLARE SUB glEnd LIB "opengl32.dll" ALIAS "glEnd" ()
DECLARE SUB glEndList LIB "opengl32.dll" ALIAS "glEndList" ()
DECLARE SUB glGenTextures LIB "opengl32.dll" ALIAS "glGenTextures" (BYVAL n&, textures AS ANY)
DECLARE SUB glHint LIB "opengl32.dll" ALIAS "glHint" (BYVAL ntarget AS DWORD, BYVAL MODE AS DWORD)
DECLARE SUB glLightfv LIB "opengl32.dll" ALIAS "glLightfv" (BYVAL light AS DWORD, BYVAL pname AS DWORD, params AS ANY)
DECLARE SUB glLineWidth LIB "opengl32.dll" ALIAS "glLineWidth" (BYVAL nwidth AS SINGLE)
DECLARE SUB glLoadIdentity LIB "opengl32.dll" ALIAS "glLoadIdentity" ()
DECLARE SUB glNewList LIB "opengl32.dll" ALIAS "glNewList" (BYVAL list AS DWORD, BYVAL MODE AS DWORD)
DECLARE SUB glRotatef LIB "opengl32.dll" ALIAS "glRotatef" (BYVAL angle AS SINGLE, BYVAL x AS SINGLE, BYVAL y AS SINGLE, BYVAL z AS SINGLE)
DECLARE SUB glShadeModel LIB "opengl32.dll" ALIAS "glShadeModel" (BYVAL MODE AS DWORD)
DECLARE SUB glTexCoord2f LIB "opengl32.dll" ALIAS "glTexCoord2f" (BYVAL s AS SINGLE, BYVAL t AS SINGLE)
DECLARE SUB glTexImage2D LIB "opengl32.dll" ALIAS "glTexImage2D" (BYVAL ntarget AS DWORD, BYVAL level&, BYVAL internalformat&, BYVAL nwidth&, BYVAL height&, BYVAL border&, BYVAL format AS DWORD, BYVAL ntype AS DWORD, npixels AS ANY)
DECLARE SUB glTexParameteri LIB "opengl32.dll" ALIAS "glTexParameteri" (BYVAL ntarget AS DWORD, BYVAL pname AS DWORD, BYVAL param&)
DECLARE SUB glTranslatef LIB "opengl32.dll" ALIAS "glTranslatef" (BYVAL x AS SINGLE, BYVAL y AS SINGLE, BYVAL z AS SINGLE)
DECLARE SUB gluCylinder    LIB "glu32.dll" ALIAS "gluCylinder"    (BYVAL qobj AS DWORD, BYVAL baseRadius#, BYVAL topRadius#, BYVAL nheight#, BYVAL slices&, BYVAL stacks AS LONG)
DECLARE SUB gluDeleteQuadric    LIB "glu32.dll" ALIAS "gluDeleteQuadric"   (BYVAL STATE AS DWORD)
DECLARE SUB gluDisk   LIB "glu32.dll" ALIAS "gluDisk"   (BYVAL qobj AS DWORD, BYVAL innerRadius#, BYVAL outerRadius#, BYVAL slices&, BYVAL loops AS LONG)
DECLARE SUB gluQuadricNormals   LIB "glu32.dll" ALIAS "gluQuadricNormals"  (BYVAL quadObject AS DWORD, BYVAL normals AS DWORD)
DECLARE SUB gluQuadricTexture   LIB "glu32.dll" ALIAS "gluQuadricTexture"  (BYVAL quadObject AS DWORD, BYVAL textureCoords AS DWORD)' ANY)
DECLARE SUB glVertex3f LIB "opengl32.dll" ALIAS "glVertex3f" (BYVAL x AS SINGLE, BYVAL y AS SINGLE, BYVAL z AS SINGLE)
DECLARE SUB glColor4f LIB "opengl32.dll" ALIAS "glColor4f" (BYVAL red AS SINGLE, BYVAL green AS SINGLE, BYVAL blue AS SINGLE, BYVAL alpha AS SINGLE)
DECLARE SUB InitCommonControls LIB "COMCTL32.DLL" ALIAS "InitCommonControls" ()
DECLARE SUB PostQuitMessage LIB "USER32.DLL" ALIAS "PostQuitMessage" (BYVAL nExitCode AS LONG)
DECLARE SUB glMaterialfv LIB "OPENGL32.DLL" ALIAS "glMaterialfv" (BYVAL face AS DWORD, BYVAL pname AS DWORD, BYREF params AS SINGLE)
DECLARE SUB glColor3f LIB "OPENGL32.DLL" ALIAS "glColor3f" (BYVAL nRed AS SINGLE, BYVAL nGreen AS SINGLE, BYVAL nBlue AS SINGLE)
DECLARE SUB glPopMatrix LIB "OPENGL32.DLL" ALIAS "glPopMatrix" ()
DECLARE SUB glPushMatrix LIB "OPENGL32.DLL" ALIAS "glPushMatrix" ()
DECLARE SUB glColor4ub LIB "OPENGL32.DLL" ALIAS "glColor4ub" (BYVAL nRed AS BYTE, BYVAL nGreen AS BYTE, BYVAL nBlue AS BYTE, BYVAL alpha AS BYTE)
DECLARE SUB glScalef LIB "OPENGL32.DLL" ALIAS "glScalef" ( BYVAL x AS SINGLE, BYVAL y AS SINGLE, BYVAL z AS SINGLE)
DECLARE SUB glDeleteTextures LIB "opengl32.dll" ALIAS "glDeleteTextures" (BYVAL n&, textures AS ANY)

DECLARE SUB glVertex3fv LIB "OPENGL32.DLL" ALIAS "glVertex3fv" (BYVAL DWORD)
DECLARE SUB glTexEnvi LIB "opengl32.dll" ALIAS "glTexEnvi" (BYVAL DWORD, BYVAL DWORD, BYVAL LONG)
DECLARE SUB glPointSize LIB "opengl32.dll" ALIAS "glPointSize" (BYVAL lsize AS SINGLE)
DECLARE SUB glLineWidth LIB "opengl32.dll" ALIAS "glLineWidth" (BYVAL nwidth AS SINGLE)
DECLARE SUB glMatrixMode LIB "OPENGL32.DLL" ALIAS "glMatrixMode" (BYVAL DWORD)
DECLARE SUB glOrtho LIB "OPENGL32.DLL" ALIAS "glOrtho" (BYVAL DOUBLE, BYVAL DOUBLE, BYVAL DOUBLE, BYVAL DOUBLE, BYVAL DOUBLE, BYVAL DOUBLE)
DECLARE SUB glViewport LIB "OPENGL32.DLL" ALIAS "glViewport" (BYVAL x AS LONG, BYVAL y AS LONG, BYVAL width AS LONG, BYVAL height AS LONG)
DECLARE SUB glMultMatrixf LIB "OPENGL32.DLL" ALIAS "glMultMatrixf" (BYREF m AS SINGLE)
DECLARE SUB glColor3fv LIB "OPENGL32.DLL" ALIAS "glColor3fv" (BYREF v AS SINGLE)
DECLARE SUB glAlphaFunc LIB "OPENGL32.DLL" ALIAS "glAlphaFunc" (BYVAL func AS DWORD, BYVAL ref AS SINGLE)

%GL_TRIANGLES                      = &H0004???

%MAX_PATH = 260
%WM_DROPFILES = &H233
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 DragQueryFile LIB "SHELL32.DLL" ALIAS "DragQueryFileA" (BYVAL hDrop AS DWORD, BYVAL uiFile AS DWORD, lpStr AS ASCIIZ, BYVAL cch AS DWORD) AS DWORD

'------------------------------------------------------------------------------------------
#INCLUDE "WINLIFT.INC"
#INCLUDE "GDImage.inc"
#INCLUDE "BassAudio.inc"
#INCLUDE "Ion.inc"
#RESOURCE "glicon.pbr"

'------------------------------------------------------------------------------------------
DECLARE FUNCTION zTrace LIB "zTrace.DLL" ALIAS "zTrace" (zMessage AS ASCIIZ) AS LONG

%IDC_GLCTRL    = -100
%IDC_STATIC    = -101
%IDC_LABEL     = -102
%IDC_ZOOM      = -103
%IDC_CLOCK     = -104
%IDC_LOGO      = -105
%IDC_TIMER     = -107
%IDC_PANEL     = -108

TYPE THISOBJECT
    radius      AS SINGLE
    barsize     AS SINGLE
    xoff        AS SINGLE
    yoff        AS SINGLE
    zoff        AS SINGLE
    xrot        AS SINGLE
    yrot        AS SINGLE
    xcpy        AS SINGLE
    ycpy        AS SINGLE
    move        AS LONG
    xdown       AS LONG
    ydown       AS LONG
    mouseDown   AS LONG
    listIndex   AS LONG
END TYPE

GLOBAL glObj AS THISOBJECT
GLOBAL mt() AS ZGLTEXTUREX

GLOBAL g_hMain, g_hGLcontrol, g_hGLproc AS DWORD
GLOBAL g_UseFont AS ZGLFONT
GLOBAL g_sResource AS STRING

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 wc          AS WndClassEx
    LOCAL zClass      AS ASCIIZ * 16
    LOCAL zMessage    AS ASCIIZ * 260
    LOCAL dwExStyle, dwStyle, hMutex, hFound, hCtrl AS DWORD
    LOCAL rc          AS RECT
    LOCAL x, y        AS LONG
    LOCAL p           AS POINTAPI

    zClass = "ZGL_ASLEEP"

    hMutex = CreateMutex(BYVAL %Null, 0, zClass)
    IF hMutex THEN
       IF GetLastError = %ERROR_ALREADY_EXISTS THEN
          DO
             hFound = FindWindow(zClass, ""): IF hFound THEN EXIT DO
             WHILE PeekMessage(Msg, %NULL, %NULL, %NULL, %PM_REMOVE): WEND
          LOOP
          IF IsIconic(hFound) THEN ShowWindow(hFound, %SW_RESTORE)
          SetForeGroundWindow(hFound)
          FUNCTION = 0
          EXIT FUNCTION
       END IF
    END IF

    wc.cbSize = SIZEOF(wc)
    IsInitialized& = GetClassInfoEx(zInstance, zClass, wc)
    IF IsInitialized&   = 0 THEN
       wc.cbSize        = SIZEOF(wc)
       wc.style         = %CS_HREDRAW OR %CS_VREDRAW
       wc.lpfnWndProc   = CODEPTR(WndProc)
       wc.cbClsExtra    = 0
       wc.cbWndExtra    = 0
       wc.hInstance     = hInstance
       wc.hIcon         = LoadIcon(wc.hInstance, "PROGRAM")
       wc.hCursor       = LoadCursor(%NULL, BYVAL %IDC_ARROW)
       wc.hbrBackground = %NULL
       wc.lpszMenuName  = %NULL
       wc.lpszClassName = VARPTR(zClass)
       wc.hIconSm       = wc.hIcon
       IF RegisterClassEx(wc) THEN IsInitialized& = %TRUE
    END IF
'
    IF IsInitialized& THEN

     '************************************************************************************
     ' Load the GDImage.dll
       IF RegisterGDImageClass() = 0 THEN
          FUNCTION = 99:  EXIT FUNCTION ' If it fails to register then return ERROR = 99
       ELSE
          ZI_LoadDLL("")
       END IF
     '************************************************************************************

'
     ' Window Extended Style
       dwExStyle = %WS_EX_APPWINDOW OR %WS_EX_WINDOWEDGE
     ' Windows Style
       dwStyle = %WS_OVERLAPPEDWINDOW
       SetRect(rc, 0, 0, 868, 532)
       AdjustWindowRectEx(rc, dwStyle, %FALSE, dwExStyle)  ' Adjust Window To True Requested Size
'
       x = MAX&((GetSystemMetrics(%SM_CXSCREEN) - rc.nRight - rc.nLeft) \ 2, 0)
       y = MAX&((GetSystemMetrics(%SM_CYSCREEN) - rc.nBottom - rc.nTop) \ 2, 0)
'
     ' Create The Window
       zMessage = "Asleep"
       g_hMain = CreateWindowEx(dwExStyle, _           ' Extended Style For The Window
                             zClass, _               ' Class Name
                             zMessage, _             ' Window Title
                             dwStyle OR _            ' Defined Window Style
                             %WS_CLIPSIBLINGS OR _   ' Required Window Style
                             %WS_CLIPCHILDREN, _     ' Required Window Style
                             x, y, _                 ' Window Position
                             rc.nRight - rc.nLeft, _ ' Calculate Window Width
                             rc.nBottom - rc.nTop, _ ' Calculate Window Height
                             %NULL, _                ' No Parent Window
                             %NULL, _                ' No Menu
                             hInstance, _            ' Instance
                             BYVAL %NULL)            ' Dont Pass Anything To WM_CREATE

       IF g_hMain THEN

        ' *******************************************************************************
        ' Alternate methode to create a GDImage OpenGL control
        ' Note: when GDImage is active the OpenGL $GLImageClassName is already registered
        ' -------------------------------------------------------------------------------
          g_hGLcontrol = CreateWindowEx(0, _
                                 $GLImageClassName, _         ' Make it an OpenGL control
                                 "", _                        ' Currently not used
                                 %WS_CHILD OR %WS_VISIBLE, _  ' window style
                                 10, _                        ' initial x position
                                 10, _                        ' initial y position
                                 712, _                       ' Calculate Window Width
                                 512, _                       ' Calculate Window Height
                                 g_hMain, _                   ' parent window handle
                                 %IDC_GLCTRL, _               ' ControlID
                                 hInstance, _                 ' program instance handle
                                 BYVAL %NULL)                 ' creation parameters

'         // Subclass the OpenGL control
          IF g_hGLcontrol THEN
             g_hGLproc = SetWindowLong(g_hGLcontrol, %GWL_WNDPROC, CODEPTR(glWndProc))
          END IF

          ZI_SetAnchorMode(g_hGLcontrol, %ANCHOR_HEIGHT_WIDTH)  ' Anchor the control (make it a resizable)


'         // Add trackbar
          hCtrl = CreateWindowEx( 0, _
                                 "MSCTLS_TRACKBAR32", _
                                 "", _
                                 %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %TBS_HORZ OR %TBS_BOTTOM OR %TBS_AUTOTICKS, _
                                 740, 457, 120, 16, _
                                 g_hMain, %IDC_ZOOM, _
                                 hInstance, _
                                 BYVAL %NULL)
          ZI_SetAnchorMode(hCtrl, %ANCHOR_BOTTOM_RIGHT)
'         // Setup the trackbar parameters.
          SendMessage(hCtrl, %TBM_SETPAGESIZE, 0, 1)
          SendMessage(hCtrl, %TBM_SETLINESIZE, 0, 1)
          SendMessage(hCtrl, %TBM_SETTICFREQ, 0, 1)
          SendMessage(hCtrl, %TBM_SETRANGE, 1, MAK(LONG, 1, 100)) '// Set the zoom range
          SendMessage(hCtrl, %TBM_SETPOS, 1, 50)


          g_sResource = EXE.PATH$ + "Resource\"

        ' ----------------------------------------
        ' Load any of the supported GDImage graphic format to create a texture
          InitOpenGL()

          g_UseFont.fontName = "Pristina"
          g_UseFont.fontHeight = 14
          g_UseFont.fontWeight = %FW_BOLD
          ZI_BuildGLfont(ZI_GetGLDC(g_hGLcontrol), g_UseFont) ' Build OpenGL font for our OpenGL window

          IF skInitEngine("Podcast.sks", "") THEN

             skSkinWindow(g_hMain, "Dock|Undock|Minimize|Maximize|Restore|Close")

'            // Add a skinned border around the GDImage control.
             GetWindowRect(g_hGLcontrol, rc)
             p.x = rc.nLeft: p.y = rc.nTop
             ScreenToClient(g_hMain, p)
             skBorder(g_hGLcontrol, p.x - 1, p.y - 1, rc.nRight - rc.nLeft + 2, rc.nBottom - rc.nTop + 2, 0, 1)

'            // Add a WinLIFT clock
             hCtrl = skClockCtrl(g_hMain, g_sResource + "Clock.png", p.x + rc.nRight - rc.nLeft + 31, p.y, 0, 0, %IDC_CLOCK, &H7FCB0000, &H7F8F8F8F, 0)
             skSetAnchorCtrl(hCtrl, %ANCHOR_RIGHT)
             skCreateToolTip(hCtrl, "WinLIFT clock widget")


'            // Add a static control to display the help text.
             GetClientRect(g_hMain, rc)
             zMessage = $CRLF + "Mouse button" + $CRLF + $CRLF + "Left: rotation, and view angle." _
                      + $CRLF + $CRLF + $CRLF + "Play audio" + $CRLF + "using" + $CRLF + "drag && drop."
             hCtrl = CreateWindowEx(0, "STATIC", zMessage, %WS_CHILD OR %WS_VISIBLE OR %SS_CENTER OR %WS_BORDER, _
                                    rc.nRight - (129 + 5), 10 + (22 + 5) * 7 + 5 - 57, 129, 216, g_hMain, %IDC_LABEL, hInstance, BYVAL %NULL)
'            // Skin the static control on the fly.
             skSkinChildCtrl(hCtrl, 0)
             ZI_SetAnchorMode(hCtrl, %ANCHOR_BOTTOM_RIGHT)
'            // Use a custom font with the static control.
             skSetLabelFont(hCtrl, "TREBUCHET MS", 15, skARGB(200, 255,255,255), %FontStyleBold)

'            // Draw a panel behind the static help control.
             hCtrl = skStaticImage(g_hMain, g_sResource + "assistant.png", rc.nRight - 138, 200 - 57, 137, 224 + 57, %IDC_PANEL)
             skSetZorder(hCtrl, %HWND_BOTTOM)
             skSetAnchorCtrl(hCtrl, %ANCHOR_BOTTOM_RIGHT)

'            // Diplay the GDImage logo.
             'hCtrl = skStaticImage(g_hMain, g_sResource + "Caption.png", -8, -40, rc.nRight + 16, 123, %IDC_LOGO)
             'ZI_SetAnchorMode(hCtrl, %ANCHOR_WIDTH)

'            // To perform audio file drag and drop
             CALL DragAcceptFiles(g_hMain, %TRUE)

             ta.AudioFile = g_sResource$ + "audio.ogg"
             BassChannelPlay(g_hMain)

'            // All is done, it is time to show the main window.
             ShowWindow(g_hMain, iCmdShow)
             SetForegroundWindow(g_hMain)                ' Slightly Higher Priority
             SetFocus(g_hMain)                           ' Sets Keyboard Focus To The Window

'            // Main message pump.
             SetTimer(g_hMain, %IDC_TIMER, 1, 0) ' 60 FPS
             WHILE GetMessage(Msg, 0, 0, 0)
                TranslateMessage(Msg)
                DispatchMessage(Msg)
             WEND
             KillTimer(g_hMain, %IDC_TIMER)

             BassCloseChannel()
             BassFree()

          END IF

          FUNCTION = msg.wParam
       END IF

    END IF

    IF hMutex THEN CloseHandle(hMutex)
'
END FUNCTION


SUB InitObject()
    LOCAL i AS LONG

    Randomize(36000)'TIMER)

    glObj.xoff = -0.0  ' Initial x location.
    glObj.yoff = -0.0  ' Initial y location.
    glObj.zoff = -3.0  ' Initial zoom factor.

    glObj.xrot = 5.0
    glObj.yrot = 0.0
    glObj.radius = 0.0

    g_nIons = 150
    g_nSize = 20
    g_nEmitters = 6
    g_nAttracters = 6
    g_nSpeed = 8
    g_nCameraSpeed = 5


    DIM newRgb(2) AS SINGLE
    DIM billboardMat(15) AS SINGLE

    REDIM elist(g_nEmitters - 1) AS Temitter
    FOR i = 0 TO g_nEmitters - 1
        elist(i).X = rsRandf(1000.0!) - 500.0!
        elist(i).Y = rsRandf(1000.0!) - 500.0!
        elist(i).Z = rsRandf(1000.0!) - 500.0!
    NEXT

    REDIM alist(g_nAttracters - 1) AS Tattracter
    FOR i = 0 TO g_nAttracters - 1
        alist(i).X = rsRandf(1000.0!) - 500.0!
        alist(i).Y = rsRandf(1000.0!) - 500.0!
        alist(i).Z = rsRandf(1000.0!) - 500.0!
    NEXT

    REDIM ilist(g_nIons - 1) AS Tion
    LOCAL rTemp AS SINGLE
    FOR I = 0 TO g_nIons - 1
        ilist(I).X = 0.0!
        ilist(I).Y = 0.0!
        ilist(I).Z = 0.0!
        ilist(I).R = 0.0!
        ilist(I).G = 0.0!
        ilist(I).B = 0.0!
        rTemp =  rsRandf(2.0!) + 0.4!
        ilist(I).iSize  = g_nSize * rTemp
        iList(I).iSpeed = g_nSpeed * 12.0! / rTemp
    NEXT

    TrsTimer()

END SUB

' Set up our OpenGL scene
SUB InitOpenGL()

    InitObject()

    glClearColor(0.0, 0.0, 0.0, 0.0)     '// Black Background
    glDisable(%GL_DEPTH_TEST)
    glEnable(%GL_BLEND)
    glLightModeli(%GL_LIGHT_MODEL_LOCAL_VIEWER, %GL_TRUE)
    glEnable(%GL_NORMALIZE)
    glBlendFunc(%GL_SRC_ALPHA, %GL_ONE)
    glHint(%GL_PERSPECTIVE_CORRECTION_HINT, %GL_NICEST) '//Realy Nice perspective calculations

    glEnable(%GL_TEXTURE_2D)             '// Enable Texture Mapping

'   //Load textures
    DIM mt(7) AS ZGLTEXTUREX

    mt(0).FullName = g_sResource + "flare0.png":  mt(0).ID = 1: mt(0).Square = 0 ' Particle

    mt(1).FullName = g_sResource + "V1.png": mt(1).ID = 2: mt(1).Square = 0
    mt(2).FullName = g_sResource + "V2.png": mt(2).ID = 3: mt(2).Square = 0
    mt(3).FullName = g_sResource + "V3.png": mt(3).ID = 4: mt(3).Square = 0
    mt(4).FullName = g_sResource + "V4.png": mt(4).ID = 5: mt(4).Square = 0
    mt(5).FullName = g_sResource + "V5.png": mt(5).ID = 6: mt(5).Square = 0
    mt(6).FullName = g_sResource + "V6.png": mt(6).ID = 7: mt(6).Square = 0

    mt(7).FullName = g_sResource + "frame.png": mt(7).ID = 8: mt(7).Square = 0

    ZI_MakeMultipleTexture(BYVAL VARPTR(mt(LBOUND(mt))), UBOUND(mt) - LBOUND(mt) + 1)

'   // Initialize the particle display list
    glNewList(1, %GL_COMPILE)
      'glBindTexture(%GL_TEXTURE_2D, mt(0).Texture)
      glBegin(%GL_TRIANGLES)
        glTexCoord2f(0.0!, 0.0!):  glVertex3f(-0.5!, -0.5!, 0.0!)
        glTexCoord2f(1.0!, 0.0!):  glVertex3f(0.5!, -0.5!, 0.0!)
        glTexCoord2f(1.0!, 1.0!):  glVertex3f(0.5!, 0.5!, 0.0!)
        glTexCoord2f(0.0!, 0.0!):  glVertex3f(-0.5!, -0.5!, 0.0!)
        glTexCoord2f(1.0!, 1.0!):  glVertex3f(0.5!, 0.5!, 0.0!)
        glTexCoord2f(0.0!, 1.0!):  glVertex3f(-0.5!, 0.5!, 0.0!)
      glEnd()
    glEndList()

END SUB

DECLARE SUB glFrustum LIB "opengl32.dll" ALIAS "glFrustum" (BYVAL nleft AS DOUBLE, BYVAL nright AS DOUBLE, BYVAL bottom AS DOUBLE, BYVAL top AS DOUBLE, BYVAL zNear AS DOUBLE, BYVAL zFar AS DOUBLE)
        SUB setGLPerspective(fovy  AS SINGLE, nAspect AS SINGLE,_
                             zNear AS SINGLE, zFar    AS SINGLE)
            LOCAL xmin!, xmax!, ymin!, ymax!
            ymax =  zNear * TAN(fovy * 0.00872664626)
            ymin = -ymax
            xmin =  ymin * nAspect
            xmax =  ymax * nAspect
            CALL glFrustum( xmin, xmax, ymin, ymax, zNear, zFar)
        END SUB
FUNCTION GLfovy(BYVAL fovy&, BYVAL RW&) AS LONG
    STATIC Wasfovy&
    IF RW& THEN
       IF fovy& < 1 THEN fovy& = 45
       Wasfovy& = MIN&(fovy&, 180)
    END IF
    IF Wasfovy& = 0 THEN Wasfovy& = 45
    FUNCTION = Wasfovy&
END FUNCTION
SUB SetGLzoom (BYVAL hWnd AS LONG, BYVAL fovy AS LONG)
    CALL GLfovy(fovy, 1)
END SUB

SUB ResizeGLWindow (BYVAL hWnd AS LONG)
    LOCAL rc AS RECT, fovy AS LONG
    CALL GetClientRect(hWnd, rc)
    CALL glViewport( 0, 0, rc.nRight, rc.nBottom )
    aspect! = rc.nRight / rc.nBottom
    CALL glMatrixMode(%GL_PROJECTION)
    CALL glLoadIdentity()

    fovy = GLfovy(0,0): IF fovy = 0 THEN fovy = 60

    CALL setGLPerspective(CDBL(fovy), aspect!, 0.1, 10000.0)

    'CALL glMatrixMode(%GL_MODELVIEW )
END SUB

SUB SetZoom(BYVAL zoom AS LONG)
    SetGLzoom(g_hGLcontrol, zoom)
    ResizeGLWindow(g_hGLcontrol)
END SUB

SUB RenderOpenGL()

    LOCAL i AS LONG
    STATIC nInitDone, nIonsReleased AS LONG, rReleaseTime, rTmp AS SINGLE


    LOCAL nValue, nLValue, nRValue AS LONG, cPulse, Pulse AS SINGLE

    IF ta.Channel = 0 THEN
       BassChannelPlay(g_hMain)
       IF ta.Channel THEN InitObject()
    END IF
    IF ta.Channel THEN

       nValue          = BASS_ChannelGetLevel(ta.Channel)
       ta.Lpeak        = SolvePeak(LO(WORD, nValue), 128)
       ta.Rpeak        = SolvePeak(HI(WORD, nValue), 128)
       ta.FFTdata      = BassChannelGetData()
       ta.FFTsize      = 256
       ta.WIMdata      = BassChannelGetWimData(ta.Channel)

       nLValue = (ta.Lpeak / 700)
       nRValue = (ta.Rpeak / 768)
       nValue = MAX&(nLValue, nRValue)
       Pulse = nValue / 14

       cPulse = Pulse / 2 ' 4

    END IF


'   // We overwrite the global variable to smooth the camera movment based on the music pulse.
    'g_nCameraSpeed = 5 * cPulse
    g_nSpeed = 10 + (Pulse * 10)

    '// Camera movements
    '// first do translation (distance from center)
    STATIC oldCameraDistance, cameraDistance, targetCameraDistance, preCameraInterp, cameraInterp AS SINGLE
    IF nInitDone = 0 THEN
       targetCameraDistance = -1000.0!
       preCameraInterp = PI
    END IF
    preCameraInterp += g_nCameraSpeed * g_rFrameTime * 0.01!
    cameraInterp = 0.5! - (0.5! * COS(preCameraInterp))
    cameraDistance = -1300 ' (1.0! - cameraInterp) * oldCameraDistance + cameraInterp * targetCameraDistance
    IF (preCameraInterp >= PI) THEN
       oldCameraDistance = targetCameraDistance
       targetCameraDistance = -rsRandf(1300.0!) - 200.0!
       preCameraInterp = 0.0!
    END IF
    glMatrixMode(%GL_MODELVIEW)

    glLoadIdentity()

'   //////////////////////////////////////////////////
'   // Set the camera location based on user mousing.
    glTranslatef(glObj.xoff, glObj.yoff, glObj.zoff)
    glRotatef(glObj.xrot, 1.0, 0.0, 0.0)
    glRotatef(glObj.yrot, 0.0, 1.0, 0.0)
'   //////////////////////////////////////////////////

    glTranslatef(0.0, 0.0, cameraDistance)

    '// Do rotation
    DIM radialVel AS STATIC TrsVec: IF nInitDone = 0 THEN radialVel.X = 0.0!: radialVel.Y = 0.0!: radialVel.Z = 0.0!
    DIM targetRadialVel AS STATIC TrsVec: IF nInitDone = 0 THEN targetRadialVel = radialVel
    DIM rotQuat AS STATIC TrsQuat: IF nInitDone = 0 THEN quat_set(rotQuat, 0.0!, 0.0!, 0.0!, 1.0!)
    LOCAL radialVelDiff AS TrsVec
    radialVelDiff.X = targetRadialVel.X - radialVel.X
    radialVelDiff.Y = targetRadialVel.Y - radialVel.Y
    radialVelDiff.Z = targetRadialVel.Z - radialVel.Z
    LOCAL changeRemaining AS SINGLE
    changeRemaining = normalize(radialVelDiff)
    LOCAL change AS SINGLE
    change =  g_nCameraSpeed * 0.0002! * g_rFrameTime
    IF (changeRemaining > change) THEN
       radialVelDiff.X *= change
       radialVelDiff.Y *= change
       radialVelDiff.Z *= change
       radialVel.X += radialVelDiff.X
       radialVel.Y += radialVelDiff.Y
       radialVel.Z += radialVelDiff.Z
    ELSE
       radialVel = targetRadialVel
       IF (rsRandi(2)) THEN
          targetRadialVel.X = rsRandf(1.0!): targetRadialVel.Y = rsRandf(1.0!): targetRadialVel.Z = rsRandf(1.0!)
          normalize(targetRadialVel)
          rTmp = g_nCameraSpeed * rsRandf(0.002!)
          targetRadialVel.X *= rTmp
          targetRadialVel.Y *= rTmp
          targetRadialVel.Z *= rTmp
       ELSE
          targetRadialVel.X = 0.0!
          targetRadialVel.Y = 0.0!
          targetRadialVel.Z = 0.0!
       END IF
    END IF
    DIM tempRadialVel AS TrsVec
    tempRadialVel = radialVel
    LOCAL rAngle AS SINGLE
    rAngle = normalize(tempRadialVel)
    DIM radialQuat AS TrsQuat
    quat_make(radialQuat, rAngle, tempRadialVel)
    quat_preMult(rotQuat, radialQuat)
    DIM rotMat AS TrsMatrix
    mat_fromQuat(rotMat, rotQuat)

    '// Make billboard matrix for rotating particles when they are drawn
    MoveMemory(BYVAL VARPTR(billboardMat(0)), BYVAL VARPTR(rotmat), 64)

    '// Calculate new color
    DIM oldHsl AS STATIC TrsRgb
    DIM newHsl AS STATIC TrsRgb
    DIM targetHsl AS STATIC TrsRgb
    STATIC colorInterp, colorChange AS SINGLE
    IF nInitDone = 0 THEN
       newHsl.R = 1.0!: newHsl.G = 1.0!: newHsl.B = 1.0!
       colorInterp = 1.0!
    END IF
    colorInterp += g_rFrameTime * colorChange
    IF (colorInterp >= 1.0!) THEN
       IF (NOT rsRandi(3) AND g_nIons > 99) THEN  '// change color suddenly
          newHsl.R = rsRandf(1.0!)
          newHsl.G = 1.0! - (rsRandf(1.0!) * rsRandf(1.0!))
          newHsl.B = 1.0!
       END IF
       oldHsl = newHsl
       targetHsl.R = rsRandf(1.0!)
       targetHsl.G = 1.0! - (rsRandf(1.0!) * rsRandf(1.0!))
       targetHsl.B = 1.0!
       colorInterp = 0.0!
       '// amount by which to change colorInterp each second
       colorChange = rsRandf(0.005! * g_nSpeed) + (0.002! * g_nSpeed)
    ELSE
       LOCAL diff AS SINGLE
       diff = targetHsl.R - oldHsl.R
       IF (diff < -0.5! OR (diff > 0.0! AND diff < 0.5!)) THEN
          newHsl.R = oldHsl.R + colorInterp * diff
       ELSE
          newHsl.R = oldHsl.R - colorInterp * diff
       END IF
       diff = targetHsl.G - oldHsl.G
       newHsl.G = oldHsl.G + colorInterp * diff
       IF (newHsl.R < 0.0!) THEN newHsl.R += 1.0!
       IF (newHsl.R > 1.0!) THEN newHsl.R -= 1.0!
       hsl2rgb(newHsl.R, newHsl.G, 1.0!, newRgb(0), newRgb(1), newRgb(2))
    END IF

    '// Release ions
    IF (nIonsReleased < g_nIons) THEN
       rReleaseTime -= g_rFrameTime
       WHILE (nIonsReleased < g_nIons AND rReleaseTime <= 0.0!)
          ion_start(nIonsReleased)
          nIonsReleased += 1
          '// all ions released after 2 minutes
          rReleaseTime += 120.0! / (g_nIons)
       WEND
    END IF

    '// Set interpolation value for emitters and attracters
    STATIC rWait, rInterp, rPreinterp, rInterpconst AS SINGLE
    IF rPreinterp = 0 THEN rPreinterp = PI
    IF rInterpconst = 0 THEN rInterpconst = 0.001!
    rWait -= g_rFrameTime
    IF (rWait <= 0.0!) THEN
       rPreinterp += g_rFrameTime * (g_nSpeed) * rInterpconst
       rInterp = 0.5! - (0.5! * COS(rPreinterp))
    END IF
    IF (rPreinterp >= PI) THEN
       '// select new taget points (not the same pattern twice in a row)
       STATIC nNewTarget, nLastTarget AS LONG
       nLastTarget = nNewTarget
       nNewTarget = rsRandi(10)
       IF (nNewTarget = nLastTarget) THEN
          nNewTarget += 1
       END IF

       setTargets(nNewTarget)

       rPreinterp = 0.0!
       rInterp = 0.0!
       rWait = 10.0!  '// pause after forming each new pattern
       rInterpconst = 0.001!
       IF (NOT rsRandi(4)) THEN '// interpolate really fast sometimes
          rInterpconst = 0.1!
       END IF
    END IF

    '// Update particles
    FOR i = LBOUND(elist) TO UBOUND(elist)
        emitter_interppos(i, rInterp)
        emitter_update(i)
    NEXT
    FOR i = LBOUND(alist) TO UBOUND(alist)
        attracter_interppos(i, rInterp)
    NEXT
    FOR i = LBOUND(ilist) TO nIonsReleased - 1
        ion_update(i)
    NEXT

    '// Draw
    '// clear the screen
    'glClear(%GL_COLOR_BUFFER_BIT)
    glClear(%GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT)

    nInitDone = -1

    '// Draw ions
    glMatrixMode(%GL_MODELVIEW)
    glBlendFunc(%GL_ONE, %GL_ONE)
    glBindTexture(%GL_TEXTURE_2D, mt(0).texture)

    LOCAL sqrPulse AS SINGLE
    sqrPulse = SQR(Pulse)
    FOR i = 0 TO nIonsReleased - 1
        ion_draw(i, sqrPulse)
    NEXT

    '// Draw an object at the attracter center.
    glPushMatrix()
    Quad_Draw(Pulse)'sqrPulse)'Pulse)
    glPopMatrix()

    '// Update the display
    ZI_UpdateGLWindow(g_hGLcontrol)

END SUB

SUB DrawQuad(BYVAL x AS SINGLE, BYVAL y AS SINGLE, Byval z AS SINGLE, BYVAL nTexture AS LONG)
   glBindTexture(%GL_TEXTURE_2D, nTexture)
   glBegin(%GL_QUADS)
      glTexCoord2f(0.0, 0.0): CALL glVertex3f(-x * 1.063,-y, z) ' Bottom Left Of The Texture And Quad
      glTexCoord2f(1.0, 0.0): CALL glVertex3f( x * 1.063,-y, z) ' Bottom Right Of The Texture And Quad
      glTexCoord2f(1.0, 1.0): CALL glVertex3f( x, y, z) ' Top Right Of The Texture And Quad
      glTexCoord2f(0.0, 1.0): CALL glVertex3f(-x, y, z) ' Top Left Of The Texture And Quad
   glEnd()
END SUB

SUB Quad_Draw(BYVAL Pulse AS LONG)

    LOCAL K AS LONG, x, y, z, sSize, sPulseSize AS SINGLE
    STATIC UseAngle AS SINGLE
    UseAngle += 0.1 + Pulse
    UseAngle = UseAngle MOD 360

'   // The culling section.
    DIM A1(g_nAttracters - 1) AS SINGLE, A2(g_nAttracters - 1) AS LONG
    FOR K = 0 TO g_nAttracters - 1
        A1(K) = alist(K).X * billboardMat(2) + alist(K).Y * billboardMat(6) + alist(K).Z * billboardMat(10)
        A2(K) = K
    NEXT
'   // Sort bazed on the Z-order location.
    ARRAY SORT A1(), TAGARRAY A2()

    FOR K = 0 TO g_nAttracters - 1

        glPushMatrix()
           x = alist(A2(K)).X * billboardMat(0) + alist(A2(K)).Y * billboardMat(4) + alist(A2(K)).Z * billboardMat(8)
           y = alist(A2(K)).X * billboardMat(1) + alist(A2(K)).Y * billboardMat(5) + alist(A2(K)).Z * billboardMat(9)
           z = A1(K)
           glTranslatef(x, y, z)

           CALL glColor4f(0.95, 0.95, 0.95, 0.5)
           sSize = 200

           IF K = g_nAttracters -1 THEN
              IF (A2(K)+1) <> 6 THEN
                 sPulseSize = sSize + (Pulse * 5)
              ELSE
                 sPulseSize = sSize
              END IF
              DrawQuad(sPulseSize, sPulseSize, 0, mt(A2(K)+1).Texture)
              DrawQuad(sSize, sSize, 0, mt(7).Texture)
           ELSE
              IF (A2(K)+1) <> 6 THEN
                 sPulseSize = sSize + (Pulse * 5)
              ELSE
                 sPulseSize = sSize
              END IF
              'glRotatef(UseAngle + (K * 5), 0, 1, 0)
              'DrawQuad(sSize, sSize, 0, mt(1).Texture)
              DrawQuad(sPulseSize, sPulseSize, 0, mt(A2(K)+1).Texture)

           END IF
        glPopMatrix()
    NEXT

END SUB

SUB PaintMain(BYVAL hWin AS LONG)
    LOCAL ps AS PAINTSTRUCT
    BeginPaint(hWin, ps)
    EndPaint(hWin, ps)

    RenderOpenGL()

END SUB

FUNCTION WndProc(BYVAL hWin AS DWORD, BYVAL Msg AS LONG, BYVAL wParam AS DWORD, BYVAL lParam AS DWORD) AS LONG

    SELECT CASE LONG Msg

    CASE %WM_DROPFILES '// Drag & drop
         LOCAL szFileName AS ASCIIZ *  %MAX_PATH, nFilesDropped AS LONG
         nFilesDropped = DragQueryFile(wParam, -1, "", 0)
         szFileName = ""
         IF nFilesDropped > 0 THEN
            CALL DragQueryFile(wParam, 0, szFileName, %MAX_PATH)
            szFileName = LCASE$(szFileName)
         END IF
         CALL DragFinish(wParam)
         CALL SetForegroundWindow(g_hMain)
         IF LEN(szFileName) THEN
             ta.AudioFile = szFileName
             BassChannelPlay(g_hMain)
         END IF

    CASE %WM_SIZE
         ResizeGLWindow(g_hGLcontrol)
         RenderOpenGL()

    CASE %WM_CLOSE
         BassCloseChannel()

    CASE %WM_HSCROLL
         IF GetDlgCtrlId(lParam) = %IDC_ZOOM THEN
            '// Do not use nPosition, because it could be NULL.
            SetZoom(101 - SendMessage(lParam, %TBM_GetPos, 0, 0))
            RenderOpenGL()
         END IF

    CASE %WM_TIMER
         g_rFrameTime = TrsTick()
         RenderOpenGL()
         FUNCTION = 0: EXIT FUNCTION

    CASE %WM_PAINT
         PaintMain(hWin)
         FUNCTION = 0: EXIT FUNCTION

    CASE %WM_DESTROY
         ZI_DeleteGLFont(g_UseFont)
         ZI_DestroyTexture(BYVAL VARPTR(mt(LBOUND(mt))), UBOUND(mt) - LBOUND(mt) + 1)
         PostQuitMessage(0)
         FUNCTION = 0: EXIT FUNCTION
    END SELECT

    FUNCTION = DefWindowProc(hWin, Msg, wParam, lParam)

END FUNCTION

FUNCTION glWndProc(BYVAL hWnd AS DWORD, BYVAL Msg AS LONG, BYVAL wParam AS DWORD, BYVAL lParam AS DWORD) AS LONG

    LOCAL rc AS RECT
    STATIC LeftMousing, RightMousing, wasLX, wasLY, wasRX, wasRY AS LONG

    LOCAL x, y, dx, dy AS LONG

    SELECT CASE LONG Msg

    CASE %WM_PAINT
        RenderOpenGL()

    CASE %WM_LBUTTONDOWN
        IF (LeftMousing = %FALSE) THEN
            x = LO(INTEGER, lParam): y = HI(INTEGER, lParam)
            glObj.xcpy = glObj.xrot
            glObj.ycpy = glObj.yrot

            glObj.xdown = x
            glObj.ydown = y
            LeftMousing = %TRUE
        END IF
        IF (GetFocus() <> hWnd) THEN SetFocus(hWnd)

    CASE %WM_LBUTTONUP
        LeftMousing = %FALSE

    CASE %WM_RBUTTONDOWN
        IF (RightMousing = %FALSE) THEN
            x = LO(INTEGER, lParam): y = HI(INTEGER, lParam)
            glObj.xcpy = glObj.xoff
            glObj.ycpy = glObj.yoff

            glObj.xdown = x
            glObj.ydown = y
            RightMousing = %TRUE
        END IF
        IF (GetFocus() <> hWnd) THEN SetFocus(hWnd)

    CASE %WM_RBUTTONUP
        RightMousing = %FALSE

    CASE %WM_MOUSEMOVE
        x = LO(INTEGER, lParam): y = HI(INTEGER, lParam)

        IF (NOT ZI_IsLButtonDown()) THEN
            LeftMousing = %FALSE
        ELSE
            IF ((wasLX <> x) OR (wasLY <> y)) THEN
                IF (LeftMousing) THEN
                   dx = x - glObj.xdown: glObj.yrot = glObj.ycpy + dx / 2.0
                   dy = y - glObj.ydown: glObj.xrot = glObj.xcpy + dy / 2.0
                END IF
                RenderOpenGL()
            END IF
            wasLX = x: wasLY = y
        END IF

        IF (NOT ZI_IsRButtonDown()) THEN
            RightMousing = %FALSE
        ELSE
            IF ((wasLX <> x) OR (wasLY <> y)) THEN
                IF (RightMousing) THEN
                    GetClientRect(g_hGLcontrol, rc)
                    dx = x - glObj.xdown: glObj.xoff = glObj.xcpy - (-45 * dx) / (12.0 * rc.nRight)  ' Use 12.0 instead of 2.0 to reduce sensitivity
                    dy = y - glObj.ydown: glObj.yoff = glObj.ycpy + (-45 * dy) / (12.0 * rc.nBottom) ' Use 12.0 instead of 2.0 to reduce sensitivity
                END IF
                RenderOpenGL()
            END IF
            wasRX = x: wasRY = y
        END IF

    END SELECT

    FUNCTION = CallWindowProc(g_hGLproc, hWnd, Msg, wParam, lParam)

END FUNCTION
