cyberarm_engine 0.12.1 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +8 -8
  3. data/.travis.yml +5 -5
  4. data/Gemfile +6 -6
  5. data/LICENSE.txt +21 -21
  6. data/README.md +43 -43
  7. data/Rakefile +10 -10
  8. data/bin/console +14 -14
  9. data/bin/setup +8 -8
  10. data/cyberarm_engine.gemspec +36 -36
  11. data/lib/cyberarm_engine.rb +47 -46
  12. data/lib/cyberarm_engine/animator.rb +54 -0
  13. data/lib/cyberarm_engine/background.rb +175 -175
  14. data/lib/cyberarm_engine/bounding_box.rb +149 -149
  15. data/lib/cyberarm_engine/common.rb +96 -96
  16. data/lib/cyberarm_engine/engine.rb +101 -101
  17. data/lib/cyberarm_engine/game_object.rb +256 -256
  18. data/lib/cyberarm_engine/game_state.rb +88 -88
  19. data/lib/cyberarm_engine/gosu_ext/circle.rb +8 -8
  20. data/lib/cyberarm_engine/ray.rb +55 -55
  21. data/lib/cyberarm_engine/shader.rb +262 -205
  22. data/lib/cyberarm_engine/text.rb +146 -146
  23. data/lib/cyberarm_engine/timer.rb +22 -22
  24. data/lib/cyberarm_engine/transform.rb +272 -83
  25. data/lib/cyberarm_engine/ui/border_canvas.rb +100 -100
  26. data/lib/cyberarm_engine/ui/dsl.rb +98 -101
  27. data/lib/cyberarm_engine/ui/element.rb +275 -259
  28. data/lib/cyberarm_engine/ui/elements/button.rb +66 -66
  29. data/lib/cyberarm_engine/ui/elements/check_box.rb +58 -58
  30. data/lib/cyberarm_engine/ui/elements/container.rb +176 -162
  31. data/lib/cyberarm_engine/ui/elements/edit_line.rb +171 -102
  32. data/lib/cyberarm_engine/ui/elements/flow.rb +16 -16
  33. data/lib/cyberarm_engine/ui/elements/image.rb +51 -51
  34. data/lib/cyberarm_engine/ui/elements/label.rb +49 -49
  35. data/lib/cyberarm_engine/ui/elements/progress.rb +49 -49
  36. data/lib/cyberarm_engine/ui/elements/stack.rb +12 -12
  37. data/lib/cyberarm_engine/ui/elements/toggle_button.rb +55 -55
  38. data/lib/cyberarm_engine/ui/event.rb +46 -45
  39. data/lib/cyberarm_engine/ui/gui_state.rb +134 -134
  40. data/lib/cyberarm_engine/ui/style.rb +36 -36
  41. data/lib/cyberarm_engine/ui/theme.rb +120 -119
  42. data/lib/cyberarm_engine/vector.rb +202 -198
  43. data/lib/cyberarm_engine/version.rb +4 -4
  44. metadata +6 -5
