{
From: BERNIE PALLEK
Subj: GRAF_13H.PAS
---------------------------------------------------------------------------
}
(**************************************************)
(*                                                *)
(*         GRAPHICS ROUTINES FOR MODE 13H         *)
(*         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~         *)
(*        320x200x256 (linearly-addressed)        *)
(*  Collected from routines in the Public Domain  *)
(*          Assembled by Bernie Pallek            *)
(*                                                *)
(**************************************************)

{ DISCLAIMER: Use this unit at your own risk.  I will not be liable
              for anything negative resulting from use of this unit. }

UNIT Graf_13h;

INTERFACE

CONST
  Color : Byte = 0;

TYPE
  RGBPalette = Array[0..767] of Byte;

FUNCTION  GetVideoMode : Byte;
PROCEDURE SetVideoMode(desiredVideoMode : Byte);
FUNCTION  GetPixel(pix2get_x, pix2get_y : Word) : Byte;
PROCEDURE SetPixel(pix2set_x, pix2set_y : Word; pix2set_c : Byte);
PROCEDURE Ellipse(exc, eyc, ea, eb : Integer);
PROCEDURE Line(lnx1, lny1, lnx2, lny2 : Integer);
PROCEDURE GetPalette(index2get : Byte; VAR r_inte, g_inte, b_inte : Byte);
PROCEDURE SetPalette(index2set, r_inte, g_inte, b_inte : Byte);
PROCEDURE BurstSetPalette(burstPalette : RGBPalette);
PROCEDURE ScaleBitmap(VAR bmp2scale; bwidth, bheight : Byte;
  bstrtx, bstrty, bendx, bendy : Word);
PROCEDURE WaitForRetrace;
PROCEDURE ClearScr;


IMPLEMENTATION


{ private type used by ScaleBitmap() }
TYPE
  Fixed = RECORD CASE Boolean OF
    True  : (w : LongInt);
    False : (f, i : Word);
  END;

FUNCTION GetVideoMode : Byte;
VAR
  tempVMode : Byte;
BEGIN
  ASM
    mov ah,$0f
    int $10
    mov tempvmode,al
  END;
  GetVideoMode := tempVMode;
END;

PROCEDURE SetVideoMode(desiredVideoMode : Byte);
{ desiredVideoMode = $03 : 80x25 colour text
                     $13 : 320x200x256 monoplaned
                           video data from $A000:0000 to $A000:FFFF
}
BEGIN
  ASM
    mov ah,0
    mov al,desiredvideomode;
    int $10
  END;
END;

FUNCTION GetPixel(pix2get_x, pix2get_y : Word) : Byte;
BEGIN
  GetPixel := Mem[$A000 : pix2get_y * 320 + pix2get_x];
END;

PROCEDURE SetPixel(pix2set_x, pix2set_y : Word; pix2set_c : Byte);
BEGIN
  Mem[$A000 : pix2set_y * 320 + pix2set_x] := pix2set_c;
END;

{ originally by Sean Palmer, I just mangled it  :^) }
PROCEDURE Ellipse(exc, eyc, ea, eb : Integer);
VAR
  elx, ely : Integer;
  aa, aa2, bb, bb2, d, dx, dy : LongInt;
BEGIN
  elx := 0; ely := eb; aa := LongInt(ea) * ea; aa2 := 2 * aa;
  bb := LongInt(eb) * eb; bb2 := 2 * bb;
  d := bb - aa * eb + aa DIV 4; dx := 0; dy := aa2 * eb;
  SetPixel(exc, eyc - ely, Color); SetPixel(exc, eyc + ely, Color);
  SetPixel(exc - ea, eyc, Color); SetPixel(exc + ea, eyc, Color);

  WHILE (dx < dy) DO BEGIN
    IF (d > 0) THEN BEGIN Dec(ely); Dec(dy, aa2); Dec(d, dy); END;
    Inc(elx); Inc(dx, bb2); Inc(d, bb + dx);
    SetPixel(exc + elx, eyc + ely, Color);
    SetPixel(exc - elx, eyc + ely, Color);
    SetPixel(exc + elx, eyc - ely, Color);
    SetPixel(exc - elx, eyc - ely, Color);
  END;
  Inc(d, (3 * (aa - bb) DIV 2 - (dx + dy)) DIV 2);
  WHILE (ely > 0) DO BEGIN
    IF (d < 0) THEN BEGIN Inc(elx); Inc(dx, bb2); Inc(d, bb + dx); END;
    Dec(ely); Dec(dy, aa2); Inc(d, aa - dy);
    SetPixel(exc + elx, eyc + ely, Color);
    SetPixel(exc - elx, eyc + ely, Color);
    SetPixel(exc + elx, eyc - ely, Color);
    SetPixel(exc - elx, eyc - ely, Color);
  END;
END;

{ originally by Sean Palmer, I just mangled it }
PROCEDURE Line(lnx1, lny1, lnx2, lny2 : Integer);
VAR
  lndd, lndx, lndy, lnai, lnbi, lnxi, lnyi : Integer;
BEGIN
  IF (lnx1 < lnx2) THEN BEGIN lnxi := 1; lndx := lnx2 - lnx1;
  END ELSE BEGIN lnxi := (-1); lndx := lnx1 - lnx2; END;
  IF (lny1 < lny2) THEN BEGIN lnyi := 1; lndy := lny2 - lny1;
  END ELSE BEGIN lnyi := (-1); lndy := lny1 - lny2; END;
  SetPixel(lnx1, lny1, Color);
  IF (lndx > lndy) THEN BEGIN lnai := (lndy - lndx) * 2;
    lnbi := lndy * 2;
    lndd := lnbi - lndx;
    REPEAT IF (lndd >= 0) THEN BEGIN Inc(lny1, lnyi);
      Inc(lndd, lnai); END ELSE Inc(lndd, lnbi);
      Inc(lnx1, lnxi); SetPixel(lnx1, lny1, Color);
    UNTIL (lnx1 = lnx2);
  END ELSE BEGIN lnai := (lndx - lndy) * 2; lnbi := lndx * 2;
    lndd := lnbi - lndy;
    REPEAT IF (lndd >= 0) THEN BEGIN Inc(lnx1, lnxi);
      Inc(lndd, lnai); END ELSE Inc(lndd, lnbi);
      Inc(lny1, lnyi); SetPixel(lnx1, lny1, Color);
    UNTIL (lny1 = lny2);
  END;
END;

PROCEDURE GetPalette(index2get : Byte; VAR r_inte, g_inte, b_inte : Byte);
{ returns the r, g, and b values of a palette index }
BEGIN
  Port[$3C7] := index2get;
  r_inte := Port[$3C9];
  g_inte := Port[$3C9];
  b_inte := Port[$3C9];
END;

PROCEDURE SetPalette(index2set, r_inte, g_inte, b_inte : Byte);
{ sets the r, g, and b values of a palette index }
BEGIN
  Port[$3C8] := index2set;
  Port[$3C9] := r_inte;
  Port[$3C9] := g_inte;
  Port[$3C9] := b_inte;
END;

PROCEDURE BurstSetPalette(burstPalette : RGBPalette);
VAR
  burstCount : Word;
BEGIN
  Port[$3C8] := 0;
  FOR burstCount := 0 TO 767 DO Port[$3C9] := burstPalette[burstCount];
END;

{ originally by Sean Palmer, I just mangled it }
PROCEDURE ScaleBitmap(VAR bmp2scale; bwidth, bheight : Byte;
  bstrtx, bstrty, bendx, bendy : Word);
{ - bmp2scale is an array [0..bwidth, 0..bheight] of byte      }
{   which contains the original bitmap                         }
{ - bwidth and bheight are the actual width - 1 and the actual }
{   height - 1 of the normal bitmap                            }
{ - bstrtx and bstrty are the x and y values for the upper-    }
{   left-hand corner of the scaled bitmap                      }
{ - bendx and bendy are the lower-right-hand corner of the     }
{   scaled version of the original bitmap                      }
{ - eg. to paste an unscaled version of a bitmap that is 64x64 }
{   pixels in size in the top left-hand corner of the screen,  }
{   fill the array with data and call:                         }
{     ScaleBitmap(bitmap, 64, 64, 0, 0, 63, 63);               }
{ - to create an array for the bitmap, make it like this:      }
{     VAR myBitmap : Array[0..bmpHeight, 0..bmpWidth] of Byte; }
{   where bmpHeight is the actual height of the normal-size    }
{   bitmap less one, and bmpWidth is the actual width less one }
VAR
  bmp_sx, bmp_sy, bmp_cy : Fixed;
  bmp_s, bmp_w, bmp_h    : Word;

BEGIN
  bmp_w := bendx - bstrtx + 1; bmp_h := bendy - bstrty + 1;
  bmp_sx.w := bwidth * $10000 DIV bmp_w;
  bmp_sy.w := bheight * $10000 DIV bmp_h;
  bmp_s := 320 - bmp_w; bmp_cy.w := 0;
  ASM
    push ds; mov ds,word ptr bmp2scale + 2;
    mov ax,$a000; mov es,ax; cld; mov ax,320;
    mul bstrty; add ax,bstrtx; mov di,ax;
   @l2:
    mov ax,bmp_cy.i; mul bwidth; mov bx,ax;
    add bx,word ptr bmp2scale;
    mov cx,bmp_w; mov si,0; mov dx,bmp_sx.f;
   @l:
    mov al,[bx]; stosb; add si,dx; adc bx,bmp_sx.i;
    loop @l;
    add di,bmp_s; mov ax,bmp_sy.f; mov bx,bmp_sy.i;
    add bmp_cy.f,ax; adc bmp_cy.i,bx;
    dec word ptr bmp_h; jnz @l2; pop ds;
  END;
END;

PROCEDURE WaitForRetrace;
{ waits for a vertical retrace to reduce flicker }
BEGIN
  REPEAT UNTIL (Port[$3DA] AND 8) = 8;
END;

PROCEDURE ClearScr;
BEGIN
  FillChar(Mem[$A000:0000], 64000, 0);
END;

END.  { of unit }

That's it!  It's not complete, but it's meant as a starter for all who are
interested in VGA graphics.  Happy programming!

Bernie.


--- Maximus/2 2.01wb
 * Origin: * idiot savant * +1 905 935 6628 * (1:247/128)
