diff --git a/internal/game/imgui.go b/internal/game/imgui.go index 1bcae21..7ceb1c6 100644 --- a/internal/game/imgui.go +++ b/internal/game/imgui.go @@ -1,7 +1,6 @@ package game import ( - "fmt" "log" "math" "os" @@ -9,6 +8,8 @@ import ( "edgaru089.ml/go/gl01/internal/asset" "edgaru089.ml/go/gl01/internal/igwrap" + "edgaru089.ml/go/gl01/internal/igwrap/backend" + "edgaru089.ml/go/gl01/internal/io" "edgaru089.ml/go/gl01/internal/util/itype" "edgaru089.ml/go/gl01/internal/world" "github.com/go-gl/glfw/v3.3/glfw" @@ -19,6 +20,8 @@ type guiState struct { showLog, showDebugInfo bool logFollow bool + lastframeCgoCalls int64 + loadChunkFile string loadChunkID [2]int32 @@ -35,7 +38,7 @@ func (g *Game) initImgui(win *glfw.Window) { cfg.SetOversampleV(1) cfg.SetPixelSnapH(true) g.io.Fonts().AddFontFromMemoryTTFV(asset.Unifont, 16, cfg, g.io.Fonts().GlyphRangesChineseFull()) - igwrap.Init(win) + backend.Init(win) g.gui = guiState{ showLog: true, @@ -49,6 +52,19 @@ func (g *Game) initImgui(win *glfw.Window) { } func (g *Game) imgui() { + if io.ShowDebugInfo { + imgui.SetNextWindowPosV(imgui.Vec2{}, imgui.ConditionAlways, imgui.Vec2{}) + if igwrap.Begin("F3", nil, imgui.WindowFlagsAlwaysAutoResize|imgui.WindowFlagsNoBackground|imgui.WindowFlagsNoNavFocus|imgui.WindowFlagsNoDecoration|imgui.WindowFlagsNoInputs|imgui.WindowFlagsNoSavedSettings|imgui.WindowFlagsNoFocusOnAppearing) { + igwrap.Text("Gl01(glfw%s, imgui%s) - compiled by %s[%s/%s]", glfw.GetVersionString(), imgui.Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH) + igwrap.Text("CgoCalls:%d (%d lastframe), Goroutines:%d", runtime.NumCgoCall(), runtime.NumCgoCall()-g.gui.lastframeCgoCalls, runtime.NumGoroutine()) + imgui.Text("") + + pos := g.player.Position() + igwrap.Text("Player: (%.3f, %.5f, %.3f) - (Y%.2f, Z%.2f)", pos[0], pos[1], pos[2], g.rotY.Degrees(), g.rotZ) + imgui.End() + } + } + g.gui.lastframeCgoCalls = runtime.NumCgoCall() if imgui.BeginV("Player", nil, imgui.WindowFlagsAlwaysAutoResize) { pos := g.player.Position() @@ -58,17 +74,6 @@ func (g *Game) imgui() { } imgui.End() - if imgui.BeginV("Go Runtime", nil, imgui.WindowFlagsAlwaysAutoResize) { - imgui.Text(fmt.Sprintf("%s/%s, compiler: %s", runtime.GOOS, runtime.GOARCH, runtime.Compiler)) - imgui.Text(fmt.Sprintf("NumCPU=%d, NumGOMAXPROCS=%d", runtime.NumCPU(), runtime.GOMAXPROCS(0))) - imgui.Text(fmt.Sprintf("NumCgoCalls=%d, NumGoroutine=%d", runtime.NumCgoCall(), runtime.NumGoroutine())) - imgui.Spacing() - if imgui.ButtonV("!!! PANIC !!!", imgui.Vec2{X: -2, Y: 0}) { - panic("Manual Panic") - } - } - imgui.End() - if igwrap.Begin("Logs", &g.gui.showLog, imgui.WindowFlagsMenuBar) { if imgui.BeginMenuBar() { if imgui.Button("Clear") { diff --git a/internal/game/logic.go b/internal/game/logic.go index fe600d0..4059ada 100644 --- a/internal/game/logic.go +++ b/internal/game/logic.go @@ -6,7 +6,7 @@ import ( "os" "time" - "edgaru089.ml/go/gl01/internal/igwrap" + "edgaru089.ml/go/gl01/internal/igwrap/backend" "edgaru089.ml/go/gl01/internal/io" "edgaru089.ml/go/gl01/internal/render" "edgaru089.ml/go/gl01/internal/util/itype" @@ -105,13 +105,13 @@ func (g *Game) Init(win *glfw.Window) { win.SetMouseButtonCallback(func(w *glfw.Window, button glfw.MouseButton, action glfw.Action, mods glfw.ModifierKey) { if g.paused { - igwrap.MouseButtonCallback(button, action) + backend.MouseButtonCallback(button, action) } }) win.SetKeyCallback(func(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) { if g.paused { - igwrap.KeyCallback(key, action) + backend.KeyCallback(key, action) } if action == glfw.Press { if g.paused { @@ -157,13 +157,13 @@ func (g *Game) Init(win *glfw.Window) { win.SetCharCallback(func(w *glfw.Window, char rune) { if g.paused { - igwrap.InputCallback(char) + backend.InputCallback(char) } }) win.SetScrollCallback(func(w *glfw.Window, xpos, ypos float64) { if g.paused { - igwrap.MouseScrollCallback(xpos, ypos) + backend.MouseScrollCallback(xpos, ypos) } }) @@ -173,7 +173,7 @@ const airAccel = 0.1 // Update updates the game state, not necessarily in the main thread. func (g *Game) Update(win *glfw.Window, delta time.Duration) { - igwrap.NewFrame() + backend.NewFrame() imgui.ShowDemoWindow(nil) if !g.paused { @@ -251,5 +251,5 @@ func (g *Game) Render(win *glfw.Window) { g.worldrender.Render(g.world, g.view) render.Framewire.Render(g.view) - igwrap.Render(win) + backend.Render(win) } diff --git a/internal/igwrap/glfw.go b/internal/igwrap/backend/glfw.go similarity index 99% rename from internal/igwrap/glfw.go rename to internal/igwrap/backend/glfw.go index e843d86..d5887cb 100644 --- a/internal/igwrap/glfw.go +++ b/internal/igwrap/backend/glfw.go @@ -1,4 +1,4 @@ -package igwrap +package backend import ( "time" diff --git a/internal/igwrap/glyph_ranges.go b/internal/igwrap/backend/glyph_ranges.go similarity index 96% rename from internal/igwrap/glyph_ranges.go rename to internal/igwrap/backend/glyph_ranges.go index 0a6438d..0d7f706 100644 --- a/internal/igwrap/glyph_ranges.go +++ b/internal/igwrap/backend/glyph_ranges.go @@ -1,4 +1,4 @@ -package igwrap +package backend import "github.com/inkyblackness/imgui-go/v4" diff --git a/internal/igwrap/render.go b/internal/igwrap/backend/render.go similarity index 97% rename from internal/igwrap/render.go rename to internal/igwrap/backend/render.go index f59c7e9..32cc476 100644 --- a/internal/igwrap/render.go +++ b/internal/igwrap/backend/render.go @@ -1,8 +1,9 @@ -package igwrap +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" @@ -86,6 +87,7 @@ func CreateFontsTexture() { ) io.Fonts().SetTextureID(imgui.TextureID(tex)) + igwrap.SetTextureFlag(tex, igwrap.TextureFlag_Red) gl.BindTexture(gl.TEXTURE_2D, uint32(lastTexture)) } @@ -202,6 +204,7 @@ func Render(win *glfw.Window) { 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)) diff --git a/internal/igwrap/backend/shader.frag b/internal/igwrap/backend/shader.frag new file mode 100644 index 0000000..12adf13 --- /dev/null +++ b/internal/igwrap/backend/shader.frag @@ -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; + } +} + diff --git a/internal/igwrap/shader.vert b/internal/igwrap/backend/shader.vert similarity index 100% rename from internal/igwrap/shader.vert rename to internal/igwrap/backend/shader.vert diff --git a/internal/igwrap/color.go b/internal/igwrap/color.go deleted file mode 100644 index 13b433b..0000000 --- a/internal/igwrap/color.go +++ /dev/null @@ -1,13 +0,0 @@ -package igwrap - -import "github.com/inkyblackness/imgui-go/v4" - -// Color converts non-premultiplied RGBA color into imgui.Vec4. -func Color(r, g, b, a uint8) imgui.Vec4 { - return imgui.Vec4{ - X: float32(r) / 255, - Y: float32(g) / 255, - Z: float32(b) / 255, - W: float32(a) / 255, - } -} diff --git a/internal/igwrap/convert.go b/internal/igwrap/convert.go new file mode 100644 index 0000000..9bc6725 --- /dev/null +++ b/internal/igwrap/convert.go @@ -0,0 +1,26 @@ +package igwrap + +import ( + "edgaru089.ml/go/gl01/internal/util/itype" + "github.com/inkyblackness/imgui-go/v4" +) + +// Color converts non-premultiplied RGBA color into imgui.Vec4. +func Color(r, g, b, a uint8) imgui.Vec4 { + return imgui.Vec4{ + X: float32(r) / 255, + Y: float32(g) / 255, + Z: float32(b) / 255, + W: float32(a) / 255, + } +} + +// Vec2 converts itype.Vec2f to imgui.Vec2. +func Vec2(v itype.Vec2f) imgui.Vec2 { + return imgui.Vec2{X: v[0], Y: v[1]} +} + +// Vec4 converts itype.Vec4f to imgui.Vec4. +func Vec4(v itype.Vec4f) imgui.Vec4 { + return imgui.Vec4{X: v[0], Y: v[1], Z: v[2], W: v[3]} +} diff --git a/internal/igwrap/imagewrap.go b/internal/igwrap/imagewrap.go new file mode 100644 index 0000000..3a4708b --- /dev/null +++ b/internal/igwrap/imagewrap.go @@ -0,0 +1,77 @@ +package igwrap + +import ( + "sync" + + "edgaru089.ml/go/gl01/internal/util/itype" + "github.com/inkyblackness/imgui-go/v4" +) + +// Image creates a ImGUI image based on the given texture. +// For *render.Texture, use tex.Handle(). +// +// size is in pixels. texRange is in [0, 1]. +func Image(tex uint32, size itype.Vec2f, texRange itype.Rectf) { + min, max := texRange.MinPoint(), texRange.MaxPoint() + imgui.ImageV( + imgui.TextureID(tex), + Vec2(size), + imgui.Vec2{X: min[0], Y: max[1]}, + imgui.Vec2{X: max[0], Y: min[1]}, + Color(255, 255, 255, 255), + imgui.Vec4{}, + ) +} + +// ImageV creates a ImGUI image based on the given texture. +// For *render.Texture, use tex.Handle(). +// +// size is in pixels. texRange is in [0, 1]. +func ImageV(tex uint32, size itype.Vec2f, texRange itype.Rectf, texColor itype.Vec4f, borderColor itype.Vec4f) { + imgui.ImageV( + imgui.TextureID(tex), + Vec2(size), + Vec2(texRange.MinPoint()), + Vec2(texRange.MaxPoint()), + Vec4(texColor), + Vec4(borderColor), + ) +} + +type TextureFlag int + +const ( + TextureFlag_Red TextureFlag = 1 << iota // Renders the Red channel. + TextureFlag_Green // Renders the Green channel. + TextureFlag_Blue // Renders the Blue channel. + TextureFlag_Alpha // Renders the Alpha channel. + + TextureFlag_Linear // Linear source data, requires gamma correction. + + TextureFlag_RGB = TextureFlag_Red | TextureFlag_Green | TextureFlag_Blue + TextureFlag_RGBA = TextureFlag_Red | TextureFlag_Green | TextureFlag_Blue | TextureFlag_Alpha +) + +var ( + texflags map[uint32]TextureFlag = make(map[uint32]TextureFlag) + texflagslock sync.RWMutex +) + +// SetTextureFlag changes the flag of a texture to the given flags combined. +func SetTextureFlag(tex uint32, flags ...TextureFlag) { + var f TextureFlag + for _, f0 := range flags { + f |= f0 + } + + texflagslock.Lock() + defer texflagslock.Unlock() + texflags[tex] = f +} + +// TextureFlag returns the flags of a given texture. +func GetTextureFlag(tex uint32) TextureFlag { + texflagslock.RLock() + defer texflagslock.RUnlock() + return texflags[tex] +} diff --git a/internal/igwrap/shader.frag b/internal/igwrap/shader.frag deleted file mode 100644 index 7500784..0000000 --- a/internal/igwrap/shader.frag +++ /dev/null @@ -1,13 +0,0 @@ -#version 330 - -uniform sampler2D tex; - -in vec2 fragUV; -in vec4 fragColor; - -out vec4 outputColor; - -void main() { - outputColor = vec4(fragColor.rgb, fragColor.a * texture(tex, fragUV.st).r); -} - diff --git a/internal/igwrap/wrap.go b/internal/igwrap/wrap.go index 24a4286..bbfc152 100644 --- a/internal/igwrap/wrap.go +++ b/internal/igwrap/wrap.go @@ -28,7 +28,7 @@ func Text(format string, a ...interface{}) { // returns true. func Begin(id string, open *bool, flags imgui.WindowFlags) bool { // skip if the window is not open - if !(*open) { + if open != nil && !(*open) { return false } diff --git a/internal/util/itype/vec.go b/internal/util/itype/vec.go index d108b4f..44f5a5d 100644 --- a/internal/util/itype/vec.go +++ b/internal/util/itype/vec.go @@ -61,6 +61,10 @@ func (v Vec2f) Addv(x, y float32) Vec2f { return Vec2f{v[0] + x, v[1] + y} } +func (v Vec2f) Multiply(x float32) Vec2f { + return Vec2f{v[0] * x, v[1] * x} +} + func (v Vec2f) Floor() Vec2i { return Vec2i{ int(math.Floor(float64(v[0]))),