Этот раздел главы посвящается графике
Этот раздел главы посвящается графике. Впрочем, основы графики в Windows в принципе достаточно тривиальны, поэтому мы рассмотрим один простой пример - на вывод графических образов. Но в начале я изложу некоторые опорные моменты:
1. Система координат для вывода графических образов такая же, как и для ввода текстовой информации. Координаты измеряются в логических единицах, которые по умолчанию совпадают с пикселями. При желании эту пропорцию можно изменить.
2. Цвет рисования образуется тремя способами. При использовании функции SetPixel задается цвет данной точки. Для линий необходимо задать цвет пера. Для задания цвета замкнутых графических объектов следует задать цвет кисти.
3. Перо создается при помощи функции CreatePen, кисть - при помощи CreateSolidBrush (мы ее уже использовали). Для создания разноцветной картинки можно заранее создать несколько кистей и перьев, а затем в нужный момент выбирать при помощи функции SelectObject (мы также уже использовали эту функцию).
4. Для рисования можно использовать следующие функции API:
5. Если при рисовании замкнутой фигуры был установлен цвет кисти, отличный от цвета основного фона, то замкнутая фигура окрашивается этим цветом.
6. Для установки соотношения между логическими единицами и пикселями используется функция SetMapMode.
7. Можно установить область вывода при помощи функции SetViewportExtEx. С помощью функции SetViewportOrgEx можно задать начало области ввода.
После всего сказанного пора продемонстрировать программу. Программа достаточно проста, но в ней заложены основы работы с графикой. По щелчку левой кнопки мыши сначала появляется горизонтальная линия, по второму щелчку - наклонная линия, по третьему щелчку - заполненный прямоугольник. Программа показана на Рисунок 2.1.6, результат ее работы - на Рисунок 2.1.7.
; файл graph1.inc ; константы ; сообщение приходит при закрытии окна WM_DESTROY equ 2 ; сообщение приходит при создании окна WM_CREATE equ 1 ; сообщение при щелчке левой кнопкой мыши в области окна WM_LBUTTONDOWN equ 201h ; сообщение приходит при перерисовке окна WM_PAINT equ 0FH ; свойства окна CS_VREDRAW equ 1h CS_HREDRAW equ 2h CS_GLOBALCLASS equ 4000h WS_OVERLAPPEDWINDOW equ 000CF0000H stylcl equ CS_HREDRAW + CS_VREDRAW + CS_GLOBALCLASS DX0 equ 600 DY0 equ 400 ; компоненты цветов RGBW equ (50 or (50 shl 8)) or (255 shl 16) ; цвет окна RGBR equ 150 ; цвет региона RGBL equ 0 ; цвет линии RGBP equ 255 or (100 shl 8) ; цвет точки ; идентификатор стандартной иконки IDI_APPLICATION equ 32512 ; идентификатор курсора IDC_CROSS equ 32515 ; режим показа окна - нормальный SW_SHOWNORMAL equ 1 ; прототипы внешних процедур EXTERN CreateWindowExA@48:NEAR EXTERN DefWindowProcA@16:NEAR EXTERN DispatchMessageA@4:NEAR EXTERN ExitProcess@4:NEAR EXTERN GetMessageA@16:NEAR EXTERN GetModuleHandleA@4:NEAR EXTERN LoadCursorA@8:NEAR EXTERN LoadIconA@8:NEAR EXTERN PostQuitMessage@4:NEAR EXTERN RegisterClassA@4:NEAR EXTERN ShowWindow@8:NEAR EXTERN TranslateMessage@4:NEAR EXTERN UpdateWindow@4:NEAR EXTERN BeginPaint@8:NEAR EXTERN EndPaint@8:NEAR EXTERN GetStockObject@4:NEAR EXTERN CreateSolidBrush@4:NEAR EXTERN GetSystemMetrics@4:NEAR EXTERN GetDC@4:NEAR EXTERN CreateCompatibleDC@4:NEAR EXTERN SelectObject@8:NEAR EXTERN CreateCompatibleBitmap@12:NEAR EXTERN PatBlt@24:NEAR EXTERN BitBlt@36:NEAR EXTERN ReleaseDC@8:NEAR EXTERN DeleteObject@4:NEAR EXTERN InvalidateRect@12:NEAR EXTERN GetStockObject@4:NEAR EXTERN DeleteDC@4:NEAR EXTERN CreatePen@12:NEAR EXTERN SetPixel@16:NEAR EXTERN LineTo@12:NEAR EXTERN MoveToEx@16:NEAR EXTERN Rectangle@20:NEAR
; структуры ; структура сообщения MSGSTRUCT STRUC MSHWND DD ? ; идентификатор окна, получающего сообщение MSMESSAGE DD ? ; идентификатор сообщения MSWPARAM DD ? ; доп. информация о сообщении MSLPARAM DD ? ; доп. информация о сообщении MSTIME DD ? ; время посылки сообщения MSPT DD ? ; положение курсора во время ; посылки сообщения MSGSTRUCT ENDS
WNDCLASS STRUC CLSSTYLE DD ? ; стиль окна CLSLPFNWNDPROC DD ? ; указатель на процедуру окна CLSCBCLSEXTRA DD ? ; информация о доп. байтах для ; данной структуры
CLSCBWNDEXTRA DD ? ; информация о доп. байтах для окна CLSHINSTANCE DD ? ; дескриптор приложения CLSHICON DD ? ; идентификатор иконы окна CLSHCURSOR DD ? ; идентификатор курсора окна CLSHBRBACKGROUND DD ? ; идентификатор кисти окна MENNAME DD ? ; имя-идентификатор меню CLSNAME DD ? ; специфицирует имя класса окон WNDCLASS ENDS
PAINTSTR STRUC hdc DD 0 fErase DD 0 left DD 0 top DD 0 right DD 0 bottom DD 0 fRes DD 0 fIncUp DD 0 Reserv DB 32 dup(0) PAINTSTR ENDS
RECT STRUC L DD ? ; Х-левого верхнего угла T DD ? ; Y-левого верхнего угла R DD ? ; Х- правого нижнего угла B DD ? ; Y- правого нижнего угла RECT ENDS
; файл graph.asm .386P ; плоская модель .MODEL FLAT, stdcall ;------------------------------------------------------------------ include graph1.inc ; подключения библиотек includelib c:\masm32\iib\user32.lib includelib c:\masm32\lib\kernel32.lib includelib c:\masm32\lib\gdi32.lib ;------------------------------------------------------------------ ; сегмент данных _DATA SEGMENT DWORD PUBLIC USE32 'DATA' NEWHWND DWORD 0 MSG MSGSTRUCT <?> WC WNDCLASS <?> PNT PAINTSTR <?> HINST DWORD 0 TITLENAME BYTE 'Графика в окне',0 NAM BYTE 'CLASS32',0 XT DWORD 30 YT DWORD 30 XM DWORD ? YM DWORD ? HDC DWORD ? MEMDC DWORD ? HPEN DWORD ? HBRUSH DWORD ? P DWORD 0 ; признак вывода XP DWORD ? YP DWORD ? _DATA ENDS
; сегмент кода _TEXT SEGMENT DWORD PUBLIC USE32 'CODE' START: ; получить дескриптор приложения PUSH 0 CALL GetModuleHandleA@4 MOV [HINST], EAX REG_CLASS: ; заполнить структуру окна ; стиль MOV [WC.CLSSTYLE],stylcl ; процедура обработки сообщений MOV [WC.CLSLPFNWNDPROC], OFFSET WNDPROC MOV [WC.CLSCBCLSEXTRA],0 MOV [WC.CLSCBWNDEXTRA], 0 MOV EAX, [HINST] MOV [WC.CLSHINSTANCE], EAX ; ----------иконка окна PUSH IDI_APPLICATION PUSH 0 CALL LoadIconA@8 MOV [WC.CLSHICON], EAX ; ----------курсор окна PUSH IDC_CROSS PUSH 0 CALL LoadCursorA@8 MOV [WC.CLSHCURSOR], EAX ;----------- PUSH RGBW ; цвет кисти CALL CreateSolidBrush@4 ; создать кисть MOV [WC.CLSHBRBACKGROUND], EAX MOV DWORD PTR [WC.MENNAME],0 MOV DWORD PTR [WC.CLSNAME], OFFSET NAM PUSH OFFSET WC CALL RegisterClassA@4 ; создать окно зарегистрированного класса PUSH 0 PUSH [HINST] PUSH 0 PUSH 0 PUSH DY0 ; DYO - высота окна PUSH DX0 ; DXO - ширина окна PUSH 100 ; координата Y PUSH 100 ; координата X PUSH WS_OVERLAPPEDWINDOW PUSH OFFSET TITLENAME ; имя окна PUSH OFFSET NAM ; имя класса PUSH 0 CALL CreateWindowExA@48 ; проверка на ошибку CMP EAX, 0 JZ _ERR MOV [NEWHWND], EAX ; дескриптор окна ;------------------------------------------------------------ PUSH SW_SHOWNORMAL PUSH [NEWHWND] CALL ShowWindow@8 ; показать созданное окно ;------------------------------------------------------------ PUSH [NEWHWND] CALL UpdateWindow@4 ; перерисовать видимую часть окна ; петля обработки сообщений MSG_LOOP: PUSH 0 PUSH 0 PUSH 0 PUSH OFFSET MSG CALL GetMessageA@16 CMP AX, 0 JE END_LOOP PUSH OFFSET MSG CALL TranslateMessage@4 PUSH OFFSET MSG CALL DispatchMessageA@4 JMP MSG_LOOP END_LOOP: ; выход из программы (закрыть процесс) PUSH [MSG.MSWPARAM] CALL ExitProcess@4 _ERR: JMP END_LOOP ;------------------------------------------------------------ ; процедура окна ; расположение параметров в стеке ; [EBP+014Н] ; LPARAM ; [EBP+10H] ; WAPARAM ; [EBP+0CH] ; MES ; [EBP+8] ; HWND WNDPROC PROC PUSH EBP MOV EBP,ESP PUSH EBX PUSH ESI PUSH EDI CMP DWORD PTR [EBP+0CH],WM_DESTROY JE WMDESTROY CMP DWORD PTR [EBP+0CH],WM_CREATE JE WMCREATE CMP DWORD PTR [EBP+0CH],WM_PAINT JE WMPAINT CMP DWORD PTR [EBP+0CH],WM_LBUTTONDOWN JE LBUTTON JMP DEFWNDPROC LBUTTON: CMP P,0 JNE F1 ; линия точками (горизонтальная) MOV YP,50 ; Y MOV XP,10 ; X MOV ECX,200 LL: PUSH ECX PUSH RGBP PUSH YP PUSH XP PUSH MEMDC CALL SetPixel@16 INC XP POP ECX LOOP LL INC P JMP F3 F1: CMP P,1 JNE F2 ; вначале установим текущие координаты на конец ; предыдущей линии PUSH 0 PUSH YP PUSH XP PUSH MEMDC CALL MoveToEx@16 ; линия пером PUSH 300 PUSH 550 PUSH MEMDC CALL LineTo@12 INC P JMP F3 F2: CMP P,2 JNE FIN ; замкнутая фигура - прямоугольник ; вначале выбрать кисть для заполнения области PUSH HBRUSH PUSH MEMDC CALL SelectObject@8 ; теперь рисуем заполненный прямоугольник если не выбирать ; кисть, то будет нарисован незаполненный прямоугольник PUSH 350 PUSH 400 PUSH 200 PUSH 200 PUSH MEMDC CALL Rectangle@20 INC P F3: ; дать команду перерисовать окно PUSH 0 PUSH OFFSET RECT PUSH DWORD PTR [EBP+08H] CALL InvalidateRect@12 FIN: MOV EAX, 0 JMP FINISH WMPAINT: PUSH OFFSET PNT PUSH DWORD PTR [EBP+08H] CALL BeginPaint@8 MOV HDC,EAX ; сохранить контекст (дескриптор) ; скопировать виртуальное окно на реальное PUSH 0CC0020h ; SRCCOPY=изображение как есть PUSH 0 ; у-источника PUSH 0 ; х-источника PUSH MEMDC ; контекст источника PUSH YM ; высота - куда PUSH XM ; ширина - куда PUSH 0 ; у - куда PUSH 0 ; х-куда PUSH HDC ; контекст - куда CALL BitBlt@36 ;---------------- закрыть контекст окна PUSH OFFSET PNT PUSH DWORD PTR [EBP+08H] CALL EndPaint@8 MOV EAX, 0 JMP FINISH WMCREATE: ; размеры экрана PUSH 0 ; X CALL GetSystemMetrics@4 MOV XM, EAX PUSH 1 ; Y CALL GetSystemMetrics@4 MOV YM, EAX ; открыть контекст окна PUSH DWORD PTR [EBP+08H] CALL GetDC@4 MOV HDC,EAX ; создать совместимый с данным окном контекст PUSH EAX CALL CreateCompatibleDC@4 MOV MEMDC, EAX ; создать в памяти растровое изображение, совместимое с hdc PUSH YM PUSH XM PUSH HDC CALL CreateCompatibleBitmap@12 ; выбрать растровое изображение в данном контексте PUSH EAX PUSH MEMDC CALL SelectObject@8 ; цвет кисти PUSH RGBW CALL CreateSolidBrush@4 ; создать кисть ; выбрать кисть в данном контексте PUSH EAX PUSH MEMDC CALL SelectObject@8 ; заполнить данную прямоугольную область PUSH 0F00021h ; РАТСОРУ=заполнить данным цветом PUSH YM PUSH XM PUSH 0 PUSH 0 PUSH MEMDC CALL PatBlt@24 ; создать кисть и перо для рисования ; цвет кисти PUSH RGBR CALL CreateSolidBrush@4 ; создать кисть MOV HBRUSH,EAX ; задать перо PUSH RGBR ; цвет PUSH 0 ; толщина=1 PUSH 0 ; сплошная линия CALL CreatePen@12 MOV HPEN, EAX ; удалить контекст PUSH HDC PUSH DWORD PTR [EBP+08H] CALL ReleaseDC@8 MOV EAX, 0 JMP FINISH DEFWNDPROC: PUSH DWORD PTR [EBP+14H] PUSH DWORD PTR [EBP+10H] PUSH DWORD PTR [EBP+0CH] PUSH DWORD PTR [EBP+08H] CALL DefWindowProcA@16 JMP FINISH WMDESTROY: ; удалить перо PUSH HPEN CALL DeleteDC@4 ; удалить кисть PUSH HBRUSH CALL DeleteDC@4 ; удалить виртуальное окно PUSH MEMDC CALL DeleteDC@4 ; выход PUSH 0 CALL PostQuitMessage@4 ; WM_QUIT MOV EAX, 0 FINISH: POP EDI POP ESI POP EBX POP EBP RET 16 WNDPROC ENDP _TEXT ENDS END START