1
0
Fork 0

Adding upstream version 0.0~git20250520.a1d9079+dfsg.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-05-24 19:46:29 +02:00
parent 590ac7ff5f
commit 20149b7f3a
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
456 changed files with 70406 additions and 0 deletions

109
exp/f32/affine.go Normal file
View file

@ -0,0 +1,109 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package f32
import "fmt"
// An Affine is a 3x3 matrix of float32 values for which the bottom row is
// implicitly always equal to [0 0 1].
// Elements are indexed first by row then column, i.e. m[row][column].
type Affine [2]Vec3
func (m Affine) String() string {
return fmt.Sprintf(`Affine[% 0.3f, % 0.3f, % 0.3f,
% 0.3f, % 0.3f, % 0.3f]`,
m[0][0], m[0][1], m[0][2],
m[1][0], m[1][1], m[1][2])
}
// Identity sets m to be the identity transform.
func (m *Affine) Identity() {
*m = Affine{
{1, 0, 0},
{0, 1, 0},
}
}
// Eq reports whether each component of m is within epsilon of the same
// component in n.
func (m *Affine) Eq(n *Affine, epsilon float32) bool {
for i := range m {
for j := range m[i] {
diff := m[i][j] - n[i][j]
if diff < -epsilon || +epsilon < diff {
return false
}
}
}
return true
}
// Mul sets m to be p × q.
func (m *Affine) Mul(p, q *Affine) {
// Store the result in local variables, in case m == a || m == b.
m00 := p[0][0]*q[0][0] + p[0][1]*q[1][0]
m01 := p[0][0]*q[0][1] + p[0][1]*q[1][1]
m02 := p[0][0]*q[0][2] + p[0][1]*q[1][2] + p[0][2]
m10 := p[1][0]*q[0][0] + p[1][1]*q[1][0]
m11 := p[1][0]*q[0][1] + p[1][1]*q[1][1]
m12 := p[1][0]*q[0][2] + p[1][1]*q[1][2] + p[1][2]
m[0][0] = m00
m[0][1] = m01
m[0][2] = m02
m[1][0] = m10
m[1][1] = m11
m[1][2] = m12
}
// Inverse sets m to be the inverse of p.
func (m *Affine) Inverse(p *Affine) {
m00 := p[1][1]
m01 := -p[0][1]
m02 := p[1][2]*p[0][1] - p[1][1]*p[0][2]
m10 := -p[1][0]
m11 := p[0][0]
m12 := p[1][0]*p[0][2] - p[1][2]*p[0][0]
det := m00*m11 - m10*m01
m[0][0] = m00 / det
m[0][1] = m01 / det
m[0][2] = m02 / det
m[1][0] = m10 / det
m[1][1] = m11 / det
m[1][2] = m12 / det
}
// Scale sets m to be a scale followed by p.
// It is equivalent to m.Mul(p, &Affine{{x,0,0}, {0,y,0}}).
func (m *Affine) Scale(p *Affine, x, y float32) {
m[0][0] = p[0][0] * x
m[0][1] = p[0][1] * y
m[0][2] = p[0][2]
m[1][0] = p[1][0] * x
m[1][1] = p[1][1] * y
m[1][2] = p[1][2]
}
// Translate sets m to be a translation followed by p.
// It is equivalent to m.Mul(p, &Affine{{1,0,x}, {0,1,y}}).
func (m *Affine) Translate(p *Affine, x, y float32) {
m[0][0] = p[0][0]
m[0][1] = p[0][1]
m[0][2] = p[0][0]*x + p[0][1]*y + p[0][2]
m[1][0] = p[1][0]
m[1][1] = p[1][1]
m[1][2] = p[1][0]*x + p[1][1]*y + p[1][2]
}
// Rotate sets m to a rotation in radians followed by p.
// It is equivalent to m.Mul(p, affineRotation).
func (m *Affine) Rotate(p *Affine, radians float32) {
s, c := Sin(radians), Cos(radians)
m.Mul(p, &Affine{
{+c, +s, 0},
{-s, +c, 0},
})
}

140
exp/f32/affine_test.go Normal file
View file

@ -0,0 +1,140 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package f32
import (
"math"
"testing"
)
var xyTests = []struct {
x, y float32
}{
{0, 0},
{1, 1},
{2, 3},
{6.5, 4.3},
}
var a = Affine{
{3, 4, 5},
{6, 7, 8},
}
func TestInverse(t *testing.T) {
wantInv := Affine{
{-2.33333, 1.33333, 1},
{2, -1, -2},
}
var gotInv Affine
gotInv.Inverse(&a)
if !gotInv.Eq(&wantInv, 0.01) {
t.Errorf("Inverse: got %s want %s", gotInv, wantInv)
}
var wantId, gotId Affine
wantId.Identity()
gotId.Mul(&a, &wantInv)
if !gotId.Eq(&wantId, 0.01) {
t.Errorf("Identity #0: got %s want %s", gotId, wantId)
}
gotId.Mul(&wantInv, &a)
if !gotId.Eq(&wantId, 0.01) {
t.Errorf("Identity #1: got %s want %s", gotId, wantId)
}
}
func TestAffineScale(t *testing.T) {
for _, test := range xyTests {
want := a
want.Mul(&want, &Affine{{test.x, 0, 0}, {0, test.y, 0}})
got := a
got.Scale(&got, test.x, test.y)
if !got.Eq(&want, 0.01) {
t.Errorf("(%.2f, %.2f): got %s want %s", test.x, test.y, got, want)
}
}
}
func TestAffineTranslate(t *testing.T) {
for _, test := range xyTests {
want := a
want.Mul(&want, &Affine{{1, 0, test.x}, {0, 1, test.y}})
got := a
got.Translate(&got, test.x, test.y)
if !got.Eq(&want, 0.01) {
t.Errorf("(%.2f, %.2f): got %s want %s", test.x, test.y, got, want)
}
}
}
func TestAffineRotate(t *testing.T) {
want := Affine{
{-4.000, 3.000, 5.000},
{-7.000, 6.000, 8.000},
}
got := a
got.Rotate(&got, math.Pi/2)
if !got.Eq(&want, 0.01) {
t.Errorf("rotate π: got %s want %s", got, want)
}
want = a
got = a
got.Rotate(&got, 2*math.Pi)
if !got.Eq(&want, 0.01) {
t.Errorf("rotate 2π: got %s want %s", got, want)
}
got = a
got.Rotate(&got, math.Pi)
got.Rotate(&got, math.Pi)
if !got.Eq(&want, 0.01) {
t.Errorf("rotate π then π: got %s want %s", got, want)
}
got = a
got.Rotate(&got, math.Pi/3)
got.Rotate(&got, -math.Pi/3)
if !got.Eq(&want, 0.01) {
t.Errorf("rotate π/3 then -π/3: got %s want %s", got, want)
}
}
func TestAffineScaleTranslate(t *testing.T) {
mulVec := func(m *Affine, v [2]float32) (mv [2]float32) {
mv[0] = m[0][0]*v[0] + m[0][1]*v[1] + m[0][2]
mv[1] = m[1][0]*v[0] + m[1][1]*v[1] + m[1][2]
return mv
}
v := [2]float32{1, 10}
var sThenT Affine
sThenT.Identity()
sThenT.Scale(&sThenT, 13, 17)
sThenT.Translate(&sThenT, 101, 151)
wantSTT := [2]float32{
13 * (101 + 1),
17 * (151 + 10),
}
if got := mulVec(&sThenT, v); got != wantSTT {
t.Errorf("S then T: got %v, want %v", got, wantSTT)
}
var tThenS Affine
tThenS.Identity()
tThenS.Translate(&tThenS, 101, 151)
tThenS.Scale(&tThenS, 13, 17)
wantTTS := [2]float32{
101 + (13 * 1),
151 + (17 * 10),
}
if got := mulVec(&tThenS, v); got != wantTTS {
t.Errorf("T then S: got %v, want %v", got, wantTTS)
}
}

93
exp/f32/f32.go Normal file
View file

