Plazma (shade bobs)

    -- Sebastian Pawlak, 1995.


Jeżeli ktoś chce napisać grę lub zakodować demo musi liczyć się z tym, że aby jego produkt był naprawdę dobry powinien zawierać jakieś ciekawe efekty graficzne. Często stosuje się skomplikowane skrolingi tekstu, rotacje obrazu, projekcję obiektów 3D oraz wiele innych. Jednak najczęściej spotkać można efekt tzw. "plazmy". Nie można tu podać żadnej konkretnej definicji jak powinna wyglądać plazma. U niektórych autorów przypomina ona mgłę, a u innych wzburzoną kałużę z olejem samochodowym. To tylko dwa z prostszych do opisania słowami efektów, których można stworzyć dziesiątki. Osobiście nie widziałem dwóch identycznych plazm, chodź bywały one niekiedy podobne.

Program, który napisałem jest bardzo prosty, a plazma powstająca w wyniku jego działania dość efektowna. W tym momencie mam wątpliwości czy to coś jest w ogóle plazmą. Niektórzy stwierdziliby, że tak a inni, że nie. Zdania na ten temat byłyby podzielone.

Przejdźmy teraz do opisu algorytmu.
Opiera się on na przesuwaniu po ekranie kwadratu, który podczas kreślenia dla każdego swojego punktu wyświetla piksel o wartości odpowiadającej mu komórki pamięci ekranu zwiększonej o jeden. Dla przykładu, gdybyśmy cały czas odbijali nasz kwadrat w tym samym miejscu to wartość każdego punktu ekranu w obrębie wyświetlanego obiektu była by: 0, 1 , 2 , 3 , ... , 255 , 0 , 1 , 2 , ... . Kwadrat przesuwany jest o losowo wybraną liczbę dla osi X i Y.

Oto, program do wpisania i uruchomienia:


(*          "PLAZMA"          *)
(*  autor:  Sebastian Pawlak  *)
(*  marzec 1995 r.            *)
Program Plazma;
Uses Crt;
Var   X_Kwadr,Y_Kwadr:integer; {Pozycja kwadratu.}
      Nr_Kol:byte; {Numer ustawianego koloru.}
Const Bok:byte=50; {Wielkość boku kwadratu.}

{Kreśli specjalny kwadrat do plazmy.}
Procedure Kwadrat (Poz_X,Poz_Y:word;Bok:byte); Assembler;
Asm
 Mov ax,0a000h  {Ustawienie rejestru ES na segment pamięci}
 Mov es,ax    {ekranu (musi być ustawiany za każdym razem,}
   {ponieważ np. procedura Delay również wykorzystuje ES i}
   {po jej wstawieniu bez ustawiania ES komputer może się}
   {zawiesić).}
 {Obliczanie adresu odpowiadającego pozycji Poz_X, Poz_Y}
 {na ekranie, Poz_na_ekr=Poz_Y*Szerokość_ekr+Poz_X.}
 Mov bx,Poz_Y {Rejestr bx zawiera pozycje Y.}
 Mov cl,6     {Rejestr cl zawiera wartość 6.}
 Shl bx,cl    {Mnożenie pozycji Y przez 64.}
 Mov cx,bx    {Rejestr cx zawiera wynik mnożenia Y*64.}
 Shl bx,1     {Mnożymy wysokość Y przez 2, i przez 2, gdyż}
 Shl bx,1     {jest to szybsze niż mnożenie przez 4.}
 Add bx,cx    {BX=BX+CX lub BX=Poz_Y*64*2*2+Poz_Y*64.}
 Add bx,Poz_X {BX=BX+Poz_X lub BX=Poz_Y*256+Poz_Y*64+Poz_X.}
 {Od tej chwili rejestr BX zawiera pozycje w pamięci ekr.}
 {odpowiadającą lewemu górnemu rogowi kwadratu.}
 Mov dx,word ptr [Bok] {Rejestr DX zawiera wielkość boku.}
 Mov cx,dx    {CX zawiera DX (Bok).}
@Nastepny_wiersz:
 Push cx               {Odkłada na stosie wartość rej. CX.}
 Mov cx,dx             {Rejestr CX zawiera DX (Bok).}
