package main import ( "image/color" "sync" "syscall/js" "time" "github.com/llgcode/draw2d/draw2dimg" "github.com/llgcode/draw2d/draw2dkit" "github.com/markfarnan/go-canvas/canvas" "git.jacknet.io/S.D/Chip-8_Go/chip8" ) var done chan struct{} var cvs *canvas.Canvas2d var width, height float64 = 64, 32 var sizeMultiplier = 8 var drawBuf = [64 * 32]byte{} var drawNeeded = false var graphicsLock sync.Mutex var keysLock sync.Mutex var window, beep js.Value var keys [16]byte var gameRunning = true var keyMap = map[int]int{ 88: 0, // x 49: 1, // 1 50: 2, // 2 51: 3, // 3 81: 4, // q 87: 5, // w 69: 6, // e 65: 7, // a 83: 8, // s 68: 9, // d 90: 10, // z 67: 11, // c 52: 12, // 4 82: 13, // r 70: 14, // f 86: 15, // v } var gameMap = map[string]func() []byte{ "pong": getPong, "spaceinv": getSpaceInvaders, "tetris": getTetris, } func keyEventHandle(event js.Value) { //println(event.Get("type").String()) //println(event.Get("keyCode").Int()) elem, ok := keyMap[event.Get("keyCode").Int()] if ok { keysLock.Lock() defer keysLock.Unlock() if event.Get("type").String() == "keydown" { keys[elem] = 1 } else if event.Get("type").String() == "keyup" { keys[elem] = 0 } } } func cpuCycle(cpu *chip8.Chip8, c chan int, i int) { cpu.PerformCycle() if cpu.DrawIsNeeded() { drawNeeded = true graphicsLock.Lock() drawBuf = cpu.GetGraphicsBuffer() graphicsLock.Unlock() keysLock.Lock() cpu.UpdateKeys(keys) keysLock.Unlock() } if i > 7 { cpu.TickTimers() //println("here!") } if cpu.BeepNeeded() { go playSound() } c <- 1 } func timeCycle(c chan int) { time.Sleep(2000 * time.Microsecond) c <- 0 } func runGame(game []byte) { cpu := chip8.NewCHIP8(game) i := 0 for gameRunning { c := make(chan int) go timeCycle(c) i++ go cpuCycle(cpu, c, i) if i > 7 { i = 0 } x, y := <-c, <-c if x == 0 { println("CPU RUNNING SLOW") println(x, y) } } } func changeGame(event js.Value) { //println(event.Get("target").Get("value").String()) println(event.Get("target").Get("value").String()) elem, ok := gameMap[event.Get("target").Get("value").String()] if ok { println("change event!!!!") gameRunning = false time.Sleep(1 * time.Second) //println("changing games!!") gameRunning = true go runGame(elem()) } else { panic("value not found!") } } func playSound() { beep.Call("play") //window.Get("navigator").Call("vibrate", 300) } func main() { println("CHIP8 IS HERE!") window = js.Global() beep = window.Get("Audio").New("data:audio/mp3;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU2LjI1LjEwMQAAAAAAAAAAAAAA/+NAwAAAAAAAAAAAAFhpbmcAAAAPAAAAAwAAA3YAlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaW8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw////////////////////////////////////////////AAAAAExhdmYAAAAAAAAAAAAAAAAAAAAAACQAAAAAAAAAAAN2UrY2LgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/jYMQAEvgiwl9DAAAAO1ALSi19XgYG7wIAAAJOD5R0HygIAmD5+sEHLB94gBAEP8vKAgGP/BwMf+D4Pgh/DAPg+D5//y4f///8QBhMQBgEAfB8HwfAgIAgAHAGCFAj1fYUCZyIbThYFExkefOCo8Y7JxiQ0mGVaHKwwGCtGCUkY9OCugoFQwDKqmHQiUCxRAKOh4MjJFAnTkq6QqFGavRpYUCmMxpZnGXJa0xiJcTGZb1gJjwOJDJgoUJG5QQuDAsypiumkp5TUjrOobR2liwoGBf/X1nChmipnKVtSmMNQDGitG1fT/JhR+gYdCvy36lTrxCVV8Paaz1otLndT2fZuOMp3VpatmVR3LePP/8bSQpmhQZECqWsFeJxoepX9dbfHS13/////aysppUblm//8t7p2Ez7xKD/42DE4E5z9pr/nNkRw6bhdiCAZVVSktxunhxhH//4xF+bn4//6//3jEvylMM2K9XmWSn3ah1L2MqVIjmNlJtpQux1n3ajA0ZnFSu5EpX////uGatn///////1r/pYabq0mKT//TRyTEFNRTMuOTkuNaqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq/+MQxNIAAANIAcAAAKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqg==") window.Call("addEventListener", "keydown", js.FuncOf(func(this js.Value, args []js.Value) interface{} { keyEventHandle(args[0]) return nil })) window.Call("addEventListener", "keyup", js.FuncOf(func(this js.Value, args []js.Value) interface{} { keyEventHandle(args[0]) return nil })) window.Call("addEventListener", "change", js.FuncOf(func(this js.Value, args []js.Value) interface{} { changeGame(args[0]) return nil })) cvs, _ = canvas.NewCanvas2d(false) cvs.Create(int(width)*sizeMultiplier, int(height)*sizeMultiplier) height = float64(cvs.Height()) width = float64(cvs.Width()) cvs.Start(60, Render) go runGame(getPong()) never_returns := make(chan int) <-never_returns } func Render(gc *draw2dimg.GraphicContext) bool { if !drawNeeded { return false } drawNeeded = false gc.SetFillColor(color.RGBA{0x00, 0x00, 0x00, 0xff}) gc.Clear() gc.SetFillColor(color.RGBA{0x00, 0xff, 0x00, 0xff}) //gc.SetStrokeColor(color.RGBA{0x00, 0xff, 0x00, 0xff}) gc.BeginPath() //gc.ArcTo(gs.laserX, gs.laserY, gs.laserSize, gs.laserSize, 0, math.Pi*2) graphicsLock.Lock() defer graphicsLock.Unlock() for i, val := range drawBuf { if val != 0 { x := i % 64 y := i / 64 // println("drawing to ", x, y) draw2dkit.Rectangle(gc, float64(x*sizeMultiplier), float64(y*sizeMultiplier), float64((x*sizeMultiplier)+sizeMultiplier), float64((y*sizeMultiplier)+sizeMultiplier)) } } gc.FillStroke() gc.Close() //println("drawing") return true }