From 3398cdf3f120be3817e6bad52bd22533ce584700 Mon Sep 17 00:00:00 2001 From: Dmitry Sergeev Date: Tue, 25 Aug 2026 12:09:40 +0300 Subject: [PATCH] imgui wrapper --- cmd/mxl-player/main.go | 9 +++ go.mod | 2 +- internal/imgui/backend_vulkan.go | 0 internal/imgui/input_sdl3.go | 108 ++++++++++++++++++++++++++ internal/imgui/shaders.go | 9 +++ internal/imgui/shaders/imgui.frag | 14 ++++ internal/imgui/shaders/imgui.frag.spv | Bin 0 -> 844 bytes internal/imgui/shaders/imgui.vert | 25 ++++++ internal/imgui/shaders/imgui.vert.spv | Bin 0 -> 1368 bytes internal/sdl/sdl.go | 21 ++++- 10 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 internal/imgui/backend_vulkan.go create mode 100644 internal/imgui/input_sdl3.go create mode 100644 internal/imgui/shaders.go create mode 100644 internal/imgui/shaders/imgui.frag create mode 100644 internal/imgui/shaders/imgui.frag.spv create mode 100644 internal/imgui/shaders/imgui.vert create mode 100644 internal/imgui/shaders/imgui.vert.spv diff --git a/cmd/mxl-player/main.go b/cmd/mxl-player/main.go index ab2bd8d..a68b0ac 100644 --- a/cmd/mxl-player/main.go +++ b/cmd/mxl-player/main.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "log" + "mxl-player/internal/imgui" "mxl-player/internal/renderer" "mxl-player/internal/sdl" "mxl-player/internal/source" @@ -137,6 +138,13 @@ func main() { return } + // ImGui init + gui := imgui.New() + defer gui.Destroy() + sdl.StartTextInput(windowHandler) + defer sdl.StopTextInput(windowHandler) + // fin on ImGui init + if err := vk.Load(); err != nil { panic(err) } @@ -542,6 +550,7 @@ func main() { resized = true } } + gui.ProcessEvent(&event) } if !running { break diff --git a/go.mod b/go.mod index 2f15b17..475a75a 100644 --- a/go.mod +++ b/go.mod @@ -11,4 +11,4 @@ require github.com/qvest-digital/go-mxl v1.1.0-rc.1 require github.com/spf13/pflag v1.0.10 -require github.com/AllenDang/cimgui-go v1.5.0 // indirect +require github.com/AllenDang/cimgui-go v1.5.0 diff --git a/internal/imgui/backend_vulkan.go b/internal/imgui/backend_vulkan.go new file mode 100644 index 0000000..e69de29 diff --git a/internal/imgui/input_sdl3.go b/internal/imgui/input_sdl3.go new file mode 100644 index 0000000..cc63ee7 --- /dev/null +++ b/internal/imgui/input_sdl3.go @@ -0,0 +1,108 @@ +package imgui + +import ( + "mxl-player/internal/sdl" + "unsafe" + + cimgui "github.com/AllenDang/cimgui-go/imgui" +) + +// SDL3 event (128 byte raw buffer) -> imgui +func (c *Context) ProcessEvent(event *[128]byte) { + eventType := *(*uint32)(unsafe.Pointer(&event[0])) + + // CommonEvent (16 bytes: type uint32 + reserved uint32 + timestamp uint64) + switch eventType { + case sdl.EventKeyDown, sdl.EventKeyUp: + scancode := *(*uint32)(unsafe.Pointer(&event[24])) + down := eventType == sdl.EventKeyDown + key := sdlScancodeToImGuiKey(scancode) + if key >= 0 { + c.io.AddKeyEvent(key, down) + } + // MouseMotionEvent: +16 windowID(4), +20 which(4), +24 state(4), +28 x(float32), +32 y(float32) + case sdl.EventMouseMotion: + x := *(*float32)(unsafe.Pointer(&event[28])) + y := *(*float32)(unsafe.Pointer(&event[32])) + c.io.AddMousePosEvent(x, y) + // MouseButtonEvent: +16 windowID(4), +20 which(4), +24 button(1), +25 down(bool) + case sdl.EventMouseButtonDown, sdl.EventMouseButtonUp: + button := *(*uint8)(unsafe.Pointer(&event[24])) + down := eventType == sdl.EventMouseButtonDown + c.io.AddMouseButtonEvent(int32(button-1), down) + // MouseWheelEvent: +16 windowID(4), +20 which(4), +24 x(float32), +28 y(float32) + case sdl.EventMouseWheel: + x := *(*float32)(unsafe.Pointer(&event[24])) + y := *(*float32)(unsafe.Pointer(&event[28])) + c.io.AddMouseWheelEvent(x, y) + // TextInputEvent: +16 windowID(4), +20 text(*char pointer, 8 bytes on 64-bit) + case sdl.EventTextInput: + // text pointer is at offset 24, 8 bytes (pointer) + ptr := *(*uintptr)(unsafe.Pointer(&event[24])) + if ptr != 0 { + text := cstr(ptr) + c.io.AddInputCharactersUTF8(text) + } + + } +} + +func sdlScancodeToImGuiKey(scancode uint32) cimgui.Key { + switch scancode { + case 40: // SDL_SCANCODE_RETURN + return cimgui.KeyEnter + case 42: // SDL_SCANCODE_BACKSPACE + return cimgui.KeyBackspace + case 41: // SDL_SCANCODE_ESCAPE + return cimgui.KeyEscape + case 43: // SDL_SCANCODE_TAB + return cimgui.KeyTab + case 44: // SDL_SCANCODE_SPACE + return cimgui.KeySpace + case 80: // SDL_SCANCODE_LEFT + return cimgui.KeyLeftArrow + case 79: // SDL_SCANCODE_RIGHT + return cimgui.KeyRightArrow + case 82: // SDL_SCANCODE_UP + return cimgui.KeyUpArrow + case 81: // SDL_SCANCODE_DOWN + return cimgui.KeyDownArrow + case 225: // SDL_SCANCODE_LSHIFT + return cimgui.KeyLeftShift + case 229: // SDL_SCANCODE_RSHIFT + return cimgui.KeyRightShift + case 224: // SDL_SCANCODE_LCTRL + return cimgui.KeyLeftCtrl + case 228: // SDL_SCANCODE_RCTRL + return cimgui.KeyRightCtrl + case 226: // SDL_SCANCODE_LALT + return cimgui.KeyLeftAlt + case 230: // SDL_SCANCODE_RALT + return cimgui.KeyRightAlt + default: + // Letters A-Z: scancodes 4-29 map to ImGui KeyA-KeyZ + if scancode >= 4 && scancode <= 29 { + return cimgui.Key(int(cimgui.KeyA) + int(scancode-4)) + } + // Numbers 0-9: scancodes 30-39 + if scancode >= 30 && scancode <= 39 { + return cimgui.Key(int(cimgui.Key0) + int(scancode-30)) + } + return -1 + } +} + +// cstr reads a NUL-terminated C string at p. +// TODO: same func used in Vulkan +// Maybe i should create something like "package common" +// for funcs like this +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)) +} diff --git a/internal/imgui/shaders.go b/internal/imgui/shaders.go new file mode 100644 index 0000000..b0d59e3 --- /dev/null +++ b/internal/imgui/shaders.go @@ -0,0 +1,9 @@ +package imgui + +import _ "embed" + +//go:embed shaders/imgui.vert.spv +var vertSPV []byte + +//go:embed shaders/imgui.frag.spv +var fragSPV []byte diff --git a/internal/imgui/shaders/imgui.frag b/internal/imgui/shaders/imgui.frag new file mode 100644 index 0000000..ce7e6f7 --- /dev/null +++ b/internal/imgui/shaders/imgui.frag @@ -0,0 +1,14 @@ +#version 450 core +layout(location = 0) out vec4 fColor; + +layout(set=0, binding=0) uniform sampler2D sTexture; + +layout(location = 0) in struct { + vec4 Color; + vec2 UV; +} In; + +void main() +{ + fColor = In.Color * texture(sTexture, In.UV.st); +} diff --git a/internal/imgui/shaders/imgui.frag.spv b/internal/imgui/shaders/imgui.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..87b9aeab901069d2d086071aeed19b327e76a54b GIT binary patch literal 844 zcmYk3+e!jq6ot2WO!JhfnI&46fpk$3L_tIhf#5}_%OP}v0aNi1^#HwCPt{G(`oW{hDl;ve5>EKmBQCzQ@{U|A6S#x@>)9*XIJ9jXhy7R@?$a6>j*mH;e%o{BH4-Z`? zqVvat(Q+6SB&CSf1ylR&b~2jG%#x~^6Xv9Z)^T_(E)j6d@$|gX)AzlmNa|NpJb&~) z7t5KtF>}KA*Lwn^k79B>(FHp4tDy*v`e1g#S=ZZDOg{QX7}Ni`z5#Qw3l1~?ib=}f=%3!oGUlP@D=F!7 yTLurNZe2!Aa(I7FMh+tL#8WcW?c96j+%tEM(`gS@jA@xQvu=iFv9?WHh!NJadoVf~4a;geeERGOj1AMV zL^zw~yv@7%|0POuiZ#WiVpnlZab3~TUt9ZcHFeb!jKW|%4o2_7cs>uy>U)-iS(+!| zG%b?2O1~!XR+o5b9%uD*nc#`Be6OcF&gl+T&v<9~(JY%47VBD!xj&v7F*V(R_QFay1bi(F7J#YWURF_Fsb*eqR(%pjncj~+81vR2iYPC$s1nX>zOZ?0Odx&ycD>YiPmSNyyu;}P z>g6q*y_XU>3k?>0=KZhNIn#pg@PTD7G@Lfrs$xg#=pX1VektU8%6i&;#lG&)kIvS7 zKWh3ohuc@pcZ37(tL9gR7Wm7iW@fNm)fcq;ik9NAsn?aW=-<%J8JhG{;}aO?+uG6M z-1YA$cjuRyoO$S{##eW~ubh6)`^xYYEwry{=M0QqYJMMJP7BY`;_di}j(ht}<-8jl zKDDm^L;s-3;WIlv-dC_({lHc~-aOYg#AAGCF~c7rp7vKlnR!crH*baF%S8oV!e{nd3SWV~;|!F8{}P8gZY$^mcYSx1`wH%H zeRq|E|7`m1DW@0wSQy?sRDiP_cBmYzrI^SCe0ZdQ%Nc&+A$Q}+V+G&Pc|r~UuM}P= F{sFu>Tju}( literal 0 HcmV?d00001 diff --git a/internal/sdl/sdl.go b/internal/sdl/sdl.go index bcbdb41..74f3d4c 100644 --- a/internal/sdl/sdl.go +++ b/internal/sdl/sdl.go @@ -16,7 +16,16 @@ const ( EventQuit uint32 = 0x100 EventWindowResized uint32 = 0x206 EventPixelSizeChanged uint32 = 0x207 - EventKeyDown uint32 = 0x300 + + EventKeyDown uint32 = 0x300 + EventKeyUp uint32 = 0x301 + + EventMouseMotion uint32 = 0x400 + EventMouseButtonDown uint32 = 0x401 + EventMouseButtonUp uint32 = 0x402 + EventMouseWheel uint32 = 0x403 + + EventTextInput uint32 = 0x303 KeyEscape uint32 = 0x1B KeyF uint32 = 0x66 @@ -49,6 +58,9 @@ var ( 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 @@ -79,6 +91,9 @@ func Load() error { 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 } @@ -174,3 +189,7 @@ func GetAudioPlaybackDevices() []AudioDevice { } return devs } + +// Input wrappers +func StartTextInput(window uintptr) { sdlStartTextInput(window) } +func StopTextInput(window uintptr) { sdlStopTextInput(window) }