From bd3f423021cc8c8d66bae82fa07821e138f6770f Mon Sep 17 00:00:00 2001 From: djfinlay <8754126+djfinlay@users.noreply.github.com> Date: Tue, 14 Oct 2025 12:55:42 +0100 Subject: [PATCH 1/6] Align raymath functions with C versions --- .../internal/cmd/genraymath/binding.go.tmpl | 27 + raylib/internal/cmd/genraymath/helper.go.tmpl | 157 + raylib/internal/cmd/genraymath/main.go | 447 ++ .../internal/cmd/genraymath/methods.go.tmpl | 25 + raylib/internal/cmd/genraymath/test.go.tmpl | 122 + raylib/raymath.go | 476 +- raylib/raymath_generated_binding.go | 816 +++ raylib/raymath_generated_test.go | 5002 +++++++++++++++++ raylib/raymath_test.go | 192 + raylib/rcore.go | 10 - .../FuzzMatrixDeterminant/ef7c045ed1986603 | 17 + .../fuzz/FuzzMatrixFrustum/14155074da34118b | 7 + .../fuzz/FuzzMatrixLookAt/8fbc1d984795cc11 | 10 + .../fuzz/FuzzMatrixLookAt/9ad75835daa1541f | 10 + .../fuzz/FuzzQuaternionSlerp/509f5490c8952865 | 10 + .../fuzz/FuzzQuaternionSlerp/7094170c6348cebf | 10 + .../1608fe79e1c832a4 | 5 + .../64c25f227ec3e612 | 5 + .../ab8e069d6a3cf0fb | 5 + .../bb7cd68c914b767e | 5 + .../c3aca23da620d7bb | 5 + .../fuzz/FuzzVector2Angle/1a9a7f78f17648a9 | 5 + .../fuzz/FuzzVector2Rotate/06a6aed80735d1a1 | 4 + .../fuzz/FuzzVector2Rotate/89bbb2c6faf7be5e | 4 + .../fuzz/FuzzVector2Rotate/ae2d7f041c3fd4e0 | 4 + .../fuzz/FuzzVector2Rotate/b79bca504b15bda6 | 4 + .../187d7f6f85c6fc52 | 7 + .../088607e6fb0c7930 | 8 + 28 files changed, 7154 insertions(+), 245 deletions(-) create mode 100644 raylib/internal/cmd/genraymath/binding.go.tmpl create mode 100644 raylib/internal/cmd/genraymath/helper.go.tmpl create mode 100644 raylib/internal/cmd/genraymath/main.go create mode 100644 raylib/internal/cmd/genraymath/methods.go.tmpl create mode 100644 raylib/internal/cmd/genraymath/test.go.tmpl create mode 100644 raylib/raymath_generated_binding.go create mode 100644 raylib/raymath_generated_test.go create mode 100644 raylib/raymath_test.go create mode 100644 raylib/testdata/fuzz/FuzzMatrixDeterminant/ef7c045ed1986603 create mode 100644 raylib/testdata/fuzz/FuzzMatrixFrustum/14155074da34118b create mode 100644 raylib/testdata/fuzz/FuzzMatrixLookAt/8fbc1d984795cc11 create mode 100644 raylib/testdata/fuzz/FuzzMatrixLookAt/9ad75835daa1541f create mode 100644 raylib/testdata/fuzz/FuzzQuaternionSlerp/509f5490c8952865 create mode 100644 raylib/testdata/fuzz/FuzzQuaternionSlerp/7094170c6348cebf create mode 100644 raylib/testdata/fuzz/FuzzQuaternionToAxisAngle/1608fe79e1c832a4 create mode 100644 raylib/testdata/fuzz/FuzzQuaternionToAxisAngle/64c25f227ec3e612 create mode 100644 raylib/testdata/fuzz/FuzzQuaternionToAxisAngle/ab8e069d6a3cf0fb create mode 100644 raylib/testdata/fuzz/FuzzQuaternionToAxisAngle/bb7cd68c914b767e create mode 100644 raylib/testdata/fuzz/FuzzQuaternionToAxisAngle/c3aca23da620d7bb create mode 100644 raylib/testdata/fuzz/FuzzVector2Angle/1a9a7f78f17648a9 create mode 100644 raylib/testdata/fuzz/FuzzVector2Rotate/06a6aed80735d1a1 create mode 100644 raylib/testdata/fuzz/FuzzVector2Rotate/89bbb2c6faf7be5e create mode 100644 raylib/testdata/fuzz/FuzzVector2Rotate/ae2d7f041c3fd4e0 create mode 100644 raylib/testdata/fuzz/FuzzVector2Rotate/b79bca504b15bda6 create mode 100644 raylib/testdata/fuzz/FuzzVector3OrthoNormalize/187d7f6f85c6fc52 create mode 100644 raylib/testdata/fuzz/FuzzVector3RotateByAxisAngle/088607e6fb0c7930 diff --git a/raylib/internal/cmd/genraymath/binding.go.tmpl b/raylib/internal/cmd/genraymath/binding.go.tmpl new file mode 100644 index 00000000..fe1b57a1 --- /dev/null +++ b/raylib/internal/cmd/genraymath/binding.go.tmpl @@ -0,0 +1,27 @@ +// Code generated by ./internal/cmd/genraymath DO NOT EDIT. + +package rl + +//#include "raymath.h" +import "C" + +import "unsafe" + +{{ range . -}} +{{ if .SkipBinding }}{{ continue }}{{ end }} +{{ $fn := .Name }} +func c{{ .Name }}({{ template "params" . }}) {{ .ReturnType }} { + {{- range $param := .Params }} + {{- range $param.Names }} + c{{ . }} := {{ $param.CType . }} + {{- end }} + {{- end }} + {{- if .ReturnType }} + ret := C.{{ $fn }}({{ template "cargs" . }}) + return {{ .ReturnValue }} + {{- else }} + C.{{ $fn }}({{ template "cargs" . }}) + {{- end }} +} + +{{ end }} diff --git a/raylib/internal/cmd/genraymath/helper.go.tmpl b/raylib/internal/cmd/genraymath/helper.go.tmpl new file mode 100644 index 00000000..e891bf9e --- /dev/null +++ b/raylib/internal/cmd/genraymath/helper.go.tmpl @@ -0,0 +1,157 @@ +{{ define "params" }} +{{- range $i, $param := .Params -}} + {{- range $j, $name := .Names -}} + {{- if or $i $j }}, {{ end -}} + {{ $name }} + {{- end }} {{ $param.TypeName }} +{{- end -}} +{{ end }} + +{{ define "args" }} +{{- range $i, $param := .Params -}} + {{- range $j, $name := .Names -}} + {{- if or $i $j }}, {{ end -}} + {{ $name }} + {{- end -}} +{{- end -}} +{{ end }} + +{{ define "testargs" }} +{{- range $i, $param := .Params -}} + {{- range $j, $name := .Names -}} + {{- if or $i $j }}, {{ end -}} + {{ testvar $name }} + {{- end -}} +{{- end -}} +{{ end }} + +{{ define "methodparams" }} +{{- $comma := false -}} +{{- range $i, $param := .Params -}} + {{- range $j, $name := .Names -}} + {{- if or $i $j -}} + {{- if $comma }} ,{{ end -}} + {{- $comma = true -}} + {{ $name }} + {{- end -}} + {{- end -}} + {{- if or $i (gt (len .Names) 1) }} {{ $param.TypeName }}{{- end -}} +{{- end -}} +{{ end }} + +{{ define "methodargs" }} +{{- range $i, $param := .Params -}} + {{- range $j, $name := .Names -}} + {{- if or $i $j }}, {{ $name }} + {{- end -}} + {{- end -}} +{{- end -}} +{{ end }} + +{{ define "cargs" }} +{{- range $i, $param := .Params -}} + {{- range $j, $name := .Names -}} + {{- if or $i $j }}, {{ end -}} + c{{ $name }} + {{- end -}} +{{- end -}} +{{ end }} + +{{ define "fuzzparams" }} +{{- range $i, $param := .Params -}} + {{- range $j, $name := .Names -}} + {{- if eq $param.TypeName "Vector2" }} + {{ $name }}X, {{ $name }}Y float32, + {{- else if eq $param.TypeName "Vector3" }} + {{ $name }}X, {{ $name }}Y, {{ $name }}Z float32, + {{- else if eq $param.TypeName "Vector4" }} + {{ $name }}X, {{ $name }}Y, {{ $name }}Z, {{$name}}W float32, + {{- else if eq $param.TypeName "Quaternion" }} + {{ $name }}X, {{ $name }}Y, {{ $name }}Z, {{$name}}W float32, + {{- else if eq $param.TypeName "Mat2" }} + {{ $name }}M00, {{ $name }}M01, {{ $name }}M10, {{$name}}M11 float32, + {{- else if eq $param.TypeName "Matrix" }} + {{ $name }}M0, {{ $name }}M4, {{ $name }}M8, {{ $name }}M12, + {{ $name }}M1, {{ $name }}M5, {{ $name }}M9, {{ $name }}M13, + {{ $name }}M2, {{ $name }}M6, {{ $name }}M10, {{ $name }}M14, + {{ $name }}M3, {{ $name }}M7, {{ $name }}M11, {{ $name }}M15 float32, + {{- else }} + {{ testvar $name }} {{ $param.TypeName }}, + {{- end -}} + {{- end -}} +{{- end }} +{{ end }} + +{{- define "fuzzvars" -}} +{{- range $i, $param := .Params -}} + {{- range $j, $name := .Names -}} + {{- if eq $param.TypeName "Vector2" }} + {{ testvar $name }} := NewVector2({{ $name }}X, {{ $name }}Y) + {{- else if eq $param.TypeName "Vector3" }} + {{ testvar $name }} := NewVector3({{ $name }}X, {{ $name }}Y, {{ $name }}Z) + {{- else if eq $param.TypeName "Vector4" }} + {{ testvar $name }} := NewVector4({{ $name }}X, {{ $name }}Y, {{ $name }}Z, {{$name}}W) + {{- else if eq $param.TypeName "Quaternion" }} + {{ testvar $name }} := NewQuaternion({{ $name }}X, {{ $name }}Y, {{ $name }}Z, {{$name}}W) + {{- else if eq $param.TypeName "Mat2" }} + {{ testvar $name }} := NewMat2({{ $name }}M00, {{ $name }}M01, {{ $name }}M10, {{$name}}M11) + {{- else if eq $param.TypeName "Matrix" }} + {{ testvar $name }} := NewMatrix( + {{ $name }}M0, {{ $name }}M4, {{ $name }}M8, {{ $name }}M12, + {{ $name }}M1, {{ $name }}M5, {{ $name }}M9, {{ $name }}M13, + {{ $name }}M2, {{ $name }}M6, {{ $name }}M10, {{ $name }}M14, + {{ $name }}M3, {{ $name }}M7, {{ $name }}M11, {{ $name }}M15, + ) + {{- end -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{- define "fuzzcorpus" -}} +f.Add( +{{ range $i, $param := .Params -}} + {{- range $j, $name := .Names -}} + {{- if eq $param.TypeName "Vector2" -}} + float32(1), float32(2), + {{ else if eq $param.TypeName "Vector3" -}} + float32(1), float32(2), float32(3), + {{ else if eq $param.TypeName "Vector4" -}} + float32(1), float32(2), float32(3), float32(4), + {{ else if eq $param.TypeName "Quaternion" -}} + float32(1), float32(2), float32(3), float32(4), + {{ else if eq $param.TypeName "Mat2" -}} + float32(1), float32(2), float32(3), float32(4), + {{ else if eq $param.TypeName "Matrix" -}} + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + {{ else -}} + float32({{ add $j 1 }}), + {{ end -}} + {{- end -}} +{{- end -}} +) +{{- end -}} + +{{- define "quickvars" -}} +{{- range $i, $param := .Params -}} + {{- range $j, $name := .Names }} + {{ testvar $name }} := {{ if eq $param.TypeName "Vector2" -}} + NewVector2(1, 2) + {{- else if eq $param.TypeName "Vector3" -}} + NewVector3(1, 2, 3) + {{- else if eq $param.TypeName "Vector4" -}} + NewVector4(1, 2, 3, 4) + {{- else if eq $param.TypeName "Quaternion" -}} + NewQuaternion(1, 2, 3, 4) + {{- else if eq $param.TypeName "Mat2" -}} + NewMat2(1, 2, 3, 4) + {{- else if eq $param.TypeName "Matrix" -}} + NewMatrix(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4) + {{- else -}} + float32({{ add $j 1 }}) + {{- end -}} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/raylib/internal/cmd/genraymath/main.go b/raylib/internal/cmd/genraymath/main.go new file mode 100644 index 00000000..868e8d18 --- /dev/null +++ b/raylib/internal/cmd/genraymath/main.go @@ -0,0 +1,447 @@ +package main + +import ( + "bytes" + "cmp" + "embed" + "errors" + "flag" + "fmt" + "go/ast" + "go/format" + "go/parser" + "go/token" + "log" + "os" + "os/exec" + "path/filepath" + "slices" + "strings" + "text/template" + "unicode" + "unicode/utf8" +) + +var ( + //go:embed *.tmpl + templatesFS embed.FS +) + +var ( + // don't generate tests or bindings for these functions + skipTestAndBinding = []string{ + // not in raymath.h + "Mat2MultiplyVector2", + "Mat2Radians", + "Mat2Transpose", + "MatrixNormalize", + "Mat2Set", + + "Vector2Cross", // alias for Vector2CrossProduct + "Vector2LenSqr", // alias for Vector2LengthSqr + "MatrixToFloat", // MatrixToFloatV tested + "Vector3ToFloat", // Vector3ToFloatV tested + } + + // these functions are tested manually + skipTest = []string{ + // pointer params makes code gen more complicated - simpler just to write manually for now + "Vector3OrthoNormalize", + "QuaternionToAxisAngle", + "MatrixDecompose", + } + + // fuzz testing these functions is flakey unless the test precision is lowered + lowPrecision = []string{ + "Vector3RotateByAxisAngle", + "Vector2Rotate", + } + + // the C versions of these functions use double params instead of floats + useDouble = []string{ + "MatrixFrustum", + "MatrixPerspective", + "MatrixOrtho", + } +) + +func main() { + if err := run(); err != nil { + fmt.Fprintf(os.Stderr, "error: %v\n", err) + os.Exit(1) + } +} + +func run() error { + var ( + goSrc = flag.String("src", "raymath.go", "path to raylib-go's raymath.go") + shouldFormat = flag.Bool("format", true, "run Go formatter on output") + inlineMethods = flag.Bool("inline-methods", false, "inline function bodies when generating methods") + + skipGenTests = flag.Bool("skip-tests", false, "don't generate tests or bindings") + skipGenMethods = flag.Bool("skip-methods", true, "don't generate methods") + + fuzzTime = flag.Duration("fuzztime", 0, "run fuzz tests for given time after generating") + fuzzFrom = flag.String("fuzzfrom", "", "resume fuzzing from given function name") + fuzzContinue = flag.Bool("fuzzcontinue", false, "don't exit on fuzz test error") + ) + flag.Parse() + + if *fuzzTime > 0 { + *skipGenTests = true + *skipGenMethods = true + } + + t := template.New("") + t.Funcs(template.FuncMap{ + "add": func(a, b int) int { return a + b }, + "testvar": func(name string) string { + switch name { + // make sure these variable names aren't used for tests/fuzzing/benchmarks + case "b", "t", "f": + return name + "1" + default: + return name + } + }, + }) + templates, err := t.ParseFS(templatesFS, "*.tmpl") + if err != nil { + return err + } + + data, err := os.ReadFile(*goSrc) + if err != nil { + return err + } + fset := token.NewFileSet() + file, err := parser.ParseFile(fset, *goSrc, data, parser.SkipObjectResolution|parser.ParseComments) + if err != nil { + return err + } + var funcs []funcInfo + ast.Inspect(file, func(n ast.Node) bool { + fn, ok := n.(*ast.FuncDecl) + if !ok { + return true + } + t, err := parseFunc(fn, fset, *inlineMethods) + if err != nil { + if !errors.Is(err, errSkip) { + log.Printf("%s: %v", fn.Name, err) + } + return false + } + funcs = append(funcs, t) + return false + }) + slices.SortFunc(funcs, func(a, b funcInfo) int { + return cmp.Compare(a.Name, b.Name) + }) + + var outputs []*output + if !*skipGenTests { + outputs = append(outputs, + &output{name: "binding.go"}, // C bindings can't live in the test unfortunately + &output{name: "test.go"}, + ) + } + if !*skipGenMethods { + outputs = append(outputs, + &output{name: "methods.go"}, + ) + } + for _, v := range outputs { + var buf bytes.Buffer + err := templates.ExecuteTemplate(&buf, v.name+".tmpl", funcs) + if err != nil { + return err + } + v.data = buf.Bytes() + if *shouldFormat { + v.data, err = format.Source(v.data) + if err != nil { + return err + } + } + } + + // only write once we're sure the output data is good + for _, v := range outputs { + name := "raymath_generated_" + v.name + path := filepath.Join(filepath.Dir(*goSrc), name) + err = os.WriteFile(path, v.data, 0600) + if err != nil { + return err + } + } + + if *fuzzTime <= 0 { + return nil + } + + // helper for running all the fuzz tests + var total int + for _, fn := range funcs { + if fn.SkipTest || len(fn.Params) == 0 { + continue + } + total++ + } + var failed []string + ok := *fuzzFrom == "" + var n int + for _, fn := range funcs { + if fn.SkipTest || len(fn.Params) == 0 { + continue + } + n++ + if ok || fn.Name == *fuzzFrom { + ok = true + } else { + continue + } + log.Printf("running fuzz test %d/%d for %q", n, total, fn.Name) + testName := "^Fuzz" + fn.Name + "$" + cmd := exec.Command("go", "test", + "-run", testName, + "-fuzz", testName, + "-fuzztime", (*fuzzTime).String(), + ) + cmd.Stderr = os.Stderr + cmd.Stdout = os.Stdout + cmd.Dir = filepath.Dir(*goSrc) + err := cmd.Run() + if err != nil { + if !*fuzzContinue { + return err + } + failed = append(failed, fn.Name) + } + } + if len(failed) != 0 { + log.Println(failed) + return errors.New("failed") + } + return nil +} + +type output struct { + name string + data []byte +} + +var errSkip = errors.New("skip") + +func parseFunc(fn *ast.FuncDecl, fset *token.FileSet, inlineMethods bool) (funcInfo, error) { + var ret funcInfo + + if !fn.Name.IsExported() { + return ret, errSkip + } + + ret.Name = fn.Name.Name + if slices.Contains(skipTestAndBinding, ret.Name) { + ret.SkipBinding = true + ret.SkipTest = true + } + if slices.Contains(skipTest, ret.Name) { + ret.SkipTest = true + } + + if fn.Type.Params != nil { + for _, v := range fn.Type.Params.List { + typeName, ok := exprString(v.Type) + if !ok { + return ret, fmt.Errorf("invalid param type: %#v", v.Type) + } + if !ret.SkipTest && strings.HasPrefix(typeName, "*") { + log.Printf("skipping %q with pointer param", ret.Name) + ret.SkipTest = true + } + names := make([]string, 0, len(v.Names)) + for _, name := range v.Names { + names = append(names, name.Name) + } + ret.Params = append(ret.Params, param{ + Names: names, + TypeName: typeName, + UseDouble: typeName == "float32" && slices.Contains(useDouble, fn.Name.Name), + }) + } + } + if fn.Type.Results != nil { + if len(fn.Type.Results.List) > 1 { + return ret, fmt.Errorf("invalid number of results: %v", len(fn.Type.Results.List)) + } + v := fn.Type.Results.List[0] + typeName, ok := exprString(v.Type) + if !ok { + return ret, fmt.Errorf("invalid result type: %#v", v.Type) + } + if !ret.SkipTest && strings.HasPrefix(typeName, "*") { + log.Printf("skipping %q with pointer return type", ret.Name) + ret.SkipTest = true + } + ret.ReturnType = typeName + } + if ret.SkipBinding { + ret.SkipTest = true + } + + if fn.Doc != nil { + ret.Comments = make([]string, 0, len(fn.Doc.List)) + for _, v := range fn.Doc.List { + text := v.Text + if ret.CanBeMethod() { + text = strings.ReplaceAll(text, ret.Name, ret.MethodName()) + } + ret.Comments = append(ret.Comments, text) + } + } + if inlineMethods && ret.CanBeMethod() { + // rename first parameter + ast.Inspect(fn.Body, func(n ast.Node) bool { + ident, ok := n.(*ast.Ident) + if !ok { + return true + } + if ident.Name == ret.Params[0].Names[0] { + ident.Name = ret.Self() + } + return true + }) + + var buf bytes.Buffer + // some comments are missing but oh well + err := format.Node(&buf, fset, fn.Body) + if err != nil { + return ret, err + } + ret.Body = buf.String() + } + return ret, nil +} + +type funcInfo struct { + Name string + Params []param + ReturnType string + Comments []string + SkipTest bool + SkipBinding bool + Body string +} + +func (f funcInfo) CanBeMethod() bool { + if len(f.Params) == 0 { + return false + } + return strings.HasPrefix(f.Name, f.Params[0].TypeName) +} + +func (f funcInfo) Self() string { + return strings.ToLower(string(f.Name[0])) +} + +func (f funcInfo) Struct() string { + return f.Params[0].TypeName +} + +func (f funcInfo) MethodName() string { + return strings.TrimPrefix(f.Name, f.Params[0].TypeName) +} + +func (f funcInfo) ReturnValue() string { + t := f.ReturnType + switch t { + case "float32": + return "float32(ret)" + case "bool": + return "ret != 0" + default: + return "*(*" + t + ")(unsafe.Pointer(&ret))" + } +} + +func (f funcInfo) TestNotEqual(a, b string) string { + t := f.ReturnType + if t == "bool" { + return a + " != " + b + } + + rightBracketIndex := strings.IndexRune(t, ']') + if rightBracketIndex != -1 { // slice or array + t = t[rightBracketIndex+1:] + "Slice" + if rightBracketIndex != 1 { // array + a += "[:]" + b += "[:]" + } + } + + prec := 6 + if slices.Contains(lowPrecision, f.Name) { + prec = 2 + } + + first, size := utf8.DecodeRuneInString(t) + t = string(unicode.ToUpper(first)) + t[size:] + return fmt.Sprintf("!test%sEquals(%s, %s, 1e-%d)", t, a, b, prec) +} + +type param struct { + Names []string + TypeName string + UseDouble bool +} + +func (p param) CType(arg string) string { + name := p.TypeName + if p.UseDouble { + name = "float64" + } + name, isPointer := strings.CutPrefix(name, "*") + + var cname string + switch name { + case "float32": + cname = "float" + case "float64": + cname = "double" + default: + if isPointer { + return "(*C." + name + ")(unsafe.Pointer(" + arg + "))" + } + return "*(*C." + name + ")(unsafe.Pointer(&" + arg + "))" + } + + if isPointer { + return "(*C." + cname + ")(" + arg + ")" + } + return "C." + cname + "(" + arg + ")" +} + +func exprString(expr ast.Expr) (string, bool) { + switch t := expr.(type) { + case *ast.Ident: + return t.Name, true + case *ast.ArrayType: + s, ok := exprString(t.Elt) + if !ok { + return "", false + } + var length string + if lit, ok := t.Len.(*ast.BasicLit); ok { + length = lit.Value + } + return "[" + length + "]" + s, true + case *ast.StarExpr: + s, ok := exprString(t.X) + if !ok { + return "", false + } + return "*" + s, true + default: + return "", false + } +} diff --git a/raylib/internal/cmd/genraymath/methods.go.tmpl b/raylib/internal/cmd/genraymath/methods.go.tmpl new file mode 100644 index 00000000..04e114f5 --- /dev/null +++ b/raylib/internal/cmd/genraymath/methods.go.tmpl @@ -0,0 +1,25 @@ +// Code generated by ./internal/cmd/genraymath DO NOT EDIT. + +package rl + +{{ range . -}} + {{ if .Body -}} + import ( + "math" + ) + {{ break }} + {{- end -}} +{{- end }} + +{{ range . -}} +{{- if not .CanBeMethod }}{{ continue }}{{ end }} +{{- range .Comments -}} +{{ . }} +{{ end -}} +func ({{ .Self }} {{ .Struct }}) {{ .MethodName }}({{ template "methodparams" . }}) {{ .ReturnType }}{{ if .Body }}{{ .Body }} + +{{ else }} { + {{ if .ReturnType }}return {{ end }}{{ .Name }}({{ .Self }}{{ template "methodargs" . }}) +} +{{ end -}} +{{- end -}} diff --git a/raylib/internal/cmd/genraymath/test.go.tmpl b/raylib/internal/cmd/genraymath/test.go.tmpl new file mode 100644 index 00000000..bba242d0 --- /dev/null +++ b/raylib/internal/cmd/genraymath/test.go.tmpl @@ -0,0 +1,122 @@ +// Code generated by ./internal/cmd/genraymath DO NOT EDIT. + +package rl + +import ( + "math" + "testing" + "time" +) + + +{{ range . -}} +{{ if .SkipTest }}{{ continue }}{{ end }} +func Benchmark{{ .Name }}(b *testing.B) { + {{- template "quickvars" . }} + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + c{{.Name}}({{ template "testargs" . }}) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + {{.Name}}({{ template "testargs" . }}) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +{{if .Params -}} +func Fuzz{{ .Name }}(f *testing.F) { + {{ template "fuzzcorpus" . }} + f.Fuzz(func(t *testing.T, {{ template "fuzzparams" . }}) { + {{- template "fuzzvars" . }} + want := c{{.Name}}({{ template "testargs" . }}) + got := {{.Name}}({{ template "testargs" . }}) + if {{ .TestNotEqual "want" "got" }} { + t.Errorf("got %v; want %v", got, want) + } + }) +} +{{ else }} +func Test{{ .Name }}(t *testing.T) { + want := c{{.Name}}() + got := {{.Name}}() + if {{ .TestNotEqual "want" "got" }} { + t.Errorf("got %v; want %v", got, want) + } +} +{{ end -}} +{{ end }} + +// helpers + +func testFloat32Equals(a, b float32, epsilon float64) bool { + if math.IsNaN(float64(a)) && math.IsNaN(float64(b)) { + return true + } + if math.IsInf(float64(a), 1) && math.IsInf(float64(b), 1) { + return true + } + if math.IsInf(float64(a), -1) && math.IsInf(float64(b), -1) { + return true + } + return math.Abs(float64(a-b)) <= epsilon*math.Max(1.0, math.Max(math.Abs(float64(a)), math.Abs(float64(b)))) +} + +func testFloat32SliceEquals(a, b []float32, epsilon float64) bool { + if len(a) != len(b) { + return false + } + for i := range a { + if !testFloat32Equals(a[i], b[i], epsilon) { + return false + } + } + return true +} + +func testVector2Equals(a, b Vector2, epsilon float64) bool { + return testFloat32Equals(a.X, b.X, epsilon) && + testFloat32Equals(a.Y, b.Y, epsilon) +} + +func testVector3Equals(a, b Vector3, epsilon float64) bool { + return testFloat32Equals(a.X, b.X, epsilon) && + testFloat32Equals(a.Y, b.Y, epsilon) && + testFloat32Equals(a.Z, b.Z, epsilon) +} + +func testQuaternionEquals(a, b Quaternion, epsilon float64) bool { + return testFloat32Equals(a.X, b.X, epsilon) && + testFloat32Equals(a.Y, b.Y, epsilon) && + testFloat32Equals(a.Z, b.Z, epsilon) && + testFloat32Equals(a.W, b.W, epsilon) +} + +func testMatrixEquals(a, b Matrix, epsilon float64) bool { + return testFloat32Equals(a.M0, b.M0, epsilon) && + testFloat32Equals(a.M1, b.M1, epsilon) && + testFloat32Equals(a.M2, b.M2, epsilon) && + testFloat32Equals(a.M3, b.M3, epsilon) && + testFloat32Equals(a.M4, b.M4, epsilon) && + testFloat32Equals(a.M5, b.M5, epsilon) && + testFloat32Equals(a.M6, b.M6, epsilon) && + testFloat32Equals(a.M7, b.M7, epsilon) && + testFloat32Equals(a.M8, b.M8, epsilon) && + testFloat32Equals(a.M9, b.M9, epsilon) && + testFloat32Equals(a.M10, b.M10, epsilon) && + testFloat32Equals(a.M11, b.M11, epsilon) && + testFloat32Equals(a.M12, b.M12, epsilon) && + testFloat32Equals(a.M13, b.M13, epsilon) && + testFloat32Equals(a.M14, b.M14, epsilon) && + testFloat32Equals(a.M15, b.M15, epsilon) +} diff --git a/raylib/raymath.go b/raylib/raymath.go index e0aefc68..6cbbbe15 100644 --- a/raylib/raymath.go +++ b/raylib/raymath.go @@ -1,9 +1,12 @@ +//go:generate go run ./internal/cmd/genraymath package rl import ( "math" ) +const epsilon = 1e-6 + // Clamp - Clamp float value func Clamp(value, min, max float32) float32 { var res float32 @@ -42,7 +45,7 @@ func Wrap(value, min, max float32) float32 { // FloatEquals - Check whether two given floats are almost equal func FloatEquals(x, y float32) bool { - return (math.Abs(float64(x-y)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(x)), math.Abs(float64(y))))) + return (math.Abs(float64(x-y)) <= epsilon*math.Max(1.0, math.Max(math.Abs(float64(x)), math.Abs(float64(y))))) } // Vector2Zero - Vector with components value 0.0 @@ -101,10 +104,13 @@ func Vector2DistanceSqr(v1 Vector2, v2 Vector2) float32 { } // Vector2Angle - Calculate angle from two vectors in radians +// NOTE: Coordinate system convention: positive X right, positive Y down, +// positive angles appear clockwise, and negative angles appear counterclockwise func Vector2Angle(v1, v2 Vector2) float32 { - result := math.Atan2(float64(v2.Y), float64(v2.X)) - math.Atan2(float64(v1.Y), float64(v1.X)) + dot := v1.X*v2.X + v1.Y*v2.Y + det := v1.X*v2.Y - v1.Y*v2.X - return float32(result) + return float32(math.Atan2(float64(det), float64(dot))) } // Vector2LineAngle - Calculate angle defined by a two vectors line @@ -176,8 +182,7 @@ func Vector2Reflect(v Vector2, normal Vector2) Vector2 { func Vector2Rotate(v Vector2, angle float32) Vector2 { var result = Vector2{} - cosres := float32(math.Cos(float64(angle))) - sinres := float32(math.Sin(float64(angle))) + sinres, cosres := sincos(angle) result.X = v.X*cosres - v.Y*sinres result.Y = v.X*sinres + v.Y*cosres @@ -244,8 +249,8 @@ func Vector2ClampValue(v Vector2, min float32, max float32) Vector2 { // Vector2Equals - Check whether two given vectors are almost equal func Vector2Equals(p Vector2, q Vector2) bool { - return (math.Abs(float64(p.X-q.X)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.X)), math.Abs(float64(q.X)))) && - math.Abs(float64(p.Y-q.Y)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.Y)), math.Abs(float64(q.Y))))) + return (math.Abs(float64(p.X-q.X)) <= epsilon*math.Max(1.0, math.Max(math.Abs(float64(p.X)), math.Abs(float64(q.X)))) && + math.Abs(float64(p.Y-q.Y)) <= epsilon*math.Max(1.0, math.Max(math.Abs(float64(p.Y)), math.Abs(float64(q.Y))))) } // Vector2CrossProduct - Calculate two vectors cross product @@ -258,11 +263,6 @@ func Vector2Cross(value float32, vector Vector2) Vector2 { return NewVector2(-value*vector.Y, value*vector.X) } -// Vector2LenSqr - Returns the len square root of a vector -func Vector2LenSqr(vector Vector2) float32 { - return vector.X*vector.X + vector.Y*vector.Y -} - // Vector3Zero - Vector with components value 0.0 func Vector3Zero() Vector3 { return NewVector3(0.0, 0.0, 0.0) @@ -454,10 +454,10 @@ func Vector3Reject(v1, v2 Vector3) Vector3 { // Makes vectors normalized and orthogonal to each other // Gram-Schmidt function implementation func Vector3OrthoNormalize(v1, v2 *Vector3) { - Vector3Normalize(*v1) + *v1 = Vector3Normalize(*v1) vn1 := Vector3CrossProduct(*v1, *v2) - Vector3Normalize(vn1) + vn1 = Vector3Normalize(vn1) vn2 := Vector3CrossProduct(vn1, *v1) *v2 = vn2 @@ -709,6 +709,12 @@ func Vector3Unproject(source Vector3, projection Matrix, view Matrix) Vector3 { return result } +// Vector3ToFloat - Converts Vector3 to float32 slice +func Vector3ToFloat(vec Vector3) []float32 { + data := Vector3ToFloatV(vec) + return data[:] +} + // Vector3ToFloatV - Get Vector3 as float array func Vector3ToFloatV(v Vector3) [3]float32 { var result [3]float32 @@ -762,9 +768,9 @@ func Vector3ClampValue(v Vector3, min float32, max float32) Vector3 { // Vector3Equals - Check whether two given vectors are almost equal func Vector3Equals(p Vector3, q Vector3) bool { - return (math.Abs(float64(p.X-q.X)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.X)), math.Abs(float64(q.X)))) && - math.Abs(float64(p.Y-q.Y)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.Y)), math.Abs(float64(q.Y)))) && - math.Abs(float64(p.Z-q.Z)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.Z)), math.Abs(float64(q.Z))))) + return (math.Abs(float64(p.X-q.X)) <= epsilon*math.Max(1.0, math.Max(math.Abs(float64(p.X)), math.Abs(float64(q.X)))) && + math.Abs(float64(p.Y-q.Y)) <= epsilon*math.Max(1.0, math.Max(math.Abs(float64(p.Y)), math.Abs(float64(q.Y)))) && + math.Abs(float64(p.Z-q.Z)) <= epsilon*math.Max(1.0, math.Max(math.Abs(float64(p.Z)), math.Abs(float64(q.Z))))) } // Vector3Refract - Compute the direction of a refracted ray @@ -792,16 +798,14 @@ func Vector3Refract(v Vector3, n Vector3, r float32) Vector3 { // Mat2Radians - Creates a matrix 2x2 from a given radians value func Mat2Radians(radians float32) Mat2 { - c := float32(math.Cos(float64(radians))) - s := float32(math.Sin(float64(radians))) + s, c := sincos(radians) return NewMat2(c, -s, s, c) } // Mat2Set - Set values from radians to a created matrix 2x2 func Mat2Set(matrix *Mat2, radians float32) { - cos := float32(math.Cos(float64(radians))) - sin := float32(math.Sin(float64(radians))) + sin, cos := sincos(radians) matrix.M00 = cos matrix.M01 = -sin @@ -821,33 +825,27 @@ func Mat2MultiplyVector2(matrix Mat2, vector Vector2) Vector2 { // MatrixDeterminant - Compute matrix determinant func MatrixDeterminant(mat Matrix) float32 { - var result float32 - - a00 := mat.M0 - a01 := mat.M1 - a02 := mat.M2 - a03 := mat.M3 - a10 := mat.M4 - a11 := mat.M5 - a12 := mat.M6 - a13 := mat.M7 - a20 := mat.M8 - a21 := mat.M9 - a22 := mat.M10 - a23 := mat.M11 - a30 := mat.M12 - a31 := mat.M13 - a32 := mat.M14 - a33 := mat.M15 - - result = a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 + - a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 + - a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 + - a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 + - a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 + - a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33 - - return result + m0 := mat.M0 + m1 := mat.M1 + m2 := mat.M2 + m3 := mat.M3 + m4 := mat.M4 + m5 := mat.M5 + m6 := mat.M6 + m7 := mat.M7 + m8 := mat.M8 + m9 := mat.M9 + m10 := mat.M10 + m11 := mat.M11 + m12 := mat.M12 + m13 := mat.M13 + m14 := mat.M14 + m15 := mat.M15 + + return (m0*(m5*(m10*m15-m11*m14)-m9*(m6*m15-m7*m14)+m13*(m6*m11-m7*m10)) - + m4*(m1*(m10*m15-m11*m14)-m9*(m2*m15-m3*m14)+m13*(m2*m11-m3*m10)) + + m8*(m1*(m6*m15-m7*m14)-m5*(m2*m15-m3*m14)+m13*(m2*m7-m3*m6)) - + m12*(m1*(m6*m11-m7*m10)-m5*(m2*m11-m3*m10)+m9*(m2*m7-m3*m6))) } // MatrixTrace - Returns the trace of the matrix (sum of the values along the diagonal) @@ -1071,8 +1069,7 @@ func MatrixRotate(axis Vector3, angle float32) Matrix { z *= length } - sinres := float32(math.Sin(float64(angle))) - cosres := float32(math.Cos(float64(angle))) + sinres, cosres := sincos(angle) t := 1.0 - cosres // Cache some matrix values (speed optimization) @@ -1125,12 +1122,11 @@ func MatrixRotate(axis Vector3, angle float32) Matrix { func MatrixRotateX(angle float32) Matrix { result := MatrixIdentity() - cosres := float32(math.Cos(float64(angle))) - sinres := float32(math.Sin(float64(angle))) + sinres, cosres := sincos(angle) result.M5 = cosres - result.M6 = -sinres - result.M9 = sinres + result.M6 = sinres + result.M9 = -sinres result.M10 = cosres return result @@ -1140,12 +1136,11 @@ func MatrixRotateX(angle float32) Matrix { func MatrixRotateY(angle float32) Matrix { result := MatrixIdentity() - cosres := float32(math.Cos(float64(angle))) - sinres := float32(math.Sin(float64(angle))) + sinres, cosres := sincos(angle) result.M0 = cosres - result.M2 = sinres - result.M8 = -sinres + result.M2 = -sinres + result.M8 = sinres result.M10 = cosres return result @@ -1155,38 +1150,34 @@ func MatrixRotateY(angle float32) Matrix { func MatrixRotateZ(angle float32) Matrix { result := MatrixIdentity() - cosres := float32(math.Cos(float64(angle))) - sinres := float32(math.Sin(float64(angle))) + sinres, cosres := sincos(angle) result.M0 = cosres - result.M1 = -sinres - result.M4 = sinres + result.M1 = sinres + result.M4 = -sinres result.M5 = cosres return result } // MatrixRotateXYZ - Get xyz-rotation matrix (angles in radians) -func MatrixRotateXYZ(ang Vector3) Matrix { +func MatrixRotateXYZ(angle Vector3) Matrix { result := MatrixIdentity() - cosz := float32(math.Cos(float64(-ang.Z))) - sinz := float32(math.Sin(float64(-ang.Z))) - cosy := float32(math.Cos(float64(-ang.Y))) - siny := float32(math.Sin(float64(-ang.Y))) - cosx := float32(math.Cos(float64(-ang.X))) - sinx := float32(math.Sin(float64(-ang.X))) + sinz, cosz := sincos(-angle.Z) + siny, cosy := sincos(-angle.Y) + sinx, cosx := sincos(-angle.X) result.M0 = cosz * cosy - result.M4 = (cosz * siny * sinx) - (sinz * cosx) - result.M8 = (cosz * siny * cosx) + (sinz * sinx) + result.M1 = (cosz * siny * sinx) - (sinz * cosx) + result.M2 = (cosz * siny * cosx) + (sinz * sinx) - result.M1 = sinz * cosy + result.M4 = sinz * cosy result.M5 = (sinz * siny * sinx) + (cosz * cosx) - result.M9 = (sinz * siny * cosx) - (cosz * sinx) + result.M6 = (sinz * siny * cosx) - (cosz * sinx) - result.M2 = -siny - result.M6 = cosy * sinx + result.M8 = -siny + result.M9 = cosy * sinx result.M10 = cosy * cosx return result @@ -1197,12 +1188,9 @@ func MatrixRotateXYZ(ang Vector3) Matrix { func MatrixRotateZYX(angle Vector3) Matrix { var result = Matrix{} - var cz = float32(math.Cos(float64(angle.Z))) - var sz = float32(math.Sin(float64(angle.Z))) - var cy = float32(math.Cos(float64(angle.Y))) - var sy = float32(math.Sin(float64(angle.Y))) - var cx = float32(math.Cos(float64(angle.X))) - var sx = float32(math.Sin(float64(angle.X))) + sz, cz := sincos(angle.Z) + sy, cy := sincos(angle.Y) + sx, cx := sincos(angle.X) result.M0 = cz * cy result.M4 = cz*sy*sx - cx*sz @@ -1239,42 +1227,60 @@ func MatrixScale(x, y, z float32) Matrix { } // MatrixFrustum - Returns perspective projection matrix -func MatrixFrustum(left, right, bottom, top, near, far float32) Matrix { +func MatrixFrustum(left, right, bottom, top, nearPlane, farPlane float32) Matrix { var result Matrix rl := right - left tb := top - bottom - fn := far - near + fn := farPlane - nearPlane - result.M0 = (near * 2.0) / rl + result.M0 = (nearPlane * 2.0) / rl result.M1 = 0.0 result.M2 = 0.0 result.M3 = 0.0 result.M4 = 0.0 - result.M5 = (near * 2.0) / tb + result.M5 = (nearPlane * 2.0) / tb result.M6 = 0.0 result.M7 = 0.0 - result.M8 = right + left/rl - result.M9 = top + bottom/tb - result.M10 = -(far + near) / fn + result.M8 = (right + left) / rl + result.M9 = (top + bottom) / tb + result.M10 = -(farPlane + nearPlane) / fn result.M11 = -1.0 result.M12 = 0.0 result.M13 = 0.0 - result.M14 = -(far * near * 2.0) / fn + result.M14 = -(farPlane * nearPlane * 2.0) / fn result.M15 = 0.0 return result } // MatrixPerspective - Returns perspective projection matrix -func MatrixPerspective(fovy, aspect, near, far float32) Matrix { - top := near * float32(math.Tan(float64(fovy*Pi)/360.0)) +// NOTE: Fovy angle must be provided in radians +func MatrixPerspective(fovY, aspect, nearPlane, farPlane float32) Matrix { + var result Matrix + + top := nearPlane * float32(math.Tan(float64(fovY)*0.5)) + bottom := -top right := top * aspect + left := -right + + // MatrixFrustum(-right, right, -top, top, near, far); + rl := float32(right - left) + tb := float32(top - bottom) + fn := float32(farPlane - nearPlane) + + result.M0 = (nearPlane * 2.0) / rl + result.M5 = (nearPlane * 2.0) / tb + result.M8 = (right + left) / rl + result.M9 = (top + bottom) / tb + result.M10 = -(farPlane + nearPlane) / fn + result.M11 = -1.0 + result.M14 = -(farPlane * nearPlane * 2.0) / fn - return MatrixFrustum(-right, right, -top, top, near, far) + return result } // MatrixOrtho - Returns orthographic projection matrix @@ -1309,29 +1315,28 @@ func MatrixOrtho(left, right, bottom, top, near, far float32) Matrix { func MatrixLookAt(eye, target, up Vector3) Matrix { var result Matrix - z := Vector3Subtract(eye, target) - z = Vector3Normalize(z) - x := Vector3CrossProduct(up, z) - x = Vector3Normalize(x) - y := Vector3CrossProduct(z, x) - y = Vector3Normalize(y) - - result.M0 = x.X - result.M1 = x.Y - result.M2 = x.Z - result.M3 = -((x.X * eye.X) + (x.Y * eye.Y) + (x.Z * eye.Z)) - result.M4 = y.X - result.M5 = y.Y - result.M6 = y.Z - result.M7 = -((y.X * eye.X) + (y.Y * eye.Y) + (y.Z * eye.Z)) - result.M8 = z.X - result.M9 = z.Y - result.M10 = z.Z - result.M11 = -((z.X * eye.X) + (z.Y * eye.Y) + (z.Z * eye.Z)) - result.M12 = 0.0 - result.M13 = 0.0 - result.M14 = 0.0 - result.M15 = 1.0 + vz := Vector3Subtract(eye, target) + vz = Vector3Normalize(vz) + vx := Vector3CrossProduct(up, vz) + vx = Vector3Normalize(vx) + vy := Vector3CrossProduct(vz, vx) + + result.M0 = vx.X + result.M1 = vy.X + result.M2 = vz.X + result.M3 = 0 + result.M4 = vx.Y + result.M5 = vy.Y + result.M6 = vz.Y + result.M7 = 0 + result.M8 = vx.Z + result.M9 = vy.Z + result.M10 = vz.Z + result.M11 = 0 + result.M12 = -Vector3DotProduct(vx, eye) + result.M13 = -Vector3DotProduct(vy, eye) + result.M14 = -Vector3DotProduct(vz, eye) + result.M15 = 1 return result } @@ -1503,48 +1508,59 @@ func QuaternionNlerp(q1 Quaternion, q2 Quaternion, amount float32) Quaternion { result.Z = q1.Z + amount*(q2.Z-q1.Z) result.W = q1.W + amount*(q2.W-q1.W) - // QuaternionNormalize(q); - q := result - length := float32(math.Sqrt(float64(q.X*q.X + q.Y*q.Y + q.Z*q.Z + q.W*q.W))) + // QuaternionNormalize(r); + r := result + length := float32(math.Sqrt(float64(r.X*r.X + r.Y*r.Y + r.Z*r.Z + r.W*r.W))) if length == 0.0 { length = 1.0 } ilength := 1.0 / length - result.X = q.X * ilength - result.Y = q.Y * ilength - result.Z = q.Z * ilength - result.W = q.W * ilength + result.X = r.X * ilength + result.Y = r.Y * ilength + result.Z = r.Z * ilength + result.W = r.W * ilength return result } // QuaternionSlerp - Calculates spherical linear interpolation between two quaternions func QuaternionSlerp(q1, q2 Quaternion, amount float32) Quaternion { - var result Quaternion - cosHalfTheta := q1.X*q2.X + q1.Y*q2.Y + q1.Z*q2.Z + q1.W*q2.W + if cosHalfTheta < 0 { + q2.X = -q2.X + q2.Y = -q2.Y + q2.Z = -q2.Z + q2.W = -q2.W + cosHalfTheta = -cosHalfTheta + } + if math.Abs(float64(cosHalfTheta)) >= 1.0 { - result = q1 + return q1 + } + if cosHalfTheta > 0.95 { + return QuaternionNlerp(q1, q2, amount) + } + + var result Quaternion + + halfTheta := float32(math.Acos(float64(cosHalfTheta))) + sinHalfTheta := float32(math.Sqrt(float64(1.0 - cosHalfTheta*cosHalfTheta))) + + if math.Abs(float64(sinHalfTheta)) < epsilon { + result.X = (q1.X*0.5 + q2.X*0.5) + result.Y = (q1.Y*0.5 + q2.Y*0.5) + result.Z = (q1.Z*0.5 + q2.Z*0.5) + result.W = (q1.W*0.5 + q2.W*0.5) } else { - halfTheta := float32(math.Acos(float64(cosHalfTheta))) - sinHalfTheta := float32(math.Sqrt(float64(1.0 - cosHalfTheta*cosHalfTheta))) - - if math.Abs(float64(sinHalfTheta)) < 0.001 { - result.X = q1.X*0.5 + q2.X*0.5 - result.Y = q1.Y*0.5 + q2.Y*0.5 - result.Z = q1.Z*0.5 + q2.Z*0.5 - result.W = q1.W*0.5 + q2.W*0.5 - } else { - ratioA := float32(math.Sin(float64((1-amount)*halfTheta))) / sinHalfTheta - ratioB := float32(math.Sin(float64(amount*halfTheta))) / sinHalfTheta - - result.X = q1.X*ratioA + q2.X*ratioB - result.Y = q1.Y*ratioA + q2.Y*ratioB - result.Z = q1.Z*ratioA + q2.Z*ratioB - result.W = q1.W*ratioA + q2.W*ratioB - } + ratioA := float32(math.Sin(float64((1-amount)*halfTheta))) / sinHalfTheta + ratioB := float32(math.Sin(float64(amount*halfTheta))) / sinHalfTheta + + result.X = (q1.X*ratioA + q2.X*ratioB) + result.Y = (q1.Y*ratioA + q2.Y*ratioB) + result.Z = (q1.Z*ratioA + q2.Z*ratioB) + result.W = (q1.W*ratioA + q2.W*ratioB) } return result @@ -1580,49 +1596,55 @@ func QuaternionFromVector3ToVector3(from Vector3, to Vector3) Quaternion { } // QuaternionFromMatrix - Returns a quaternion for a given rotation matrix -func QuaternionFromMatrix(matrix Matrix) Quaternion { +func QuaternionFromMatrix(mat Matrix) Quaternion { var result Quaternion - trace := MatrixTrace(matrix) + fourWSquaredMinus1 := mat.M0 + mat.M5 + mat.M10 + fourXSquaredMinus1 := mat.M0 - mat.M5 - mat.M10 + fourYSquaredMinus1 := mat.M5 - mat.M0 - mat.M10 + fourZSquaredMinus1 := mat.M10 - mat.M0 - mat.M5 - if trace > 0.0 { - s := float32(math.Sqrt(float64(trace+1)) * 2.0) - invS := 1.0 / s + biggestIndex := 0 + fourBiggestSquaredMinus1 := fourWSquaredMinus1 + if fourXSquaredMinus1 > fourBiggestSquaredMinus1 { + fourBiggestSquaredMinus1 = fourXSquaredMinus1 + biggestIndex = 1 + } - result.W = s * 0.25 - result.X = (matrix.M6 - matrix.M9) * invS - result.Y = (matrix.M8 - matrix.M2) * invS - result.Z = (matrix.M1 - matrix.M4) * invS - } else { - m00 := matrix.M0 - m11 := matrix.M5 - m22 := matrix.M10 - - if m00 > m11 && m00 > m22 { - s := float32(math.Sqrt(float64(1.0+m00-m11-m22)) * 2.0) - invS := 1.0 / s - - result.W = (matrix.M6 - matrix.M9) * invS - result.X = s * 0.25 - result.Y = (matrix.M4 + matrix.M1) * invS - result.Z = (matrix.M8 + matrix.M2) * invS - } else if m11 > m22 { - s := float32(math.Sqrt(float64(1.0+m11-m00-m22)) * 2.0) - invS := 1.0 / s - - result.W = (matrix.M8 - matrix.M2) * invS - result.X = (matrix.M4 + matrix.M1) * invS - result.Y = s * 0.25 - result.Z = (matrix.M9 + matrix.M6) * invS - } else { - s := float32(math.Sqrt(float64(1.0+m22-m00-m11)) * 2.0) - invS := 1.0 / s - - result.W = (matrix.M1 - matrix.M4) * invS - result.X = (matrix.M8 + matrix.M2) * invS - result.Y = (matrix.M9 + matrix.M6) * invS - result.Z = s * 0.25 - } + if fourYSquaredMinus1 > fourBiggestSquaredMinus1 { + fourBiggestSquaredMinus1 = fourYSquaredMinus1 + biggestIndex = 2 + } + + if fourZSquaredMinus1 > fourBiggestSquaredMinus1 { + fourBiggestSquaredMinus1 = fourZSquaredMinus1 + biggestIndex = 3 + } + + biggestVal := float32(math.Sqrt(float64(fourBiggestSquaredMinus1)+1.0) * 0.5) + mult := 0.25 / biggestVal + + switch biggestIndex { + case 0: + result.W = biggestVal + result.X = (mat.M6 - mat.M9) * mult + result.Y = (mat.M8 - mat.M2) * mult + result.Z = (mat.M1 - mat.M4) * mult + case 1: + result.X = biggestVal + result.W = (mat.M6 - mat.M9) * mult + result.Y = (mat.M1 + mat.M4) * mult + result.Z = (mat.M8 + mat.M2) * mult + case 2: + result.Y = biggestVal + result.W = (mat.M8 - mat.M2) * mult + result.X = (mat.M1 + mat.M4) * mult + result.Z = (mat.M6 + mat.M9) * mult + case 3: + result.Z = biggestVal + result.W = (mat.M1 - mat.M4) * mult + result.X = (mat.M8 + mat.M2) * mult + result.Y = (mat.M6 + mat.M9) * mult } return result @@ -1630,45 +1652,28 @@ func QuaternionFromMatrix(matrix Matrix) Quaternion { // QuaternionToMatrix - Returns a matrix for a given quaternion func QuaternionToMatrix(q Quaternion) Matrix { - var result Matrix - - x := q.X - y := q.Y - z := q.Z - w := q.W - - x2 := x + x - y2 := y + y - z2 := z + z - - xx := x * x2 - xy := x * y2 - xz := x * z2 + result := MatrixIdentity() - yy := y * y2 - yz := y * z2 - zz := z * z2 + a2 := q.X * q.X + b2 := q.Y * q.Y + c2 := q.Z * q.Z + ac := q.X * q.Z + ab := q.X * q.Y + bc := q.Y * q.Z + ad := q.W * q.X + bd := q.W * q.Y + cd := q.W * q.Z + result.M0 = 1 - 2*(b2+c2) + result.M1 = 2 * (ab + cd) + result.M2 = 2 * (ac - bd) - wx := w * x2 - wy := w * y2 - wz := w * z2 + result.M4 = 2 * (ab - cd) + result.M5 = 1 - 2*(a2+c2) + result.M6 = 2 * (bc + ad) - result.M0 = 1.0 - (yy + zz) - result.M1 = xy - wz - result.M2 = xz + wy - result.M3 = 0.0 - result.M4 = xy + wz - result.M5 = 1.0 - (xx + zz) - result.M6 = yz - wx - result.M7 = 0.0 - result.M8 = xz - wy - result.M9 = yz + wx - result.M10 = 1.0 - (xx + yy) - result.M11 = 0.0 - result.M12 = 0.0 - result.M13 = 0.0 - result.M14 = 0.0 - result.M15 = 1.0 + result.M8 = 2 * (ac + bd) + result.M9 = 2 * (bc - ad) + result.M10 = 1 - 2*(a2+b2) return result } @@ -1683,8 +1688,7 @@ func QuaternionFromAxisAngle(axis Vector3, angle float32) Quaternion { axis = Vector3Normalize(axis) - sinres := float32(math.Sin(float64(angle))) - cosres := float32(math.Cos(float64(angle))) + sinres, cosres := sincos(angle) result.X = axis.X * sinres result.Y = axis.Y * sinres @@ -1707,7 +1711,7 @@ func QuaternionToAxisAngle(q Quaternion, outAxis *Vector3, outAngle *float32) { resAngle := 2.0 * float32(math.Acos(float64(q.W))) den := float32(math.Sqrt(float64(1.0 - q.W*q.W))) - if den > 0.0001 { + if den > epsilon { resAxis.X = q.X / den resAxis.Y = q.Y / den resAxis.Z = q.Z / den @@ -1726,12 +1730,9 @@ func QuaternionToAxisAngle(q Quaternion, outAxis *Vector3, outAngle *float32) { func QuaternionFromEuler(pitch, yaw, roll float32) Quaternion { var result Quaternion - x0 := float32(math.Cos(float64(pitch * 0.5))) - x1 := float32(math.Sin(float64(pitch * 0.5))) - y0 := float32(math.Cos(float64(yaw * 0.5))) - y1 := float32(math.Sin(float64(yaw * 0.5))) - z0 := float32(math.Cos(float64(roll * 0.5))) - z1 := float32(math.Sin(float64(roll * 0.5))) + x1, x0 := sincos(pitch * 0.5) + y1, y0 := sincos(yaw * 0.5) + z1, z0 := sincos(roll * 0.5) result.X = x1*y0*z0 - x0*y1*z1 result.Y = x0*y1*z0 + x1*y0*z1 @@ -1782,15 +1783,15 @@ func QuaternionTransform(q Quaternion, mat Matrix) Quaternion { } // QuaternionEquals - Check whether two given quaternions are almost equal -func QuaternionEquals(p, q Quaternion) bool { - return (math.Abs(float64(p.X-q.X)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.X)), math.Abs(float64(q.X)))) && - math.Abs(float64(p.Y-q.Y)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.Y)), math.Abs(float64(q.Y)))) && - math.Abs(float64(p.Z-q.Z)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.Z)), math.Abs(float64(q.Z)))) && - math.Abs(float64(p.W-q.W)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.W)), math.Abs(float64(q.W)))) || - math.Abs(float64(p.X+q.X)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.X)), math.Abs(float64(q.X)))) && - math.Abs(float64(p.Y+q.Y)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.Y)), math.Abs(float64(q.Y)))) && - math.Abs(float64(p.Z+q.Z)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.Z)), math.Abs(float64(q.Z)))) && - math.Abs(float64(p.W+q.W)) <= 0.000001*math.Max(1.0, math.Max(math.Abs(float64(p.W)), math.Abs(float64(q.W))))) +func QuaternionEquals(q, p Quaternion) bool { + return (math.Abs(float64(q.X-p.X)) <= epsilon*math.Max(1.0, math.Max(math.Abs(float64(q.X)), math.Abs(float64(p.X)))) && + math.Abs(float64(q.Y-p.Y)) <= epsilon*math.Max(1.0, math.Max(math.Abs(float64(q.Y)), math.Abs(float64(p.Y)))) && + math.Abs(float64(q.Z-p.Z)) <= epsilon*math.Max(1.0, math.Max(math.Abs(float64(q.Z)), math.Abs(float64(p.Z)))) && + math.Abs(float64(q.W-p.W)) <= epsilon*math.Max(1.0, math.Max(math.Abs(float64(q.W)), math.Abs(float64(p.W)))) || + math.Abs(float64(q.X+p.X)) <= epsilon*math.Max(1.0, math.Max(math.Abs(float64(q.X)), math.Abs(float64(p.X)))) && + math.Abs(float64(q.Y+p.Y)) <= epsilon*math.Max(1.0, math.Max(math.Abs(float64(q.Y)), math.Abs(float64(p.Y)))) && + math.Abs(float64(q.Z+p.Z)) <= epsilon*math.Max(1.0, math.Max(math.Abs(float64(q.Z)), math.Abs(float64(p.Z)))) && + math.Abs(float64(q.W+p.W)) <= epsilon*math.Max(1.0, math.Max(math.Abs(float64(q.W)), math.Abs(float64(p.W))))) } // MatrixDecompose - Decompose a transformation matrix into its rotational, translational and scaling components @@ -1845,3 +1846,8 @@ func MatrixDecompose(mat Matrix, translation *Vector3, rotation *Quaternion, sca *rotation = QuaternionIdentity() } } + +func sincos(angle float32) (sin, cos float32) { + sind, cosd := math.Sincos(float64(angle)) + return float32(sind), float32(cosd) +} diff --git a/raylib/raymath_generated_binding.go b/raylib/raymath_generated_binding.go new file mode 100644 index 00000000..86cb04bc --- /dev/null +++ b/raylib/raymath_generated_binding.go @@ -0,0 +1,816 @@ +// Code generated by ./internal/cmd/genraymath DO NOT EDIT. + +package rl + +//#include "raymath.h" +import "C" + +import "unsafe" + +func cClamp(value, min, max float32) float32 { + cvalue := C.float(value) + cmin := C.float(min) + cmax := C.float(max) + ret := C.Clamp(cvalue, cmin, cmax) + return float32(ret) +} + +func cFloatEquals(x, y float32) bool { + cx := C.float(x) + cy := C.float(y) + ret := C.FloatEquals(cx, cy) + return ret != 0 +} + +func cLerp(start, end, amount float32) float32 { + cstart := C.float(start) + cend := C.float(end) + camount := C.float(amount) + ret := C.Lerp(cstart, cend, camount) + return float32(ret) +} + +func cMatrixAdd(left, right Matrix) Matrix { + cleft := *(*C.Matrix)(unsafe.Pointer(&left)) + cright := *(*C.Matrix)(unsafe.Pointer(&right)) + ret := C.MatrixAdd(cleft, cright) + return *(*Matrix)(unsafe.Pointer(&ret)) +} + +func cMatrixDecompose(mat Matrix, translation *Vector3, rotation *Quaternion, scale *Vector3) { + cmat := *(*C.Matrix)(unsafe.Pointer(&mat)) + ctranslation := (*C.Vector3)(unsafe.Pointer(translation)) + crotation := (*C.Quaternion)(unsafe.Pointer(rotation)) + cscale := (*C.Vector3)(unsafe.Pointer(scale)) + C.MatrixDecompose(cmat, ctranslation, crotation, cscale) +} + +func cMatrixDeterminant(mat Matrix) float32 { + cmat := *(*C.Matrix)(unsafe.Pointer(&mat)) + ret := C.MatrixDeterminant(cmat) + return float32(ret) +} + +func cMatrixFrustum(left, right, bottom, top, nearPlane, farPlane float32) Matrix { + cleft := C.double(left) + cright := C.double(right) + cbottom := C.double(bottom) + ctop := C.double(top) + cnearPlane := C.double(nearPlane) + cfarPlane := C.double(farPlane) + ret := C.MatrixFrustum(cleft, cright, cbottom, ctop, cnearPlane, cfarPlane) + return *(*Matrix)(unsafe.Pointer(&ret)) +} + +func cMatrixIdentity() Matrix { + ret := C.MatrixIdentity() + return *(*Matrix)(unsafe.Pointer(&ret)) +} + +func cMatrixInvert(mat Matrix) Matrix { + cmat := *(*C.Matrix)(unsafe.Pointer(&mat)) + ret := C.MatrixInvert(cmat) + return *(*Matrix)(unsafe.Pointer(&ret)) +} + +func cMatrixLookAt(eye, target, up Vector3) Matrix { + ceye := *(*C.Vector3)(unsafe.Pointer(&eye)) + ctarget := *(*C.Vector3)(unsafe.Pointer(&target)) + cup := *(*C.Vector3)(unsafe.Pointer(&up)) + ret := C.MatrixLookAt(ceye, ctarget, cup) + return *(*Matrix)(unsafe.Pointer(&ret)) +} + +func cMatrixMultiply(left, right Matrix) Matrix { + cleft := *(*C.Matrix)(unsafe.Pointer(&left)) + cright := *(*C.Matrix)(unsafe.Pointer(&right)) + ret := C.MatrixMultiply(cleft, cright) + return *(*Matrix)(unsafe.Pointer(&ret)) +} + +func cMatrixOrtho(left, right, bottom, top, near, far float32) Matrix { + cleft := C.double(left) + cright := C.double(right) + cbottom := C.double(bottom) + ctop := C.double(top) + cnear := C.double(near) + cfar := C.double(far) + ret := C.MatrixOrtho(cleft, cright, cbottom, ctop, cnear, cfar) + return *(*Matrix)(unsafe.Pointer(&ret)) +} + +func cMatrixPerspective(fovY, aspect, nearPlane, farPlane float32) Matrix { + cfovY := C.double(fovY) + caspect := C.double(aspect) + cnearPlane := C.double(nearPlane) + cfarPlane := C.double(farPlane) + ret := C.MatrixPerspective(cfovY, caspect, cnearPlane, cfarPlane) + return *(*Matrix)(unsafe.Pointer(&ret)) +} + +func cMatrixRotate(axis Vector3, angle float32) Matrix { + caxis := *(*C.Vector3)(unsafe.Pointer(&axis)) + cangle := C.float(angle) + ret := C.MatrixRotate(caxis, cangle) + return *(*Matrix)(unsafe.Pointer(&ret)) +} + +func cMatrixRotateX(angle float32) Matrix { + cangle := C.float(angle) + ret := C.MatrixRotateX(cangle) + return *(*Matrix)(unsafe.Pointer(&ret)) +} + +func cMatrixRotateXYZ(angle Vector3) Matrix { + cangle := *(*C.Vector3)(unsafe.Pointer(&angle)) + ret := C.MatrixRotateXYZ(cangle) + return *(*Matrix)(unsafe.Pointer(&ret)) +} + +func cMatrixRotateY(angle float32) Matrix { + cangle := C.float(angle) + ret := C.MatrixRotateY(cangle) + return *(*Matrix)(unsafe.Pointer(&ret)) +} + +func cMatrixRotateZ(angle float32) Matrix { + cangle := C.float(angle) + ret := C.MatrixRotateZ(cangle) + return *(*Matrix)(unsafe.Pointer(&ret)) +} + +func cMatrixRotateZYX(angle Vector3) Matrix { + cangle := *(*C.Vector3)(unsafe.Pointer(&angle)) + ret := C.MatrixRotateZYX(cangle) + return *(*Matrix)(unsafe.Pointer(&ret)) +} + +func cMatrixScale(x, y, z float32) Matrix { + cx := C.float(x) + cy := C.float(y) + cz := C.float(z) + ret := C.MatrixScale(cx, cy, cz) + return *(*Matrix)(unsafe.Pointer(&ret)) +} + +func cMatrixSubtract(left, right Matrix) Matrix { + cleft := *(*C.Matrix)(unsafe.Pointer(&left)) + cright := *(*C.Matrix)(unsafe.Pointer(&right)) + ret := C.MatrixSubtract(cleft, cright) + return *(*Matrix)(unsafe.Pointer(&ret)) +} + +func cMatrixToFloatV(mat Matrix) [16]float32 { + cmat := *(*C.Matrix)(unsafe.Pointer(&mat)) + ret := C.MatrixToFloatV(cmat) + return *(*[16]float32)(unsafe.Pointer(&ret)) +} + +func cMatrixTrace(mat Matrix) float32 { + cmat := *(*C.Matrix)(unsafe.Pointer(&mat)) + ret := C.MatrixTrace(cmat) + return float32(ret) +} + +func cMatrixTranslate(x, y, z float32) Matrix { + cx := C.float(x) + cy := C.float(y) + cz := C.float(z) + ret := C.MatrixTranslate(cx, cy, cz) + return *(*Matrix)(unsafe.Pointer(&ret)) +} + +func cMatrixTranspose(mat Matrix) Matrix { + cmat := *(*C.Matrix)(unsafe.Pointer(&mat)) + ret := C.MatrixTranspose(cmat) + return *(*Matrix)(unsafe.Pointer(&ret)) +} + +func cNormalize(value, start, end float32) float32 { + cvalue := C.float(value) + cstart := C.float(start) + cend := C.float(end) + ret := C.Normalize(cvalue, cstart, cend) + return float32(ret) +} + +func cQuaternionAdd(q1 Quaternion, q2 Quaternion) Quaternion { + cq1 := *(*C.Quaternion)(unsafe.Pointer(&q1)) + cq2 := *(*C.Quaternion)(unsafe.Pointer(&q2)) + ret := C.QuaternionAdd(cq1, cq2) + return *(*Quaternion)(unsafe.Pointer(&ret)) +} + +func cQuaternionAddValue(q Quaternion, add float32) Quaternion { + cq := *(*C.Quaternion)(unsafe.Pointer(&q)) + cadd := C.float(add) + ret := C.QuaternionAddValue(cq, cadd) + return *(*Quaternion)(unsafe.Pointer(&ret)) +} + +func cQuaternionDivide(q1 Quaternion, q2 Quaternion) Quaternion { + cq1 := *(*C.Quaternion)(unsafe.Pointer(&q1)) + cq2 := *(*C.Quaternion)(unsafe.Pointer(&q2)) + ret := C.QuaternionDivide(cq1, cq2) + return *(*Quaternion)(unsafe.Pointer(&ret)) +} + +func cQuaternionEquals(q, p Quaternion) bool { + cq := *(*C.Quaternion)(unsafe.Pointer(&q)) + cp := *(*C.Quaternion)(unsafe.Pointer(&p)) + ret := C.QuaternionEquals(cq, cp) + return ret != 0 +} + +func cQuaternionFromAxisAngle(axis Vector3, angle float32) Quaternion { + caxis := *(*C.Vector3)(unsafe.Pointer(&axis)) + cangle := C.float(angle) + ret := C.QuaternionFromAxisAngle(caxis, cangle) + return *(*Quaternion)(unsafe.Pointer(&ret)) +} + +func cQuaternionFromEuler(pitch, yaw, roll float32) Quaternion { + cpitch := C.float(pitch) + cyaw := C.float(yaw) + croll := C.float(roll) + ret := C.QuaternionFromEuler(cpitch, cyaw, croll) + return *(*Quaternion)(unsafe.Pointer(&ret)) +} + +func cQuaternionFromMatrix(mat Matrix) Quaternion { + cmat := *(*C.Matrix)(unsafe.Pointer(&mat)) + ret := C.QuaternionFromMatrix(cmat) + return *(*Quaternion)(unsafe.Pointer(&ret)) +} + +func cQuaternionFromVector3ToVector3(from Vector3, to Vector3) Quaternion { + cfrom := *(*C.Vector3)(unsafe.Pointer(&from)) + cto := *(*C.Vector3)(unsafe.Pointer(&to)) + ret := C.QuaternionFromVector3ToVector3(cfrom, cto) + return *(*Quaternion)(unsafe.Pointer(&ret)) +} + +func cQuaternionIdentity() Quaternion { + ret := C.QuaternionIdentity() + return *(*Quaternion)(unsafe.Pointer(&ret)) +} + +func cQuaternionInvert(quat Quaternion) Quaternion { + cquat := *(*C.Quaternion)(unsafe.Pointer(&quat)) + ret := C.QuaternionInvert(cquat) + return *(*Quaternion)(unsafe.Pointer(&ret)) +} + +func cQuaternionLength(quat Quaternion) float32 { + cquat := *(*C.Quaternion)(unsafe.Pointer(&quat)) + ret := C.QuaternionLength(cquat) + return float32(ret) +} + +func cQuaternionLerp(q1 Quaternion, q2 Quaternion, amount float32) Quaternion { + cq1 := *(*C.Quaternion)(unsafe.Pointer(&q1)) + cq2 := *(*C.Quaternion)(unsafe.Pointer(&q2)) + camount := C.float(amount) + ret := C.QuaternionLerp(cq1, cq2, camount) + return *(*Quaternion)(unsafe.Pointer(&ret)) +} + +func cQuaternionMultiply(q1, q2 Quaternion) Quaternion { + cq1 := *(*C.Quaternion)(unsafe.Pointer(&q1)) + cq2 := *(*C.Quaternion)(unsafe.Pointer(&q2)) + ret := C.QuaternionMultiply(cq1, cq2) + return *(*Quaternion)(unsafe.Pointer(&ret)) +} + +func cQuaternionNlerp(q1 Quaternion, q2 Quaternion, amount float32) Quaternion { + cq1 := *(*C.Quaternion)(unsafe.Pointer(&q1)) + cq2 := *(*C.Quaternion)(unsafe.Pointer(&q2)) + camount := C.float(amount) + ret := C.QuaternionNlerp(cq1, cq2, camount) + return *(*Quaternion)(unsafe.Pointer(&ret)) +} + +func cQuaternionNormalize(q Quaternion) Quaternion { + cq := *(*C.Quaternion)(unsafe.Pointer(&q)) + ret := C.QuaternionNormalize(cq) + return *(*Quaternion)(unsafe.Pointer(&ret)) +} + +func cQuaternionScale(q Quaternion, mul float32) Quaternion { + cq := *(*C.Quaternion)(unsafe.Pointer(&q)) + cmul := C.float(mul) + ret := C.QuaternionScale(cq, cmul) + return *(*Quaternion)(unsafe.Pointer(&ret)) +} + +func cQuaternionSlerp(q1, q2 Quaternion, amount float32) Quaternion { + cq1 := *(*C.Quaternion)(unsafe.Pointer(&q1)) + cq2 := *(*C.Quaternion)(unsafe.Pointer(&q2)) + camount := C.float(amount) + ret := C.QuaternionSlerp(cq1, cq2, camount) + return *(*Quaternion)(unsafe.Pointer(&ret)) +} + +func cQuaternionSubtract(q1 Quaternion, q2 Quaternion) Quaternion { + cq1 := *(*C.Quaternion)(unsafe.Pointer(&q1)) + cq2 := *(*C.Quaternion)(unsafe.Pointer(&q2)) + ret := C.QuaternionSubtract(cq1, cq2) + return *(*Quaternion)(unsafe.Pointer(&ret)) +} + +func cQuaternionSubtractValue(q Quaternion, sub float32) Quaternion { + cq := *(*C.Quaternion)(unsafe.Pointer(&q)) + csub := C.float(sub) + ret := C.QuaternionSubtractValue(cq, csub) + return *(*Quaternion)(unsafe.Pointer(&ret)) +} + +func cQuaternionToAxisAngle(q Quaternion, outAxis *Vector3, outAngle *float32) { + cq := *(*C.Quaternion)(unsafe.Pointer(&q)) + coutAxis := (*C.Vector3)(unsafe.Pointer(outAxis)) + coutAngle := (*C.float)(outAngle) + C.QuaternionToAxisAngle(cq, coutAxis, coutAngle) +} + +func cQuaternionToEuler(q Quaternion) Vector3 { + cq := *(*C.Quaternion)(unsafe.Pointer(&q)) + ret := C.QuaternionToEuler(cq) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cQuaternionToMatrix(q Quaternion) Matrix { + cq := *(*C.Quaternion)(unsafe.Pointer(&q)) + ret := C.QuaternionToMatrix(cq) + return *(*Matrix)(unsafe.Pointer(&ret)) +} + +func cQuaternionTransform(q Quaternion, mat Matrix) Quaternion { + cq := *(*C.Quaternion)(unsafe.Pointer(&q)) + cmat := *(*C.Matrix)(unsafe.Pointer(&mat)) + ret := C.QuaternionTransform(cq, cmat) + return *(*Quaternion)(unsafe.Pointer(&ret)) +} + +func cRemap(value, inputStart, inputEnd, outputStart, outputEnd float32) float32 { + cvalue := C.float(value) + cinputStart := C.float(inputStart) + cinputEnd := C.float(inputEnd) + coutputStart := C.float(outputStart) + coutputEnd := C.float(outputEnd) + ret := C.Remap(cvalue, cinputStart, cinputEnd, coutputStart, coutputEnd) + return float32(ret) +} + +func cVector2Add(v1, v2 Vector2) Vector2 { + cv1 := *(*C.Vector2)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector2)(unsafe.Pointer(&v2)) + ret := C.Vector2Add(cv1, cv2) + return *(*Vector2)(unsafe.Pointer(&ret)) +} + +func cVector2AddValue(v Vector2, add float32) Vector2 { + cv := *(*C.Vector2)(unsafe.Pointer(&v)) + cadd := C.float(add) + ret := C.Vector2AddValue(cv, cadd) + return *(*Vector2)(unsafe.Pointer(&ret)) +} + +func cVector2Angle(v1, v2 Vector2) float32 { + cv1 := *(*C.Vector2)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector2)(unsafe.Pointer(&v2)) + ret := C.Vector2Angle(cv1, cv2) + return float32(ret) +} + +func cVector2Clamp(v Vector2, min Vector2, max Vector2) Vector2 { + cv := *(*C.Vector2)(unsafe.Pointer(&v)) + cmin := *(*C.Vector2)(unsafe.Pointer(&min)) + cmax := *(*C.Vector2)(unsafe.Pointer(&max)) + ret := C.Vector2Clamp(cv, cmin, cmax) + return *(*Vector2)(unsafe.Pointer(&ret)) +} + +func cVector2ClampValue(v Vector2, min float32, max float32) Vector2 { + cv := *(*C.Vector2)(unsafe.Pointer(&v)) + cmin := C.float(min) + cmax := C.float(max) + ret := C.Vector2ClampValue(cv, cmin, cmax) + return *(*Vector2)(unsafe.Pointer(&ret)) +} + +func cVector2CrossProduct(v1, v2 Vector2) float32 { + cv1 := *(*C.Vector2)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector2)(unsafe.Pointer(&v2)) + ret := C.Vector2CrossProduct(cv1, cv2) + return float32(ret) +} + +func cVector2Distance(v1, v2 Vector2) float32 { + cv1 := *(*C.Vector2)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector2)(unsafe.Pointer(&v2)) + ret := C.Vector2Distance(cv1, cv2) + return float32(ret) +} + +func cVector2DistanceSqr(v1 Vector2, v2 Vector2) float32 { + cv1 := *(*C.Vector2)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector2)(unsafe.Pointer(&v2)) + ret := C.Vector2DistanceSqr(cv1, cv2) + return float32(ret) +} + +func cVector2Divide(v1, v2 Vector2) Vector2 { + cv1 := *(*C.Vector2)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector2)(unsafe.Pointer(&v2)) + ret := C.Vector2Divide(cv1, cv2) + return *(*Vector2)(unsafe.Pointer(&ret)) +} + +func cVector2DotProduct(v1, v2 Vector2) float32 { + cv1 := *(*C.Vector2)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector2)(unsafe.Pointer(&v2)) + ret := C.Vector2DotProduct(cv1, cv2) + return float32(ret) +} + +func cVector2Equals(p Vector2, q Vector2) bool { + cp := *(*C.Vector2)(unsafe.Pointer(&p)) + cq := *(*C.Vector2)(unsafe.Pointer(&q)) + ret := C.Vector2Equals(cp, cq) + return ret != 0 +} + +func cVector2Invert(v Vector2) Vector2 { + cv := *(*C.Vector2)(unsafe.Pointer(&v)) + ret := C.Vector2Invert(cv) + return *(*Vector2)(unsafe.Pointer(&ret)) +} + +func cVector2Length(v Vector2) float32 { + cv := *(*C.Vector2)(unsafe.Pointer(&v)) + ret := C.Vector2Length(cv) + return float32(ret) +} + +func cVector2LengthSqr(v Vector2) float32 { + cv := *(*C.Vector2)(unsafe.Pointer(&v)) + ret := C.Vector2LengthSqr(cv) + return float32(ret) +} + +func cVector2Lerp(v1, v2 Vector2, amount float32) Vector2 { + cv1 := *(*C.Vector2)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector2)(unsafe.Pointer(&v2)) + camount := C.float(amount) + ret := C.Vector2Lerp(cv1, cv2, camount) + return *(*Vector2)(unsafe.Pointer(&ret)) +} + +func cVector2LineAngle(start Vector2, end Vector2) float32 { + cstart := *(*C.Vector2)(unsafe.Pointer(&start)) + cend := *(*C.Vector2)(unsafe.Pointer(&end)) + ret := C.Vector2LineAngle(cstart, cend) + return float32(ret) +} + +func cVector2MoveTowards(v Vector2, target Vector2, maxDistance float32) Vector2 { + cv := *(*C.Vector2)(unsafe.Pointer(&v)) + ctarget := *(*C.Vector2)(unsafe.Pointer(&target)) + cmaxDistance := C.float(maxDistance) + ret := C.Vector2MoveTowards(cv, ctarget, cmaxDistance) + return *(*Vector2)(unsafe.Pointer(&ret)) +} + +func cVector2Multiply(v1, v2 Vector2) Vector2 { + cv1 := *(*C.Vector2)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector2)(unsafe.Pointer(&v2)) + ret := C.Vector2Multiply(cv1, cv2) + return *(*Vector2)(unsafe.Pointer(&ret)) +} + +func cVector2Negate(v Vector2) Vector2 { + cv := *(*C.Vector2)(unsafe.Pointer(&v)) + ret := C.Vector2Negate(cv) + return *(*Vector2)(unsafe.Pointer(&ret)) +} + +func cVector2Normalize(v Vector2) Vector2 { + cv := *(*C.Vector2)(unsafe.Pointer(&v)) + ret := C.Vector2Normalize(cv) + return *(*Vector2)(unsafe.Pointer(&ret)) +} + +func cVector2One() Vector2 { + ret := C.Vector2One() + return *(*Vector2)(unsafe.Pointer(&ret)) +} + +func cVector2Reflect(v Vector2, normal Vector2) Vector2 { + cv := *(*C.Vector2)(unsafe.Pointer(&v)) + cnormal := *(*C.Vector2)(unsafe.Pointer(&normal)) + ret := C.Vector2Reflect(cv, cnormal) + return *(*Vector2)(unsafe.Pointer(&ret)) +} + +func cVector2Rotate(v Vector2, angle float32) Vector2 { + cv := *(*C.Vector2)(unsafe.Pointer(&v)) + cangle := C.float(angle) + ret := C.Vector2Rotate(cv, cangle) + return *(*Vector2)(unsafe.Pointer(&ret)) +} + +func cVector2Scale(v Vector2, scale float32) Vector2 { + cv := *(*C.Vector2)(unsafe.Pointer(&v)) + cscale := C.float(scale) + ret := C.Vector2Scale(cv, cscale) + return *(*Vector2)(unsafe.Pointer(&ret)) +} + +func cVector2Subtract(v1, v2 Vector2) Vector2 { + cv1 := *(*C.Vector2)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector2)(unsafe.Pointer(&v2)) + ret := C.Vector2Subtract(cv1, cv2) + return *(*Vector2)(unsafe.Pointer(&ret)) +} + +func cVector2SubtractValue(v Vector2, sub float32) Vector2 { + cv := *(*C.Vector2)(unsafe.Pointer(&v)) + csub := C.float(sub) + ret := C.Vector2SubtractValue(cv, csub) + return *(*Vector2)(unsafe.Pointer(&ret)) +} + +func cVector2Transform(v Vector2, mat Matrix) Vector2 { + cv := *(*C.Vector2)(unsafe.Pointer(&v)) + cmat := *(*C.Matrix)(unsafe.Pointer(&mat)) + ret := C.Vector2Transform(cv, cmat) + return *(*Vector2)(unsafe.Pointer(&ret)) +} + +func cVector2Zero() Vector2 { + ret := C.Vector2Zero() + return *(*Vector2)(unsafe.Pointer(&ret)) +} + +func cVector3Add(v1, v2 Vector3) Vector3 { + cv1 := *(*C.Vector3)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector3)(unsafe.Pointer(&v2)) + ret := C.Vector3Add(cv1, cv2) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3AddValue(v Vector3, add float32) Vector3 { + cv := *(*C.Vector3)(unsafe.Pointer(&v)) + cadd := C.float(add) + ret := C.Vector3AddValue(cv, cadd) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3Angle(v1 Vector3, v2 Vector3) float32 { + cv1 := *(*C.Vector3)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector3)(unsafe.Pointer(&v2)) + ret := C.Vector3Angle(cv1, cv2) + return float32(ret) +} + +func cVector3Barycenter(p, a, b, c Vector3) Vector3 { + cp := *(*C.Vector3)(unsafe.Pointer(&p)) + ca := *(*C.Vector3)(unsafe.Pointer(&a)) + cb := *(*C.Vector3)(unsafe.Pointer(&b)) + cc := *(*C.Vector3)(unsafe.Pointer(&c)) + ret := C.Vector3Barycenter(cp, ca, cb, cc) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3Clamp(v Vector3, min Vector3, max Vector3) Vector3 { + cv := *(*C.Vector3)(unsafe.Pointer(&v)) + cmin := *(*C.Vector3)(unsafe.Pointer(&min)) + cmax := *(*C.Vector3)(unsafe.Pointer(&max)) + ret := C.Vector3Clamp(cv, cmin, cmax) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3ClampValue(v Vector3, min float32, max float32) Vector3 { + cv := *(*C.Vector3)(unsafe.Pointer(&v)) + cmin := C.float(min) + cmax := C.float(max) + ret := C.Vector3ClampValue(cv, cmin, cmax) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3CrossProduct(v1, v2 Vector3) Vector3 { + cv1 := *(*C.Vector3)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector3)(unsafe.Pointer(&v2)) + ret := C.Vector3CrossProduct(cv1, cv2) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3Distance(v1, v2 Vector3) float32 { + cv1 := *(*C.Vector3)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector3)(unsafe.Pointer(&v2)) + ret := C.Vector3Distance(cv1, cv2) + return float32(ret) +} + +func cVector3DistanceSqr(v1 Vector3, v2 Vector3) float32 { + cv1 := *(*C.Vector3)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector3)(unsafe.Pointer(&v2)) + ret := C.Vector3DistanceSqr(cv1, cv2) + return float32(ret) +} + +func cVector3Divide(v1 Vector3, v2 Vector3) Vector3 { + cv1 := *(*C.Vector3)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector3)(unsafe.Pointer(&v2)) + ret := C.Vector3Divide(cv1, cv2) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3DotProduct(v1, v2 Vector3) float32 { + cv1 := *(*C.Vector3)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector3)(unsafe.Pointer(&v2)) + ret := C.Vector3DotProduct(cv1, cv2) + return float32(ret) +} + +func cVector3Equals(p Vector3, q Vector3) bool { + cp := *(*C.Vector3)(unsafe.Pointer(&p)) + cq := *(*C.Vector3)(unsafe.Pointer(&q)) + ret := C.Vector3Equals(cp, cq) + return ret != 0 +} + +func cVector3Invert(v Vector3) Vector3 { + cv := *(*C.Vector3)(unsafe.Pointer(&v)) + ret := C.Vector3Invert(cv) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3Length(v Vector3) float32 { + cv := *(*C.Vector3)(unsafe.Pointer(&v)) + ret := C.Vector3Length(cv) + return float32(ret) +} + +func cVector3LengthSqr(v Vector3) float32 { + cv := *(*C.Vector3)(unsafe.Pointer(&v)) + ret := C.Vector3LengthSqr(cv) + return float32(ret) +} + +func cVector3Lerp(v1, v2 Vector3, amount float32) Vector3 { + cv1 := *(*C.Vector3)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector3)(unsafe.Pointer(&v2)) + camount := C.float(amount) + ret := C.Vector3Lerp(cv1, cv2, camount) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3Max(vec1, vec2 Vector3) Vector3 { + cvec1 := *(*C.Vector3)(unsafe.Pointer(&vec1)) + cvec2 := *(*C.Vector3)(unsafe.Pointer(&vec2)) + ret := C.Vector3Max(cvec1, cvec2) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3Min(vec1, vec2 Vector3) Vector3 { + cvec1 := *(*C.Vector3)(unsafe.Pointer(&vec1)) + cvec2 := *(*C.Vector3)(unsafe.Pointer(&vec2)) + ret := C.Vector3Min(cvec1, cvec2) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3Multiply(v1, v2 Vector3) Vector3 { + cv1 := *(*C.Vector3)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector3)(unsafe.Pointer(&v2)) + ret := C.Vector3Multiply(cv1, cv2) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3Negate(v Vector3) Vector3 { + cv := *(*C.Vector3)(unsafe.Pointer(&v)) + ret := C.Vector3Negate(cv) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3Normalize(v Vector3) Vector3 { + cv := *(*C.Vector3)(unsafe.Pointer(&v)) + ret := C.Vector3Normalize(cv) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3One() Vector3 { + ret := C.Vector3One() + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3OrthoNormalize(v1, v2 *Vector3) { + cv1 := (*C.Vector3)(unsafe.Pointer(v1)) + cv2 := (*C.Vector3)(unsafe.Pointer(v2)) + C.Vector3OrthoNormalize(cv1, cv2) +} + +func cVector3Perpendicular(v Vector3) Vector3 { + cv := *(*C.Vector3)(unsafe.Pointer(&v)) + ret := C.Vector3Perpendicular(cv) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3Project(v1, v2 Vector3) Vector3 { + cv1 := *(*C.Vector3)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector3)(unsafe.Pointer(&v2)) + ret := C.Vector3Project(cv1, cv2) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3Reflect(vector, normal Vector3) Vector3 { + cvector := *(*C.Vector3)(unsafe.Pointer(&vector)) + cnormal := *(*C.Vector3)(unsafe.Pointer(&normal)) + ret := C.Vector3Reflect(cvector, cnormal) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3Refract(v Vector3, n Vector3, r float32) Vector3 { + cv := *(*C.Vector3)(unsafe.Pointer(&v)) + cn := *(*C.Vector3)(unsafe.Pointer(&n)) + cr := C.float(r) + ret := C.Vector3Refract(cv, cn, cr) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3Reject(v1, v2 Vector3) Vector3 { + cv1 := *(*C.Vector3)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector3)(unsafe.Pointer(&v2)) + ret := C.Vector3Reject(cv1, cv2) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3RotateByAxisAngle(v Vector3, axis Vector3, angle float32) Vector3 { + cv := *(*C.Vector3)(unsafe.Pointer(&v)) + caxis := *(*C.Vector3)(unsafe.Pointer(&axis)) + cangle := C.float(angle) + ret := C.Vector3RotateByAxisAngle(cv, caxis, cangle) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3RotateByQuaternion(v Vector3, q Quaternion) Vector3 { + cv := *(*C.Vector3)(unsafe.Pointer(&v)) + cq := *(*C.Quaternion)(unsafe.Pointer(&q)) + ret := C.Vector3RotateByQuaternion(cv, cq) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3Scale(v Vector3, scale float32) Vector3 { + cv := *(*C.Vector3)(unsafe.Pointer(&v)) + cscale := C.float(scale) + ret := C.Vector3Scale(cv, cscale) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3Subtract(v1, v2 Vector3) Vector3 { + cv1 := *(*C.Vector3)(unsafe.Pointer(&v1)) + cv2 := *(*C.Vector3)(unsafe.Pointer(&v2)) + ret := C.Vector3Subtract(cv1, cv2) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3SubtractValue(v Vector3, sub float32) Vector3 { + cv := *(*C.Vector3)(unsafe.Pointer(&v)) + csub := C.float(sub) + ret := C.Vector3SubtractValue(cv, csub) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3ToFloatV(v Vector3) [3]float32 { + cv := *(*C.Vector3)(unsafe.Pointer(&v)) + ret := C.Vector3ToFloatV(cv) + return *(*[3]float32)(unsafe.Pointer(&ret)) +} + +func cVector3Transform(v Vector3, mat Matrix) Vector3 { + cv := *(*C.Vector3)(unsafe.Pointer(&v)) + cmat := *(*C.Matrix)(unsafe.Pointer(&mat)) + ret := C.Vector3Transform(cv, cmat) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3Unproject(source Vector3, projection Matrix, view Matrix) Vector3 { + csource := *(*C.Vector3)(unsafe.Pointer(&source)) + cprojection := *(*C.Matrix)(unsafe.Pointer(&projection)) + cview := *(*C.Matrix)(unsafe.Pointer(&view)) + ret := C.Vector3Unproject(csource, cprojection, cview) + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cVector3Zero() Vector3 { + ret := C.Vector3Zero() + return *(*Vector3)(unsafe.Pointer(&ret)) +} + +func cWrap(value, min, max float32) float32 { + cvalue := C.float(value) + cmin := C.float(min) + cmax := C.float(max) + ret := C.Wrap(cvalue, cmin, cmax) + return float32(ret) +} diff --git a/raylib/raymath_generated_test.go b/raylib/raymath_generated_test.go new file mode 100644 index 00000000..e83c8db0 --- /dev/null +++ b/raylib/raymath_generated_test.go @@ -0,0 +1,5002 @@ +// Code generated by ./internal/cmd/genraymath DO NOT EDIT. + +package rl + +import ( + "math" + "testing" + "time" +) + +func BenchmarkClamp(b *testing.B) { + value := float32(1) + min := float32(2) + max := float32(3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cClamp(value, min, max) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Clamp(value, min, max) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzClamp(f *testing.F) { + f.Add( + float32(1), + float32(2), + float32(3), + ) + f.Fuzz(func(t *testing.T, + value float32, + min float32, + max float32, + ) { + want := cClamp(value, min, max) + got := Clamp(value, min, max) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkFloatEquals(b *testing.B) { + x := float32(1) + y := float32(2) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cFloatEquals(x, y) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + FloatEquals(x, y) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzFloatEquals(f *testing.F) { + f.Add( + float32(1), + float32(2), + ) + f.Fuzz(func(t *testing.T, + x float32, + y float32, + ) { + want := cFloatEquals(x, y) + got := FloatEquals(x, y) + if want != got { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkLerp(b *testing.B) { + start := float32(1) + end := float32(2) + amount := float32(3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cLerp(start, end, amount) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Lerp(start, end, amount) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzLerp(f *testing.F) { + f.Add( + float32(1), + float32(2), + float32(3), + ) + f.Fuzz(func(t *testing.T, + start float32, + end float32, + amount float32, + ) { + want := cLerp(start, end, amount) + got := Lerp(start, end, amount) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkMatrixAdd(b *testing.B) { + left := NewMatrix(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4) + right := NewMatrix(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixAdd(left, right) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixAdd(left, right) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixAdd(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + leftM0, leftM4, leftM8, leftM12, + leftM1, leftM5, leftM9, leftM13, + leftM2, leftM6, leftM10, leftM14, + leftM3, leftM7, leftM11, leftM15 float32, + rightM0, rightM4, rightM8, rightM12, + rightM1, rightM5, rightM9, rightM13, + rightM2, rightM6, rightM10, rightM14, + rightM3, rightM7, rightM11, rightM15 float32, + ) { + left := NewMatrix( + leftM0, leftM4, leftM8, leftM12, + leftM1, leftM5, leftM9, leftM13, + leftM2, leftM6, leftM10, leftM14, + leftM3, leftM7, leftM11, leftM15, + ) + right := NewMatrix( + rightM0, rightM4, rightM8, rightM12, + rightM1, rightM5, rightM9, rightM13, + rightM2, rightM6, rightM10, rightM14, + rightM3, rightM7, rightM11, rightM15, + ) + want := cMatrixAdd(left, right) + got := MatrixAdd(left, right) + if !testMatrixEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkMatrixDeterminant(b *testing.B) { + mat := NewMatrix(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixDeterminant(mat) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixDeterminant(mat) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixDeterminant(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + matM0, matM4, matM8, matM12, + matM1, matM5, matM9, matM13, + matM2, matM6, matM10, matM14, + matM3, matM7, matM11, matM15 float32, + ) { + mat := NewMatrix( + matM0, matM4, matM8, matM12, + matM1, matM5, matM9, matM13, + matM2, matM6, matM10, matM14, + matM3, matM7, matM11, matM15, + ) + want := cMatrixDeterminant(mat) + got := MatrixDeterminant(mat) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkMatrixFrustum(b *testing.B) { + left := float32(1) + right := float32(2) + bottom := float32(3) + top := float32(4) + nearPlane := float32(5) + farPlane := float32(6) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixFrustum(left, right, bottom, top, nearPlane, farPlane) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixFrustum(left, right, bottom, top, nearPlane, farPlane) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixFrustum(f *testing.F) { + f.Add( + float32(1), + float32(2), + float32(3), + float32(4), + float32(5), + float32(6), + ) + f.Fuzz(func(t *testing.T, + left float32, + right float32, + bottom float32, + top float32, + nearPlane float32, + farPlane float32, + ) { + want := cMatrixFrustum(left, right, bottom, top, nearPlane, farPlane) + got := MatrixFrustum(left, right, bottom, top, nearPlane, farPlane) + if !testMatrixEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkMatrixIdentity(b *testing.B) { + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixIdentity() + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixIdentity() + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func TestMatrixIdentity(t *testing.T) { + want := cMatrixIdentity() + got := MatrixIdentity() + if !testMatrixEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } +} + +func BenchmarkMatrixInvert(b *testing.B) { + mat := NewMatrix(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixInvert(mat) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixInvert(mat) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixInvert(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + matM0, matM4, matM8, matM12, + matM1, matM5, matM9, matM13, + matM2, matM6, matM10, matM14, + matM3, matM7, matM11, matM15 float32, + ) { + mat := NewMatrix( + matM0, matM4, matM8, matM12, + matM1, matM5, matM9, matM13, + matM2, matM6, matM10, matM14, + matM3, matM7, matM11, matM15, + ) + want := cMatrixInvert(mat) + got := MatrixInvert(mat) + if !testMatrixEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkMatrixLookAt(b *testing.B) { + eye := NewVector3(1, 2, 3) + target := NewVector3(1, 2, 3) + up := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixLookAt(eye, target, up) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixLookAt(eye, target, up) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixLookAt(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + eyeX, eyeY, eyeZ float32, + targetX, targetY, targetZ float32, + upX, upY, upZ float32, + ) { + eye := NewVector3(eyeX, eyeY, eyeZ) + target := NewVector3(targetX, targetY, targetZ) + up := NewVector3(upX, upY, upZ) + want := cMatrixLookAt(eye, target, up) + got := MatrixLookAt(eye, target, up) + if !testMatrixEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkMatrixMultiply(b *testing.B) { + left := NewMatrix(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4) + right := NewMatrix(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixMultiply(left, right) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixMultiply(left, right) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixMultiply(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + leftM0, leftM4, leftM8, leftM12, + leftM1, leftM5, leftM9, leftM13, + leftM2, leftM6, leftM10, leftM14, + leftM3, leftM7, leftM11, leftM15 float32, + rightM0, rightM4, rightM8, rightM12, + rightM1, rightM5, rightM9, rightM13, + rightM2, rightM6, rightM10, rightM14, + rightM3, rightM7, rightM11, rightM15 float32, + ) { + left := NewMatrix( + leftM0, leftM4, leftM8, leftM12, + leftM1, leftM5, leftM9, leftM13, + leftM2, leftM6, leftM10, leftM14, + leftM3, leftM7, leftM11, leftM15, + ) + right := NewMatrix( + rightM0, rightM4, rightM8, rightM12, + rightM1, rightM5, rightM9, rightM13, + rightM2, rightM6, rightM10, rightM14, + rightM3, rightM7, rightM11, rightM15, + ) + want := cMatrixMultiply(left, right) + got := MatrixMultiply(left, right) + if !testMatrixEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkMatrixOrtho(b *testing.B) { + left := float32(1) + right := float32(2) + bottom := float32(3) + top := float32(4) + near := float32(5) + far := float32(6) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixOrtho(left, right, bottom, top, near, far) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixOrtho(left, right, bottom, top, near, far) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixOrtho(f *testing.F) { + f.Add( + float32(1), + float32(2), + float32(3), + float32(4), + float32(5), + float32(6), + ) + f.Fuzz(func(t *testing.T, + left float32, + right float32, + bottom float32, + top float32, + near float32, + far float32, + ) { + want := cMatrixOrtho(left, right, bottom, top, near, far) + got := MatrixOrtho(left, right, bottom, top, near, far) + if !testMatrixEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkMatrixPerspective(b *testing.B) { + fovY := float32(1) + aspect := float32(2) + nearPlane := float32(3) + farPlane := float32(4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixPerspective(fovY, aspect, nearPlane, farPlane) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixPerspective(fovY, aspect, nearPlane, farPlane) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixPerspective(f *testing.F) { + f.Add( + float32(1), + float32(2), + float32(3), + float32(4), + ) + f.Fuzz(func(t *testing.T, + fovY float32, + aspect float32, + nearPlane float32, + farPlane float32, + ) { + want := cMatrixPerspective(fovY, aspect, nearPlane, farPlane) + got := MatrixPerspective(fovY, aspect, nearPlane, farPlane) + if !testMatrixEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkMatrixRotate(b *testing.B) { + axis := NewVector3(1, 2, 3) + angle := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixRotate(axis, angle) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixRotate(axis, angle) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixRotate(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), + ) + f.Fuzz(func(t *testing.T, + axisX, axisY, axisZ float32, + angle float32, + ) { + axis := NewVector3(axisX, axisY, axisZ) + want := cMatrixRotate(axis, angle) + got := MatrixRotate(axis, angle) + if !testMatrixEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkMatrixRotateX(b *testing.B) { + angle := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixRotateX(angle) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixRotateX(angle) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixRotateX(f *testing.F) { + f.Add( + float32(1), + ) + f.Fuzz(func(t *testing.T, + angle float32, + ) { + want := cMatrixRotateX(angle) + got := MatrixRotateX(angle) + if !testMatrixEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkMatrixRotateXYZ(b *testing.B) { + angle := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixRotateXYZ(angle) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixRotateXYZ(angle) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixRotateXYZ(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + angleX, angleY, angleZ float32, + ) { + angle := NewVector3(angleX, angleY, angleZ) + want := cMatrixRotateXYZ(angle) + got := MatrixRotateXYZ(angle) + if !testMatrixEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkMatrixRotateY(b *testing.B) { + angle := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixRotateY(angle) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixRotateY(angle) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixRotateY(f *testing.F) { + f.Add( + float32(1), + ) + f.Fuzz(func(t *testing.T, + angle float32, + ) { + want := cMatrixRotateY(angle) + got := MatrixRotateY(angle) + if !testMatrixEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkMatrixRotateZ(b *testing.B) { + angle := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixRotateZ(angle) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixRotateZ(angle) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixRotateZ(f *testing.F) { + f.Add( + float32(1), + ) + f.Fuzz(func(t *testing.T, + angle float32, + ) { + want := cMatrixRotateZ(angle) + got := MatrixRotateZ(angle) + if !testMatrixEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkMatrixRotateZYX(b *testing.B) { + angle := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixRotateZYX(angle) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixRotateZYX(angle) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixRotateZYX(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + angleX, angleY, angleZ float32, + ) { + angle := NewVector3(angleX, angleY, angleZ) + want := cMatrixRotateZYX(angle) + got := MatrixRotateZYX(angle) + if !testMatrixEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkMatrixScale(b *testing.B) { + x := float32(1) + y := float32(2) + z := float32(3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixScale(x, y, z) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixScale(x, y, z) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixScale(f *testing.F) { + f.Add( + float32(1), + float32(2), + float32(3), + ) + f.Fuzz(func(t *testing.T, + x float32, + y float32, + z float32, + ) { + want := cMatrixScale(x, y, z) + got := MatrixScale(x, y, z) + if !testMatrixEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkMatrixSubtract(b *testing.B) { + left := NewMatrix(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4) + right := NewMatrix(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixSubtract(left, right) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixSubtract(left, right) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixSubtract(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + leftM0, leftM4, leftM8, leftM12, + leftM1, leftM5, leftM9, leftM13, + leftM2, leftM6, leftM10, leftM14, + leftM3, leftM7, leftM11, leftM15 float32, + rightM0, rightM4, rightM8, rightM12, + rightM1, rightM5, rightM9, rightM13, + rightM2, rightM6, rightM10, rightM14, + rightM3, rightM7, rightM11, rightM15 float32, + ) { + left := NewMatrix( + leftM0, leftM4, leftM8, leftM12, + leftM1, leftM5, leftM9, leftM13, + leftM2, leftM6, leftM10, leftM14, + leftM3, leftM7, leftM11, leftM15, + ) + right := NewMatrix( + rightM0, rightM4, rightM8, rightM12, + rightM1, rightM5, rightM9, rightM13, + rightM2, rightM6, rightM10, rightM14, + rightM3, rightM7, rightM11, rightM15, + ) + want := cMatrixSubtract(left, right) + got := MatrixSubtract(left, right) + if !testMatrixEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkMatrixToFloatV(b *testing.B) { + mat := NewMatrix(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixToFloatV(mat) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixToFloatV(mat) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixToFloatV(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + matM0, matM4, matM8, matM12, + matM1, matM5, matM9, matM13, + matM2, matM6, matM10, matM14, + matM3, matM7, matM11, matM15 float32, + ) { + mat := NewMatrix( + matM0, matM4, matM8, matM12, + matM1, matM5, matM9, matM13, + matM2, matM6, matM10, matM14, + matM3, matM7, matM11, matM15, + ) + want := cMatrixToFloatV(mat) + got := MatrixToFloatV(mat) + if !testFloat32SliceEquals(want[:], got[:], 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkMatrixTrace(b *testing.B) { + mat := NewMatrix(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixTrace(mat) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixTrace(mat) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixTrace(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + matM0, matM4, matM8, matM12, + matM1, matM5, matM9, matM13, + matM2, matM6, matM10, matM14, + matM3, matM7, matM11, matM15 float32, + ) { + mat := NewMatrix( + matM0, matM4, matM8, matM12, + matM1, matM5, matM9, matM13, + matM2, matM6, matM10, matM14, + matM3, matM7, matM11, matM15, + ) + want := cMatrixTrace(mat) + got := MatrixTrace(mat) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkMatrixTranslate(b *testing.B) { + x := float32(1) + y := float32(2) + z := float32(3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixTranslate(x, y, z) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixTranslate(x, y, z) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixTranslate(f *testing.F) { + f.Add( + float32(1), + float32(2), + float32(3), + ) + f.Fuzz(func(t *testing.T, + x float32, + y float32, + z float32, + ) { + want := cMatrixTranslate(x, y, z) + got := MatrixTranslate(x, y, z) + if !testMatrixEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkMatrixTranspose(b *testing.B) { + mat := NewMatrix(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cMatrixTranspose(mat) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + MatrixTranspose(mat) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixTranspose(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + matM0, matM4, matM8, matM12, + matM1, matM5, matM9, matM13, + matM2, matM6, matM10, matM14, + matM3, matM7, matM11, matM15 float32, + ) { + mat := NewMatrix( + matM0, matM4, matM8, matM12, + matM1, matM5, matM9, matM13, + matM2, matM6, matM10, matM14, + matM3, matM7, matM11, matM15, + ) + want := cMatrixTranspose(mat) + got := MatrixTranspose(mat) + if !testMatrixEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkNormalize(b *testing.B) { + value := float32(1) + start := float32(2) + end := float32(3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cNormalize(value, start, end) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Normalize(value, start, end) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzNormalize(f *testing.F) { + f.Add( + float32(1), + float32(2), + float32(3), + ) + f.Fuzz(func(t *testing.T, + value float32, + start float32, + end float32, + ) { + want := cNormalize(value, start, end) + got := Normalize(value, start, end) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionAdd(b *testing.B) { + q1 := NewQuaternion(1, 2, 3, 4) + q2 := NewQuaternion(1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionAdd(q1, q2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionAdd(q1, q2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionAdd(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + q1X, q1Y, q1Z, q1W float32, + q2X, q2Y, q2Z, q2W float32, + ) { + q1 := NewQuaternion(q1X, q1Y, q1Z, q1W) + q2 := NewQuaternion(q2X, q2Y, q2Z, q2W) + want := cQuaternionAdd(q1, q2) + got := QuaternionAdd(q1, q2) + if !testQuaternionEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionAddValue(b *testing.B) { + q := NewQuaternion(1, 2, 3, 4) + add := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionAddValue(q, add) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionAddValue(q, add) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionAddValue(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), + ) + f.Fuzz(func(t *testing.T, + qX, qY, qZ, qW float32, + add float32, + ) { + q := NewQuaternion(qX, qY, qZ, qW) + want := cQuaternionAddValue(q, add) + got := QuaternionAddValue(q, add) + if !testQuaternionEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionDivide(b *testing.B) { + q1 := NewQuaternion(1, 2, 3, 4) + q2 := NewQuaternion(1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionDivide(q1, q2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionDivide(q1, q2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionDivide(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + q1X, q1Y, q1Z, q1W float32, + q2X, q2Y, q2Z, q2W float32, + ) { + q1 := NewQuaternion(q1X, q1Y, q1Z, q1W) + q2 := NewQuaternion(q2X, q2Y, q2Z, q2W) + want := cQuaternionDivide(q1, q2) + got := QuaternionDivide(q1, q2) + if !testQuaternionEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionEquals(b *testing.B) { + q := NewQuaternion(1, 2, 3, 4) + p := NewQuaternion(1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionEquals(q, p) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionEquals(q, p) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionEquals(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + qX, qY, qZ, qW float32, + pX, pY, pZ, pW float32, + ) { + q := NewQuaternion(qX, qY, qZ, qW) + p := NewQuaternion(pX, pY, pZ, pW) + want := cQuaternionEquals(q, p) + got := QuaternionEquals(q, p) + if want != got { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionFromAxisAngle(b *testing.B) { + axis := NewVector3(1, 2, 3) + angle := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionFromAxisAngle(axis, angle) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionFromAxisAngle(axis, angle) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionFromAxisAngle(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), + ) + f.Fuzz(func(t *testing.T, + axisX, axisY, axisZ float32, + angle float32, + ) { + axis := NewVector3(axisX, axisY, axisZ) + want := cQuaternionFromAxisAngle(axis, angle) + got := QuaternionFromAxisAngle(axis, angle) + if !testQuaternionEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionFromEuler(b *testing.B) { + pitch := float32(1) + yaw := float32(2) + roll := float32(3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionFromEuler(pitch, yaw, roll) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionFromEuler(pitch, yaw, roll) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionFromEuler(f *testing.F) { + f.Add( + float32(1), + float32(2), + float32(3), + ) + f.Fuzz(func(t *testing.T, + pitch float32, + yaw float32, + roll float32, + ) { + want := cQuaternionFromEuler(pitch, yaw, roll) + got := QuaternionFromEuler(pitch, yaw, roll) + if !testQuaternionEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionFromMatrix(b *testing.B) { + mat := NewMatrix(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionFromMatrix(mat) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionFromMatrix(mat) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionFromMatrix(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + matM0, matM4, matM8, matM12, + matM1, matM5, matM9, matM13, + matM2, matM6, matM10, matM14, + matM3, matM7, matM11, matM15 float32, + ) { + mat := NewMatrix( + matM0, matM4, matM8, matM12, + matM1, matM5, matM9, matM13, + matM2, matM6, matM10, matM14, + matM3, matM7, matM11, matM15, + ) + want := cQuaternionFromMatrix(mat) + got := QuaternionFromMatrix(mat) + if !testQuaternionEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionFromVector3ToVector3(b *testing.B) { + from := NewVector3(1, 2, 3) + to := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionFromVector3ToVector3(from, to) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionFromVector3ToVector3(from, to) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionFromVector3ToVector3(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + fromX, fromY, fromZ float32, + toX, toY, toZ float32, + ) { + from := NewVector3(fromX, fromY, fromZ) + to := NewVector3(toX, toY, toZ) + want := cQuaternionFromVector3ToVector3(from, to) + got := QuaternionFromVector3ToVector3(from, to) + if !testQuaternionEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionIdentity(b *testing.B) { + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionIdentity() + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionIdentity() + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func TestQuaternionIdentity(t *testing.T) { + want := cQuaternionIdentity() + got := QuaternionIdentity() + if !testQuaternionEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } +} + +func BenchmarkQuaternionInvert(b *testing.B) { + quat := NewQuaternion(1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionInvert(quat) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionInvert(quat) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionInvert(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + quatX, quatY, quatZ, quatW float32, + ) { + quat := NewQuaternion(quatX, quatY, quatZ, quatW) + want := cQuaternionInvert(quat) + got := QuaternionInvert(quat) + if !testQuaternionEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionLength(b *testing.B) { + quat := NewQuaternion(1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionLength(quat) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionLength(quat) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionLength(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + quatX, quatY, quatZ, quatW float32, + ) { + quat := NewQuaternion(quatX, quatY, quatZ, quatW) + want := cQuaternionLength(quat) + got := QuaternionLength(quat) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionLerp(b *testing.B) { + q1 := NewQuaternion(1, 2, 3, 4) + q2 := NewQuaternion(1, 2, 3, 4) + amount := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionLerp(q1, q2, amount) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionLerp(q1, q2, amount) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionLerp(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), + ) + f.Fuzz(func(t *testing.T, + q1X, q1Y, q1Z, q1W float32, + q2X, q2Y, q2Z, q2W float32, + amount float32, + ) { + q1 := NewQuaternion(q1X, q1Y, q1Z, q1W) + q2 := NewQuaternion(q2X, q2Y, q2Z, q2W) + want := cQuaternionLerp(q1, q2, amount) + got := QuaternionLerp(q1, q2, amount) + if !testQuaternionEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionMultiply(b *testing.B) { + q1 := NewQuaternion(1, 2, 3, 4) + q2 := NewQuaternion(1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionMultiply(q1, q2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionMultiply(q1, q2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionMultiply(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + q1X, q1Y, q1Z, q1W float32, + q2X, q2Y, q2Z, q2W float32, + ) { + q1 := NewQuaternion(q1X, q1Y, q1Z, q1W) + q2 := NewQuaternion(q2X, q2Y, q2Z, q2W) + want := cQuaternionMultiply(q1, q2) + got := QuaternionMultiply(q1, q2) + if !testQuaternionEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionNlerp(b *testing.B) { + q1 := NewQuaternion(1, 2, 3, 4) + q2 := NewQuaternion(1, 2, 3, 4) + amount := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionNlerp(q1, q2, amount) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionNlerp(q1, q2, amount) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionNlerp(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), + ) + f.Fuzz(func(t *testing.T, + q1X, q1Y, q1Z, q1W float32, + q2X, q2Y, q2Z, q2W float32, + amount float32, + ) { + q1 := NewQuaternion(q1X, q1Y, q1Z, q1W) + q2 := NewQuaternion(q2X, q2Y, q2Z, q2W) + want := cQuaternionNlerp(q1, q2, amount) + got := QuaternionNlerp(q1, q2, amount) + if !testQuaternionEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionNormalize(b *testing.B) { + q := NewQuaternion(1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionNormalize(q) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionNormalize(q) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionNormalize(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + qX, qY, qZ, qW float32, + ) { + q := NewQuaternion(qX, qY, qZ, qW) + want := cQuaternionNormalize(q) + got := QuaternionNormalize(q) + if !testQuaternionEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionScale(b *testing.B) { + q := NewQuaternion(1, 2, 3, 4) + mul := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionScale(q, mul) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionScale(q, mul) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionScale(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), + ) + f.Fuzz(func(t *testing.T, + qX, qY, qZ, qW float32, + mul float32, + ) { + q := NewQuaternion(qX, qY, qZ, qW) + want := cQuaternionScale(q, mul) + got := QuaternionScale(q, mul) + if !testQuaternionEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionSlerp(b *testing.B) { + q1 := NewQuaternion(1, 2, 3, 4) + q2 := NewQuaternion(1, 2, 3, 4) + amount := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionSlerp(q1, q2, amount) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionSlerp(q1, q2, amount) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionSlerp(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), + ) + f.Fuzz(func(t *testing.T, + q1X, q1Y, q1Z, q1W float32, + q2X, q2Y, q2Z, q2W float32, + amount float32, + ) { + q1 := NewQuaternion(q1X, q1Y, q1Z, q1W) + q2 := NewQuaternion(q2X, q2Y, q2Z, q2W) + want := cQuaternionSlerp(q1, q2, amount) + got := QuaternionSlerp(q1, q2, amount) + if !testQuaternionEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionSubtract(b *testing.B) { + q1 := NewQuaternion(1, 2, 3, 4) + q2 := NewQuaternion(1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionSubtract(q1, q2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionSubtract(q1, q2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionSubtract(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + q1X, q1Y, q1Z, q1W float32, + q2X, q2Y, q2Z, q2W float32, + ) { + q1 := NewQuaternion(q1X, q1Y, q1Z, q1W) + q2 := NewQuaternion(q2X, q2Y, q2Z, q2W) + want := cQuaternionSubtract(q1, q2) + got := QuaternionSubtract(q1, q2) + if !testQuaternionEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionSubtractValue(b *testing.B) { + q := NewQuaternion(1, 2, 3, 4) + sub := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionSubtractValue(q, sub) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionSubtractValue(q, sub) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionSubtractValue(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), + ) + f.Fuzz(func(t *testing.T, + qX, qY, qZ, qW float32, + sub float32, + ) { + q := NewQuaternion(qX, qY, qZ, qW) + want := cQuaternionSubtractValue(q, sub) + got := QuaternionSubtractValue(q, sub) + if !testQuaternionEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionToEuler(b *testing.B) { + q := NewQuaternion(1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionToEuler(q) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionToEuler(q) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionToEuler(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + qX, qY, qZ, qW float32, + ) { + q := NewQuaternion(qX, qY, qZ, qW) + want := cQuaternionToEuler(q) + got := QuaternionToEuler(q) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionToMatrix(b *testing.B) { + q := NewQuaternion(1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionToMatrix(q) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionToMatrix(q) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionToMatrix(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + qX, qY, qZ, qW float32, + ) { + q := NewQuaternion(qX, qY, qZ, qW) + want := cQuaternionToMatrix(q) + got := QuaternionToMatrix(q) + if !testMatrixEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkQuaternionTransform(b *testing.B) { + q := NewQuaternion(1, 2, 3, 4) + mat := NewMatrix(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cQuaternionTransform(q, mat) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + QuaternionTransform(q, mat) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionTransform(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + qX, qY, qZ, qW float32, + matM0, matM4, matM8, matM12, + matM1, matM5, matM9, matM13, + matM2, matM6, matM10, matM14, + matM3, matM7, matM11, matM15 float32, + ) { + q := NewQuaternion(qX, qY, qZ, qW) + mat := NewMatrix( + matM0, matM4, matM8, matM12, + matM1, matM5, matM9, matM13, + matM2, matM6, matM10, matM14, + matM3, matM7, matM11, matM15, + ) + want := cQuaternionTransform(q, mat) + got := QuaternionTransform(q, mat) + if !testQuaternionEquals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkRemap(b *testing.B) { + value := float32(1) + inputStart := float32(2) + inputEnd := float32(3) + outputStart := float32(4) + outputEnd := float32(5) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cRemap(value, inputStart, inputEnd, outputStart, outputEnd) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Remap(value, inputStart, inputEnd, outputStart, outputEnd) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzRemap(f *testing.F) { + f.Add( + float32(1), + float32(2), + float32(3), + float32(4), + float32(5), + ) + f.Fuzz(func(t *testing.T, + value float32, + inputStart float32, + inputEnd float32, + outputStart float32, + outputEnd float32, + ) { + want := cRemap(value, inputStart, inputEnd, outputStart, outputEnd) + got := Remap(value, inputStart, inputEnd, outputStart, outputEnd) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2Add(b *testing.B) { + v1 := NewVector2(1, 2) + v2 := NewVector2(1, 2) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2Add(v1, v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2Add(v1, v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2Add(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), float32(2), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y float32, + v2X, v2Y float32, + ) { + v1 := NewVector2(v1X, v1Y) + v2 := NewVector2(v2X, v2Y) + want := cVector2Add(v1, v2) + got := Vector2Add(v1, v2) + if !testVector2Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2AddValue(b *testing.B) { + v := NewVector2(1, 2) + add := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2AddValue(v, add) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2AddValue(v, add) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2AddValue(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), + ) + f.Fuzz(func(t *testing.T, + vX, vY float32, + add float32, + ) { + v := NewVector2(vX, vY) + want := cVector2AddValue(v, add) + got := Vector2AddValue(v, add) + if !testVector2Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2Angle(b *testing.B) { + v1 := NewVector2(1, 2) + v2 := NewVector2(1, 2) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2Angle(v1, v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2Angle(v1, v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2Angle(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), float32(2), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y float32, + v2X, v2Y float32, + ) { + v1 := NewVector2(v1X, v1Y) + v2 := NewVector2(v2X, v2Y) + want := cVector2Angle(v1, v2) + got := Vector2Angle(v1, v2) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2Clamp(b *testing.B) { + v := NewVector2(1, 2) + min := NewVector2(1, 2) + max := NewVector2(1, 2) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2Clamp(v, min, max) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2Clamp(v, min, max) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2Clamp(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), float32(2), + float32(1), float32(2), + ) + f.Fuzz(func(t *testing.T, + vX, vY float32, + minX, minY float32, + maxX, maxY float32, + ) { + v := NewVector2(vX, vY) + min := NewVector2(minX, minY) + max := NewVector2(maxX, maxY) + want := cVector2Clamp(v, min, max) + got := Vector2Clamp(v, min, max) + if !testVector2Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2ClampValue(b *testing.B) { + v := NewVector2(1, 2) + min := float32(1) + max := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2ClampValue(v, min, max) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2ClampValue(v, min, max) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2ClampValue(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), + float32(1), + ) + f.Fuzz(func(t *testing.T, + vX, vY float32, + min float32, + max float32, + ) { + v := NewVector2(vX, vY) + want := cVector2ClampValue(v, min, max) + got := Vector2ClampValue(v, min, max) + if !testVector2Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2CrossProduct(b *testing.B) { + v1 := NewVector2(1, 2) + v2 := NewVector2(1, 2) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2CrossProduct(v1, v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2CrossProduct(v1, v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2CrossProduct(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), float32(2), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y float32, + v2X, v2Y float32, + ) { + v1 := NewVector2(v1X, v1Y) + v2 := NewVector2(v2X, v2Y) + want := cVector2CrossProduct(v1, v2) + got := Vector2CrossProduct(v1, v2) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2Distance(b *testing.B) { + v1 := NewVector2(1, 2) + v2 := NewVector2(1, 2) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2Distance(v1, v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2Distance(v1, v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2Distance(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), float32(2), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y float32, + v2X, v2Y float32, + ) { + v1 := NewVector2(v1X, v1Y) + v2 := NewVector2(v2X, v2Y) + want := cVector2Distance(v1, v2) + got := Vector2Distance(v1, v2) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2DistanceSqr(b *testing.B) { + v1 := NewVector2(1, 2) + v2 := NewVector2(1, 2) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2DistanceSqr(v1, v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2DistanceSqr(v1, v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2DistanceSqr(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), float32(2), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y float32, + v2X, v2Y float32, + ) { + v1 := NewVector2(v1X, v1Y) + v2 := NewVector2(v2X, v2Y) + want := cVector2DistanceSqr(v1, v2) + got := Vector2DistanceSqr(v1, v2) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2Divide(b *testing.B) { + v1 := NewVector2(1, 2) + v2 := NewVector2(1, 2) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2Divide(v1, v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2Divide(v1, v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2Divide(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), float32(2), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y float32, + v2X, v2Y float32, + ) { + v1 := NewVector2(v1X, v1Y) + v2 := NewVector2(v2X, v2Y) + want := cVector2Divide(v1, v2) + got := Vector2Divide(v1, v2) + if !testVector2Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2DotProduct(b *testing.B) { + v1 := NewVector2(1, 2) + v2 := NewVector2(1, 2) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2DotProduct(v1, v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2DotProduct(v1, v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2DotProduct(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), float32(2), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y float32, + v2X, v2Y float32, + ) { + v1 := NewVector2(v1X, v1Y) + v2 := NewVector2(v2X, v2Y) + want := cVector2DotProduct(v1, v2) + got := Vector2DotProduct(v1, v2) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2Equals(b *testing.B) { + p := NewVector2(1, 2) + q := NewVector2(1, 2) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2Equals(p, q) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2Equals(p, q) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2Equals(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), float32(2), + ) + f.Fuzz(func(t *testing.T, + pX, pY float32, + qX, qY float32, + ) { + p := NewVector2(pX, pY) + q := NewVector2(qX, qY) + want := cVector2Equals(p, q) + got := Vector2Equals(p, q) + if want != got { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2Invert(b *testing.B) { + v := NewVector2(1, 2) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2Invert(v) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2Invert(v) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2Invert(f *testing.F) { + f.Add( + float32(1), float32(2), + ) + f.Fuzz(func(t *testing.T, + vX, vY float32, + ) { + v := NewVector2(vX, vY) + want := cVector2Invert(v) + got := Vector2Invert(v) + if !testVector2Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2Length(b *testing.B) { + v := NewVector2(1, 2) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2Length(v) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2Length(v) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2Length(f *testing.F) { + f.Add( + float32(1), float32(2), + ) + f.Fuzz(func(t *testing.T, + vX, vY float32, + ) { + v := NewVector2(vX, vY) + want := cVector2Length(v) + got := Vector2Length(v) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2LengthSqr(b *testing.B) { + v := NewVector2(1, 2) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2LengthSqr(v) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2LengthSqr(v) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2LengthSqr(f *testing.F) { + f.Add( + float32(1), float32(2), + ) + f.Fuzz(func(t *testing.T, + vX, vY float32, + ) { + v := NewVector2(vX, vY) + want := cVector2LengthSqr(v) + got := Vector2LengthSqr(v) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2Lerp(b *testing.B) { + v1 := NewVector2(1, 2) + v2 := NewVector2(1, 2) + amount := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2Lerp(v1, v2, amount) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2Lerp(v1, v2, amount) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2Lerp(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), float32(2), + float32(1), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y float32, + v2X, v2Y float32, + amount float32, + ) { + v1 := NewVector2(v1X, v1Y) + v2 := NewVector2(v2X, v2Y) + want := cVector2Lerp(v1, v2, amount) + got := Vector2Lerp(v1, v2, amount) + if !testVector2Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2LineAngle(b *testing.B) { + start := NewVector2(1, 2) + end := NewVector2(1, 2) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2LineAngle(start, end) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2LineAngle(start, end) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2LineAngle(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), float32(2), + ) + f.Fuzz(func(t *testing.T, + startX, startY float32, + endX, endY float32, + ) { + start := NewVector2(startX, startY) + end := NewVector2(endX, endY) + want := cVector2LineAngle(start, end) + got := Vector2LineAngle(start, end) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2MoveTowards(b *testing.B) { + v := NewVector2(1, 2) + target := NewVector2(1, 2) + maxDistance := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2MoveTowards(v, target, maxDistance) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2MoveTowards(v, target, maxDistance) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2MoveTowards(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), float32(2), + float32(1), + ) + f.Fuzz(func(t *testing.T, + vX, vY float32, + targetX, targetY float32, + maxDistance float32, + ) { + v := NewVector2(vX, vY) + target := NewVector2(targetX, targetY) + want := cVector2MoveTowards(v, target, maxDistance) + got := Vector2MoveTowards(v, target, maxDistance) + if !testVector2Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2Multiply(b *testing.B) { + v1 := NewVector2(1, 2) + v2 := NewVector2(1, 2) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2Multiply(v1, v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2Multiply(v1, v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2Multiply(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), float32(2), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y float32, + v2X, v2Y float32, + ) { + v1 := NewVector2(v1X, v1Y) + v2 := NewVector2(v2X, v2Y) + want := cVector2Multiply(v1, v2) + got := Vector2Multiply(v1, v2) + if !testVector2Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2Negate(b *testing.B) { + v := NewVector2(1, 2) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2Negate(v) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2Negate(v) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2Negate(f *testing.F) { + f.Add( + float32(1), float32(2), + ) + f.Fuzz(func(t *testing.T, + vX, vY float32, + ) { + v := NewVector2(vX, vY) + want := cVector2Negate(v) + got := Vector2Negate(v) + if !testVector2Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2Normalize(b *testing.B) { + v := NewVector2(1, 2) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2Normalize(v) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2Normalize(v) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2Normalize(f *testing.F) { + f.Add( + float32(1), float32(2), + ) + f.Fuzz(func(t *testing.T, + vX, vY float32, + ) { + v := NewVector2(vX, vY) + want := cVector2Normalize(v) + got := Vector2Normalize(v) + if !testVector2Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2One(b *testing.B) { + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2One() + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2One() + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func TestVector2One(t *testing.T) { + want := cVector2One() + got := Vector2One() + if !testVector2Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } +} + +func BenchmarkVector2Reflect(b *testing.B) { + v := NewVector2(1, 2) + normal := NewVector2(1, 2) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2Reflect(v, normal) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2Reflect(v, normal) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2Reflect(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), float32(2), + ) + f.Fuzz(func(t *testing.T, + vX, vY float32, + normalX, normalY float32, + ) { + v := NewVector2(vX, vY) + normal := NewVector2(normalX, normalY) + want := cVector2Reflect(v, normal) + got := Vector2Reflect(v, normal) + if !testVector2Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2Rotate(b *testing.B) { + v := NewVector2(1, 2) + angle := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2Rotate(v, angle) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2Rotate(v, angle) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2Rotate(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), + ) + f.Fuzz(func(t *testing.T, + vX, vY float32, + angle float32, + ) { + v := NewVector2(vX, vY) + want := cVector2Rotate(v, angle) + got := Vector2Rotate(v, angle) + if !testVector2Equals(want, got, 1e-2) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2Scale(b *testing.B) { + v := NewVector2(1, 2) + scale := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2Scale(v, scale) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2Scale(v, scale) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2Scale(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), + ) + f.Fuzz(func(t *testing.T, + vX, vY float32, + scale float32, + ) { + v := NewVector2(vX, vY) + want := cVector2Scale(v, scale) + got := Vector2Scale(v, scale) + if !testVector2Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2Subtract(b *testing.B) { + v1 := NewVector2(1, 2) + v2 := NewVector2(1, 2) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2Subtract(v1, v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2Subtract(v1, v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2Subtract(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), float32(2), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y float32, + v2X, v2Y float32, + ) { + v1 := NewVector2(v1X, v1Y) + v2 := NewVector2(v2X, v2Y) + want := cVector2Subtract(v1, v2) + got := Vector2Subtract(v1, v2) + if !testVector2Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2SubtractValue(b *testing.B) { + v := NewVector2(1, 2) + sub := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2SubtractValue(v, sub) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2SubtractValue(v, sub) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2SubtractValue(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), + ) + f.Fuzz(func(t *testing.T, + vX, vY float32, + sub float32, + ) { + v := NewVector2(vX, vY) + want := cVector2SubtractValue(v, sub) + got := Vector2SubtractValue(v, sub) + if !testVector2Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2Transform(b *testing.B) { + v := NewVector2(1, 2) + mat := NewMatrix(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2Transform(v, mat) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2Transform(v, mat) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector2Transform(f *testing.F) { + f.Add( + float32(1), float32(2), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + vX, vY float32, + matM0, matM4, matM8, matM12, + matM1, matM5, matM9, matM13, + matM2, matM6, matM10, matM14, + matM3, matM7, matM11, matM15 float32, + ) { + v := NewVector2(vX, vY) + mat := NewMatrix( + matM0, matM4, matM8, matM12, + matM1, matM5, matM9, matM13, + matM2, matM6, matM10, matM14, + matM3, matM7, matM11, matM15, + ) + want := cVector2Transform(v, mat) + got := Vector2Transform(v, mat) + if !testVector2Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector2Zero(b *testing.B) { + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector2Zero() + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector2Zero() + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func TestVector2Zero(t *testing.T) { + want := cVector2Zero() + got := Vector2Zero() + if !testVector2Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } +} + +func BenchmarkVector3Add(b *testing.B) { + v1 := NewVector3(1, 2, 3) + v2 := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Add(v1, v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Add(v1, v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Add(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y, v1Z float32, + v2X, v2Y, v2Z float32, + ) { + v1 := NewVector3(v1X, v1Y, v1Z) + v2 := NewVector3(v2X, v2Y, v2Z) + want := cVector3Add(v1, v2) + got := Vector3Add(v1, v2) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3AddValue(b *testing.B) { + v := NewVector3(1, 2, 3) + add := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3AddValue(v, add) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3AddValue(v, add) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3AddValue(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), + ) + f.Fuzz(func(t *testing.T, + vX, vY, vZ float32, + add float32, + ) { + v := NewVector3(vX, vY, vZ) + want := cVector3AddValue(v, add) + got := Vector3AddValue(v, add) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Angle(b *testing.B) { + v1 := NewVector3(1, 2, 3) + v2 := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Angle(v1, v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Angle(v1, v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Angle(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y, v1Z float32, + v2X, v2Y, v2Z float32, + ) { + v1 := NewVector3(v1X, v1Y, v1Z) + v2 := NewVector3(v2X, v2Y, v2Z) + want := cVector3Angle(v1, v2) + got := Vector3Angle(v1, v2) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Barycenter(b *testing.B) { + p := NewVector3(1, 2, 3) + a := NewVector3(1, 2, 3) + b1 := NewVector3(1, 2, 3) + c := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Barycenter(p, a, b1, c) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Barycenter(p, a, b1, c) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Barycenter(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + pX, pY, pZ float32, + aX, aY, aZ float32, + bX, bY, bZ float32, + cX, cY, cZ float32, + ) { + p := NewVector3(pX, pY, pZ) + a := NewVector3(aX, aY, aZ) + b1 := NewVector3(bX, bY, bZ) + c := NewVector3(cX, cY, cZ) + want := cVector3Barycenter(p, a, b1, c) + got := Vector3Barycenter(p, a, b1, c) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Clamp(b *testing.B) { + v := NewVector3(1, 2, 3) + min := NewVector3(1, 2, 3) + max := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Clamp(v, min, max) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Clamp(v, min, max) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Clamp(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + vX, vY, vZ float32, + minX, minY, minZ float32, + maxX, maxY, maxZ float32, + ) { + v := NewVector3(vX, vY, vZ) + min := NewVector3(minX, minY, minZ) + max := NewVector3(maxX, maxY, maxZ) + want := cVector3Clamp(v, min, max) + got := Vector3Clamp(v, min, max) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3ClampValue(b *testing.B) { + v := NewVector3(1, 2, 3) + min := float32(1) + max := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3ClampValue(v, min, max) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3ClampValue(v, min, max) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3ClampValue(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), + float32(1), + ) + f.Fuzz(func(t *testing.T, + vX, vY, vZ float32, + min float32, + max float32, + ) { + v := NewVector3(vX, vY, vZ) + want := cVector3ClampValue(v, min, max) + got := Vector3ClampValue(v, min, max) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3CrossProduct(b *testing.B) { + v1 := NewVector3(1, 2, 3) + v2 := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3CrossProduct(v1, v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3CrossProduct(v1, v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3CrossProduct(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y, v1Z float32, + v2X, v2Y, v2Z float32, + ) { + v1 := NewVector3(v1X, v1Y, v1Z) + v2 := NewVector3(v2X, v2Y, v2Z) + want := cVector3CrossProduct(v1, v2) + got := Vector3CrossProduct(v1, v2) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Distance(b *testing.B) { + v1 := NewVector3(1, 2, 3) + v2 := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Distance(v1, v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Distance(v1, v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Distance(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y, v1Z float32, + v2X, v2Y, v2Z float32, + ) { + v1 := NewVector3(v1X, v1Y, v1Z) + v2 := NewVector3(v2X, v2Y, v2Z) + want := cVector3Distance(v1, v2) + got := Vector3Distance(v1, v2) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3DistanceSqr(b *testing.B) { + v1 := NewVector3(1, 2, 3) + v2 := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3DistanceSqr(v1, v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3DistanceSqr(v1, v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3DistanceSqr(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y, v1Z float32, + v2X, v2Y, v2Z float32, + ) { + v1 := NewVector3(v1X, v1Y, v1Z) + v2 := NewVector3(v2X, v2Y, v2Z) + want := cVector3DistanceSqr(v1, v2) + got := Vector3DistanceSqr(v1, v2) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Divide(b *testing.B) { + v1 := NewVector3(1, 2, 3) + v2 := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Divide(v1, v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Divide(v1, v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Divide(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y, v1Z float32, + v2X, v2Y, v2Z float32, + ) { + v1 := NewVector3(v1X, v1Y, v1Z) + v2 := NewVector3(v2X, v2Y, v2Z) + want := cVector3Divide(v1, v2) + got := Vector3Divide(v1, v2) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3DotProduct(b *testing.B) { + v1 := NewVector3(1, 2, 3) + v2 := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3DotProduct(v1, v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3DotProduct(v1, v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3DotProduct(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y, v1Z float32, + v2X, v2Y, v2Z float32, + ) { + v1 := NewVector3(v1X, v1Y, v1Z) + v2 := NewVector3(v2X, v2Y, v2Z) + want := cVector3DotProduct(v1, v2) + got := Vector3DotProduct(v1, v2) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Equals(b *testing.B) { + p := NewVector3(1, 2, 3) + q := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Equals(p, q) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Equals(p, q) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Equals(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + pX, pY, pZ float32, + qX, qY, qZ float32, + ) { + p := NewVector3(pX, pY, pZ) + q := NewVector3(qX, qY, qZ) + want := cVector3Equals(p, q) + got := Vector3Equals(p, q) + if want != got { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Invert(b *testing.B) { + v := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Invert(v) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Invert(v) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Invert(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + vX, vY, vZ float32, + ) { + v := NewVector3(vX, vY, vZ) + want := cVector3Invert(v) + got := Vector3Invert(v) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Length(b *testing.B) { + v := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Length(v) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Length(v) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Length(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + vX, vY, vZ float32, + ) { + v := NewVector3(vX, vY, vZ) + want := cVector3Length(v) + got := Vector3Length(v) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3LengthSqr(b *testing.B) { + v := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3LengthSqr(v) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3LengthSqr(v) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3LengthSqr(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + vX, vY, vZ float32, + ) { + v := NewVector3(vX, vY, vZ) + want := cVector3LengthSqr(v) + got := Vector3LengthSqr(v) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Lerp(b *testing.B) { + v1 := NewVector3(1, 2, 3) + v2 := NewVector3(1, 2, 3) + amount := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Lerp(v1, v2, amount) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Lerp(v1, v2, amount) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Lerp(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + float32(1), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y, v1Z float32, + v2X, v2Y, v2Z float32, + amount float32, + ) { + v1 := NewVector3(v1X, v1Y, v1Z) + v2 := NewVector3(v2X, v2Y, v2Z) + want := cVector3Lerp(v1, v2, amount) + got := Vector3Lerp(v1, v2, amount) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Max(b *testing.B) { + vec1 := NewVector3(1, 2, 3) + vec2 := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Max(vec1, vec2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Max(vec1, vec2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Max(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + vec1X, vec1Y, vec1Z float32, + vec2X, vec2Y, vec2Z float32, + ) { + vec1 := NewVector3(vec1X, vec1Y, vec1Z) + vec2 := NewVector3(vec2X, vec2Y, vec2Z) + want := cVector3Max(vec1, vec2) + got := Vector3Max(vec1, vec2) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Min(b *testing.B) { + vec1 := NewVector3(1, 2, 3) + vec2 := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Min(vec1, vec2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Min(vec1, vec2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Min(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + vec1X, vec1Y, vec1Z float32, + vec2X, vec2Y, vec2Z float32, + ) { + vec1 := NewVector3(vec1X, vec1Y, vec1Z) + vec2 := NewVector3(vec2X, vec2Y, vec2Z) + want := cVector3Min(vec1, vec2) + got := Vector3Min(vec1, vec2) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Multiply(b *testing.B) { + v1 := NewVector3(1, 2, 3) + v2 := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Multiply(v1, v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Multiply(v1, v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Multiply(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y, v1Z float32, + v2X, v2Y, v2Z float32, + ) { + v1 := NewVector3(v1X, v1Y, v1Z) + v2 := NewVector3(v2X, v2Y, v2Z) + want := cVector3Multiply(v1, v2) + got := Vector3Multiply(v1, v2) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Negate(b *testing.B) { + v := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Negate(v) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Negate(v) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Negate(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + vX, vY, vZ float32, + ) { + v := NewVector3(vX, vY, vZ) + want := cVector3Negate(v) + got := Vector3Negate(v) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Normalize(b *testing.B) { + v := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Normalize(v) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Normalize(v) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Normalize(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + vX, vY, vZ float32, + ) { + v := NewVector3(vX, vY, vZ) + want := cVector3Normalize(v) + got := Vector3Normalize(v) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3One(b *testing.B) { + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3One() + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3One() + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func TestVector3One(t *testing.T) { + want := cVector3One() + got := Vector3One() + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } +} + +func BenchmarkVector3Perpendicular(b *testing.B) { + v := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Perpendicular(v) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Perpendicular(v) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Perpendicular(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + vX, vY, vZ float32, + ) { + v := NewVector3(vX, vY, vZ) + want := cVector3Perpendicular(v) + got := Vector3Perpendicular(v) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Project(b *testing.B) { + v1 := NewVector3(1, 2, 3) + v2 := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Project(v1, v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Project(v1, v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Project(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y, v1Z float32, + v2X, v2Y, v2Z float32, + ) { + v1 := NewVector3(v1X, v1Y, v1Z) + v2 := NewVector3(v2X, v2Y, v2Z) + want := cVector3Project(v1, v2) + got := Vector3Project(v1, v2) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Reflect(b *testing.B) { + vector := NewVector3(1, 2, 3) + normal := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Reflect(vector, normal) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Reflect(vector, normal) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Reflect(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + vectorX, vectorY, vectorZ float32, + normalX, normalY, normalZ float32, + ) { + vector := NewVector3(vectorX, vectorY, vectorZ) + normal := NewVector3(normalX, normalY, normalZ) + want := cVector3Reflect(vector, normal) + got := Vector3Reflect(vector, normal) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Refract(b *testing.B) { + v := NewVector3(1, 2, 3) + n := NewVector3(1, 2, 3) + r := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Refract(v, n, r) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Refract(v, n, r) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Refract(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + float32(1), + ) + f.Fuzz(func(t *testing.T, + vX, vY, vZ float32, + nX, nY, nZ float32, + r float32, + ) { + v := NewVector3(vX, vY, vZ) + n := NewVector3(nX, nY, nZ) + want := cVector3Refract(v, n, r) + got := Vector3Refract(v, n, r) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Reject(b *testing.B) { + v1 := NewVector3(1, 2, 3) + v2 := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Reject(v1, v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Reject(v1, v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Reject(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y, v1Z float32, + v2X, v2Y, v2Z float32, + ) { + v1 := NewVector3(v1X, v1Y, v1Z) + v2 := NewVector3(v2X, v2Y, v2Z) + want := cVector3Reject(v1, v2) + got := Vector3Reject(v1, v2) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3RotateByAxisAngle(b *testing.B) { + v := NewVector3(1, 2, 3) + axis := NewVector3(1, 2, 3) + angle := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3RotateByAxisAngle(v, axis, angle) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3RotateByAxisAngle(v, axis, angle) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3RotateByAxisAngle(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + float32(1), + ) + f.Fuzz(func(t *testing.T, + vX, vY, vZ float32, + axisX, axisY, axisZ float32, + angle float32, + ) { + v := NewVector3(vX, vY, vZ) + axis := NewVector3(axisX, axisY, axisZ) + want := cVector3RotateByAxisAngle(v, axis, angle) + got := Vector3RotateByAxisAngle(v, axis, angle) + if !testVector3Equals(want, got, 1e-2) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3RotateByQuaternion(b *testing.B) { + v := NewVector3(1, 2, 3) + q := NewQuaternion(1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3RotateByQuaternion(v, q) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3RotateByQuaternion(v, q) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3RotateByQuaternion(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + vX, vY, vZ float32, + qX, qY, qZ, qW float32, + ) { + v := NewVector3(vX, vY, vZ) + q := NewQuaternion(qX, qY, qZ, qW) + want := cVector3RotateByQuaternion(v, q) + got := Vector3RotateByQuaternion(v, q) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Scale(b *testing.B) { + v := NewVector3(1, 2, 3) + scale := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Scale(v, scale) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Scale(v, scale) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Scale(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), + ) + f.Fuzz(func(t *testing.T, + vX, vY, vZ float32, + scale float32, + ) { + v := NewVector3(vX, vY, vZ) + want := cVector3Scale(v, scale) + got := Vector3Scale(v, scale) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Subtract(b *testing.B) { + v1 := NewVector3(1, 2, 3) + v2 := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Subtract(v1, v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Subtract(v1, v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Subtract(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y, v1Z float32, + v2X, v2Y, v2Z float32, + ) { + v1 := NewVector3(v1X, v1Y, v1Z) + v2 := NewVector3(v2X, v2Y, v2Z) + want := cVector3Subtract(v1, v2) + got := Vector3Subtract(v1, v2) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3SubtractValue(b *testing.B) { + v := NewVector3(1, 2, 3) + sub := float32(1) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3SubtractValue(v, sub) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3SubtractValue(v, sub) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3SubtractValue(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), + ) + f.Fuzz(func(t *testing.T, + vX, vY, vZ float32, + sub float32, + ) { + v := NewVector3(vX, vY, vZ) + want := cVector3SubtractValue(v, sub) + got := Vector3SubtractValue(v, sub) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3ToFloatV(b *testing.B) { + v := NewVector3(1, 2, 3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3ToFloatV(v) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3ToFloatV(v) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3ToFloatV(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + vX, vY, vZ float32, + ) { + v := NewVector3(vX, vY, vZ) + want := cVector3ToFloatV(v) + got := Vector3ToFloatV(v) + if !testFloat32SliceEquals(want[:], got[:], 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Transform(b *testing.B) { + v := NewVector3(1, 2, 3) + mat := NewMatrix(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Transform(v, mat) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Transform(v, mat) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Transform(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + vX, vY, vZ float32, + matM0, matM4, matM8, matM12, + matM1, matM5, matM9, matM13, + matM2, matM6, matM10, matM14, + matM3, matM7, matM11, matM15 float32, + ) { + v := NewVector3(vX, vY, vZ) + mat := NewMatrix( + matM0, matM4, matM8, matM12, + matM1, matM5, matM9, matM13, + matM2, matM6, matM10, matM14, + matM3, matM7, matM11, matM15, + ) + want := cVector3Transform(v, mat) + got := Vector3Transform(v, mat) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Unproject(b *testing.B) { + source := NewVector3(1, 2, 3) + projection := NewMatrix(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4) + view := NewMatrix(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Unproject(source, projection, view) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Unproject(source, projection, view) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3Unproject(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + sourceX, sourceY, sourceZ float32, + projectionM0, projectionM4, projectionM8, projectionM12, + projectionM1, projectionM5, projectionM9, projectionM13, + projectionM2, projectionM6, projectionM10, projectionM14, + projectionM3, projectionM7, projectionM11, projectionM15 float32, + viewM0, viewM4, viewM8, viewM12, + viewM1, viewM5, viewM9, viewM13, + viewM2, viewM6, viewM10, viewM14, + viewM3, viewM7, viewM11, viewM15 float32, + ) { + source := NewVector3(sourceX, sourceY, sourceZ) + projection := NewMatrix( + projectionM0, projectionM4, projectionM8, projectionM12, + projectionM1, projectionM5, projectionM9, projectionM13, + projectionM2, projectionM6, projectionM10, projectionM14, + projectionM3, projectionM7, projectionM11, projectionM15, + ) + view := NewMatrix( + viewM0, viewM4, viewM8, viewM12, + viewM1, viewM5, viewM9, viewM13, + viewM2, viewM6, viewM10, viewM14, + viewM3, viewM7, viewM11, viewM15, + ) + want := cVector3Unproject(source, projection, view) + got := Vector3Unproject(source, projection, view) + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +func BenchmarkVector3Zero(b *testing.B) { + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cVector3Zero() + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Vector3Zero() + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func TestVector3Zero(t *testing.T) { + want := cVector3Zero() + got := Vector3Zero() + if !testVector3Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } +} + +func BenchmarkWrap(b *testing.B) { + value := float32(1) + min := float32(2) + max := float32(3) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cWrap(value, min, max) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Wrap(value, min, max) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzWrap(f *testing.F) { + f.Add( + float32(1), + float32(2), + float32(3), + ) + f.Fuzz(func(t *testing.T, + value float32, + min float32, + max float32, + ) { + want := cWrap(value, min, max) + got := Wrap(value, min, max) + if !testFloat32Equals(want, got, 1e-6) { + t.Errorf("got %v; want %v", got, want) + } + }) +} + +// helpers + +func testFloat32Equals(a, b float32, epsilon float64) bool { + if math.IsNaN(float64(a)) && math.IsNaN(float64(b)) { + return true + } + if math.IsInf(float64(a), 1) && math.IsInf(float64(b), 1) { + return true + } + if math.IsInf(float64(a), -1) && math.IsInf(float64(b), -1) { + return true + } + return math.Abs(float64(a-b)) <= epsilon*math.Max(1.0, math.Max(math.Abs(float64(a)), math.Abs(float64(b)))) +} + +func testFloat32SliceEquals(a, b []float32, epsilon float64) bool { + if len(a) != len(b) { + return false + } + for i := range a { + if !testFloat32Equals(a[i], b[i], epsilon) { + return false + } + } + return true +} + +func testVector2Equals(a, b Vector2, epsilon float64) bool { + return testFloat32Equals(a.X, b.X, epsilon) && + testFloat32Equals(a.Y, b.Y, epsilon) +} + +func testVector3Equals(a, b Vector3, epsilon float64) bool { + return testFloat32Equals(a.X, b.X, epsilon) && + testFloat32Equals(a.Y, b.Y, epsilon) && + testFloat32Equals(a.Z, b.Z, epsilon) +} + +func testQuaternionEquals(a, b Quaternion, epsilon float64) bool { + return testFloat32Equals(a.X, b.X, epsilon) && + testFloat32Equals(a.Y, b.Y, epsilon) && + testFloat32Equals(a.Z, b.Z, epsilon) && + testFloat32Equals(a.W, b.W, epsilon) +} + +func testMatrixEquals(a, b Matrix, epsilon float64) bool { + return testFloat32Equals(a.M0, b.M0, epsilon) && + testFloat32Equals(a.M1, b.M1, epsilon) && + testFloat32Equals(a.M2, b.M2, epsilon) && + testFloat32Equals(a.M3, b.M3, epsilon) && + testFloat32Equals(a.M4, b.M4, epsilon) && + testFloat32Equals(a.M5, b.M5, epsilon) && + testFloat32Equals(a.M6, b.M6, epsilon) && + testFloat32Equals(a.M7, b.M7, epsilon) && + testFloat32Equals(a.M8, b.M8, epsilon) && + testFloat32Equals(a.M9, b.M9, epsilon) && + testFloat32Equals(a.M10, b.M10, epsilon) && + testFloat32Equals(a.M11, b.M11, epsilon) && + testFloat32Equals(a.M12, b.M12, epsilon) && + testFloat32Equals(a.M13, b.M13, epsilon) && + testFloat32Equals(a.M14, b.M14, epsilon) && + testFloat32Equals(a.M15, b.M15, epsilon) +} diff --git a/raylib/raymath_test.go b/raylib/raymath_test.go new file mode 100644 index 00000000..dc28d1b7 --- /dev/null +++ b/raylib/raymath_test.go @@ -0,0 +1,192 @@ +package rl + +import ( + "testing" + "time" +) + +// tests in raymath_generated_test.go too + +func BenchmarkVector3OrthoNormalize(b *testing.B) { + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + v1 := NewVector3(1, 2, 3) + v2 := NewVector3(1, 2, 3) + cVector3OrthoNormalize(&v1, &v2) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + v1 := NewVector3(1, 2, 3) + v2 := NewVector3(1, 2, 3) + Vector3OrthoNormalize(&v1, &v2) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzVector3OrthoNormalize(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), + float32(1), float32(2), float32(3), + ) + f.Fuzz(func(t *testing.T, + v1X, v1Y, v1Z float32, + v2X, v2Y, v2Z float32, + ) { + want1 := NewVector3(v1X, v1Y, v1Z) + want2 := NewVector3(v2X, v2Y, v2Z) + cVector3OrthoNormalize(&want1, &want2) + + got1 := NewVector3(v1X, v1Y, v1Z) + got2 := NewVector3(v2X, v2Y, v2Z) + Vector3OrthoNormalize(&got1, &got2) + + if !testVector3Equals(want1, got1, 1e-6) { + t.Errorf("v1: got %v; want %v", got1, want1) + } + if !testVector3Equals(want2, got2, 1e-6) { + t.Errorf("v2: got %v; want %v", got2, want2) + } + }) +} + +func BenchmarkQuaternionToAxisAngle(b *testing.B) { + q := NewQuaternion(1, 2, 3, 4) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + var axis Vector3 + var angle float32 + cQuaternionToAxisAngle(q, &axis, &angle) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + var outAxis Vector3 + var outAngle float32 + QuaternionToAxisAngle(q, &outAxis, &outAngle) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzQuaternionToAxisAngle(f *testing.F) { + skip := NewVector3(1, 0, 0) + f.Add( + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + qX, qY, qZ, qW float32, + ) { + q := NewQuaternion(qX, qY, qZ, qW) + + var wantAxis Vector3 + var wantAngle float32 + cQuaternionToAxisAngle(q, &wantAxis, &wantAngle) + + var gotAxis Vector3 + var gotAngle float32 + QuaternionToAxisAngle(q, &gotAxis, &gotAngle) + + if !testVector3Equals(wantAxis, skip, 1e-6) && // it's ok if our version has higher precision + !testVector3Equals(wantAxis, gotAxis, 0.2) { + t.Errorf("axis: got %v; want %v", gotAxis, wantAxis) + } + if !testFloat32Equals(wantAngle, gotAngle, 1e-3) { + t.Errorf("angle: got %v; want %v", gotAngle, wantAngle) + } + }) +} + +func BenchmarkMatrixDecompose(b *testing.B) { + mat := NewMatrix( + 1, 2, 3, 4, + 1, 2, 3, 4, + 1, 2, 3, 4, + 1, 2, 3, 4, + ) + var ( + perCCall time.Duration + perGoCall time.Duration + ) + b.Run("c", func(b *testing.B) { + for i := 0; i < b.N; i++ { + var translation Vector3 + var rotation Quaternion + var scale Vector3 + cMatrixDecompose(mat, &translation, &rotation, &scale) + } + perCCall = b.Elapsed() / time.Duration(b.N) + }) + b.Run("go", func(b *testing.B) { + for i := 0; i < b.N; i++ { + var translation Vector3 + var rotation Quaternion + var scale Vector3 + MatrixDecompose(mat, &translation, &rotation, &scale) + } + perGoCall = b.Elapsed() / time.Duration(b.N) + }) + if perCCall < perGoCall { + b.Log("Go slower than C") + } +} + +func FuzzMatrixDecompose(f *testing.F) { + f.Add( + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + float32(1), float32(2), float32(3), float32(4), + ) + f.Fuzz(func(t *testing.T, + m0, m4, m8, m12, + m1, m5, m9, m13, + m2, m6, m10, m14, + m3, m7, m11, m15 float32, + + ) { + mat := NewMatrix( + m0, m4, m8, m12, + m1, m5, m9, m13, + m2, m6, m10, m14, + m3, m7, m11, m15, + ) + + var wantTranslation Vector3 + var wantRotation Quaternion + var wantScale Vector3 + cMatrixDecompose(mat, &wantTranslation, &wantRotation, &wantScale) + + var gotTranslation Vector3 + var gotRotation Quaternion + var gotScale Vector3 + cMatrixDecompose(mat, &gotTranslation, &gotRotation, &gotScale) + + if !testVector3Equals(wantTranslation, gotTranslation, 1e-6) { + t.Errorf("translation: got %v; want %v", gotTranslation, wantTranslation) + } + if !testQuaternionEquals(wantRotation, gotRotation, 1e-6) { + t.Errorf("rotation: got %v; want %v", gotRotation, wantRotation) + } + if !testVector3Equals(wantScale, gotScale, 1e-6) { + t.Errorf("scale: got %v; want %v", gotScale, wantScale) + } + }) +} diff --git a/raylib/rcore.go b/raylib/rcore.go index 9d029d78..9533a75c 100644 --- a/raylib/rcore.go +++ b/raylib/rcore.go @@ -891,16 +891,6 @@ func GetPixelDataSize(width, height, format int32) int32 { return v } -// Vector3ToFloat - Converts Vector3 to float32 slice -func Vector3ToFloat(vec Vector3) []float32 { - data := make([]float32, 0) - data[0] = vec.X - data[1] = vec.Y - data[2] = vec.Z - - return data -} - // GetRandomValue - Returns a random value between min and max (both included) func GetRandomValue(min, max int32) int32 { cmin := (C.int)(min) diff --git a/raylib/testdata/fuzz/FuzzMatrixDeterminant/ef7c045ed1986603 b/raylib/testdata/fuzz/FuzzMatrixDeterminant/ef7c045ed1986603 new file mode 100644 index 00000000..611c47dd --- /dev/null +++ b/raylib/testdata/fuzz/FuzzMatrixDeterminant/ef7c045ed1986603 @@ -0,0 +1,17 @@ +go test fuzz v1 +float32(1) +float32(2) +float32(3) +float32(4) +float32(1) +float32(0.22222222) +float32(3) +float32(4) +float32(1) +float32(2) +float32(3) +float32(4) +float32(1) +float32(2) +float32(3) +float32(4) diff --git a/raylib/testdata/fuzz/FuzzMatrixFrustum/14155074da34118b b/raylib/testdata/fuzz/FuzzMatrixFrustum/14155074da34118b new file mode 100644 index 00000000..8764696f --- /dev/null +++ b/raylib/testdata/fuzz/FuzzMatrixFrustum/14155074da34118b @@ -0,0 +1,7 @@ +go test fuzz v1 +float32(0) +float32(-92) +float32(-8) +float32(0) +float32(0) +float32(0) diff --git a/raylib/testdata/fuzz/FuzzMatrixLookAt/8fbc1d984795cc11 b/raylib/testdata/fuzz/FuzzMatrixLookAt/8fbc1d984795cc11 new file mode 100644 index 00000000..112ce7ab --- /dev/null +++ b/raylib/testdata/fuzz/FuzzMatrixLookAt/8fbc1d984795cc11 @@ -0,0 +1,10 @@ +go test fuzz v1 +float32(1) +float32(2) +float32(3) +float32(1) +float32(2) +float32(0.5) +float32(1) +float32(2) +float32(3) diff --git a/raylib/testdata/fuzz/FuzzMatrixLookAt/9ad75835daa1541f b/raylib/testdata/fuzz/FuzzMatrixLookAt/9ad75835daa1541f new file mode 100644 index 00000000..92b32567 --- /dev/null +++ b/raylib/testdata/fuzz/FuzzMatrixLookAt/9ad75835daa1541f @@ -0,0 +1,10 @@ +go test fuzz v1 +float32(1) +float32(86) +float32(-69) +float32(1) +float32(2) +float32(3) +float32(1) +float32(2) +float32(91) diff --git a/raylib/testdata/fuzz/FuzzQuaternionSlerp/509f5490c8952865 b/raylib/testdata/fuzz/FuzzQuaternionSlerp/509f5490c8952865 new file mode 100644 index 00000000..630a2fd3 --- /dev/null +++ b/raylib/testdata/fuzz/FuzzQuaternionSlerp/509f5490c8952865 @@ -0,0 +1,10 @@ +go test fuzz v1 +float32(1) +float32(2) +float32(-7) +float32(4) +float32(1) +float32(2) +float32(3) +float32(4) +float32(4) diff --git a/raylib/testdata/fuzz/FuzzQuaternionSlerp/7094170c6348cebf b/raylib/testdata/fuzz/FuzzQuaternionSlerp/7094170c6348cebf new file mode 100644 index 00000000..75ac9522 --- /dev/null +++ b/raylib/testdata/fuzz/FuzzQuaternionSlerp/7094170c6348cebf @@ -0,0 +1,10 @@ +go test fuzz v1 +float32(-29) +float32(0.6666667) +float32(3) +float32(4) +float32(1) +float32(12) +float32(1.5) +float32(4) +float32(1) diff --git a/raylib/testdata/fuzz/FuzzQuaternionToAxisAngle/1608fe79e1c832a4 b/raylib/testdata/fuzz/FuzzQuaternionToAxisAngle/1608fe79e1c832a4 new file mode 100644 index 00000000..c9c32ec8 --- /dev/null +++ b/raylib/testdata/fuzz/FuzzQuaternionToAxisAngle/1608fe79e1c832a4 @@ -0,0 +1,5 @@ +go test fuzz v1 +float32(1) +float32(2) +float32(3) +float32(68) diff --git a/raylib/testdata/fuzz/FuzzQuaternionToAxisAngle/64c25f227ec3e612 b/raylib/testdata/fuzz/FuzzQuaternionToAxisAngle/64c25f227ec3e612 new file mode 100644 index 00000000..49f1fd75 --- /dev/null +++ b/raylib/testdata/fuzz/FuzzQuaternionToAxisAngle/64c25f227ec3e612 @@ -0,0 +1,5 @@ +go test fuzz v1 +float32(0.16666667) +float32(0.6666667) +float32(0.3) +float32(3672) diff --git a/raylib/testdata/fuzz/FuzzQuaternionToAxisAngle/ab8e069d6a3cf0fb b/raylib/testdata/fuzz/FuzzQuaternionToAxisAngle/ab8e069d6a3cf0fb new file mode 100644 index 00000000..354a42c4 --- /dev/null +++ b/raylib/testdata/fuzz/FuzzQuaternionToAxisAngle/ab8e069d6a3cf0fb @@ -0,0 +1,5 @@ +go test fuzz v1 +float32(0.16666667) +float32(2.6666667) +float32(0.3) +float32(3705) diff --git a/raylib/testdata/fuzz/FuzzQuaternionToAxisAngle/bb7cd68c914b767e b/raylib/testdata/fuzz/FuzzQuaternionToAxisAngle/bb7cd68c914b767e new file mode 100644 index 00000000..568178ce --- /dev/null +++ b/raylib/testdata/fuzz/FuzzQuaternionToAxisAngle/bb7cd68c914b767e @@ -0,0 +1,5 @@ +go test fuzz v1 +float32(0.16666667) +float32(0.6666667) +float32(0.3) +float32(408) diff --git a/raylib/testdata/fuzz/FuzzQuaternionToAxisAngle/c3aca23da620d7bb b/raylib/testdata/fuzz/FuzzQuaternionToAxisAngle/c3aca23da620d7bb new file mode 100644 index 00000000..bc0b00c9 --- /dev/null +++ b/raylib/testdata/fuzz/FuzzQuaternionToAxisAngle/c3aca23da620d7bb @@ -0,0 +1,5 @@ +go test fuzz v1 +float32(1) +float32(0.6666667) +float32(0.3) +float32(408) diff --git a/raylib/testdata/fuzz/FuzzVector2Angle/1a9a7f78f17648a9 b/raylib/testdata/fuzz/FuzzVector2Angle/1a9a7f78f17648a9 new file mode 100644 index 00000000..9dcdf946 --- /dev/null +++ b/raylib/testdata/fuzz/FuzzVector2Angle/1a9a7f78f17648a9 @@ -0,0 +1,5 @@ +go test fuzz v1 +float32(1) +float32(10) +float32(-24) +float32(-76) diff --git a/raylib/testdata/fuzz/FuzzVector2Rotate/06a6aed80735d1a1 b/raylib/testdata/fuzz/FuzzVector2Rotate/06a6aed80735d1a1 new file mode 100644 index 00000000..c30a40e6 --- /dev/null +++ b/raylib/testdata/fuzz/FuzzVector2Rotate/06a6aed80735d1a1 @@ -0,0 +1,4 @@ +go test fuzz v1 +float32(-1465) +float32(2091.5999) +float32(-98) diff --git a/raylib/testdata/fuzz/FuzzVector2Rotate/89bbb2c6faf7be5e b/raylib/testdata/fuzz/FuzzVector2Rotate/89bbb2c6faf7be5e new file mode 100644 index 00000000..e370e005 --- /dev/null +++ b/raylib/testdata/fuzz/FuzzVector2Rotate/89bbb2c6faf7be5e @@ -0,0 +1,4 @@ +go test fuzz v1 +float32(-14650) +float32(20931.998) +float32(-98) diff --git a/raylib/testdata/fuzz/FuzzVector2Rotate/ae2d7f041c3fd4e0 b/raylib/testdata/fuzz/FuzzVector2Rotate/ae2d7f041c3fd4e0 new file mode 100644 index 00000000..3aced773 --- /dev/null +++ b/raylib/testdata/fuzz/FuzzVector2Rotate/ae2d7f041c3fd4e0 @@ -0,0 +1,4 @@ +go test fuzz v1 +float32(-88) +float32(135.4) +float32(-98) diff --git a/raylib/testdata/fuzz/FuzzVector2Rotate/b79bca504b15bda6 b/raylib/testdata/fuzz/FuzzVector2Rotate/b79bca504b15bda6 new file mode 100644 index 00000000..dfdfed00 --- /dev/null +++ b/raylib/testdata/fuzz/FuzzVector2Rotate/b79bca504b15bda6 @@ -0,0 +1,4 @@ +go test fuzz v1 +float32(-148) +float32(210.4) +float32(-98) diff --git a/raylib/testdata/fuzz/FuzzVector3OrthoNormalize/187d7f6f85c6fc52 b/raylib/testdata/fuzz/FuzzVector3OrthoNormalize/187d7f6f85c6fc52 new file mode 100644 index 00000000..0a660249 --- /dev/null +++ b/raylib/testdata/fuzz/FuzzVector3OrthoNormalize/187d7f6f85c6fc52 @@ -0,0 +1,7 @@ +go test fuzz v1 +float32(1) +float32(2) +float32(3) +float32(1) +float32(0.2) +float32(3) diff --git a/raylib/testdata/fuzz/FuzzVector3RotateByAxisAngle/088607e6fb0c7930 b/raylib/testdata/fuzz/FuzzVector3RotateByAxisAngle/088607e6fb0c7930 new file mode 100644 index 00000000..b6cd4a7d --- /dev/null +++ b/raylib/testdata/fuzz/FuzzVector3RotateByAxisAngle/088607e6fb0c7930 @@ -0,0 +1,8 @@ +go test fuzz v1 +float32(7) +float32(14) +float32(7) +float32(1) +float32(2) +float32(7.9) +float32(21) From 271288d33c281830a6f3a85bdd0006ad6ab8b021 Mon Sep 17 00:00:00 2001 From: djfinlay <8754126+djfinlay@users.noreply.github.com> Date: Mon, 20 Oct 2025 16:05:26 +0100 Subject: [PATCH 2/6] Generate methods for raymath functions --- raylib/internal/cmd/genraymath/main.go | 2 +- raylib/raymath_generated_methods.go | 472 +++++++++++++++++++++++++ 2 files changed, 473 insertions(+), 1 deletion(-) create mode 100644 raylib/raymath_generated_methods.go diff --git a/raylib/internal/cmd/genraymath/main.go b/raylib/internal/cmd/genraymath/main.go index 868e8d18..42a42e72 100644 --- a/raylib/internal/cmd/genraymath/main.go +++ b/raylib/internal/cmd/genraymath/main.go @@ -79,7 +79,7 @@ func run() error { inlineMethods = flag.Bool("inline-methods", false, "inline function bodies when generating methods") skipGenTests = flag.Bool("skip-tests", false, "don't generate tests or bindings") - skipGenMethods = flag.Bool("skip-methods", true, "don't generate methods") + skipGenMethods = flag.Bool("skip-methods", false, "don't generate methods") fuzzTime = flag.Duration("fuzztime", 0, "run fuzz tests for given time after generating") fuzzFrom = flag.String("fuzzfrom", "", "resume fuzzing from given function name") diff --git a/raylib/raymath_generated_methods.go b/raylib/raymath_generated_methods.go new file mode 100644 index 00000000..57263a81 --- /dev/null +++ b/raylib/raymath_generated_methods.go @@ -0,0 +1,472 @@ +// Code generated by ./internal/cmd/genraymath DO NOT EDIT. + +package rl + +// MultiplyVector2 - Multiplies a vector by a matrix 2x2 +func (m Mat2) MultiplyVector2(vector Vector2) Vector2 { + return Mat2MultiplyVector2(m, vector) +} + +// Transpose - Returns the transpose of a given matrix 2x2 +func (m Mat2) Transpose() Mat2 { + return Mat2Transpose(m) +} + +// Add - Add two matrices +func (m Matrix) Add(right Matrix) Matrix { + return MatrixAdd(m, right) +} + +// Decompose - Decompose a transformation matrix into its rotational, translational and scaling components +func (m Matrix) Decompose(translation *Vector3, rotation *Quaternion, scale *Vector3) { + MatrixDecompose(m, translation, rotation, scale) +} + +// Determinant - Compute matrix determinant +func (m Matrix) Determinant() float32 { + return MatrixDeterminant(m) +} + +// Invert - Invert provided matrix +func (m Matrix) Invert() Matrix { + return MatrixInvert(m) +} + +// Multiply - Returns two matrix multiplication +func (m Matrix) Multiply(right Matrix) Matrix { + return MatrixMultiply(m, right) +} + +// Normalize - Normalize provided matrix +func (m Matrix) Normalize() Matrix { + return MatrixNormalize(m) +} + +// Subtract - Subtract two matrices (left - right) +func (m Matrix) Subtract(right Matrix) Matrix { + return MatrixSubtract(m, right) +} + +// ToFloat - Converts Matrix to float32 slice +func (m Matrix) ToFloat() []float32 { + return MatrixToFloat(m) +} + +// ToFloatV - Get float array of matrix data +func (m Matrix) ToFloatV() [16]float32 { + return MatrixToFloatV(m) +} + +// Trace - Returns the trace of the matrix (sum of the values along the diagonal) +func (m Matrix) Trace() float32 { + return MatrixTrace(m) +} + +// Transpose - Transposes provided matrix +func (m Matrix) Transpose() Matrix { + return MatrixTranspose(m) +} + +// Add - Add two quaternions +func (q Quaternion) Add(q2 Quaternion) Quaternion { + return QuaternionAdd(q, q2) +} + +// AddValue - Add quaternion and float value +func (q Quaternion) AddValue(add float32) Quaternion { + return QuaternionAddValue(q, add) +} + +// Divide - Divide two quaternions +func (q Quaternion) Divide(q2 Quaternion) Quaternion { + return QuaternionDivide(q, q2) +} + +// Equals - Check whether two given quaternions are almost equal +func (q Quaternion) Equals(p Quaternion) bool { + return QuaternionEquals(q, p) +} + +// Invert - Invert provided quaternion +func (q Quaternion) Invert() Quaternion { + return QuaternionInvert(q) +} + +// Length - Compute the length of a quaternion +func (q Quaternion) Length() float32 { + return QuaternionLength(q) +} + +// Lerp - Calculate linear interpolation between two quaternions +func (q Quaternion) Lerp(q2 Quaternion, amount float32) Quaternion { + return QuaternionLerp(q, q2, amount) +} + +// Multiply - Calculate two quaternion multiplication +func (q Quaternion) Multiply(q2 Quaternion) Quaternion { + return QuaternionMultiply(q, q2) +} + +// Nlerp - Calculate slerp-optimized interpolation between two quaternions +func (q Quaternion) Nlerp(q2 Quaternion, amount float32) Quaternion { + return QuaternionNlerp(q, q2, amount) +} + +// Normalize - Normalize provided quaternion +func (q Quaternion) Normalize() Quaternion { + return QuaternionNormalize(q) +} + +// Scale - Scale quaternion by float value +func (q Quaternion) Scale(mul float32) Quaternion { + return QuaternionScale(q, mul) +} + +// Slerp - Calculates spherical linear interpolation between two quaternions +func (q Quaternion) Slerp(q2 Quaternion, amount float32) Quaternion { + return QuaternionSlerp(q, q2, amount) +} + +// Subtract - Subtract two quaternions +func (q Quaternion) Subtract(q2 Quaternion) Quaternion { + return QuaternionSubtract(q, q2) +} + +// SubtractValue - Subtract quaternion and float value +func (q Quaternion) SubtractValue(sub float32) Quaternion { + return QuaternionSubtractValue(q, sub) +} + +// ToAxisAngle - Returns the rotation angle and axis for a given quaternion +func (q Quaternion) ToAxisAngle(outAxis *Vector3, outAngle *float32) { + QuaternionToAxisAngle(q, outAxis, outAngle) +} + +// ToEuler - Get the Euler angles equivalent to quaternion (roll, pitch, yaw) +// NOTE: Angles are returned in a Vector3 struct in radians +func (q Quaternion) ToEuler() Vector3 { + return QuaternionToEuler(q) +} + +// ToMatrix - Returns a matrix for a given quaternion +func (q Quaternion) ToMatrix() Matrix { + return QuaternionToMatrix(q) +} + +// Transform - Transform a quaternion given a transformation matrix +func (q Quaternion) Transform(mat Matrix) Quaternion { + return QuaternionTransform(q, mat) +} + +// Add - Add two vectors (v1 + v2) +func (v Vector2) Add(v2 Vector2) Vector2 { + return Vector2Add(v, v2) +} + +// AddValue - Add vector and float value +func (v Vector2) AddValue(add float32) Vector2 { + return Vector2AddValue(v, add) +} + +// Angle - Calculate angle from two vectors in radians +// NOTE: Coordinate system convention: positive X right, positive Y down, +// positive angles appear clockwise, and negative angles appear counterclockwise +func (v Vector2) Angle(v2 Vector2) float32 { + return Vector2Angle(v, v2) +} + +// Clamp - Clamp the components of the vector between min and max values specified by the given vectors +func (v Vector2) Clamp(min Vector2, max Vector2) Vector2 { + return Vector2Clamp(v, min, max) +} + +// ClampValue - Clamp the magnitude of the vector between two min and max values +func (v Vector2) ClampValue(min float32, max float32) Vector2 { + return Vector2ClampValue(v, min, max) +} + +// CrossProduct - Calculate two vectors cross product +func (v Vector2) CrossProduct(v2 Vector2) float32 { + return Vector2CrossProduct(v, v2) +} + +// Distance - Calculate distance between two vectors +func (v Vector2) Distance(v2 Vector2) float32 { + return Vector2Distance(v, v2) +} + +// DistanceSqr - Calculate square distance between two vectors +func (v Vector2) DistanceSqr(v2 Vector2) float32 { + return Vector2DistanceSqr(v, v2) +} + +// Divide - Divide vector by vector +func (v Vector2) Divide(v2 Vector2) Vector2 { + return Vector2Divide(v, v2) +} + +// DotProduct - Calculate two vectors dot product +func (v Vector2) DotProduct(v2 Vector2) float32 { + return Vector2DotProduct(v, v2) +} + +// Equals - Check whether two given vectors are almost equal +func (v Vector2) Equals(q Vector2) bool { + return Vector2Equals(v, q) +} + +// Invert - Invert the given vector +func (v Vector2) Invert() Vector2 { + return Vector2Invert(v) +} + +// Length - Calculate vector length +func (v Vector2) Length() float32 { + return Vector2Length(v) +} + +// LengthSqr - Calculate vector square length +func (v Vector2) LengthSqr() float32 { + return Vector2LengthSqr(v) +} + +// Lerp - Calculate linear interpolation between two vectors +func (v Vector2) Lerp(v2 Vector2, amount float32) Vector2 { + return Vector2Lerp(v, v2, amount) +} + +// LineAngle - Calculate angle defined by a two vectors line +// NOTE: Parameters need to be normalized. Current implementation should be aligned with glm::angle +func (v Vector2) LineAngle(end Vector2) float32 { + return Vector2LineAngle(v, end) +} + +// MoveTowards - Move Vector towards target +func (v Vector2) MoveTowards(target Vector2, maxDistance float32) Vector2 { + return Vector2MoveTowards(v, target, maxDistance) +} + +// Multiply - Multiply vector by vector +func (v Vector2) Multiply(v2 Vector2) Vector2 { + return Vector2Multiply(v, v2) +} + +// Negate - Negate vector +func (v Vector2) Negate() Vector2 { + return Vector2Negate(v) +} + +// Normalize - Normalize provided vector +func (v Vector2) Normalize() Vector2 { + return Vector2Normalize(v) +} + +// Reflect - Calculate reflected vector to normal +func (v Vector2) Reflect(normal Vector2) Vector2 { + return Vector2Reflect(v, normal) +} + +// Rotate - Rotate vector by angle +func (v Vector2) Rotate(angle float32) Vector2 { + return Vector2Rotate(v, angle) +} + +// Scale - Scale vector (multiply by value) +func (v Vector2) Scale(scale float32) Vector2 { + return Vector2Scale(v, scale) +} + +// Subtract - Subtract two vectors (v1 - v2) +func (v Vector2) Subtract(v2 Vector2) Vector2 { + return Vector2Subtract(v, v2) +} + +// SubtractValue - Subtract vector by float value +func (v Vector2) SubtractValue(sub float32) Vector2 { + return Vector2SubtractValue(v, sub) +} + +// Transform - Transforms a Vector2 by a given Matrix +func (v Vector2) Transform(mat Matrix) Vector2 { + return Vector2Transform(v, mat) +} + +// Add - Add two vectors +func (v Vector3) Add(v2 Vector3) Vector3 { + return Vector3Add(v, v2) +} + +// AddValue - Add vector and float value +func (v Vector3) AddValue(add float32) Vector3 { + return Vector3AddValue(v, add) +} + +// Angle - Calculate angle between two vectors +func (v Vector3) Angle(v2 Vector3) float32 { + return Vector3Angle(v, v2) +} + +// Barycenter - Barycenter coords for p in triangle abc +func (v Vector3) Barycenter(a, b, c Vector3) Vector3 { + return Vector3Barycenter(v, a, b, c) +} + +// Clamp - Clamp the components of the vector between min and max values specified by the given vectors +func (v Vector3) Clamp(min Vector3, max Vector3) Vector3 { + return Vector3Clamp(v, min, max) +} + +// ClampValue - Clamp the magnitude of the vector between two values +func (v Vector3) ClampValue(min float32, max float32) Vector3 { + return Vector3ClampValue(v, min, max) +} + +// CrossProduct - Calculate two vectors cross product +func (v Vector3) CrossProduct(v2 Vector3) Vector3 { + return Vector3CrossProduct(v, v2) +} + +// Distance - Calculate distance between two vectors +func (v Vector3) Distance(v2 Vector3) float32 { + return Vector3Distance(v, v2) +} + +// DistanceSqr - Calculate square distance between two vectors +func (v Vector3) DistanceSqr(v2 Vector3) float32 { + return Vector3DistanceSqr(v, v2) +} + +// Divide - Divide vector by vector +func (v Vector3) Divide(v2 Vector3) Vector3 { + return Vector3Divide(v, v2) +} + +// DotProduct - Calculate two vectors dot product +func (v Vector3) DotProduct(v2 Vector3) float32 { + return Vector3DotProduct(v, v2) +} + +// Equals - Check whether two given vectors are almost equal +func (v Vector3) Equals(q Vector3) bool { + return Vector3Equals(v, q) +} + +// Invert - Invert the given vector +func (v Vector3) Invert() Vector3 { + return Vector3Invert(v) +} + +// Length - Calculate vector length +func (v Vector3) Length() float32 { + return Vector3Length(v) +} + +// LengthSqr - Calculate vector square length +func (v Vector3) LengthSqr() float32 { + return Vector3LengthSqr(v) +} + +// Lerp - Calculate linear interpolation between two vectors +func (v Vector3) Lerp(v2 Vector3, amount float32) Vector3 { + return Vector3Lerp(v, v2, amount) +} + +// Max - Return max value for each pair of components +func (v Vector3) Max(vec2 Vector3) Vector3 { + return Vector3Max(v, vec2) +} + +// Min - Return min value for each pair of components +func (v Vector3) Min(vec2 Vector3) Vector3 { + return Vector3Min(v, vec2) +} + +// Multiply - Multiply vector by vector +func (v Vector3) Multiply(v2 Vector3) Vector3 { + return Vector3Multiply(v, v2) +} + +// Negate - Negate provided vector (invert direction) +func (v Vector3) Negate() Vector3 { + return Vector3Negate(v) +} + +// Normalize - Normalize provided vector +func (v Vector3) Normalize() Vector3 { + return Vector3Normalize(v) +} + +// Perpendicular - Calculate one vector perpendicular vector +func (v Vector3) Perpendicular() Vector3 { + return Vector3Perpendicular(v) +} + +// Project - Calculate the projection of the vector v1 on to v2 +func (v Vector3) Project(v2 Vector3) Vector3 { + return Vector3Project(v, v2) +} + +// Reflect - Calculate reflected vector to normal +func (v Vector3) Reflect(normal Vector3) Vector3 { + return Vector3Reflect(v, normal) +} + +// Refract - Compute the direction of a refracted ray +// +// v: normalized direction of the incoming ray +// n: normalized normal vector of the interface of two optical media +// r: ratio of the refractive index of the medium from where the ray comes to the refractive index of the medium on the other side of the surface +func (v Vector3) Refract(n Vector3, r float32) Vector3 { + return Vector3Refract(v, n, r) +} + +// Reject - Calculate the rejection of the vector v1 on to v2 +func (v Vector3) Reject(v2 Vector3) Vector3 { + return Vector3Reject(v, v2) +} + +// RotateByAxisAngle - Rotates a vector around an axis +func (v Vector3) RotateByAxisAngle(axis Vector3, angle float32) Vector3 { + return Vector3RotateByAxisAngle(v, axis, angle) +} + +// RotateByQuaternion - Transform a vector by quaternion rotation +func (v Vector3) RotateByQuaternion(q Quaternion) Vector3 { + return Vector3RotateByQuaternion(v, q) +} + +// Scale - Scale provided vector +func (v Vector3) Scale(scale float32) Vector3 { + return Vector3Scale(v, scale) +} + +// Subtract - Subtract two vectors +func (v Vector3) Subtract(v2 Vector3) Vector3 { + return Vector3Subtract(v, v2) +} + +// SubtractValue - Subtract vector by float value +func (v Vector3) SubtractValue(sub float32) Vector3 { + return Vector3SubtractValue(v, sub) +} + +// ToFloat - Converts Vector3 to float32 slice +func (v Vector3) ToFloat() []float32 { + return Vector3ToFloat(v) +} + +// ToFloatV - Get Vector3 as float array +func (v Vector3) ToFloatV() [3]float32 { + return Vector3ToFloatV(v) +} + +// Transform - Transforms a Vector3 by a given Matrix +func (v Vector3) Transform(mat Matrix) Vector3 { + return Vector3Transform(v, mat) +} + +// Unproject - Projects a Vector3 from screen space into object space +// NOTE: We are avoiding calling other raymath functions despite available +func (v Vector3) Unproject(projection Matrix, view Matrix) Vector3 { + return Vector3Unproject(v, projection, view) +} From 9968cd6bfd984f30dac5b4b5ba7b0f18363cfbbf Mon Sep 17 00:00:00 2001 From: djfinlay <8754126+djfinlay@users.noreply.github.com> Date: Mon, 20 Oct 2025 16:42:17 +0100 Subject: [PATCH 3/6] Fix examples --- physics/physics.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/physics/physics.go b/physics/physics.go index e98c675a..79d3917c 100644 --- a/physics/physics.go +++ b/physics/physics.go @@ -935,7 +935,7 @@ func solveCircleToCircle(manifold *Manifold) { // Calculate translational vector, which is normal var normal rl.Vector2 = rl.Vector2Subtract(bodyB.Position, bodyA.Position) - distSqr := rl.Vector2LenSqr(normal) + distSqr := rl.Vector2LengthSqr(normal) radius := bodyA.Shape.Radius + bodyB.Shape.Radius // Check if circles are not in contact @@ -1246,7 +1246,7 @@ func initializeManifolds(manifold *Manifold) { // The idea is if the only thing moving this object is gravity, then the collision should be // performed without any restitution rad := rl.NewVector2(gravityForce.X*deltaTime/1000, gravityForce.Y*deltaTime/1000) - if rl.Vector2LenSqr(radiusV) < (rl.Vector2LenSqr(rad) + epsilon) { + if rl.Vector2LengthSqr(radiusV) < (rl.Vector2LengthSqr(rad) + epsilon) { manifold.Restitution = 0 } } From 74b4a24c4f8d1383932400a92a30a3381b187bae Mon Sep 17 00:00:00 2001 From: djfinlay <8754126+djfinlay@users.noreply.github.com> Date: Mon, 20 Oct 2025 19:31:04 +0100 Subject: [PATCH 4/6] Skip unstable test cases for Vector3OrthoNormalize --- raylib/raymath_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/raylib/raymath_test.go b/raylib/raymath_test.go index dc28d1b7..c883a0ac 100644 --- a/raylib/raymath_test.go +++ b/raylib/raymath_test.go @@ -36,7 +36,7 @@ func BenchmarkVector3OrthoNormalize(b *testing.B) { func FuzzVector3OrthoNormalize(f *testing.F) { f.Add( float32(1), float32(2), float32(3), - float32(1), float32(2), float32(3), + float32(4), float32(5), float32(6), ) f.Fuzz(func(t *testing.T, v1X, v1Y, v1Z float32, @@ -44,6 +44,9 @@ func FuzzVector3OrthoNormalize(f *testing.F) { ) { want1 := NewVector3(v1X, v1Y, v1Z) want2 := NewVector3(v2X, v2Y, v2Z) + if testVector3Equals(Vector3CrossProduct(want1, want2), Vector3Zero(), 1e-3) { + t.SkipNow() // too unstable on macos + } cVector3OrthoNormalize(&want1, &want2) got1 := NewVector3(v1X, v1Y, v1Z) From b5d3006a5868b0f8e51e77340d410e72a6a09681 Mon Sep 17 00:00:00 2001 From: djfinlay <8754126+djfinlay@users.noreply.github.com> Date: Thu, 23 Oct 2025 15:18:39 +0100 Subject: [PATCH 5/6] Fix failures from fuzz tests --- raylib/internal/cmd/genraymath/main.go | 5 +++-- raylib/raymath.go | 2 +- raylib/raymath_generated_test.go | 6 +++--- .../testdata/fuzz/FuzzQuaternionSlerp/1aa7556fb6fb5fff | 10 ++++++++++ .../testdata/fuzz/FuzzVector2Rotate/f190ff97fc2a8155 | 4 ++++ raylib/testdata/fuzz/FuzzWrap/a974dad357b2fd41 | 4 ++++ 6 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 raylib/testdata/fuzz/FuzzQuaternionSlerp/1aa7556fb6fb5fff create mode 100644 raylib/testdata/fuzz/FuzzVector2Rotate/f190ff97fc2a8155 create mode 100644 raylib/testdata/fuzz/FuzzWrap/a974dad357b2fd41 diff --git a/raylib/internal/cmd/genraymath/main.go b/raylib/internal/cmd/genraymath/main.go index 42a42e72..a4e1a1ee 100644 --- a/raylib/internal/cmd/genraymath/main.go +++ b/raylib/internal/cmd/genraymath/main.go @@ -55,6 +55,7 @@ var ( lowPrecision = []string{ "Vector3RotateByAxisAngle", "Vector2Rotate", + "QuaternionSlerp", } // the C versions of these functions use double params instead of floats @@ -204,7 +205,7 @@ func run() error { log.Printf("running fuzz test %d/%d for %q", n, total, fn.Name) testName := "^Fuzz" + fn.Name + "$" cmd := exec.Command("go", "test", - "-run", testName, + "-run", "^$", "-fuzz", testName, "-fuzztime", (*fuzzTime).String(), ) @@ -381,7 +382,7 @@ func (f funcInfo) TestNotEqual(a, b string) string { prec := 6 if slices.Contains(lowPrecision, f.Name) { - prec = 2 + prec = 1 } first, size := utf8.DecodeRuneInString(t) diff --git a/raylib/raymath.go b/raylib/raymath.go index 6cbbbe15..6be4d003 100644 --- a/raylib/raymath.go +++ b/raylib/raymath.go @@ -40,7 +40,7 @@ func Remap(value, inputStart, inputEnd, outputStart, outputEnd float32) float32 // Wrap - Wrap input value from min to max func Wrap(value, min, max float32) float32 { - return float32(float64(value) - float64(max-min)*math.Floor(float64((value-min)/(max-min)))) + return value - (max-min)*float32(math.Floor(float64((value-min)/(max-min)))) } // FloatEquals - Check whether two given floats are almost equal diff --git a/raylib/raymath_generated_test.go b/raylib/raymath_generated_test.go index e83c8db0..f89c4a82 100644 --- a/raylib/raymath_generated_test.go +++ b/raylib/raymath_generated_test.go @@ -1892,7 +1892,7 @@ func FuzzQuaternionSlerp(f *testing.F) { q2 := NewQuaternion(q2X, q2Y, q2Z, q2W) want := cQuaternionSlerp(q1, q2, amount) got := QuaternionSlerp(q1, q2, amount) - if !testQuaternionEquals(want, got, 1e-6) { + if !testQuaternionEquals(want, got, 1e-1) { t.Errorf("got %v; want %v", got, want) } }) @@ -3125,7 +3125,7 @@ func FuzzVector2Rotate(f *testing.F) { v := NewVector2(vX, vY) want := cVector2Rotate(v, angle) got := Vector2Rotate(v, angle) - if !testVector2Equals(want, got, 1e-2) { + if !testVector2Equals(want, got, 1e-1) { t.Errorf("got %v; want %v", got, want) } }) @@ -4525,7 +4525,7 @@ func FuzzVector3RotateByAxisAngle(f *testing.F) { axis := NewVector3(axisX, axisY, axisZ) want := cVector3RotateByAxisAngle(v, axis, angle) got := Vector3RotateByAxisAngle(v, axis, angle) - if !testVector3Equals(want, got, 1e-2) { + if !testVector3Equals(want, got, 1e-1) { t.Errorf("got %v; want %v", got, want) } }) diff --git a/raylib/testdata/fuzz/FuzzQuaternionSlerp/1aa7556fb6fb5fff b/raylib/testdata/fuzz/FuzzQuaternionSlerp/1aa7556fb6fb5fff new file mode 100644 index 00000000..1322c815 --- /dev/null +++ b/raylib/testdata/fuzz/FuzzQuaternionSlerp/1aa7556fb6fb5fff @@ -0,0 +1,10 @@ +go test fuzz v1 +float32(-29) +float32(-31.333334) +float32(0.3) +float32(4) +float32(-12) +float32(12) +float32(40.5) +float32(4) +float32(-70) diff --git a/raylib/testdata/fuzz/FuzzVector2Rotate/f190ff97fc2a8155 b/raylib/testdata/fuzz/FuzzVector2Rotate/f190ff97fc2a8155 new file mode 100644 index 00000000..d996a4e2 --- /dev/null +++ b/raylib/testdata/fuzz/FuzzVector2Rotate/f190ff97fc2a8155 @@ -0,0 +1,4 @@ +go test fuzz v1 +float32(-146500) +float32(209328.98) +float32(-98) diff --git a/raylib/testdata/fuzz/FuzzWrap/a974dad357b2fd41 b/raylib/testdata/fuzz/FuzzWrap/a974dad357b2fd41 new file mode 100644 index 00000000..7d67d153 --- /dev/null +++ b/raylib/testdata/fuzz/FuzzWrap/a974dad357b2fd41 @@ -0,0 +1,4 @@ +go test fuzz v1 +float32(-496) +float32(15.666667) +float32(22) From 6b2b83acde20007ac66338f54bba4d0616a237ad Mon Sep 17 00:00:00 2001 From: djfinlay <8754126+djfinlay@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:15:59 +0000 Subject: [PATCH 6/6] Normalize some test inputs rather than lowering precision --- raylib/internal/cmd/genraymath/helper.go.tmpl | 3 + raylib/internal/cmd/genraymath/main.go | 17 +- raylib/internal/cmd/genraymath/test.go.tmpl | 64 ++-- raylib/raymath_generated_test.go | 299 +++++++++--------- raylib/raymath_test.go | 19 +- 5 files changed, 204 insertions(+), 198 deletions(-) diff --git a/raylib/internal/cmd/genraymath/helper.go.tmpl b/raylib/internal/cmd/genraymath/helper.go.tmpl index e891bf9e..84ee9b12 100644 --- a/raylib/internal/cmd/genraymath/helper.go.tmpl +++ b/raylib/internal/cmd/genraymath/helper.go.tmpl @@ -103,6 +103,9 @@ {{ $name }}M3, {{ $name }}M7, {{ $name }}M11, {{ $name }}M15, ) {{- end -}} + {{- if $param.Normalize }} + {{ testvar $name }} = {{ $param.TypeName}}Normalize({{ testvar $name }}) + {{- end -}} {{- end -}} {{- end -}} {{- end -}} diff --git a/raylib/internal/cmd/genraymath/main.go b/raylib/internal/cmd/genraymath/main.go index a4e1a1ee..e2c5a968 100644 --- a/raylib/internal/cmd/genraymath/main.go +++ b/raylib/internal/cmd/genraymath/main.go @@ -36,9 +36,8 @@ var ( "Mat2Transpose", "MatrixNormalize", "Mat2Set", + "Vector2Cross", - "Vector2Cross", // alias for Vector2CrossProduct - "Vector2LenSqr", // alias for Vector2LengthSqr "MatrixToFloat", // MatrixToFloatV tested "Vector3ToFloat", // Vector3ToFloatV tested } @@ -51,8 +50,9 @@ var ( "MatrixDecompose", } - // fuzz testing these functions is flakey unless the test precision is lowered - lowPrecision = []string{ + // some outputs can differ a lot when the input is big (especially for rotations) so we need to + // normalize test inputs + normalize = []string{ "Vector3RotateByAxisAngle", "Vector2Rotate", "QuaternionSlerp", @@ -267,6 +267,7 @@ func parseFunc(fn *ast.FuncDecl, fset *token.FileSet, inlineMethods bool) (funcI ret.Params = append(ret.Params, param{ Names: names, TypeName: typeName, + Normalize: strings.HasPrefix(fn.Name.Name, typeName) && slices.Contains(normalize, fn.Name.Name), UseDouble: typeName == "float32" && slices.Contains(useDouble, fn.Name.Name), }) } @@ -380,19 +381,15 @@ func (f funcInfo) TestNotEqual(a, b string) string { } } - prec := 6 - if slices.Contains(lowPrecision, f.Name) { - prec = 1 - } - first, size := utf8.DecodeRuneInString(t) t = string(unicode.ToUpper(first)) + t[size:] - return fmt.Sprintf("!test%sEquals(%s, %s, 1e-%d)", t, a, b, prec) + return fmt.Sprintf("!test%sEquals(%s, %s)", t, a, b) } type param struct { Names []string TypeName string + Normalize bool UseDouble bool } diff --git a/raylib/internal/cmd/genraymath/test.go.tmpl b/raylib/internal/cmd/genraymath/test.go.tmpl index bba242d0..16ed76b2 100644 --- a/raylib/internal/cmd/genraymath/test.go.tmpl +++ b/raylib/internal/cmd/genraymath/test.go.tmpl @@ -59,7 +59,7 @@ func Test{{ .Name }}(t *testing.T) { // helpers -func testFloat32Equals(a, b float32, epsilon float64) bool { +func testFloat32Equals(a, b float32) bool { if math.IsNaN(float64(a)) && math.IsNaN(float64(b)) { return true } @@ -72,51 +72,51 @@ func testFloat32Equals(a, b float32, epsilon float64) bool { return math.Abs(float64(a-b)) <= epsilon*math.Max(1.0, math.Max(math.Abs(float64(a)), math.Abs(float64(b)))) } -func testFloat32SliceEquals(a, b []float32, epsilon float64) bool { +func testFloat32SliceEquals(a, b []float32) bool { if len(a) != len(b) { return false } for i := range a { - if !testFloat32Equals(a[i], b[i], epsilon) { + if !testFloat32Equals(a[i], b[i]) { return false } } return true } -func testVector2Equals(a, b Vector2, epsilon float64) bool { - return testFloat32Equals(a.X, b.X, epsilon) && - testFloat32Equals(a.Y, b.Y, epsilon) +func testVector2Equals(a, b Vector2) bool { + return testFloat32Equals(a.X, b.X) && + testFloat32Equals(a.Y, b.Y) } -func testVector3Equals(a, b Vector3, epsilon float64) bool { - return testFloat32Equals(a.X, b.X, epsilon) && - testFloat32Equals(a.Y, b.Y, epsilon) && - testFloat32Equals(a.Z, b.Z, epsilon) +func testVector3Equals(a, b Vector3) bool { + return testFloat32Equals(a.X, b.X) && + testFloat32Equals(a.Y, b.Y) && + testFloat32Equals(a.Z, b.Z) } -func testQuaternionEquals(a, b Quaternion, epsilon float64) bool { - return testFloat32Equals(a.X, b.X, epsilon) && - testFloat32Equals(a.Y, b.Y, epsilon) && - testFloat32Equals(a.Z, b.Z, epsilon) && - testFloat32Equals(a.W, b.W, epsilon) +func testQuaternionEquals(a, b Quaternion) bool { + return testFloat32Equals(a.X, b.X) && + testFloat32Equals(a.Y, b.Y) && + testFloat32Equals(a.Z, b.Z) && + testFloat32Equals(a.W, b.W) } -func testMatrixEquals(a, b Matrix, epsilon float64) bool { - return testFloat32Equals(a.M0, b.M0, epsilon) && - testFloat32Equals(a.M1, b.M1, epsilon) && - testFloat32Equals(a.M2, b.M2, epsilon) && - testFloat32Equals(a.M3, b.M3, epsilon) && - testFloat32Equals(a.M4, b.M4, epsilon) && - testFloat32Equals(a.M5, b.M5, epsilon) && - testFloat32Equals(a.M6, b.M6, epsilon) && - testFloat32Equals(a.M7, b.M7, epsilon) && - testFloat32Equals(a.M8, b.M8, epsilon) && - testFloat32Equals(a.M9, b.M9, epsilon) && - testFloat32Equals(a.M10, b.M10, epsilon) && - testFloat32Equals(a.M11, b.M11, epsilon) && - testFloat32Equals(a.M12, b.M12, epsilon) && - testFloat32Equals(a.M13, b.M13, epsilon) && - testFloat32Equals(a.M14, b.M14, epsilon) && - testFloat32Equals(a.M15, b.M15, epsilon) +func testMatrixEquals(a, b Matrix) bool { + return testFloat32Equals(a.M0, b.M0) && + testFloat32Equals(a.M1, b.M1) && + testFloat32Equals(a.M2, b.M2) && + testFloat32Equals(a.M3, b.M3) && + testFloat32Equals(a.M4, b.M4) && + testFloat32Equals(a.M5, b.M5) && + testFloat32Equals(a.M6, b.M6) && + testFloat32Equals(a.M7, b.M7) && + testFloat32Equals(a.M8, b.M8) && + testFloat32Equals(a.M9, b.M9) && + testFloat32Equals(a.M10, b.M10) && + testFloat32Equals(a.M11, b.M11) && + testFloat32Equals(a.M12, b.M12) && + testFloat32Equals(a.M13, b.M13) && + testFloat32Equals(a.M14, b.M14) && + testFloat32Equals(a.M15, b.M15) } diff --git a/raylib/raymath_generated_test.go b/raylib/raymath_generated_test.go index f89c4a82..aa069bed 100644 --- a/raylib/raymath_generated_test.go +++ b/raylib/raymath_generated_test.go @@ -46,7 +46,7 @@ func FuzzClamp(f *testing.F) { ) { want := cClamp(value, min, max) got := Clamp(value, min, max) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -131,7 +131,7 @@ func FuzzLerp(f *testing.F) { ) { want := cLerp(start, end, amount) got := Lerp(start, end, amount) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -196,7 +196,7 @@ func FuzzMatrixAdd(f *testing.F) { ) want := cMatrixAdd(left, right) got := MatrixAdd(left, right) - if !testMatrixEquals(want, got, 1e-6) { + if !testMatrixEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -246,7 +246,7 @@ func FuzzMatrixDeterminant(f *testing.F) { ) want := cMatrixDeterminant(mat) got := MatrixDeterminant(mat) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -299,7 +299,7 @@ func FuzzMatrixFrustum(f *testing.F) { ) { want := cMatrixFrustum(left, right, bottom, top, nearPlane, farPlane) got := MatrixFrustum(left, right, bottom, top, nearPlane, farPlane) - if !testMatrixEquals(want, got, 1e-6) { + if !testMatrixEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -330,7 +330,7 @@ func BenchmarkMatrixIdentity(b *testing.B) { func TestMatrixIdentity(t *testing.T) { want := cMatrixIdentity() got := MatrixIdentity() - if !testMatrixEquals(want, got, 1e-6) { + if !testMatrixEquals(want, got) { t.Errorf("got %v; want %v", got, want) } } @@ -379,7 +379,7 @@ func FuzzMatrixInvert(f *testing.F) { ) want := cMatrixInvert(mat) got := MatrixInvert(mat) - if !testMatrixEquals(want, got, 1e-6) { + if !testMatrixEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -426,7 +426,7 @@ func FuzzMatrixLookAt(f *testing.F) { up := NewVector3(upX, upY, upZ) want := cMatrixLookAt(eye, target, up) got := MatrixLookAt(eye, target, up) - if !testMatrixEquals(want, got, 1e-6) { + if !testMatrixEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -491,7 +491,7 @@ func FuzzMatrixMultiply(f *testing.F) { ) want := cMatrixMultiply(left, right) got := MatrixMultiply(left, right) - if !testMatrixEquals(want, got, 1e-6) { + if !testMatrixEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -544,7 +544,7 @@ func FuzzMatrixOrtho(f *testing.F) { ) { want := cMatrixOrtho(left, right, bottom, top, near, far) got := MatrixOrtho(left, right, bottom, top, near, far) - if !testMatrixEquals(want, got, 1e-6) { + if !testMatrixEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -591,7 +591,7 @@ func FuzzMatrixPerspective(f *testing.F) { ) { want := cMatrixPerspective(fovY, aspect, nearPlane, farPlane) got := MatrixPerspective(fovY, aspect, nearPlane, farPlane) - if !testMatrixEquals(want, got, 1e-6) { + if !testMatrixEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -633,7 +633,7 @@ func FuzzMatrixRotate(f *testing.F) { axis := NewVector3(axisX, axisY, axisZ) want := cMatrixRotate(axis, angle) got := MatrixRotate(axis, angle) - if !testMatrixEquals(want, got, 1e-6) { + if !testMatrixEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -671,7 +671,7 @@ func FuzzMatrixRotateX(f *testing.F) { ) { want := cMatrixRotateX(angle) got := MatrixRotateX(angle) - if !testMatrixEquals(want, got, 1e-6) { + if !testMatrixEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -710,7 +710,7 @@ func FuzzMatrixRotateXYZ(f *testing.F) { angle := NewVector3(angleX, angleY, angleZ) want := cMatrixRotateXYZ(angle) got := MatrixRotateXYZ(angle) - if !testMatrixEquals(want, got, 1e-6) { + if !testMatrixEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -748,7 +748,7 @@ func FuzzMatrixRotateY(f *testing.F) { ) { want := cMatrixRotateY(angle) got := MatrixRotateY(angle) - if !testMatrixEquals(want, got, 1e-6) { + if !testMatrixEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -786,7 +786,7 @@ func FuzzMatrixRotateZ(f *testing.F) { ) { want := cMatrixRotateZ(angle) got := MatrixRotateZ(angle) - if !testMatrixEquals(want, got, 1e-6) { + if !testMatrixEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -825,7 +825,7 @@ func FuzzMatrixRotateZYX(f *testing.F) { angle := NewVector3(angleX, angleY, angleZ) want := cMatrixRotateZYX(angle) got := MatrixRotateZYX(angle) - if !testMatrixEquals(want, got, 1e-6) { + if !testMatrixEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -869,7 +869,7 @@ func FuzzMatrixScale(f *testing.F) { ) { want := cMatrixScale(x, y, z) got := MatrixScale(x, y, z) - if !testMatrixEquals(want, got, 1e-6) { + if !testMatrixEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -934,7 +934,7 @@ func FuzzMatrixSubtract(f *testing.F) { ) want := cMatrixSubtract(left, right) got := MatrixSubtract(left, right) - if !testMatrixEquals(want, got, 1e-6) { + if !testMatrixEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -984,7 +984,7 @@ func FuzzMatrixToFloatV(f *testing.F) { ) want := cMatrixToFloatV(mat) got := MatrixToFloatV(mat) - if !testFloat32SliceEquals(want[:], got[:], 1e-6) { + if !testFloat32SliceEquals(want[:], got[:]) { t.Errorf("got %v; want %v", got, want) } }) @@ -1034,7 +1034,7 @@ func FuzzMatrixTrace(f *testing.F) { ) want := cMatrixTrace(mat) got := MatrixTrace(mat) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -1078,7 +1078,7 @@ func FuzzMatrixTranslate(f *testing.F) { ) { want := cMatrixTranslate(x, y, z) got := MatrixTranslate(x, y, z) - if !testMatrixEquals(want, got, 1e-6) { + if !testMatrixEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -1128,7 +1128,7 @@ func FuzzMatrixTranspose(f *testing.F) { ) want := cMatrixTranspose(mat) got := MatrixTranspose(mat) - if !testMatrixEquals(want, got, 1e-6) { + if !testMatrixEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -1172,7 +1172,7 @@ func FuzzNormalize(f *testing.F) { ) { want := cNormalize(value, start, end) got := Normalize(value, start, end) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -1215,7 +1215,7 @@ func FuzzQuaternionAdd(f *testing.F) { q2 := NewQuaternion(q2X, q2Y, q2Z, q2W) want := cQuaternionAdd(q1, q2) got := QuaternionAdd(q1, q2) - if !testQuaternionEquals(want, got, 1e-6) { + if !testQuaternionEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -1257,7 +1257,7 @@ func FuzzQuaternionAddValue(f *testing.F) { q := NewQuaternion(qX, qY, qZ, qW) want := cQuaternionAddValue(q, add) got := QuaternionAddValue(q, add) - if !testQuaternionEquals(want, got, 1e-6) { + if !testQuaternionEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -1300,7 +1300,7 @@ func FuzzQuaternionDivide(f *testing.F) { q2 := NewQuaternion(q2X, q2Y, q2Z, q2W) want := cQuaternionDivide(q1, q2) got := QuaternionDivide(q1, q2) - if !testQuaternionEquals(want, got, 1e-6) { + if !testQuaternionEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -1385,7 +1385,7 @@ func FuzzQuaternionFromAxisAngle(f *testing.F) { axis := NewVector3(axisX, axisY, axisZ) want := cQuaternionFromAxisAngle(axis, angle) got := QuaternionFromAxisAngle(axis, angle) - if !testQuaternionEquals(want, got, 1e-6) { + if !testQuaternionEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -1429,7 +1429,7 @@ func FuzzQuaternionFromEuler(f *testing.F) { ) { want := cQuaternionFromEuler(pitch, yaw, roll) got := QuaternionFromEuler(pitch, yaw, roll) - if !testQuaternionEquals(want, got, 1e-6) { + if !testQuaternionEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -1479,7 +1479,7 @@ func FuzzQuaternionFromMatrix(f *testing.F) { ) want := cQuaternionFromMatrix(mat) got := QuaternionFromMatrix(mat) - if !testQuaternionEquals(want, got, 1e-6) { + if !testQuaternionEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -1522,7 +1522,7 @@ func FuzzQuaternionFromVector3ToVector3(f *testing.F) { to := NewVector3(toX, toY, toZ) want := cQuaternionFromVector3ToVector3(from, to) got := QuaternionFromVector3ToVector3(from, to) - if !testQuaternionEquals(want, got, 1e-6) { + if !testQuaternionEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -1553,7 +1553,7 @@ func BenchmarkQuaternionIdentity(b *testing.B) { func TestQuaternionIdentity(t *testing.T) { want := cQuaternionIdentity() got := QuaternionIdentity() - if !testQuaternionEquals(want, got, 1e-6) { + if !testQuaternionEquals(want, got) { t.Errorf("got %v; want %v", got, want) } } @@ -1591,7 +1591,7 @@ func FuzzQuaternionInvert(f *testing.F) { quat := NewQuaternion(quatX, quatY, quatZ, quatW) want := cQuaternionInvert(quat) got := QuaternionInvert(quat) - if !testQuaternionEquals(want, got, 1e-6) { + if !testQuaternionEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -1630,7 +1630,7 @@ func FuzzQuaternionLength(f *testing.F) { quat := NewQuaternion(quatX, quatY, quatZ, quatW) want := cQuaternionLength(quat) got := QuaternionLength(quat) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -1676,7 +1676,7 @@ func FuzzQuaternionLerp(f *testing.F) { q2 := NewQuaternion(q2X, q2Y, q2Z, q2W) want := cQuaternionLerp(q1, q2, amount) got := QuaternionLerp(q1, q2, amount) - if !testQuaternionEquals(want, got, 1e-6) { + if !testQuaternionEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -1719,7 +1719,7 @@ func FuzzQuaternionMultiply(f *testing.F) { q2 := NewQuaternion(q2X, q2Y, q2Z, q2W) want := cQuaternionMultiply(q1, q2) got := QuaternionMultiply(q1, q2) - if !testQuaternionEquals(want, got, 1e-6) { + if !testQuaternionEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -1765,7 +1765,7 @@ func FuzzQuaternionNlerp(f *testing.F) { q2 := NewQuaternion(q2X, q2Y, q2Z, q2W) want := cQuaternionNlerp(q1, q2, amount) got := QuaternionNlerp(q1, q2, amount) - if !testQuaternionEquals(want, got, 1e-6) { + if !testQuaternionEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -1804,7 +1804,7 @@ func FuzzQuaternionNormalize(f *testing.F) { q := NewQuaternion(qX, qY, qZ, qW) want := cQuaternionNormalize(q) got := QuaternionNormalize(q) - if !testQuaternionEquals(want, got, 1e-6) { + if !testQuaternionEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -1846,7 +1846,7 @@ func FuzzQuaternionScale(f *testing.F) { q := NewQuaternion(qX, qY, qZ, qW) want := cQuaternionScale(q, mul) got := QuaternionScale(q, mul) - if !testQuaternionEquals(want, got, 1e-6) { + if !testQuaternionEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -1889,10 +1889,12 @@ func FuzzQuaternionSlerp(f *testing.F) { amount float32, ) { q1 := NewQuaternion(q1X, q1Y, q1Z, q1W) + q1 = QuaternionNormalize(q1) q2 := NewQuaternion(q2X, q2Y, q2Z, q2W) + q2 = QuaternionNormalize(q2) want := cQuaternionSlerp(q1, q2, amount) got := QuaternionSlerp(q1, q2, amount) - if !testQuaternionEquals(want, got, 1e-1) { + if !testQuaternionEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -1935,7 +1937,7 @@ func FuzzQuaternionSubtract(f *testing.F) { q2 := NewQuaternion(q2X, q2Y, q2Z, q2W) want := cQuaternionSubtract(q1, q2) got := QuaternionSubtract(q1, q2) - if !testQuaternionEquals(want, got, 1e-6) { + if !testQuaternionEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -1977,7 +1979,7 @@ func FuzzQuaternionSubtractValue(f *testing.F) { q := NewQuaternion(qX, qY, qZ, qW) want := cQuaternionSubtractValue(q, sub) got := QuaternionSubtractValue(q, sub) - if !testQuaternionEquals(want, got, 1e-6) { + if !testQuaternionEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2016,7 +2018,7 @@ func FuzzQuaternionToEuler(f *testing.F) { q := NewQuaternion(qX, qY, qZ, qW) want := cQuaternionToEuler(q) got := QuaternionToEuler(q) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2055,7 +2057,7 @@ func FuzzQuaternionToMatrix(f *testing.F) { q := NewQuaternion(qX, qY, qZ, qW) want := cQuaternionToMatrix(q) got := QuaternionToMatrix(q) - if !testMatrixEquals(want, got, 1e-6) { + if !testMatrixEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2109,7 +2111,7 @@ func FuzzQuaternionTransform(f *testing.F) { ) want := cQuaternionTransform(q, mat) got := QuaternionTransform(q, mat) - if !testQuaternionEquals(want, got, 1e-6) { + if !testQuaternionEquals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2159,7 +2161,7 @@ func FuzzRemap(f *testing.F) { ) { want := cRemap(value, inputStart, inputEnd, outputStart, outputEnd) got := Remap(value, inputStart, inputEnd, outputStart, outputEnd) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2202,7 +2204,7 @@ func FuzzVector2Add(f *testing.F) { v2 := NewVector2(v2X, v2Y) want := cVector2Add(v1, v2) got := Vector2Add(v1, v2) - if !testVector2Equals(want, got, 1e-6) { + if !testVector2Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2244,7 +2246,7 @@ func FuzzVector2AddValue(f *testing.F) { v := NewVector2(vX, vY) want := cVector2AddValue(v, add) got := Vector2AddValue(v, add) - if !testVector2Equals(want, got, 1e-6) { + if !testVector2Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2287,7 +2289,7 @@ func FuzzVector2Angle(f *testing.F) { v2 := NewVector2(v2X, v2Y) want := cVector2Angle(v1, v2) got := Vector2Angle(v1, v2) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2334,7 +2336,7 @@ func FuzzVector2Clamp(f *testing.F) { max := NewVector2(maxX, maxY) want := cVector2Clamp(v, min, max) got := Vector2Clamp(v, min, max) - if !testVector2Equals(want, got, 1e-6) { + if !testVector2Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2379,7 +2381,7 @@ func FuzzVector2ClampValue(f *testing.F) { v := NewVector2(vX, vY) want := cVector2ClampValue(v, min, max) got := Vector2ClampValue(v, min, max) - if !testVector2Equals(want, got, 1e-6) { + if !testVector2Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2422,7 +2424,7 @@ func FuzzVector2CrossProduct(f *testing.F) { v2 := NewVector2(v2X, v2Y) want := cVector2CrossProduct(v1, v2) got := Vector2CrossProduct(v1, v2) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2465,7 +2467,7 @@ func FuzzVector2Distance(f *testing.F) { v2 := NewVector2(v2X, v2Y) want := cVector2Distance(v1, v2) got := Vector2Distance(v1, v2) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2508,7 +2510,7 @@ func FuzzVector2DistanceSqr(f *testing.F) { v2 := NewVector2(v2X, v2Y) want := cVector2DistanceSqr(v1, v2) got := Vector2DistanceSqr(v1, v2) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2551,7 +2553,7 @@ func FuzzVector2Divide(f *testing.F) { v2 := NewVector2(v2X, v2Y) want := cVector2Divide(v1, v2) got := Vector2Divide(v1, v2) - if !testVector2Equals(want, got, 1e-6) { + if !testVector2Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2594,7 +2596,7 @@ func FuzzVector2DotProduct(f *testing.F) { v2 := NewVector2(v2X, v2Y) want := cVector2DotProduct(v1, v2) got := Vector2DotProduct(v1, v2) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2676,7 +2678,7 @@ func FuzzVector2Invert(f *testing.F) { v := NewVector2(vX, vY) want := cVector2Invert(v) got := Vector2Invert(v) - if !testVector2Equals(want, got, 1e-6) { + if !testVector2Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2715,7 +2717,7 @@ func FuzzVector2Length(f *testing.F) { v := NewVector2(vX, vY) want := cVector2Length(v) got := Vector2Length(v) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2754,7 +2756,7 @@ func FuzzVector2LengthSqr(f *testing.F) { v := NewVector2(vX, vY) want := cVector2LengthSqr(v) got := Vector2LengthSqr(v) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2800,7 +2802,7 @@ func FuzzVector2Lerp(f *testing.F) { v2 := NewVector2(v2X, v2Y) want := cVector2Lerp(v1, v2, amount) got := Vector2Lerp(v1, v2, amount) - if !testVector2Equals(want, got, 1e-6) { + if !testVector2Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2843,7 +2845,7 @@ func FuzzVector2LineAngle(f *testing.F) { end := NewVector2(endX, endY) want := cVector2LineAngle(start, end) got := Vector2LineAngle(start, end) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2889,7 +2891,7 @@ func FuzzVector2MoveTowards(f *testing.F) { target := NewVector2(targetX, targetY) want := cVector2MoveTowards(v, target, maxDistance) got := Vector2MoveTowards(v, target, maxDistance) - if !testVector2Equals(want, got, 1e-6) { + if !testVector2Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2932,7 +2934,7 @@ func FuzzVector2Multiply(f *testing.F) { v2 := NewVector2(v2X, v2Y) want := cVector2Multiply(v1, v2) got := Vector2Multiply(v1, v2) - if !testVector2Equals(want, got, 1e-6) { + if !testVector2Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -2971,7 +2973,7 @@ func FuzzVector2Negate(f *testing.F) { v := NewVector2(vX, vY) want := cVector2Negate(v) got := Vector2Negate(v) - if !testVector2Equals(want, got, 1e-6) { + if !testVector2Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3010,7 +3012,7 @@ func FuzzVector2Normalize(f *testing.F) { v := NewVector2(vX, vY) want := cVector2Normalize(v) got := Vector2Normalize(v) - if !testVector2Equals(want, got, 1e-6) { + if !testVector2Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3041,7 +3043,7 @@ func BenchmarkVector2One(b *testing.B) { func TestVector2One(t *testing.T) { want := cVector2One() got := Vector2One() - if !testVector2Equals(want, got, 1e-6) { + if !testVector2Equals(want, got) { t.Errorf("got %v; want %v", got, want) } } @@ -3083,7 +3085,7 @@ func FuzzVector2Reflect(f *testing.F) { normal := NewVector2(normalX, normalY) want := cVector2Reflect(v, normal) got := Vector2Reflect(v, normal) - if !testVector2Equals(want, got, 1e-6) { + if !testVector2Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3123,9 +3125,10 @@ func FuzzVector2Rotate(f *testing.F) { angle float32, ) { v := NewVector2(vX, vY) + v = Vector2Normalize(v) want := cVector2Rotate(v, angle) got := Vector2Rotate(v, angle) - if !testVector2Equals(want, got, 1e-1) { + if !testVector2Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3167,7 +3170,7 @@ func FuzzVector2Scale(f *testing.F) { v := NewVector2(vX, vY) want := cVector2Scale(v, scale) got := Vector2Scale(v, scale) - if !testVector2Equals(want, got, 1e-6) { + if !testVector2Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3210,7 +3213,7 @@ func FuzzVector2Subtract(f *testing.F) { v2 := NewVector2(v2X, v2Y) want := cVector2Subtract(v1, v2) got := Vector2Subtract(v1, v2) - if !testVector2Equals(want, got, 1e-6) { + if !testVector2Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3252,7 +3255,7 @@ func FuzzVector2SubtractValue(f *testing.F) { v := NewVector2(vX, vY) want := cVector2SubtractValue(v, sub) got := Vector2SubtractValue(v, sub) - if !testVector2Equals(want, got, 1e-6) { + if !testVector2Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3306,7 +3309,7 @@ func FuzzVector2Transform(f *testing.F) { ) want := cVector2Transform(v, mat) got := Vector2Transform(v, mat) - if !testVector2Equals(want, got, 1e-6) { + if !testVector2Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3337,7 +3340,7 @@ func BenchmarkVector2Zero(b *testing.B) { func TestVector2Zero(t *testing.T) { want := cVector2Zero() got := Vector2Zero() - if !testVector2Equals(want, got, 1e-6) { + if !testVector2Equals(want, got) { t.Errorf("got %v; want %v", got, want) } } @@ -3379,7 +3382,7 @@ func FuzzVector3Add(f *testing.F) { v2 := NewVector3(v2X, v2Y, v2Z) want := cVector3Add(v1, v2) got := Vector3Add(v1, v2) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3421,7 +3424,7 @@ func FuzzVector3AddValue(f *testing.F) { v := NewVector3(vX, vY, vZ) want := cVector3AddValue(v, add) got := Vector3AddValue(v, add) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3464,7 +3467,7 @@ func FuzzVector3Angle(f *testing.F) { v2 := NewVector3(v2X, v2Y, v2Z) want := cVector3Angle(v1, v2) got := Vector3Angle(v1, v2) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3515,7 +3518,7 @@ func FuzzVector3Barycenter(f *testing.F) { c := NewVector3(cX, cY, cZ) want := cVector3Barycenter(p, a, b1, c) got := Vector3Barycenter(p, a, b1, c) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3562,7 +3565,7 @@ func FuzzVector3Clamp(f *testing.F) { max := NewVector3(maxX, maxY, maxZ) want := cVector3Clamp(v, min, max) got := Vector3Clamp(v, min, max) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3607,7 +3610,7 @@ func FuzzVector3ClampValue(f *testing.F) { v := NewVector3(vX, vY, vZ) want := cVector3ClampValue(v, min, max) got := Vector3ClampValue(v, min, max) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3650,7 +3653,7 @@ func FuzzVector3CrossProduct(f *testing.F) { v2 := NewVector3(v2X, v2Y, v2Z) want := cVector3CrossProduct(v1, v2) got := Vector3CrossProduct(v1, v2) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3693,7 +3696,7 @@ func FuzzVector3Distance(f *testing.F) { v2 := NewVector3(v2X, v2Y, v2Z) want := cVector3Distance(v1, v2) got := Vector3Distance(v1, v2) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3736,7 +3739,7 @@ func FuzzVector3DistanceSqr(f *testing.F) { v2 := NewVector3(v2X, v2Y, v2Z) want := cVector3DistanceSqr(v1, v2) got := Vector3DistanceSqr(v1, v2) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3779,7 +3782,7 @@ func FuzzVector3Divide(f *testing.F) { v2 := NewVector3(v2X, v2Y, v2Z) want := cVector3Divide(v1, v2) got := Vector3Divide(v1, v2) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3822,7 +3825,7 @@ func FuzzVector3DotProduct(f *testing.F) { v2 := NewVector3(v2X, v2Y, v2Z) want := cVector3DotProduct(v1, v2) got := Vector3DotProduct(v1, v2) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3904,7 +3907,7 @@ func FuzzVector3Invert(f *testing.F) { v := NewVector3(vX, vY, vZ) want := cVector3Invert(v) got := Vector3Invert(v) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3943,7 +3946,7 @@ func FuzzVector3Length(f *testing.F) { v := NewVector3(vX, vY, vZ) want := cVector3Length(v) got := Vector3Length(v) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -3982,7 +3985,7 @@ func FuzzVector3LengthSqr(f *testing.F) { v := NewVector3(vX, vY, vZ) want := cVector3LengthSqr(v) got := Vector3LengthSqr(v) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -4028,7 +4031,7 @@ func FuzzVector3Lerp(f *testing.F) { v2 := NewVector3(v2X, v2Y, v2Z) want := cVector3Lerp(v1, v2, amount) got := Vector3Lerp(v1, v2, amount) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -4071,7 +4074,7 @@ func FuzzVector3Max(f *testing.F) { vec2 := NewVector3(vec2X, vec2Y, vec2Z) want := cVector3Max(vec1, vec2) got := Vector3Max(vec1, vec2) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -4114,7 +4117,7 @@ func FuzzVector3Min(f *testing.F) { vec2 := NewVector3(vec2X, vec2Y, vec2Z) want := cVector3Min(vec1, vec2) got := Vector3Min(vec1, vec2) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -4157,7 +4160,7 @@ func FuzzVector3Multiply(f *testing.F) { v2 := NewVector3(v2X, v2Y, v2Z) want := cVector3Multiply(v1, v2) got := Vector3Multiply(v1, v2) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -4196,7 +4199,7 @@ func FuzzVector3Negate(f *testing.F) { v := NewVector3(vX, vY, vZ) want := cVector3Negate(v) got := Vector3Negate(v) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -4235,7 +4238,7 @@ func FuzzVector3Normalize(f *testing.F) { v := NewVector3(vX, vY, vZ) want := cVector3Normalize(v) got := Vector3Normalize(v) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -4266,7 +4269,7 @@ func BenchmarkVector3One(b *testing.B) { func TestVector3One(t *testing.T) { want := cVector3One() got := Vector3One() - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } } @@ -4304,7 +4307,7 @@ func FuzzVector3Perpendicular(f *testing.F) { v := NewVector3(vX, vY, vZ) want := cVector3Perpendicular(v) got := Vector3Perpendicular(v) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -4347,7 +4350,7 @@ func FuzzVector3Project(f *testing.F) { v2 := NewVector3(v2X, v2Y, v2Z) want := cVector3Project(v1, v2) got := Vector3Project(v1, v2) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -4390,7 +4393,7 @@ func FuzzVector3Reflect(f *testing.F) { normal := NewVector3(normalX, normalY, normalZ) want := cVector3Reflect(vector, normal) got := Vector3Reflect(vector, normal) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -4436,7 +4439,7 @@ func FuzzVector3Refract(f *testing.F) { n := NewVector3(nX, nY, nZ) want := cVector3Refract(v, n, r) got := Vector3Refract(v, n, r) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -4479,7 +4482,7 @@ func FuzzVector3Reject(f *testing.F) { v2 := NewVector3(v2X, v2Y, v2Z) want := cVector3Reject(v1, v2) got := Vector3Reject(v1, v2) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -4522,10 +4525,12 @@ func FuzzVector3RotateByAxisAngle(f *testing.F) { angle float32, ) { v := NewVector3(vX, vY, vZ) + v = Vector3Normalize(v) axis := NewVector3(axisX, axisY, axisZ) + axis = Vector3Normalize(axis) want := cVector3RotateByAxisAngle(v, axis, angle) got := Vector3RotateByAxisAngle(v, axis, angle) - if !testVector3Equals(want, got, 1e-1) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -4568,7 +4573,7 @@ func FuzzVector3RotateByQuaternion(f *testing.F) { q := NewQuaternion(qX, qY, qZ, qW) want := cVector3RotateByQuaternion(v, q) got := Vector3RotateByQuaternion(v, q) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -4610,7 +4615,7 @@ func FuzzVector3Scale(f *testing.F) { v := NewVector3(vX, vY, vZ) want := cVector3Scale(v, scale) got := Vector3Scale(v, scale) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -4653,7 +4658,7 @@ func FuzzVector3Subtract(f *testing.F) { v2 := NewVector3(v2X, v2Y, v2Z) want := cVector3Subtract(v1, v2) got := Vector3Subtract(v1, v2) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -4695,7 +4700,7 @@ func FuzzVector3SubtractValue(f *testing.F) { v := NewVector3(vX, vY, vZ) want := cVector3SubtractValue(v, sub) got := Vector3SubtractValue(v, sub) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -4734,7 +4739,7 @@ func FuzzVector3ToFloatV(f *testing.F) { v := NewVector3(vX, vY, vZ) want := cVector3ToFloatV(v) got := Vector3ToFloatV(v) - if !testFloat32SliceEquals(want[:], got[:], 1e-6) { + if !testFloat32SliceEquals(want[:], got[:]) { t.Errorf("got %v; want %v", got, want) } }) @@ -4788,7 +4793,7 @@ func FuzzVector3Transform(f *testing.F) { ) want := cVector3Transform(v, mat) got := Vector3Transform(v, mat) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -4857,7 +4862,7 @@ func FuzzVector3Unproject(f *testing.F) { ) want := cVector3Unproject(source, projection, view) got := Vector3Unproject(source, projection, view) - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -4888,7 +4893,7 @@ func BenchmarkVector3Zero(b *testing.B) { func TestVector3Zero(t *testing.T) { want := cVector3Zero() got := Vector3Zero() - if !testVector3Equals(want, got, 1e-6) { + if !testVector3Equals(want, got) { t.Errorf("got %v; want %v", got, want) } } @@ -4931,7 +4936,7 @@ func FuzzWrap(f *testing.F) { ) { want := cWrap(value, min, max) got := Wrap(value, min, max) - if !testFloat32Equals(want, got, 1e-6) { + if !testFloat32Equals(want, got) { t.Errorf("got %v; want %v", got, want) } }) @@ -4939,7 +4944,7 @@ func FuzzWrap(f *testing.F) { // helpers -func testFloat32Equals(a, b float32, epsilon float64) bool { +func testFloat32Equals(a, b float32) bool { if math.IsNaN(float64(a)) && math.IsNaN(float64(b)) { return true } @@ -4952,51 +4957,51 @@ func testFloat32Equals(a, b float32, epsilon float64) bool { return math.Abs(float64(a-b)) <= epsilon*math.Max(1.0, math.Max(math.Abs(float64(a)), math.Abs(float64(b)))) } -func testFloat32SliceEquals(a, b []float32, epsilon float64) bool { +func testFloat32SliceEquals(a, b []float32) bool { if len(a) != len(b) { return false } for i := range a { - if !testFloat32Equals(a[i], b[i], epsilon) { + if !testFloat32Equals(a[i], b[i]) { return false } } return true } -func testVector2Equals(a, b Vector2, epsilon float64) bool { - return testFloat32Equals(a.X, b.X, epsilon) && - testFloat32Equals(a.Y, b.Y, epsilon) -} - -func testVector3Equals(a, b Vector3, epsilon float64) bool { - return testFloat32Equals(a.X, b.X, epsilon) && - testFloat32Equals(a.Y, b.Y, epsilon) && - testFloat32Equals(a.Z, b.Z, epsilon) -} - -func testQuaternionEquals(a, b Quaternion, epsilon float64) bool { - return testFloat32Equals(a.X, b.X, epsilon) && - testFloat32Equals(a.Y, b.Y, epsilon) && - testFloat32Equals(a.Z, b.Z, epsilon) && - testFloat32Equals(a.W, b.W, epsilon) -} - -func testMatrixEquals(a, b Matrix, epsilon float64) bool { - return testFloat32Equals(a.M0, b.M0, epsilon) && - testFloat32Equals(a.M1, b.M1, epsilon) && - testFloat32Equals(a.M2, b.M2, epsilon) && - testFloat32Equals(a.M3, b.M3, epsilon) && - testFloat32Equals(a.M4, b.M4, epsilon) && - testFloat32Equals(a.M5, b.M5, epsilon) && - testFloat32Equals(a.M6, b.M6, epsilon) && - testFloat32Equals(a.M7, b.M7, epsilon) && - testFloat32Equals(a.M8, b.M8, epsilon) && - testFloat32Equals(a.M9, b.M9, epsilon) && - testFloat32Equals(a.M10, b.M10, epsilon) && - testFloat32Equals(a.M11, b.M11, epsilon) && - testFloat32Equals(a.M12, b.M12, epsilon) && - testFloat32Equals(a.M13, b.M13, epsilon) && - testFloat32Equals(a.M14, b.M14, epsilon) && - testFloat32Equals(a.M15, b.M15, epsilon) +func testVector2Equals(a, b Vector2) bool { + return testFloat32Equals(a.X, b.X) && + testFloat32Equals(a.Y, b.Y) +} + +func testVector3Equals(a, b Vector3) bool { + return testFloat32Equals(a.X, b.X) && + testFloat32Equals(a.Y, b.Y) && + testFloat32Equals(a.Z, b.Z) +} + +func testQuaternionEquals(a, b Quaternion) bool { + return testFloat32Equals(a.X, b.X) && + testFloat32Equals(a.Y, b.Y) && + testFloat32Equals(a.Z, b.Z) && + testFloat32Equals(a.W, b.W) +} + +func testMatrixEquals(a, b Matrix) bool { + return testFloat32Equals(a.M0, b.M0) && + testFloat32Equals(a.M1, b.M1) && + testFloat32Equals(a.M2, b.M2) && + testFloat32Equals(a.M3, b.M3) && + testFloat32Equals(a.M4, b.M4) && + testFloat32Equals(a.M5, b.M5) && + testFloat32Equals(a.M6, b.M6) && + testFloat32Equals(a.M7, b.M7) && + testFloat32Equals(a.M8, b.M8) && + testFloat32Equals(a.M9, b.M9) && + testFloat32Equals(a.M10, b.M10) && + testFloat32Equals(a.M11, b.M11) && + testFloat32Equals(a.M12, b.M12) && + testFloat32Equals(a.M13, b.M13) && + testFloat32Equals(a.M14, b.M14) && + testFloat32Equals(a.M15, b.M15) } diff --git a/raylib/raymath_test.go b/raylib/raymath_test.go index c883a0ac..fbad255f 100644 --- a/raylib/raymath_test.go +++ b/raylib/raymath_test.go @@ -44,7 +44,7 @@ func FuzzVector3OrthoNormalize(f *testing.F) { ) { want1 := NewVector3(v1X, v1Y, v1Z) want2 := NewVector3(v2X, v2Y, v2Z) - if testVector3Equals(Vector3CrossProduct(want1, want2), Vector3Zero(), 1e-3) { + if testVector3Equals(Vector3CrossProduct(want1, want2), Vector3Zero()) { t.SkipNow() // too unstable on macos } cVector3OrthoNormalize(&want1, &want2) @@ -53,10 +53,10 @@ func FuzzVector3OrthoNormalize(f *testing.F) { got2 := NewVector3(v2X, v2Y, v2Z) Vector3OrthoNormalize(&got1, &got2) - if !testVector3Equals(want1, got1, 1e-6) { + if !testVector3Equals(want1, got1) { t.Errorf("v1: got %v; want %v", got1, want1) } - if !testVector3Equals(want2, got2, 1e-6) { + if !testVector3Equals(want2, got2) { t.Errorf("v2: got %v; want %v", got2, want2) } }) @@ -98,6 +98,7 @@ func FuzzQuaternionToAxisAngle(f *testing.F) { qX, qY, qZ, qW float32, ) { q := NewQuaternion(qX, qY, qZ, qW) + q = QuaternionNormalize(q) var wantAxis Vector3 var wantAngle float32 @@ -107,11 +108,11 @@ func FuzzQuaternionToAxisAngle(f *testing.F) { var gotAngle float32 QuaternionToAxisAngle(q, &gotAxis, &gotAngle) - if !testVector3Equals(wantAxis, skip, 1e-6) && // it's ok if our version has higher precision - !testVector3Equals(wantAxis, gotAxis, 0.2) { + if !testVector3Equals(wantAxis, skip) && // it's ok if our version has higher precision + !testVector3Equals(wantAxis, gotAxis) { t.Errorf("axis: got %v; want %v", gotAxis, wantAxis) } - if !testFloat32Equals(wantAngle, gotAngle, 1e-3) { + if !testFloat32Equals(wantAngle, gotAngle) { t.Errorf("angle: got %v; want %v", gotAngle, wantAngle) } }) @@ -182,13 +183,13 @@ func FuzzMatrixDecompose(f *testing.F) { var gotScale Vector3 cMatrixDecompose(mat, &gotTranslation, &gotRotation, &gotScale) - if !testVector3Equals(wantTranslation, gotTranslation, 1e-6) { + if !testVector3Equals(wantTranslation, gotTranslation) { t.Errorf("translation: got %v; want %v", gotTranslation, wantTranslation) } - if !testQuaternionEquals(wantRotation, gotRotation, 1e-6) { + if !testQuaternionEquals(wantRotation, gotRotation) { t.Errorf("rotation: got %v; want %v", gotRotation, wantRotation) } - if !testVector3Equals(wantScale, gotScale, 1e-6) { + if !testVector3Equals(wantScale, gotScale) { t.Errorf("scale: got %v; want %v", gotScale, wantScale) } })