NoName 4 (3/00)
www.noname.zum.pl
Wstęp
Współpraca
Redakcja
Prenumerata
Adverty
Bonus
Ciekawe strony
Strony czytelników
Pomoc dla NoName
Podkład muzyczny
Poważne teksty
Ból
Bóg - kontra jARRodxa
Bóg - kontra Cactoosa
Bóg - kontra Nowaczka
Bóg - kontra Oddiego
Bóg - kontra Ninghijzhinda
Bóg jest miłością
Pioruny
Państwo idealne!
Sposób na wkucie
Atom bomb
Tolkien
Czy warto medytować?
Jak to zrobić?
Usłysz, czego ucho...
C Y B E R K U L T U R A...
Star Wars Customizable...
Utopia
Co jest madre, a co glupie
Człowiek w cylindrze
Elektrownia atomowa w...
Tego Nostradamus nie...
Zabawne teksty
Humor by Sergiusz
Usuwanie Problemów...
Dramatyczna historia...
Słoń a sprawa polska
Pamiętnik policjanta
Komputery
Grafikiem być (?)
Jak rozpalić ogień...
IRC - cień z drugiej strony
Jak zwiększyć popularność...
Piractwo
Kevin Mitnick...
Test na lamera...
Moralność crackerów
Internet
Plagiat
Bezpieczeństwo w sieci
Historia z życia pewnej...
Poezja
Pieśń nie pieśń
Opowiadania
Nieuniknione
Mechy
Dzikie Pola
Wstęp
Przyjaźń szlachecka...
Muzyka
PanterA

Jak rozpalić ogień w 3 krokach ?

programowanie grafiki dla początkujących

      Oglądałeś kiedyś jakieś starsze demko demoscemowe ? Przypuszczam że tak (jeśli nie to wejdź na ww.hornet.org - tam jest tego cała masa). Na pewno widziałeś w jednym z nich (często też w intrach scenowych) efekt graficzny spalania -ogień. Na początku pomyślałeś pewnie - "jak oni to zrobili to niemożliwe !?", póxniej pewnie zacząłeś się nad tym głębiej zastanawiać. Jeśli do tej pory jeszcze do niczego konkretnego nie doszedłeś, a nadal chcesz zrobić swój własny, niepowtarzalny efekt graficzny ognia to usiadź wygodnie i czytaj dalej...

Krok 1
TEORETYCZNY ZARYS TWORZENIA PŁOMIENI PRZY POMOCY KARTY VGA.
(czyli jak to w ogóle działa ?:))

      Widziałeś kiedyś płomień ? Na pewno tak. Jaki on jest ? Najjaśniejszy (czyli najbardziej czerwony :)) jest on u swej podstawy a wyciemnia się w miarę wznoszenia. Do tego jego płomienie biegną w górę nieregularnie- powiedzmy w losowo wybranych kierunkach. Tak samo będzie wyglądał nasz symulowany/programowy płomień, tylko że on będzie działał tylko na płaskiej powierzchni i nie będzie mógł się wypalić (to chyba jego plus:)), tak jak to zwykł robić naturalny płomień. Ok., znasz już podstawy. Dzwoń po straż pożarną - niech będą w pogotowiu - przechodzimy do kroku nr 2....

Krok 2
CO BĘDZIE NAM POTRZEBNE ?
(czyli opis wszystkiego oprócz kompilatora).

      Aby w ogóle zacząć cokolwiek pisać musimy przełączyć się z tekstowego w tryb graficzny. Na kartach VGA (a o takie nam chodzi) jest stosunkowo dużo trybów do wyboru, my jednak zajmiemy się implementacją trybu o wdzięcznym numerze 13h, ze względu na jego dość duże możliwości przy małym stopniu trudności. Aby wydusić z karty VGA tryb 13h należy użyć następującej wstawki assemblerowej:

...
asm{mov ah,0 // w AH musi być zero
mov al,13h // a w AL. numer trybu - tu 13h
int 10h} // włączamy powyższe przez przerwanie karty- 10h        ...

