Это демоверсия моей демки.
Она представляет собой звезды летящие на вас,
режим 640х480х256.
Одна маленькая особенность: чтоб выйти из нее, нужно нажать Alt-F4 :-) Описание работы с DirectDraw. В качестве тестирующей версии использовался DirectX5. Для чего нужен DirectDraw надеюсь понятно, так как этот текст предназначен для ПРОГРАММИСТОВ!!! Для работы с DirectDraw вам нужен модуль DDraw.pas и Delphi 2.0 and higher. Нужен также DDCanvas.dcu. Итак, Неоходимо подключить модуль Ddraw,Ole2 (ole2 необходим потому, что все объекты DirectX доступны через OLE контейнер) В разделе PUBLIC описать переменную типа IDirectDraw, например: ... DD:IDirectDraw; ... этим вы опишите интерфейс DirectDraw, но он не позволяет непосредственно работать с видеопамятью, зато он позволяет создать объект IDDSurface, который и позволяет непосредственно работать с экранной поверхностью. Например так: ... DDS:IDDSurface; .... Еще нужно описать поинтер, который будет указывать на начало видеопамяти, например так: ... P_v:pointer; ... Далее работа будет протекать в три этапа -
|
procedure TForm1.FormCreate(Sender: TObject); begin if DirectDrawCreate(nil, DD, Nil)<>DD_OK then beep; //какие-то действия по обработке end; |
затем в обработчике OnShow создать остальное и произвести
инициализацию. Для приличной графики, нам необходим весь экран,
да еще и в удобном нам видео режиме. DirectDraw позволяет и то и другое.
Первая команда в следующем примере это настройка системы таким
образом, что-бы весь экран принадлежал мне. А затем устанавливаю
видео режим. Далее нам необходимо получить доступ к поверхности,
но сначала создать ее. ddscaps_primarysurface означает, что
поверхность будет расположена на экране. Чтобы получить адрес
начала видеопамяти, отведенной этой поверхности, я сначала
блокирую, а затем снова разблокирую ее. И наконец создаю
новую цепочку... Для чего она нужна? Логично, вы можете и не делать этого, все зависит от того что вам нужно, но в программе Летящие Звезды я использую цепочку, с основным циклом программы, и выставляю ее приоритет в наивысший, с помощью команды API Win32. |
procedure TForm1.FormShow(Sender: TObject); var y:integer; ddscaps:TDDscaps; dr:Prect; a:pointer; ddsd:TDDSD; begin if dd.SetCooperativeLevel(handle, ddscl_exclusive or ddscl_fullscreen)<>dd_ok then close; if dd.SetDisplayMode(640,480,8)<>dd_ok then close; {setdisplaymode(x,y,c) - где х и y и c - параметры экрана. } fillchar(ddsd,sizeof(ddsd),0); with ddsd do begin dwSize:=sizeof(ddsd); dwFlags:=ddsd_caps; ddscaps.dwCaps:=ddscaps_primarysurface end; if dd.createsurface(ddsd,dds,nil)<>dd_ok then close; dr:=nil; dds.Lock(dr,@ddsd,DDLOCK_SURFACEMEMORYPTR,y); P_v:=ddsd.lpSurface; dds.Unlock(dr); ht:=createthread(nil,0,@StarThread,nil,0,TID); end; //Ну и теперь удаление объектов: procedure TForm1.FormDestroy(Sender: TObject); begin if assigned(dds) then p_s.release; if assigned(DD) then DD.release; end; |
Что вы теперь можете?
ну например вы можете получить DC на поверхность... DDS.getdc(dc); предварительно описав dc:hdc; и с помощью API функций рисовать примитивы... это достаточно легко сделать, в помощи Delphi это есть... еще вы имеете DD для работы с DirectDraw. например синхронизация с лучем DD.WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN ,0); и т.д. поверхность DDS для работы с поверхностью, например копирование, создание цветового ключа, создание палитры... также вы имеете указатель на видео память P_v для прямого доступа к видеопамяти... |
asm mov esi,p_v mov ecx,640*480 mov eax,0 @l: mov [esi],al inc eax inc esi loop @L end; |
если вы знакомы с assembler то вы найдете применение этой
возможности... но нужно быть осторожным - P_v внутри процедуры не всегда содержит корректную информацию при обращении с помощью asm, я рекомендую завести локальный поинтер, и присвоить его глобальному, и в ассемблерной вставке использовать уже локальный указатель на видеопамять. создание палитры производится таким образом: создается массив элементов палитры TPaletteEntry, например ttt:array[0..255] of TPaletteEntry; создается объект палитра: ... DDP:IdirectDrawPalette; ... потом у этого массива устанавливаются необходимые значения, и dd.CreatePalette(DDPCAPS_8BIT,@ttt[0],ddp,nil); dds.SetPalette(ddp); В прошлый раз я говорил о том, что можно пользоватся Canvas, и даже показал как. Да, можно. Но я не советую... Когда я пользовался Canvas, я перезагружался каждые 5 минут, когда я от него отказался - каждые 15 :-) Также, если вы хотите использовать DX в реал-тайме, не используйте ТТimer, это будет ужасно медленно. Создайте лучше цепочку, и все, что вы хотели сделать в обработчике таймера, сделайте в этой цепочке. Это сделать легко, но есть одна проблема - Canvas в цепочке не работает, и многие другие компоненты тоже... Придется пользоватся DC. Как создать цепочку? начать нужно с того, что вы заводите процедуру в которую прыгнет цепочка при создании: |
procedure StartThread(p:Pointer); begin repeat // какие-то действия until stopwork; threadstopped:=true; end; |
процедура обязательно должна иметь входной параметр
pointer. Все остальное нет. Но я делаю так: сам я получать сообщения Windows не умею, и использую стандартные события формы для получения информации о действиях пользователя. Так вот, самой необходимой информацией является информация о том что форма закрывается. так вот, в момент закрытия, в обработчике OnDestroy, я присваиваю stopwork:=true; и делаю цикл: repeat until threadstopped; естественно, что при создании я устанавливаю обе булевские переменные в соответствующие значения. теперь о создании цепочки: ht:=createthread(nil,0,@StartThread,nil,0,TID); где ht и TID простой integer. Все. В момент выполнения этой команды ваша процедура запускается на исполнение параллельно с цепочкой формы. Но вот как теперь быть без Canvas? проблема... придется получить DC dds.getdc(dc); и с помощью него рисовать примитивы. Нужно ли отказыватся от формы? решать вам, но мой совет такой - если вы хотите сделать что-то более менее серьезное, не тряситесь над каждым байтом... Сейчас я начну потихоньку рассказ о том как отказатся от формы. Вообще форма в Delphi жрет много памяти, и отказавшись от нее, вы наверняка уменьшите объем программы раз в 10. Не хило :-). Но что-бы отказатся от формы, нужно создавать окно самому, заводить цепочку под основной цикл программы, и получать сообщения от Windows, типа нажатых клавиш, и передвинутой мышки... Чтоб сделать это, вам нужно компилировать исходники самому, с помощью Dcc32.exe из подкаталога bin. Я использую FAR менеджер для этих целей, но можно любую DOS оболочку, запущенную под Windows. Ключей указывать не надо. Единственное условие - все файлы лучше держать в одном каталоге. Может и можно по другому, но я не знаю. В поле uses подключайте следующие модули: uses windows,messages,ddraw,ole2; это минимум, для большего, нужно больше модулей :-) (я имею в виду больше того, что предоставляют эти модули.) Дальше, нужно описать функцию примерно такого вида: |
function winreg:boolean; var wc:TWndClass; begin wc.style:=cs_hredraw or cs_vredraw; wc.lpfnwndproc:=@windowproc;//имя процедуры // в которую проинициализируется цепочка окна. wc.cbclsextra:=0; wc.cbwndextra:=0; wc.hinstance:=HInstance; wc.hicon:=loadicon(100,0); wc.hcursor:=loadcursor(0,IDC_NO); wc.hbrbackground:=hbrush(nil); wc.lpszmenuname:=nil; wc.lpszclassname:=a_name; result:=registerclass(wc)<>0; end; |
поэксперементируйте с параметрами, для вашего
удобства...
Опишите глобальные переменные ... am:TMsg; hw:hwnd; ... и еще одну функцию: |
function wincreate:hwnd; var hW:hwnd; begin hw:=createwindow(a_name,'Ваше имя',ws_popup or WS_EX_TOPMOST, cw_usedefault,cw_usedefault,cw_usedefault,cw_usedefault, 0,0,hinstance,nil); if hw<>0 then begin showwindow(hw,cmdshow); updatewindow(hw) end; result:=hw; end; |
третий параметр функции createwindow, характеризует
стиль окна, в данном случае окно будет без рамки,
и постоянно на поверхности.
Третья обязательная функция, которую вы должны описать это - |
function windowproc(w:HWnd;AM,WP,LP:Longint):longint;stdcall;export; begin windowproc:=0; case am of wm_destroy:begin postquitmessage(0);exit end end; windowproc:=DefWindowProc(w,am,wp,lp); end; |
она получает и обрабатывает только одно сообщение,
о разрушении окна.
Вот, теперь, в теле программы можно сделать так: |
if not winreg then begin messagebox(0,'Не могу зарегестрировать окно.',nil,mb_ok); exit end; hw:=wincreate; if hw=0 then begin messagebox(0,'Не могу создать окно.',nil,mb_ok); exit end; |
Тут вроде не сложно, регистрируем и создаем.
и под конец транслируем сообщения ядра, главной процедуре. |
while getmessage(am,0,0,0) do begin translatemessage(am); dispatchmessage(am) end; halt(am.wparam); |
после этого можно ставить End.
Это первая часть моего личного опыта работы с ДД. В следующей я расскажу как использовать GDI Сейчас я все это уже умею, но не тиснул клаву :-)... Учучь работать с D3D, DirectSound, DirectPlay... Как научусь, расскажу... P.S. Много информации по DX есть в SDK, в основном в хелп-файле... Исходный документ находится на Alex Key Homepage Перечисленные программы и модули можно скачать оттуда! |