make Window and ImgUi into singletons; there will only ever be one of each
This commit is contained in:
parent
078f97ae87
commit
6faac2f08e
@ -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),
|
||||
)
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 "<nil>"
|
||||
} else {
|
||||
return scene.Name()
|
||||
}
|
||||
Destroy() error
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 "<nil>"
|
||||
} 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)
|
||||
}
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user