2018-07-22 00:12:22 +00:00
|
|
|
// Package sdl provides an SDL2 renderer for Doodle.
|
|
|
|
package sdl
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"git.kirsle.net/apps/doodle/events"
|
|
|
|
"git.kirsle.net/apps/doodle/render"
|
|
|
|
"github.com/veandco/go-sdl2/sdl"
|
|
|
|
"github.com/veandco/go-sdl2/ttf"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Renderer manages the SDL state.
|
|
|
|
type Renderer struct {
|
|
|
|
// Configurable fields.
|
|
|
|
title string
|
|
|
|
width int32
|
|
|
|
height int32
|
|
|
|
startTime time.Time
|
|
|
|
|
|
|
|
// Private fields.
|
|
|
|
events *events.State
|
|
|
|
window *sdl.Window
|
|
|
|
renderer *sdl.Renderer
|
|
|
|
running bool
|
|
|
|
ticks uint64
|
|
|
|
|
|
|
|
// Optimizations to minimize SDL calls.
|
|
|
|
lastColor render.Color
|
|
|
|
}
|
|
|
|
|
|
|
|
// New creates the SDL renderer.
|
|
|
|
func New(title string, width, height int32) *Renderer {
|
|
|
|
return &Renderer{
|
|
|
|
events: events.New(),
|
|
|
|
title: title,
|
|
|
|
width: width,
|
|
|
|
height: height,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Teardown tasks when exiting the program.
|
|
|
|
func (r *Renderer) Teardown() {
|
|
|
|
r.renderer.Destroy()
|
|
|
|
r.window.Destroy()
|
|
|
|
sdl.Quit()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setup the renderer.
|
|
|
|
func (r *Renderer) Setup() error {
|
|
|
|
// Initialize SDL.
|
|
|
|
log.Info("Initializing SDL")
|
|
|
|
if err := sdl.Init(sdl.INIT_EVERYTHING); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize SDL_TTF.
|
|
|
|
log.Info("Initializing SDL_TTF")
|
|
|
|
if err := ttf.Init(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create our window.
|
|
|
|
log.Info("Creating the Main Window")
|
|
|
|
window, err := sdl.CreateWindow(
|
|
|
|
r.title,
|
|
|
|
sdl.WINDOWPOS_CENTERED,
|
|
|
|
sdl.WINDOWPOS_CENTERED,
|
|
|
|
r.width,
|
|
|
|
r.height,
|
|
|
|
sdl.WINDOW_SHOWN,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
r.window = window
|
|
|
|
|
|
|
|
// Blank out the window in white.
|
|
|
|
log.Info("Creating the SDL Renderer")
|
|
|
|
renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
r.renderer = renderer
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetTicks gets SDL's current tick count.
|
|
|
|
func (r *Renderer) GetTicks() uint32 {
|
|
|
|
return sdl.GetTicks()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Poll for events.
|
|
|
|
func (r *Renderer) Poll() (*events.State, error) {
|
|
|
|
s := r.events
|
|
|
|
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
|
|
|
|
switch t := event.(type) {
|
|
|
|
case *sdl.QuitEvent:
|
|
|
|
return s, errors.New("quit")
|
|
|
|
case *sdl.MouseMotionEvent:
|
|
|
|
if DebugMouseEvents {
|
|
|
|
log.Debug("[%d ms] tick:%d MouseMotion type:%d id:%d x:%d y:%d xrel:%d yrel:%d",
|
|
|
|
t.Timestamp, r.ticks, t.Type, t.Which, t.X, t.Y, t.XRel, t.YRel,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Push the cursor position.
|
|
|
|
s.CursorX.Push(t.X)
|
|
|
|
s.CursorY.Push(t.Y)
|
|
|
|
s.Button1.Push(t.State == 1)
|
|
|
|
case *sdl.MouseButtonEvent:
|
|
|
|
if DebugClickEvents {
|
|
|
|
log.Debug("[%d ms] tick:%d MouseButton type:%d id:%d x:%d y:%d button:%d state:%d",
|
|
|
|
t.Timestamp, r.ticks, t.Type, t.Which, t.X, t.Y, t.Button, t.State,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Push the cursor position.
|
|
|
|
s.CursorX.Push(t.X)
|
|
|
|
s.CursorY.Push(t.Y)
|
|
|
|
|
|
|
|
// Is a mouse button pressed down?
|
|
|
|
if t.Button == 1 {
|
|
|
|
var eventName string
|
2018-07-26 03:25:02 +00:00
|
|
|
if t.State == 1 && s.Button1.Now == false {
|
|
|
|
eventName = "DOWN"
|
|
|
|
} else if t.State == 0 && s.Button1.Now == true {
|
|
|
|
eventName = "UP"
|
2018-07-22 00:12:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if eventName != "" {
|
|
|
|
s.Button1.Push(eventName == "DOWN")
|
|
|
|
|
|
|
|
// Return the event immediately.
|
|
|
|
return s, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// s.Button2.Push(t.Button == 3 && t.State == 1)
|
|
|
|
case *sdl.MouseWheelEvent:
|
|
|
|
if DebugMouseEvents {
|
|
|
|
log.Debug("[%d ms] tick:%d MouseWheel type:%d id:%d x:%d y:%d",
|
|
|
|
t.Timestamp, r.ticks, t.Type, t.Which, t.X, t.Y,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
case *sdl.KeyboardEvent:
|
2018-07-22 03:43:01 +00:00
|
|
|
if DebugKeyEvents {
|
|
|
|
log.Debug("[%d ms] tick:%d Keyboard type:%d sym:%c modifiers:%d state:%d repeat:%d\n",
|
|
|
|
t.Timestamp, r.ticks, t.Type, t.Keysym.Sym, t.Keysym.Mod, t.State, t.Repeat,
|
|
|
|
)
|
2018-07-22 00:12:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch t.Keysym.Scancode {
|
|
|
|
case sdl.SCANCODE_ESCAPE:
|
2018-07-22 03:43:01 +00:00
|
|
|
if t.Repeat == 1 {
|
|
|
|
continue
|
|
|
|
}
|
2018-07-22 00:12:22 +00:00
|
|
|
s.EscapeKey.Push(t.State == 1)
|
2018-07-22 03:43:01 +00:00
|
|
|
case sdl.SCANCODE_RETURN:
|
|
|
|
if t.Repeat == 1 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
s.EnterKey.Push(t.State == 1)
|
2018-07-22 00:12:22 +00:00
|
|
|
case sdl.SCANCODE_F12:
|
|
|
|
s.ScreenshotKey.Push(t.State == 1)
|
|
|
|
case sdl.SCANCODE_UP:
|
|
|
|
s.Up.Push(t.State == 1)
|
|
|
|
case sdl.SCANCODE_LEFT:
|
|
|
|
s.Left.Push(t.State == 1)
|
|
|
|
case sdl.SCANCODE_RIGHT:
|
|
|
|
s.Right.Push(t.State == 1)
|
|
|
|
case sdl.SCANCODE_DOWN:
|
|
|
|
s.Down.Push(t.State == 1)
|
2018-07-22 03:43:01 +00:00
|
|
|
case sdl.SCANCODE_LSHIFT:
|
|
|
|
case sdl.SCANCODE_RSHIFT:
|
|
|
|
s.ShiftActive.Push(t.State == 1)
|
|
|
|
continue
|
|
|
|
case sdl.SCANCODE_LALT:
|
|
|
|
case sdl.SCANCODE_RALT:
|
|
|
|
case sdl.SCANCODE_LCTRL:
|
|
|
|
case sdl.SCANCODE_RCTRL:
|
|
|
|
continue
|
|
|
|
case sdl.SCANCODE_BACKSPACE:
|
|
|
|
// Make it a key event with "\b" as the sequence.
|
|
|
|
if t.State == 1 || t.Repeat == 1 {
|
|
|
|
s.KeyName.Push(`\b`)
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
// Push the string value of the key.
|
|
|
|
if t.State == 1 {
|
|
|
|
s.KeyName.Push(string(t.Keysym.Sym))
|
|
|
|
}
|
2018-07-22 00:12:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return s, nil
|
|
|
|
}
|
|
|
|
|
2018-07-22 03:43:01 +00:00
|
|
|
// Present the current frame.
|
|
|
|
func (r *Renderer) Present() error {
|
2018-07-22 00:12:22 +00:00
|
|
|
r.renderer.Present()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delay using sdl.Delay
|
|
|
|
func (r *Renderer) Delay(time uint32) {
|
|
|
|
sdl.Delay(time)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Loop is the main loop.
|
|
|
|
func (r *Renderer) Loop() error {
|
|
|
|
return nil
|
|
|
|
}
|