1
Fork 0

switch imgui backend to cimgui

This commit is contained in:
Alex Yatskov 2019-01-03 19:05:19 -08:00
parent 8c28fc6839
commit ad7067101a
8 changed files with 279 additions and 321 deletions

2
.gitmodules vendored
View File

@ -2,5 +2,5 @@
path = formats/mpq/stormlib
url = https://github.com/ladislav-zezula/StormLib.git
[submodule "platform/imgui/cimgui"]
path = platform/imgui/imgui_wrapper/cimgui
path = platform/imgui/cimgui
url = https://github.com/cimgui/cimgui.git

View File

@ -1,14 +1,58 @@
package imgui
// #cgo linux CFLAGS: -I./cimgui
// #cgo linux LDFLAGS: -L./cimgui -l:cimgui.a -lstdc++ -lm
// #include "native.h"
import "C"
import (
"log"
"unsafe"
imgui "github.com/FooSoft/imgui-go"
"github.com/FooSoft/lazarus/math"
"github.com/go-gl/gl/v2.1/gl"
"github.com/veandco/go-sdl2/sdl"
)
const (
pointerSize = unsafe.Sizeof(C.uintptr_t(0))
drawCommandSize = unsafe.Sizeof(C.ImDrawCmd{})
indexSize = unsafe.Sizeof(C.ImDrawIdx(0))
vertexSize = unsafe.Sizeof(C.ImDrawVert{})
vertexOffsetPos = unsafe.Offsetof(C.ImDrawVert{}.pos)
vertexOffsetUv = unsafe.Offsetof(C.ImDrawVert{}.uv)
vertexOffsetCol = unsafe.Offsetof(C.ImDrawVert{}.col)
)
var keyMapping = map[int]C.int{
C.ImGuiKey_Tab: sdl.SCANCODE_TAB,
C.ImGuiKey_LeftArrow: sdl.SCANCODE_LEFT,
C.ImGuiKey_RightArrow: sdl.SCANCODE_RIGHT,
C.ImGuiKey_UpArrow: sdl.SCANCODE_UP,
C.ImGuiKey_DownArrow: sdl.SCANCODE_DOWN,
C.ImGuiKey_PageUp: sdl.SCANCODE_PAGEUP,
C.ImGuiKey_PageDown: sdl.SCANCODE_PAGEDOWN,
C.ImGuiKey_Home: sdl.SCANCODE_HOME,
C.ImGuiKey_End: sdl.SCANCODE_END,
C.ImGuiKey_Insert: sdl.SCANCODE_INSERT,
C.ImGuiKey_Delete: sdl.SCANCODE_DELETE,
C.ImGuiKey_Backspace: sdl.SCANCODE_BACKSPACE,
C.ImGuiKey_Space: sdl.SCANCODE_BACKSPACE,
C.ImGuiKey_Enter: sdl.SCANCODE_RETURN,
C.ImGuiKey_Escape: sdl.SCANCODE_ESCAPE,
C.ImGuiKey_A: sdl.SCANCODE_A,
C.ImGuiKey_C: sdl.SCANCODE_C,
C.ImGuiKey_V: sdl.SCANCODE_V,
C.ImGuiKey_X: sdl.SCANCODE_X,
C.ImGuiKey_Y: sdl.SCANCODE_Y,
C.ImGuiKey_Z: sdl.SCANCODE_Z,
}
var singleton struct {
nativeContext *C.ImGuiContext
nativeIo *C.ImGuiIO
refCount int
}
type Context struct {
buttonsDown [3]bool
lastTime uint64
@ -21,77 +65,55 @@ func New(displaySize, bufferSize math.Vec2i) (*Context, error) {
singleton.refCount++
if singleton.refCount == 1 {
log.Println("imgui global create")
singleton.context = imgui.CreateContext(nil)
singleton.nativeContext = C.igCreateContext(nil)
singleton.nativeIo = C.igGetIO()
keys := map[int]int{
imgui.KeyTab: sdl.SCANCODE_TAB,
imgui.KeyLeftArrow: sdl.SCANCODE_LEFT,
imgui.KeyRightArrow: sdl.SCANCODE_RIGHT,
imgui.KeyUpArrow: sdl.SCANCODE_UP,
imgui.KeyDownArrow: sdl.SCANCODE_DOWN,
imgui.KeyPageUp: sdl.SCANCODE_PAGEUP,
imgui.KeyPageDown: sdl.SCANCODE_PAGEDOWN,
imgui.KeyHome: sdl.SCANCODE_HOME,
imgui.KeyEnd: sdl.SCANCODE_END,
imgui.KeyInsert: sdl.SCANCODE_INSERT,
imgui.KeyDelete: sdl.SCANCODE_DELETE,
imgui.KeyBackspace: sdl.SCANCODE_BACKSPACE,
imgui.KeySpace: sdl.SCANCODE_BACKSPACE,
imgui.KeyEnter: sdl.SCANCODE_RETURN,
imgui.KeyEscape: sdl.SCANCODE_ESCAPE,
imgui.KeyA: sdl.SCANCODE_A,
imgui.KeyC: sdl.SCANCODE_C,
imgui.KeyV: sdl.SCANCODE_V,
imgui.KeyX: sdl.SCANCODE_X,
imgui.KeyY: sdl.SCANCODE_Y,
imgui.KeyZ: sdl.SCANCODE_Z,
}
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
io := imgui.CurrentIO()
for imguiKey, nativeKey := range keys {
io.KeyMap(imguiKey, nativeKey)
for imguiKey, nativeKey := range keyMapping {
singleton.nativeIo.KeyMap[imguiKey] = nativeKey
}
}
log.Println("imgui context create")
c := &Context{displaySize: displaySize, bufferSize: bufferSize}
// Build texture atlas
io := imgui.CurrentIO()
image := io.Fonts().TextureDataRGBA32()
var imageData *C.uchar
var imageWidth, imageHeight C.int
C.ImFontAtlas_GetTexDataAsRGBA32(singleton.nativeIo.Fonts, &imageData, &imageWidth, &imageHeight, nil)
// Store state
var lastTexture int32
gl.GetIntegerv(gl.TEXTURE_BINDING_2D, &lastTexture)
// Create texture
gl.GenTextures(1, &c.fontTexture)
gl.BindTexture(gl.TEXTURE_2D, c.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(image.Width),
int32(image.Height),
0,
gl.RGBA,
gl.UNSIGNED_BYTE,
image.Pixels,
)
// Restore state
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))
// Store texture identifier
io.Fonts().SetTextureID(imgui.TextureID(c.fontTexture))
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
}
return nil
}
func (c *Context) SetDisplaySize(displaySize math.Vec2i) {
c.displaySize = displaySize
}
@ -100,22 +122,171 @@ func (c *Context) SetBufferSize(bufferSize math.Vec2i) {
c.bufferSize = bufferSize
}
func (c *Context) Destroy() error {
if c == nil || c.fontTexture == 0 {
return nil
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)
currentTime := sdl.GetPerformanceCounter()
if c.lastTime > 0 {
singleton.nativeIo.DeltaTime = C.float(float32(currentTime-c.lastTime) / float32(sdl.GetPerformanceFrequency()))
} else {
singleton.nativeIo.DeltaTime = C.float(1.0 / 60.0)
}
c.lastTime = currentTime
x, y, state := sdl.GetMouseState()
singleton.nativeIo.MousePos.x = C.float(x)
singleton.nativeIo.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
}
log.Println("imgui context destroy")
gl.DeleteTextures(1, &c.fontTexture)
imgui.CurrentIO().Fonts().SetTextureID(0)
c.fontTexture = 0
C.igNewFrame()
}
singleton.refCount--
if singleton.refCount == 0 {
log.Println("imgui global destroy")
singleton.context.Destroy()
singleton.context = nil
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++
} else if wheelEvent.X < 0 {
singleton.nativeIo.MouseDelta.x--
}
if wheelEvent.Y > 0 {
singleton.nativeIo.MouseDelta.y++
} else if wheelEvent.Y < 0 {
singleton.nativeIo.MouseDelta.y--
}
return true, nil
case sdl.MOUSEBUTTONDOWN:
buttonEvent := event.(*sdl.MouseButtonEvent)
switch buttonEvent.Button {
case sdl.BUTTON_LEFT:
c.buttonsDown[0] = true
break
case sdl.BUTTON_RIGHT:
c.buttonsDown[1] = true
break
case sdl.BUTTON_MIDDLE:
c.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])))
return true, nil
case sdl.KEYDOWN:
keyEvent := event.(*sdl.KeyboardEvent)
singleton.nativeIo.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)
case sdl.KEYUP:
keyEvent := event.(*sdl.KeyboardEvent)
singleton.nativeIo.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)
return true, nil
}
return false, nil
}
func (c *Context) EndFrame() error {
C.igRender()
var lastTexture int32
gl.GetIntegerv(gl.TEXTURE_BINDING_2D, &lastTexture)
var lastPolygonMode [2]int32
gl.GetIntegerv(gl.POLYGON_MODE, &lastPolygonMode[0])
var lastViewport [4]int32
gl.GetIntegerv(gl.VIEWPORT, &lastViewport[0])
var lastScissorBox [4]int32
gl.GetIntegerv(gl.SCISSOR_BOX, &lastScissorBox[0])
gl.PushAttrib(gl.ENABLE_BIT | gl.COLOR_BUFFER_BIT | gl.TRANSFORM_BIT)
gl.Enable(gl.BLEND)
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
gl.Disable(gl.CULL_FACE)
gl.Disable(gl.DEPTH_TEST)
gl.Disable(gl.LIGHTING)
gl.Disable(gl.COLOR_MATERIAL)
gl.Enable(gl.SCISSOR_TEST)
gl.EnableClientState(gl.VERTEX_ARRAY)
gl.EnableClientState(gl.TEXTURE_COORD_ARRAY)
gl.EnableClientState(gl.COLOR_ARRAY)
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.MatrixMode(gl.PROJECTION)
gl.PushMatrix()
gl.LoadIdentity()
gl.Ortho(0, float64(c.displaySize.X), float64(c.displaySize.Y), 0, -1, 1)
gl.MatrixMode(gl.MODELVIEW)
gl.PushMatrix()
gl.LoadIdentity()
drawData := C.igGetDrawData()
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)),
},
)
for i := C.int(0); i < drawData.CmdListsCount; i++ {
var (
commandList = *(**C.ImDrawList)(unsafe.Pointer(uintptr(unsafe.Pointer(drawData.CmdLists)) + pointerSize*uintptr(i)))
vertexBuffer = unsafe.Pointer(commandList.VtxBuffer.Data)
indexBuffer = unsafe.Pointer(commandList.IdxBuffer.Data)
elementCount = C.unsigned(0)
)
gl.VertexPointer(2, gl.FLOAT, int32(vertexSize), unsafe.Pointer(uintptr(vertexBuffer)+uintptr(vertexOffsetPos)))
gl.TexCoordPointer(2, gl.FLOAT, int32(vertexSize), unsafe.Pointer(uintptr(vertexBuffer)+uintptr(vertexOffsetUv)))
gl.ColorPointer(4, gl.UNSIGNED_BYTE, int32(vertexSize), unsafe.Pointer(uintptr(vertexBuffer)+uintptr(vertexOffsetCol)))
for j := C.int(0); j < commandList.CmdBuffer.Size; j++ {
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(command.ClipRect.z-command.ClipRect.x),
int32(command.ClipRect.w-command.ClipRect.y),
)
gl.BindTexture(gl.TEXTURE_2D, uint32(uintptr(command.TextureId)))
gl.DrawElements(
gl.TRIANGLES,
int32(command.ElemCount),
gl.UNSIGNED_SHORT,
unsafe.Pointer(uintptr(unsafe.Pointer(indexBuffer))+uintptr(elementCount)*uintptr(indexSize)),
)
elementCount += command.ElemCount
}
}
gl.DisableClientState(gl.COLOR_ARRAY)
gl.DisableClientState(gl.TEXTURE_COORD_ARRAY)
gl.DisableClientState(gl.VERTEX_ARRAY)
gl.BindTexture(gl.TEXTURE_2D, uint32(lastTexture))
gl.MatrixMode(gl.MODELVIEW)
gl.PopMatrix()
gl.MatrixMode(gl.PROJECTION)
gl.PopMatrix()
gl.PopAttrib()
gl.PolygonMode(gl.FRONT, uint32(lastPolygonMode[0]))
gl.PolygonMode(gl.BACK, uint32(lastPolygonMode[1]))
gl.Viewport(lastViewport[0], lastViewport[1], lastViewport[2], lastViewport[3])
gl.Scissor(lastScissorBox[0], lastScissorBox[1], lastScissorBox[2], lastScissorBox[3])
return nil
}

