Adding upstream version 0.0~git20250520.a1d9079+dfsg.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
590ac7ff5f
commit
20149b7f3a
456 changed files with 70406 additions and 0 deletions
109
exp/f32/affine.go
Normal file
109
exp/f32/affine.go
Normal 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
140
exp/f32/affine_test.go
Normal 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
93
exp/f32/f32.go
Normal 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
361
exp/f32/f32_test.go
Normal 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
48
exp/f32/gen.go
Normal 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
63
exp/f32/mat3.go
Normal 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
195
exp/f32/mat4.go
Normal 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
4105
exp/f32/table.go
Normal file
File diff suppressed because it is too large
Load diff
49
exp/f32/vec3.go
Normal file
49
exp/f32/vec3.go
Normal 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
47
exp/f32/vec4.go
Normal 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]
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue