graphics 1.0.0b6 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/History.rdoc +88 -0
  5. data/Manifest.txt +2 -0
  6. data/Rakefile +7 -8
  7. data/examples/boid.rb +44 -63
  8. data/examples/bounce.rb +4 -4
  9. data/examples/canvas.rb +17 -16
  10. data/examples/collision.rb +1 -1
  11. data/examples/demo.rb +1 -1
  12. data/examples/editor.rb +1 -1
  13. data/examples/fluid.rb +6 -6
  14. data/examples/fluid2.rb +22 -9
  15. data/examples/gol.rb +1 -1
  16. data/examples/gol2.rb +14 -22
  17. data/examples/math.rb +1 -1
  18. data/examples/pi_polygon.rb +8 -3
  19. data/examples/radar.rb +3 -3
  20. data/examples/rainbow_fluid.rb +4 -3
  21. data/examples/tank.rb +7 -3
  22. data/examples/tank2.rb +3 -3
  23. data/examples/targeting.rb +3 -3
  24. data/examples/vants.rb +13 -4
  25. data/examples/walker.rb +1 -1
  26. data/examples/walker2.rb +1 -1
  27. data/examples/zombies.rb +13 -7
  28. data/ext/sdl/extconf.rb +12 -20
  29. data/ext/sdl/sdl.c +619 -360
  30. data/ext/sdl/sge/Makefile +36 -11
  31. data/ext/sdl/sge/Makefile.conf +15 -9
  32. data/ext/sdl/sge/sge_bm_text.cpp +7 -6
  33. data/ext/sdl/sge/sge_collision.cpp +3 -1
  34. data/ext/sdl/sge/sge_config.h +0 -2
  35. data/ext/sdl/sge/sge_internal.h +0 -8
  36. data/ext/sdl/sge/sge_primitives.cpp +0 -11
  37. data/ext/sdl/sge/sge_primitives.h +0 -3
  38. data/ext/sdl/sge/sge_rotation.cpp +1 -1
  39. data/ext/sdl/sge/sge_shape.cpp +18 -9
  40. data/ext/sdl/sge/sge_surface.cpp +10 -4
  41. data/ext/sdl/sge/sge_textpp.cpp +17 -13
  42. data/graphics_setup.sh +43 -13
  43. data/lib/graphics.rb +1 -1
  44. data/lib/graphics/body.rb +8 -0
  45. data/lib/graphics/decorators.rb +15 -3
  46. data/lib/graphics/extensions.rb +1 -1
  47. data/lib/graphics/rainbows.rb +17 -25
  48. data/lib/graphics/simulation.rb +265 -106
  49. data/lib/graphics/v.rb +8 -1
  50. data/resources/sounds/attribution.txt +2 -0
  51. data/resources/sounds/bullet.wav +0 -0
  52. data/test/test_graphics.rb +232 -107
  53. metadata +37 -43
  54. metadata.gz.sig +1 -2
@@ -1,26 +1,56 @@
1
1
  #!/bin/sh
2
2
  set -e
3
+ set -v
3
4
 
4
- for pkg in sdl sdl_image sdl_ttf sdl_mixer sdl_gfx smpeg freetype libogg libvorbis libsmpeg libpng libtiff; do
5
- brew uninstall $pkg || true
6
- done
5
+ # if [ $(id -u) != 0 ]; then
6
+ # echo "Please run this as root or with sudo"
7
+ # exit 1
8
+ # fi
7
9
 
8
- for gem in graphics rubysdl rsdl; do
9
- gem uninstall -ax $gem || true
10
+ for gem in graphics rsdl; do
11
+ gem uninstall -ax $gem || true
10
12
  done
11
13
 
12
- # brew update
14
+ case `uname` in
15
+ Darwin)
16
+ echo "I'm on OSX. Not using sudo"
17
+ SUDO=
18
+
19
+ brew unlink sdl
20
+ brew unlink sdl_mixer
21
+ brew unlink sdl_ttf
22
+ brew unlink sdl_image
23
+
24
+ brew install sdl2
25
+ brew install sdl2_mixer
26
+ brew install sdl2_ttf
27
+ brew install sdl2_image --without-webp
28
+ brew install sdl2_gfx
29
+ ;;
30
+ Linux)
31
+ echo "I'm on linux, using sudo where needed"
32
+ SUDO=sudo
33
+
34
+ $SUDO apt-get install --no-install-recommends --no-install-suggests libsdl1.2-dev libsdl-image1.2-dev libsdl-mixer1.2-dev libsdl-ttf2.0-dev
35
+ $SUDO apt-get install --no-install-recommends --no-install-suggests gcc g++
36
+ ;;
37
+ *)
38
+ echo "Unknown OS $OSTYPE, aborting"
39
+ exit 1
40
+ ;;
41
+ esac
42
+
43
+ $SUDO gem update --system -N -V
13
44
 
