Jump to content

Best way to draw on GUI


Recommended Posts

Because of the glitches in my previous Yahtzee game, I am revamping most of the main code. I have the background set already. I have to put the dice on top of the png background somehow. After thinking about it, I came up with a few different ways:

1. Using GDI+, I could create a copy of the background, draw the dice on the copy, and then set the copy as the new background.

2. Using GDI+, I could create a new child GUI, then draw the dice onto that GUI.

3. I could also use Yashied's Icons UDF to create controls on a new GUI and set the control to the image of the GUI.

Here is a very stripped down piece of code that shows the general framework of the GUI:

#include <GDIPlus.au3>
#include <Misc.au3>
#include <StructureConstants.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>

_GDIPlus_Startup()
OnAutoItExitRegister("CleanupGame")
Opt("MouseCoordMode", 2)

Global $GameBackgroundPath = @ScriptDir & "\Images\Gameplay\Background.png"
Global $GameBackgroundImage = _GDIPlus_ImageLoadFromFile($GameBackgroundPath)
Global $DicePath = @ScriptDir & "\Images\Gameplay\Dice.png"
Global $DiceImage = _GDIPlus_ImageLoadFromFile($DicePath)
Dim $Dice[7][2]

InitializeDice()

$GameGUI = GUICreate("", 480, 480, -1, -1, $WS_POPUP, $WS_EX_LAYERED)
SetBitmap($GameGUI, $GameBackgroundImage, 255)
GUISetState(@SW_SHOW, $GameGUI)

While 1
    If _IsPressed("01") Then
        $MousePos = MouseGetPos()

        If _PointInCircle($MousePos[0], $MousePos[1], 316, 9, 25) Then
            MenuButtonPressed()
        EndIf

        While _IsPressed("01")
            Sleep(50)
        WEnd
    EndIf
WEnd

Func InitializeDice()
    For $i = 1 To 6
        $Dice[$i][0] = _GDIPlus_BitmapCloneArea($DiceImage, 0, ($i - 1) * 50, 50, 50)
        $Dice[$i][1] = _GDIPlus_BitmapCloneArea($DiceImage, 50, ($i - 1) * 50, 50, 50)
    Next
EndFunc ;==>InitializeDice

Func MenuButtonPressed()
    ConsoleWrite("Menu Button Pressed" & @CRLF)
EndFunc ;==>MenuButtonPressed

Func _PointInCircle($iX, $iY, $iLeft, $iTop, $iRadius)
    Return ($iX - ($iLeft + $iRadius)) ^ 2 + ($iY - ($iTop + $iRadius)) ^ 2 <= $iRadius ^ 2
EndFunc ;==>_PointInCircle

Func CleanupGame()
    _GDIPlus_ImageDispose($GameBackgroundImage)
    _GDIPlus_Shutdown()
EndFunc ;==>CleanupGame

Func SetBitmap($hGUI, $hImage, $iOpacity, $CenterGUI = True)
    Local $hScrDC, $hMemDC, $hBitmap, $hOld, $pSize, $tSize, $pSource, $tSource, $pBlend, $tBlend, $AC_SRC_ALPHA = 1

    $hScrDC = _WinAPI_GetDC(0)
    $hMemDC = _WinAPI_CreateCompatibleDC($hScrDC)
    $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
    $hOld = _WinAPI_SelectObject($hMemDC, $hBitmap)
    $tSize = DllStructCreate($tagSIZE)
    $pSize = DllStructGetPtr($tSize)
    DllStructSetData($tSize, "X", _GDIPlus_ImageGetWidth($hImage))
    DllStructSetData($tSize, "Y", _GDIPlus_ImageGetHeight($hImage))
    $tSource = DllStructCreate($tagPOINT)
    $pSource = DllStructGetPtr($tSource)
    $tBlend = DllStructCreate($tagBLENDFUNCTION)
    $pBlend = DllStructGetPtr($tBlend)
    DllStructSetData($tBlend, "Alpha", $iOpacity)
    DllStructSetData($tBlend, "Format", $AC_SRC_ALPHA)
    _WinAPI_UpdateLayeredWindow($hGUI, $hScrDC, 0, $pSize, $hMemDC, $pSource, 0, $pBlend, $ULW_ALPHA)
    If $CenterGUI Then WinMove($hGUI, "", (@DesktopWidth - _GDIPlus_ImageGetWidth($hImage)) / 2, (@DesktopHeight - _GDIPlus_ImageGetHeight($hImage)) / 2)

    _WinAPI_ReleaseDC(0, $hScrDC)
    _WinAPI_SelectObject($hMemDC, $hOld)
    _WinAPI_DeleteObject($hBitmap)
    _WinAPI_DeleteDC($hMemDC)
EndFunc ;==>SetBitmap

