mirror of
https://github.com/SleepingInsomniac/pixelfaucet
synced 2025-01-26 07:58:03 +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,
|
1, 0,
|
||||||
]
|
]
|
||||||
|
|
||||||
m.class.should eq(Matrix(Int32, 2, 2))
|
m.class.should eq(Matrix(Int32, 4))
|
||||||
m[1, 0].should eq(1)
|
m[1, 0].should eq(1)
|
||||||
m[0, 1].should eq(1)
|
m[0, 1].should eq(1)
|
||||||
end
|
end
|
||||||
|
@ -24,7 +24,7 @@ describe Matrix do
|
||||||
1.0, 2.0, 3.0, 4.0,
|
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[
|
ident = Matrix[
|
||||||
1.0, 0.0, 0.0, 0.0,
|
1.0, 0.0, 0.0, 0.0,
|
||||||
|
|
|
@ -11,7 +11,7 @@ module PF
|
||||||
property aspect_ratio : Float64?
|
property aspect_ratio : Float64?
|
||||||
property camera : Camera
|
property camera : Camera
|
||||||
property light : Vector3(Float64) = Vector3.new(0.0, 0.0, -1.0).normalized
|
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 clipping_plane_near : Vector3(Float64)
|
||||||
property near_plane_normal : Vector3(Float64) = Vector3.new(0.0, 0.0, 1.0)
|
property near_plane_normal : Vector3(Float64) = Vector3.new(0.0, 0.0, 1.0)
|
||||||
@fov_rad : Float64?
|
@fov_rad : Float64?
|
||||||
|
|
|
@ -83,6 +83,7 @@ module PF
|
||||||
calculate_fps(et)
|
calculate_fps(et)
|
||||||
update((et - @last_time) / 1000.0, event)
|
update((et - @last_time) / 1000.0, event)
|
||||||
@last_time = et
|
@last_time = et
|
||||||
|
GC.collect
|
||||||
end
|
end
|
||||||
|
|
||||||
private def calculate_fps(et)
|
private def calculate_fps(et)
|
||||||
|
|
151
src/matrix.cr
151
src/matrix.cr
|
@ -1,84 +1,63 @@
|
||||||
module PF
|
module PF
|
||||||
struct Matrix(T, W, H)
|
struct Matrix(T, S)
|
||||||
property values : Slice(T)
|
include Indexable::Mutable(T)
|
||||||
|
|
||||||
|
getter values : StaticArray(T, S)
|
||||||
|
getter width : UInt8
|
||||||
|
getter height : UInt8
|
||||||
|
|
||||||
# Creates a new square `Matrix` with the given *args*
|
# Creates a new square `Matrix` with the given *args*
|
||||||
#
|
#
|
||||||
# ```
|
# ```
|
||||||
# m = Matrix[1, 2, 3, 4]
|
# m = Matrix[1, 2, 3, 4] # => Matrix(Int32, 4) 2x2 [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)
|
|
||||||
# ```
|
# ```
|
||||||
macro [](*args)
|
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
|
# width and height are the isqrt of args.size
|
||||||
{% if args.size == 1 %}
|
{% if args.size == 4 %}
|
||||||
PF::Matrix(typeof({{*args}}), 1, 1).new(%values)
|
PF::Matrix(typeof({{*args}}), 4).new(2, 2, StaticArray[{{*args}}])
|
||||||
{% elsif args.size == 4 %}
|
|
||||||
PF::Matrix(typeof({{*args}}), 2, 2).new(%values)
|
|
||||||
{% elsif args.size == 9 %}
|
{% 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 %}
|
{% elsif args.size == 16 %}
|
||||||
PF::Matrix(typeof({{*args}}), 4, 4).new(%values)
|
PF::Matrix(typeof({{*args}}), 16).new(4, 4, StaticArray[{{*args}}])
|
||||||
{% else %}
|
{% else %}
|
||||||
raise "Cannot determine width and height of matrix with {{ args.size }} elements, " \
|
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 %}
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.identity
|
def initialize(@width : UInt8, @height : UInt8)
|
||||||
new.tap do |m|
|
@values = StaticArray(T, S).new(T.new(0))
|
||||||
m.size.times { |n| m[n, n] = T.new(1) }
|
end
|
||||||
end
|
|
||||||
|
def initialize(@width : UInt8, @height : UInt8, @values : StaticArray(T, S))
|
||||||
end
|
end
|
||||||
|
|
||||||
delegate :fill, to: @values
|
delegate :fill, to: @values
|
||||||
|
|
||||||
def initialize
|
def index(col : Int, row : Int)
|
||||||
@values = Slice(T).new(W * H, T.new(0))
|
row * width + col
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def size
|
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
|
end
|
||||||
|
|
||||||
# Tests the equality of two matricies
|
# Tests the equality of two matricies
|
||||||
|
@ -86,50 +65,26 @@ module PF
|
||||||
self.values == other.values
|
self.values == other.values
|
||||||
end
|
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)
|
def *(other : Matrix)
|
||||||
result = Matrix(typeof(self[0, 0] * other[0, 0]), W, H).new
|
result = Matrix(typeof(@values.unsafe_fetch(0) * other.values.unsafe_fetch(0)), S).new(width, height)
|
||||||
{% for y in (0...H) %}
|
(0...height).each do |row|
|
||||||
{% for x in (0...W) %}
|
(0...width).each do |col|
|
||||||
{% for n in (0...W) %}
|
(0...width).each do |n|
|
||||||
result[{{x}},{{y}}] = result[{{x}},{{y}}] + self[{{n}}, {{y}}] * other[{{x}}, {{n}}]
|
result[col, row] = result[col, row] + self[n, row] * other[col, n]
|
||||||
{% end %}
|
end
|
||||||
{% end %}
|
end
|
||||||
{% end %}
|
end
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_s(io)
|
def to_s(io)
|
||||||
io << {{ @type }} << '['
|
io << {{@type}} << ' ' << width << "x" << height << " ["
|
||||||
(0...H).each do |y|
|
{% for i in 0...S %}
|
||||||
(0...W).each do |x|
|
io << unsafe_fetch({{i}})
|
||||||
io << self[x, y]
|
{% if i != S - 1 %}
|
||||||
io << ' ' unless x == W - 1
|
io << ", "
|
||||||
end
|
{% end %}
|
||||||
io << ", " unless y == H - 1
|
{% end %}
|
||||||
end
|
|
||||||
io << ']'
|
io << ']'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,7 @@ require "./vector"
|
||||||
|
|
||||||
module PF
|
module PF
|
||||||
class Transform2d
|
class Transform2d
|
||||||
property matrix : Matrix(Float64, 3, 3)
|
property matrix : Matrix(Float64, 9)
|
||||||
|
|
||||||
def self.identity
|
def self.identity
|
||||||
Matrix[
|
Matrix[
|
||||||
|
|
|
@ -3,7 +3,7 @@ require "./vector"
|
||||||
|
|
||||||
module PF
|
module PF
|
||||||
class Transform3d
|
class Transform3d
|
||||||
property matrix : Matrix(Float64, 4, 4)
|
property matrix : Matrix(Float64, 16)
|
||||||
|
|
||||||
def self.identity
|
def self.identity
|
||||||
Matrix[
|
Matrix[
|
||||||
|
@ -67,7 +67,7 @@ module PF
|
||||||
|
|
||||||
# Does not work for scaling, only for rotation / translation
|
# Does not work for scaling, only for rotation / translation
|
||||||
def self.quick_inverse(other : Matrix)
|
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[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[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
|
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
|
end
|
||||||
|
|
||||||
# TODO: Optionally return the result of w in some way (pointer / tuple?)
|
# 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(
|
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, 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],
|
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