;
; Description
;		OpenGL window using MM_TIMER
; 		
; Settings
		WindowSize equ		500
		TimerWait equ		10
;
; Structure
;		start:
;			Create Window
;			Create Timer
;			Message Loop:
;				Paint every second
;				Handle Window messages
;		Timer function
;		Paint function
;		Frames/second update:
;			Check >999
;			Convert to ASCII
;			Display in Window title
;		Window functions:
;			Default
;			Create
;			Size
;			Activate
;			Keydown
;			Destroy
;
; Code
		format PE gui
		start:
			
			push 0      		; lpModuleName
			call[GetModuleHandle]
			mov[wc.hInstance],eax
			push 32512  		; lpIconName (IDI_APPLICATION)
			push 0      		; hInstance
			call[LoadIcon]
			mov[wc.hIcon],eax
			push 32512  		; lpCursorName (IDC_ARROW)
			push 0      		; hInstance
			call[LoadCursor]
			mov[wc.hCursor],eax
			push wc     		; *lpWndClass
			call[RegisterClass]
			push 0              	; lpParam
			push wc.hInstance   	; hInstance
			push 0              	; hMenu
			push 0             	; hWndParent
			push WindowSize		; nHeight
			push WindowSize		; nWidth
			push 16             	; y
			push 16             	; x
			push 0x16CF0000     	; dwStyle (WS_VISIBLE+WS_DLGFRAME+WS_SYSMENU)
			push _title         	; lpWindowName
			push _classname     	; lpClassName
			push 0              	; dwExStyle
			call[CreateWindowEx]
			mov[hWnd],eax
		
			call[GetTickCount]
			mov[lastframetick],eax
			mov[nopaint],1
			push 8  			; sizeof timecaps
			push timecaps
			call[timeGetDevCaps]
			push[timecaps.wPeriodMin]
			call[timeBeginPeriod]
			push 1                      	; fuEvent (TIME_PERIODIC)
			push 0                      	; dwUser
			push timer_function		; lpTimeProc
			push[timecaps.wPeriodMin]   	; uResolution
			push TimerWait                 	; uDelay
			call[timeSetEvent]
			
			msg_loop:
			
				call[GetTickCount]
				sub eax,[lastframetick]
				cmp eax,1000
				jl dont_update_fps
				push eax
				call update_fps
    			    	dont_update_fps:
				cmp[nopaint],1
				je dont_paint
    			    	do_paint:
				call paint_function
				mov[nopaint],1
    			    	dont_paint:
				
				push 0      		; wMsgFilterMax
				push 0      		; wMsgFilterMin
				push 0      		; hWnd
				push msg    		; lpMsg
				call[GetMessage]
				or eax,eax
				jz end_loop
				push msg    		; *lpMsg
				call[TranslateMessage]
				push msg    		; *lpMsg
				call[DispatchMessage]
				jmp msg_loop
    				end_loop:
				push[msg.wParam]   	; uExitCode
				call[ExitProcess]


		timer_function:
			
			mov[nopaint],0
			push 0      		; bErase (FALSE)
			push 0      		; lpRect
			push[hWnd] 		; hWnd
			call[InvalidateRect]
			ret 20
		
		paint_function:
			
			push 0x4000    		; mask (GL_COLOR_BUFFER_BIT)
			call[glClear]
			push 1.0        	; z
			push 0.0        	; y
			push 0.0        	; x
			push[theta]     	; angle
			call[glRotatef]
			push 7      		; mode (GL_QUADS)
			call[glBegin]
			push 0.1    		; blue
			push 0.1    		; green
			push 1.0    		; red
			call[glColor3f]
			push 0.0    		; z
			push -0.6   		; y
			push -0.6   		; x
			call[glVertex3f]
			push 0.1    		; blue
			push 0.1    		; green
			push 0.1    		; red
			call[glColor3f]
			push 0.0    		; z
			push -0.6   		; y
			push 0.6    		; x
			call[glVertex3f]
			push 1.0    		; blue
			push 0.1    		; green
			push 0.1    		; red
			call[glColor3f]
			push 0.0    		; z
			push 0.6    		; y
			push 0.6    		; x
			call[glVertex3f]
			push 1.0    		; blue
			push 0.1    		; green
			push 1.0    		; red
			call[glColor3f]
			push 0.0    		; z
			push 0.6    		; y
			push -0.6   		; x
			call[glVertex3f]
			call[glEnd]
			push[hdc]   		; hdc
			call[SwapBuffers]
			xor eax,eax
			inc[drawcount]
			ret
		
		update_fps:
			
			push ebp
			mov ebp,esp
			mov ebx,dword[ebp+0x8]
			mov eax,[drawcount]
			mov ecx,1000
			mul cx
			div bx
			cmp eax,999
			jge fps_too_big
			
			mov ebx,100
			mov ecx,eax
			div bl
			mov[_title+23],al
			add[_title+23],48
			mov ah,0
			mul bl
			sub ecx,eax
			mov eax,ecx
			mov ebx,10
			div bl
			mov[_title+25],ah
			add[_title+25],48
			mov[_title+24],al
			add[_title+24],48
			jmp fps_fine
			
			fps_too_big:
				
				mov[_title+23],'9'
				mov[_title+24],'9'
				mov[_title+25],'9'

			fps_fine:
			
				mov[_title+21],' '
				mov[_title+22],'['
				mov[_title+26],'f'
				mov[_title+27],'p'
				mov[_title+28],'s'
				mov[_title+29],']'
				mov[_title+30],0
				mov[drawcount],0
				push _title
				push[hWnd]
				call[SetWindowText]
				call[GetTickCount]
				mov[lastframetick],eax
				leave
				ret
		
		window_function:
		
			push ebp
			mov ebp,esp
			push esi
			push edi
			hwnd equ dword[ebp+0x8]
			wmsg equ dword[ebp+0xC]
			wparam equ dword[ebp+0x10]
			lparam equ dword[ebp+0x14]
			cmp wmsg,0x1   			; WM_CREATE
			je wmcreate
			cmp wmsg,0x5    		; WM_SIZE
			je wmsize
			cmp wmsg,0x1C   		; WM_ACTIVATEAPP
			je wmactivateapp
			cmp wmsg,0x100  		; WM_KEYDOWN
			je wmkeydown
			cmp wmsg,0x2    		; WM_DESTROY
			je wmdestroy
			
			defwndproc:
			
				push lparam
				push wparam
				push wmsg
				push hwnd
				call[DefWindowProc]
				jmp finish
			
			wmcreate:
			
				push hwnd     				; hWnd
				call[GetDC]
				mov[hdc],eax
				mov edi,pixelformat
				mov ecx,0x28 shr 2  			; (sizeof.PIXELFORMATDESCRIPTOR)
				xor eax,eax
				rep stosd
				mov[pixelformat.nSize],0x28 		; (sizeof.PIXELFORMATDESCRIPTOR)
				mov[pixelformat.nVersion],1
				mov[pixelformat.dwFlags],0x25      	; PFD_SUPPORT_OPENGL+PFD_DOUBLEBUFFER+PFD_DRAW_TO_WINDOW
				mov[pixelformat.dwLayerMask],0     	; PFD_MAIN_PLANE
				mov[pixelformat.iPixelType],0      	; PFD_TYPE_RGBA
				mov[pixelformat.cColorBits],16
				mov[pixelformat.cDepthBits],16
				mov[pixelformat.cAccumBits],0
				mov[pixelformat.cStencilBits],0
				push pixelformat    			; ppfd
				push[hdc]           			; hdc
				call[ChoosePixelFormat]
				push pixelformat    			; ppfd
				push eax            			; iPixelFormat
				push[hdc]           			; hdc
				call[SetPixelFormat]
				push[hdc]   				; hdc
				call[wglCreateContext]
				mov[hrc],eax
				push[hrc]   				; hglrc
				push[hdc]   				; hdc
				call[wglMakeCurrent]
				push rect   				; lpRect
				push hwnd   				; hWnd
				call[GetClientRect]
				push[rect.bottom]   			; height
				push[rect.right]    			; width
				push 0              			; x
				push 0              			; y
				call[glViewport]
				xor eax,eax
				jmp finish
			
			wmsize:
			
				push rect   		; lpRect
				push hwnd   		; hWnd
				call[GetClientRect]
				push[rect.bottom]   	; height
				push[rect.right]    	; width
				push 0              	; x
				push 0              	; y
				call[glViewport]
				push 0      		; bErase (FALSE)
				push 0      		; lpRect
				push hwnd   		; hWnd
				call[InvalidateRect]
				xor eax,eax
				jmp finish
			
			wmactivateapp:
			
				push wmsg
				pop[active]
				xor eax,eax
				jmp finish
			
			wmkeydown:
				
				cmp wparam,0x01B   	; VK_ESCAPE
				jne defwndproc
			
			wmdestroy:
			
				push 0  		; hglrc
				push 0  		; hdc
				call[wglMakeCurrent]
				push[hrc]   		; hglrc
				call[wglDeleteContext]
				push[hdc]   		; hDC
				push hwnd   		; hWnd
				call[ReleaseDC]
				push 0  		; nExitCode
				call[PostQuitMessage]
				xor eax,eax
			
			finish:
				
				pop edi
				pop esi
				leave
				ret


