Основи DirectDraw на Visual Basic

Частина перша: щось замість введення

Antiloop

А чо це таке?

Це не чо. Це – друга редакція мого підручника з DirectDraw, написана тільки завдяки старанням якоїсь маловідомої осиротілої і напіврозваленій корпорації Microsoft.

Думаю ви вже здогадалися, що справа піде про DirectX7. Писати інші частини на DirectX7, коли всі основи написані на DirectX 5-6, виявилося досить проблематично, через те, що вже згадувана контора вирішила поміняти всі інтерфейси з аналогів Сі-шних (як в PS-TLB) на перекоряченние, але VB-шні.

Це SE переписано з урахуванням непереборного бажання народу юзати сьомий DX, а також доповнено деякими уточненнями, поясненнями та полупофіксеннимі багами
🙂

Звичайно, ви можете подивитися стару версію підручника, завантаживши його тут

Введення

Ну що ж, привіт всім, хто тут. Сподіваюся, це маленьке керівництво допоможе вам усвідомити куди котиться наш і Ваш улюблений Visual Basic. Саме туди … Туди, куди програмує на Сі дотягується тільки після багатьох років вивчення, кректання і потіння. Ну да ладно, я нікого образити не хочу, а хочу тільки показати, як за допомогою Visual Basic можна створити свою власну гру за допомогою бібліотеки DirectX.

Note:
I don’t accept any responiblity for anything that might happen to your
system.

Тобто, я типу не винен, якщо Ви раптом захочете викинути свою систему в вікно під впливом від прочитаного тут.

А що мені треба, щоб почати програмувати Direct Draw?

Передусім розуміння, що дитячі ігри закінчилися. Тут вам доведеться напружити всі своє вміння, як програміста на Basic’e, щоб довести, що не тільки CЮшнікі можуть думати на папірці. Так-так, саме на папірці. Мені довелося розробляти мої супер графічні Engin’и саме на папері. Чому? Та тому що існує список достоїнств і недоліків програмування DirectX на VB. Раджу прочитати принаймні частина “недоліки” перш, ніж вирушити в дорогу.

Переваги

Недоліки

Ось такі от справи. Але якщо ви думаєте, що тепер можна приступати до роботі, то ви знову помилитеся. Просто так ось узяти і програмувати DirectX вам не вдасться. Перш за все, вам дізнатися про одну людину – його ім’я Patrice Scribe і він ніби як Француз. Точно говорити не буду – Сам не знаю. Так от, саме цей хороший чоловік придумав бібліотеки для роботи з DirectX на VB, за що величезне йому спасибі. Так от, раз вже ми вирішили використовувати DirectX7, тоді його TLB для DirectX 5-6 нам не знадобляться. Однак, було б непогано використовувати Win32 TLB. У цій бібліотеці описані всілякі типи, які зустрічаються при роботі з DirectX. Так-що раджу вам завантажити цю бібліотеку з мого сайту.

Другий крок при підготовці до роботи – подивіться, а чи встановлений у вас DirectX7? Ні???! Біжіть в магазин і купуйте диск з супер-навороченной грою Half-Life 2 World з датою випуску ще через півроку, напевно там вже буде DX7. А якщо серйозно, то знайдіть де-небудь дистрибутив DX7 і учстановіте його собі.

І не в якому разі не піддавайтеся на провокації Microsoft, що намагаються змусити вас завантажити DirectX SDK з ихнего сайту! Знаєте, що це таке? Це купа макулатури, прикладів і даремних програм, які якщо і будуть комусь корисні, але тільки не початківцям. Причому все це в їхньому улюбленому форматі HTML Help, які замість того, щоб стискати текст роздуває його до розмірів відеокліпу.

Вам не потрібен SDK, щоб повноцінно користуватися DirectX7 з Visual Basic!!!!

Ну ось, тепер начебто і все. Залишилося тільки сказати, що у мене на Наразі встановлено Visual Basic 6.0 і все проги я тестував на ньому. Дехто в Мережі використовує і VB5 (в основному Америкоси), так що на ньому теж піде. А ось вже що стосується більш ранніх версій, то можу сказати власникам таких, що апргейд вам не тільки не зашкодить але й піде на користь в кілька разів.

