Sign in to follow this  
Followers 0

Converting GDI+ Bitmap/Image to SDL Surface

6 posts in this topic

#1 ·  Posted (edited)

Anyone else thinks it would be cool if you could move data between a bitmap and a surface?

It would be useful for both SDL and GDI+ users.

If you use SDL:
Load images from disc with GDI+ instead of big SDL_image.
There's one problem with this, per-pixel alpha. I don't know why but it's just solid black. I would be very grateful for any help on this!

If you use GDI+:
Use SDL to blit to screen.
SDL is faster, handles redrawing "automagically", and you doesn't need any "double-buffer template" to combat flickering.


Here's an example demonstrating loading images with GDI+ for usage in SDL. The second image uses alpha to show the problem above.
 

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseX64=n
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****

#Include <GDIPlus.au3>
#Include "SDL.au3"

Local $sFile1 = RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\AutoIt v3\AutoIt", "InstallDir") _
    & "\Examples\GUI\msoobe.jpg"   ;Path to image1
Local $sFile2 = RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\AutoIt v3\AutoIt", "InstallDir") _
    & "\Examples\GUI\Torus.png"   ;Path to image2

;Initialize libraries
_SDL_Init($_SDL_INIT_VIDEO)   ;initialize SDL
_GDIPlus_Startup()

$pScreen = _SDL_GuiCreate(StringTrimRight(@ScriptName, 4), 1024, 768, 32, $_SDL_SWSURFACE)   ;You can use zero on bbp and SDL will choose what it thinks is appropriate

$hImage1 = _SDL_GDIPlus_ImageLoadFromFile($sFile1)
_SDL_BlitSurface($hImage1, 0, $pScreen, 0)
_SDL_FreeSurface($hImage1)

$hImage2 = _SDL_GDIPlus_ImageLoadFromFile($sFile2)
_SDL_BlitSurface($hImage2, 0, $pScreen, 0)
_SDL_FreeSurface($hImage2)

_SDL_Flip($pScreen)

While 1
    Sleep(10)
WEnd

Func _SDL_GDIPlus_ImageLoadFromFile($sFile)
    $hImage = _GDIPlus_ImageLoadFromFile($sFile)
    $iWidth = _GDIPlus_ImageGetWidth($hImage)
    $iHeight = _GDIPlus_ImageGetHeight($hImage)

    $Reslt = _GDIPlus_BitmapLockBits($hImage, 0, 0, $iWidth, $iHeight, $GDIP_ILMREAD, $GDIP_PXF32ARGB)
    $Scan0 = DllStructGetData($Reslt, "Scan0")
    $pOldBitmap = _SDL_CreateRGBSurfaceFrom($Scan0, $iWidth, $iHeight, 32, $iWidth * 4, 0, 0, 0, 0)

    $pNewSurface = _SDL_CreateRGBSurface($_SDL_SWSURFACE, $iWidth, $iHeight, 32, 0, 0, 0, 0)   ;If you set 0 for $iRmask, $iGmask, $iBmask, $iAmask it will be set to a default value
    _SDL_BlitSurface($pOldBitmap, 0, $pNewSurface, 0)

    _SDL_FreeSurface($pOldBitmap)
    _GDIPlus_BitmapUnlockBits($hImage, $Reslt)
    _GDIPlus_ImageDispose($hImage)

    Return $pNewSurface
EndFunc

And a quick example to show the extra speed you get with SDL:

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseX64=n
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****

#Include <GDIPlus.au3>
#Include "SDL.au3"
#include <WindowsConstants.au3>

Opt("GUIOnEventMode", 1)

Global $iBlittingMethod = 1, $asBlittingMethod[4] = ["", "SDL", "GDI+", "GDI+wSDL"]

HotKeySet("{SPACE}", "_Next")

Local $iWidth = 800, $iHeight = 600

$hGui = GUICreate(StringTrimRight(@ScriptName, 4), $iWidth, $iHeight, 0, 0)
EnvSet("SDL_WINDOWID", $hGui)

_SDL_Init($_SDL_INIT_VIDEO)
_GDIPlus_Startup()

$hScreenSurface = _SDL_SetVideoMode($iWidth, $iHeight, 32, $_SDL_SWSURFACE)

