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.
...
Announcement
Collapse
No announcement yet.
Rotating Bitmaps - some fun
Collapse
X
-
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:
-
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:
-
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:
-
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, 11:26 AM.
Leave a comment:
-
and the EXE comes out to be 27 KB in size
SDK source code is larger, but we both know that it produces smaller and faster EXE...
Leave a comment:
-
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:
-
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:
-
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:
-
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:
-
Paul,
Very interesting code.
Not quite as fast a world transformation, but not bad.
Leave a comment:
-
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:
-
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:
-
Originally posted by Chris Boss View PostSemens 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
'*********************************************************************************
' 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:
-
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!
Leave a comment:
-
>The downside to this is that these API's are not in Windows 95/98/ME.
There is no downside!
Leave a comment:
-
it is calling the world transformation API's itself
Leave a comment:
-
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:
-
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:
Leave a comment: