[rec.games.programmer] Write Mode 1 on EGA/VGA cards

anicolao@watcgl.waterloo.edu (Alex Nicolaou) (04/15/91)

 I know that it is possible to do the following on EGA and VGA cards, 
but am not clear on the exact step by step actions you need to do it.
I would love it if someone has a ready made source example that does this
or would be willing to write one - my problem is that although I am 
proficient in C and C++, I can barely code in assembly. So here's
the problem/program I need solved/written:

	1. Draw an image on an off-screen area of video memory
	2. Set the card into "Write Mode 1"
	3. Use a fast machine instruction to copy the block
	  containing the off screen image onto the screen (MOVSW)
	4. Restore the card to the previous write mode

Now, if anyone can provide me with ANY code written in ANYTHING (excepting
fortran :-) that does this, I want to read it. Please mail it to me!

I am operating under the following constraints:

	1. I would like to draw off screen using the Borland graphics
	  functions, but don't know if it clips to the screen boundaries
	  or not.

	2. I want the code I eventually produce to run on an 8088 (and
	  therefore it will run on anything better, too).

If anyone out there wants to / can construct a working example using
Turbo C or Borland C++ with inline assembly, it would be very very
appreciated.

Thanks,

alex
	

jdb@swamp.cis.ufl.edu (Brian K. W. Hook) (04/16/91)

In article <1991Apr15.061148.29923@watcgl.waterloo.edu> anicolao@watcgl.waterloo.edu (Alex Nicolaou) writes:
|>
|> I know that it is possible to do the following on EGA and VGA cards, 
|>but am not clear on the exact step by step actions you need to do it.
|>I would love it if someone has a ready made source example that does this
|>or would be willing to write one - my problem is that although I am 
|>proficient in C and C++, I can barely code in assembly. So here's
|>the problem/program I need solved/written:
|>
|>	1. Draw an image on an off-screen area of video memory
|>	2. Set the card into "Write Mode 1"
|>	3. Use a fast machine instruction to copy the block
|>	  containing the off screen image onto the screen (MOVSW)
|>	4. Restore the card to the previous write mode
|>
|>Now, if anyone can provide me with ANY code written in ANYTHING (excepting
|>fortran :-) that does this, I want to read it. Please mail it to me!
|>
|>I am operating under the following constraints:
|>
|>	1. I would like to draw off screen using the Borland graphics
|>	  functions, but don't know if it clips to the screen boundaries
|>	  or not.

As far as I know, you might as well give it up using the Borland graphics
functions.  They are quite powerful (for being bundled with the compiler)
but don't support writing to an offscreen buffer.  However....you can write
to a hidden page using setvisualpage() and setactivepage() and swap pages,
which is faster than doig a bitblt transfer.  However, you can adapt this
to writing to an offscreen buffer via using setactivepage() and
setvisualpage(), then using getimage() and putimage()...e.g.

   setvisualpage(0);  // look at page 0
   setactivepage(1);  // write to hidden page
    .
    .  // do graphics things to hidden page
    .
   getimage(/* graphics block on hidden page */);
   setactivepage(0);  // put the image on page 0
   putimage(/* wherever you want */);
   
   While this is not near as fast as assembly, it does get the job done
using the BGI.  However, using the MetaGraphics code library you can write
to offscreen virtual bitmaps (very handy) and it is only 99 dollars and it
is written in asm.  Unfortunately, the library is a set of hooks into a
~90K TSR.  MetaWindows/Plus is a linkable library, but costs about 300
bucks.

|>
|>	2. I want the code I eventually produce to run on an 8088 (and
|>	  therefore it will run on anything better, too).

Ouch.  Better do it ALL in asm then.  Can't help you then.  I wouldn't aim
so high (or low) since the 80286 is now officially the most predominant
machine on the market.a  Also, not many XTs are running EGA/VGA boards
these days anyhow.

paulg@bhpmrl.oz.au (Paul Gallagher) (04/17/91)