14
- brew install sdl --universal
15
- brew install sdl_mixer --universal --with-smpeg
16
- brew install sdl_ttf --universal
17
- brew install sdl_image --universal --without-webp
45
+ gem install hoe --conservative
46
+ $SUDO rake newb
47
+ rake test
18
48
 
19
49
  if [ -f $0 ]; then
20
50
  rake clean package
21
- gem install pkg/graphics*.gem
51
+ $SUDO gem install pkg/graphics*.gem
22
52
  else
23
- gem install graphics --pre
53
+ $SUDO gem install graphics --pre
24
54
  fi
25
55
 
26
- rsdl -rgraphics -e 'Class.new(Graphics::Simulation) { def draw n; clear :white; text "hit escape to quit", 100, 100, :black; end; }.new(500, 250, 0, "Working!").run'
56
+ rsdl -Ilib -rgraphics -e 'Class.new(Graphics::Simulation) { def draw n; clear :white; text "hit escape to quit", 100, 100, :black; end; }.new(500, 250, 0, "Working!").run'
@@ -2,7 +2,7 @@
2
2
  # The top-level namespace.
3
3
 
4
4
  class Graphics
5
- VERSION = "1.0.0b6" # :nodoc:
5
+ VERSION = "1.0.0" # :nodoc:
6
6
  end
7
7
 
8
8
  require "graphics/simulation"
@@ -70,6 +70,14 @@ class Graphics::Body
70
70
  self.m = 0.0
71
71
  end
72
72
 
73
+ ##
74
+ # Update the body. Does nothing by default. Override this method to
75
+ # add behavior to the body.
76
+
77
+ def update
78
+ # do nothing
79
+ end
80
+
73
81
  def inspect # :nodoc:
74
82
  "%s(%.2fx%.2f @ %.2f°x%.2f == %p @ %p)" %
75
83
  [self.class, x, y, a, m, position, velocity]
@@ -1,12 +1,20 @@
1
+ ##
2
+ # Include this in your simulation to automatically include an FPS
3
+ # meter.
4
+
1
5
  module ShowFPS
2
- def draw n
6
+ def draw n # :nodoc:
3
7
  super
4
8
  fps n
5
9
  end
6
10
  end
7
11
 
12
+ ##
13
+ # Include this in your simulation and define +GRID_WIDTH+ to draw a
14
+ # grid in the window.
15
+
8
16
  module DrawGrid
9
- def pre_draw n
17
+ def pre_draw n # :nodoc:
10
18
  super
11
19
 
12
20
  (0...w).step(self.class::GRID_WIDTH).each do |x|
@@ -16,6 +24,10 @@ module DrawGrid
16
24
  end
17
25
  end
18
26
 
27
+ ##
28
+ # Include this in your simulation to make the background white.
29
+
19
30
  module WhiteBackground
20
- CLEAR_COLOR = :white
31
+ CLEAR_COLOR = :white # :nodoc:
32
+ DEBUG_COLOR = :black # :nodoc:
21
33
  end
@@ -25,7 +25,7 @@ class Numeric
25
25
  # Normalize a number to be within 0...360
26
26
 
27
27
  def degrees
28
- (self < 0 ? self + 360 : self) % 360
28
+ self % 360
29
29
  end
30
30
 
31
31
  ##
@@ -1,17 +1,20 @@
1
+ ##
2
+ # Creates a range of colors all at once. See #initialize_rainbow.
3
+
1
4
  class Graphics::Rainbow
2
- attr_reader :cache
5
+ attr_reader :cache # :nodoc:
3
6
 
4
- def initialize
7
+ def initialize # :nodoc:
5
8
  @cache = self.cache_colors
6
9
  end
7
10
 
8
- def clamp d, min, max
11
+ def clamp d, min, max # :nodoc:
9
12
  [[min, d].max, max].min
10
13
  end
11
14
 
12
15
  ##
13
- # Takes a value and a range,
14
- # and scales that range to 0-360
16
+ # Takes a value and a range, and scales that range to 0-360
17
+
15
18
  def scale d, min, max
16
19
  range = max - min
17
20
  if range != 0
@@ -22,7 +25,7 @@ class Graphics::Rainbow
22
25
  end
23
26
  end
24
27
 
25
- def cache_colors
28
+ def cache_colors # :nodoc:
26
29
  # Saves all the colors to a hash
