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,189 @@
1
+ # This file holds the mouse motion and button events.
2
+
3
+ require 'sdl'
4
+
5
+ #
6
+ module Tea
7
+
8
+ module Mouse
9
+
10
+ # Mouse button constants for mouse events.
11
+ LEFT = :LEFT
12
+ MIDDLE = :MIDDLE
13
+ RIGHT = :RIGHT
14
+
15
+ # Event generated when the mouse cursor is moved.
16
+ #
17
+ # +x+, +y+:: coordinates of the mouse cursor
18
+ # +buttons+:: an array that may contain +:left+, +:middle+ and +:right+
19
+ class Move
20
+ attr_reader :x, :y, :buttons
21
+ def initialize(sdl_event)
22
+ @x = sdl_event.x
23
+ @y = sdl_event.y
24
+ @buttons = {}
25
+ @buttons[Mouse::LEFT] = (sdl_event.state & SDL::Mouse::BUTTON_LMASK) != 0
26
+ @buttons[Mouse::MIDDLE] = (sdl_event.state & SDL::Mouse::BUTTON_MMASK) != 0
27
+ @buttons[Mouse::RIGHT] = (sdl_event.state & SDL::Mouse::BUTTON_RMASK) != 0
28
+ end
29
+ end
30
+
31
+ # Event generated when a mouse button is held down.
32
+ #
33
+ # +x+, +y+:: coordinates of the mouse cursor
34
+ # +button+:: the mouse button that is down: +:left+, +:middle+ or +:right+
35
+ class Down
36
+ attr_reader :x, :y, :button
37
+ def initialize(sdl_event)
38
+ @x = sdl_event.x
39
+ @y = sdl_event.y
40
+ case sdl_event.button
41
+ when SDL::Mouse::BUTTON_LEFT then @button = Mouse::LEFT
42
+ when SDL::Mouse::BUTTON_MIDDLE then @button = Mouse::MIDDLE
43
+ when SDL::Mouse::BUTTON_RIGHT then @button = Mouse::RIGHT
44
+ end
45
+ end
46
+ end
47
+
48
+ # Event generated when a mouse button that was held down is released.
49
+ #
50
+ # +x+, +y+:: coordinates of the mouse cursor
51
+ # +button+:: the mouse button that was released: +:left+, +:middle+ or
52
+ # +:right+
53
+ class Up
54
+ attr_reader :x, :y, :button
55
+ def initialize(sdl_event)
56
+ @x = sdl_event.x
57
+ @y = sdl_event.y
58
+ case sdl_event.button
59
+ when SDL::Mouse::BUTTON_LEFT then @button = Mouse::LEFT
60
+ when SDL::Mouse::BUTTON_MIDDLE then @button = Mouse::MIDDLE
61
+ when SDL::Mouse::BUTTON_RIGHT then @button = Mouse::RIGHT
62
+ end
63
+ end
64
+ end
65
+
66
+ # Event generated when the mouse wheel is scrolled.
67
+ #
68
+ # +x+, +y+:: coordinates of the mouse cursor.
69
+ # +delta+:: 1 when scrolling down, -1 when scrolling up.
70
+ class Scroll
71
+ attr_reader :x, :y, :delta
72
+ def initialize(sdl_event)
73
+ @x = sdl_event.x
74
+ @y = sdl_event.y
75
+ case sdl_event.button
76
+ when Event::BUTTON_WHEELDOWN_ then @delta = 1
77
+ when Event::BUTTON_WHEELUP_ then @delta = -1
78
+ else
79
+ raise Tea::Error, "Tea::Mouse::Scroll given an unexpected event: #{sdl_event.inspect}", caller
80
+ end
81
+ end
82
+ end
83
+
84
+ # Defaults for Mouse.x, Mouse.y, Mouse.left?, Mouse.middle?, Mouse.right?
85
+ # and Mouse.in_app?
86
+ @x = 0
87
+ @y = 0
88
+ @left = false
89
+ @middle = false
90
+ @right = false
91
+ @in_app = false
92
+
93
+ # Report the x position of the mouse in the screen window. Updated when
94
+ # Event.get is called.
95
+ def Mouse.x
96
+ @x
97
+ end
98
+
99
+ # Report the y position of the mouse in the screen window. Updated when
100
+ # Event.get is called.
101
+ def Mouse.y
102
+ @y
103
+ end
104
+
105
+ # Returns true if the left mouse button is down. Updated when Event.get is
106
+ # called.
107
+ def Mouse.left?
108
+ @left
109
+ end
110
+
111
+ # Returns true if the middle mouse button is down. Updated when Event.get
112
+ # is called.
113
+ def Mouse.middle?
114
+ @middle
115
+ end
116
+
117
+ # Returns true if the right mouse button is down. Updated when Event.get
118
+ # is called.
119
+ def Mouse.right?
120
+ @right
121
+ end
122
+
123
+ # Returns true if the mouse is in the screen window
124
+ def Mouse.in_app?
125
+ @in_app
126
+ end
127
+
128
+ # Update the mouse state, so that Mouse.x, Mouse.y, Mouse.left?,
129
+ # Mouse.middle? and Mouse.right? return recent data.
130
+ def Mouse.update_state(tea_event)
131
+ case tea_event
132
+ when Move
133
+ @x = tea_event.x
134
+ @y = tea_event.y
135
+ when Down
136
+ case tea_event.button
137
+ when LEFT then @left = true
138
+ when MIDDLE then @middle = true
139
+ when RIGHT then @right = true
140
+ end
141
+ when Up
142
+ case tea_event.button
143
+ when LEFT then @left = false
144
+ when MIDDLE then @middle = false
145
+ when RIGHT then @right = false
146
+ end
147
+ when Lost
148
+ @in_app = false
149
+ when Gained
150
+ @in_app = true
151
+ end
152
+ end
153
+ end
154
+
155
+ module Event
156
+
157
+ # Missing mouse wheel button constants from rubysdl. For internal use only.
158
+ BUTTON_WHEELUP_ = 4
159
+ BUTTON_WHEELDOWN_ = 5
160
+
161
+ # Convert a mouse-related SDL::Event into a Tea event. For internal use only.
162
+ def Event.translate_mouse_event(sdl_event)
163
+ out_events = []
164
+
165
+ case sdl_event
166
+ when SDL::Event::MouseMotion
167
+ out_events.push Mouse::Move.new(sdl_event)
168
+ when SDL::Event::MouseButtonDown
169
+ case sdl_event.button
170
+ when SDL::Mouse::BUTTON_LEFT, SDL::Mouse::BUTTON_MIDDLE, SDL::Mouse::BUTTON_RIGHT
171
+ out_events.push Mouse::Down.new(sdl_event)
172
+ when BUTTON_WHEELDOWN_, BUTTON_WHEELUP_
173
+ out_events.push Mouse::Scroll.new(sdl_event)
174
+ end
175
+ when SDL::Event::MouseButtonUp
176
+ # Ignore MouseButtonUp for the scroll wheel.
177
+ case sdl_event.button
178
+ when SDL::Mouse::BUTTON_LEFT, SDL::Mouse::BUTTON_MIDDLE, SDL::Mouse::BUTTON_RIGHT
179
+ out_events.push Mouse::Up.new(sdl_event)
180
+ end
181
+ end
182
+
183
+ out_events
184
+ end
185
+ private_class_method :translate_mouse_event
186
+
187
+ end
188
+
189
+ end
@@ -0,0 +1,31 @@
1
+ # This file contains the Blitting mixin.
2
+
3
+ require 'sdl'
4
+
5
+ #
6
+ module Tea
7
+
8
+ # The Blitting mixin allows objects with SDL::Surface to draw or 'blit' onto
9
+ # each other.
10
+ #
11
+ # To use this mixin, include it and write/alias a blitting_buffer method
12
+ # that gets the SDL::Surface.
13
+ #
14
+ # include Blitting
15
+ # def blitting_buffer
16
+ # @my_sdl_surface
17
+ # end
18
+ module Blitting
19
+
20
+ # Draw the source_blittable onto the current object at (x, y).
21
+ #
22
+ # source_blittable needs to include the Blitting mixin too.
23
+ def blit(source_blittable, x, y)
24
+ src = source_blittable.blitting_buffer
25
+ dest = blitting_buffer
26
+ SDL::Surface.blit src, 0, 0, src.w, src.h, dest, x, y
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,71 @@
1
+ # This file holds the Clipping mixin.
2
+
3
+ require 'sdl'
4
+
5
+ #
6
+ module Tea
7
+
8
+ # The Clipping mixin enables anything with an SDL-like buffer can get, set
9
+ # and use a clipping rectangle to restrict where drawing takes place.
10
+ #
11
+ # To use the Clipping mixin, include it, and provide a clipping_buffer method
12
+ # that returns the buffer to be clipped.
13
+ #
14
+ # include Tea::Clipping
15
+ # def clipping_buffer
16
+ # @sdl_buffer
17
+ # end
18
+ module Clipping
19
+
20
+ # Get, set or run a block with a clipping rectangle that restricts where
21
+ # drawing can take place.
22
+ #
23
+ # Getting the current clipping rectangle:
24
+ #
25
+ # x, y, width, height = clippable_object.clip
26
+ #
27
+ # Setting a new clipping rectangle:
28
+ #
29
+ # old_x, old_y, old_w, old_h = clippable_object.clip(new_x, new_y, new_w, new_h)
30
+ #
31
+ # Running a block with a clipping rectangle temporarily set:
32
+ #
33
+ # clippable_object.clip(clip_x, clip_y, clip_w, clip_h) do
34
+ # # Draw onto clippable_object within clip rect here.
35
+ # end
36
+ #
37
+ def clip(x=nil, y=nil, w=nil, h=nil)
38
+ buffer = clipping_buffer
39
+
40
+ # rubysdl's SDL::Surface#get_clip_rect doesn't return anything useful.
41
+ # Seems to be a bug, or at least compilation quirk.
42
+ @clipping_rect = [0, 0, buffer.w, buffer.h] unless @clipping_rect
43
+ old_clipping_rect = @clipping_rect
44
+
45
+ case
46
+ when !(x || y || w || h) # Get clip rect.
47
+ # Do nothing.
48
+ when x && y && w && h && !block_given? # Set clip rect.
49
+ @clipping_rect = [x, y, w, h]
50
+ buffer.set_clip_rect *@clipping_rect
51
+ when x && y && w && h && block_given? # Run block with clip rect.
52
+ @clipping_rect = [x, y, w, h]
53
+ buffer.set_clip_rect *@clipping_rect
54
+ begin
55
+ yield
56
+ ensure
57
+ @clipping_rect = old_clipping_rect
58
+ buffer.set_clip_rect *old_clipping_rect
59
+ end
60
+ else
61
+ arg_count = 0
62
+ [x, y, w, h].each { |arg| arg_count += 1 if arg == nil }
63
+ raise ArgumentError, "wrong number of arguments (#{arg_count} for 0 or 4)", caller
64
+ end
65
+
66
+ old_clipping_rect
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -0,0 +1,86 @@
1
+ # This file contains the Grabbing mixin, which makes a new Bitmap object based
2
+ # on some part of a bitmap-like pixel buffer.
3
+
4
+ require 'sdl'
5
+
6
+ require 'tea/c_bitmap'
7
+ require 'tea/m_color'
8
+
9
+ #
10
+ module Tea
11
+
12
+ # This module gives bitmap-like objects a +grab+ method that takes a
13
+ # 'snapshot' of some part of it and returns it as a new Bitmap.
14
+ #
15
+ # To use this mixin, include it and define a +grabbing_buffer+ method:
16
+ #
17
+ # include Grabbing
18
+ # def grabbing_buffer
19
+ # @my_sdl_buffer
20
+ # end
21
+ #
22
+ module Grabbing
23
+
24
+ # Grab some part of the bitmap-like object, and return it as a new
25
+ # Tea::Bitmap object.
26
+ #
27
+ # This can be called in two ways:
28
+ #
29
+ # * ():: create a deep-copy of the whole bitmap-like object.
30
+ # * (x, y, w, h):: copy the pixels within the box at (x, y) of size w * h.
31
+ #
32
+ # May raise Tea::Error if the box given (if any) is outside the bitmap.
33
+ def grab(*box)
34
+ buffer = grabbing_buffer
35
+
36
+ case box.length
37
+ when 0
38
+ x = 0
39
+ y = 0
40
+ w = buffer.w
41
+ h = buffer.h
42
+ when 4
43
+ if clipped_box = grabbing_clip(*box, 0, 0, buffer.w, buffer.h)
44
+ x, y, w, h = clipped_box
45
+ else
46
+ raise Tea::Error, "cannot grab (#{x}, #{y}, #{w}, #{h}), not within (#{buffer.x}, #{buffer.y}, #{buffer.w}, #{buffer.h})", caller
47
+ end
48
+ else
49
+ raise ArgumentError, "wrong number of arguments (#{box.length} for 0 or 4)", caller
50
+ end
51
+
52
+ bitmap = Bitmap.new(w, h, Tea::Color::CLEAR)
53
+
54
+ for buf_y in y...(y + h)
55
+ for buf_x in x...(x + w)
56
+ bitmap[buf_x - x, buf_y - y] = Color.mix(*buffer.get_rgba(buffer[buf_x, buf_y]))
57
+ end
58
+ end
59
+
60
+ bitmap
61
+ end
62
+
63
+ # Keep the rect (x, y, w, h) within the rect (bound_x, bound_y, bound_w, bound_h).
64
+ #
65
+ # Returns [in_x, in_y, in_w, in_h], defining a rect like (x, y, w, h), but
66
+ # within the bounding rect. Returns nil if the rect given is not within
67
+ # the bounding rect at all, i.e. w or h would be less than 1.
68
+ def grabbing_clip(x, y, w, h, bound_x, bound_y, bound_w, bound_h)
69
+ return nil if x + w <= bound_x || x >= bound_x + bound_w || y + h <= bound_y || y >= bound_y + bound_h
70
+
71
+ in_x = (x >= bound_x) ? x : bound_x
72
+ in_y = (y >= bound_y) ? y : bound_y
73
+
74
+ x2 = x + w
75
+ y2 = y + h
76
+ in_x2 = (x2 <= bound_x + bound_w) ? x2 : bound_x + bound_w
77
+ in_y2 = (y2 <= bound_y + bound_h) ? y2 : bound_y + bound_h
78
+ in_w = in_x2 - in_x
79
+ in_h = in_y2 - in_y
80
+
81
+ [in_x, in_y, in_w, in_h]
82
+ end
83
+
84
+ end
85
+
86
+ end
@@ -0,0 +1,70 @@
1
+ # This file holds the ImageSaving mixin.
2
+
3
+ require 'RMagick'
4
+ require 'sdl'
5
+
6
+ require 'tea/c_error'
7
+
8
+ #
9
+ module Tea
10
+
11
+ # This mixin allows SDL surface-backed classes to be saved as image files.
12
+ #
13
+ # To use, include the mixin and implement an image_saving_buffer method:
14
+ #
15
+ # include ImageSaving
16
+ # def image_saving_buffer
17
+ # @my_sdl_buffer
18
+ # end
19
+ module ImageSaving
20
+
21
+ # Save the object as an image file at the given path.
22
+ #
23
+ # The format is determined by the extension at the end of the path. ".bmp"
24
+ # will save it as Windows Bitmap image.
25
+ #
26
+ # May raise Tea::Error if the desired image file format can't be
27
+ # determined, or isn't supported.
28
+ def save(path)
29
+ extension_match = /\..+$/.match(path)
30
+
31
+ if extension_match
32
+ ext = extension_match[0]
33
+ case ext
34
+ when '.bmp'
35
+ image_saving_buffer.save_bmp path
36
+ when '.png'
37
+ image_saving_cheat_save path
38
+ else
39
+ raise Tea::Error, "can't determine image format '#{ext}' for saving", caller
40
+ end
41
+ else
42
+ raise Tea::Error, "can't determine desired image file format for #{path}", caller
43
+ end
44
+
45
+ rescue SDL::Error => e
46
+ raise Tea::Error, e.message, e.backtrace
47
+ end
48
+
49
+ private
50
+
51
+ # Cheat by using RMagick to save in formats other than BMP.
52
+ def image_saving_cheat_save(path)
53
+ buffer = image_saving_buffer
54
+
55
+ buffer_string = String.new
56
+ for y in 0...buffer.h
57
+ for x in 0...buffer.w
58
+ r, g, b, a = buffer.get_rgba(buffer[x, y])
59
+ buffer_string << r << g << b << a
60
+ end
61
+ end
62
+
63
+ image = Magick::Image.new(buffer.w, buffer.h)
64
+ image.import_pixels 0, 0, buffer.h, buffer.w, 'RGBA', buffer_string, Magick::CharPixel
65
+ image.write path
66
+ end
67
+
68
+ end
69
+
70
+ end