www.pudn.com > 11242.zip > Clock.asm


;----------------------------------------- 
;   Clock.asm -- Analogue Clock Demo 
;   based on Charles Petzold's DIGCLOCK.C 
;   Translated into assembly 20/9/99 by 
;   Ron Thomas Ron_Thom@Compuserve.com	 
;----------------------------------------- 
 
.386				; 32 bit when .386 appears before .MODEL 
.MODEL FLAT,STDCALL 
 
include windows.inc 
 
include user32.inc 
include kernel32.inc 
include gdi32.inc 
 
includelib user32.lib 
includelib kernel32.lib 
includelib gdi32.lib 
 
WinMain		PROTO :DWORD, :DWORD, :DWORD, :SDWORD 
 
.data 
 
ID_TIMER EQU 1 
 
ClassName db "SimpleWinClass",0 
AppName   db "Analogue Clock",0 
 
fChange		BOOL	?	 
 
 
cxClient	dd 	? 
cyClient	dd 	? 
cxC_over2	dd	? 
cyC_over2	dd	? 
 
theta		real4	?	; Required rotation in degrees 
math_X_Coord	real4	?	; Math space coords 
math_Y_Coord	real4	?	;  
New_X1		real4	? 
New_Y1		real4	? 
 
pt		POINT	{0, -150},{100,0},{0,600},{-100,0},{0,-150}, \  
			{0, -200},{ 50,0},{0,800},{ -50,0},{0,-200}, \ 
			{0,    0},{  0,0},{0,  0},{   0,0},{0, 800} 
		 
.data? 
 
hInstance HINSTANCE ? 
CommandLine LPSTR ? 
 
stPrevious	SYSTEMTIME <>	; Previous time data 
stCurrent	SYSTEMTIME <>	; Current 	"  
 
;--------------------------------------------------------------------------- 
LOWORD	MACRO bigword		;; Retrieves the low word from double word argument 
 
	mov	eax,bigword 
	and	eax,0FFFFh	;; Get low word  
	ENDM 
 
HIWORD	MACRO bigword  		;; Retrieves the high word from double word  
 
	mov	ebx,bigword 
	shr	ebx,16		;; Shift 16 for high word to set to high word 
				 
	ENDM 
 
RGB	MACRO red, green, blue	;; Get composite number from red green and blue bytes  
 
	mov	al,blue			;; ,,,blue	 
	shl	eax,8			;; ,,blue, 
 
	add	al,green		;; ,,blue,green 
	shl	eax,8			;; ,blue,green, 
	add	al,red			;; ,blue,green,red 
	and	eax,0FFFFFFh		;; Mask out top byte to complete COLORREF dword  
 
	ENDM 
;--------------------------------------------------------------------------- 
.code 
start: 
	invoke GetModuleHandle, NULL 
	mov    hInstance,eax 
	invoke GetCommandLine 
        invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT 
	invoke ExitProcess,eax 
 
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:SDWORD 
 
	LOCAL wc:WNDCLASSEX 
	LOCAL msg:MSG 
        LOCAL hwnd:HWND 
 
	mov   wc.cbSize,SIZEOF WNDCLASSEX 
	mov   wc.style, CS_HREDRAW or CS_VREDRAW 
	mov   wc.lpfnWndProc, OFFSET WndProc 
	mov   wc.cbClsExtra,NULL 
	mov   wc.cbWndExtra,NULL 
        push  hInstance 
        pop   wc.hInstance 
	mov   wc.hbrBackground,COLOR_WINDOW+1 
	mov   wc.lpszMenuName,NULL 
	mov   wc.lpszClassName,OFFSET ClassName 
        invoke LoadIcon,NULL,IDI_APPLICATION 
	mov   wc.hIcon,eax 
        mov   wc.hIconSm,0 
        invoke LoadCursor,NULL,IDC_ARROW 
	mov   wc.hCursor,eax  
        invoke RegisterClassEx, addr wc 
 
        INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\ 
           WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\ 
           CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\ 
           hInst,NULL 
        mov   hwnd,eax 
        INVOKE ShowWindow, hwnd,SW_SHOWNORMAL 
        INVOKE UpdateWindow, hwnd 
        .WHILE TRUE 
                INVOKE GetMessage, ADDR msg,NULL,0,0 
                .BREAK .IF (!eax) 
                INVOKE TranslateMessage, ADDR msg 
                INVOKE DispatchMessage, ADDR msg 
        .ENDW 
        mov     eax,msg.wParam 
        ret 
WinMain endp 
 
SetIsotropic proc hdc:HDC  
 
	invoke SetMapMode, hdc, MM_ISOTROPIC	; Select isotropic mapping  
 
;  Set window extents to 1000 and the viewport extents to 1/2 width of client area, 
;  and the negative of 1/2 height of client area 
 
	invoke SetWindowExtEx, hdc, 1000, 1000, NULL 
	mov	eax,cyC_over2 
	neg	eax			; Get -cyClient/2 
	invoke SetViewportExtEx, hdc, cxC_over2, eax ,NULL 
	invoke SetViewportOrgEx, hdc, cxC_over2, cyC_over2, NULL 
	 
	ret 
SetIsotropic endp 
 
 
DrawClock proc hdc:HDC 
 
LOCAL   iAngle:DWORD, pt4[3]:POINT 
 
	mov	iAngle,0 
 
	.WHILE	iAngle < 360 
 
	mov	pt4[0].x,0 
	mov	pt4[0].y,900 
 
	fild	pt4[0*8].x 
	fstp	math_X_Coord 
	 
	fild	pt4[0*8].y 
	fstp	math_Y_Coord 
 
	fild	iAngle 
	fstp	theta 
 
	mov	esi,offset theta	; Point at parameter block 
 
	call	rotate			; Rotate the 5-minute or minute marks 
 
	fld	New_X1			; Get new X coord 
	fistp	pt4[0*8].x		; Store in structure 
 
	fld	New_Y1			; Ditto for Y coord 
	fistp	pt4[0*8].y		;  
 
	mov	eax,iAngle 
	mov	ecx,5 
	mov	edx,0 
	div	ecx			; Get the remainder in dx 
 
	.IF edx 
	    mov pt4[2*8].x,33		; if edx is true its a minute mark (small circle) 
	    mov pt4[2*8].y,33 
	.ELSEIF 
	    mov pt4[2*8].x,100		; if its false its a 5-minute mark (larger circle) 
	    mov pt4[2*8].y,100	 
	.ENDIF 
 
	mov	eax,pt4[2*8].x 
	shr	eax,1			; (pt[2].x)/2 
	sub	pt4[0].x,eax 
	 
	mov	eax,pt4[2*8].y 
	shr	eax,1			; (pt[2].y)/2 
	sub	pt4[0].y,eax 
 
	mov	eax,pt4[0].x 
	add	eax,pt4[2*8].x 
	mov	pt4[1*8].x,eax 
 
	mov	eax,pt4[0].y 
	add	eax,pt4[2*8].y 
	mov	pt4[1*8].y,eax 
 
	invoke	GetStockObject, BLACK_BRUSH 
	invoke  SelectObject, hdc, eax 
 
	invoke Ellipse, hdc, pt4[0].x, pt4[0].y, pt4[1*8].x, pt4[1*8].y	 
 
	add	iAngle,6 
 
	.ENDW	 
 
	ret 
DrawClock endp   
 
			 
DrawHands proc	hdc:HDC, pst:DWORD, Change:BOOL	; pst points @ current or previous TIME data 
 
LOCAL iAngle[3]:DWORD, ptTemp[15]:POINT	; Provide space for copy of polyline points  
 
;	This routine is entered twice, once to erase the old hand position and then 
;	a second time it uses the new time data to update the hand positions.    
  
;	Convert time data (hour, min and sec) into angles for the three hands 
 		 
	mov	ebx,pst			; Get address of current or previous SYSTEMTIME 
 
	mov	ax,[ebx+8]		; Get hours 
	mov	edx,0 
	mov	cx,30			; Scaling factor for 360 degrees 
	mul	cx 
	mov	cx,360 
	div	cx			; mod 360 divide; get hours-remainder in edx 
	mov	cx,[ebx+10]		; Get minute value 
	shr	cx,1			; 
	add	dx,cx			; Add on angle for fractional part of the hour 
	mov	iAngle[0],edx		; Now have hour-hand angle 
 
	mov	ax,[ebx+10]		; Get minutes again 
	mov	edx,0 
	mov	cx,6			; Scale factor for minute-hand angle 
	mul	cx 
	mov	iAngle[4],eax		; Got minute-hand angle 
 
	mov	ax,[ebx+12]		; Get seconds 
	mov	edx,0 
	mov	cx,6			; Scale factor for second-hand angle 
	mul	cx 
	mov	iAngle[8],eax		; Got second-hand angle	 
 
