ashton 0.0.1alpha → 0.0.2alpha

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.
Files changed (116) hide show
  1. data/LICENSE +21 -21
  2. data/README.md +95 -68
  3. data/Rakefile +41 -23
  4. data/examples/bloom_example.rb +59 -0
  5. data/examples/lighting_example.rb +127 -0
  6. data/examples/media/SmallStar.png +0 -0
  7. data/examples/media/Starfighter.png +0 -0
  8. data/examples/media/simple.png +0 -0
  9. data/examples/noise_example.rb +94 -0
  10. data/examples/outline_example.rb +86 -0
  11. data/examples/particle_emitter_example.rb +114 -0
  12. data/examples/pixelate_example.rb +51 -49
  13. data/examples/pixelated_texture_example.rb +69 -0
  14. data/examples/radial_blur_example.rb +60 -62
  15. data/examples/shader_image_example.rb +74 -41
  16. data/examples/{shockwave2_example.rb → shockwave_example.rb} +74 -75
  17. data/examples/stencil_shader_example.rb +104 -0
  18. data/examples/{framebuffer_example.rb → texture_render_example.rb} +53 -49
  19. data/examples/{tv_screen_and_noise_example.rb → tv_screen_and_static_example.rb} +59 -59
  20. data/ext/ashton/GLee.c +18170 -0
  21. data/ext/ashton/GLee.h +17647 -0
  22. data/ext/ashton/ashton.c +42 -0
  23. data/ext/ashton/ashton.h +31 -0
  24. data/ext/ashton/color.c +45 -0
  25. data/ext/ashton/color.h +25 -0
  26. data/ext/ashton/common.h +41 -0
  27. data/ext/ashton/extconf.rb +42 -0
  28. data/ext/ashton/fast_math.c +30 -0
  29. data/ext/ashton/fast_math.h +30 -0
  30. data/ext/ashton/font.c +8 -0
  31. data/ext/ashton/font.h +16 -0
  32. data/ext/ashton/gosu.c +18 -0
  33. data/ext/ashton/gosu.h +19 -0
  34. data/ext/ashton/image.c +8 -0
  35. data/ext/ashton/image.h +16 -0
  36. data/ext/ashton/particle_emitter.c +788 -0
  37. data/ext/ashton/particle_emitter.h +171 -0
  38. data/ext/ashton/pixel_cache.c +237 -0
  39. data/ext/ashton/pixel_cache.h +58 -0
  40. data/ext/ashton/shader.c +9 -0
  41. data/ext/ashton/shader.h +16 -0
  42. data/ext/ashton/texture.c +442 -0
  43. data/ext/ashton/texture.h +63 -0
  44. data/ext/ashton/window.c +8 -0
  45. data/ext/ashton/window.h +16 -0
  46. data/lib/ashton.rb +38 -26
  47. data/lib/ashton/1.9/ashton.so +0 -0
  48. data/lib/ashton/gosu_ext/color.rb +24 -11
  49. data/lib/ashton/gosu_ext/font.rb +58 -0
  50. data/lib/ashton/gosu_ext/gosu_module.rb +16 -0
  51. data/lib/ashton/gosu_ext/image.rb +95 -31
  52. data/lib/ashton/gosu_ext/window.rb +78 -35
  53. data/lib/ashton/image_stub.rb +32 -36
  54. data/lib/ashton/lighting/light_source.rb +146 -0
  55. data/lib/ashton/lighting/manager.rb +98 -0
  56. data/lib/ashton/mixins/version_checking.rb +23 -0
  57. data/lib/ashton/particle_emitter.rb +87 -0
  58. data/lib/ashton/pixel_cache.rb +24 -0
  59. data/lib/ashton/shader.rb +353 -35
  60. data/lib/ashton/shaders/bloom.frag +41 -0
  61. data/lib/ashton/shaders/color_inversion.frag +11 -0
  62. data/lib/ashton/{post_process → shaders}/contrast.frag +16 -16
  63. data/lib/ashton/{shader → shaders}/default.frag +22 -19
  64. data/lib/ashton/{shader → shaders}/default.vert +13 -13
  65. data/lib/ashton/shaders/fade.frag +14 -0
  66. data/lib/ashton/shaders/grayscale.frag +15 -0
  67. data/lib/ashton/shaders/include/classicnoise2d.glsl +113 -0
  68. data/lib/ashton/shaders/include/classicnoise3d.glsl +177 -0
  69. data/lib/ashton/shaders/include/classicnoise4d.glsl +302 -0
  70. data/lib/ashton/{include/simplex.glsl → shaders/include/noise2d.glsl} +70 -63
  71. data/lib/ashton/shaders/include/noise3d.glsl +102 -0
  72. data/lib/ashton/shaders/include/noise4d.glsl +128 -0
  73. data/lib/ashton/shaders/include/rand.glsl +5 -0
  74. data/lib/ashton/shaders/lighting/distort.frag +57 -0
  75. data/lib/ashton/shaders/lighting/draw_shadows.frag +60 -0
  76. data/lib/ashton/shaders/lighting/shadow_blur.frag +60 -0
  77. data/lib/ashton/shaders/mezzotint.frag +22 -0
  78. data/lib/ashton/shaders/multitexture2.vert +19 -0
  79. data/lib/ashton/shaders/outline.frag +45 -0
  80. data/lib/ashton/{post_process → shaders}/pixelate.frag +48 -48
  81. data/lib/ashton/shaders/radial_blur.frag +63 -0
  82. data/lib/ashton/shaders/sepia.frag +26 -0
  83. data/lib/ashton/{post_process/shockwave2.frag → shaders/shockwave.frag} +38 -35
  84. data/lib/ashton/shaders/signed_distance_field.frag +80 -0
  85. data/lib/ashton/{post_process/noise.frag → shaders/static.frag} +25 -27
  86. data/lib/ashton/shaders/stencil.frag +27 -0
  87. data/lib/ashton/shaders/tv_screen.frag +23 -0
  88. data/lib/ashton/signed_distance_field.rb +151 -0
  89. data/lib/ashton/texture.rb +186 -0
  90. data/lib/ashton/version.rb +2 -2
  91. data/lib/ashton/window_buffer.rb +16 -0
  92. data/spec/ashton/ashton_spec.rb +22 -0
  93. data/spec/ashton/gosu_ext/color_spec.rb +34 -0
  94. data/spec/ashton/gosu_ext/font_spec.rb +57 -0
  95. data/spec/ashton/gosu_ext/gosu_spec.rb +11 -0
  96. data/spec/ashton/gosu_ext/image_spec.rb +66 -0
  97. data/spec/ashton/gosu_ext/window_spec.rb +71 -0
  98. data/spec/ashton/image_stub_spec.rb +46 -0
  99. data/spec/ashton/particle_emitter_spec.rb +123 -0
  100. data/spec/ashton/pixel_cache_spec.rb +153 -0
  101. data/spec/ashton/shader_spec.rb +152 -0
  102. data/spec/ashton/signed_distance_field_spec.rb +163 -0
  103. data/spec/ashton/texture_spec.rb +347 -0
  104. data/spec/helper.rb +12 -0
  105. metadata +159 -28
  106. data/examples/output/README.txt +0 -1
  107. data/lib/ashton/base_shader.rb +0 -172
  108. data/lib/ashton/framebuffer.rb +0 -183
  109. data/lib/ashton/post_process.rb +0 -83
  110. data/lib/ashton/post_process/default.vert +0 -9
  111. data/lib/ashton/post_process/fade.frag +0 -11
  112. data/lib/ashton/post_process/mezzotint.frag +0 -24
  113. data/lib/ashton/post_process/radial_blur.frag +0 -31
  114. data/lib/ashton/post_process/sepia.frag +0 -19
  115. data/lib/ashton/post_process/shockwave.frag +0 -40
  116. data/lib/ashton/post_process/tv_screen.frag +0 -32
@@ -1,63 +1,61 @@
1
- # Use of GLSL shader in Gosu to post-process the entire screen.
2
-
3
- begin
4
- require 'rubygems'
5
- rescue LoadError
6
- end
7
-
8
- $LOAD_PATH.unshift File.expand_path('../lib/', File.dirname(__FILE__))
9
- require "ashton"
10
-
11
- def shader(file); File.read File.expand_path("../lib/ashton/post_process/#{file}", File.dirname(__FILE__)) end
12
-
13
- class TestWindow < Gosu::Window
14
- def initialize
15
- super 640, 480, false
16
- self.caption = "Post-processing with 'radial_blur' - hold space to disable; 1..9 sets blurriness"
17
-
18
- @blur = Ashton::PostProcess.new shader('radial_blur.frag')
19
- @blur['in_BrightFactor'] = 1.5
20
- @blur['in_BlurFactor'] = @blur_factor = 2.0
21
- @blur['in_Passes'] = 20 # Quite a lot of work, but just proves how fast shader are!
22
- @font = Gosu::Font.new self, Gosu::default_font_name, 40
23
-
24
- update # Ensure the values are initially set.
25
- end
26
-
27
- def update
28
- # Wiggle the blur about a bit each frame!
29
- @blur['in_OriginX'] = mouse_x
30
- @blur['in_OriginY'] = mouse_y
31
- end
32
-
33
- def button_down(id)
34
- if (Gosu::Kb1..Gosu::Kb9).include? id
35
- @blur_factor = (id - Gosu::Kb1 + 1).to_f
36
- @blur['in_BlurFactor'] = @blur_factor
37
- elsif id == Gosu::KbEscape
38
- close
39
- end
40
- end
41
-
42
- def draw_scene
43
- @font.draw_rel "Hello world!", 100, 100, 0, 0, 0.5, 0.5
44
- @font.draw_rel "Goodbye world!", 400, 280, 0, 0.5, 0.5
45
-
46
- @font.draw_rel "X", mouse_x, mouse_y, 0, 0.5, 0.5
47
- end
48
-
49
- def draw
50
- if button_down? Gosu::KbSpace
51
- draw_scene
52
- else
53
- post_process @blur do
54
- draw_scene
55
- end
56
- end
57
-
58
- # Drawing after the effect isn't processed, which is useful for GUI elements.
59
- @font.draw "Blur Factor: #{@blur_factor}", 0, 0, 0
60
- end
61
- end
62
-
1
+ # Use of GLSL shader in Gosu to post-process the entire screen.
2
+
3
+ begin
4
+ require 'rubygems'
5
+ rescue LoadError
6
+ end
7
+
8
+ $LOAD_PATH.unshift File.expand_path('../lib/', File.dirname(__FILE__))
9
+ require "ashton"
10
+
11
+ def media_path(file); File.expand_path "media/#{file}", File.dirname(__FILE__) end
12
+
13
+ class TestWindow < Gosu::Window
14
+ def initialize
15
+ super 640, 480, false
16
+ self.caption = "Post-processing with 'radial_blur' - mouse pos affects spacing/strength"
17
+
18
+ @blur = Ashton::Shader.new fragment: :radial_blur
19
+ @font = Gosu::Font.new self, Gosu::default_font_name, 40
20
+ @background = Gosu::Image.new(self, media_path("Earth.png"), true)
21
+
22
+ update # Ensure the values are initially set.
23
+ end
24
+
25
+ def update
26
+ $gosu_blocks.clear if defined? $gosu_blocks # Workaround for Gosu bug (0.7.45)
27
+
28
+ @blur.spacing = [2.0 * mouse_x / width, 0.0].max
29
+ @blur.strength = [4.4 * mouse_y / height, 0.0].max
30
+ end
31
+
32
+ def needs_cursor?; true end
33
+
34
+ def button_down(id)
35
+ if (Gosu::Kb1..Gosu::Kb9).include? id
36
+ @blur_factor = (id - Gosu::Kb1 + 1).to_f
37
+ @blur.blur_factor = @blur_factor
38
+ elsif id == Gosu::KbEscape
39
+ close
40
+ end
41
+ end
42
+
43
+ def draw
44
+ shaders = button_down?(Gosu::KbSpace) ? [] : [@blur]
45
+ post_process(*shaders) do
46
+ @background.draw 0, 0, 0, width.fdiv(@background.width), height.fdiv(@background.height)
47
+
48
+ @font.draw_rel "Hello world!", 100, 100, 0, 0.5, 0.5, 1, 1, Gosu::Color::RED
49
+ @font.draw_rel "Goodbye world!", 400, 280, 0, 0.5, 0.5, 1, 1, Gosu::Color::BLUE
50
+ end
51
+
52
+ # Drawing after the effect isn't processed, which is useful for GUI elements.
53
+ @font.draw_rel "Less spacing", 0, height / 2, 0, 0, 0.5
54
+ @font.draw_rel "More spacing", width, height / 2, 0, 1, 0.5
55
+
56
+ @font.draw_rel "Less strength", width / 2, 0, 0, 0.5, 0
57
+ @font.draw_rel "More strength", width / 2, height, 0, 0.5, 1
58
+ end
59
+ end
60
+
63
61
  TestWindow.new.show