Ага, тепер я можу вже почати!?

Прелестно, ви доставлені необхідні бібліотеки, і в повній збройної готовності хочете почати творити. У мене таке питання. А ви знаєте, як влаштований і як працює DirectDraw? Якщо знаєте, можете з розумним виглядом пропустити наступний абзац. Якщо ні, ось вам маленьке роз’яснення.

Що стосується того, як DD влаштований можу сказати тільки одне: поняття не маю. Зате як працює – знаю. І вам раджу. Отже, найголовнішим, що ви повинні знати, є те як проиходит анімація. Існують такі буфера або поверхні (surface), за допомогою яких все це неподобство відбувається. Існує два основних буфера: передній і задній. Передній – Це видимий буфер, він являє собою те, що ви бачите на екрані. Задній буфер – невидимий на ньому ви малюєте. Звідси напрошується правильний питання: “Навіщо мені малювати на невидимому буфері?” Відповідь буде дуже вченим. Уявіть собі, як працює ваш монітор. Ззаду скла встановлена ​​магнітна гармата, що плюються електронами з трубки. (У мене з фізики не дуже добре було, так що не треба кидатися всякими тухлими продуктами в мою сторону) Ці електрони створюють зображення на екрані, причому промінь трубки має тенденцію йти з лівого верхнього ула по рядках і вниз. Відповідно, він кінчає промальовування екрану в правому нижньому кутку, після чого, вже нічого не малюючи, він направляється назад в стартову позицію. Ця дія називається Vertical Blank. Так як робиться це зі скаженою швидкістю, ви не помічаєте, як ваш екран оновлюється.

Так от, поки екран зайнятий своїми справами, ви малюєте на невидимому задньому буфері кадр номер 1 повішення улюбленого вчителя з інформатики, і потім, поки трубка преходить на початок наступного циклу оновлення, швиденько шльопати сцену на передній буфер, з якого гармата тепер буде оновлювати екран, і поки відбувається оновлення, Виготуєте кадр 2. Теоретично, ви можете малювати вашу анімацію зі швидкістю оновлення екрану. -Есть яка встановлена ​​у вашого монітора частота, з такою і буде відбувається оновлення екрану, наприклад 70 разів на секунду. Практично ж тут відбувається багато накладок. По-перше, на це впливає швидкодію комп’ютера, тобто поки ви обробите черговий кадр, оновлення екрану пройде вже кілька раз, і ви починаєте програвати в швидкості. По-друге, якщо дядечко Сі працює сам по собі і в десять разів швидше, то VB постійно спирається на свої підпори – Runtime-бібліотеки, за допомогою яких він, власне кажучи і працює. Це займає час, і наслідки очевидні.

Ну ось, узагальнюючи, виводжу принцип дії. Спочатку ви малюєте сцену на задньому буфері, а потім перекладаєте її на передній буфер, поки він промальовується, ви не втрачаючи часу очищаєте задній буфер і знову малюєте на ньому наступний кадр. Потім перевертаєте … І так до упору.

Для особливо шкідливих пояснюю, що якби ви збирали сцену на передньому буфері без мороки зі фліппінгом, як з BitBlt тоді б було таке мерехтіння, що побудувати програму, яка б привертала користувача було б на VB неможливо.

Ну а тепер-то???! …

Так! Тепер можна. Почнемо з найпростішого. Створимо об’єкт DirectDraw і встановимо дозвіл екрану як 640x480x16, помилуємося створеним і при натисканні будь-якої клавіші вийдемо назад в редактор.

Перш за все додайте в розділі References необхідні TLB

ну а далі наберіть програму. Зауважте, що ніякі контроли на форму ставити не треба. І взагалі, форма тут зовсім ні при чому, можете її хоч квадратної зробити – все одно, тому що працювати програма буде в повноекранному режимі.

Отже, почнемо з оголошення об’єктів DD:

Private dx As New DirectX7 ‘Головний об’єкт DirectX
Private dd As DirectDraw7 ‘Об’єкт DirectDraw
Private ddsPrimary As DirectDrawSurface7 ‘Передня поверхня
Private ddsBack As DirectDrawSurface7 ‘Задній буфер
Private ddsd As DDSURFACEDESC2 ‘Тип, з описом поверхні
Private caps As DDSCAPS2 ‘Тип з можливостями заліза (Hardware)