27
30
  cache = {}
28
31
  (0..360).each do |degree|
@@ -31,12 +34,12 @@ class Graphics::Rainbow
31
34
  cache
32
35
  end
33
36
 
34
- def color d, min=0, max=360
37
+ def color d, min=0, max=360 # :nodoc:
35
38
  scaled = scale d, min, max
36
39
  @cache[scaled]
37
40
  end
38
41
 
39
- def _color degree
42
+ def _color degree # :nodoc:
40
43
  raise "Subclass responsibility"
41
44
  end
42
45
  private :_color
@@ -46,11 +49,7 @@ end
46
49
  # Black to white gradient
47
50
  #
48
51
  class Graphics::Greyscale < Graphics::Rainbow
49
- def initialize
50
- super
51
- end
52
-
53
- def _color degree
52
+ def _color degree # :nodoc:
54
53
  brightness_unit = degree/360.0
55
54
  brightness = (brightness_unit*255.0).floor # Scale back to RGB
56
55
 
@@ -62,12 +61,7 @@ end
62
61
  # The full RGB spectrum
63
62
  #
64
63
  class Graphics::Hue < Graphics::Rainbow
65
-
66
- def initialize
67
- super
68
- end
69
-
70
- def _color degree
64
+ def _color degree # :nodoc:
71
65
  main_color = 1 * 255 # Let chroma (saturation * brightness) always == 1
72
66
  second_strongest_color = ((1 - (degree/60.0 % 2 - 1).abs) * 255).floor
73
67
 
@@ -93,12 +87,7 @@ end
93
87
  # Spectrum with linearly increasing brightness
94
88
  #
95
89
  class Graphics::Cubehelix < Graphics::Rainbow
96
-
97
- def initialize
98
- super
99
- end
100
-
101
- def _color degree
90
+ def _color degree # :nodoc:
102
91
  d = degree/360.0
103
92
  start = 0.5 # Starting position in color space - 0=blue, 1=red, 2=green
104
93
  rotations = -1.5 # How many rotations through the rainbow?
@@ -119,6 +108,9 @@ class Graphics::Cubehelix < Graphics::Rainbow
119
108
  end
120
109
 
121
110
  class Graphics::Simulation
111
+ ##
112
+ # Generate colors using a rainbow and a prefix name.
113
+
122
114
  def initialize_rainbow rainbow, name
123
115
  rainbow.cache.each do |degree, color|
124
116
  color_name = "#{name}_#{degree}".to_sym
@@ -2,16 +2,64 @@
2
2
 
3
3
  require "sdl/sdl"
4
4
 
5
- module SDL; end # :nodoc: -- stupid rdoc :(
5
+ module SDL # :nodoc:
6
+ init INIT_EVERYTHING
7
+ end
8
+
9
+ module SDL
10
+ ##
11
+ # Renderer is the workhorse of the graphics gem. Everything
12
+ # graphical gets done through the renderer.
13
+
14
+ class Renderer
15
+ ##
16
+ # The PixelFormat for the current renderer.
17
+
18
+ attr_reader :format
19
+
20
+ ##
21
+ # The surface used by this renderer.
22
+
23
+ attr_reader :surface
24
+
25
+ ##
26
+ # The window for this renderer
27
+
28
+ attr_reader :window
29
+
30
+ ##
31
+ # The title of the window.
32
+
33
+ def title
34
+ @window.title
35
+ end
36
+
37
+ ##
38
+ # Sets the title of the window.
39
+
40
+ def title= s
41
+ @window.title = s
42
+ end
43
+ end
44
+ end
6
45
 
7
46
  ##
8
47
  # An abstract simulation. See Graphics::Simulation and Graphics::Drawing.
9
48
 
10
49
  class Graphics::AbstractSimulation
11
50
 
12
- # The default color to clear the screen.
51
+ ##
52
+ # Flags to be used when initializing a window. Defaults to 0. See
53
+ # SDL doco for more.
54
+
55
+ SCREEN_FLAGS = 0
56
+
57
+ # The default color to clear the window.
13
58
  CLEAR_COLOR = :black
14
59
 
60
+ # The default font color for `debug` calls.
61
+ DEBUG_COLOR = :white
62
+
15
63
  # degrees to radians
16
64
  D2R = Math::PI / 180.0
17
65
 
@@ -21,11 +69,19 @@ class Graphics::AbstractSimulation
21
69
  # Call +log+ every N ticks, if +log+ is defined.
22
70
  LOG_INTERVAL = 60
23
71
 
