ruby-processing 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/CHANGELOG +12 -0
  2. data/README +3 -0
  3. data/lib/core/core.jar +0 -0
  4. data/lib/core/jruby-complete.jar +0 -0
  5. data/lib/patches/JRubyApplet.diff +24 -0
  6. data/lib/patches/PATCHES.txt +3 -0
  7. data/lib/patches/PApplet.diff +27 -0
  8. data/lib/ruby-processing.rb +4 -1
  9. data/lib/ruby-processing/app.rb +121 -75
  10. data/lib/ruby-processing/exporters/applet_exporter.rb +1 -1
  11. data/lib/ruby-processing/exporters/base_exporter.rb +21 -16
  12. data/lib/ruby-processing/exporters/creator.rb +12 -6
  13. data/lib/ruby-processing/runner.rb +2 -2
  14. data/lib/ruby-processing/runners/base.rb +59 -0
  15. data/lib/ruby-processing/runners/live.rb +2 -2
  16. data/lib/ruby-processing/runners/run.rb +2 -1
  17. data/lib/ruby-processing/runners/watch.rb +47 -11
  18. data/lib/templates/applet/index.html.erb +6 -6
  19. data/lib/templates/create/bare_sketch.rb.erb +7 -0
  20. data/lib/templates/create/blank_sketch.rb.erb +2 -2
  21. data/library/control_panel/control_panel.rb +6 -2
  22. data/library/opengl/library/export.txt +0 -0
  23. data/library/opengl/library/opengl.jar +0 -0
  24. data/library/pdf/library/itext.jar +0 -0
  25. data/library/pdf/library/pdf.jar +0 -0
  26. data/library/pdf/notes.txt +3 -4
  27. data/samples/animator.rb +35 -39
  28. data/samples/bezier_playground.rb +2 -4
  29. data/samples/fern.rb +34 -42
  30. data/samples/flight_patterns.rb +48 -54
  31. data/samples/full_screen.rb +20 -25
  32. data/samples/getting_started.rb +19 -39
  33. data/samples/learning_processing/chapter_01/1_stroke_and_fill.rb +14 -30
  34. data/samples/learning_processing/chapter_01/2_nofill.rb +18 -23
  35. data/samples/learning_processing/chapter_01/3_rgb_color.rb +16 -28
  36. data/samples/learning_processing/chapter_01/4_alpha_transparency.rb +7 -1
  37. data/samples/learning_processing/chapter_01/5_zoog.rb +20 -33
  38. data/samples/learning_processing/chapter_02/1_zoog_again.rb +3 -1
  39. data/samples/learning_processing/chapter_03/6_interactive_zoog.rb +34 -42
  40. data/samples/learning_processing/chapter_16/03_adjust_video_brightness.rb +49 -0
  41. data/samples/learning_processing/chapter_17/01_simple_displaying_text.rb +14 -0
  42. data/samples/learning_processing/chapter_17/02_text_align.rb +21 -0
  43. data/samples/learning_processing/chapter_17/03_scrolling_headlines.rb +35 -0
  44. data/samples/learning_processing/chapter_17/04_text_mirror.rb +68 -0
  45. data/samples/learning_processing/chapter_17/05_rotating_text.rb +22 -0
  46. data/samples/learning_processing/chapter_17/06_text_breaking_up.rb +73 -0
  47. data/samples/learning_processing/chapter_17/07_boxes_along_a_curve.rb +49 -0
  48. data/samples/learning_processing/chapter_17/08_characters_along_a_curve.rb +51 -0
  49. data/samples/learning_processing/chapter_17/data/ArialMT-16.vlw +0 -0
  50. data/samples/learning_processing/chapter_17/data/Courier-Bold-20.vlw +0 -0
  51. data/samples/learning_processing/chapter_18/01_user_input.rb +39 -0
  52. data/samples/learning_processing/chapter_18/02_graphing_comma_separated_numbers_from_a_text_file.rb +28 -0
  53. data/samples/learning_processing/chapter_18/03_creating_object_from_a_text_file.rb +64 -0
  54. data/samples/learning_processing/chapter_18/data/data-1.txt +1 -0
  55. data/samples/learning_processing/chapter_18/data/data-2.txt +10 -0
  56. data/samples/orbit.rb +45 -0
  57. data/samples/processing_app/basics/image/pointillism.rb +1 -1
  58. data/samples/processing_app/topics/effects/lens.rb +1 -0
  59. metadata +30 -13
  60. data/library/opengl/bin/processing/opengl/PGraphicsOpenGL$ImageCache.class +0 -0
  61. data/library/opengl/bin/processing/opengl/PGraphicsOpenGL$TessCallback.class +0 -0
  62. data/library/opengl/bin/processing/opengl/PGraphicsOpenGL.class +0 -0
  63. data/library/pdf/bin/processing/pdf/PGraphicsPDF.class +0 -0
