Efficient 'Graphics Engine'

Cags
08-12-2006, 09:13 AM
I posted here rather than games as its only the graphics I'm asking about, feel free to move if you think it would be better in the game section. Its also worth noting I'm actually working in C#, but since its a question about theory not actually code I don't think this matters (I know VB.Net well enough to understand most code snippets people might throw at me). I originally posted this question ot the DotNetForums, but I posted it again here as more people use this site.

I've been working on what is essentially a sliding block game for Pocket PC. My game has a few alternative modes to simply sliding however which is causing me a few nightmares. My game has gone through several iterations in terms of 'Graphics Engines' but as usual I'm still not happy and keep changing it. All you really need to understand is a square 'Board' consists of 'Tiles' (currently max size is 5x5). These tiles can move about in allsorts of various manners. Each square will end up on another square when it is moved, but various modes will have animated slides so the tiles do overlap for a time. These are the methods I've tried.

1. Using Controls is the easiest method, once each tile is drawn it can be moved about without redrawing anything. When an effect needs to be added to every tile however you can see each tile refresh independtly (generally only the tiniest delay between, but it bugs me).

2. Using the Graphics objects and GDI+ I wrote a method that redraws all tiles to a backbuffer then the backbuffer to the screen, this works rather slow however and makes animations very slow and not at all smooth.

Each idea I have only seems to be perfect in certain situations. The sliding puzzle for example works fine with GDI+, because I can tell it to only draw certain squares. I could do the same with other modes but calculating which squares when they all interact would be far more difficult, and moves away from a standardised Graphics Engine and essentially creates a seperate one for each game mode. I've also considered replacing the Graphics object by using GDI, but I'm not sure if it will be worth the effort. Basically I'm wondering if anyone has any suggests on the best way to proceed.

JNewt
08-12-2006, 05:32 PM
Can't say I'm really familiar with PocketPC development, but GDI+ performance is generally good enough for games with relatively few animated objects; your trouble might be in how your render loop is set up --could you post some code? Also, is DirectX an option with PocketPC? It'd mean some steep learning but it's the way to go if you want serious graphical performance.

Cags
08-13-2006, 03:36 AM
As stated before the code is c# and not entirely relevant on these forums. A quick pseudo vb conversion of the code is as follows
Dim srcImage As new Bitmap(path)
Dim offscreenBitmap As new Bitmap(Me.Width, Me.Height)
Dim offscreenGraphics As Graphics.FromImage(offscreenBitmap)

Private Sub AnimMovingTiles(ByRef movingTiles As Tile(), ByVal targets As Point)
' calc total displacement of each Tile

For i = 0 To 10
System.Threading.Thread.Sleep(5)
For j = 0 To movingTiles.Length
tiles(j).Displace(displacement.X / 10, displacement.Y / 10)
Next
DrawAll()
Next
End Sub

Private Sub DrawAll()
offscrenGraphics.Clear(Color.Black)
For i = 0 to 25
tiles(i).Draw(offscreenGraphics)
Next

Refresh()
End Sub

' tiles is an array of Tile classes the Draw method simply contains
Private Sub Draw()
offscreenGraphics.DrawImage(srcImage, rectBounds, rectInitBounds, GraphicsUnit.Pixel)

If DrawBoarder Then
offscreenGraphics.DrawRectangle(StaticGraphics.BoarderPen, rectBounds)
End IF

If DrawIndex Then
offscreenGraphcis.DrawString(Index.ToString(), StaticGraphics.IndexFont, StaticGraphics.IndexBrush, rectBounds)
End IF
End Sub

' where srcImage is a reference to the srcImage in the Board class

' Both paint methods are overriden with OnPaint simply containing the following. OnPaintBackground contains no code.

If srcImage Not Nothing Then
e.Graphics.DrawImage(offscreenBitmap, new Rectangle(...), new Rectangle(...), GraphicsUnit.Pixel)
End IF
Whilst I could provide more details of the code, as I'm sure there are many small optimisations that could be made. I feel that it's not the calcuations that are taking the majority of the time, its the actual draw commands. What I'm looking for is suggestions of either speeding up the actual drawing, or alternatively a decent (dynamic) way of deciding which Tiles need drawing. Thus removing the overheads of drawing them.

One method I considered was to draw the board entirely (minus the moving tiles) as the start of the anim then using this as a buffer during each displacement iteration. Simply draw the buffer then the moving Tiles. This would reduce the drawing count from 25 calls to Draw() to movingTiles.Length + 1 calls on each iteration. Obviously 25 - movingTiles.Length calls would need to be made initially but as this isn't done on every iteration it shouldn't effect the animation. This method would use slightly more memory however since the new buffer would need to be stored, but I don't think it would really be big enough to be too much of an issue. Of course this method is reliant on one call to Graphics.DrawImage() with a large image being more efficient than 20 odd calls with a smaller image.

Another option I considered was similar to the above but only Invalidating parts of the screen. This would require more calcuations, but I feel they are cheaper than the actual drawing code. What I'm looking for is guidance on whether I'm better spending time optimising my calls to DrawImage() or replacing DrawImage(). And no Direct X is not an option. I could go with GAPI which is what most commercial developers seem to be doing, but without a wrapper (which costs considerably) this is going to be quite complicated for what is a simple game.

I should mention that the most tiles likely to be moved in one Animation loop is 5, but I would prefer if my framework could support them all moving if I required it.

CForrester
09-08-2006, 03:59 AM
Hey, I'm not sure how much this would help, but here's a tutorial for wrapping GAPI: http://www.microsoft.com/downloads/details.aspx?familyid=0887887E-8010-4FF5-9833-4499E3328D21&displaylang=en

Cags
09-08-2006, 04:07 AM
Thanks for the suggestion, but there were two reasons I ruled out GAPI, firstly it looked far too complicated, lol. Secondly and more importantly I got the impression it could only be used for full screen applications, wheras I wanted the menu and taskbar to stay present.

CForrester
09-08-2006, 04:09 AM
Well, I can't argue with the complicated bit. ;) But I saw a few screenshots here: http://www.wincesoft.de/html/gapi_for_hpc_s.html of it running with a taskbar and title bar...

Cags
09-08-2006, 04:18 AM
Your right WindowsCE devices at least seem to be able to run 'windowed' applications, I would assume therefore that PocketPC applications can do the same. I obviously mis-interpretted the documentation. Thankfully I've come up with a solution that seems to suit my needs for the time being. It's has a tiny delay at the start of animation on the Pocket PC emulator, but I've found from experience that the emulator is far slower (on my PC at least) than on any real device I've ever used. It has the added bonus of being 1000x simpler that using GAPI. I would love to delve into GAPI properly, but I feel its probably beyond my current understanding to create anything very useful without completely ripping code from the examples on MSDN.

EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum