tung-tea 0.2.1 → 0.2.2
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/README.rdoc +6 -16
- data/doc/example/lines_aa.rb +1 -2
- data/doc/example/rect_alpha.rb +47 -7
- data/doc/reference.textile +5 -0
- data/lib/tea/m_primitive_drawing.rb +108 -55
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -65,25 +65,15 @@ Below is a simple bouncing circle demo.
|
|
65
65
|
|
66
66
|
== Status
|
67
67
|
|
68
|
-
What's
|
69
|
-
|
70
|
-
*
|
71
|
-
|
72
|
-
- Tea::Bitmap (loaded from PNGs)
|
73
|
-
- Drawing of bitmaps on the screen/other bitmaps.
|
74
|
-
- Drawing of primitive shapes (rects, lines, circles).
|
75
|
-
* Events
|
76
|
-
- Tea::Event.get.
|
77
|
-
- Tea::App::Minimized, Restored.
|
78
|
-
- Tea::Kbd::Down, Up.
|
79
|
-
- Tea::Mouse::Move, Down, Up, Scroll.
|
80
|
-
- State checking of App, Kbd, Mouse.
|
68
|
+
What's working:
|
69
|
+
|
70
|
+
* Events/Input - done
|
71
|
+
* Graphics - halfway done, fixing transparency, grabbing sub-bitmaps
|
81
72
|
|
82
73
|
What isn't done yet:
|
83
74
|
|
84
|
-
*
|
85
|
-
*
|
86
|
-
* Handling of alpha in colours for primitives
|
75
|
+
* Fonts - support bitmap and TrueType fonts in ASCII
|
76
|
+
* Sound - support loading and playing sound files
|
87
77
|
|
88
78
|
|
89
79
|
== More information
|
data/doc/example/lines_aa.rb
CHANGED
@@ -8,7 +8,7 @@ require 'tea'
|
|
8
8
|
|
9
9
|
puts <<TEST
|
10
10
|
You should see 16 green lines in a wheel, with a green dot in the center,
|
11
|
-
against a grey
|
11
|
+
against a grey square.
|
12
12
|
|
13
13
|
Press any key to exit.
|
14
14
|
TEST
|
@@ -28,7 +28,6 @@ Tea::Screen.rect 150, 100, 100, 100, 0x404040ff
|
|
28
28
|
|
29
29
|
b.line CENTER_X, CENTER_Y, CENTER_X, CENTER_Y, LINE_COLOR, :antialias => true, :mix => :replace
|
30
30
|
|
31
|
-
# TODO: Enable lines for all spokes.
|
32
31
|
SPOKES.times do |n|
|
33
32
|
angle = n * Math::PI * 2 / SPOKES
|
34
33
|
x1 = CENTER_X + LINE_CENTER_CLEARANCE * Math.cos(angle)
|
data/doc/example/rect_alpha.rb
CHANGED
@@ -9,22 +9,62 @@
|
|
9
9
|
require 'tea'
|
10
10
|
|
11
11
|
puts <<TEST
|
12
|
-
You should see
|
12
|
+
You should see:
|
13
13
|
|
14
14
|
* center: red rectangle (background)
|
15
15
|
* top-left: translucent green rectangle
|
16
16
|
* bottom-left: translucent white rectangle
|
17
17
|
* bottom-right: solid blue rectangle
|
18
|
+
|
19
|
+
A smaller box with these same rectangles should appear in the top-right. It
|
20
|
+
can be moved with the arrow keys.
|
21
|
+
|
22
|
+
Press ESC key to exit.
|
18
23
|
TEST
|
19
24
|
|
20
25
|
Tea.init
|
21
26
|
Tea::Screen.set_mode 400, 300
|
22
27
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
28
|
+
x, y = 205, 15
|
29
|
+
up, down, left, right = false, false, false, false
|
30
|
+
wait_for_event = true
|
31
|
+
|
32
|
+
begin
|
33
|
+
Tea::Screen.clear
|
34
|
+
|
35
|
+
Tea::Screen.rect 100, 75, 200, 150, 0xff0000ff
|
36
|
+
Tea::Screen.rect 0, 0, 200, 150, 0x00ff0080, :mix => :blend
|
37
|
+
Tea::Screen.rect 200, 150, 200, 150, 0x0000ff80, :mix => :replace
|
38
|
+
Tea::Screen.rect 0, 150, 200, 150, 0xffffff80
|
27
39
|
|
28
|
-
Tea::
|
40
|
+
b = Tea::Bitmap.new(180, 130, 0x00000000)
|
41
|
+
b.rect 45, 32, 90, 65, 0xff0000ff
|
42
|
+
b.rect 0, 0, 90, 65, 0x00ff0080, :mix => :blend
|
43
|
+
b.rect 90, 65, 90, 65, 0x0000ff80, :mix => :replace
|
44
|
+
b.rect 0, 65, 90, 65, 0xffffff80
|
45
|
+
Tea::Screen.blit b, x, y
|
29
46
|
|
30
|
-
|
47
|
+
Tea::Screen.update
|
48
|
+
e = Tea::Event.get(wait_for_event)
|
49
|
+
case e
|
50
|
+
when Tea::Kbd::Down
|
51
|
+
case e.key
|
52
|
+
when Tea::Kbd::UP then up = true
|
53
|
+
when Tea::Kbd::DOWN then down = true
|
54
|
+
when Tea::Kbd::LEFT then left = true
|
55
|
+
when Tea::Kbd::RIGHT then right = true
|
56
|
+
end
|
57
|
+
when Tea::Kbd::Up
|
58
|
+
case e.key
|
59
|
+
when Tea::Kbd::UP then up = false
|
60
|
+
when Tea::Kbd::DOWN then down = false
|
61
|
+
when Tea::Kbd::LEFT then left = false
|
62
|
+
when Tea::Kbd::RIGHT then right = false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
wait_for_event = !(up || down || left || right)
|
66
|
+
x -= 8 if left
|
67
|
+
x += 8 if right
|
68
|
+
y -= 8 if up
|
69
|
+
y += 8 if down
|
70
|
+
end until e.class == Tea::App::Exit || (e.class == Tea::Kbd::Down && e.key == Tea::Kbd::ESCAPE)
|
data/doc/reference.textile
CHANGED
@@ -38,6 +38,23 @@ module Tea
|
|
38
38
|
primitive_buffer[x, y] = primitive_color(color)
|
39
39
|
end
|
40
40
|
|
41
|
+
# Mixer for alpha blend mix strategy.
|
42
|
+
BLEND_MIXER = lambda do |src_r, src_g, src_b, src_a, dest_r, dest_g, dest_b, dest_a, intensity|
|
43
|
+
ai = src_a * intensity
|
44
|
+
ratio = dest_a > 0 ? ai / dest_a.to_f : 1
|
45
|
+
ratio = 1 if ratio > 1
|
46
|
+
final_r = dest_r + (src_r - dest_r) * ratio
|
47
|
+
final_g = dest_g + (src_g - dest_g) * ratio
|
48
|
+
final_b = dest_b + (src_b - dest_b) * ratio
|
49
|
+
final_a = (dest_a + ai < 255) ? (dest_a + ai) : 255
|
50
|
+
[final_r, final_g, final_b, final_a]
|
51
|
+
end
|
52
|
+
|
53
|
+
# Mixer for replace mix strategy.
|
54
|
+
REPLACE_MIXER = lambda do |src_r, src_g, src_b, src_a, dest_r, dest_g, dest_b, dest_a, intensity|
|
55
|
+
[src_r, src_g, src_b, src_a * intensity]
|
56
|
+
end
|
57
|
+
|
41
58
|
# Draw a rectangle of size w * h with the top-left corner at (x, y) with
|
42
59
|
# the given color (0xRRGGBBAA). Hash arguments that can be used:
|
43
60
|
#
|
@@ -62,14 +79,24 @@ module Tea
|
|
62
79
|
mix = options[:mix]
|
63
80
|
end
|
64
81
|
|
82
|
+
r, g, b, a = primitive_hex_to_rgba(color)
|
65
83
|
case mix
|
66
84
|
when :blend
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
primitive_buffer.
|
85
|
+
if a == 0xff
|
86
|
+
# Same as for mix == :replace
|
87
|
+
primitive_buffer.fill_rect x, y, w, h, primitive_rgba_to_color(r, g, b, a)
|
88
|
+
elsif primitive_buffer.class == SDL::Screen
|
89
|
+
# SGE's broken alpha blending doesn't matter on the screen, so
|
90
|
+
# optimise for it. rubysdl's draw_rect is off-by-one for width and
|
91
|
+
# height, so compensate for that.
|
92
|
+
primitive_buffer.draw_rect x, y, w - 1, h - 1, primitive_rgba_to_color(r, g, b, 255), true, a
|
93
|
+
else
|
94
|
+
# CAUTION: This is _really_ slow, almost unusably so. Perhaps I
|
95
|
+
# should consider not making :blend the default mix mode.
|
96
|
+
primitive_rect x, y, w, h, r, g, b, a, BLEND_MIXER
|
97
|
+
end
|
71
98
|
when :replace
|
72
|
-
primitive_buffer.fill_rect x, y, w, h,
|
99
|
+
primitive_buffer.fill_rect x, y, w, h, primitive_rgba_to_color(r, g, b, a)
|
73
100
|
end
|
74
101
|
end
|
75
102
|
|
@@ -94,34 +121,15 @@ module Tea
|
|
94
121
|
end
|
95
122
|
end
|
96
123
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
mixer = lambda do |buffer, x, y, r, g, b, a, intensity|
|
101
|
-
return buffer.map_rgba(r, g, b, a * intensity)
|
102
|
-
end
|
103
|
-
when :blend
|
104
|
-
mixer = lambda do |buffer, x, y, r, g, b, a, intensity|
|
105
|
-
br, bg, bb, ba = buffer.get_rgba(buffer[x, y])
|
106
|
-
ai = a * intensity
|
107
|
-
ratio = ba > 0 ? ai / ba.to_f : 1
|
108
|
-
ratio = 1 if ratio > 1
|
109
|
-
fr = br + (r - br) * ratio
|
110
|
-
fg = bg + (g - bg) * ratio
|
111
|
-
fb = bb + (b - bb) * ratio
|
112
|
-
fa = (ba + ai < 255) ? (ba + ai) : 255
|
113
|
-
return buffer.map_rgba(fr, fg, fb, fa)
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
if antialias
|
118
|
-
r, g, b, a = primitive_hex_to_rgba(color)
|
119
|
-
primitive_aa_line x1, y1, x2, y2, r, g, b, a, mixer
|
120
|
-
elsif a == 0xff
|
121
|
-
primitive_buffer.draw_line x1, y1, x2, y2, primitive_color(color)
|
124
|
+
r, g, b, a = primitive_hex_to_rgba(color)
|
125
|
+
if primitive_buffer.class == SDL::Screen
|
126
|
+
primitive_buffer.draw_line x1, y1, x2, y2, primitive_rgba_to_color(r, g, b, (mix == :replace ? a : 255)), antialias, (mix == :blend ? a : nil)
|
122
127
|
else
|
123
|
-
|
124
|
-
|
128
|
+
if antialias
|
129
|
+
primitive_aa_line x1, y1, x2, y2, r, g, b, a, (mix == :blend ? BLEND_MIXER : REPLACE_MIXER)
|
130
|
+
else
|
131
|
+
primitive_line x1, y1, x2, y2, r, g, b, a, (mix == :blend ? BLEND_MIXER : REPLACE_MIXER)
|
132
|
+
end
|
125
133
|
end
|
126
134
|
end
|
127
135
|
|
@@ -160,7 +168,7 @@ module Tea
|
|
160
168
|
case mix
|
161
169
|
when :blend
|
162
170
|
r, g, b, a = primitive_hex_to_rgba(color)
|
163
|
-
if !outline && antialias && a <
|
171
|
+
if !outline && antialias && a < 0xff
|
164
172
|
# rubysdl can't draw filled antialiased alpha circles for some reason.
|
165
173
|
# Big endian because the SGE-powered circle antialiasing apparently
|
166
174
|
# doesn't like it any other way.
|
@@ -232,26 +240,31 @@ module Tea
|
|
232
240
|
# +alpha+ is passed to the +mixer+ proc to determine how the line and
|
233
241
|
# bitmap colours should be mixed.
|
234
242
|
#
|
235
|
-
# mixer = { |
|
243
|
+
# mixer = { |src_red, src_green, src_blue, src_alpha, dest_red, dest_green, dest_blue, dest_alpha, intensity| ... }
|
236
244
|
def primitive_line(x1, y1, x2, y2, red, green, blue, alpha, mixer)
|
237
245
|
|
238
246
|
buffer = primitive_buffer
|
239
247
|
dx = x2 - x1
|
240
248
|
dy = y2 - y1
|
241
249
|
|
250
|
+
plot = Proc.new do |x, y, i|
|
251
|
+
buf_r, buf_g, buf_b, buf_a = buffer.get_rgba(buffer[x, y])
|
252
|
+
buffer[x, y] = buffer.map_rgba(*mixer.call(red, green, blue, alpha, buf_r, buf_g, buf_b, buf_a, i))
|
253
|
+
end
|
254
|
+
|
242
255
|
case
|
243
256
|
when dx == 0 && dy == 0 # point
|
244
|
-
|
257
|
+
plot.call x1, y1, 1.0
|
245
258
|
when dx == 0 && dy != 0 # vertical line
|
246
259
|
primitive_buffer_with_lock do
|
247
260
|
for y in (y1.to_i)..(y2.to_i)
|
248
|
-
|
261
|
+
plot.call x1, y, 1.0
|
249
262
|
end
|
250
263
|
end
|
251
264
|
when dx != 0 && dy == 0 # horizontal line
|
252
265
|
primitive_buffer_with_lock do
|
253
266
|
for x in (x1.to_i)..(x2.to_i)
|
254
|
-
|
267
|
+
plot.call x, y1, 1.0
|
255
268
|
end
|
256
269
|
end
|
257
270
|
else # Use Bresenham's line algorithm, from John Hall's Programming Linux Games.
|
@@ -282,7 +295,7 @@ module Tea
|
|
282
295
|
primitive_buffer_with_lock do
|
283
296
|
if xspan < yspan # Draw a mostly vertical line.
|
284
297
|
for step in 0..yspan
|
285
|
-
|
298
|
+
plot.call x, y, 1.0
|
286
299
|
error += xspan
|
287
300
|
if error >= yspan
|
288
301
|
x += xinc
|
@@ -292,7 +305,7 @@ module Tea
|
|
292
305
|
end
|
293
306
|
else # Draw a mostly horizontal line.
|
294
307
|
for step in 0..xspan
|
295
|
-
|
308
|
+
plot.call x, y, 1.0
|
296
309
|
error += yspan
|
297
310
|
if error >= xspan
|
298
311
|
y += yinc
|
@@ -310,26 +323,31 @@ module Tea
|
|
310
323
|
# blue). The +alpha+ is passed to the +mixer+ proc to determine how the
|
311
324
|
# line and bitmap colours should be mixed.
|
312
325
|
#
|
313
|
-
# mixer = { |
|
326
|
+
# mixer = { |src_red, src_green, src_blue, src_alpha, dest_red, dest_green, dest_blue, dest_alpha, intensity| ... }
|
314
327
|
def primitive_aa_line(x1, y1, x2, y2, red, green, blue, alpha, mixer)
|
315
328
|
|
316
329
|
buffer = primitive_buffer
|
317
330
|
dx = x2 - x1
|
318
331
|
dy = y2 - y1
|
319
332
|
|
333
|
+
plot = Proc.new do |x, y, i|
|
334
|
+
buf_r, buf_g, buf_b, buf_a = buffer.get_rgba(buffer[x, y])
|
335
|
+
buffer[x, y] = buffer.map_rgba(*mixer.call(red, green, blue, alpha, buf_r, buf_g, buf_b, buf_a, i))
|
336
|
+
end
|
337
|
+
|
320
338
|
case
|
321
339
|
when dx == 0 && dy == 0 # point
|
322
|
-
|
340
|
+
plot.call x1, y1, 1.0
|
323
341
|
when dx == 0 && dy != 0 # vertical line
|
324
342
|
primitive_buffer_with_lock do
|
325
343
|
for y in (y1.to_i)..(y2.to_i)
|
326
|
-
|
344
|
+
plot.call x1, y, 1.0
|
327
345
|
end
|
328
346
|
end
|
329
347
|
when dx != 0 && dy == 0 # horizontal line
|
330
348
|
primitive_buffer_with_lock do
|
331
349
|
for x in (x1.to_i)..(x2.to_i)
|
332
|
-
|
350
|
+
plot.call x, y1, 1.0
|
333
351
|
end
|
334
352
|
end
|
335
353
|
else # Use Xiaolin Wu's line algorithm, described on Wikipedia.
|
@@ -347,8 +365,8 @@ module Tea
|
|
347
365
|
xgap = primitive_rfpart(x1 + 0.5)
|
348
366
|
xpxl1 = xend # This will be used in the main loop.
|
349
367
|
ypxl1 = yend.truncate
|
350
|
-
|
351
|
-
|
368
|
+
plot.call xpxl1, ypxl1, primitive_rfpart(yend) * xgap
|
369
|
+
plot.call xpxl1, ypxl1 + 1, primitive_fpart(yend) * xgap
|
352
370
|
intery = yend + gradient # First y-intersection for the main loop.
|
353
371
|
|
354
372
|
# Handle second endpoint.
|
@@ -357,14 +375,14 @@ module Tea
|
|
357
375
|
xgap = primitive_fpart(x2 + 0.5)
|
358
376
|
xpxl2 = xend # This will be used in the main loop.
|
359
377
|
ypxl2 = yend.truncate
|
360
|
-
|
361
|
-
|
378
|
+
plot.call xpxl2, ypxl2, primitive_rfpart(yend) * xgap
|
379
|
+
plot.call xpxl2, ypxl2 = 1, primitive_fpart(yend) * xgap
|
362
380
|
|
363
381
|
primitive_buffer_with_lock do
|
364
382
|
for x in (xpxl1 + 1)..(xpxl2 - 1)
|
365
383
|
intery_int = intery.truncate
|
366
|
-
|
367
|
-
|
384
|
+
plot.call x, intery_int, primitive_rfpart(intery)
|
385
|
+
plot.call x, intery_int + 1, primitive_fpart(intery)
|
368
386
|
intery += gradient
|
369
387
|
end
|
370
388
|
end
|
@@ -381,8 +399,8 @@ module Tea
|
|
381
399
|
ygap = primitive_rfpart(y1 + 0.5)
|
382
400
|
ypxl1 = yend # This will be used in the main loop.
|
383
401
|
xpxl1 = xend.truncate
|
384
|
-
|
385
|
-
|
402
|
+
plot.call xpxl1, ypxl1, primitive_rfpart(xend) * ygap
|
403
|
+
plot.call xpxl1 + 1, ypxl1, primitive_fpart(xend) * ygap
|
386
404
|
interx = xend + gradient # First x-intersection for the main loop.
|
387
405
|
|
388
406
|
# Handle second endpoint.
|
@@ -391,14 +409,14 @@ module Tea
|
|
391
409
|
ygap = primitive_fpart(y2 + 0.5)
|
392
410
|
ypxl2 = yend # This will be used in the main loop.
|
393
411
|
xpxl2 = xend.truncate
|
394
|
-
|
395
|
-
|
412
|
+
plot.call xpxl2, ypxl2, primitive_rfpart(xend) * ygap
|
413
|
+
plot.call xpxl2 + 1, ypxl2, primitive_fpart(xend) * ygap
|
396
414
|
|
397
415
|
primitive_buffer_with_lock do
|
398
416
|
for y in (ypxl1 + 1)..(ypxl2 - 1)
|
399
417
|
interx_int = interx.truncate
|
400
|
-
|
401
|
-
|
418
|
+
plot.call interx_int, y, primitive_rfpart(interx)
|
419
|
+
plot.call interx_int + 1, y, primitive_fpart(interx)
|
402
420
|
interx += gradient
|
403
421
|
end
|
404
422
|
end
|
@@ -407,6 +425,41 @@ module Tea
|
|
407
425
|
end
|
408
426
|
end
|
409
427
|
|
428
|
+
# Draw a rectangle of size (w, h) with the top-left corner at (x, y), with
|
429
|
+
# the colour (red, green, blue) and mixed with +alpha+ and +mixer+.
|
430
|
+
#
|
431
|
+
# mixer = { |src_red, src_green, src_blue, src_alpha, dest_red, dest_green, dest_blue, dest_alpha, intensity| ... }
|
432
|
+
def primitive_rect(x, y, w, h, red, green, blue, alpha, mixer)
|
433
|
+
buffer = primitive_buffer
|
434
|
+
|
435
|
+
# Keep x, y, w, h within the clipping rectangle.
|
436
|
+
x2 = x + w
|
437
|
+
y2 = y + h
|
438
|
+
clip_x, clip_y, clip_w, clip_h = buffer.get_clip_rect
|
439
|
+
clip_x = 0 unless clip_x
|
440
|
+
clip_y = 0 unless clip_y
|
441
|
+
clip_w = buffer.w unless clip_w
|
442
|
+
clip_h = buffer.h unless clip_h
|
443
|
+
clip_x2 = clip_x + clip_w
|
444
|
+
clip_y2 = clip_y + clip_h
|
445
|
+
x = clip_x if x < clip_x
|
446
|
+
y = clip_y if y < clip_y
|
447
|
+
x2 = clip_x2 if x2 > clip_x2
|
448
|
+
y2 = clip_y2 if y2 > clip_y2
|
449
|
+
w = x2 - x
|
450
|
+
h = y2 - y
|
451
|
+
return unless w > 0 && h > 0
|
452
|
+
|
453
|
+
primitive_buffer_with_lock do
|
454
|
+
for py in y...(y + h)
|
455
|
+
for px in x...(x + w)
|
456
|
+
buf_r, buf_g, buf_b, buf_a = buffer.get_rgba(buffer[px, py])
|
457
|
+
buffer[px, py] = buffer.map_rgba(*mixer.call(red, green, blue, alpha, buf_r, buf_g, buf_b, buf_a, 1.0))
|
458
|
+
end
|
459
|
+
end
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
410
463
|
end
|
411
464
|
|
412
465
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tung-tea
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tung Nguyen
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-08-
|
12
|
+
date: 2009-08-04 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|