refactor ImGUI code files
This commit is contained in:
126
internal/igwrap/backend/glfw.go
Normal file
126
internal/igwrap/backend/glfw.go
Normal file
@ -0,0 +1,126 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/go-gl/glfw/v3.3/glfw"
|
||||
"github.com/inkyblackness/imgui-go/v4"
|
||||
)
|
||||
|
||||
const (
|
||||
mouseButtonPrimary = iota
|
||||
mouseButtonSecondary
|
||||
mouseButtonTertiary
|
||||
mouseButtonCount
|
||||
)
|
||||
|
||||
var (
|
||||
win *glfw.Window
|
||||
io imgui.IO
|
||||
|
||||
lastframe time.Time
|
||||
mouseJustPressed [mouseButtonCount]bool
|
||||
)
|
||||
|
||||
func Init(window *glfw.Window) {
|
||||
win = window
|
||||
io = imgui.CurrentIO()
|
||||
|
||||
setKeymap()
|
||||
lastframe = time.Now()
|
||||
|
||||
renderInit()
|
||||
}
|
||||
|
||||
// NewFrame marks the begin of a render pass.
|
||||
func NewFrame() {
|
||||
dsx, dsy := win.GetSize()
|
||||
io.SetDisplaySize(imgui.Vec2{X: float32(dsx), Y: float32(dsy)})
|
||||
|
||||
now := time.Now()
|
||||
deltaTime := float32(time.Since(lastframe).Seconds())
|
||||
if deltaTime <= 0.0 {
|
||||
deltaTime = 1e-6
|
||||
}
|
||||
io.SetDeltaTime(deltaTime)
|
||||
lastframe = now
|
||||
|
||||
if win.GetAttrib(glfw.Focused) != 0 {
|
||||
x, y := win.GetCursorPos()
|
||||
io.SetMousePosition(imgui.Vec2{X: float32(x), Y: float32(y)})
|
||||
}
|
||||
|
||||
for i := 0; i < mouseButtonCount; i++ {
|
||||
down := mouseJustPressed[i] || (win.GetMouseButton(glfwButtonIDByIndex[i]) == glfw.Press)
|
||||
io.SetMouseButtonDown(i, down)
|
||||
mouseJustPressed[i] = false
|
||||
}
|
||||
imgui.NewFrame()
|
||||
}
|
||||
|
||||
func setKeymap() {
|
||||
io.KeyMap(imgui.KeyTab, int(glfw.KeyTab))
|
||||
io.KeyMap(imgui.KeyLeftArrow, int(glfw.KeyLeft))
|
||||
io.KeyMap(imgui.KeyRightArrow, int(glfw.KeyRight))
|
||||
io.KeyMap(imgui.KeyUpArrow, int(glfw.KeyUp))
|
||||
io.KeyMap(imgui.KeyDownArrow, int(glfw.KeyDown))
|
||||
io.KeyMap(imgui.KeyPageUp, int(glfw.KeyPageUp))
|
||||
io.KeyMap(imgui.KeyPageDown, int(glfw.KeyPageDown))
|
||||
io.KeyMap(imgui.KeyHome, int(glfw.KeyHome))
|
||||
io.KeyMap(imgui.KeyEnd, int(glfw.KeyEnd))
|
||||
io.KeyMap(imgui.KeyInsert, int(glfw.KeyInsert))
|
||||
io.KeyMap(imgui.KeyDelete, int(glfw.KeyDelete))
|
||||
io.KeyMap(imgui.KeyBackspace, int(glfw.KeyBackspace))
|
||||
io.KeyMap(imgui.KeySpace, int(glfw.KeySpace))
|
||||
io.KeyMap(imgui.KeyEnter, int(glfw.KeyEnter))
|
||||
io.KeyMap(imgui.KeyEscape, int(glfw.KeyEscape))
|
||||
io.KeyMap(imgui.KeyA, int(glfw.KeyA))
|
||||
io.KeyMap(imgui.KeyC, int(glfw.KeyC))
|
||||
io.KeyMap(imgui.KeyV, int(glfw.KeyV))
|
||||
io.KeyMap(imgui.KeyX, int(glfw.KeyX))
|
||||
io.KeyMap(imgui.KeyY, int(glfw.KeyY))
|
||||
io.KeyMap(imgui.KeyZ, int(glfw.KeyZ))
|
||||
}
|
||||
|
||||
var glfwButtonIndexByID = map[glfw.MouseButton]int{
|
||||
glfw.MouseButton1: mouseButtonPrimary,
|
||||
glfw.MouseButton2: mouseButtonSecondary,
|
||||
glfw.MouseButton3: mouseButtonTertiary,
|
||||
}
|
||||
|
||||
var glfwButtonIDByIndex = map[int]glfw.MouseButton{
|
||||
mouseButtonPrimary: glfw.MouseButton1,
|
||||
mouseButtonSecondary: glfw.MouseButton2,
|
||||
mouseButtonTertiary: glfw.MouseButton3,
|
||||
}
|
||||
|
||||
// MouseButtonCallback is the callback called when the mouse button changes.
|
||||
func MouseButtonCallback(button glfw.MouseButton, action glfw.Action) {
|
||||
if index, known := glfwButtonIndexByID[button]; known && (action == glfw.Press) {
|
||||
mouseJustPressed[index] = true
|
||||
}
|
||||
}
|
||||
|
||||
// MouseScrollCallback is called when scroll status changes.
|
||||
func MouseScrollCallback(x, y float64) {
|
||||
io.AddMouseWheelDelta(float32(x), float32(y))
|
||||
}
|
||||
|
||||
// KeyCallback is called when a key is pressed or released.
|
||||
func KeyCallback(key glfw.Key, action glfw.Action) {
|
||||
if action == glfw.Press {
|
||||
io.KeyPress(int(key))
|
||||
}
|
||||
if action == glfw.Release {
|
||||
io.KeyRelease(int(key))
|
||||
}
|
||||
io.KeyCtrl(int(glfw.KeyLeftControl), int(glfw.KeyRightControl))
|
||||
io.KeyShift(int(glfw.KeyLeftShift), int(glfw.KeyRightShift))
|
||||
io.KeyAlt(int(glfw.KeyLeftAlt), int(glfw.KeyRightAlt))
|
||||
io.KeySuper(int(glfw.KeyLeftSuper), int(glfw.KeyRightSuper))
|
||||
}
|
||||
|
||||
// InputCallback is called when a char is inputed (CharChange)
|
||||
func InputCallback(input rune) {
|
||||
io.AddInputCharacters(string(input))
|
||||
}
|
24
internal/igwrap/backend/glyph_ranges.go
Normal file
24
internal/igwrap/backend/glyph_ranges.go
Normal file
@ -0,0 +1,24 @@
|
||||
package backend
|
||||
|
||||
import "github.com/inkyblackness/imgui-go/v4"
|
||||
|
||||
var glyphRanges imgui.AllocatedGlyphRanges
|
||||
|
||||
// GlyphRanges returns a custom-built glyph ranges set.
|
||||
//
|
||||
// The ImGUI context must be already initialized.
|
||||
func GlyphRanges() imgui.GlyphRanges {
|
||||
if glyphRanges.GlyphRanges == 0 {
|
||||
b := &imgui.GlyphRangesBuilder{}
|
||||
|
||||
b.AddExisting(imgui.CurrentIO().Fonts().GlyphRangesChineseFull())
|
||||
|
||||
// Greek
|
||||
b.Add(0x0391, 0x03A1)
|
||||
b.Add(0x03A3, 0x03FF)
|
||||
|
||||
glyphRanges = b.Build()
|
||||
}
|
||||
|
||||
return glyphRanges.GlyphRanges
|
||||
}
|
251
internal/igwrap/backend/render.go
Normal file
251
internal/igwrap/backend/render.go
Normal file
@ -0,0 +1,251 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
|
||||
"edgaru089.ml/go/gl01/internal/igwrap"
|
||||
"edgaru089.ml/go/gl01/internal/render"
|
||||
"github.com/go-gl/gl/all-core/gl"
|
||||
"github.com/go-gl/glfw/v3.3/glfw"
|
||||
"github.com/go-gl/mathgl/mgl32"
|
||||
"github.com/inkyblackness/imgui-go/v4"
|
||||
)
|
||||
|
||||
//go:embed shader.vert
|
||||
var vertex string
|
||||
|
||||
//go:embed shader.frag
|
||||
var fragment string
|
||||
|
||||
var (
|
||||
shader *render.Shader
|
||||
texture *render.Texture
|
||||
|
||||
vbo, elem uint32
|
||||
attribPosition, attribUV, attribColor uint32
|
||||
)
|
||||
|
||||
func renderInit() {
|
||||
// Backup GL state
|
||||
var lastTexture int32
|
||||
var lastArrayBuffer int32
|
||||
var lastVertexArray int32
|
||||
gl.GetIntegerv(gl.TEXTURE_BINDING_2D, &lastTexture)
|
||||
gl.GetIntegerv(gl.ARRAY_BUFFER_BINDING, &lastArrayBuffer)
|
||||
gl.GetIntegerv(gl.VERTEX_ARRAY_BINDING, &lastVertexArray)
|
||||
|
||||
var err error
|
||||
shader, err = render.NewShader(vertex, fragment)
|
||||
if err != nil {
|
||||
panic("igwrap.renderInit(): " + err.Error())
|
||||
}
|
||||
|
||||
gl.BindFragDataLocation(shader.Handle(), 0, gl.Str("outputColor\x00"))
|
||||
|
||||
gl.GenBuffers(1, &vbo)
|
||||
gl.GenBuffers(1, &elem)
|
||||
|
||||
CreateFontsTexture()
|
||||
shader.SetUniformTexture("tex", texture)
|
||||
|
||||
attribPosition = uint32(gl.GetAttribLocation(shader.Handle(), gl.Str("pos\x00")))
|
||||
attribUV = uint32(gl.GetAttribLocation(shader.Handle(), gl.Str("uv\x00")))
|
||||
attribColor = uint32(gl.GetAttribLocation(shader.Handle(), gl.Str("color\x00")))
|
||||
|
||||
// Restore modified GL state
|
||||
gl.BindTexture(gl.TEXTURE_2D, uint32(lastTexture))
|
||||
gl.BindBuffer(gl.ARRAY_BUFFER, uint32(lastArrayBuffer))
|
||||
gl.BindVertexArray(uint32(lastVertexArray))
|
||||
}
|
||||
|
||||
func CreateFontsTexture() {
|
||||
|
||||
// build the texture atlas
|
||||
io := imgui.CurrentIO()
|
||||
image := io.Fonts().TextureDataAlpha8()
|
||||
|
||||
var lastTexture int32
|
||||
gl.GetIntegerv(gl.TEXTURE_BINDING_2D, &lastTexture)
|
||||
|
||||
if texture != nil {
|
||||
texture.Free()
|
||||
}
|
||||
texture = render.NewTexture()
|
||||
tex := texture.Handle()
|
||||
|
||||
gl.BindTexture(gl.TEXTURE_2D, tex)
|
||||
gl.TexImage2D(
|
||||
gl.TEXTURE_2D,
|
||||
0,
|
||||
gl.RED,
|
||||
int32(image.Width),
|
||||
int32(image.Height),
|
||||
0,
|
||||
gl.RED,
|
||||
gl.UNSIGNED_BYTE,
|
||||
image.Pixels,
|
||||
)
|
||||
|
||||
io.Fonts().SetTextureID(imgui.TextureID(tex))
|
||||
igwrap.SetTextureFlag(tex, igwrap.TextureFlag_Red)
|
||||
|
||||
gl.BindTexture(gl.TEXTURE_2D, uint32(lastTexture))
|
||||
}
|
||||
|
||||
func Render(win *glfw.Window) {
|
||||
displayWidth, displayHeight := win.GetSize()
|
||||
fbWidth, fbHeight := win.GetFramebufferSize()
|
||||
|
||||
imgui.Render()
|
||||
draw := imgui.RenderedDrawData()
|
||||
|
||||
draw.ScaleClipRects(imgui.Vec2{
|
||||
X: float32(fbWidth) / float32(displayWidth),
|
||||
Y: float32(fbHeight) / float32(displayHeight),
|
||||
})
|
||||
|
||||
// Backup GL state
|
||||
var lastActiveTexture int32
|
||||
gl.GetIntegerv(gl.ACTIVE_TEXTURE, &lastActiveTexture)
|
||||
gl.ActiveTexture(gl.TEXTURE0)
|
||||
var lastProgram int32
|
||||
gl.GetIntegerv(gl.CURRENT_PROGRAM, &lastProgram)
|
||||
var lastTexture int32
|
||||
gl.GetIntegerv(gl.TEXTURE_BINDING_2D, &lastTexture)
|
||||
var lastSampler int32
|
||||
gl.GetIntegerv(gl.SAMPLER_BINDING, &lastSampler)
|
||||
var lastArrayBuffer int32
|
||||
gl.GetIntegerv(gl.ARRAY_BUFFER_BINDING, &lastArrayBuffer)
|
||||
var lastElementArrayBuffer int32
|
||||
gl.GetIntegerv(gl.ELEMENT_ARRAY_BUFFER_BINDING, &lastElementArrayBuffer)
|
||||
var lastVertexArray int32
|
||||
gl.GetIntegerv(gl.VERTEX_ARRAY_BINDING, &lastVertexArray)
|
||||
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])
|
||||
var lastBlendSrcRgb int32
|
||||
gl.GetIntegerv(gl.BLEND_SRC_RGB, &lastBlendSrcRgb)
|
||||
var lastBlendDstRgb int32
|
||||
gl.GetIntegerv(gl.BLEND_DST_RGB, &lastBlendDstRgb)
|
||||
var lastBlendSrcAlpha int32
|
||||
gl.GetIntegerv(gl.BLEND_SRC_ALPHA, &lastBlendSrcAlpha)
|
||||
var lastBlendDstAlpha int32
|
||||
gl.GetIntegerv(gl.BLEND_DST_ALPHA, &lastBlendDstAlpha)
|
||||
var lastBlendEquationRgb int32
|
||||
gl.GetIntegerv(gl.BLEND_EQUATION_RGB, &lastBlendEquationRgb)
|
||||
var lastBlendEquationAlpha int32
|
||||
gl.GetIntegerv(gl.BLEND_EQUATION_ALPHA, &lastBlendEquationAlpha)
|
||||
lastEnableBlend := gl.IsEnabled(gl.BLEND)
|
||||
lastEnableCullFace := gl.IsEnabled(gl.CULL_FACE)
|
||||
lastEnableDepthTest := gl.IsEnabled(gl.DEPTH_TEST)
|
||||
lastEnableScissorTest := gl.IsEnabled(gl.SCISSOR_TEST)
|
||||
|
||||
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
|
||||
gl.Enable(gl.BLEND)
|
||||
gl.BlendEquation(gl.FUNC_ADD)
|
||||
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
|
||||
gl.Disable(gl.CULL_FACE)
|
||||
gl.Disable(gl.DEPTH_TEST)
|
||||
gl.Enable(gl.SCISSOR_TEST)
|
||||
gl.PolygonMode(gl.FRONT_AND_BACK, gl.FILL)
|
||||
|
||||
// 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(fbWidth), int32(fbHeight))
|
||||
orthoProjection := mgl32.Mat4{
|
||||
2.0 / float32(displayWidth), 0.0, 0.0, 0.0,
|
||||
0.0, 2.0 / float32(-displayHeight), 0.0, 0.0,
|
||||
0.0, 0.0, -1.0, 0.0,
|
||||
-1.0, 1.0, 0.0, 1.0,
|
||||
}
|
||||
shader.BindTextures()
|
||||
shader.UseProgram()
|
||||
shader.SetUniformMat4("projection", orthoProjection)
|
||||
gl.BindSampler(0, 0) // Rely on combined texture/sampler state.
|
||||
|
||||
// Recreate the VAO every time
|
||||
// (This is to easily allow multiple GL contexts. VAO are not shared among GL contexts, and
|
||||
// we don't track creation/deletion of windows so we don't have an obvious key to use to cache them.)
|
||||
var vao uint32
|
||||
gl.GenVertexArrays(1, &vao)
|
||||
gl.BindVertexArray(vao)
|
||||
gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
|
||||
gl.EnableVertexAttribArray(uint32(attribPosition))
|
||||
gl.EnableVertexAttribArray(uint32(attribUV))
|
||||
gl.EnableVertexAttribArray(uint32(attribColor))
|
||||
vertexSize, vertexOffsetPos, vertexOffsetUv, vertexOffsetCol := imgui.VertexBufferLayout()
|
||||
gl.VertexAttribPointerWithOffset(uint32(attribPosition), 2, gl.FLOAT, false, int32(vertexSize), uintptr(vertexOffsetPos))
|
||||
gl.VertexAttribPointerWithOffset(uint32(attribUV), 2, gl.FLOAT, false, int32(vertexSize), uintptr(vertexOffsetUv))
|
||||
gl.VertexAttribPointerWithOffset(uint32(attribColor), 4, gl.UNSIGNED_BYTE, true, int32(vertexSize), uintptr(vertexOffsetCol))
|
||||
indexSize := imgui.IndexBufferLayout()
|
||||
drawType := gl.UNSIGNED_SHORT
|
||||
const bytesPerUint32 = 4
|
||||
if indexSize == bytesPerUint32 {
|
||||
drawType = gl.UNSIGNED_INT
|
||||
}
|
||||
|
||||
// Draw
|
||||
for _, list := range draw.CommandLists() {
|
||||
var indexBufferOffset uintptr
|
||||
|
||||
vertexBuffer, vertexBufferSize := list.VertexBuffer()
|
||||
gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
|
||||
gl.BufferData(gl.ARRAY_BUFFER, vertexBufferSize, vertexBuffer, gl.STREAM_DRAW)
|
||||
|
||||
indexBuffer, indexBufferSize := list.IndexBuffer()
|
||||
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, elem)
|
||||
gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, indexBufferSize, indexBuffer, gl.STREAM_DRAW)
|
||||
|
||||
for _, cmd := range list.Commands() {
|
||||
if cmd.HasUserCallback() {
|
||||
cmd.CallUserCallback(list)
|
||||
} else {
|
||||
shader.SetUniformInt("flags", int32(igwrap.GetTextureFlag(uint32(cmd.TextureID()))))
|
||||
gl.BindTexture(gl.TEXTURE_2D, uint32(cmd.TextureID()))
|
||||
clipRect := cmd.ClipRect()
|
||||
gl.Scissor(int32(clipRect.X), int32(fbHeight)-int32(clipRect.W), int32(clipRect.Z-clipRect.X), int32(clipRect.W-clipRect.Y))
|
||||
gl.DrawElementsWithOffset(gl.TRIANGLES, int32(cmd.ElementCount()), uint32(drawType), indexBufferOffset)
|
||||
}
|
||||
indexBufferOffset += uintptr(cmd.ElementCount() * indexSize)
|
||||
}
|
||||
}
|
||||
gl.DeleteVertexArrays(1, &vao)
|
||||
|
||||
// Restore modified GL state
|
||||
gl.UseProgram(uint32(lastProgram))
|
||||
gl.BindTexture(gl.TEXTURE_2D, uint32(lastTexture))
|
||||
gl.BindSampler(0, uint32(lastSampler))
|
||||
gl.ActiveTexture(uint32(lastActiveTexture))
|
||||
gl.BindVertexArray(uint32(lastVertexArray))
|
||||
gl.BindBuffer(gl.ARRAY_BUFFER, uint32(lastArrayBuffer))
|
||||
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, uint32(lastElementArrayBuffer))
|
||||
gl.BlendEquationSeparate(uint32(lastBlendEquationRgb), uint32(lastBlendEquationAlpha))
|
||||
gl.BlendFuncSeparate(uint32(lastBlendSrcRgb), uint32(lastBlendDstRgb), uint32(lastBlendSrcAlpha), uint32(lastBlendDstAlpha))
|
||||
if lastEnableBlend {
|
||||
gl.Enable(gl.BLEND)
|
||||
} else {
|
||||
gl.Disable(gl.BLEND)
|
||||
}
|
||||
if lastEnableCullFace {
|
||||
gl.Enable(gl.CULL_FACE)
|
||||
} else {
|
||||
gl.Disable(gl.CULL_FACE)
|
||||
}
|
||||
if lastEnableDepthTest {
|
||||
gl.Enable(gl.DEPTH_TEST)
|
||||
} else {
|
||||
gl.Disable(gl.DEPTH_TEST)
|
||||
}
|
||||
if lastEnableScissorTest {
|
||||
gl.Enable(gl.SCISSOR_TEST)
|
||||
} else {
|
||||
gl.Disable(gl.SCISSOR_TEST)
|
||||
}
|
||||
gl.PolygonMode(gl.FRONT_AND_BACK, uint32(lastPolygonMode[0]))
|
||||
gl.Viewport(lastViewport[0], lastViewport[1], lastViewport[2], lastViewport[3])
|
||||
gl.Scissor(lastScissorBox[0], lastScissorBox[1], lastScissorBox[2], lastScissorBox[3])
|
||||
}
|
33
internal/igwrap/backend/shader.frag
Normal file
33
internal/igwrap/backend/shader.frag
Normal file
@ -0,0 +1,33 @@
|
||||
#version 330
|
||||
|
||||
#define FLAG_RED (1<<0)
|
||||
#define FLAG_GREEN (1<<1)
|
||||
#define FLAG_BLUE (1<<2)
|
||||
#define FLAG_ALPHA (1<<3)
|
||||
#define FLAG_COLORS (FLAG_RED | FLAG_GREEN | FLAG_BLUE | FLAG_ALPHA)
|
||||
|
||||
#define FLAG_LINEAR (1<<4)
|
||||
|
||||
uniform sampler2D tex;
|
||||
uniform int flags;
|
||||
|
||||
in vec2 fragUV;
|
||||
in vec4 fragColor;
|
||||
|
||||
out vec4 outputColor;
|
||||
|
||||
const float gamma = 2.2;
|
||||
|
||||
void main() {
|
||||
if ((flags & FLAG_COLORS) == FLAG_RED) {
|
||||
outputColor = vec4(fragColor.rgb, fragColor.a * texture(tex, fragUV.st).r);
|
||||
} else {
|
||||
vec4 color = texture(tex, fragUV.st);
|
||||
if ((flags & FLAG_LINEAR) != 0)
|
||||
color.rgb = pow(color.rgb, vec3(1.0/gamma));
|
||||
outputColor = color * fragColor;
|
||||
if ((flags & FLAG_ALPHA) == 0)
|
||||
outputColor.a = 1;
|
||||
}
|
||||
}
|
||||
|
17
internal/igwrap/backend/shader.vert
Normal file
17
internal/igwrap/backend/shader.vert
Normal file
@ -0,0 +1,17 @@
|
||||
#version 330
|
||||
|
||||
uniform mat4 projection;
|
||||
|
||||
in vec2 pos;
|
||||
in vec2 uv;
|
||||
in vec4 color;
|
||||
|
||||
out vec2 fragUV;
|
||||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
fragUV = uv;
|
||||
fragColor = color;
|
||||
gl_Position = projection * vec4(pos.xy, 0, 1);
|
||||
}
|
||||
|
Reference in New Issue
Block a user