@@ -61,7 +61,7 @@ module Processing
61
61
 
62
62
  def calculate_substitutions
63
63
  file_list = Dir.glob(@dest + "{/**/*.{rb,jar},/data/*.*}").map {|f| f.sub(@dest+"/","")}
64
- @width_plus_14 = (@width.to_i + 14).to_s
64
+ @width = @width.to_i
65
65
  @file_list = file_list.join(",")
66
66
  end
67
67
 
@@ -8,12 +8,12 @@ module Processing
8
8
  class BaseExporter
9
9
  include FileUtils
10
10
 
11
- DEFAULT_TITLE = "Ruby-Processing Sketch"
12
- DEFAULT_DIMENSIONS = {'width' => '500', 'height' => '500'}
11
+ DEFAULT_DIMENSIONS = {'width' => '200', 'height' => '200'}
13
12
  DEFAULT_DESCRIPTION = ''
14
13
 
15
14
  # Returns the filepath, basename, and directory name of the sketch.
16
15
  def get_main_file(file)
16
+ @file = file
17
17
  return file, File.basename(file), File.dirname(file)
18
18
  end
19
19
 
@@ -37,40 +37,45 @@ module Processing
37
37
  # Searches the source for a class name.
38
38
  def extract_class_name(source)
39
39
  match = source.match(/(\w+)\s*<\s*Processing::App/)
40
- match ? match[1] : nil
40
+ match ? match[1] : 'Sketch'
41
41
  end
42
42
 
43
43
  # Searches the source for a title.
44
44
  def extract_title(source)
