Re: Drawing thread not getting enough time from scheduler?

Alex F. wrote:

doesn’t work at all if thread.join is called, but runs
pretty smoothly (about 8s total) otherwise. At some level
you’ll also be caught by the granularity of Ruby’s thread
time slices (10ms IIRC), and garbage collection, which is
taking up to 9ms tracking wxRuby objects alone in your
example.

OK, so avoid excessive object creation… Oh, yes, and I forgot
(again) to mention I’m on Windows, as are my main target users.
Interesting that the thread handling seems to be so much better on
OSX.

I see a couple of further potential optimisations in your
code which improve smoothness for me:

  • Take the calls to surface.pen= and surface.pen.cap= out
    of the 30.times loop.
  • See whether the drawing could be more efficiently done
    with a single draw_polygon (which acccepts an Array of
    Wx::Points)

It only happens to look like a polygon - my actual game needs to draw
individual lines (in varying colors and line widths). But that’s OK,
because your below suggestion allowed me to draw everything at decent
speed…

Another untested possibility to improve perceived
smoothness might be to drive the animation from a
Wx::Timer. Have it run at regular intervals, calling
window.refresh to invalidate the window, then copy from the
bitmap inside an evt_paint handler.

This was the key. It’s drawing 300 lines in under 33 milliseconds
now, even on my laptop. The close button and window dragging respond
immediately.

require ‘rubygems’
require ‘wx’

class MyApp < Wx::App

def on_init

  #Containing frame.
  frame = Wx::Frame.new(nil, :size => [300, 300])
  frame.show

  #Offscreen drawing buffer.
  buffer = Wx::Bitmap.new(300, 300)

  #Displays drawing.
  window = Wx::Window.new(frame, :size => [300, 300])
  window.evt_paint do |event|
    update_window(window, buffer)
  end

  #Initialize drawing loop counter.
  @i = 0

  #Animate periodically.
  timer_id = Wx::ID_HIGHEST + 1
  t = Wx::Timer.new(self, timer_id)
  evt_timer(timer_id) {animate(window, buffer)}
  t.start(33)

end

def animate(window, buffer)
  green_pen = Wx::Pen.new(Wx::Colour.new(128, 255, 128), 3)
  black_pen = Wx::Pen.new(Wx::Colour.new(0, 0, 0), 0)
  buffer.draw do |surface|
    #Clear screen.
    surface.pen = black_pen
    surface.brush = Wx::BLACK_BRUSH
    surface.draw_rectangle(0, 0, 300, 300)
    #Draw lines.
    surface.pen = green_pen
    surface.pen.cap = Wx::CAP_ROUND
    300.times do |j|
      x = @i + j
      surface.draw_line(x, 0, x+100, 100)
    end
  end
  #Update screen.
  update_window(window, buffer)
  @i += 1
  @i = 0 if @i > 300
end

def update_window(window, buffer)
  window.paint do |dc|
    #Copy the buffer to the viewable window.
    dc.draw_bitmap(buffer, 0, 0, false)
  end
end

end

app = MyApp.new
app.main_loop

Now to see if I can get similar results from the game itself. Thanks
to everyone for the assistance!

-Jay McGavren
http://jay.mcgavren.com/zyps