func (sg *OpenGLGraphics) Text(x, y int, t string, align string, rot int, f chart.Font) { if len(align) == 1 { align = "c" + align } _, fh, _ := sg.FontMetrics(f) tex := glh.MakeText(t, float64(fh)) tex.Flipped = true defer tex.Destroy() switch align[0] { case 'b': case 'c': y += fh / 2 case 't': y += fh default: log.Panicf("Unknown alignment: ", align) } switch align[1] { case 'l': case 'c': x -= tex.W / 2 case 'r': x -= tex.W default: log.Panicf("Unknown alignment: ", align) } if f.Color == nil { gl.Color4f(1, 1, 1, 1) } else { glh.ColorC(f.Color) } glh.With(tex, func() { tex.Draw(x, y) }) }
func main_loop(data *ProgramData) { start := time.Now() frames := 0 lastblocks := 0 // Frame counter go func() { for { time.Sleep(time.Second) if *verbose { memstats := new(runtime.MemStats) runtime.ReadMemStats(memstats) fps := float64(frames) / time.Since(start).Seconds() blocks := len(data.blocks) bps := float64(blocks-lastblocks) / time.Since(start).Seconds() lastblocks = blocks log.Printf("fps = %5.2f; blocks = %4d; bps = %5.2f sparemem = %6d MB; alloc'd = %6.6f; (+footprint = %6.6f)", fps, len(data.blocks), bps, SpareRAM(), float64(memstats.Alloc)/1024/1024, float64(memstats.Sys-memstats.Alloc)/1024/1024) PrintTimers(frames) } start = time.Now() frames = 0 } }() // Necessary at the moment to prevent eventual OOM go func() { for { time.Sleep(5 * time.Second) if *verbose { log.Print("GC()") } runtime.GC() if *verbose { GCStats() } } }() var i int64 = -int64(*nback) // TODO(pwaller): Make this work again // text := glh.MakeText(data.filename, 32) // Location of mouse in record space var rec, rec_actual int64 = 0, 0 var stacktext, dwarftext []*glh.Text var recordtext *glh.Text = nil var mousex, mousey, mousedownx, mousedowny int var mousepx, mousepy float64 var lbutton bool escape_hit := false glfw.SetMouseWheelCallback(func(pos int) { nback_prev := *nback if pos < 0 { *nback = 40 * 1024 << uint(-pos) } else { *nback = 40 * 1024 >> uint(pos) } //log.Print("Mousewheel position: ", pos, " nback: ", *nback) if rec == 0 { return } // mouse cursor is at screen "rec_actual", and it should be after // the transformation // We need to adjust `i` to keep this value constant: // rec_actual == i + int64(constpart * float64(*nback)) // where constpart <- (-const + 2.) / 4. // (that way, the mouse is still pointing at the same place after scaling) constpart := float64(rec_actual-i) / float64(nback_prev) rec_actual_after := i + int64(constpart*float64(*nback)) delta := rec_actual_after - rec_actual i -= delta // Ensure the mouse cursor position doesn't change when zooming rec = rec_actual - i }) update_text := func() { if DoneThisFrame(RenderText) { return } if recordtext != nil { recordtext.Destroy() recordtext = nil } //r := 0 //data.GetRecord(rec_actual) //if r != nil { //log.Print(data.records[rec_actual]) //recordtext = MakeText(r.String(), 32) //} for j := range stacktext { stacktext[j].Destroy() } // TODO: Load records on demand if false { stack := data.GetStackNames(rec_actual) stacktext = make([]*glh.Text, len(stack)) for j := range stack { stacktext[j] = glh.MakeText(stack[j], 32) } } } glfw.SetMouseButtonCallback(func(button, action int) { switch button { case glfw.Mouse1: switch action { case glfw.KeyPress: mousedownx, mousedowny = mousex, mousey lbutton = true r := data.GetRecord(rec_actual) if r != nil { if r.Type == MEMA_ACCESS { log.Print(r) ma := r.MemAccess() dwarf := data.GetDwarf(ma.Pc) log.Print("Can has dwarf? ", len(dwarf)) for i := range dwarf { log.Print(" ", dwarf[i]) //recordtext = MakeText(data.records[rec_actual].String(), 32) } log.Print("") for j := range dwarftext { dwarftext[j].Destroy() } dwarftext = make([]*glh.Text, len(dwarf)) for j := range dwarf { dwarftext[j] = glh.MakeText(fmt.Sprintf("%q", dwarf[j]), 32) } } //recordtext = MakeText(data.records[rec_actual].String(), 32) } case glfw.KeyRelease: lbutton = false } } }) glfw.SetMousePosCallback(func(x, y int) { px, py := glh.WindowToProj(x, y) // Record index rec = int64((py+2)*float64(*nback)/4. + 0.5) rec_actual = rec + i dpy := py - mousepy di := int64(-dpy * float64(*nback) / 4.) if lbutton { i += di } mousepx, mousepy = px, py mousex, mousey = x, y //log.Printf("Mouse motion: (%3d, %3d), (%f, %f), (%d, %d) dpy=%f di=%d", //x, y, px, py, rec, rec_actual, dpy, di) update_text() }) glfw.SetKeyCallback(func(key, state int) { switch key { case glfw.KeyEsc: escape_hit = true } }) draw_mousepoint := func() { // Draw the mouse point glh.With(glh.Matrix{gl.MODELVIEW}, func() { gl.Translated(0, -2, 0) gl.Scaled(1, 4/float64(*nback), 1) gl.Translated(0, float64(rec), 0) gl.PointSize(10) glh.With(glh.Primitive{gl.POINTS}, func() { gl.Color4f(1, 1, 1, 1) gl.Vertex3d(mousepx, 0, 0) }) }) } draw_text := func() { // Draw any text glh.With(glh.WindowCoords{}, func() { w, h := glh.GetViewportWHD() glh.With(glh.Attrib{gl.ENABLE_BIT}, func() { gl.Enable(gl.TEXTURE_2D) // text.Draw(0, 0) for text_idx := range stacktext { stacktext[text_idx].Draw(int(w*0.55), int(h)-35-text_idx*16) } for text_idx := range dwarftext { dwarftext[text_idx].Draw(int(w*0.55), 35+text_idx*16) } if recordtext != nil { recordtext.Draw(int(w*0.55), 35) } }) }) } Draw = func() { gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) // Draw the memory access/function data data.Draw(i, *nback) draw_mousepoint() draw_text() // Visible region quad // gl.Color4f(1, 1, 1, 0.25) // DrawQuadd(-2.1, -2.25, 4.4, 2.1 - -2.25) // StatsHUD() } interrupt := make(chan os.Signal) signal.Notify(interrupt, os.Interrupt) ctrlc_hit := false go func() { <-interrupt ctrlc_hit = true }() done := false for !done { done_this_frame = make(map[WorkType]bool) glh.With(&Timer{Name: "Draw"}, func() { Draw() }) glfw.SwapBuffers() DoMainThreadWork() done = ctrlc_hit || escape_hit || glfw.WindowParam(glfw.Opened) == 0 frames += 1 } }