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

    {
    ====================================================================

    FILENAME :    REMAP.PAS

    AUTHOR   :    SCOTT TUNSTALL B.Sc

    CREATION :    16TH NOVEMBER 1996
    DATE

    PURPOSE  :    ORGANISES THE PALETTE OF A 256 COLOUR PCX SO THAT
                  THE USED COLOURS ARE ARRANGED SEQUENTIALLY,
                  AND UN-USED COLOURS IN YOUR PCX ARE DELETED
                  (MEANING, RESET TO R,G,B 0 0 0 )

                  THIS UTIL IS ONLY USEFUL FOR GAMES PROGRAMMERS,
                  OR THOSE WHO WANT A WELL ORGANISED PALETTE!

           THIS UTIL NEEDS KOJAKVGA 3.3 FOR SUCCESSFUL OPERATION!!
           KOJAKVGA 3.1/3.2 HAS BUGS IN THE PCX SAVE ROUTINES.

    --------------------------------------------------------------------

    INTRODUCTION
    ------------

    With a 256 colour picture, it's quite likely that not all 256 colours
    are used on screen.

    This program counts the number of colours used in a PCX file, then
    organises the palette entries so that all colours used are
    sequential. Duh?

    Say for example you had a PCX file which used 6 from the 256 colours.
    The colours used being 1,2,4,9,127,255. (The rest obviously
    are unused.)

    Wouldn't you like those colours to be remapped so that colour 4
    would move to unused colour slot 3, colour 9 to 4, colour 127 to 5?
    Thus having colours 1,2,3,4,5,6 used? And 7-255 free?

    "Why?" You ask. Reason is, games programmers like to reserve a portion
    of the palette for sprites and the other portion for the background.

    Say colours 0-127 was reserved for shapes, and 128-255 was
    reserved for the background. But colour 200 was used as a
    shape colour.

    That would mean every 128 colour background palette you loaded
    would have to preserve colour 200's RGB value just in case a
    shape required it.

    And say the shape palette needed to be changed but a background
    palette needed a particular colour. Annoying huh?

    By using this program with a bare background screen (no sprites
    present) you can organise your palette and then allocate a sequential
    palette space for sprites.

            This text is (C) 1996 Crap explanations ltd.
            Do not sue me :)

    WHAT DO YOU DO?
    ---------------

    This works from DOS:

    Syntax: REMAP [/M] <256 Colour PCX to remap> [Dest PCX name]

    If you specify the command line /M (For MERGE) then the palette
    shall be shrunk to it's smallest size; duplicate palette entries
    shall be merged if two colours present on screen have identical
    RGB values. (Of course, this may disrupt PCX's with hidden
    graphics, say for example, black text on a black background,
    which will then be faded in later on in a program)

    You MUST specify the name of the PCX to remap. The PCX may be
    UP TO 320 x 200: IF LARGER, THE PCX's DIMENSIONS ARE CLIPPED
    TO 320 x 200!!!

    You need not specify the name of the destination PCX file. The
    default name is REMAPPED.PCX .

    When the program ends, you will be told how many colours were used.
    This number also indicates the first free colour which you can use
    for backgrounds etc.

    If you decided to condense the palette, you will see how many
    colours remain after palette merge.

    DISCLAIMER
    ----------

    If the PCX turns out funny it's not my fault OK! And I take ZERO
    responsibility for any damage this program causes. This program
    seems to work OK on my machine. (i.e. -> it's not crashed yet)

    Use this program at your own risk.

    --------------------------------------------------------------------
    }

    Program REMAP_PCX;

    Uses crt,KOJAKVGA;

    {
    If you're using KOJAKVGA version 3.3, or you've removed the PCX
    save errors from KOJAKVGA 3.1/3.2 then delete the next line :)
    }

    {$DEFINE EMBARASS_SCOTT}

    Var
       SrcBmap   : Pointer;
       DstBMap   : Pointer;
       SrcPalette: PaletteType;
       DstPalette: PaletteType;
       Merge     : Boolean;
       Remapped  : Byte;
       Adjusted  : Byte;
       InFileName,
       OutFileName: string[80];

    { Returns TRUE if Colour WhichColour is present on the 64K
      bitmap specified }

    Function ColourUsed(TheBitmap: pointer; WhichColour:byte): boolean;
    Assembler;
    Asm
         PUSH DS
         LDS SI,TheBitmap
         MOV AH,WhichColour

         MOV CX,64000
         CLD

    @Check:
         LODSB
         CMP AL,AH
         JZ @ItsUsed
         DEC CX
         JNZ @Check

         MOV AL,False
         JMP @Exit

    @ItsUsed:
         MOV AL,True

    @Exit:
         POP DS
    End;

    {
    Normally I'd write 20000 lines of documentation for this, but really
    I can't be bothered as it's operation is so simple.

    Basically the RGB data for colour ColNo in Palette SrcPal
    is moved to colour NewNo in Palette DstPal, and every pixel
    which matches colour ColNo on the source bitmap is changed to
    colour NewNo on the dest bitmap.

    Got that? No? Tough! =)

    }

    Procedure RemapBitmap( Src: pointer; ColNo: byte;
                           Dst: pointer; NewNo: byte);
    Begin

         Asm
         PUSH DS
         MOV BL,NewNo

         LES DI,Dst
         LDS SI,Src

         MOV CX,64000
         CLD

    @ChangeLoop:
         MOV AL,[SI]
         CMP AL,ColNo
         JNZ @NoRemapByte

         MOV [ES:DI],BL

    @NoRemapByte:
         INC SI
         INC DI

         DEC CX
         JNZ @ChangeLoop
         POP DS
         End;

    End;

    {
    If a colour is used, it's shunted to an area in the palette that's
    unused, therefore bunching all used colours TOGETHER.
    }

    Function SqueezePalette( SrcBMap:pointer; SrcPal:PaletteType;
                             DstBMap:pointer; Var DstPal:PaletteType): byte;
    Var ColCount: byte;
        RemapNum: byte;

    Begin
         RemapNum:=0;
         For Colcount:=0 to 255 do
             If ColourUsed(SrcBmap,ColCount) Then
                Begin
                DstPal.RedLevel[RemapNum]:=SrcPal.RedLevel[ColCount];
                DstPal.GreenLevel[RemapNum]:=SrcPal.GreenLevel[ColCount];
                DstPal.BlueLevel[RemapNum]:=SrcPal.BlueLevel[ColCount];
                RemapBitmap(SrcBMap,ColCount,DstBMap,RemapNum);
                Inc(RemapNum);
             End;

         SqueezePalette:=RemapNum;
    End;

    {
    Merge duplicate palette entries.
    If any two colours on the bitmap have the same RGB, this will remove
    one of the identical colours, therefore creating a free RGB entry.

    Returns number of merged colours.
    }

    Function MergeDuplicates( TheBitmap:pointer;
                               Var ThePalette: PaletteType;
                               PaletteSize: byte) : byte;
    Var ColCount:  byte;
        ColCount2: byte;

    Begin
         For ColCount:=0 to (PaletteSize-1) do
             For ColCount2:=(ColCount+1) to PaletteSize do
                 Begin
                 With ThePalette do
                 if (RedLevel[ColCount]=RedLevel[ColCount2])
                 And (GreenLevel[ColCount]=GreenLevel[ColCount2])
                 And (BlueLevel[ColCount]=BlueLevel[ColCount2]) Then
                     RemapBitmap(TheBitMap,ColCount2,TheBitMap,ColCount);
             End;

         MergeDuplicates:=SqueezePalette( TheBitmap,ThePalette,TheBitmap,
                                          ThePalette);
    End;

    Begin
         {
         KOJAKVGA 3.1/3.2 couldn't save PCX files 100% correctly
         so this code stops you from wasting time.
         }

    {$IFDEF EMBARASS_SCOTT}

         If GetVersion < $0303 Then
            Begin
            Writeln;
            Writeln('YOU ARE USING AN OUT OF DATE KOJAKVGA UNIT.');
            Writeln;
            Writeln('This program needs KOJAKVGA version 3.3 or better');
            Writeln('in order for the PCX save routine to work properly !');
            Writeln('(ahem, sorry etc.)');
            Writeln;
            Writeln('Version 3.3 should be in the SWAG though, probably in');
            Writeln('the same post where you got this from ! :)');
            Writeln;
            Halt(1);
         End;

    {$ENDIF}

         If (ParamCount = 0) or (ParamCount > 3) Then
            Begin
            Writeln;
            Writeln;
            Writeln('REMAP by Scott Tunstall B.Sc (whoo! =) )   16/11/96');
            Writeln;
            Writeln('Syntax: REMAP [/M] <InFileName> [OutFileName]');
            Writeln;
            Writeln('To merge duplicate palette entries, specify /M switch.');
            Writeln('   (This switch is optional)');
            Writeln;
            Writeln('<InFilename> is required, and specifies the name of the');
            Writeln('   PCX file to remap.');
            Writeln;
            Writeln('[OutFileName] is optional. It specifies the name of the');
            Writeln('   PCX file which shall be hold the remapped data. If you');
            Writeln('   do not specify a file name, the default is REMAPPED.PCX.');
            Writeln;
            If ParamCount > 3 Then
               Begin
               Writeln('Error: 3 parameters max..');
               Writeln;
            End;

            Halt(1);
         End;

         Merge:=False;
         OutFileName:='REMAPPED.PCX';

    { There's no validation of command line parameters. }

         If ParamCount = 1 Then
            InFileName:=Paramstr(1)
         Else
             If ParamCount = 2 Then
                Begin
                If (ParamStr(1)='/m') or (ParamStr(1)='/M') Then
                   Begin
                   Merge:=True;
                   InFileName:=ParamStr(2);
                   Sound(50);
                   Delay(10);
                   NoSound;
                   End
                Else
                    Begin
                    InFileName:=ParamStr(1);
                    OutFileName:=ParamStr(2);
                End;
                End
             Else
                 Begin
                 If (ParamStr(1)='/m') or (ParamStr(1)='/M') Then
                    Begin
                    Merge:=True;
                    InFileName:=ParamStr(2);
                    OutFileName:=ParamStr(3);
                    End
                 Else
                     Begin
                     Writeln;
                     Writeln('WHAT PLANET ARE YOU ON? /M EXPECTED !!!');
                     Halt(1);
                 End;
             End;

         { Now lets get going :) }

         SrcBmap:=New64KBitmap;
         UseBitmap(SrcBMap);
         Cls;
         LoadPCX(InFileName,SrcPalette);
         DstBMap:=New64KBitmap;
         CopyBitmapTo(DstBMap);

         FillChar(DstPalette,SizeOf(DstPalette),0);         { All black }

         Write('Remapping ',InFileName,'...');
         Remapped:=SqueezePalette(SrcBmap,SrcPalette,DstBmap,DstPalette);
         Writeln('Done.');

         If Merge Then
            Begin
            Write('Removing duplicate colours...');
            Adjusted:=MergeDuplicates(DstBmap,DstPalette,Remapped-1);
            Writeln('Done.');
         End;

         Write('Saving ',OutFileName,'...');

         UseBitmap(DstBMap);
         SaveAreaAsPCX(OutFileName,DstPalette,0,0,320,200);
         Writeln('Done.');
         Writeln;

         { All done! :) }

         Writeln('# of unique colours used in original :',Remapped);
         If Merge Then
         Writeln('After duplicates removed             :',Adjusted);
         Writeln;

         Writeln('Press ENTER to return to DOS.');
         FreeBitmap(SrcBmap);
         FreeBitmap(DstBMap);
         Readln;
    End.

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