tung-tea 0.2.2 → 0.2.3

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
@@ -68,7 +68,7 @@ Below is a simple bouncing circle demo.
68
68
  What's working:
69
69
 
70
70
  * Events/Input - done
71
- * Graphics - halfway done, fixing transparency, grabbing sub-bitmaps
71
+ * Graphics - nearly done, still need sub-bitmap grabbing
72
72
 
73
73
  What isn't done yet:
74
74
 
@@ -1,5 +1,6 @@
1
1
  # Test that alpha blending works for circles.
2
- # Expected results
2
+ # Expected results: 8 green circles drawn over the edges of a white rectangle,
3
+ # varying in outline, anti-aliasing and blend/replace alpha mixing.
3
4
 
4
5
  require 'tea'
5
6
 
@@ -0,0 +1,50 @@
1
+ # Test that alpha blending works for circles.
2
+ # Expected results: 8 green circles drawn over the edges of a white-bordered
3
+ # blue rectangle, varying in outline, anti-aliasing and blend/replace alpha
4
+ # mixing.
5
+
6
+ require 'tea'
7
+
8
+ puts <<TEST
9
+ You should see a white-bordered blue rectangle and circles along the edges:
10
+
11
+ --b --r -ab
12
+
13
+ -ar o-b
14
+
15
+ o-r oab oar
16
+
17
+ o-- = outline
18
+ -a- = antialias
19
+ --b/r = blend/replace
20
+
21
+ Press any key to exit.
22
+ TEST
23
+
24
+ Tea.init
25
+ Tea::Screen.set_mode 400, 300
26
+
27
+ Tea::Screen.rect 100, 75, 200, 150, 0xffffffff
28
+
29
+ b = Tea::Bitmap.new(Tea::Screen.w, Tea::Screen.h, 0x00000000)
30
+ b.rect 105, 80, 190, 140, 0x0000ffff
31
+
32
+ b.circle 100, 75, 25, 0x00ff0080, :outline => false, :antialias => false, :mix => :blend
33
+ b.circle 200, 75, 25, 0x00ff0080, :outline => false, :antialias => false, :mix => :replace
34
+ b.circle 300, 75, 25, 0x00ff0080, :outline => false, :antialias => true, :mix => :blend
35
+
36
+ b.circle 100, 150, 25, 0x00ff0080, :outline => false, :antialias => true, :mix => :replace
37
+ b.circle 300, 150, 25, 0x00ff0080, :outline => true, :antialias => false, :mix => :blend
38
+
39
+ b.circle 100, 225, 25, 0x00ff0080, :outline => true, :antialias => false, :mix => :replace
40
+ b.circle 200, 225, 25, 0x00ff0080, :outline => true, :antialias => true, :mix => :blend
41
+ b.circle 300, 225, 25, 0x00ff0080, :outline => true, :antialias => true, :mix => :replace
42
+
43
+ Tea::Screen.blit b, 0, 0
44
+
45
+ Tea::Screen.update
46
+
47
+ loop do
48
+ e = Tea::Event.get(true)
49
+ break if e.class == Tea::App::Exit || e.class == Tea::Kbd::Down
50
+ end
@@ -0,0 +1,18 @@
1
+ # Test that a circle drawn to a bitmap is drawn correctly.
2
+ # Expected result is a filled white circle.
3
+
4
+ require 'tea'
5
+
6
+ puts <<TEST
7
+ You should see a filled white circle for 5 seconds.
8
+ TEST
9
+
10
+ Tea.init
11
+ Tea::Screen.set_mode 320, 240
12
+
13
+ b = Tea::Bitmap.new(320, 240, 0x00000000)
14
+ b.circle 160, 120, 100, 0xffffffff, :mix => :replace
15
+ Tea::Screen.blit b, 0, 0
16
+
17
+ Tea::Screen.update
18
+ sleep 5
@@ -0,0 +1,46 @@
1
+ # Test that getting, setting and using the clip rectangle all work.
2
+ # Expected result is a rectangle of smileys, and one at the bottom-right
3
+ # corner.
4
+
5
+ require 'tea'
6
+
7
+ puts <<TEST
8
+ You should see a rectangle of smileys, and one in the bottom-right corner,
9
+ for 10 seconds.
10
+
11
+ Expected output:
12
+ Clip rect is 0, 0, 400, 300
13
+ Clip rect is now 50, 50, 290, 185
14
+ Clip rect is 0, 0, 400, 300 again
15
+ Clip rect is now 368, 268, 32, 32
16
+
17
+ Actual output:
18
+ TEST
19
+
20
+ Tea.init
21
+ Tea::Screen.set_mode 400, 300
22
+
23
+ puts "Clip rect is #{Tea::Screen.clip.join(", ")}"
24
+
25
+ smiley = Tea::Bitmap.new('smile.png')
26
+
27
+ Tea::Screen.clip(50, 50, 290, 185) do
28
+ puts "Clip rect is now #{Tea::Screen.clip.join(", ")}"
29
+
30
+ for y in 0..(Tea::Screen.h / smiley.h)
31
+ for x in 0..(Tea::Screen.w / smiley.w)
32
+ Tea::Screen.blit smiley, x * smiley.w, y * smiley.h
33
+ end
34
+ end
35
+ end
36
+
37
+ puts "Clip rect is #{Tea::Screen.clip.join(", ")} again"
38
+
39
+ Tea::Screen.clip Tea::Screen.w - smiley.w, Tea::Screen.h - smiley.h, smiley.w, smiley.h
40
+ Tea::Screen.blit smiley, Tea::Screen.w - smiley.w, Tea::Screen.h - smiley.h
41
+
42
+ puts "Clip rect is now #{Tea::Screen.clip.join(", ")}"
43
+
44
+ Tea::Screen.update
45
+
46
+ sleep 10
@@ -25,6 +25,13 @@ Instances of Tea::Bitmap share methods from the following modules:
25
25
  Tea::Blitting:
26
26
  * blit(source_blittable, x, y)
27
27
 
28
+ Tea::Clipping:
29
+ * clip
30
+ * clip(x, y, w, h)
31
+ * clip(x, y, w, h) { ... }
32
+
33
+ These clip methods get, set and run a block with a clipping rectangle respectively. While a clipping rectangle is set, drawing will be clipped inside it.
34
+
28
35
  Tea::PrimitiveDrawing:
29
36
  * clear()
30
37
  * point(x, y, color)
@@ -62,6 +69,13 @@ Since Tea::Screen is an object and not a class, its mixins add methods to Tea::S
62
69
  Tea::Blitting:
63
70
  * blit(source_blittable, x, y)
64
71
 
72
+ Tea::Clipping:
73
+ * clip
74
+ * clip(x, y, w, h)
75
+ * clip(x, y, w, h) { ... }
76
+
77
+ These clip methods get, set and run a block with a clipping rectangle respectively. While a clipping rectangle is set, drawing will be clipped inside it.
78
+
65
79
  Tea::PrimitiveDrawing:
66
80
  * clear()
67
81
  * point(x, y, color)
data/lib/tea/c_bitmap.rb CHANGED
@@ -4,6 +4,7 @@
4
4
  require 'sdl'
5
5
 
6
6
  require 'tea/m_blitting'
7
+ require 'tea/m_clipping'
7
8
  require 'tea/m_primitive_drawing'
8
9
 
9
10
  #
@@ -43,6 +44,11 @@ module Tea
43
44
  @buffer
44
45
  end
45
46
 
47
+ include Tea::Clipping
48
+ def clipping_buffer
49
+ @buffer
50
+ end
51
+
46
52
  include Tea::PrimitiveDrawing
47
53
  def primitive_buffer
48
54
  @buffer
@@ -0,0 +1,69 @@
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; @sdl_buffer; end
16
+ module Clipping
17
+
18
+ # Get, set or run a block with a clipping rectangle that restricts where
19
+ # drawing can take place.
20
+ #
21
+ # Getting the current clipping rectangle:
22
+ #
23
+ # x, y, width, height = clippable_object.clip
24
+ #
25
+ # Setting a new clipping rectangle:
26
+ #
27
+ # old_x, old_y, old_w, old_h = clippable_object.clip(new_x, new_y, new_w, new_h)
28
+ #
29
+ # Running a block with a clipping rectangle temporarily set:
30
+ #
31
+ # clippable_object.clip(clip_x, clip_y, clip_w, clip_h) do
32
+ # # Draw onto clippable_object within clip rect here.
33
+ # end
34
+ #
35
+ def clip(x=nil, y=nil, w=nil, h=nil)
36
+ buffer = clipping_buffer
37
+
38
+ # rubysdl's SDL::Surface#get_clip_rect doesn't return anything useful.
39
+ # Seems to be a bug, or at least compilation quirk.
40
+ @clipping_rect = [0, 0, buffer.w, buffer.h] unless @clipping_rect
41
+ old_clipping_rect = @clipping_rect
42
+
43
+ case
44
+ when !(x || y || w || h) # Get clip rect.
45
+ # Do nothing.
46
+ when x && y && w && h && !block_given? # Set clip rect.
47
+ @clipping_rect = [x, y, w, h]
48
+ buffer.set_clip_rect *@clipping_rect
49
+ when x && y && w && h && block_given? # Run block with clip rect.
50
+ @clipping_rect = [x, y, w, h]
51
+ buffer.set_clip_rect *@clipping_rect
52
+ begin
53
+ yield
54
+ ensure
55
+ @clipping_rect = old_clipping_rect
56
+ buffer.set_clip_rect *old_clipping_rect
57
+ end
58
+ else
59
+ arg_count = 0
60
+ [x, y, w, h].each { |arg| arg_count += 1 if arg == nil }
61
+ raise ArgumentError, "wrong number of arguments (#{arg_count} for 0 or 4)", caller
62
+ end
63
+
64
+ old_clipping_rect
65
+ end
66
+
67
+ end
68
+
69
+ end
@@ -165,26 +165,33 @@ module Tea
165
165
  end
166
166
  end
167
167
 
168
- case mix
169
- when :blend
170
- r, g, b, a = primitive_hex_to_rgba(color)
171
- if !outline && antialias && a < 0xff
172
- # rubysdl can't draw filled antialiased alpha circles for some reason.
173
- # Big endian because the SGE-powered circle antialiasing apparently
174
- # doesn't like it any other way.
175
- ts = SDL::Surface.new(SDL::SWSURFACE, (radius + 1) * 2, (radius + 1) * 2, 32,
176
- 0xff000000,
177
- 0x00ff0000,
178
- 0x0000ff00,
179
- 0x000000ff)
180
- ts.draw_circle radius + 1, radius + 1, radius, ts.map_rgba(r, g, b, a), true, true
181
- SDL::Surface.blit ts, 0, 0, ts.w, ts.h, primitive_buffer, x - radius - 1, y - radius - 1
182
- else
183
- primitive_buffer.draw_circle x, y, radius, primitive_rgba_to_color(r, g, b, 255),
184
- !outline, antialias, (a == 255 ? nil : a)
168
+ if primitive_buffer.class == SDL::Screen
169
+ case mix
170
+ when :blend
171
+ r, g, b, a = primitive_hex_to_rgba(color)
172
+ if !outline && antialias && a < 0xff
173
+ # rubysdl can't draw filled antialiased alpha circles for some reason.
174
+ # Big endian because the SGE-powered circle antialiasing apparently
175
+ # doesn't like it any other way.
176
+ ts = SDL::Surface.new(SDL::SWSURFACE, (radius + 1) * 2, (radius + 1) * 2, 32,
177
+ 0xff000000,
178
+ 0x00ff0000,
179
+ 0x0000ff00,
180
+ 0x000000ff)
181
+ ts.draw_circle radius + 1, radius + 1, radius, ts.map_rgba(r, g, b, a), true, true
182
+ SDL::Surface.blit ts, 0, 0, ts.w, ts.h, primitive_buffer, x - radius - 1, y - radius - 1
183
+ else
184
+ primitive_buffer.draw_circle x, y, radius, primitive_rgba_to_color(r, g, b, 255),
185
+ !outline, antialias, (a == 255 ? nil : a)
186
+ end
187
+ when :replace
188
+ primitive_buffer.draw_circle x, y, radius, primitive_color(color), !outline, antialias
185
189
  end
