ATARI
portfolio


Programování grafiky na portfoliu

     Nazačátek bych zde vysvětlil některé techniky zobrazování používané na normálním PC.
     Unbuffered mode, popř. direct access - je případ, kdy body scény průběžně vykreslujeme na obrazovku. To lze provést buď funkcí BIOSu (pomalé) nebo přímým zápisem do VRAM. Tento způsob je výhodný v případě, že vykreslujeme malé jednoduché objekty z pár pixelů. Také nemusíme ani mazat celou obrazovku, ale stačí, když si před vykreslením schováme hodnoty původních bodů, překreslíme je, a při dalším frame je opět obnovíme.
     Double buffering - protože je zápis do VRAM pomalejší než do jiné oblasti RAM, používá se u složitých scén bufferu v normální RAM, kam se vše kreslí a když je frame hotov, překopíruje se celý buffer do VRAM. To lze provést rychle pomocí MOVSW/MOVSD. Před začátkem kreslení dalšího frame se musí buffer smazat.
     Page flipping - Lze použít ve videorežimech nabízejících více stránek. Máme-li dvě stránky ve VRAM, tak jednu necháme zobrazovat na obrazovce a druhou namapujeme do adresního prostoru PC a kreslíme do ní. Když je frame hotov, prohodíme stránky, smažeme předtím zobrazovanou stránku a kreslíme do ní nový frame.

     Jak je to na portfoliu? LCD displej portfolia má rozlišení 240x64 bodů hloubky 1bit. VRAM leží na adresách B000:0000 až B000:0FFF, velikost aktivní stránky je 240x64/8 = 1920 B. Z toho plyne, že 1 Byte obsahuje 8 pixelů a to tak, že MSB je pixel nejvíce nalevo a LSB nejvíce napravo. Pokud je bit nastaven na 1, je zobrazen tmavý bod, pokud 0 ne zobrazen světlý bod. Zásadní rozdíl mezi PC a portfoliem je v tom, že pokud něco zapíšeme přímo do VRAM, tak se změna projeví až po 1 nebo 128s, podle nastavení časovače v SETUPu. O vlastní kreslení na LCD se stará řadič Hitachi HD61830, který je přístupný přes I/O porty 8010h a 8011h (viz níže).

Napřed musíme nastavit grafický mód:
void setmode(Byte mode)      /* set mode GFX/TXT */
{
  union REGS regs;
  regs.h.ah = 0;             /* MOV AH,0 - služba 0 */
  regs.h.al = mode;          /* MOV AL,číslo módu ;07 = text, 04 = grafika*/
  int86(0x10, ®s, ®s); /* INT 10h */
}

Jako první si ukážeme přístup přez BIOS, který je stejný jako na PC. BIOS se sám postará o 'okamžité' zobrazení bodu, je to však nejpomalejší způsob; vykreslení všech 1920ti bodů zabere asi 10s.
void putpix(Byte x, Byte y, Byte color) /* putpixel prez BIOS 0/1 */
{
  union REGS regs;
  regs.h.ah = 0x0c;          /* MOV AH,0Ch - služba 0Ch */
  regs.h.al = color;         /* MOV AL,barva bodu ;0 = světlý, 1 = tmavý */
  regs.h.bh = 0;             /* MOV BH,číslo aktivní stránky */
  regs.x.cx = x;             /* MOV CX,Xová souřadníce bodu ;provádí se clipping */
  regs.x.dx = y;             /* MOV DX,Yová souřadníce bodu ;provádí se clipping */
  int86(0x10, ®s, ®s); /* INT 10h */
}


Byte getpix(Byte x, Byte y) /* get pixel color 0/1 */
{
  union REGS regs;
  regs.h.ah = 0x0d;          /* MOV AH,0Dh - služba 0Dh */
  regs.h.bh = 0;             /* MOV BH,číslo aktivní stránky */
  regs.x.cx = x;             /* MOV CX,Xová souřadníce bodu */
  regs.x.dx = y;             /* MOV DX,Yová souřadníce bodu */
  int86(0x10, ®s, ®s); /* INT 10h */
  return(regs.h.al);
}