72
+ # The default font. Menlo on OS X, Deja Vu Sans Mono on linux.
73
+ DEFAULT_FONT = case RUBY_PLATFORM
74
+ when /darwin/ then "Menlo"
75
+ when /linux/ then "DejaVuSansMono"
76
+ else
77
+ raise "Unsupported platform #{RUBY_PLATFORM}. Please fix."
78
+ end
79
+
24
80
  # Collection of collections of Bodies to auto-update and draw.
25
81
  attr_accessor :_bodies
26
82
 
27
- # The window the simulation is drawing in.
28
- attr_accessor :screen
83
+ # The renderer (software or hardware backed) the simulation is drawing in.
84
+ attr_accessor :renderer
29
85
 
30
86
  # The window width.
31
87
  attr_accessor :w
@@ -42,9 +98,6 @@ class Graphics::AbstractSimulation
42
98
  # A hash of color names to their values.
43
99
  attr_accessor :color
44
100
 
45
- # A hash of color values to their rgb values. For text, apparently. *shrug*
46
- attr_accessor :rgb
47
-
48
101
  # Number of update iterations per drawing tick.
49
102
  attr_accessor :iter_per_tick
50
103
 
@@ -64,22 +117,28 @@ class Graphics::AbstractSimulation
64
117
  #
65
118
  # This also names a bunch colors and hues for convenience.
66
119
 
67
- def initialize w, h, bpp = 0, name = self.class.name, full = false
68
- SDL.init SDL::INIT_VIDEO
120
+ def initialize w=nil, h=nil, name=self.class.name, full=false
121
+ w ||= SDL::Screen::W/2
122
+ h ||= SDL::Screen::H/2
123
+
124
+ # TODO: remove for 1.0.0 final
125
+ raise "Do NOT pass bpp to Simulation anymore" if !name || Integer === name
69
126
 
70
127
  full = full ? SDL::FULLSCREEN : 0
71
128
 
72
129
  self._bodies = []
73
130
 
74
- self.font = find_font("Menlo", 32)
131
+ self.font = find_font(DEFAULT_FONT, 32)
75
132
 
76
- SDL::WM.set_caption name, name
133
+ name ||= "Unknown"
134
+ name = name.gsub(/[A-Z]/, ' \0').strip
77
135
 
78
- self.screen = SDL::Screen.open w, h, bpp, self.class::SCREEN_FLAGS|full
79
- self.w, self.h = screen.w, screen.h
136
+ self.renderer = SDL::Screen.open w, h, 32, self.class::SCREEN_FLAGS|full
137
+ self.w, self.h = w, h
138
+
139
+ renderer.title = name
80
140
 
81
141
  self.color = {}
82
- self.rgb = Hash.new { |hash, k| hash[k] = screen.format.get_rgb(color[k]) }
83
142
  self.paused = false
84
143
 
85
144
  self.iter_per_tick = 1
@@ -89,6 +148,9 @@ class Graphics::AbstractSimulation
89
148
 
90
149
  initialize_keys
91
150
  initialize_colors
151
+
152
+ clear # so you start with the right color blank window on frame 0
153
+ renderer.present
92
154
  end
93
155
 
94
156
  ##
@@ -109,17 +171,17 @@ class Graphics::AbstractSimulation
109
171
  register_color :red, 255, 0, 0
110
172
  register_color :green, 0, 255, 0
111
173
  register_color :blue, 0, 0, 255
112
- register_color :cyan, 0, 255, 255
113
- register_color :magenta, 255, 0, 255
174
+ register_color :cyan, 0, 255, 255
175
+ register_color :magenta, 255, 0, 255
114
176
  register_color :yellow, 255, 255, 0
115
- register_color :alpha, 0, 0, 0, 0
177
+ register_color :alpha, 0, 0, 0, 0
116
178
 
117
179
  (0..99).each do |n|
118
180
  m = (255 * (n / 100.0)).to_i
119
- register_color(("gray%02d" % n).to_sym, m, m, m)
120
- register_color(("red%02d" % n).to_sym, m, 0, 0)
121
- register_color(("green%02d" % n).to_sym, 0, m, 0)
122
- register_color(("blue%02d" % n).to_sym, 0, 0, m)
181
+ register_color(("gray%02d" % n).to_sym, m, m, m)
182
+ register_color(("red%02d" % n).to_sym, m, 0, 0)
183
+ register_color(("green%02d" % n).to_sym, 0, m, 0)
184
+ register_color(("blue%02d" % n).to_sym, 0, 0, m)
123
185
  register_color(("cyan%02d" % n).to_sym, 0, m, m)
124
186
  register_color(("magenta%02d" % n).to_sym, m, 0, m)
125
187
  register_color(("yellow%02d" % n).to_sym, m, m, 0)
@@ -137,10 +199,16 @@ class Graphics::AbstractSimulation
137
199
  end
138
200
  end
139
201
 
140
- sys_font = "/System/Library/Fonts"
141
- lib_font = "/Library/Fonts"
142
- user_font = File.expand_path "~/Library/Fonts/"
143
- FONT_GLOB = "{#{sys_font},#{lib_font},#{user_font}}" # :nodoc:
202
+ font_dirs = [
203
+ # OS X
204
+ "/System/Library/Fonts",
205
+ "/Library/Fonts",
206
+ File.expand_path("~/Library/Fonts/"),
207
+
208
+ # Ubuntu
209
+ "/usr/share/fonts/truetype/**/",
210
+ ]
211
+ FONT_GLOB = "{#{font_dirs.join(",")}}" # :nodoc:
144
212
 
145
213
  ##
146
214
  # Find and open a (TTF) font. Should be as system agnostic as possible.
@@ -165,7 +233,7 @@ class Graphics::AbstractSimulation
165
233
  # Register a single Body to be auto-updated and drawn.
166
234
 
167
235
  def register_body obj
168
- _bodies << [obj]
236
+ register_bodies Array(obj)
169
237
  obj
170
238
  end
171
239
 
@@ -173,7 +241,77 @@ class Graphics::AbstractSimulation
173
241
  # Name a color w/ rgba values.
174
242
 
175
243
  def register_color name, r, g, b, a = 255
176
- color[name] = screen.format.map_rgba r, g, b, a
244
+ color[name] = renderer.format.map_rgba r, g, b, a
245
+ end
246
+
247
+ ##
248
+ # Name a color w/ HSL values.
249
+
250
+ def register_hsla n, h, s, l, a = 1.0
251
+ register_color n, *from_hsl(h, s, l), (a*255).round
252
+ end
253
+
254
+ ##
255
+ # Name a color w/ HSV values.
256
+
257
+ def register_hsva n, h, s, v, a = 1.0
258
+ register_color n, *from_hsv(h, s, v), (a*255).round
259
+ end
260
+
261
+ ##
262
+ # Convert HSL to RGB.
263
+ #
264
+ # https://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV
265
+
266
+ def from_hsl h, s, l # 0..360, 0..1, 0..1
267
+ raise ArgumentError, "%f, %f, %f out of range" % [h, s, v] unless
268
+ h.between?(0, 360) && s.between?(0, 1) && l.between?(0, 1)
269
+
270
+ c = (1 - (2*l - 1).abs) * s
271
+ h2 = h / 60.0
272
+ x = c * (1 - (h2 % 2 - 1).abs)
273
+ m = l - c/2
274
+
275
+ r, g, b = case
276
+ when 0 <= h2 && h2 < 1 then [c+m, x+m, 0+m]
277
+ when 1 <= h2 && h2 < 2 then [x+m, c+m, 0+m]
278
+ when 2 <= h2 && h2 < 3 then [0+m, c+m, x+m]
279
+ when 3 <= h2 && h2 < 4 then [0+m, x+m, c+m]
280
+ when 4 <= h2 && h2 < 5 then [x+m, 0+m, c+m]
281
+ when 5 <= h2 && h2 < 6 then [c+m, 0+m, x+m]
282
+ else
283
+ raise [h, s, v, h2, x, m].inspect
284
+ end
285
+
286
+ [(r*255).round, (g*255).round, (b*255).round]
287
+ end
288
+
289
+ ##
290
+ # Convert HSV to RGB.
291
+ #
292
+ # https://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV
293
+
294
+ def from_hsv h, s, v # 0..360, 0..1, 0..1
295
+ raise ArgumentError, "%f, %f, %f out of range" % [h, s, v] unless
296
+ h.between?(0, 360) && s.between?(0, 1) && v.between?(0, 1)
297
+
298
+ c = v * s
299
+ h2 = h / 60.0
300
+ x = c * (1 - (h2 % 2 - 1).abs)
301
+ m = v - c
302
+
303
+ r, g, b = case
304
+ when 0 <= h2 && h2 < 1 then [c+m, x+m, 0+m]
305
+ when 1 <= h2 && h2 < 2 then [x+m, c+m, 0+m]
306
+ when 2 <= h2 && h2 < 3 then [0+m, c+m, x+m]
307
+ when 3 <= h2 && h2 < 4 then [0+m, x+m, c+m]
308
+ when 4 <= h2 && h2 < 5 then [x+m, 0+m, c+m]
309
+ when 5 <= h2 && h2 < 6 then [c+m, 0+m, x+m]
310
+ else
311
+ raise [h, s, v, h2, x, m].inspect
312
+ end
313
+
314
+ [(r*255).round, (g*255).round, (b*255).round]
177
315
  end
