mirror of
https://github.com/SleepingInsomniac/pixelfaucet
synced 2025-01-24 07:58:18 +01:00
Improve matrix speed by using stack allocated memory
This commit is contained in:
parent
bf2fcaef58
commit
cc1757ab4f
6 changed files with 61 additions and 105 deletions
|
@ -10,7 +10,7 @@ describe Matrix do
|
|||
1, 0,
|
||||
]
|
||||
|
||||
m.class.should eq(Matrix(Int32, 2, 2))
|
||||
m.class.should eq(Matrix(Int32, 4))
|
||||
m[1, 0].should eq(1)
|
||||
m[0, 1].should eq(1)
|
||||
end
|
||||
|
@ -24,7 +24,7 @@ describe Matrix do
|
|||
1.0, 2.0, 3.0, 4.0,
|
||||
]
|
||||
|
||||
mat.class.should eq(Matrix(Float64, 4, 4))
|
||||
mat.class.should eq(Matrix(Float64, 16))
|
||||
|
||||
ident = Matrix[
|
||||
1.0, 0.0, 0.0, 0.0,
|
||||
|
|
|
@ -11,7 +11,7 @@ module PF
|
|||
property aspect_ratio : Float64?
|
||||
property camera : Camera
|
||||
property light : Vector3(Float64) = Vector3.new(0.0, 0.0, -1.0).normalized
|
||||
property mat_proj : Matrix(Float64, 4, 4)?
|
||||
property mat_proj : Matrix(Float64, 16)?
|
||||
property clipping_plane_near : Vector3(Float64)
|
||||
property near_plane_normal : Vector3(Float64) = Vector3.new(0.0, 0.0, 1.0)
|
||||
@fov_rad : Float64?
|
||||
|
|
|
@ -83,6 +83,7 @@ module PF
|
|||
calculate_fps(et)
|
||||
update((et - @last_time) / 1000.0, event)
|
||||
@last_time = et
|
||||
GC.collect
|
||||
end
|
||||
|
||||
private def calculate_fps(et)
|
||||
|
|
151
src/matrix.cr
151
src/matrix.cr
|
@ -1,84 +1,63 @@
|
|||
module PF
|
||||
struct Matrix(T, W, H)
|
||||
property values : Slice(T)
|
||||
struct Matrix(T, S)
|
||||
include Indexable::Mutable(T)
|
||||
|
||||
getter values : StaticArray(T, S)
|
||||
getter width : UInt8
|
||||
getter height : UInt8
|
||||
|
||||
# Creates a new square `Matrix` with the given *args*
|
||||
#
|
||||
# ```
|
||||
# m = Matrix[1, 2, 3, 4]
|
||||
# m[0, 0] # => 1
|
||||
# m[1, 0] # => 2
|
||||
# m[0, 1] # => 3
|
||||
# m[1, 1] # => 4
|
||||
# m.class # => Matrix(Int32, 2, 2)
|
||||
# m = Matrix[1, 2, 3, 4] # => Matrix(Int32, 4) 2x2 [1, 2, 3, 4]
|
||||
# ```
|
||||
macro [](*args)
|
||||
%values = Slice(typeof({{*args}})).new({{args.size}}, typeof({{*args}}).new(0))
|
||||
{% for arg, i in args %}
|
||||
%values.to_unsafe[{{i}}] = {{arg}}
|
||||
{% end %}
|
||||
# width and height are the isqrt of args.size
|
||||
{% if args.size == 1 %}
|
||||
PF::Matrix(typeof({{*args}}), 1, 1).new(%values)
|
||||
{% elsif args.size == 4 %}
|
||||
PF::Matrix(typeof({{*args}}), 2, 2).new(%values)
|
||||
{% if args.size == 4 %}
|
||||
PF::Matrix(typeof({{*args}}), 4).new(2, 2, StaticArray[{{*args}}])
|
||||
{% elsif args.size == 9 %}
|
||||
PF::Matrix(typeof({{*args}}), 3, 3).new(%values)
|
||||
PF::Matrix(typeof({{*args}}), 9).new(3, 3, StaticArray[{{*args}}])
|
||||
{% elsif args.size == 16 %}
|
||||
PF::Matrix(typeof({{*args}}), 4, 4).new(%values)
|
||||
PF::Matrix(typeof({{*args}}), 16).new(4, 4, StaticArray[{{*args}}])
|
||||
{% else %}
|
||||
raise "Cannot determine width and height of matrix with {{ args.size }} elements, " \
|
||||
"please provide them explicitly Matrix(Int32, 4, 4).new(...)"
|
||||
"please provide them explicitly Matrix(Int32, 16).new(4, 4, StaticArray[...])"
|
||||
{% end %}
|
||||
end
|
||||
|
||||
def self.identity
|
||||
new.tap do |m|
|
||||
m.size.times { |n| m[n, n] = T.new(1) }
|
||||
end
|
||||
def initialize(@width : UInt8, @height : UInt8)
|
||||
@values = StaticArray(T, S).new(T.new(0))
|
||||
end
|
||||
|
||||
def initialize(@width : UInt8, @height : UInt8, @values : StaticArray(T, S))
|
||||
end
|
||||
|
||||
delegate :fill, to: @values
|
||||
|
||||
def initialize
|
||||
@values = Slice(T).new(W * H, T.new(0))
|
||||
end
|
||||
|
||||
def initialize(@values)
|
||||
end
|
||||
|
||||
# Create a new matrix
|
||||
#
|
||||
# ```
|
||||
# PF::Matrix(Int32, 2, 2).new(1, 2, 3, 4)
|
||||
# ```
|
||||
def initialize(*nums : T)
|
||||
@values = Slice(T).new(W * H, T.new(0))
|
||||
nums.each_with_index { |n, i| @values[i] = n }
|
||||
end
|
||||
|
||||
def reset_to_identity!
|
||||
{% unless W == H %}
|
||||
raise "Matrix({{W}}x{{H}}) is not square"
|
||||
{% end %}
|
||||
fill(T.new(0))
|
||||
{% for i in 0...W %}
|
||||
self[{{i}}, {{i}}] = T.new(1)
|
||||
{% end %}
|
||||
end
|
||||
|
||||
# Width of the matrix
|
||||
def width
|
||||
W
|
||||
end
|
||||
|
||||
# Height of the matrix
|
||||
def height
|
||||
H
|
||||
def index(col : Int, row : Int)
|
||||
row * width + col
|
||||
end
|
||||
|
||||
def size
|
||||
W * H
|
||||
S
|
||||
end
|
||||
|
||||
def unsafe_fetch(index : Int)
|
||||
@values.unsafe_fetch(index)
|
||||
end
|
||||
|
||||
def unsafe_put(index : Int, value : T)
|
||||
@values.unsafe_put(index, value)
|
||||
end
|
||||
|
||||
# Fetch a value at a specified *column* and *row*
|
||||
def [](col : Int, row : Int)
|
||||
unsafe_fetch(index(col, row))
|
||||
end
|
||||
|
||||
# Put a value at a specified *column* and *row*
|
||||
def []=(col : Int, row : Int, value : T)
|
||||
unsafe_put(index(col, row), value)
|
||||
end
|
||||
|
||||
# Tests the equality of two matricies
|
||||
|
@ -86,50 +65,26 @@ module PF
|
|||
self.values == other.values
|
||||
end
|
||||
|
||||
# Get the index of an element in the matrix by *x* and *y* coordinates
|
||||
def index(x : Int, y : Int)
|
||||
y * width + x
|
||||
end
|
||||
|
||||
def [](i : Int)
|
||||
@values[i]
|
||||
end
|
||||
|
||||
def []=(i : Int, value : T)
|
||||
@values[i] = value
|
||||
end
|
||||
|
||||
# Get an element
|
||||
def [](x : Int, y : Int)
|
||||
self[index(x, y)]
|
||||
end
|
||||
|
||||
# Set an element at an *x* and *y* position
|
||||
def []=(x : Int, y : Int, value : T)
|
||||
self[index(x, y)] = value
|
||||
end
|
||||
|
||||
def *(other : Matrix)
|
||||
result = Matrix(typeof(self[0, 0] * other[0, 0]), W, H).new
|
||||
{% for y in (0...H) %}
|
||||
{% for x in (0...W) %}
|
||||
{% for n in (0...W) %}
|
||||
result[{{x}},{{y}}] = result[{{x}},{{y}}] + self[{{n}}, {{y}}] * other[{{x}}, {{n}}]
|
||||
{% end %}
|
||||
{% end %}
|
||||
{% end %}
|
||||
result = Matrix(typeof(@values.unsafe_fetch(0) * other.values.unsafe_fetch(0)), S).new(width, height)
|
||||
(0...height).each do |row|
|
||||
(0...width).each do |col|
|
||||
(0...width).each do |n|
|
||||
result[col, row] = result[col, row] + self[n, row] * other[col, n]
|
||||
end
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def to_s(io)
|
||||
io << {{ @type }} << '['
|
||||
(0...H).each do |y|
|
||||
(0...W).each do |x|
|
||||
io << self[x, y]
|
||||
io << ' ' unless x == W - 1
|
||||
end
|
||||
io << ", " unless y == H - 1
|
||||
end
|
||||
io << {{@type}} << ' ' << width << "x" << height << " ["
|
||||
{% for i in 0...S %}
|
||||
io << unsafe_fetch({{i}})
|
||||
{% if i != S - 1 %}
|
||||
io << ", "
|
||||
{% end %}
|
||||
{% end %}
|
||||
io << ']'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,7 +3,7 @@ require "./vector"
|
|||
|
||||
module PF
|
||||
class Transform2d
|
||||
property matrix : Matrix(Float64, 3, 3)
|
||||
property matrix : Matrix(Float64, 9)
|
||||
|
||||
def self.identity
|
||||
Matrix[
|
||||
|
|
|
@ -3,7 +3,7 @@ require "./vector"
|
|||
|
||||
module PF
|
||||
class Transform3d
|
||||
property matrix : Matrix(Float64, 4, 4)
|
||||
property matrix : Matrix(Float64, 16)
|
||||
|
||||
def self.identity
|
||||
Matrix[
|
||||
|
@ -67,7 +67,7 @@ module PF
|
|||
|
||||
# Does not work for scaling, only for rotation / translation
|
||||
def self.quick_inverse(other : Matrix)
|
||||
matrix = Matrix(Float64, 4, 4).new
|
||||
matrix = Matrix(Float64, 16).new(4, 4)
|
||||
matrix[0, 0] = other[0, 0]; matrix[0, 1] = other[1, 0]; matrix[0, 2] = other[2, 0]; matrix[0, 3] = 0.0
|
||||
matrix[1, 0] = other[0, 1]; matrix[1, 1] = other[1, 1]; matrix[1, 2] = other[2, 1]; matrix[1, 3] = 0.0
|
||||
matrix[2, 0] = other[0, 2]; matrix[2, 1] = other[1, 2]; matrix[2, 2] = other[2, 2]; matrix[2, 3] = 0.0
|
||||
|
@ -92,7 +92,7 @@ module PF
|
|||
end
|
||||
|
||||
# TODO: Optionally return the result of w in some way (pointer / tuple?)
|
||||
def self.apply(point : Vector3(Float64), matrix : Matrix(Float64, 4, 4))
|
||||
def self.apply(point : Vector3(Float64), matrix : Matrix(Float64, 16))
|
||||
vec = Vector3.new(
|
||||
point.x * matrix[0, 0] + point.y * matrix[1, 0] + point.z * matrix[2, 0] + matrix[3, 0],
|
||||
point.x * matrix[0, 1] + point.y * matrix[1, 1] + point.z * matrix[2, 1] + matrix[3, 1],
|
||||
|
|
Loading…
Add table
Reference in a new issue