Тепер, додайте в процедуру Form_Load наступні рядки:

‘Створюємо об’єкти і встановлюємо режим екрану
Set dd = dX.DirectDrawCreate (“”) ‘Створити об’єкт DirectDraw
Call dd.SetCooperativeLevel(me.Hwnd, DDSCL_EXCLUSIVE Or DDSCL_FULLSCREEN Or DDSCL_ALLOWREBOOT) ‘Повноекранний
‘Ексклюзивний режим з дозволеним CAD
Call dd.SetDisplayMode (640, 480, 16, 0, DDSDM_DEFAULT) ‘Ось такий режим екрану

‘Тепер створюємо головну поверхню з одним заднім буфером
‘Заповнюємо опис створюваної поверхні
ddsd.lFlags = DDSD_CAPS Or DDSD_BACKBUFFERCOUNT ‘Поверхня з заднім буфером
ddsd.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE Or DDSCAPS_FLIP Or DDSCAPS_COMPLEX ‘Комплексна головна поверхню з можливим фліппінгом
ddsd.lBackBufferCount = 1 ‘Один задній буфер (схема подвійний буферизації)
‘Подвійна буферизація – головний буфер і один задній буфер

Set ddsPrimary = dd.CreateSurface (ddsd) ‘Створити поверхню

‘Отримати BackBuffer
caps.lCaps = DDSCAPS_BACKBUFFER
Set ddsBack = ddsPrimary.GetAttachedSurface(caps)

Отже, перед вами спосіб створення об’єктів DD. Саме з цього вам треба починати, коли будете писати свою велику DirectX гру. Зверніть увагу, як створюється структура буферів: спочатку ми створюємо головну поверхню, яка є комплексною, тобто містить кілька буферів. У нашому випадку – головний і задній. Однак цього недостатньо. Вам ще треба одержати задній буфер в своє користування – GetAttachedSurface, що буквально перекладається, як “отримати прикріплену поверхню”.

Така комплексна поверхня, що складається з передньої поверхні і задніх буферів називається ланцюгом фліппінга (flipping chain). Задніх буферів може бути більше, ніж один, але не будемо забивати собі голову.

Ура, тепер ви вмієте міняти дозвіл екрану і створювати якісь об’єкти, проте, як я вже зауважував раніше, мало того, що ці об’єкти створити, їх ще треба і правильно знищити. Так от як зробити їм це саме харакірі я зараз і покажу. Додайте в процедуру Form_Unload наступний код:

Call dd.RestoreDisplayMode ‘Відновити дозвіл екрану
Call dd.SetCooperativeLevel (0, DDSCL_NORMAL) ‘Зворотно у віконний режим

‘Увага! Спочатку вбиваємо оффскрінние буфера, потім задній буфер,
‘ПОТІМ головну поверхню і В ОСТАННЮ ЧЕРГУ об’єкт DirectDraw
Set ddsBack = Nothing
Set ddsPrimary = Nothing
Set dd = Nothing

Залишилося тільки передбачити вихід для того випадку, якщо ви в повноекранному режимі не побачите вікна. Я тестів на різних комп’ютерах і на всіх було по різному.
Додайте в програму процедуру Form_KeyPress:

Private Sub Form_KeyPress(KeyAscii As Integer)
Call Form_Unload(0)
End
End Sub

Запускаємо програму і … Краса!! Режим екрана помінявся і з удовльствіем спостерігаємо противний чорний екран (Може і не чорний – у кого як).

А як же анімація і все таке?