178
316
 
179
317
  ##
@@ -254,20 +392,19 @@ class Graphics::AbstractSimulation
254
392
  handle_event event, n while event = SDL::Event.poll
255
393
  handle_keys
256
394
 
257
- next if paused
395
+ break if done
396
+ next if paused
258
397
 
259
398
  iter_per_tick.times { update n; n += 1 }
260
399
  draw_and_flip n
261
400
 
262
401
  log if logger and n % log_interval == 0
263
-
264
- break if done
265
402
  end
266
403
  end
267
404
 
268
405
  def draw_and_flip n # :nodoc:
269
406
  self.draw n
270
- screen.flip
407
+ renderer.present
271
408
  end
272
409
 
273
410
  ##
@@ -280,10 +417,17 @@ class Graphics::AbstractSimulation
280
417
  post_draw n
281
418
  end
282
419
 
420
+ ##
421
+ # The pre-draw phase. Defaults to clearing.
422
+
283
423
  def pre_draw n
284
424
  clear
285
425
  end
286
426
 
427
+ ##
428
+ # The post-draw phase. Defaults to having all bodies draw
429
+ # themselves.
430
+
287
431
  def post_draw n
288
432
  _bodies.each do |ary|
289
433
  draw_collection ary
@@ -316,31 +460,36 @@ class Graphics::AbstractSimulation
316
460
  end
317
461
 
318
462
  ##
319
- # Clear the whole screen. Defaults to CLEAR_COLOR.
463
+ # Clear the whole window. Defaults to CLEAR_COLOR.
320
464
 
321
465
  def clear c = self.class::CLEAR_COLOR
322
- fast_rect 0, 0, w, h, c
466
+ cc = color[c]
467
+ if cc then
468
+ renderer.clear cc
469
+ else
470
+ warn "Color #{c} doesn't appear to be registered. Skipping clear."
471
+ end
323
472
  end
324
473
 
325
474
  ##
326
475
  # Draw an antialiased line from x1/y1 to x2/y2 in color c.
327
476
 
328
- def line x1, y1, x2, y2, c
477
+ def line x1, y1, x2, y2, c, aa = true
329
478
  h = self.h
330
- screen.draw_line x1, h-y1-1, x2, h-y2-1, color[c]
479
+ renderer.draw_line x1, h-y1-1, x2, h-y2-1, color[c], aa
331
480
  end
332
481
 
333
482
  ##
334
483
  # Draw a horizontal line from x1 to x2 at y in color c.
335
484
 
336
- def hline y, c, x1 = 0, x2 = h
485
+ def hline y, c, x1 = 0, x2 = w
337
486
  line x1, y, x2, y, c
338
487
  end
339
488
 
340
489
  ##
341
490
  # Draw a vertical line from y1 to y2 at y in color c.
342
491
 
343
- def vline x, c, y1 = 0, y2 = w
492
+ def vline x, c, y1 = h-1, y2 = 0
344
493
  line x, y1, x, y2, c
345
494
  end
346
495
 
@@ -367,14 +516,21 @@ class Graphics::AbstractSimulation
367
516
  # Draw a rect at x/y with w by h dimensions in color c. Ignores blending.
368
517
 
369
518
  def fast_rect x, y, w, h, c
370
- screen.fast_rect x, self.h-y-h, w, h, color[c]
519
+ y = self.h-y-h # TODO: -1???
520
+ renderer.fast_rect x, y, w, h, color[c]
371
521
  end
372
522
 
373
523
  ##
374
- # Draw a point at x/y w/ color c.
524
+ # Read or write a color to x/y. If c is given, write, otherwise read.
525
+ #
526
+ # Reading is pretty slow. Try to avoid.
375
527
 
376
- def point x, y, c
377
- screen[x, h-y-1] = color[c]
528
+ def point x, y, c = nil
529
+ if c then
530
+ renderer[x, h-y-1] = color[c]
531
+ else
532
+ renderer[x, h-y-1]
533
+ end
378
534
  end
379
535
 
380
536
  ##
@@ -390,45 +546,38 @@ class Graphics::AbstractSimulation
390
546
  # Draw a rect at x/y with w by h dimensions in color c.
391
547
 
392
548
  def rect x, y, w, h, c, fill = false
