zorldo

Goofing around with Ebiten
git clone git://bsandro.tech/zorldo
Log | Files | Refs | README

screen.go (11931B)


      1 // Copyright 2015 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 // Package screen provides interfaces for portable two-dimensional graphics and
      6 // input events.
      7 //
      8 // Screens are not created directly. Instead, driver packages provide access to
      9 // the screen through a Main function that is designed to be called by the
     10 // program's main function. The golang.org/x/exp/shiny/driver package provides
     11 // the default driver for the system, such as the X11 driver for desktop Linux,
     12 // but other drivers, such as the OpenGL driver, can be explicitly invoked by
     13 // calling that driver's Main function. To use the default driver:
     14 //
     15 //	package main
     16 //
     17 //	import (
     18 //		"golang.org/x/exp/shiny/driver"
     19 //		"golang.org/x/exp/shiny/screen"
     20 //		"golang.org/x/mobile/event/lifecycle"
     21 //	)
     22 //
     23 //	func main() {
     24 //		driver.Main(func(s screen.Screen) {
     25 //			w, err := s.NewWindow(nil)
     26 //			if err != nil {
     27 //				handleError(err)
     28 //				return
     29 //			}
     30 //			defer w.Release()
     31 //
     32 //			for {
     33 //				switch e := w.NextEvent().(type) {
     34 //				case lifecycle.Event:
     35 //					if e.To == lifecycle.StageDead {
     36 //						return
     37 //					}
     38 //					etc
     39 //				case etc:
     40 //					etc
     41 //				}
     42 //			}
     43 //		})
     44 //	}
     45 //
     46 // Complete examples can be found in the shiny/example directory.
     47 //
     48 // Each driver package provides Screen, Buffer, Texture and Window
     49 // implementations that work together. Such types are interface types because
     50 // this package is driver-independent, but those interfaces aren't expected to
     51 // be implemented outside of drivers. For example, a driver's Window
     52 // implementation will generally work only with that driver's Buffer
     53 // implementation, and will not work with an arbitrary type that happens to
     54 // implement the Buffer methods.
     55 package screen // import "golang.org/x/exp/shiny/screen"
     56 
     57 import (
     58 	"image"
     59 	"image/color"
     60 	"image/draw"
     61 	"unicode/utf8"
     62 
     63 	"golang.org/x/image/math/f64"
     64 )
     65 
     66 // TODO: specify image format (Alpha or Gray, not just RGBA) for NewBuffer
     67 // and/or NewTexture?
     68 
     69 // Screen creates Buffers, Textures and Windows.
     70 type Screen interface {
     71 	// NewBuffer returns a new Buffer for this screen.
     72 	NewBuffer(size image.Point) (Buffer, error)
     73 
     74 	// NewTexture returns a new Texture for this screen.
     75 	NewTexture(size image.Point) (Texture, error)
     76 
     77 	// NewWindow returns a new Window for this screen.
     78 	//
     79 	// A nil opts is valid and means to use the default option values.
     80 	NewWindow(opts *NewWindowOptions) (Window, error)
     81 }
     82 
     83 // TODO: rename Buffer to Image, to be less confusing with a Window's back and
     84 // front buffers.
     85 
     86 // Buffer is an in-memory pixel buffer. Its pixels can be modified by any Go
     87 // code that takes an *image.RGBA, such as the standard library's image/draw
     88 // package. A Buffer is essentially an *image.RGBA, but not all *image.RGBA
     89 // values (including those returned by image.NewRGBA) are valid Buffers, as a
     90 // driver may assume that the memory backing a Buffer's pixels are specially
     91 // allocated.
     92 //
     93 // To see a Buffer's contents on a screen, upload it to a Texture (and then
     94 // draw the Texture on a Window) or upload it directly to a Window.
     95 //
     96 // When specifying a sub-Buffer via Upload, a Buffer's top-left pixel is always
     97 // (0, 0) in its own coordinate space.
     98 type Buffer interface {
     99 	// Release releases the Buffer's resources, after all pending uploads and
    100 	// draws resolve.
    101 	//
    102 	// The behavior of the Buffer after Release, whether calling its methods or
    103 	// passing it as an argument, is undefined.
    104 	Release()
    105 
    106 	// Size returns the size of the Buffer's image.
    107 	Size() image.Point
    108 
    109 	// Bounds returns the bounds of the Buffer's image. It is equal to
    110 	// image.Rectangle{Max: b.Size()}.
    111 	Bounds() image.Rectangle
    112 
    113 	// RGBA returns the pixel buffer as an *image.RGBA.
    114 	//
    115 	// Its contents should not be accessed while the Buffer is uploading.
    116 	//
    117 	// The contents of the returned *image.RGBA's Pix field (of type []byte)
    118 	// can be modified at other times, but that Pix slice itself (i.e. its
    119 	// underlying pointer, length and capacity) should not be modified at any
    120 	// time.
    121 	//
    122 	// The following is valid:
    123 	//	m := buffer.RGBA()
    124 	//	if len(m.Pix) >= 4 {
    125 	//		m.Pix[0] = 0xff
    126 	//		m.Pix[1] = 0x00
    127 	//		m.Pix[2] = 0x00
    128 	//		m.Pix[3] = 0xff
    129 	//	}
    130 	// or, equivalently:
    131 	//	m := buffer.RGBA()
    132 	//	m.SetRGBA(m.Rect.Min.X, m.Rect.Min.Y, color.RGBA{0xff, 0x00, 0x00, 0xff})
    133 	// and using the standard library's image/draw package is also valid:
    134 	//	dst := buffer.RGBA()
    135 	//	draw.Draw(dst, dst.Bounds(), etc)
    136 	// but the following is invalid:
    137 	//	m := buffer.RGBA()
    138 	//	m.Pix = anotherByteSlice
    139 	// and so is this:
    140 	//	*buffer.RGBA() = anotherImageRGBA
    141 	RGBA() *image.RGBA
    142 }
    143 
    144 // Texture is a pixel buffer, but not one that is directly accessible as a
    145 // []byte. Conceptually, it could live on a GPU, in another process or even be
    146 // across a network, instead of on a CPU in this process.
    147 //
    148 // Buffers can be uploaded to Textures, and Textures can be drawn on Windows.
    149 //
    150 // When specifying a sub-Texture via Draw, a Texture's top-left pixel is always
    151 // (0, 0) in its own coordinate space.
    152 type Texture interface {
    153 	// Release releases the Texture's resources, after all pending uploads and
    154 	// draws resolve.
    155 	//
    156 	// The behavior of the Texture after Release, whether calling its methods
    157 	// or passing it as an argument, is undefined.
    158 	Release()
    159 
    160 	// Size returns the size of the Texture's image.
    161 	Size() image.Point
    162 
    163 	// Bounds returns the bounds of the Texture's image. It is equal to
    164 	// image.Rectangle{Max: t.Size()}.
    165 	Bounds() image.Rectangle
    166 
    167 	Uploader
    168 
    169 	// TODO: also implement Drawer? If so, merge the Uploader and Drawer
    170 	// interfaces??
    171 }
    172 
    173 // EventDeque is an infinitely buffered double-ended queue of events.
    174 type EventDeque interface {
    175 	// Send adds an event to the end of the deque. They are returned by
    176 	// NextEvent in FIFO order.
    177 	Send(event interface{})
    178 
    179 	// SendFirst adds an event to the start of the deque. They are returned by
    180 	// NextEvent in LIFO order, and have priority over events sent via Send.
    181 	SendFirst(event interface{})
    182 
    183 	// NextEvent returns the next event in the deque. It blocks until such an
    184 	// event has been sent.
    185 	//
    186 	// Typical event types include:
    187 	//	- lifecycle.Event
    188 	//	- size.Event
    189 	//	- paint.Event
    190 	//	- key.Event
    191 	//	- mouse.Event
    192 	//	- touch.Event
    193 	// from the golang.org/x/mobile/event/... packages. Other packages may send
    194 	// events, of those types above or of other types, via Send or SendFirst.
    195 	NextEvent() interface{}
    196 
    197 	// TODO: LatestLifecycleEvent? Is that still worth it if the
    198 	// lifecycle.Event struct type loses its DrawContext field?
    199 
    200 	// TODO: LatestSizeEvent?
    201 }
    202 
    203 // Window is a top-level, double-buffered GUI window.
    204 type Window interface {
    205 	// Release closes the window.
    206 	//
    207 	// The behavior of the Window after Release, whether calling its methods or
    208 	// passing it as an argument, is undefined.
    209 	Release()
    210 
    211 	EventDeque
    212 
    213 	Uploader
    214 
    215 	Drawer
    216 
    217 	// Publish flushes any pending Upload and Draw calls to the window, and
    218 	// swaps the back buffer to the front.
    219 	Publish() PublishResult
    220 }
    221 
    222 // PublishResult is the result of an Window.Publish call.
    223 type PublishResult struct {
    224 	// BackBufferPreserved is whether the contents of the back buffer was
    225 	// preserved. If false, the contents are undefined.
    226 	BackBufferPreserved bool
    227 }
    228 
    229 // NewWindowOptions are optional arguments to NewWindow.
    230 type NewWindowOptions struct {
    231 	// Width and Height specify the dimensions of the new window. If Width
    232 	// or Height are zero, a driver-dependent default will be used for each
    233 	// zero value dimension.
    234 	Width, Height int
    235 
    236 	// Title specifies the window title.
    237 	Title string
    238 
    239 	// TODO: fullscreen, icon, cursorHidden?
    240 }
    241 
    242 // GetTitle returns a sanitized form of o.Title. In particular, its length will
    243 // not exceed 4096, and it may be further truncated so that it is valid UTF-8
    244 // and will not contain the NUL byte.
    245 //
    246 // o may be nil, in which case "" is returned.
    247 func (o *NewWindowOptions) GetTitle() string {
    248 	if o == nil {
    249 		return ""
    250 	}
    251 	return sanitizeUTF8(o.Title, 4096)
    252 }
    253 
    254 func sanitizeUTF8(s string, n int) string {
    255 	if n < len(s) {
    256 		s = s[:n]
    257 	}
    258 	i := 0
    259 	for i < len(s) {
    260 		r, n := utf8.DecodeRuneInString(s[i:])
    261 		if r == 0 || (r == utf8.RuneError && n == 1) {
    262 			break
    263 		}
    264 		i += n
    265 	}
    266 	return s[:i]
    267 }
    268 
    269 // Uploader is something you can upload a Buffer to.
    270 type Uploader interface {
    271 	// Upload uploads the sub-Buffer defined by src and sr to the destination
    272 	// (the method receiver), such that sr.Min in src-space aligns with dp in
    273 	// dst-space. The destination's contents are overwritten; the draw operator
    274 	// is implicitly draw.Src.
    275 	//
    276 	// It is valid to upload a Buffer while another upload of the same Buffer
    277 	// is in progress, but a Buffer's image.RGBA pixel contents should not be
    278 	// accessed while it is uploading. A Buffer is re-usable, in that its pixel
    279 	// contents can be further modified, once all outstanding calls to Upload
    280 	// have returned.
    281 	//
    282 	// TODO: make it optional that a Buffer's contents is preserved after
    283 	// Upload? Undoing a swizzle is a non-trivial amount of work, and can be
    284 	// redundant if the next paint cycle starts by clearing the buffer.
    285 	//
    286 	// When uploading to a Window, there will not be any visible effect until
    287 	// Publish is called.
    288 	Upload(dp image.Point, src Buffer, sr image.Rectangle)
    289 
    290 	// Fill fills that part of the destination (the method receiver) defined by
    291 	// dr with the given color.
    292 	//
    293 	// When filling a Window, there will not be any visible effect until
    294 	// Publish is called.
    295 	Fill(dr image.Rectangle, src color.Color, op draw.Op)
    296 }
    297 
    298 // TODO: have a Downloader interface? Not every graphical app needs to be
    299 // interactive or involve a window. You could use the GPU for hardware-
    300 // accelerated image manipulation: upload a buffer, do some texture ops, then
    301 // download the result.
    302 
    303 // Drawer is something you can draw Textures on.
    304 //
    305 // Draw is the most general purpose of this interface's methods. It supports
    306 // arbitrary affine transformations, such as translations, scales and
    307 // rotations.
    308 //
    309 // Copy and Scale are more specific versions of Draw. The affected dst pixels
    310 // are an axis-aligned rectangle, quantized to the pixel grid. Copy copies
    311 // pixels in a 1:1 manner, Scale is more general. They have simpler parameters
    312 // than Draw, using ints instead of float64s.
    313 //
    314 // When drawing on a Window, there will not be any visible effect until Publish
    315 // is called.
    316 type Drawer interface {
    317 	// Draw draws the sub-Texture defined by src and sr to the destination (the
    318 	// method receiver). src2dst defines how to transform src coordinates to
    319 	// dst coordinates. For example, if src2dst is the matrix
    320 	//
    321 	// m00 m01 m02
    322 	// m10 m11 m12
    323 	//
    324 	// then the src-space point (sx, sy) maps to the dst-space point
    325 	// (m00*sx + m01*sy + m02, m10*sx + m11*sy + m12).
    326 	Draw(src2dst f64.Aff3, src Texture, sr image.Rectangle, op draw.Op, opts *DrawOptions)
    327 
    328 	// DrawUniform is like Draw except that the src is a uniform color instead
    329 	// of a Texture.
    330 	DrawUniform(src2dst f64.Aff3, src color.Color, sr image.Rectangle, op draw.Op, opts *DrawOptions)
    331 
    332 	// Copy copies the sub-Texture defined by src and sr to the destination
    333 	// (the method receiver), such that sr.Min in src-space aligns with dp in
    334 	// dst-space.
    335 	Copy(dp image.Point, src Texture, sr image.Rectangle, op draw.Op, opts *DrawOptions)
    336 
    337 	// Scale scales the sub-Texture defined by src and sr to the destination
    338 	// (the method receiver), such that sr in src-space is mapped to dr in
    339 	// dst-space.
    340 	Scale(dr image.Rectangle, src Texture, sr image.Rectangle, op draw.Op, opts *DrawOptions)
    341 }
    342 
    343 // These draw.Op constants are provided so that users of this package don't
    344 // have to explicitly import "image/draw".
    345 const (
    346 	Over = draw.Over
    347 	Src  = draw.Src
    348 )
    349 
    350 // DrawOptions are optional arguments to Draw.
    351 type DrawOptions struct {
    352 	// TODO: transparency in [0x0000, 0xffff]?
    353 	// TODO: scaler (nearest neighbor vs linear)?
    354 }