@ -0,0 +1,93 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:generate go run gen.go -output table.go
// Package f32 implements some linear algebra and GL helpers for float32s.
//
// Types defined in this package have methods implementing common
// mathematical operations. The common form for these functions is
//
// func (dst *T) Op(lhs, rhs *T)
//
// which reads in traditional mathematical notation as
//
// dst = lhs op rhs.
//
// It is safe to use the destination address as the left-hand side,
// that is, dst *= rhs is dst.Mul(dst, rhs).
//
// # WARNING
//
// The interface to this package is not stable. It will change considerably.
// Only use functions that provide package documentation. Semantics are
// non-obvious. Be prepared for the package name to change.
package f32
import (
"encoding/binary"
"fmt"
"math"
)
type Radian float32
func Cos(x float32) float32 {
const n = sinTableLen
i := uint32(int32(x * (n / math.Pi)))
i += n / 2
i &= 2*n - 1
if i >= n {
return -sinTable[i&(n-1)]
}
return sinTable[i&(n-1)]
}
func Sin(x float32) float32 {
const n = sinTableLen
i := uint32(int32(x * (n / math.Pi)))
i &= 2*n - 1
if i >= n {
return -sinTable[i&(n-1)]
}
return sinTable[i&(n-1)]
}
func Sqrt(x float32) float32 {
return float32(math.Sqrt(float64(x))) // TODO(crawshaw): implement
}
func Tan(x float32) float32 {
return float32(math.Tan(float64(x))) // TODO(crawshaw): fast version
}
// Bytes returns the byte representation of float32 values in the given byte
// order. byteOrder must be either binary.BigEndian or binary.LittleEndian.
func Bytes(byteOrder binary.ByteOrder, values ...float32) []byte {
le := false
switch byteOrder {
case binary.BigEndian:
case binary.LittleEndian:
le = true
default:
panic(fmt.Sprintf("invalid byte order %v", byteOrder))
}
b := make([]byte, 4*len(values))
for i, v := range values {
u := math.Float32bits(v)
if le {
b[4*i+0] = byte(u >> 0)
b[4*i+1] = byte(u >> 8)
b[4*i+2] = byte(u >> 16)
b[4*i+3] = byte(u >> 24)
} else {
b[4*i+0] = byte(u >> 24)
b[4*i+1] = byte(u >> 16)
b[4*i+2] = byte(u >> 8)
b[4*i+3] = byte(u >> 0)
}
}
return b
}

361
exp/f32/f32_test.go Normal file
View file