393
- y = self.h-y-h-1
394
- if fill then
395
- screen.fill_rect x, y, w, h, color[c]
396
- else
397
- screen.draw_rect x, y, w, h, color[c]
398
- end
549
+ y = self.h-y-h # TODO: -1???
550
+ renderer.draw_rect x, y, w, h, color[c], fill
399
551
  end
400
552
 
401
553
  ##
402
554
  # Draw a circle at x/y with radius r in color c.
403
555
 
404
- def circle x, y, r, c, fill = false
556
+ def circle x, y, r, c, fill = false, aa = true
405
557
  y = h-y-1
406
- if fill then
407
- screen.fill_circle x, y, r, color[c]
408
- else
409
- screen.draw_circle x, y, r, color[c]
410
- end
558
+ renderer.draw_circle x, y, r, color[c], aa, fill
411
559
  end
412
560
 
413
561
  ##
414
562
  # Draw a circle at x/y with radiuses w/h in color c.
415
563
 
416
- def ellipse x, y, w, h, c, fill = false
564
+ def ellipse x, y, w, h, c, fill = false, aa = true
417
565
  y = self.h-y-1
418
- if fill then
419
- screen.fill_ellipse x, y, w, h, color[c]
420
- else
421
- screen.draw_ellipse x, y, w, h, color[c]
422
- end
566
+ renderer.draw_ellipse x, y, w, h, color[c], aa, fill
423
567
  end
424
568
 
425
569
  ##
426
570
  # Draw an antialiased curve from x1/y1 to x2/y2 via control points
427
571
  # cx1/cy1 & cx2/cy2 in color c.
428
572
 
429
- def bezier x1, y1, cx1, cy1, cx2, cy2, x2, y2, c, l = 7
430
- h = self.h
431
- screen.draw_bezier x1, h-y1-1, cx1, h-cy1, cx2, h-cy2, x2, h-y2-1, l, color[c]
573
+ def bezier *points, c
574
+ h = self.h-1
575
+
576
+ # TODO: there is probably a cleaner way... or move entirely into C
577
+ xs, ys = points.each_slice(2).to_a.transpose
578
+ ys.map! { |y| h-y }
579
+
580
+ renderer.draw_bezier xs, ys, 5, color[c]
432
581
  end
433
582
 
434
583
  ## Text
@@ -437,14 +586,14 @@ class Graphics::AbstractSimulation
437
586
  # Return the w/h of the text s in font f.
438
587
 
439
588
  def text_size s, f = font
440
- f.text_size s
589
+ f.text_size s.to_s
441
590
  end
442
591
 
443
592
  ##
444
593
  # Return the rendered text s in color c in font f.
445
594
 
446
595
  def render_text s, c, f = font
447
- f.render screen, s, color[c]
596
+ f.render renderer, s, color[c]
448
597
  end
449
598
 
450
599
  ##
@@ -452,7 +601,7 @@ class Graphics::AbstractSimulation
452
601
 
453
602
  def text s, x, y, c, f = font
454
603
  y = self.h-y-f.height-1
455
- f.draw screen, s, x, y, color[c]
604
+ f.draw renderer, s, x, y, color[c]
456
605
  end
457
606
 
458
607
  ##
@@ -461,24 +610,22 @@ class Graphics::AbstractSimulation
461
610
 
462
611
  def debug fmt, *args
463
612
  s = fmt % args
464
- text s, 10, h-40-font.height, :white
613
+ text s, 10, h-40-font.height, self.class::DEBUG_COLOR
465
614
  end
466
615
 
467
616
  attr_accessor :start_time # :nodoc:
468
617
 
469
618
  ##
470
- # Draw the current frames-per-second in the top left corner in green.
619
+ # Draw the current frames-per-second in the top left corner. Defaults to green.
471
620
 
472
- def fps n
621
+ def fps n, color = :green
473
622
  secs = Time.now - start_time
474
623
  fps = "%5.1f fps" % [n / secs]
475
- text fps, 10, h-font.height, :green
624
+ text fps, 10, h-font.height, color
476
625
  end
477
626
 
478
627
  ### Blitting Methods:
479
628
 
480
- # TODO: copy_rect(x,y,w,h)
481
-
482
629
  ##
483
630
  # Load an image at path into a new surface.
484
631
 
@@ -512,48 +659,40 @@ class Graphics::AbstractSimulation
512
659
  ##
513
660
  # Draw a bitmap centered at x/y with optional angle, x/y scale, and flags.
514
661
 