45
45
  match = source.match(/#{@info[:class_name]}\.new.*?:title\s=>\s["'](.+)["']/m)
46
- match ? match[1] : DEFAULT_TITLE
46
+ match ? match[1] : File.basename(@file, '.rb').titleize
47
47
  end
48
48
 
49
49
  # Searches the source for the width and height of the sketch.
50
50
  def extract_dimension(source, dimension)
51
- match = source.match(/#{@info[:class_name]}\.new.*?:#{dimension}\s=>\s(\d+)/m)
52
- match ? match[1] : DEFAULT_DIMENSIONS[dimension]
51
+ match = source.match(/#{@info[:class_name]}\.new.*?:#{dimension}\s?=>\s?(\d+)/m)
52
+ size_match = source.match(/^[^#]*size\(?\s*(\d+)\s*,\s*(\d+)\s*\)?/)
53
+ return match[1] if match
54
+ return (dimension == 'width' ? size_match[1] : size_match[2]) if size_match
55
+ DEFAULT_DIMENSIONS[dimension]
53
56
  end
54
57
 
55
58
  # Searches the source for a description of the sketch.
56
59
  def extract_description(source)
57
- match = source.match(/# Description:(.*?)\n[^#]/m)
58
- match ? match[1].gsub!(/\n(\s*)?#/, "") : DEFAULT_DESCRIPTION
60
+ match = source.match(/\A((\s*#(.*?)\n)+)[^#]/m)
61
+ match ? match[1].gsub(/\s*#\s*/, "\n") : DEFAULT_DESCRIPTION
59
62
  end
60
63
 
61
- # Searches the source any libraries that have been loaded.
64
+ # Searches the source for any libraries that have been loaded.
62
65
  def extract_libraries(source)
63
66
  libs = []
64
67
  code = source.dup
65
68
  loop do
66
- matchdata = code.match(/load\w+librar(y|ies).+?["':](\S+?)["'\s]/)
69
+ matchdata = code.match(/^[^#]*load_librar(y|ies)\s+(.+)\n/)
67
70
  break unless matchdata
68
- match = matchdata[2]
69
- @opengl = true if match.match(/opengl/i)
70
- local_path = "#{local_dir}/library/#{match}"
71
- rp5_path = "#{RP5_ROOT}/library/#{match}"
72
- File.exists?(local_path) ? libs << local_path :
73
- (libs << rp5_path if File.exists?(rp5_path))
71
+ candidates = matchdata[2].gsub(/[:"'\s]/, '').split(/,/)
72
+ candidates.each do |cand|
73
+ @opengl = true if cand.match(/opengl/i)
74
+ local_path = "#{local_dir}/library/#{cand}"
75
+ rp5_path = "#{RP5_ROOT}/library/#{cand}"
76
+ libs << rp5_path if File.exists?(rp5_path)
77
+ libs << local_path if File.exists?(local_path)
78
+ end
74
79
  code = matchdata.post_match
75
80
  end
76
81
  libs
@@ -3,6 +3,8 @@ module Processing
3
3
  # This class creates blank sketches, with the boilerplate filled in.
4
4
  class Creator < BaseExporter
5
5
 
6
+ ALL_DIGITS = /\A\d+\Z/
7
+
6
8
  # Create a blank sketch, given a path.
7
9
  def create!(path, args)
8
10
  usage path
@@ -15,16 +17,20 @@ module Processing
15
17
  end
16
18
 
17
19
  # Get the substitutions
18
- @name = main_file.camelize
19
- @file_name = main_file.underscore
20
- @title = main_file.titleize
21
- @width = args[0] || "500"
22
- @height = args[1] || "500"
20
+ @name = main_file.camelize
21
+ @file_name = main_file.underscore
22
+ @title = main_file.titleize
23
+
24
+ bare = !!args.delete('--bare')
25
+ @width, @height = args[0], args[1]
26
+ @with_size = @width && @width.match(ALL_DIGITS) &&
27
+ @height && @height.match(ALL_DIGITS)
23
28
 
24
29
  # Make the file
25
30
  dir = File.dirname path
26
31
  mkdir_p dir
27
- template = File.new("#{RP5_ROOT}/lib/templates/create/blank_sketch.rb.erb")
32
+ template_name = bare ? 'bare_sketch.rb.erb' : 'blank_sketch.rb.erb'
33
+ template = File.new("#{RP5_ROOT}/lib/templates/create/#{template_name}")
28
34
  rendered = render_erb_from_string_with_binding(template.read, binding)
29
35
  full_path = File.join(dir, "#{@file_name}.rb")
30
36
  File.open(full_path, "w") {|f| f.print(rendered) }
@@ -18,11 +18,11 @@ module Processing
18
18
  Examples:
19
19
  rp5 unpack samples
20
20
  rp5 run samples/jwishy.rb
21
- rp5 create some_new_sketch 640 480
21
+ rp5 create some_new_sketch --bare 640 480
22
22
  rp5 watch some_new_sketch.rb
23
23
  rp5 applet some_new_sketch.rb
24
24
 
25
- Further information:
25
+ Everything Else:
26
26
  http://wiki.github.com/jashkenas/ruby-processing
27
27
 
28
28
  EOS
@@ -1,5 +1,64 @@
1
1
  $LOAD_PATH << File.expand_path(File.dirname(__FILE__) + "/../../")
2
+ SKETCH_ROOT = File.dirname(ARGV[0]) unless defined? SKETCH_ROOT
3
+
4
+ require 'ruby-processing'
5
+ require 'ruby-processing/app'
6
+
2
7
 
3
8
  module Processing
9
+
4
10
  SKETCH_PATH = ARGV[0]
11
+
12
+ # For use with "bare" sketches that don't want to define a class or methods
13
+ SKETCH_TEMPLATE = <<-EOS
14
+ class Sketch < Processing::App
15
+ <% if has_methods %>
16
+ <%= source %>
17
+ <% else %>
18
+ def setup
19
+ size(DEFAULT_WIDTH, DEFAULT_HEIGHT, JAVA2D)
20
+ <%= source %>
21
+ no_loop
22
+ end
23
+ <% end %>
24
+ end
25
+ EOS
26
+
27
+ # This method is the common entry point to run a sketch, bare or complete.
28
+ def self.load_and_run_sketch
29
+ source = self.read_sketch_source
30
+ has_sketch = !!source.match(/^[^#]*< Processing::App/)
31
+ has_methods = !!source.match(/^[^#]*def setup/)
32
+
33
+ if has_sketch
34
+ load Processing::SKETCH_PATH
35
+ Processing::App.sketch_class.new if !$app
36
+ return
37
+ else
38
+ require 'erb'
39
+ code = ERB.new(SKETCH_TEMPLATE).result(binding)
40
+ Object.class_eval code, Processing::SKETCH_PATH, 0
41
+ Processing::App.sketch_class.new if !$app
42
+ end
43
+ end
44
+
45
+
46
+ # Read in the sketch source code. Needs to work both online and offline.
47
+ def self.read_sketch_source
48
+ if Processing::App.online?
49
+ # Fuck the following lines. Fucking Java can go sit on broken glass.
50
+ source = ''
51
+ url = java.net.URL.new(JRUBY_APPLET.get_code_base, Processing::SKETCH_PATH)
52
+ input = java.io.BufferedReader.new(java.io.InputStreamReader.new(url.open_stream))
53
+ while line = input.read_line do
54
+ source << (line + "\n") if line
55
+ end
56
+ input.close
57
+ else
58
+ # Ahhh, much better.
59
+ source = File.read(Processing::SKETCH_PATH)
60
+ end
61
+ source
62
+ end
63
+
5
64
  end
@@ -6,6 +6,6 @@ require "#{File.dirname(__FILE__)}/base.rb"
6
6
 
7
7
  require 'irb'
8
8
  ARGV[0] = nil # To keep IRB from trying to run it multiple times.
9
- require Processing::SKETCH_PATH
10
9
  IRB.setup(__FILE__)
11
- IRB.start()
10
+ Processing.load_and_run_sketch
11
+ IRB.start()
@@ -7,4 +7,5 @@ if ARGV[1] == '--windows-app'
7
7
  end
8
8
 
9
9
  require "#{File.dirname(__FILE__)}/base.rb"
10
- require Processing::SKETCH_PATH
10
+
11
+ Processing.load_and_run_sketch
@@ -6,12 +6,13 @@ module Processing
6
6
  # the feedback between code and effect.
7
7
  class Watcher
8
8
 
9
- # Sic a new Processing::Watcher on a given sketch.
10
- def initialize(sketch)
11
- @file = sketch
9
+ # Sic a new Processing::Watcher on the sketch
10
+ def initialize
11
+ @file = Processing::SKETCH_PATH
12
12
  @time = Time.now
13
- record_state_of_ruby
14
- load @file
13
+ # Doesn't work well enough for now.
14
+ # record_state_of_ruby
15
+ Processing.load_and_run_sketch unless $app
15
16
  start_watching
16
17
  end
17
18
 
@@ -24,22 +25,44 @@ module Processing
24
25
  file_mtime = File.stat(@file).mtime
25
26
  if file_mtime > @time
26
27
  @time = file_mtime
27
- Processing::App.wipe_out_current_app!
28
- rewind_to_recorded_state
28
+ wipe_out_current_app!
29
+ # Taking it out the reset until it can be made to work more reliably
30
+ # rewind_to_recorded_state
29
31
  GC.start
30
32
  begin
31
- load @file
33
+ Processing.load_and_run_sketch
32
34
  rescue SyntaxError
33
35
  print "Syntax Error in your sketch: ", $!, "\n"
34
36
  end
35
37
  end
36
- sleep 0.1
38
+ sleep 0.33
37
39
  end
38
40
  end
39
41
  thread.join
40
42
  end
41
43
 
42
44
 
45
+ # Used to completely remove all traces of the current sketch,
46
+ # so that it can be loaded afresh. Go down into modules to find it, even.
47
+ def wipe_out_current_app!
48
+ app = $app
49
+ return unless app
50
+ app.no_loop
51
+ # Wait for the animation thread to finish rendering
52
+ sleep 0.05
53
+ app.close
54
+ constant_names = app.class.to_s.split(/::/)
55
+ app_class_name = constant_names.pop
56
+ obj = constant_names.inject(Object) {|o, name| o.send(:const_get, name) }
57
+ obj.send(:remove_const, app_class_name)
58
+ end
59
+
60
+ # The following methods were intended to make the watcher clean up all code
61
+ # loaded in from the sketch, gems, etc, and have them be reloaded properly
62
+ # when the sketch is.... but it seems that this is neither a very good idea
63
+ # or a very possible one. If you can make the scheme work, please do,
64
+ # otherwise the following methods will probably be removed soonish.
65
+
43
66
  # Do the best we can to take a picture of the current Ruby interpreter.
44
67
  # For now, this means top-level constants and loaded .rb files.
45
68
  def record_state_of_ruby
@@ -57,7 +80,7 @@ module Processing
57
80
  new_features = $LOADED_FEATURES.reject {|f| @saved_features.include?(f) }
58
81
  new_globals = Kernel.global_variables.reject {|g| @saved_globals.include?(g) }
59
82
 
60
- new_constants.each {|c| Object.send(:remove_const, c) }
83
+ Processing::App.recursively_remove_constants(Object, new_constants)
61
84
  new_load_paths.each {|p| $LOAD_PATH.delete(p) }
62
85
  new_features.each {|f| $LOADED_FEATURES.delete(f) }
63
86
  new_globals.each do |g|
@@ -69,7 +92,20 @@ module Processing
69
92
  end
70
93
  end
71
94
 
95
+
96
+ # Used to clean up declared constants in code that needs to be reloaded.
97
+ def recursively_remove_constants(base, constant_names)
98
+ constants = constant_names.map {|name| base.const_get(name) }
99
+ constants.each_with_index do |c, i|
100
+ java_obj = Java::JavaLang::Object
101
+ constants[i] = constant_names[i] = nil if c.respond_to?(:ancestors) && c.ancestors.include?(java_obj)
102
+ constants[i] = nil if !c.is_a?(Class) && !c.is_a?(Module)
103
+ end
104
+ constants.each {|c| recursively_remove_constants(c, c.constants) if c }
105
+ constant_names.each {|name| base.send(:remove_const, name.to_sym) if name }
106
+ end
107
+
72
108
  end
73
109
  end
74
110
 
75
- Processing::Watcher.new(Processing::SKETCH_PATH)
111
+ Processing::Watcher.new
@@ -24,7 +24,7 @@
24
24
  padding: 0;
25
25
  }
26
26
  #container {
27
- width: <%= @width_plus_14 %>px;
27
+ width: <%= @width + 14 %>px;
28
28
  margin: 0 auto;
29
29
  margin-top: 20px;
30
30
  }
@@ -42,8 +42,8 @@
42
42
  }
43
43
  #description {
44
44
  font-size: 12px;
45
- width: <%= @width %>px;
46
- padding: 7px;
45
+ width: <%= @width - 16 %>px;
46
+ padding: 7px 15px 7px 15px;
47
47
  background: #111;
48
48
  text-align: justify;
49
49
  margin: 0 auto;
@@ -72,7 +72,7 @@
72
72
  width="<%= @width %>" height="<%= @height %>">
73
73
 
74
74
  <param name="archive" value="<%= @file_list %>" />
75
- <param name="jruby.script" value="<%= @main_file %>" />
75
+ <param name="jruby.eval" value="ARGV[0] = '<%= @main_file %>'; require 'ruby-processing/runners/run.rb'" />
76
76
  <param name="image" value="images/ruby.jpg" />
77
77
  <param name="boxbgcolor" value="#000000" />
78
78
  <param name="lang" value="en" />
@@ -92,14 +92,14 @@
92
92
  </div>
93
93
 
94
94
  <div id="built_with">
95
- <a href="http://the-shoebox.org/apps/44/">
95
+ <a href="http://wiki.github.com/jashkenas/ruby-processing">
96
96
  <img src="images/built_with.jpg" alt="Ruby-Processing" />
97
97
  </a>
98
98
  Via <a href="http://jruby.codehaus.org/">JRuby</a> and <a href="http://processing.org/">Processing</a><br />
99
99
  Source: <a href="<%= @main_file %>"><%= @main_file %></a>
100
100
  </div>
101
101
 
102
- <% unless @description.empty? %>
102
+ <% if @description && !@description.empty? %>
103
103
  <div id="description">
104
104
  <h1><%= @title %></h1>
105
105
  <p><%= @description %></p>
@@ -0,0 +1,7 @@
1
+ def setup
2
+ <%= "size #{@width}, #{@height}" if @with_size %>
3
+ end
4
+
5
+ def draw
6
+
7
+ end
@@ -1,4 +1,4 @@
1
- require 'ruby-processing'
1
+ # <%= @title %>
2
2
 
3
3
  class <%= @name %> < Processing::App
4
4
 
@@ -12,4 +12,4 @@ class <%= @name %> < Processing::App
12
12
 
13
13
  end
14
14
 
15
- <%= @name %>.new :title => "<%= @title %>", :width => <%= @width %>, :height => <%= @height %>
15
+ <%= @name %>.new :title => "<%= @title %>"<%= ", :width => #{@width}" if @with_size %><%= ", :height => #{@height}" if @with_size %>
@@ -97,8 +97,12 @@ module ControlPanel
97
97
  set_size 200, 30 + (64 * @elements.size)
98
98
  set_default_close_operation javax.swing.JFrame::DISPOSE_ON_CLOSE
99
99
  set_resizable false
100
- set_location($app.width + 10, 0)
101
- show
100
+ # Need to wait for the sketch to finish sizing...
101
+ Thread.new do
102
+ sleep 0.2 while $app.default_size? || !$app.done_displaying?
103
+ set_location($app.width + 10, 0)
104
+ show
105
+ end
102
106
  end
103
107
 
104
108
  def add_element(element, name, has_label=true, button=false)
File without changes
Binary file
Binary file
Binary file
@@ -1,9 +1,8 @@
1
1
  The majority of the work in this library is done by iText.
2
2
  http://www.lowagie.com/iText/
3
3
 
4
- The version bundled in this release is 2.1.2u.
4
+ The version bundled in this release is 2.1.4.
5
5
 
6
- The files in the library must be named itext.jar (not iText-2.1.2u.jar)
7
- because they're specifically included on the classpath as part of the
8
- build/platform/make.sh scripts.
6
+ The files in the library must be named itext.jar because they're specifically
7
+ included on the classpath as part of the build/platform/make.sh scripts.
9
8
 
data/samples/animator.rb CHANGED
@@ -1,47 +1,43 @@
1
1
  # From the Processing Examples
2
+ # Uses the "bare" style, where a Processing::App sketch is implicitly wrapped
3
+ # around the code.
2
4
  # -- omygawshkenas
3
5
 
4
- require 'ruby-processing'
6
+ FRAME_COUNT = 12
5
7
 
6
- class Animator < Processing::App
7
- FRAME_COUNT = 12
8
+ def setup
9
+ @frames = []
10
+ @last_time = 0
11
+ @current_frame = 0
12
+ @draw = false
13
+ @back_color = 204
14
+ size 350, 350
15
+ stroke_weight 4
16
+ smooth
17
+ background @back_color
18
+ FRAME_COUNT.times { @frames << get() }
19
+ end
8
20
 
9
- def setup
10
- @frames = []
11
- @last_time = 0
12
- @current_frame = 0
13
- @draw = false
14
- @back_color = 204
15
- stroke_weight 4
16
- smooth
17
- background @back_color
18
- FRAME_COUNT.times { @frames << get() }
19
- end
20
-
21
- def draw
22
- time = millis()
23
- if time > @last_time + 100
24
- next_frame
25
- @last_time = time
26
- end
27
- line(pmouse_x, pmouse_y, mouse_x, mouse_y) if @draw
28
- end
29
-
30
- def mouse_pressed; @draw = true; end
31
- def mouse_released; @draw = false; end
32
-
33
- def key_pressed
34
- background @back_color
35
- @frames.size.times {|i| @frames[i] = get()}
36
- end
37
-
38
- def next_frame
39
- @frames[@current_frame] = get()
40
- @current_frame += 1
41
- @current_frame = 0 if @current_frame >= @frames.size
42
- image(@frames[@current_frame], 0, 0)
21
+ def draw
22
+ time = millis()
23
+ if time > @last_time + 100
24
+ next_frame
25
+ @last_time = time
43
26
  end
44
-
27
+ line(pmouse_x, pmouse_y, mouse_x, mouse_y) if @draw
28
+ end
29
+
30
+ def mouse_pressed; @draw = true; end
31
+ def mouse_released; @draw = false; end
32
+
33
+ def key_pressed
34
+ background @back_color
35
+ @frames.size.times {|i| @frames[i] = get()}
45
36
  end
46
37
 
47
- Animator.new :title => "Animator", :width => 350, :height => 350
38
+ def next_frame
39
+ @frames[@current_frame] = get()
40
+ @current_frame += 1
41
+ @current_frame = 0 if @current_frame >= @frames.size
42
+ image(@frames[@current_frame], 0, 0)
43
+ end