|
-
Feb 19th, 2010, 07:24 AM
#1
Graphics Speed
First let me say that I am a novice at using graphics. I am writing an implementation of Conway's Game of Life Wiki Ref.. Basically you have a world of cells that can be dead or alive based on the rules given in the reference.
My implementation:
- I use a picturebox to show the state of the world. The image is large enough to hold a world of 269 x 269 with each cell being 3 x 3.
- when the world is created I create a bitmap and graphics(_G) object of the appropriate size
- the bitmap is initially filled to the dead cell color
- To draw individual cells I use
Code:
_G.FillRectangle(Brush, New Rectangle(x * _BlockSize, y * _BlockSize, _BlockSize, _BlockSize))
- The next state of the world is displayed with
Code:
BackGroundBM = theWorld.NextTick() 'NextTick returns the worlds bitmap
PictureBox1.Image = BackGroundBM
- After the initial pass I only draw cells that have changed, and process those that may have changed.
My problem is that the drawing seems slow. Any help is appreciated.
-
Feb 19th, 2010, 07:28 AM
#2
Re: Graphics Speed
Current stats:
With 600 alive cells and 600 changes I am getting around 30 frames per second.
With one of the simplest patterns that has 5 alive cells, and 4 changes I get 40 FPS.
-
Feb 19th, 2010, 08:25 AM
#3
Re: Graphics Speed
I can only theoritize about whether it woud help to speed the process up, but if you draw your black and white cells once you can save the result into an image and then invoke DrawImage instead. DrawImage should be faster for smaller images and other drawing methods should be faster if your image is big
Also - you have a finite number of possible x and y values and possibly - a fixed blocksize. So you can precalculate all possible x * blocksize and y * blocksize and store them into an array - will save you a few ticks. General rule - all that can be calculated beforehands should be thrown over the board (put somewhere else out of the paint event handler).
And what do you have in your BAckGroundBM? If it's just a grid then try drawing actual lines instead - it will be faster than manipulating of so big an image.
Also - if you simply use square cells filled with color you would probably want to join adjacent cellss together into one rectangle or a graphicpath and fill the resulting figure in one pass instead of several (fill operation is the most time consuming one save only the drawing of large bitmaps).
Last edited by cicatrix; Feb 19th, 2010 at 08:42 AM.
-
Feb 19th, 2010, 08:38 AM
#4
Re: Graphics Speed
BackGroundBM is a BitMap.
-
Feb 19th, 2010, 08:43 AM
#5
Re: Graphics Speed
The reason I don't assign directly to the picture box is because I have an auto mode that runs in a Timer Tick event. That looks like
Code:
Do While Not imgReady 'is the image ready?
Thread.Sleep(0) 'no
Loop
'image ready
PictureBox1.Image = BackGroundBM 'get it
imgReady = False 'let the other thread get started
Thread.Sleep(0)
There is another thread that looks like this
Code:
Public Sub BackGrndNextTick()
Do
If Not imgReady Then
BackGroundBM = theWorld.NextTick
imgReady = True
Else
If Timer1.Interval <= 20 Then Thread.Sleep(0) Else Thread.Sleep(Timer1.Interval \ 10)
End If
Loop While RunBKG
End Sub
-
Feb 19th, 2010, 08:48 AM
#6
Re: Graphics Speed
So you're drawing your game state into a bitmap and only then copy your bitmap to the picturebox - along with all 'empty space'. Basically you copy emptiness of your game board thus eating your processor time.
Instead, each 'generation' of your cells should have a state indicating whether the situation has changed or not. Well, probably it is always be so until your colony is degenerated into stable figures. And every time the situation has changed you should invoke the invalidate method and perform the drawing directly in the picturebox without copying empty areas on your game board.
And I repeat - pre-calculate everything.
Instead of using 2 multiplication operations to determine the coordinates of the upper left corner of the grid cell (6;10) you can feed your drawing procedure with pre-calculated values CellCoordsX(6), CellCoordsY(10).
Last edited by cicatrix; Feb 19th, 2010 at 08:53 AM.
-
Feb 19th, 2010, 08:59 AM
#7
Re: Graphics Speed
I use the computation because the block size can change. I only use the FillRectangle when an individual cell changes, so in the best case scenario I posted previously there are only 4 done. With the timer tick interval set to the minimum, which really mean 10-15 ms., I can theoretically draw 100 FPS.
-
Feb 19th, 2010, 09:01 AM
#8
Re: Graphics Speed
Isn't it simplier to re-calculate new coordinates only when the blocksize is actually changed?
-
Feb 19th, 2010, 09:16 AM
#9
Re: Graphics Speed
OK, I pre-computed x,y and there was not a speed improvement noticed.
-
Feb 19th, 2010, 11:43 AM
#10
Re: Graphics Speed
It's a small step, really, can you post your paint code?
-
Feb 19th, 2010, 12:00 PM
#11
Re: Graphics Speed
There is no paint code to speak of. The assignment in the timer tick event I posted is it.
As I said, in the best case scenario I am only executing the fillrectangle code (with pre-computed x,y) 4 times.
-
Feb 19th, 2010, 12:06 PM
#12
Re: Graphics Speed
Oh well, I still think that copying bitmaps like you do is wasting of cpu time.
-
Feb 19th, 2010, 02:18 PM
#13
Re: Graphics Speed
Try this code, it's pretty fast:
vb.net Code:
Public Class Form1 Private pic As PictureBox Private btnStartStop As Button Private Running As Boolean = False Private Const BOARD_WIDTH As Integer = 50 Private Const BOARD_HEIGHT As Integer = 50 Private CellSize As New SizeF Private cells(BOARD_WIDTH - 1, BOARD_HEIGHT - 1) As State Private Rects(BOARD_WIDTH - 1, BOARD_HEIGHT - 1) As RectangleF Private linePen As New Pen(Color.Green) With {.DashStyle = Drawing2D.DashStyle.Dot} Private CellBrush As New SolidBrush(Color.White) Private Enum State Empty = 0 Birth = 1 Alive = 2 Dying = 3 End Enum Public Sub New() InitializeComponent() Me.SuspendLayout() pic = New PictureBox With _ {.BackColor = Color.Black, _ .Left = 120, .Top = 0, .Height = Me.ClientRectangle.Height, .Width = Me.ClientRectangle.Width - 120, _ .Anchor = AnchorStyles.Bottom Or AnchorStyles.Right Or AnchorStyles.Left Or AnchorStyles.Top} btnStartStop = New Button With _ {.Text = "Start", .Width = 100, .Height = Me.Font.Height * 2, .Left = 10, .Top = 10} Me.Controls.AddRange(New Control() {pic, btnStartStop}) Me.AcceptButton = btnStartStop Me.ResumeLayout() End Sub Private Sub Drawing(ByVal sender As Object, ByVal e As PaintEventArgs) Dim x, y As Single Dim ix, iy As Integer For x = 0 To BOARD_WIDTH - 1 For y = 0 To BOARD_HEIGHT - 1 ix = CInt(x) iy = CInt(y) Select Case cells(ix, iy) Case State.Dying cells(ix, iy) = State.Empty Case State.Birth cells(ix, iy) = State.Alive End Select If cells(CInt(x), CInt(y)) = State.Alive Then e.Graphics.FillRectangle(CellBrush, Rects(CInt(x), CInt(y))) Next Next For x = 0 To pic.ClientRectangle.Width - 1 Step CellSize.Width e.Graphics.DrawLine(linePen, x, 0, x, pic.ClientRectangle.Height - 1) Next For y = 0 To pic.ClientRectangle.Height - 1 Step CellSize.Height e.Graphics.DrawLine(linePen, 0, y, pic.ClientRectangle.Width - 1, y) Next End Sub Private Sub StartStop(ByVal sender As Object, ByVal e As EventArgs) Running = Not Running If Running Then btnStartStop.Text = "Stop" RemoveHandler pic.MouseClick, AddressOf UserClick Else btnStartStop.Text = "Start" AddHandler pic.MouseClick, AddressOf UserClick End If If Running Then GoForthAndMultiply() End Sub Private Sub GoForthAndMultiply() Do Application.DoEvents() Generation() pic.Invalidate() If Running = False Then Exit Sub Loop End Sub Private Sub Generation() ' cell dies if it has less than 2 or more than 3 neighbors ' cell is born if it has exactly 3 neighbors Dim x, y As Integer Dim Neighbors As Integer = 0 For x = 0 To BOARD_WIDTH - 1 For y = 0 To BOARD_HEIGHT - 1 If y > 0 AndAlso cells(x, y - 1) >= State.Alive Then Neighbors += 1 If y > 0 AndAlso x < (BOARD_WIDTH - 1) AndAlso cells(x + 1, y - 1) >= State.Alive Then Neighbors += 1 If x < (BOARD_WIDTH - 1) AndAlso cells(x + 1, y) >= State.Alive Then Neighbors += 1 If x < (BOARD_WIDTH - 1) AndAlso y < (BOARD_HEIGHT - 1) AndAlso cells(x + 1, y + 1) >= State.Alive Then Neighbors += 1 If y < (BOARD_HEIGHT - 1) AndAlso cells(x, y + 1) >= State.Alive Then Neighbors += 1 If x > 0 AndAlso y < (BOARD_HEIGHT - 1) AndAlso cells(x - 1, y + 1) >= State.Alive Then Neighbors += 1 If x > 0 AndAlso cells(x - 1, y) >= State.Alive Then Neighbors += 1 If x > 0 AndAlso y > 0 AndAlso cells(x - 1, y - 1) >= State.Alive Then Neighbors += 1 Select Case Neighbors Case 0, 1, Is > 3 If cells(x, y) <> State.Empty Then cells(x, y) = State.Dying Case 3 If cells(x, y) = State.Empty Then cells(x, y) = State.Birth End Select Neighbors = 0 Next Next End Sub Private Sub UserClick(ByVal sender As Object, ByVal e As MouseEventArgs) Dim cell As New Point Dim x, y As Integer x = CInt(Fix((e.X / CellSize.Width))) y = CInt(Fix((e.Y / CellSize.Height))) Select Case cells(x, y) Case State.Alive, State.Dying cells(x, y) = State.Empty Case State.Empty, State.Birth cells(x, y) = State.Alive End Select pic.Invalidate() End Sub Private Sub SetCellSize() Dim w, h As Single w = CSng(pic.ClientRectangle.Width / BOARD_WIDTH) h = CSng(pic.ClientRectangle.Height / BOARD_HEIGHT) Dim x, y As Integer For y = 0 To BOARD_HEIGHT - 1 For x = 0 To BOARD_WIDTH - 1 Rects(x, y) = New RectangleF(x * w, y * h, w, h) Next Next CellSize.Width = w CellSize.Height = h End Sub Private Sub Pic_Resize(ByVal sender As Object, ByVal e As System.EventArgs) SetCellSize() pic.Invalidate() End Sub Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load AddHandler btnStartStop.Click, AddressOf StartStop AddHandler pic.Paint, AddressOf Drawing AddHandler pic.MouseClick, AddressOf UserClick AddHandler pic.Resize, AddressOf Pic_Resize SetCellSize() End Sub End Class
-
Feb 19th, 2010, 03:47 PM
#14
Re: Graphics Speed
With grid lines it run with avg fps =25 in full screen mode, without grid lines it was around 100 frames per second (also in full screen - with default form size the fps was up to 320).
-
Feb 19th, 2010, 03:59 PM
#15
Re: Graphics Speed
the issue is the timer in my opinion. zero execution time would give you a best of 100 frames/sec. You should research a game loop. I was bottlenecking framerates on a simple game as well and when i removed the timer and put a do loop in with getasynckeystate to check for keypresses to exit, my framerate increased by a factor of ten.
as a side note, it's possible to only invalidate the region of the screen that changed instead of the whole thing. Yeah you are only changing certain parts when you paint it, but unless you tell windows otherwise with clip regions, it will still redraw the entire image every time a single part of it changes.
-
Feb 19th, 2010, 04:28 PM
#16
Re: Graphics Speed
 Originally Posted by cicatrix