Do it ALL in asm. Ouch? I thought good graphics were ONLY done in assembler!
I'm convinced there's a forgotten market out there for good animation etc
that CAN run on an XT. It seems that over the past five years or so
programmers have given in and said "Bugger it! Why bother when you can
pop out and buy a processor upgrade instead".

Enough of the inflamatory comments! The previous poster was right: forget BGI.
Take a look at Michael Abrash's "Power Graphics Programming" though, and
either key in or get the accompanying disk (if its still available). You'll
see there's still life in the XT yet!

Paul Gallagher

PS: there's got to be a merket out there for a 3GL compiler optimised for
PC graphics. Has there ever been such a beast? I guess Sierra must have
an in-house system of probably 4GL stature, along with the other games
manufacturers, but is there anything on the market?

anicolao@watcgl.waterloo.edu (Alex Nicolaou) (04/17/91)

In article <1991Apr17.135925.9063@bhpmrl.oz.au> paulg@bhpmrl.oz.au 
	(Paul Gallagher) writes:
>
>Do it ALL in asm. I thought good graphics were ONLY done in assembler!

 ** Well, impressive ANIMATION for the amazingly pathetic graphics cards 
currently available for IBM PCs and compatibles does require a good solid
knowledge of assembly. But I don't have the time or patience to work on 
the fastest routines possible; the Borland BGI stuff is quite fast (better
than BIOS) and affords me some device independance. I'm not interested in
changing my code for each new graphics standard that comes around. And since
at the moment I don't want to animate, I am safe in my choice of tools.

  However, I won't contest that the moving of the image from an off-screen
area onto the screen is a task that requires assembly code; as of yet, I
haven't received even one response which contains code that can do this :-(.

>I'm convinced there's a forgotten market out there for good animation etc
>that CAN run on an XT. 

 ** The market for games is small small small. When was the last time you BOUGHT
a game? I imagine it is only the established games companies that can afford to 
create libraries good enough to run from an XT upwards.
>
>Take a look at Michael Abrash's "Power Graphics Programming" though, and

 ** Thanks for the book reference! I'll try to find it. (If you've keyed in code
that does what I need I'd love to see it in my mailbox!).
>

alex

devries@symcom.math.uiuc.edu (Alan DeVries) (04/18/91)

In article <1991Apr17.154316.9832@watcgl.waterloo.edu> anicolao@watcgl.waterloo.edu (Alex Nicolaou) writes:
>In article <1991Apr17.135925.9063@bhpmrl.oz.au> paulg@bhpmrl.oz.au 
>	(Paul Gallagher) writes:
>>
>>Do it ALL in asm. I thought good graphics were ONLY done in assembler!
>>
>>I'm convinced there's a forgotten market out there for good animation etc
>>that CAN run on an XT. 
>
> ** The market for games is small small. When was the last time you BOUGHT
a game? I imagine it is only the established games companies that can afford to 
>create libraries good enough to run from an XT upwards.

   As the owner of an XT, I've noticed that even established game
companies can't write versions of their games which run well on the XT,
they're all too slow.  :-(

                                             Alan

dmurdoch@watstat.waterloo.edu (Duncan Murdoch) (04/18/91)

In article <1991Apr15.061148.29923@watcgl.waterloo.edu> anicolao@watcgl.waterloo.edu (Alex Nicolaou) writes:
>
>	2. I want the code I eventually produce to run on an 8088 (and
>	  therefore it will run on anything better, too).
>

I don't know if it can do exactly what you wanted, but a very fast graphics
library (with interface to a bunch of C memory models, and Turbo Pascal) 
is Acromole.  I've used it to smoothly spin wire frames with a dozen or twenty
lines on an 8 Mhz 8086; it can smoothly spin 1000 points on my 486.

It's basically the same routines as used in the Acrospin program, but 
put into .OBJ files so you can link them in.  They add something like 40K
or 50K to your program, and support most of the common graphics cards.

It's pretty cheap (something like $35), and comes with fairly ugly 
(but reasonably clear) documentation, and a sample program in really ugly 
TP.  I don't know if the author's C style is better, but I had
to run it through a reformatter before I could stand to play with it.

