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.
- data/COPYING +674 -0
- data/COPYING.LESSER +165 -0
- data/README.rdoc +93 -0
- data/doc/example/bitmap_draw.rb +21 -0
- data/doc/example/bitmap_load.rb +14 -0
- data/doc/example/bitmap_new.rb +19 -0
- data/doc/example/circle.rb +24 -0
- data/doc/example/circle_alpha.rb +45 -0
- data/doc/example/circle_alpha_bitmap.rb +51 -0
- data/doc/example/circle_bitmap.rb +18 -0
- data/doc/example/clip.rb +46 -0
- data/doc/example/event_app.rb +45 -0
- data/doc/example/event_keyboard.rb +43 -0
- data/doc/example/event_mouse.rb +85 -0
- data/doc/example/font_hello.rb +22 -0
- data/doc/example/font_word_wrap.rb +44 -0
- data/doc/example/grab.rb +28 -0
- data/doc/example/init.rb +10 -0
- data/doc/example/lines.rb +49 -0
- data/doc/example/lines_aa.rb +44 -0
- data/doc/example/lines_alpha.rb +33 -0
- data/doc/example/point.rb +26 -0
- data/doc/example/rect.rb +15 -0
- data/doc/example/rect_alpha.rb +75 -0
- data/doc/example/screen_set_mode.rb +18 -0
- data/doc/example/screen_update.rb +14 -0
- data/doc/example/sfont_hello.rb +22 -0
- data/doc/example/smile.png +0 -0
- data/doc/example/smile_bounce.rb +44 -0
- data/doc/example/smile_move.rb +58 -0
- data/doc/example/smile_move_2.rb +78 -0
- data/doc/example/sound.rb +101 -0
- data/doc/example/state_app.rb +33 -0
- data/doc/example/state_keyboard.rb +23 -0
- data/doc/example/state_mouse.rb +60 -0
- data/doc/key_constants.textile +129 -0
- data/doc/key_modifiers.textile +19 -0
- data/doc/reference.textile +421 -0
- data/lib/tea.rb +34 -0
- data/lib/tea/c_bitmap.rb +122 -0
- data/lib/tea/c_error.rb +11 -0
- data/lib/tea/c_font.rb +302 -0
- data/lib/tea/c_sound.rb +144 -0
- data/lib/tea/m_color.rb +50 -0
- data/lib/tea/m_event.rb +65 -0
- data/lib/tea/m_event_app.rb +96 -0
- data/lib/tea/m_event_dispatch.rb +54 -0
- data/lib/tea/m_event_keyboard.rb +311 -0
- data/lib/tea/m_event_mouse.rb +189 -0
- data/lib/tea/mix_blitting.rb +31 -0
- data/lib/tea/mix_clipping.rb +71 -0
- data/lib/tea/mix_grabbing.rb +86 -0
- data/lib/tea/mix_image_saving.rb +70 -0
- data/lib/tea/mix_primitive.rb +613 -0
- data/lib/tea/o_screen.rb +98 -0
- 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
|