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 CHANGED
@@ -65,25 +65,15 @@ Below is a simple bouncing circle demo.
65
65
 
66
66
  == Status
67
67
 
68
- What's done:
69
-
70
- * Graphics
71
- - Tea::Screen
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
- * Sound
85
- * Screen resizing
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
@@ -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 rectangle.
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)
@@ -9,22 +9,62 @@
9
9
  require 'tea'
10
10
 
11
11
  puts <<TEST
12
- You should see for 5 seconds:
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
- Tea::Screen.rect 100, 75, 200, 150, 0xff0000ff
24
- Tea::Screen.rect 0, 0, 200, 150, 0x00ff0080, :mix => :blend
25
- Tea::Screen.rect 200, 150, 200, 150, 0x0000ff80, :mix => :replace
26
- Tea::Screen.rect 0, 150, 200, 150, 0xffffff80
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::Screen.update
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
- sleep 5
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)
@@ -253,3 +253,8 @@ Returns true when the right mouse button is held down.
253
253
  h1. Sound
254
254
 
255
255
  Nothing yet.
256
+
257
+
258
+ h1. Fonts
259
+
260
+ Nothing yet.
@@ -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
- r, g, b, a = primitive_hex_to_rgba(color)
68
- # draw_rect has an off-by-one error with the width and height, hence the "- 1"s.
69
- return if w < 1 || h < 1
70
- primitive_buffer.draw_rect x, y, w - 1, h - 1, primitive_rgba_to_color(r, g, b, 255), true, a
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, primitive_color(color)
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
- mixer = nil
98
- case mix
99
- when :replace
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
- r, g, b, a = primitive_hex_to_rgba(color)
124
- primitive_line x1, y1, x2, y2, r, g, b, a, mixer
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 < 255
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 = { |buffer, x, y, red, green, blue, alpha| ... }
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
- buffer[x1, y1] = mixer.call buffer, x1, y1, red, green, blue, alpha, 1.0
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
- buffer[x1, y] = mixer.call buffer, x1, y, red, green, blue, alpha, 1.0
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
- buffer[x, y1] = mixer.call buffer, x, y1, red, green, blue, alpha, 1.0
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
- buffer[x, y] = mixer.call buffer, x, y, red, green, blue, alpha, 1.0
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
- buffer[x, y] = mixer.call buffer, x, y, red, green, blue, alpha, 1.0
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 = { |buffer, x, y, red, green, blue, alpha, intensity| ... }
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
- buffer[x1, y1] = mixer.call buffer, x1, y1, red, green, blue, alpha, 1.0
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
- buffer[x1, y] = mixer.call buffer, x1, y, red, green, blue, alpha, 1.0
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
- buffer[x, y1] = mixer.call buffer, x, y1, red, green, blue, alpha, 1.0
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
- buffer[xpxl1, ypxl1] = mixer.call buffer, xpxl1, ypxl1, red, green, blue, alpha, primitive_rfpart(yend) * xgap
351
- buffer[xpxl1, ypxl1 + 1] = mixer.call buffer, xpxl1, ypxl1 + 1, red, green, blue, alpha, primitive_fpart(yend) * xgap
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
- buffer[xpxl2, ypxl2] = mixer.call buffer, xpxl2, ypxl2, red, green, blue, alpha, primitive_rfpart(yend) * xgap
361
- buffer[xpxl2, ypxl2 + 1] = mixer.call buffer, xpxl2, ypxl2 + 1, red, green, blue, alpha, primitive_fpart(yend) * xgap
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
- buffer[x, intery_int] = mixer.call buffer, x, intery_int, red, green, blue, alpha, primitive_rfpart(intery)
367
- buffer[x, intery_int + 1] = mixer.call buffer, x, intery_int + 1, red, green, blue, alpha, primitive_fpart(intery)
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
- buffer[xpxl1, ypxl1] = mixer.call buffer, xpxl1, ypxl1, red, green, blue, alpha, primitive_rfpart(xend) * ygap
385
- buffer[xpxl1 + 1, ypxl1] = mixer.call buffer, xpxl1 + 1, ypxl1, red, green, blue, alpha, primitive_fpart(xend) * ygap
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
- buffer[xpxl2, ypxl2] = mixer.call buffer, xpxl2, ypxl2, red, green, blue, alpha, primitive_rfpart(xend) * ygap
395
- buffer[xpxl2 + 1, ypxl2] = mixer.call buffer, xpxl2 + 1, ypxl2, red, green, blue, alpha, primitive_fpart(xend) * ygap
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
- buffer[interx_int, y] = mixer.call buffer, interx_int, y, red, green, blue, alpha, primitive_rfpart(interx)
401
- buffer[interx_int + 1, y] = mixer.call buffer, interx_int + 1, y, red, green, blue, alpha, primitive_fpart(interx)
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.1
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-02 00:00:00 -07:00
12
+ date: 2009-08-04 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency