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,27 +1,25 @@
1
- #version 110
2
-
3
- // Rather poor quality noise generation, but better than nothing and sort of looks like TV static a bit.
4
-
5
- uniform sampler2D in_Texture;
6
-
7
- uniform int in_WindowWidth; // Not used.
8
- uniform int in_WindowHeight; // Not used.
9
-
10
- uniform float in_Intensity;
11
- uniform float in_T;
12
-
13
- varying vec2 var_TexCoord;
14
-
15
- float rand(vec2 co) {
16
- return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);
17
- }
18
-
19
- void main() {
20
- vec4 color = texture2D(in_Texture, var_TexCoord);
21
-
22
- vec4 influence = min(color, 1.0 - color);
23
-
24
- float noise = 1.0 - 2.0 * rand(var_TexCoord + float(in_T));
25
-
26
- gl_FragColor = color + in_Intensity * influence * noise;
27
- }
1
+ #version 110
2
+
3
+ #include <rand>
4
+
5
+ // Rather poor quality noise generation, but better than nothing and sort of looks like TV static a bit.
6
+
7
+ uniform sampler2D in_Texture;
8
+
9
+ uniform int in_WindowWidth; // Not used.
10
+ uniform int in_WindowHeight; // Not used.
11
+
12
+ uniform float in_Intensity;
13
+ uniform float in_T;
14
+
15
+ varying vec2 var_TexCoord;
16
+
17
+ void main() {
18
+ vec4 color = texture2D(in_Texture, var_TexCoord);
19
+
20
+ vec4 influence = min(color, 1.0 - color);
21
+
22
+ float noise = 1.0 - 2.0 * rand(var_TexCoord + float(in_T));
23
+
24
+ gl_FragColor = color + in_Intensity * influence * noise;
25
+ }
@@ -0,0 +1,27 @@
1
+ #version 110
2
+
3
+ // Use a stencil texture to selectively draw. Drawing of the image will occur
4
+ // where the stencil is transparent (or only where the stencil is opaque if
5
+ // inverted).
6
+ //
7
+ // Partial transparency in the stencil will allow the image to be drawn
8
+ // partially too.
9
+
10
+ varying vec4 var_Color;
11
+ varying vec2 var_TexCoord0; // The texture/image to draw.
12
+ varying vec2 var_TexCoord1; // The stencil (multitexture).
13
+
14
+ uniform sampler2D in_Texture0; // The texture/image to draw.
15
+ uniform sampler2D in_Texture1; // The stencil (multitexture).
16
+ uniform bool in_Inverted; // true to draw in opaque areas / false to draw in transparent areas.
17
+
18
+ void main()
19
+ {
20
+ vec4 texColor = texture2D(in_Texture0, var_TexCoord0);
21
+ vec4 maskColor = texture2D(in_Texture1, var_TexCoord1);
22
+
23
+ // Only draw the texture where the stencil is transparent (unless inverted).
24
+ float mask_alpha = in_Inverted ? (1.0 - maskColor.a) : maskColor.a;
25
+
26
+ gl_FragColor = vec4(texColor.r, texColor.g, texColor.b, texColor.a - mask_alpha);
27
+ }
@@ -0,0 +1,23 @@
1
+ #version 110
2
+
3
+ uniform sampler2D in_Texture;
4
+
5
+ uniform float in_ColumnWidth; // In pixels.
6
+ uniform int in_WindowWidth;
7
+ uniform int in_WindowHeight; // Not used in this shader.
8
+
9
+ varying vec2 var_TexCoord;
10
+
11
+ void main()
12
+ {
13
+ vec3 color = texture2D(in_Texture, var_TexCoord).rgb;
14
+
15
+ gl_FragColor = vec4(color * 0.25, 1.0);
16
+
17
+ float column_index = var_TexCoord.x * float(in_WindowWidth) / in_ColumnWidth;
18
+
19
+ int c = int(mod(column_index, 3.0));
20
+ if(c == 0) { gl_FragColor.r = color.r; }
21
+ else if(c == 1) { gl_FragColor.g = color.g; }
22
+ else if(c == 2) { gl_FragColor.b = color.b; }
23
+ }
@@ -0,0 +1,151 @@
1
+ module Ashton
2
+ class SignedDistanceField
3
+ ZERO_DISTANCE = 128 # color channel containing 0 => -128, 128 => 0, 129 => +1, 255 => +128
4
+
5
+ attr_reader :width, :height
6
+
7
+ # Creates a Signed Distance Field based on a given image.
8
+ # When drawing into the SDF, drawing should ONLY have alpha of 0 (clear) or 255 (solid)
9
+ #
10
+ # @param width [Integer]
11
+ # @param height [Integer]
12
+ # @param max_distance [Integer] Maximum distance to measure.
13
+ # @option options :step_size [Integer] (1) pixels to step out.
14
+ # @option options :scale [Integer] (1) Scale relative to the image.
15
+ def initialize(width, height, max_distance, options = {}, &block)
16
+ options = {
17
+ scale: 1,
18
+ step_size: 1,
19
+ }.merge! options
20
+
21
+ @width, @height = width, height
22
+ @scale = options[:scale].to_f
23
+
24
+ @shader = Shader.new fragment: :signed_distance_field, uniforms: {
25
+ max_distance: max_distance.ceil,
26
+ step_size: options[:step_size].floor, # One pixel.
27
+ texture_size: [width, height].map(&:to_f),
28
+ }
29
+
30
+ @field = Texture.new (width / @scale).ceil, (height / @scale).ceil
31
+ @mask = Texture.new @field.width, @field.height
32
+
33
+ if block_given?
34
+ render_field &block
35
+ else
36
+ @field.clear color: Gosu::Color.rgb(*([ZERO_DISTANCE + max_distance] * 3))
37
+ end
38
+ end
39
+
40
+ # Is the position clear for a given radius around it.
41
+ def position_clear?(x, y, radius)
42
+ sample_distance(x, y) >= radius
43
+ end
44
+
45
+ # If positive, distance, in pixels, to the nearest opaque pixel.
46
+ # If negative, distance in pixels to the nearest transparent pixel.
47
+ def sample_distance(x, y)
48
+ x = [[x, width - 1].min, 0].max
49
+ y = [[y, height - 1].min, 0].max
50
+ # Could be checking any of red/blue/green.
51
+ @field.red((x / @scale).round, (y / @scale).round) - ZERO_DISTANCE
52
+ end
53
+
54
+ # Gets the gradient of the field at a given point.
55
+ # @return [Float, Float] gradient_x, gradient_y
56
+ def sample_gradient(x, y)
57
+ d0 = sample_distance x, y - 1
58
+ d1 = sample_distance x - 1, y
59
+ d2 = sample_distance x + 1, y
60
+ d3 = sample_distance x, y + 1
61
+
62
+ [(d2 - d1) / @scale, (d3 - d0) / @scale]
63
+ end
64
+
65
+ # Get the normal at a given point.
66
+ # @return [Float, Float] normal_x, normal_y
67
+ def sample_normal(x, y)
68
+ gradient_x, gradient_y = sample_gradient x, y
69
+ length = Gosu::distance 0, 0, gradient_x, gradient_y
70
+ if length == 0
71
+ [0, 0] # This could be NaN in edge cases.
72
+ else
73
+ [gradient_x / length, gradient_y / length]
74
+ end
75
+ end
76
+
77
+ # Does the point x1, x2 have line of sight to x2, y2 (that is, no solid in the way).
78
+ def line_of_sight?(x1, y1, x2, y2)
79
+ !line_of_sight_blocked_at(x1, y1, x2, y2)
80
+ end
81
+
82
+ # Returns blocking position, else nil if line of sight isn't blocked.
83
+ def line_of_sight_blocked_at(x1, y1, x2, y2)
84
+ distance_to_travel = Gosu::distance x1, y1, x2, y2
85
+ distance_x, distance_y = x2 - x1, y2 - y1
86
+ distance_travelled = 0
87
+ x, y = x1, y1
88
+
89
+ loop do
90
+ distance = sample_distance x, y
91
+
92
+ # Blocked?
93
+ return [x, y] if distance <= 0
94
+
95
+ distance_travelled += distance
96
+
97
+ # Got to destination in the clear.
98
+ return nil if distance_travelled >= distance_to_travel
99
+
100
+ lerp = distance_travelled.fdiv distance_to_travel
101
+ x = x1 + distance_x * lerp
102
+ y = y1 + distance_y * lerp
103
+ end
104
+ end
105
+
106
+ # Update the SDF should the image have changed.
107
+ # Draw the mask in the passed block.
108
+ def render_field
109
+ raise ArgumentError, "Block required" unless block_given?
110
+
111
+ @mask.render do
112
+ @mask.clear
113
+ $window.scale 1.0 / @scale do
114
+ yield self
115
+ end
116
+ end
117
+
118
+ @shader.enable do
119
+ @field.render do
120
+ @mask.draw 0, 0, 0
121
+ end
122
+ end
123
+
124
+ nil
125
+ end
126
+
127
+ # Draw the field, usually for debugging purposes.
128
+ # @see Ashton::Texture#draw
129
+ def draw(x, y, z, options = {})
130
+ options = {
131
+ mode: :add,
132
+ }.merge! options
133
+
134
+ $window.scale @scale do
135
+ @field.draw x, y, z, options
136
+ end
137
+
138
+ nil
139
+ end
140
+
141
+ # Convert into a nested array of sample values.
142
+ # @return [Array<Array<Integer>>]
143
+ def to_a
144
+ width.times.map do |x|
145
+ height.times.map do |y|
146
+ sample_distance x, y
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,186 @@
1
+ module Ashton
2
+ class Texture
3
+ include Mixins::VersionChecking
4
+
5
+ DEFAULT_DRAW_COLOR = Gosu::Color::WHITE
6
+ VALID_DRAW_MODES = [:alpha_blend, :add, :multiply, :replace]
7
+
8
+ class << self
9
+ # [Boolean] Whether or not to pixelate (rather than smooth) on #draw
10
+ attr_writer :pixelated
11
+ # [Boolean] Whether or not to pixelate (rather than smooth) on #draw. Set true when Gosu::enable_undocumented_retrofication called.
12
+ def pixelated?; @pixelated end
13
+ end
14
+ self.pixelated = false
15
+
16
+ # [Boolean] Is this texture being rendered to currently?
17
+ def rendering?; @rendering end
18
+
19
+ # @overload initialize(image)
20
+ # Create a texture from a Gosu::Image
21
+ #
22
+ # @see Image#to_texture
23
+ # @param image [Gosu::Image]
24
+ #
25
+ # @overload initialize(blob, width, height)
26
+ # Create a texture from a binary blob.
27
+ #
28
+ # @param blob [String]
29
+ # @param width [Integer]
30
+ # @param height [Integer]
31
+ #
32
+ # @overload initialize(width, height)
33
+ # Create a blank (transparent) texture.
34
+ #
35
+ # @param width [Integer]
36
+ # @param height [Integer]
37
+ def initialize(*args)
38
+ case args.size
39
+ when 1
40
+ # Create from Gosu::Image
41
+ image = args[0]
42
+ raise TypeError, "Expected Gosu::Image" unless image.is_a? Gosu::Image
43
+ initialize_ image.width, image.height, nil
44
+
45
+ render do
46
+ # TODO: Ideally we'd draw the image in replacement mode, but Gosu doesn't support that.
47
+ $window.gl do
48
+ info = image.gl_tex_info
49
+ glEnable GL_TEXTURE_2D
50
+ glBindTexture GL_TEXTURE_2D, info.tex_name
51
+ glEnable GL_BLEND
52
+ glBlendFunc GL_ONE, GL_ZERO
53
+
54
+ glBegin GL_QUADS do
55
+ glTexCoord2d info.left, info.top
56
+ glVertex2d 0, height # BL
57
+
58
+ glTexCoord2d info.left, info.bottom
59
+ glVertex2d 0, 0 # TL
60
+
61
+ glTexCoord2d info.right, info.bottom
62
+ glVertex2d width, 0 # TR
63
+
64
+ glTexCoord2d info.right, info.top
65
+ glVertex2d width, height # BR
66
+ end
67
+ end
68
+ end
69
+
70
+ when 2
71
+ # Create blank image.
72
+ width, height = *args
73
+ initialize_ width, height, nil
74
+ clear
75
+
76
+ when 3
77
+ # Create from blob - create a Gosu image first.
78
+ blob, width, height = *args
79
+ raise ArgumentError, "Blob data is not of expected size" if blob.length != width * height * 4
80
+ initialize_ width, height, blob
81
+
82
+ else
83
+ raise ArgumentError, "Expected 1, 2 or 3 parameters."
84
+ end
85
+
86
+ @rendering = false
87
+ end
88
+
89
+ public
90
+ # Clears the buffer, optionally to a specific color.
91
+ #
92
+ # @option options :color [Gosu::Color, Array<Float>] (transparent)
93
+ def clear(options = {})
94
+ options = {
95
+ color: [0.0, 0.0, 0.0, 0.0],
96
+ }.merge! options
97
+
98
+ color = options[:color]
99
+ color = color.to_opengl if color.is_a? Gosu::Color
100
+
101
+ glBindFramebufferEXT GL_FRAMEBUFFER_EXT, fbo_id unless rendering?
102
+
103
+ glDisable GL_BLEND # Need to replace the alpha too.
104
+ glClearColor *color
105
+ glClear GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
106
+ glEnable GL_BLEND
107
+
108
+ glBindFramebufferEXT GL_FRAMEBUFFER_EXT, 0 unless rendering?
109
+
110
+ nil
111
+ end
112
+
113
+ public
114
+ # Enable the texture to use (e.g. to draw or convert it).
115
+ def render
116
+ raise ArgumentError, "Block required" unless block_given?
117
+ raise Error, "Can't nest rendering" if rendering?
118
+
119
+ $window.flush # Ensure that any drawing _before_ the render block is drawn to screen, rather than into the buffer.
120
+
121
+ render_
122
+
123
+ @rendering = true
124
+
125
+ # Project onto the texture itself, using Gosu (inverted) coordinates.
126
+ glPushMatrix
127
+ glMatrixMode GL_PROJECTION
128
+ glLoadIdentity
129
+ glViewport 0, 0, width, height
130
+ glOrtho 0, width, height, 0, -1, 1
131
+
132
+ begin
133
+ yield self
134
+ ensure
135
+ $window.flush # Force all the drawing to draw now!
136
+ glBindFramebufferEXT GL_FRAMEBUFFER_EXT, 0
137
+
138
+ @rendering = false
139
+
140
+ glPopMatrix
141
+
142
+ cache.refresh # Force lazy reloading of the cache.
143
+ end
144
+
145
+ self
146
+ end
147
+
148
+ # @!method draw(x, y, z, options = {})
149
+ # Draw the Texture.
150
+ #
151
+ # This is not as versatile as converting the Texture into a Gosu::Image and then
152
+ # drawing it, but it is many times faster, so use it when you are updating the buffer
153
+ # every frame, rather than just composing an image.
154
+ #
155
+ # Drawing in Gosu orientation will be flipped in standard OpenGL and visa versa.
156
+ #
157
+ # @param x [Number] Top left corner x.
158
+ # @param y [Number] Top left corner y.
159
+ # @param z [Number] Z-order (can be nil to draw immediately)
160
+ #
161
+ # @option options :shader [Ashton::Shader] Shader to apply to drawing.
162
+ # @option options :color [Gosu::Color] (Gosu::Color::WHITE) Color to apply to the drawing.
163
+ # @option options :mode [Symbol] (:alpha_blend) :alpha_blend, :add, :multiply, :replace
164
+ # @option options :multitexture [Texture] A texture to be used in a multi-texturing shader.
165
+ # @option options :pixelated [Boolean] (true if Gosu::enable_undocumented_retrofication ever called) Pixelate, rather than smooth, when zoomed out.
166
+
167
+ public
168
+ # Convert the current contents of the buffer into a Gosu::Image
169
+ #
170
+ # @option options :caching [Boolean] (true) TexPlay behaviour.
171
+ # @option options :tileable [Boolean] (false) Standard Gosu behaviour.
172
+ # @option options :rect [Array<Integer>] ([0, 0, width, height]) Rectangular area of buffer to use to create the image [x, y, w, h]
173
+ def to_image(*args)
174
+ cache.to_image *args
175
+ end
176
+
177
+ def dup
178
+ # Create a new texture and draw self into it.
179
+ new_texture = Texture.new width, height
180
+ new_texture.render do
181
+ draw 0, 0, 0, mode: :replace
182
+ end
183
+ new_texture
184
+ end
185
+ end
186
+ end
@@ -1,3 +1,3 @@
1
- module Ashton
2
- VERSION = "0.0.1alpha"
1
+ module Ashton
2
+ VERSION = "0.0.2alpha"
3
3
  end