View File

@ -1,21 +1,28 @@
package imgui
// #include "native.h"
import "C"
import (
imgui "github.com/FooSoft/imgui-go"
"unsafe"
"github.com/FooSoft/lazarus/graphics"
"github.com/FooSoft/lazarus/math"
)
func (*Context) DialogBegin(label string) bool {
return imgui.Begin(label)
labelC := C.CString(label)
defer C.free(unsafe.Pointer(labelC))
return bool(C.igBegin(labelC, nil, 0))
}
func (*Context) DialogEnd() {
imgui.End()
C.igEnd()
}
func (*Context) Button(label string) bool {
return imgui.Button(label)
labelC := C.CString(label)
defer C.free(unsafe.Pointer(labelC))
return bool(C.igButton(labelC, C.ImVec2{}))
}
func (c *Context) Image(texture graphics.Texture) {
@ -23,16 +30,28 @@ func (c *Context) Image(texture graphics.Texture) {
}
func (*Context) ImageSized(texture graphics.Texture, size math.Vec2i) {
imgui.Image(imgui.TextureID(texture.Id()), imgui.Vec2{X: float32(size.X), Y: float32(size.Y)})
C.igImage(
C.nativeHandleCast(C.uintptr_t(texture.Id())),
C.ImVec2{x: C.float(size.X), y: C.float(size.Y)},
C.ImVec2{0, 0},
C.ImVec2{1, 1},
C.ImVec4{1, 1, 1, 1},
C.ImVec4{0, 0, 0, 0},
)
}
func (*Context) SliderInt(label string, value *int, min, max int) bool {
temp := int32(*value)
result := imgui.SliderInt(label, &temp, int32(min), int32(max))
*value = int(temp)
labelC := C.CString(label)
defer C.free(unsafe.Pointer(labelC))
valueC := C.int(*value)
result := bool(C.igSliderInt(labelC, &valueC, (C.int)(min), (C.int)(max), nil))
*value = int(valueC)
return result
}
func (*Context) Text(label string) {
imgui.Text(label)
labelStartC := C.CString(label)
labelEndC := (*C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(labelStartC)) + uintptr(len(label))))
defer C.free(unsafe.Pointer(labelStartC))
C.igTextUnformatted(labelStartC, labelEndC)
}

