Jump to content

Converting GDI+ Bitmap/Image to SDL Surface


AdmiralAlkex
 Share

Recommended Posts

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
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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
Link to comment
Share on other sites

  • 3 years later...

@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!

Link to comment
Share on other sites

@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.

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...