Download bindings/go/motionbricks.go from chibifire/motion-bricks.cpp: direct link, hf CLI and curl.
- Browser
- Download file 17.6 kB
-
https://huggingface.co/chibifire/motion-bricks.cpp/resolve/main/bindings/go/motionbricks.go
- Command line
-
hf download hf://chibifire/motion-bricks.cpp/bindings/go/motionbricks.go
-
curl -L -o motionbricks.go https://huggingface.co/chibifire/motion-bricks.cpp/resolve/main/bindings/go/motionbricks.go
17.6 kB
| //go:build linux || darwin || freebsd | |
| // Package motionbricks provides a PureGo wrapper around the stable opaque C ABI. | |
| package motionbricks | |
| import ( | |
| "errors" | |
| "fmt" | |
| "math" | |
| "unsafe" | |
| "github.com/ebitengine/purego" | |
| ) | |
| type Device uint32 | |
| const ( | |
| DeviceAuto Device = 0 | |
| DeviceCPU Device = 1 | |
| DeviceVulkan Device = 2 | |
| ) | |
| const errorBufferSize = 1024 | |
| type Library struct { | |
| handle uintptr | |
| abiVersion func() uint32 | |
| statusString func(uint32) uintptr | |
| optionsCreate func(unsafe.Pointer, unsafe.Pointer, uint64) uint32 | |
| optionsFree func(uintptr) | |
| optionsSetDevice func(uintptr, uint32, unsafe.Pointer, uint64) uint32 | |
| modelLoad func(unsafe.Pointer, uintptr, unsafe.Pointer, unsafe.Pointer, uint64) uint32 | |
| modelFree func(uintptr) | |
| modelJointCount func(uintptr, unsafe.Pointer, unsafe.Pointer, uint64) uint32 | |
| modelJointName func(uintptr, uint32, unsafe.Pointer, unsafe.Pointer, uint64) uint32 | |
| modelJointParent func(uintptr, uint32, unsafe.Pointer, unsafe.Pointer, uint64) uint32 | |
| modelNeutralPosition func(uintptr, uint32, unsafe.Pointer, unsafe.Pointer, unsafe.Pointer, unsafe.Pointer, uint64) uint32 | |
| styleLoad func(uintptr, unsafe.Pointer, unsafe.Pointer, unsafe.Pointer, uint64) uint32 | |
| styleFree func(uintptr) | |
| styleName func(uintptr, unsafe.Pointer, unsafe.Pointer, uint64) uint32 | |
| styleSpeed func(uintptr, unsafe.Pointer, unsafe.Pointer, uint64) uint32 | |
| agentCreate func(uintptr, unsafe.Pointer, unsafe.Pointer, uint64) uint32 | |
| agentFree func(uintptr) | |
| agentReset func(uintptr, uintptr, unsafe.Pointer, uint64) uint32 | |
| agentSetContext func(uintptr, unsafe.Pointer, unsafe.Pointer, uint64, uint64, unsafe.Pointer, uint64) uint32 | |
| agentPlan func(uintptr, uintptr, unsafe.Pointer, unsafe.Pointer, uint64) uint32 | |
| agentAdvance func(uintptr, uint32, unsafe.Pointer, uint64) uint32 | |
| commandCreate func(unsafe.Pointer, unsafe.Pointer, uint64) uint32 | |
| commandFree func(uintptr) | |
| commandSetStyle func(uintptr, uintptr, unsafe.Pointer, uint64) uint32 | |
| commandSetMovement func(uintptr, float32, float32, float32, unsafe.Pointer, uint64) uint32 | |
| commandSetFacing func(uintptr, float32, float32, float32, unsafe.Pointer, uint64) uint32 | |
| commandSetSpeed func(uintptr, float32, unsafe.Pointer, uint64) uint32 | |
| commandSetWorldTarget func(uintptr, float32, float32, float32, float32, uint32, unsafe.Pointer, uint64) uint32 | |
| commandSetSeed func(uintptr, uint64, unsafe.Pointer, uint64) uint32 | |
| motionFree func(uintptr) | |
| motionFrames func(uintptr, unsafe.Pointer, unsafe.Pointer, uint64) uint32 | |
| motionJoints func(uintptr, unsafe.Pointer, unsafe.Pointer, uint64) uint32 | |
| motionRoots func(uintptr, unsafe.Pointer, unsafe.Pointer, unsafe.Pointer, uint64) uint32 | |
| motionRotations func(uintptr, unsafe.Pointer, unsafe.Pointer, unsafe.Pointer, uint64) uint32 | |
| motionTargetFrames func(uintptr, unsafe.Pointer, unsafe.Pointer, uint64) uint32 | |
| motionTargetRoots func(uintptr, unsafe.Pointer, unsafe.Pointer, unsafe.Pointer, uint64) uint32 | |
| motionTargetRotations func(uintptr, unsafe.Pointer, unsafe.Pointer, unsafe.Pointer, uint64) uint32 | |
| } | |
| func Open(path string) (*Library, error) { | |
| handle, err := purego.Dlopen(path, purego.RTLD_NOW|purego.RTLD_LOCAL) | |
| if err != nil { | |
| return nil, err | |
| } | |
| library := &Library{handle: handle} | |
| register := func(target any, name string) { purego.RegisterLibFunc(target, handle, name) } | |
| register(&library.abiVersion, "mb_abi_version") | |
| register(&library.statusString, "mb_status_string") | |
| register(&library.optionsCreate, "mb_runtime_options_create") | |
| register(&library.optionsFree, "mb_runtime_options_free") | |
| register(&library.optionsSetDevice, "mb_runtime_options_set_device") | |
| register(&library.modelLoad, "mb_model_load") | |
| register(&library.modelFree, "mb_model_free") | |
| register(&library.modelJointCount, "mb_model_get_joint_count") | |
| register(&library.modelJointName, "mb_model_get_joint_name") | |
| register(&library.modelJointParent, "mb_model_get_joint_parent") | |
| register(&library.modelNeutralPosition, "mb_model_get_neutral_joint_position") | |
| register(&library.styleLoad, "mb_style_load") | |
| register(&library.styleFree, "mb_style_free") | |
| register(&library.styleName, "mb_style_get_name") | |
| register(&library.styleSpeed, "mb_style_get_speed") | |
| register(&library.agentCreate, "mb_agent_create") | |
| register(&library.agentFree, "mb_agent_free") | |
| register(&library.agentReset, "mb_agent_reset") | |
| register(&library.agentSetContext, "mb_agent_set_context") | |
| register(&library.agentPlan, "mb_agent_plan") | |
| register(&library.agentAdvance, "mb_agent_advance") | |
| register(&library.commandCreate, "mb_command_create") | |
| register(&library.commandFree, "mb_command_free") | |
| register(&library.commandSetStyle, "mb_command_set_style") | |
| register(&library.commandSetMovement, "mb_command_set_movement_direction") | |
| register(&library.commandSetFacing, "mb_command_set_facing_direction") | |
| register(&library.commandSetSpeed, "mb_command_set_target_speed") | |
| register(&library.commandSetWorldTarget, "mb_command_set_world_target") | |
| register(&library.commandSetSeed, "mb_command_set_seed") | |
| register(&library.motionFree, "mb_motion_free") | |
| register(&library.motionFrames, "mb_motion_get_frame_count") | |
| register(&library.motionJoints, "mb_motion_get_joint_count") | |
| register(&library.motionRoots, "mb_motion_get_root_translations") | |
| register(&library.motionRotations, "mb_motion_get_local_rotations_xyzw") | |
| register(&library.motionTargetFrames, "mb_motion_get_target_frame_count") | |
| register(&library.motionTargetRoots, "mb_motion_get_target_root_translations") | |
| register(&library.motionTargetRotations, "mb_motion_get_target_local_rotations_xyzw") | |
| if version := library.abiVersion(); version != 1 { | |
| library.Close() | |
| return nil, fmt.Errorf("motionbricks ABI version %d is unsupported", version) | |
| } | |
| return library, nil | |
| } | |
| func (l *Library) Close() error { | |
| if l == nil || l.handle == 0 { | |
| return nil | |
| } | |
| err := purego.Dlclose(l.handle) | |
| l.handle = 0 | |
| return err | |
| } | |
| func cString(value string) ([]byte, error) { | |
| for _, char := range value { | |
| if char == 0 { | |
| return nil, errors.New("string contains NUL") | |
| } | |
| } | |
| return append([]byte(value), 0), nil | |
| } | |
| func goString(pointer uintptr) string { | |
| if pointer == 0 { | |
| return "" | |
| } | |
| const maximum = 1 << 20 | |
| bytes := make([]byte, 0, 64) | |
| for index := uintptr(0); index < maximum; index++ { | |
| value := *(*byte)(unsafe.Pointer(pointer + index)) | |
| if value == 0 { | |
| return string(bytes) | |
| } | |
| bytes = append(bytes, value) | |
| } | |
| return "" | |
| } | |
| func errorPointer(buffer []byte) unsafe.Pointer { return unsafe.Pointer(&buffer[0]) } | |
| func (l *Library) check(operation string, status uint32, buffer []byte) error { | |
| if status == 0 { | |
| return nil | |
| } | |
| message := "" | |
| for index, value := range buffer { | |
| if value == 0 { | |
| message = string(buffer[:index]) | |
| break | |
| } | |
| } | |
| if message == "" { | |
| message = goString(l.statusString(status)) | |
| } | |
| return fmt.Errorf("%s: %s", operation, message) | |
| } | |
| type Model struct { | |
| library *Library | |
| handle uintptr | |
| } | |
| type Style struct { | |
| library *Library | |
| handle uintptr | |
| Name string | |
| Speed float32 | |
| } | |
| type Agent struct { | |
| model *Model | |
| handle uintptr | |
| } | |
| type Command struct { | |
| library *Library | |
| handle uintptr | |
| } | |
| type Joint struct { | |
| Name string `json:"name"` | |
| Parent int32 `json:"parent"` | |
| Position [3]float32 `json:"position"` | |
| } | |
| type Motion struct { | |
| Frames uint64 `json:"frames"` | |
| Joints uint64 `json:"joints"` | |
| Roots []float32 `json:"roots"` | |
| Rotations []float32 `json:"rotations"` | |
| Targets *Keyframes `json:"-"` | |
| } | |
| type Keyframes struct { | |
| Frames uint64 `json:"frames"` | |
| Joints uint64 `json:"joints"` | |
| Roots []float32 `json:"roots"` | |
| Rotations []float32 `json:"rotations"` | |
| } | |
| func (l *Library) LoadModel(path string, device Device) (*Model, error) { | |
| pathBytes, err := cString(path) | |
| if err != nil { | |
| return nil, err | |
| } | |
| buffer := make([]byte, errorBufferSize) | |
| var options uintptr | |
| if err = l.check("create runtime options", l.optionsCreate(unsafe.Pointer(&options), errorPointer(buffer), uint64(len(buffer))), buffer); err != nil { | |
| return nil, err | |
| } | |
| defer l.optionsFree(options) | |
| if err = l.check("select device", l.optionsSetDevice(options, uint32(device), errorPointer(buffer), uint64(len(buffer))), buffer); err != nil { | |
| return nil, err | |
| } | |
| var handle uintptr | |
| status := l.modelLoad(unsafe.Pointer(&pathBytes[0]), options, unsafe.Pointer(&handle), errorPointer(buffer), uint64(len(buffer))) | |
| if err = l.check("load model", status, buffer); err != nil { | |
| return nil, err | |
| } | |
| return &Model{library: l, handle: handle}, nil | |
| } | |
| func (m *Model) Close() { | |
| if m != nil && m.handle != 0 { | |
| m.library.modelFree(m.handle) | |
| m.handle = 0 | |
| } | |
| } | |
| func (m *Model) Skeleton() ([]Joint, error) { | |
| buffer := make([]byte, errorBufferSize) | |
| var count uint32 | |
| if err := m.library.check("get joint count", m.library.modelJointCount(m.handle, unsafe.Pointer(&count), errorPointer(buffer), uint64(len(buffer))), buffer); err != nil { | |
| return nil, err | |
| } | |
| joints := make([]Joint, count) | |
| for index := uint32(0); index < count; index++ { | |
| var name uintptr | |
| if err := m.library.check("get joint name", m.library.modelJointName(m.handle, index, unsafe.Pointer(&name), errorPointer(buffer), uint64(len(buffer))), buffer); err != nil { | |
| return nil, err | |
| } | |
| joints[index].Name = goString(name) | |
| if err := m.library.check("get joint parent", m.library.modelJointParent(m.handle, index, unsafe.Pointer(&joints[index].Parent), errorPointer(buffer), uint64(len(buffer))), buffer); err != nil { | |
| return nil, err | |
| } | |
| position := &joints[index].Position | |
| if err := m.library.check("get neutral position", m.library.modelNeutralPosition(m.handle, index, unsafe.Pointer(&position[0]), unsafe.Pointer(&position[1]), unsafe.Pointer(&position[2]), errorPointer(buffer), uint64(len(buffer))), buffer); err != nil { | |
| return nil, err | |
| } | |
| } | |
| return joints, nil | |
| } | |
| func (m *Model) LoadStyle(path string) (*Style, error) { | |
| pathBytes, err := cString(path) | |
| if err != nil { | |
| return nil, err | |
| } | |
| buffer := make([]byte, errorBufferSize) | |
| var handle uintptr | |
| if err = m.library.check("load style", m.library.styleLoad(m.handle, unsafe.Pointer(&pathBytes[0]), unsafe.Pointer(&handle), errorPointer(buffer), uint64(len(buffer))), buffer); err != nil { | |
| return nil, err | |
| } | |
| style := &Style{library: m.library, handle: handle} | |
| var name uintptr | |
| if err = m.library.check("get style name", m.library.styleName(handle, unsafe.Pointer(&name), errorPointer(buffer), uint64(len(buffer))), buffer); err != nil { | |
| style.Close() | |
| return nil, err | |
| } | |
| style.Name = goString(name) | |
| if err = m.library.check("get style speed", m.library.styleSpeed(handle, unsafe.Pointer(&style.Speed), errorPointer(buffer), uint64(len(buffer))), buffer); err != nil { | |
| style.Close() | |
| return nil, err | |
| } | |
| return style, nil | |
| } | |
| func (s *Style) Close() { | |
| if s != nil && s.handle != 0 { | |
| s.library.styleFree(s.handle) | |
| s.handle = 0 | |
| } | |
| } | |
| func (m *Model) NewAgent() (*Agent, error) { | |
| buffer := make([]byte, errorBufferSize) | |
| var handle uintptr | |
| if err := m.library.check("create agent", m.library.agentCreate(m.handle, unsafe.Pointer(&handle), errorPointer(buffer), uint64(len(buffer))), buffer); err != nil { | |
| return nil, err | |
| } | |
| return &Agent{model: m, handle: handle}, nil | |
| } | |
| func (a *Agent) Close() { | |
| if a != nil && a.handle != 0 { | |
| a.model.library.agentFree(a.handle) | |
| a.handle = 0 | |
| } | |
| } | |
| func (a *Agent) Reset(style *Style) error { | |
| buffer := make([]byte, errorBufferSize) | |
| return a.model.library.check("reset agent", a.model.library.agentReset(a.handle, style.handle, errorPointer(buffer), uint64(len(buffer))), buffer) | |
| } | |
| func (a *Agent) Advance(frames uint32) error { | |
| buffer := make([]byte, errorBufferSize) | |
| return a.model.library.check("advance agent", a.model.library.agentAdvance(a.handle, frames, errorPointer(buffer), uint64(len(buffer))), buffer) | |
| } | |
| func (a *Agent) SetContext(roots, rotations []float32, frames uint64) error { | |
| if frames < 4 || len(roots) != int(frames*3) || len(rotations) != int(frames*34*4) { | |
| return errors.New("invalid G1 context shape") | |
| } | |
| buffer := make([]byte, errorBufferSize) | |
| return a.model.library.check("set agent context", a.model.library.agentSetContext(a.handle, unsafe.Pointer(&roots[0]), unsafe.Pointer(&rotations[0]), frames, 34, errorPointer(buffer), uint64(len(buffer))), buffer) | |
| } | |
| func (l *Library) NewCommand() (*Command, error) { | |
| buffer := make([]byte, errorBufferSize) | |
| var handle uintptr | |
| if err := l.check("create command", l.commandCreate(unsafe.Pointer(&handle), errorPointer(buffer), uint64(len(buffer))), buffer); err != nil { | |
| return nil, err | |
| } | |
| return &Command{library: l, handle: handle}, nil | |
| } | |
| func (c *Command) Close() { | |
| if c != nil && c.handle != 0 { | |
| c.library.commandFree(c.handle) | |
| c.handle = 0 | |
| } | |
| } | |
| func (c *Command) SetStyle(style *Style) error { | |
| buffer := make([]byte, errorBufferSize) | |
| return c.library.check("set command style", c.library.commandSetStyle(c.handle, style.handle, errorPointer(buffer), uint64(len(buffer))), buffer) | |
| } | |
| func (c *Command) SetMovement(x, y, z float32) error { | |
| buffer := make([]byte, errorBufferSize) | |
| return c.library.check("set movement", c.library.commandSetMovement(c.handle, x, y, z, errorPointer(buffer), uint64(len(buffer))), buffer) | |
| } | |
| func (c *Command) SetFacing(x, y, z float32) error { | |
| buffer := make([]byte, errorBufferSize) | |
| return c.library.check("set facing", c.library.commandSetFacing(c.handle, x, y, z, errorPointer(buffer), uint64(len(buffer))), buffer) | |
| } | |
| func (c *Command) SetSpeed(speed float32) error { | |
| if math.IsNaN(float64(speed)) { | |
| return errors.New("speed is NaN") | |
| } | |
| buffer := make([]byte, errorBufferSize) | |
| return c.library.check("set speed", c.library.commandSetSpeed(c.handle, speed, errorPointer(buffer), uint64(len(buffer))), buffer) | |
| } | |
| func (c *Command) SetSeed(seed uint64) error { | |
| buffer := make([]byte, errorBufferSize) | |
| return c.library.check("set seed", c.library.commandSetSeed(c.handle, seed, errorPointer(buffer), uint64(len(buffer))), buffer) | |
| } | |
| func (c *Command) SetWorldTarget(x, y, z, heading float32, enabled bool) error { | |
| var flag uint32 | |
| if enabled { | |
| flag = 1 | |
| } | |
| buffer := make([]byte, errorBufferSize) | |
| return c.library.check("set world target", c.library.commandSetWorldTarget(c.handle, x, y, z, heading, flag, errorPointer(buffer), uint64(len(buffer))), buffer) | |
| } | |
| func (a *Agent) Plan(command *Command) (*Motion, error) { | |
| buffer := make([]byte, errorBufferSize) | |
| var handle uintptr | |
| if err := a.model.library.check("plan motion", a.model.library.agentPlan(a.handle, command.handle, unsafe.Pointer(&handle), errorPointer(buffer), uint64(len(buffer))), buffer); err != nil { | |
| return nil, err | |
| } | |
| defer a.model.library.motionFree(handle) | |
| motion := &Motion{} | |
| var rootsPointer, rotationsPointer, targetRootsPointer, targetRotationsPointer uintptr | |
| var rootsCount, rotationsCount, targetRootsCount, targetRotationsCount uint64 | |
| if err := a.model.library.check("get frame count", a.model.library.motionFrames(handle, unsafe.Pointer(&motion.Frames), errorPointer(buffer), uint64(len(buffer))), buffer); err != nil { | |
| return nil, err | |
| } | |
| if err := a.model.library.check("get joint count", a.model.library.motionJoints(handle, unsafe.Pointer(&motion.Joints), errorPointer(buffer), uint64(len(buffer))), buffer); err != nil { | |
| return nil, err | |
| } | |
| if err := a.model.library.check("get roots", a.model.library.motionRoots(handle, unsafe.Pointer(&rootsPointer), unsafe.Pointer(&rootsCount), errorPointer(buffer), uint64(len(buffer))), buffer); err != nil { | |
| return nil, err | |
| } | |
| if err := a.model.library.check("get rotations", a.model.library.motionRotations(handle, unsafe.Pointer(&rotationsPointer), unsafe.Pointer(&rotationsCount), errorPointer(buffer), uint64(len(buffer))), buffer); err != nil { | |
| return nil, err | |
| } | |
| targets := &Keyframes{Joints: motion.Joints} | |
| if err := a.model.library.check("get target frame count", a.model.library.motionTargetFrames(handle, unsafe.Pointer(&targets.Frames), errorPointer(buffer), uint64(len(buffer))), buffer); err != nil { | |
| return nil, err | |
| } | |
| if err := a.model.library.check("get target roots", a.model.library.motionTargetRoots(handle, unsafe.Pointer(&targetRootsPointer), unsafe.Pointer(&targetRootsCount), errorPointer(buffer), uint64(len(buffer))), buffer); err != nil { | |
| return nil, err | |
| } | |
| if err := a.model.library.check("get target rotations", a.model.library.motionTargetRotations(handle, unsafe.Pointer(&targetRotationsPointer), unsafe.Pointer(&targetRotationsCount), errorPointer(buffer), uint64(len(buffer))), buffer); err != nil { | |
| return nil, err | |
| } | |
| if rootsCount != motion.Frames*3 || rotationsCount != motion.Frames*motion.Joints*4 || | |
| targetRootsCount != targets.Frames*3 || targetRotationsCount != targets.Frames*targets.Joints*4 { | |
| return nil, errors.New("native motion data has inconsistent dimensions") | |
| } | |
| motion.Roots = append([]float32(nil), unsafe.Slice((*float32)(unsafe.Pointer(rootsPointer)), rootsCount)...) | |
| motion.Rotations = append([]float32(nil), unsafe.Slice((*float32)(unsafe.Pointer(rotationsPointer)), rotationsCount)...) | |
| targets.Roots = append([]float32(nil), unsafe.Slice((*float32)(unsafe.Pointer(targetRootsPointer)), targetRootsCount)...) | |
| targets.Rotations = append([]float32(nil), unsafe.Slice((*float32)(unsafe.Pointer(targetRotationsPointer)), targetRotationsCount)...) | |
| motion.Targets = targets | |
| return motion, nil | |
| } | |