$hScreenGraphics = _GDIPlus_GraphicsCreateFromHWND($hGui)
$hBitmap = _GDIPlus_BitmapCreateFromGraphics($iWidth, $iHeight, $hScreenGraphics)
$hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap)

GUISetState()
GUISetOnEvent(-3, "_Exit")

Global $iLoopCurrent = 0

AdlibRegister("_FPS", 1000)

Do
    Switch $iBlittingMethod
        Case 1
            _SDL_FillRect($hScreenSurface, 0, Random(0, 0xFFFFFF, 1))
            _SDL_Flip($hScreenSurface)
        Case 2
            $hBrush = _GDIPlus_BrushCreateSolid("0xFF" & Random(0, 0xFFFFFF, 1))
            _GDIPlus_GraphicsFillRect($hScreenGraphics, 0, 0, $iWidth, $iHeight, $hBrush)
            _GDIPlus_BrushDispose($hBrush)
        Case 3
            $hBrush = _GDIPlus_BrushCreateSolid("0xFF" & Random(0, 0xFFFFFF, 1))
            _GDIPlus_GraphicsFillRect($hGraphics, 0, 0, $iWidth, $iHeight, $hBrush)
            _GDIPlus_BrushDispose($hBrush)

            $Reslt = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $iWidth, $iHeight, $GDIP_ILMREAD, $GDIP_PXF32ARGB)
            $Scan0 = DllStructGetData($Reslt, "Scan0")
            $pOldBitmap = _SDL_CreateRGBSurfaceFrom($Scan0, $iWidth, $iHeight, 32, $iWidth * 4, 0, 0, 0, 0)

            _SDL_BlitSurface($pOldBitmap, 0, $hScreenSurface, 0)
            _SDL_FreeSurface($pOldBitmap)
            _GDIPlus_BitmapUnlockBits($hBitmap, $Reslt)

            _SDL_Flip($hScreenSurface)
    EndSwitch

    $iLoopCurrent += 1
Until 0

Func _FPS()
    WinSetTitle($hGui, "", "Rendering with: " & $asBlittingMethod[$iBlittingMethod] & " (" & $iLoopCurrent & " FPS)")
    $iLoopCurrent = 0
EndFunc

Func _Next()
    $iBlittingMethod += 1
    If $iBlittingMethod = 4 Then $iBlittingMethod = 1
EndFunc

Func _Exit()
    _SDL_Quit()
    Exit
EndFunc

If you don't have the SDL udf already, download it from >HERE (you only need SDL.dll and SDL.au3 for the above code).

Edited by AdmiralAlkex
1 person likes this

Share this post


Link to post
Share on other sites



#2 ·  Posted

You can use SDL_SetColorKey, so you only need 24 bits image.

_SDL_SetColorKey($pNewSurface, $_SDL_SRCCOLORKEY, 0)
_SDL_BlitSurface($pOldBitmap, 0, $pNewSurface, 0)

According to the documentation:

[RGBA]mask are the bitmasks used to extract that colour from a pixel. For instance, Rmask being FF000000 means the red data is stored in the most significant byte. Using zeros for the RGB masks sets a default value, based on the depth. (e.g. SDL_CreateRGBSurface(flags,w,h,32,0,0,0,0);)However, using zero for the Amask results in an Amask of 0.

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

That's a neat trick, as long as you don't need anything between fully opaque and fully transparent ;)

It looks like this now:

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseX64=n
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****

#Include <GDIPlus.au3>
#Include "SDL.au3"

Local $sFile1 = RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\AutoIt v3\AutoIt", "InstallDir") _
    & "\Examples\GUI\msoobe.jpg"   ;Path to image1
Local $sFile2 = RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\AutoIt v3\AutoIt", "InstallDir") _
    & "\Examples\GUI\Torus.png"   ;Path to image2

;Initialize libraries
_SDL_Init($_SDL_INIT_VIDEO)   ;initialize SDL
_GDIPlus_Startup()

;~ _MemTest()   ;Uncomment and look at task manager. "Private Working Set" does increase a few MB, but how often do you load 10K images normally?? :P