View File

@ -1,44 +0,0 @@
package imgui
// #define CIMGUI_DEFINE_ENUMS_AND_STRUCTS
// #include "cimgui/cimgui.h"
// #cgo linux LDFLAGS: -L./cimgui -l:cimgui.a -lstdc++ -lm
import "C"
import "unsafe"
type Context = C.ImGuiContext
type DrawData = C.ImDrawData
type FontAtlas = C.ImFontAtlas
type Io = C.ImGuiIO
func CreateContext(fontAtlas *FontAtlas) *Context {
c := C.igCreateContext(fontAtlas)
return c
}
func (c *Context) Destroy() {
C.igDestroyContext(c)
}
func NewFrame() {
C.igNewFrame()
}
func Render() {
C.igRender()
}
func GetDrawData() *DrawData {
return C.igGetDrawData()
}
func GetIo() *Io {
return C.igGetIO()
}
func (fa *FontAtlas) GetTexDataAsRGBA32() (pixels unsafe.Pointer, width, height int32) {
var data *C.uint8_t
var w, h C.int
C.ImFontAtlas_GetTexDataAsRGBA32(fa, &data, &w, &h, nil)
return unsafe.Pointer(data), int32(w), int32(h)
}

View File

@ -1,202 +0,0 @@
package imgui
import (
"unsafe"
"github.com/FooSoft/imgui-go"
"github.com/go-gl/gl/v2.1/gl"
"github.com/veandco/go-sdl2/sdl"
)
var singleton struct {
context *imgui.Context
refCount int
}
func (c *Context) BeginFrame() error {
// Setup display size (every frame to accommodate for window resizing)
io := imgui.CurrentIO()
io.SetDisplaySize(imgui.Vec2{
X: float32(c.displaySize.X),
Y: float32(c.displaySize.Y),
})
// Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
frequency := sdl.GetPerformanceFrequency()
currentTime := sdl.GetPerformanceCounter()
if c.lastTime > 0 {
io.SetDeltaTime(float32(currentTime-c.lastTime) / float32(frequency))
} else {
io.SetDeltaTime(1.0 / 60.0)
}
c.lastTime = currentTime
// If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
x, y, state := sdl.GetMouseState()
for i, button := range []uint32{sdl.BUTTON_LEFT, sdl.BUTTON_RIGHT, sdl.BUTTON_MIDDLE} {
io.SetMouseButtonDown(i, c.buttonsDown[i] || (state&sdl.Button(button)) != 0)
c.buttonsDown[i] = false
}
io.SetMousePosition(imgui.Vec2{X: float32(x), Y: float32(y)})
imgui.NewFrame()
return nil
}
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field.
func (c *Context) ProcessEvent(event sdl.Event) (bool, error) {
switch io := imgui.CurrentIO(); event.GetType() {
case sdl.MOUSEWHEEL:
wheelEvent := event.(*sdl.MouseWheelEvent)
var deltaX, deltaY float32
if wheelEvent.X > 0 {
deltaX++
} else if wheelEvent.X < 0 {
deltaX--
}
if wheelEvent.Y > 0 {
deltaY++
} else if wheelEvent.Y < 0 {
deltaY--
}
return true, nil
case sdl.MOUSEBUTTONDOWN:
buttonEvent := event.(*sdl.MouseButtonEvent)
switch buttonEvent.Button {
case sdl.BUTTON_LEFT:
c.buttonsDown[0] = true
break
case sdl.BUTTON_RIGHT:
c.buttonsDown[1] = true
break
case sdl.BUTTON_MIDDLE:
c.buttonsDown[2] = true
break
}
return true, nil
case sdl.TEXTINPUT:
inputEvent := event.(*sdl.TextInputEvent)
io.AddInputCharacters(string(inputEvent.Text[:]))
return true, nil
case sdl.KEYDOWN:
keyEvent := event.(*sdl.KeyboardEvent)
io.KeyPress(int(keyEvent.Keysym.Scancode))
modState := int(sdl.GetModState())
io.KeyShift(modState&sdl.KMOD_LSHIFT, modState&sdl.KMOD_RSHIFT)
io.KeyCtrl(modState&sdl.KMOD_LCTRL, modState&sdl.KMOD_RCTRL)
io.KeyAlt(modState&sdl.KMOD_LALT, modState&sdl.KMOD_RALT)
case sdl.KEYUP:
keyEvent := event.(*sdl.KeyboardEvent)
io.KeyRelease(int(keyEvent.Keysym.Scancode))
modState := int(sdl.GetModState())
io.KeyShift(modState&sdl.KMOD_LSHIFT, modState&sdl.KMOD_RSHIFT)
io.KeyCtrl(modState&sdl.KMOD_LCTRL, modState&sdl.KMOD_RCTRL)
io.KeyAlt(modState&sdl.KMOD_LALT, modState&sdl.KMOD_RALT)
return true, nil
}
return false, nil
}
// OpenGL2 Render function.
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL singleton explicitly, in order to be able to run within any OpenGL engine that doesn't do so.
func (c *Context) EndFrame() error {
imgui.Render()
drawData := imgui.RenderedDrawData()
drawData.ScaleClipRects(imgui.Vec2{
X: float32(c.bufferSize.X) / float32(c.displaySize.X),
Y: float32(c.bufferSize.Y) / float32(c.displaySize.Y),
})
// We are using the OpenGL fixed pipeline to make the example code simpler to read!
// Setup render singleton: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill.
var lastTexture int32
gl.GetIntegerv(gl.TEXTURE_BINDING_2D, &lastTexture)
var lastPolygonMode [2]int32
gl.GetIntegerv(gl.POLYGON_MODE, &lastPolygonMode[0])
var lastViewport [4]int32
gl.GetIntegerv(gl.VIEWPORT, &lastViewport[0])
var lastScissorBox [4]int32
gl.GetIntegerv(gl.SCISSOR_BOX, &lastScissorBox[0])
gl.PushAttrib(gl.ENABLE_BIT | gl.COLOR_BUFFER_BIT | gl.TRANSFORM_BIT)
gl.Enable(gl.BLEND)
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
gl.Disable(gl.CULL_FACE)
gl.Disable(gl.DEPTH_TEST)
gl.Disable(gl.LIGHTING)
gl.Disable(gl.COLOR_MATERIAL)
gl.Enable(gl.SCISSOR_TEST)
gl.EnableClientState(gl.VERTEX_ARRAY)
gl.EnableClientState(gl.TEXTURE_COORD_ARRAY)
gl.EnableClientState(gl.COLOR_ARRAY)
gl.Enable(gl.TEXTURE_2D)
gl.PolygonMode(gl.FRONT_AND_BACK, gl.FILL)
// You may want this if using this code in an OpenGL 3+ context where shaders may be bound
// gl.UseProgram(0)
// Setup viewport, orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.
gl.Viewport(0, 0, int32(c.bufferSize.X), int32(c.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.MatrixMode(gl.MODELVIEW)
gl.PushMatrix()
gl.LoadIdentity()
vertexSize, vertexOffsetPos, vertexOffsetUv, vertexOffsetCol := imgui.VertexBufferLayout()
indexSize := imgui.IndexBufferLayout()
drawType := gl.UNSIGNED_SHORT
if indexSize == 4 {
drawType = gl.UNSIGNED_INT
}
// Render command lists
for _, commandList := range drawData.CommandLists() {
vertexBuffer, _ := commandList.VertexBuffer()
indexBuffer, _ := commandList.IndexBuffer()
indexBufferOffset := uintptr(indexBuffer)
gl.VertexPointer(2, gl.FLOAT, int32(vertexSize), unsafe.Pointer(uintptr(vertexBuffer)+uintptr(vertexOffsetPos)))
gl.TexCoordPointer(2, gl.FLOAT, int32(vertexSize), unsafe.Pointer(uintptr(vertexBuffer)+uintptr(vertexOffsetUv)))
gl.ColorPointer(4, gl.UNSIGNED_BYTE, int32(vertexSize), unsafe.Pointer(uintptr(vertexBuffer)+uintptr(vertexOffsetCol)))
for _, command := range commandList.Commands() {
if command.HasUserCallback() {
command.CallUserCallback(commandList)
} else {
clipRect := command.ClipRect()
gl.Scissor(int32(clipRect.X), int32(c.bufferSize.Y)-int32(clipRect.W), int32(clipRect.Z-clipRect.X), int32(clipRect.W-clipRect.Y))
gl.BindTexture(gl.TEXTURE_2D, uint32(command.TextureID()))
gl.DrawElements(gl.TRIANGLES, int32(command.ElementCount()), uint32(drawType), unsafe.Pointer(indexBufferOffset))
}
indexBufferOffset += uintptr(command.ElementCount() * indexSize)
}
}
// Restore modified state
gl.DisableClientState(gl.COLOR_ARRAY)
gl.DisableClientState(gl.TEXTURE_COORD_ARRAY)
gl.DisableClientState(gl.VERTEX_ARRAY)
gl.BindTexture(gl.TEXTURE_2D, uint32(lastTexture))
gl.MatrixMode(gl.MODELVIEW)
gl.PopMatrix()
gl.MatrixMode(gl.PROJECTION)
gl.PopMatrix()
gl.PopAttrib()
gl.PolygonMode(gl.FRONT, uint32(lastPolygonMode[0]))
gl.PolygonMode(gl.BACK, uint32(lastPolygonMode[1]))
gl.Viewport(lastViewport[0], lastViewport[1], lastViewport[2], lastViewport[3])
gl.Scissor(lastScissorBox[0], lastScissorBox[1], lastScissorBox[2], lastScissorBox[3])
return nil
}

10
platform/imgui/native.h Normal file
View File

@ -0,0 +1,10 @@
#include <stdlib.h>
#define CIMGUI_DEFINE_ENUMS_AND_STRUCTS
#define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER))
#include "cimgui/cimgui.h"
// silly trick to get go-vet off our back
inline ImTextureID nativeHandleCast(uintptr_t id) {
return (ImTextureID)id;
}

View File

@ -46,7 +46,11 @@ func (s *scene) Name() string {
}
func (s *scene) Destroy(window *platform.Window) error {
return s.texture.Destroy()
if s.texture != nil {
return s.texture.Destroy()
}
return nil
}
func (s *scene) Advance(window *platform.Window) error {