diff --git a/cmd/tins2020/tins2020.go b/cmd/tins2020/tins2020.go index d1518fe..4585e24 100644 --- a/cmd/tins2020/tins2020.go +++ b/cmd/tins2020/tins2020.go @@ -72,7 +72,10 @@ func run() error { ctx.Init(renderer) - err = ctx.Fonts.Load("default", "fonts/OpenSans-Regular.ttf", 12) + err = ctx.Fonts.LoadDesc( + tins2020.FontDescriptor{Name: "debug", Path: "fonts/OpenSans-Regular.ttf", Size: 12}, + tins2020.FontDescriptor{Name: "default", Path: "fonts/FiraMono-Regular.ttf", Size: 10}, + ) if err != nil { return err } @@ -126,8 +129,15 @@ func run() error { } game := tins2020.NewGame() - control := tins2020.NewTerrainRenderer(game.Terrain) - err = control.Init(ctx) + + app := tins2020.NewContainer() + overlays := tins2020.NewContainer() + overlays.AddChild(&tins2020.FPS{}) + content := tins2020.NewContainer() + app.AddChild(content) + app.AddChild(overlays) + content.AddChild(tins2020.NewTerrainRenderer(game.Terrain)) + err = app.Init(ctx) if err != nil { return err } @@ -153,7 +163,7 @@ func run() error { ctx.Quit() } } - control.Handle(ctx, event) + app.Handle(ctx, event) } if ctx.ShouldQuit { @@ -162,7 +172,7 @@ func run() error { renderer.SetDrawColor(0, 0, 0, 255) renderer.Clear() - control.Render(ctx) + app.Render(ctx) renderer.Present() } return nil diff --git a/container.go b/container.go new file mode 100644 index 0000000..d4fbc90 --- /dev/null +++ b/container.go @@ -0,0 +1,39 @@ +package tins2020 + +import ( + "github.com/veandco/go-sdl2/sdl" +) + +type Container struct { + Children []Control +} + +func NewContainer() *Container { + return &Container{} +} + +func (c *Container) AddChild(child Control) { + c.Children = append(c.Children, child) +} + +func (c *Container) Handle(ctx *Context, event sdl.Event) { + for _, child := range c.Children { + child.Handle(ctx, event) + } +} + +func (c *Container) Render(ctx *Context) { + for _, child := range c.Children { + child.Render(ctx) + } +} + +func (c *Container) Init(ctx *Context) error { + for _, child := range c.Children { + err := child.Init(ctx) + if err != nil { + return err + } + } + return nil +} diff --git a/control.go b/control.go new file mode 100644 index 0000000..1bd3646 --- /dev/null +++ b/control.go @@ -0,0 +1,18 @@ +package tins2020 + +import "github.com/veandco/go-sdl2/sdl" + +type Control interface { + Init(*Context) error + Handle(*Context, sdl.Event) + Render(*Context) +} + +type ControlBase struct { +} + +func (b *ControlBase) Handle(*Context, sdl.Event) {} + +func (b *ControlBase) Render(*Context) {} + +func (b *ControlBase) Init(*Context) error { return nil } diff --git a/fonts.go b/fonts.go index a93934e..c0feb32 100644 --- a/fonts.go +++ b/fonts.go @@ -1,6 +1,8 @@ package tins2020 import ( + "fmt" + "github.com/veandco/go-sdl2/ttf" "opslag.de/schobers/fs/vfs" ) @@ -15,6 +17,24 @@ func (f *Fonts) Init(dir vfs.CopyDir) { f.fonts = map[string]*ttf.Font{} } +func (f *Fonts) Font(name string) *ttf.Font { return f.fonts[name] } + +type FontDescriptor struct { + Name string + Path string + Size int +} + +func (f *Fonts) LoadDesc(fonts ...FontDescriptor) error { + for _, desc := range fonts { + err := f.Load(desc.Name, desc.Path, desc.Size) + if err != nil { + return fmt.Errorf("error loading '%s'; error: %v", desc.Name, err) + } + } + return nil +} + func (f *Fonts) Load(name, path string, size int) error { fontPath, err := f.dir.Retrieve(path) if err != nil { diff --git a/fpsrenderer.go b/fpsrenderer.go new file mode 100644 index 0000000..9073ab7 --- /dev/null +++ b/fpsrenderer.go @@ -0,0 +1,51 @@ +package tins2020 + +import ( + "fmt" + "time" + + "github.com/veandco/go-sdl2/sdl" +) + +type FPS struct { + ControlBase + + start time.Time + stamp time.Duration + slot int + ticks []int + total int +} + +func (f *FPS) Init(*Context) error { + f.start = time.Now() + f.stamp = 0 + f.ticks = make([]int, 51) + return nil +} + +func (f *FPS) Render(ctx *Context) { + elapsed := time.Since(f.start) + stamp := elapsed / (20 * time.Millisecond) + for f.stamp < stamp { + f.total += f.ticks[f.slot] + f.slot = (f.slot + 1) % len(f.ticks) + f.total -= f.ticks[f.slot] + f.ticks[f.slot] = 0 + f.stamp++ + } + f.ticks[f.slot]++ + + font := ctx.Fonts.Font("debug") + surface, err := font.RenderUTF8Solid(fmt.Sprintf("FPS: %d", f.total), sdl.Color{R: 255, G: 255, B: 255, A: 255}) + if err != nil { + return + } + defer surface.Free() + texture, err := NewTextureFromSurface(ctx.Renderer, surface) + if err != nil { + return + } + defer texture.Destroy() + texture.Copy(ctx.Renderer, texture.RectOffset(Pt(5, 5))) +} diff --git a/renderer.go b/renderer.go deleted file mode 100644 index 7d35246..0000000 --- a/renderer.go +++ /dev/null @@ -1,9 +0,0 @@ -package tins2020 - -import "github.com/veandco/go-sdl2/sdl" - -type Control interface { - Init(*Context) error - Handle(*Context, sdl.Event) - Render(*Context) -} diff --git a/textures.go b/textures.go index 2e52aea..d7bbdfb 100644 --- a/textures.go +++ b/textures.go @@ -24,6 +24,10 @@ func NewTextureFromSurface(renderer *sdl.Renderer, surface *sdl.Surface) (*Textu func (t *Texture) Rect() *sdl.Rect { return t.rect } +func (t *Texture) RectOffset(offset Point) *sdl.Rect { + return &sdl.Rect{X: offset.X, Y: offset.Y, W: t.rect.W, H: t.rect.H} +} + func (t *Texture) Copy(renderer *sdl.Renderer, target *sdl.Rect) { renderer.Copy(t.texture, t.rect, target) }