;	Copy polyline data to temp storage 
 
	mov	esi,offset pt		; es and ds point to same segment  
	lea	edi,ptTemp 
	mov	ecx,sizeof pt 
	cld 
	rep	movsb			; Copy polyline points to ptTemp 
 
	.IF Change 
	mov     esi,0			; If hour or minute hands have changed position 
	mov	ebx,0 
	.ELSE 
	mov     esi,2*4			; If second hand only has changed  
	mov	ebx,2*40  
	.ENDIF 
 
.WHILE  ebx < 3*40 
 
	mov	edi,0			; Index to point 
 
    .WHILE      edi < 40		; Loop for all points in the structure 
 
	push	edi 
	add	edi,ebx			; Add offset for the appropriate hand			 
 
	fild	iAngle[esi]		; Load data into the rotate parameter block				 
	fstp	theta			; 
	fild	ptTemp[edi].x		; 
	fstp	math_X_Coord		; 
	fild	ptTemp[edi].y		; 
	fstp	math_Y_Coord		; 
 
	push	esi 
	mov	esi,offset theta	; Point at parameter block 
 
	call   rotate			; Rotate the point 
	pop	esi 
 
	fld	New_X1			; Get new X coord 
	fistp	ptTemp[edi].x		; Store in hands structure 
 
	fld	New_Y1			; Ditto for Y coord 
	fistp	ptTemp[edi].y		; 
  
	pop	edi 
	add	edi,8 
 
    .ENDW 
 
	invoke Polyline, hdc,ADDR ptTemp[ebx],5 ; Draw the hand 
  
	add	ebx,40				; Inc to next hand 
	add	esi,4				; Inc index for angle of next hand 
 
.ENDW 
	 
	ret 
DrawHands endp 
 
 
WndProc proc uses ebx esi edi, hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM 
 
        LOCAL  hdc:HDC, ps:PAINTSTRUCT  
	  		 
	mov    eax,uMsg 
 
	.IF	eax==WM_CREATE 
 
	  finit				; Initialise the coprocessor 
	 
	  invoke   SetTimer, hWnd, ID_TIMER, 1000, NULL	; 
	  invoke   GetLocalTime, ADDR stCurrent 
 
	.ELSEIF eax==WM_SIZE		; lParam gives new window size  
 
	  LOWORD	lParam		; Get low word from lParam in eax 
	  mov	cxClient,eax 
	  shr	eax,1 
	  mov	cxC_over2,eax		; cxClient/2 
 
	  HIWORD	lParam		; Get high "	"	"     ebx 
	  mov	cyClient,ebx 
	  shr	ebx,1 
	  mov	cyC_over2,ebx		; cyClient/2 
 
	.ELSEIF eax==WM_TIMER 
 
	  invoke GetLocalTime, ADDR stCurrent 
 
	  mov	cx,stCurrent.wHour 
	  mov	dx,stCurrent.wMinute 
 
	  .IF     cx != stPrevious.wHour 
	     mov  fChange, TRUE 
	  .ELSEIF dx != stPrevious.wMinute 
	     mov  fChange, TRUE 
	  .ELSE 
	     mov  fChange, FALSE 
	  .ENDIF 
 
	  invoke GetDC, hWnd 
	  mov	hdc,eax 
 
	  invoke SetIsotropic, hdc 
 
	  invoke GetStockObject, WHITE_PEN		; Erase hands 
	  invoke SelectObject, hdc, eax  
	  invoke DrawHands, hdc, ADDR stPrevious, fChange 
 
	  invoke GetStockObject, BLACK_PEN		; Draw hands at new position 
	  invoke SelectObject, hdc, eax  
	  invoke DrawHands, hdc, ADDR stCurrent, TRUE 
 
	  invoke ReleaseDC, hWnd, hdc 
 
	  mov	ax,stCurrent.wHour		; Save the current time 
	  mov	stPrevious.wHour,ax		; 
	  mov	ax,stCurrent.wMinute		; 
	  mov	stPrevious.wMinute,ax		; 
	  mov	ax,stCurrent.wSecond		; 
	  mov	stPrevious.wSecond,ax		; 
 
        .ELSEIF eax==WM_PAINT 
 
          invoke  BeginPaint, hWnd, ADDR ps 
 
          mov	hdc,eax	 			; Get handle to device context 
  
	  invoke  SetIsotropic, hdc 
 
	  invoke  DrawClock, hdc		; Draw the dial 
 
          invoke  EndPaint, hWnd, ADDR ps 
 
	.ELSEIF eax==WM_DESTROY 
 
          invoke  KillTimer, hWnd, ID_TIMER 
          invoke  PostQuitMessage,NULL 
 
        .ELSE 
 
            invoke  DefWindowProc, hWnd, uMsg, wParam, lParam 
            ret 
 
	.ENDIF 
        xor    eax,eax 
	ret 
 
