func main() { runtime.GOMAXPROCS(runtime.NumCPU()) mandala.Verbose = true mandala.Debug = true // Create rendering loop control channels renderLoopControl := newRenderLoopControl() // Start the rendering loop loop.GoRecoverable( renderLoopFunc(renderLoopControl), func(rs loop.Recoverings) (loop.Recoverings, error) { for _, r := range rs { mandala.Logf("%s", r.Reason) mandala.Logf("%s", mandala.Stacktrace()) } return rs, fmt.Errorf("Unrecoverable loop\n") }, ) // Start the event loop loop.GoRecoverable( eventLoopFunc(renderLoopControl), func(rs loop.Recoverings) (loop.Recoverings, error) { for _, r := range rs { mandala.Logf("%s", r.Reason) mandala.Logf("%s", mandala.Stacktrace()) } return rs, fmt.Errorf("Unrecoverable loop\n") }, ) }
// eventLoopFunc listen to events originating from the // framework. func eventLoopFunc(renderLoopControl *renderLoopControl) loop.LoopFunc { return func(loop loop.Loop) error { for { select { case untypedEvent := <-mandala.Events(): switch event := untypedEvent.(type) { // Receive a native window // from the framework and send // it to the render loop in // order to begin the // rendering process. case mandala.NativeWindowCreatedEvent: renderLoopControl.window <- event.Window // Finger down/up on the screen. case mandala.ActionUpDownEvent: if event.Down { renderLoopControl.tapEvent <- [2]float32{event.X, event.Y} } // Finger is moving on the screen. case mandala.ActionMoveEvent: mandala.Logf("Finger is moving at coord %f %f", event.X, event.Y) case mandala.DestroyEvent: mandala.Logf("Quitting from application now...\n") return nil case mandala.NativeWindowRedrawNeededEvent: case mandala.PauseEvent: mandala.Logf("Application was paused. Stopping rendering ticker.") renderLoopControl.pause <- event case mandala.ResumeEvent: mandala.Logf("Application was resumed. Reactivating rendering ticker.") renderLoopControl.resume <- true } } } } }
func (t *TestSuite) timeoutLoopFunc() loop.LoopFunc { return func(loop loop.Loop) error { time := <-t.timeout err := fmt.Errorf("Tests timed out after %v", time) mandala.Logf("%s %s", err.Error(), mandala.Stacktrace()) t.Error(err) return nil } }
// Run runs renderLoop. The loop renders a frame and swaps the buffer // at each tick received. func renderLoopFunc(control *renderLoopControl) loop.LoopFunc { return func(loop loop.Loop) error { var window mandala.Window // Lock/unlock the loop to the current OS thread. This is // necessary because OpenGL functions should be called from // the same thread. runtime.LockOSThread() defer runtime.UnlockOSThread() // Create an instance of ticker and immediately stop // it because we don't want to swap buffers before // initializing a rendering state. ticker := time.NewTicker(time.Duration(1e9 / int(FRAMES_PER_SECOND))) ticker.Stop() for { select { case window = <-control.window: ticker.Stop() window.MakeContextCurrent() width, height := window.GetSize() gl.Viewport(0, 0, width, height) mandala.Logf("Restarting rendering loop...") ticker = time.NewTicker(time.Duration(1e9 / int(FRAMES_PER_SECOND))) // Compute window radius windowRadius = math.Sqrt(math.Pow(float64(height), 2) + math.Pow(float64(width), 2)) //gl.Init() gl.Disable(gl.DEPTH_TEST) // antialiasing gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) //gl.Enable(gl.LINE_SMOOTH) // At each tick render a frame and swap buffers. case <-ticker.C: draw() window.SwapBuffers() case event := <-control.pause: ticker.Stop() event.Paused <- true case <-control.resume: case <-loop.ShallStop(): ticker.Stop() return nil } } } }
// Run runs renderLoop. The loop renders a frame and swaps the buffer // at each tick received. func renderLoopFunc(control *renderLoopControl) loop.LoopFunc { return func(loop loop.Loop) error { var window mandala.Window // Lock/unlock the loop to the current OS thread. This is // necessary because OpenGL functions should be called from // the same thread. runtime.LockOSThread() defer runtime.UnlockOSThread() // Create an instance of ticker and immediately stop // it because we don't want to swap buffers before // initializing a rendering state. ticker := time.NewTicker(time.Duration(1e9 / int(FRAMES_PER_SECOND))) ticker.Stop() for { select { case window = <-control.window: ticker.Stop() window.MakeContextCurrent() width, height := window.GetSize() gl.Viewport(0, 0, gl.Sizei(width), gl.Sizei(height)) mandala.Logf("Restarting rendering loop...") ticker = time.NewTicker(time.Duration(1e9 / int(FRAMES_PER_SECOND))) // At each tick render a frame and swap buffers. case <-ticker.C: draw() window.SwapBuffers() case event := <-control.pause: ticker.Stop() event.Paused <- true case <-control.resume: case <-loop.ShallStop(): ticker.Stop() return nil } } } }
func (t *TestSuite) BeforeAll() { // Create rendering loop control channels t.rlControl = newRenderLoopControl() // Start the rendering loop loop.GoRecoverable( t.renderLoopFunc(t.rlControl), func(rs loop.Recoverings) (loop.Recoverings, error) { for _, r := range rs { mandala.Logf("%s", r.Reason) mandala.Logf("%s", mandala.Stacktrace()) } return rs, fmt.Errorf("Unrecoverable loop\n") }, ) // Start the event loop loop.GoRecoverable( t.eventLoopFunc(t.rlControl), func(rs loop.Recoverings) (loop.Recoverings, error) { for _, r := range rs { mandala.Logf("%s", r.Reason) mandala.Logf("%s", mandala.Stacktrace()) } return rs, fmt.Errorf("Unrecoverable loop\n") }, ) if t.timeout != nil { // Start the timeout loop loop.GoRecoverable( t.timeoutLoopFunc(), func(rs loop.Recoverings) (loop.Recoverings, error) { for _, r := range rs { mandala.Logf("%s", r.Reason) mandala.Logf("%s", mandala.Stacktrace()) } return rs, fmt.Errorf("Unrecoverable loop\n") }, ) } }
// eventLoopFunc listen to events originating from the // framework. func eventLoopFunc(renderLoopControl *renderLoopControl) loop.LoopFunc { return func(loop loop.Loop) error { for { select { // Receive an EGL state from the // framework and notify the render // loop about that. // case eglState := <-mandala.Init: // mandala.Logf("EGL surface initialized W:%d H:%d", eglState.SurfaceWidth, eglState.SurfaceHeight) // renderLoopControl.eglState <- eglState // Receive events from the framework. // // When the application starts the // typical events chain is: // // * onCreate // * onResume // * onInputQueueCreated // * onNativeWindowCreated // * onNativeWindowResized // * onWindowFocusChanged // * onNativeRedrawNeeded // // Pausing (i.e. clicking on the back // button) the application produces // following events chain: // // * onPause // * onWindowDestroy // * onWindowFocusChanged // * onInputQueueDestroy // * onDestroy case untypedEvent := <-mandala.Events(): switch event := untypedEvent.(type) { // Receive a native window // from the framework and send // it to the render loop in // order to begin the // rendering process. case mandala.NativeWindowCreatedEvent: renderLoopControl.window <- event.Window // Finger down/up on the screen. case mandala.ActionUpDownEvent: if event.Down { mandala.Logf("Finger is DOWN at %f %f", event.X, event.Y) } else { mandala.Logf("Finger is now UP") } // Finger is moving on the screen. case mandala.ActionMoveEvent: mandala.Logf("Finger is moving at coord %f %f", event.X, event.Y) case mandala.DestroyEvent: mandala.Logf("Stop rendering...\n") mandala.Logf("Quitting from application...\n") return nil case mandala.NativeWindowRedrawNeededEvent: case mandala.PauseEvent: mandala.Logf("Application was paused. Stopping rendering ticker.") renderLoopControl.pause <- true case mandala.ResumeEvent: mandala.Logf("Application was resumed. Reactivating rendering ticker.") renderLoopControl.resume <- true } } } } }
func check() { error := gl.GetError() if error != 0 { mandala.Logf("An error occurred! Code: 0x%x", error) } }
func main() { runtime.LockOSThread() verbose := flag.Bool("verbose", false, "produce verbose output") debug := flag.Bool("debug", false, "produce debug output") size := flag.String("size", "320x480", "set the size of the window") flag.Parse() if *verbose { mandala.Verbose = true } if *debug { mandala.Debug = true } dims := strings.Split(strings.ToLower(*size), "x") width, err := strconv.Atoi(dims[0]) if err != nil { panic(err) } height, err := strconv.Atoi(dims[1]) if err != nil { panic(err) } if !glfw.Init() { panic("Can't init glfw!") } defer glfw.Terminate() // Enable OpenGL ES 2.0. glfw.WindowHint(glfw.ClientApi, glfw.OpenglEsApi) glfw.WindowHint(glfw.ContextVersionMajor, 2) window, err := glfw.CreateWindow(width, height, "{{.AppName}}", nil, nil) if err != nil { panic(err) } mandala.Init(window) // Create a rendering loop control struct containing a set of // channels that control rendering. renderLoopControl := newRenderLoopControl() // Start the rendering loop loop.GoRecoverable( renderLoopFunc(renderLoopControl), func(rs loop.Recoverings) (loop.Recoverings, error) { for _, r := range rs { mandala.Logf("%s", r.Reason) mandala.Logf("%s", mandala.Stacktrace()) } return rs, fmt.Errorf("Unrecoverable loop\n") }, ) // Start the event loop loop.GoRecoverable( eventLoopFunc(renderLoopControl), func(rs loop.Recoverings) (loop.Recoverings, error) { for _, r := range rs { mandala.Logf("%s", r.Reason) mandala.Logf("%s", mandala.Stacktrace()) } return rs, fmt.Errorf("Unrecoverable loop\n") }, ) for !window.ShouldClose() { glfw.WaitEvents() } }
// Run runs renderLoop. The loop renders a frame and swaps the buffer // at each tick received. func renderLoopFunc(control *renderLoopControl) loop.LoopFunc { return func(loop loop.Loop) error { // renderState keeps the rendering state variables // such as the EGL status renderState := new(renderState) // Lock/unlock the loop to the current OS thread. This is // necessary because OpenGL functions should be called from // the same thread. runtime.LockOSThread() defer runtime.UnlockOSThread() // Create an instance of ticker and immediately stop // it because we don't want to swap buffers before // initializing a rendering state. ticker := time.NewTicker(time.Duration(1e9 / int(FRAMES_PER_SECOND))) ticker.Stop() for { select { case window := <-control.window: ticker.Stop() renderState.init(window) mandala.Logf("Restarting rendering loop...") ticker = time.NewTicker(time.Duration(1e9 / int(FRAMES_PER_SECOND))) // At each tick render a frame and swap buffers. case <-ticker.C: renderState.angle += 0.05 renderState.cube.Rotate(renderState.angle, [3]float32{0, 1, 0}) renderState.world.Draw() renderState.window.SwapBuffers() case viewport := <-control.resizeViewport: if renderState.world != nil { if viewport.width != renderState.world.Width || viewport.height != renderState.world.Height { mandala.Logf("Resize native window W:%v H:%v\n", viewport.width, viewport.height) ticker.Stop() renderState.world.Resize(viewport.width, viewport.height) ticker = time.NewTicker(time.Duration(1e9 / int(FRAMES_PER_SECOND))) } } case event := <-control.pause: renderState.savedAngle = renderState.angle mandala.Logf("Save an angle value of %f", renderState.savedAngle) ticker.Stop() event.Paused <- true case <-control.resume: renderState.angle = renderState.savedAngle mandala.Logf("Restore an angle value of %f", renderState.angle) case <-loop.ShallStop(): ticker.Stop() return nil } } } }