github.com/racerxdl/gonx@v0.0.0-20210103083128-c5afc43bcbd2/services/display/frame.go (about)

     1  package display
     2  
     3  import (
     4  	"github.com/racerxdl/gonx/font"
     5  	"github.com/racerxdl/gonx/nx/nxtypes"
     6  	"github.com/racerxdl/gonx/svc"
     7  	"image"
     8  	"image/color"
     9  	"time"
    10  	"unsafe"
    11  )
    12  
    13  const minScreenFps = 30 // 30 fps
    14  const vsyncTimeout = time.Second / minScreenFps
    15  
    16  type Frame struct {
    17  	surface     *Surface
    18  	buff        []byte // Local Image Buffer
    19  	surfaceBuff []byte // GPU Remote Buffer
    20  	bounds      image.Rectangle
    21  }
    22  
    23  func (f *Frame) Convert(c color.Color) color.Color {
    24  	return c
    25  }
    26  
    27  // ColorModel returns the Image's color model.
    28  func (f *Frame) ColorModel() color.Model {
    29  	return f
    30  }
    31  
    32  // Bounds returns the domain for which At can return non-zero color.
    33  // The bounds do not necessarily contain the point (0, 0).
    34  func (f *Frame) Bounds() image.Rectangle {
    35  	return f.bounds
    36  }
    37  
    38  // At returns the color of the pixel at (x, y).
    39  // At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
    40  // At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
    41  func (f *Frame) At(x, y int) color.Color {
    42  	w := f.bounds.Size().X
    43  	off := (y*w + x) * 4
    44  	_ = f.buff[off+3]
    45  	return color.RGBA{
    46  		R: f.buff[off+0],
    47  		G: f.buff[off+1],
    48  		B: f.buff[off+2],
    49  		A: f.buff[off+3],
    50  	}
    51  }
    52  
    53  func (f *Frame) Size() (x, y int16) {
    54  	return int16(f.Bounds().Size().X), int16(f.Bounds().Size().Y)
    55  }
    56  
    57  func (f *Frame) SetPixel(x, y int16, c color.RGBA) {
    58  	w := f.bounds.Size().X
    59  	off := (int(y)*w + int(x)) * 4
    60  	_ = f.buff[off+3]
    61  	f.buff[off+0] = c.R
    62  	f.buff[off+1] = c.G
    63  	f.buff[off+2] = c.B
    64  	f.buff[off+3] = c.A
    65  }
    66  
    67  //go:nobounds
    68  func (f *Frame) Clear(c color.RGBA) {
    69  	u32color := (uint32(c.A) << 24) + (uint32(c.B) << 16) + (uint32(c.G) << 8) + uint32(c.R)
    70  	u32len := len(f.buff) / 4
    71  
    72  	for i := 0; i < u32len; i++ {
    73  		*(*uint32)(unsafe.Pointer(&f.buff[i*4])) = u32color
    74  	}
    75  }
    76  
    77  func (f *Frame) DrawStringAt(x, y int, data string, c color.RGBA, font *font.Data) {
    78  	cx := x
    79  	cy := y
    80  	for _, v := range data {
    81  		if v == '\n' {
    82  			cy += font.CharHeight
    83  			cx = x
    84  			continue
    85  		}
    86  		if v == '\r' {
    87  			continue
    88  		}
    89  		g := font.GetGlyph(uint32(v))
    90  		g.DrawAt(cx, cy, c, f.buff, f.bounds.Size().X)
    91  		cx += font.CharWidth
    92  	}
    93  }
    94  
    95  func (f *Frame) Display() error {
    96  	s := f.bounds.Size()
    97  	GFXSlowSwizzlingBlit(f.surfaceBuff, f.buff, s.X, s.Y, 0, 0)
    98  	err := f.surface.QueueBuffer()
    99  	if err != nil {
   100  		return err
   101  	}
   102  
   103  	return f.surface.refreshFrame(f)
   104  }
   105  
   106  func (f *Frame) WaitVSync() error {
   107  	vsync, err := GetVSyncEvent()
   108  	if err != nil {
   109  		return err
   110  	}
   111  
   112  	return svc.WaitSynchronizationSingle(nxtypes.Handle(vsync), vsyncTimeout)
   113  }
   114  
   115  func (f *Frame) Destroy() error {
   116  	if f.surface.State == SURFACE_STATE_DEQUEUED {
   117  		return f.surface.QueueBuffer()
   118  	}
   119  	return nil
   120  }