Try this code, it's pretty fast:
vb.net Code:
Public Class Form1
Private pic As PictureBox
Private btnStartStop As Button
Private Running As Boolean = False
Private Const BOARD_WIDTH As Integer = 50
Private Const BOARD_HEIGHT As Integer = 50
Private CellSize As New SizeF
Private cells(BOARD_WIDTH - 1, BOARD_HEIGHT - 1) As State
Private Rects(BOARD_WIDTH - 1, BOARD_HEIGHT - 1) As RectangleF
Private linePen As New Pen(Color.Green) With {.DashStyle = Drawing2D.DashStyle.Dot}
Private CellBrush As New SolidBrush(Color.White)
Private Enum State
Empty = 0
Birth = 1
Alive = 2
Dying = 3
End Enum
Public Sub New()
InitializeComponent()
Me.SuspendLayout()
pic = New PictureBox With _
{.BackColor = Color.Black, _
.Left = 120, .Top = 0, .Height = Me.ClientRectangle.Height, .Width = Me.ClientRectangle.Width - 120, _
.Anchor = AnchorStyles.Bottom Or AnchorStyles.Right Or AnchorStyles.Left Or AnchorStyles.Top}
btnStartStop = New Button With _
{.Text = "Start", .Width = 100, .Height = Me.Font.Height * 2, .Left = 10, .Top = 10}
Me.Controls.AddRange(New Control() {pic, btnStartStop})
Me.AcceptButton = btnStartStop
Me.ResumeLayout()
End Sub
Private Sub Drawing(ByVal sender As Object, ByVal e As PaintEventArgs)
Dim x, y As Single
Dim ix, iy As Integer
For x = 0 To BOARD_WIDTH - 1
For y = 0 To BOARD_HEIGHT - 1
ix = CInt(x)
iy = CInt(y)
Select Case cells(ix, iy)
Case State.Dying
cells(ix, iy) = State.Empty
Case State.Birth
cells(ix, iy) = State.Alive
End Select
If cells(CInt(x), CInt(y)) = State.Alive Then e.Graphics.FillRectangle(CellBrush, Rects(CInt(x), CInt(y)))
Next
Next
For x = 0 To pic.ClientRectangle.Width - 1 Step CellSize.Width
e.Graphics.DrawLine(linePen, x, 0, x, pic.ClientRectangle.Height - 1)
Next
For y = 0 To pic.ClientRectangle.Height - 1 Step CellSize.Height
e.Graphics.DrawLine(linePen, 0, y, pic.ClientRectangle.Width - 1, y)
Next
End Sub
Private Sub StartStop(ByVal sender As Object, ByVal e As EventArgs)
Running = Not Running
If Running Then
btnStartStop.Text = "Stop"
RemoveHandler pic.MouseClick, AddressOf UserClick
Else
btnStartStop.Text = "Start"
AddHandler pic.MouseClick, AddressOf UserClick
End If
If Running Then GoForthAndMultiply()
End Sub
Private Sub GoForthAndMultiply()
Do
Application.DoEvents()
Generation()
pic.Invalidate()
If Running = False Then Exit Sub
Loop
End Sub
Private Sub Generation()
' cell dies if it has less than 2 or more than 3 neighbors
' cell is born if it has exactly 3 neighbors
Dim x, y As Integer
Dim Neighbors As Integer = 0
For x = 0 To BOARD_WIDTH - 1
For y = 0 To BOARD_HEIGHT - 1
If y > 0 AndAlso cells(x, y - 1) >= State.Alive Then Neighbors += 1
If y > 0 AndAlso x < (BOARD_WIDTH - 1) AndAlso cells(x + 1, y - 1) >= State.Alive Then Neighbors += 1
If x < (BOARD_WIDTH - 1) AndAlso cells(x + 1, y) >= State.Alive Then Neighbors += 1
If x < (BOARD_WIDTH - 1) AndAlso y < (BOARD_HEIGHT - 1) AndAlso cells(x + 1, y + 1) >= State.Alive Then Neighbors += 1
If y < (BOARD_HEIGHT - 1) AndAlso cells(x, y + 1) >= State.Alive Then Neighbors += 1
If x > 0 AndAlso y < (BOARD_HEIGHT - 1) AndAlso cells(x - 1, y + 1) >= State.Alive Then Neighbors += 1
If x > 0 AndAlso cells(x - 1, y) >= State.Alive Then Neighbors += 1
If x > 0 AndAlso y > 0 AndAlso cells(x - 1, y - 1) >= State.Alive Then Neighbors += 1
Select Case Neighbors
Case 0, 1, Is > 3
If cells(x, y) <> State.Empty Then cells(x, y) = State.Dying
Case 3
If cells(x, y) = State.Empty Then cells(x, y) = State.Birth
End Select
Neighbors = 0
Next
Next
End Sub
Private Sub UserClick(ByVal sender As Object, ByVal e As MouseEventArgs)
Dim cell As New Point
Dim x, y As Integer
x = CInt(Fix((e.X / CellSize.Width)))
y = CInt(Fix((e.Y / CellSize.Height)))
Select Case cells(x, y)
Case State.Alive, State.Dying
cells(x, y) = State.Empty
Case State.Empty, State.Birth
cells(x, y) = State.Alive
End Select
pic.Invalidate()
End Sub
Private Sub SetCellSize()
Dim w, h As Single
w = CSng(pic.ClientRectangle.Width / BOARD_WIDTH)
h = CSng(pic.ClientRectangle.Height / BOARD_HEIGHT)
Dim x, y As Integer
For y = 0 To BOARD_HEIGHT - 1
For x = 0 To BOARD_WIDTH - 1
Rects(x, y) = New RectangleF(x * w, y * h, w, h)
Next
Next
CellSize.Width = w
CellSize.Height = h
End Sub
Private Sub Pic_Resize(ByVal sender As Object, ByVal e As System.EventArgs)
SetCellSize()
pic.Invalidate()
End Sub
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
AddHandler btnStartStop.Click, AddressOf StartStop
AddHandler pic.Paint, AddressOf Drawing
AddHandler pic.MouseClick, AddressOf UserClick
AddHandler pic.Resize, AddressOf Pic_Resize
SetCellSize()
End Sub
End Class
How does it do with a height / width of 269 and a cell of 3 x 3? How many frames per second?
-
Feb 19th, 2010, 04:31 PM
#17
Re: Graphics Speed
If I comment this
Code:
PictureBox1.Image = BackGroundBM
out of the timer it runs at 100 FPS.
-
Feb 19th, 2010, 05:54 PM
#18
Re: Graphics Speed
I think that the actual drawing code takes negligible time to execute. It's the actual drawing (done by windows I guess) that takes so much time.
If you don't set the picturebox image, then the drawing code is executed, but it is never actually drawn so you are only seeing a very minor delay. As soon as you set the image of the picturebox however, it needs to be drawn, and this is what takes so much time.
That's why, when calling Invalidate, you should always try to minimize the region that is invalidated. You can do that by passing a rectangle, or Region, or possibly other structures, to the Invalidate function. Then, only that region is painted, and of course it takes less time to draw a small region.
I've wondered about this before, but I guess it makes sense. If you have some drawing code (in a Paint event), then that code is executed entirely every time the paint event is called. But that doesn't mean that all of it is actually drawn to the screen. If you call Invalidate with only a tiny rectangle, then only that rectangle is repainted (even though the entire Paint code is executed). This takes much less time than painting the entire thing in one go.
If you look at my game of life example, you'll notice the same behavior. If you choose a large grid size (say 150x150) then it takes quite a lot of time to draw the grid initially (try loading a file of 150x150 for example). But when you run the simulation, the cells are drawn virtually at constant speed (10 times per second because the timer is at 100 ms interval). This is because I am only invalidating the areas on the grid that actually change (eg: the bounds of the cells that change). If I had it repaint the entire grid every 'tick', it would run extremely slow.
-
Feb 19th, 2010, 06:02 PM
#19
Re: Graphics Speed
Here is a pattern that should start small and fill up the screen.
Code:
#Life 1.05
#D Small spacefiller drawn by spaceships.
#D A 187 point rotationally symmetric spacefiller with
#D flipper stretchers in place of the normally period
#D 2 stretchers. The pattern on the interior of this
#D spacefiller is forced by the stabilization requirements.
#D This spacefiller also exists in a vertically reflected
#D symmetric form that also has 187 points. By Tim Coe.
#N
#P -17 -12
.............***...***
............*..*...*..*
...............*...*
...............*...*
.*.............*...*
*............................******
*.....*......***...***......*.....*
******........*..*..*.............*
........*.....*.***.**.....*.....*
........*....*............*.*
....****....********.**.**
...*****........*..*...*.*....**
..**.***...****..*..****...***.**
...**....*.*...*..*........*****
.........**.**.********....****
......*.*............*....*
.*.....*.....**.***.*.....*
*.............*..*..*........******
*.....*......***...***......*.....*
******............................*
...............*...*.............*
...............*...*
...............*...*
............*..*...*..*
.............***...***
With a 273 x 273 grid, cell dimension of 3 x 3, how well does your method run?
-
Feb 19th, 2010, 06:07 PM
#20
Re: Graphics Speed
With this pattern
at the same dimensions I am getting between 35-40 FPS.
-
Feb 19th, 2010, 06:10 PM
#21
Re: Graphics Speed
 Originally Posted by dbasnett
