diff --git a/lib/cyberarm_engine/shader.rb b/lib/cyberarm_engine/shader.rb index b40381b..8e024f9 100644 --- a/lib/cyberarm_engine/shader.rb +++ b/lib/cyberarm_engine/shader.rb @@ -188,18 +188,19 @@ module CyberarmEngine def set_uniform(variable, value, location = nil) attr_loc = location ? location : attribute_location(variable) - case value.class.to_s.downcase.to_sym + case value.class.to_s.split("::").last.downcase.to_sym when :integer glUniform1i(attr_loc, value) when :float glUniform1f(attr_loc, value) when :string - when :array + when :transform + glUniformMatrix4fv(attr_loc, 1, GL_FALSE, value.elements.pack("F16")) + when :vector + glUniformVec4f(attr_loc, *value.to_a) else raise NotImplementedError, "Shader support for #{value.class.inspect} not implemented." end - - Window.handle_gl_error end end end \ No newline at end of file diff --git a/lib/cyberarm_engine/transform.rb b/lib/cyberarm_engine/transform.rb index 734d429..76fd202 100644 --- a/lib/cyberarm_engine/transform.rb +++ b/lib/cyberarm_engine/transform.rb @@ -1,12 +1,28 @@ module CyberarmEngine + # Basic 4x4 matrix operations class Transform attr_reader :elements def initialize(matrix) @elements = matrix raise "Transform is wrong size! Got #{@elements.size}, expected 16" if 16 != @elements.size + raise "Invalid value for matrix, must all be numeric!" if @elements.any? { |e| e.nil? || !e.is_a?(Numeric)} end + def self.identity + Transform.new( + [ + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + ] + ) + end + + ### 2D Operations meant for interacting with Gosu ### + + # 2d rotate operation, replicates Gosu's Gosu.rotate function def self.rotate(angle, rotate_around = nil) double c = Math.cos(angle).degrees_to_radians double s = Math.sin(angle).degrees_to_radians @@ -31,6 +47,7 @@ module CyberarmEngine return rotate_matrix end + # 2d translate operation, replicates Gosu's Gosu.translate function def self.translate(vector) x, y, z = vector.to_a[0..2] matrix = [ @@ -43,6 +60,7 @@ module CyberarmEngine Transform.new(matrix) end + # 2d scale operation, replicates Gosu's Gosu.rotate function def self.scale(vector, center_around = nil) scale_x, scale_y, scale_z = vector.to_a[0..2] matrix = [ @@ -80,5 +98,94 @@ module CyberarmEngine Transform.new(matrix) end + + #### 3D Operations meant for OpenGL ### + + def self.translate_3d(vector) + x, y, z = vector.to_a[0..2] + matrix = [ + 1, 0, 0, x, + 0, 1, 0, y, + 0, 0, 1, z, + 0, 0, 0, 1, + ] + + Transform.new(matrix) + end + + def self.rotate_3d(vector, order = "xyz") + x, y, z = vector.to_a[0..2] + + rotation_x = Transform.new( + [ + 1, 0, 0, 0, + 0, Math.cos(x), -Math.sin(x), 0, + 0, Math.sin(x), Math.cos(x), 0, + 0, 0, 0, 1, + ] + ) + + rotation_y = Transform.new( + [ + Math.cos(y), 0, -Math.sin(y), 0, + 0, 1, 0, 0, + Math.sin(y), 1, Math.cos(y), 0, + 0, 0, 1, 1 + ] + ) + + rotation_z = Transform.new( + [ + Math.cos(z), -Math.sin(z), 0, 0, + Math.sin(z), Math.cos(z), 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + ] + ) + + rotation_x * rotation_y * rotation_z + end + + def *(other) + + case other + when CyberarmEngine::Vector + matrix = Array.new(@elements.size) + list = other.to_a + + @elements.each_with_index do |e, i| + matrix[i] = e + list[i] + end + + Transform.new(matrix) + + when CyberarmEngine::Transform + return multiply_matrices(other) + else + p other.class + raise TypeError, "Expected CyberarmEngine::Vector or CyberarmEngine::Transform got #{other.class}" + end + end + + def get(x, y) + width = 4 + + # puts "Transform|#{self.object_id} -> #{@elements[width * y + x].inspect} (index: #{width * y + x})" + @elements[width * y + x] + end + + def multiply_matrices(other) + matrix = Array.new(16, 0) + + 4.times do |x| + 4.times do |y| + 4.times do |k| + matrix[4 * y + x] += get(x, k) * other.get(k, y) + end + end + end + + return Transform.new(matrix) + end end end \ No newline at end of file