WndProc endp 
 
;---------------------------------------------------------------; 
; This routine finds new values for cartesian coordinates X & Y	; 
; when the point is rotated by theta degrees			; 
;								; 
; Enter: DS:SI points at a data block in the calling routine	; 
;								; 
;	  [si] (real4) contains the rotation angle in degrees	; 
;	[si+4] (real4) contains the math X coordinate		; 
;	[si+8] (real4) contains the math Y coordinate		;     	    
;	[si+12](real4) will contain the new X coordinate	; 
;	[si+16](real4) will contain the new Y coordinate	; 
;								; 
; Note: I keep the orignal coords (as opposed to updating	; 
;	so that a program can reuse the same values if required	; 
;								; 		  														; 
;	X1 =  X * cos(theta)  +  Y * sin(theta) 		; 
;	Y1 = -X * sin(theta)  +  Y * cos(theta)			; 
; 								; 
; Return:  New coords are updated in callers parameter block.	;   
;---------------------------------------------------------------; 
 
.DATA 
deg2rad		real4	1.7453292E-2	; 2 * pi / 360 (conversion factor for radians) 
 
.CODE 
 
angle	equ	dword ptr [esi] 
X_Coord	equ 	dword ptr [esi+4] 
Y_Coord	equ	dword ptr [esi+8] 
New_X	equ	dword ptr [esi+12] 
New_Y	equ	dword ptr [esi+16]   
 
rotate	PROC	  
 
	fld	angle			; Put the rotation in degrees into st(0) 
 
	fmul	deg2rad			; st=radians 
	fsincos				; st=cos,   st(1)=sin 
 
	fld	st			; st=cos,   st(1)=cos, st(2)=sin 
 
	fmul	X_Coord			; st=X*cos, st(1)=cos, st(2)=sin 
 
	fxch				; st=cos,   st(1)=X*cos, st(2)=sin 
	fmul	Y_Coord			; st=Y*cos, st(1)=X*cos, st(2)=sin 
 
	fxch	st(2)			; st=sin,   st(1)=X*cos, st(2)=Y*cos 
 
	fld	st			; st=sin, st1=sin, st2=X*cos, st3=Y*cos					;now X, X, Y*sin, Y*cos, cos, sin	 
 
	fmul	X_Coord			; X*sin, sin,   X*cos, Y*cos 
 
	fxch				; sin,   X*sin, X*cos, Y*cos 
	fmul	Y_Coord			; Y*sin, X*sin, X*cos, Y*cos 
	fadd	st,st(2)		; Y*sin + X*cos, X*sin, X*cos, Y*cos 
 
	fstp	New_X			; X*sin, X*cos, Y*cos ; Stored new X coord 
  
	fxch	st(1)			; X*cos, X*sin, Y*cos 
	fstp	st			; X*sin, Y*cos   
	fsub				; -X*sin +Y*cos 
 
	fstp	New_Y			; Stored new Y coord 
	 
	RET 
 
rotate	ENDP 
 
        end start