section '.data' data readable writeable

  _title db 'OpenGL using MM_TIMER',0,0,0,0,0,0,0,0,0,0
  _classname db 'MyClass',0
  
  hWnd dd 0
  hdc dd 0
  hrc dd 0
  
  drawcount dd 0
  
  lastframetick dd 0
  nopaint db 0
  
  ; TIMECAPS
  timecaps:
  timecaps.wPeriodMin dd 0
  timecaps.wPeriodMax dd 0
  
  ; WNDCLASS
  wc:
  wc.style dd 0
  wc.lpfnWndProc dd window_function
  wc.cbClsExtra dd 0
  wc.cbWndExtra dd 0
  wc.hInstance dd 0
  wc.hIcon dd 0
  wc.hCursor dd 0
  wc.hbrBackground dd 16
  wc.lpszMenuName dd 0
  wc.lpszClassName dd _classname
  
  ; MSG
  msg:
  msg.hwnd dd 0
  msg.message dd 0
  msg.wParam dd 0
  msg.lParam dd 0
  msg.time dd 0
  msg.pt.x dd 0
  msg.pt.y dd 0
  
  ; RECT
  rect:
  rect.left dd 0
  rect.top dd 0
  rect.right dd 0
  rect.bottom dd 0
  
  ; PIXELFORMATDESCRIPTOR
  pixelformat:
  pixelformat.nSize dw 0
  pixelformat.nVersion dw 0
  pixelformat.dwFlags dd 0
  pixelformat.iPixelType db 0
  pixelformat.cColorBits db 0
  pixelformat.cRedBits db 0
  pixelformat.cRedShift db 0
  pixelformat.cGreenBits db 0
  pixelformat.cGreenShift db 0
  pixelformat.cBlueBits db 0
  pixelformat.cBlueShift db 0
  pixelformat.cAlphaBits db 0
  pixelformat.cAlphaShift db 0
  pixelformat.cAccumBits db 0
  pixelformat.cAccumRedBits db 0
  pixelformat.cAccumGreenBits db 0
  pixelformat.cAccumBlueBits db 0
  pixelformat.cAccumAlphaBits db 0
  pixelformat.cDepthBits db 0
  pixelformat.cStencilBits db 0
  pixelformat.cAuxBuffers db 0
  pixelformat.iLayerType db 0
  pixelformat.bReserved db 0
  pixelformat.dwLayerMask dd 0
  pixelformat.dwVisibleMask dd 0
  pixelformat.dwDamageMask dd 0
  sizeof.PIXELFORMATDESCRIPTOR equ 0x28
  
  active dd 0
  theta dd 0.6
  
