Національний університет «Львівська Політехніка»
Лабораторна робота №4
Робота з методами DirectDraw.
Львів 2011
Тема ( Робота з методами DirectDraw.
Мета ( Зрозуміти принципи та навчитись використовувати методи DirectDraw.
ТЕОРЕТИЧНІ ПОЛОЖЕННЯ
Для роботи з графікою існує обширний набір функцій GDI (Graphics Device Interface) – інтерфейс графічного пристрою. Ці функції універсальні як для малювання як на екрані, так і на принтері, але платою за універсальність є швидкодія. Створити більш-менш динамічну графічну програму з використанням лише GDI-функцій (наприклад, SetPixel) практично неможливо. На допомогу приходять методи прямого запису даних у відео-пам’ять, які дають максимальну швидкодію.
Методи DirectDraw включаються в концепцію DirextX, який включає в себе також методи DirectSound та Direct3D, які постійно поновлюються. Саме тому компанія Microsoft вирішила, що зручніше поновлювати таблицю віртуальних методів, ніж кожний раз створювати нові API-функції для нових версій методів, і реалізувала їх як звичайні методи абстрактних COM-об’єктів.
Для створення екземпляру об’єкту DirectDraw можна використовувати звичайний механізм створення COM-об’єктів за допомогою API-функції CoCreateInstance, яку ви використовували в лабораторній роботі №1. Після створення його необхідно ініциалізувати методом ініціалізації (див. таблицю 5), але цього можна не робити, якщо використовувати спеціалізовану API-функцію DirectDrawCreate. Параметрами цієї функції є ідентифікатор версії (або 0 ( для поточної версії), адреса змінної, яка буде містити вказівник на об’єкт після виконання функції, а також зарезервований параметр (що дорівнює 0).
Особливістю використання об’єкту DirectDraw є те, що він вимагає наявність вікна. Вікно можна створити з довільними параметрами, навіть не видимим. Виконання функції DirectDrawCreate необхідно робити тоді, коли вікно вже створене, тобто у віконній процедурі при обробці повідомлення WM_CREATE. Одразу ж після створення об’єкту DirectDraw необхідно викликати його 20-й метод “SetCooperativeLevel” (таблиця 5), який встановить ексклюзивні права на область відео-пам’яті, яку ви використовуєте та зарезервує повноекранний відео-буфер, який електронними засобами відео-карти буде відображатись на екрані монітору. Після цього необхідно переключити відео-карту у потрібний відео-режим за допомогою 21-го методу “SetDisplayMode”. В параметрах цього метода необхідно вказати ширину та висоту екрану в пікселях, а також кількість біт на один піксель.
Таблиця 5
№
Адр.
Назва методу
параметри
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
18
19
20
21
22
00
04
08
0c
10
14
18
1c
20
24
28
2c
30
34
38
3c
40
44
48
4c
50
54
58
QueryInterface
AddRef 
Release
Compact
CreateClipper
CreatePalette
CreateSurface
DuplicateSurface
EnumDisplayModes
EnumSurfaces
FlipToGDISurface
GetCaps
GetDisplayMode
GetFourCCCodes
GetGDISurface
GetMonitorFrequency
GetScanLine
GetVerticalBlankStatus
Initialize
RestoreDisplayMode
SetCooperativeLevel
SetDisplayMode
WaitForVerticalBlank
riid, LPVOID  ppvObj
LPDIRECTDRAWCLIPPER FAR*, Iunknown
LPPALET, LPDIRECTDRAWPAL, IUnknown
LPDDSURF, LPDIRECTDRAWSURF, IUnknown
LPDIRECTDRAWSURF, LPDIRECTDRAWSURF
LPDDSURF, LPVOID, LPDDENUMMODCALLBACK
LPDDSURF,LPVOID,LPDDENUMSURFACESCALLB
LPDDCAPS;
LPDWORD
*
*
*
LPBOOL 
GUID
HWND, DWORD
DWORD, DWORD,DWORD
DWORD, HANDLE
Після того, як відео-карта переключена у відповідний режим, можна створити об’єкт Surface, методи якого показані в таблиці 6. Для створення цього об’єкту використовуємо 7-й метод DirectDraw: “CreateSurface” (таблиця 5). Результатом цього методу буде вказівник LPS на новий об’єкт Surface, який представляє видиму відео-сторінку, і методи якого представлені в таблиці 6 (див. програму далі). Одним з параметрів цього метода є вказівник на структуру DDSURFACEDESC2, в якій буде записана адреса відео-сторінки (lpSurface), в яку можна буде записати відео-дані.
Для роботи з іншою відео-сторінкою, яка в даний момент не видима необхідно отримати іншу таблицю віртуальних методів за допомогою метода “GetAttachedSurface” об’єкта LPS (таблиця 6, див. програму далі). В результаті виконання цього методу отримуємо вказівник DDBACK на таблицю віртуальних методів для роботи з невидимою відео-сторінкою. Тепер утворені всі необхідні компоненти DirectDraw і можна приступати до малювання.
Таблиця 6
№
Адр.
Назва методу
параметри
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
00
04
08
0c
10
14
18
1c
20
24
28
2c
30
34
38
3c
40
44
48
4c
50
54
58
5c
60
64
68
6c
70
74
78
7c
80
84
88
8c
QueryInterface
AddRef
Release
AddAttachedSurface
AddOverlayDirtyRect
Blt
BltBatch
BltFast
DeleteAttachedSurface
EnumAttachedSurfaces
EnumOverlayZOrders
Flip
GetAttachedSurface
GetBltStatus
GetCaps
GetClipper
GetColorKey
GetDC
GetFlipStatus
GetOverlayPosition
GetPalette
GetPixelFormat
GetSurfaceDesc
Initialize
IsLost
Lock
ReleaseDC
Restore
SetClipper
SetColorKey
SetOverlayPosition
SetPalette
Unlock
UpdateOverlay
UpdateOverlayDisplay
UpdateOverlayZOrder
REFIID riid, LPVOID ppvObj
LPDIRECTDRAWSURFACE
LPRECT
LPRECT,LPDIRECT, LPRECT,DWRD, LPDDBLT
LPDDBLTBATCH, DWORD, DWORD
DWORD,DWORD,LPDIRECT, LPRECT,DWORD
DWORD,LPDIRECTDRAWSURFACE) PURE
LPVOID,LPDDENUMSURFACESCALLBACK
DWORD,LPVOID,LPDDENUMSCALLBACK
LPDIRECTDRAWSURFACE, DWORD
LPDDSCAPS, LPDIRECTDRAWSURFACE
DWORD
LPDDSCAPS
PURE,LPDIRECTDRAWCLIPPER FAR 
DWORD, LPDDCOLORKEY
HDC
DWORD
LPLONG, LPLONG 
LPDIRECTDRAWPALETTE FAR
LPDDPIXELFORMAT
LPDDSURFACEDESC
LPDIRECTDRAW, LPDDSURFACEDESC
LPRECT,LPDDSURFACEDESC,DWORD,HANDLE
HDC
LPDIRECTDRAWCLIPPER
DWORD, LPDDCOLORKEY
LONG, LONG 
LPDIRECTDRAWPALETTE
LPVOID
LPRECT, LPDIR,LPRECT,DWD, LPDDOVERLAX
DWORD
DWORD, LPDIRECTDRAWSURFACE
Для малювання в програмі необхідно створити таймер, і при надходженні у віконну процедуру повідомлення WM_TIMER необхідно переключити відео-сторінки. Таким чином можна досягти плавності малювання об’єктів, які рухаються, тому що коли на екрані зображена одна відео-сторінка, процес виводу змінює відео-дані іншої сторінки, яка в даний момент не видима.
Для запису у відео-сторінку необхідно, щоб вона була фізично присутня в пам’яті, тому перед записом необхідно застосувати метод Lock з таблиці віртуальних методів об’єкту DDBACK невидимої відео-сторінки. Ця таблиця має таку ж саму структуру, як і таблиця 6, але всі методи відносяться до невидимої відео-сторінки.
В результаті виконання 26-го метода “Lock” змінна lpSurface буде містити початок невидимої відео-сторінки, яку використовує процедура малювання. Після закінчення малювання використовується 12-й метод “Flip” з таблиці віртуальних методів для видимої відео-сторінки LPS. Метод “Flip” фактично міняє місцями відео-сторінки на екрані монітору, але вказівники LPS і DDBACK як і раніше містять адреси методів для роботи з видимою і невидимою відео-сторінками. Після малювання бажано розблокувати відео-сторінку методом “Unlock” (№33 у таблиці 6).
.486
.model flat, stdcall
extrn CreateWindowExA:Proc, RegisterClassA:Proc, GetMessageA:Proc
extrn DispatchMessageA:Proc, DefWindowProcA:Proc, MessageBoxA:Proc
extrn DirectDrawCreate:Proc, SetTimer:Proc, ShowCursor:Proc, TextOutA:Proc
extrn lstrlen:Proc, SetBkMode:Proc, ExitProcess:Proc
	      INCLUDELIB DDraw.LIB
	SetCooperativeLevel		equ  50h
	SetDisplayMode		equ  54h
	CreateSurface			equ  18h
	Surface_Lock			equ  64h
	Surface_Unlock		equ  80h
	Surface_Restore		equ  6Ch
	Surface_GetDC		equ  44h
	Surface_ReleaseDC		equ  68h
	GetAttachedSurface		equ  30h
	Surface_Flip			equ  2Ch
WM_CREATE               equ 1h
WM_KEYDOWN		equ 100h
WM_TIMER                equ 113h
WS_POPUP                equ 80000000h
DDSD_CAPS		equ  000001h
DDSD_PITCH		equ  000008h
DDSD_BACKBUFFERCOUNT	equ  000020h
DDSCAPS_PRIMARYSURFACE	equ 200h
DDSCAPS_FRONTBUFFER	equ 20h
DDSCAPS_BACKBUFFER	equ 04h
DDSCAPS_FLIP		equ 10h
DDSCAPS_COMPLEX		equ 08h
DDLOCK_WAIT		equ 1
DDFLIP_WAIT			equ 1
DDSCL_FULLSCREEN	equ  1h
DDSCL_EXCLUSIVE		equ  10h
;=======================================================
.data
wc:  dd 0, offset WndProc, 7 dup(0), offset WndClassName
msg:
    msHWND	dd 0
    msMESSAGE	dd 0
    msWPARAM	dd 0
    msLPARAM	dd 0
    msTIME	dd 0
    ptX		dd 0
    ptY		dd 0
NewHWnd         dd 0
WndClassName    db "DeepPurple",0
TEXT1		db " Приклад DirectDraw ",0
SCREEN_WIDTH	dd 800
SCREEN_HEIGHT	dd 600
SCREEN_BPP	dd 16
LPDD	dd 0	; ddraw interface pointer
LPS	dd 0
DDBACK	dd 0
DDSURFACEDESC2:
 dd 108,DDSD_CAPS or DDSD_BACKBUFFERCOUNT,0,0
 lPitch			dd 0
 dwBackBufferCount	dd 1,0,0,0
 lpSurface		dd 0,16 dup(0) ; вказівник на відео-сторінку
 ddsCaps		dd DDSCAPS_PRIMARYSURFACE or DDSCAPS_COMPLEX or DDSCAPS_FLIP
 dwTextureStage	dd 0
BEGIN_COLOR	dd 00
HDC		dd 0
X	dd 0
Y	dd 0
HV	dd 1
VV	DD 1
R		db 0
G	db 0
B		db 0
;======================================================
.code
Start:	call    RegisterClassA,offset wc
        call    CreateWindowExA,0,eax,0,WS_POPUP,1,1,1,1,0,0,0,0
        mov     NewHWnd,eax
	call	ShowCursor,0
	call	SetTimer,NewHWnd,0,20,offset WndProc
;===================================================
msg_loop:  call    GetMessageA,offset msg,NewHWnd,0,0
        cmp     eax,-1
        jz      STOP
	cmp     msMESSAGE,WM_KEYDOWN
	jnz	CONTINUE_LOOP
	cmp	msWPARAM,1bh
	jz      STOP
  CONTINUE_LOOP:
        call    DispatchMessageA,offset msg
        jmp     msg_loop
STOP:	call ExitProcess,0
;=====================================================
WndProc          proc  hwnd:DWORD, wmsg:DWORD, wparam:DWORD, lparam:DWORD
	cmp wmsg,WM_CREATE	; Створення об’єктів DirectDraw та Surface
	jnz TIMER
	call	DirectDrawCreate, 0, offset LPDD, 0
	mov	eax,LPDD
	mov	eax, [eax]
	call	[eax+SetCooperativeLevel],LPDD, hwnd, DDSCL_EXCLUSIVE OR DDSCL_FULLSCREEN  
	mov	eax,LPDD
	mov	eax, [eax]
	call	[eax+SetDisplayMode],LPDD, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP
	mov     eax, LPDD
	mov     eax, [eax]
	call    dword ptr [eax+CreateSurface],LPDD, offset DDSURFACEDESC2, offset LPS,0
	or eax,eax
	jnz STOP
	mov	ddsCaps,DDSCAPS_BACKBUFFER
	mov	eax,LPS
	mov	eax, [eax]
	call	dword ptr [eax+GetAttachedSurface],LPS, offset ddsCaps, offset DDBACK
	or eax,eax
	jnz STOP
;---------------------------------------------------------------------------------------------------
TIMER:	cmp	wmsg,WM_TIMER
	jnz	EXIT1				; Обробка подій від таймеру
	mov	eax,DDBACK
	mov	eax, [eax]
	call	dword ptr [eax+Surface_Lock], DDBACK, 0, offset DDSURFACEDESC2, DDLOCK_WAIT, 0
	or	eax,eax
	jnz	NO_PAINT
	call PAINT	; Ваша процедура малювання
	mov     eax,LPS
	mov     eax, [eax]
	call    [eax+Surface_Flip],LPS,0,0
NO_PAINT:
EXIT1:	call    DefWindowProcA, hwnd, wmsg, wparam, lparam
        ret
WndProc          endp
;=====================================================
PAINT: pushad
	cld
	mov eax,BEGIN_COLOR
	and eax,0ffffffh
	mov edx,SCREEN_HEIGHT
	mov ebx,lpSurface	; початок відео-сторінки
L_BLT:	mov edi,ebx
	mov ecx,SCREEN_WIDTH
	add eax,10001h
	push eax
	call CONVERT_to_RGB16
	not ax
	repnz stosw		; Прямий запис у відео-пам’ять
	pop eax
	add ebx,lPitch		; Перехід на новий рядок
	dec edx
jnz L_BLT
	popad
	mov     eax,DDBACK
	mov     eax, [eax]
	call    [eax+Surface_Unlock],DDBACK,0
	mov     eax,DDBACK
	mov     eax, [eax]
	call    [eax+Surface_GetDC],DDBACK,offset HDC
	call	SetBkMode,HDC,1
	call	lstrlen,offset TEXT1
	call	TextOutA,HDC,X,Y,offset TEXT1,eax
	mov     eax,DDBACK
	mov     eax, [eax]
	call    [eax+Surface_ReleaseDC],DDBACK,HDC
	mov	eax,HV
	add	X,eax
	mov	eax,VV
	add	Y,eax
	cmp	X,700
	jb	M1
	neg	HV
 M1:	cmp	Y,590
	jb	M2
	neg	VV
 M2:
	add BEGIN_COLOR,010305h
ret
;---------------------------------- Процедура для перетворення EAX у 16-бітний колір
CONVERT_to_RGB16:
	mov B,al
	mov G,ah
	shr eax,16
	mov R,al
	shr R,3			; 5 біт = 8-3 на червону компоненту
	shr G,2		; 6 біт = 8-2 на зелену компоненту
	shr B,3			; 5 біт = 8-3 на синю компоненту
	xor eax,eax
	mov al,R
	shl ax,6
	or al,G
	shl ax,5
	or al,B
ret
end Start
Для застосування до відео-сторінки функцій GDI (наприклад, вивід тексту) необхідно застосувати 18-й метод “GetDC” з таблиці віртуальних методів відповідної відео-сторінки. Після закінчення використання функцій GDI в даній відео-сторінці необхідно викликати 27-й метод “ReleaseDC”.
ПОРЯДОК ВИКОНАННЯ РОБОТИ
Створити файл DDraw.LIB з файлу DDraw.DLL за допомогою програми H:\tasm\bin\implib.exe. Для цього треба скопіювати вказані файли в свій каталог і запустити команду: IMPLIB.EXE DDraw.LIB DDraw.DLL
Запустити програму та проглянути послідовність методів, що викликаються.
Змінити текст, який виводиться в програмі на своє прізвище.
Змінити шрифт вказаного надпису так, як було описано у файлі SYS_DD3.doc.
Намалювати на екрані прямокутник шляхом прямого запису в пам’ять.
Приклад Реалізації програми
Висновок:
    Для створення цьго малюнка, я використав методи Direct Draw. Рух здійснюється за допомогою збільшення координат позиції фігури.