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

unit fastputimage;

{
 *******************************************************
 *                *VERY* FAST PUTIMAGE                 *
 *******************************************************
 *                (C) Petr Sulla 1996                  *
 *             E-mail: xsulla@fi.muni.cz               *
 *******************************************************
 *  Public domain, use at your own risk. Enjoy it !!!  *
 *******************************************************


 Hi all ! I was just in need of a *REALLY* fast putimage but I couldn't
 find it anywhere. So I sat down for a couple of hours and here it is !
 The FASTEST putimage I've ever seen.

 The x-position must be a multiplicate of 8 due to the VGA/EGA
 memory organisation. (will be automatically rounded)

 The image should not exceed the screen size (this case is not tested
 and could cause strange results...

 The image structure is *not* compatible with the Borland's one.
 Old images can be easily converted by displaying them and then
 saving them using this new getimage.

 It could be possibly even faster - some code optimization could help.
 I find it fast enough as it is now, anyway ;-)

 An example follows.
 }

interface

{$g+}

function myimagesize(x,y,x0,y0:word):word;
procedure mygetimage(x,y,x0,y0:word;p:pointer);
procedure myputimage(x,y:word;p:pointer);
procedure waitretrace;

implementation

function myimagesize(x,y,x0,y0:word):word;
var dummy:longint;
    sx,sy:word;
begin
  sx:=succ(abs(x0-x) div 8);
  sy:=succ(abs(y0-y));
  dummy:=sx*sy*4+10;        {*4 because of 4 bitplanes}
  if dummy<65520 then
    myimagesize:=dummy
  else
    myimagesize:=0;
end;

procedure mygetimage(x,y,x0,y0:word;p:pointer);assembler;
var m:word;
asm
    sti
    push es
    push ds
    cld                              {rep adds}
    les di,[p]                       {x0 <- width, y0 <- height, write to buffer}
    mov ax,x0
    sub ax,x
    shr ax,3                         {x0:=x0 div 8}
    mov x0,ax
    mov es:[di],ax
    inc x0
    mov ax,y0
    sub ax,y
    mov y0,ax
    mov es:[di+2],ax
    inc y0
    add di,4                         {es:di <- pointer to data}
    shr x,3                          {x:=x div 8}
    mov bx,y                         {m:=y*80+x - offset in vram}
    mov cx,bx
    shl bx,4
    shl cx,6
    add bx,cx
    add bx,x
    mov m,bx
    mov ax,0a000h                    {ds:si <- beginning of vram}
    mov ds,ax
    mov bx,y0                        {bx - lines counter}
    mov dx,03ceh                     {dx - port address}
    mov al,4
    out dx,al
    inc dx
@@1:
    mov ah,4                         {ah - 3=1.bit plane, 2=2.bitpl.,1=3.bitpl.,0=4.bitpl.}
@@2:
    mov al,ah
    dec al
    out dx,al                        {send number of bitplane to the graphic card}
    mov si,m                         {offset in videoram}
    mov cx,x0                        {image width to counter}
    rep movsb                        {send  cx bytes from DS:SI(vram) to ES:DI(image)}
    dec ah                           {decrement al - next bitplane}
    jnz @@2                          {is zero ? - no=next bitplane}
    add m,80                         {next line in vram}
    dec bx                           {decrement lines counter}
    jnz @@1                          {last line  ? no=next line}
    dec dx                           {set graphic card back to std. modus}
    mov al,3
    out dx,al
    inc dx
    xor al,al
    out dx,al
    pop ds
    pop es
    cli
end;

procedure myputimage(x,y:word;p:pointer);assembler;
var sx,sy,m:word;
asm
    sti
    push es
    push ds
    cld                              {rep adds}
    shr x,3                          {x:=x div 8}
    mov bx,y                         {m:=y*80+x - offset in vram}
    mov cx,bx
    shl bx,4
    shl cx,6
    add bx,cx
    add bx,x
    mov m,bx
    lds si,[p]                       {sx <- width, sy <- height}
    mov ax,word ptr ds:[si]
    inc ax
    mov sx,ax
    mov ax,word ptr ds:[si+2]
    inc ax
    mov sy,ax
    add si,4                         {ds:si <- pointer to data}
    mov ax,0a000h                    {es:di <- beginning of vram}
    mov es,ax
    mov bx,sy                        {bx - lines counter}
    mov dx,03c4h                     {dx - port address}
    mov al,2
    out dx,al
    inc dx
@@1:
    mov al,8                         {al - 8=1.bit plane, 4=2.bitpl.,2=3.bpl.,1=4.bpl.}
@@2:
    out dx,al                        {send bitplane number to the graphic card}
    mov di,m                         {offset in videoram}
    mov cx,sx                        {image width to counter}
    rep movsb                        {send cx bytes from DS:SI(image) to ES:DI(vram)}
    shr al,1                         {divide al by 2 - next bitplane of 4}
    jnz @@2                          {is zero ? - no=next bitplane}
    add m,80                         {next line in vram}
    dec bx                           {decrement lines counter}
    jnz @@1                          {last line ? no=next line}
    dec dx                           {set graphic card back to std. modus}
    mov al,2
    out dx,al
    inc dx
    mov al,15
    out dx,al
    pop ds
    pop es
    cli
end;

procedure waitretrace;assembler;    {can be handy for smooth animation}
asm
        mov dx,$3da
@1:     in al,dx
        test al,8
        jz @1
@2:     in al,dx
        test al,8
        jnz @2
end;

end.

{------------- 8< ------ Cut here ---------- 8< ----------------------}

{
 *******************************************************
 *                FAST PUTIMAGE EXAMPLE                *
 *******************************************************
 *                 (C) Petr Sulla 1996                 *
 *              E-mail: xsulla@fi.muni.cz              *
 *******************************************************
 *    Public domain, use at your own risk. Enjoy !!!   *
 *******************************************************
 }

uses crt,graph,fastputimage;
var gd,gm:integer;
    p,q:pointer;

procedure garbage;
var i,j,k:integer;
begin
  for i:=1 to 80 do
    begin
      j:=random(15)+1;
      setcolor(j);
      setfillstyle(1,j);
      j:=random(200);
      k:=random(200);
      case random(3) of
       0:rectangle(j,k,j+random(200),k+random(200));
       1:bar(j,k,j+random(200),k+random(200));
       2:circle(j,k,random(200));
      end;
    end;
end;

begin
  gd:=detect;
  initgraph(gd,gm,'');  {<- insert path to your egavga.bgi here}

  getmem(p,myimagesize(0,0,300,343));  {get some memory for the two test images}
  getmem(q,myimagesize(0,0,300,343));

  randomize;

  setfillstyle(1,8);
  bar(0,0,getmaxx,getmaxy);
  garbage;                             {generate some garbage on screen}
  mygetimage(0,0,300,343,p);           {and make it to an image ;-) }

  repeat until keypressed;
  while keypressed do readkey;
  cleardevice;

  setfillstyle(1,13);                  {and the same once more with}
  bar(0,0,getmaxx,getmaxy);            {another background color}
  garbage;
  mygetimage(0,0,300,343,q);

  repeat until keypressed;
  while keypressed do readkey;
  cleardevice;

  repeat
    myputimage(random(330),random(135),p);   {display both images in a loop}
    myputimage(random(330),random(135),q);
  until keypressed;
  while keypressed do readkey;

  freemem(p,myimagesize(0,0,300,343));       {free the memory occupied by the images}
  freemem(q,myimagesize(0,0,300,343));

  closegraph;
end.


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