section '.idata' import data readable writeable

  dd 0,0,0,rva kernel_name,rva kernel_table
  dd 0,0,0,rva user32_name,rva user32_table
  dd 0,0,0,rva gdi32_name,rva gdi32_table
  dd 0,0,0,rva opengl32_name,rva opengl32_table
  dd 0,0,0,rva glu32_name,rva glu32_table
  dd 0,0,0,rva winmm_name,rva winmm_table
  dd 0,0,0,0,0

  kernel_table:
    ExitProcess dd rva _ExitProcess
    GetModuleHandle dd rva _GetModuleHandle
    GetTickCount dd rva _GetTickCount
    QueryPerformanceCounter dd rva _QueryPerformanceCounter
    QueryPerformanceFrequency dd rva _QueryPerformanceFrequency
    CreateTimerQueueTimer dd rva _CreateTimerQueueTimer
    DeleteTimerQueueTimer dd rva _DeleteTimerQueueTimer
    dd 0
  
  user32_table:
    MessageBox dd rva _MessageBox
    GetDesktopWindow dd rva _GetDesktopWindow
    LoadIcon dd rva _LoadIcon
    LoadCursor dd rva _LoadCursor
    RegisterClass dd rva _RegisterClass
    CreateWindowEx dd rva _CreateWindowEx
    GetMessage dd rva _GetMessage
    TranslateMessage dd rva _TranslateMessage
    DispatchMessage dd rva _DispatchMessage
    DefWindowProc dd rva _DefWindowProc
    PostQuitMessage dd rva _PostQuitMessage
    InvalidateRect dd rva _InvalidateRect
    GetDC dd rva _GetDC
    GetClientRect dd rva _GetClientRect
    ReleaseDC dd rva _ReleaseDC
    SetTimer dd rva _SetTimer
    SetWindowText dd rva _SetWindowText
    PeekMessage dd rva _PeekMessage
    PostMessage dd rva _PostMessage
    dd 0
  
  gdi32_table:
    ChoosePixelFormat dd rva _ChoosePixelFormat
    SetPixelFormat dd rva _SetPixelFormat
    SwapBuffers dd rva _SwapBuffers
    dd 0
  
  opengl32_table:
    wglCreateContext dd rva _wglCreateContext
    wglMakeCurrent dd rva _wglMakeCurrent
    glViewport dd rva _glViewport
    glClear dd rva _glClear
    glRotatef dd rva _glRotatef
    glBegin dd rva _glBegin
    glColor3f dd rva _glColor3f
    glVertex3f dd rva _glVertex3f
    glEnd dd rva _glEnd
    wglDeleteContext dd rva _wglDeleteContext
    dd 0
  
  glu32_table:
    dd 0
  
  winmm_table:
    timeBeginPeriod dd rva _timeBeginPeriod
    timeEndPeriod dd rva _timeEndPeriod
    timeSetEvent dd rva _timeSetEvent
    timeGetDevCaps dd rva _timeGetDevCaps
    dd 0
  
  kernel_name db 'KERNEL32.DLL',0
  user32_name db 'USER32.DLL',0
  gdi32_name db 'GDI32.DLL',0
  opengl32_name db 'OPENGL32.DLL',0
  glu32_name db 'GLU32.DLL',0
  winmm_name db 'WINMM.DLL',0
  
  _ExitProcess dw 0
    db 'ExitProcess',0
  _GetModuleHandle dw 0
    db 'GetModuleHandleA',0
  _MessageBox dw 0
    db 'MessageBoxA',0
  _GetDesktopWindow dw 0
    db 'GetDesktopWindow',0
  _LoadIcon dw 0
    db 'LoadIconA',0
  _LoadCursor dw 0
    db 'LoadCursorA',0
  _RegisterClass dw 0
    db 'RegisterClassA',0
  _CreateWindowEx dw 0
    db 'CreateWindowExA',0
  _GetMessage dw 0
    db 'GetMessageA',0
  _TranslateMessage dw 0
    db 'TranslateMessage',0
  _DispatchMessage dw 0
    db 'DispatchMessageA',0
  _DefWindowProc dw 0
    db 'DefWindowProcA',0
  _PostQuitMessage dw 0
    db 'PostQuitMessage',0
  _InvalidateRect dw 0
    db 'InvalidateRect',0
  _GetDC dw 0
    db 'GetDC',0
  _ChoosePixelFormat dw 0
    db 'ChoosePixelFormat',0
  _SetPixelFormat dw 0
    db 'SetPixelFormat',0
  _wglCreateContext dw 0
    db 'wglCreateContext',0
  _wglMakeCurrent dw 0
    db 'wglMakeCurrent',0
  _GetClientRect dw 0
    db 'GetClientRect',0
  _glViewport dw 0
    db 'glViewport',0
  _glClear dw 0
    db 'glClear',0
  _glRotatef dw 0
    db 'glRotatef',0
  _glBegin dw 0
    db 'glBegin',0
  _glColor3f dw 0
    db 'glColor3f',0
  _glVertex3f dw 0
    db 'glVertex3f',0
  _glEnd dw 0
    db 'glEnd',0
  _SwapBuffers dw 0
    db 'SwapBuffers',0
  _wglDeleteContext dw 0
    db 'wglDeleteContext',0
  _ReleaseDC dw 0
    db 'ReleaseDC',0
  _SetTimer dw 0
    db 'SetTimer',0
  _SetWindowText dw 0
    db 'SetWindowTextA',0
  _GetTickCount dw 0
    db 'GetTickCount',0
  _QueryPerformanceCounter dw 0
    db 'QueryPerformanceCounter',0
  _QueryPerformanceFrequency dw 0
    db 'QueryPerformanceFrequency',0
  _PeekMessage dw 0
    db 'PeekMessageA',0
  _timeBeginPeriod dw 0
    db 'timeBeginPeriod',0
  _timeEndPeriod dw 0
    db 'timeEndPeriod',0
  _timeSetEvent dw 0
    db 'timeSetEvent',0
  _PostMessage dw 0
    db 'PostMessageA',0
  _timeGetDevCaps dw 0
    db 'timeGetDevCaps',0
  _CreateTimerQueueTimer dw 0
    db 'CreateTimerQueueTimer',0
  _DeleteTimerQueueTimer dw 0
    db 'DeleteTimerQueueTimer',0