Class: CyberarmEngine::Shader

Inherits:
Object
  • Object
show all
Includes:
OpenGL
Defined in:
lib/cyberarm_engine/shader.rb

Overview

Constant Summary collapse

@@shaders =
{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name:, vertex: "shaders/default.vert", fragment:) ⇒ Shader

Returns a new instance of Shader.

Raises:

  • (ArgumentError)


57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/cyberarm_engine/shader.rb', line 57

def initialize(name:, vertex: "shaders/default.vert", fragment:)
  @name = name
  @vertex_file   = vertex
  @fragment_file = fragment
  @compiled = false

  @program = nil

  @error_buffer_size = 1024
  @variable_missing = {}

  raise ArgumentError, "Shader files not found: #{@vertex_file} or #{@fragment_file}" unless shader_files_exist?

  create_shaders
  compile_shaders

  # Only add shader if it successfully compiles
  if @compiled
    Shader.add(@name, self)
  else
    puts "FAILED to compile shader: #{@name}", ""
  end
end

Instance Attribute Details

#nameObject (readonly)

Returns the value of attribute name.



56
57
58
# File 'lib/cyberarm_engine/shader.rb', line 56

def name
  @name
end

#programObject (readonly)

Returns the value of attribute program.



56
57
58
# File 'lib/cyberarm_engine/shader.rb', line 56

def program
  @program
end

Class Method Details

.active_shaderObject



28
29
30
# File 'lib/cyberarm_engine/shader.rb', line 28

def self.active_shader
  @active_shader
end

.active_shader=(instance) ⇒ Object



32
33
34
# File 'lib/cyberarm_engine/shader.rb', line 32

def self.active_shader=(instance)
  @active_shader = instance
end

.add(name, instance) ⇒ Object



7
8
9
# File 'lib/cyberarm_engine/shader.rb', line 7

def self.add(name, instance)
  @@shaders[name] = instance
end

.attribute_location(variable) ⇒ Object

Raises:

  • (RuntimeError)


46
47
48
49
# File 'lib/cyberarm_engine/shader.rb', line 46

def self.attribute_location(variable)
  raise RuntimeError, "No active shader!" unless Shader.active_shader
  Shader.active_shader.attribute_location(variable)
end

.available?(name) ⇒ Boolean

Returns:

  • (Boolean)


20
21
22
# File 'lib/cyberarm_engine/shader.rb', line 20

def self.available?(name)
  @@shaders.dig(name).is_a?(Shader)
end

.get(name) ⇒ Object



24
25
26
# File 'lib/cyberarm_engine/shader.rb', line 24

def self.get(name)
  @@shaders.dig(name)
end

.set_uniform(variable, value) ⇒ Object

Raises:

  • (RuntimeError)


51
52
53
54
# File 'lib/cyberarm_engine/shader.rb', line 51

def self.set_uniform(variable, value)
  raise RuntimeError, "No active shader!" unless Shader.active_shader
  Shader.active_shader.set_uniform(variable, value)
end

.stopObject



36
37
38
39
40
41
42
43
44
# File 'lib/cyberarm_engine/shader.rb', line 36

def self.stop
  shader = Shader.active_shader

  if shader
    shader.stop
  else
    raise ArgumentError, "No active shader to stop!"
  end
end

.use(name, &block) ⇒ Object



11
12
13
14
15
16
17
18
# File 'lib/cyberarm_engine/shader.rb', line 11

def self.use(name, &block)
  shader = @@shaders.dig(name)
  if shader
    shader.use(&block)
  else
    raise ArgumentError, "Shader '#{name}' not found!"
  end
end

Instance Method Details

#attribute_location(variable) ⇒ Object



184
185
186
# File 'lib/cyberarm_engine/shader.rb', line 184

def attribute_location(variable)
  glGetUniformLocation(@program, variable)
end

#compile_shadersObject



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/cyberarm_engine/shader.rb', line 98

