func updateCamera(ws *websocket.WebSocket, gl *webgl.Context, renderer <-chan struct{}) { const tick30hz = (1000 / 30) * time.Millisecond var ( camera trace.FreeFlightCamera oldPos [3]float32 positions = make(chan [3]float32, 1) ) positions <- oldPos go func() { for { pos := <-positions fmt.Println("New position:", pos) m, err := json.Marshal(updateMessage{Position: pos}) assert(err) assert(ws.Send(string(m))) <-renderer } }() for _ = range time.Tick(tick30hz) { switch { case keys[38]: // Up camera.YRot += cameraSpeed case keys[40]: // Down camera.YRot -= cameraSpeed case keys[37]: // Left camera.XRot += cameraSpeed case keys[39]: // Right camera.XRot -= cameraSpeed case keys[87]: // W camera.Move(cameraSpeed) case keys[83]: // S camera.Move(-cameraSpeed) case keys[65]: // A camera.Strafe(cameraSpeed) case keys[68]: // D camera.Strafe(-cameraSpeed) case keys[69]: // E camera.Lift(cameraSpeed) case keys[81]: // Q camera.Lift(-cameraSpeed) } if oldPos != camera.Pos { select { case positions <- camera.Pos: oldPos = camera.Pos default: } } mat := mat4.Ident mat.AssignEulerRotation(camera.XRot, camera.YRot, 0) mat.Transpose() gl.UniformMatrix4fv(uniformViewLocation, false, mat.Slice()) gl.DrawArrays(gl.TRIANGLES, 0, 6) } }