Files
nterm/main.go
2022-07-05 07:12:11 +04:00

235 lines
5.6 KiB
Go
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"fmt"
"math/rand"
"github.com/bloeys/gglm/gglm"
"github.com/bloeys/nmage/engine"
"github.com/bloeys/nmage/input"
"github.com/bloeys/nmage/materials"
"github.com/bloeys/nmage/meshes"
"github.com/bloeys/nmage/renderer/rend3dgl"
nmageimgui "github.com/bloeys/nmage/ui/imgui"
"github.com/bloeys/nterm/glyphs"
"github.com/golang/freetype/truetype"
"github.com/veandco/go-sdl2/sdl"
"golang.org/x/image/font"
)
var _ engine.Game = &program{}
type program struct {
win *engine.Window
rend *rend3dgl.Rend3DGL
imguiInfo nmageimgui.ImguiInfo
FontSize uint32
Dpi float64
GlyphRend *glyphs.GlyphRend
gridMesh *meshes.Mesh
gridMat *materials.Material
shouldDrawGrid bool
}
const subPixelX = 64
const subPixelY = 64
const hinting = font.HintingNone
func main() {
err := engine.Init()
if err != nil {
panic("Failed to init engine. Err: " + err.Error())
}
rend := rend3dgl.NewRend3DGL()
win, err := engine.CreateOpenGLWindowCentered("nTerm", 1280, 720, engine.WindowFlags_ALLOW_HIGHDPI|engine.WindowFlags_RESIZABLE, rend)
if err != nil {
panic("Failed to create window. Err: " + err.Error())
}
engine.SetVSync(true)
p := &program{
win: win,
rend: rend,
imguiInfo: nmageimgui.NewImGUI(),
FontSize: 20,
}
p.win.EventCallbacks = append(p.win.EventCallbacks, func(e sdl.Event) {
switch e := e.(type) {
case *sdl.WindowEvent:
if e.Event == sdl.WINDOWEVENT_SIZE_CHANGED {
p.handleWindowResize()
}
}
})
//Don't flash white
p.win.SDLWin.GLSwap()
engine.Run(p, p.win, p.imguiInfo)
}
func (p *program) Init() {
dpi, _, _, err := sdl.GetDisplayDPI(0)
if err != nil {
panic("Failed to get display DPI. Err: " + err.Error())
}
fmt.Printf("DPI: %f, font size: %d\n", dpi, p.FontSize)
w, h := p.win.SDLWin.GetSize()
p.GlyphRend, err = glyphs.NewGlyphRend("./res/fonts/KawkabMono-Regular.ttf", &truetype.Options{Size: float64(p.FontSize), DPI: p.Dpi, SubPixelsX: subPixelX, SubPixelsY: subPixelY, Hinting: hinting}, w, h)
if err != nil {
panic("Failed to create atlas from font file. Err: " + err.Error())
}
glyphs.SaveImgToPNG(p.GlyphRend.Atlas.Img, "./debug-atlas.png")
//Load resources
p.gridMesh, err = meshes.NewMesh("grid", "./res/models/quad.obj", 0)
if err != nil {
panic(err.Error())
}
p.gridMat = materials.NewMaterial("grid", "./res/shaders/grid.glsl")
p.handleWindowResize()
}
func (p *program) Update() {
if input.IsQuitClicked() || input.KeyClicked(sdl.K_ESCAPE) {
engine.Quit()
}
if input.KeyClicked(sdl.K_SPACE) {
p.handleWindowResize()
}
//Font sizing
oldFont := p.FontSize
fontSizeChanged := false
if input.KeyClicked(sdl.K_KP_PLUS) {
p.FontSize += 2
fontSizeChanged = true
} else if input.KeyClicked(sdl.K_KP_MINUS) {
p.FontSize -= 2
fontSizeChanged = true
}
if fontSizeChanged {
err := p.GlyphRend.SetFace(&truetype.Options{Size: float64(p.FontSize), DPI: p.Dpi, SubPixelsX: subPixelX, SubPixelsY: subPixelY, Hinting: hinting})
if err != nil {
p.FontSize = oldFont
println("Failed to update font face. Err: " + err.Error())
} else {
glyphs.SaveImgToPNG(p.GlyphRend.Atlas.Img, "./debug-atlas.png")
println("New font size:", p.FontSize, "; New texture size:", p.GlyphRend.Atlas.Img.Rect.Max.X, "\n")
}
}
//Move text
var speed float32 = 1
if input.KeyDown(sdl.K_RIGHT) {
xOff += speed
} else if input.KeyDown(sdl.K_LEFT) {
xOff -= speed
}
if input.KeyDown(sdl.K_UP) {
yOff += speed
} else if input.KeyDown(sdl.K_DOWN) {
yOff -= speed
}
//Grid
if input.KeyClicked(sdl.K_SPACE) {
p.shouldDrawGrid = !p.shouldDrawGrid
}
}
var xOff float32 = 0
var yOff float32 = 0
var r = rand.Float32()
var g = rand.Float32()
var b = rand.Float32()
func (p *program) Render() {
defer p.GlyphRend.Draw()
if p.shouldDrawGrid {
p.drawGrid()
}
const colorSpd = 0.005
r += colorSpd
if r > 1 {
r = 0
}
g += colorSpd
if g > 1 {
g = 0
}
b += colorSpd
if b > 1 {
b = 0
}
textColor := gglm.NewVec4(r, g, b, 1)
str := " مرحبا بك"
// str := " ijojo\n\n Hello there, friend|. pq?\n ABCDEFG\tHIJKLMNOPQRSTUVWXYZ\nمرحبا بك"
// str := " ijojo\n\n Hello there, friend|. pq?\n ABCDEFG\tHIJKLMNOPQRSTUVWXYZ"
p.GlyphRend.DrawTextOpenGLAbs(str, gglm.NewVec3(xOff, float32(p.GlyphRend.Atlas.LineHeight)*5+yOff, 0), textColor)
// strLen := len(str)
// const charsPerFrame = 10_000
// for i := 0; i < charsPerFrame/strLen; i++ {
// p.GlyphRend.DrawTextOpenGLAbs(str, gglm.NewVec3(xOff, float32(p.GlyphRend.Atlas.LineHeight)*8+yOff, 0), textColor)
// }
// p.win.SDLWin.SetTitle(fmt.Sprint("FPS:", int(timing.GetAvgFPS()), "; Draws per frame:", math.Ceil(charsPerFrame/glyphs.MaxGlyphsPerBatch)))
}
func (p *program) drawGrid() {
sizeX := float32(p.GlyphRend.ScreenWidth)
sizeY := float32(p.GlyphRend.ScreenHeight)
//columns
adv := p.GlyphRend.Atlas.Advance
for i := int32(0); i < p.GlyphRend.ScreenWidth; i += int32(adv) {
p.rend.Draw(p.gridMesh, gglm.NewTrMatId().Translate(gglm.NewVec3(float32(i)+0.5, sizeY/2, 0)).Scale(gglm.NewVec3(1, sizeY, 1)), p.gridMat)
}
//rows
for i := int32(0); i < p.GlyphRend.ScreenHeight; i += int32(p.GlyphRend.Atlas.LineHeight) {
p.rend.Draw(p.gridMesh, gglm.NewTrMatId().Translate(gglm.NewVec3(sizeX/2, float32(i), 0)).Scale(gglm.NewVec3(sizeX, 1, 1)), p.gridMat)
}
}
func (p *program) FrameEnd() {
}
func (p *program) DeInit() {
}
func (p *program) handleWindowResize() {
w, h := p.win.SDLWin.GetSize()
p.GlyphRend.SetScreenSize(w, h)
projMtx := gglm.Ortho(0, float32(w), float32(h), 0, 0.1, 20)
viewMtx := gglm.LookAt(gglm.NewVec3(0, 0, -10), gglm.NewVec3(0, 0, 0), gglm.NewVec3(0, 1, 0))
p.gridMat.SetUnifMat4("projViewMat", &projMtx.Mul(viewMtx).Mat4)
}