ashton 0.0.1alpha → 0.0.2alpha

Sign up to get free protection for your applications and to get access to all the features.
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