Гм. Тут то і починається найцікавіше. Як робити анімацію? – На цей питання є безліч відповідей. Сам факт анімації, як ви повинні знати полягає в тому, що якщо ви хочете, наприклад, зобразити ходить чоловічка, то ви малюєте його в положенні 1, потім піднімаєте йому одну ногу, опускаєте, піднімаєте другу і так до упору. Потім, ви всі кадри ставите в один файл таким чином, що виходить щось на зразок таблиці. Малюючи анімацію на екрані, ви вирізуєте потрібний в даний момент спрайт, поміщаєте його на екран, перете, вирізуєте інший і в тому ж дусі. Як це працює в DirectDraw: таблицю спрайтів ви завантажуєте в буфер об’єкта DD, створений спеціально для цього файлу, тобто завантажуєте набір спрайтів в пам’ять. Коли треба малювати, ви переміщаєте прямокутник з вказаними координатами на Задній буфер, з іншого буфера, що містить інший набір спрайтів поміщаєте інший спрайт на Задній буфер … коли все закінчено, робите “фліп” – переводите задній буфер на передній, очищаєте задній, повторюєте все спочатку. Уфф. Напевно я вас втомив.

Проблема тут у тому, що припустимо ви намалювали чарівного чоловічка – Вилитого Неверхуда – зобразили його у всіх мислимих і немислимих позиціях і вже зібралися робити анімацію, коли раптом до вас доходить: “Стоп! А як же фон?! “Так, так! Про фон, то ми і забули. Кому потрібен чоловічок, капризний по смутному сірому творінню Мікрософт – вікна?! OK. Намалювали прекрасний фон, але ж спрайт не повторює форми якогось обмежуючого контуру – Він прямокутний. І місце в прямокутнику не зайняте фігурою буде зайвим. А от би його зробити прозорим. Сказано – зроблено! Беремо будь колір фону, краще небудь простий, наприклад, чорний, і малюємо Неверхуда якими тільки завгодно квітами, але тільки нечорним. Все що буде чорним – Бедет просвічуватися як тільки що вимите вікно.

Програмно це робиться просто. Відповідному властивості присвоюється відповідне значення кольору, потім викликається функція, яка вчиняє побітовий перенос зображення всіх кольорів крім фонового з джерела на рисуемую поверхню. Ось і все.

Джерелом, як правило є якась оффскрінная поверхню. Оффскрінная (Невидима) поверхню – це ділянка відеопам’яті, в якому зберігаються зображення, з якими ви збираєтеся працювати. Окремим випадком оффскрінной поверхні є задній буфер. Зазвичай такі поверхні (крім заднього буфера) служать для зберігання набору спрайтів, текстур або ще чогось. Оффскрінний поверхні мають розміри (ширину і висоту) як і головна поверхню.
Ви завжди можете створювати оффскрінние поверхні розміром не більшим, чому головна поверхню, проте якщо ви хочете створити невидиму поверхню більшого розміру, ніж задній буфер, вам необхідно спочатку перевірити, чи підтримує апаратура комп’ютера великі оффскрінние поверхні. Але про це не зараз.

Отже, як створити просту оффскрінную поверхню:

‘Спочатку, звичайно, оголосимо поверхню
Dim ddsSample as DirectDrawSurface7
Dim ddsd as DDSURFACEDEDSC2 ‘Це структура з описом поверхні

‘Тепер, зазначаємо, що за поверхню ми створюємо
ddsd.lFlags = DDSD_CAPS Or DDSD_WIDTH Or DDSD_HEIGHT ‘Необхідні прапори
ddsd.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN ‘Поверхня оффскрінная
ddsd.lHeight = 100 ‘Висота поверхні в пікселах
ddsd.lWidth = 100 ‘Ширина поверхні в пікселах

‘І нарешті, викликаємо метод, який створює поверхню
Set ddsSample = dd.CreateSurface (ddsd) ‘Тут, dd – об’єкт DirectDraw7

Ось так створюється найпростіша поверхню. У цьому прикладі створилася поверхня 100×100. Для того, щоб знищити поверхню, виконайте операцію

ddsSample=Nothing

Нам знадобиться створити дуже часто вживану процедуру, яка буде створювати оффскрінную поверхню і завантажувати в неї графічний файл. При цьому, поверхня буде відповідати розмірам графічного файлу, тому, далі я покажу як можна вивудити таку інформацію із завантаженого файлу растра.
Перш, ніж приступити, зроблю примітка: надалі коді ви побачите рядок наподобии “Win32.BITMAP“. Це означає використання струкутри або функції з тієї самої бібліотеки Win32.tlb, яку я порадив вам завантажити. Ви можете, звичайно самі визначити всі подібні функції та структури, користуючись API Loader, Але навіщо винаходити велосипед другий раз?! Тому, підключайте Win32, якщо хочете користуватися наступним кодом без змін

