Алгоритм пламени

Материал из 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