178 lines
4.3 KiB
Go
178 lines
4.3 KiB
Go
package hrend
|
|
|
|
// This is the linear algebra junk? Vectors, matrices, etc
|
|
import (
|
|
"math"
|
|
)
|
|
|
|
type Vec3f struct {
|
|
X, Y, Z float32
|
|
}
|
|
|
|
type Vec2i struct {
|
|
X, Y int
|
|
}
|
|
|
|
type Vec2f struct {
|
|
X, Y float32
|
|
}
|
|
|
|
// A ROW MAJOR matrix
|
|
type Mat44f [16]float32
|
|
|
|
func (m *Mat44f) Set(x int, y int, val float32) {
|
|
m[x+y*4] = val
|
|
}
|
|
func (m *Mat44f) Get(x int, y int) float32 {
|
|
return m[x+y*4]
|
|
}
|
|
func (m *Mat44f) ZeroFill() {
|
|
for i := range m {
|
|
m[i] = 0
|
|
}
|
|
}
|
|
func (m *Mat44f) SetIdentity() {
|
|
m.ZeroFill()
|
|
for i := range 4 {
|
|
m.Set(i, i, 1)
|
|
}
|
|
}
|
|
|
|
// NOTE: we use "Set" instead of "Create" for all these so we reuse the matrix
|
|
// instead of creating a new one all the time (garbage collection)
|
|
|
|
// Compute the projection matrix, filling the given matrix. FOV is in degrees
|
|
func (m *Mat44f) SetProjection(fov float32, aspect float32, near float32, far float32) {
|
|
// Projection matrix is (ROW MAJOR!)
|
|
// S 0 0 0
|
|
// 0 S 0 0
|
|
// 0 0 -f/(f-n) -1
|
|
// 0 0 -fn/(f-n) 0
|
|
// where S (scale) is 1 / tan(fov / 2) (assuming fov is radians)
|
|
// // NOTE: -1 there is actually -1/c, where c is distance from viewer to
|
|
// // projection plane. We fix it at 1 for now but...
|
|
// m.ZeroFill()
|
|
// scale := float32(1 / math.Tan(float64(fov)*0.5*math.Pi/180))
|
|
// m.Set(0, 0, scale)
|
|
// m.Set(1, 1, scale)
|
|
// m.Set(2, 2, -far/(far-near))
|
|
// m.Set(3, 2, -1)
|
|
// m.Set(2, 3, -far*near/(far-near))
|
|
// OK apparently I suck, let's use somebody else's projection matrix:
|
|
m.ZeroFill()
|
|
|
|
DEG2RAD := math.Acos(-1.0) / 180.0
|
|
tangent := math.Tan(float64(fov/2.0) * DEG2RAD) // tangent of half fovY
|
|
top := near * float32(tangent) // half height of near plane
|
|
right := top * aspect // half width of near plane
|
|
// Column major maybe???
|
|
// n/r 0 0 0
|
|
// 0 n/t 0 0
|
|
// 0 0 -(f+n)/(f-n) -1
|
|
// 0 0 -(2fn)/(f-n) 0
|
|
|
|
m.Set(0, 0, near/right)
|
|
m.Set(1, 1, near/top)
|
|
m.Set(2, 2, -(far+near)/(far-near))
|
|
m.Set(3, 2, -1)
|
|
m.Set(2, 3, -(2*far*near)/(far-near))
|
|
}
|
|
|
|
func (m *Mat44f) SetTranslation(x, y, z float32) {
|
|
m.SetIdentity()
|
|
m.Set(0, 3, x) // Let user decide how to offset x
|
|
m.Set(1, 3, y) // Let user decide how to offset x
|
|
m.Set(2, 3, z) // Get farther away from the face (user)
|
|
}
|
|
|
|
func (m *Mat44f) SetViewport(tl Vec3f, br Vec3f) { //width, height, depth int) {
|
|
m.ZeroFill()
|
|
m.Set(0, 0, (br.X-tl.X)/2)
|
|
m.Set(1, 1, (tl.Y-br.Y)/2) // Inverted because screen funny
|
|
m.Set(2, 2, (br.Z-tl.Z)/2)
|
|
m.Set(3, 3, 1)
|
|
m.Set(0, 3, (br.X+tl.X)/2)
|
|
m.Set(1, 3, (br.Y+tl.Y)/2)
|
|
m.Set(2, 3, (br.Z+tl.Z)/2)
|
|
}
|
|
|
|
func (m *Mat44f) SetViewportSimple(width, height, depth int) {
|
|
var tl Vec3f // All zero
|
|
br := Vec3f{
|
|
X: float32(width),
|
|
Y: float32(height),
|
|
Z: float32(depth),
|
|
}
|
|
m.SetViewport(tl, br)
|
|
}
|
|
|
|
// Multiply the given point by our vector. Remember this is row-major order
|
|
func (m *Mat44f) MultiplyPoint3(p Vec3f) Vec3f {
|
|
var out Vec3f
|
|
// We hope very much that Go will optimize the function calls for us,
|
|
// along with computing the constants.
|
|
out.X = p.X*m.Get(0, 0) + p.Y*m.Get(0, 1) + p.Z*m.Get(0, 2) + m.Get(0, 3)
|
|
out.Y = p.X*m.Get(1, 0) + p.Y*m.Get(1, 1) + p.Z*m.Get(1, 2) + m.Get(1, 3)
|
|
out.Z = p.X*m.Get(2, 0) + p.Y*m.Get(2, 1) + p.Z*m.Get(2, 2) + m.Get(2, 3)
|
|
w := p.X*m.Get(3, 0) + p.Y*m.Get(3, 1) + p.Z*m.Get(3, 2) + m.Get(3, 3)
|
|
if w != 1 {
|
|
out.X /= w
|
|
out.Y /= w
|
|
out.Z /= w
|
|
}
|
|
return out
|
|
}
|
|
|
|
// Multiply two 4x4 matrices together (not optimized)
|
|
func (m *Mat44f) Multiply(m2 *Mat44f) Mat44f {
|
|
var result Mat44f
|
|
// This is the x and y of our resulting matrix
|
|
for y := 0; y < 4; y++ {
|
|
for x := 0; x < 4; x++ {
|
|
for i := 0; i < 4; i++ {
|
|
result[x+y*4] += m[i+y*4] * m2[x+i*4]
|
|
}
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (vi *Vec2i) ToF() Vec2f {
|
|
return Vec2f{float32(vi.X), float32(vi.Y)}
|
|
}
|
|
|
|
func (vi *Vec3f) ToVec2i() Vec2i {
|
|
return Vec2i{int(vi.X), int(vi.Y)}
|
|
}
|
|
|
|
func (v0 *Vec3f) Sub(v1 Vec3f) Vec3f {
|
|
return Vec3f{
|
|
X: v0.X - v1.X,
|
|
Y: v0.Y - v1.Y,
|
|
Z: v0.Z - v1.Z,
|
|
}
|
|
}
|
|
|
|
func (v0 *Vec3f) CrossProduct(v1 Vec3f) Vec3f {
|
|
return Vec3f{
|
|
X: v0.Y*v1.Z - v0.Z*v1.Y,
|
|
Y: v0.Z*v1.X - v0.X*v1.Z,
|
|
Z: v0.X*v1.Y - v0.Y*v1.X,
|
|
}
|
|
}
|
|
|
|
//func (v
|
|
|
|
func (v *Vec3f) Normalize() Vec3f {
|
|
l := float32(math.Sqrt(float64(v.MultSimp(v))))
|
|
return Vec3f{
|
|
X: v.X / l,
|
|
Y: v.Y / l,
|
|
Z: v.Z / l,
|
|
}
|
|
}
|
|
|
|
func (v0 *Vec3f) MultSimp(v1 *Vec3f) float32 {
|
|
return v0.X*v1.X + v0.Y*v1.Y + v0.Z*v1.Z
|
|
}
|