Announcement

Collapse
No announcement yet.

Paul Dixon's sprite demo

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

  • Paul Dixon's sprite demo

    Paul

    I mistakenly replied to the source code forum so I thought I better start something here. Gotta say that I am impressed. I hope you keep improving your demo. You said that you were going to implement alphablending. I hope you do. I saw on a separate thread that you used MMX in the incorporation of alphablending. I wish I knew assembler and I think this is the shove I needed to dive in and learn.

    One suggestion if possible, when you are done optimizing the code that satisfies you, could your code be arranged in one master function that does it all so it could be dropped in a program by mere mortals. The CPU usage on my computer was on about 15% at worst and I bumped the FPS to 60.

    Thanks again Paul. I really appreciate your knowledge and work here.

    Jim
    Last edited by james klutho; 16 Nov 2009, 05:53 PM.

  • #2
    Okay, this is the first time I have seen non-DX sprite code posted that beats mine. I am extremely impressed. Awesome job, Paul!

    I generally won't touch code posted here because of legalities (people rarely post what license its released under), but this is very interesting code.

    Comment


    • #3
      James,
      I didn't say I was going to add alphablending, I said it didn't look too difficult. Maybe I'll get around to it sometime.
      I wish I knew assembler
      Go ahead and learn it, it's not too difficult. For a start it has way less commands to learn than BASIC!

      There are only 3 small blocks of assembler in that program. Most of it is BASIC.
      One is a block copy because it's a little faster than copying one string to another. You could actually delete the block copy and unrem the line Bmp2 = bmp as all the copy does is copy the string bmp to the string Bmp2 a little faster than the compiler would.

      The second block is more important but if you look at it, all it does is copy small blocks of memory, in this case sprite images onto the screen buffer string.
      The third part is very similar to the second and checks that 2 sprites don't collide. It's unused in the posted example as I don't check for collisions.



      Brice,
      I assume all code posted on the forum is there to be used by others. Why else would anyone post it on a public forum?

      Paul.

      Comment


      • #4
        Thanks for the pep talk Paul. I need to get to work. Again I love looking at your code.

        Jim

        Comment


        • #5
          Paul: Good to know, thank you

          Comment


          • #6
            Paul,

            Add my thanks to the list. I don't have time to go through the code right now, but there's no doubt I will go through it in more detail later this week.

            Did you program it first, without ASM? If so, I'd really like to see that version as well.

            If you did, and the limit on sprites still allowed 100+ sprites at 15fps or more, that would be still be very useful for those of us who aren't (yet) assembly guys!

            If you didn't I'll probably give it a shot myself.

            Not having done any sprite work in PowerBASIC, I don't have any good idea about the useful limits on speed/# of sprites. I've posts by Patrice and Chris on their works, but that's about the only information I've seen recently. I don't know how that translates to what a user (of less experience in that area) might be able to expect.

            You may recall that I had a post a while back about having created a (very slow) PowerBASIC version of Falling Sand. The sprite code you posted today may be a big help in getting that application into usable form. I also have an animation game and physics engine I once wrote could stand a redo too. All of that, is, of course, as soon as I can get the time. Responsibilities get in the way of having fun!

            Thanks again,
            Last edited by Gary Beene; 17 Nov 2009, 02:32 PM.

            Comment


            • #7
              Gary,
              no, I don't have the original BASIC code but it's easy to convert it back.
              Delete the collision code as it wasn't called in the posted demo.
              The block copy was just to replace Bmp2 = Bmp so delete that and uncomment the line.
              That leaves the sprite copy routine which is really very straight forward as it only copies 1 line from a sprite to the final bitmap.

              If I got it right then the code below is what you want, delete the #IF 0/#ENDIF block and it may be clearer.

              Paul.
              Code:
              #COMPILE EXE
              #BREAK ON
              #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, %RED,%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 90'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 = RND(1,10)
                  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 160'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 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
              
                  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
              
              LOCAL pSpriteOffset, pBmpOffset AS DWORD PTR
              pSpriteOffset = SpriteOffset
              pBmpOffset = BMPoffset
              
                                  FOR x = 0 TO xLimit\4   'The x loop is time sensitive so do it in ASM
                                      IF @pSpriteOffset[x] <> Transparent THEN
                                          @pBmpOffset[x]= @pSpriteOffset[x]
                                      END IF
              
              
              #IF 0
                                  !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 -ve then exit
              
              
                                  !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 -ve then exit
              
                                  !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 -ve then exit
              
              
                                  !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
              #ENDIF
              
                             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

              Comment


              • #8
                Gary,
                the program was started off in BASIC as you could probably tell by the left over comments, but it didn't evolve from working BASIC code into a faster ASM version, it developed into working code while it became ASM.

                Having just run the back to BASIC demo you might not see a lot of difference if you only want 100 Sprites!

                You could probably improve the BASIC program by re-enabling register variables and choosing something appropriate to store in a register. They were disabled in the ASM because I used the registers explicitly myself.
                as soon as I can get the time
                I have the same problem.

                Paul.

                Comment


                • #9
                  Paul,

                  Thank you very much for the no-ASM code version of your sprites program. It was exactly what I wanted to see.

                  Sorry for the late response. I was distracted the last week and didn't see your post until tonight. That's probably just as well, else I'd have been hard pressed to tend to other responsibilities when something as fun as this was sitting there, demanding my attention!

                  On a quick look at the original (with ASM) and the new (all BASIC), I can't visually see any difference between the two with 10K sprites, even when I see the timer to 20ms (50fps). Processor usage was only 60% with ASM and 65% with all-BASIC.

                  Best wishes,

                  Comment


                  • #10
                    Gary,
                    number of sprites doesn't matter since the code to handle the number of sprites was all in BASIC anyway.
                    The ASM just copied blocks of data so the difference will be seen most in the amount of data copied.
                    If you have 10,000 tiny sprites of 3x3 pixels (36 bytes) each then 360,000 bytes of data is moved each frame.
                    If you have 1,000 bigger sprites of 30x30 (3,600 bytes each) then 3,600,000 bytes of data will be copied each frame.
                    10 times as much data will be copied in the second example even though there is 1/10th the number of sprites so the BASIC version will not perform as well in the second example.

                    Paul.

                    Comment


                    • #11
                      Paul,

                      I get a significant difference in speed in your code when it uses assembler, versus the code which does not.

                      I would like to convert some of the code in my sprite engine to assembler, but is has been a long, long time since I wrote any assember code (back when I was writing code on an 8086 CPU).

                      What would you recommend (book, web site w/tutorials, etc.) as a good source for a refresher course for the basics of assembler ?
                      Chris Boss
                      Computer Workshop
                      Developer of "EZGUI"
                      http://cwsof.com
                      http://twitter.com/EZGUIProGuy

                      Comment


                      • #12
                        I compared the two versions of the sprite program , one using assembler, the other using only basic. I set the time interval to 10 ms, instead of 40 ms to try to get the app to run as fast as possible.

                        Big difference!

                        Here are the FPS for each specific sprite screen (6 different screens with different sprites or sprite count) (FPS are averaged):

                        ASM version Basic version
                        #0 48 FPS 48 FPS (5 large sprites)
                        #1 28 FPS 15 FPS (100 large sprites)
                        #2 32 FPS 12 FPS (200 medium sprites)
                        #3 48 FPS 32 FPS (1000 small sprites)
                        #4 42 FPS 33 FPS (10,000 tiny sprites)
                        #5 33 FPS 20 FPS (200 mixed sprites)



                        Chris Boss
                        Computer Workshop
                        Developer of "EZGUI"
                        http://cwsof.com
                        http://twitter.com/EZGUIProGuy

                        Comment


                        • #13
                          Chris,
                          because the program handles too much work by dropping whole frames then you might not get useful results by counting fps.
                          e.g. assume 40ms per frame is set (=25fps). If the code runs in 39ms then you'll get 25fps but if the code is just 5% slower at 41ms then you'll get a dropped frame every other frame giving fps=12.5. It's really 5% slower but appears half as fast.
                          A better way is to time the 2 SUBs. Get the time on entry and the time on exit and print the difference in a console window. You can then see exactly how long each SUB takes for each frame so you can measure the smaller differences as you tweak the code.


                          For learning ASM, it's difficult to give good sources but you can check out this thread, which mentions a few:
                          http://www.powerbasic.com/support/pb...ad.php?t=11567

                          And get the Pentium manuals:
                          http://www.powerbasic.com/support/pb...ad.php?t=40773

                          And this one was mentioned before:
                          http://flatassembler.net/docs.php?article=manual


                          Paul.

                          Comment


                          • #14
                            For ultimate speed, then better use GPU.

                            ...
                            Patrice Terrier
                            www.zapsolution.com
                            www.objreader.com
                            Addons: GDImage.DLL 32/64-bit (Graphic library), WinLIFT.DLL 32/64-bit (Skin Engine).

                            Comment


                            • #15
                              Using Paul's posted ASM version of the code, I can modify it to 40,000 sprites and get over 100 fps, I only start losing FPS when I get up to around 50,000 sprites.

                              Comment


                              • #16
                                Again--

                                The maximum FPS you can have on VISTA and Seven is something around 60 FPS, because of DWM and vertical retrace synchro.

                                And the vertical synchro also apply to older OS.

                                When doing animation it is very important to avoid frame drop, and produce smooth result. For example when you watch a movie the motion is produced by the flipping of 30 image per second, aka 30 FPS, and that is the perfect rate for human eyes.

                                And to play GIF animation it is very common to use only 15 FPS or even less, based on the number of frame. In the "IceWalk" animation, the frame rate is limited to 15 FPS because the pinguin are walking not running!

                                ...
                                Patrice Terrier
                                www.zapsolution.com
                                www.objreader.com
                                Addons: GDImage.DLL 32/64-bit (Graphic library), WinLIFT.DLL 32/64-bit (Skin Engine).

                                Comment


                                • #17
                                  For ultimate speed, then better use GPU.
                                  This is not entirely accurate.

                                  The maximum FPS you can have on VISTA and Seven is something around 60 FPS, because of DWM and vertical retrace synchro.

                                  And the vertical synchro also apply to older OS.
                                  You are misunderstanding a key issue, therefore you are incorrect. However, this is not the thread to discuss it, nor is it the thread to use as a venue to promote your products.

                                  Comment


                                  • #18
                                    You are misunderstanding a key issue, therefore you are incorrect.
                                    I thought i had a good knowledge of DWM, but you may have a better one

                                    ...
                                    Patrice Terrier
                                    www.zapsolution.com
                                    www.objreader.com
                                    Addons: GDImage.DLL 32/64-bit (Graphic library), WinLIFT.DLL 32/64-bit (Skin Engine).

                                    Comment


                                    • #19
                                      A culture of competition has arisen among game enthusiasts with regards to frame rates, with players striving to obtain the highest FPS possible, due to their utility in demonstrating a system's power and efficiency. Indeed, many benchmarks (such as 3DMark) released by the marketing departments of hardware manufacturers and published in hardware reviews focus on the FPS measurement. Even though the LCD monitors typical of present times are locked at 60 FPS, making extremely high framerates impossible to see in realtime, playthroughs of game “timedemos” at hundreds or thousands of FPS for benchmarking purposes are still common.
                                      ...
                                      Patrice Terrier
                                      www.zapsolution.com
                                      www.objreader.com
                                      Addons: GDImage.DLL 32/64-bit (Graphic library), WinLIFT.DLL 32/64-bit (Skin Engine).

                                      Comment


                                      • #20
                                        Some of the new monitors that support 3D have a refresh rate of 120 Hz. This is the required refresh rate to play games in 3D. I wonder if they maintain this same refresh rate when playing non-3D as well. My guess is that they probably do.

                                        120 Hz monitors aren't common yet but they're becoming more so and I understand they're popular with hard core gamers. I'm not a hard core gamer and I don't know anyone who is but I have heard that mentioned in tech podcasts a time or two.

                                        Barry

                                        Comment

                                        Working...
                                        X