Programowanie w rozdzielczości 1024x768

Gawronxxl

W artykule chciałbym przedstawić jak programować w rozdzielczości 1024x768 w 256 kolorach przy pomocy procedur które sami napiszemy. Na wstępie dodam że duża cześć procedur będzie pisana przy pomocy wbudowanego asemblera w kompilator TP. A wiec zaczynamy. Życzę miłej lektury :D

Aby wyświetlić pixel lub narysować linie itp. trzeba najpierw zainicjować tryb 1024x768x256.
W tym celu posłużymy się funkcja 4F02h przerwania 10h. Przystępujemy do pisania procedurki inicjującej ten tryb :D.

Procedure Init1024x768x256;assembler;
 Asm
  mov ax, 4F02h
  mov bx, 105h
  int 10h
 End;

I mały programik w tp z jej wykorzystaniem :D

uses crt;
 
Begin
 Init1024x768x256;
 repeat until keypressed;
End.

Hmmm. Ale co my tu mamy. Po uruchomieniu programu widzimy tylko ciemny ekran! Niestety tak wygląda ten tryb po inicjacji. Aby zobaczyć coś więcej musimy coś narysować! Lecz zanim przystąpimy do wyświetlania pikseli, rysowania linii, prostokątów itp. Powiem kilka słów o organizacji ekranu w tym trybie. Jak zapewne wiecie ekran w trybie 13h czyli o rozdzielczości 320x200 pikseli zajmuje w pamięci 320200=64000 bajtów i znajduje się pod adresem A000:F9FF czyli zajmuje niecały bufor wideo. To też dla wyjaśnienia powiem ze bufor wideo ma rozmiar 65536 bajtów czyli począwszy od adresu A000 do FFFF. Wyświetlanie piksela w tej rozdzielczości nie nastręcza problemów takich jak w 1024x768 bo nie wymaga przełączania banków (będę używał określenia bank lub bit plan), ale o tym za chwile.
Ekran przy rozdzielczości 1024x768 ma rozmiar 786432 bajty czyli znacznie więcej niż calu bufor wideo. Gdybyśmy nie przełączali banków ekranu maksymalny możliwy do wyświetlenia piksel miałby współrzędne 1023,64. W tym celu aby np wyświetlić piksel o współrzędnych 200,200 trzeba posłużyć się przełączaniem banków ekranu. Ekran w rozdzielczości 1024x768 ma ich 1024
768/65536=12. Czyli licząc od zera do 11 daje 12 :P. Trochę zamotałem :D. Więcej nie będę opisywał tylko przystąpmy do pisania procedurki do wyświetlania pikseli :D. Oto ona.

Procedure PutPixel(x,y:word;kolor:byte);assembler;
 Asm
  {liczenie ofsetu}
  mov ax, 1024
  cmp ax, x
  jz @000
  jl @000
  mov ax, 768
  cmp ax, y
  jz @000
  jl @000
  mov di, y
  shl di, 10
  add di, x
  {sprawdzanie i zmiana aktywnego banku bit planu}
  mov dx, y
  shr dx, 6
  cmp dx, BitPlan
  jz @nie_zmieniaj {=}
  mov ax, 4F05h
  mov bx, 0
  int 10h
  mov BitPlan, dx
 @nie_zmieniaj:
  {wyswietlenie pixela}
  mov ax, 0a000h
  mov es, ax
  mov al, kolor
  mov byte ptr es:[di], al
 @000:
 End;

Nie będę opisywał dokładnie jej działania, ważne że działa i wyświetla piksel w rozdzielczości 1024x768x256 :D

Część 2 :D.

Jak obiecałem oto dalszy ciąg pisania procedurek i funkcji do obsługi rozdzielczości 1024x768 w 256 kolorach. No dobra, dobra nie będę już męczył zbędnym paplaniem tylko przechodzimy do sedna sprawy. Umiemy zainicjować tryb pracy w 1024x768x256, poza tym umiemy już wyświetlać piksele w tej rozdzielczości. Teraz napiszemy funkcje która będzie zwracać kolor piksela w punkcie x, y :D. Oto ona.

Function GetPixel(x,y:word):byte;assembler;
 Asm
  mov ax, 1024
  cmp ax, x
  jz @000
  jl @000
  mov ax, 768
  cmp ax, y
  jz @000
  jl @000
  mov di, y
  shl di, 10
  add di, x
  mov dx, y
  shr dx, 6
  cmp BitPlan, dx
  jz @nie_zmieniaj {=}
  mov ax, 4F05h
  mov bx, 0
  int 10h
  mov BitPlan, dx
 @nie_zmieniaj:
  mov ax, 0a000h
  mov es, ax
  mov al, byte ptr es:[di]
 @000:
 End;

