Announcement

Collapse
No announcement yet.

Rotating Bitmaps - some fun

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

  • Patrice Terrier
    replied
    Chris,

    Granulaity has always been one of my major concern.

    While we are unable to use static linking doesn't mean that we can't clean up our code. Fortunatly a tool like Borje's inclean utility does a very nice job.

    I was just amazed by the difference in size.

    Removing the background in PlgBlt would not make the code twice large.

    I wrote it to show the use of an API that was almost unknown by most of us.

    In case of image rotation FPS is absolutly not meaningful, what is meaningful is are you using linear interploation, bicubic, Nearestneighbor, etc.

    If we do not use the same algorithm then we can't do any fair comparison.

    ...

    Leave a comment:


  • Chris Boss
    replied
    I agree with Paul.

    Frame speed is important because it shows how fast the code itself is being executed. One actually wants to use the CPU 100% during testing of code speed. This is why I don't use things like timers with test code, since one does not get a real picture of the actual code speed.

    While the bitmap rotation using world transforms and PlgBlt are quite reasonable for one single image of medium or small size, I am not sure it would be so fast when dealing with dozens of images at one time.

    Another consideration is the effects of running an app when other apps are running and there is less CPU time per app. A frame rate at 100% CPU time and one app running does not mean the frame rate will be that good when multiple apps are running at the same time.

    Personally I like to squeeze out every bit of speed I possibly can, so when the code is run in the real world it will run at a decent speed.

    I am also interested in the avoidance of later API's if possible so I can run the code on Windows 95/98/ME (I know, everybody says they are obsolete). I try to design software which can take advantage of legacy systems.

    Leave a comment:


  • Chris Boss
    replied
    Patrice,

    I wouldn't start touting SDK code as half the size of DDT quite yet.

    First, your code doesn't use the API includes, but simply has the declares for what is used.

    When compiled using the PB 9.0 compiler, your plgblt.bas app compiles to:

    18 KB (no includes)
    25 KB (when using win32api.inc and deleting references to commtrl.inc)
    61 KB (when using win32api.inc and commctrl.inc)

    The API include files add some fat to an application, albeit not an awful lot.

    Also your app isn't cleaning up the background of each blit (which requires extra memory buffers and redrawing them each time), so it has a little less code.

    Also DDT apps when using DDT commands add a bit more runtime library time code when compiled. This adds a little more fat when the program is small, but balances out when the app gets bigger (runtime code is efficient and modular so size savings are not found until the app gets some size).

    For those browsing the forums and new to PB it is only fair to get the real facts on DDT. DDT is quite efficient and lean, IMO. One does not gain significant advantages by using SDK style code over DDT for most applications.

    Leave a comment:


  • Paul Dixon
    replied
    Patrice,
    FPS gives an indication of the speed of the code.

    500fps means the one frame is being drawn in 2ms or less.
    127fps means the one frame takes 7.8ms or less.


    I only used fps as a measure because Chris uses it in his example so I was keeping to the same units in order to make an easy comparison.
    Perhaps timing a single pass of the rotation code would be better.

    Paul.

    Leave a comment:


  • Patrice Terrier
    replied
    Paul,

    FPS is very subjective, and whatever you are doing you must always avoid to hog the whole CPU, thus in real application you should used something that is close to movie animation (24 FPS) this is quite enough because you won't see any difference due to the human eyes conformation.

    I usualy use 30 FPS (see my BassBox project for an example of real time application)


    Added:
    Paul, the bitmap being used in PglBlt is larger, and to produce faster code the solution is to use a permanent memory DC instead of re-creating it for each iteration.


    ...
    Last edited by Patrice Terrier; 29 May 2009, 12:26 PM.

    Leave a comment:


  • Patrice Terrier
    replied
    and the EXE comes out to be 27 KB in size
    Yes, twice bigger than pure SDK

    SDK source code is larger, but we both know that it produces smaller and faster EXE...

    Leave a comment:


  • Paul Dixon
    replied
    Chris,
    so far, at least on my computer, the version written entirely in BASIC in post #24 is by far the fastest.

    Rotating your logo1.bmp image in all cases, your code is doing 112 frames per second and the BASIC code in post #24 is running at 500fps.
    Patrice's appears to do 257 fps but doesn't clear the background. If the background doesn't need to be cleared then the code in post #24 runs at 560fps, over twice as fast as the next nearest and there are plenty of ways to speed it up further.

    Paul.

    Leave a comment:


  • Chris Boss
    replied
    Paul,

    I was not trying to imply anything negative by my comment about speed.

    I am just curious about what is the fastest way to accomplish image rotation. PlgBlt appears to be quite fast. Both PlgBlt and SetWorldTransform (and BltBlt) are quite fast.

    What I am wondering is whether it would be better to just use this feature in Windows (limited to NT systems, XP, Vista) or to write my own routine ?

    Your code (and some others) shows it can be done other ways and that would make the code usable on Windows 95/98/ME as well.


    Patrice, the EXE I posted has a lot of library code generated by my DDT designer and I didn't remove the extra library code, so it would be much larger. I rewrote the code using a simple DDT dialog and no library code by hand and the EXE comes out to be 27 KB in size.

    Leave a comment:


  • Paul Dixon
    replied
    Chris: "Not quite as fast a world transformation,"
    Patrice: "i found amazing to compare the size of the resulting EXE solutions "

    There's just no pleasing some people!
    The code was just straight forward BASIC, it was not intended to be extra small or extra fast but, just to keep you happy, here's a slightly modified version of the same code which appears to be faster.

    As for smaller, the RTL included with the compiler is 23k so I'd have to avoid the GRAPHIC commands but they make life easier. The rotation code itself is already quite small but I'm sure I could shrink it further and speed it up if I use a bit of ASM.

    Paul.

    Code:
    'PBCC5.01 program
    #COMPILE EXE
    #BREAK ON
    #DIM ALL
    
    %xWindowSize = 280
    %yWindowSize = 280
    
    %xRotateOffset=140
    %yRotateOffset=140
    
    FUNCTION PBMAIN () AS LONG
    LOCAL hInitialBMP,hWindow, hThread AS DWORD
    LOCAL InitialBMPstring, RotatedBMPstring AS STRING
    LOCAL x,y,a,xSize,ySize,t1,t2, Oldx,Oldy, QuitAll, lResult AS LONG
    LOCAL Angle,sina, cosa AS EXT
    LOCAL file AS STRING
    LOCAL initial(), rotated() AS LONG
    
    
    file$="logo1.bmp"
    x = FREEFILE
    OPEN file$ FOR BINARY AS x
    GET #x, 19, xSize
    GET #x, 23, ySize
    CLOSE x
    
                     
    GRAPHIC WINDOW "Rotation test",200,200, %xWindowSize,%yWindowSize TO hWindow
    GRAPHIC ATTACH hWindow,0
    GRAPHIC GET BITS TO RotatedBMPstring
    GRAPHIC DETACH
    
    GRAPHIC BITMAP LOAD file$, xSize&, ySize&  TO hInitialBMP
    GRAPHIC ATTACH hInitialBMP,0
    GRAPHIC GET BITS TO InitialBMPstring
    GRAPHIC DETACH
    
    THREAD CREATE RedrawGraphics (hWindow) TO hThread
    
    DIM initial&(1 TO xSize&,1 TO ySize&) AT STRPTR(InitialBMPstring)+8
    DIM rotated&(1 TO %xWindowSize,1 TO %yWindowSize) AT STRPTR(RotatedBMPstring)+8
    
    
    
    LOCAL tc, ts AS EXT
    
    t1&=TIMER*100
    
    FOR a& = 0 TO 360    'degrees
        
    angle##=a&/(180/3.141592653589)
    cosa=COS(angle##)
    sina=SIN(angle##)
    
    
    FOR x&=1 TO %xWindowSize
        tc = (x& - %xRotateOffset) *cosa  + %xRotateOffset  -40
        ts = -(x& - %xRotateOffset)*sina + %yRotateOffset  -70
        FOR y& = 1 TO %yWindowSize
    
           oldx& =tc + (y& - %yRotateOffset)*sina
           oldy& =(y& - %yRotateOffset) *cosa + ts
            
                          
           IF oldx&>0 AND oldx& < xSize&  AND oldy&>0 AND oldy&< ySize& THEN
                Rotated&(x&,y&)   =  Initial&(oldx& ,oldy&)
           ELSE
                Rotated&(x&,y&)   =  %WHITE
                
           END IF
       
    
        NEXT
    NEXT
    
    
    GRAPHIC ATTACH hWindow,0 ,REDRAW
    GRAPHIC SET BITS RotatedBMPstring
    GRAPHIC DETACH
    
    SLEEP 0
    NEXT
    
    t2&=TIMER*100
    PRINT "Time Taken = "(t2&-t1&)/100
    PRINT "Frames per second ="; 360/((t2&-t1&)/100 )
    
    QuitAll& =1
    
    THREAD CLOSE hThread TO lResult
    WAITKEY$
    
    END FUNCTION
    
    
    
    'This is a flag intended to cause all otherwise non-terminating threads to quit
    GLOBAL QuitAll&
    
    'This routine and the main program must use GRAPHIC ATTACH WindowID,0,REDRAW but the main program shouldn't
    'issue a GRAPHIC REDRAW command in normal use. Leave that up to this thread.
    FUNCTION RedrawGraphics(BYVAL WinID AS DWORD) AS DWORD
    
    GRAPHIC ATTACH WinID,0,REDRAW
    
    DO
    
        GRAPHIC REDRAW
        SLEEP 1
    LOOP UNTIL QuitAll&
    
    END FUNCTION

    Leave a comment:


  • Patrice Terrier
    replied
    Paul,

    Thank you to remind me the old method i was using in my PDS 7.1 applications, still very accurate with modern processors!

    By the way i found amazing to compare the size of the resulting EXE solutions that have been posted there:
    - DDT.exe = 58880 bytes (Chris, rotate.exe)
    - Console.exe = 36864 bytes (Paul, PBCC GRAPHIC example)
    - SDK.exe = 12288 bytes (Patrice, PlgBlt.exe)

    ...

    Leave a comment:


  • Chris Boss
    replied
    Paul,

    Very interesting code.

    Not quite as fast a world transformation, but not bad.

    Leave a comment:


  • Chris Boss
    replied
    Kevin,

    I meant no offense.

    I was just refering to the original code being in C and yours was a translation of it to BCX.

    Leave a comment:


  • Paul Dixon
    replied
    How do these "new" methods compare with just the old fashioned way of writing the rotation code in BASIC?

    The following code appears to be 50% faster than the code in post 13 of this thread and it rotates the full sized image, rather than shinking it to half size as that code appears to do.


    Paul.
    Code:
    #COMPILE EXE
    #BREAK ON
    
    
    #INCLUDE "win32api.inc"
    
    %xWindowSize = 400
    %yWindowSize = 400
    
    %xRotateOffset=200
    %yRotateOffset=200
    
    FUNCTION PBMAIN () AS LONG
    LOCAL hInitialBMP,hRotatedBMP,hWindow AS DWORD
    LOCAL InitialBMPstring, RotatedBMPstring AS STRING
    LOCAL x,y,r,t AS LONG
    LOCAL sina, cosa AS EXT
                         
    
    nFile& = FREEFILE
    OPEN "rose.bmp" FOR BINARY AS nFile&
    GET #nFile&, 19, xSize& 'nWidth&
    GET #nFile&, 23, ySize& 'nHeight&
    CLOSE nFile&
    
                     
    GRAPHIC WINDOW "Rotation test",200,200, %xWindowSize,%yWindowSize TO hWindow
    GRAPHIC ATTACH hWindow,0
    GRAPHIC GET BITS TO RotatedBMPstring
    GRAPHIC DETACH
    
    GRAPHIC BITMAP LOAD "rose.bmp", xSize&, ySize&, %HALFTONE  TO hInitialBMP
    GRAPHIC ATTACH hInitialBMP,0
    GRAPHIC GET BITS TO InitialBMPstring
    GRAPHIC DETACH
    
    THREAD CREATE RedrawGraphics (hWindow) TO hThread&
    
    DIM initial&(1 TO xSize&,1 TO ySize&) AT STRPTR(InitialBMPstring)+8
    DIM rotated&(1 TO %xWindowSize,1 TO %yWindowSize) AT STRPTR(RotatedBMPstring)+8
    
    
    t1&=TIMER*100
    
    FOR a& = 0 TO 360    'degrees
        
    angle##=a&/(180/3.141592653589)
    cosa=COS(angle##)
    sina=SIN(angle##)
    
    FOR x&=1 TO %xWindowSize
        FOR y& = 1 TO %yWindowSize
    
           oldx& =(x& - %xRotateOffset) *cosa + (y& - %yRotateOffset)*sina + %xRotateOffset -50
       
           oldy& =(y& - %yRotateOffset) *cosa - (x& - %xRotateOffset)*sina + %yRotateOffset  -50
            
                          
           IF oldx&>0 AND oldx& < xSize&  AND oldy&>0 AND oldy&< ySize& THEN
                Rotated&(x&,y&)   =  Initial&(oldx& ,oldy&)
            ELSE
                Rotated&(x&,y&)   =  %WHITE
                
            END IF
       
    
        NEXT
    NEXT
     
    
    GRAPHIC ATTACH hWindow,0 ,REDRAW
    GRAPHIC SET BITS RotatedBMPstring
    GRAPHIC DETACH
                                    
    SLEEP 0
    NEXT
    
    t2&=TIMER*100
    PRINT "Time Taken = "(t2&-t1&)/100
    PRINT "Frames per second ="; 360/((t2&-t1&)/100 )
    
    QuitAll& =1
    
    THREAD CLOSE hThread& TO lResult&
    WAITKEY$
    
    END FUNCTION
    
    
    
    'This is a flag intended to cause all otherwise non-terminating threads to quit
    GLOBAL QuitAll&
    
    'This routine and the main program must use GRAPHIC ATTACH WindowID,0,REDRAW but the main program shouldn't
    'issue a GRAPHIC REDRAW command in normal use. Leave that up to this thread.
    FUNCTION RedrawGraphics(BYVAL WinID AS DWORD) AS DWORD
    
    GRAPHIC ATTACH WinID,0,REDRAW
    
    DO
    
        GRAPHIC REDRAW
        SLEEP 1
    LOOP UNTIL QuitAll&
    
    END FUNCTION

    Leave a comment:


  • Mr. Kevin Diggins
    replied
    Originally posted by Chris Boss View Post
    Semens code appears to be based on the technique found on the web page noted in Kevens code (which is only a translation of someone elses code) found here:
    http://www.codeguru.com/cpp/g-m/bitm...icle.php/c1743
    Chris ... Unlike your purported BIG SECRET, I named my sources:

    '*********************************************************************************
    ' Original MFC code by Zafir Anjum August 5, 1998
    ' http://www.codeguru.com/cpp/g-m/bitm...cle.php/c1743/
    ' Converted to BCX by Kevin Diggins with help by Mike Henning
    ' Specify rotation angle using decimal degrees instead of radians
    '*********************************************************************************

    Leave a comment:


  • Patrice Terrier
    replied
    Of course not as good as GDImage

    Leave a comment:


  • Paul Squires
    replied
    Originally posted by Edwin Knoppert View Post
    >The downside to this is that these API's are not in Windows 95/98/ME.

    There is no downside!
    Yes, may Windows 95/98/ME rest in peace.

    Leave a comment:


  • Edwin Knoppert
    replied
    >The downside to this is that these API's are not in Windows 95/98/ME.

    There is no downside!

    Leave a comment:


  • Patrice Terrier
    replied
    it is calling the world transformation API's itself
    I don't know if GDIPLUS is using the initial NT world transformation, however it is using matrix world transformation for sure (you are getting hot)

    Leave a comment:


  • Chris Boss
    replied
    The interesting thing about all of this is that I have the impression that even GDI plus uses this technique. When you examine the GDI plus dll using Depends (shows all dependencies of a DLL or EXE), it is calling the world transformation API's itself.

    I can't know for sure, but it is quite possible the rotation code was already in Windows (NT,200,XP, Vista) and GDI plus is simply accessing it.

    The downside to this is that these API's are not in Windows 95/98/ME.

    Leave a comment:


  • Chris Boss
    replied
    I have played with Semens code gleaned from the forums.

    It works with a DIB and manipulates pixel by pixel.

    I have attached a zip file to this post, with a modified version of his code, both an exe and the basic source code.

    I don't fully understand his code, so I just changed a few things so I could time the rotation.

    It runs nearly half the speed of my latest code using world transformations. The Windows GDI

    World Transformations are much faster and well optimized.

    I do think one could write a routine which is faster by optimizing it with assembler or using precalculated tables.

    Semens code appears to be based on the technique found on the web page noted in Kevens code (which is only a translation of someone elses code) found here:

    http://www.codeguru.com/cpp/g-m/bitm...icle.php/c1743


    Both my first zip file (exe) using world transformations and Semens code are rotating an image 1 degree at a time (360 iterations) and time the results. The images are not the same but close in size though (give or take a little).
    Attached Files

    Leave a comment:

Working...
X