Files
go-mxl-player/internal/sdl/sdl.go
T
2026-08-23 12:40:59 +03:00

177 lines
5.6 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
KeyEscape uint32 = 0x1B
KeyF uint32 = 0x66
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
)
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")
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
}