@@ -1,42 +1,75 @@
1
- # Use of GLSL shader in Gosu.
2
-
3
- begin
4
- require 'rubygems'
5
- rescue LoadError
6
- end
7
-
8
- $LOAD_PATH.unshift File.expand_path('../lib/', File.dirname(__FILE__))
9
- require "ashton"
10
-
11
- def media_path(file); File.expand_path "media/#{file}", File.dirname(__FILE__) end
12
- def output_path(file); File.expand_path "output/#{file}", File.dirname(__FILE__) end
13
-
14
- class GameWindow < Gosu::Window
15
- def initialize
16
- super 640, 480, false
17
- self.caption = "Gosu & OpenGL Integration Demo (SHADERS)"
18
-
19
- @font = Gosu::Font.new self, Gosu::default_font_name, 20
20
- @image = Gosu::Image.new self, media_path("Earth.png"), true
21
- @shader = Ashton::Shader.new # Just use default shader for now.
22
- end
23
-
24
- def draw
25
- # draw, with and without colour.
26
- @image.draw 10, 10, 0, :shader => @shader
27
- @image.draw 10, @image.height + 20, 0, 1, 1, Gosu::Color::RED, :shader => @shader
28
-
29
- # draw#rot, with and without colour.
30
- @image.draw_rot 280, 0, 0, 10, 0, 0, :shader => @shader
31
- @image.draw_rot 280, @image.height + 10, 0, 10, 0, 0, 1, 1, Gosu::Color::RED, :shader => @shader
32
- end
33
-
34
- def button_down(id)
35
- if id == Gosu::KbEscape
36
- close
37
- end
38
- end
39
- end
40
-
41
- window = GameWindow.new
1
+ # Use of GLSL shader in Gosu.
2
+
3
+ begin
4
+ require 'rubygems'
5
+ rescue LoadError
6
+ end
7
+
8
+ $LOAD_PATH.unshift File.expand_path('../lib/', File.dirname(__FILE__))
9
+ require "ashton"
10
+
11
+ def media_path(file); File.expand_path "media/#{file}", File.dirname(__FILE__) end
12
+ def output_path(file); File.expand_path "output/#{file}", File.dirname(__FILE__) end
13
+
14
+ class GameWindow < Gosu::Window
15
+ def initialize
16
+ super 640, 480, false
17
+ self.caption = "Gosu & OpenGL Integration Demo (SHADERS)"
18
+
19
+ @font = Gosu::Font.new self, Gosu::default_font_name, 24
20
+ @image = Gosu::Image.new self, media_path("Earth.png"), true
21
+
22
+ @sepia = Ashton::Shader.new fragment: :sepia
23
+ @contrast = Ashton::Shader.new fragment: :contrast
24
+ @mezzotint = Ashton::Shader.new fragment: :mezzotint
25
+ @grayscale = Ashton::Shader.new fragment: :grayscale
26
+ @color_inversion = Ashton::Shader.new fragment: :color_inversion
27
+ @fade = Ashton::Shader.new fragment: :fade, uniforms: {
28
+ fade: 0.75,
29
+ }
30
+
31
+ update # Ensure values are set before draw.
32
+ end
33
+
34
+ def update
35
+ $gosu_blocks.clear if defined? $gosu_blocks # workaround for Gosu 0.7.45 bug.
36
+
37
+ @fade.fade = @fade_fade = Math::sin(Gosu::milliseconds / 1000.0) / 2 + 0.5
38
+ @contrast.contrast = @contrast_contrast = Math::sin(Gosu::milliseconds / 1000.0) * 2 + 2
39
+ @mezzotint.t = (Gosu::milliseconds / 100.0).to_i
40
+ end
41
+
42
+ def draw
43
+ @image.draw 0, 0, 0, width.fdiv(@image.width), height.fdiv(@image.height)
44
+
45
+ # draw, with and without colour.
46
+ @image.draw 10, 10, 0, :shader => @sepia
47
+ @font.draw ":sepia", 10, 150, 0
48
+
49
+ @image.draw 10, @image.height + 120, 0, 1, 1, Gosu::Color::RED, :shader => @mezzotint
50
+ @font.draw ":mezzotint", 10, 400, 0
51
+
52
+ # draw_rot, with and without colour.
53
+ @image.draw_rot 235, 0, 0, 10, 0, 0, :shader => @contrast
54
+ @font.draw ":contrast #{"%.2f" % @contrast_contrast}", 235, 150, 0
55
+
56
+ @image.draw_rot 235, @image.height + 110, 0, 10, 0, 0, 1, 1, Gosu::Color::RED, :shader => @fade
57
+ @font.draw ":fade #{"%.2f" % @fade_fade}", 235, 400, 0
58
+
59
+ # More draws.
60
+ @image.draw 430, 10, 0, :shader => @grayscale
61
+ @font.draw ":grayscale", 430, 150, 0
62
+
63
+ @image.draw 430, @image.height + 110, 0, :shader => @color_inversion
64
+ @font.draw ":color_inversion", 430, 400, 0
65
+ end
66
+
67
+ def button_down(id)
68
+ if id == Gosu::KbEscape
69
+ close
70
+ end
71
+ end
72
+ end
73
+
74
+ window = GameWindow.new
42
75
  window.show
