faster image drawing?
faster image drawing?
faster image drawing?
faster image drawing?
faster image drawing?
faster image drawing? faster image drawing? faster image drawing? faster image drawing? faster image drawing? faster image drawing? faster image drawing? faster image drawing?
faster image drawing? faster image drawing?
faster image drawing?
Go Back  Xtreme Visual Basic Talk > > > faster image drawing?


Reply
 
Thread Tools Display Modes
  #1  
Old 08-12-2011, 02:11 PM
Lestes Lestes is offline
Newcomer
 
Join Date: Aug 2011
Posts: 2
Question faster image drawing?


New here, so hello!

Anyho:
I'm writing a game in VB 2005 Express and at the moment it involves using the drawimage method to first draw a background and then various sprites onto my form every time a timer ticks. It's all double buffered so there's no flicker or anything but it just goes very slowly, so can someone please tell me, basically, how to speed it up.

I've come across the term blitting (bitblt), which seems like it would be useful, but haven't been able to work out exactly what it is, whether it can be used in this version of vb, how to use it etc.

Thanks

PS. Here's my code (or at least an approximation of the relevant bits seeing as the whole thing is rather long):

Public Class Form1
Dim BackgroundImg as Image 'plus all of my sprite images declared
Dim Mybuffer As BufferedGraphics
Dim MyContext As BufferedGraphicsContext

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

mycontext = BufferedGraphicsManager.Current
Mybuffer = mycontext.Allocate(Me.CreateGraphics, Me.DisplayRectangle)

BackgroundImg = My.Resources.backgroundimg
'plus for all of the sprites


'other stuff in here

Timer1.Interval() = 20

End Sub

Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

'calculations etc.

Mybuffer.Graphics.DrawImage(BackgroundImg,position, size)

Mybuffer.Graphics.DrawImage(sprite images,position, size)

'some of the sprites have containers to allow rotation of that sprite:

GContainer = Mybuffer.Graphics.BeginContainer()
Mybuffer.Graphics.RotateTransform(some angle)
Mybuffer.Graphics.DrawImage(sprite images,position, size)
Mybuffer.Graphics.EndContainer(GContainer)

Mybuffer.render

End Sub

'loads of other subs here

End Class
Reply With Quote
  #2  
Old 08-12-2011, 02:29 PM
passel's Avatar
passelfaster image drawing? passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 8,028
Default

BitBlt in Windows Forms would involve using the older GDI programming interface, which would require a few hoops compared to what you're doing currently in VB.net.
I've had mixed results using a TextureBrush to paint a filled rectangle in place of DrawImage.
In my first test case, found here, the test seem to indicate that using TextureBrush vs DrawImage, the drawing speed was around 50 times faster.
But in one case, where I took someones game, who had just gotten started, and converted it to use TextureBrush instead of DrawImage, it only made a few frames per second difference. Not much increase at all.
I haven't had to time to sit down and do further investigation to see in what instances does one method have a decided advantage over another.

The test case referenced above is probably in VS2008 or VS2010. You can probably create a new VB2005 project and replace some of the files with the ones from the examples and get it to work.
I do still have VS2005 on my work machine, so could probably convert it back if you have trouble (or you could install VS2008 and/or VB2010 express).
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
Reply With Quote
  #3  
Old 08-12-2011, 03:34 PM
Lestes Lestes is offline
Newcomer
 
Join Date: Aug 2011
Posts: 2
Default

Oh wow! That is a lot faster.
Thank you.
Reply With Quote
  #4  
Old 08-22-2011, 04:10 PM
passel's Avatar
passelfaster image drawing? passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 8,028
Default

FYI.
Be aware that I've found the reason for the difference in performance for the two cases of using DrawImage.
In the Spinning Red Car demo, the DrawImage line is transferring a rectanglar area of pixels from the source sprite sheet to the destination, like so:
gameGraphic.DrawImage(spriteSheet, dstRect, srcRect, GraphicsUnit.Pixel)

This format can stretch or shrink a picture if the dstRect and srcRect were different sizes.
Having the possibility of this occuring, slows the code down quite a bit.
There is another method, DrawImageUnscaled, which would be nice to be able to use in this situation, since we don't want to resize the image, but DrawImageUnscaled won't allow you to pass a source rectangle, so can't be used to select an area from a sprite sheet.

If you had individual bitmaps, (and what I did is copied the sprites from the spritesheet during Form_Load, into a two dimensional array of bitmaps, named "carBmps") then you could use either DrawImageUnscaled like this:
gameGraphic.DrawImageUnscaled(carBmps(FrameSelectY, FrameSelectX), dstRect.X, dstRect.Y)
or similiarly, DrawImage:
gameGraphic.DrawImage(carBmps(FrameSelectY, FrameSelectX), dstRect.X, dstRect.Y)

Using DrawImage without the source rectangle sped DrawImage up in the neighborhood of 40 times faster on the machine I was using.
It didn't make any noticeable difference whether DrawImage, or DrawImageUnscaled was used. With the parameters above, they are probably executing the same code under the hood.

As part of this investigation, I determined that the update from backbuffer to screen was taking a significant chunk of time on this machine.
The method used in the test is to write to a bitmap which the picturebox's .Image object is referencing.
Thus when you do a Refresh on the picturebox, the control will automatically refresh the screen from its Image object.
On this machine, it took 8-10 ms to update the screen from the image (and this isn't full screen, so a bigger window takes even more time), so was chewing up more than 50% of 15.625 ms we had available to run at our max 64hz.
To maintain 64hz, our drawing would have to take 5ms or less.

So, how can we get the backbuffer written to the screen quicker.
I tried several things.
Create a brush from the backbuffer and paint a big filled rectangle with it. Slower.
Create a GDI BitBlt compatible bitmap of the backbuffer and use bitblt. Slower.
Don't associate the bitmap with the Picturebox's Image, but instead use the more traditional
e.Graphics.DrawImage(gameDisplay,0,0)
in the Paint event.
This was actually the same speed as having the control refresh itself from the backbuffer, so between the two, it would probably be better and more acceptable to do the DrawImage in the Paint Event, as it is more in line with the expected .Net practice.

So, I couldn't find a faster method, with the current way the backbuffer was done.
I then decided to look into using the .Net provided class for BackBuffering (the BufferedGraphics class) to see if it using it could cut down on the time to refresh the screen from the BackBuffer.

So, I changed the gameDisplay variable from being a Bitmap to being a BufferedGraphicsContext
' Dim gameDisplay As Bitmap
Dim gameDisplay as BufferedGraphicsContext

Changed gameGraphic
' Dim gameGraphic as Graphics
to
Dim gameGraphic as BufferedGraphics

Changed the initialization of gameDisplay and gameGraphic to fit their new purpose
' gameDisplay = New Bitmap(PictureBox1.ClientSize.Width, PictureBox1.ClientSize.Height) 'our backbuffer
' gameGraphic = Graphics.FromImage(gameDisplay) 'our Graphics object to access the backbuffer
to
gameDisplay = BufferedGraphicsManager.Current
gameGraphic = gameDisplay.Allocate(PictureBox1.CreateGraphics, PictureBox1.DisplayRectangle)

Now everyplace that used to draw into our backbuffer, was changed to draw into the BufferedGraphics (changed "gameGraphic" to "gameGraphic.Graphics". Some examples:

' gameGraphic.Clear(Color.LightGreen)
to
gameGraphic.Graphics.Clear(Color.LightGreen)
' gameGraphic.Graphics.DrawImage(carBmps(FrameSelectY, FrameSelectX), dstRect.X, dstRect.Y)
to
gameGraphic.Graphics.DrawImageUnscaled(carBmps(FrameSelectY, FrameSelectX), dstRect.X, dstRect.Y)

And lastly, in the PictureBox1.Paint event, rendered the BufferedGraphics into the picturebox:
gameGraphic.Render(e.Graphics)

Well, the good news is that is cut down on the time to get graphics from backbuffer to screen significantly.
On this machine, the refresh now only takes 2-3 ms, vs the 8-10 it was taking before.
The total frame rate, with the drawing of the 225 cars increased around 50%.

Another plus, in the eyes of the .Net purist, is that while the GDI bitblt also increased in speed, it didn't increase as much as the .DrawImage and TextureBrush methods did.
So, the .DrawImage (using single bitmaps) is now pretty much on par with the BitBlt, and the TextureBrush is almost 10% faster than either of those methods.

So, Yay!!!, you don't have to resort to unmanaged GDI bitblt to get fast updates.
Using TextureBrush and the BufferedGraphics class will beat even bitblt in Windows Forms.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.

Last edited by passel; 08-22-2011 at 04:18 PM.
Reply With Quote
  #5  
Old 08-22-2011, 05:37 PM
snarfblam's Avatar
snarfblamfaster image drawing? snarfblam is offline
Senior Contributor

Forum Leader
* Expert *
 
Join Date: Apr 2005
Location: USA
Posts: 896
Default

Quote:
Originally Posted by passel View Post
There is another method, DrawImageUnscaled, which would be nice to be able to use in this situation, since we don't want to resize the image, but DrawImageUnscaled won't allow you to pass a source rectangle, so can't be used to select an area from a sprite sheet.
Just an FYI: DrawImageUnscaled is very misleading. It tries to draw the image at the correct physical size, taking into account the image's DPI information and the monitor's DPI, and scaling the pixels to produce a correctly sized result.

The texture brush is an interesting trick to work around scaling issues. I'll need to keep that in mind!
__________________
C# _VB.NET _
Reply With Quote
  #6  
Old 08-23-2011, 08:13 AM
OnErr0r's Avatar
OnErr0rfaster image drawing? OnErr0r is offline
Obsessive OPtimizer

Administrator
* Guru *
 
Join Date: Jun 2002
Location: Debug Window
Posts: 13,774
Default

I like the TextureBrush trick too. However, unmanaged BitBlt is still being called by BufferedGraphics.Render.
__________________
Quis custodiet ipsos custodues.
Reply With Quote
  #7  
Old 08-23-2011, 09:42 AM
passel's Avatar
passelfaster image drawing? passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 8,028
Default

I guess being new to this the distinction between managed and unmanaged code, and the impact of a .NET programmer using classes provided by the .NET framework that use unmanaged API calls “under the hood”, is unclear.

My impression was that if you used a managed language, like VB.net , and used classes provided in the .NET framework, then the code was considered managed code, regardless of whether the class itself wrapped calls to unmanaged Windows APIs. It would be up to the class to “manage” the unmanaged resources, so would still be managed code from the users perspective.

In my case, I didn’t mean to imply how the .Render method worked, or that it didn’t use bitblt.
It was that the user didn’t have to bypass the .Net Framework in order to get speed comparable to using bitblt themselves.

If the .Render method is one example of the .NET framework wrapping a use of bitblt, I would have appreciated if the .NET framework had wrapped a little more of bitblt’s functionality in other methods, because I have some VB6 code that took advantage of some ROPs for more than masking, and I don’t know how to implement the same functionality in VB.net without resorting to using unmanaged bitblt calls directly.
I don’t know if having the capability to use unmanaged code to do things not available or easily done in the .NET Framework is what is "obviously" expected by the architects at Microsoft.

And I thought about clarifying that the case where this is faster than using bitblt, on this machine, for the purpose of drawing the cars, actually involves two bitblts. If we were drawing background tiles that didn’t need transparency, thus only needed one bitblt, that would still be the quickest way to tile the initial background layer, most likely, so there could still be a use for mixed mode drawing at the casual game programmer’s level (I say casual, because using windows forms drawing for doing games is not ideal).
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
faster image drawing?
faster image drawing?
faster image drawing? faster image drawing?
faster image drawing?
faster image drawing?
faster image drawing? faster image drawing? faster image drawing? faster image drawing? faster image drawing? faster image drawing? faster image drawing?
faster image drawing?
faster image drawing?
 
faster image drawing?
faster image drawing?
 
-->