C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
DIRECT DRAW и Builder
Grigoriy
Отправлено: 20.08.2006, 09:27


Мастер участка

Группа: Участник
Сообщений: 381



В общем при использовании Direct Draw в Билдере куча проблем.

Я присоединяю файл
#include

Во первых почему то линковщик выдает ошибку — не найден адрес точки входа в функцию DirectDrawCreate.
Я решил эту проблему с помощью функций LoadLibrary("ddraw.dll")
и GetProcAddress.
Но когда я написал инициализацию графики в обработчике нажатия кнопки Button — в конце обработчика возникает ошибка.
Я переместил этот код в обработчик нажатия на клавишу на клавиатуре.
Вот мой код
CODE

#include <ddraw.h>
//------------
LPDIRECTDRAW lpDD=0;//объект DirectDraw
LPDIRECTDRAWSURFACE lpDDSPrimary=0;//первичная поверхность
LPDIRECTDRAWSURFACE lpDDSBack=0;//вторичная поверхность
DDSURFACEDESC ddsd;
DDSCAPS ddscaps;
HRESULT result;
void* ddraw_dll;
HRESULT (*DirectDrawCreate_)(_GUID* lpGUID,IDirectDraw** lplpDD, IUnknown* pUnkOuter);
TForm1 *Form1;
//--------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
ddraw_dll=LoadLibrary("ddraw.dll");
(void*)DirectDrawCreate_=(void*)GetProcAddress(ddraw_dll,"DirectDrawCreate");
}
//--------------

void __fastcall TForm1::FormKeyPress(TObject *Sender, char &Key)
{
if (Key=='r')
{
//уничтожение объектов при нажатии клавиши 'r'
if (lpDDSBack) {lpDDSBack->Release();lpDDSBack=0;};
if (lpDDSPrimary) {lpDDSPrimary->Release();lpDDSPrimary=0;};
if (lpDD) {lpDD->Release();lpDD=0;};
Application->Terminate();
};
if (Key=='e')
{
//result=DirectDrawCreate( NULL,&lpDD,NULL);не работает !
//создаем основной объект DIRECT DRAW для программы
result=DirectDrawCreate_(NULL,&lpDD,NULL);
//устанавливаем приоритет использования видеопамяти программой
//по сравнению с другими программами
result=lpDD->SetCooperativeLevel(Form1->Handle,DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN);
//установка графического режима
result=lpDD->SetDisplayMode(1024,768,32);
//задаем данные для создания графической поверхности
//(страницы видеопамяти)
ddsd.dwSize=sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE |DDSCAPS_FLIP |DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1;
//создаем графическую поверхность в памяти видеокарты
result = lpDD->CreateSurface( &ddsd, &lpDDSPrimary,NULL );
//задаем параметр связанной графической поверхности
//(она будет также в памяти видеоадаптера и
//будет служить дополнительной поверхностью)
ddscaps.dwCaps=DDSCAPS_BACKBUFFER;
//создаем эту дополнительную поверхность
result = lpDDSPrimary->GetAttachedSurface(&ddscaps,&lpDDSBack);
};
if (Key=='w')
{
//если нажимаем клавишу 'w' — то эти обе
//графические поверхности меняются ролями
//таким образом возможно избежать "разрезания" изображения
//пока отображается одна из графических поверхностей -
//в связанную поверхность с ней можно спокойно записывать информацию
lpDDSPrimary->Flip(NULL,DDFLIP_WAIT);
};
}


Но куча проблем возникает все равно.
Например не удается запустить стандартный компонент TTimer.
После создания объектов выполнение оператора
Timer1->Enabled=true;
приводит к ошибке !

И ещё я должен узнать, как получить прямой доступ к видеопамяти видеокарты через указатель. Для него выделено отдельное поле в структуре
DDSURFACEDESC
Оно имеет тип void*
и называется
lpSurface
Я знаю, что Direct Draw может позволить напрямую записывать в видеопамять данные в прикладной программе.
Но указатель наверно должна возвращать сама система, а структура типа DDSURFACEDESC служит для задания начальных параметров для создания графической поверхности.
Grigoriy
Отправлено: 20.08.2006, 21:17


Мастер участка

Группа: Участник
Сообщений: 381



Разобрался я как получить адрес поверхности.
Нужно использовать функцию блокировки поверхности.
Например так
CODE

DDSURFACEDESC ddsd;
//-------------------------------
lpDDSBack->Lock(NULL,&ddsd,DDLOCK_NOSYSLOCK | DDLOCK_WAIT,NULL);

После чего функция возвращает в структуре ddsd всю информацию о поверхности, в том числе и ddsd.lpSurface
И можно записывать данные на поверхность.
Потом сделать обмен поверхностями
CODE

t1=(int*)ddsd.lpSurface;
for (int i=98;i<1024*768;i++) t1[i] = 78;
lpDDSBack->Unlock(NULL);
if (DDERR_SURFACELOST==lpDDSPrimary->Flip(NULL,0))
lpDDSPrimary->Restore();


Но все равно после выполнения этих операторов непонятные глюки в программе.
Операторы выполняются правильно, но например вот такой оператор
CODE

if (Key=='w')
{
//----------------------------

Приводит к неизвестного происхождения ошибке нарушение общей защиты (запись в недоступную область памяти) ! sad.gif sad.gif
Переменная Key — параметр обработчика нажатия клавиши — передается по адресу. Я ее сохранил в локальной переменной функции и использовать далее её и все правильно, но конфликты будут возникать все равно. Билдер несовместим с Direct Draw ! И это можно понять хотя бы потому, что даже в ХЕЛПе о нем не написано ни слова.

Программисты советуют писать с Direct Draw в Delphi и сначала удалить все начальное вставленное ДЕЛФИ и написать собственные оконные функции.
А ещё лучше на ассемблере составлять.

Вернуться в Вопросы программирования в C++Builder