tea 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
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