You can call the company which sells it (Acrobits) at an 800 number; I think
it's just 1-800-ACR-OBIT.  They've recently moved from California to Utah, I
think; perhaps if that 800 number doesn't work, their old number (415)-369-0838
will at least get you started to find them.

Duncan Murdoch
dmurdoch@watstat.waterloo.edu

u855203@probitas.cs.utas.edu.au (Michael Harlow) (04/19/91)

In <1991Apr17.135925.9063@bhpmrl.oz.au> paulg@bhpmrl.oz.au (Paul Gallagher) writes:


>Do it ALL in asm. Ouch? I thought good graphics were ONLY done in assembler!
>Enough of the inflamatory comments! The previous poster was right: forget BGI.
>Take a look at Michael Abrash's "Power Graphics Programming" though, and
>either key in or get the accompanying disk (if its still available). You'll
>see there's still life in the XT yet!

I have tried to order this book from down under through book stores.
Could someone PLEASE send me the address of a bookstore/mail order place
that will deal with international orders for this book very quickly. I 
needed this book yesterday 8(
I beleive its very good, based on the extracts I've seen in magazines.

Thanks.
Mike

--
| Michael Harlow          |  u855203@probitas.cs.utas.edu.au
| GPO Box 1201,           |  
| Hobart, 7001            |  Computer Science Department
| Tasmania, Australia     |  University Of Tasmania 

paulg@bhpmrl.oz.au (Paul Gallagher) (04/23/91)

I've got to agree that the IBM PC graphics cards are certainly not
the bee's knees, but they are a _challenge_! Why write code once, when
you can do it over and over for the various screen modes?!?

I'm attaching some ASM, based on an example in "Power graphics programming".
NB: I just pulled this file off my hard disk - I think it's the right one.
It should animate 6 multicolored balls bouncing around the screen (EGA/VGA)
with no screen flicker, and at a respectable speed even on a 4.77MHz XT.
(this is an intereseting point - the animation speed, since it is
keyed to the vertical retrace, is totally dependant on the video hardware.
The processors actually idling for much of the time. The implication is
that there is still time left to do direction-velocity calculations,
collision detection etc. You will note that in this example the ball vectors
are pre-determined, and the only collisions are those with the side of the scren
)

It illustrates the use of VRAM for storing sprites - a feature I think you
were interested in?

Regards,
PaulG.

PS: Sorry, the code is not documented well. 

     /\/\       Paul Gallagher, PC Support Officer,
    / / /\      Computer Systems Group,
   / / /  \     BHP Melbourne Research Laboratories
  / / / /\ \    245 Wellington Rd Mulgrave Vic 3170 AUSTRALIA
  \ \/ / / /    Phone : +61-3-560-7066,  Fax : +61-3-561-6709
   \  / / /     ACSnet  :  paulg@bhpmrl.OZ.AU        
    \/\/\/

Code begins here-------------------------------------------------------->
; written for TASM in MASM mode
.MODEL SMALL
.STACK 512

hires      equ 0

VidSeg     equ 0A000h
ScrWidth   equ 640/8
ScrHeight  equ 350
Page0      equ 0
Page1      equ 1
Page0Offs  equ 0
Page1Offs  equ ScrWidth*ScrHeight
Xlow       equ 1
Xhi        equ Scrwidth-4
Ylow       equ 8
Yhi        equ ScrHeight-Ylow-24
BallWidth  equ 24/8
BallHeight equ 24
BlankOffs  equ Page1Offs*2
Ball0Offs  equ BlankOffs+(BallWidth*BallHeight)
Ball1Offs  equ Ball0Offs+(BallWidth*BallHeight)
NumBalls   equ 6

SCIndex    equ 3C4h
MapMask    equ 2
GCIndex    equ 3CEh
GCMode     equ 5
CRTCIndex  equ 03D4h
StartAddressHi equ 0Ch
StartAddressLo equ 0Dh
CRTCOffs   equ 13h
StatusRegister1 equ 03DAh
VSyncMask       equ 08h

.DATA
CurrentPage     db Page1
CurrentPageOffs dw Page1Offs
BallPlane0Image LABEL byte
   db 000h, 000h, 000h
   db 000h, 000h, 000h    ;  blue plane
   db 000h, 000h, 000h
   db 000h, 001h, 000h    ;
   db 000h, 003h, 080h
   db 000h, 001h, 000h    ;
   db 000h, 000h, 000h 
   db 000h, 000h, 000h    ;
   db 000h, 000h, 000h
   db 000h, 000h, 000h    ;
   db 000h, 000h, 000h
   db 000h, 000h, 000h    ;
   db 000h, 000h, 000h
   db 000h, 000h, 000h    ;
   db 000h, 000h, 000h
   db 000h, 000h, 000h    ;
   db 000h, 000h, 000h
   db 000h, 000h, 000h    ;
   db 000h, 000h, 000h
   db 000h, 000h, 000h    ;
   db 000h, 000h, 000h
   db 000h, 000h, 000h    ;
   db 000h, 000h, 000h
   db 000h, 000h, 000h    ;
BallPlane1Image LABEL byte
   db 000h, 000h, 000h
   db 000h, 003h, 000h    ; green plane
   db 000h, 007h, 0C0h
   db 000h, 00Fh, 0E0h    ;
   db 000h, 00Fh, 0E0h
   db 000h, 00Fh, 0E0h    ;
   db 000h, 007h, 0C0h
   db 000h, 003h, 000h    ;
   db 000h, 000h, 000h
   db 000h, 000h, 000h    ;
   db 000h, 000h, 000h
   db 000h, 000h, 000h    ;
   db 000h, 000h, 000h
   db 000h, 000h, 000h    ;
   db 000h, 000h, 000h
   db 000h, 000h, 000h    ;
   db 000h, 000h, 000h
   db 000h, 000h, 000h    ;
   db 000h, 000h, 000h
   db 000h, 000h, 000h    ;
   db 000h, 000h, 000h
   db 000h, 000h, 000h    ;
   db 000h, 000h, 000h
   db 000h, 000h, 000h    ;
BallPlane2Image LABEL byte
   db 000h, 03Ch, 000h
   db 001h, 0FFh, 080h    ; red plane
   db 007h, 0FFh, 0E0h
   db 00Fh, 0FFh, 0F0h    ;
   db 01Fh, 0FFh, 0F8h
   db 03Fh, 0FFh, 0FCh    ;
   db 03Fh, 0FFh, 0FCh
   db 07Fh, 0FFh, 0FEh    ; 
   db 07Fh, 0FFh, 0FEh
   db 03Fh, 0FFh, 0FFh    ;
   db 03Fh, 0FFh, 0FFh
   db 03Fh, 0FFh, 0FFh    ;
   db 01Fh, 0FFh, 0FFh
   db 01Fh, 0FFh, 0FFh    ;
   db 00Fh, 0FFh, 0FFh
   db 007h, 0FFh, 0FEh    ;
   db 001h, 0FFh, 0FCh
   db 000h, 03Fh, 0F8h    ;
   db 000h, 007h, 0F0h
   db 000h, 000h, 000h    ;
   db 000h, 000h, 000h
   db 000h, 000h, 000h    ;
   db 000h, 000h, 000h
   db 000h, 000h, 000h    ;
BallPlane3Image LABEL byte
   db 000h, 03Ch, 000h
   db 001h, 0FFh, 080h    ; intensity plane
   db 007h, 0FFh, 0E0h
   db 00Fh, 0FFh, 0F0h    ;
   db 007h, 0FFh, 0F8h
   db 007h, 0FFh, 0FCh    ;
   db 003h, 0FFh, 0FCh
   db 001h, 0FFh, 0FEh    ; 
   db 000h, 0FFh, 0FEh
   db 0C0h, 07Fh, 0FFh    ;*
   db 0C0h, 07Fh, 0FEh
   db 0C0h, 03Fh, 0FCh    ;
   db 0E0h, 01Fh, 0F0h
   db 0E0h, 00Fh, 0C0h    ;
   db 0F0h, 000h, 000h
   db 078h, 000h, 000h    ;
   db 07Eh, 000h, 002h
   db 03Fh, 0C0h, 004h    ;
   db 03Fh, 0F8h, 00Ch
   db 01Fh, 0FFh, 0F8h    ;
   db 00Fh, 0FFh, 0F0h
   db 007h, 0FFh, 0E0h    ;
   db 001h, 0FFh, 080h
   db 000h, 03Ch, 000h    ;

BallX     dw 50, 12, 50, 35, 20, 2
BallY     dw 230, 100, 300, 50, 150, 180
LastBallX dw 50, 12, 50, 35, 20, 1
LastBallY dw 230, 100, 300, 50, 150, 180
LLastBallX dw 50, 12, 50, 35, 20, 1
LLastBallY dw 230, 100, 300, 50, 150, 180
BallXInc  dw 2, 1, -1, -1, 1, 2
BallYInc  dw -4, 1, 2, 8, -3, -1 

BallOffs  dw Ball0Offs,Ball1Offs
          dw Ball1Offs,Ball0Offs
          dw Ball0Offs,Ball1Offs


.CODE

SETREG  macro  p1,p2
        mov    dx,p1
        mov    ah,al
        mov    al,p2
        out    dx,ax
        ENDM

DrawBall macro 
        LOCAL writeballLoop
        mov  ax,ScrWidth
        mul  dx
        add  ax,cx
        add  ax,[CurrentPageOffs]
        mov  di,ax
        mov  bp,BallHeight
        push ds
        push es
        pop  ds
WriteBallLoop:
        push di
        mov  cx,BallWidth
        rep  movsb
        pop  di
        add  di,ScrWidth
        dec  bp
        jnz  WriteBallLoop
        pop  ds
        endm

start   PROC near

        mov  ax,@data
        mov  ds,ax
IFDEF hires
        mov  ax,010h
ELSE
        mov  ax,0eh
ENDIF
        int  10h

        mov  ax,VidSeg
        mov  es,ax

        mov  di,Page0Offs
        call  DrawBorder
        mov  di,Page1Offs
        call  DrawBorder

        mov  al,01h
        SETREG  SCIndex,MapMask
        mov  si,OFFSET BallPlane0Image
        mov  di,Ball0Offs
        mov  cx,BallWidth * BallHeight
        rep  movsb
        mov  si,OFFSET BallPlane1Image
        mov  di,Ball1Offs
        mov  cx,BallWidth * BallHeight
        rep  movsb
        mov  al,02h
        SETREG  SCIndex,MapMask
        mov  si,OFFSET BallPlane1Image
        mov  di,Ball0Offs
        mov  cx,BallWidth * BallHeight
        rep  movsb
        mov  si,OFFSET BallPlane2Image
        mov  di,Ball1Offs
        mov  cx,BallWidth * BallHeight
        rep  movsb
        mov  al,04h
        SETREG  SCIndex,MapMask
        mov  si,OFFSET BallPlane2Image
        mov  di,Ball0Offs
        mov  cx,BallWidth * BallHeight
        rep  movsb
        mov  si,OFFSET BallPlane0Image
        mov  di,Ball1Offs
        mov  cx,BallWidth * BallHeight
        rep  movsb
        mov  al,08h
        SETREG  SCIndex,MapMask
        mov  si,OFFSET BallPlane3Image
        mov  di,Ball0Offs
        mov  cx,BallWidth * BallHeight
        rep  movsb
        mov  si,OFFSET BallPlane3Image
        mov  di,Ball1Offs
        mov  cx,BallWidth * BallHeight
        rep  movsb

        mov  al,0fh
        SETREG  SCIndex,MapMask
        mov  di,BlankOffs
        mov  cx,BallWidth * BallHeight
        sub  al,al
        rep  stosb

        mov  al,1
        SETREG  GCIndex,GCMode

        mov  al,ScrWidth/2
        SETREG  CRTCIndex,CRTCOffs

BallAnimLoop:
        mov  bx,(NumBalls*2)-2
MoveBallLoop:

        mov  ax,[LastBallX+bx]
        mov  [lLastBallX+bx],ax
        mov  ax,[BallX+bx]
        mov  [LastBallX+bx],ax

        add  ax,[BallXInc+bx]        
        cmp  ax,Xlow
        jle  Border1test
        cmp  ax,Xhi
        jle  NextY
Border1test:
        neg  [BallXinc+bx]  
NextY:
        mov  ax,[BallXInc+bx]
        add  [BallX+bx],ax

        mov  ax,[LastBallY+bx]
        mov  [LLastBallY+bx],ax
        mov  ax,[BallY+bx]
        mov  [LastBallY+bx],ax

        add  ax,[BallYInc+bx]
        cmp  ax,Ylow
        jle  Border2test
        cmp  ax,Yhi
        jle  NextYY
Border2test:
        neg  [BallYinc+bx]  
NextYY:
        mov  ax,[BallYInc+bx]
        add  [BallY+bx],ax

        dec  bx
        dec  bx
        jns  MoveBallLoop

        mov  bx,(NumBalls*2)-2
DrawBallLoop:
        mov  si,BlankOffs
        mov  cx,[LLastBallX+bx]
        mov  dx,[LLastBallY+bx]
        DrawBall
        mov  si,[BallOffs+bx]
        mov  cx,[BallX+bx]
        mov  dx,[BallY+bx]
        DrawBall
        dec  bx
        dec  bx
        jns  DrawBallLoop

;        call WaitVSync

        mov  ax,[CurrentPageOffs]
        push ax
        SETREG CRTCIndex,StartAddressLo
        pop  ax
        mov  al,ah
        SETREG CRTCIndex,StartAddressHi

        call WaitVSync

        xor  [CurrentPage],1
        jnz  IsPage1
        mov  [CurrentPageOffs],Page0Offs
        jmp  short EndFlipPage
IsPage1:
        mov  [CurrentPageOffs],Page1Offs
EndFlipPage:


        mov  ah,1
        int  16h
        jnz  done
        jmp  BallAnimLoop

Done:
        mov  ah,0
        int  10h
 
        mov  ax,3
        int  10h

        mov  ah,4ch
        int  21h

start   endp


WaitVSync proc near
        mov  dx,StatusRegister1
WaitNotVSyncLoop:
        in   al,dx
        and  al,VSyncMask
        jnz  WaitNotVSyncLoop
WaitVSyncLoop:
        in   al,dx
        and  al,VSyncMask
        jz   WaitVSyncLoop
        ret
WaitVSync endp

DrawBorder proc near
        push  di
        mov  cx,ScrHeight/16
DrawLeftBorderLoop:
        mov  al,0ch
        call DrawBorderBlock 
        add  di,ScrWidth*8
        mov  al,0eh
        call DrawBorderBlock 
        add  di,ScrWidth*8
        loop DrawLeftBorderLoop
        pop  di
        push di
        add  di,ScrWidth-1
        mov  cx,ScrHeight/16
DrawRightBorderLoop:
        mov  al,0eh
        call DrawBorderBlock 
        add  di,ScrWidth*8
        mov  al,0ch
        call DrawBorderBlock 
        add  di,ScrWidth*8
        loop DrawRightBorderLoop
        pop  di
        push di
        mov  cx,(ScrWidth-2)/2
DrawTopBorderLoop:
        inc  di
        mov  al,0eh
        call DrawBorderBlock
        inc  di
        mov  al,0ch
        call DrawBorderBlock
        loop DrawTopBorderLoop
        pop  di
        add  di,(ScrHeight-8)*ScrWidth
        mov  cx,(ScrWidth-2)/2
DrawBottomBorderLoop:
        inc  di
        mov  al,0ch
        call DrawBorderBlock
        inc  di
        mov  al,0eh
        call DrawBorderBlock
        loop DrawBottomBorderLoop
        ret
DrawBorder endp

DrawBorderBlock proc near
        push di
        SETREG SCIndex,MapMask
        mov  al,0ffh
        rept 8
        stosb
        add  di,ScrWidth-1
        endm
        pop  di
        ret
DrawBorderBlock endp

        end start