@@ -1,89 +1,89 @@
1
- module CyberarmEngine
2
- class GameState
3
- include Common
4
-
5
- attr_accessor :options, :global_pause
6
- attr_reader :game_objects, :containers
7
-
8
- def initialize(options={})
9
- @options = options
10
- @game_objects = []
11
- @global_pause = false
12
- $window.text_input = nil unless options[:preserve_text_input]
13
-
14
- @down_keys = {}
15
- end
16
-
17
- def setup
18
- end
19
-
20
- def draw
21
- @game_objects.each(&:draw)
22
- end
23
-
24
- def update
25
- @game_objects.each(&:update)
26
- end
27
-
28
- def draw_bounding_box(box)
29
- x,y, max_x, max_y = box.x, box.y, box.max_x, box.max_y
30
-
31
- color = Gosu::Color.rgba(255, 127, 64, 240)
32
-
33
- # pipe = 4
34
- # Gosu.draw_rect(x-width, y-height, x+(width*2), y+(height*2), color, Float::INFINITY)
35
- # puts "BB render: #{x}:#{y} w:#{x.abs+width} h:#{y.abs+height}"
36
- # Gosu.draw_rect(x, y, x.abs+width, y.abs+height, color, Float::INFINITY)
37
-
38
- # TOP LEFT to BOTTOM LEFT
39
- $window.draw_line(
40
- x, y, color,
41
- x, max_y, color,
42
- Float::INFINITY
43
- )
44
- # BOTTOM LEFT to BOTTOM RIGHT
45
- $window.draw_line(
46
- x, max_y, color,
47
- max_x, max_y, color,
48
- Float::INFINITY
49
- )
50
- # BOTTOM RIGHT to TOP RIGHT
51
- $window.draw_line(
52
- max_x, max_y, color,
53
- max_x, y, color,
54
- Float::INFINITY
55
- )
56
- # TOP RIGHT to TOP LEFT
57
- $window.draw_line(
58
- max_x, y, color,
59
- x, y, color,
60
- Float::INFINITY
61
- )
62
- end
63
-
64
- def destroy
65
- @options.clear
66
- @game_objects.clear
67
- end
68
-
69
- def button_down(id)
70
- @down_keys[id] = true
71
-
72
- @game_objects.each do |o|
73
- o.button_down(id)
74
- end
75
- end
76
-
77
- def button_up(id)
78
- @down_keys.delete(id)
79
-
80
- @game_objects.each do |o|
81
- o.button_up(id)
82
- end
83
- end
84
-
85
- def add_game_object(object)
86
- @game_objects << object
87
- end
88
- end
1
+ module CyberarmEngine
2
+ class GameState
3
+ include Common
4
+
5
+ attr_accessor :options, :global_pause
6
+ attr_reader :game_objects, :containers
7
+
8
+ def initialize(options={})
9
+ @options = options
10
+ @game_objects = []
11
+ @global_pause = false
12
+ $window.text_input = nil unless options[:preserve_text_input]
13
+
14
+ @down_keys = {}
15
+ end
16
+
17
+ def setup
18
+ end
19
+
20
+ def draw
21
+ @game_objects.each(&:draw)
22
+ end
23
+
24
+ def update
25
+ @game_objects.each(&:update)
26
+ end
27
+
28
+ def draw_bounding_box(box)
29
+ x,y, max_x, max_y = box.x, box.y, box.max_x, box.max_y
30
+
31
+ color = Gosu::Color.rgba(255, 127, 64, 240)
32
+
33
+ # pipe = 4
34
+ # Gosu.draw_rect(x-width, y-height, x+(width*2), y+(height*2), color, Float::INFINITY)
35
+ # puts "BB render: #{x}:#{y} w:#{x.abs+width} h:#{y.abs+height}"
36
+ # Gosu.draw_rect(x, y, x.abs+width, y.abs+height, color, Float::INFINITY)
37
+
38
+ # TOP LEFT to BOTTOM LEFT
39
+ $window.draw_line(
40
+ x, y, color,
41
+ x, max_y, color,
42
+ Float::INFINITY
43
+ )
44
+ # BOTTOM LEFT to BOTTOM RIGHT
45
+ $window.draw_line(
46
+ x, max_y, color,
47
+ max_x, max_y, color,
48
+ Float::INFINITY
49
+ )
50
+ # BOTTOM RIGHT to TOP RIGHT
51
+ $window.draw_line(
52
+ max_x, max_y, color,
53
+ max_x, y, color,
54
+ Float::INFINITY
55
+ )
56
+ # TOP RIGHT to TOP LEFT
57
+ $window.draw_line(
58
+ max_x, y, color,
59
+ x, y, color,
60
+ Float::INFINITY
61
+ )
62
+ end
63
+
64
+ def destroy
65
+ @options.clear
66
+ @game_objects.clear
67
+ end
68
+
69
+ def button_down(id)
70
+ @down_keys[id] = true
71
+
72
+ @game_objects.each do |o|
73
+ o.button_down(id)
74
+ end
75
+ end
76
+
77
+ def button_up(id)
78
+ @down_keys.delete(id)
79
+
80
+ @game_objects.each do |o|
81
+ o.button_up(id)
82
+ end
83
+ end
84
+
85
+ def add_game_object(object)
86
+ @game_objects << object
87
+ end
88
+ end
89
89
  end
@@ -1,9 +1,9 @@
1
- module Gosu
2
- # Sourced from https://gist.github.com/ippa/662583
3
- def self.draw_circle(cx,cy,r, z = 9999,color = Gosu::Color::GREEN, step = 10)
4
- 0.step(360, step) do |a1|
5
- a2 = a1 + step
6
- draw_line(cx + Gosu.offset_x(a1, r), cy + Gosu.offset_y(a1, r), color, cx + Gosu.offset_x(a2, r), cy + Gosu.offset_y(a2, r), color, z)
7
- end
8
- end
1
+ module Gosu
2
+ # Sourced from https://gist.github.com/ippa/662583
3
+ def self.draw_circle(cx,cy,r, z = 9999,color = Gosu::Color::GREEN, step = 10)
4
+ 0.step(360, step) do |a1|
5
+ a2 = a1 + step
6
+ draw_line(cx + Gosu.offset_x(a1, r), cy + Gosu.offset_y(a1, r), color, cx + Gosu.offset_x(a2, r), cy + Gosu.offset_y(a2, r), color, z)
7
+ end
8
+ end
9
9
  end
@@ -1,56 +1,56 @@
1
- module CyberarmEngine
2
- class Ray
3
- def initialize(origin, direction, range = Float::INFINITY)
4
- raise "Origin must be a Vector!" unless origin.is_a?(Vector)
5
- raise "Direction must be a Vector!" unless direction.is_a?(Vector)
6
-
7
- @origin = origin
8
- @direction = direction
9
- @range = range
10
-
11
- @inverse_direction = @direction.inverse
12
- end
13
-
14
- def intersect?(intersectable)
15
- if intersectable.is_a?(BoundingBox)
16
- intersect_bounding_box?(intersectable)
17
- else
18
- raise NotImplementedError, "Ray intersection test for #{intersectable.class} not implemented."
19
- end
20
- end
21
-
22
- # Based on: https://tavianator.com/fast-branchless-raybounding-box-intersections/
23
- def intersect_bounding_box?(box)
24
- tmin = -@range
25
- tmax = @range
26
-
27
- tx1 = (box.min.x - @origin.x) * @inverse_direction.x
28
- tx2 = (box.max.x - @origin.x) * @inverse_direction.x
29
-
30
- tmin = max(tmin, min(tx1, tx2))
31
- tmax = min(tmax, max(tx1, tx2))
32
-
33
- ty1 = (box.min.y - @origin.y) * @inverse_direction.y
34
- ty2 = (box.max.y - @origin.y) * @inverse_direction.y
35
-
36
- tmin = max(tmin, min(ty1, ty2))
37
- tmax = min(tmax, max(ty1, ty2))
38
-
39
- tz1 = (box.min.z - @origin.z) * @inverse_direction.z
40
- tz2 = (box.max.z - @origin.z) * @inverse_direction.z
41
-
42
- tmin = max(tmin, min(tz1, tz2))
43
- tmax = min(tmax, max(tz1, tz2))
44
-
45
- return tmax >= max(tmin, 0.0);
46
- end
47
-
48
- def min(x, y)
49
- ((x) < (y) ? (x) : (y))
50
- end
51
-
52
- def max(x, y)
53
- ((x) > (y) ? (x) : (y))
54
- end
55
- end
1
+ module CyberarmEngine
2
+ class Ray
3
+ def initialize(origin, direction, range = Float::INFINITY)
4
+ raise "Origin must be a Vector!" unless origin.is_a?(Vector)
5
+ raise "Direction must be a Vector!" unless direction.is_a?(Vector)
6
+
7
+ @origin = origin
8
+ @direction = direction
9
+ @range = range
10
+
11
+ @inverse_direction = @direction.inverse
12
+ end
13
+
14
+ def intersect?(intersectable)
15
+ if intersectable.is_a?(BoundingBox)
16
+ intersect_bounding_box?(intersectable)
17
+ else
18
+ raise NotImplementedError, "Ray intersection test for #{intersectable.class} not implemented."
19
+ end
20
+ end
21
+
22
+ # Based on: https://tavianator.com/fast-branchless-raybounding-box-intersections/
23
+ def intersect_bounding_box?(box)
24
+ tmin = -@range
25
+ tmax = @range
26
+
27
+ tx1 = (box.min.x - @origin.x) * @inverse_direction.x
28
+ tx2 = (box.max.x - @origin.x) * @inverse_direction.x
29
+
30
+ tmin = max(tmin, min(tx1, tx2))
31
+ tmax = min(tmax, max(tx1, tx2))
32
+
33
+ ty1 = (box.min.y - @origin.y) * @inverse_direction.y
34
+ ty2 = (box.max.y - @origin.y) * @inverse_direction.y
35
+
36
+ tmin = max(tmin, min(ty1, ty2))
37
+ tmax = min(tmax, max(ty1, ty2))
38
+
39
+ tz1 = (box.min.z - @origin.z) * @inverse_direction.z
40
+ tz2 = (box.max.z - @origin.z) * @inverse_direction.z
41
+
42
+ tmin = max(tmin, min(tz1, tz2))
43
+ tmax = min(tmax, max(tz1, tz2))
44
+
45
+ return tmax >= max(tmin, 0.0);
46
+ end
47
+
48
+ def min(x, y)
49
+ ((x) < (y) ? (x) : (y))
50
+ end
51
+
52
+ def max(x, y)
53
+ ((x) > (y) ? (x) : (y))
54
+ end
55
+ end
56
56
  end
