[comp.sys.amiga.tech] Animate vs Manual Blitter

kumbach@nro.cs.athabascau.ca (Kevin Umbach) (12/06/90)

I'm writing a video game for the Amiga that has 6 small men (12 by 11 
pixels, 2 planes) running around on the screen. I currently have them 
defined as animation objects and I'm using the Animate function to 
move them. Even though I'm only using a 320X200 2plane screen, the
anim objects move very slowly.
 
So here's my question:
   Is it faster to use blitter directly and keep track of all positional
   information manually, or do I have to be an expert programmer to 
   get things moving faster than Animate?
   
I currently have the program coded using Lattice C. Any hints and tips
for speeding up animation would be greatly appreciated.
 

ken@cbmvax.commodore.com (Ken Farinsky - CATS) (12/08/90)

In article <BZLRT1w163w@ersys.uucp> ersys!kumbach@nro.cs.athabascau.ca (Kevin Umbach) writes:
>I'm writing a video game for the Amiga that has 6 small men (12 by 11 
>pixels, 2 planes) running around on the screen. I currently have them 
>defined as animation objects and I'm using the Animate function to 
>move them. Even though I'm only using a 320X200 2plane screen, the
>anim objects move very slowly.

Why don't you use sprites or vsprites?  The objects are small enough,
and you are running on a lores screen, so sprites would work.  They
should be a lot faster.

-- 
--
Ken Farinsky - CATS - (215) 431-9421 - Commodore Business Machines
uucp: ken@cbmvax.commodore.com   or  ...{uunet,rutgers}!cbmvax!ken
bix:  kfarinsky

ckp@grebyn.com (Checkpoint Technologies) (12/08/90)

In article <BZLRT1w163w@ersys.uucp> ersys!kumbach@nro.cs.athabascau.ca (Kevin Umbach) writes:
>I'm writing a video game for the Amiga that has 6 small men (12 by 11 
>pixels, 2 planes) running around on the screen. I currently have them 
>defined as animation objects and I'm using the Animate function to 
>move them. Even though I'm only using a 320X200 2plane screen, the
>anim objects move very slowly.

It seems your objects are small enough, few enough, and shallow enough
that you could be using sprites.  Is there some basic reason why you
aren't?  If you switch from Bobs to VSprites, your code won't change
much, and you can get perfectly smooth and flicker-free animation
without double buffering.  You will also be able to use different colors
for them than your playfield, though I don't know if that's an issue for
you.
-- 
First comes the logo: C H E C K P O I N T  T E C H N O L O G I E S      / /  
                                                                    \\ / /    
Then, the disclaimer:  All expressed opinions are, indeed, opinions. \  / o
Now for the witty part:    I'm pink, therefore, I'm spam!             \/

jnmoyne@lbl.gov (Jean-Noel MOYNE) (12/08/90)

               If your objects can be only 8 points wide, and 3 colors 
(you can use different colors from the backgroud), then go for sprites ... 
You'll be able to animate 8 objects very quickly (and that means in sync 
with the display, which is your goal for a game).

               Otherwise, you can quite easilly boost the blitter's perfs 
