diff --git a/internal/game/imgui.go b/internal/game/imgui.go index f8c2cb5..5e217e7 100644 --- a/internal/game/imgui.go +++ b/internal/game/imgui.go @@ -55,17 +55,14 @@ func (g *Game) imgui() { if io.ShowDebugInfo { imgui.SetNextWindowPosV(imgui.Vec2{}, imgui.ConditionAlways, imgui.Vec2{}) imgui.SetNextWindowSize(imgui.Vec2{X: float32(io.DisplaySize[0]), Y: float32(io.DisplaySize[1])}) - if igwrap.Begin("F3", nil, imgui.WindowFlagsAlwaysAutoResize|imgui.WindowFlagsNoBackground|imgui.WindowFlagsNoNavFocus|imgui.WindowFlagsNoDecoration|imgui.WindowFlagsNoInputs|imgui.WindowFlagsNoSavedSettings|imgui.WindowFlagsNoFocusOnAppearing) { - bg := itype.Vec4f{0, 0, 0, 0.5} - pad := igwrap.Vec2f(imgui.CurrentStyle().ItemSpacing()) - - igwrap.TextBackground(bg, pad, "Gl01 compiled by %s/%s [%s/%s] (120AVG) %.1f FPS (%.3f frame)", runtime.Compiler, runtime.Version(), runtime.GOOS, runtime.GOARCH, imgui.CurrentIO().Framerate(), 1000/imgui.CurrentIO().Framerate()) - igwrap.TextBackground(bg, pad, "GLFW %s, Dear ImGUI %s", glfw.GetVersionString(), imgui.Version()) - igwrap.TextBackground(bg, pad, "CgoCalls:%d (%d lastframe), Goroutines:%d", runtime.NumCgoCall(), runtime.NumCgoCall()-g.gui.lastframeCgoCalls, runtime.NumGoroutine()) - imgui.Dummy(imgui.Vec2{X: 8, Y: 8}) + if igwrap.Begin("F3", nil, igwrap.WindowFlagsOverlay) { + igwrap.TextBackground("Gl01 compiled by %s/%s [%s/%s] (120AVG) %.1f FPS (%.3f frame)", runtime.Compiler, runtime.Version(), runtime.GOOS, runtime.GOARCH, imgui.CurrentIO().Framerate(), 1000/imgui.CurrentIO().Framerate()) + igwrap.TextBackground("GLFW %s, Dear ImGUI %s", glfw.GetVersionString(), imgui.Version()) + igwrap.TextBackground("CgoCalls:%d (%d lastframe), Goroutines:%d", runtime.NumCgoCall(), runtime.NumCgoCall()-g.gui.lastframeCgoCalls, runtime.NumGoroutine()) + igwrap.TextBlank() pos := g.player.Position() - igwrap.TextBackground(bg, pad, "Player: (%.3f, %.5f, %.3f) (Y%.2f, Z%.2f)", pos[0], pos[1], pos[2], g.rotY.Degrees(), g.rotZ) + igwrap.TextBackground("Player: (%.3f, %.5f, %.3f) (Y%.2f, Z%.2f)", pos[0], pos[1], pos[2], g.rotY.Degrees(), g.rotZ) imgui.End() } } diff --git a/internal/igwrap/backend/shader.frag b/internal/igwrap/backend/shader.frag index cb8fc96..ab59f4e 100644 --- a/internal/igwrap/backend/shader.frag +++ b/internal/igwrap/backend/shader.frag @@ -8,6 +8,7 @@ #define FLAG_LINEAR (1<<4) #define FLAG_IMGUI_FONT (1<<5) +#define FLAG_FLIP_Y (1<<6) uniform sampler2D tex; uniform int flags; diff --git a/internal/igwrap/backend/shader.vert b/internal/igwrap/backend/shader.vert index a230d00..1aac6df 100644 --- a/internal/igwrap/backend/shader.vert +++ b/internal/igwrap/backend/shader.vert @@ -1,6 +1,17 @@ #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) +#define FLAG_IMGUI_FONT (1<<5) +#define FLAG_FLIP_Y (1<<6) + uniform mat4 projection; +uniform int flags; in vec2 pos; in vec2 uv; @@ -13,5 +24,8 @@ void main() { fragUV = uv; fragColor = color; gl_Position = projection * vec4(pos.xy, 0, 1); + + if ((flags & FLAG_FLIP_Y) != 0) + fragUV.y = 1 - fragUV.y; } diff --git a/internal/igwrap/imagewrap.go b/internal/igwrap/imagewrap.go index 56ebca4..9aa1a85 100644 --- a/internal/igwrap/imagewrap.go +++ b/internal/igwrap/imagewrap.go @@ -38,6 +38,7 @@ func ImageV(tex uint32, size itype.Vec2f, texRange itype.Rectf, texColor itype.V ) } +// Per-texture flags. This is passed to the shader as-is and handled only there. type TextureFlag int const ( @@ -48,6 +49,7 @@ const ( TextureFlag_Linear // Linear source data, requires gamma correction. TextureFlag_ImGUIFont // This is a font texture from ImGUI, with a single red channel. + TextureFlag_FlipY // The render should flip the Y axis of the texture. By default ImageXXX()s render textures with (0,0) at the bottom left, and this is for in case you want to flip them. TextureFlag_RGB = TextureFlag_Red | TextureFlag_Green | TextureFlag_Blue TextureFlag_RGBA = TextureFlag_Red | TextureFlag_Green | TextureFlag_Blue | TextureFlag_Alpha @@ -70,6 +72,18 @@ func SetTextureFlag(tex uint32, flags ...TextureFlag) { texflags[tex] = f } +// AddTextureFlag adds the given flags to the texture. +func AddTextureFlag(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() diff --git a/internal/igwrap/wrap.go b/internal/igwrap/wrap.go index 5fc713f..2f1e4a2 100644 --- a/internal/igwrap/wrap.go +++ b/internal/igwrap/wrap.go @@ -7,6 +7,10 @@ import ( "github.com/inkyblackness/imgui-go/v4" ) +const ( + WindowFlagsOverlay imgui.WindowFlags = imgui.WindowFlagsAlwaysAutoResize | imgui.WindowFlagsNoBackground | imgui.WindowFlagsNoNavFocus | imgui.WindowFlagsNoNavInputs | imgui.WindowFlagsNoDecoration | imgui.WindowFlagsNoBringToFrontOnFocus | imgui.WindowFlagsNoSavedSettings | imgui.WindowFlagsNoFocusOnAppearing +) + // MenuItem wraps imgui.MenuItemV to create a // easy-to-use and intuitive interface. func MenuItem(name, shortcut string, selected *bool, enabled bool) { @@ -21,11 +25,18 @@ func Text(format string, a ...interface{}) { imgui.Text(fmt.Sprintf(format, a...)) } -// TextBackground wraps imgui.Text to create a -// shortcut for fmt.Sprintf. +// TextBackground wraps imgui.Text to create a shortcut for fmt.Sprintf. +// +// It also fills the background of the text with half-transparant black, and takes care of the padding. +func TextBackground(format string, a ...interface{}) { + pad := Vec2f(imgui.CurrentStyle().ItemSpacing()) + TextBackgroundV(itype.Vec4f{0, 0, 0, 0.5}, pad, format, a...) +} + +// TextBackgroundV wraps imgui.Text to create a shortcut for fmt.Sprintf. // // It also fills the background of the text with the given color. -func TextBackground(color itype.Vec4f, padding itype.Vec2f, format string, a ...interface{}) { +func TextBackgroundV(color itype.Vec4f, padding itype.Vec2f, format string, a ...interface{}) { text := fmt.Sprintf(format, a...) orig := imgui.CursorScreenPos() size := imgui.CalcTextSize(text, false, 0) @@ -35,6 +46,12 @@ func TextBackground(color itype.Vec4f, padding itype.Vec2f, format string, a ... imgui.Text(text) } +// TextBlank blanks a line with a nice-looking height (half the font height plus paddings). +func TextBlank() { + fontSize := imgui.FontSize() + imgui.Dummy(imgui.Vec2{X: fontSize / 2, Y: fontSize / 2}) +} + // Begin wraps imgui.BeginV to create a // easy-to-use and intuitive interface. // diff --git a/internal/render/render_world.go b/internal/render/render_world.go index f2e6517..d07b6aa 100644 --- a/internal/render/render_world.go +++ b/internal/render/render_world.go @@ -2,6 +2,7 @@ package render import ( "errors" + "math" "math/rand" "time" "unsafe" @@ -132,6 +133,7 @@ func (r *WorldRenderer) Init(w *world.World) (err error) { gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAX_ANISOTROPY, maxaf) r.gbuffer.shader.SetUniformTexture("tex", r.texture) r.water.shader.SetUniformTexture("tex", r.texture) + igwrap.SetTextureFlag(r.texture.Handle(), igwrap.TextureFlag_RGBA, igwrap.TextureFlag_FlipY) r.depthmap.shader.SetUniformMat4("model", mgl32.Ident4()) r.gbuffer.shader.SetUniformMat4("model", mgl32.Ident4()) @@ -295,10 +297,11 @@ func (r *WorldRenderer) ResizeDisplay(newSize itype.Vec2i) { } var ( - sun = [3]float32{0.2, 0.4, 0.3} - alpha = float32(0.55) - gamma = float32(2.2) - exposure = float32(1) + sun = [3]float32{0.2, 0.4, 0.3} + alpha = float32(0.55) + gamma = float32(2.2) + exposure = float32(1) + atlasScale = float32(1) ) func (r *WorldRenderer) Render(world *world.World, view *View) { @@ -445,7 +448,7 @@ func (r *WorldRenderer) Render(world *world.World, view *View) { // Show G-buffers? if io.ShowDebugInfo { imgui.SetNextWindowPosV(imgui.Vec2{X: float32(r.lastDisplaySize[0]), Y: 0}, imgui.ConditionAlways, imgui.Vec2{X: 1, Y: 0}) - if igwrap.Begin("Renderer Textures/Outputs", nil, imgui.WindowFlagsAlwaysAutoResize|imgui.WindowFlagsNoBackground|imgui.WindowFlagsNoNavFocus|imgui.WindowFlagsNoDecoration|imgui.WindowFlagsNoInputs|imgui.WindowFlagsNoSavedSettings|imgui.WindowFlagsNoFocusOnAppearing) { + if igwrap.Begin("Renderer Textures/Outputs", nil, igwrap.WindowFlagsOverlay) { imgui.PushStyleVarVec2(imgui.StyleVarItemSpacing, imgui.Vec2{}) imageSize := r.lastDisplaySize.ToFloat32().Multiply(0.25) @@ -460,5 +463,28 @@ func (r *WorldRenderer) Render(world *world.World, view *View) { imgui.PopStyleVar() imgui.End() } + + if igwrap.Begin("F3", nil, 0) { + imgui.PushStyleColor(imgui.StyleColorButton, imgui.Vec4{0, 0, 0, 0.5}) + imgui.PushStyleColor(imgui.StyleColorButtonHovered, imgui.Vec4{0, 0, 0, 0.6}) + imgui.PushStyleColor(imgui.StyleColorButtonActive, imgui.Vec4{0, 0, 0, 0.8}) + igwrap.TextBlank() + isize := asset.WorldTextureAtlas.ImageSize + igwrap.TextBackground("Texture Atlas Size: (%dx%d)", isize[0], isize[1]) + imgui.SameLine() + igwrap.TextBackground("[Hover]") + if imgui.IsItemHoveredV(imgui.HoveredFlagsAllowWhenDisabled) { + _, wheely := imgui.CurrentIO().MouseWheel() + if math.Abs(float64(wheely)) > 1e-3 { + atlasScale = util.Maxf(1, atlasScale+wheely) + } + imgui.BeginTooltip() + igwrap.Image(r.texture.Handle(), isize.ToFloat32().Multiply(atlasScale), itype.Rectf{0, 0, 1, 1}) + imgui.EndTooltip() + } + + imgui.PopStyleColorV(3) + imgui.End() + } } }