tea 0.6.1

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 (56) hide show
  1. data/COPYING +674 -0
  2. data/COPYING.LESSER +165 -0
  3. data/README.rdoc +93 -0
  4. data/doc/example/bitmap_draw.rb +21 -0
  5. data/doc/example/bitmap_load.rb +14 -0
  6. data/doc/example/bitmap_new.rb +19 -0
  7. data/doc/example/circle.rb +24 -0
  8. data/doc/example/circle_alpha.rb +45 -0
  9. data/doc/example/circle_alpha_bitmap.rb +51 -0
  10. data/doc/example/circle_bitmap.rb +18 -0
  11. data/doc/example/clip.rb +46 -0
  12. data/doc/example/event_app.rb +45 -0
  13. data/doc/example/event_keyboard.rb +43 -0
  14. data/doc/example/event_mouse.rb +85 -0
  15. data/doc/example/font_hello.rb +22 -0
  16. data/doc/example/font_word_wrap.rb +44 -0
  17. data/doc/example/grab.rb +28 -0
  18. data/doc/example/init.rb +10 -0
  19. data/doc/example/lines.rb +49 -0
  20. data/doc/example/lines_aa.rb +44 -0
  21. data/doc/example/lines_alpha.rb +33 -0
  22. data/doc/example/point.rb +26 -0
  23. data/doc/example/rect.rb +15 -0
  24. data/doc/example/rect_alpha.rb +75 -0
  25. data/doc/example/screen_set_mode.rb +18 -0
  26. data/doc/example/screen_update.rb +14 -0
  27. data/doc/example/sfont_hello.rb +22 -0
  28. data/doc/example/smile.png +0 -0
  29. data/doc/example/smile_bounce.rb +44 -0
  30. data/doc/example/smile_move.rb +58 -0
  31. data/doc/example/smile_move_2.rb +78 -0
  32. data/doc/example/sound.rb +101 -0
  33. data/doc/example/state_app.rb +33 -0
  34. data/doc/example/state_keyboard.rb +23 -0
  35. data/doc/example/state_mouse.rb +60 -0
  36. data/doc/key_constants.textile +129 -0
  37. data/doc/key_modifiers.textile +19 -0
  38. data/doc/reference.textile +421 -0
  39. data/lib/tea.rb +34 -0
  40. data/lib/tea/c_bitmap.rb +122 -0
  41. data/lib/tea/c_error.rb +11 -0
  42. data/lib/tea/c_font.rb +302 -0
  43. data/lib/tea/c_sound.rb +144 -0
  44. data/lib/tea/m_color.rb +50 -0
  45. data/lib/tea/m_event.rb +65 -0
  46. data/lib/tea/m_event_app.rb +96 -0
  47. data/lib/tea/m_event_dispatch.rb +54 -0
  48. data/lib/tea/m_event_keyboard.rb +311 -0
  49. data/lib/tea/m_event_mouse.rb +189 -0
  50. data/lib/tea/mix_blitting.rb +31 -0
  51. data/lib/tea/mix_clipping.rb +71 -0
  52. data/lib/tea/mix_grabbing.rb +86 -0
  53. data/lib/tea/mix_image_saving.rb +70 -0
  54. data/lib/tea/mix_primitive.rb +613 -0
  55. data/lib/tea/o_screen.rb +98 -0
  56. metadata +137 -0
