ashton 0.0.1alpha
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/CHANGELOG +0 -0
- data/LICENSE +21 -0
- data/README.md +68 -0
- data/Rakefile +24 -0
- data/examples/framebuffer_example.rb +50 -0
- data/examples/media/Earth.png +0 -0
- data/examples/media/LargeStar.png +0 -0
- data/examples/media/Star.png +0 -0
- data/examples/media/Starfighter.bmp +0 -0
- data/examples/media/simple.png +0 -0
- data/examples/output/README.txt +1 -0
- data/examples/pixelate_example.rb +50 -0
- data/examples/radial_blur_example.rb +63 -0
- data/examples/shader_image_example.rb +42 -0
- data/examples/shockwave2_example.rb +76 -0
- data/examples/tv_screen_and_noise_example.rb +60 -0
- data/lib/ashton/base_shader.rb +172 -0
- data/lib/ashton/framebuffer.rb +183 -0
- data/lib/ashton/gosu_ext/color.rb +12 -0
- data/lib/ashton/gosu_ext/image.rb +32 -0
- data/lib/ashton/gosu_ext/window.rb +36 -0
- data/lib/ashton/image_stub.rb +37 -0
- data/lib/ashton/include/simplex.glsl +63 -0
- data/lib/ashton/post_process/contrast.frag +16 -0
- data/lib/ashton/post_process/default.vert +9 -0
- data/lib/ashton/post_process/fade.frag +11 -0
- data/lib/ashton/post_process/mezzotint.frag +24 -0
- data/lib/ashton/post_process/noise.frag +27 -0
- data/lib/ashton/post_process/pixelate.frag +48 -0
- data/lib/ashton/post_process/radial_blur.frag +31 -0
- data/lib/ashton/post_process/sepia.frag +19 -0
- data/lib/ashton/post_process/shockwave.frag +40 -0
- data/lib/ashton/post_process/shockwave2.frag +35 -0
- data/lib/ashton/post_process/tv_screen.frag +32 -0
- data/lib/ashton/post_process.rb +83 -0
- data/lib/ashton/shader/default.frag +19 -0
- data/lib/ashton/shader/default.vert +14 -0
- data/lib/ashton/shader.rb +62 -0
- data/lib/ashton/version.rb +3 -0
- data/lib/ashton.rb +26 -0
- metadata +201 -0
data/CHANGELOG
ADDED
File without changes
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2012 Bil Bas
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
Ashton
|
2
|
+
======
|
3
|
+
|
4
|
+
Description
|
5
|
+
-----------
|
6
|
+
|
7
|
+
Add extra visual effects to the Gosu game-development library, utilising OpenGL shaders (using shader model 1.0, for maximum compatibility) and frame-buffers.
|
8
|
+
|
9
|
+
"Ashton" is named after [Clark Ashton Smith](http://en.wikipedia.org/wiki/Clark_Ashton_Smith), an fantasy/horror author
|
10
|
+
with a particularly colourful imagination.
|
11
|
+
|
12
|
+
- Author: Bil Bas (Spooner)
|
13
|
+
- License: MIT
|
14
|
+
|
15
|
+
Usage
|
16
|
+
-----
|
17
|
+
|
18
|
+
gem install ashton --pre
|
19
|
+
|
20
|
+
Features
|
21
|
+
--------
|
22
|
+
|
23
|
+
- Gosu::Font
|
24
|
+
* [TODO] #draw - Added :shader hash option to choose optional shader to use.
|
25
|
+
* [TODO] #draw_rel - Added :shader hash option to choose optional shader to use.
|
26
|
+
|
27
|
+
- Gosu::Image
|
28
|
+
* #draw - Added :shader hash option to choose optional shader to use.
|
29
|
+
* #draw_rot - Added :shader hash option to choose optional shader to use.
|
30
|
+
* [TODO] #flip!, #flip, #mirror!, #mirror, #scale!, #scale, etc.
|
31
|
+
* [TODO] #resize (Well, create another image which is smaller/larger).
|
32
|
+
* [TODO] #to_framebuffer
|
33
|
+
|
34
|
+
- Gosu::Window
|
35
|
+
* #post_process {} - Draws contents of block into a back-buffer, then applies a shader as it draws that onto the screen.
|
36
|
+
* [TODO] #to_framebuffer - Copy the contents of the window as a {Ashton::Framebuffer}.
|
37
|
+
* [TODO] #to_image - Create Gosu::Image from window contents.
|
38
|
+
* [TODO] #draw_line - Added :shader hash option
|
39
|
+
* [TODO] #draw_quad - Added :shader hash option
|
40
|
+
* [TODO] #draw_triangle - Added :shader hash option
|
41
|
+
|
42
|
+
- {Ashton::Shader}
|
43
|
+
* #use {} - Inside the block, all draw operations are affected by the shader.
|
44
|
+
* Supports vertex and fragment shaders.
|
45
|
+
|
46
|
+
- {Ashton::PostProcess}
|
47
|
+
* A specific type of shader to perform full-screen post-processing.
|
48
|
+
* #process - Used to post-process the entire Gosu::Window at once, after some, or all, drawing is complete.
|
49
|
+
* Supports fragment shaders.
|
50
|
+
* [TODO] Includes a small library of example shaders (:blur, :simplex, etc).
|
51
|
+
|
52
|
+
- {Ashton::Framebuffer}
|
53
|
+
* #use {} - Inside the block, draw operations go into the framebuffer, rather than onto the window.
|
54
|
+
* #to_image - Convert to Gosu::Image.
|
55
|
+
* #draw - Draw directly onto a Gosu::Window.
|
56
|
+
* [TODO] #flip!, #flip - Invert framebuffer's vertical orientation.
|
57
|
+
|
58
|
+
Similar Libraries
|
59
|
+
-----------------
|
60
|
+
|
61
|
+
- [TexPlay](https://github.com/banister/texplay) - Deals with Gosu::Image manipulation, such as per-pixel editing and drawing. It is compatible with, and complementary to, this gem.
|
62
|
+
|
63
|
+
Credits
|
64
|
+
-------
|
65
|
+
|
66
|
+
- simplex.glsl - simplex noise implementation - Copyright (C) 2011 Ashima Arts - MIT license.
|
67
|
+
|
68
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rake/clean'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require 'yard'
|
4
|
+
require 'redcloth'
|
5
|
+
require 'launchy'
|
6
|
+
require 'rubygems/package_task'
|
7
|
+
|
8
|
+
|
9
|
+
spec = Gem::Specification.load Dir['*.gemspec'].first
|
10
|
+
|
11
|
+
Gem::PackageTask.new spec do
|
12
|
+
end
|
13
|
+
|
14
|
+
YARD::Rake::YardocTask.new
|
15
|
+
|
16
|
+
task :default => :spec
|
17
|
+
|
18
|
+
RSpec::Core::RakeTask.new do |t|
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "Open yard docs in browser"
|
22
|
+
task :browse_yard => :yard do
|
23
|
+
Launchy.open "doc/index.html" rescue nil
|
24
|
+
end
|
@@ -0,0 +1,50 @@
|
|
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
|
+
|
13
|
+
class GameWindow < Gosu::Window
|
14
|
+
def initialize
|
15
|
+
super 800, 600, false
|
16
|
+
self.caption = "Ashton::Framebuffer example - composing an image inside a buffer - hold <LMB> to draw - <delete> to clear"
|
17
|
+
|
18
|
+
@font = Gosu::Font.new(self, Gosu::default_font_name, 20)
|
19
|
+
@star = Gosu::Image.new(self, media_path("LargeStar.png"), true)
|
20
|
+
@framebuffer = Ashton::Framebuffer.new width, height
|
21
|
+
end
|
22
|
+
|
23
|
+
def update
|
24
|
+
if button_down? Gosu::MsLeft
|
25
|
+
# Draw into the framebuffer, rather than onto the screen.
|
26
|
+
@framebuffer.use do
|
27
|
+
@star.draw_rot mouse_x, mouse_y, 0, 0, 0.5, 0.5
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def draw
|
33
|
+
@framebuffer.draw 0, 0 # Draws immediately.
|
34
|
+
@star.draw_rot mouse_x, mouse_y, 0, 0, 0.5, 0.5
|
35
|
+
|
36
|
+
@font.draw "FPS: #{Gosu::fps}", 0, 0, 0
|
37
|
+
end
|
38
|
+
|
39
|
+
def button_down(id)
|
40
|
+
case id
|
41
|
+
when Gosu::KbDelete
|
42
|
+
@framebuffer.clear
|
43
|
+
when Gosu::KbEscape
|
44
|
+
close
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
window = GameWindow.new
|
50
|
+
window.show
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
Output from the examples will be saved here, to prove that some functionality works.
|
@@ -0,0 +1,50 @@
|
|
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 TestWindow < Gosu::Window
|
15
|
+
def initialize
|
16
|
+
super 640, 480, false
|
17
|
+
self.caption = "Post-processing with 'pixelate' - 1..9 affect pixel size"
|
18
|
+
|
19
|
+
@pixelate = Ashton::PostProcess.new shader('pixelate.frag')
|
20
|
+
@pixelate['in_PixelSize'] = @pixel_size = 4
|
21
|
+
|
22
|
+
@font = Gosu::Font.new self, Gosu::default_font_name, 40
|
23
|
+
@star = Gosu::Image.new(self, media_path("LargeStar.png"), true)
|
24
|
+
|
25
|
+
update # Ensure the values are initially set.
|
26
|
+
end
|
27
|
+
|
28
|
+
def button_down(id)
|
29
|
+
if (Gosu::Kb1..Gosu::Kb9).include? id
|
30
|
+
@pixel_size = (id - Gosu::Kb1 + 1) ** 2
|
31
|
+
@pixelate['in_PixelSize'] = @pixel_size
|
32
|
+
elsif id == Gosu::KbEscape
|
33
|
+
close
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def draw
|
38
|
+
post_process @pixelate do
|
39
|
+
@font.draw_rel "Hello world!", 350, 50, 0, 0.5, 0.5
|
40
|
+
@font.draw_rel "Goodbye world!", 400, 350, 0, 0.5, 0.5
|
41
|
+
@star.draw 0, 0, 0
|
42
|
+
@star.draw 200, 100, 0
|
43
|
+
end
|
44
|
+
|
45
|
+
# Drawing after the effect isn't processed, which is useful for GUI elements.
|
46
|
+
@font.draw "Pixel ratio: 1:#{@pixel_size}", 0, 0, 0
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
TestWindow.new.show
|
@@ -0,0 +1,63 @@
|
|
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
|
+
|
63
|
+
TestWindow.new.show
|
@@ -0,0 +1,42 @@
|
|
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
|
42
|
+
window.show
|
@@ -0,0 +1,76 @@
|
|
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
|
+
|
76
|
+
TestWindow.new.show
|
@@ -0,0 +1,60 @@
|
|
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 TestWindow < Gosu::Window
|
15
|
+
def initialize
|
16
|
+
super 640, 480, false
|
17
|
+
self.caption = "Post-processing with both 'tv_screen.frag' and 'noise.frag'"
|
18
|
+
|
19
|
+
@screen = Ashton::PostProcess.new shader('tv_screen.frag')
|
20
|
+
@screen['in_ColumnWidth'] = 1.0
|
21
|
+
|
22
|
+
@noise = Ashton::PostProcess.new shader('noise.frag')
|
23
|
+
|
24
|
+
|
25
|
+
@font = Gosu::Font.new self, Gosu::default_font_name, 40
|
26
|
+
@star = Gosu::Image.new(self, media_path("LargeStar.png"), true)
|
27
|
+
@background = Gosu::Image.new(self, media_path("Earth.png"), true)
|
28
|
+
|
29
|
+
update # Ensure the values are initially set.
|
30
|
+
end
|
31
|
+
|
32
|
+
def update
|
33
|
+
@noise['in_T'] = Math::sin(Gosu::milliseconds / 500.0) * 1000
|
34
|
+
@noise['in_Intensity'] = Math::sin(Gosu::milliseconds / 2345.0) + 1.5
|
35
|
+
end
|
36
|
+
|
37
|
+
def draw
|
38
|
+
@background.draw 0, 0, 0, width.fdiv(@background.width), height.fdiv(@background.height)
|
39
|
+
|
40
|
+
@font.draw_rel "Hello world!", 350, 50, 0, 0.5, 0.5, 1, 1, Gosu::Color::GREEN
|
41
|
+
@font.draw_rel "Goodbye world!", 400, 350, 0, 0.5, 0.5, 2, 2, Gosu::Color::BLUE
|
42
|
+
|
43
|
+
@star.draw 0, 0, 0
|
44
|
+
@star.draw 200, 100, 0
|
45
|
+
|
46
|
+
@noise.process
|
47
|
+
@screen.process
|
48
|
+
|
49
|
+
# Drawing after the effect isn't processed, which is useful for GUI elements.
|
50
|
+
@font.draw "FPS: #{Gosu::fps}", 0, 0, 0
|
51
|
+
end
|
52
|
+
|
53
|
+
def button_down(id)
|
54
|
+
if id == Gosu::KbEscape
|
55
|
+
close
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
TestWindow.new.show
|
@@ -0,0 +1,172 @@
|
|
1
|
+
module Ashton
|
2
|
+
# @abstract
|
3
|
+
class BaseShader
|
4
|
+
INVALID_LOCATION = -1
|
5
|
+
MIN_OPENGL_VERSION = 2.0
|
6
|
+
|
7
|
+
attr_reader :fragment_source, :vertex_source
|
8
|
+
|
9
|
+
# Todo: Pass in a filename (String) or name of built-in pp shader (Symbol)
|
10
|
+
#
|
11
|
+
# @option options [String] :vertex Source code for vertex shader.
|
12
|
+
# @option options [String] :vert equivalent to :vertex
|
13
|
+
# @option options [String] :fragment Source code for fragment shader.
|
14
|
+
# @option options [String] :frag equivalent to :fragment
|
15
|
+
def initialize(vertex_source, fragment_source)
|
16
|
+
raise "Can't instantiate abstract class" if self.class == BaseShader
|
17
|
+
|
18
|
+
unless GL.version_supported? MIN_OPENGL_VERSION
|
19
|
+
raise NotSupportedError, "Ashton requires OpenGL #{MIN_OPENGL_VERSION} support to utilise shaders"
|
20
|
+
end
|
21
|
+
|
22
|
+
@uniform_locations = {}
|
23
|
+
@attribute_locations = {}
|
24
|
+
@program = nil
|
25
|
+
|
26
|
+
@vertex_source = vertex_source
|
27
|
+
@fragment_source = fragment_source
|
28
|
+
|
29
|
+
@vertex = compile GL_VERTEX_SHADER, vertex_source
|
30
|
+
@fragment = compile GL_FRAGMENT_SHADER, fragment_source
|
31
|
+
|
32
|
+
link
|
33
|
+
|
34
|
+
glBindFragDataLocationEXT @program, 0, "out_FragColor"
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
# Creates a copy of the shader program, recompiling the source,
|
39
|
+
# but not preserving the uniform values.
|
40
|
+
def dup
|
41
|
+
self.class.new :vertex => @vertex_source, :fragment => @fragment_source
|
42
|
+
end
|
43
|
+
|
44
|
+
# Make this the current shader program.
|
45
|
+
def use
|
46
|
+
previous_program = glGetIntegerv GL_CURRENT_PROGRAM
|
47
|
+
glUseProgram @program
|
48
|
+
|
49
|
+
if block_given?
|
50
|
+
result = yield self
|
51
|
+
$window.flush # TODO: need to work out how to make shader affect delayed draws.
|
52
|
+
glUseProgram previous_program
|
53
|
+
end
|
54
|
+
|
55
|
+
result
|
56
|
+
end
|
57
|
+
|
58
|
+
# Disable the shader program (not needed in block version of #use).
|
59
|
+
def disable
|
60
|
+
glUseProgram 0 # Disable the shader!
|
61
|
+
end
|
62
|
+
|
63
|
+
# Is this the current shader program?
|
64
|
+
def current?
|
65
|
+
glGetIntegerv(GL_CURRENT_PROGRAM) == @program
|
66
|
+
end
|
67
|
+
|
68
|
+
# Set the value of a uniform.
|
69
|
+
def []=(name, value)
|
70
|
+
use do
|
71
|
+
case value
|
72
|
+
when true, GL_TRUE
|
73
|
+
glUniform1i uniform(name), 1
|
74
|
+
|
75
|
+
when false, GL_FALSE
|
76
|
+
glUniform1i uniform(name), 0
|
77
|
+
|
78
|
+
when Float
|
79
|
+
glUniform1f uniform(name), value
|
80
|
+
|
81
|
+
when Integer
|
82
|
+
glUniform1i uniform(name), value
|
83
|
+
|
84
|
+
when Array
|
85
|
+
size = value.size
|
86
|
+
|
87
|
+
raise ArgumentError, "Empty array not supported for uniform data" if size.zero?
|
88
|
+
raise ArgumentError, "Only support uniforms up to 4 elements" if size > 4
|
89
|
+
|
90
|
+
case value[0]
|
91
|
+
when Float
|
92
|
+
GL.send "glUniform#{size}f", uniform(name), *value
|
93
|
+
|
94
|
+
when Integer
|
95
|
+
GL.send "glUniform#{size}i", uniform(name), *value
|
96
|
+
|
97
|
+
else
|
98
|
+
raise ArgumentError, "Uniform data type not supported for element of type: #{value[0].class}"
|
99
|
+
end
|
100
|
+
|
101
|
+
else
|
102
|
+
raise ArgumentError, "Uniform data type not supported for type: #{value.class}"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
|
109
|
+
def uniform(name)
|
110
|
+
location = @uniform_locations[name]
|
111
|
+
if location
|
112
|
+
location
|
113
|
+
else
|
114
|
+
location = glGetUniformLocation @program, name.to_s
|
115
|
+
raise ShaderUniformError, "No #{name} uniform specified in program" if location == INVALID_LOCATION
|
116
|
+
@uniform_locations[name] = location
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
protected
|
121
|
+
def attribute(name)
|
122
|
+
location = @attribute_locations[name]
|
123
|
+
if location
|
124
|
+
location
|
125
|
+
else
|
126
|
+
location = glGetAttribLocation @program, name.to_s
|
127
|
+
raise ShaderAttributeError, "No #{name} attribute specified in program" if location == INVALID_LOCATION
|
128
|
+
@attribute_locations[name] = location
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
protected
|
133
|
+
def compile(type, source)
|
134
|
+
shader = glCreateShader type
|
135
|
+
glShaderSource shader, source
|
136
|
+
glCompileShader shader
|
137
|
+
|
138
|
+
unless glGetShaderiv shader, GL_COMPILE_STATUS
|
139
|
+
error = glGetShaderInfoLog shader
|
140
|
+
error_lines = error.scan(/0\((\d+)\)+/m).map {|num| num.first.to_i }.uniq
|
141
|
+
|
142
|
+
if type == GL_VERTEX_SHADER
|
143
|
+
type_name = "Vertex"
|
144
|
+
source = @vertex_source
|
145
|
+
else
|
146
|
+
type_name = "Fragment"
|
147
|
+
source = @fragment_source
|
148
|
+
end
|
149
|
+
|
150
|
+
source_lines = source.split("\n")
|
151
|
+
lines = error_lines.map {|i| "#{i.to_s.rjust 3}: #{source_lines[i - 1].rstrip}" }.join "\n"
|
152
|
+
raise ShaderCompileError, "#{type_name} shader error: #{glGetShaderInfoLog(shader)}\n#{lines}"
|
153
|
+
end
|
154
|
+
|
155
|
+
shader
|
156
|
+
end
|
157
|
+
|
158
|
+
protected
|
159
|
+
def link
|
160
|
+
@program = glCreateProgram
|
161
|
+
glAttachShader @program, @vertex
|
162
|
+
glAttachShader @program, @fragment
|
163
|
+
glLinkProgram @program
|
164
|
+
|
165
|
+
unless glGetProgramiv @program, GL_LINK_STATUS
|
166
|
+
raise ShaderLinkError, "Shader link error: #{glGetProgramInfoLog(@program)}"
|
167
|
+
end
|
168
|
+
|
169
|
+
nil
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|