package main import ( "image/color" "log" "math" "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/vector" ) const width = 512 const height = 512 type appOption func(a *app) type app struct { strokes []stroke diameter float32 canvas *ebiten.Image sizeAnchorPos Vec2 historyIndex uintptr } func (a *app) Draw(screen *ebiten.Image) { screen.Fill(color.White) opts := ebiten.DrawImageOptions{} screen.DrawImage(a.canvas, &opts) cursor := cursorPosition() vector.StrokeCircle( screen, cursor.x, cursor.y, a.diameter/2, 3, color.White, true, ) vector.StrokeCircle( screen, cursor.x, cursor.y, a.diameter/2, 1, color.Black, true, ) } func (a *app) Layout(_, _ int) (screenWidth int, screenHeight int) { return width, height } func (a *app) Update() error { is_drawing := drawWhite.isPressed() || drawBlack.isPressed() just_started_drawing := drawWhite.isJustPressed() || drawBlack.isJustPressed() var clr color.Color if drawBlack.isPressed() { clr = color.Black } else if drawWhite.isPressed() { clr = color.White } if just_started_drawing { if clr == nil { log.Fatal("drawing color in update is nil") // should never happen } a.strokes = append(a.strokes, stroke{ points: []Vec2{}, width: a.diameter, color: clr, }) } // TODO current history pointer is not updated as it should // TODO tests if len(a.strokes) > 0 { currentStroke := &a.strokes[len(a.strokes)-1] if is_drawing { currentStroke.appendIfMoved(cursorPosition()) currentStroke.drawLast(a.canvas) } } if resize.isJustPressed() { a.sizeAnchorPos = cursorPosition() } if resize.isPressed() { prevPos := a.sizeAnchorPos currPos := cursorPosition() reltivePos := Vec2{ prevPos.x - currPos.x, prevPos.y - currPos.y, } length := float32(math.Sqrt( float64(reltivePos.x) * float64(reltivePos.x) + float64(reltivePos.y) * float64(reltivePos.y), )) a.diameter = length * 2.0 } return nil } func newApp( opts ...appOption ) app { a := app{} for _, opt := range opts { opt(&a) } return a } func main() { ebiten.SetWindowTitle("whiteboard") ebiten.SetWindowResizingMode(ebiten.WindowResizingModeEnabled) ebiten.CursorPosition() whiteboardApp := newApp( func(a *app) { a.diameter = 10 a.canvas = ebiten.NewImage(width, height) a.canvas.Fill(color.White) }) ebiten.RunGame(&whiteboardApp) }