186
- when :replace
187
- primitive_buffer.draw_circle x, y, radius, primitive_color(color), !outline, antialias
190
+ else
191
+ # SGE and alpha mixing don't... mix. Gotta do it ourselves.
192
+ mixer = (mix == :blend) ? BLEND_MIXER : REPLACE_MIXER
193
+ r, g, b, a = primitive_hex_to_rgba(color)
194
+ primitive_circle x, y, radius, !outline, antialias, r, g, b, a, mixer
188
195
  end
189
196
  end
190
197
 
@@ -247,9 +254,16 @@ module Tea
247
254
  dx = x2 - x1
248
255
  dy = y2 - y1
249
256
 
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))
257
+ # Optimise for REPLACE_MIXER, which doesn't need source pixel info.
258
+ if mixer == REPLACE_MIXER
259
+ plot = Proc.new do |x, y, i|
260
+ buffer[x, y] = buffer.map_rgba(*mixer.call(red, green, blue, alpha, 0, 0, 0, 0, i))
261
+ end
262
+ else
263
+ plot = Proc.new do |x, y, i|
264
+ buf_r, buf_g, buf_b, buf_a = buffer.get_rgba(buffer[x, y])
265
+ buffer[x, y] = buffer.map_rgba(*mixer.call(red, green, blue, alpha, buf_r, buf_g, buf_b, buf_a, i))
266
+ end
253
267
  end
254
268
 
255
269
  case
@@ -330,9 +344,16 @@ module Tea
330
344
  dx = x2 - x1
331
345
  dy = y2 - y1
332
346
 
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))
347
+ # Optimise for REPLACE_MIXER, which doesn't need source pixel info.
348
+ if mixer == REPLACE_MIXER
349
+ plot = Proc.new do |x, y, i|
350
+ buffer[x, y] = buffer.map_rgba(*mixer.call(red, green, blue, alpha, 0, 0, 0, 0, i))
351
+ end
352
+ else
353
+ plot = Proc.new do |x, y, i|
354
+ buf_r, buf_g, buf_b, buf_a = buffer.get_rgba(buffer[x, y])
355
+ buffer[x, y] = buffer.map_rgba(*mixer.call(red, green, blue, alpha, buf_r, buf_g, buf_b, buf_a, i))
356
+ end
336
357
  end
337
358
 
338
359
  case
@@ -450,16 +471,140 @@ module Tea
450
471
  h = y2 - y
451
472
  return unless w > 0 && h > 0
452
473
 
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))
474
+ # Optimise for REPLACE_MIXER, which doesn't need source pixel info.
475
+ if mixer == REPLACE_MIXER
476
+ primitive_buffer_with_lock do
477
+ for py in y...(y + h)
478
+ for px in x...(x + w)
479
+ buffer[px, py] = buffer.map_rgba(*mixer.call(red, green, blue, alpha, 0, 0, 0, 0, 1.0))
480
+ end
481
+ end
482
+ end
483
+ else
484
+ primitive_buffer_with_lock do
485
+ for py in y...(y + h)
486
+ for px in x...(x + w)
487
+ buf_r, buf_g, buf_b, buf_a = buffer.get_rgba(buffer[px, py])
488
+ buffer[px, py] = buffer.map_rgba(*mixer.call(red, green, blue, alpha, buf_r, buf_g, buf_b, buf_a, 1.0))
489
+ end
458
490
  end
459
491
  end
460
492
  end
461
493
  end
462
494
 
495
+ # Draw a circle centred at (x, y) with the given radius.
496
+ def primitive_circle(x, y, radius, filled, antialias, red, green, blue, alpha, mixer)
497
+ buffer = primitive_buffer
498
+
499
+ radius = radius.round
500
+ return if radius < 1 ||
501
+ x + radius < 0 || x - radius >= buffer.w ||
502
+ y + radius < 0 || y - radius >= buffer.h
503
+
504
+ # Optimise for REPLACE_MIXER, which doesn't need source pixel info.
505
+ if mixer == REPLACE_MIXER
506
+ plot = Proc.new do |px, py, i|
507
+ buffer[px, py] = buffer.map_rgba(*mixer.call(red, green, blue, alpha, 0, 0, 0, 0, i))
508
+ end
509
+ else
510
+ plot = Proc.new do |px, py, i|
511
+ buf_r, buf_g, buf_b, buf_a = buffer.get_rgba(buffer[px, py])
512
+ buffer[px, py] = buffer.map_rgba(*mixer.call(red, green, blue, alpha, buf_r, buf_g, buf_b, buf_a, i))
513
+ end
514
+ end
515
+
516
+ # Xiaolin Wu's circle algorithm, with extra stuff. Graphics Gems II, part IX, chapter 9.
517
+ plot.call x + radius, y, 1.0
518
+ plot.call x - radius, y, 1.0
519
+ plot.call x, y + radius, 1.0
520
+ plot.call x, y - radius, 1.0
521
+
522
+ if filled
523
+ # Fill the centre and cardinal directions before iterating.
524
+ plot.call x, y, 1.0
525
+ ((x + 1)..(x + radius - 1)).each { |fill_x| plot.call fill_x, y, 1.0 }
526
+ ((y + 1)..(y + radius - 1)).each { |fill_y| plot.call x, fill_y, 1.0 }
527
+ ((x - radius + 1)..(x - 1)).each { |fill_x| plot.call fill_x, y, 1.0 }
528
+ ((y - radius + 1)..(y - 1)).each { |fill_y| plot.call x, fill_y, 1.0 }
529
+ end
530
+
531
+ i = radius
532
+ j = 0
533
+ t = 0
534
+
535
+ # Stop two steps short so we can join the octants ourselves.
536
+ until i - 2 <= j
537
+ j += 1
538
+ radius2_j2_diff = Math.sqrt(radius * radius - j * j)
539
+ d = radius2_j2_diff.ceil - radius2_j2_diff
540
+ inv_d = 1.0 - d
541
+ # Graphics Gems II seems to get this wrong by writing the reverse condition.
542
+ i -= 1 unless d > t
543
+
544
+ if antialias
545
+ plot.call x + i, y + j, inv_d
546
+ plot.call x + j, y + i, inv_d
547
+ plot.call x - j, y + i, inv_d
548
+ plot.call x - i, y + j, inv_d
549
+ plot.call x - i, y - j, inv_d
550
+ plot.call x - j, y - i, inv_d
551
+ plot.call x + j, y - i, inv_d
552
+ plot.call x + i, y - j, inv_d
553
+ else
554
+ plot.call x + i, y + j, 1.0
555
+ plot.call x + j, y + i, 1.0
556
+ plot.call x - j, y + i, 1.0
557
+ plot.call x - i, y + j, 1.0
558
+ plot.call x - i, y - j, 1.0
559
+ plot.call x - j, y - i, 1.0
560
+ plot.call x + j, y - i, 1.0
561
+ plot.call x + i, y - j, 1.0
562
+ end
563
+
564
+ if filled
565
+ ((x + j )..(x + i - 1)).each { |fill_x| plot.call fill_x, y + j, 1.0 }
566
+ ((y + j + 1)..(y + i - 1)).each { |fill_y| plot.call x + j, fill_y, 1.0 }
567
+ ((y + j + 1)..(y + i - 1)).each { |fill_y| plot.call x - j, fill_y, 1.0 }
568
+ ((x - i + 1)..(x - j )).each { |fill_x| plot.call fill_x, y + j, 1.0 }
569
+ ((x - i + 1)..(x - j )).each { |fill_x| plot.call fill_x, y - j, 1.0 }
570
+ ((y - i + 1)..(y - j - 1)).each { |fill_y| plot.call x - j, fill_y, 1.0 }
571
+ ((y - i + 1)..(y - j - 1)).each { |fill_y| plot.call x + j, fill_y, 1.0 }
572
+ ((x + j )..(x + i - 1)).each { |fill_x| plot.call fill_x, y - j, 1.0 }
573
+ elsif antialias
574
+ # Anti-aliased drawing needs its inner pixel if no filling is happening.
575
+ plot.call x + i - 1, y + j, d
576
+ plot.call x + j, y + i - 1, d
577
+ plot.call x - j, y + i - 1, d
578
+ plot.call x - i + 1, y + j, d
579
+ plot.call x - i + 1, y - j, d
580
+ plot.call x - j, y - i + 1, d
581
+ plot.call x + j, y - i + 1, d
582
+ plot.call x + i - 1, y - j, d
583
+ end
584
+
585
+ t = d
586
+ end
587
+
588
+ # plot final octant meeting points relative to octants 1, 3, 5 & 7
589
+ j += 1
590
+ radius2_j2_diff = Math.sqrt(radius * radius - j * j)
591
+ d = radius2_j2_diff.ceil - radius2_j2_diff
592
+ inv_d = 1.0 - d
593
+ i -= 1 unless d > t
594
+ if antialias
595
+ plot.call x + i, y + j, inv_d
596
+ plot.call x - j, y + i, inv_d
597
+ plot.call x - i, y - j, inv_d
598
+ plot.call x + j, y - i, inv_d
599
+ else
600
+ plot.call x + i, y + j, 1.0
601
+ plot.call x - j, y + i, 1.0
602
+ plot.call x - i, y - j, 1.0
603
+ plot.call x + j, y - i, 1.0
604
+ end
605
+
606
+ end
607
+
463
608
  end
