Главная » 2D графика » Быстрая работа с графикой в среде Windows

RSS

Быстрая работа с графикой в среде Windows

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

Быстрая работа с графикой

Пример быстрой работы с графикой в среде Windows без использования средств DirectX
Совместимость: Windows 95, 98, NT, 2000, Me, TrE, XP, Whistler, Tristler :) )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
type
TfmMain = class(TForm)
pbDraw: TPaintBox;
Timer1: TTimer;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
procedure CreateBitmap(aSX, aSY: Integer);
procedure RecreateBitmap(aSX, aSY: Integer);
procedure DeleteBitmap;
procedure RestrictSize(var msg: TMessage); message WM_GETMINMAXINFO;
procedure pbDrawPaint(Sender: TObject);
private
ScrBitmap: TBitmap;
Scr: Pointer;
SX, SY: Integer;

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
type
 
TBig = array[0..0] of Integer;
 
procedure TfmMain.CreateBitmap(aSX, aSY: Integer);
var
BInfo: tagBITMAPINFO;
begin
// Создание DIB
SX := aSX; SY := aSY;
BInfo.bmiHeader.biSize := sizeof(tagBITMAPINFOHEADER);
BInfo.bmiHeader.biWidth := SX;
BInfo.bmiHeader.biHeight := -SY;
BInfo.bmiHeader.biPlanes := 1;
BInfo.bmiHeader.biBitCount := 32;
BInfo.bmiHeader.biCompression := BI_RGB;
ScrBitmap := TBitmap.Create();
ScrBitmap.Handle := CreateDIBSection(Canvas.Handle, BInfo, DIB_RGB_COLORS, Scr, 0, 0);
ZeroMemory(Scr, SX * SY * 4);
end;
 
procedure TfmMain.DeleteBitmap;
begin
// Удаление DIB
ScrBitmap.FreeImage();
ScrBitmap.Destroy;
end;
 
procedure TfmMain.RecreateBitmap(aSX, aSY: Integer);
var
BInfo: tagBITMAPINFO;
begin
// Пересоздание DIB при изменении размеров "экрана"
ScrBitmap.FreeImage();
SX := aSX; SY := aSY;
BInfo.bmiHeader.biSize := sizeof(tagBITMAPINFOHEADER);
BInfo.bmiHeader.biWidth := SX;
BInfo.bmiHeader.biHeight := -SY;
BInfo.bmiHeader.biPlanes := 1;
BInfo.bmiHeader.biBitCount := 32;
BInfo.bmiHeader.biCompression := BI_RGB;
ScrBitmap.Handle := CreateDIBSection(Canvas.Handle, BInfo, DIB_RGB_COLORS, Scr, 0, 0);
ZeroMemory(Scr, SX * SY * 4);
end;
 
procedure TfmMain.FormCreate(Sender: TObject);
begin
CreateBitmap(pbDraw.ClientWidth, pbDraw.ClientHeight);
pbDraw.Canvas.Draw(0, 0, ScrBitmap);
Caption := 'Визуализатор'; Application.Title := Caption;
end;
 
procedure TfmMain.FormDestroy(Sender: TObject);
begin
DeleteBitmap();
end;
 
procedure TfmMain.FormResize(Sender: TObject);
begin
ReCreateBitmap(pbDraw.ClientWidth, pbDraw.ClientHeight);
pbDraw.Canvas.Draw(0, 0, ScrBitmap);
end;
 
procedure TfmMain.RestrictSize(var msg: TMessage);
var
p: PMinMaxInfo;
begin
// Ограничитель размеров окна (обработка сообщений Windows).
// Удобная вещь кстати (важно: см. объявление процедуры в классе TFmMain)
p := PMinMaxInfo(Msg.lParam);
p.ptMinTrackSize.x := 520;
p.ptMinTrackSize.y := 240;
end;
 
procedure TfmMain.pbDrawPaint(Sender: TObject);
begin
pbDraw.Canvas.Draw(0, 0, ScrBitmap);
end;

Пример работы с данной конструкцией

  • SX – текущий размер нашего «экрана» по горизонтали
  • SY – по вертикали
  • TBig(Scr^). Scr – это указатель на массив пикселей битмапа, который в нашем случае имеет разрядность 32 (32 бита, или 4 байта на пиксел, что эквивалентно типу Integer. См. объявление типа TBig).

Конструкция TBig(Scr^) позволяет адресовать эту память как массив пиксел. Чтобы получить доступ к пикселу нужно использовать индекс массива [x + y * SX].

Функция RGB.

Это стандартная делфяцкая функция, не приспособленная для того что мы тут творим, а только для своего «родного» класс TCanvas и его цветовых кодов. В Windows при использовании 32-разрядных битмапов формат пиксела такой (начиная с первого байта):

BBBBBBB GGGGGGGG RRRRRRRR ********

В Delphi (то что ВСЕГДА возвращает функция RGB, при любой разрядности картинки):

RRRRRRRR GGGGGGGG BBBBBBBB ********

Усматривается аналогия :) Все что нужно это просто перечислить аргументы функции в обратном порядке :) )

Big(Scr^)[x + y * SX] := RGB(B, G, R);

B, G, R – соответственно значения интенсивности синего, зеленого, и красного цветов размером байт, т.е. [0..255].

Палитра 32-разрядным режимом не поддерживается, за нас думает Windows (вернее, понятия палитры в таком режиме вообще нет). Ну а нам остается это все юзать как надо +)))

Чтобы почистить виртуальный экран, нужно сделать так: ZeroMemory(Scr, SX * SY * 4);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
procedure TfmMain.Timer1Timer(Sender: TObject);
var
x, y: Integer;
begin
// В цикле рисуется полная левота. Рисуйте тут свою левоту :)
for x := 0 to SX - 1 do for y := 0 to SY - 1 do
TBig(Scr^)[x + y * SX] := RGB(Random(256),Random(256),Random(256));
// При желании, используем средства Delphi на объекте ScrBitmap типа TBitmap
// в т.ч. можно нарисовать на нем другой Bitmap с помощью функции
// ScrBitmap.Canvas.Draw(x,y,AnotherBitmap);
// Чтобы текст выглядел красивее (без фона), раскомментируйте строки
// SetBkMode(ScrBitmap.Canvas.Handle, TRANSPARENT);
ScrBitmap.Canvas.Font.Size := 24;
ScrBitmap.Canvas.TextOut(10, 10, 'Demo');
// SetBkMode(ScrBitmap.Canvas.Handle, OPAQUE);
// Нарисуемся
pbDrawPaint(Self);
end;

В примере я (Мироводин Дмитрий) добавил вывод значения FPS, и несколько заменил процедуру заполнения массива пикселями. Дело в том, что функция Random является достаточно долгой по времени выполнения (причем всегда с разным) и по этому я заменил ее на более простую – TBig(Scr^)[x + y * SX] := RGB(254,200,23); Т.е. простая «заливка». При таком подходе Вы можете оценить реальную скорость работы цепочки заполнение памяти – отрисовка.

Итак значения примерно следующие:

  • полный экран 800×600 – 70-80 ms
  • с использованием Random – 100-120 ms

Исходный код примера

Copyright © Koster
Greetz to: Vano aka RIS, Uras aka Assargadon
Special thanx to: Leon the Trillennium

Таги: , ,