Jump to content

This site uses cookies. By continuing to browse the site you are agreeing to our use of cookies. Find out more here. X
X


Photo

Converting GDI+ Bitmap/Image to SDL Surface


  • Please log in to reply
2 replies to this topic

#1 AdmiralAlkex

AdmiralAlkex

    Here be dragons

  • Active Members
  • PipPipPipPipPipPip
  • 4,607 posts

Posted 12 October 2010 - 10:58 AM

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.

AutoIt         
#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:
AutoIt         
#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, I have zipped the 2 files needed for these examples (SDL.dll and SDL.au3). Download here: http://hem.passagen.se/amax/autoit/SDL.zip (126 KB)
  • Xandy likes this







#2 Authenticity

Authenticity

    Universalist

  • MVPs
  • 2,619 posts

Posted 12 October 2010 - 01:21 PM

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.



#3 AdmiralAlkex

AdmiralAlkex

    Here be dragons

  • Active Members
  • PipPipPipPipPipPip
  • 4,607 posts

Posted 12 October 2010 - 05:48 PM

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

It looks like this now:

AutoIt         
#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, 16 October 2010 - 01:15 PM.





0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users