def compile_shaders
  return unless shader_files_exist?

  glCompileShader(@vertex)
  buffer = '    '
  glGetShaderiv(@vertex, GL_COMPILE_STATUS, buffer)
  compiled = buffer.unpack('L')[0]

  if compiled == 0
    log = ' ' * @error_buffer_size
    glGetShaderInfoLog(@vertex, @error_buffer_size, nil, log)
    puts "Shader Error: Program \"#{@name}\""
    puts "  Vectex Shader InfoLog:", "  #{log.strip.split("\n").join("\n  ")}\n\n"
    puts "  Shader Compiled status: #{compiled}"
    puts "    NOTE: assignment of uniforms in shaders is illegal!"
    puts
    return
  end

  glCompileShader(@fragment)
  buffer = '    '
  glGetShaderiv(@fragment, GL_COMPILE_STATUS, buffer)
  compiled = buffer.unpack('L')[0]

  if compiled == 0
    log = ' ' * @error_buffer_size
    glGetShaderInfoLog(@fragment, @error_buffer_size, nil, log)
    puts "Shader Error: Program \"#{@name}\""
    puts "  Fragment Shader InfoLog:", "  #{log.strip.split("\n").join("\n  ")}\n\n"
    puts "  Shader Compiled status: #{compiled}"
    puts "    NOTE: assignment of uniforms in shader is illegal!"
    puts
    return
  end

  @program = glCreateProgram
  glAttachShader(@program, @vertex)
  glAttachShader(@program, @fragment)
  glLinkProgram(@program)

  buffer = '    '
  glGetProgramiv(@program, GL_LINK_STATUS, buffer)
  linked = buffer.unpack('L')[0]

  if linked == 0
    log = ' ' * @error_buffer_size
    glGetProgramInfoLog(@program, @error_buffer_size, nil, log)
    puts "Shader Error: Program \"#{@name}\""
    puts "  Program InfoLog:", "  #{log.strip.split("\n").join("\n  ")}\n\n"
  end

  @compiled = linked == 0 ? false : true
end

#compiled?Boolean

Returns:

  • (Boolean)


180
181
182
# File 'lib/cyberarm_engine/shader.rb', line 180

def compiled?
  @compiled
end

#create_shadersObject



85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/cyberarm_engine/shader.rb', line 85

def create_shaders
  @vertex   = glCreateShader(GL_VERTEX_SHADER)
  @fragment = glCreateShader(GL_FRAGMENT_SHADER)

  source = [File.read(@vertex_file)].pack('p')
  size   = [File.size(@vertex_file)].pack('I')
  glShaderSource(@vertex, 1, source, size)

  source = [File.read(@fragment_file)].pack('p')
  size   = [File.size(@fragment_file)].pack('I')
  glShaderSource(@fragment, 1, source, size)
end

#set_uniform(variable, value, location = nil) ⇒ Object



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/cyberarm_engine/shader.rb', line 188

def set_uniform(variable, value, location = nil)
  attr_loc = location ? location : attribute_location(variable)

  case value.class.to_s.downcase.to_sym
  when :integer
    glUniform1i(attr_loc, value)
  when :float
    glUniform1f(attr_loc, value)
  when :string
  when :array
  else
    raise NotImplementedError, "Shader support for #{value.class.inspect} not implemented."
  end

  Window.handle_gl_error
end

#shader_files_exist?Boolean

Returns:

  • (Boolean)


81
82
83
# File 'lib/cyberarm_engine/shader.rb', line 81

def shader_files_exist?
  File.exist?(@vertex_file) && File.exist?(@fragment_file)
end

#stopObject



175
176
177
178
# File 'lib/cyberarm_engine/shader.rb', line 175

def stop
  Shader.active_shader = nil if Shader.active_shader == self
  glUseProgram(0)
end

#use(&block) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/cyberarm_engine/shader.rb', line 162

def use(&block)
  return unless compiled?
  raise "Another shader is already in use! #{Shader.active_shader.name.inspect}" if Shader.active_shader
  Shader.active_shader=self

  glUseProgram(@program)

  if block
    block.call(self)
    stop
  end
end

#variable(variable) ⇒ Object

Returns the location of a uniform variable



153
154
155
156
157
158
159
160
# File 'lib/cyberarm_engine/shader.rb', line 153

def variable(variable)
  loc = glGetUniformLocation(@program, variable)
  if (loc == -1)
    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]
    @variable_missing[variable] = true
  end
  return loc
end