199 lines
6.3 KiB
Go
199 lines
6.3 KiB
Go
package sdl
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime"
|
|
"unsafe"
|
|
|
|
"github.com/ebitengine/purego"
|
|
)
|
|
|
|
const (
|
|
InitVideo uint32 = 0x00000020
|
|
WindowVulkan uint64 = 0x0000000010000000
|
|
WindowResizable uint64 = 0x0000000000000020
|
|
|
|
EventQuit uint32 = 0x100
|
|
EventWindowResized uint32 = 0x206
|
|
EventPixelSizeChanged uint32 = 0x207
|
|
|
|
EventKeyDown uint32 = 0x300
|
|
EventKeyUp uint32 = 0x301
|
|
|
|
EventMouseMotion uint32 = 0x400
|
|
EventMouseButtonDown uint32 = 0x401
|
|
EventMouseButtonUp uint32 = 0x402
|
|
EventMouseWheel uint32 = 0x403
|
|
|
|
EventTextInput uint32 = 0x303
|
|
|
|
// it's about SDL_keycode, not SDL_scancode
|
|
KeyEscape uint32 = 0x1B
|
|
KeyF uint32 = 0x66
|
|
KeyQ uint32 = 0x71
|
|
KeyF1 uint32 = 0x4000003A
|
|
|
|
InitAudio uint32 = 0x00000010
|
|
AudioDeviceDefaultPlayback uint32 = 0xFFFFFFFF
|
|
AudioF32 uint16 = 0x8120
|
|
)
|
|
|
|
var (
|
|
sdlInit func(flags uint32) bool
|
|
sdlQuit func()
|
|
sdlGetError func() uintptr
|
|
|
|
sdlCreateWindow func(title *byte, w, h int32, flags uint64) uintptr
|
|
sdlDestroyWindow func(window uintptr)
|
|
|
|
sdlVulkanGetInstanceExtensions func(count *uint32) uintptr
|
|
sdlVulkanCreateSurface func(window, instance, allocator uintptr, surface *uint64) bool
|
|
|
|
sdlPollEvent func(event unsafe.Pointer) bool
|
|
|
|
sdlGetWindowSizeInPixels func(window uintptr, w, h *int32) bool
|
|
sdlSetWindowFullscreen func(window uintptr, fullscreen bool) bool
|
|
|
|
sdlOpenAudioDeviceStream func(devid uint32, spec unsafe.Pointer, callback uintptr, userdata uintptr) uintptr
|
|
sdlResumeAudioStreamDevice func(stream uintptr) bool
|
|
sdlPutAudioStreamData func(stream uintptr, buf unsafe.Pointer, length int32) bool
|
|
sdlGetAudioStreamQueued func(stream uintptr) int32
|
|
sdlDestroyAudioStream func(stream uintptr)
|
|
sdlGetAudioPlaybackDevices func(count *int32) uintptr
|
|
sdlGetAudioDeviceName func(devid uint32) uintptr
|
|
|
|
sdlStartTextInput func(window uintptr)
|
|
sdlStopTextInput func(window uintptr)
|
|
)
|
|
|
|
var loaded = false
|
|
|
|
func Load() error {
|
|
if loaded {
|
|
return nil
|
|
}
|
|
h, err := purego.Dlopen("libSDL3.so.0", purego.RTLD_NOW|purego.RTLD_GLOBAL)
|
|
if err != nil {
|
|
return fmt.Errorf("win: load SDL3: %w", err)
|
|
}
|
|
purego.RegisterLibFunc(&sdlInit, h, "SDL_Init")
|
|
purego.RegisterLibFunc(&sdlQuit, h, "SDL_Quit")
|
|
purego.RegisterLibFunc(&sdlGetError, h, "SDL_GetError")
|
|
purego.RegisterLibFunc(&sdlCreateWindow, h, "SDL_CreateWindow")
|
|
purego.RegisterLibFunc(&sdlDestroyWindow, h, "SDL_DestroyWindow")
|
|
purego.RegisterLibFunc(&sdlVulkanGetInstanceExtensions, h, "SDL_Vulkan_GetInstanceExtensions")
|
|
purego.RegisterLibFunc(&sdlVulkanCreateSurface, h, "SDL_Vulkan_CreateSurface")
|
|
purego.RegisterLibFunc(&sdlPollEvent, h, "SDL_PollEvent")
|
|
purego.RegisterLibFunc(&sdlGetWindowSizeInPixels, h, "SDL_GetWindowSizeInPixels")
|
|
purego.RegisterLibFunc(&sdlSetWindowFullscreen, h, "SDL_SetWindowFullscreen")
|
|
// audio
|
|
purego.RegisterLibFunc(&sdlOpenAudioDeviceStream, h, "SDL_OpenAudioDeviceStream")
|
|
purego.RegisterLibFunc(&sdlResumeAudioStreamDevice, h, "SDL_ResumeAudioStreamDevice")
|
|
purego.RegisterLibFunc(&sdlPutAudioStreamData, h, "SDL_PutAudioStreamData")
|
|
purego.RegisterLibFunc(&sdlGetAudioStreamQueued, h, "SDL_GetAudioStreamQueued")
|
|
purego.RegisterLibFunc(&sdlDestroyAudioStream, h, "SDL_DestroyAudioStream")
|
|
purego.RegisterLibFunc(&sdlGetAudioPlaybackDevices, h, "SDL_GetAudioPlaybackDevices")
|
|
purego.RegisterLibFunc(&sdlGetAudioDeviceName, h, "SDL_GetAudioDeviceName")
|
|
// input
|
|
purego.RegisterLibFunc(&sdlStartTextInput, h, "SDL_StartTextInput")
|
|
purego.RegisterLibFunc(&sdlStopTextInput, h, "SDL_StopTextInput")
|
|
loaded = true
|
|
return nil
|
|
}
|
|
|
|
func Init(flags uint32) bool { return sdlInit(flags) }
|
|
func Quit() { sdlQuit() }
|
|
func GetError() string { return cstr(sdlGetError()) }
|
|
|
|
func CreateWindow(title string, w, h int32, flags uint64) uintptr {
|
|
return sdlCreateWindow(cbytes(title), w, h, flags)
|
|
}
|
|
func DestroyWindow(window uintptr) { sdlDestroyWindow(window) }
|
|
|
|
func VulkanGetInstanceExtensions() []string {
|
|
var count uint32
|
|
vkExts := sdlVulkanGetInstanceExtensions(&count)
|
|
if vkExts == 0 {
|
|
return nil
|
|
}
|
|
exts := make([]string, count)
|
|
for i := uint32(0); i < count; i++ {
|
|
p := *(*uintptr)(unsafe.Pointer(vkExts + uintptr(i)*unsafe.Sizeof(uintptr(0))))
|
|
exts[i] = cstr(p)
|
|
}
|
|
return exts
|
|
}
|
|
func VulkanCreateSurface(window, instance, allocator uintptr, surface *uint64) bool {
|
|
return sdlVulkanCreateSurface(window, instance, allocator, surface)
|
|
}
|
|
|
|
func PollEvent(event unsafe.Pointer) bool { return sdlPollEvent(event) }
|
|
|
|
func GetWindowSizeInPixels(window uintptr, w, h *int32) bool {
|
|
return sdlGetWindowSizeInPixels(window, w, h)
|
|
}
|
|
func SetWindowFullscreen(window uintptr, fullscreen bool) bool {
|
|
return sdlSetWindowFullscreen(window, fullscreen)
|
|
}
|
|
|
|
// cstr reads a NUL-terminated C string at p.
|
|
func cstr(p uintptr) string {
|
|
if p == 0 {
|
|
return ""
|
|
}
|
|
var n int
|
|
for *(*byte)(unsafe.Pointer(p + uintptr(n))) != 0 {
|
|
n++
|
|
}
|
|
return string(unsafe.Slice((*byte)(unsafe.Pointer(p)), n))
|
|
}
|
|
|
|
// cbytes returns a NUL-terminated copy of s as *byte, kept alive by the caller.
|
|
func cbytes(s string) *byte {
|
|
b := make([]byte, len(s)+1)
|
|
copy(b, s)
|
|
runtime.KeepAlive(b)
|
|
return &b[0]
|
|
}
|
|
|
|
type AudioSpec struct {
|
|
Format uint16
|
|
Channels int32
|
|
Freq int32
|
|
}
|
|
|
|
func OpenAudioDeviceStream(devid uint32, spec AudioSpec) uintptr {
|
|
return sdlOpenAudioDeviceStream(devid, unsafe.Pointer(&spec), 0, 0)
|
|
}
|
|
func ResumeAudioStreamDevice(stream uintptr) bool { return sdlResumeAudioStreamDevice(stream) }
|
|
func DestroyAudioStream(stream uintptr) { sdlDestroyAudioStream(stream) }
|
|
func PutAudioStreamData(stream uintptr, buf []byte) bool {
|
|
return sdlPutAudioStreamData(stream, unsafe.Pointer(&buf[0]), int32(len(buf)))
|
|
}
|
|
func GetAudioStreamQueued(stream uintptr) int32 { return sdlGetAudioStreamQueued(stream) }
|
|
|
|
// playback device
|
|
type AudioDevice struct {
|
|
ID uint32
|
|
Name string
|
|
}
|
|
|
|
func GetAudioPlaybackDevices() []AudioDevice {
|
|
var count int32
|
|
ptr := sdlGetAudioPlaybackDevices(&count)
|
|
if ptr == 0 || count == 0 {
|
|
return nil
|
|
}
|
|
ids := unsafe.Slice((*uint32)(unsafe.Pointer(ptr)), count)
|
|
devs := make([]AudioDevice, 0, count)
|
|
for _, id := range ids {
|
|
name := cstr(sdlGetAudioDeviceName(id))
|
|
devs = append(devs, AudioDevice{ID: id, Name: name})
|
|
}
|
|
return devs
|
|
}
|
|
|
|
// Input wrappers
|
|
func StartTextInput(window uintptr) { sdlStartTextInput(window) }
|
|
func StopTextInput(window uintptr) { sdlStopTextInput(window) }
|