How does it do with a height / width of 269 and a cell of 3 x 3? How many frames per second?
Around 28 FPS (without grid)
-
Feb 19th, 2010, 06:11 PM
#22
Re: Graphics Speed
My simulator can't read those files. I am saving simply text files with 0 for dead and 1 for alive cells. A 273x273 grid is quite large though, I think it will be slow.
Also, mine doesn't try to go as fast as possible. I'm just using a timer set at 100 ms interval which calculates the new grid every tick. I just tried a grid of 273x273 with 3x3 cells and it sure didn't run at 100 ms interval though. More like twice per second which would be 500 ms, so there's a large delay.
I wasn't saying my simulator was faster than yours (I didn't try yours yet), I am merely saying that painting just the changed cells will be hell of a lot faster than painting the entire grid.
Just for the fun of it I tried it again (273x273) without painting just the changed cells. This time, I am painting the whole grid each timer tick. It takes about 5 seconds to draw the new grid where it should run at 0.1 seconds.
-
Feb 19th, 2010, 06:13 PM
#23
Re: Graphics Speed
 Originally Posted by cicatrix
Around 28 FPS (without grid)
Which pattern?
-
Feb 19th, 2010, 06:18 PM
#24
Re: Graphics Speed
 Originally Posted by NickThissen
My simulator can't read those files. I am saving simply text files with 0 for dead and 1 for alive cells. A 273x273 grid is quite large though, I think it will be slow.
Also, mine doesn't try to go as fast as possible. I'm just using a timer set at 100 ms interval which calculates the new grid every tick. I just tried a grid of 273x273 with 3x3 cells and it sure didn't run at 100 ms interval though. More like twice per second which would be 500 ms, so there's a large delay.
I wasn't saying my simulator was faster than yours (I didn't try yours yet), I am merely saying that painting just the changed cells will be hell of a lot faster than painting the entire grid.
Just for the fun of it I tried it again (273x273) without painting just the changed cells. This time, I am painting the whole grid each timer tick. It takes about 5 seconds to draw the new grid where it should run at 0.1 seconds.
I have some code that stores x,y,DeadAlive in a list of just the cells that changed. When I added code to pull the data from the list and just draw those cells in the paint event, the speed was about the same.
Code:
For z = 0 To lDP.Count - 1
If lDP(z).OnOff Then
e.FillRectangle(_OBrush, lDP(z).X, lDP(z).Y, _BlockSize, _BlockSize)
Else
e.FillRectangle(_NOBrush, lDP(z).X, lDP(z).Y, _BlockSize, _BlockSize)
End If
Next
-
Feb 19th, 2010, 06:31 PM
#25
Re: Graphics Speed
But that is besides the point. You may be calling FillRectangle only on the changed cells, but if you call Invalidate (without specifying a region), or setting the Image of the picturebox, the whole image will be painted regardless.
If you have some code in your paint event that simply paints the backcolor of the picturebox with a random color each time. Then when you call Invalidate without parameters, the whole picturebox will be painted in a random color. If you call Invalidate with a small rectangle though, then only that rectangle will get a new (random) color. The rest stays the old color, because it is never repainted. It will eventually get repainted (when the window is repainted, when you drag something over it, when you resize it, etc), but that is outside of your control.
The point is that calling Invalidate without a rectangle (letting it paint the entire picturebox) takes longer than calling it with a rectangle (letting it paint only the specified rectangle), even if the paint code is the same (just a single call to FillRectangle). Of course, with this random color example you won't notice the difference unless the form is huge, but still.
-
Feb 19th, 2010, 06:39 PM
#26
Re: Graphics Speed
 Originally Posted by dbasnett
