diff --git a/platform/imgui/context.go b/platform/imgui/context.go index 7fd83b4..4eba0f7 100644 --- a/platform/imgui/context.go +++ b/platform/imgui/context.go @@ -1,9 +1,9 @@ package imgui -// #cgo linux LDFLAGS: -L./cimgui -l:cimgui.a -lstdc++ -lm // #include "native.h" import "C" import ( + "errors" "log" "unsafe" @@ -12,6 +12,10 @@ import ( "github.com/veandco/go-sdl2/sdl" ) +var ( + ErrNotInit = errors.New("imgui context was not created") +) + const ( pointerSize = unsafe.Sizeof(C.uintptr_t(0)) drawCommandSize = unsafe.Sizeof(C.ImDrawCmd{}) @@ -46,159 +50,162 @@ var keyMapping = map[int]C.int{ C.ImGuiKey_Z: sdl.SCANCODE_Z, } -var singleton struct { - nativeContext *C.ImGuiContext - nativeIo *C.ImGuiIO - refCount int -} +var imguiState struct { + imguiContext *C.ImGuiContext + imguiIo *C.ImGuiIO -type Context struct { - buttonsDown [3]bool - lastTime uint64 fontTexture uint32 displaySize math.Vec2i bufferSize math.Vec2i + buttonsDown [3]bool + lastTime uint64 } -func New(displaySize, bufferSize math.Vec2i) (*Context, error) { - singleton.refCount++ - if singleton.refCount == 1 { - log.Println("imgui global create") - singleton.nativeContext = C.igCreateContext(nil) - singleton.nativeIo = C.igGetIO() - - for imguiKey, nativeKey := range keyMapping { - singleton.nativeIo.KeyMap[imguiKey] = nativeKey - } +func Create() error { + if IsCreated() { + return nil } - log.Println("imgui context create") - c := &Context{displaySize: displaySize, bufferSize: bufferSize} + log.Println("imgui create") + imguiState.imguiContext = C.igCreateContext(nil) + imguiState.imguiIo = C.igGetIO() + + for imguiKey, nativeKey := range keyMapping { + imguiState.imguiIo.KeyMap[imguiKey] = nativeKey + } var imageData *C.uchar var imageWidth, imageHeight C.int - C.ImFontAtlas_GetTexDataAsRGBA32(singleton.nativeIo.Fonts, &imageData, &imageWidth, &imageHeight, nil) + C.ImFontAtlas_GetTexDataAsRGBA32(imguiState.imguiIo.Fonts, &imageData, &imageWidth, &imageHeight, nil) var lastTexture int32 gl.GetIntegerv(gl.TEXTURE_BINDING_2D, &lastTexture) - gl.GenTextures(1, &c.fontTexture) - gl.BindTexture(gl.TEXTURE_2D, c.fontTexture) + gl.GenTextures(1, &imguiState.fontTexture) + gl.BindTexture(gl.TEXTURE_2D, imguiState.fontTexture) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) gl.PixelStorei(gl.UNPACK_ROW_LENGTH, 0) gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(imageWidth), int32(imageHeight), 0, gl.RGBA, gl.UNSIGNED_BYTE, unsafe.Pointer(imageData)) gl.BindTexture(gl.TEXTURE_2D, uint32(lastTexture)) - return c, nil + return nil } -func (c *Context) Destroy() error { - if c == nil || c.fontTexture == 0 { +func IsCreated() bool { + return imguiState.imguiContext != nil +} + +func Destroy() error { + if !IsCreated() { return nil } - log.Println("imgui context destroy") - gl.DeleteTextures(1, &c.fontTexture) - singleton.nativeIo.Fonts.TexID = C.nativeHandleCast(C.uintptr_t(c.fontTexture)) - c.fontTexture = 0 + gl.DeleteTextures(1, &imguiState.fontTexture) + imguiState.imguiIo.Fonts.TexID = C.nativeHandleCast(C.uintptr_t(imguiState.fontTexture)) + imguiState.fontTexture = 0 - singleton.refCount-- - if singleton.refCount == 0 { - log.Println("imgui global destroy") - C.igDestroyContext(singleton.nativeContext) - singleton.nativeContext = nil - singleton.nativeIo = nil - } + log.Println("imgui destroy") + C.igDestroyContext(imguiState.imguiContext) + imguiState.imguiContext = nil + imguiState.imguiIo = nil return nil } -func (c *Context) SetDisplaySize(displaySize math.Vec2i) { - c.displaySize = displaySize -} +func BeginFrame(displaySize, bufferSize math.Vec2i) error { + if !IsCreated() { + return ErrNotInit + } -func (c *Context) SetBufferSize(bufferSize math.Vec2i) { - c.bufferSize = bufferSize -} + imguiState.displaySize = displaySize + imguiState.bufferSize = bufferSize -func (c *Context) BeginFrame() { - singleton.nativeIo.Fonts.TexID = C.nativeHandleCast(C.uintptr_t(c.fontTexture)) - singleton.nativeIo.DisplaySize.x = C.float(c.displaySize.X) - singleton.nativeIo.DisplaySize.y = C.float(c.displaySize.Y) + imguiState.imguiIo.Fonts.TexID = C.nativeHandleCast(C.uintptr_t(imguiState.fontTexture)) + imguiState.imguiIo.DisplaySize.x = C.float(displaySize.X) + imguiState.imguiIo.DisplaySize.y = C.float(displaySize.Y) currentTime := sdl.GetPerformanceCounter() - if c.lastTime > 0 { - singleton.nativeIo.DeltaTime = C.float(float32(currentTime-c.lastTime) / float32(sdl.GetPerformanceFrequency())) + if imguiState.lastTime > 0 { + imguiState.imguiIo.DeltaTime = C.float(float32(currentTime-imguiState.lastTime) / float32(sdl.GetPerformanceFrequency())) } else { - singleton.nativeIo.DeltaTime = C.float(1.0 / 60.0) + imguiState.imguiIo.DeltaTime = C.float(1.0 / 60.0) } - c.lastTime = currentTime + imguiState.lastTime = currentTime x, y, state := sdl.GetMouseState() - singleton.nativeIo.MousePos.x = C.float(x) - singleton.nativeIo.MousePos.y = C.float(y) + imguiState.imguiIo.MousePos.x = C.float(x) + imguiState.imguiIo.MousePos.y = C.float(y) for i, button := range []uint32{sdl.BUTTON_LEFT, sdl.BUTTON_RIGHT, sdl.BUTTON_MIDDLE} { - singleton.nativeIo.MouseDown[i] = C.bool(c.buttonsDown[i] || (state&sdl.Button(button)) != 0) - c.buttonsDown[i] = false + imguiState.imguiIo.MouseDown[i] = C.bool(imguiState.buttonsDown[i] || (state&sdl.Button(button)) != 0) + imguiState.buttonsDown[i] = false } C.igNewFrame() + return nil } -func (c *Context) ProcessEvent(event sdl.Event) (bool, error) { +func ProcessEvent(event sdl.Event) (bool, error) { + if !IsCreated() { + return false, ErrNotInit + } + switch event.GetType() { case sdl.MOUSEWHEEL: wheelEvent := event.(*sdl.MouseWheelEvent) if wheelEvent.X > 0 { - singleton.nativeIo.MouseDelta.x++ + imguiState.imguiIo.MouseDelta.x++ } else if wheelEvent.X < 0 { - singleton.nativeIo.MouseDelta.x-- + imguiState.imguiIo.MouseDelta.x-- } if wheelEvent.Y > 0 { - singleton.nativeIo.MouseDelta.y++ + imguiState.imguiIo.MouseDelta.y++ } else if wheelEvent.Y < 0 { - singleton.nativeIo.MouseDelta.y-- + imguiState.imguiIo.MouseDelta.y-- } return true, nil case sdl.MOUSEBUTTONDOWN: buttonEvent := event.(*sdl.MouseButtonEvent) switch buttonEvent.Button { case sdl.BUTTON_LEFT: - c.buttonsDown[0] = true + imguiState.buttonsDown[0] = true break case sdl.BUTTON_RIGHT: - c.buttonsDown[1] = true + imguiState.buttonsDown[1] = true break case sdl.BUTTON_MIDDLE: - c.buttonsDown[2] = true + imguiState.buttonsDown[2] = true break } return true, nil case sdl.TEXTINPUT: inputEvent := event.(*sdl.TextInputEvent) - C.ImGuiIO_AddInputCharactersUTF8(singleton.nativeIo, (*C.char)(unsafe.Pointer(&inputEvent.Text[0]))) + C.ImGuiIO_AddInputCharactersUTF8(imguiState.imguiIo, (*C.char)(unsafe.Pointer(&inputEvent.Text[0]))) return true, nil case sdl.KEYDOWN: keyEvent := event.(*sdl.KeyboardEvent) - singleton.nativeIo.KeysDown[keyEvent.Keysym.Scancode] = true + imguiState.imguiIo.KeysDown[keyEvent.Keysym.Scancode] = true modState := sdl.GetModState() - singleton.nativeIo.KeyCtrl = C.bool(modState&sdl.KMOD_CTRL != 0) - singleton.nativeIo.KeyAlt = C.bool(modState&sdl.KMOD_ALT != 0) - singleton.nativeIo.KeyShift = C.bool(modState&sdl.KMOD_SHIFT != 0) + imguiState.imguiIo.KeyCtrl = C.bool(modState&sdl.KMOD_CTRL != 0) + imguiState.imguiIo.KeyAlt = C.bool(modState&sdl.KMOD_ALT != 0) + imguiState.imguiIo.KeyShift = C.bool(modState&sdl.KMOD_SHIFT != 0) case sdl.KEYUP: keyEvent := event.(*sdl.KeyboardEvent) - singleton.nativeIo.KeysDown[keyEvent.Keysym.Scancode] = false + imguiState.imguiIo.KeysDown[keyEvent.Keysym.Scancode] = false modState := sdl.GetModState() - singleton.nativeIo.KeyCtrl = C.bool(modState&sdl.KMOD_CTRL != 0) - singleton.nativeIo.KeyAlt = C.bool(modState&sdl.KMOD_ALT != 0) - singleton.nativeIo.KeyShift = C.bool(modState&sdl.KMOD_SHIFT != 0) + imguiState.imguiIo.KeyCtrl = C.bool(modState&sdl.KMOD_CTRL != 0) + imguiState.imguiIo.KeyAlt = C.bool(modState&sdl.KMOD_ALT != 0) + imguiState.imguiIo.KeyShift = C.bool(modState&sdl.KMOD_SHIFT != 0) return true, nil } return false, nil } -func (c *Context) EndFrame() error { +func EndFrame() error { + if !IsCreated() { + return ErrNotInit + } + C.igRender() var lastTexture int32 @@ -223,11 +230,11 @@ func (c *Context) EndFrame() error { gl.Enable(gl.TEXTURE_2D) gl.PolygonMode(gl.FRONT_AND_BACK, gl.FILL) - gl.Viewport(0, 0, int32(c.bufferSize.X), int32(c.bufferSize.Y)) + gl.Viewport(0, 0, int32(imguiState.bufferSize.X), int32(imguiState.bufferSize.Y)) gl.MatrixMode(gl.PROJECTION) gl.PushMatrix() gl.LoadIdentity() - gl.Ortho(0, float64(c.displaySize.X), float64(c.displaySize.Y), 0, -1, 1) + gl.Ortho(0, float64(imguiState.displaySize.X), float64(imguiState.displaySize.Y), 0, -1, 1) gl.MatrixMode(gl.MODELVIEW) gl.PushMatrix() gl.LoadIdentity() @@ -236,8 +243,8 @@ func (c *Context) EndFrame() error { C.ImDrawData_ScaleClipRects( drawData, C.ImVec2{ - x: C.float(float32(c.bufferSize.X) / float32(c.displaySize.X)), - y: C.float(float32(c.bufferSize.Y) / float32(c.displaySize.Y)), + x: C.float(float32(imguiState.bufferSize.X) / float32(imguiState.displaySize.X)), + y: C.float(float32(imguiState.bufferSize.Y) / float32(imguiState.displaySize.Y)), }, ) @@ -257,7 +264,7 @@ func (c *Context) EndFrame() error { command := (*C.ImDrawCmd)(unsafe.Pointer(uintptr(unsafe.Pointer(commandList.CmdBuffer.Data)) + drawCommandSize*uintptr(j))) gl.Scissor( int32(command.ClipRect.x), - int32(c.bufferSize.Y)-int32(command.ClipRect.w), + int32(imguiState.bufferSize.Y)-int32(command.ClipRect.w), int32(command.ClipRect.z-command.ClipRect.x), int32(command.ClipRect.w-command.ClipRect.y), ) diff --git a/platform/imgui/imgui.go b/platform/imgui/imgui.go index 88f9686..dd8c5e7 100644 --- a/platform/imgui/imgui.go +++ b/platform/imgui/imgui.go @@ -1,5 +1,6 @@ package imgui +// #cgo linux LDFLAGS: -L./cimgui -l:cimgui.a -lstdc++ -lm // #include "native.h" import "C" import ( @@ -9,27 +10,27 @@ import ( "github.com/FooSoft/lazarus/math" ) -func (*Context) DialogBegin(label string) bool { +func DialogBegin(label string) bool { labelC := C.CString(label) defer C.free(unsafe.Pointer(labelC)) return bool(C.igBegin(labelC, nil, 0)) } -func (*Context) DialogEnd() { +func DialogEnd() { C.igEnd() } -func (*Context) Button(label string) bool { +func Button(label string) bool { labelC := C.CString(label) defer C.free(unsafe.Pointer(labelC)) return bool(C.igButton(labelC, C.ImVec2{})) } -func (c *Context) Image(texture graphics.Texture) { - c.ImageSized(texture, texture.Size()) +func Image(texture graphics.Texture) { + ImageSized(texture, texture.Size()) } -func (*Context) ImageSized(texture graphics.Texture, size math.Vec2i) { +func ImageSized(texture graphics.Texture, size math.Vec2i) { C.igImage( C.nativeHandleCast(C.uintptr_t(texture.Id())), C.ImVec2{x: C.float(size.X), y: C.float(size.Y)}, @@ -40,7 +41,7 @@ func (*Context) ImageSized(texture graphics.Texture, size math.Vec2i) { ) } -func (*Context) SliderInt(label string, value *int, min, max int) bool { +func SliderInt(label string, value *int, min, max int) bool { labelC := C.CString(label) defer C.free(unsafe.Pointer(labelC)) valueC := C.int(*value) @@ -49,7 +50,7 @@ func (*Context) SliderInt(label string, value *int, min, max int) bool { return result } -func (*Context) Text(label string) { +func Text(label string) { labelStartC := C.CString(label) labelEndC := (*C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(labelStartC)) + uintptr(len(label)))) defer C.free(unsafe.Pointer(labelStartC)) diff --git a/platform/platform.go b/platform/platform.go index caba3cf..36b2ec7 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -4,99 +4,45 @@ import ( "log" "runtime" - "github.com/FooSoft/lazarus/math" "github.com/veandco/go-sdl2/sdl" ) -var singleton struct { +var platfromState struct { sdlIsInit bool - windows []*Window } func Advance() (bool, error) { - if err := advanceWindows(); err != nil { - return false, err - } - for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() { switch event.(type) { case *sdl.QuitEvent: return false, nil default: - if err := processWindowEvents(event); err != nil { + if _, err := windowProcessEvent(event); err != nil { return false, err } } } - return len(singleton.windows) > 0, nil + run, err := windowAdvance() + if !run { + WindowDestroy() + } + + return run, err } -func NewWindow(title string, size math.Vec2i, scene Scene) (*Window, error) { - if !singleton.sdlIsInit { - runtime.LockOSThread() - - log.Println("sdl global init") - if err := sdl.Init(sdl.INIT_VIDEO); err != nil { - return nil, err - } - - sdl.GLSetAttribute(sdl.GL_CONTEXT_MAJOR_VERSION, 2) - sdl.GLSetAttribute(sdl.GL_CONTEXT_MINOR_VERSION, 1) - sdl.GLSetAttribute(sdl.GL_DOUBLEBUFFER, 1) - - singleton.sdlIsInit = true +func platformInit() error { + if platfromState.sdlIsInit { + return nil } - w, err := newWindow(title, size, scene) - if err != nil { - return nil, err - } - - appendWindow(w) - return w, err -} - -func appendWindow(window *Window) { - singleton.windows = append(singleton.windows, window) -} - -func removeWindow(window *Window) bool { - for i, w := range singleton.windows { - if w == window { - singleton.windows = append(singleton.windows[:i], singleton.windows[i+1:]...) - return true - } - } - - return false -} - -func advanceWindows() error { - var windowsToRemove []*Window - for _, window := range singleton.windows { - run, err := window.advance() - if err != nil { - return err - } - if !run { - windowsToRemove = append(windowsToRemove, window) - } - } - - for _, window := range windowsToRemove { - removeWindow(window) - } - - return nil -} - -func processWindowEvents(event sdl.Event) error { - for _, window := range singleton.windows { - if _, err := window.processEvent(event); err != nil { - return err - } + runtime.LockOSThread() + + log.Println("sdl init") + if err := sdl.Init(sdl.INIT_VIDEO); err != nil { + return err } + platfromState.sdlIsInit = true return nil } diff --git a/platform/scene.go b/platform/scene.go index b580e00..fe9e4cc 100644 --- a/platform/scene.go +++ b/platform/scene.go @@ -5,21 +5,13 @@ type Scene interface { } type SceneCreator interface { - Create(window *Window) error + Create() error } type SceneAdvancer interface { - Advance(window *Window) error + Advance() error } type SceneDestroyer interface { - Destroy(window *Window) error -} - -func sceneName(scene Scene) string { - if scene == nil { - return "" - } else { - return scene.Name() - } + Destroy() error } diff --git a/platform/texture.go b/platform/texture.go index c7ed378..ed40d8a 100644 --- a/platform/texture.go +++ b/platform/texture.go @@ -9,11 +9,15 @@ import ( ) type texture struct { - size math.Vec2i glTexture uint32 + size math.Vec2i } -func newTextureFromRgba(colors []math.Color4b, size math.Vec2i) (graphics.Texture, error) { +func NewTextureFromRgba(colors []math.Color4b, size math.Vec2i) (graphics.Texture, error) { + if !WindowIsCreated() { + return nil, ErrWindowNotExists + } + var glLastTexture int32 gl.GetIntegerv(gl.TEXTURE_BINDING_2D, &glLastTexture) @@ -26,10 +30,14 @@ func newTextureFromRgba(colors []math.Color4b, size math.Vec2i) (graphics.Textur gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(size.X), int32(size.Y), 0, gl.RGBA, gl.UNSIGNED_BYTE, unsafe.Pointer(&colors[0])) gl.BindTexture(gl.TEXTURE_2D, uint32(glLastTexture)) - return &texture{size, glTexture}, nil + return &texture{glTexture, size}, nil } -func newTextureFromRgb(colors []math.Color3b, size math.Vec2i) (graphics.Texture, error) { +func NewTextureFromRgb(colors []math.Color3b, size math.Vec2i) (graphics.Texture, error) { + if !WindowIsCreated() { + return nil, ErrWindowNotExists + } + var glLastTexture int32 gl.GetIntegerv(gl.TEXTURE_BINDING_2D, &glLastTexture) @@ -43,7 +51,7 @@ func newTextureFromRgb(colors []math.Color3b, size math.Vec2i) (graphics.Texture gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGB, int32(size.X), int32(size.Y), 0, gl.RGB, gl.UNSIGNED_BYTE, unsafe.Pointer(&colors[0])) gl.BindTexture(gl.TEXTURE_2D, uint32(glLastTexture)) - return &texture{size, glTexture}, nil + return &texture{glTexture, size}, nil } func (t *texture) Id() graphics.TextureId { diff --git a/platform/window.go b/platform/window.go index b11d37c..7fd13ae 100644 --- a/platform/window.go +++ b/platform/window.go @@ -1,6 +1,7 @@ package platform import ( + "errors" "log" "github.com/FooSoft/lazarus/graphics" @@ -10,78 +11,88 @@ import ( "github.com/veandco/go-sdl2/sdl" ) -type Window struct { +var ( + ErrWindowExists = errors.New("only one window can exist at a time") + ErrWindowNotExists = errors.New("no window has been created") +) + +var windowState struct { sdlWindow *sdl.Window sdlGlContext sdl.GLContext - imguiContext *imgui.Context scene Scene } -func newWindow(title string, size math.Vec2i, scene Scene) (*Window, error) { +func WindowCreate(title string, size math.Vec2i, scene Scene) error { + if WindowIsCreated() { + return ErrWindowExists + } + + platformInit() + + var err error log.Println("window create") - sdlWindow, err := sdl.CreateWindow( - title, - sdl.WINDOWPOS_CENTERED, - sdl.WINDOWPOS_CENTERED, - int32(size.X), - int32(size.Y), - sdl.WINDOW_OPENGL, - ) - if err != nil { - return nil, err + if windowState.sdlWindow, err = sdl.CreateWindow(title, sdl.WINDOWPOS_CENTERED, sdl.WINDOWPOS_CENTERED, int32(size.X), int32(size.Y), sdl.WINDOW_OPENGL); err != nil { + return err } - sdlGlContext, err := sdlWindow.GLCreateContext() - if err != nil { - sdlWindow.Destroy() - return nil, err + log.Println("window gl context create") + if windowState.sdlGlContext, err = windowState.sdlWindow.GLCreateContext(); err != nil { + WindowDestroy() + return err } - w := &Window{ - sdlWindow: sdlWindow, - sdlGlContext: sdlGlContext, - } + log.Println("window gl context make current") + windowState.sdlWindow.GLMakeCurrent(windowState.sdlGlContext) - w.makeCurrent() - - log.Println("opengl init") + log.Println("window gl init") if err := gl.Init(); err != nil { - return nil, err + WindowDestroy() + return err } - w.imguiContext, err = imgui.New(w.DisplaySize(), w.BufferSize()) - if err != nil { - w.Destroy() - return nil, err + if err := imgui.Create(); err != nil { + WindowDestroy() + return err } - if err := w.SetScene(scene); err != nil { - w.Destroy() - return nil, err + if err := WindowSetScene(scene); err != nil { + WindowDestroy() + return err } - return w, nil + return nil } -func (w *Window) SetScene(scene Scene) error { - if w.scene == scene { +func WindowSetScene(scene Scene) error { + if !WindowIsCreated() { + return ErrWindowNotExists + } + + if windowState.scene == scene { return nil } - log.Printf("scene transition \"%v\" => \"%v\"\n", sceneName(w.scene), sceneName(scene)) + sceneName := func(s Scene) string { + if s == nil { + return "" + } else { + return s.Name() + } + } - if sceneDestroyer, ok := w.scene.(SceneDestroyer); ok { - log.Printf("scene notify destroy \"%s\"\n", sceneName(w.scene)) - if err := sceneDestroyer.Destroy(w); err != nil { + if sceneDestroyer, ok := windowState.scene.(SceneDestroyer); ok { + log.Printf("window scene notify destroy \"%s\"\n", sceneName(windowState.scene)) + if err := sceneDestroyer.Destroy(); err != nil { return err } } - w.scene = scene + log.Printf("window scene transition \"%v\" => \"%v\"\n", sceneName(windowState.scene), sceneName(scene)) + windowState.scene = scene if sceneCreator, ok := scene.(SceneCreator); ok { - log.Printf("scene notify create \"%s\"\n", sceneName(w.scene)) - if err := sceneCreator.Create(w); err != nil { + log.Printf("window scene notify create \"%s\"\n", sceneName(windowState.scene)) + if err := sceneCreator.Create(); err != nil { return err } } @@ -89,52 +100,41 @@ func (w *Window) SetScene(scene Scene) error { return nil } -func (w *Window) Destroy() error { - if w == nil || w.sdlWindow == nil { +func WindowDestroy() error { + if !WindowIsCreated() { return nil } - w.makeCurrent() - - if err := w.SetScene(nil); err != nil { + if err := WindowSetScene(nil); err != nil { return err } - if err := w.imguiContext.Destroy(); err != nil { + if err := imgui.Destroy(); err != nil { return err } - w.imguiContext = nil - sdl.GLDeleteContext(w.sdlGlContext) - w.sdlGlContext = nil - - if err := w.sdlWindow.Destroy(); err != nil { - return err - } - w.sdlWindow = nil + log.Println("window gl context destroy") + sdl.GLDeleteContext(windowState.sdlGlContext) + windowState.sdlGlContext = nil log.Println("window destroy") - removeWindow(w) + if err := windowState.sdlWindow.Destroy(); err != nil { + return err + } + windowState.sdlWindow = nil return nil } -func (w *Window) CreateTextureRgba(colors []math.Color4b, size math.Vec2i) (graphics.Texture, error) { - w.makeCurrent() - return newTextureFromRgba(colors, size) -} +func WindowRenderTexture(texture graphics.Texture, position math.Vec2i) error { + if !WindowIsCreated() { + return ErrWindowNotExists + } -func (w *Window) CreateTextureRgb(colors []math.Color3b, size math.Vec2i) (graphics.Texture, error) { - w.makeCurrent() - return newTextureFromRgb(colors, size) -} - -func (w *Window) RenderTexture(texture graphics.Texture, position math.Vec2i) { size := texture.Size() gl.Enable(gl.TEXTURE_2D) gl.BindTexture(gl.TEXTURE_2D, uint32(texture.Id())) - gl.Begin(gl.QUADS) gl.TexCoord2f(0, 0) gl.Vertex2f(0, 0) @@ -145,31 +145,48 @@ func (w *Window) RenderTexture(texture graphics.Texture, position math.Vec2i) { gl.TexCoord2f(1, 0) gl.Vertex2f(float32(size.X), 0) gl.End() + + return nil } -func (w *Window) DisplaySize() math.Vec2i { - width, height := w.sdlWindow.GetSize() - return math.Vec2i{X: int(width), Y: int(height)} +func WindowDisplaySize() (math.Vec2i, error) { + if !WindowIsCreated() { + return math.Vec2i{}, ErrWindowNotExists + } + + width, height := windowState.sdlWindow.GetSize() + return math.Vec2i{X: int(width), Y: int(height)}, nil } -func (w *Window) BufferSize() math.Vec2i { - width, height := w.sdlWindow.GLGetDrawableSize() - return math.Vec2i{X: int(width), Y: int(height)} +func WindowIsCreated() bool { + return windowState.sdlWindow != nil } -func (w *Window) Imgui() *imgui.Context { - return w.imguiContext +func windowBufferSize() (math.Vec2i, error) { + if !WindowIsCreated() { + return math.Vec2i{}, ErrWindowNotExists + } + + width, height := windowState.sdlWindow.GLGetDrawableSize() + return math.Vec2i{X: int(width), Y: int(height)}, nil } -func (w *Window) advance() (bool, error) { - w.makeCurrent() +func windowAdvance() (bool, error) { + if !WindowIsCreated() { + return false, ErrWindowNotExists + } - displaySize := w.DisplaySize() - w.imguiContext.SetDisplaySize(displaySize) - bufferSize := w.BufferSize() - w.imguiContext.SetBufferSize(bufferSize) + displaySize, err := WindowDisplaySize() + if err != nil { + return false, err + } - w.imguiContext.BeginFrame() + bufferSize, err := windowBufferSize() + if err != nil { + return false, err + } + + imgui.BeginFrame(displaySize, bufferSize) gl.Viewport(0, 0, int32(displaySize.X), int32(displaySize.Y)) gl.Clear(gl.COLOR_BUFFER_BIT) @@ -179,23 +196,22 @@ func (w *Window) advance() (bool, error) { gl.MatrixMode(gl.MODELVIEW) gl.LoadIdentity() - if sceneAdvancer, ok := w.scene.(SceneAdvancer); ok { - if err := sceneAdvancer.Advance(w); err != nil { + if sceneAdvancer, ok := windowState.scene.(SceneAdvancer); ok { + if err := sceneAdvancer.Advance(); err != nil { return false, err } } - w.imguiContext.EndFrame() - w.sdlWindow.GLSwap() + imgui.EndFrame() + windowState.sdlWindow.GLSwap() - return w.scene != nil, nil + return windowState.scene != nil, nil } -func (w *Window) processEvent(event sdl.Event) (bool, error) { - return w.imguiContext.ProcessEvent(event) -} - -func (w *Window) makeCurrent() { - w.sdlWindow.GLMakeCurrent(w.sdlGlContext) +func windowProcessEvent(event sdl.Event) (bool, error) { + if !WindowIsCreated() { + return false, ErrWindowNotExists + } + return imgui.ProcessEvent(event) } diff --git a/tools/viewer/viewer.go b/tools/viewer/viewer.go index 1617832..64d59ed 100644 --- a/tools/viewer/viewer.go +++ b/tools/viewer/viewer.go @@ -12,6 +12,7 @@ import ( "github.com/FooSoft/lazarus/graphics" "github.com/FooSoft/lazarus/math" "github.com/FooSoft/lazarus/platform" + "github.com/FooSoft/lazarus/platform/imgui" ) func loadPalette(path string) (*dat.DatPalette, error) { @@ -45,7 +46,7 @@ func (s *scene) Name() string { return "viewer" } -func (s *scene) Destroy(window *platform.Window) error { +func (s *scene) Destroy() error { if s.texture != nil { return s.texture.Destroy() } @@ -53,20 +54,18 @@ func (s *scene) Destroy(window *platform.Window) error { return nil } -func (s *scene) Advance(window *platform.Window) error { +func (s *scene) Advance() error { var ( directionIndex = s.directionIndex frameIndex = s.frameIndex ) if s.texture == nil { - if err := s.updateTexture(window); err != nil { + if err := s.updateTexture(); err != nil { return err } } - imgui := window.Imgui() - imgui.DialogBegin("DC6 Viewer") imgui.Image(s.texture) direction := s.animation.Directions[directionIndex] @@ -78,20 +77,20 @@ func (s *scene) Advance(window *platform.Window) error { imgui.Text(fmt.Sprintf("Size: %+v", frame.Size)) imgui.Text(fmt.Sprintf("Offset: %+v", frame.Offset)) if imgui.Button("Exit") { - window.SetScene(nil) + platform.WindowSetScene(nil) } imgui.DialogEnd() if directionIndex != s.directionIndex || frameIndex != s.frameIndex { s.directionIndex = directionIndex s.frameIndex = frameIndex - s.updateTexture(window) + s.updateTexture() } return nil } -func (s *scene) updateTexture(window *platform.Window) error { +func (s *scene) updateTexture() error { frame := s.animation.Directions[s.directionIndex].Frames[s.frameIndex] colors := make([]math.Color3b, frame.Size.X*frame.Size.Y) for y := 0; y < frame.Size.Y; y++ { @@ -107,7 +106,7 @@ func (s *scene) updateTexture(window *platform.Window) error { } var err error - s.texture, err = window.CreateTextureRgb(colors, frame.Size) + s.texture, err = platform.NewTextureFromRgb(colors, frame.Size) if err != nil { return err } @@ -151,12 +150,11 @@ func main() { } scene := &scene{animation: animation, palette: palette} - window, err := platform.NewWindow("Viewer", math.Vec2i{X: 1024, Y: 768}, scene) - if err != nil { + if err := platform.WindowCreate("Viewer", math.Vec2i{X: 1024, Y: 768}, scene); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } - defer window.Destroy() + defer platform.WindowDestroy() for { run, err := platform.Advance()