Главная » 2D графика » Низкоуровневая загрузка растра

RSS

Низкоуровневая загрузка растра

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

Загрузка растра из файла

Рассмотренный выше способ довольно прост в реализации, но не очень гибок, хотя и применяется в большинстве коммерческих продуктов. Он не подходит для большинства больших игр – разве Вы видели файл типа Dialblo.exe размеров ~600 МБ :) … нет вот и я не видел, а вот файлы типа gamedata.dat размерами 1 Гб пожалуйста.

Для дальнейшего изучения материала необходимо знание внутренней структуры BMP файла, по этому я отправлю Вас на изучение моей статьи Обзор формата DIB и компонентов для работы с ним. Итак приступим.

Для начала необходимо наметить алгоритм загрузки файла: это подготовка структур, последовательное считывание структур из файла, создание растра. Т.е. в результате подобных действий у нас получится указатель на HBitmap.

В настоящее время широко используются растры двух форматов 24 битные и 8 битные. 24-х битные обычно применяются в качестве текстур, фонов и т.д., а 8-ми битные до сих пор применяю для хранения спрайтов. Да, да, 8 битные растры до сих пор в моде, хороший пример тому культовая игра Heroes III (на счет четвёрки не знаю).

По этому я напишу две разные процедуры для загрузки растров, хотя можно было бы объединить их в одну, но зачем на делать лишние проверки ? Ведь при загрузке мы точно знаем какой тип растра загружаем.

Первым делом объявим глобальную переменную для хранения загруженного растра:

1
2
3
4
5
Var// Переменная для хранения растра
Bitmap : HBITMAP;

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

1
2
3
const
Bitmap24bitFileName='..\Resource\some24bit.bmp';
Bitmap8bitFileName='..\Resource\some8bit.bmp';

Конечно можно передавать их самим процедурам загрузки, но это уже тонкости реализации. Сначала я рассмотрю процедуру для загрузки 24-х битного растра, т.к. у него нет палитры и это несколько упрощает дело. Объявляем необходимые переменные:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
procedure LoadBitmap24bit(const hWindow: THandle);
var
// Файл
F : File;
// Заголовочные структуры
BitmapFileHeader : TBITMAPFILEHEADER;
BitmapInfoHeader : TBITMAPINFOHEADER;
BitmapInfo : TBitMapInfo;
// Указатель на массив битов
BitmapBits : Pointer;
// Счетчик чтения файла
ReadCount : DWORD;
// Контекст устройства
DC : HDC;

Сама процедура выглядит так:

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
37
38
39
40
41
42
// Открытие файла и установка на начало
AssignFile(F, Bitmap24bitFileName);
Reset(F, 1);
// Чтение заголовка TBitmapFileHeader
BlockRead(F, BitmapFileHeader, SizeOf(TBitmapFileHeader), ReadCount);
if (ReadCount <> SizeOf(TBitmapFileHeader)) then
begin
  MessageBox(hWnd, 'Ошибка чтения BITMAPFILEHEADER', 'DIB From File Sample', MB_OK+MB_ICONERROR);
  CloseFile(F);
  Exit;
end;
// Чтение заголовка TBitmapInfoHeader
BlockRead(F, BitmapInfoHeader, SizeOf(TBitmapInfoHeader), ReadCount);
if (ReadCount <> SizeOf(TBitmapInfoHeader)) then
begin
  MessageBox(hWnd, 'Ошибка чтения TBITMAPINFOHEADER', 'DIB From File Sample', MB_OK+MB_ICONERROR);
  CloseFile(F);
  Exit;
end;
// Выделение памяти под массив битов
GetMem(BitmapBits, BitmapInfoHeader.biSizeImage);
// Чтение массива битов, т.е. непосредственно битового образа
BlockRead(F, BitmapBits^, BitmapInfoHeader.biSizeImage, ReadCount);
if (ReadCount <> BitmapInfoHeader.biSizeImage) then
begin
  MessageBox(hWnd, 'Ошибка чтения данных файла.', 'DIB From File Sample', MB_OK+MB_ICONERROR);
  CloseFile(F);
  Exit;
end;
// TBitmapInfo нужна только для функции CreateDIBitmap, по этому приходится инициализировать и её
BitmapInfo.bmiHeader:=BitmapInfoHeader;
// Получение контекста устройства
// Вотзачем нам потребовалось передавать дискриптор окна !
DC:=GetDC(hWindow);
// Создание битмапа из инициализорованных структур
Bitmap:=CreateDIBitmap(DC, BitmapInfoHeader, CBM_INIT, BitmapBits, BitmapInfo, DIB_RGB_COLORS);
// Освобождаем контекста устройства
ReleaseDC(hWindow, DC);
// Небольшая проверочка напоследок
if Bitmap=0 then
  MessageBox(hWnd, 'Ошибка создания растра.', 'DIB From File Sample', MB_OK+MB_ICONERROR);
CloseFile(F);

В принципе, ничего лишнего. Единственно что можно оптимизировать, так это получение контекста устройства внутри процедуры, отключение проверок и попробовать считывать TBitmapInfo, а то он лежит у нас практически до конца процедуры «мертвым грузом».

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

Таги: , , ,