Assembler - Просто и Эффективно. Глава #11 - Графика GDI
Assembler
Глава #11 - Графика.
Для отображения несложной графики используется GDI (graphics device interface). Особенности GDI - простота использования
и низкая скорость, что делает его пригодным, в основном, для создания нестандартных элементов интерфейса и приложений со
"слабой" графикой.
Для создания изображений часто применяются команды FPU и SIMD инструкции (MMX;XMM;3DNow!), поэтому изложенные материалы о
GDI будут использоваться в следующих главах для наглядного изучения дополнительных инструкций процессора.
-------------------------------
Общая информация.
Основное понятие GDI - это Device Context -DC. - Представляет из себя набор свойств среды рисования: изображение, используемые
шрифты, цвета и т.д.
Для того, чтобы добавить/заменить в DC какой-либо элемент, нужно создать его, а после использовать ф-цию SelectObject. Рисование
производится на объекте типа Bitmap.
Цвета, передаваемые функциям GDI - RGB: байт #0 определяет уровень красного цвета, #1 - зеленого, #2 - синего, и #3=0
С.м в MSDN: Graphics and Multimedia->Windows GDI
-------------------------------
Рисование в окнах
Чаще всего GDI используется для отображения графики в окне.
При необходимости обновить часть изображения окна, Windows добавляет этот регион в т.н Update Region и, позже, посылает сообщение
WM_PAINT. Обработчик сообщения обычно вызывает ф-цию BeginPaint, возвращающую хэндл DC клиент-части окна, с установленным
clipping region'ом равным update region'у. Т.е рисование будет происходить только в части окна, необходимой для обновления.
Это сделано для избежания мерцания при рисовании. Далее Update Region очищается и следующее сообщение WM_PAINT произойдет
только при следующей необходимости прорисовки изображения.
В случае надобности перерисовки всего клиент-содержимого окна кроме WM_PAINT посылается также WM_ERASEBKGND, а для обновления
не клиент-части - WM_NCPAINT.
Для добавления части/всего окна в update region используются ф-ции InvalidateRect/ InvalidateRgn. Автоматическое добавление
происходит при смене размера окна, удаления перекрытия другими окнами и т.д.
Можно получить DC окна функциями GetDC, GetWindowDC, и вывести изображение, но при появлении update region'а оно будет не
действительным. Эти ф-ции не влияют и не зависят от Update Region'а
Некоторые свойства GDI зависят от стиля окна, стиля класса, хэндла кисти фона класса. Для избежания мигания изображения кисть
фона обычно устанавливается в ноль при регистрации класса.
-------------------------------
Изображение в памяти.
Можно создать DC, существующее только в памяти и не отображаемое на экране - Memory DC, вызвав ф-цию CreateCompatibleDC.
Memory DC чаще всего используется для:
Избежания мерцания (Flicker) изображения при прорисовке.
Мерцание происходит если пользователь видит процесс создания изображения, при прорисовке перекрывающихся элементов т.к графика,
выводимая в DC окна, сразу же отображается. Для устранения мерцания можно использовать объекты типа Region, но чаще создается
DC в памяти, на котором происходит рисование, а по завершению процесса создания изображения производится копирование из Memory
DC в DC окна (обычно ф-цией BitBlt).
Объект Bitmap в таких случаях можно создать ф-цией CreateCompatibleBitmap
Рисование изображения для последующих манипуляций с данными изображения. В таком случае объект Bitmap обычно создается
ф-цией CreateDIBSection что позволяет иметь непосредственный досутп (чтение/запись) к массиву точек изображения. Ф-ции рисования
в DC также влияют на массив точек изображения в памяти. Такое изображение можно легко сохранить в .bmp файл, записав сначала
струкутру BITMAPFILEHEADER, за ней BITMAPINFOHEADER, далее палитру (если есть), и массив точек изображения (с выравниванием
строк на dword)
-------------------------------
Пример
Данная программа предназначена для определения цвета. Исходник по размеру несколько больше чем обычно, зато обладает некой
минимальной функциональностью.
Напоминаю, что примеры в рассылке приводятся для обучения, и для усвоения/ развития изложенных материалов. Желательно чтобы
вы изучали, модифицировали их, создавали на их основе тэстовые программы, тренируясь в использовании родственных ф-ций, не
описанных в статье.
.486
.model flat,stdcall
;используем inc и lib файлы из пакета masm32 (с.м главу #8)
include c:\masm32\include\windows.inc
include c:\masm32\include\kernel32.inc
includelib c:\masm32\lib\kernel32.lib
include c:\masm32\include\user32.inc
includelib c:\masm32\lib\user32.lib
include c:\masm32\include\gdi32.inc
includelib c:\masm32\lib\gdi32.lib
RightSpace=25
ImageX =256+RightSpace
BottomSpace = 35
ImageY=256+BottomSpace
.data
ProgramClassName db 'ColorPicker',0 ;класс основного окошка
WinTitle db 'Color Picker',0
ColorFormat db 'Color #%06lX',0
WndRect RECT<0,0,ImageX,ImageY> ;Client Rect окна
BitmapHeader BITMAPINFO <>
BlueLevel dd 0 ;Уровень синего
EdgeRect RECT <0,256,ImageX,ImageY>
WClass WNDCLASSEX
DCFont LOGFONT <>
MsgS MSG <>
MemDC dd ?
BitsPointer dd ?
.code
;Процедура для заполнения объекта-изображения цветами.
;использует BitsPointer,BlueLevel
;работает непосредственно с памятью объекта Bitmap
FillColorDC proc
pusha
mov edi,[BitsPointer]
add edi,ImageX*4*BottomSpace
mov eax,[BlueLevel]
xor edx,edx
cld
DrawColorLine:
stosd
add eax,100h
cmp ah,0
jnz DrawColorLine
mov ecx,RightSpace
xchg eax,ebx
mov eax,edx
cmp bl,dl
jnz NotCurrentBlueLevel
mov eax,0FFFFFFh
NotCurrentBlueLevel:
rep stosd
xchg eax,ebx
inc dl
jnz DrawColorLine
popa
ret
FillColorDC endp
;Процедура для отображения текущего цвета
; - прорисовки нижней части изображения
;Вход: eax - номер цвета
;использует: BitsPointer,MemDC
InitBottomColor proc
local ColorText [16]:byte
pusha
invoke wsprintf,addr ColorText,offset ColorFormat,eax
;заполним нижнюю часть Memory DC выбранным цветом,
; записывая данные непосредственно в память
mov eax,dword ptr [esp+1Ch] ;eax in stack
bswap eax
shr eax,8
mov edi,[BitsPointer]
mov ecx,BottomSpace*ImageX
cld
rep stosd
;прямоугольник выбранного цвета нарисован.
;нарисуем рамку, используя ф-цию GDI
invoke DrawEdge,[MemDC],offset EdgeRect,EDGE_SUNKEN,BF_RECT
;отобразим текст с номером цвета
invoke DrawText,[MemDC],addr ColorText,-1,offset EdgeRect,\
DT_CENTER or DT_VCENTER or DT_SINGLELINE
popa
ret
InitBottomColor endp
;Точка входа.
start:
;создадим Memory DC
invoke CreateCompatibleDC,0
mov MemDC,eax
;создадим объект Bitmap. Получим в BitsPointer адрес массива точек изображения
invoke CreateDIBSection,0,offset BitmapHeader,\
DIB_RGB_COLORS,offset BitsPointer,0,0
;добавим объект Bitmap в Memory DC
invoke SelectObject,[MemDC],eax
;установим цвет текста и фона текста в DC
invoke SetBkColor,[MemDC],0FF4040h
invoke SetTextColor,[MemDC],0FFFFFFh
;получим хэндл стандартного шрифта
invoke GetStockObject,DEFAULT_GUI_FONT
;получим структуру, описывающую объект - шрифт
invoke GetObject,eax,size LOGFONT,offset DCFont
;создадим шрифт нужного размера на основе системного
mov DCFont.lfHeight,BottomSpace-10
invoke CreateFontIndirect,offset DCFont
;добавим созданный шрифт в DC
invoke SelectObject,[MemDC],eax
;инициализируем Memory DC изначальным изображением
call FillColorDC
xor eax,eax
call InitBottomColor
;До MainWindowProc - стандартная часть
;зарегистрируем класс главного окна (см главу #7)
mov edi,offset WClass
assume edi:ptr WNDCLASSEX
invoke GetModuleHandle,0
mov [edi].hInstance,eax
invoke LoadIcon,0,IDI_APPLICATION
mov [edi].hIcon,eax
mov [edi].hIconSm,eax
invoke LoadCursor,0,IDC_ARROW
mov [edi].hCursor,eax
assume edi:nothing
invoke RegisterClassEx,edi
;определим размер основного окна, на основе необходимого Client Rect'а
MainWindowstyle="WS_CAPTION" or WS_DLGFRAME or WS_VISIBLE or WS_MINIMIZEBOX or WS_SYSMENU
invoke AdjustWindowRect,offset WndRect,MainWindowStyle,0
mov eax,WndRect.right
sub eax,WndRect.left
mov ecx,WndRect.bottom
sub ecx,WndRect.top
;создадим главное окно
invoke CreateWindowEx,0,offset ProgramClassName,offset WinTitle,\
MainWindowStyle,CW_USEDEFAULT,CW_USEDEFAULT,eax,ecx,\
0,0,[WClass.hInstance],0
MsgLoop:
invoke GetMessage,offset MsgS,0,0,0
inc eax
jz EndMsgLoop
dec eax
jz EndMsgLoop
invoke TranslateMessage,offset MsgS
invoke DispatchMessage,offset MsgS
jmp MsgLoop
EndMsgLoop:
invoke ExitProcess,0
MainWindowProc proc hwnd:dword,uMsg:dword,wParam:dword,lParam:dword
local ps:PAINTSTRUCT
cmp [uMsg],WM_PAINT
jnz NotWmPaint
;обработчик WM_PAINT
;просто копирует Memory DC в DC окошка.
invoke BeginPaint,[hwnd],addr ps
invoke BitBlt,eax,0,0,ImageX,ImageY,[MemDC],0,0,SRCCOPY
invoke EndPaint,[hwnd],addr ps
xor eax,eax
ret
NotWmPaint:
cmp [uMsg],WM_LBUTTONDOWN
jz CheckMouseEvent
cmp [uMsg],WM_MOUSEMOVE
jnz NotWmMouseMove
CheckMouseEvent:
cmp [wParam],MK_LBUTTON
jnz NotWmMouseMove
movzx eax,word ptr [lParam] ;mouse X
movzx ecx,word ptr [lParam+2] ;mouse Y
cmp ecx,255
ja CallDefProc
cmp eax,255
jbe NotBlueDrag
;пользователь изменил уровнь синего
not cl
mov [BlueLevel],ecx
call FillColorDC
;объявим всю клиент-площадь недействительной.
invoke InvalidateRect,[hwnd],0,0
jmp CallDefProc
NotBlueDrag:
;получим цвет точки под мышом
invoke GetPixel,[MemDC],eax,ecx
;обновим информацию о текущем цвете (что находится внизу Memory DC)
call InitBottomColor
;получим DC клиент-части окна
invoke GetDC,[hwnd]
;обновим только нижнюю часть окна (для большего быстродействия)
push eax
invoke BitBlt,eax,0,256,ImageX,BottomSpace,[MemDC],0,256,SRCCOPY
pop eax
invoke ReleaseDC,[hwnd],eax
jmp CallDefProc
NotWmMouseMove:
;стандартная часть процедуры обработки сообщений с.м главу #7.
cmp [uMsg],WM_DESTROY
jnz NotWmDestroy
invoke PostQuitMessage,0
xor eax,eax
ret
NotWmDestroy:
CallDefProc:
invoke DefWindowProc,[hwnd],[uMsg],[wParam],[lParam]
ret
MainWindowProc endp
end start
-------------------------------
Содержание дальнейших выпусков зависит от вас. Будут разъясняться те темы, которые непонятны большинству читателей.
Присылайте свои вопросы и предложения по адресу: asm32@nm.ru . -------------------------------
Автор рассылки Владимир Пронин. Любое коммерческое использование материалов рассылки без ведома и прямого согласия автора
запрещено.
Письма присланные автору рассылки могут быть опубликованы целиком или частично без предварительного уведомления. Если вы
не хотите, чтобы ваше письмо было опубликовано укажите это в начале письма.
Перепечатка материалов разрешена только с непосредственной ссылкой на asm32.nm.ru