@@ -1,76 +1,75 @@
1
- # Use of GLSL shader in Gosu to post-process the entire screen.
2
-
3
- begin
4
- require 'rubygems'
5
- rescue LoadError
6
- end
7
-
8
- $LOAD_PATH.unshift File.expand_path('../lib/', File.dirname(__FILE__))
9
- require "ashton"
10
-
11
- def shader(file); File.read File.expand_path("../lib/ashton/post_process/#{file}", File.dirname(__FILE__)) end
12
- def media_path(file); File.expand_path "media/#{file}", File.dirname(__FILE__) end
13
-
14
- class Shockwave
15
- def age; Gosu::milliseconds - @start_time; end
16
-
17
- def process
18
- @shader.process
19
- end
20
-
21
- def initialize(x, y)
22
- @shader = Ashton::PostProcess.new shader('shockwave2.frag')
23
- @shader['in_ShockParams'] = [10.0, 0.8, 0.1]
24
- @shader['in_Center'] = [x, $window.height - y]
25
- @start_time = Gosu::milliseconds
26
- end
27
-
28
- def update
29
- @shader['in_Time'] = age / 1000.0
30
- end
31
- end
32
-
33
- class TestWindow < Gosu::Window
34
- def initialize
35
- super 640, 480, false
36
- self.caption = "Post-processing with 'shockwave2.frag' - Click on window to create a splash"
37
-
38
- @font = Gosu::Font.new self, Gosu::default_font_name, 40
39
- @background = Gosu::Image.new(self, media_path("Earth.png"), true)
40
- @waves = []
41
- end
42
-
43
- def update
44
- @waves.each {|w| w.update }
45
- @waves.delete_if {|w| w.age > 3000 }
46
- end
47
-
48
- def needs_cursor?
49
- true
50
- end
51
-
52
- def button_down(id)
53
- case id
54
- when Gosu::MsLeft
55
- @waves << Shockwave.new(mouse_x, mouse_y)
56
- when Gosu::KbEscape
57
- close
58
- end
59
- end
60
-
61
- def draw
62
- @background.draw 0, 0, 0, width.fdiv(@background.width), height.fdiv(@background.height)
63
- @font.draw_rel "Hello world!", 350, 50, 0, 0.5, 0.5
64
- @font.draw_rel "Goodbye world!", 400, 350, 0, 0.5, 0.5
65
-
66
- # Since we want to process multiple post-processing effects...
67
- @waves.each do |wave|
68
- wave.process
69
- end
70
-
71
- # Drawing after the effect isn't processed, which is useful for GUI elements.
72
- @font.draw "FPS: #{Gosu::fps} Waves: #{@waves.size}", 0, 0, 0
73
- end
74
- end
75
-
1
+ # Use of GLSL shader in Gosu to post-process the entire screen.
2
+
3
+ begin
4
+ require 'rubygems'
5
+ rescue LoadError
6
+ end
7
+
8
+ $LOAD_PATH.unshift File.expand_path('../lib/', File.dirname(__FILE__))
9
+ require "ashton"
10
+
11
+ def media_path(file); File.expand_path "media/#{file}", File.dirname(__FILE__) end
12
+
13
+ class Shockwave
14
+ attr_reader :shader
15
+
16
+ def age; (Gosu::milliseconds - @start_time) / 1000.0; end
17
+ def dead?; age > 3.0 end
18
+
19
+ def initialize(x, y)
20
+ @shader = Ashton::Shader.new fragment: :shockwave, uniforms: {
21
+ shock_params: [10.0, 0.8, 0.1], # Not entirely sure what these represent!
22
+ center: [x, y],
23
+ }
24
+ @start_time = Gosu::milliseconds
25
+ end
26
+
27
+ def update
28
+ @shader.time = age
29
+ end
30
+ end
31
+
32
+ class TestWindow < Gosu::Window
33
+ def initialize
34
+ super 640, 480, false
35
+ self.caption = "Post-processing with 'shockwave2.frag' - Click on window to create a splash!"
36
+
37
+ @font = Gosu::Font.new self, Gosu::default_font_name, 40
38
+ @background = Gosu::Image.new(self, media_path("Earth.png"), true)
39
+ @waves = []
40
+ end
41
+
42
+ def update
43
+ $gosu_blocks.clear if defined? $gosu_blocks # Workaround for Gosu bug (0.7.45)
44
+
45
+ @waves.delete_if {|w| w.dead? }
46
+ @waves.each {|w| w.update }
47
+ end
48
+
49
+ def needs_cursor?
50
+ true
51
+ end
52
+
53
+ def button_down(id)
54
+ case id
55
+ when Gosu::MsLeft
56
+ @waves << Shockwave.new(mouse_x, mouse_y)
57
+ when Gosu::KbEscape
58
+ close
59
+ end
60
+ end
61
+
62
+ def draw
63
+ shaders = @waves.map {|w| w.shader }
64
+ post_process(*shaders) do
65
+ @background.draw 0, 0, 0, width.fdiv(@background.width), height.fdiv(@background.height)
66
+ @font.draw_rel "Hello world!", 350, 50, 0, 0.5, 0.5
67
+ @font.draw_rel "Goodbye world!", 400, 350, 0, 0.5, 0.5
68
+ end
69
+
70
+ # Drawing after the effect isn't processed, which is useful for GUI elements.
71
+ @font.draw "FPS: #{Gosu::fps} Waves: #{@waves.size}", 0, 0, 0
72
+ end
73
+ end
74
+
76
75
  TestWindow.new.show