@ -0,0 +1,361 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package f32
import (
"bytes"
"encoding/binary"
"math"
"testing"
)
func TestAffineTranslationsCommute(t *testing.T) {
a := &Affine{
{1, 0, 3},
{0, 1, 4},
}
b := &Affine{
{1, 0, 20},
{0, 1, 30},
}
var m0, m1 Affine
m0.Mul(a, b)
m1.Mul(b, a)
if !m0.Eq(&m1, 0) {
t.Errorf("m0, m1 differ.\nm0: %v\nm1: %v", m0, m1)
}
}
func TestAffineMat3Equivalence(t *testing.T) {
a0 := Affine{
{13, 19, 37},
{101, 149, 311},
}
m0 := Mat3{
a0[0],
a0[1],
{0, 0, 1},
}
a1 := Affine{
{1009, 1051, 1087},
{563, 569, 571},
}
m1 := Mat3{
a1[0],
a1[1],
{0, 0, 1},
}
a2 := Affine{}
a2.Mul(&a0, &a1)
m2 := Mat3{
a2[0],
a2[1],
{0, 0, 1},
}
mm := Mat3{}
mm.Mul(&m0, &m1)
if !m2.Eq(&mm, 0) {
t.Errorf("m2, mm differ.\nm2: %v\nmm: %v", m2, mm)
}
}
var x3 = Mat3{
{0, 1, 2},
{3, 4, 5},
{6, 7, 8},
}
var x3sq = Mat3{
{15, 18, 21},
{42, 54, 66},
{69, 90, 111},
}
var id3 = Mat3{
{1, 0, 0},
{0, 1, 0},
{0, 0, 1},
}
func TestMat3Mul(t *testing.T) {
tests := []struct{ m0, m1, want Mat3 }{
{x3, id3, x3},
{id3, x3, x3},
{x3, x3, x3sq},
{
Mat3{
{+1.811, +0.000, +0.000},
{+0.000, +2.414, +0.000},
{+0.000, +0.000, -1.010},
},
Mat3{
{+0.992, -0.015, +0.123},
{+0.000, +0.992, +0.123},
{-0.124, -0.122, +0.985},
},
Mat3{
{+1.797, -0.027, +0.223},
{+0.000, +2.395, +0.297},
{+0.125, +0.123, -0.995},
},
},
}
for i, test := range tests {
got := Mat3{}
got.Mul(&test.m0, &test.m1)
if !got.Eq(&test.want, 0.01) {
t.Errorf("test #%d:\n%s *\n%s =\n%s, want\n%s", i, test.m0, test.m1, got, test.want)
}
}
}
func TestMat3SelfMul(t *testing.T) {
m := x3
m.Mul(&m, &m)
if !m.Eq(&x3sq, 0) {
t.Errorf("m, x3sq differ.\nm: %v\nx3sq: %v", m, x3sq)
}
}
var x4 = Mat4{
{0, 1, 2, 3},
{4, 5, 6, 7},
{8, 9, 10, 11},
{12, 13, 14, 15},
}
var x4sq = Mat4{
{56, 62, 68, 74},
{152, 174, 196, 218},
{248, 286, 324, 362},
{344, 398, 452, 506},
}
var id4 = Mat4{
{1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 1},
}
func TestMat4Eq(t *testing.T) {
tests := []struct {
m0, m1 Mat4
eq bool
}{
{x4, x4, true},
{id4, id4, true},
{x4, id4, false},
}
for _, test := range tests {
got := test.m0.Eq(&test.m1, 0.01)
if got != test.eq {
t.Errorf("Eq=%v, want %v for\n%s\n%s", got, test.eq, test.m0, test.m1)
}
}
}
func TestMat4Mul(t *testing.T) {
tests := []struct{ m0, m1, want Mat4 }{
{x4, id4, x4},
{id4, x4, x4},
{x4, x4, x4sq},
{
Mat4{
{+1.811, +0.000, +0.000, +0.000},
{+0.000, +2.414, +0.000, +0.000},
{+0.000, +0.000, -1.010, -1.000},
{+0.000, +0.000, -2.010, +0.000},
},
Mat4{
{+0.992, -0.015, +0.123, +0.000},
{+0.000, +0.992, +0.123, +0.000},
{-0.124, -0.122, +0.985, +0.000},
{-0.000, -0.000, -8.124, +1.000},
},
Mat4{
{+1.797, -0.027, +0.223, +0.000},
{+0.000, +2.395, +0.297, +0.000},
{+0.125, +0.123, +7.129, -1.000},
{+0.249, +0.245, -1.980, +0.000},
},
},
}
for i, test := range tests {
got := Mat4{}
got.Mul(&test.m0, &test.m1)
if !got.Eq(&test.want, 0.01) {
t.Errorf("test #%d:\n%s *\n%s =\n%s, want\n%s", i, test.m0, test.m1, got, test.want)
}
}
}
func TestMat4LookAt(t *testing.T) {
tests := []struct {
eye, center, up Vec3
want Mat4
}{
{
Vec3{1, 1, 8}, Vec3{0, 0, 0}, Vec3{0, 1, 0},
Mat4{
{0.992, -0.015, 0.123, 0.000},
{0.000, 0.992, 0.123, 0.000},
{-0.124, -0.122, 0.985, 0.000},
{-0.000, -0.000, -8.124, 1.000},
},
},
{
Vec3{4, 5, 7}, Vec3{0.1, 0.2, 0.3}, Vec3{0, -1, 0},
Mat4{
{-0.864, 0.265, 0.428, 0.000},
{0.000, -0.850, 0.526, 0.000},
{0.503, 0.455, 0.735, 0.000},
{-0.064, 0.007, -9.487, 1.000},
},
},
}
for _, test := range tests {
got := Mat4{}
got.LookAt(&test.eye, &test.center, &test.up)
if !got.Eq(&test.want, 0.01) {
t.Errorf("LookAt(%s,%s%s) =\n%s\nwant\n%s", test.eye, test.center, test.up, got, test.want)
}
}
}
func TestMat4Perspective(t *testing.T) {
want := Mat4{
{1.811, 0.000, 0.000, 0.000},
{0.000, 2.414, 0.000, 0.000},
{0.000, 0.000, -1.010, -1.000},
{0.000, 0.000, -2.010, 0.000},
}
got := Mat4{}
got.Perspective(Radian(math.Pi/4), 4.0/3, 1, 200)
if !got.Eq(&want, 0.01) {
t.Errorf("got\n%s\nwant\n%s", got, want)
}
}
func TestMat4Rotate(t *testing.T) {
want := &Mat4{
{2.000, 1.000, -0.000, 3.000},
{6.000, 5.000, -4.000, 7.000},
{10.000, 9.000, -8.000, 11.000},
{14.000, 13.000, -12.000, 15.000},
}
got := new(Mat4)
got.Rotate(&x4, Radian(math.Pi/2), &Vec3{0, 1, 0})
if !got.Eq(want, 0.01) {
t.Errorf("got\n%s\nwant\n%s", got, want)
}
}
func TestMat4Scale(t *testing.T) {
want := &Mat4{
{0 * 2, 1 * 3, 2 * 4, 3 * 1},
{4 * 2, 5 * 3, 6 * 4, 7 * 1},
{8 * 2, 9 * 3, 10 * 4, 11 * 1},
{12 * 2, 13 * 3, 14 * 4, 15 * 1},
}
got := new(Mat4)
got.Scale(&x4, 2, 3, 4)
if !got.Eq(want, 0.01) {
t.Errorf("got\n%s\nwant\n%s", got, want)
}
}
func TestMat4Translate(t *testing.T) {
want := &Mat4{
{0, 1, 2, 0*0.1 + 1*0.2 + 2*0.3 + 3*1},
{4, 5, 6, 4*0.1 + 5*0.2 + 6*0.3 + 7*1},
{8, 9, 10, 8*0.1 + 9*0.2 + 10*0.3 + 11*1},
{12, 13, 14, 12*0.1 + 13*0.2 + 14*0.3 + 15*1},
}
got := new(Mat4)
got.Translate(&x4, 0.1, 0.2, 0.3)
if !got.Eq(want, 0.01) {
t.Errorf("got\n%s\nwant\n%s", got, want)
}
}
func testTrig(t *testing.T, gotFunc func(float32) float32, wantFunc func(float64) float64) {
nBad := 0
for a := float32(-9); a < +9; a += .01 {
got := gotFunc(a)
want := float32(wantFunc(float64(a)))
diff := got - want
if diff < 0 {
diff = -diff
}
if diff > 0.001 {
if nBad++; nBad == 10 {
t.Errorf("too many failures")
break
}
t.Errorf("a=%+.2f: got %+.4f, want %+.4f, diff=%.4f", a, got, want, diff)
}
}
}
func TestCos(t *testing.T) { testTrig(t, Cos, math.Cos) }
func TestSin(t *testing.T) { testTrig(t, Sin, math.Sin) }
func TestTan(t *testing.T) { testTrig(t, Tan, math.Tan) }
func BenchmarkSin(b *testing.B) {
for i := 0; i < b.N; i++ {
for a := 0; a < 3141; a++ {
Sin(float32(a) / 1000)
}
}
}
func TestBytes(t *testing.T) {
testCases := []struct {
byteOrder binary.ByteOrder
want []byte
}{{
binary.BigEndian,
[]byte{
// The IEEE 754 binary32 format is 1 sign bit, 8 exponent bits and 23 fraction bits.
0x00, 0x00, 0x00, 0x00, // float32(+0.00) is 0 0000000_0 0000000_00000000_00000000
0x3f, 0xa0, 0x00, 0x00, // float32(+1.25) is 0 0111111_1 0100000_00000000_00000000
0xc0, 0x00, 0x00, 0x00, // float32(-2.00) is 1 1000000_0 0000000_00000000_00000000
},
}, {
binary.LittleEndian,
[]byte{
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xa0, 0x3f,
0x00, 0x00, 0x00, 0xc0,
},
}}
for _, tc := range testCases {
got := Bytes(tc.byteOrder, +0.00, +1.25, -2.00)
if !bytes.Equal(got, tc.want) {
t.Errorf("%v:\ngot % x\nwant % x", tc.byteOrder, got, tc.want)
}
}
}

