Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backend: refactoring #126

Merged
merged 4 commits into from
Apr 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 75 additions & 126 deletions backend.go
Original file line number Diff line number Diff line change
@@ -1,161 +1,110 @@
//go:build !exclude_cimgui_glfw
// +build !exclude_cimgui_glfw

package imgui

// #cgo amd64,linux LDFLAGS: ${SRCDIR}/lib/linux/x64/libglfw3.a -ldl -lGL -lX11
// #cgo amd64,windows LDFLAGS: -L${SRCDIR}/lib/windows/x64 -l:libglfw3.a -lgdi32 -lopengl32 -limm32
// #cgo darwin LDFLAGS: -framework Cocoa -framework IOKit -framework CoreVideo
// #cgo amd64,darwin LDFLAGS: ${SRCDIR}/lib/macos/x64/libglfw3.a
// #cgo arm64,darwin LDFLAGS: ${SRCDIR}/lib/macos/arm64/libglfw3.a
// #cgo !gles2,darwin LDFLAGS: -framework OpenGL
// #cgo gles2,darwin LDFLAGS: -lGLESv2
// #cgo CPPFLAGS: -DCIMGUI_GO_USE_GLFW
// extern void glfwWindowLoopCallback();
// extern void glfwBeforeRender();
// extern void glfwAfterRender();
// extern void glfwAfterCreateContext();
// extern void glfwBeforeDestoryContext();
// #include <stdint.h>
// #include "backend.h"
// extern void loopCallback();
// extern void beforeRender();
// extern void afterRender();
// extern void afterCreateContext();
// extern void beforeDestoryContext();
import "C"

import (
"image"
"unsafe"
)

type GLFWWindowFlags int

const (
GLFWWindowFlagsNone GLFWWindowFlags = GLFWWindowFlags(C.GLFWWindowFlagsNone)
GLFWWindowFlagsNotResizable GLFWWindowFlags = GLFWWindowFlags(C.GLFWWindowFlagsNotResizable)
GLFWWindowFlagsMaximized GLFWWindowFlags = GLFWWindowFlags(C.GLFWWindowFlagsMaximized)
GLFWWindowFlagsFloating GLFWWindowFlags = GLFWWindowFlags(C.GLFWWindowFlagsFloating)
GLFWWindowFlagsFrameless GLFWWindowFlags = GLFWWindowFlags(C.GLFWWindowFlagsFrameless)
GLFWWindowFlagsTransparent GLFWWindowFlags = GLFWWindowFlags(C.GLFWWindowFlagsTransparent)
)

type voidCallbackFunc func()

var (
afterCreateContext voidCallbackFunc
loopFunc voidCallbackFunc
beforeRender voidCallbackFunc
afterRender voidCallbackFunc
beforeDestoryContext voidCallbackFunc
)

type GLFWwindow uintptr

func (w GLFWwindow) handle() *C.GLFWwindow {
return (*C.GLFWwindow)(unsafe.Pointer(w))
}

func SetAfterCreateContextHook(hook func()) {
afterCreateContext = hook
}

func SetBeforeDestroyContextHook(hook func()) {
beforeDestoryContext = hook
}

func SetBeforeRenderHook(hook func()) {
beforeRender = hook
}

func SetAfterRenderHook(hook func()) {
afterRender = hook
}
var currentBackend Backend

func SetBgColor(color Vec4) {
C.igSetBgColor(color.toC())
}

func (w GLFWwindow) Run(loop func()) {
loopFunc = loop
C.igRunLoop(w.handle(), C.VoidCallback(C.glfwWindowLoopCallback), C.VoidCallback(C.glfwBeforeRender), C.VoidCallback(C.glfwAfterRender), C.VoidCallback(C.glfwBeforeDestoryContext))
}

func (w GLFWwindow) DisplaySize() (width int32, height int32) {
widthArg, widthFin := wrapNumberPtr[C.int, int32](&width)
defer widthFin()

heightArg, heightFin := wrapNumberPtr[C.int, int32](&height)
defer heightFin()

C.igGLFWWindow_GetDisplaySize(w.handle(), widthArg, heightArg)

return
}

func (w GLFWwindow) SetShouldClose(value bool) {
C.igGLFWWindow_SetShouldClose(w.handle(), C.int(castBool(value)))
}