by programming it yourself. Remeber the graphics.lib routines where made 
for general purposes,  you can allways make a specific routine for your 
needs, and it'll be a lot faster. The only problem is that the blitter is 
not really easy to program by hand, and that you'll have to access it 
relatively to _custombase (don't do it otherwise than this way), it's a 
little dirty but if you need to modify it for a specific Amiga it can be 
do easilly.

             If you choose this solution, I strongly recomand you to get 
the program blitlab (Radical Eye software, it's PD), and it's 
documentation. Next buy some patience too (for the debuging) (-:

         JNM

--
These are my own ideas (not LBL's)
" Just make it!", BO in 'BO knows Unix'

farren@well.sf.ca.us (Mike Farren) (12/11/90)

ersys!kumbach@nro.cs.athabascau.ca (Kevin Umbach) writes:
>I'm writing a video game for the Amiga that has 6 small men (12 by 11 
>pixels, 2 planes) running around on the screen. I currently have them 
>defined as animation objects and I'm using the Animate function to 
>move them. Even though I'm only using a 320X200 2plane screen, the
>anim objects move very slowly.
> 
>So here's my question:
>   Is it faster to use blitter directly and keep track of all positional
>   information manually, or do I have to be an expert programmer to 
>   get things moving faster than Animate?

My experience with Animate, back when I was doing the port of Crystal
Quest to the Amy, was that it was just too slow to do an arcade-game
type movement for any significant number of objects (where significant ==
3 or more).  I whipped up a quick blitter routine in assembly which
moved an object as desired (16 X 16 pixels), and it blazed - I could
have nearly 50 objects moving around before a noticable speed degradation
happened.  Of course, I wasn't doing background saves or anything like
that, but that would have been easy to add, and wouldn't have hurt the
performance all THAT much - six men, 12 X 11, should be a piece of cake.
Or, since you're only using 2 planes, how about setting 'em up as sprites,
which would take essentially nothing in the way of resources?

-- 
Mike Farren 				     farren@well.sf.ca.us

pashdown@javelin.es.com (Pete Ashdown) (12/12/90)

farren@well.sf.ca.us (Mike Farren) writes:

>I whipped up a quick blitter routine in assembly which
>moved an object as desired (16 X 16 pixels), and it blazed - I could
>have nearly 50 objects moving around before a noticable speed degradation
>happened.  Of course, I wasn't doing background saves or anything like
>that, but that would have been easy to add, and wouldn't have hurt the
>performance all THAT much - six men, 12 X 11, should be a piece of cake.

Hey Mike, how about a post of that routine?

>Mike Farren 				     farren@well.sf.ca.us

-- 
"While you are here, your wives and girlfriends are dating handsome American
 movie and TV stars. Stars like Tom Selleck, Bruce Willis, and Bart Simpson."
                                -- Baghdad Betty
  Pete Ashdown  pashdown%javelin@dsd.es.com  ...dsd.es.com!javelin!pashdown

farren@well.sf.ca.us (Mike Farren) (12/19/90)

pashdown@javelin.es.com (Pete Ashdown) writes:

>farren@well.sf.ca.us (Mike Farren) writes:
>>I whipped up a quick blitter routine in assembly 

>Hey Mike, how about a post of that routine?

Sure thing.   Here you are:


; This routine draws an object directly to the bitplanes.
;
; The shape data is organized as one large block, for ease of loading via
; a standard "fread" statement.  In this case, there are 73 shapes possible,
; and the shape number and location onscreen are passed to the drawshape
; routines.

; There are five arrays, plus the actual shape data.  The first two arrays
; are held in the area pointed to by the "shape" pointer, and are
; a series of pointers to the shape and mask data, respectively.  The
; next three are held in the area pointed to by the "shapeinfo" pointer,
; and are the width of the shape (in pixels), the height of the
; shape (in lines), and the modulo of the shape (the number of bytes per
; line - with this data being constrained to either two or three bytes).
;
; The shape data is simply the bit patterns of the shape, plane by plane.
; The mask data is used to "cookie-cut" the shape onto the screen, and
; is the bit pattern of the shape, with a set bit whenever the same
; bit in the final shape is not transparent.  The first longword in
; the shape data is a length word, indicating the total length of the
; data area - this is for simplicity in loading.

; The basic coordinates are held in a Mac-like "rect" array, which holds
; four words: the leftmost x coordinate, the topmost y coordinate, the
; rightmost x coordinate, and the bottommost y coordinate.  This arrangement
; makes it easy to compute collisons between rectangles.
 
LEFT           EQU    0
TOP            EQU    2

; The offsets into the big array are precomputed for ease of access

SHOFF          EQU    0              ;The offset of the shape data pointers
MOFF           EQU    292            ;The offset of the mask data pointers
HEIGHT         EQU    584            ;The offset of the height values
WIDTH          EQU    146            ;The offset of the width values
MODULO         EQU    292            ;The offset of the modulo values

                include 'types.i'
                include 'custom.i'
                include 'blit.i'
                include 'dmabits.i'

                CSECT        data,1

; these are the externals.  Mostly self-explanatory, except for "bp",
; which is an array of pointers to the individual bitplanes which make
; up the playfield.  In this example, four planes are hardwired in.

                XREF        _Screen     ; The screen structure (playfield)
                XREF        _custom     ; To point to blitter
                XREF        _shapes     ; The shape and mask data
                XREF        _bp         ; a pointer to the bitplane pointers
                XREF        _shapeinfo  ; The shape height, width, and modulo

; these are defined here for debugging purposes only.

                XDEF        fbltcon0
                XDEF        fbltcon1
                XDEF        fbltafwm
                XDEF        fbltalwm
                XDEF        fbltcpth
                XDEF        fbltcptl
                XDEF        fbltbpth
                XDEF        fbltbptl
                XDEF        fbltapth
                XDEF        fbltaptl
                XDEF        fbltdpth
                XDEF        fbltdptl
                XDEF        fbltsize
                XDEF        fbltcmod
                XDEF        fbltbmod
                XDEF        fbltamod
                XDEF        fbltdmod

; these are the blitter shadow registers.  For some reason, direct writes
; to the blitter register did not work correctly, while indirect writes
; did not.  I haven't the slightest idea why - but this works, at the
; cost of one additional set of accesses.

fbltcon0:    DC.W        0
fbltcon1:    DC.W        0
fbltafwm:    DC.W        0
fbltalwm:    DC.W        0
fbltcpth:    DC.W        0
fbltcptl:    DC.W        0
fbltbpth:    DC.W        0
fbltbptl:    DC.W        0
fbltapth:    DC.W        0
fbltaptl:    DC.W        0
fbltdpth:    DC.W        0
fbltdptl:    DC.W        0
fbltsize:    DC.W        0
fbltcmod:    DC.W        0
fbltbmod:    DC.W        0
fbltamod:    DC.W        0
fbltdmod:    DC.W        0

                CSECT    text

; drawshape(number, where)
; short number;
; struct Rect *where;
;
; (using Lattice register parameter passing, number is passed in d0, 
; the pointer to where in a0.)
;
; eraseshape(number, where)
; parameters as above.

                XDEF        _drawshape
                XDEF        _eraseshape

; outside routines used, using Lattice's bindings instead of "OVF" styles.

                XREF        _OwnBlitter
                XREF        _DisownBlitter
                XREF        _WaitBlit

_drawshape:
                movem.l    d2-d7/a2-a6,-(a7)
                lea        _custom,a5           ;point to the custom address
                
;Calculate the bitplane offset for this X,Y value - place into D2, with
;D3 the number of pixels offset from the word boundary

                move        (a0)+,d2            ;get the Y value
                ext.l        d2                 ;make it a long
                asl.l        #3,d2              ;d2 = Y*8
                move.l       d2,d1              ;save it for now
                asl.l        #2,d2              ;d2 = Y*32
                add.l        d1,d2              ;d2 = Y*40
                move        (a0),d3             ;d3 = X
                ext.l        d3                 ;make it long
                move.l       d3,d1              ;temp save x in d0
                andi.l       #15,d3             ;d3 = bit shift
                ror.w        #4,d3              ;move to high order nibble
                asr.l        #3,d1              ;d0 = words of x
                andi        #$fffffffe,d1       ;convert to word address
                add.l        d1,d2              ;d2 = y*40+x

;Extract addresses and dimensions from shapeinfo.  Figure address ends up
;in A2, mask address in A3.  Height in d4, modulo in d5.  Setup some of
;the blitter shadow registers as appropriate.

                ext.l        d0                 ;make the number a fake long
                movea.l       _shapeinfo,a0     ;point to the shape information
                adda.l       #4,a0              ;a0 points to shape data offset
                movea.l       a0,a4             ;save it here, too...
                adda.l       #HEIGHT,a4         ;a4 points to height data offset
                asl.l        #1,d0              ;times two (for WORD)
                adda.l       d0,a4              ;calculate height offset
                asl.l        #1,d0              ;calculate the offset for data
                adda.l       d0,a0              ;a0 points to figure data offset
                movea.l       _shapes,a2        ;get the shape data pointer
                movea.l       a2,a3             ;into both registers
                adda.l       (a0),a2            ;a2 now points to figure data
                adda.l       MOFF(a0),a3        ;a3 now points to mask data
                move.w       (a4),d4            ;d4 now has the height
                move.w       MODULO(a4),d6      ;and d6 the modulo

;Setup the blitter shadow registers.  Most of these will not change
;from plane to plane, so can be set up now.

                move.l       a3,fbltbpth        ;address of mask data in "B"
                move.w       #0,fbltamod        ;no modulo for figure
                move.w       #0,fbltbmod        ;or mask
                move.l       #-1,fbltafwm       ;setup masks
                move.l       #$0fe20000,d0      ;save bltcons temporarily
                or.l         d3,d0              ;or in the "b" shift value
                swap         d3                 ;swap words in shift
                or.l         d3,d0              ;"or" in the "a" shift value
                move.l       d0,fbltcon0        ;setup controller
                move.w       d4,d5              ;calculate the modulo for figure
                cmpi.w       #3,d6              ;if modulo == 3, setup differs
                bne.s        notthree           ;
                asl.w        #1,d4              ;height * 4 words
                asl.w        #2,d5              ;d5 = height * 4
                add.w        d4,d5              ;d4 = height * 6
                asl.w        #5,d4              ;d4 = vertical size
                or.w         #3,d4              ;horizontal size = 3
                move.w       d4,fbltsize
                move.w       #34,fbltcmod       ;34 byte modulo for this one
                move.w       #34,fbltdmod       ;and this, too.
                bra.s        domod              ;finish it off
notthree:
                asl.w        #6,d4              ;size = height * 64
                asl.w        #2,d5              ;size of this bit plane mod.
                or.w         #2,d4              ;or in the width
                move.w       d4,fbltsize        ;and save it
                move.w       #36,fbltcmod       ;36 byte modulo for screen
                move.w       #36,fbltdmod       ;in both registers
domod:

                
;Setup the pointer to the bitplanes in a4, and the bitplane counter in
;d7.
                ext.l        d5                 ;make sure d5 is long
                lea          _bp,a4             ;get pointer to first plane
                moveq        #4,d7              ;do four planes
PlaneLoop:      movea.l      (a4)+,a0           ;a0 = bitplane to do
                adda.l       d2,a0              ;add in offset to first word
                move.l       a2,fbltapth        ;address of data in "A"
                move.l       a0,fbltcpth        ;address of screen in "C"
                move.l       a0,fbltdpth        ;and in "D"
                jsr          DoRealBlit
                adda.l       d5,a2              ;point to next line of shape
                subq.w       #1,d7              ;
                bne          PlaneLoop          ;and the planes
                movem.l      (a7)+,d2-d7/a2-a6  ;restore registers
                rts                             ;and return


_eraseshape:
                movem.l      d2-d7/a2-a6,-(a7)
                lea          _custom,a5         ;point to the custom address
                
;Calculate the bitplane offset for this X,Y value - place into D2, with
;D3 the number of pixels offset from the word boundary

                move         (a0)+,d2           ;get the Y value
                ext.l        d2                 ;make it a word
                asl.l        #3,d2              ;d2 = Y*8
                move.l       d2,d1              ;save it for now
                asl.l        #2,d2              ;d2 = Y*32
                add.l        d1,d2              ;d2 = Y*40
                move         (a0),d3            ;d3 = X
                ext.l        d3                 ;make it a word
                move.l       d3,d1              ;temp save x in d0
                andi.l       #15,d3             ;d3 = bit shift
                ror.w        #4,d3              ;move to high order nibble
                asr.l        #3,d1              ;d0 = words of x
                andi         #$fffffffe,d1      ;convert to word address
                add.l        d1,d2              ;d2 = y*40+x

;Extract addresses and dimensions from shapeinfo.  Mask address ends up
;in A2, height in d4, modulo in d5.  Setup some of the blitter shadow
;registers as appropriate.

                ext.l        d0                 ;extend the pointer to a long
                movea.l      _shapeinfo,a0      ;point to the shape information
                adda.l       #4,a0              ;a0 points to shape data offset
                movea.l      a0,a4              ;save it here, too...
                adda.l       #HEIGHT,a4         ;a4 points to height data offset
                asl.l        #1,d0              ;times two (for WORD)
                adda.l       d0,a4              ;calculate height offset
                asl.l        #1,d0              ;calculate the offset for data
                adda.l       d0,a0              ;a0 points to figure data offset
                movea.l      _shapes,a3         ;get the shape data pointer
                adda.l       MOFF(a0),a3        ;a3 now points to mask data
                move.w       (a4),d4            ;d4 now has the height
                move.w       MODULO(a4),d6      ;and d6 the modulo

;Setup the blitter shadow registers.  Most of these will not change
;from plane to plane, so can be set up now.

                move.l       a3,fbltapth        ;address of mask data in "A"
                move.w       #0,fbltamod        ;no modulo for figure
                move.l       #-1,fbltafwm       ;setup masks
                move.l       #$0b0a0000,d0      ;save bltcons temporarily
                swap         d3                 ;swap words in shift
                or.l         d3,d0              ;"or" in the "a" shift value
                move.l       d0,fbltcon0        ;setup controller
                cmpi         #3,d6              ;if modulo == 3, setup differs
                bne.s        notthreea          ;
                asl.w        #1,d4              ;height * 4 words
                asl.w        #2,d5              ;d5 = height * 4
                add.w        d4,d5              ;d4 = height * 6
                asl.w        #5,d4              ;d4 = vertical size
                or.w         #3,d4              ;horizontal size = 3
                move.w       d4,fbltsize
                move.w       #34,fbltcmod       ;34 byte modulo for this one
                move.w       #34,fbltdmod       ;and this, too.
                bra.s        domoda             ;finish it off
notthreea:
                asl.w        #6,d4              ;size = height * 64
                or.w         #2,d4              ;or in the width
                move.w       d4,fbltsize        ;and save it
                move.w       #36,fbltcmod       ;36 byte modulo for screen
                move.w       #36,fbltdmod       ;in both registers
domoda:

                
;Setup the pointer to the bitplanes in a4, and the bitplane counter in
;d7.
                ext.l        d5                 ;make sure d5 is long
                lea          _bp,a4             ;get pointer to first plane
                moveq        #4,d7              ;do four planes

PlaneLoopa:     movea.l      (a4)+,a0           ;a0 = bitplane to do
                adda.l       d2,a0              ;add in offset to first word
                move.l       a0,fbltcpth        ;address of screen in "C"
                move.l       a0,fbltdpth        ;and in "D"
                jsr          DoRealBlit
                subq.w       #1,d7              ;
                bne          PlaneLoopa         ;and the planes
                movem.l      (a7)+,d2-d7/a2-a6  ;restore registers
                rts                             ;and return

DoRealBlit:
                jsr          _OwnBlitter
                jsr          _WaitBlit
                move         #$8400,dmacon(a5)  ;nasty blitter
                move         fbltcon0,bltcon0(a5)
                move         fbltcon1,bltcon1(a5)
                move         fbltafwm,bltafwm(a5)
                move         fbltalwm,bltalwm(a5)
                move.l       fbltcpth,bltcpt(a5)
                move.l       fbltbpth,bltbpt(a5)
                move.l       fbltapth,bltapt(a5)
                move.l       fbltdpth,bltdpt(a5)
                move         fbltcmod,bltcmod(a5)
                move         fbltbmod,bltbmod(a5)
                move         fbltamod,bltamod(a5)
                move         fbltdmod,bltdmod(a5)
                move         fbltsize,bltsize(a5)
w1:             btst         #DMAB_BLTDONE-8,dmaconr(a5)    ;check it
                bne.s        w1                 ;loop 'til done
                jsr          _DisownBlitter
                rts

                end

-- 
Mike Farren 				     farren@well.sf.ca.us