48
exp/f32/gen.go Normal file
View file

@ -0,0 +1,48 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ignore
package main
/*
This program generates table.go. Invoke it as:
go run gen.go -output table.go
*/
import (
"bytes"
"flag"
"fmt"
"go/format"
"log"
"math"
"os"
)
// N is the number of entries in the sin look-up table. It must be a power of 2.
const N = 4096
var filename = flag.String("output", "table.go", "output file name")
func main() {
b := new(bytes.Buffer)
fmt.Fprintf(b, "// Code generated by go run gen.go; DO NOT EDIT\n\npackage f32\n\n")
fmt.Fprintf(b, "const sinTableLen = %d\n\n", N)
fmt.Fprintf(b, "// sinTable[i] equals sin(i * π / sinTableLen).\n")
fmt.Fprintf(b, "var sinTable = [sinTableLen]float32{\n")
for i := 0; i < N; i++ {
radians := float64(i) * (math.Pi / N)
fmt.Fprintf(b, "%v,\n", float32(math.Sin(radians)))
}
fmt.Fprintf(b, "}\n")
data, err := format.Source(b.Bytes())
if err != nil {
log.Fatal(err)
}
if err := os.WriteFile(*filename, data, 0644); err != nil {
log.Fatal(err)
}
}

63
exp/f32/mat3.go Normal file
View file

