make Window and ImgUi into singletons; there will only ever be one of each

This commit is contained in:
Alex Yatskov 2019-01-06 17:00:19 -08:00
parent 078f97ae87
commit 6faac2f08e
7 changed files with 248 additions and 280 deletions

View File

@ -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()
func Create() error {
if IsCreated() {
return nil
}
log.Println("imgui create")
imguiState.imguiContext = C.igCreateContext(nil)
imguiState.imguiIo = C.igGetIO()
for imguiKey, nativeKey := range keyMapping {
singleton.nativeIo.KeyMap[imguiKey] = nativeKey
imguiState.imguiIo.KeyMap[imguiKey] = nativeKey
}
}
log.Println("imgui context create")
c := &Context{displaySize: displaySize, bufferSize: bufferSize}
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
}
func (c *Context) Destroy() error {
if c == nil || c.fontTexture == 0 {
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
singleton.refCount--
if singleton.refCount == 0 {
log.Println("imgui global destroy")
C.igDestroyContext(singleton.nativeContext)
singleton.nativeContext = nil
singleton.nativeIo = nil
func IsCreated() bool {
return imguiState.imguiContext != nil
}
func Destroy() error {
if !IsCreated() {
return nil
}
gl.DeleteTextures(1, &imguiState.fontTexture)
imguiState.imguiIo.Fonts.TexID = C.nativeHandleCast(C.uintptr_t(imguiState.fontTexture))
imguiState.fontTexture = 0
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 ProcessEvent(event sdl.Event) (bool, error) {
if !IsCreated() {
return false, ErrNotInit
}
func (c *Context) ProcessEvent(event sdl.Event) (bool, error) {
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),
)

View File

@ -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))

View File

@ -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 platformInit() error {
if platfromState.sdlIsInit {
return nil
}
func NewWindow(title string, size math.Vec2i, scene Scene) (*Window, error) {
if !singleton.sdlIsInit {
runtime.LockOSThread()
log.Println("sdl global init")
log.Println("sdl 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
}
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
}
}
platfromState.sdlIsInit = true
return nil
}

View File

@ -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
}

View File

@ -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) {
if !WindowIsCreated() {
return nil, ErrWindowNotExists
}
func newTextureFromRgba(colors []math.Color4b, size math.Vec2i) (graphics.Texture, error) {
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) {
if !WindowIsCreated() {
return nil, ErrWindowNotExists
}
func newTextureFromRgb(colors []math.Color3b, size math.Vec2i) (graphics.Texture, error) {
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 {

View File

@ -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
}
func (w *Window) SetScene(scene Scene) error {
if w.scene == scene {
return nil
}
log.Printf("scene transition \"%v\" => \"%v\"\n", sceneName(w.scene), sceneName(scene))
func WindowSetScene(scene Scene) error {
if !WindowIsCreated() {
return ErrWindowNotExists
}
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 windowState.scene == scene {
return nil
}
sceneName := func(s Scene) string {
if s == nil {
return "<nil>"
} else {
return s.Name()
}
}
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
}
func (w *Window) BufferSize() math.Vec2i {
width, height := w.sdlWindow.GLGetDrawableSize()
return math.Vec2i{X: int(width), Y: int(height)}
width, height := windowState.sdlWindow.GetSize()
return math.Vec2i{X: int(width), Y: int(height)}, nil
}
func (w *Window) Imgui() *imgui.Context {
return w.imguiContext
func WindowIsCreated() bool {
return windowState.sdlWindow != nil
}
func (w *Window) advance() (bool, error) {
w.makeCurrent()
func windowBufferSize() (math.Vec2i, error) {
if !WindowIsCreated() {
return math.Vec2i{}, ErrWindowNotExists
}
displaySize := w.DisplaySize()
w.imguiContext.SetDisplaySize(displaySize)
bufferSize := w.BufferSize()
w.imguiContext.SetBufferSize(bufferSize)
width, height := windowState.sdlWindow.GLGetDrawableSize()
return math.Vec2i{X: int(width), Y: int(height)}, nil
}
w.imguiContext.BeginFrame()
func windowAdvance() (bool, error) {
if !WindowIsCreated() {
return false, ErrWindowNotExists
}
displaySize, err := WindowDisplaySize()
if err != nil {
return false, err
}
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 windowProcessEvent(event sdl.Event) (bool, error) {
if !WindowIsCreated() {
return false, ErrWindowNotExists
}
func (w *Window) makeCurrent() {
w.sdlWindow.GLMakeCurrent(w.sdlGlContext)
return imgui.ProcessEvent(event)
}

View File

@ -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()