Aby wrócić spowrotem do trybu tekstowego zamiast 13h prześlij do al. 03h.

Przykładowa funkcja do zmiany trybów w języku C może wyglądać następująco:

tryb(unsigned char tryb)
{
asm
{mov ah,0
mov al,tryb
int 10h
};

Okiej ta funkcja nie jest trudna do zrozumienia, więc możemy przejść dalej.

Jako że postanowiłem zrobić mały ogień o wysokości 63 pixeli (to możesz potem b. łatwo zmienić), potrzebujemy więc 63 odcieni czerwieni. Zeby nie utrudniać sprawy i szukać tych kolorów niwiadomo gdzie po standardowej palecie, proponuję zaprogramować własną paletę - składającą się tylko z 64 składników. Jak to zrobić ? Bardzo łatwo wystarczy że:

  • powiesz komputerowi że chcesz zmieniać rejestry palety kolorów,
  • powiesz że chcesz do nich zapisywać (a możnaby też odczytywać :)),i wktórym indeksie palety chcesz grzebać,
  • prześlesz kolejno do rejestru danych karty składniki RGB dla wyżej wymienionego koloru.
  • i już.

Aby to zaimplementować trzeba wiedzieć jeszcze o kilku innych ważnych rzeczach:

  • otóż maska palety kolorów to 0x3c6
  • maska dla oznaczenia rejestru do zapisu to 0x3c8
  • maska dla rejestru do odczytu to 0x3c7
  • maska dla składników rgb wybranego koloru to 0x3c9 - i tu właśnie trzeba przesłać wszystkie dane o kolorze :)

Okiej. Wszystko już wiesz. Trzeba to zaimplementować !

Najpierw zadeklarujemy jako stałe maski palety:

(w języku C najepiej je po prostu zdefiniować)

...
#define PALETTE_MASK        0x3c6
#define PALETTE_REGISTER_RD 0x3c7
#define PALETTE_REGISTER_WR 0x3c8
#define PALETTE_DATA        0x3c9
...

Aby przesłać kolory do palety można to zrobić kolejno, bezpośredni, ale my żeby było ciekawiej użyjemy do oznaczenia koloru RGB bardzo prostej struktury danych:

...
typedef struct RGB_color_typ
{
unsigned char red;
unsigned char green;
unsigned char blue;
}RGB_color,*RGB_color_ptr;
...

Proste co nie, ta struktura jest tylko opcją, więc jeśli tworzenie struktur sprawia Ci jakiekolwiek trudności olej to i zrób po swojemu :)

Teraz trzeba by napisać funkcję zmieniającą podany kolor. TA funkcja może wyglądać tak:

...
void Set_Palette_Register(int index, RGB_color_ptr color)
{
outp(PALETTE_MASK,0xff); // ustawienie maski palety
outp(PALETTE_REGISTER_WR, index); // ustawienie indeksu w którym będziemy zapisywać
outp(PALETTE_DATA,color->red); // przesłanie danych ze struktury, ale możesz też przesyłać to w inny sposób
outp(PALETTE_DATA,color->green);
outp(PALETTE_DATA,color->blue);
}
...

Aby poprawnie ustawić kolor to jak już pewnie skapowałeś trzeba najpierw odpowiednio wypełnić strukturę.

Dobra jest, idzie nam całkiem dobrze :) Mam nadzieję że po tym nudzeniu jeszcze się nie zniechęciłeś - ale wierz mi operacje na palecie naprawdę Ci się przydadzą - możan dzięki temu tworzyć naprawdę bajer efekty - fady itp.

Jeśli mamy już kolor to trzeba o takim kolorze wyświetlić pixel. To chyba najłatwiejsza sprawa w tym punkcie :)

Aby zaimplementować funkcję wyświetlającą pixel musisz wiedzieć tylko, że:

  • bufor karty VGA to najzwyklejszy w świecie, ciągły ciąg znaków (przez to to wszystko jest takie proste),
  • zaczyna się on w pamięci od adresu A000:0000 a kończy się na A000:F9FF, i ma dokładnie 64000 bajtów (bo jeden pixel to 1 bajt),
  • aby obliczyć współrzędną punktu na ekranie, jako że bufor VGA jest ciągiem/jednowymiarową tablicą musisz:
    • pomnożyć współrzędną y przez 320,
    • dodać współrzędną x do wyniku,
    • przesunąć się o tyle w buforze video,
    • zapisać pod ten adres wartość z zakresu 0-255 - czyli wartość koloru.

Prawda że proste ! W praktyce wygląda to mniej więcej tak:

...
unsigned char far *video_buffer = (char far *)0xA0000000L;
... // wskaźnik na pamięć VIDEO
...
void Pixel(int x, int y, unsigned char color)
{
video_buffer[y*320+x]=color;
}
...

I już - pyk,cud i na ekranie świeci się kropeczka (kwadracik:))! Potrzebna będzie nam jeszcze funkcja do pobierania koloru pixela, ale jest to tak proste że nie będę się o tym teraz rozpisywał...

Wszystko już wiemy, wszystko już mamy. Teraz przechodzimy do następnego punktu, by wreszcie wziąć się za konkrety ..

Krok 3
IMPLEMENTACJA OGNIA.
(czyli implementacja ognia ! (nareszcie)).

Teraz już pójdzie z górki. Najpierw ustawiamy potrzebną nam paletke, składajacą się z 64 odcieni czerwieni. To naprawdę BARDZO proste, funkcja w języku C będzie wyglądć tak:

void Paletka(void)
{
RGB_color color;
int index;
for (index=0; index < 64; index++)
   {
    Get_Palette_Register(index,(RGB_color_ptr)&color);
    color.red = index;     color.green = 0;
    color.blue = 0;
   Set_Palette_Register(index, (RGB_color_ptr)&color);

   }
}

To bardzo proste - z łatwoscią możesz teraz przekonwertować to na dowolny język programowania !

Teraz trzeba dolać troche paliwa - czyli wygenerować w dole ekranu linię o najjaśniejszym kolorze (bo u podstawy ogień jest najjaśniejszy).

Funkcja to robiaca wygląda tak:

void Podst()
{
int i;
for(i=0;i<320;i++)
Pixel(i,199,63);
};

Po prostu w pętli stawia kolejne pixele o współrzędnej y=199 i x=x++.

Teraz najciekawsza funkcja ze wszystkich - palenie.

Aby palić trzeba po prostu w pętli sprawdzać kolejno od góry czy poniżej jest ogień (czyli czy poniżej jest kolor jaśniejszy od 3). Jak jest to trzeba go zmniejszyć o losową liczbę z przedziału 1..3 - żeby się wygasał. Nie można sprawdzać tylko ostatniej lini - 199 bo ogień by się wypalił. Aby ogień nie szedł pionowo w górę tylko naturalnie płonął należy dać mu jakieś przesunięcie. Można to zrobić przez sprawdzanie punktu nie przez getpixel(x,y+1), tylko getpixel(x+random(3)-1,y+1). Prawda że proste ! Teraz wystarczy to zaimplementować:

...
Burn()
{
int x,y;
int c;
for(y=0;y<199;y++)
for(x=0;x<320;x++)
{
c=Get_Pixel(x+(rand()&30)/10-1,y+1);
if(c>3)
Pixel(x,y,c-(rand()&30)/10-1);
}
};
...

I już napisałeś efekt ognia ! tylko skompilować i cieszyć się płomieniami.

Efekt ten możesz oczywiście dowolnie przerabiać - fajnie wygląda np. zielony ogień.

Możesz spalać obrazki itp.. (efekt - Burning :: ZONE).

Poniżej pełne kody przykładowego programu w języku c:

//////////////////////////////////////////////////////////////////////////////////
///// Biblioteka graficzna dla trybu 13h karty VGA - PioTraK (c) 2000 Piotrak //////
/////                          Tylko do wglądu !!!                          //////
//////////////////////////////////////////////////////////////////////////////////
#include <io.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <bios.h>
#include <fcntl.h>
#include <memory.h>
#include <math.h>
#include <string.h>

////////////////////////////////// Definicje /////////////////////////////////////
#define PALETTE_MASK        0x3c6
#define PALETTE_REGISTER_RD 0x3c7
#define PALETTE_REGISTER_WR 0x3c8
#define PALETTE_DATA        0x3c9
unsigned char far *video_buffer = (char far *)0xA0000000L;
/////  Struktura danych: RGB_color (kolory: czerwony, zielony, niebieski)   //////
typedef struct RGB_color_typ
{
unsigned char red;
unsigned char green;
unsigned char blue;
}RGB_color,*RGB_color_ptr;

////////////////// Ustawienie rejestru palety kart VGA ///////////////////////////
void Set_Palette_Register(int index, RGB_color_ptr color)
{
outp(PALETTE_MASK,0xff);
outp(PALETTE_REGISTER_WR, index);
outp(PALETTE_DATA,color->red);
outp(PALETTE_DATA,color->green);
outp(PALETTE_DATA,color->blue);
}

//////////////////////// Pobranie wartosci rejestru palety ///////////////////////
void Get_Palette_Register(int index, RGB_color_ptr color)
{
outp(PALETTE_MASK,0xff);
outp(PALETTE_REGISTER_RD, index);
color->red = inp(PALETTE_DATA);
color->green = inp(PALETTE_DATA);
color->blue = inp(PALETTE_DATA);
}

///////////////////// Stworzenie fantastycznej palety kolorow ////////////////////
void Paletka(void)
{
RGB_color color;
int index;
for (index=0; index < 64; index++)
   {
    Get_Palette_Register(index,(RGB_color_ptr)&color);
    color.red = index;
    color.green = 0;
    color.blue = 0;
   Set_Palette_Register(index, (RGB_color_ptr)&color);

   }
}

////////////////////// Funkcja do rysowania lini pionowej ////////////////////////
void Linia_V(int y1, int y2, int x, unsigned int color)
{
unsigned char far *video_buffer = (char far *)0xA0000000L;
unsigned int line_offset, index;
line_offset =((y1<<8)+(y1<<6))+x;
for(index=0; index<=y2-y1; index++)
{
video_buffer[line_offset]= color;
line_offset+=320;
}
}

/////////////////////// Funkcja do rysowania lini poziomej ///////////////////////
void Linia_H(int x1, int x2, int y, unsigned int color)
{
unsigned char far *video_buffer = (char far *)0xA0000000L;
_fmemset((char far *)(video_buffer + ((y<<8)+(y<<6))+x1),
color,x2-x1+1);
}

////////////////////////// Funkcja do rysowania pixela ///////////////////////////
void Pixel(int x, int y, unsigned char color)
{
unsigned char far *video_buffer = (char far *)0xA0000000L;
video_buffer[y*320+x]=color;
}

unsigned char Get_Pixel(int x,int y)
{
return video_buffer[((y<<8) + (y<<6)) + x];
};

void Podst()
{
int i;
for(i=0;i<320;i++)
Pixel(i,199,63);
};

Burn()
{
int x,y;
int c;
for(y=0;y<199;y++)
for(x=0;x<320;x++)
{
c=Get_Pixel(x+(rand()&30)/10-1,y+1);
if(c>3)
Pixel(x,y,c-(rand()&30)/10-1);
}
};

/////////////////////////////////// Funkcja glowna ///////////////////////////////
void main(void)
{
int a;
RGB_color color, color_1;
asm{mov ah,0
mov al,13h
int 10h
}
Paletka();
Podst();
while(!kbhit())
Burn();
}

Dla magazynu NoName:
PioTraK - piotrak@box43.gnet.pl



Banner przyjaciela