mirror of
https://github.com/mvvasilev/last_light.git
synced 2025-04-19 12:49:52 +03:00
163 lines
2.9 KiB
Go
163 lines
2.9 KiB
Go
package engine
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
|
|
"github.com/gdamore/tcell/v2"
|
|
"github.com/gdamore/tcell/v2/views"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
const (
|
|
TERMINAL_SIZE_WIDTH int = 80
|
|
TERMINAL_SIZE_HEIGHT int = 24
|
|
DEFAULT_STYLE_BACKGROUND tcell.Color = tcell.ColorReset
|
|
DEFAULT_STYLE_FOREGROUND tcell.Color = tcell.ColorReset
|
|
)
|
|
|
|
type Drawable interface {
|
|
UniqueId() uuid.UUID
|
|
Draw(v views.View)
|
|
}
|
|
|
|
func Multidraw(drawables ...Drawable) []Drawable {
|
|
arr := make([]Drawable, 0)
|
|
|
|
if drawables == nil {
|
|
return arr
|
|
}
|
|
|
|
for _, d := range drawables {
|
|
if d == nil {
|
|
continue
|
|
}
|
|
|
|
arr = append(arr, d)
|
|
}
|
|
|
|
return arr
|
|
}
|
|
|
|
type RenderContext struct {
|
|
screen tcell.Screen
|
|
view *views.ViewPort
|
|
|
|
events chan tcell.Event
|
|
quit chan struct{}
|
|
drawables chan Drawable
|
|
}
|
|
|
|
func CreateRenderContext() (*RenderContext, error) {
|
|
screen, sErr := tcell.NewScreen()
|
|
|
|
if sErr != nil {
|
|
log.Fatalf("%~v", sErr)
|
|
}
|
|
|
|
stopScreen := func() {
|
|
screen.Fini()
|
|
}
|
|
|
|
if err := screen.Init(); err != nil {
|
|
stopScreen()
|
|
log.Fatal(err)
|
|
return nil, err
|
|
}
|
|
|
|
width, height := screen.Size()
|
|
|
|
if width < TERMINAL_SIZE_WIDTH || height < TERMINAL_SIZE_HEIGHT {
|
|
stopScreen()
|
|
log.Fatal("Unable to start; Terminal must be at least 80x24")
|
|
return nil, errors.New("Terminal is undersized; must be at least 80x24")
|
|
}
|
|
|
|
view := views.NewViewPort(
|
|
screen,
|
|
(width/2)-(TERMINAL_SIZE_WIDTH/2),
|
|
(height/2)-(TERMINAL_SIZE_HEIGHT/2),
|
|
TERMINAL_SIZE_WIDTH,
|
|
TERMINAL_SIZE_HEIGHT,
|
|
)
|
|
|
|
events := make(chan tcell.Event)
|
|
quit := make(chan struct{})
|
|
|
|
go screen.ChannelEvents(events, quit)
|
|
|
|
context := new(RenderContext)
|
|
|
|
context.screen = screen
|
|
context.events = events
|
|
context.quit = quit
|
|
context.view = view
|
|
context.drawables = make(chan Drawable)
|
|
|
|
return context, nil
|
|
}
|
|
|
|
func (c *RenderContext) Stop() {
|
|
c.screen.Fini()
|
|
}
|
|
|
|
func (c *RenderContext) CollectInputEvents() []*tcell.EventKey {
|
|
events := make([]tcell.Event, len(c.events))
|
|
|
|
select {
|
|
case e := <-c.events:
|
|
events = append(events, e)
|
|
default:
|
|
}
|
|
|
|
inputEvents := make([]*tcell.EventKey, 0, len(events))
|
|
|
|
for _, e := range events {
|
|
switch ev := e.(type) {
|
|
case *tcell.EventKey:
|
|
inputEvents = append(inputEvents, ev)
|
|
case *tcell.EventResize:
|
|
c.onResize(ev)
|
|
}
|
|
}
|
|
|
|
return inputEvents
|
|
}
|
|
|
|
func (c *RenderContext) DrawableQueue() chan Drawable {
|
|
return c.drawables
|
|
}
|
|
|
|
func (c *RenderContext) onResize(ev *tcell.EventResize) {
|
|
width, height := ev.Size()
|
|
|
|
c.screen.Clear()
|
|
|
|
c.view.Resize(
|
|
(width/2)-(TERMINAL_SIZE_WIDTH/2),
|
|
(height/2)-(TERMINAL_SIZE_HEIGHT/2),
|
|
TERMINAL_SIZE_WIDTH,
|
|
TERMINAL_SIZE_HEIGHT,
|
|
)
|
|
|
|
c.screen.Sync()
|
|
}
|
|
|
|
func (c *RenderContext) Draw(deltaTime int64, drawables []Drawable) {
|
|
fps := 1_000_000 / deltaTime
|
|
|
|
c.view.Clear()
|
|
|
|
msPerFrame := float32(fps) / 1000.0
|
|
|
|
fpsText := CreateText(0, 0, 16, 1, fmt.Sprintf("%vms", msPerFrame), tcell.StyleDefault)
|
|
|
|
for _, d := range drawables {
|
|
d.Draw(c.view)
|
|
}
|
|
|
|
fpsText.Draw(c.view)
|
|
|
|
c.screen.Show()
|
|
}
|