{****************************************************************************}
{Unit VNM_PCX - it is a addon unit for graphics library VenomGFX.            }
{It bring a loader for .PCX graphics files                                   }
{   It defines function Load_PCX                                             }
{      written by Laaca                                                      }
{****************************************************************************}

unit vnm_PCX;
{$IFDEF VER2}{$DEFINE NEWFPC}{$ENDIF}
{$IFDEF VER3}{$DEFINE NEWFPC}{$ENDIF}
{$IFDEF NEWFPC}{$CALLING OLDFPCCALL}{$ENDIF}

{$ASMMODE INTEL}

interface
uses VenomGFX;

Function Load_PCX(s:string;var w:virtualwindow):byte;
{virtualwindow W will be initialized inside loader}


implementation
uses GRPfile,VenomMng,objects;
Function Load_PCX(s:string;var w:virtualwindow):byte;

var
PCX_Header    : Record
                           Manufacturer      : Byte;
                           Version           : Byte;
                           Encoding          : Byte;
                           BitsPerPixel      : Byte;
                           xmin,ymin         : Word;
                           xmax,ymax         : Word;
                           Hdpi,Vdpi         : Word;
                           Palette           : Array[0..47] of Byte;
                           Reserved          : Byte;
                           ColorPlanes       : Byte;
                           BytesPerLine      : Word;
                           PalettenInfo      : Word;
                           H_ScreenSize      : Word;
                           V_ScreenSize      : Word;
                           CTM_definedYMax   : Word;
                           CTM_definedXMax   : Word;
                           Nothing_else_shit : Array[1..52] of Byte;
                          End;

    cbf:array[0..767] of byte;
    zdroj,zdroj2,dcil:pointer;
    cil:array[0..16384] of byte;
    red,green,blue:array[0..255] of word;
    a,b,l,red_p,green_p,blue_p,sirka:longint;
    c:word;
    grp:TGrpStream;

begin
 (******* Load PCX header and set window parameters ************************)
w.VWoffset:=0;
grp.Init(s,stOpenRead);
l:=grp.GetSize;
if l<129 then Exit(1);
grp.Read(PCX_Header,128);
if PCX_Header.manufacturer<>$0a then Exit(1);
if PCX_Header.bitsperpixel<>8 then Exit(2);
if not (PCX_Header.ColorPlanes in [1,3]) then Exit(3);
Init_VW(w,PCX_Header.xmax-PCX_Header.xmin+1,PCX_Header.ymax-PCX_Header.ymin+1,false);

dcil:=pointer(w.VWoffset);
GetMem(zdroj,l);
zdroj2:=zdroj;
grp.Read(zdroj^,l-128);
sirka:=w.breite;
If PCX_Header.ColorPlanes=1 then
begin
{****************************************************************************}
{---------------------------------- 256 barev -------------------------------}
{****************************************************************************}
grp.Seek(l-768);         { palette position }
grp.Read(cbf,768);       { palette loaded, but the colors are still shitty }
a:=0;
for b:=0 to 255 do       { color conversion to work properly in HiColor mode }
   begin
   c:=cbf[a] shr 3;red[b]:=c shl 11;inc(a);
   c:=cbf[a] shr 2;green[b]:=c shl 5;inc(a);
   c:=cbf[a] shr 3;blue[b]:=c;inc(a);
   end;
