[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]