{ >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.