@@ -0,0 +1,46 @@
1
+ # Test that getting, setting and using the clip rectangle all work.
2
+ # Expected result is a rectangle of smileys, and one at the bottom-right
3
+ # corner.
4
+
5
+ require 'tea'
6
+
7
+ puts <<TEST
8
+ You should see a rectangle of smileys, and one in the bottom-right corner,
9
+ for 10 seconds.
10
+
11
+ Expected output:
12
+ Clip rect is 0, 0, 400, 300
13
+ Clip rect is now 50, 50, 290, 185
14
+ Clip rect is 0, 0, 400, 300 again
15
+ Clip rect is now 368, 268, 32, 32
16
+
17
+ Actual output:
18
+ TEST
19
+
20
+ Tea.init
21
+ Tea::Screen.set_mode 400, 300
22
+
23
+ puts "Clip rect is #{Tea::Screen.clip.join(", ")}"
24
+
25
+ smiley = Tea::Bitmap.new('smile.png')
26
+
27
+ Tea::Screen.clip(50, 50, 290, 185) do
28
+ puts "Clip rect is now #{Tea::Screen.clip.join(", ")}"
29
+
30
+ for y in 0..(Tea::Screen.h / smiley.h)
31
+ for x in 0..(Tea::Screen.w / smiley.w)
32
+ Tea::Screen.blit smiley, x * smiley.w, y * smiley.h
33
+ end
34
+ end
35
+ end
36
+
37
+ puts "Clip rect is #{Tea::Screen.clip.join(", ")} again"
38
+
39
+ Tea::Screen.clip Tea::Screen.w - smiley.w, Tea::Screen.h - smiley.h, smiley.w, smiley.h
40
+ Tea::Screen.blit smiley, Tea::Screen.w - smiley.w, Tea::Screen.h - smiley.h
41
+
42
+ puts "Clip rect is now #{Tea::Screen.clip.join(", ")}"
43
+
44
+ Tea::Screen.update
45
+
46
+ sleep 10
@@ -0,0 +1,45 @@
1
+ # Test that app events are being picked up.
2
+ # This test is interactive, and should display messages for:
3
+ #
4
+ # * Gaining and losing mouse focus
5
+ # * Gaining and losing keyboard focus
6
+ # * Minimising and restoring the screen window
7
+ # * App exit
8
+
9
+ require 'tea'
10
+
11
+ puts <<TEST
12
+ This is an interactive event test. It should display messages for:
13
+
14
+ * Gaining and losing mouse focus
15
+ * Gaining and losing keyboard focus
16
+ * Minimising and restoring the screen window
17
+ * App exit
18
+
19
+ Go ahead and start doing things like changing focus.
20
+
21
+ TEST
22
+
23
+ Tea.init
24
+ Tea::Screen.set_mode 320, 240
25
+
26
+ loop do
27
+ case (e = Tea::Event.get)
28
+ when Tea::Mouse::Gained
29
+ puts 'Mouse::Gained event received'
30
+ when Tea::Mouse::Lost
31
+ puts 'Mouse::Lost event received'
32
+ when Tea::Kbd::Gained
33
+ puts 'Kbd::Gained event received'
34
+ when Tea::Kbd::Lost
35
+ puts 'Kbd::Lost event received'
36
+ when Tea::App::Restored
37
+ puts 'App::Restored event received'
38
+ when Tea::App::Minimized
39
+ puts 'App::Minimized event received'
40
+ when Tea::App::Exit
41
+ puts 'App::Exit event received'
42
+ exit
43
+ end
44
+ sleep 0.01
45
+ end
@@ -0,0 +1,43 @@
1
+ # Test that keyboard events are being picked up.
2
+ # Expected results are messages responding to key presses.
3
+
4
+ require 'tea'
5
+
6
+ puts <<TEST
7
+ You should see a small window. Try pressing some keys, or Esc to exit.
8
+ TEST
9
+
10
+ Tea.init
11
+ Tea::Screen.set_mode 320, 240
12
+
13
+ loop do
14
+ e = Tea::Event.get(true)
15
+
16
+ break if e.class == Tea::App::Exit
17
+ next unless e.class == Tea::Kbd::Down || e.class == Tea::Kbd::Up
18
+ break if e.key == Tea::Kbd::ESCAPE
19
+
20
+ out = []
21
+
22
+ if e.class == Tea::Kbd::Down
23
+ out << 'down:'
24
+ else
25
+ out << ' up:'
26
+ end
27
+
28
+ out << '(' << e.key.to_s << ')'
29
+
30
+ if RUBY_VERSION =~ /1\.8/
31
+ mods = (e.mods.select { |mod, down| down }).map { |pair| pair[0] }
32
+ else
33
+ mods = (e.mods.select { |mod, down| down }).keys
34
+ end
35
+ out << "++ #{mods.join(' + ')}" if mods.length > 0
36
+
37
+ if e.respond_to?(:char)
38
+ out << '='
39
+ out << "\"#{e.char}\""
40
+ end
41
+
42
+ puts out.join(' ')
43
+ end
@@ -0,0 +1,85 @@
1
+ # Test that mouse events are being picked up.
2
+ # Expected output is reporting of mouse move/down/up/scroll events, with
3
+ # position and relevant buttons.
4
+
5
+ require 'tea'
6
+
7
+ puts <<TEST
8
+ Move the mouse in the window. Mouse move/down/up events should be reported,
9
+ with position and relevant buttons. Mouse wheel scrolling should also be
10
+ picked up, with at least the cursor position.
11
+ TEST
12
+
13
+ ##############################################################################
14
+
15
+ # We can avoid flooding the terminal with VT100 codes. Sorry Windows.
16
+ $windows = RUBY_PLATFORM =~ /w(?:in)?32/
17
+ SAVE_POSITION = "\x1b[s"
18
+ RESTORE_POSITION = "\x1b[u"
19
+ HIDE_CURSOR = "\x1b[?25l"
20
+ UNHIDE_CURSOR = "\x1b[?25h"
21
+ CLEAR_TO_LINE_END = "\x1b[K"
22
+
23
+ # VT100-enhanced printing function that overwrites the current terminal line.
24
+ def pr(*args)
25
+ print HIDE_CURSOR, SAVE_POSITION if !$windows
26
+ print *args
27
+ if $windows
28
+ puts
29
+ else
30
+ print CLEAR_TO_LINE_END, RESTORE_POSITION, UNHIDE_CURSOR
31
+ end
32
+ end
33
+
34
+ ##############################################################################
35
+
36
+ Tea.init
37
+ Tea::Screen.set_mode 400, 300
38
+
39
+ # Event tracking to only put newlines when the event class changes.
40
+ mouse_events = [Tea::Mouse::Move,
41
+ Tea::Mouse::Down,
42
+ Tea::Mouse::Up,
43
+ Tea::Mouse::Scroll]
44
+ handled = false
45
+ last_event_class = Tea::Mouse::Move
46
+
47
+ # Track repeated scrolling in the same direction.
48
+ scroll_pos = 0
49
+
50
+ loop do
51
+ e = Tea::Event.get(true)
52
+
53
+ if e.class == Tea::App::Exit
54
+ puts
55
+ break
56
+ end
57
+
58
+ # Put a newline when the event class changes.
59
+ if handled && mouse_events.include?(e.class) && e.class != last_event_class
60
+ puts
61
+ last_event_class = e.class
62
+ scroll_pos = 0
63
+ end
64
+
65
+ handled = true
66
+ case e
67
+ when Tea::Mouse::Move
68
+ if RUBY_VERSION =~ /1\.8/
69
+ buttons = (e.buttons.select { |button, down| down }).map { |pair| pair[0] }
70
+ else
71
+ buttons = (e.buttons.select { |button, down| down }).keys
72
+ end
73
+ pr "mouse move : x = #{e.x}, y = #{e.y}, buttons = #{buttons.join(',')}"
74
+ when Tea::Mouse::Down
75
+ pr "mouse down : x = #{e.x}, y = #{e.y}, button = #{e.button}"
76
+ when Tea::Mouse::Up
77
+ pr "mouse up : x = #{e.x}, y = #{e.y}, button = #{e.button}"
78
+ when Tea::Mouse::Scroll
79
+ dir = e.delta == 1 ? 'down' : 'up '
80
+ scroll_pos += e.delta
81
+ pr "scroll #{dir}: x = #{e.x}, y = #{e.y}, position = #{scroll_pos} (#{e.delta})"
82
+ else
83
+ handled = false
84
+ end
85
+ end
@@ -0,0 +1,22 @@
1
+ # This tests that fonts can be loaded, rendered and drawn.
2
+ # Expected result: 'hello' in a small window for 5 seconds.
3
+
4
+ require 'tea'
5
+
6
+ puts <<TEST
7
+ You should see 'hello' in a small window for 5 seconds.
8
+ TEST
9
+
10
+ Tea.init
11
+ Tea::Screen.set_mode 320, 240
12
+
13
+ font = Tea::Font.new('font.bmp', Tea::Font::BITMAP_FONT, :transparent_color => Tea::Color::MAGENTA)
14
+ message = 'hello'
15
+
16
+ x = (Tea::Screen.w - font.string_w(message)) / 2
17
+ y = (Tea::Screen.h - font.h) / 2
18
+ font.draw_to Tea::Screen, x, y, message
19
+
20
+ Tea::Screen.update
21
+
22
+ sleep 5
@@ -0,0 +1,44 @@
1
+ # Test that word-wrapping works.
2
+
3
+ require 'tea'
4
+
5
+ puts <<TEST
6
+ You should see several lines of bitmapped and SFont text.
7
+ Magenta lines indicate the end of the final lines.
8
+ Press any key to exit.
9
+ TEST
10
+
11
+ Tea.init
12
+ Tea::Screen.set_mode 400, 300
13
+
14
+ message = "This is a long line. " +
15
+ "I hope it's long enough to wrap around. " +
16
+ "If it wraps, then font word wrapping is working."
17
+
18
+ font_a = Tea::Font.new('font.bmp', Tea::Font::BITMAP_FONT, :transparent_color => Tea::Color::MAGENTA)
19
+ font_b = Tea::Font.new('sfont.png', Tea::Font::SFONT)
20
+
21
+ lines_a = font_a.word_wrap(message, Tea::Screen.w)
22
+ lines_b = font_b.word_wrap(message, Tea::Screen.w)
23
+
24
+ y_pos = 0
25
+ lines_a.each do |line|
26
+ break if y_pos + font_a.h >= Tea::Screen.h / 2
27
+ font_a.draw_to Tea::Screen, 0, y_pos, line
28
+ y_pos += font_a.h
29
+ end
30
+ Tea::Screen.line lines_a.end_x, 0, lines_a.end_x, y_pos, Tea::Color::MAGENTA
31
+
32
+ old_y_pos = y_pos
33
+ lines_b.each do |line|
34
+ break if y_pos + font_b.h >= Tea::Screen.h
35
+ font_b.draw_to Tea::Screen, 0, y_pos, line
36
+ y_pos += font_b.h
37
+ end
38
+ Tea::Screen.line lines_b.end_x, old_y_pos, lines_b.end_x, y_pos, Tea::Color::MAGENTA
39
+
40
+ Tea::Screen.update
41
+
42
+ begin
43
+ e = Tea::Event.get(true)
44
+ end until e.class == Tea::App::Exit || e.class == Tea::Kbd::Down
@@ -0,0 +1,28 @@
1
+ # Test that grabbing from bitmaps works.
2
+ # Expected results are a smiley on the screen, but with its quarters swapped.
3
+
4
+ require 'tea'
5
+
6
+ puts <<TEST
7
+ You should see a smiley in the centre of the screen for 5 seconds, but with its
8
+ quarters swapped.
9
+ TEST
10
+
11
+ Tea.init
12
+ Tea::Screen.set_mode 320, 240
13
+
14
+ smiley = Tea::Bitmap.new("smile.png")
15
+ sw2 = smiley.w / 2
16
+ sh2 = smiley.h / 2
17
+ top_left = smiley.grab( 0, 0, sw2, sh2)
18
+ top_right = smiley.grab(sw2, 0, sw2, sh2)
19
+ bottom_left = smiley.grab( 0, sh2, sw2, sh2)
20
+ bottom_right = smiley.grab(sw2, sh2, sw2, sh2)
21
+
22
+ Tea::Screen.blit bottom_right, Tea::Screen.w / 2 - sw2, Tea::Screen.h / 2 - sh2
23
+ Tea::Screen.blit bottom_left, Tea::Screen.w / 2, Tea::Screen.h / 2 - sh2
24
+ Tea::Screen.blit top_right, Tea::Screen.w / 2 - sw2, Tea::Screen.h / 2
25
+ Tea::Screen.blit top_left, Tea::Screen.w / 2, Tea::Screen.h / 2
26
+ Tea::Screen.update
27
+
28
+ sleep 5
@@ -0,0 +1,10 @@
1
+ # Test if Tea can initialise.
2
+ # Expected result is nothing.
3
+
4
+ require 'tea'
5
+
6
+ puts <<TEST
7
+ This line should be the only output of this test.
8
+ TEST
9
+
10
+ Tea.init
@@ -0,0 +1,49 @@
1
+ # Test that lines of various colours can be drawn.
2
+ # Expected results are a 400x300 for 5 seconds with:
3
+ #
4
+ # * 3 vertical lines on the left: red, green, blue
5
+ # * 3 horizontal lines at the top-right: yellow, magenta, cyan
6
+ # * 2 diagonal lines at the bottom-right: white and grey
7
+ #
8
+ # The white line should be antialiased.
9
+
10
+ require 'tea'
11
+
12
+ puts <<TEST
13
+ You should see a 400x300 window for 5 seconds with:
14
+
15
+ * 3 vertical lines on the left: red, green, blue
16
+ * 3 horizontal lines at the top-right: yellow, magenta, cyan
17
+ * 2 diagonal lines at the bottom-right: white and grey
18
+
19
+ The white line should be antialiased.
20
+ TEST
21
+
22
+ Tea.init
23
+ Tea::Screen.set_mode 400, 300
24
+
25
+ grid_x = Tea::Screen.w / 10
26
+ grid_y = Tea::Screen.h / 10
27
+
28
+ lines = [[1, 1, 1, 9, Tea::Color::RED],
29
+ [2, 1, 2, 9, Tea::Color::GREEN],
30
+ [3, 1, 3, 9, Tea::Color::BLUE],
31
+ [6, 1, 9, 1, Tea::Color::YELLOW],
32
+ [6, 2, 9, 2, Tea::Color::MAGENTA],
33
+ [6, 3, 9, 3, Tea::Color::CYAN],
34
+ [6, 9, 9, 6, Tea::Color::DARK_GRAY]]
35
+
36
+ lines.each do |line|
37
+ Tea::Screen.line grid_x * line[0], grid_y * line[1],
38
+ grid_x * line[2], grid_y * line[3],
39
+ line[4]
40
+ end
41
+
42
+ Tea::Screen.line grid_x * 6, grid_y * 6,
43
+ grid_x * 9, grid_y * 9,
44
+ Tea::Color::WHITE,
45
+ :antialias => true
46
+
47
+ Tea::Screen.update
48
+
49
+ sleep 5
@@ -0,0 +1,44 @@
1
+ # Test that anti-aliased lines work as expected.
2
+ # Anti-aliased lines in replace mode should just overwrite the RGBA of the
3
+ # pixels it affects. In blend mode, the line RGB and destination RGB should be
4
+ # blended according to their ratio, while the final alpha should be the sum of
5
+ # the line and destination alpha values.
6
+
7
+ require 'tea'
8
+
9
+ puts <<TEST
10
+ You should see 16 green lines in a wheel, with a green dot in the center,
11
+ against a grey square.
12
+
13
+ Press any key to exit.
14
+ TEST
15
+
16
+ Tea.init
17
+ Tea::Screen.set_mode 400, 300
18
+
19
+ b = Tea::Bitmap.new(250, 250, Tea::Color.mix(0, 0, 0, 0))
20
+ CENTER_X = b.w / 2
21
+ CENTER_Y = b.h / 2
22
+ LINE_CENTER_CLEARANCE = 10
23
+ LINE_LENGTH = 100
24
+ LINE_COLOR = Tea::Color.mix(0, 255, 0, 128)
25
+ SPOKES = 16
26
+
27
+ Tea::Screen.rect 150, 100, 100, 100, Tea::Color.mix(64, 64, 64)
28
+
29
+ b.line CENTER_X, CENTER_Y, CENTER_X, CENTER_Y, LINE_COLOR, :antialias => true, :mix => :replace
30
+
31
+ SPOKES.times do |n|
32
+ angle = n * Math::PI * 2 / SPOKES
33
+ x1 = CENTER_X + LINE_CENTER_CLEARANCE * Math.cos(angle)
34
+ y1 = CENTER_Y + LINE_CENTER_CLEARANCE * Math.sin(angle)
35
+ x2 = CENTER_X + (LINE_CENTER_CLEARANCE + LINE_LENGTH) * Math.cos(angle)
36
+ y2 = CENTER_Y + (LINE_CENTER_CLEARANCE + LINE_LENGTH) * Math.sin(angle)
37
+ b.line x1, y1, x2, y2, LINE_COLOR, :antialias => true, :mix => n.even? ? :blend : :replace
38
+ end
39
+
40
+ Tea::Screen.blit b, (Tea::Screen.w - b.w) / 2, (Tea::Screen.h - b.h) / 2
41
+ Tea::Screen.update
42
+ begin
43
+ e = Tea::Event.get(true)
44
+ end until e.class == Tea::App::Exit || e.class == Tea::Kbd::Down
@@ -0,0 +1,33 @@
1
+ # Test that line alpha mixes properly.
2
+ # Expected results:
3
+ #
4
+ # * half-red background
5
+ # * green line, translucent
6
+ # * blue line, translucent
7
+ # * white line, solid
8
+
9
+ require 'tea'
10
+
11
+ puts <<TEST
12
+ You should see for 5 seconds:
13
+
14
+ * half-red background
15
+ * green line, translucent
16
+ * blue line, translucent
17
+ * white line, solid
18
+ TEST
19
+
20
+ Tea.init
21
+ Tea::Screen.set_mode 400, 300
22
+
23
+ tl_green = Tea::Color.mix( 0, 255, 0, 128)
24
+ tl_blue = Tea::Color.mix( 0, 0, 255, 128)
25
+ tl_white = Tea::Color.mix(255, 255, 255, 128)
26
+
27
+ Tea::Screen.rect 200, 0, 200, 300, Tea::Color::RED
28
+ 20.times { |n| Tea::Screen.line 10, 10 + n, 390, 10 + n, tl_green }
29
+ 20.times { |n| Tea::Screen.line 10, 100 + n, 390, 100 + n, tl_blue, :mix => :blend }
30
+ 20.times { |n| Tea::Screen.line 10, 200 + n, 390, 200 + n, tl_white, :mix => :replace }
31
+
32
+ Tea::Screen.update
33
+ sleep 5