@ -0,0 +1,63 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package f32
import "fmt"
// A Mat3 is a 3x3 matrix of float32 values.
// Elements are indexed first by row then column, i.e. m[row][column].
type Mat3 [3]Vec3
func (m Mat3) String() string {
return fmt.Sprintf(`Mat3[% 0.3f, % 0.3f, % 0.3f,
% 0.3f, % 0.3f, % 0.3f,
% 0.3f, % 0.3f, % 0.3f]`,
m[0][0], m[0][1], m[0][2],
m[1][0], m[1][1], m[1][2],
m[2][0], m[2][1], m[2][2])
}
func (m *Mat3) Identity() {
*m = Mat3{
{1, 0, 0},
{0, 1, 0},
{0, 0, 1},
}
}
func (m *Mat3) Eq(n *Mat3, epsilon float32) bool {
for i := range m {
for j := range m[i] {
diff := m[i][j] - n[i][j]
if diff < -epsilon || +epsilon < diff {
return false
}
}
}
return true
}
// Mul stores a × b in m.
func (m *Mat3) Mul(a, b *Mat3) {
// Store the result in local variables, in case m == a || m == b.
m00 := a[0][0]*b[0][0] + a[0][1]*b[1][0] + a[0][2]*b[2][0]
m01 := a[0][0]*b[0][1] + a[0][1]*b[1][1] + a[0][2]*b[2][1]
m02 := a[0][0]*b[0][2] + a[0][1]*b[1][2] + a[0][2]*b[2][2]
m10 := a[1][0]*b[0][0] + a[1][1]*b[1][0] + a[1][2]*b[2][0]
m11 := a[1][0]*b[0][1] + a[1][1]*b[1][1] + a[1][2]*b[2][1]
m12 := a[1][0]*b[0][2] + a[1][1]*b[1][2] + a[1][2]*b[2][2]
m20 := a[2][0]*b[0][0] + a[2][1]*b[1][0] + a[2][2]*b[2][0]
m21 := a[2][0]*b[0][1] + a[2][1]*b[1][1] + a[2][2]*b[2][1]
m22 := a[2][0]*b[0][2] + a[2][1]*b[1][2] + a[2][2]*b[2][2]
m[0][0] = m00
m[0][1] = m01
m[0][2] = m02
m[1][0] = m10
m[1][1] = m11
m[1][2] = m12
m[2][0] = m20
m[2][1] = m21
m[2][2] = m22
}

195
exp/f32/mat4.go Normal file
View file

