Skip to content

Instantly share code, notes, and snippets.

@Omustardo
Last active September 24, 2024 08:33
Show Gist options
  • Save Omustardo/b15eedaacabdf4d6a6579f762a8a05a0 to your computer and use it in GitHub Desktop.
Save Omustardo/b15eedaacabdf4d6a6579f762a8a05a0 to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
imgui "github.com/AllenDang/cimgui-go"
"os"
"time"
"unsafe"
_ "embed"
)
// Embed the full ttf file contents within the golang binary at compile-time. This requires importing the `embed` package.
// Note that any TTF file will work. I got this one from https://fonts.google.com/specimen/Merriweather
// If you have a different way of loading a ttf (e.g. hard-coding the TTF bytes as a base64 string), this can be replaced.
//
//go:embed Merriweather-Regular.ttf
var defaultFontTTF []byte
const (
DefaultFontSize int32 = 20
MinFontSize int32 = 10
MaxFontSize int32 = 100
)
var (
selectedFontSize int32 = DefaultFontSize
// FontsBySize is populated by a single font, rendered from MinFontSize through MaxFontSize. This allows using
// different the font at different sizes without needing to scale them (i.e. `imgui.CurrentFont().SetScale(2)`).
// Scaling the font usually causes blurriness or other distortion. It's preferable to load the font at all
// of the sizes you plan to use, if you know those sizes in advance.
FontsBySize map[int]*imgui.Font
)
// InitFonts must be called in `backend.SetAfterCreateContextHook(hookFunc)`. Before rendering, imgui may not
// have a context. During the game loop, imgui doesn't allow loading fonts.
func InitFonts() {
fmt.Println("Loading fonts...")
start := time.Now()
FontsBySize = make(map[int]*imgui.Font)
for i := MinFontSize; i <= MaxFontSize; i++ {
FontsBySize[int(i)] = loadFont(float32(i))
}
imgui.CurrentIO().Fonts().Build()
imgui.CurrentIO().SetFontDefault(FontsBySize[int(DefaultFontSize)])
fmt.Printf("Finished loading fonts in %v\n", time.Now().Sub(start).Round(time.Millisecond))
}
func loadFont(fontSize float32) *imgui.Font {
// NOTE: It takes an estimated 2ms per font, so for 100 sizes it's slightly noticeable to load these at startup.
// You may want to add a loading screen, or simply load less sizes fonts. Perhaps keep only a few different
// fonts, named based on their usage (e.g. Title, Heading1, etc)
cfg := imgui.NewFontConfig()
cfg.SetFontData(uintptr(unsafe.Pointer(imgui.SliceToPtr(defaultFontTTF))))
cfg.SetFontDataSize(int32(len(defaultFontTTF)))
cfg.SetSizePixels(fontSize)
cfg.SetFontDataOwnedByAtlas(false) // Let golang manage this memory. Otherwise imgui crashes when trying to clean it up while exiting. The error is: `munmap_chunk(): invalid pointer`.
cfg.SetPixelSnapH(true)
return imgui.CurrentIO().Fonts().AddFont(cfg)
}
func loop() {
imgui.Begin("Window1")
{
imgui.Text("Size: ")
imgui.SameLine()
imgui.SliderInt("##FontSizeSlider", &selectedFontSize, MinFontSize, MaxFontSize)
imgui.PushFont(FontsBySize[int(selectedFontSize)])
imgui.Text(fmt.Sprintf("%d default default default", selectedFontSize))
imgui.PopFont()
for i := MinFontSize; i <= MaxFontSize; i += 10 {
imgui.PushFont(FontsBySize[int(i)])
imgui.Text(fmt.Sprintf("%d test test test test test test", i))
imgui.PopFont()
}
}
imgui.End()
}
func main() {
backend, err := imgui.CreateBackend(imgui.NewGLFWBackend())
if err != nil {
fmt.Printf("Error creating backend: %v\n", err)
os.Exit(1)
}
backend.SetAfterCreateContextHook(func() {
InitFonts()
})
backend.CreateWindow("Resized font demo", 1500, 900)
backend.Run(loop)
}
@Omustardo
Copy link
Author

Screenshot from 2024-09-24 00-15-37

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment