[Back to GRAPHICS SWAG index]  [Back to Main SWAG index]  [Original]

{
A while ago, I've written a simple BMP viewer using Turbo Pascal 6.0
and VBE functions. You can use this as an example. You can see that the
VBE interface isn't easy, but not too hard.

}
program bmp;

{ Variables }

var bitmap : record
     bfType      : word;
     bfSize      : longint;
     bfReserved1 : word;
     bfReserved2 : word;
     bfOffBits   : longint;
     biSize          : longint;
     biWidth         : longint;
     biHeight        : longint;
     biPlanes        : word;
     biBitCount      : word;
     biCompression   : longint;
     biSizeImage     : longint;
     biXPelsPerMeter : longint;
     biYPelsPerMeter : longint;
     biClrUsed       : longint;
     biClrImportant  : longint
    end;

    palette : array[0..255] of record B, G, R, alpha : byte end;

    VbeInfoBlock : record
     VbeSignature      : longint;
     VbeVersion        : word;
     OemStringPtr      : pointer;
     Capabilities      : longint;
     VideoModePtr      : pointer;
     TotalMemory       : word;
    { Added for VBE 2.0 }
     OemSoftwareRev    : word;
     OemVendorNamePtr  : pointer;
     OemProductNamePtr : pointer;
     OemProductRevPtr  : pointer;
     Reserved          : array[0..221] of byte;
     OemData           : array[0..255] of byte
    end;

    ModeInfoBlock : record
    { Mandatory information for all VBE revisions }
     ModeAttributes      : word;
     WinAAttributes      : byte;
     WinBAttributes      : byte;
     WinGranularity      : word;
     WinSize             : word;
     WinASegment         : word;
     WinBSegment         : word;
     WinFuncPtr          : pointer;
     BytesPerScanLine    : word;
    { Mandatory information for VBE 1.2 and above }
     XResolution         : word;
     YResolution         : word;
     XCharSize           : byte;
     YCharSize           : byte;
     NumberOfPlanes      : byte;
     BitsPerPixel        : byte;
     NumberOfBanks       : byte;
     MemoryModel         : byte;
     BankSize            : byte;
     NumberOfImagePages  : byte;
     Reserved1           : byte;
    { Direct Color fields (required for direct/6 and YUV/7 memory models) }
     RedMaskSize         : byte;
     RedFieldPosition    : byte;
     GreenMaskSize       : byte;
     GreenFieldPosition  : byte;
     BlueMaskSize        : byte;
     BlueFieldPosition   : byte;
     RsvdMaskSize        : byte;
     RsvdFieldPosition   : byte;
     DirectColorModeInfo : byte;
    { Mandatory information for VBE 2.0 and above }
     PhysBasePtr         : longint;
     OffScreenMemOffset  : longint;
     OffScreenMemSize    : word;
     Reserved2           : array[0..205] of byte
    end;

    bmpfile : file;
    buf : array[0..1279] of byte;

    OldMode, Mode, Window, Segment, Units, Offset : word;
    Size, Address : longint;
    x,y : word;


{ VESA interface }

function ReturnVBEInfo(var VbeInfoBlockPtr) : word; assembler;
asm mov ax,4F00h; les di,VbeInfoBlockPtr; int 10h end;

function ReturnModeInfo(Mode : word; var ModeInfoBlockPtr) : word; assembler;
asm mov ax,4F01h; mov cx,Mode; les di,ModeInfoBlockPtr; int 10h end;

function SetVBEMode(Mode : word) : word; assembler;
asm mov ax,4F02h; mov bx,Mode; int 10h end;

function ReturnVBEMode : word; assembler;
asm mov ax,4F03h; int 10h; mov ax,bx end;

function SetWindow(Window, Units : word) : word; assembler;
asm mov ax,4F05h; mov bx,Window; mov dx,Units; int 10h end;

{ Palette... }

procedure SetPalette(First, N : word; var Palette); assembler;
asm
 pushf
 push ds
 mov al,byte ptr First
 mov dx,3C8h
 out dx,al
 inc dx
 std
 mov cx,N
 lds si,Palette
 add si,2
@SP:
 lodsb
 shr al,2
 out dx,al
 lodsb
 shr al,2
 out dx,al
 lodsb
 shr al,2
 out dx,al
 add si,7
 loop @SP
 pop ds
 popf
end;

begin
{ Open bitmap file }
 if ParamCount = 1 then with bitmap do begin
  assign(bmpfile,ParamStr(1)); reset(bmpfile,1);
  blockread(bmpfile, bitmap, sizeof(bitmap));
  if bfType = $4D42 then begin

{ Show details }
   writeln(#10'Bitmap   : ', ParamStr(1));
   writeln(   ' width   : ',biWidth);
   writeln(   ' height  : ',biHeight);
   writeln(   ' bits    : ',biBitCount);
   if biClrUsed = 0 then biClrUsed := 1 shl biBitCount;
   writeln(   ' colours : ',biClrUsed);
   if ((biBitCount = 4) or (biBitCount = 8)) and (biWidth > 0) and (biHeight >
0)   and (biWidth <= 1280) and (biHeight <= 1024) then begin
    if biBitCount = 4 then
     biWidth := (biWidth + 7) and $FFF8
    else
     biWidth := (biWidth + 3) and $FFFC;

{ Get VESA interface }
    if ReturnVBEInfo(VbeInfoBlock) = $004F then with VbeInfoBlock do begin
     writeln(#10'VBE version  : ', hi(VbeVersion), '.', lo(VbeVersion), '0');
     case biWidth of
        1.. 640:Mode:=$100; 641.. 800:Mode:=$103;
      801..1024:Mode:=$105;1025..1280:Mode:=$107
     end;
     case biHeight of
          1..400:x :=$100;401.. 480:x :=$101;481..600:x :=$103;
        601..768:x :=$105;769..1024:x :=$107
     end;
     if Mode < x then Mode := x;
     if (ReturnModeInfo(Mode, ModeInfoBlock) = $004F)
     and odd(ModeInfoBlock.ModeAttributes) then with ModeInfoBlock do begin

{ Show details}
      writeln(' mode        : ', Mode, 'd');
      writeln(' granularity : ', WinGranularity,'KB');
      writeln(' window size : ', WinSize,'KB');
      if (WinAAttributes and 4) = 4 then begin
       Window := 0; Segment := WinASegment
      end else begin
       Window := 1; Segment := WinBSegment
      end;
      writeln(' window      : ', chr(ord('A') + window));
      writeln(' segment     : ', Segment, 'd');
      writeln(' bytes/line  : ', BytesPerScanLine);
      Units := WinSize div WinGranularity;
      Size := longint(WinSize) shl 10;
      writeln(#10'Press <Enter> to display bitmap'); readln;
      OldMode := ReturnVBEMode;
      if SetVBEMode(Mode) = $004F then begin

{ Read and set palette }
       blockread(bmpfile, palette, biClrUsed shl 2);
       SetPalette(0,biClrUsed,Palette);

{ Show bitmap}
       for y := pred(biHeight) downto 0 do begin
        Address := longint(y) * BytesPerScanLine;
        SetWindow(Window, Address div Size);
        Offset := Address mod Size;
        if biBitCount = 4 then begin

{ Show 4-bit bitmap }
         blockread(bmpfile, buf, biWidth shr 1);
         for x := pred(biWidth shr 1) downto 0 do begin
          buf[succ(x shl 1)] := buf[x] and $0F;
          buf[x shl 1] := buf[x] shr 4
         end;
         if Offset <= (Size - biWidth) then
          move(buf, mem[Segment:Offset], biWidth)
         else begin
          move(buf, mem[Segment:Offset], Size - Offset);
          SetWindow(Window, succ(Address div Size));
          move(buf, mem[Segment:0], biWidth - Size + Offset)
         end
        end else

{ Show 8-bit bitmap }
         if Offset <= (Size - biWidth) then
          blockread(bmpfile, mem[Segment:Offset], biWidth)
         else begin
          blockread(bmpfile, mem[Segment:Offset], Size - Offset);
          SetWindow(Window, succ(Address div Size));
          blockread(bmpfile, mem[Segment:0], biWidth - Size + Offset)
        end
       end;
       readln; SetVBEMode(OldMode)
      end else writeln('VESA mode could not be set')
     end else writeln('VESA mode not supported in hardware')
    end else writeln('No VESA BIOS found')
   end else writeln('Unable to display bitmap')
  end else writeln('File is not a BMP file');
  close(bmpfile)
 end else writeln('Usage : BMP <filename>.BMP')
end.

[Back to GRAPHICS SWAG index]  [Back to Main SWAG index]  [Original]