github.com/SahandAslani/gomobile@v0.0.0-20210909130135-2cb2d44c09b2/exp/app/debug/fps.go (about)

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build darwin || linux || windows
     6  // +build darwin linux windows
     7  
     8  // Package debug provides GL-based debugging tools for apps.
     9  package debug // import "github.com/SahandAslani/gomobile/exp/app/debug"
    10  
    11  import (
    12  	"image"
    13  	"image/color"
    14  	"image/draw"
    15  	"time"
    16  
    17  	"github.com/SahandAslani/gomobile/event/size"
    18  	"github.com/SahandAslani/gomobile/exp/gl/glutil"
    19  	"github.com/SahandAslani/gomobile/geom"
    20  )
    21  
    22  // FPS draws a count of the frames rendered per second.
    23  type FPS struct {
    24  	sz       size.Event
    25  	images   *glutil.Images
    26  	m        *glutil.Image
    27  	lastDraw time.Time
    28  	// TODO: store *gl.Context
    29  }
    30  
    31  // NewFPS creates an FPS tied to the current GL context.
    32  func NewFPS(images *glutil.Images) *FPS {
    33  	return &FPS{
    34  		lastDraw: time.Now(),
    35  		images:   images,
    36  	}
    37  }
    38  
    39  // Draw draws the per second framerate in the bottom-left of the screen.
    40  func (p *FPS) Draw(sz size.Event) {
    41  	const imgW, imgH = 7*(fontWidth+1) + 1, fontHeight + 2
    42  
    43  	if sz.WidthPx == 0 && sz.HeightPx == 0 {
    44  		return
    45  	}
    46  	if p.sz != sz {
    47  		p.sz = sz
    48  		if p.m != nil {
    49  			p.m.Release()
    50  		}
    51  		p.m = p.images.NewImage(imgW, imgH)
    52  	}
    53  
    54  	display := [7]byte{
    55  		4: 'F',
    56  		5: 'P',
    57  		6: 'S',
    58  	}
    59  	now := time.Now()
    60  	f := 0
    61  	if dur := now.Sub(p.lastDraw); dur > 0 {
    62  		f = int(time.Second / dur)
    63  	}
    64  	display[2] = '0' + byte((f/1e0)%10)
    65  	display[1] = '0' + byte((f/1e1)%10)
    66  	display[0] = '0' + byte((f/1e2)%10)
    67  	draw.Draw(p.m.RGBA, p.m.RGBA.Bounds(), image.White, image.Point{}, draw.Src)
    68  	for i, c := range display {
    69  		glyph := glyphs[c]
    70  		if len(glyph) != fontWidth*fontHeight {
    71  			continue
    72  		}
    73  		for y := 0; y < fontHeight; y++ {
    74  			for x := 0; x < fontWidth; x++ {
    75  				if glyph[fontWidth*y+x] == ' ' {
    76  					continue
    77  				}
    78  				p.m.RGBA.SetRGBA((fontWidth+1)*i+x+1, y+1, color.RGBA{A: 0xff})
    79  			}
    80  		}
    81  	}
    82  
    83  	p.m.Upload()
    84  	p.m.Draw(
    85  		sz,
    86  		geom.Point{0, sz.HeightPt - imgH},
    87  		geom.Point{imgW, sz.HeightPt - imgH},
    88  		geom.Point{0, sz.HeightPt},
    89  		p.m.RGBA.Bounds(),
    90  	)
    91  
    92  	p.lastDraw = now
    93  }
    94  
    95  func (f *FPS) Release() {
    96  	if f.m != nil {
    97  		f.m.Release()
    98  		f.m = nil
    99  		f.images = nil
   100  	}
   101  }
   102  
   103  const (
   104  	fontWidth  = 5
   105  	fontHeight = 7
   106  )
   107  
   108  // glyphs comes from the 6x10 fixed font from the plan9port:
   109  // https://github.com/9fans/plan9port/tree/master/font/fixed
   110  //
   111  // 6x10 becomes 5x7 because each glyph has a 1-pixel margin plus space for
   112  // descenders.
   113  //
   114  // Its README file says that those fonts were converted from XFree86, and are
   115  // in the public domain.
   116  var glyphs = [256]string{
   117  	'0': "" +
   118  		"  X  " +
   119  		" X X " +
   120  		"X   X" +
   121  		"X   X" +
   122  		"X   X" +
   123  		" X X " +
   124  		"  X  ",
   125  	'1': "" +
   126  		"  X  " +
   127  		" XX  " +
   128  		"X X  " +
   129  		"  X  " +
   130  		"  X  " +
   131  		"  X  " +
   132  		"XXXXX",
   133  	'2': "" +
   134  		" XXX " +
   135  		"X   X" +
   136  		"    X" +
   137  		"  XX " +
   138  		" X   " +
   139  		"X    " +
   140  		"XXXXX",
   141  	'3': "" +
   142  		"XXXXX" +
   143  		"    X" +
   144  		"   X " +
   145  		"  XX " +
   146  		"    X" +
   147  		"X   X" +
   148  		" XXX ",
   149  	'4': "" +
   150  		"   X " +
   151  		"  XX " +
   152  		" X X " +
   153  		"X  X " +
   154  		"XXXXX" +
   155  		"   X " +
   156  		"   X ",
   157  	'5': "" +
   158  		"XXXXX" +
   159  		"X    " +
   160  		"X XX " +
   161  		"XX  X" +
   162  		"    X" +
   163  		"X   X" +
   164  		" XXX ",
   165  	'6': "" +
   166  		"  XX " +
   167  		" X   " +
   168  		"X    " +
   169  		"X XX " +
   170  		"XX  X" +
   171  		"X   X" +
   172  		" XXX ",
   173  	'7': "" +
   174  		"XXXXX" +
   175  		"    X" +
   176  		"   X " +
   177  		"   X " +
   178  		"  X  " +
   179  		" X   " +
   180  		" X   ",
   181  	'8': "" +
   182  		" XXX " +
   183  		"X   X" +
   184  		"X   X" +
   185  		" XXX " +
   186  		"X   X" +
   187  		"X   X" +
   188  		" XXX ",
   189  	'9': "" +
   190  		" XXX " +
   191  		"X   X" +
   192  		"X  XX" +
   193  		" XX X" +
   194  		"    X" +
   195  		"   X " +
   196  		" XX  ",
   197  	'F': "" +
   198  		"XXXXX" +
   199  		"X    " +
   200  		"X    " +
   201  		"XXXX " +
   202  		"X    " +
   203  		"X    " +
   204  		"X    ",
   205  	'P': "" +
   206  		"XXXX " +
   207  		"X   X" +
   208  		"X   X" +
   209  		"XXXX " +
   210  		"X    " +
   211  		"X    " +
   212  		"X    ",
   213  	'S': "" +
   214  		" XXX " +
   215  		"X   X" +
   216  		"X    " +
   217  		" XXX " +
   218  		"    X" +
   219  		"X   X" +
   220  		" XXX ",
   221  }