I was wondering what you guys thought would be the most reliable way to put the dice on the main GUI. If anyone has any other ideas, I would love to hear them.

If you want the images for the background and the dice, they are here and here.

Link to comment
Share on other sites

Maybe I'm biased (lol?), but I would say that SDL should be one of the considerations, due to it's faster speed among other things. And it's easy to use when you get the hang of it.

If it has to be GDI+ I have to say option 1, for no particular reason other than it sounds neater.

Anyway, if you have any question or somethig about SDL, don't hesitate to ask! :(

Link to comment
Share on other sites

I have never tried SDL before. I looked at your UDF and I have to say, it looks confusing to me to start. I noticed though that you have a large group of examples (one of which is a transparent png) which will make it much easier to get the hang of it. I will look into this a bit more because it looks interesting.

A few simple questions:

1. What is the difference in overhead between SDL and GDI+?

2. Is there any redrawing bugs or is it all handled inside the dlls? (just gotta make sure)

3. What dll files are required for drawing png images on a GUI? (there seem to be a lot in the examples folder)

4. Is it reliable enough to work on most computers?

Edited by dantay9
Link to comment
Share on other sites

I agree it's confusing, I'm still clueless on some things, and I've written the damn au3-files!

1. What sort of overhead are we talking about? Hard drive space? The SDL.dll is about 250Kb, add another 200Kb or so for PNG-support (SDL_Image.dll, libpng12-0.dll and zlib1.dll). I suppose you could implement one of the "dll in exe"-techniques floating around the forum if you don't like the extra files.

2. Like flickering? Maybe it's just me, but it seems pretty much flickerfree by default. :)

But for those special cased there's always the $_SDL_DOUBLEBUF flag.

3. SDL.au3 and SDL.dll does the main stuff, and is what you mean when you say SDL, but to load png-files you would need SDL_image.au3 with SDL_Image.dll, libpng12-0.dll and zlib1.dll.

An alternative would be to convert the graphics to bmp and use Color-keying, then you wouldn't need anything else than the SDL.dll.

4. SDL should work on everything from Windows 95 and up, so it beats AuotIt in backwards compatibility :(

Something worthy of notice is the lack of x64 code, so you're stuck in x86-land.

5. If I understand correctly look at "SDL Example Video Bitmaps Pixels.au3" :)

Edited by AdmiralAlkex
Link to comment
Share on other sites

Right, that took a little longer than I expected :(

Anyway, graphics in SDL are based on one thing, a "surface", not like in GDI+ where you have "graphics", "images" and whatnot.

When you want to "blit" (copy) from one surface to another you call _SDL_BlitSurface, which has 4 parameters:

1. Source surface

2. Source rect

3. Destination surface

4. Destination rect

The surfaces are simply a pointer (to a struct), that has been returned from an earlier function, like _SDL_SetVideoMode or _SDL_LoadBMP. Rect is short for rectangle, and should be the return from _SDL_Rect_Create, which takes the left, top, width and height as parameters.

You can see all this in "SDL Example Video Bitmaps Pixels.au3". Play around with the values in the Rects and see how things move around.

Tip: If you're going to use the same Rects multiple time, save it to a variable so you can reuse it!

You may also want to give ShiftER a quick look. It's an image viewer I made that uses SDL. It doesn't have many comments but you should be able to get the feeling for how it works.

And for fun, here's an example based on your first post, complete with it's own benchmark featuring it's own teeny tiny coffee bar. :)

;SDL only exist for x86 so lets make sure AutoIt uses x86.
#AutoIt3Wrapper_UseX64=n

#Include "SDL.au3"  ;Remember to change to wherever you placed SDL.au3
#Include "SDL_image.au3"    ;Remember to change to wherever you placed SDL_image.au3

;Most functions needs the corresponding subsystem to be Initiated before usage.
;We only need video so lets Init with that.
_SDL_Init($_SDL_INIT_VIDEO)
;Initialize SDL_Image.
_SDL_Init_image()

;SDL can also give a borderless window.
$pSurface = _SDL_GuiCreate(@ScriptName, 480, 480, 0, BitOR($_SDL_SWSURFACE, $_SDL_NOFRAME)) ;0 bit-depth makes SDL choose one a fitting one by itself (probably same as the desktop I would imagine)
;$pSurface is now a pointer to the "screen"-surface.

;Load our images inte surfaces.
$pBackground = _IMG_Load(@ScriptDir & "\background.png")
$pDice = _IMG_Load(@ScriptDir & "\dice.png")

;Blit the background to our window.
_SDL_BlitSurface($pBackground, 0, $pSurface, 0)

;Now we update the "screen" by either SDL_UpdateRect or SDL_Flip depending on the situation.
;Here we choose _SDL_Flip for no particular reason at all.
_SDL_Flip($pSurface)

Local $Array[6]
$Array[0] = _SDL_Rect_Create(0, 0, 50, 50)
$Array[1] = _SDL_Rect_Create(0, 50, 50, 50)
$Array[2] = _SDL_Rect_Create(0, 100, 50, 50)
$Array[3] = _SDL_Rect_Create(0, 150, 50, 50)
$Array[4] = _SDL_Rect_Create(0, 200, 50, 50)
$Array[5] = _SDL_Rect_Create(0, 250, 50, 50)

Local $Array2[5]
$Array2[0] = _SDL_Rect_Create(400, 27, 0, 0)
$Array2[1] = _SDL_Rect_Create(333, 93, 0, 0)
$Array2[2] = _SDL_Rect_Create(400, 159, 0, 0)
$Array2[3] = _SDL_Rect_Create(333, 225, 0, 0)
$Array2[4] = _SDL_Rect_Create(400, 291, 0, 0)

Local $iTimer = TimerInit(), $iLoops = 0

While 1
    _SDL_BlitSurface($pDice, $Array[Random(0, 5, 1)], $pSurface, $Array2[0])
    _SDL_BlitSurface($pDice, $Array[Random(0, 5, 1)], $pSurface, $Array2[1])
    _SDL_BlitSurface($pDice, $Array[Random(0, 5, 1)], $pSurface, $Array2[2])
    _SDL_BlitSurface($pDice, $Array[Random(0, 5, 1)], $pSurface, $Array2[3])
    _SDL_BlitSurface($pDice, $Array[Random(0, 5, 1)], $pSurface, $Array2[4])
    _SDL_Flip($pSurface)

    $iLoops += 1

    If TimerDiff($iTimer) > 1000 Then
        ConsoleWrite("Loops per second: " & $iLoops & @CRLF)
        $iLoops = 0
        $iTimer = TimerInit()
    EndIf
WEnd

I get around 1450 loops/sec on my main pc! :)

