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

    {
    >I am making a computer game using pascal and a 640x480x16 resolution,
    >using Jordan Hargrafix's SVGABG16.BGI driver, and I want to use the
    >setactivepage/setvisualpage commands to "hide" the screen as it is being
    >redrawn, and then show it again to give the effect of super fast screen
    >refresh (i.e. so fast, you can't see it)

    I don't havce time to find out what you mean exactly.
    This unit redraws sprites, and doesn't display them until
    ShowVirtualScreen is activated.
    }
    unit Sprites;
    { Basically a simple and effective spriteengine for use with Turbo }
    { Pascal 6.0. (Does not require the GRAPH unit..)                  }
    {                                                                  }
    { Designed for use with MCGA, VGA and compatibles. Works in mode   }
    { mode $13 (320x200 with 256 simultaneously colours.               }
    {                                                                  }
    { Written by:                                                      }
    {            Marius Kjeldahl                                       }
    {            Stud. post 104                                        }
    {            N-7034 Trondheim - NTH                                }
    {            Norway                                                }
    {            Ph. +47 7 58 91 11                                    }
    {            e-mail: mariusk@lise.unit.no                          }
    {                    (at NTH - Norwegian Institute of Technology ) }
    {                    (dept. of Business and Information Technolgy) }
    {                                                                  }
    { These routines are being distributed as shareware. To be used in,}
    { or as part of any commercial product, you have to become a       }
    { registered user. As a registered user you will receive upgrades  }
    { and rights to distribute these routines with your products.      }
    { To become a registered user, you will have to send a letter with }
    { who you are and what product(s) will use these routines and      }
    { make US$39 payable to the author (cheque or money..).            }
    {                                                                  }
    {                                                                  }
    { If you have any suggestions or comments please do not hesitate   }
    { to contact me. Have fun...                                       }
    {                                                                  }
    { Future plans for enhancements: interrupt driven, faster rep      }
    { movsw for sprites, built in animation, screen region scrolling   }
    { and more..                                                       }

    interface
    uses
      Dos;
    const
      MaxSprites = 14; { Maximum number of sprites activated simultaneously }
      MaxDim = 80*10;  { Dimensions of largest sprite to be used (x*y)      }
    type
      ScreenTypePointer = ^ScreenType;       { Pointer to a virtual screen  }
      ScreenType = array [1..64000] of byte; { Array to hold virtual screen }
      SpriteType = record                    { Misc. sprite data            }
                     oldx, oldy,             { - old location               }
                     x, y : integer;         { - current location           }
                     w, h : byte;            { - width and height           }
                     SpriteData,             { - spriteimage                }
                     Buffer : array [0..MaxDim-1] of byte; { spritebackgr.  }
                     Active : boolean;       { - currently active           }
                     ix, iy : integer;       { - sprite increment           }
                                             {   (not currently used)       }
                   end;
    var
      Sprite : array [1..MaxSprites] of SpriteType; { Array of sprites      }
      Virtual_Screen : ScreenTypePointer;    { Pointer to virtual screen    }

      procedure DrawSprites;
      { Saves background and draws all currently active sprites at their    }
      { current location.                                                   }

      procedure LoadSprite (Num : byte; FileName : string);
      { Loads spritedata from ordinary text file. Examine the .SPR files    }
      { for further details. Use .CEL files instead if you've have          }
      { purchased AutoDesk Animator...                                      }

      procedure SetMode (Mode : word);
      { Sets screen mode. Use $13 for use with sprites                      }

      procedure ShowVirtualScreen ;
      { Copies the VirtualScreen to the users screen. Any changes done with }
      { the sprites and/or their position will NOT be visible until this    }
      { routine has been called!                                            }

      procedure LoadCOL (FileName : string);
      { Loads a file containing the palette desc. of the 256 colours and    }
      { programs the VGA/MCGA to use these palette. It uses AutoDesk        }
      { Animators file format - so you can use Animator to select colors and}
      { then save the palette in Animators ordinary .COL file.              }
      { For those without Animator (you should not be..) the file format is }
      { simple. Each colour (from 0 to 255) has three bytes which containts }
      { red, green and blue values. First in the file comes (usually)       }
      { 0,0,0 - black and so on until the last colour.                      }

      procedure LoadCEL (FileName :  string; ScrPtr : pointer);
      { Directly loads a CEL to the location pointed to by ScrPtr.          }
      { This routine uses AutoDesk Animators file format. This means you    }
      { can use Animators excellent drawing tools to design you sprites and }
      { save them in a ordinary .CEL file.                                  }
      { For those without Animator; here is a short desc. of the format:    }
      { The first 800 bytes is Animators header. It does include various    }
      { information like it's own colours palette, width and height.        }
      { However this version skips all that information and just reads the  }
      { image data into the location pointed to by ScrPtr. Remember to      }
      { set the sprites width and height too! (It is NOT read you of the    }
      { .CEL file in this release..                                         }

      procedure DisableAllSprites;
      { Disables all sprites. But this routine does not restore the screen  }
      { image (compare with HideSprites..                                   }

      procedure HideSprites;
      { Disables all sprites. Basically same as DisableAllSprites, but this }
      { routine also recovers the "original" screen image.                  }

      procedure FillBox (x1, y1, x2, y2 : integer; b : byte);
      { Draws a coloured box with upper left corner x1,y1 and lower right   }
      { corner x2,y2.                                                       }

      procedure CopySprite (var Sprite : SpriteType; x1, y1 : integer);
      { "Stamps" a copy of any sprite at the chosen location x1,y1.         }
      { Use this routine if you want to put the image there, but do not plan}
      { to animate in anyway..                                              }

      procedure WaitForVerticalRetrace;
      { Waits for vertical retrace. Will be used in further releases..      }

    implementation

    procedure CopySprite (var Sprite : SpriteType; x1, y1 : integer); assembler;
    label
      _Redraw, _DrawLoop, _Exit, _LineLoop, _NextLine, _Store, _NoPaint;
      asm
        push  ds
        push  es
        lds   si,Sprite
        mov   ax,x1     { ax = x }
        mov   bx,y1     { bx = y }
    _Redraw:
        push  ax
        push  bx
        mov   ax,word(Virtual_Screen+2)
        mov   es,ax         { ES=A000h }
        pop   bx            { ax = y }
        mov   ax,320
        mul   bx            { ax = y * 320 }
        pop   bx            { ax = x }
        add   ax,bx         { bx = bx + ax dvs. skjermadr.. }
        mov   di,ax         { di = skjermadr. }
        mov   dl,[si+9]     { dl = height of sprite }
        xor   ch,ch
        mov   cl,[si+8]     { cx = width of sprite }
        add   si,10         { si = start of spritedata }
        cld
    _DrawLoop:
        push  di            { store y adr. for later }
        push  cx            { store width }
    _LineLoop:
        mov   bl,byte ptr [si]
        or    bl,bl
        jnz   _Store
    _NoPaint:
        inc    si
        inc    di
        loop   _LineLoop
        jmp    _NextLine
    _Store:
    {    test   byte ptr [es:di],1
        jz     _NoPaint}
        movsb
        loop  _LineLoop
    _NextLine:
        pop   cx
        pop   di
        dec   dl
        jz    _Exit
        add   di,320        { di = next line of sprite }
        jmp   _DrawLoop
    _Exit:
        pop   es
        pop   ds
      end;

    procedure DrawSprite (var Sprite : SpriteType); assembler;
    label
      _Redraw, _DrawLoop, _Exit, _LineLoop, _NextLine, _Store, _NoPaint;
      asm
        push  ds
        push  es
        lds   si,Sprite
        mov   ax,[si+4]     { ax = x }
        mov   bx,[si+6]     { bx = y }
        cmp   ax,[si]        {if x <> oldx then _Redraw}
        jne   _Redraw       {
        cmp   bx,[si+2]
       je    _Exit         { if (x=oldx) and (y=oldy) then exit }
    _Redraw:
        mov   [si],ax       { oldx = x }
        mov   [si+2],bx     { oldy = y }
        push  ax
        push  bx
        mov   ax,word(Virtual_Screen+2)
        mov   es,ax         { ES=A000h }
        pop   bx            { ax = y }
        mov   ax,320
        mul   bx            { ax = y * 320 }
        pop   bx            { ax = x }
        add   ax,bx         { bx = bx + ax dvs. skjermadr.. }
        mov   di,ax         { di = skjermadr. }
        mov   dl,[si+9]     { dl = height of sprite }
        xor   ch,ch
        mov   cl,[si+8]     { cx = width of sprite }
        add   si,10         { si = start of spritedata }
        cld
    _DrawLoop:
        push  di            { store y adr. for later }
        push  cx            { store width }
    _LineLoop:
        mov   bl,byte ptr [si]
        or    bl,bl
        jnz   _Store
    _NoPaint:
        inc    si
        inc    di
        loop   _LineLoop
        jmp    _NextLine
    _Store:
    {    test   byte ptr [es:di],1
        jz     _NoPaint}
        movsb
        loop  _LineLoop
    _NextLine:
        pop   cx
        pop   di
        dec   dl
        jz    _Exit
        add   di,320        { di = next line of sprite }
        jmp   _DrawLoop
    _Exit:
        pop   es
        pop   ds
      end;

    procedure SaveSpriteBackground (var Sprite : Spritetype); assembler;
    label
      _Redraw, _DrawLoop, _Exit;
      asm
        push  ds
        push  es
        les   di,Sprite
        mov   ax,es:[di+4]     { ax = x }
        mov   bx,es:[di+6]     { bx = y }
        push  ax
        push  bx
        mov   ax,word(Virtual_Screen+2)
        mov   ds,ax         { DS=A000h }
        pop   bx            { bx = y }
        mov   ax,320
        mul   bx            { ax = y * 320 }
        pop   bx            { bx = x }
        add   ax,bx         { ax = ax + bx dvs. skjermadr.. }
        mov   si,ax         { si = skjermadr. }
        mov   dl,es:[di+9]     { dl = height of sprite }
        xor   ch,ch
        mov   cl,es:[di+8]     { cx = width of sprite }
        add   di,10+MaxDim  { di = start of screenbuffer }
        cld
    _DrawLoop:
        push  si            { store y adr. for later }
        push  cx            { store width }
        rep   movsb
        pop   cx
        pop   si
        dec   dl
        jz    _Exit
        add   si,320        { di = next line of sprite }
        jmp   _DrawLoop
    _Exit:
        pop   es
        pop   ds
      end;

    procedure FillBox (x1, y1, x2, y2 : integer; b : byte); assembler;
    label
      _l1;
    asm
      push  ds
      push  es
      mov   ax,word(Virtual_Screen+2)
      mov   es,ax
      mov   ax,y1
      mov   bx,320
      mul   bx
      mov   di,ax
      add   di,x1
      mov   ax,y1
      mov   dx,y2
      sub   dx,ax
      inc   dx

      mov   ax,x1
      mov   cx,x2
      sub   cx,ax { cx contains number of bytes across }
      inc   cx
      mov   al,b
      cld
    _l1:
      push  di
      push  cx
      rep   stosb
      pop   cx
      pop   di
      add   di,320
      dec   dx
      jnz   _l1
      pop   es
      pop   ds
    end;

    procedure RestoreSpriteBackground (var Sprite : Spritetype); assembler;
    label
      _Redraw, _DrawLoop, _Exit, _LineLoop;
      asm
        push  ds
        push  es
        lds   si,Sprite
        mov   ax,[si]     { ax = x }
        mov   bx,[si+2]     { bx = y }
        push  ax
        push  bx
        mov   ax,word(Virtual_Screen+2)
        mov   es,ax         { ES=A000h }
        pop   bx            { ax = y }
        mov   ax,320
        mul   bx            { ax = y * 320 }
        pop   bx            { ax = x }
        add   ax,bx         { bx = bx + ax dvs. skjermadr.. }
        mov   di,ax         { di = skjermadr. }
        mov   dl,[si+9]     { dl = height of sprite }
        xor   ch,ch
        mov   cl,[si+8]     { cx = width of sprite }
        add   si,10+MaxDim         { si = start of spritedata }
        cld
    _DrawLoop:
        push  di            { store y adr. for later }
        push  cx            { store width }
        rep   movsb
        pop   cx
        pop   di
        dec   dl
        jz    _Exit
        add   di,320        { di = next line of sprite }
        jmp   _DrawLoop
    _Exit:
        pop   es
        pop   ds
      end;

    procedure DrawSprites;
    var
      I : byte;
    begin
      for I := MaxSprites downto 1 do
        if (Sprite[I].Active) and (Sprite [I].oldx <> -1) then
          RestoreSpriteBackground (Sprite [I]);
      for I := 1 to MaxSprites do begin
        if Sprite [I].Active then begin
          SaveSpriteBackground (Sprite [I]);
          DrawSprite (Sprite [I]);
        end;
      end;
    end;

    procedure HideSprites;
    var
      I : byte;
    begin
      for I := MaxSprites downto 1 do
        if (Sprite [I].oldx <> -1) then begin
          RestoreSpriteBackground (Sprite [I]);
          Sprite [I].oldx := -1;
        end;
    end;

    procedure SetMode (Mode : word);
    begin
      asm
        mov ax,Mode;
        int 10h
      end;
    end;

    procedure LoadSprite (Num : byte; FileName : string);
    var
      Fil : text;
      fx, fy : word;
    begin
      assign (Fil, FileName);
      reset (Fil);
      fillchar (Sprite [Num], sizeof (Sprite[1]), 0);
      with Sprite [Num] do begin
        oldx := integer ($FFFF);
        readln (Fil, w, h);          {integer-32768}
        for fy := 1 to h do begin
          for fx := 1 to w do
            read (Fil, SpriteData [pred (fy) * w + pred (fx)]);
          readln (fil);
        end;
      end;
      close (Fil);
    end;

    procedure LoadCOL (FileName : string);
    type
      DACType = array [0..255] of record
                                    R, G, B : byte;
                                  end;
    var
      DAC : DACType;
      Fil : file of DACType;
      I : integer;
      Regs : Registers;
    begin
      assign (Fil, FileName);
      reset (Fil);
      read (Fil, DAC);
      close (Fil);
      for I := 0 to 255 do begin
        with Regs do begin
          AX := $1010;
          BX := I;
          DH := DAC [I].R;
          CH := DAC [I].G;
          CL := DAC [I].B;
        end;
        Intr ($10, Regs);
      end;
    end;

    procedure WaitForVerticalRetrace; assembler;
    label
      l1, l2;
    asm
        cli
        mov dx,3DAh
    l1:
        in al,dx
        and al,08h
        jnz l1
    l2:
        in al,dx
        and al,08h
        jz  l2
        sti
    end;

    procedure ShowVirtualScreen; assembler;
        asm
          push ds
          push es
          xor  si,si
          xor  di,di
          cld
          mov  ax,word(Virtual_Screen + 2)
          mov  ds,ax
          mov  ax,0A000h
          mov  es,ax
          mov  cx,7D00h
          rep  movsw
          pop  es
          pop  ds
        end;

    procedure LoadCEL (FileName :  string; ScrPtr : pointer);
    var
      Fil : file;
      Buf : array [1..1024] of byte;
      BlocksRead, Count : word;
    begin
      assign (Fil, FileName);
      reset (Fil, 1);
      BlockRead (Fil, Buf, 800);
      Count := 0; BlocksRead := $FFFF;
      while (not eof (Fil)) and (BlocksRead <> 0) do begin
        BlockRead (Fil, mem [seg (ScrPtr^): ofs (ScrPtr^) + Count], 1024,
    BlocksRead);
        Count := Count + 1024;
      end;
      close (Fil);
    end;

    procedure DisableAllSprites;
    var
      I : integer;
    begin
      for I := 1 to MaxSprites do
        with Sprite [I] do begin
          OldX := -1;
          Active := FALSE;
        end;
    end;

    var
      Dum : ^byte;
    begin
      DisableAllSprites;
      repeat
        new (Virtual_Screen);
        if ofs (Virtual_Screen^) <> 0 then begin
          dispose (Virtual_Screen);
          new (Dum);
        end;
      until ofs (Virtual_Screen^) = 0;
    end.

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