515
- def blit src, x, y, a° = 0, xscale = 1, yscale = 1, flags = 0
516
- img = src.transform src.format.colorkey, -a°, xscale, yscale, flags
517
-
518
- SDL::Surface.blit img, 0, 0, 0, 0, screen, x-img.w/2, h-y-img.h/2
662
+ def blit src, x, y, a° = nil, xscale = nil, yscale = nil, flags = nil
663
+ renderer.blit src, x-src.w/2, h-y-src.h/2, a°, xscale, yscale, :center
519
664
  end
520
665
 
521
666
  ##
522
667
  # Draw a bitmap at x/y with optional angle, x/y scale, and flags.
523
668
 
524
- def put src, x, y, a° = 0, xscale = 1, yscale = 1, flags = 0
525
- img = src.transform src.format.colorkey, -a°, xscale, yscale, flags
526
-
527
- # why x-1? because transform adds a pixel to all sides even if a°==0
528
- SDL::Surface.blit img, 0, 0, 0, 0, screen, x-1, h-y-img.h
669
+ def put src, x, y, a° = nil, xscale = nil, yscale = nil, flags = nil
670
+ renderer.blit src, x, h-y-src.h, a°, xscale, yscale, false
529
671
  end
530
672
 
531
673
  ##
532
- # Save the current screen to a bmp
674
+ # Save the current window to a png.
533
675
 
534
676
  def save path
535
- screen.save path
677
+ renderer.save path
536
678
  end
537
679
 
538
680
  ##
539
- # Create a new sprite with a given width and height and yield to a
540
- # block with the new sprite as the current screen. All drawing
541
- # primitives will work and the resulting surface is returned.
681
+ # Create a new renderer with a given width and height and yield to a
682
+ # block for drawing. The resulting surface is returned.
542
683
 
543
684
  def sprite w, h
544
- new_screen = SDL::Surface.new w, h, screen.format
545
- old_screen = screen
546
- old_w, old_h = self.w, self.h
685
+ old_renderer = renderer
686
+ new_renderer = renderer.sprite w, h
687
+ old_w, old_h = renderer.w, renderer.h
547
688
  self.w, self.h = w, h
689
+ self.renderer = new_renderer
548
690
 
549
- self.screen = new_screen
550
691
  yield if block_given?
551
692
 
552
- new_screen.set_color_key SDL::SRCCOLORKEY, 0
553
-
554
- new_screen
693
+ new_renderer.surface
555
694
  ensure
556
- self.screen = old_screen
695
+ self.renderer = old_renderer
557
696
  self.w, self.h = old_w, old_h
558
697
  end
559
698
  end
@@ -577,7 +716,7 @@ end
577
716
  # + Ball::View.draw takes a window and a ball and draws it.
578
717
 
579
718
  class Graphics::Simulation < Graphics::AbstractSimulation
580
- SCREEN_FLAGS = SDL::HWSURFACE|SDL::DOUBLEBUF
719
+
581
720
  end
582
721
 
583
722
  ##
@@ -587,23 +726,43 @@ end
587
726
  # See AbstractSimulation for most methods.
588
727
 
589
728
  class Graphics::Drawing < Graphics::AbstractSimulation
590
- SCREEN_FLAGS = SDL::HWSURFACE
729
+ ##
730
+ # The canvas used for all drawing.
731
+
732
+ attr_accessor :texture
591
733
 
592
- def initialize(*a)
734
+ def initialize(*a) # :nodoc:
593
735
  super
594
736
 
595
- clear
737
+ self.texture = renderer.new_texture
738
+
739
+ draw_on texture do
740
+ clear
741
+ yield if block_given?
742
+ end
596
743
  end
597
744
 
598
- def draw_and_flip n
599
- screen.update 0, 0, 0, 0
600
- # no flip
745
+ ##
746
+ # Temporarily render to a texture instead of the renderer's window,
747
+ # then copy that texture to the renderer and present it.
748
+
749
+ def draw_on texture
750
+ renderer.target = texture
751
+
752
+ yield if block_given?
753
+ ensure
754
+ renderer.target = nil
755
+ renderer.copy_texture texture
756
+ renderer.present
601
757
  end
602
- end
603
758
 
604
- if $0 == __FILE__ then
605
- SDL.init SDL::INIT_EVERYTHING
606
- SDL.set_video_mode(640, 480, 16, SDL::SWSURFACE)
607
- sleep 1
608
- puts "if you saw a window, it was working"
759
+ def pre_draw n # :nodoc:
760
+ # no clear
761
+ end
762
+
763
+ def draw_and_flip n # :nodoc:
764
+ draw_on texture do
765
+ self.draw n
766
+ end
767
+ end
609
768
  end