Which pattern?
Just some random clicks (pretty many of clicks in order to get a lively population).
I used 300x300 board and the dots were very small - even on full screen. I experimented with the board size and I think that 50x50 is probably an optimum dimensions. Well, maybe 100x100 will do, but is it really necessary?
Tell me, why use timers at all? In a graphics app where you use FPS to measure performance?
Mine just enters the loop and redraws as soon a life cycle is completed - the sooner the better. Every frame is a new generation or I don't have to redraw the screen do I? Look at how DirectX works - it just refreshes the presentation in a loop - no timers.
Last edited by cicatrix; Feb 19th, 2010 at 06:45 PM.
-
Feb 20th, 2010, 01:23 PM
#27
Re: Graphics Speed
 Originally Posted by cicatrix
Just some random clicks (pretty many of clicks in order to get a lively population).
I used 300x300 board and the dots were very small - even on full screen. I experimented with the board size and I think that 50x50 is probably an optimum dimensions. Well, maybe 100x100 will do, but is it really necessary?
Tell me, why use timers at all? In a graphics app where you use FPS to measure performance?
Mine just enters the loop and redraws as soon a life cycle is completed - the sooner the better. Every frame is a new generation or I don't have to redraw the screen do I? Look at how DirectX works - it just refreshes the presentation in a loop - no timers.
There are a lot of existing patterns, and a fair number of them want a world of a large size.
When I started with the timer business it was simply to advance to the next cycle once per second automatically, and then, being a manly man and all, it progressed to how fast. Of course the underlying premise of a life every controlled period remains.
After messing with this for hours I have discovered that when the number of changes in a cycle is small, drawing the individual cells is faster than re-drawing the entire world. In my case that number is 500-600. So what I did is to make a decision based on frame rate. I draw the individual cells until the rate drops below 30 FPS. When less than 30 FPS I draw the entire world. I am still playing with it, but will post soon.
So with this pattern (which I posted earlier)
I am now able to run it at 100 FPS, which is the max using a timer.
Last edited by dbasnett; Feb 20th, 2010 at 01:42 PM.
-
Feb 21st, 2010, 08:24 AM
#28
Re: Graphics Speed
Latest in my quest to better understand this.
The code that only drew the cells that changed was invalidating that rectangle as soon as it was drawn. I added another rectangle and made it the union of itself and the rectangle just drawn.
After all of the cells have been drawn I now invalidate the union.
Code:
'accumulate all Rect and when finished invalidate
If Not RUnions.IsEmpty Then RUnions = Rectangle.Union(RUnions, Rect) Else RUnions = Rect
Next
PictureBox1.Invalidate(RUnions) 'draw them
I tried doing the same thing with regions, but it seemed slower.
-
Feb 21st, 2010, 08:39 AM
#29
Re: Graphics Speed
If my understanding of Invalidate is correct, then you shouldn't need to do that.
For one, suppose only the top-left cell and the bottom-right cell have changed. Then, the union of those two cells is the entire grid, so you are still painting the entire grid! I'm not sure if regions have that problem too (I don't think so, I think a region can have two disconnected rectangles, right?) so I would think it would be faster with regions (although regions might be slower for a different reason).
But more importantly, as far as I understand it, Invalidate will not immediately repaint the picturebox. It will merely place the region to invalidate in some sort of queue. If you call Invalidate successively in a quick loop, then it will place all those regions in the queue, and once you call Update (or if you wait a little while for the paint message to get through), all those invalidated regions will be repainted in one go.
So, calling invalidate once with the total rectangle, or calling it 10000 times with a small part of that rectangle each time should not make a difference, at least not in painting time. Only when you call Update does the control paint all its invalidated regions.
So, what you are doing now (placing each rectangle to invalidate in a union of rectangles) is more or less what the framework already provides for you, except that a union of all rectangles isn't a very good way to form the 'queue' of areas to paint.
-
Feb 21st, 2010, 08:54 AM
#30
Re: Graphics Speed
Believe me I am over my head here. I believe what you said, and that is what I think also. I am not certain why it is faster for that reason, but it is.
Like I said in my first post, I am a novice at graphics, and still am because the results don't make sense to me.
-
Feb 21st, 2010, 02:39 PM
#31
Re: Graphics Speed
GDI+ has its limitations. For fastest performance you should use DirectX.
-
Feb 23rd, 2010, 04:10 PM
#32
Re: Graphics Speed
Well, the entire project, with about 130 patterns, is here.
http://www.vbforums.com/showthread.php?t=603846
@nick /cica - thanks for your input.
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|