@Nastepny_piksel_wiersza:
 Mov al,es:[bx] {Pobiera wartość piksela z pamięci.}
 Inc al         {Zwiększa wartość tego piksela o jeden.}
 Mov es:[bx],al {Zapisuje tę wartość na to samo miejsce.}
 Inc bx         {Zwiększa pozycję w pamięci o jeden bajt.}
 Loop @Nastepny_piksel_wiersza {Następny punkt wiersza.}
 Sub bx,word ptr [Bok] {Ustawienie pozycji w pamięci}
 Add bx,320            {dla następnego wiersza, poprzez:}
   {odjęcie od ostatniej pozycji wartości boku i dodanie}
   {szerokości ekranu.}
 Pop cx    {Podniesienie ze stosu wartości pozycji Y dla}
           {kolejnego wiersza kwadratu.}
 Loop @Nastepny_wiersz {Następny wiersz.}
End;

{Ustawia barwę dla danego koloru.}
Procedure SetRgbPalette (Nr_Kol,R,G,B:byte); Assembler;
Asm
 Mov bx,word ptr [Nr_Kol] {BX zawiera numer koloru.}
 Mov dh,R   {Poszczególne wartości składowych barwy.}
 Mov ch,G
 Mov cl,B
 Mov ah,10h {Funkcja 10h - ustawienie RGB dla palety.}
 Mov al,10h {Podfunkcja 10h - wartości dla jednego koloru.}
 Int 10h    {Wywołanie przerwania 10h.}
End;

Begin
 Asm
  Mov ax,13h {Inicjuje tryb graficzny 13h, 320x200 256 kol.}
  Int 10h
 End;

 {Ustawianie barw kolorów w palecie.}
 For Nr_Kol:=0 to 85 do
  SetRgbPalette (Nr_Kol,0,Nr_Kol div 2,0);
 For Nr_Kol:=86 to 169 do
  SetRgbPalette (Nr_Kol,(Nr_Kol-86) div 2,0,0);
 For Nr_Kol:=170 to 255 do
  SetRgbPalette (Nr_Kol,0,0,(Nr_Kol-170) div 2);

 Randomize; {Inicjuje działanie generatora liczb losowych.}
 Repeat
  {Pozycja X i Y kwadratu jest zwiększana albo zmniejszana}
  {o losową wartość.}
  X_Kwadr:=X_Kwadr+random (20)-10;
  Y_Kwadr:=Y_Kwadr+random (20)-10;
  {Jeżeli pozycja kwadratu jest większa niż 200-Bok lub}
  {mniejsza od 0 wtedy odpowiednio zmniejsza albo zwiększa}
  {jej wartość.}
  if X_Kwadr>200-Bok then X_Kwadr:=X_Kwadr-(200-Bok);
  if Y_Kwadr>200-Bok then Y_Kwadr:=Y_Kwadr-(200-Bok);
  if X_Kwadr<0 then X_Kwadr:=200-Bok+X_Kwadr;
  if Y_Kwadr<0 then Y_Kwadr:=200-Bok+Y_Kwadr;
  {Wyświetla przesunięty od 60 pikseli kwadrat.}
  Kwadrat (X_Kwadr+60,Y_Kwadr,Bok);
 Until KeyPressed; {Wyświetla kwadraty do czasu naciśnięcia}
                   {dowolnego klawisza.}
 Asm
  Mov ah,0ch {Czyszczenie bufora klawiatury po ostatniej}
  mov al,0   {funkcji KeyPressed, gdyż dalej też jest}
  int 21h    {testowana zawartość bufora klawiatury.}
 End;

 {Teraz wyświetlany jest jeden duży kwadrat, tam gdzie były}
 {wyświetlane poprzednio małe obiekty, co daje efekt}
 {"rozchodzenia" się kolorów.}
 repeat
  Kwadrat (60,0,200); {Wyświetla wycentrowany duży kwadrat.}
 until KeyPressed; {Wyświetla duży kwadrat do momentu}
                   {naciśnięcia dowolnego klawisza.}
 Asm
  Mov ax,3h {Inicjuje tryb tekstowy 3H, 80x25 16 kol.}
  Int 10h
 End;
End.

  Bez kłopotów można modyfikować program:
- zmieniać wielkość boku kwadratu,
- trochę zmieniony efekt uzyskuje się zwiększając
  parametr w funkcji Random, aby ruchy kwadratu stały
  się bardziej swobodne,
- można też ingerować w barwy poszczególnych kolorów,
  eksperymentując z parametrami procedury SetRgbPalette.

Mam nadzieję, że trud wpisania programu opłaci się, a algorytm znajdzie zastosowanie w jakichś pracach.


Literatura: 1. "Turbo Assembler  Biblia użytkownika"
                                         - Gary Syck,
            2. "Jak pisać Wirusy"    - Andrzej Dudek.
w3cw3c
automatyka przemysłowa