@@ -0,0 +1,104 @@
1
+ # Use of a stencil shader and multitexturing in Gosu.
2
+
3
+ begin
4
+ require 'rubygems'
5
+ rescue LoadError
6
+ end
7
+
8
+ $LOAD_PATH.unshift File.expand_path('../lib/', File.dirname(__FILE__))
9
+ require "ashton"
10
+
11
+ def media_path(file); File.expand_path "media/#{file}", File.dirname(__FILE__) end
12
+ def output_path(file); File.expand_path "output/#{file}", File.dirname(__FILE__) end
13
+
14
+ class GameWindow < Gosu::Window
15
+ def initialize
16
+ super 640, 480, false
17
+ self.caption = "Stencil shader - <space> new stencil layout <I> to invert stencilling effect"
18
+
19
+ setup_example_objects
20
+
21
+ @image = Gosu::Image.new self, media_path("LargeStar.png"), false
22
+ @stencil = Gosu::Image.new self, media_path("SmallStar.png"), false
23
+
24
+ # The texture to draw the stencil on. It's best to use an
25
+ # Ashton::WindowBuffer, since it is the same size as the window itself.
26
+ @stencil_texture = Ashton::WindowBuffer.new
27
+
28
+ # Fill the stencil texture
29
+ place_stencils
30
+
31
+ @shader = Ashton::Shader.new vertex: :multitexture2, fragment: :stencil
32
+ @inverted = false
33
+ end
34
+
35
+ def draw
36
+ # Draw the background and ship
37
+ draw_example_objects
38
+
39
+
40
+ # We'll use the window's primary buffer to draw our images that need to be masked.
41
+ # We can use this buffer as long as we don't expect it to be cleared before we use it
42
+ # or unaltered between our uses of it.
43
+ primary_buffer.render do |buffer|
44
+ buffer.clear
45
+ @image.draw_rot(@image.width / 2, @image.height / 2, 0, @rotation)
46
+ end
47
+
48
+ # Draw the primary buffer with our shader and give it our stencil to work with.
49
+ primary_buffer.draw 0, 0, 0, shader: @shader, multitexture: @stencil_texture
50
+
51
+ @font.draw "Stencil effect #{"(INVERTED)" if @inverted}", 0, 0, 0
52
+
53
+ # Show the stencil texture drawn directly on the screen, for comparison.
54
+ @stencil_texture.draw 320, 0, 0, mode: :replace
55
+ @font.draw "Stencil texture (black is transparent)", 320, 0, 0
56
+ end
57
+
58
+ # Clear the stencil texture and draw new stencils on top of it
59
+ def place_stencils
60
+ @stencil_texture.render do |texture|
61
+ texture.clear
62
+ 5.times do
63
+ @stencil.draw_rot(rand(@image.width), rand(@image.height), 1, 0, 0.5, 0.5, 2, 2)
64
+ end
65
+ end
66
+ end
67
+
68
+ # Not important --------
69
+
70
+ def update
71
+ $gosu_blocks.clear if defined? $gosu_blocks # Workaround for Gosu bug (0.7.45)
72
+ @rotation = (@rotation + 1) % 360
73
+ end
74
+
75
+ def button_down(id)
76
+ case id
77
+ when Gosu::KbEscape
78
+ close
79
+
80
+ when Gosu::KbSpace
81
+ place_stencils
82
+
83
+ when Gosu::KbI
84
+ @inverted = !@inverted
85
+ @shader.inverted = @inverted
86
+ end
87
+ end
88
+
89
+ private
90
+ def draw_example_objects
91
+ @background.draw 0, 0, 0, width.fdiv(@background.width), height.fdiv(@background.height)
92
+ @ship.draw(100, 200 + 200 * Math.sin(@rotation.gosu_to_radians), 0)
93
+ end
94
+
95
+ def setup_example_objects
96
+ @font = Gosu::Font.new $window, Gosu::default_font_name, 20
97
+ @background = Gosu::Image.new self, media_path("Earth.png"), true
98
+ @ship = Gosu::Image.new self, media_path("Starfighter.bmp"), false
99
+ @rotation = 0
100
+ end
101
+ end
102
+
103
+ window = GameWindow.new
104
+ window.show