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,37 +1,33 @@
1
- module Ashton
2
- # Used internally to create images from raw binary (blob) data.
3
- #
4
- # This object duck-types an RMagick image (#rows, #columns, #to_blob), so that Gosu will import it.
5
- class ImageStub
6
-
7
- # @return [Integer]
8
- attr_reader :rows, :columns
9
-
10
- # The first pixel in the blob will be at the top left hand corner of the created image, since that is the orientation
11
- # of Gosu images.
12
- #
13
- # @param [String] blob_data Raw data string to import. Must be RGBA ordered, (4 * width * height) bytes in length.
14
- # @param [Integer] width Number of pixels wide.
15
- # @param [Integer] height Number of pixels high.
16
- def initialize(blob_data, width, height)
17
- @data, @columns, @rows = blob_data, width, height
18
- end
19
-
20
- # @return [String]
21
- def to_blob
22
- @data
23
- end
24
- end
25
-
26
- # Used internally to create blank images (red/blue/green/alpha all 0).
27
- #
28
- # Credit to philomory for this class.
29
- class EmptyImageStub < ImageStub
30
- # @param width (see ImageStub#initialize)
31
- # @param height (see ImageStub#initialize)
32
- def initialize(width, height)
33
- #raise ArgumentError if (width > TexPlay::TP_MAX_QUAD_SIZE || height > TexPlay::TP_MAX_QUAD_SIZE)
34
- super('\0' * (width * height * 4), width, height)
35
- end
36
- end
1
+ module Ashton
2
+ # Used internally to create images from raw binary (blob) data.
3
+ #
4
+ # This object duck-types an RMagick image (#rows, #columns, #to_blob), so that Gosu will import it.
5
+ class ImageStub
6
+
7
+ # @return [Integer]
8
+ attr_reader :rows
9
+ # @return [Integer]
10
+ attr_reader :columns
11
+
12
+ # The first pixel in the blob will be at the top left hand corner of the created image, since that is the orientation
13
+ # of Gosu images.
14
+ #
15
+ # @param [String] blob_data Raw data string to import. Must be RGBA ordered, (4 * width * height) bytes in length.
16
+ # @param [Integer] width Number of pixels wide.
17
+ # @param [Integer] height Number of pixels high.
18
+ def initialize(blob_data, width, height)
19
+ raise ArgumentError, "Width must be >= 1 pixel" unless width > 0
20
+ raise ArgumentError, "Height must be >= 1 pixel" unless height > 0
21
+
22
+ expected_size = width * height * 4
23
+ raise ArgumentError, "Expected blob to be #{expected_size} bytes" unless blob_data.size == expected_size
24
+
25
+ @data, @columns, @rows = blob_data, width, height
26
+ end
27
+
28
+ # @return [String]
29
+ def to_blob
30
+ @data
31
+ end
32
+ end
37
33
  end