asm        { Let's go ! }
cld
mov esi,zdroj2
mov dx,PCX_header.ymin

@Dalsi_radek:                { external cycle - NextLine cycle }
lea edi,cil
xor ebx,ebx

@pokracuj_v_radku:           { internal cycle I - next byte in the row }
mov al,ds:[esi];inc esi
mov ah,al
and al,0c0h
cmp al,0c0h
jz @opakovac                 { single pixel or block ? }
mov es:[edi],ah;inc edi           {...only one pixel }
inc ebx
jmp @preskoc_opakovac

@opakovac:                   { whole block }
xor ecx,ecx
mov cl,ah
and cl,03fh       { switch off the upper two bits }
add ebx,ecx
mov al,ds:[esi];inc esi { reads the second byte }
mov ah,al;push ax;shl eax,16;pop ax
shr ecx,1;pushf;shr ecx,1;rep stosd;adc ecx,ecx  { fast 32bit }
rep stosw;popf;adc ecx,ecx;rep stosb             { write      }

@preskoc_opakovac:
cmp bx,PCX_header.bytesperline
jb @pokracuj_v_radku         { end of internal cycle I }
{---------------------------------------------------------------------------}
push esi      { color conversion - palette entries to colors }
push edx
lea esi,cil           { go to the begin of converting line }
mov edx,esi
mov ecx,sirka         { X-size of the image }
mov edi,dcil          { output }

@dalsi_pixel:     { internal cycle II }
xor eax,eax
xor ebx,ebx
mov esi,edx
mov al,ds:[esi];inc edx
shl eax,1
lea esi,red;add esi,eax;add bx,ds:[esi]
lea esi,green;add esi,eax;add bx,ds:[esi]
lea esi,blue;add esi,eax;add bx,ds:[esi]
mov es:[edi],bx
add edi,2
sub ecx,1
jnz @dalsi_pixel  { end of internal cycle II }
mov dcil,edi
pop edx
pop esi
{---------------------------------------------------------------------------}
inc dx
cmp dx,PCX_header.ymax
jbe @dalsi_radek          { end of external cycle }
end;
end else
begin
{****************************************************************************}
{-------------------------------- 24 bit PCX --------------------------------}
{****************************************************************************}
a:=PCX_header.bytesperline*3;
b:=PCX_header.bytesperline;
asm
cld
mov esi,zdroj2
mov dx,PCX_header.ymin

@Dalsi_radek24:
lea edi,cil
xor ebx,ebx

@pokracuj_v_radku24:
mov al,ds:[esi];inc esi
mov ah,al
and al,0c0h
cmp al,0c0h
jz @opakovac24
mov es:[edi],ah;inc edi
inc ebx
jmp @preskoc_opakovac24

@opakovac24:
xor ecx,ecx
mov cl,ah
and cl,03fh
add ebx,ecx
mov al,ds:[esi];inc esi
mov ah,al;push ax;shl eax,16;pop ax
shr ecx,1;pushf;shr ecx,1;rep stosd;adc ecx,ecx
rep stosw;popf;adc ecx,ecx;rep stosb

@preskoc_opakovac24:
cmp bx,word a
jb @pokracuj_v_radku24
{---------------------------------------------------------------------------}
push esi
mov ecx,sirka
lea esi,cil          { set on the begin of decoding line }
mov red_p,esi             { begin of red part }
add esi,b
mov green_p,esi           { begin of green part }
add esi,b
mov blue_p,esi            { begin of blue part }
mov edi,dcil              { output }

@dalsi_pixel24:
xor eax,eax
xor ebx,ebx

mov esi,red_p;inc red_p
mov bl,ds:[esi]
shr ebx,3
shl ebx,11             { red... }

mov esi,green_p;inc green_p
mov al,ds:[esi]
shr eax,2
shl eax,5
add ebx,eax            { green...  }

mov esi,blue_p;inc blue_p
xor eax,eax
mov al,ds:[esi]
shr eax,3
add ebx,eax            { blue...   }

mov es:[edi],bx
add edi,2
sub ecx,1
jnz @dalsi_pixel24
mov dcil,edi
pop esi
{---------------------------------------------------------------------------}
inc dx
cmp dx,PCX_header.ymax
jbe @dalsi_radek24
end;
end;
grp.Done;
FreeMem(zdroj,l);
Load_PCX:=0;
end;

Procedure Register_PCX_Loader;
begin
RegisterImageLoader('PCX',@Load_PCX);
end;

begin
Register_PCX_Loader;
end.