464
609
 
465
610
  end
data/lib/tea/screen.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require 'sdl'
4
4
 
5
5
  require 'tea/m_blitting'
6
+ require 'tea/m_clipping'
6
7
  require 'tea/m_primitive_drawing'
7
8
 
8
9
  #
@@ -51,6 +52,9 @@ module Tea
51
52
  extend Blitting
52
53
  def Screen.blittable_buffer; @screen; end
53
54
 
55
+ extend Clipping
56
+ def Screen.clipping_buffer; @screen; end
57
+
54
58
  extend PrimitiveDrawing
55
59
  def Screen.primitive_buffer; @screen; end
56
60
 
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.2
4
+ version: 0.2.3
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-04 00:00:00 -07:00
12
+ date: 2009-08-12 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -39,6 +39,9 @@ files:
39
39
  - doc/example/bitmap_new.rb
40
40
  - doc/example/circle.rb
41
41
  - doc/example/circle_alpha.rb
42
+ - doc/example/circle_alpha_bitmap.rb
43
+ - doc/example/circle_bitmap.rb
44
+ - doc/example/clip.rb
42
45
  - doc/example/event_app.rb
43
46
  - doc/example/event_keyboard.rb
44
47
  - doc/example/event_mouse.rb
@@ -65,6 +68,7 @@ files:
65
68
  - lib/tea/c_bitmap.rb
66
69
  - lib/tea/c_error.rb
67
70
  - lib/tea/m_blitting.rb
71
+ - lib/tea/m_clipping.rb
68
72
  - lib/tea/m_event.rb
69
73
  - lib/tea/m_event_app.rb
70
74
  - lib/tea/m_event_dispatch.rb