; Kod napisany przez Piotra Tarsę ; Linie zaczynające się od średnika są komentarzem i nie są brane pod uwagę ; przy kopilacji ; Program: Bum (wersja dwuwymiarowa - 2W). ; Opis: Program przedstawiający dziecinnie prosty do wykonania efekt graficz ; ny typu wybuch. Zrobiona przeze mnie wersja tego efektu jest dość znacznie ; uproszczona (dla większej czytelności kodu). Program działa w rozdzielczoś ; ci 320x200x256 kolorów. Korzysta z kernela przełączającego w tryb 32-bitow ; y autorstwa Mikołaja Feliksa (nie zawarłem tutaj jego kodu, gdyż objaśnien ; ie jego działania od strony technicznej i zasad pracy procesora (przede ws ; zystkim obliczania adresów bezwzględnych) w różnych trybach; użyty tutaj p ; rzeze mnie 32-bitowy tryb chroniony jest dość trudny do opanowania, więc d ; ołączyłem tylko skompilowany kernel (plik kernel.obj). Pobieżny opis dwóch ; najważniejszych trybów procesora zająby kilkanaście kilobajtów i nie jest ; potrzebny do zrozumienia działania poniższego programu. ; Algorytm: Program działa w pętli. Na początku inicjujemy wszystkie punkty: ; ich współrzędne ustawiamy na (0,0) - aby wybuch zaczął się od środka ekran ; u, a prędkości pionowe (vy) i poziome (vx) ustawiamy na losową wartość z m ; ałego przedziału. Potem zmniejszamy wartość koloru. Wartość ta jest zmniej ; szana z każdą klatką animacji, a więc punkty z czasem stają się coraz bard ; ziej ciemne. Po dojściu do zera kolor się przekręca i ma wartość 255 (jest ; zmienną typu bajt, a więc będzie przekręcał się co 256 klatek animacji). W ; każdym powtórzeniu pętli sprawdzane jest czy przypadkiem kolor nie przyjął ; wartości zero. W takim przypadku punkty są reinicjowane (dlatego początkow ; ą wartoś zmiennej kolor ustawiłem na 1 - aby na początku zainicjować wszys ; tkie punkty). Teraz rysujemy punkty: do współrzędnych x i y dodajemy korek ; ty odpowiednio x i y, aby wybuch było widać na środku ekranu i obliczamy p ; ozycję piksela w buforze ze wzoru: p = 320*y + x, ponieważ szerokość ekran ; u wynosi 320. W tym programie rysowane są kwadraty 2x2 zamiast pikseli, by ; były bardziej widoczne. Ważne jest też, by punkty nie wychodziły poza ekra ; n i nie były na jego brzegu - w takim przypadku nie rysujemy ich. Po narys ; owaniu punktów rozmazujemy obraz (rozmazywanie tutaj polega na zsumowaniu ; pikseli nad, pod, z lewej i z prawej aktualnego piksela i podzielenia wyni ; ku przez 4) i ściemniamy obraz o 1. Rysowanie odbywa się cały czas na tym ; samym ekranie, dzięki czemu widać tak jakby ślad po ruchu pikseli. Po nary ; sowaniu wszystkich punktów przetwarzamy je: do współrzędnych x i y dodajem ; y odpowiednio prędkości vx i vy (punkty poruszają się we wszystkie strony) ; , prędkości spowalniamy mnożąc je przez np: 0.95 (aby punkty poruszały się ; coraz wolniej) i dodajemy grawitację do prędkości pionowej (vy) - aby punk ; ty też powoli spadały w dół. Cały proces jest powtarzany dopóty, dopóki uż ; ytkownik nie naciśnie klawisza 'Esc' co kończy cały program. MAX_P equ 600 ; ilość punktów ; Program wykorzystuje interfejs DPMI, a więc musi być zainstalowany w pamię ; ci jakiś DOS extender typu CWSDPMI, EMM386 lub inny. Może też być wINDOW$ ; 32-bitowy. .486p locals code32 segment para public use32 ; używamy segmentów 32-bitowych, a więc assume cs:code32, ds:code32 ; mamy wszystko w jednym segmencie, tak ; jak pod wINDOZE global _main:proc ; potrzebne kernelowi global code32_base:dword ; zwrócone przez kernel dpmi_regs struc ; struktura potrzebna do wywołań przerwa _edi dd ? ; ń 16-bitowych w trybie 32-bitowym, par _esi dd ? ; ametry przekazywane są do tej struktur _ebp dd ? ; y, resztą zajmuje się DOS extender _none1 dd ? _ebx dd ? _edx dd ? _ecx dd ? _eax dd ? _flags dw ? _es dw ? _ds dw ? _fs dw ? _gs dw ? _none2 dw ? _none3 dw ? _sp dw ? _ss dw ? ends losuj proc mov bx,los_pom add bx,9248h ror bx,3 mov los_pom,bx mov ax,los_max sub ax,los_min mul bx mov ax,dx add ax,los_min ; ax - liczba losowa ret endp _main proc finit ; inicjujemy koprocesor matematyczny poczatek: ; alokujemy 64000 bajtów pamięci (na nasz bufor ekranu) mov cx,64000 ; rozmiar pamięci do zaalokowania podaje xor bx,bx ; my w BX:CX mov ax,0501h ; wybieramy funkcję alokowania pamięci int 31h ; wywołujemy host DPMI jc koniec ; jak błąd to kaplica shl ebx,16 mov bx,cx sub ebx,code32_base mov ax,si shl eax,16 mov ax,di mov uchwyt_bufora,eax ; uchwyt zwracany w SI:DI mov ekran,ebx ; adres bezwzględny BX:CX (ale przerobil ; iśmy go na względny, aby można go było ; używać) ; czyścimy nasz bufor ekranu mov edi,ebx xor eax,eax mov ecx,64000/4 cld rep stosd ; obliczamy względny adres VRAM - pamięć ekranu mov eax,0a0000h sub eax,code32_base mov _a0000h,eax ; ustaw tryb 13h (graficzny) mov ax,0300h mov bx,10h mov edi,offset _regs mov [edi._eax],13h int 31h ; podajemy numer koloru od którego zaczynamy (w tym przypadku 0) mov dx,03c8h xor ax,ax out dx,al ; zwiększamy numer portu (podawanie kolorów), i wysyłamy kolory (skala ; odcieni szarości). Podajemy składowe R, G, B. Maksymalna wartość któ ; rejkolwiek składowej wynosi 63 (bo wczesne karty graficzne VGA miały ; 6-bitowy przetwornik analogowo-cyfrowy (DAC) i tak pozostało, aby pr ; ogramy były kompatybilne z każdą kartą graficzną. Można włączyć 8-bi ; towy DAC, ale to jest rzadko używane (w tym programie też jest używa ; ny 6-bitowy DAC). inc dx ; za każdym razem ustawiamy 4 jednakowe kolory, zwiększamy jasność o j ; eden i tak w kółko 64 razy mov bx,64 paleta: mov cx,12 paleta_pentla: out dx,al loop paleta_pentla ; loopnięcie, czyli inaczej dec cx \ jnz inc al dec bx jnz paleta main_loop: ; siedzimy ostro w pętli dopóki użyszkod ; nik nie naciśnie eskejta dec kolor jnz jedziemy_dalej ; inicjujemy punkty mov ecx,MAX_P mov esi,offset punkt_tab inicjujemy_punkty: fldz ; ładujemy zero i ustawiamy nim współrzę fst dword ptr [esi] ; dne punktów (wybuch zaczyna się na śro fstp dword ptr [esi+4] ; dku ekranu) mov los_max, 12000 ; losujemy liczbę z przedziału 0...12000 call losuj ; , odejmujemy 6000 otrzymując wartość z sub ax,6000 ; przedziału -6000...6000, dzielimy prze mov fpom16,ax ; z skalę (700) i ustawiamy nią prędkość fild fpom16 ; vx fdiv skala fstp dword ptr [esi+8] call losuj ; to samo co wyżej dla prędkości vy call losuj ; dwa razy losuj, bo funkcja losuj jest sub ax,6000 ; niedoskonała mov fpom16,ax fild fpom16 fdiv skala fstp dword ptr [esi+12] add esi,16 ; przechodzimy do następnego punktu dec ecx ; jeżeli jeszcze coś zostało to powtarza jnz inicjujemy_punkty ; my pętlę jedziemy_dalej: ; zaczynamy wykonywanie punktów mov ecx,MAX_P mov esi,offset punkt_tab mov edi,ekran wykonuj_punkty: fld dword ptr [esi] ; ładujemy współrzędne punktu, dodajemy fadd korekta_x ; korekty x i y (aby wybuch był na środk fistp word ptr [xe] ; ku ekranu) i zapisujemy je w zmiennych fld dword ptr [esi+4] ; przechowujących współrzędne ekranowe fadd korekta_y fistp word ptr [ye] fld dword ptr [esi+8] ; ładujemy prędkość vx fadd dword ptr [esi] ; dodajemy do współrzędnej x fstp dword ptr [esi] ; zapisujemy wynik we współrzędnej x fld dword ptr [esi+12] ; ładujemy prędkość vy fadd dword ptr [esi+4] ; dodajemy do współrzędnej y fstp dword ptr [esi+4] ; zapisujemy wynik we współrzędnej y fld dword ptr [esi+8] ; ładujemy prędkość vx fmul delta_v ; spowalniamy deczko fstp dword ptr [esi+8] ; zapisujemy wynik w prędkości vx fld dword ptr [esi+12] ; ładujemy prędkość vy fmul delta_v ; spowalniamy deczko fadd grav ; dodajemy grawitację (aby sobie spadały fstp dword ptr [esi+12] ; zapisujemy wynik w prędkości vy cmp word ptr [xe],0 ; sprawdzamy współrzędne ekranowe je punkt_nastempny ; nie powinny one być na brzegu ekranu cmp word ptr [ye],0 ; (obojętne, czy górnym, czy lewym, czy je punkt_nastempny ; jakim), ani nie powinny wychodzić poza cmp word ptr [xe],318 ; ekran (logiczne) ja punkt_nastempny cmp word ptr [ye],198 ja punkt_nastempny xor eax,eax ; obliczamy pozycję naszego pikselka w b mov ax,ye ; uforze ekranu ze wzoru: p = 320*y + x, shl ax,6 ; stosuję metodę przesunięć logicznych, mov bx,ax ; bo jest o wiele szybsza od mnożenia (o shl ax,2 ; ptymalizacja) add ax,bx add ax,xe ; mamy naszą pozycję p pikselka add eax,edi ; dodajemy adres bufora ekranu mov bl,kolor ; rysujemy kwadracik 2x2 o kolorze podan mov bh,bl ; ym w zmiennej kolor mov [eax],bx mov [eax+320],bx punkt_nastempny: add esi,16 ; przechodzimy do następnego punktu dec ecx ; sprawdzamy czy zostały jeszcze punkty jnz wykonuj_punkty ; jeżeli tak to powtarzamy pętlę ; kończymy wykonywać punkty ; blur start mov edi,ekran ; zerujemy (czyścimy) pierwszą linię ekr xor eax,eax ; anu mov ecx,320/4 cld rep stosd mov edx,64000-640 ; rozmazujemy cały ekran oprócz pierwsze xor ebx,ebx ; j i ostatniej linii blur_skok: mov al,[edi-1] ; bierzemy piksele po lewej, prawej, u g mov bl,[edi-320] ; óry i u dołu, sumujemy je, dzielimy to add ax,bx ; przez 4, odejmujemy 1 (ściemniamy) i z mov bl,[edi+1] ; apisujemy add ax,bx mov bl,[edi+320] add ax,bx shr ax,2 jz blur_dalej dec al mov [edi],al blur_dalej: inc edi dec edx jnz blur_skok xor eax,eax ; zerujemy (czyścimy) ostatnią linię ekr mov ecx,320/4 ; anu rep stosd ; blur end ; czekamy na odświeżenie ekranu mov dx,03dah c1: in al,dx test al,8 jz c1 c2: in al,dx test al,8 jnz c2 ; wywalamy nasz bufor na ekran mov esi,ekran mov edi,_a0000h mov ecx,64000/4 cld rep movsd ; jeżeli nie naciśnięto eskejta to powtarzamy pętelkę in al,60h dec al jnz main_loop ; zwalniamy pamięć mov eax,uchwyt_bufora mov di,ax shr eax,16 mov si,ax mov ax,0502h int 31h ; z powrotem tryb tekstowy (03h) mov ax,0300h mov bx,10h mov edi,offset _regs mov [edi._eax],03h int 31h koniec: ; koniec programu i powrót do DOS'a mov ah,4Ch int 21h kolor db 1 ; kolor do rysowania pikseli even los_min dw 0 ; do losowania: liczba minimalna, los_max dw 0 ; maksymalna i liczba pomocnicza ( los_pom dw 1234h ; tak jak zmienna randomseed w pas fpom16 dw 0 ; zczalu) xe dw 0 ; współrzędne ekranowe x i y (po k ye dw 0 ; orekcie) align 4 _a0000h dd 0 ; adres pamięci ekranu (dostęp bez ; pośredni) ekran dd 0 ; przechowuje adres bufora ekranu uchwyt_bufora dd 0 ; a ten jego uchwyt (potrzebny do fpom32 dd 0.0 ; późniejszego zwolnienia pamięci) korekta_x dd 160.0 ; korekty współrzędnych (rysujemy korekta_y dd 100.0 ; od środka ekranu) delta_v dd 0.95 ; spowolnienie grav dd 0.056636246626546456 ; siła grawitacji skala dd 700.0 ; do obliczania prędkości punktów hor_resolution dd 320.0 ; rozdzielczość pozioma _regs dpmi_regs ? punkt_tab dd MAX_P dup(?,?,?,?) ; x,y,vx,vy (16 bajtów) endp code32 ends end