I oto jest :D. Jeszcze jedno. PutPixel i GetPixel używają zmiennej BitPlan typu word którą należy wcześniej zdefiniować. Użyłem tu zmiennej do przechowywania aktywnego bit planu dlatego że jest to dużo szybsze rozwiązanie niż jego zmiana za każdym razem nawet kiedy kolejny rysowany piksel znajduje się w tym samym bit planie. Ok. Hmm, narysowanie czegoś z pojedynczych pikseli to strasznie monotonne zadanie, więc zróbmy procedurę do rysowania całych linii. Rysowanie linii z punktu x, y do punktu x1, y1 o podanym kolorze :D.

Procedure Line(x1,y1,x2,y2:word;kolor:byte);
  var licznik,s,d1x,d1y,d2x,d2y,r_x,r_y,m,n:integer;
  Function znak(liczba:integer):integer;assembler;
   Asm
    mov ax, liczba
    cmp ax, 0
    jg @001
    jl @002
    jz @003
   @001:
    mov ax, 1
    jmp @000
   @002:
    mov ax, -1
    jmp @000
   @003:
    mov ax, 0
   @000:
   End;
 
 Begin
  asm
   mov ax, x2
   mov bx, x1
   sub ax, bx
   mov r_x, ax
   mov ax, y2
   mov bx, y1
   sub ax, bx
   mov r_y, ax
   mov d2y, 0
  end;
  d1x:=znak(r_x);
  d1y:=znak(r_y);
  d2x:=znak(r_x);
  m:=abs(r_x);
  n:=abs(r_y);
  if (m<=n) then
   begin
    asm
     mov d2x, 0
    end;
    d2y:=znak(r_y);
    m:=abs(r_y);
    n:=abs(r_x);
   end;
  asm
   mov ax, m
   shr ax, 1
   mov s, ax
   mov cx, m
   inc cx
   @petla:
   mov ax, x1
   mov bx, y1
   mov dx, word ptr kolor
   push ax
   push bx
   push dx
   call PutPixel
   mov ax, s
   mov bx, n
   add ax, bx
   mov s, ax
   cmp ax, m
   jl @001
   mov ax, s
   mov bx, m
   sub ax, bx
   mov s, ax
   mov ax, x1
   mov bx, d1x
   add ax, bx
   mov x1, ax
   mov ax, y1
   mov bx, d1y
   add ax, bx
   mov y1, ax
   jmp @000
  @001:
   mov ax, x1
   mov bx, d2x
   add ax, bx
   mov x1, ax
   mov ax, y1
   mov bx, d2y
   add ax, bx
   mov y1, ax
  @000:
   loop @petla
  end;
 End;

Trochę bazgraniny było ale działa :D. Powiem jeszcze ze procedura line używa procedury PutPixel, ale to na pewno udało się wam zauważyć :P.
Na tym chwilowo kończę. Ale nie martwcie się już niedługo ciąg dalszy :D.

Artykuł będzie z czasem rozszerzany. Proszę o cierpliwość i wyrozumiałość.

Pozdrawiam Gawron.

8 komentarzy

A ja wam powiem, że po prostu opisuje on swoim językiem a nie typowym specjalistycznym językem, i tak jeden z ciekawszych artów o ASMie

Zawsze można zrobić jeszcze bardziej nieczytelna w samym asmie :D. Lub bardziej czytelna w Pascalu. A tu wybrałem takie poplątanie co by było wiadomo o co biega i żeby była w miarę szybka. Pozdrawiam i dalej myślę nad kolejnym rozszerzeniem art...

PS. tak właściwie ta procedura rysująca linię - nie lepiej byłoby użyć zamiast niej procedury pascala która wywoływałaby PutPixel? Bo obecna wersja jest, hm, lekko nieczytelna ;)

Ale się czepiacie :D Może te emotki i denerwują, ale sam się często ledwo powstrzymuje podczas pisania artów.

Na tym chwilowo kończę. Ale nie martwcie się już niedługo ciąg dalszy :D.
To może lepiej stwórz osobną kategorię, np. "używanie asemblera w pascalu w celu znacznego rozszerzenia możliwości rysowania grafiki" (albo coś bardziej zwięzłego ;) ) i podziel na kilka artów?

Tak czy inaczej nie przejmuj się moimi poprzednikami bo zapowiada się ciekawie (sam się zawsze zastanawiałem, kiedy jeszcze używałem pascala, jak to zrobić)

też mnie emotki uderzyły w treści...

Ale dretwy tekst :| Emoticony w artykule, heh...

do tego co to za tytuł artykułu - nie mówi prawie nic! popraw go, niech będzie opisowy, no i podpisuj się na końcu pracy, nie w tytule.

pamięć karty graficznej w trybie rzeczywistym zajmuje obszar od $A0000 do $AFFFF, plus obszar na tekst - $B0000-$B7FFF lub $B8000-$BFFFF. popraw te błędy i sprawdź, co to jest segment i offset.