/
main.go
139 lines (120 loc) · 3.96 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Example code for getting closer to operator overloading in Go through employing Lua
package main
import (
"fmt"
"github.com/westphae/quaternion"
"github.com/yuin/gopher-lua"
)
const (
// Lua file that can use the Quat class that is defined below
luaFilename = "main.lua"
// Internal ID for the Quat class in Lua
lQuatClass = "Quat"
)
// List of methods to register for the Quat class in Lua
// For an overview of available metamethods, see:
// http://www.lua.org/manual/5.1/manual.html#2.8
var quatMethods = map[string]lua.LGFunction{
"__tostring": quatString,
"__mul": quatMul,
"__add": quatAdd,
}
// Method for multiplying quaternions in Lua
func quatMul(L *lua.LState) int {
self := checkQuat(L, 1) // arg 1 (the object)
other := checkQuat(L, 2) // arg 2 (first method argument)
// Multiply self with other and return the result
result := quaternion.Prod(*self, *other)
userdata, err := constructQuat(L, &result)
if err != nil {
fmt.Println("ERROR", err)
L.Push(lua.LString(err.Error()))
return 1 // Number of returned values
}
L.Push(userdata)
return 1 // Number of returned values
}
// Method for adding quaternions in Lua
func quatAdd(L *lua.LState) int {
self := checkQuat(L, 1) // arg 1 (the object)
other := checkQuat(L, 2) // arg 2 (first method argument)
// Add self with other and return the result
result := quaternion.Quaternion{self.X + other.X, self.Y + other.Y, self.Z + other.Z, self.W + other.W}
userdata, err := constructQuat(L, &result)
if err != nil {
fmt.Println(err)
L.Push(lua.LString(err.Error()))
return 1 // Number of returned values
}
L.Push(userdata)
return 1 // Number of returned values
}
// For converting from a *unum.Quat to a userdata Quat in Lua
func constructQuat(L *lua.LState, q *quaternion.Quaternion) (*lua.LUserData, error) {
ud := L.NewUserData()
ud.Value = q
L.SetMetatable(ud, L.GetTypeMetatable(lQuatClass))
return ud, nil
}
// Check that the given argument number is a userdata Quat, and return it
func checkQuat(L *lua.LState, argnr int) *quaternion.Quaternion {
ud := L.CheckUserData(argnr)
if quat, ok := ud.Value.(*quaternion.Quaternion); ok {
return quat
}
L.ArgError(argnr, "Quat expected")
return nil
}
// Represent a userdata Quat as a Lua string
func quatString(L *lua.LState) int {
self := checkQuat(L, 1) // arg 1 (before the ":")
// Create a string representation of the Quaternion
repr := fmt.Sprintf("[%.3f %.3f %.3f %.3f]", self.X, self.Y, self.Z, self.W)
L.Push(lua.LString(repr))
return 1 // number of results
}
func main() {
// Create a new Lua VM
L := lua.NewState()
defer L.Close()
// Register the Quat class and the methods that belongs with it.
mt := L.NewTypeMetatable(lQuatClass)
mt.RawSetH(lua.LString("__index"), mt)
L.SetFuncs(mt, quatMethods)
// The Lua constructor for new Quat objects. Takes four numbers.
L.SetGlobal("Quat", L.NewFunction(func(L *lua.LState) int {
// Get the four numeric values
x := float64(L.ToNumber(1)) // argument 1
y := float64(L.ToNumber(2)) // argument 2
z := float64(L.ToNumber(3)) // argument 3
w := float64(L.ToNumber(4)) // argument 4
// Construct a new Quat
userdata, err := constructQuat(L, &quaternion.Quaternion{x, y, z, w})
if err != nil {
fmt.Println("ERROR", err)
L.Push(lua.LString(err.Error()))
return 1 // Number of returned values
}
// Construct a Lua table with the four values
table := L.NewTable()
table.Append(lua.LNumber(x))
table.Append(lua.LNumber(y))
table.Append(lua.LNumber(z))
table.Append(lua.LNumber(w))
// Set object fields that are not methods, but values
mt := L.GetMetatable(userdata)
L.SetField(mt, "x", lua.LNumber(x))
L.SetField(mt, "y", lua.LNumber(y))
L.SetField(mt, "z", lua.LNumber(z))
L.SetField(mt, "w", lua.LNumber(w))
L.SetField(mt, "table", table)
L.SetMetatable(userdata, mt)
// Return the Lua Quat object
L.Push(userdata)
return 1 // number of results
}))
// Run the Lua script
if err := L.DoFile(luaFilename); err != nil {
panic(err)
}
}