Gopher2600/gui/sdlimgui/atlas.go
JetSetIlly 5c1f071ca6 'using bevel' option in addition to 'pixel perfect' option
if pixel perfect is disabled and using bevel is enabled, then the curve
and rounded corners amount are fixed values specific to the selected
bevel. currently only the 'solid state' bevel is allowed

set new default values for crt preferences

increased perlin noise value for CRT screen
2024-12-28 13:58:40 +00:00

272 lines
8.4 KiB
Go

// This file is part of Gopher2600.
//
// Gopher2600 is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Gopher2600 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Gopher2600. If not, see <https://www.gnu.org/licenses/>.
package sdlimgui
import (
"fmt"
"math"
"github.com/inkyblackness/imgui-go/v4"
"github.com/jetsetilly/gopher2600/gui/fonts"
)
type fontDisplay interface {
displayDPI() (float32, error)
}
type fontAtlas struct {
display fontDisplay
// gui font
gui imgui.Font
guiSize float32
smallGui imgui.Font
smallGuiSize float32
// used for notifications (eg. network access, etc.)
largeFontAwesome imgui.Font
largeFontAwesomeSize float32
// used for rewind/fast-forward state
veryLargeFontAwesome imgui.Font
veryLargeFontAwesomeSize float32
// custom icons for controllers and other peripherals
gopher2600Icons imgui.Font
gopher2600IconsSize float32
// annotation of diagrams
diagram imgui.Font
diagramSize float32
// terminal
terminal imgui.Font
terminalSize float32
// source code
code imgui.Font
codeSize float32
}
func scaleFontForDPI(pt float32, dpi float32) float32 {
return float32(math.Round(float64(pt * (dpi / 72))))
}
func (atlas *fontAtlas) initialise(display fontDisplay, renderer renderer, prefs *preferences) error {
setFontBuilderFlags(imgui.CurrentIO().Fonts())
dpi, err := display.displayDPI()
if err != nil {
return fmt.Errorf("font: %w", err)
}
err = atlas.setDefaultFont(prefs, dpi)
if err != nil {
return err
}
// load small gui font
if atlas.smallGui == 0 {
smallGuiConfig := imgui.NewFontConfig()
defer smallGuiConfig.Delete()
smallGuiConfig.SetPixelSnapH(true)
var smallGuiBuilder imgui.GlyphRangesBuilder
smallGuiBuilder.Add(fonts.JetBrainsMonoMin, fonts.JetBrainsMonoMax)
atlas.smallGuiSize = float32(prefs.guiFontSize.Get().(int)) * 0.85
atlas.smallGuiSize = scaleFontForDPI(atlas.smallGuiSize, dpi)
atlas.smallGui = imgui.CurrentIO().Fonts().AddFontFromMemoryTTFV(fonts.JetBrainsMono, atlas.smallGuiSize, smallGuiConfig, smallGuiBuilder.Build().GlyphRanges)
if atlas.smallGui == 0 {
return fmt.Errorf("font: error loading JetBrainsMono font from memory")
}
}
// load large font awesome
if atlas.largeFontAwesome == 0 {
largeFontAwesomeConfig := imgui.NewFontConfig()
defer largeFontAwesomeConfig.Delete()
largeFontAwesomeConfig.SetPixelSnapH(true)
var largeFontAwesomeBuilder imgui.GlyphRangesBuilder
largeFontAwesomeBuilder.Add(fonts.FontAwesomeMin, fonts.FontAwesomeMax)
atlas.largeFontAwesomeSize = 22.0
atlas.largeFontAwesome = imgui.CurrentIO().Fonts().AddFontFromMemoryTTFV(fonts.FontAwesome, atlas.largeFontAwesomeSize, largeFontAwesomeConfig, largeFontAwesomeBuilder.Build().GlyphRanges)
if atlas.largeFontAwesome == 0 {
return fmt.Errorf("font: error loading font-awesome from memory")
}
}
// load very-large font awesome
if atlas.veryLargeFontAwesome == 0 {
veryLargeFontAwesomeConfig := imgui.NewFontConfig()
defer veryLargeFontAwesomeConfig.Delete()
veryLargeFontAwesomeConfig.SetPixelSnapH(true)
var veryLargeFontAwesomeBuilder imgui.GlyphRangesBuilder
veryLargeFontAwesomeBuilder.Add(fonts.FontAwesomeMin, fonts.FontAwesomeMax)
atlas.veryLargeFontAwesomeSize = 44.0
atlas.veryLargeFontAwesome = imgui.CurrentIO().Fonts().AddFontFromMemoryTTFV(fonts.FontAwesome, atlas.veryLargeFontAwesomeSize, veryLargeFontAwesomeConfig, veryLargeFontAwesomeBuilder.Build().GlyphRanges)
if atlas.veryLargeFontAwesome == 0 {
return fmt.Errorf("font: error loading font-awesome from memory")
}
}
// load gopher icons
if atlas.gopher2600Icons == 0 {
gopher2600IconConfig := imgui.NewFontConfig()
defer gopher2600IconConfig.Delete()
gopher2600IconConfig.SetPixelSnapH(true)
gopher2600IconConfig.SetGlyphOffsetY(1.0)
var gopher2600IconBuilder imgui.GlyphRangesBuilder
gopher2600IconBuilder.Add(fonts.Gopher2600IconMin, fonts.Gopher2600IconMax)
atlas.gopher2600IconsSize = 60.0
atlas.gopher2600Icons = imgui.CurrentIO().Fonts().AddFontFromMemoryTTFV(fonts.Gopher2600Icons, atlas.gopher2600IconsSize, gopher2600IconConfig, gopher2600IconBuilder.Build().GlyphRanges)
if atlas.gopher2600Icons == 0 {
return fmt.Errorf("font: error loading Gopher2600 font from memory")
}
}
// load diagram font
if atlas.diagram == 0 {
diagramConfig := imgui.NewFontConfig()
defer diagramConfig.Delete()
diagramConfig.SetPixelSnapH(true)
var diagramBuilder imgui.GlyphRangesBuilder
diagramBuilder.Add(fonts.HackMin, fonts.HackMax)
atlas.diagramSize = scaleFontForDPI(10.0, dpi)
atlas.diagram = imgui.CurrentIO().Fonts().AddFontFromMemoryTTFV(fonts.Hack, atlas.diagramSize, diagramConfig, diagramBuilder.Build().GlyphRanges)
if atlas.diagram == 0 {
return fmt.Errorf("font: error loading hack font from memory")
}
}
// load terminal font
err = atlas.terminalFont(prefs, dpi)
if err != nil {
return fmt.Errorf("font: %w", err)
}
// load source code font
err = atlas.sourceCodeFont(prefs, dpi)
if err != nil {
return fmt.Errorf("font: %w", err)
}
// create textures and register with imgui
tex := renderer.addFontTexture(imgui.CurrentIO().Fonts())
imgui.CurrentIO().Fonts().SetTextureID(imgui.TextureID(tex.getID()))
return nil
}
func (atlas *fontAtlas) setDefaultFont(prefs *preferences, dpi float32) error {
guiFontSize := float32(prefs.guiFontSize.Get().(int))
if atlas.guiSize != 0 && guiFontSize == atlas.guiSize {
return nil
}
atlas.guiSize = guiFontSize
// load gui font
cfg := imgui.NewFontConfig()
defer cfg.Delete()
var builder imgui.GlyphRangesBuilder
builder.Add(fonts.JetBrainsMonoMin, fonts.JetBrainsMonoMax)
guiFontSize = scaleFontForDPI(guiFontSize, dpi)
atlas.gui = imgui.CurrentIO().Fonts().AddFontFromMemoryTTFV(fonts.JetBrainsMono, guiFontSize, cfg, builder.Build().GlyphRanges)
if atlas.gui == 0 {
return fmt.Errorf("font: error loading JetBrainsMono font from memory")
}
atlas.mergeFontAwesome(guiFontSize, 1.0)
return nil
}
func (atlas *fontAtlas) sourceCodeFont(prefs *preferences, dpi float32) error {
codeSize := float32(prefs.codeFontSize.Get().(int))
if atlas.codeSize != 0 && codeSize == atlas.codeSize {
return nil
}
atlas.codeSize = codeSize
cfg := imgui.NewFontConfig()
defer cfg.Delete()
var builder imgui.GlyphRangesBuilder
builder.Add(fonts.JetBrainsMonoMin, fonts.JetBrainsMonoMax)
codeSize = scaleFontForDPI(codeSize, dpi)
atlas.code = imgui.CurrentIO().Fonts().AddFontFromMemoryTTFV(fonts.JetBrainsMono, codeSize, cfg, builder.Build().GlyphRanges)
if atlas.code == 0 {
return fmt.Errorf("font: error loading JetBrainsMono font from memory")
}
atlas.mergeFontAwesome(codeSize, 0.0)
return nil
}
func (atlas *fontAtlas) terminalFont(prefs *preferences, dpi float32) error {
terminalSize := float32(prefs.terminalFontSize.Get().(int))
if atlas.terminalSize != 0 && terminalSize == atlas.terminalSize {
return nil
}
atlas.terminalSize = terminalSize
cfg := imgui.NewFontConfig()
defer cfg.Delete()
var builder imgui.GlyphRangesBuilder
builder.Add(fonts.JetBrainsMonoMin, fonts.JetBrainsMonoMax)
terminalSize = scaleFontForDPI(terminalSize, dpi)
atlas.terminal = imgui.CurrentIO().Fonts().AddFontFromMemoryTTFV(fonts.JetBrainsMono, terminalSize, cfg, builder.Build().GlyphRanges)
if atlas.terminal == 0 {
return fmt.Errorf("font: error loading JetBrainsMono font from memory")
}
atlas.mergeFontAwesome(terminalSize, 0.0)
return nil
}
func (atlas *fontAtlas) mergeFontAwesome(size float32, adjust float32) error {
mergeConfig := imgui.NewFontConfig()
defer mergeConfig.Delete()
mergeConfig.SetMergeMode(true)
mergeConfig.SetGlyphOffsetY(adjust)
// limit what glyphs we load
var glyphBuilder imgui.GlyphRangesBuilder
glyphBuilder.Add(fonts.FontAwesomeMin, fonts.FontAwesomeMax)
// merge font awesome
merge := imgui.CurrentIO().Fonts().AddFontFromMemoryTTFV(fonts.FontAwesome, size, mergeConfig, glyphBuilder.Build().GlyphRanges)
if merge == 0 {
return fmt.Errorf("font: error loading font-awesome from memory")
}
return nil
}