Link to comment
Share on other sites

This is definately something I am going to try. It looks a lot less confusing now than it did before. I guess a lot of the code is going to be variables that aren't going to be used in a loop. The actual loop seems pretty simple. Thanks for the example!

Link to comment
Share on other sites

Before I embark on creating code to draw text on another new gui, is there any way to draw text on the screen with SDL? I don't see an example or any documentation in the help file.

Edit: Ok, I found the UDF for drawing text on the screen, but can't get the hang of it. Can you create a simple example using SDL_ttf.au3 to draw text onto a gui for me (or are all the functions still untested)?

Edited by dantay9
Link to comment
Share on other sites

Something like this:

#Include "SDL_ttf.au3"
#Include "SDL.au3"

_SDL_Init($_SDL_INIT_VIDEO)
_SDL_Init_ttf()

_TTF_Init()
$pFont = _TTF_OpenFont(@ScriptDir & "\freefont-20090104\FreeSansBold.ttf", 28)

$pSurface = _SDL_GuiCreate(@ScriptName, 640, 480, 32, $_SDL_SWSURFACE)

_SDL_FillRect($pSurface, 0, 0xFF0000)
$sMessage = _TTF_RenderText_Solid($pFont, "The quick brown fox jumps over the lazy dog", 0x00FF00)
_SDL_BlitSurface($sMessage, 0, $pSurface, 0)
_SDL_Flip($pSurface)

While 1
    Sleep(10)
WEnd

Of course you need a TrueType font somewhere. You could probably google something. In this example I use a font from freefont-ttf-20090104.tar.gz from here.

For sdl_ttf to work you need:

SDL_ttf.dll

libfreetype-6.dll

zlib1.dll

Link to comment
Share on other sites

No thank you for seriously considering my UDF, it's more than most people seem to do (from what I can tell anyway). You know, it's a bit funny that no one of the GDI+ people have been here... Or even Yashied. Did I scare them away? :(

Edited by AdmiralAlkex
Link to comment
Share on other sites

I think the regulars on this forum know that Danty9 has a good understanding of GDI+ and knows the limitations and advantages and doesn't need that level of information. As well he seems to have found his solution.... I've been playing a lot with GDI+ as well and you peaked my interest too. Somehow your post flew under my radar screen, I'm way too far along in my main project now to consider switching.....but mark my words, I plan to investigate this SDL stuff much more in future projects...I have bookmarked this link

Link to comment
Share on other sites

@picea892

Thanks for the compliment.

@AdmiralAlkex

I think one of the reasons your UDF is not used as much as GDI+ is because there haven't been many people using this on a large project. Also, for me, the dlls are a negative aspect. I don't mind since I have many images anyway, but I am sure some people want a standalone program. I think it is a viable option because everything can be drawn on the screen without the need for more guis or controls. That should improve the reliability of my program.

I had pizza last night.

Edited by dantay9
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...