@@ -1,205 +1,262 @@
1
- module CyberarmEngine
2
- # Ref: https://github.com/vaiorabbit/ruby-opengl/blob/master/sample/OrangeBook/brick.rb
3
- class Shader
4
- include OpenGL
5
- @@shaders = {}
6
-
7
- def self.add(name, instance)
8
- @@shaders[name] = instance
9
- end
10
-
11
- def self.use(name, &block)
12
- shader = @@shaders.dig(name)
13
- if shader
14
- shader.use(&block)
15
- else
16
- raise ArgumentError, "Shader '#{name}' not found!"
17
- end
18
- end
19
-
20
- def self.available?(name)
21
- @@shaders.dig(name).is_a?(Shader)
22
- end
23
-
24
- def self.get(name)
25
- @@shaders.dig(name)
26
- end
27
-
28
- def self.active_shader
29
- @active_shader
30
- end
31
-
32
- def self.active_shader=(instance)
33
- @active_shader = instance
34
- end
35
-
36
- def self.stop
37
- shader = Shader.active_shader
38
-
39
- if shader
40
- shader.stop
41
- else
42
- raise ArgumentError, "No active shader to stop!"
43
- end
44
- end
45
-
46
- def self.attribute_location(variable)
47
- raise RuntimeError, "No active shader!" unless Shader.active_shader
48
- Shader.active_shader.attribute_location(variable)
49
- end
50
-
51
- def self.set_uniform(variable, value)
52
- raise RuntimeError, "No active shader!" unless Shader.active_shader
53
- Shader.active_shader.set_uniform(variable, value)
54
- end
55
-
56
- attr_reader :name, :program
57
- def initialize(name:, vertex: "shaders/default.vert", fragment:)
58
- @name = name
59
- @vertex_file = vertex
60
- @fragment_file = fragment
61
- @compiled = false
62
-
63
- @program = nil
64
-
65
- @error_buffer_size = 1024
66
- @variable_missing = {}
67
-
68
- raise ArgumentError, "Shader files not found: #{@vertex_file} or #{@fragment_file}" unless shader_files_exist?
69
-
70
- create_shaders
71
- compile_shaders
72
-
73
- # Only add shader if it successfully compiles
74
- if @compiled
75
- Shader.add(@name, self)
76
- else
77
- puts "FAILED to compile shader: #{@name}", ""
78
- end
79
- end
80
-
81
- def shader_files_exist?
82
- File.exist?(@vertex_file) && File.exist?(@fragment_file)
83
- end
84
-
85
- def create_shaders
86
- @vertex = glCreateShader(GL_VERTEX_SHADER)
87
- @fragment = glCreateShader(GL_FRAGMENT_SHADER)
88
-
89
- source = [File.read(@vertex_file)].pack('p')
90
- size = [File.size(@vertex_file)].pack('I')
91
- glShaderSource(@vertex, 1, source, size)
92
-
93
- source = [File.read(@fragment_file)].pack('p')
94
- size = [File.size(@fragment_file)].pack('I')
95
- glShaderSource(@fragment, 1, source, size)
96
- end
97
-
98
- def compile_shaders
99
- return unless shader_files_exist?
100
-
101
- glCompileShader(@vertex)
102
- buffer = ' '
103
- glGetShaderiv(@vertex, GL_COMPILE_STATUS, buffer)
104
- compiled = buffer.unpack('L')[0]
105
-
106
- if compiled == 0
107
- log = ' ' * @error_buffer_size
108
- glGetShaderInfoLog(@vertex, @error_buffer_size, nil, log)
109
- puts "Shader Error: Program \"#{@name}\""
110
- puts " Vectex Shader InfoLog:", " #{log.strip.split("\n").join("\n ")}\n\n"
111
- puts " Shader Compiled status: #{compiled}"
112
- puts " NOTE: assignment of uniforms in shaders is illegal!"
113
- puts
114
- return
115
- end
116
-
117
- glCompileShader(@fragment)
118
- buffer = ' '
119
- glGetShaderiv(@fragment, GL_COMPILE_STATUS, buffer)
120
- compiled = buffer.unpack('L')[0]
121
-
122
- if compiled == 0
123
- log = ' ' * @error_buffer_size
124
- glGetShaderInfoLog(@fragment, @error_buffer_size, nil, log)
125
- puts "Shader Error: Program \"#{@name}\""
126
- puts " Fragment Shader InfoLog:", " #{log.strip.split("\n").join("\n ")}\n\n"
127
- puts " Shader Compiled status: #{compiled}"
128
- puts " NOTE: assignment of uniforms in shader is illegal!"
129
- puts
130
- return
131
- end
132
-
133
- @program = glCreateProgram
134
- glAttachShader(@program, @vertex)
135
- glAttachShader(@program, @fragment)
136
- glLinkProgram(@program)
137
-
138
- buffer = ' '
139
- glGetProgramiv(@program, GL_LINK_STATUS, buffer)
140
- linked = buffer.unpack('L')[0]
141
-
142
- if linked == 0
143
- log = ' ' * @error_buffer_size
144
- glGetProgramInfoLog(@program, @error_buffer_size, nil, log)
145
- puts "Shader Error: Program \"#{@name}\""
146
- puts " Program InfoLog:", " #{log.strip.split("\n").join("\n ")}\n\n"
147
- end
148
-
149
- @compiled = linked == 0 ? false : true
150
- end
151
-
152
- # Returns the location of a uniform variable
153
- def variable(variable)
154
- loc = glGetUniformLocation(@program, variable)
155
- if (loc == -1)
156
- puts "Shader Error: Program \"#{@name}\" has no such uniform named \"#{variable}\"", " Is it used in the shader? GLSL may have optimized it out.", " Is it miss spelled?" unless @variable_missing[variable]
157
- @variable_missing[variable] = true
158
- end
159
- return loc
160
- end
161
-
162
- def use(&block)
163
- return unless compiled?
164
- raise "Another shader is already in use! #{Shader.active_shader.name.inspect}" if Shader.active_shader
165
- Shader.active_shader=self
166
-
167
- glUseProgram(@program)
168
-
169
- if block
170
- block.call(self)
171
- stop
172
- end
173
- end
174
-
175
- def stop
176
- Shader.active_shader = nil if Shader.active_shader == self
177
- glUseProgram(0)
178
- end
179
-
180
- def compiled?
181
- @compiled
182
- end
183
-
184
- def attribute_location(variable)
185
- glGetUniformLocation(@program, variable)
186
- end
187
-
188
- def set_uniform(variable, value, location = nil)
189
- attr_loc = location ? location : attribute_location(variable)
190
-
191
- case value.class.to_s.downcase.to_sym
192
- when :integer
193
- glUniform1i(attr_loc, value)
194
- when :float
195
- glUniform1f(attr_loc, value)
196
- when :string
197
- when :array
198
- else
199
- raise NotImplementedError, "Shader support for #{value.class.inspect} not implemented."
200
- end
201
-
202
- Window.handle_gl_error
203
- end
204
- end
205
- end
1
+ module CyberarmEngine
2
+ # Ref: https://github.com/vaiorabbit/ruby-opengl/blob/master/sample/OrangeBook/brick.rb
3
+ class Shader
4
+ include OpenGL
5
+ @@shaders = {}
6
+ PREPROCESSOR_CHARACTER = "@"
7
+
8
+ def self.add(name, instance)
9
+ @@shaders[name] = instance
10
+ end
11
+
12
+ def self.use(name, &block)
13
+ shader = @@shaders.dig(name)
14
+ if shader
15
+ shader.use(&block)
16
+ else
17
+ raise ArgumentError, "Shader '#{name}' not found!"
18
+ end
19
+ end
20
+
21
+ def self.available?(name)
22
+ @@shaders.dig(name).is_a?(Shader)
23
+ end
24
+
25
+ def self.get(name)
26
+ @@shaders.dig(name)
27
+ end
28
+
29
+ def self.active_shader
30
+ @active_shader
31
+ end
32
+
33
+ def self.active_shader=(instance)
34
+ @active_shader = instance
35
+ end
36
+
37
+ def self.stop
38
+ shader = Shader.active_shader
39
+
40
+ if shader
41
+ shader.stop
42
+ else
43
+ raise ArgumentError, "No active shader to stop!"
44
+ end
45
+ end
46
+
47
+ def self.attribute_location(variable)
48
+ raise RuntimeError, "No active shader!" unless Shader.active_shader
49
+ Shader.active_shader.attribute_location(variable)
50
+ end
51
+
52
+ def self.set_uniform(variable, value)
53
+ raise RuntimeError, "No active shader!" unless Shader.active_shader
54
+ Shader.active_shader.set_uniform(variable, value)
55
+ end
56
+
57
+ attr_reader :name, :program
58
+ def initialize(name:, includes_dir: nil, vertex: "shaders/default.vert", fragment:)
59
+ raise "Shader name can not be blank" if name.length == 0
60
+
61
+ @name = name
62
+ @includes_dir = includes_dir
63
+ @compiled = false
64
+
65
+ @program = nil
66
+
67
+ @error_buffer_size = 1024
68
+ @variable_missing = {}
69
+
70
+ @data = {shaders: {}}
71
+
72
+ unless shader_files_exist?(vertex: vertex, fragment: fragment)
73
+ raise ArgumentError, "Shader files not found: #{vertex} or #{fragment}"
74
+ end
75
+
76
+ create_shader(type: :vertex, source: File.read(vertex))
77
+ create_shader(type: :fragment, source: File.read(fragment))
78
+
79
+ compile_shader(type: :vertex)
80
+ compile_shader(type: :fragment)
81
+ link_shaders
82
+
83
+ # Only add shader if it successfully compiles
84
+ if @compiled
85
+ puts "compiled!"
86
+ puts "Compiled shader: #{@name}"
87
+ Shader.add(@name, self)
88
+ else
89
+ warn "FAILED to compile shader: #{@name}", ""
90
+ end
91
+ end
92
+
93
+ def shader_files_exist?(vertex:, fragment:)
94
+ File.exist?(vertex) && File.exist?(fragment)
95
+ end
96
+
97
+ def create_shader(type:, source:)
98
+ _shader = nil
99
+
100
+ case type
101
+ when :vertex
102
+ _shader = glCreateShader(GL_VERTEX_SHADER)
103
+ when :fragment
104
+ _shader = glCreateShader(GL_FRAGMENT_SHADER)
105
+ else
106
+ warn "Unsupported shader type: #{type.inspect}"
107
+ end
108
+
109
+ processed_source = preprocess_source(source: source)
110
+
111
+ _source = [processed_source].pack("p")
112
+ _size = [processed_source.length].pack("I")
113
+ glShaderSource(_shader, 1, _source, _size)
114
+
115
+ @data[:shaders][type] =_shader
116
+ end
117
+
118
+ def preprocess_source(source:)
119
+ lines = source.lines
120
+
121
+ lines.each_with_index do |line, i|
122
+ if line.start_with?(PREPROCESSOR_CHARACTER)
123
+ preprocessor = line.strip.split(" ")
124
+ lines.delete(line)
125
+
126
+ case preprocessor.first
127
+ when "@include"
128
+ raise ArgumentError, "Shader preprocessor include directory was not given for shader #{@name}" unless @includes_dir
129
+
130
+ preprocessor[1..preprocessor.length - 1].join.scan(/"([^"]*)"/).flatten.each do |file|
131
+ source = File.read("#{@includes_dir}/#{file}.glsl")
132
+
133
+ lines.insert(i, source)
134
+ end
135
+ else
136
+ warn "Unsupported preprocessor #{preprocessor.first} for #{@name}"
137
+ end
138
+ end
139
+ end
140
+
141
+ lines.join
142
+ end
143
+
144
+ def compile_shader(type:)
145
+ _compiled = false
146
+ _shader = @data[:shaders][type]
147
+ raise ArgumentError, "No shader for #{type.inspect}" unless _shader
148
+
149
+ glCompileShader(_shader)
150
+ buffer = ' '
151
+ glGetShaderiv(_shader, GL_COMPILE_STATUS, buffer)
152
+ compiled = buffer.unpack('L')[0]
153
+
154
+ if compiled == 0
155
+ log = ' ' * @error_buffer_size
156
+ glGetShaderInfoLog(_shader, @error_buffer_size, nil, log)
157
+ puts "Shader Error: Program \"#{@name}\""
158
+ puts " #{type.to_s.capitalize} Shader InfoLog:", " #{log.strip.split("\n").join("\n ")}\n\n"
159
+ puts " Shader Compiled status: #{compiled}"
160
+ puts " NOTE: assignment of uniforms in shaders is illegal!"
161
+ puts
162
+ else
163
+ _compiled = true
164
+ end
165
+
166
+ return _compiled
167
+ end
168
+
169
+ def link_shaders
170
+ @program = glCreateProgram
171
+ @data[:shaders].values.each do |_shader|
172
+ glAttachShader(@program, _shader)
173
+ end
174
+ glLinkProgram(@program)
175
+
176
+ buffer = ' '
177
+ glGetProgramiv(@program, GL_LINK_STATUS, buffer)
178
+ linked = buffer.unpack('L')[0]
179
+
180
+ if linked == 0
181
+ log = ' ' * @error_buffer_size
182
+ glGetProgramInfoLog(@program, @error_buffer_size, nil, log)
183
+ puts "Shader Error: Program \"#{@name}\""
184
+ puts " Program InfoLog:", " #{log.strip.split("\n").join("\n ")}\n\n"
185
+ end
186
+
187
+ @compiled = linked == 0 ? false : true
188
+ end
189
+
190
+ # Returns the location of a uniform variable
191
+ def variable(variable)
192
+ loc = glGetUniformLocation(@program, variable)
193
+ if (loc == -1)
194
+ puts "Shader Error: Program \"#{@name}\" has no such uniform named \"#{variable}\"", " Is it used in the shader? GLSL may have optimized it out.", " Is it miss spelled?" unless @variable_missing[variable]
195
+ @variable_missing[variable] = true
196
+ end
197
+ return loc
198
+ end
199
+
200
+ def use(&block)
201
+ return unless compiled?
202
+ raise "Another shader is already in use! #{Shader.active_shader.name.inspect}" if Shader.active_shader
203
+ Shader.active_shader=self
204
+
205
+ glUseProgram(@program)
206
+
207
+ if block
208
+ block.call(self)
209
+ stop
210
+ end
211
+ end
212
+
213
+ def stop
214
+ Shader.active_shader = nil if Shader.active_shader == self
215
+ glUseProgram(0)
216
+ end
217
+
218
+ def compiled?
219
+ @compiled
220
+ end
221
+
222
+ def attribute_location(variable)
223
+ glGetUniformLocation(@program, variable)
224
+ end
225
+
226
+ def uniform_transform(variable, value, location = nil)
227
+ attr_loc = location ? location : attribute_location(variable)
228
+
229
+ glUniformMatrix4fv(attr_loc, 1, GL_FALSE, value.to_gl.pack("F16"))
230
+ end
231
+
232
+ def uniform_boolean(variable, value, location = nil)
233
+ attr_loc = location ? location : attribute_location(variable)
234
+
235
+ glUniform1i(attr_loc, value ? 1 : 0)
236
+ end
237
+
238
+ def uniform_integer(variable, value, location = nil)
239
+ attr_loc = location ? location : attribute_location(variable)
240
+
241
+ glUniform1i(attr_loc, value)
242
+ end
243
+
244
+ def uniform_float(variable, value, location = nil)
245
+ attr_loc = location ? location : attribute_location(variable)
246
+
247
+ glUniform1f(attr_loc, value)
248
+ end
249
+
250
+ def uniform_vec3(variable, value, location = nil)
251
+ attr_loc = location ? location : attribute_location(variable)
252
+
253
+ glUniform3f(attr_loc, *value.to_a[0..2])
254
+ end
255
+
256
+ def uniform_vec4(variable, value, location = nil)
257
+ attr_loc = location ? location : attribute_location(variable)
258
+
259
+ glUniform4f(attr_loc, *value.to_a)
260
+ end
261
+ end
262
+ end