НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ “ЛЬВІВСЬКА ПОЛІТЕХНІКА”
Лабораторна робота №1
з дисципліни “ Операційні системи ”
“Робота з методами DirectDraw ”
Bиконав:
студент групи КН – 20
Фединишин Ростислав
Лектор: Зербіно Д. Д.
Керівник лабораторних занять: Зербіно Д. Д.
Львів – 2012
Мета ( Зрозуміти принципи та навчитись використовувати методи 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).
Програмна реалізація:
Вміст файла DATA.txt:
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 "Fedynyshyn Rostyk",0
SCREEN_WIDTH dd 1024
SCREEN_HEIGHT dd 768
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
LOGFONTA:
lfHeight DD 50 ; Висота
lfWidth DD 20 ; Ширина
lfEscapement DD 3600 ; Кут нахилу * 10
lfOrientation DD 0 ;
lfWeight DD 1000 ; Жирнiсть (1000-Bold)
lfItalic DB 1 ; Курсив
lfUnderline DB 1 ; Пiдкреслення
lfStrikeOut DB 0
lfCharSet DB 1 ; 255 – шрифти DOS
lfOutPrecision DB 0
lfClipPrecision DB 0
lfQuality DB 1
lfPitchAndFamily DB 0
lfFaceName DB 'Algerian' ; Назва фонту
Reserv DB 32-6 dup(0)
HRedPen dd 0
OldPos dd 0,0
HGreenPen dd 0
HYELLPen dd 0
HBRUSHRED dd 0
HBRUSHGRAY dd 0
HBRUSHBLACK dd 0
HBRUSHYELL dd 0
HBLACKPen dd 0
HBRUSHGreen dd 0
HGOLDPen dd 0
HFont dd 0
Вміст файла MyPic.txt:
call SelectObject,HDC,HGOLDPen
call SelectObject,HDC,HBRUSHRED
Call Rectangle,HDC,40,430,160,375
call SelectObject,HDC,HGOLDPen
call SelectObject,HDC,HBRUSHGreen
Call Rectangle,HDC,39,420,25,428
Call Rectangle,HDC,49,375,70,350
call SelectObject,HDC, HBRUSHYELL
Call Rectangle,HDC,75,374,90,360
Call Rectangle,HDC,100,374,140,330
call SelectObject,HDC,HBRUSHGreen
Call Rectangle,HDC,160,430,210,340
call SelectObject,HDC,HBRUSHGRAY
Call Rectangle,HDC,205,430,265,380
call SelectObject,HDC,HBRUSHGreen
Call Rectangle,HDC,265,430,250,425
Call MoveToEx,HDC,205,375,offset OldPos
Call LineTo,HDC,260,375
Call LineTo,HDC,265,380
Call LineTo,HDC,210,380
Call LineTo,HDC,205,375
Call MoveToEx,HDC,220,376,offset OldPos
Call MoveToEx,HDC,265,380,offset OldPos
Call LineTo,HDC,260,375
Call LineTo,HDC,210,375
Call LineTo,HDC,215,380
Call LineTo,HDC,265,380
Call MoveToEx,HDC,160,375,offset OldPos
Call LineTo,HDC,160,430
Call LineTo,HDC,160,375
call SelectObject,HDC,HBRUSHGreen
Call Rectangle,HDC,204,380,165,345
Call MoveToEx,HDC,165,420, offset OldPos
Call LineTo,HDC,170,420
Call LineTo,HDC,204,380
Call LineTo,HDC,165,380
Call LineTo,HDC,165,420
Call Rectangle,HDC,170,377,199,348
;колеса
call SelectObject,HDC,HBRUSHBLACK
call SelectObject,HDC,HBLACKPen
Call Ellipse, HDC, 70,418,100,458
Call Ellipse, HDC, 170,418,200,458
;сонце
call SelectObject,HDC,HYELLPen
call SelectObject,HDC, HBRUSHYELL
Call Ellipse, HDC, -20,-20,X,Y
;===============================================================
call SelectObject,HDC,HBLACKPen
Call Rectangle,HDC,0,455,1040,485
Call Rectangle,HDC,380,340,500,460
call SelectObject,HDC,HBRUSHGRAY
Call Rectangle,HDC,390,380,432,422
Call MoveToEx,HDC,410,380,offset OldPos
Call LineTo,HDC,410,420
Call MoveToEx,HDC,410,400,offset OldPos
Call LineTo,HDC,430,400
call SelectObject,HDC,HBRUSHGreen
Call Rectangle,HDC,450,380,490,450
Call MoveToEx,HDC,470,380,offset OldPos
Call LineTo,HDC,470,450
Call MoveToEx,HDC,483,420,offset OldPos
Call LineTo,HDC,488,420
Call MoveToEx,HDC,360,340,offset OldPos
Call LineTo,HDC,440,280
Call MoveToEx,HDC,440,280,offset OldPos
Call LineTo,HDC,525,340
Call MoveToEx,HDC,525,340,offset OldPos
Call LineTo,HDC,360,340
;================================================
; ялинка
call SelectObject,HDC,HBRUSHBLACK
Call Rectangle,HDC,730,440,750,460
call SelectObject,HDC,HGreenPen
Call MoveToEx,HDC,660,440,offset OldPos
Call LineTo,HDC,740,380
Call MoveToEx,HDC,740,380,offset OldPos
Call LineTo,HDC,825,440
Call MoveToEx,HDC,825,440,offset OldPos
Call LineTo,HDC,660,440
Call MoveToEx,HDC,660,380,offset OldPos
Call LineTo,HDC,740,320
Call MoveToEx,HDC,740,320,offset OldPos
Call LineTo,HDC,825,380
Call MoveToEx,HDC,825,380,offset OldPos
Call LineTo,HDC,660,380
Call MoveToEx,HDC,660,320,offset OldPos
Call LineTo,HDC,740,260
Call MoveToEx,HDC,740,260,offset OldPos
Call LineTo,HDC,825,320
Call MoveToEx,HDC,825,320,offset OldPos
Call LineTo,HDC,660,320
Вміст файла MAIN.txt:
.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, SetTextColor:proc, CreateFontIndirectA:proc, SelectObject:proc
extrn CreatePen: Proc, MoveToEx: proc, LineTo: proc, Ellipse: proc, Rectangle: proc, CreateSolidBrush: 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
;******************************************************
include DATA.txt
;*******************************************************
.code
Start:
call CreatePen,0, 2, 0000ffh
mov HRedPen, eax
call CreatePen,0, 2, 00ff00h
mov HGreenPen, eax
call CreatePen,0, 2, 06fff0h
mov HYELLPen, eax
call CreatePen,0, 3, 465945h
mov HBLACKPen, eax
call CreatePen,0, 2, 4F7942h
mov HGOLDPen, eax
Call CreateSolidBrush, 00FF00h
mov HBRUSHGreen, eax
Call CreateSolidBrush, 0000ffh
mov HBRUSHRED, eax
Call CreateSolidBrush, 3D2B1Fh
mov HBRUSHBLACK, eax
Call CreateSolidBrush, 06fff0h
mov HBRUSHYELL, eax
call CreateFontIndirectA, offset LOGFONTA
mov HFont, eax
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
;****************************
include MyPic.txt
;****************************
call SelectObject,HDC,HFont
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,300
jb M1
neg HV
M1: cmp Y,290
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”.