$pScreen = _SDL_GuiCreate(StringTrimRight(@ScriptName, 4), 1024, 768, 32, $_SDL_SWSURFACE)   ;You can use zero on bbp and SDL will choose what it thinks is appropriate (but we want 32)

$hImage1 = _SDL_GDIPlus_ImageLoadFromFile($sFile1)
_SDL_BlitSurface($hImage1, 0, $pScreen, 0)
_SDL_FreeSurface($hImage1)

$hImage2 = _SDL_GDIPlus_ImageLoadFromFile($sFile2)
_SDL_BlitSurface($hImage2, 0, $pScreen, 0)
_SDL_FreeSurface($hImage2)

_SDL_Flip($pScreen)

While 1
    Sleep(10)
WEnd

Func _SDL_GDIPlus_ImageLoadFromFile($sFile)
    $hImage = _GDIPlus_ImageLoadFromFile($sFile)
    $iWidth = _GDIPlus_ImageGetWidth($hImage)
    $iHeight = _GDIPlus_ImageGetHeight($hImage)

    $Reslt = _GDIPlus_BitmapLockBits($hImage, 0, 0, $iWidth, $iHeight, $GDIP_ILMREAD, $GDIP_PXF32ARGB)
    $Scan0 = DllStructGetData($Reslt, "Scan0")
    $pOldBitmap = _SDL_CreateRGBSurfaceFrom($Scan0, $iWidth, $iHeight, 32, $iWidth * 4, 0, 0, 0, 0)

    $pNewSurface = _SDL_CreateRGBSurface($_SDL_SWSURFACE, $iWidth, $iHeight, 32, 0, 0, 0, 0)   ;If you set 0 for $iRmask, $iGmask, $iBmask it will be set to a default value
    _SDL_SetColorKey($pNewSurface, $_SDL_SRCCOLORKEY, 0)
    _SDL_BlitSurface($pOldBitmap, 0, $pNewSurface, 0)

    _SDL_FreeSurface($pOldBitmap)
    _GDIPlus_BitmapUnlockBits($hImage, $Reslt)
    _GDIPlus_ImageDispose($hImage)

    Return $pNewSurface
EndFunc

Func _MemTest()
    MsgBox(0, "", "Before array")
    Local $apSurfaces[10000]   ;Uses about 1.4 GB memory

    MsgBox(0, "", "Before loading")
    For $iX = 0 To UBound($apSurfaces) -1
        $apSurfaces[$iX] = _SDL_GDIPlus_ImageLoadFromFile($sFile2)
    Next


    MsgBox(0, "", "Before UNloading")
    For $iX = 0 To UBound($apSurfaces) -1
        _SDL_FreeSurface($apSurfaces[$iX])
    Next

    MsgBox(0, "", "After UNloading")
EndFunc

Thank you Authenticity!

Edited by AdmiralAlkex

Share this post


Link to post
Share on other sites

#4 ·  Posted

@AdmiralAlkex

Hello friend, the download link has problems, see:

Forbidden

You don't have permission to access /amax/autoit/SDL.zip on this server.

Additionally, a 403 Forbidden error was encountered while trying to use an ErrorDocument to handle the request.

JS


http://forum.autoitbrasil.com/ (AutoIt v3 Brazil!!!)

Somewhere Out ThereJames Ingram

somewh10.png

dropbo10.pngDownload Dropbox - Simplify your life!
Your virtual HD wherever you go, anywhere!

Share this post


Link to post
Share on other sites

#5 ·  Posted

@AdmiralAlkex

Hello friend, the download link has problems, see:

JS

 

Yes, unfortunately they discontinued their hosting service but I couldn't remember all the places where I linked to files on my site there. Thanks for telling me.

 

If it is okay for you, please download the full SDL UDF from >HERE and you can extract the needed 2 files from there. If you prefer a smaller package (pay per MB internet?) then tell me and I will prepare a new small zip.

Share this post


Link to post
Share on other sites

#6 ·  Posted

Thanks for your attention!
I've done the download, now I'm testing to see the possibilities of exchanging some functions
.

JS


http://forum.autoitbrasil.com/ (AutoIt v3 Brazil!!!)

Somewhere Out ThereJames Ingram

somewh10.png

dropbo10.pngDownload Dropbox - Simplify your life!
Your virtual HD wherever you go, anywhere!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0