📄 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -