Алгоритм пламени
Материал из DRKB
Заведем два массива 1 и 2 - один массив будет содержать текущий кадр пламени, а во второй мы будем заносить результаты вычислений. Создадим палитру пламени от 250 до 100 это будет сплошной белый цвет - пламя в очаге. Далее белый, плавно проходя через желтый, перейдет в красный и черный. Эту палитру можете посмотреть если определен Debug.
В чем состоит основа алгоритма - для каждой точки из массива 1, мы делаем следующее : берем сумму всех окружающих ее точек и делим на их количество. Для хорошего качества точек берем 8. Что же получается? Если очаг пламени организовать внизу, т.е. внизу на каждом шаге случайно ставить точки с большим значением, усредненные суммы дадут нужное затухание. Т.к. мы ставим в очаге точки случайно, то появляются красивые языки.
Последовательность действий:
- Массив 1 содержит текущий кадр пламени.
- Создаем в массиве 1 внизу случайные очаги (просто ставим точки)
- Каждый элемент массива 2 получаем как усредненную сумму, соответствующих элементов окружающий данный в массиве 1
- Массив 2 копируем на экран
- Переносим массив 2 в массив 1
- Переход на начало Для программы требуется модуль demovga.pas
{.$DEFINE DEBUG}
program Fire;
uses DemoVga, Crt;
type
PFireMem = ^TFireMem;
TFireMem = array[0..201, 0..319] of Byte;
var
FireMem: PFireMem;
I, J: Integer;
R, G, B, dR, dG, dB: Real;
procedure PlotFireHead;
var
i: Integer;
begin
for i := 0 to 319 do
if Random(2) = 1 then
begin
FireMem^[199][i] := 255;
FireMem^[198][i] := 255;
end;
end;
procedure FireLoop; assembler;
asm
Push DS
Les DI,DBuffer
Lds SI,FireMem
Add SI,320*2
Mov CX,64000
@@F:
Xor AX,AX
Add AL,[SI-321]
Adc AH,0
Add AL,[SI-320]
Adc AH,0
Add AL,[SI-319]
Adc AH,0
Add AL,[SI-1]
Adc AH,0
Add AL,[SI+1]
Adc AH,0
Add AL,[SI+319]
Adc AH,0
Add AL,[SI+320]
Adc AH,0
Add AL,[SI+321]
Adc AH,0
Shr AX,3
Or AL,AL
Jz @@1
Dec AL
@@1:
Stosb
Inc SI
Loop @@F
Pop DS
end;
begin
InitDemoPart;
GetMem(FireMem, 65000);
R := 0; G := 0; B := 0;
dR := 0.63; dG := 0.91; dB := 1.5;
for I := 1 to 100 do
begin
SetRGBColor(I, Round(R), Round(G), Round(B));
R := R + dR;
if I > 30 then G := G + dG;
if I > 60 then B := B + dB;
end;
for I := 100 to 250 do
SetRGBColor(I, 60, 60, 60);
{$IFDEF DEBUG}
for I := 1 to 100 do
for J := 1 to 100 do
Mem[$A000: J * 320 + I] := I;
ReadKey;
{$ENDIF}
FillChar(FireMem^, 65000, 0);
repeat
PlotFireHead;
FireLoop;
Move(DBuffer^, FireMem^, 64000);
Move(DBuffer^, Ptr($A000, 0)^, 64000-320*4);
until KeyPressed;
ReadKey;
FreeMem(FireMem, 65000);
RestoreDemo;
end;
ID: 04241