@@ -0,0 +1,146 @@
1
+ module Ashton
2
+ module Lighting
3
+ # Based on Catalin Zima's shader based dynamic shadows system.
4
+ # http://www.catalinzima.com/2010/07/my-technique-for-the-shader-based-dynamic-2d-shadows/
5
+ class LightSource
6
+ include Mixins::VersionChecking
7
+
8
+ # PIXEL_BUFFER_EXTENSION = "GL_EXT_pixel_buffer_object"
9
+
10
+ class << self
11
+ attr_accessor :distort_shader, :draw_shadows_shader, :blur_shader
12
+ end
13
+
14
+ attr_reader :radius
15
+ attr_accessor :x, :y, :z, :color
16
+
17
+ def width; @radius * 2 end
18
+ def height; @radius * 2 end
19
+
20
+ def initialize(x, y, z, radius, options = {})
21
+ #check_opengl_extension PIXEL_BUFFER_EXTENSION
22
+
23
+ @x, @y, @z, @radius = x, y, z, radius.to_i
24
+ @color = options[:color] || Gosu::Color::WHITE
25
+
26
+ @shadow_casters = Ashton::Texture.new width, height
27
+ @shadow_map = Ashton::Texture.new 2, height
28
+ @shadows = Ashton::Texture.new width, height
29
+ @blurred = Ashton::Texture.new width, height
30
+
31
+ load_shaders
32
+ end
33
+
34
+ public
35
+ # Only need to render shadows again if anything has actually changed!
36
+ def render_shadows(&block)
37
+ raise "block required" unless block_given?
38
+
39
+ render_shadow_casters &block
40
+
41
+ # Distort the shadow casters and reduce into a a 2-pixel wide shadow-map of the blockages.
42
+ LightSource.distort_shader.enable { distort }
43
+
44
+ # Render the shadows themselves, before blurring.
45
+ LightLightSource.draw_shadows_shader.enable { draw_shadows }
46
+
47
+ # Finally blur it up and apply the radial lighting.
48
+ LightSource.blur_shader.enable { blur }
49
+
50
+ nil
51
+ end
52
+
53
+ protected
54
+ def render_shadow_casters
55
+ raise "block required" unless block_given?
56
+ # Get a copy of the shadow-casting objects in out light-zone.
57
+ @shadow_casters.render do |buffer|
58
+ buffer.clear
59
+ $window.translate @radius - @x, @radius - @y do
60
+ yield
61
+ end
62
+ end
63
+ end
64
+
65
+ protected
66
+ def distort
67
+ LightSource.distort_shader.texture_width = width
68
+ @shadow_map.render do
69
+ $window.scale 1.0 / radius, 1 do
70
+ @shadow_casters.draw 0, 0, 0
71
+ end
72
+ end
73
+ end
74
+
75
+ protected
76
+ def draw_shadows
77
+ LightSource.draw_shadows_shader.texture_width = width
78
+ @shadows.render do
79
+ # Not actually drawing anything from the shadow map buffer.
80
+ # It is just a data input to what will be drawn.
81
+ $window.scale radius, 1 do
82
+ @shadow_map.draw 0, 0, 0
83
+ end
84
+ end
85
+ end
86
+
87
+ protected
88
+ def blur
89
+ LightSource.blur_shader.texture_width = width
90
+ @blurred.render do
91
+ @shadows.draw 0, 0, 0
92
+ end
93
+ end
94
+
95
+ public
96
+ def draw(options = {})
97
+ options = {
98
+ mode: :add,
99
+ color: @color,
100
+ }.merge! options
101
+
102
+ @blurred.draw @x - @radius, @y - @radius, @z, options
103
+ @shadow_casters.draw @x - @radius, @y - @radius, @z, options
104
+ nil
105
+ end
106
+
107
+ public
108
+ # Draw some quadrant lines (for debugging).
109
+ def draw_debug
110
+ color = @color.dup
111
+ color.alpha = 75
112
+
113
+ $window.translate -@radius, -@radius do
114
+ $window.draw_line x, y, color, x + width, y, color, z
115
+ $window.draw_line x + width, y, color, x + width, y + height, color, z
116
+ $window.draw_line x + width, y + height, color, x, y + height, color, z
117
+ $window.draw_line x, y + height, color, x, y, color, z
118
+
119
+ $window.draw_line x, y, color, x + width, y + height, color, z
120
+ $window.draw_line x, y + height, color, x + width, y, color, z
121
+ end
122
+ end
123
+
124
+ protected
125
+ def load_shaders
126
+ LightSource.distort_shader ||= Ashton::Shader.new fragment: :"lighting/distort"
127
+
128
+ LightSource.draw_shadows_shader ||= Ashton::Shader.new fragment: :"lighting/draw_shadows"
129
+
130
+ LightSource.blur_shader ||= Ashton::Shader.new fragment: :"lighting/shadow_blur"
131
+
132
+ nil
133
+ end
134
+
135
+ protected
136
+ # Used for debugging purposes only.
137
+ def save_buffers
138
+ # Only save once. for purposes of this example only.
139
+ @shadow_casters.to_image.save "output/shadow_casters_#{x}_#{y}.png"
140
+ @shadow_map.to_image.save "output/shadow_map_#{x}_#{y}.png"
141
+ @shadows.to_image.save "output/shadows_#{x}_#{y}.png"
142
+ @blurred.to_image.save "output/blurred_#{x}_#{y}.png"
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,98 @@
1
+ require 'set'
2
+
3
+ module Ashton
4
+ module Lighting
5
+ # Based on Catalin Zima's shader based dynamic shadows system.
6
+ # http://www.catalinzima.com/2010/07/my-technique-for-the-shader-based-dynamic-2d-shadows/
7
+ class Manager
8
+ include Enumerable
9
+
10
+ attr_accessor :camera_x, :camera_y, :z
11
+
12
+ def each(&block); @lights.each &block end
13
+ def size; @lights.size end
14
+ def empty?; @lights.empty? end
15
+ def width; @shadows.width end
16
+ def height; @shadows.height end
17
+
18
+ def initialize(options = {})
19
+ options = {
20
+ width: $window.width,
21
+ height: $window.height,
22
+ camera_x: 0,
23
+ camera_y: 0,
24
+ z: 0,
25
+ }.merge! options
26
+
27
+ @camera_x, @camera_y = options[:camera_x], options[:camera_y]
28
+ @z = options[:z]
29
+
30
+ @lights = Set.new
31
+ @shadows = Ashton::Texture.new options[:width], options[:height]
32
+ end
33
+
34
+ # @param light [Ashton::LightSource]
35
+ # @return [Ashton::LightSource]
36
+ def add(light)
37
+ raise TypeError unless light.is_a? LightSource
38
+
39
+ @lights << light
40
+ light
41
+ end
42
+ alias_method :<<, :add
43
+
44
+ def remove(light)
45
+ @lights -= [light]
46
+ light
47
+ end
48
+
49
+ # @see Ashton::LightSource#new
50
+ #
51
+ # @return [Ashton::LightSource]
52
+ def create_light(*args)
53
+ add LightSource.new(*args)
54
+ end
55
+
56
+ def draw(options = {})
57
+ options = {
58
+ mode: :multiply,
59
+ }.merge! options
60
+
61
+ @shadows.draw @camera_x, @camera_y, @z, options
62
+ end
63
+
64
+ def update_shadow_casters(&block)
65
+ raise ArgumentError, "Requires block" unless block_given?
66
+
67
+ unless empty?
68
+ # TODO: Need to only render to lights that are on-screen.
69
+ @lights.each do |light|
70
+ light.send :render_shadow_casters, &block
71
+ end
72
+
73
+ # Use each shader on every light, to save setting and un-setting shaders (a bit faster, depending on number of light sources).
74
+ LightSource.distort_shader.enable do
75
+ @lights.each {|light| light.send :distort }
76
+ end
77
+
78
+ LightSource.draw_shadows_shader.enable do
79
+ @lights.each {|light| light.send :draw_shadows }
80
+ end
81
+
82
+ LightSource.blur_shader.enable do
83
+ @lights.each {|light| light.send :blur }
84
+ end
85
+ end
86
+
87
+ @shadows.render do |buffer|
88
+ buffer.clear
89
+ $window.translate -@camera_x, -@camera_y do
90
+ @lights.each {|light| light.draw } unless empty?
91
+ end
92
+ end
93
+
94
+ nil
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,23 @@
1
+ module Ashton
2
+ module Mixins
3
+ module VersionChecking
4
+ # Check if a specific OpenGL version is supported on this machine.
5
+ #
6
+ # @raise NotSupportedError
7
+ def check_opengl_version(version)
8
+ unless GL.version_supported? version
9
+ raise NotSupportedError, "OpenGL #{version} required to utilise #{self.class}"
10
+ end
11
+ end
12
+
13
+ # Check if a specific OpenGL extension is supported on this machine.
14
+ #
15
+ # @raise NotSupportedError
16
+ def check_opengl_extension(extension)
17
+ unless GL.extension_supported? extension
18
+ raise NotSupportedError, "OpenGL extension #{extension} required to utilise #{self.class}"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,87 @@
1
+ module Ashton
2
+ class ParticleEmitter
3
+ def empty?; count == 0 end
4
+
5
+ DEFAULT_MAX_PARTICLES = 1000
6
+ DEFAULT_COLOR = Gosu::Color::WHITE
7
+ RANGED_ATTRIBUTES = [
8
+ :angular_velocity, :center_x, :center_y,
9
+ :fade, :friction, :interval,
10
+ :offset, :scale, :speed, :time_to_live, :zoom
11
+ ]
12
+
13
+ def initialize(x, y, z, options = {})
14
+ # I'm MUCH too lazy to implement a huge options hash manager in C, especially on a constructor.
15
+ max_particles = options[:max_particles] || DEFAULT_MAX_PARTICLES
16
+ initialize_ x, y, z, max_particles
17
+
18
+ self.shader = options[:shader]
19
+ self.image = options[:image] || $window.pixel
20
+
21
+ self.gravity = options[:gravity] || 0.0
22
+ self.color = options[:color] || DEFAULT_COLOR
23
+
24
+ self.angular_velocity = options[:angular_velocity] || 0.0
25
+ self.center_x = options[:center_x] || 0.5
26
+ self.center_y = options[:center_y] || 0.5
27
+ self.fade = options[:fade] || 0.0
28
+ self.friction = options[:friction] || 0.0
29
+ self.interval = options[:interval] || Float::INFINITY
30
+ self.offset = options[:offset] || 0.0
31
+ self.scale = options[:scale] || 1.0
32
+ self.speed = options[:speed] || 0.0
33
+ self.time_to_live = options[:time_to_live] || Float::INFINITY
34
+ self.zoom = options[:zoom] || 0.0
35
+ end
36
+
37
+ # Gosu::Color
38
+ def color
39
+ Gosu::Color.new color_argb
40
+ end
41
+
42
+ # [Gosu::Color, Integer, Array<Float>]
43
+ def color=(value)
44
+ case value
45
+ when Integer
46
+ self.color_argb = value
47
+ when Gosu::Color
48
+ self.color_argb = value.to_i
49
+ when Array
50
+ self.color_argb = Gosu::Color.from_opengl value
51
+ else
52
+ raise TypeError, "Expected argb integer, rgba opengl float array or Gosu::Color"
53
+ end
54
+
55
+ value
56
+ end
57
+
58
+ RANGED_ATTRIBUTES.each do |attr|
59
+ # Returns a Range.
60
+ define_method attr do
61
+ send("#{attr}_min")..send("#{attr}_max")
62
+ end
63
+
64
+ # Can be set as a Range or as a single number.
65
+ define_method "#{attr}=" do |value|
66
+ min, max = case value
67
+ when Numeric
68
+ [value, value]
69
+ when Range
70
+ [value.min, value.max]
71
+ else
72
+ raise TypeError, "Expecting Numeric or Range, not #{value.class}"
73
+ end
74
+
75
+ send "#{attr}_min=", min
76
+ send "#{attr}_max=", max
77
+
78
+ value
79
+ end
80
+ end
81
+
82
+ # @!method draw()
83
+
84
+ # @!method update(delta)
85
+ # @param delta (Float) number of seconds to run the simulation for.
86
+ end
87
+ end
@@ -0,0 +1,24 @@
1
+ module Ashton
2
+ class PixelCache
3
+ # Docs here.
4
+
5
+ public
6
+ # Convert the current contents of the cache into a Gosu::Image
7
+ #
8
+ # @option options :caching [Boolean] (true) TexPlay behaviour.
9
+ # @option options :tileable [Boolean] (false) Standard Gosu behaviour.
10
+ def to_image(options = {})
11
+ options = {
12
+ tileable: false,
13
+ }.merge! options
14
+
15
+ # Create a new Image from the flipped pixel data.
16
+ stub = ImageStub.new to_blob, width, height
17
+ if defined? TexPlay
18
+ Gosu::Image.new $window, stub, options[:tileable], options
19
+ else
20
+ Gosu::Image.new $window, stub, options[:tileable]
21
+ end
22
+ end
23
+ end
24
+ end