Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

Another Sprite Program

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Another Sprite Program

    There have been a few threads recently mentioning Sprite type programs so here's my contribution to add to them which may be of use to some.
    It's not finished and needs a lot of tidying up but it does work.

    As posted, it starts displaying 5 animated sprites of 140 x 140 pixels. Keep pressing a key and it displays 100 animated 140 x 140 Sprites then 200 animated number sprites of 100 x 100 pixels, then 1000 medium 14 x 14 pixel animated sprites and then 10,000 small (3 x 3) sprites and finally a mix of all of the above.

    Sprite motion is automatic once set. The animation is automatic and consumes no extra time. It's reasonably efficient for large numbers of sprites but for very small numbers, although it works, it's not so efficient as it redraws the entire screen every frame.

    The numbers of sprites set above were chosen quite low so it should run at a fixed 25fps on a low powered PC. See the top left corner of the window for current frames per second. I've had it run at 25fps with 150,000 small sprites or 1,500 large sprites on a decent PC.


    A few very brief notes.
    MaxSprites sets the maximum number of sprites. Not all sprites need to be displayed, they can be turned on and off individually by setting/clearing the %PlotSprite flag.
    The %SpriteActive flag allows the sprite position to be updated correctly even if it's not displayed because the %PlotSprite is clear.
    The Motion is currently set at 0 meaning linear motion with speed and position as given in xPos, yPos, xSpeed and ySpeed.
    The intention is that in future a non-zero motion will call a SUB which will automatically calculate complex motions but this isn't implemented yet.
    Each Sprite can have it's own transparent colour. I chose White for convenience but any colour is usable.


    The whole thing is driven by a Timer, set at 40ms in the example to give a 25 frames per second. It can be varied to suit from 2ms up to anything.
    The TimerFunction is called every time the timer triggers. It must be kept short so it only updates sprite positions and then sets a flag to indicate to the PlotThread that an update has occurred, it then returns. The PlotThread then does the more time consuming job of plotting the sprites.
    The PlotFlag event is used to allow the 2 funtions to interact efficiently.

    Certain small parts of the code are in ASM as they are speed critical.

    The collision function will tell you if any 2 sprites are currently overlapping to allow for collision detection.

    No alphablending yet. It's not too difficult but will slow things down a bit.

    The sprite bitmaps are created, copied to strings and then destroyed as only the string is needed by the code, not the original bitmap.
    The screen is buffered. The first time TimerFunction is called a copy is taken into 2 strings, Bmp and Bmp2
    Subsequently, all writes to the screen are done by copying the initial bitmap back from Bmp2 to bmp then copying the active sprites to bmp, overwriting what was already there. A higher numbered Sprite is written later so it appears in the foreground compared to a lower numbered sprite.
    Once all sprites are done the entire bmp is copied back to the screen.

    Beacuse of the way the plotting and timing are done, if the plot code takes too long (e.g.if there are too many sprites to display) then the motion will still run correctly but display frames will be dropped so frame rate of the display will fall but the motion will still be correct and will be updated each frame even if the frame isn't displayed.


    Code:
    'PBCC5.02/PBWin9.02 program
    #COMPILE EXE
    #DIM ALL
            
    %MaxSprites=  10000   'number of sprites to create
    %FrameDuration = 40   'time between updates in msec (timer trigger interval) 40 = 25fps
    
    
    %vSmall = 1
    %medium = 2
    %large = 3
    %numbers = 4
    
    
    'should screen wrap left-right or up-down or both
    %WrapX = 1  '1=sprite leaving side of screen will appear on other side automatically
    %WrapY = 1  '1=sprite leaving top/bottom of screen will appear at bottom/top automatically
    
    #INCLUDE "win32api.inc"
    
    'All bitmaps to consist of a single bitmap split horizontally into frames for animation
    TYPE Sprite
        Hnd      AS LONG         'handle to the bitmap string to use for this sprite
        xSize    AS LONG         'sprite size x
        ySize    AS LONG         'sprite size y
        xPos     AS LONG         'sprite position x
        yPos     AS LONG         'sprite position y
        xSpeed   AS LONG         'sprite x speed for simple motion
        ySpeed   AS LONG         'sprite y speed for simple motion
        Motion   AS LONG         'index of which SUB should be called to calculate complex motion. 0 = simple motion
        MaxFrame AS LONG         'number of frames for animation in this bitmap
        CurrentFrame   AS LONG   'start at frame 0
        AnimationTime  AS LONG   'The limit of AnimationCount before returning to zero and showing next frame
        AnimationCount AS LONG   'counter of time between updates of animation frames.
        Transparent    AS LONG   'which colour is transparent in this sprite
        Flags AS LONG            'bit0 = %PlotSprite, bit1 = %SpriteActive
    
    END TYPE
    
    'Flags in Sprites
    %PlotSprite = 1     'the sprite is to be draw on the screen
    %SpriteActive = 2   'the sprite is to be updated, even if not drawn
    
    
    GLOBAL TimerHandle AS LONG
    GLOBAL hGraph,hWindow AS LONG
    GLOBAL Sprites() AS Sprite
    GLOBAL ScreenWidth, ScreenHeight AS LONG
    GLOBAL SpriteStrings() AS STRING
    GLOBAL PlotFlag, QuitFlag AS LONG
    GLOBAL bmp,bmp2 AS STRING
    
    
    FUNCTION PBMAIN() AS LONG
    LOCAL nWidth, nHeight, nFile, r, num AS LONG
    
    DIM Sprites(%MaxSprites)
    DIM SpriteStrings(%MaxSprites)
    
    DESKTOP GET CLIENT TO ScreenWidth, ScreenHeight
    
    'set size to other than full screen here:
    ScreenWidth =  800
    ScreenHeight = 600
    
    GRAPHIC BITMAP NEW ScreenWidth,ScreenHeight TO hGraph
    GRAPHIC WINDOW "Sprite tests...press a key",0,0,ScreenWidth,ScreenHeight TO hWindow
    
    'draw the background graphic
    GRAPHIC ATTACH hGraph,0
    'draw/load any image you like here as the background
    GRAPHIC CLEAR %WHITE
    
    'copy the graphic to the visible window
    GRAPHIC ATTACH hWindow,0
    GRAPHIC COPY hGraph,0
    
    
    LOCAL x AS LONG
    LOCAL y,hFont, hBmp, col AS LONG
    
    'a very small sprite
    GRAPHIC BITMAP NEW 3,3 TO hBmp
    GRAPHIC ATTACH  hBmp,0
    GRAPHIC CLEAR %WHITE
    
        GRAPHIC ELLIPSE  (0,0)-(3,3),%BLACK,%BLACK
    
        Sprites(%vSmall).hnd = %vSmall
        Sprites(%vSmall).xSize = 3
        Sprites(%vSmall).ySize = 3
        Sprites(%vSmall).xPos = 400
        Sprites(%vSmall).yPos =100
        Sprites(%vSmall).xSpeed =4
        Sprites(%vSmall).ySpeed =1
        Sprites(%vSmall).Motion =0
        Sprites(%vSmall).MaxFrame = 1
        Sprites(%vSmall).CurrentFrame = 0
        Sprites(%vSmall).AnimationTime =0
        Sprites(%vSmall).AnimationCount =0
        Sprites(%vSmall).Flags =%PlotSprite OR %SpriteActive
        Sprites(%vSmall).Transparent = &hffffff
        GRAPHIC ATTACH hBmp,0
        GRAPHIC GET BITS TO SpriteStrings(%vSmall)
        GRAPHIC BITMAP END
        GRAPHIC DETACH
    
    
    
    
    
    'a medium sized animated sprite 14 x 14
    GRAPHIC BITMAP NEW 686,14 TO hBmp
    GRAPHIC ATTACH  hBmp,0
    GRAPHIC CLEAR %WHITE
    
        FOR x = 0 TO 49
            GRAPHIC ELLIPSE  (x*14,0)-(x*14+14,14),%RED,%YELLOW '* (x-4.5)/9
            GRAPHIC PIE  (x*14,0)-(x*14+14,14),x/49*2*3.142,(x+20)/49*2*3.142, %RED,%GREEN
            GRAPHIC SET POS (x*140+70,70)
        NEXT
        Sprites(%medium).hnd = %medium
        Sprites(%medium).xSize = 14
        Sprites(%medium).ySize = 14
        Sprites(%medium).xPos = 400
        Sprites(%medium).yPos =100
        Sprites(%medium).xSpeed =4
        Sprites(%medium).ySpeed =1
        Sprites(%medium).Motion =0
        Sprites(%medium).MaxFrame = 49
        Sprites(%medium).CurrentFrame = 0
        Sprites(%medium).AnimationTime =10
        Sprites(%medium).AnimationCount =0
        Sprites(%medium).Flags =%PlotSprite OR %SpriteActive
        Sprites(%medium).Transparent = &hffffff
        GRAPHIC ATTACH hBmp,0
        GRAPHIC GET BITS TO SpriteStrings(%medium)
        GRAPHIC BITMAP END
        GRAPHIC DETACH
    
    
    
    'a large animated sprite 140 x 140
    GRAPHIC BITMAP NEW 6860,140 TO hBmp
    GRAPHIC ATTACH  hBmp,0
    GRAPHIC CLEAR %WHITE
    
        FOR x = 0 TO 49
            GRAPHIC ELLIPSE  (x*140,0)-(x*140+140,140),%RED,%YELLOW '* (x-4.5)/9
            GRAPHIC PIE  (x*140,0)-(x*140+140,140),x/49*2*3.142,(x+4)/49*2*3.142, %YELLOW,%GREEN
            GRAPHIC SET POS (x*140+70,70)
            GRAPHIC PRINT x
        NEXT
        Sprites(%large).hnd = %large
        Sprites(%large).xSize = 140
        Sprites(%large).ySize = 140
        Sprites(%large).xPos = 400
        Sprites(%large).yPos =100
        Sprites(%large).xSpeed =4
        Sprites(%large).ySpeed =1
        Sprites(%large).Motion =0
        Sprites(%large).MaxFrame = 49
        Sprites(%large).CurrentFrame = 0
        Sprites(%large).AnimationTime =10
        Sprites(%large).AnimationCount =0
        Sprites(%large).Flags =%PlotSprite OR %SpriteActive
        Sprites(%large).Transparent = &hffffff
        GRAPHIC ATTACH hBmp,0
        GRAPHIC GET BITS TO SpriteStrings(%large)
        GRAPHIC BITMAP END
        GRAPHIC DETACH
    
    
    'animated numbers 100 x 100
    GRAPHIC BITMAP NEW 1000,100 TO hBmp
    GRAPHIC ATTACH  hBmp,0
    GRAPHIC CLEAR %WHITE
    FONT NEW "Courier New",100,1 TO hFont
    GRAPHIC SET FONT hFont
    
        FOR x = 0 TO 9
            GRAPHIC COLOR RGB(x*RND(1,30),x*RND(1,30),x*RND(30)),%WHITE
            GRAPHIC SET POS (x*100,-20)
            GRAPHIC PRINT FORMAT$(x);
        NEXT
        Sprites(%numbers).hnd = %numbers
        Sprites(%numbers).xSize = 100
        Sprites(%numbers).ySize = 100
        Sprites(%numbers).xPos = 400
        Sprites(%numbers).yPos =100
        Sprites(%numbers).xSpeed =4
        Sprites(%numbers).ySpeed =1
        Sprites(%numbers).Motion =0
        Sprites(%numbers).MaxFrame = 10
        Sprites(%numbers).CurrentFrame = 0
        Sprites(%numbers).AnimationTime =10
        Sprites(%numbers).AnimationCount =0
        Sprites(%numbers).Flags =%PlotSprite OR %SpriteActive
        Sprites(%numbers).Transparent = &hffffff
        GRAPHIC ATTACH hBmp,0
        GRAPHIC GET BITS TO SpriteStrings(%numbers)
        GRAPHIC DETACH
    
    
    FOR r = 0 TO 10
        Sprites(r).flags = 0 'don't plot these
    NEXT
    
    
    FOR r = 10 TO 14
        num = %large
        Sprites(r)=Sprites(num)
        Sprites(r).xpos=RND(0,ScreenWidth)
        Sprites(r).ypos=RND(0,ScreenHeight)
        Sprites(r).xSpeed=RND(-5,5)
        Sprites(r).ySpeed=RND(-5,5)
        Sprites(r).CurrentFrame = RND(0,Sprites(r).MaxFrame -1)
        Sprites(r).AnimationTime = 1
        Sprites(r).flags = %PlotSprite OR %SpriteActive
    NEXT
    
    
    
    PlotFlag = CreateEvent(BYVAL 0,BYVAL 1, BYVAL 0, BYVAL 0) 'default security,Manual Reset, Initially not-signalled, no name
                           '
    GLOBAL hPlotThread AS LONG
    LOCAL junk AS LONG
    THREAD CREATE PlotThread(junk) TO hPlotThread
    
    
    'start the main timer
    '40=milliseconds between triggers, 0=maximum timer resolution, test=the routine to call
    TimerHandle = timeSetEvent ( BYVAL %FrameDuration, BYVAL 0, CODEPTR(TimerFunction), BYVAL 0&, BYVAL %TIME_PERIODIC)
                                        
    
    'wait for key press
    GRAPHIC ATTACH hWindow,0
    
    GRAPHIC WAITKEY$
    FOR r = 10 TO 110
        num = %large
        Sprites(r)=Sprites(num)
        Sprites(r).xpos=RND(0,ScreenWidth)
        Sprites(r).ypos=RND(0,ScreenHeight)
        Sprites(r).xSpeed=RND(-5,5)
        Sprites(r).ySpeed=RND(-5,5)
        Sprites(r).CurrentFrame = RND(0,Sprites(r).MaxFrame -1)
        Sprites(r).AnimationTime = 1
        Sprites(r).flags = %PlotSprite OR %SpriteActive
    NEXT
    
    
    GRAPHIC WAITKEY$
    FOR r = 10 TO 210
        num = %numbers
        Sprites(r)=Sprites(num)
        Sprites(r).xpos=RND(0,ScreenWidth)
        Sprites(r).ypos=RND(0,ScreenHeight)
        Sprites(r).xSpeed=RND(-5,5)
        Sprites(r).ySpeed=RND(-5,5)
        Sprites(r).CurrentFrame = RND(0,Sprites(r).MaxFrame -1)
        Sprites(r).AnimationTime = RND(1,10)
        Sprites(r).flags = %PlotSprite OR %SpriteActive
    NEXT
    
    GRAPHIC WAITKEY$
    FOR r = 10 TO 1010
        num = %medium
        Sprites(r)=Sprites(num)
        Sprites(r).xpos=RND(0,ScreenWidth)
        Sprites(r).ypos=RND(0,ScreenHeight)
        Sprites(r).xSpeed=RND(-5,5)
        Sprites(r).ySpeed=RND(-5,5)
        Sprites(r).CurrentFrame = RND(0,Sprites(r).MaxFrame -1)
        Sprites(r).AnimationTime = 1
        Sprites(r).flags = %PlotSprite OR %SpriteActive
    NEXT
    
    
    GRAPHIC WAITKEY$
    FOR r = 10 TO %maxsprites
        num = %vsmall
        Sprites(r)=Sprites(num)
        Sprites(r).xpos=RND(0,ScreenWidth)
        Sprites(r).ypos=RND(0,ScreenHeight)
        Sprites(r).xSpeed=RND(-5,5)
        Sprites(r).ySpeed=RND(-5,5)
        Sprites(r).CurrentFrame = RND(0,Sprites(r).MaxFrame -1)
        Sprites(r).AnimationTime = 1
        Sprites(r).flags = %PlotSprite OR %SpriteActive
    NEXT
    
    
    GRAPHIC WAITKEY$
    FOR r = 10 TO 200
        num = RND(%vsmall,%numbers)
        Sprites(r)=Sprites(num)
        Sprites(r).xpos=RND(0,ScreenWidth)
        Sprites(r).ypos=RND(0,ScreenHeight)
        Sprites(r).xSpeed=RND(-5,5)
        Sprites(r).ySpeed=RND(-5,5)
        Sprites(r).CurrentFrame = RND(0,Sprites(r).MaxFrame -1)
        Sprites(r).AnimationTime = 1
        Sprites(r).flags = %PlotSprite OR %SpriteActive
    NEXT
    FOR r = 201 TO %MaxSprites
        Sprites(r).flags = 0
    NEXT
    
    
    GRAPHIC WAITKEY$
    
    
    QuitFlag = 1             'force all threads to terminate
    
    timeKillEvent TimerHandle
    CloseHandle PlotFlag
    
    
    GRAPHIC ATTACH hGraph,0
    GRAPHIC BITMAP END
    GRAPHIC ATTACH hWindow,0
    GRAPHIC BITMAP END
    
    'Give timer time to stop in case it triggers again after program ends' should wait and check it
    SLEEP 100
    
    
    END FUNCTION
    
    
    
    
    
    FUNCTION TimerFunction ( BYVAL uID AS LONG, BYVAL uMsg AS LONG, _
                            BYVAL dwUser AS LONG, BYVAL dw1 AS LONG, BYVAL dw2 AS LONG) AS LONG
    'this is the routine that is run everytime the timer triggers
    #REGISTER NONE
    LOCAL WhichSprite AS LONG
    
    STATIC CalledBefore AS LONG
    
    GRAPHIC ATTACH hWindow,0
    
    
    IF NOT CalledBefore THEN
        CalledBefore = -1
        GRAPHIC GET BITS TO bmp
        Bmp2=Bmp
    END IF
    
    
    'do animation
    FOR WhichSprite = 1 TO %MaxSprites
        IF (Sprites(WhichSprite).flags AND %SpriteActive) THEN
            'update Sprite position
            Sprites(WhichSprite).yPos = Sprites(WhichSprite).yPos + Sprites(WhichSprite).ySpeed
            Sprites(WhichSprite).xPos = Sprites(WhichSprite).xPos + Sprites(WhichSprite).xSpeed
    
            IF %WrapX THEN
                IF Sprites(WhichSprite).xPos > ScreenWidth THEN Sprites(WhichSprite).xPos = Sprites(WhichSprite).xPos - ScreenWidth - Sprites(WhichSprite).xSize
                IF Sprites(WhichSprite).xPos < - Sprites(WhichSprite).xSize THEN Sprites(WhichSprite).xPos = Sprites(WhichSprite).xPos + ScreenWidth + Sprites(WhichSprite).xSize
            END IF
    
            IF %WrapY THEN
                IF Sprites(WhichSprite).yPos > ScreenHeight THEN Sprites(WhichSprite).yPos = Sprites(WhichSprite).yPos - ScreenHeight - Sprites(WhichSprite).ySize
                IF Sprites(WhichSprite).yPos < -Sprites(WhichSprite).ySize THEN Sprites(WhichSprite).yPos = Sprites(WhichSprite).yPos + ScreenHeight + Sprites(WhichSprite).ySize
            END IF
    
            INCR Sprites(WhichSprite).AnimationCount
            IF Sprites(WhichSprite).AnimationCount = Sprites(WhichSprite).AnimationTime THEN
                Sprites(WhichSprite).AnimationCount = 0
                Sprites(WhichSprite).CurrentFrame = (Sprites(WhichSprite).CurrentFrame + 1) MOD Sprites(WhichSprite).MaxFrame
    
            END IF
        END IF
    NEXT
    
    'Indicate to plot thread that there's been an update so it can start to plot
    SetEvent PlotFlag
    
    
    #IF 0
    'don't bother with collision detection, just rem it out for now
    FOR x = 1 TO MIN&(220, %MaxSprites)
       FOR y = x TO MIN&(220,%MaxSprites)
           IF x <> y THEN
                IF Collision(x,y) THEN
                    Sprites(x).xSpeed=RND(-20,20)
                    Sprites(x).ySpeed=RND(-20,20)
                    Sprites(y).xSpeed=RND(-20,20)
                    Sprites(y).ySpeed=RND(-20,20)
    
                END IF
            END IF
        NEXT
    NEXT
    #ENDIF
    
    GRAPHIC DETACH
    
    END FUNCTION
    
    
    
    
    
    
    FUNCTION Collision ( Sprite1 AS LONG, Sprite2 AS LONG) AS LONG
    'Check to see if 2 sprites have collided
    #REGISTER NONE
    LOCAL x ,y, xLimit, yLimit, Transparent1, Transparent2  AS LONG
    LOCAL SpriteStart1, SpriteStart1X, SpriteStart1Y, Sprite1Base, Sprite1Offset, xSprite1TotWidth AS LONG
    LOCAL SpriteStart2, SpriteStart2X, SpriteStart2Y, Sprite2Base, Sprite2Offset, xSprite2TotWidth AS LONG
    
    
    SpriteStart1 = STRPTR(SpriteStrings(Sprites(Sprite1).hnd))+8
    SpriteStart2 = STRPTR(SpriteStrings(Sprites(Sprite2).hnd))+8
    
    xSprite1TotWidth = CVL(SpriteStrings(Sprites(Sprite1).hnd),1)
    xSprite2TotWidth = CVL(SpriteStrings(Sprites(Sprite2).hnd),1)
    
    SpriteStart2X = MAX&(0,Sprites(Sprite1).xPos-Sprites(Sprite2).xPos)
    SpriteStart2Y = MAX&(0,Sprites(Sprite1).yPos-Sprites(Sprite2).yPos)
    
    SpriteStart1X = MAX&(0,Sprites(Sprite2).xPos-Sprites(Sprite1).xPos)
    SpriteStart1Y = MAX&(0,Sprites(Sprite2).yPos-Sprites(Sprite1).yPos)
    
    xLimit = 4*(MIN&(Sprites(Sprite2).xPos + Sprites(Sprite2).xSize, Sprites(Sprite1).xPos + Sprites(Sprite1).xSize ) - Sprites(Sprite2).xPos - SpriteStart2X -1)
    yLimit = 4*(MIN&(Sprites(Sprite2).yPos + Sprites(Sprite2).ySize, Sprites(Sprite1).yPos + Sprites(Sprite1).ySize ) - Sprites(Sprite2).yPos - SpriteStart2Y -1)
    
    IF xLimit>0 AND yLimit>0 THEN
        'sprite blocks overlap so look at it in more detail to determine collision
        Transparent1 = Sprites(Sprite1).Transparent
        Transparent2 = Sprites(Sprite2).Transparent
    
        Sprite1Base = SpriteStart1 + 4 * (SpriteStart1X + Sprites(Sprite1).xSize * Sprites(Sprite1).CurrentFrame + SpriteStart1Y * xSprite1TotWidth)
        Sprite2Base = SpriteStart2 + 4 * (SpriteStart2X + Sprites(Sprite2).xSize * Sprites(Sprite2).CurrentFrame + SpriteStart2Y * xSprite2TotWidth)
    
    
        FOR y = 0 TO yLimit STEP 4
           Sprite1Offset = Sprite1Base +  y * xSprite1TotWidth
           Sprite2Offset = Sprite2Base +  y * xSprite2TotWidth
    
           ' for x = 0 to xLimit  'The x loop is time sensitive so do it in ASM
    
            !mov edx,Transparent1    'the colour to be transparent for sprite1
            !mov eax,Transparent2    'the colour to be transparent for sprite2
            !mov ecx,xLimit          'x pixel count, Count down to 0
            !mov esi,Sprite2Offset   'point to right place in sprite2
            !mov edi,Sprite1Offset   'point to right place in sprite1
    
    
        #ALIGN 16
        lp2:
           !prefetchnta [esi+ecx-64]
           !prefetchnta [edi+ecx-64]
    
    
            !cmp eax,[esi+ecx]
            !je short skip1
            !cmp edx,[edi+ecx]
            !je short skip1
            !mov function,-1
            EXIT FUNCTION
        skip1:
            !sub ecx,4               'next x. 4 bytes per pixel
            !js short xit            'if not -ve then loop back
    
            !cmp eax,[esi+ecx]
            !je short skip2
            !cmp edx,[edi+ecx]
            !je short skip2
            !mov function,-1
            EXIT FUNCTION
         skip2:
            !sub ecx,4               'next x. 4 bytes per pixel
            !js short xit            'if not -ve then loop back
    
            !cmp eax,[esi+ecx]
            !je short skip3
            !cmp edx,[edi+ecx]
            !je short skip3
            !mov function,-1
            EXIT FUNCTION
        skip3:
    
    
            !sub ecx,4               'next x. 4 bytes per pixel
            !js short xit            'if not -ve then loop back
    
            !cmp eax,[esi+ecx]
            !je short skip
            !cmp edx,[edi+ecx]
            !je short skip
            !mov function,-1
            EXIT FUNCTION
    
        skip:
            !sub ecx,4               'next x. 4 bytes per pixel
            !jns  lp2                'if not -ve then loop back
    
       xit:
    
        NEXT 'y
    
    
    END IF  'xLimit<0 and yLimit<0
    
    
    END FUNCTION
    
    
    
                            
    FUNCTION PlotThread(BYVAL junk AS LONG) AS LONG
    #REGISTER NONE
    LOCAL WhichSprite, x ,y, xLimit, yLimit, Transparent  AS LONG
    LOCAL BmpStart, BMPStart1, BmpStart2, BmpStartX, BmpStartY, BMPbase, BMPoffset, LenBmp AS LONG
    LOCAL SpriteStart, SpriteStartX, SpriteStartY, SpriteOffset, xSpriteTotWidth, SpriteBase AS LONG
    
    
    'Variables that can be deleted after testing:
    STATIC Cnt AS LONG
    STATIC Tot,k,k2 AS QUAD
    GRAPHIC ATTACH hWindow,0
    STATIC frames AS LONG
    STATIC tm1 AS EXT
    tm1 = TIMER
    
    DO
        'wait until timer has triggered and updated sprite positions
        WaitForSingleObject PlotFlag, %INFINITE
    
        BmpStart = STRPTR(Bmp2) + 8
        BMPStart1 = STRPTR(Bmp) + 8
        BMPStart2 = STRPTR(Bmp2) + 8
        LenBmp =LEN(bmp) - 8
    ReStart:
        'Bmp2 = bmp
        'This is a time consuming copy in a time sensitive place which can be done a little faster in ASM
    
        'copy entire background image to overwrite bitmap for display
        !mov ecx,LenBmp
        !mov esi,BMPstart1
        !add esi,ecx
        !mov edi,BMPstart2
        !add edi,ecx
        !shr ecx,2
        !neg ecx
    
    #ALIGN 16
    lp:
        !prefetchnta [esi+ecx*4+512]
        !movq mm0,[esi+ecx*4]
        !movq mm1,[esi+ecx*4+8]
        !movq mm2,[esi+ecx*4+16]
        !movq mm3,[esi+ecx*4+24]
        !movq mm4,[esi+ecx*4+32]
        !movq mm5,[esi+ecx*4+40]
        !movq mm6,[esi+ecx*4+48]
        !movq mm7,[esi+ecx*4+56]
        !movntq [edi+ecx*4],mm0
        !movntq [edi+ecx*4+8],mm1
        !movntq [edi+ecx*4+16],mm2
        !movntq [edi+ecx*4+24],mm3
        !movntq [edi+ecx*4+32],mm4
        !movntq [edi+ecx*4+40],mm5
        !movntq [edi+ecx*4+48],mm6
        !movntq [edi+ecx*4+56],mm7
    
        !add ecx,16
        !jnz lp
    
        !sfence
        !emms
    
    
        FOR WhichSprite = 1 TO %MaxSprites
            IF (Sprites(WhichSprite).flags AND %PlotSprite) THEN
                'copy the sprite into the correct location within Bmp2 which is then copied to the screen
    
                SpriteStart = STRPTR(SpriteStrings(Sprites(WhichSprite).hnd))+8
                xSpriteTotWidth = CVL(SpriteStrings(Sprites(WhichSprite).hnd),1)
    
                BmpStartX = MAX&(0,Sprites(WhichSprite).xPos)
                BmpStartY = MAX&(0,Sprites(WhichSprite).yPos)
                SpriteStartX = MAX&(0, - Sprites(WhichSprite).xPos) + Sprites(WhichSprite).xSize * Sprites(WhichSprite).CurrentFrame
                SpriteStartY = MAX&(0,-Sprites(WhichSprite).yPos)
                xLimit = (MIN&(Sprites(WhichSprite).xSize + Sprites(WhichSprite).xPos, Sprites(WhichSprite).xSize, ScreenWidth  - Sprites(WhichSprite).xPos) -1) *4
                yLimit = (MIN&(Sprites(WhichSprite).ySize + Sprites(WhichSprite).yPos, Sprites(WhichSprite).ySize, ScreenHeight - Sprites(WhichSprite).yPos) -1) *4
    
                IF xLimit>0 AND yLimit>0 THEN
                    'sprite is at least partly on screen so copy it
                    Transparent = Sprites(WhichSprite).Transparent
                    BMPbase = BMPstart + 4 * BmpStartX + 4 * ScreenWidth * BmpStartY
                    SpriteBase = SpriteStart + 4 * SpriteStartX + 4 *SpriteStartY * xSpriteTotWidth
    
                    FOR y = 0 TO yLimit STEP 4
                       BMPoffset =  BMPbase + y * ScreenWidth
                       SpriteOffset = SpriteBase +  y * xSpriteTotWidth
    
                       ' for x = 0 to xLimit  'The x loop is time sensitive so do it in ASM
                        !mov edx,Transparent    'the colour to be transparent for this sprite
                        !mov edi,BMPoffset      'point to right place in bitmap
                        !mov ecx,xLimit         'x pixel count, Count down to 0
                        !mov esi,SpriteOffset   'point to right place in sprite
    
                    #ALIGN 16
                    lp2:
                        !prefetchnta [esi+ecx-128]
                        !prefetcht0  [edi+ecx-64]
                        !mov eax,[esi+ecx]       'eax = pixel from sprite
                        !cmp eax,edx             'is it to be transparent?
                        !je short skip           'yes, don't write it to screen
                        !mov [edi+ecx],eax       'write pixel to screen
                    skip:
                        !sub ecx,4               'next x. 4 bytes per pixel
                        !js short xit            'if not -ve then loop back
    
    
                        !mov eax,[esi+ecx]       'eax = pixel from sprite
                        !cmp eax,edx             'is it to be transparent?
                        !je short skip1          'yes, don't write it to screen
                        !mov [edi+ecx],eax       'write pixel to screen
                   skip1:
                        !sub ecx,4               'next x. 4 bytes per pixel
                        !js short xit            'if not -ve then loop back
    
                        !mov eax,[esi+ecx]       'eax = pixel from sprite
                        !cmp eax,edx             'is it to be transparent?
                        !je short skip2          'yes, don't write it to screen
                        !mov [edi+ecx],eax       'write pixel to screen
                   skip2:
                        !sub ecx,4               'next x. 4 bytes per pixel
                        !js short xit            'if not -ve then loop back
    
    
                        !mov eax,[esi+ecx]       'eax = pixel from sprite
                        !cmp eax,edx             'is it to be transparent?
                        !je short skip3          'yes, don't write it to screen
                        !mov [edi+ecx],eax       'write pixel to screen
                   skip3:
                        !sub ecx,4               'next x. 4 bytes per pixel
                        !jns short lp2           'if not -ve then loop back
    
                   xit:
                     '  next 'x
    
    
                    NEXT 'y
    
                END IF  'xLimit<0 and yLimit<0
    
            END IF  'plotsprite
    
        NEXT  'WhichSprite
    
        GRAPHIC SET BITS bmp2           'Write the entire new bitmap to the screen
    
        ResetEvent PlotFlag             'This prevents the plot being called when there's nothing to plot
    
    LOCAL fps AS STRING
    
        'print frames per second
        INCR frames
        IF frames = 50 THEN
             frames = 0
             fps = "fps="+STR$(INT(100*50/(TIMER-tm1))/100)
             tm1=TIMER
        END IF
    
        GRAPHIC SET POS (1,1)
        GRAPHIC PRINT fps
    
    LOOP  UNTIL QuitFlag
    
    END FUNCTION

  • #2
    Wow- Way to go Paul - You da man. I gotta learn me some assembler.

    Jim

    Comment

    Working...
    X