home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 5 / ctrom5b.zip / ctrom5b / PROGRAM / DIVERSEN / PCXK53 / PCX.PAS < prev    next >
Pascal/Delphi Source File  |  1995-01-17  |  20KB  |  681 lines

  1. unit PCX;
  2.  
  3. (* {$DEFINE RegisteredVersion} *)
  4.  
  5. (* Requires Turbo/Borland Pascal for DOS, version 6 or later.
  6.  
  7.                                 Version 5.1
  8.                              Copyright (c) 1994
  9.                              by Peter Donnelly
  10.                               Skookum Software
  11.                               1301 Ryan Street
  12.                          Victoria BC Canada V8T 4Y8
  13.  
  14.    ╒══════════════════════════════════════════════════════════════════════╕
  15.    │  Permission is granted for the non-commercial distribution and       │
  16.    │  private use of this source code. This is shareware; if you use all  │
  17.    │  or portions of it in programs you distribute, or make any other     │
  18.    │  public use of it, you are expected to pay a modest registration     │
  19.    │  fee. Registered users will receive the latest version of the code,  │
  20.    │  including support for 256-color Super-VGA modes. Please see the     │
  21.    │  READ.ME file for details.                                           │
  22.    ╘══════════════════════════════════════════════════════════════════════╛
  23. *)
  24. INTERFACE
  25.  
  26. uses DOS, CRT;
  27.  
  28. CONST
  29.         NoOptions = $0000;        { to set bits for Options }
  30.         SaveMem =   $0001;
  31.         HCenter =   $0002;
  32.           VCenter =   $0004;
  33.         BlackOut =  $0008;
  34.         AutoSet = 0;              { can be passed to ReadIt }
  35.         NumModes = 11;
  36.         OurModes: array[1..NumModes] of word =
  37.                   ($0D, $0E, $10, $12, $13, $100,
  38.                    $101, $102, $103, $105, $107);
  39.         ErrNoOpen = 1;
  40.         ErrNoPal  = 2;
  41.         ErrTooWide= 3;
  42.         ErrColors = 4;
  43.         ErrNoSupp = 5;
  44.  
  45.  
  46. TYPE
  47.         RGBrec = record
  48.                    RedVal, GreenVal, BlueVal: byte;
  49.                  end;
  50.  
  51.         RGB256Rec = array[0..255] of RGBRec;
  52.  
  53.         PCXHeaderRec = record
  54.                          Signature: byte;
  55.                          Version: byte;
  56.                          Code: byte;
  57.                          BitsPerPlane: byte;
  58.                          XMin, YMin, XMax, YMax: word;
  59.                          HRes, VRes: word;
  60.                          Palette: array[0..15] of RGBRec;
  61.                          Reserved: byte;
  62.                          NumPlanes: byte;
  63.                          BytesPerLine: word;
  64.                          OtherStuff: array[69..128] of byte;
  65.                        end;
  66.  
  67.         VESAInfoRec = record
  68.                         Signature: array[0..3] of char;
  69.                         Version: word;
  70.                         OEMptr: pointer;
  71.                         Capabilities: array[0..3] of byte;
  72.                         ModePtr: pointer;
  73.         { There are reports of some VESA BIOSes returning more than 256
  74.           bytes from function 0, so this record is padded a bit. }
  75.                         Reserved: array[0..256] of byte;
  76.                       end;
  77.  
  78.         ModeInfoRec = record
  79.                         Attributes: word;
  80.                         WindowA_atts, windowB_atts: byte;
  81.                         GranuleKb, WindowKb: word;
  82.                         WindowAstart, WindowBstart: word;
  83.                         FunctionAddr: pointer;
  84.                         BytesPerLine: word;
  85.                         XRes, YRes: word;
  86.                         OtherStuff: array[23..256] of byte;
  87.                       end;
  88.  
  89. VAR
  90.         FileError: word;
  91.  
  92. FUNCTION DetectVESA(var VESAInf: VESAInfoRec): boolean;
  93. FUNCTION DetectVGA: boolean;
  94. FUNCTION HardwareSupports(Mode: word): boolean;
  95. FUNCTION WeSupport(Mode: word): boolean;
  96. FUNCTION GetMode: word;
  97. PROCEDURE SetMode(Mode, Options: word);
  98. PROCEDURE GetModeInfo(Mode: word; var ModeInfo: ModeInfoRec);
  99. FUNCTION OpenFile(PicFileName: pathstr; var PicFile: file;
  100.                   var Header: PCXHeaderRec): boolean;
  101. PROCEDURE ReportError(Error: word; var ErrorStr: string);
  102. FUNCTION ReadIt(PicFileName: pathstr; var Mode: word; Options: word): integer;
  103.  
  104. {========================================================================}
  105.  
  106. IMPLEMENTATION
  107.  
  108. CONST   MaxBufSize = 65024;
  109.  
  110. VAR
  111.         BufferSize: word;
  112.         PCXFilename: pathstr;
  113.         PCXHeader: PCXHeaderRec;
  114.         ModeInfo: ModeInfoRec;
  115.         RGBpal: array[0..15] of RGBrec;
  116.         RGB256: RGB256Rec;
  117.         VESAInfo: VESAInfoRec;
  118.         Regs: registers;
  119.         WindowEnd: word;
  120.         StartCol: word;
  121.         ColumnCount: word;
  122.         Plane: word;
  123.         BytesPerLine: word;
  124.         BytesPerScanLine: word;
  125.         XMax: word;
  126.         RepeatCount: byte;
  127.         DataLength: word;
  128.         WindowStep, WindowPos: word;
  129.         WriteWindow: byte;
  130.         VideoSeg, VideoOffs: word;
  131.         Scratch, LineBuf: pointer;
  132.         LineBufSeg, LineBufOffs: word;
  133.         LineBufIndex: word;
  134.         LineEnd, ScreenWidth: integer;
  135.         Margin: integer;
  136.  
  137. { ---------------------- Video mode routines ---------------------------- }
  138.  
  139. {$L VGAP}
  140.  
  141. PROCEDURE Decode16; far; external;
  142.  
  143. PROCEDURE Decode256; far; external;
  144.  
  145. PROCEDURE VideoOff(state: boolean);
  146.  
  147. { Hides the image by turning off video refresh. See Ferraro p. 468. }
  148.  
  149. begin
  150. regs.AH:= $12;
  151. regs.BL:= $36;
  152. regs.AL:= ord(state);
  153. intr($10, regs);
  154. end;
  155.  
  156. FUNCTION DetectVESA(var VESAInf: VESAInfoRec): boolean;
  157.  
  158. VAR  Signature: string[4];
  159.      IsVESA: boolean;
  160.  
  161. begin
  162. IsVESA:= False;
  163. Regs.AX:= $4F00;                { VESA Get SuperVGA Info function }
  164. Regs.ES:= seg(VESAInf);         { Info returns in VESAInfo record }
  165. Regs.DI:= ofs(VESAInf);
  166. intr($10, regs);
  167. if (Regs.AH = 0) then        { Function failed if AH <> 0 }
  168. begin
  169.   Signature[0]:= #4;
  170.   Move(VESAInf.Signature, Signature[1], 4);
  171.   if Signature = 'VESA' then IsVESA:= true;
  172. end;
  173. DetectVESA:= IsVESA;
  174. end;
  175.  
  176.  
  177. FUNCTION DetectVGA: boolean;
  178.  
  179. begin
  180. regs.AH:= $1A;               { See Ferraro p. 887 }
  181. regs.AL:= 0;
  182. intr($10, regs);
  183. DetectVGA:= (regs.AH <> $1A);
  184. end;
  185.  
  186.  
  187. FUNCTION HardwareSupports(Mode: word): boolean;
  188.  
  189. { VESA function $4F00 returns, among other things, a pointer to a list
  190.   of the video modes supported. The list terminates in $FFFF. }
  191.  
  192. type  ModeList = array[0..255] of word;
  193.  
  194. VAR  Supported: boolean;
  195.      Modes: ^ModeList;
  196.      x: integer;
  197.  
  198. begin
  199. Supported:= false;
  200. if Mode >= $100 then
  201. begin
  202.   if DetectVESA(VESAInfo) then    { Fills info record }
  203.   begin
  204.     x:= 0;
  205.     Modes:= VESAInfo.ModePtr;
  206.     repeat
  207.       if Modes^[x] = Mode then   { mode supported - but is window? }
  208.       begin
  209.         GetModeInfo(Mode, ModeInfo);
  210.         Supported:= (ModeInfo.WindowKb > 0);
  211.       end;
  212.       inc(x);
  213.     until Supported or (Modes^[x] = $FFFF) or (x = 256);
  214.   end else Halt;        { if VESA not detected - shouldn't get this far }
  215. end
  216. else Supported:= true;  { assume VGA present }
  217. HardwareSupports:= Supported;
  218. end;
  219.  
  220.  
  221. FUNCTION WeSupport(Mode: word): boolean;
  222.  
  223. { True if requested mode is supported by PCX.PAS }
  224.  
  225. VAR  x: integer;
  226.      InThere: boolean;
  227.  
  228. begin
  229. InThere:= false;
  230. for x:= 1 to NumModes do
  231.   if Mode = OurModes[x] then InThere:= true;
  232. WeSupport:= InThere;
  233. end;
  234.  
  235.  
  236. FUNCTION BestMode(Header: PCXHeaderRec): word;
  237.  
  238. { Attempts to match the mode to the originating format, but goes to a
  239.   higher resolution if the image doesn't fit the screen. }
  240.  
  241. VAR   M: word;
  242.  
  243.   PROCEDURE Try(Mode: word);
  244.  
  245.   begin
  246.   if HardwareSupports(Mode) and WeSupport(Mode) then M:= Mode;
  247.   end;
  248.  
  249.   FUNCTION Fits: boolean;
  250.  
  251.   begin
  252.   Fits:= (Header.XMax < Header.HRes) and (Header.YMax < Header.VRes);
  253.   end;
  254.  
  255. begin    { BestMode }
  256. if Header.NumPlanes = 1 then
  257. begin
  258.   M:= $13;
  259.   if (Header.HRes > 320) or (not Fits) then Try($101);
  260.   if (Header.HRes > 640) or (not Fits) then Try($103);
  261.   if (Header.HRes > 800) or (not Fits) then Try($105);
  262.   if (Header.HRes > 1024) or (not Fits) then Try($107);
  263. end
  264. else if Header.NumPlanes = 4 then
  265. begin
  266.   if Header.HRes <= 320 then M:= $0D else M:= $0E;
  267.   if (Header.VRes > 200) or (not Fits) then Try($10);
  268.   if (Header.VRes > 350) or (not Fits) then Try($12);
  269.   if (Header.VRes > 480) or (not Fits) then Try($102);
  270. end
  271. else M:= $FFFF;
  272. BestMode:= M;
  273. end;
  274.  
  275.  
  276. FUNCTION GetMode: word;
  277.  
  278. VAR  CurrMode: word;
  279.  
  280. begin
  281. if DetectVesa(VESAInfo) then
  282. begin
  283.   Regs.AX:= $4F03;
  284.   intr($10, Regs);
  285.   CurrMode:= Regs.BX;                  { may be inaccurate if not SVGA }
  286.   CurrMode:= CurrMode and $3FFF;       {  - see Wilton p. 448 }
  287.   if HardwareSupports(CurrMode) and (CurrMode >= $100) then
  288.   begin
  289.     GetMode:= CurrMode; exit;
  290.   end;
  291. end;
  292. Regs.AH:= $0F;                         { return VGA mode }
  293. intr($10, Regs);
  294. GetMode:= Regs.AL;
  295. end;
  296.  
  297.  
  298. PROCEDURE SetMode(Mode, Options: word);
  299.  
  300. begin
  301. if Mode >= $100 then
  302. { --- VESA Super-VGA modes }
  303. begin
  304.   if (Options and SaveMem) <> 0 then Mode:= Mode or $8000;
  305.                              { Set bit 15 to preserve video memory }
  306.   Regs.AX:= $4F02;
  307.   Regs.BX:= Mode;
  308. end else
  309. { --- Standard VGA modes }
  310. begin
  311.   if (Options and SaveMem) <> 0 then Mode:= Mode or $80;
  312.                              { Set bit 7 to preserve video memory }
  313.   Regs.AH:= 0;
  314.   Regs.AL:= lo(Mode);
  315. end;
  316. intr($10, Regs);
  317. end;  { SetMode }
  318.  
  319.  
  320. PROCEDURE GetModeInfo(Mode: word; var ModeInfo: ModeInfoRec);
  321.  
  322. { Puts information on the selected VESA mode into the ModeInfo record. }
  323.  
  324. begin
  325. Regs.AX:= $4f01;
  326. Regs.CX:= Mode;
  327. Regs.ES:= seg(ModeInfo);
  328. Regs.DI:= ofs(ModeInfo);
  329. intr($10, Regs);
  330. { Early versions of VESA BIOS extensions do not return values in the
  331.   XRes and YRes fields. We need to know the YRes for centering images. }
  332. with ModeInfo do
  333. case Mode of
  334.   $100: YRes:= 400;
  335.   $101: YRes:= 480;
  336.   $102: YRes:= 600;
  337.   $103: YRes:= 600;
  338.   $105: YRes:= 768;
  339.   $107: YRes:= 1024;
  340. end;
  341. end;
  342.  
  343. { ------------------------- Palette routines ---------------------------- }
  344.  
  345. FUNCTION Get256Palette(var TheFile: file; var PaletteStart: longint): boolean;
  346.  
  347. { TheFile must be open. }
  348.  
  349. VAR    x: integer;
  350.        PaletteFlag: byte;
  351.  
  352. begin
  353. PaletteStart:= filesize(TheFile) - 769;
  354.  
  355. { The last 769 btes of the file are palette information, starting with a
  356.    one-byte flag. Each group of three bytes represents the RGB values of
  357.    one of the color registers. We take the 6 most significant bits
  358.    to bring the values within the range 0-63 expected by the registers. }
  359.  
  360. seek(TheFile, PaletteStart);
  361. blockread(TheFile, PaletteFlag, 1);
  362. if (PaletteFlag <> 12) or (PCXHeader.Version < 5) then
  363. begin
  364.   FileError:= ErrNoPal;
  365.   Get256Palette:= false;
  366.   exit;
  367. end;
  368. blockread(TheFile, RGB256, 768);         { Get palette info. }
  369. for x:= 0 to 255 do
  370. with RGB256[x] do
  371. begin
  372.   RedVal:= RedVal shr 2;
  373.   GreenVal:= GreenVal shr 2;
  374.   BlueVal:= BlueVal shr 2;
  375. end;
  376. Get256Palette:= true;
  377. end;  { Get256Palette }
  378.    
  379.  
  380. PROCEDURE SetColorRegisters(var PalRec);
  381.  
  382. { We can't use the BGI's SetRGBPalette even for the modes supported by
  383.   the BGI, because it won't work unless the BGI initializes the mode
  384.   itself. }
  385.  
  386. { PalRec is a string of 768 bytes containing the RGB data. }
  387.  
  388. begin
  389. Regs.AH:= $10;               { BIOS color register function }
  390. Regs.AL:= $12;               { Subfunction }
  391. Regs.ES:= seg(PalRec);       { Address of palette info }
  392. Regs.DX:= ofs(PalRec);
  393. Regs.BX:= 0;                 { First register to change }
  394. Regs.CX:= $100;              { Number of registers to change }
  395. intr($10, Regs);             { Call BIOS }
  396. end;
  397.  
  398.  
  399. PROCEDURE SetPalette(var Palette);
  400.  
  401. { Replaces the BGI SetAllPalette procedure. Palette is a 17-byte record
  402.   of the contents of the 16 EGA/VGA palette registers plus the overscan
  403.   register. }
  404.  
  405. begin
  406. Regs.AH:= $10;
  407. Regs.AL:= 2;
  408. Regs.ES:= seg(Palette);
  409. Regs.DX:= ofs(Palette);
  410. intr($10, Regs);
  411. end;
  412.  
  413. { ------------------------ Miscellaneous routines ------------------------ }
  414.  
  415. PROCEDURE GetMargin(ScreenWidth: word; var Margin, LineEnd: integer);
  416.  
  417. { Calculate how many pixels have to be skipped when advancing to the
  418.   next line, so that files of less than screen width can be displayed. }
  419.  
  420. begin
  421. LineEnd:= PCXHeader.BytesPerLine;      { Used as counter in assembler }
  422. Margin:= ScreenWidth - LineEnd;
  423. if Margin < 0 then FileError:= ErrTooWide;
  424. end;
  425.  
  426.  
  427. FUNCTION SetBufferSize: word;
  428.  
  429. begin
  430. if MaxBufSize > MaxAvail then SetBufferSize:= MaxAvail
  431. else SetBufferSize:= MaxBufSize;
  432. end;
  433.  
  434.  
  435. PROCEDURE ReportError(Error: word; var ErrorStr: string);
  436.  
  437. begin
  438. case Error of
  439.   ErrNoOpen:  ErrorStr:= 'Could not open file.';
  440.   ErrNoPal:   ErrorStr:= 'No palette information in file.';
  441.   ErrTooWide: ErrorStr:= 'Picture is too wide for requested video mode.';
  442.   ErrColors:  ErrorStr:= 'Number of colors in file does not match selected mode.';
  443.   ErrNoSupp:  ErrorStr:= 'Unsupported picture format.';
  444. end;
  445. end;
  446.  
  447.    
  448. FUNCTION OpenFile(PicFileName: pathstr; var PicFile: file;
  449.                   var Header: PCXHeaderRec): boolean;
  450.  
  451. begin
  452. assign(PicFile, PicFileName);
  453. {$I-} reset(PicFile, 1);
  454. blockread(PicFile, Header, 128);  {$I+}
  455. OpenFile:= IOresult = 0;
  456. end;
  457.  
  458. FUNCTION GetFirstPix(var Header: PCXHeaderRec;
  459.                      Options, ScreenWid, ScreenHt: word): longint;
  460.  
  461. { The image is centered if the Options call for it. Otherwise it is offset
  462.   on the screen according to the values of XMin and YMin in the file header.
  463.   These are usually zero. This function returns the offset in bytes from
  464.   the start of the video buffer to where the first pixel will be written. }
  465.  
  466. VAR  FirstPix: longint;
  467.      PicWid, PicHt: integer;
  468.  
  469. begin
  470. FirstPix:= 0;
  471. with Header do
  472. begin
  473.   PicWid:= (XMax - XMin + 1);
  474.   if BitsPerPlane = 1 then PicWid:= PicWid div 8;
  475.   PicHt:= YMax - YMin + 1;
  476.   if PicHt < ScreenHt then (* INC(FIRSTPIX, 10240); *)
  477.   begin
  478.     if (Options and VCenter) = 0 then
  479.       inc(FirstPix, YMin * ScreenWid)
  480.     else inc(FirstPix, longint((ScreenHt-1-PicHt) div 2) * ScreenWid);
  481.   end;
  482.   if PicWid < ScreenWid then
  483.   begin
  484.     if (Options and HCenter) = 0 then inc(FirstPix, XMin)
  485.     else inc(FirstPix, (ScreenWid - PicWid) div 2);
  486.   end;
  487. end;   { with }
  488. GetFirstPix:= FirstPix;
  489. end;
  490.  
  491. { -------------------------- VGA 16-color files ------------------------- }
  492.  
  493. PROCEDURE Read16(var PicFile: file; Mode, Options: word);
  494.  
  495. TYPE
  496.         PaletteBytes = array[0..2] of byte;
  497.  
  498. VAR
  499.         Entry, Gun, PCXCode: byte;
  500.         PalRegs: array[0..16] of byte;
  501.         ScreenHeight: word;
  502.  
  503. begin   { READ16 }
  504. if PCXHeader.NumPlanes <> 4 then
  505. begin
  506.   FileError:= ErrColors;
  507.   exit;
  508. end;
  509. if Mode >= $100 then
  510. begin
  511.   GetModeInfo(Mode, ModeInfo);
  512.   ScreenWidth:= ModeInfo.BytesPerLine;
  513.   ScreenHeight:= ModeInfo.YRes;
  514. end
  515. else case Mode of
  516.   $0D: begin ScreenWidth:= 40; ScreenHeight:= 200; end;
  517.   $0E: begin ScreenWidth:= 80; ScreenHeight:= 200; end;
  518.   $10: begin ScreenWidth:= 80; ScreenHeight:= 350; end;
  519.   $12: begin ScreenWidth:= 80; ScreenHeight:= 480; end;
  520. end;
  521. GetMargin(ScreenWidth, Margin, LineEnd);
  522. if FileError <> 0 then exit;
  523. VideoOffs:= GetFirstPix(PCXHeader, Options, ScreenWidth, ScreenHeight);
  524. VideoSeg:= $A000;         { Segment of video memory }
  525. port[$3C4]:= 2;           { Index to map mask register }
  526. Plane:= 1;                { Initialize plane }
  527. port[$3C5]:= Plane;       { Set sequencer to mask out other planes }
  528.  
  529. { --- Decipher 16-color palette --- }
  530.  
  531. {  The palette information is stored in bytes 16-63 of the header. Each of
  532.    the 16 palette slots is allotted 3 bytes - one for each primary color.
  533.    Any of these bytes can have a value of 0-255. However, the VGA is
  534.    capable only of 6-bit RGB values (making for 64x64x64 = 256K possible
  535.    colors), so we take only the 6 most significant bits from each PCX
  536.    color value.
  537.  
  538.    In 16-color modes, the VGA uses the 16 CGA/EGA palette registers.
  539.    However, the actual color values (18 bits per slot) won't fit here,
  540.    so the palette registers are used as pointers to 16 of the 256 color
  541.    registers, which hold the RGB values.
  542.  
  543.    What we have to do is extract the RGB values from the PCX header, put
  544.    them in the first 16 color registers, then set the palette to point to
  545.    those registers. }
  546.  
  547. for Entry:= 0 to 15 do
  548. begin
  549.   for Gun:= 0 to 2 do
  550.   begin
  551.     PCXCode:= PaletteBytes(PCXHeader.Palette[entry])[Gun];
  552.     with RGBPal[Entry] do
  553.     case gun of
  554.       0: RedVal:= PCXCode shr 2;
  555.       1: GreenVal:= PCXCode shr 2;
  556.       2: BlueVal:= PCXCode shr 2;
  557.     end;
  558.   end;  { gun }
  559.   PalRegs[Entry]:= Entry;
  560. end;  { Entry }
  561. PalRegs[16]:= 0;                       { overscan color }
  562. SetColorRegisters(RGBPal);             { RGB values into registers 0-15 }
  563. SetPalette(PalRegs);                   { point to registers 0-15 }
  564.  
  565. { --- Read and decode the image data --- }
  566.  
  567. BytesPerLine:= PCXHeader.BytesPerLine;
  568. RepeatCount:= 0;                       { Initialize assembler vars. }
  569. ColumnCount:= 0;
  570. seek(PicFile, 128);
  571. BufferSize:= SetBufferSize;
  572. getmem(Scratch, BufferSize);           { Allocate scratchpad }
  573. repeat
  574.   blockread(PicFile, Scratch^, BufferSize, DataLength);
  575.   Decode16;                           { Call assembler routine }
  576. until eof(PicFile);
  577. port[$3C5]:= $F;                       { Reset mask map }
  578. freemem(Scratch,BufferSize);           { Discard scratchpad }
  579. end;  { READ16 }
  580.  
  581. { ------------------------- VGA 256-color files ------------------------- }
  582.  
  583. PROCEDURE ReadVGA256(var PicFile: file; Mode, Options: word);
  584.  
  585. VAR     TotalRead: longint;
  586.         PaletteStart: longint;
  587.  
  588. begin
  589. if PCXHeader.NumPlanes <> 1 then
  590. begin
  591.   FileError:= ErrColors;
  592.   exit;
  593. end;
  594. { --- Set palette  --- }
  595. if not Get256Palette(PicFile, PaletteStart) then exit;
  596. { If clearing video memory before displaying the picture (the default),
  597.   we wait till the entire picture is in memory before displaying it,
  598.   to give a better effect. This is done by setting all color registers
  599.   to black. Otherwise the picture colors are set before any of it is
  600.   displayed. }
  601. SetColorRegisters(RGB256);
  602. ScreenWidth:= 320;
  603. GetMargin(ScreenWidth, Margin, LineEnd);
  604. if FileError <> 0 then exit;
  605.  
  606. { --- Read image data --- }
  607. seek(PicFile, 128);
  608. TotalRead:= 128;
  609. repeatcount:= 0;                           { Initialize assembler vars. }
  610. VideoOffs:= GetFirstPix(PCXHeader, Options, ScreenWidth, 200);
  611. VideoSeg:= $A000;
  612. BufferSize:= SetBufferSize;
  613. getmem(Scratch, BufferSize);                { Allocate scratchpad }
  614. repeat
  615.   blockread(PicFile, Scratch^, BufferSize, DataLength);
  616.   inc(TotalRead, DataLength);
  617.   if (TotalRead > PaletteStart) then
  618.       dec(DataLength, TotalRead - PaletteStart);
  619.   Decode256;
  620. until (eof(PicFile)) or (TotalRead>= PaletteStart);
  621. freemem(Scratch, BufferSize);
  622. end;  { ReadVGA256 }
  623.  
  624. { ------------------------- SVGA 256-color files ------------------------ }
  625.  
  626. {$IFDEF RegisteredVersion}
  627.   {$I SVGA256.PAS}
  628. {$ELSE}
  629.  
  630. PROCEDURE ReadSVGA256(var PicFile: file; Mode, Options: word);
  631.  
  632. begin
  633.   SetMode(3, NoOptions);
  634.   Writeln('Support for this video mode is available only to registered');
  635.   Writeln('users of PCX.PAS. Please see READ.ME for details.');
  636.   Writeln;
  637. end;
  638.  
  639. {$ENDIF}
  640.  
  641. { -------------------------- Main Procedure ----------------------------- }
  642.  
  643. FUNCTION ReadIt(PicFileName: pathstr; var Mode: word; Options: word): integer;
  644.  
  645. VAR  PCXfile: file;
  646.  
  647. begin
  648. FileError:= 0;
  649. if not OpenFile(PicFileName, PCXFile, PCXHeader) then           { Gets PCX header }
  650. begin
  651.   ReadIt:= 1;
  652.   exit;
  653. end;
  654. { Trap CGA files }
  655. if (PCXHeader.BitsPerPlane < 8) and (PCXHeader.NumPlanes = 1) then
  656. begin
  657.   close(PCXFile);
  658.   ReadIt:= 5;
  659.   exit;
  660. end;
  661. if Mode = AutoSet then Mode:= BestMode(PCXHeader);
  662. if Mode = $FFFF then             { couldn't find a workable mode }
  663. begin
  664.   FileError:= ErrNoSupp;
  665.   exit;
  666. end;
  667. SetMode(Mode, Options);
  668. if (Options and Blackout) > 0 then VideoOff(true);
  669. case Mode of
  670.   $0D, $0E, $10, $12, $102: Read16(PCXFile, Mode, Options);
  671.   $13: ReadVGA256(PCXFile, Mode, Options);
  672.   $100, $101, $103, $105, $107: ReadSVGA256(PCXFile, Mode, Options);
  673. end;
  674. if (Options and Blackout) > 0 then VideoOff(false);
  675. close(PCXFile);
  676. ReadIt:= FileError;
  677. end;
  678.  
  679. BEGIN
  680. END.
  681.