home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / grafik / pcx / pcxbin / pcxbin.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-09-30  |  9.9 KB  |  326 lines

  1. {$R-,S-,I-}
  2. unit PCXBIN;
  3.   (* A unit to load graphical pictures                    *)
  4.   (* Formats supported :                                  *)
  5.   (* BSAVE Pic Format                     320 x 200 x 004 *)
  6.   (* PC/Microsoft Paintbrush .PCX files : 320 x 200 x 004 *)
  7.   (* PC/Microsoft Paintbrush .PCX files : 640 x 350 x 016 *)
  8.   (* PC/Microsoft Paintbrush .PCX files : 320 x 200 x 256 *)
  9.  
  10. interface
  11.  
  12. const
  13.   PaletteExt : string[04] = '.PAL'; {palette file extension}
  14.  
  15. type
  16.   DrawError      = (NoError, IOError, BadFormat, PaletteMissing);
  17.  
  18. var
  19.   LastDrawMode   : Word;
  20.  
  21. function FindLastDrawMode : Word;
  22.   { DOS call 10, 0F; Read Video Mode }
  23.   inline($B4/$0F/                 { MOV AH, 0F  }
  24.          $CD/$10/                 { INT 10      }
  25.          $24/$7F/                 { AND AL, 7F  -- mask high bit set by EGA}
  26.          $30/$E4);                { XOR AH, AH  -- pass back only AL}
  27.  
  28. procedure DrawMode(ModeNum : Word);
  29.  
  30. function DrawPic(FilePointer : Pointer; FBytes : LongInt) : DrawError;
  31.  
  32.   (*-------------------------------------------------------------------------*)
  33.  
  34. implementation
  35.  
  36.   var FileBytes : LongInt;
  37.  
  38.   procedure SetDrawMode(ModeNum : Word);
  39.     { DOS call 10, 00; Set Video Mode }
  40.   inline($58/                     { POP AX     -- Put ModeNum in AX }
  41.          $B4/$00/                 { MOV AH, 00 }
  42.          $CD/$10);                { INT 10     }
  43.  
  44.   procedure DrawMode(ModeNum : Word);
  45.   begin
  46.     if LastDrawMode <> ModeNum then begin
  47.       SetDrawMode(ModeNum);
  48.       LastDrawMode := FindLastDrawMode;
  49.     end;
  50.   end;
  51.  
  52.   {.PA}
  53.   function MapsSelected : Byte;
  54.     { Returns the number of bit planes enabled for writing }
  55.   const
  56.     EgaBase        = $A000;       { Base address of EGA graphics memory    }
  57.     AddrReg        = $3CE;        { Port address of EGA graphics 1 & 2 address register }
  58.     SetResetReg    = $3CF;        { Port address of EGA Set/Reset register }
  59.     ReadMapReg     = $04;         { Index of EGA Read Map select register }
  60.   var
  61.     BitMap         : Integer;
  62.     MemByte        : Byte;
  63.     EnabledPlanes  : Byte;
  64.   begin
  65.     EnabledPlanes := 0;
  66.     Port[AddrReg] := ReadMapReg;
  67.     for BitMap := 0 to 3 do
  68.       begin
  69.         Port[SetResetReg] := BitMap;
  70.         MemByte := Mem[EgaBase:0000]; { Read a dummy byte from bit plane }
  71.         Mem[EgaBase:0000] := not(MemByte); { Write the byte back inverted }
  72.         if Mem[EgaBase:0000] <> MemByte then { This plane is selected }
  73.           begin
  74.             EnabledPlanes := EnabledPlanes or (1 shl BitMap);
  75.             Mem[EgaBase:0000] := MemByte; { Reset original byte read }
  76.           end;
  77.       end;
  78.     MapsSelected := EnabledPlanes;
  79.   end;
  80.  
  81.   procedure WriteToEGAScreen(BitMap : Integer; Address : Pointer;
  82.                              From : Pointer; Reps : Word);
  83.   const
  84.     SeqAddrReg     = $3C4;        { Port address of EGA sequencer address register }
  85.     ResetReg       = $3C5;        { Port address of EGA sequencer reset register }
  86.     MapMaskReg     = $02;         { Index of EGA sequencer Map Mask register }
  87.   var
  88.     MapsEnabled    : Byte;
  89.   begin
  90.     MapsEnabled := MapsSelected;  { Save originally selected write planes }
  91.  
  92.     { Enables writing to one of the EGA's Bit planes 1..4 }
  93.     Port[SeqAddrReg] := MapMaskReg;
  94.     Port[ResetReg] := 1 shl Pred(BitMap);
  95.     Move(From^, Address^, Reps);
  96.  
  97.     Port[ResetReg] := MapsEnabled; { Restore originally selected write planes }
  98.   end;
  99.  
  100.   {.PA}
  101. const
  102.   inbuf          = 16384;         {amount to read at a time}
  103.  
  104. type
  105.   PCXtypes       = (idunno, cga, t320x200x256, ega);
  106.  
  107.   PCXHdr = record
  108.              manufacturer   : Byte;
  109.              version        : Byte;
  110.              encode_mode    : Byte;
  111.              bits_per_pixel : Byte;
  112.              start_x        : Word;
  113.              start_y        : Word;
  114.              end_x          : Word;
  115.              end_y          : Word;
  116.              x_resolution   : Word;
  117.              y_resolution   : Word;
  118.              palette_RGB    : array[1..48] of Byte;
  119.              vmode          : Byte; {ignored}
  120.              planes         : Byte;
  121.              bytes_per_line : Word;
  122.              unused         : array[1..60] of Byte;
  123.            end;
  124.  
  125.   BigArray       = array[0..MaxInt] of Byte;
  126.  
  127. var
  128.   ABuf : BigArray absolute $A000 : $0000; {screen location for EGA}
  129.   CGABuf : BigArray absolute $B800 : $0000; {screen location for CGA}
  130.   hold           : array[1..inbuf] of Byte;
  131.   FP             : Pointer;
  132.   athold         : Word;
  133.   header         : PCXHdr;
  134.  
  135.   {.PA}
  136.   procedure encget(var inbyte : Byte; var Reps : Word);
  137.   var
  138.     actually_read  : Integer;
  139.   begin
  140.     Inc(athold);
  141.     Dec(filebytes);
  142.     if athold > inbuf then begin
  143.       Move(FP^,hold,inbuf);
  144.       FP := Ptr(Seg(FP^),Ofs(FP^)+inbuf);
  145.       athold := 1;
  146.     end;
  147.  
  148.     { $c0 masks first two bytes for 11xxxxxx --- $c0 = ($c0 and hold[athold])}
  149.     if hold[athold] >= $c0 then begin
  150.       { $3f masks last five bytes for xxx11111 }
  151.       Reps := $3f and hold[athold];
  152.       Inc(athold);
  153.       Dec(filebytes);
  154.       if athold > inbuf then begin
  155.         Move(FP^,hold,inbuf);
  156.         FP := Ptr(Seg(FP^),Ofs(FP^)+inbuf);
  157.         athold := 1;
  158.       end;
  159.     end
  160.     else
  161.       Reps := 1;
  162.  
  163.     inbyte := hold[athold];
  164.   end;
  165.  
  166.   {.PA}
  167.   procedure ReadPaint(readtype : PCXtypes);
  168.   const
  169.     DrawAt : array[1..4] of Word = (0, 80, 160, 240);
  170.   var
  171.     byte_cnt       : Integer;
  172.     ScanCount      : Word;
  173.     ScanEven       : Boolean;
  174.     Startat        : Word;
  175.     Reps           : Word;
  176.     data           : Byte;
  177.     EGARow         : array[0..639] of Byte;
  178.     BitPlane       : Word;
  179.  
  180.   begin
  181.     athold := inbuf;
  182.     byte_cnt := 0;
  183.     ScanCount := 0;
  184.     ScanEven := True;
  185.     Startat := $0000;
  186.     BitPlane := 1;
  187.  
  188.     while filebytes > 0 do begin
  189.       encget(data, Reps);
  190.  
  191.       case readtype of
  192.         t320x200x256 :
  193.           begin                   {this section for 256 color 320x200}
  194.             FillChar(ABuf[byte_cnt], Reps, data);
  195.             Inc(byte_cnt, Reps);
  196.           end;
  197.         ega :
  198.           begin                   {this section for 16 color 640x350}
  199.             FillChar(EGARow[byte_cnt], Reps, data);
  200.             Inc(byte_cnt, Reps);
  201.  
  202.             { see if we have filled a row; THEN write it }
  203.             if (byte_cnt >= 320) or (filebytes = 0) then begin
  204.               for BitPlane := 1 to 4 do
  205.                 WriteToEGAScreen(BitPlane, @ABuf[Startat], @EGARow[DrawAt[BitPlane]], 80);
  206.               Dec(byte_cnt, 320);
  207.               if byte_cnt > 0 then Move(EGARow[320], EGARow[0], byte_cnt);
  208.               Inc(Startat, 80);
  209.             end;
  210.           end;
  211.         cga :
  212.           begin                   {this section for CGA}
  213.             FillChar(CGABuf[Startat+byte_cnt], Reps, data);
  214.             Inc(byte_cnt, Reps);
  215.  
  216.             { see if we have filled a row }
  217.             if byte_cnt = 80 then begin
  218.               byte_cnt := 0;
  219.               ScanEven := not ScanEven;
  220.               if ScanEven then begin
  221.                 Inc(ScanCount, 80);
  222.                 Startat := $0000+ScanCount;
  223.               end
  224.               else
  225.                 Startat := $2000+ScanCount;
  226.             end
  227.           end;
  228.       end;
  229.     end;
  230.   end;
  231.  
  232.   {.PA}
  233.   procedure SetPaletteBlock(SegBlock, OfsBlock : Word);
  234.     { DOS Call 10, 10, 12 -- Set Block of Color Registers }
  235.   inline($B8/$12/$10/             { MOV AX, $1012 }
  236.          $BB/$00/$00/             { MOV BX, 0     -- first register to set }
  237.          $B9/$00/$01/             { MOV CX, 256   -- # registers to set    }
  238.          $5A/                     { POP DX        -- offset of block       }
  239.          $07/                     { POP ES        -- segment of block      }
  240.          $CD/$10);                { INT 10        }
  241.  
  242.  
  243.   {.PA}
  244.   procedure SetEGAColor(SetColor : Word);
  245.     { DOS Call 10, 10, 00 -- Set Color Register }
  246.   inline($B8/$00/$10/             { MOV AX, $1000 }
  247.          $5B/                     { POP BX        -- BL: color, BH: value }
  248.          $CD/$10);                { INT 10        }
  249.  
  250.   procedure ChangePaletteEGA;
  251.   const
  252.     SetBit1        = 32;
  253.     SetBit2        = 4;
  254.     SetBits        = 36;
  255.   type
  256.     BxReg = record bl : Byte; bh : Byte; end;
  257.   var
  258.     Count          : Byte;
  259.     SubCount       : Word;
  260.     S              : BxReg;
  261.     SetColor       : Word absolute S;
  262.   begin
  263.     Count := 0;
  264.     repeat
  265.       S.bl := Count div 3;        {bl is color number 0-15}
  266.       S.bh := 0;                  {bh is color value 0 to 63}
  267.       {set Red (32,4), Green (16,2), or Blue (8,1)}
  268.       for SubCount := 0 to 2 do begin
  269.         Inc(Count);
  270.         case header.palette_RGB[Count] of
  271.           0 : S.bh := S.bh or 0;
  272.           85 : S.bh := S.bh or (SetBit1 shr SubCount);
  273.           170 : S.bh := S.bh or (SetBit2 shr SubCount);
  274.           255 : S.bh := S.bh or (SetBits shr SubCount);
  275.         end;
  276.       end;
  277.       SetEGAColor(SetColor);
  278.     until Count = 48;
  279.   end;
  280.  
  281.   {.PA}
  282.   function DrawPic(FilePointer : pointer; FBytes : LongInt) : DrawError;
  283.   var
  284.     PCXtype        : PCXtypes;
  285.     Result         : DrawError;
  286.     actually_read  : Integer;
  287.   begin
  288.     DrawPic := NoError;
  289.     Result := NoError;
  290.  
  291.     FileBytes := FBytes;
  292.     FP := FilePointer;
  293.     Dec(filebytes, 128);
  294.     Move(FP^,header,128);
  295.     FP := Ptr(Seg(FP^),Ofs(FP^)+128);
  296.  
  297.     {Determine PCX type}
  298.     PCXtype := idunno;
  299.     if header.manufacturer = $0A then
  300.       case header.bits_per_pixel of
  301.         8 : PCXtype := t320x200x256;
  302.         2 : PCXtype := cga;
  303.         1 : PCXtype := ega;
  304.       end;
  305.  
  306.     case PCXtype of
  307.       idunno : Result := BadFormat;
  308.       t320x200x256 : begin
  309.                        DrawMode($13);
  310.                      end;
  311.       cga : DrawMode($04);
  312.       ega : begin
  313.               DrawMode($10);
  314.               ChangePaletteEGA;
  315.             end;
  316.     end;
  317.  
  318.     if Result = NoError then ReadPaint(PCXtype);
  319.  
  320.     DrawPic := Result;
  321.   end;
  322.  
  323. begin
  324.   LastDrawMode := FindLastDrawMode;
  325. end.
  326.