I was wondering if there was a ready made tool within BBC Basic that rotates a BMP image on center? Its not that I dont want to make it myself, but I wouldn't want to make it and then someone say I wasted my time. (because I know exactly how to do it using a turtle scanner encoder. (which I have made 2 programs that do both turtle and image scanning. ( The turtle IDE and BMPtoCode )
I suspect my methods of scanning and image rotation using my turtle tool may not be that fast, as BMPtoCode was effective only with small images. (and sadly, all it did was compress image information so it could be used in a program as code.)
To keep it simple, the question is:
Is there a simple way to rotate a bmp image on center?
* if there isn't, then I will work on one for the world to use.
Rotating a BMP image
-
- Posts: 101
- Joined: Sat 23 Jun 2018, 19:52
Rotating a BMP image
Focus is on code subject. Feel free to judge the quality of my work.
Re: Rotating a BMP image
BBC BASIC has no 'built in' statement for this, but of course it's something which is done in many existing programs so there's definitely no need to re-invent the wheel by coming up with yet another solution. 'Fast' methods that I have seen used include:
- Using the Windows PlgBlt API function. This transforms a rectangular image to an arbitrary parallelogram, and of course a rotated rectangle is a parallelogram! Quite easy to use, but Windows-specific so not suitable for BBC BASIC for SDL 2.0.
- Using the SDL2 SDL_RenderCopyEx API function, which will plot a texture with an arbitrary rotation. Again quite simple to use but specific to BBC BASIC for SDL 2.0. There are examples of its use in the supplied jigsaw.bbc and aliens.bbc programs.
- Using 3D graphics (via the supplied d3dlib.bbc or ogllib.bbc libraries) by texture-mapping your BMP image onto a plane rectangle and then rotating it in 3D space. Somewhat more involved, code-wise, than the above solutions but effectively cross-platform in that it's easy to make it work in both BB4W and BBCSDL. Of course you cannot easily mix 2D and 3D graphics in the same program which may be an issue in some applications.
So it's a case of choosing which is the most appropriate method for a given application. I can see an argument for writing a library that, for example, automatically uses PlgBlt in BB4W and SDL_RenderCopyEx in BBCSDL to provide a genuine cross-platform solution, but such a library does not currently exist as far as I know. I can think of a couple of people (other than me) who would have the necessary skills to write it!
Re: Rotating a BMP image
Another good approach that's just occurred to me, and which is cross-platform, is to leverage the BOX2DGFX libraries available for both BBC BASIC for Windows and BBC BASIC for SDL 2.0. Although principally designed to be used with the Box2D physics engine they don't need to be, and they both contain routines for displaying a bitmap image with rotation (PROC_gfxPlot1 and PROC_gfxPlot2, which have identical effect in BBCSDL but provide a trade-off between speed and quality in BB4W).
The interface is perhaps slightly less friendly than a dedicated rotation library might provide, because the loading of the image is separated from its display (although this is of course what you want if you are plotting the same image multiple times). But of the available methods this is probably the one I would choose, having now thought of it.
Re: Rotating a BMP image
As it was simply a copy-and-paste exercise from existing programs, I've created just such a library (rather than PlgBlt I used GDIPlus in order to support images with an alpha channel, such as PNG or GIF). It is very much not written for the highest performance, for example the GDIPlus library is loaded and freed on every single call, which is wasteful but ensures that everything is cleaned up. But as a substitute for *DISPLAY, with optional rotation, it does the job. It's had very little testing, so feedback is welcome.RichardRussell wrote: ↑Sat 07 Mar 2020, 10:30I can see an argument for writing a library that, for example, automatically uses PlgBlt in BB4W and SDL_RenderCopyEx in BBCSDL to provide a genuine cross-platform solution
Code: Select all
REM Image rotation library for BBC BASIC for Windows and BBC BASIC for SDL 2.0
REM Version 0.00, 07-Mar-2020, (C) Richard Russell http://www.rtrussell.co.uk/
REM Display a bitmap image with optional scaling and rotation
REM img$ = Path and filename to image file (.bmp, .gif, .jpg, .png)
REM x = horizontal coordinate of image *centre*, in BBC BASIC units
REM y = vertical coordinate of image *centre*, in BBC BASIC units
REM s = scaling (1.0 to display at original size)
REM a = angle of rotation, counter-clockwise, in radians
DEF PROC_displayrotate(img$, x, y, s, a)
IF INKEY(-256) = &57 THEN
REM 'BBC BASIC for Windows'
LOCAL G%, H%, I%, L%, M%, P%, T%, W%, tSI{}
DIM T% LOCAL 513
SYS "MultiByteToWideChar", 0, 0, img$, -1, T%, 256
SYS "LoadLibrary", "GDIPLUS.DLL" TO L%
IF L% = 0 ERROR 100, "Couldn't load GDIPLUS.DLL"
SYS "GetProcAddress", L%, "GdiplusStartup" TO `GdiplusStartup`
SYS "GetProcAddress", L%, "GdipLoadImageFromFile" TO `GdipLoadImageFromFile`
SYS "GetProcAddress", L%, "GdipDrawImageFX" TO `GdipDrawImageFX`
SYS "GetProcAddress", L%, "GdipCreateMatrix2" TO `GdipCreateMatrix2`
SYS "GetProcAddress", L%, "GdipRotateMatrix" TO `GdipRotateMatrix`
SYS "GetProcAddress", L%, "GdipTranslateMatrix" TO `GdipTranslateMatrix`
SYS "GetProcAddress", L%, "GdipDeleteMatrix" TO `GdipDeleteMatrix`
SYS "GetProcAddress", L%, "GdipGetImageHeight" TO `GdipGetImageHeight`
SYS "GetProcAddress", L%, "GdipGetImageWidth" TO `GdipGetImageWidth`
SYS "GetProcAddress", L%, "GdipCreateFromHDC" TO `GdipCreateFromHDC`
SYS "GetProcAddress", L%, "GdipSetSmoothingMode" TO `GdipSetSmoothingMode`
SYS "GetProcAddress", L%, "GdipDeleteGraphics" TO `GdipDeleteGraphics`
SYS "GetProcAddress", L%, "GdipDisposeImage" TO `GdipDisposeImage`
SYS "GetProcAddress", L%, "GdiplusShutdown" TO `GdiplusShutdown`
DIM tSI{GdiplusVersion%, DebugEventCallback%, \
\ SuppressBackgroundThread%, SuppressExternalCodecs%}
tSI.GdiplusVersion% = 1
SYS `GdiplusStartup`, ^P%, tSI{}, 0
SYS `GdipLoadImageFromFile`, T%, ^I%
IF I% = 0 THEN
SYS `GdiplusShutdown`, P%
SYS "FreeLibrary", L%
ERROR 100, "Couldn't load image """ + img$ + """"
ENDPROC
ENDIF
SYS `GdipGetImageWidth`, I%, ^W%
SYS `GdipGetImageHeight`, I%, ^H%
SYS `GdipCreateMatrix2`, FN_f4(s), FN_f4(0), FN_f4(0), FN_f4(s), \
\ FN_f4(@vdu.o.x%/2+x/2), FN_f4(@vdu%!212-@vdu.o.y%/2-y/2), ^M%
SYS `GdipRotateMatrix`, M%, FN_f4(-DEGa), 0
SYS `GdipTranslateMatrix`, M%, FN_f4(-W%/2), FN_f4(-H%/2), 0
SYS `GdipCreateFromHDC`, @memhdc%, ^G%
SYS `GdipSetSmoothingMode`, G%, 2
SYS `GdipDrawImageFX`, G%, I%, 0, M%, 0, 0, 2
SYS `GdipDeleteMatrix`, M%
SYS `GdipDeleteGraphics`, G%
SYS `GdipDisposeImage`, I%
SYS `GdiplusShutdown`, P%
SYS "FreeLibrary", L%
SYS "InvalidateRect", @hwnd%, 0
ELSE
REM 'BBC BASIC for SDL 2.0'
LOCAL s%%, t%%, W%, H%, a#, dst{}, p, ARMHF
DIM dst{x%, y%, w%, h%}
SYS "STBIMG_Load", img$ TO s%%
IF @platform% AND &40 ELSE s%% = !^s%%
IF s%%=0 ERROR 104, "Couldn't load image """ + img$ + """"
SYS "SDL_SetHint", "SDL_RENDER_SCALE_QUALITY", "best"
SYS "SDL_CreateTextureFromSurface", @memhdc%, s%% TO t%%
SYS "SDL_SetHint", "SDL_RENDER_SCALE_QUALITY", "none"
IF @platform% AND &40 ELSE t%% = !^t%%
IF t%%=0 ERROR 105, "Unable to create texture"
SYS "SDL_SetTextureBlendMode", t%%, 1, @memhdc%
SYS "SDL_FreeSurface", s%%
SYS "SDL_QueryTexture", t%%, 0, 0, ^W%, ^H%
a# = -DEG(a)
IF @platform% >= &2000A00 THEN
p = PI : IF !^p = &54442D18 ARMHF = TRUE
dst.w% = FN_f4(W% * s)
dst.h% = FN_f4(H% * s)
dst.x% = FN_f4((x - W% * s) / 2)
dst.y% = FN_f4(@vdu%!212 - (y + H% * s) / 2)
IF @platform% AND &40 THEN
IF a#=0 THEN ?(^a#+7)=&80
SYS "SDL_RenderCopyExF", @memhdc%, t%%, FALSE, dst{}, a#, FALSE, FALSE
ELSE IF ARMHF THEN;
SYS "SDL_RenderCopyExF", @memhdc%, t%%, FALSE, dst{}, a#, FALSE, FALSE
ELSE
SYS "SDL_RenderCopyExF", @memhdc%, t%%, FALSE, dst{}, !^a#, !(^a#+4), FALSE, FALSE
ENDIF
ELSE
dst.w% = INT(W% * s + 0.5)
dst.h% = INT(H% * s + 0.5)
dst.x% = INT((x - W% * s) / 2 + 0.5)
dst.y% = INT(@vdu%!212 - (y + H% * s) / 2 + 0.5)
IF @platform% AND &40 THEN
IF a#=0 THEN ?(^a#+7)=&80
SYS "SDL_RenderCopyEx", @memhdc%, t%%, FALSE, dst{}, a#, FALSE, FALSE
ELSE
SYS "SDL_RenderCopyEx", @memhdc%, t%%, FALSE, dst{}, !^a#, !(^a#+4), FALSE, FALSE
ENDIF
ENDIF
SYS "SDL_DestroyTexture", t%%, @memhdc%
ENDIF
ENDPROC
DEF FN_f4(a#)LOCALp%%:p%%=^a#:IFABSa#<1E-38THEN=FALSE
=p%%!4ANDNOT&7FFFFFFFOR(p%%!4-&38000000<<3OR!p%%>>29AND7)+(!p%%>>28AND1)
-
- Posts: 101
- Joined: Sat 23 Jun 2018, 19:52
Re: Rotating a BMP image
I didnt see your coded example until after I posted my response. The times are showing that my post came after yours.. I would disregard my previous post about the optional commands for doing the task. I appreciate the code you supplied . I will try it out.
Focus is on code subject. Feel free to judge the quality of my work.
-
- Posts: 101
- Joined: Sat 23 Jun 2018, 19:52
Re: Rotating a BMP image
I guess as per conversation in email (me , Richard and Kendall Down ):
I guess the code solution Richard supplied I can use and improve and add into my programs, as the code was posted in full as a solution in public.
Thats great!!
I will of course make a link to this subject thread so that others can easily find the publicly posted solution and test and use it!!
Thanks a lot Richard Russell for the post and Kendall Down for clearing up the code usage issue in email.
Of course feel free to respond quickly to this post, as I may get ambitious and get a cool demo done to post back on this forum.
I guess the code solution Richard supplied I can use and improve and add into my programs, as the code was posted in full as a solution in public.
Thats great!!
I will of course make a link to this subject thread so that others can easily find the publicly posted solution and test and use it!!

Thanks a lot Richard Russell for the post and Kendall Down for clearing up the code usage issue in email.
Of course feel free to respond quickly to this post, as I may get ambitious and get a cool demo done to post back on this forum.

Focus is on code subject. Feel free to judge the quality of my work.
-
- Posts: 101
- Joined: Sat 23 Jun 2018, 19:52
Re: Rotating a BMP image
I made a short video demo of the rotating BMP image in BBC4W and did test it in BBCSDL. ( both worked )
* The test on BBCSDL I will send a copy of the test to Richard, as review of results will likely be desired.
This test on BBC4W was really cool and here is the link to the video:
https://youtu.be/cq3QFC5rAm4
* The test on BBCSDL I will send a copy of the test to Richard, as review of results will likely be desired.
This test on BBC4W was really cool and here is the link to the video:
https://youtu.be/cq3QFC5rAm4
Focus is on code subject. Feel free to judge the quality of my work.
Re: Rotating a BMP image
Performance in BBCSDL is likely to be considerably better than in BB4W, because in BBCSDL it can take advantage of hardware (GPU) acceleration. Of course if you have a poor GPU (such as some 'integrated graphics' chipsets on laptops) then the acceleration may not be very effective, but on a machine with a 'respectable' graphics card the performance in BBCSDL will probably be significantly better than in BB4W (it is here).
But I would still want to reiterate that the code I listed in the earlier post (which for some reason was deleted from the forum for several hours, but has now been restored) is not intended for 'dynamic' use (such as a video game). It is designed not for performance but for ease of use, and is effectively a direct replacement for the *DISPLAY command but with the added capability of rotation.
Just as you wouldn't normally consider using *DISPLAY for animated sprites, nor should you consider using PROC_displayrotate for that kind of application. Where 'video game' performance is required you should, as always, use David Williams's GFXLIB2 when coding in BBC BASIC for Windows and direct calls to the SDL2 API when coding in BBC BASIC for SDL 2.0. There are plenty of examples of both out there.
Re: Rotating a BMP image
I've just done an actual measurement, on this laptop (integrated graphics). Called 1000 times (and with a reasonably large .png image with transparency) it took 6.8 seconds in BB4W and 4.9 seconds in BBCSDL. But both are slow, in absolute terms, (about 150 fps and 200 fps respectively) which is not surprising when you consider that on every single call the file is re-read and libraries are loaded and unloaded etc. This is a terrible way to code anything if you want speed!RichardRussell wrote: ↑Mon 09 Mar 2020, 10:02the performance in BBCSDL will probably be significantly better than in BB4W
-
- Posts: 101
- Joined: Sat 23 Jun 2018, 19:52
Re: Rotating a BMP image
I did take a look at the Aliens example in BBCSDL and it was awesome. I will work with that tool.
Focus is on code subject. Feel free to judge the quality of my work.