@ -0,0 +1,195 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package f32
import "fmt"
// A Mat4 is a 4x4 matrix of float32 values.
// Elements are indexed first by row then column, i.e. m[row][column].
type Mat4 [4]Vec4
func (m Mat4) String() string {
return fmt.Sprintf(`Mat4[% 0.3f, % 0.3f, % 0.3f, % 0.3f,
% 0.3f, % 0.3f, % 0.3f, % 0.3f,
% 0.3f, % 0.3f, % 0.3f, % 0.3f,
% 0.3f, % 0.3f, % 0.3f, % 0.3f]`,
m[0][0], m[0][1], m[0][2], m[0][3],
m[1][0], m[1][1], m[1][2], m[1][3],
m[2][0], m[2][1], m[2][2], m[2][3],
m[3][0], m[3][1], m[3][2], m[3][3])
}
func (m *Mat4) Identity() {
*m = Mat4{
{1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 1},
}
}
func (m *Mat4) Eq(n *Mat4, epsilon float32) bool {
for i := range m {
for j := range m[i] {
diff := m[i][j] - n[i][j]
if diff < -epsilon || +epsilon < diff {
return false
}
}
}
return true
}
// Mul stores a × b in m.
func (m *Mat4) Mul(a, b *Mat4) {
// Store the result in local variables, in case m == a || m == b.
m00 := a[0][0]*b[0][0] + a[0][1]*b[1][0] + a[0][2]*b[2][0] + a[0][3]*b[3][0]
m01 := a[0][0]*b[0][1] + a[0][1]*b[1][1] + a[0][2]*b[2][1] + a[0][3]*b[3][1]
m02 := a[0][0]*b[0][2] + a[0][1]*b[1][2] + a[0][2]*b[2][2] + a[0][3]*b[3][2]
m03 := a[0][0]*b[0][3] + a[0][1]*b[1][3] + a[0][2]*b[2][3] + a[0][3]*b[3][3]
m10 := a[1][0]*b[0][0] + a[1][1]*b[1][0] + a[1][2]*b[2][0] + a[1][3]*b[3][0]
m11 := a[1][0]*b[0][1] + a[1][1]*b[1][1] + a[1][2]*b[2][1] + a[1][3]*b[3][1]
m12 := a[1][0]*b[0][2] + a[1][1]*b[1][2] + a[1][2]*b[2][2] + a[1][3]*b[3][2]
m13 := a[1][0]*b[0][3] + a[1][1]*b[1][3] + a[1][2]*b[2][3] + a[1][3]*b[3][3]
m20 := a[2][0]*b[0][0] + a[2][1]*b[1][0] + a[2][2]*b[2][0] + a[2][3]*b[3][0]
m21 := a[2][0]*b[0][1] + a[2][1]*b[1][1] + a[2][2]*b[2][1] + a[2][3]*b[3][1]
m22 := a[2][0]*b[0][2] + a[2][1]*b[1][2] + a[2][2]*b[2][2] + a[2][3]*b[3][2]
m23 := a[2][0]*b[0][3] + a[2][1]*b[1][3] + a[2][2]*b[2][3] + a[2][3]*b[3][3]
m30 := a[3][0]*b[0][0] + a[3][1]*b[1][0] + a[3][2]*b[2][0] + a[3][3]*b[3][0]
m31 := a[3][0]*b[0][1] + a[3][1]*b[1][1] + a[3][2]*b[2][1] + a[3][3]*b[3][1]
m32 := a[3][0]*b[0][2] + a[3][1]*b[1][2] + a[3][2]*b[2][2] + a[3][3]*b[3][2]
m33 := a[3][0]*b[0][3] + a[3][1]*b[1][3] + a[3][2]*b[2][3] + a[3][3]*b[3][3]
m[0][0] = m00
m[0][1] = m01
m[0][2] = m02
m[0][3] = m03
m[1][0] = m10
m[1][1] = m11
m[1][2] = m12
m[1][3] = m13
m[2][0] = m20
m[2][1] = m21
m[2][2] = m22
m[2][3] = m23
m[3][0] = m30
m[3][1] = m31
m[3][2] = m32
m[3][3] = m33
}
// Perspective sets m to be the GL perspective matrix.
func (m *Mat4) Perspective(fov Radian, aspect, near, far float32) {
t := Tan(float32(fov) / 2)
m[0][0] = 1 / (aspect * t)
m[1][1] = 1 / t
m[2][2] = -(far + near) / (far - near)
m[2][3] = -1
m[3][2] = -2 * far * near / (far - near)
}
// Scale sets m to be a scale followed by p.
// It is equivalent to
//
// m.Mul(p, &Mat4{
// {x, 0, 0, 0},
// {0, y, 0, 0},
// {0, 0, z, 0},
// {0, 0, 0, 1},
// }).
func (m *Mat4) Scale(p *Mat4, x, y, z float32) {
m[0][0] = p[0][0] * x
m[0][1] = p[0][1] * y
m[0][2] = p[0][2] * z
m[0][3] = p[0][3]
m[1][0] = p[1][0] * x
m[1][1] = p[1][1] * y
m[1][2] = p[1][2] * z
m[1][3] = p[1][3]
m[2][0] = p[2][0] * x
m[2][1] = p[2][1] * y
m[2][2] = p[2][2] * z
m[2][3] = p[2][3]
m[3][0] = p[3][0] * x
m[3][1] = p[3][1] * y
m[3][2] = p[3][2] * z
m[3][3] = p[3][3]
}
// Translate sets m to be a translation followed by p.
// It is equivalent to
//
// m.Mul(p, &Mat4{
// {1, 0, 0, x},
// {0, 1, 0, y},
// {0, 0, 1, z},
// {0, 0, 0, 1},
// }).
func (m *Mat4) Translate(p *Mat4, x, y, z float32) {
m[0][0] = p[0][0]
m[0][1] = p[0][1]
m[0][2] = p[0][2]
m[0][3] = p[0][0]*x + p[0][1]*y + p[0][2]*z + p[0][3]
m[1][0] = p[1][0]
m[1][1] = p[1][1]
m[1][2] = p[1][2]
m[1][3] = p[1][0]*x + p[1][1]*y + p[1][2]*z + p[1][3]
m[2][0] = p[2][0]
m[2][1] = p[2][1]
m[2][2] = p[2][2]
m[2][3] = p[2][0]*x + p[2][1]*y + p[2][2]*z + p[2][3]
m[3][0] = p[3][0]
m[3][1] = p[3][1]
m[3][2] = p[3][2]
m[3][3] = p[3][0]*x + p[3][1]*y + p[3][2]*z + p[3][3]
}
// Rotate sets m to a rotation in radians around a specified axis, followed by p.
// It is equivalent to m.Mul(p, affineRotation).
func (m *Mat4) Rotate(p *Mat4, angle Radian, axis *Vec3) {
a := *axis
a.Normalize()
c, s := Cos(float32(angle)), Sin(float32(angle))
d := 1 - c
m.Mul(p, &Mat4{{
c + d*a[0]*a[1],
0 + d*a[0]*a[1] + s*a[2],
0 + d*a[0]*a[1] - s*a[1],
0,
}, {
0 + d*a[1]*a[0] - s*a[2],
c + d*a[1]*a[1],
0 + d*a[1]*a[2] + s*a[0],
0,
}, {
0 + d*a[2]*a[0] + s*a[1],
0 + d*a[2]*a[1] - s*a[0],
c + d*a[2]*a[2],
0,
}, {
0, 0, 0, 1,
}})
}
func (m *Mat4) LookAt(eye, center, up *Vec3) {
f, s, u := new(Vec3), new(Vec3), new(Vec3)
*f = *center
f.Sub(f, eye)
f.Normalize()
s.Cross(f, up)
s.Normalize()
u.Cross(s, f)
*m = Mat4{
{s[0], u[0], -f[0], 0},
{s[1], u[1], -f[1], 0},
{s[2], u[2], -f[2], 0},
{-s.Dot(eye), -u.Dot(eye), +f.Dot(eye), 1},
}
}

4105
exp/f32/table.go Normal file

File diff suppressed because it is too large Load diff

49
exp/f32/vec3.go Normal file
View file

@ -0,0 +1,49 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package f32
import "fmt"
type Vec3 [3]float32
func (v Vec3) String() string {
return fmt.Sprintf("Vec3[% 0.3f, % 0.3f, % 0.3f]", v[0], v[1], v[2])
}
func (v *Vec3) Normalize() {
sq := v.Dot(v)
inv := 1 / Sqrt(sq)
v[0] *= inv
v[1] *= inv
v[2] *= inv
}
func (v *Vec3) Sub(v0, v1 *Vec3) {
v[0] = v0[0] - v1[0]
v[1] = v0[1] - v1[1]
v[2] = v0[2] - v1[2]
}
func (v *Vec3) Add(v0, v1 *Vec3) {
v[0] = v0[0] + v1[0]
v[1] = v0[1] + v1[1]
v[2] = v0[2] + v1[2]
}
func (v *Vec3) Mul(v0, v1 *Vec3) {
v[0] = v0[0] * v1[0]
v[1] = v0[1] * v1[1]
v[2] = v0[2] * v1[2]
}
func (v *Vec3) Cross(v0, v1 *Vec3) {
v[0] = v0[1]*v1[2] - v0[2]*v1[1]
v[1] = v0[2]*v1[0] - v0[0]*v1[2]
v[2] = v0[0]*v1[1] - v0[1]*v1[0]
}
func (v *Vec3) Dot(v1 *Vec3) float32 {
return v[0]*v1[0] + v[1]*v1[1] + v[2]*v1[2]
}

47
exp/f32/vec4.go Normal file
View file

@ -0,0 +1,47 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package f32
import "fmt"
type Vec4 [4]float32
func (v Vec4) String() string {
return fmt.Sprintf("Vec4[% 0.3f, % 0.3f, % 0.3f, % 0.3f]", v[0], v[1], v[2], v[3])
}
func (v *Vec4) Normalize() {
sq := v.Dot(v)
inv := 1 / Sqrt(sq)
v[0] *= inv
v[1] *= inv
v[2] *= inv
v[3] *= inv
}
func (v *Vec4) Sub(v0, v1 *Vec4) {
v[0] = v0[0] - v1[0]
v[1] = v0[1] - v1[1]
v[2] = v0[2] - v1[2]
v[3] = v0[3] - v1[3]
}
func (v *Vec4) Add(v0, v1 *Vec4) {
v[0] = v0[0] + v1[0]
v[1] = v0[1] + v1[1]
v[2] = v0[2] + v1[2]
v[3] = v0[3] + v1[3]
}
func (v *Vec4) Mul(v0, v1 *Vec4) {
v[0] = v0[0] * v1[0]
v[1] = v0[1] * v1[1]
v[2] = v0[2] * v1[2]
v[3] = v0[3] * v1[3]
}
func (v *Vec4) Dot(v1 *Vec4) float32 {
return v[0]*v1[0] + v[1]*v1[1] + v[2]*v1[2] + v[3]*v1[3]
}