Dále jsem pomocí této stručné dokumentace k řadiči LCD dipleje HD61830 naprogramoval vlastní funkci na kreslení bodu, je však jen asi 2x rychlejší. (Bod je zobrazován okamžitě)
#define XRES 240
#define YRES 64
#define VRAMSIZE 1920
#define MAXX (XRES-1)
#define MAXY (YRES-1)
#define MIDX (XRES/2)
#define MIDY (YRES/2)

void putpix(Byte x, Byte y, Byte color) /* putpixel prez porty 0/1 */
{
  register int offset=x+y*XRES;
  int bit=offset%8;
  register int alo=offset>>3,ahi=alo>>8;
  outportb(0x8011,10);
  outportb(0x8010,alo%256);  // low Byte address
  outportb(0x8011,11);
  outportb(0x8010,ahi);      // high Byte address
  if (color!=0)
    outportb(0x8011,15);     // set bit
  else
    outportb(0x8011,14);     // clear bit
  outportb(0x8010,bit);      // bit num in Byte
}

A jako poslení uvedu 'doublebuffer' metodu, kde však nealokuji žádný další buffer, ale používám přímo VRAM. Ta je totiž na portfoliu stejně rychlá jako ostatní RAM. Celé se nám to tedy posune tak, že uvažovaný framebuffer je nyní ve VRAM a skutečná VRAM je někde uvnitř řadiče LCD.
#define POFOVRAMSEG 0xB000
Byte far *vram=MK_FP(POFOVRAMSEG,0); /* pointer do VRAM */

void putpix(Byte x, Byte y, Byte color) /* putpixel do VRAM bufferu */
{
  register int offset=x+y*XRES;
  int bytenum=offset%8;
  int ofs=offset>>3;
  vram[ofs]=vram[ofs]|(0x80>>bytenum); 
}


void cls(unsigned int pattern) /* smaze VRAM */
{
  asm {
    push es
    push cx
    push di
    mov  cx,POFOVRAMSEG // segment VRAM
    mov  es,cx
    mov  cx,VRAMSIZE/2  // pojedeme 240x60/8/2 cyklu
    xor  di,di          // offset VRAM=0
    mov  ax,pattern     // AX bude ukladano do VRAM
    rep  stosw          // opakuj AX->ES:[DI] dokud CX neni 0
    pop  di
    pop  cx
    pop  es
  }
}
Po vykreslení scény je však ještě třeba obsah VRAM zkopírovat do vnitřní paměti LCD řadiče aby se frame objevil. To zajistí tato rutina bratří Hrdličkových (původně psaná v ASM) úžasnou rychlostí za desetinu vteřiny (10fps). Údajně existuje ještě 2x rychlejší rutina nějakého itala, ale není mi o tom nic známo.
void refresh(void) /* zkopiruje VRAM na displej (do kontroleru HD) */
{
  asm {
    cld
    push ax
    push cx
    push dx
    push bx
    push si
    push di
    push ds
    mov  si,0
    mov  ax,0b000h
    mov  ds,ax
    mov  di,64
    }
   refresh_2:
  asm {
    mov  cx,30
    mov  bx,si
    mov  al,0ah
    mov  dx,8011h
    cli
    out  dx,al
    mov  al,bl
    mov  dx,8010h
    out  dx,al
    sti
    mov  al,0bh
    mov  dx,8011h
    cli
    out  dx,al
    mov  dx,8010h
    mov  al,bh
    and  al,7
    out  dx,al
    sti
    }
   refresh_1:
  asm {
    lodsb
    ror  al,1
    mov  ah,al
    and  ah,136
    ror  al,1
    ror  al,1
    mov  bl,al
    and  bl,68
    or   ah,bl
    ror  al,1
    ror  al,1
    mov  bl,al
    and  bl,34
    or   ah,bl
    ror  al,1
    ror  al,1
    and  al,17
    or   al,ah
    mov  ah,al
    inc  dx
    mov  al,0ch
    cli
    out  dx,al
    mov  al,ah
    mov  dx,8010h
    out  dx,al
    sti
    loop refresh_1
    dec  di
    jnz  refresh_2
    pop  ds
    pop  di
    pop  si
    pop  bx
    pop  dx
    pop  cx
    pop  ax
  }
}

Pokud tedy pro portfolio programuje více lidí, zajímaly by mě vaše připomínky a zkušenosti zejména se zvukem a grafikou.


rayer^seznam*cz

zpět   zpět na index


aktualizováno 23:45; 14.5.2001