//export glfwWindowLoopCallback
func glfwWindowLoopCallback() {
if loopFunc != nil {
loopFunc()
//export loopCallback
func loopCallback() {
if currentBackend != nil {
if f := currentBackend.loopFunc(); f != nil {
f()
}
}
}

//export glfwBeforeRender
func glfwBeforeRender() {
if beforeRender != nil {
beforeRender()
//export beforeRender
func beforeRender() {
if currentBackend != nil {
if f := currentBackend.beforeRenderHook(); f != nil {
f()
}
}
}

//export glfwAfterRender
func glfwAfterRender() {
if afterRender != nil {
afterRender()
//export afterRender
func afterRender() {
if currentBackend != nil {
if f := currentBackend.afterRenderHook(); f != nil {
f()
}
}
}

//export glfwAfterCreateContext
func glfwAfterCreateContext() {
if afterCreateContext != nil {
afterCreateContext()
//export afterCreateContext
func afterCreateContext() {
if currentBackend != nil {
if f := currentBackend.afterCreateHook(); f != nil {
f()
}
}
}

//export glfwBeforeDestoryContext
func glfwBeforeDestoryContext() {
if beforeDestoryContext != nil {
beforeDestoryContext()
//export beforeDestoryContext
func beforeDestoryContext() {
if currentBackend != nil {
if f := currentBackend.beforeDestroyHook(); f != nil {
f()
}
}
}

func CreateGlfwWindow(title string, width, height int, flags GLFWWindowFlags) GLFWwindow {
titleArg, titleFin := wrapString(title)
defer titleFin()
// Backend is a special interface that implements all methods required
// to render imgui application.
type Backend interface {
SetAfterCreateContextHook(func())
SetBeforeDestroyContextHook(func())
SetBeforeRenderHook(func())
SetAfterRenderHook(func())

window := GLFWwindow(unsafe.Pointer(C.igCreateGLFWWindow(titleArg, C.int(width), C.int(height), C.GLFWWindowFlags(flags), C.VoidCallback(C.glfwAfterCreateContext))))
if window == 0 {
panic("Failed to create GLFW window")
}
SetBgColor(color Vec4)
Run(func())
Refresh()

return window
}
DisplaySize() (width, height int32)
SetShouldClose(bool)

func SetTargetFPS(fps uint) {
C.igSetTargetFPS(C.uint(fps))
}
SetTargetFPS(fps uint)

func Refresh() {
C.igRefresh()
}
CreateTexture(pixels unsafe.Pointer, width, Height int) TextureID
CreateTextureRgba(img *image.RGBA, width, height int) TextureID
DeleteTexture(id TextureID)

// TODO: flags needs generic layer
CreateWindow(title string, width, height int, flags GLFWWindowFlags)

func CreateTexture(pixels unsafe.Pointer, width, height int) TextureID {
return TextureID(C.igCreateTexture((*C.uchar)(pixels), C.int(width), C.int(height)))
// for C callbacks
// What happens here is a bit tricky:
// - user sets these callbacks via Set* methods of the backend
// - callbacks are stored in currentContext variable
// - functions below just returns that callbacks
// - on top of this file is a set of global function with names similar to these below
// - these functions are exported to C
// - backend implementation uses C references to Go callbacks to share them (again ;-) )
// into backend code.
// As you can see this is all to convert Go callback int C callback
afterCreateHook() func()
beforeRenderHook() func()
loopFunc() func()
afterRenderHook() func()
beforeDestroyHook() func()
}

func CreateTextureRgba(img *image.RGBA, width, height int) TextureID {
return TextureID(C.igCreateTexture((*C.uchar)(&(img.Pix[0])), C.int(width), C.int(height)))
func CreateBackend( /*TODO: backend type*/ ) Backend {
currentBackend = &GLFWBackend{}
return currentBackend
}

func DeleteTexture(id TextureID) {
C.igDeleteTexture(C.ImTextureID(id))
func GetBackend() Backend {
return currentBackend
}
15 changes: 8 additions & 7 deletions examples/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ var (
a float32
color4 [4]float32 = [4]float32{r, g, b, a}
selected bool
window imgui.GLFWwindow
backend imgui.Backend
img *image.RGBA
texture *imgui.Texture
barValues []int64
Expand All @@ -39,7 +39,7 @@ func showWidgetsDemo() {
imgui.SetNextWindowSizeV(imgui.NewVec2(300, 300), imgui.CondOnce)
imgui.Begin("Window 1")
if imgui.ButtonV("Click Me", imgui.NewVec2(80, 20)) {
w, h := window.DisplaySize()
w, h := backend.DisplaySize()
fmt.Println(w, h)
}
imgui.TextUnformatted("Unformatted text")
Expand Down Expand Up @@ -120,12 +120,13 @@ func main() {
barValues = append(barValues, int64(i+1))
}

imgui.SetAfterCreateContextHook(afterCreateContext)
imgui.SetBeforeDestroyContextHook(beforeDestroyContext)
backend = imgui.CreateBackend()
backend.SetAfterCreateContextHook(afterCreateContext)
backend.SetBeforeDestroyContextHook(beforeDestroyContext)

imgui.SetBgColor(imgui.NewVec4(0.45, 0.55, 0.6, 1.0))
backend.SetBgColor(imgui.NewVec4(0.45, 0.55, 0.6, 1.0))

window = imgui.CreateGlfwWindow("Hello from cimgui-go", 1200, 900, 0)
backend.CreateWindow("Hello from cimgui-go", 1200, 900, 0)

window.Run(loop)
backend.Run(loop)
}
2 changes: 1 addition & 1 deletion backend.cpp → glfw_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#define CIMGUI_USE_GLFW
#define CIMGUI_USE_OPENGL3

#include "backend.h"
#include "glfw_backend.h"
#include "cimgui/cimgui.h"
#include "cimgui/cimgui_impl.h"
#include "thirdparty/glfw/include/GLFW/glfw3.h" // Will drag system OpenGL headers
Expand Down
Loading