Отже, ось вона – функція, що створює поверхню з файлу растра:

Function CreateDDSFromFile(ByVal FileName as String, Optional CKey
as Long=0) as DirectDrawSurface7

‘Оголошення
‘============
Dim dds as DirectDrawSurface7 ‘Тимчасова допоміжна поверхня
Dim ddsd as DDSURFACEDESC2 ‘Опис тимчасової поверхні
Dim StorePic as stdPicture ‘Тимчасове сховище картинки
Dim Bmp as Win32.Bitmap ‘Тип BITMAP, що описує растрове зображення
Dim hDCPicture as Long, hDCSurface as Long ‘DC картинки і поверхні
Dim ddCK as DDCOLORKEY ‘Для установки ключового кольору

‘Завантажуємо картинку і отримуємо об’єкт картинки
‘==========================================
StorePic = LoadPicture (FileName) ‘Завантажуємо картинку з файлу
‘Отримуємо опис картинки в структуру BITMAP
Call Win32.GetObject(StorePic.Handle, Len(Bmp), Bmp)
‘Отримуємо DC картинки
hDCPicture=Win32.CreateCompatibleDC(ByVal 0&)
Call Win32.SelectObject(hDCPicture, StorePic.Handle)

‘Тепер, створюємо поверхню
‘==========================
ddsd.lFlags = DDSD_CAPS Or DDSD_WIDTH Or DDSD_HEIGHT ‘Необхідні прапори
ddsd.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN ‘Поверхня оффскрінная
ddsd.lHeight = bmp.bmHeight ‘Висота поверхні як у картинки
ddsd.lWidth = bmp.bmWidth ‘Ширина поверхні як у картинки
‘Викликаємо метод, який створює поверхню
Set dds = dd.CreateSurface (ddsd) ‘dd – глобальний об’єкт DirectDraw7

‘Переводимо картинку на поверхню
‘================================
Call dds.Restore
hDCSurface = dds.GetDC ‘Підготовка до прямому доступу до поверхні
Call Win32.StretchBlt(hDCSurface, 0, 0, bmp.bmWidth, bmp.bmHeight, hDCPicture, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY) ‘Це копіює зображення в буфер
Call dds.ReleaseDC (hDCSurface) ‘Кінець прямого доступу до поверхні
Call Win32.DeleteDC (hDCPicture) ‘Знищити об’єкт картинки – більше не потрібен

‘Встановлюємо ключовий колір
‘===========================
ddCK.low = CKey ‘Працює правильно тільки в 24-бітному кольорі
ddCK.high = ddCK.low ‘Але для простих випадків піде
Call ddи.SetColorKey (DDCKEY_SRCBLT, ddCK)

‘Повертаємо об’єкт
‘==================
Set CreateDDSFromFile=dds

End Function

І чого мені з цим робити?

Тепер, у нас є поверхня, із які на ній спрайтом. Значить пора цей спрайт показати народу, тобто перевести його на задній буфер, який потім “перевернути” на передній. (Пам’ятаєте ще процес?)

Перенесення спрайту з одного буфера на інший називається бліттінг (Blit – перенесення бітів). Для цієї процедури краще всього використовувати метод
DirectDrawSurface7.BltFast (X, Y, srcSurface, srcRECT, Flags)

Зазвичай BltFast застосовують до заднього буферу.
X і Y – Це координати верхнього лівого кута на цілі, куди буде поміщений спрайт
srcSurface – Повернхность, що містить спрайт
srcRECT – Структура RECT, що містить координати переносимого прямокутника на джерелі
Flags – DDBLTFAST_SRCCOLORKEY – з урахуванням ключового кольору, DDBLTFAST_NOCOLORKEY – Без нього

Структура RECT складається з елементів Top, Left, Bottom, Right. Що кожен з них озачает, здогадатися може будь-хто.

Однак, перш ніж почати переносити, треба зробити ще кілька дрібних речей, наприклад, очистити задній буфер.

Все це описано в наступній частині.

Приємного програмування.

[Вперед]

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*