Главная » 2D графика » Способы хранение графики в играх и бизнес приложениях

RSS

Способы хранение графики в играх и бизнес приложениях

Не нравитсяНравится   Рейтинг 0

Хранение ресурса в секции PE файла

Теперь настала пора разобраться, как поместить созданный ресурсный файл в исполняемое приложение, т.е. просто «вшить» его в exe файл. Проблемы с соединением не возникнет, а вот как с обращением к ресурсу стоит попотеть.

Как известно в PE файле есть различные секции, при этом ничего не мешает Вам писать в секцию импорта свои данные, но есть специальная секция RCData. Она то и предназначенная для записи собственных данных приложения, т.е. в неё можно пихать всё, что угодно (в смысле бинарных данных :) ), в разумных пределах конечно.

Для примера я создам файл out (с помощью описанного ранее компилятора) содержащий четыре 24-х битных растра. Количество не имеет значение, а 24-битные растры я буду помещать по тому, что их проще загружать.

Итак создаем RC файл, например Resource.rc со следующим содержанием:

1
2
3
…
GAMEDATA RCDATA out
…

GAMEDATA – название ресурса, т.е. его идентификатор;
RCDATA – название секции;
Out – имя файла, может быть только название файла, а может и целый путь.

Создаем ресурсный файл вызывая компилятор ресурсов:

1
brcc32.exe Resource.rc

…ааа вот зачем программистам в Windows нужна командная строка! После успешного завершения, мы получим бинарный ресурсный файл Resource.RES, его можно подключать к проекту директивой компилятора:

1
{$R Resource.RES}

Теперь при сборке проекта в получившемся exe файле появится секция RCDATA и в ней ресурс с названием GAMEDATA.

Осталось совсем чуть-чуть – написать процедуру загрузки. Она будет достаточна сложна, и если Вы не сильны в таких понятиях как указатели, дескрипторы, плоская модель памяти … смело пропускайте данный материал. Бездумное копирование кода до добра не доводит :)

Начнем как всегда с расшифровки переменных:

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
procedure TDibFromResForm.LoadBitmap(const ImageCount:Integer);
var
  // Указатели на структуры заголовка файла
  GameRusourceHeader : PGameRusourceHeader;
  GameResourceTable : PGameResourceTable;
  // Указатели на структуры растра
  BitmapFileHeader : PBITMAPFILEHEADER;
  BitmapInfoHeader : PBITMAPINFOHEADER;
  BitmapInfo : TBitMapInfo;
  BitmapBits : Pointer;
  // Handle заголовок данных блока ресурса
  RSRC : HRSRC;
  // Handle на область памяти ресурса
  RES : THandle;
  // Указатель на область памяти загруженного ресурса
  P : Pointer;
  // Переменная для хранит начально адреса данных ресурса
  StartAddr : Integer;
  // Счетчик смещения адресов
  I : Integer;
  // Переменная для хранения полученного битмапа
  Bitmap : HBITMAP;
  // Контекст устройства
  DC : HDC;
...

Ну как, не испугались ? Дальше интереснее будет:

1
2
3
4
5
6
7
8
RSRC:=FindResource(HInstance, 'GAMEDATA', RT_RCDATA);
if RSRC = 0 then
begin
  MessageBox(Handle,'Ресурс не найден.', MessageTitle, MB_ICONERROR+MB_OK);
  Exit;
end;
RES:=LoadResource(HInstance, RSRC);
P:=LockResource(RES);

Находим ресурс функцией FindResource по его идентификатору GAMEDATA в секции RT_RCDATA. Загружаем ресурс функцией LoadResource, блокируем доступ к нему и получаем область занимаемой им памяти в указатель P.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
StartAddr:=Integer(P);
I:=StartAddr;
GameRusourceHeader:=Ptr(I);
Inc(I, SizeOf(TGameRusourceHeader));
Inc(I, SizeOf(TGameResourceTable)*(ImageCount-1));
GameResourceTable:=Ptr(I);
I:=StartAddr+GameResourceTable.Offset;
BitmapFileHeader:=Ptr(I);
Inc(I, SizeOf(TBitmapFileHeader));
BitmapInfoHeader:=Ptr(I);
Inc(I, SizeOf(TBitmapInfoHeader));
GetMem(BitmapBits, BitmapInfoHeader.biSizeImage);
BitmapBits:=Ptr(I);
BitmapInfo.bmiHeader:=BitmapInfoHeader^;

В StartAddr получаем адрес памяти указателя P и устанавливаем счетчик I на это же значение. Далее все опрерации будем производить только со счётчиком, так нагляднее. Загружаем заголовок GameRusourceHeader, он находится прамо по адресу I или StartAddr, т.к. в самом начале блока памяти загруженного ресурса.

Увеличиваем счетчик на размер структуры TGameRusourceHeader. Параметр функции ImageCount хранит номер растра, который необходимо получить. По этому высчитываем смещение для требуемой таблицы ресурсов: SizeOf(TGameResourceTable)*(ImageCount-1). Получаем таблицу смещений. Из неё можно вытащить смещение требуемого растра: StartAddr+GameResourceTable.Offset. По этому смещению можно последовательно считать BitmapFileHeader, BitmapInfoHeader и BitmapBits. Вот собственно и все!

Осталось создать Bitmap и очистить ресурсы:

1
2
3
4
5
...
Bitmap:=CreateDIBitmap(DC, BitmapInfoHeader^, CBM_INIT, BitmapBits, BitmapInfo, DIB_RGB_COLORS);
...
UnlockResource(RES);
FreeResource(RES);

Не так все и сложно, хотя я представляю лица ( масли, выражения, жесты … ) тех, кто сел за Delphi месяц назад :) )) На самом деле, достаточно сложный для понимания материал. Хотя если Вы изучали C или ASM для Вас должно быть всё тривиально.

Страницы : 1 2 3 4