internal/ui: refactoring: reduce global functions and prefer Get()

This commit is contained in:
Hajime Hoshi 2023-10-15 00:06:07 +09:00
parent 69f1fa5f29
commit 27fd10595b
30 changed files with 226 additions and 214 deletions

View File

@ -44,7 +44,7 @@ type State struct {
//
// Start returns nil and nil if the current environment doesn't support this package.
func Start(x, y int) (states chan State, close func()) {
cx, cy := ui.LogicalPositionToClientPosition(float64(x), float64(y))
cx, cy := ui.Get().LogicalPositionToClientPosition(float64(x), float64(y))
return theTextInput.Start(int(cx), int(cy))
}

View File

@ -58,7 +58,7 @@ var theTextInput textInput
func (t *textInput) Start(x, y int) (chan State, func()) {
var session *session
ui.RunOnMainThread(func() {
ui.Get().RunOnMainThread(func() {
if t.session != nil {
t.session.end()
t.session = nil

View File

@ -1068,7 +1068,7 @@ func newImage(bounds image.Rectangle, imageType atlas.ImageType) *Image {
}
i := &Image{
image: ui.NewImage(width, height, imageType),
image: ui.Get().NewImage(width, height, imageType),
bounds: bounds,
}
i.addr = i

View File

@ -52,7 +52,7 @@ func takeScreenshot(screen *Image, transparent bool) error {
}
func dumpInternalImages() error {
dumpedDir, err := ui.DumpImages("internalimages_" + datetimeForFilename())
dumpedDir, err := ui.Get().DumpImages("internalimages_" + datetimeForFilename())
if err != nil {
return err
}

View File

@ -76,7 +76,7 @@ func IsKeyPressed(key Key) bool {
//
// KeyName is concurrent-safe.
func KeyName(key Key) string {
return ui.KeyName(ui.Key(key))
return ui.Get().KeyName(ui.Key(key))
}
// CursorPosition returns a position of a mouse cursor relative to the game screen (window). The cursor position is

View File

@ -117,7 +117,7 @@ func TestEnsureIsolatedFromSourceBackend(t *testing.T) {
}
pix = make([]byte, 4*size*size)
if err := img4.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(0, 0, size, size)); err != nil {
if err := img4.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, size, size)); err != nil {
t.Fatal(err)
}
for j := 0; j < size; j++ {
@ -195,7 +195,7 @@ func TestReputOnSourceBackend(t *testing.T) {
// Use the doubled count since img1 was on a texture atlas and became an isolated image once.
// Then, img1 requires longer time to recover to be on a texture atlas again.
for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ {
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting())
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
vs := quadVertices(size, size, 0, 0, 1)
img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false)
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
@ -203,16 +203,16 @@ func TestReputOnSourceBackend(t *testing.T) {
}
}
// Finally, img1 is on a source backend.
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting())
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
vs := quadVertices(size, size, 0, 0, 1)
img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false)
if got, want := img1.IsOnSourceBackendForTesting(), true; got != want {
t.Errorf("got: %v, want: %v", got, want)
}
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting())
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
pix = make([]byte, 4*size*size)
if err := img1.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(0, 0, size, size)); err != nil {
if err := img1.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, size, size)); err != nil {
t.Fatal(err)
}
for j := 0; j < size; j++ {
@ -236,7 +236,7 @@ func TestReputOnSourceBackend(t *testing.T) {
}
pix = make([]byte, 4*size*size)
if err := img1.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(0, 0, size, size)); err != nil {
if err := img1.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, size, size)); err != nil {
t.Fatal(err)
}
for j := 0; j < size; j++ {
@ -265,7 +265,7 @@ func TestReputOnSourceBackend(t *testing.T) {
// Use img1 as a render source, but call WritePixels.
// Now use 4x count as img1 became an isolated image again.
for i := 0; i < atlas.BaseCountToPutOnSourceBackend*4; i++ {
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting())
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
img1.WritePixels(make([]byte, 4*size*size), image.Rect(0, 0, size, size))
vs := quadVertices(size, size, 0, 0, 1)
img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false)
@ -273,7 +273,7 @@ func TestReputOnSourceBackend(t *testing.T) {
t.Errorf("got: %v, want: %v", got, want)
}
}
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting())
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
// img1 is not on an atlas due to WritePixels.
vs = quadVertices(size, size, 0, 0, 1)
@ -284,7 +284,7 @@ func TestReputOnSourceBackend(t *testing.T) {
// Use img3 as a render source. As img3 is volatile, img3 is never on an atlas.
for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ {
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting())
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
vs := quadVertices(size, size, 0, 0, 1)
img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false)
if got, want := img3.IsOnSourceBackendForTesting(), false; got != want {
@ -324,7 +324,7 @@ func TestExtend(t *testing.T) {
img1.WritePixels(p1, image.Rect(0, 0, w1, h1))
pix0 := make([]byte, 4*w0*h0)
if err := img0.ReadPixels(ui.GraphicsDriverForTesting(), pix0, image.Rect(0, 0, w0, h0)); err != nil {
if err := img0.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix0, image.Rect(0, 0, w0, h0)); err != nil {
t.Fatal(err)
}
for j := 0; j < h0; j++ {
@ -343,7 +343,7 @@ func TestExtend(t *testing.T) {
}
pix1 := make([]byte, 4*w1*h1)
if err := img1.ReadPixels(ui.GraphicsDriverForTesting(), pix1, image.Rect(0, 0, w1, h1)); err != nil {
if err := img1.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix1, image.Rect(0, 0, w1, h1)); err != nil {
t.Fatal(err)
}
for j := 0; j < h1; j++ {
@ -385,7 +385,7 @@ func TestWritePixelsAfterDrawTriangles(t *testing.T) {
dst.WritePixels(pix, image.Rect(0, 0, w, h))
pix = make([]byte, 4*w*h)
if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil {
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil {
t.Fatal(err)
}
for j := 0; j < h; j++ {
@ -427,7 +427,7 @@ func TestSmallImages(t *testing.T) {
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false)
pix = make([]byte, 4*w*h)
if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil {
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil {
t.Fatal(err)
}
for j := 0; j < h; j++ {
@ -470,7 +470,7 @@ func TestLongImages(t *testing.T) {
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false)
pix = make([]byte, 4*dstW*dstH)
if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(0, 0, dstW, dstH)); err != nil {
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, dstW, dstH)); err != nil {
t.Fatal(err)
}
for j := 0; j < h; j++ {
@ -586,7 +586,7 @@ func TestDisposedAndReputOnSourceBackend(t *testing.T) {
// Use src as a render source.
for i := 0; i < atlas.BaseCountToPutOnSourceBackend/2; i++ {
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting())
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
vs := quadVertices(size, size, 0, 0, 1)
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false)
if got, want := src.IsOnSourceBackendForTesting(), false; got != want {
@ -601,7 +601,7 @@ func TestDisposedAndReputOnSourceBackend(t *testing.T) {
atlas.FlushDeferredForTesting()
// Confirm that PutImagesOnSourceBackendForTesting doesn't panic.
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting())
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
}
// Issue #1456
@ -634,7 +634,7 @@ func TestImageIsNotReputOnSourceBackendWithoutUsingAsSource(t *testing.T) {
// Update the count without using src2 as a rendering source.
// This should not affect whether src2 is on an atlas or not.
for i := 0; i < atlas.BaseCountToPutOnSourceBackend; i++ {
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting())
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
if got, want := src2.IsOnSourceBackendForTesting(), false; got != want {
t.Errorf("got: %v, want: %v", got, want)
}
@ -642,7 +642,7 @@ func TestImageIsNotReputOnSourceBackendWithoutUsingAsSource(t *testing.T) {
// Update the count with using src2 as a rendering source.
for i := 0; i < atlas.BaseCountToPutOnSourceBackend; i++ {
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting())
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
vs := quadVertices(size, size, 0, 0, 1)
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false)
if got, want := src2.IsOnSourceBackendForTesting(), false; got != want {
@ -650,7 +650,7 @@ func TestImageIsNotReputOnSourceBackendWithoutUsingAsSource(t *testing.T) {
}
}
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting())
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
if got, want := src2.IsOnSourceBackendForTesting(), true; got != want {
t.Errorf("got: %v, want: %v", got, want)
}
@ -684,7 +684,7 @@ func TestImageWritePixelsModify(t *testing.T) {
// Check the pixels are the original ones.
pix = make([]byte, 4*size*size)
if err := img.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(0, 0, size, size)); err != nil {
if err := img.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, size, size)); err != nil {
t.Fatal(err)
}
for j := 0; j < size; j++ {
@ -767,14 +767,14 @@ func TestDestinationCountOverflow(t *testing.T) {
// Use dst0 as a destination for a while.
for i := 0; i < 31; i++ {
dst0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false)
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting())
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
}
// Use dst0 as a source for a while.
// As dst0 is used as a destination too many times (31 is a maximum), dst0's backend should never be a source backend.
for i := 0; i < 100; i++ {
dst1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{dst0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false)
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting())
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
if dst0.IsOnSourceBackendForTesting() {
t.Errorf("dst0 cannot be on a source backend: %d", i)
}
@ -801,7 +801,7 @@ func TestIteratingImagesToPutOnSourceBackend(t *testing.T) {
for _, img := range srcs {
img.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false)
}
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting())
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
// Use srcs as sources. This will register an image to imagesToPutOnSourceBackend.
// Check iterating the registered image works correctly.
@ -809,7 +809,7 @@ func TestIteratingImagesToPutOnSourceBackend(t *testing.T) {
for _, src := range srcs {
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false)
}
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting())
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
}
}

View File

@ -34,7 +34,7 @@ func TestShaderFillTwice(t *testing.T) {
vs := quadVertices(w, h, 0, 0, 1)
is := graphics.QuadIndices()
dr := image.Rect(0, 0, w, h)
g := ui.GraphicsDriverForTesting()
g := ui.Get().GraphicsDriverForTesting()
s0 := atlas.NewShader(etesting.ShaderProgramFill(0xff, 0xff, 0xff, 0xff))
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s0, nil, false)
@ -71,7 +71,7 @@ func TestImageDrawTwice(t *testing.T) {
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false)
pix := make([]byte, 4*w*h)
if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil {
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil {
t.Error(err)
}
if got, want := (color.RGBA{R: pix[0], G: pix[1], B: pix[2], A: pix[3]}), (color.RGBA{R: 0x80, G: 0x80, B: 0x80, A: 0xff}); got != want {

View File

@ -62,7 +62,7 @@ func TestClear(t *testing.T) {
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]image.Rectangle{}, nearestFilterShader, nil, false)
pix := make([]byte, 4*w*h)
if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), []graphicsdriver.PixelsArgs{
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), []graphicsdriver.PixelsArgs{
{
Pixels: pix,
Region: image.Rect(0, 0, w, h),
@ -111,7 +111,7 @@ func TestShader(t *testing.T) {
dr := image.Rect(0, 0, w, h)
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]image.Rectangle{}, nearestFilterShader, nil, false)
g := ui.GraphicsDriverForTesting()
g := ui.Get().GraphicsDriverForTesting()
s := graphicscommand.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff))
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, s, nil, false)

View File

@ -71,10 +71,10 @@ func TestRestore(t *testing.T) {
clr0 := color.RGBA{A: 0xff}
img0.WritePixels(bytesToManagedBytes([]byte{clr0.R, clr0.G, clr0.B, clr0.A}), image.Rect(0, 0, 1, 1))
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
want := clr0
@ -90,10 +90,10 @@ func TestRestoreWithoutDraw(t *testing.T) {
// If there is no drawing command on img0, img0 is cleared when restored.
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
@ -145,10 +145,10 @@ func TestRestoreChain(t *testing.T) {
dr := image.Rect(0, 0, 1, 1)
imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false)
}
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
want := clr
@ -192,10 +192,10 @@ func TestRestoreChain2(t *testing.T) {
imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false)
}
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
for i, img := range imgs {
@ -234,10 +234,10 @@ func TestRestoreOverrideSource(t *testing.T) {
img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false)
img0.WritePixels(bytesToManagedBytes([]byte{clr1.R, clr1.G, clr1.B, clr1.A}), image.Rect(0, 0, w, h))
img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false)
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
testCases := []struct {
@ -330,10 +330,10 @@ func TestRestoreComplexGraph(t *testing.T) {
img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false)
vs = quadVertices(w, h, 2, 0)
img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false)
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
testCases := []struct {
@ -424,10 +424,10 @@ func TestRestoreRecursive(t *testing.T) {
dr := image.Rect(0, 0, w, h)
img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false)
img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false)
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
testCases := []struct {
@ -474,7 +474,7 @@ func TestWritePixels(t *testing.T) {
for i := range pix {
pix[i] = 0
}
if err := img.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(5, 7, 9, 11)); err != nil {
if err := img.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(5, 7, 9, 11)); err != nil {
t.Fatal(err)
}
for j := 7; j < 11; j++ {
@ -487,13 +487,13 @@ func TestWritePixels(t *testing.T) {
}
}
}
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := img.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(5, 7, 9, 11)); err != nil {
if err := img.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(5, 7, 9, 11)); err != nil {
t.Fatal(err)
}
for j := 7; j < 11; j++ {
@ -525,14 +525,14 @@ func TestDrawTrianglesAndWritePixels(t *testing.T) {
img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false)
img1.WritePixels(bytesToManagedBytes([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), image.Rect(0, 0, 2, 1))
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
var pix [4]byte
if err := img1.ReadPixels(ui.GraphicsDriverForTesting(), pix[:], image.Rect(0, 0, 1, 1)); err != nil {
if err := img1.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix[:], image.Rect(0, 0, 1, 1)); err != nil {
t.Fatal(err)
}
got := color.RGBA{R: pix[0], G: pix[1], B: pix[2], A: pix[3]}
@ -564,14 +564,14 @@ func TestDispose(t *testing.T) {
img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false)
img1.Dispose()
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
var pix [4]byte
if err := img0.ReadPixels(ui.GraphicsDriverForTesting(), pix[:], image.Rect(0, 0, 1, 1)); err != nil {
if err := img0.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix[:], image.Rect(0, 0, 1, 1)); err != nil {
t.Fatal(err)
}
got := color.RGBA{R: pix[0], G: pix[1], B: pix[2], A: pix[3]}
@ -691,10 +691,10 @@ func TestWritePixelsOnly(t *testing.T) {
}
}
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
want := color.RGBA{R: 1, G: 2, B: 3, A: 4}
@ -731,7 +731,7 @@ func TestReadPixelsFromVolatileImage(t *testing.T) {
want := byte(0xff)
var result [4]byte
if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), result[:], image.Rect(0, 0, 1, 1)); err != nil {
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), result[:], image.Rect(0, 0, 1, 1)); err != nil {
t.Fatal(err)
}
got := result[0]
@ -771,15 +771,15 @@ func TestAllowWritePixelsForPartAfterDrawTriangles(t *testing.T) {
dst.WritePixels(bytesToManagedBytes(make([]byte, 4*2*2)), image.Rect(0, 0, 2, 2))
// WritePixels for a part of image doesn't panic.
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
result := make([]byte, 4*w*h)
if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), result, image.Rect(0, 0, w, h)); err != nil {
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), result, image.Rect(0, 0, w, h)); err != nil {
t.Fatal(err)
}
for j := 0; j < h; j++ {
@ -819,7 +819,7 @@ func TestExtend(t *testing.T) {
extended := orig.Extend(w*2, h*2) // After this, orig is already disposed.
result := make([]byte, 4*(w*2)*(h*2))
if err := extended.ReadPixels(ui.GraphicsDriverForTesting(), result, image.Rect(0, 0, w*2, h*2)); err != nil {
if err := extended.ReadPixels(ui.Get().GraphicsDriverForTesting(), result, image.Rect(0, 0, w*2, h*2)); err != nil {
t.Fatal(err)
}
for j := 0; j < h*2; j++ {
@ -865,7 +865,7 @@ func TestDrawTrianglesAndExtend(t *testing.T) {
extended := orig.Extend(w*2, h*2) // After this, orig is already disposed.
result := make([]byte, 4*(w*2)*(h*2))
if err := extended.ReadPixels(ui.GraphicsDriverForTesting(), result, image.Rect(0, 0, w*2, h*2)); err != nil {
if err := extended.ReadPixels(ui.Get().GraphicsDriverForTesting(), result, image.Rect(0, 0, w*2, h*2)); err != nil {
t.Fatal(err)
}
for j := 0; j < h*2; j++ {
@ -918,19 +918,19 @@ func TestMutateSlices(t *testing.T) {
for i := range is {
is[i] = 0
}
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
srcPix := make([]byte, 4*w*h)
if err := src.ReadPixels(ui.GraphicsDriverForTesting(), srcPix, image.Rect(0, 0, w, h)); err != nil {
if err := src.ReadPixels(ui.Get().GraphicsDriverForTesting(), srcPix, image.Rect(0, 0, w, h)); err != nil {
t.Fatal(err)
}
dstPix := make([]byte, 4*w*h)
if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), dstPix, image.Rect(0, 0, w, h)); err != nil {
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), dstPix, image.Rect(0, 0, w, h)); err != nil {
t.Fatal(err)
}
@ -988,7 +988,7 @@ func TestOverlappedPixels(t *testing.T) {
}
result := make([]byte, 4*3*3)
if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), result, image.Rect(0, 0, 3, 3)); err != nil {
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), result, image.Rect(0, 0, 3, 3)); err != nil {
t.Fatal(err)
}
for j := 0; j < 3; j++ {
@ -1017,7 +1017,7 @@ func TestOverlappedPixels(t *testing.T) {
{0, 0xff, 0, 0xff},
{0, 0xff, 0, 0xff},
}
if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), result, image.Rect(0, 0, 3, 3)); err != nil {
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), result, image.Rect(0, 0, 3, 3)); err != nil {
t.Fatal(err)
}
for j := 0; j < 3; j++ {
@ -1056,7 +1056,7 @@ func TestOverlappedPixels(t *testing.T) {
{0, 0, 0xff, 0xff},
{0, 0, 0xff, 0xff},
}
if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), result, image.Rect(0, 0, 3, 3)); err != nil {
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), result, image.Rect(0, 0, 3, 3)); err != nil {
t.Fatal(err)
}
for j := 0; j < 3; j++ {
@ -1070,14 +1070,14 @@ func TestOverlappedPixels(t *testing.T) {
}
}
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), result, image.Rect(0, 0, 3, 3)); err != nil {
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), result, image.Rect(0, 0, 3, 3)); err != nil {
t.Fatal(err)
}
for j := 0; j < 3; j++ {
@ -1106,7 +1106,7 @@ func TestDrawTrianglesAndReadPixels(t *testing.T) {
dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false)
pix := make([]byte, 4*w*h)
if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil {
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil {
t.Fatal(err)
}
if got, want := (color.RGBA{R: pix[0], G: pix[1], B: pix[2], A: pix[3]}), (color.RGBA{R: 0x80, G: 0x80, B: 0x80, A: 0x80}); !sameColors(got, want, 1) {
@ -1131,7 +1131,7 @@ func TestWritePixelsAndDrawTriangles(t *testing.T) {
// Get the pixels.
pix := make([]byte, 4*2*1)
if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(0, 0, 2, 1)); err != nil {
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, 2, 1)); err != nil {
t.Fatal(err)
}
if got, want := (color.RGBA{R: pix[0], G: pix[1], B: pix[2], A: pix[3]}), (color.RGBA{R: 0x40, G: 0x40, B: 0x40, A: 0x40}); !sameColors(got, want, 1) {

View File

@ -57,10 +57,10 @@ func TestShader(t *testing.T) {
dr := image.Rect(0, 0, 1, 1)
img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s, nil, false)
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
@ -88,10 +88,10 @@ func TestShaderChain(t *testing.T) {
imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s, nil, false)
}
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
@ -122,10 +122,10 @@ func TestShaderMultipleSources(t *testing.T) {
// Clear one of the sources after DrawTriangles. dst should not be affected.
clearImage(srcs[0], 1, 1)
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
@ -159,10 +159,10 @@ func TestShaderMultipleSourcesOnOneTexture(t *testing.T) {
// Clear one of the sources after DrawTriangles. dst should not be affected.
clearImage(srcs[0], 3, 1)
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
@ -185,10 +185,10 @@ func TestShaderDispose(t *testing.T) {
// stale.
s.Dispose()
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil {
if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err)
}

View File

@ -280,6 +280,6 @@ func (c *context) screenScaleAndOffsets() (scale, offsetX, offsetY float64) {
return
}
func LogicalPositionToClientPosition(x, y float64) (float64, float64) {
return theUI.context.logicalPositionToClientPosition(x, y, theUI.DeviceScaleFactor())
func (u *UserInterface) LogicalPositionToClientPosition(x, y float64) (float64, float64) {
return u.context.logicalPositionToClientPosition(x, y, u.DeviceScaleFactor())
}

View File

@ -19,6 +19,7 @@ import (
"sync/atomic"
)
// TODO: Move theGlobalState to UserInterface's member
var theGlobalState = globalState{
isScreenClearedEveryFrame_: 1,
graphicsLibrary_: int32(GraphicsLibraryUnknown),
@ -81,9 +82,9 @@ func FPSMode() FPSModeType {
return theGlobalState.fpsMode()
}
func SetFPSMode(fpsMode FPSModeType) {
func (u *UserInterface) SetFPSMode(fpsMode FPSModeType) {
theGlobalState.setFPSMode(fpsMode)
theUI.SetFPSMode(fpsMode)
u.setFPSMode(fpsMode)
}
func IsScreenClearedEveryFrame() bool {

View File

@ -98,8 +98,8 @@ func newGraphicsDriver(creator graphicsDriverCreator, graphicsLibrary GraphicsLi
}
}
func GraphicsDriverForTesting() graphicsdriver.Graphics {
return theUI.graphicsDriver
func (u *UserInterface) GraphicsDriverForTesting() graphicsdriver.Graphics {
return u.graphicsDriver
}
type GraphicsLibrary int

View File

@ -1,20 +0,0 @@
// Copyright 2017 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build !windows
package ui
// hideConsoleWindowOnWindows does nothing on non-Windows systems.
func hideConsoleWindowOnWindows() {}

View File

@ -43,9 +43,9 @@ func getConsoleWindow() windows.HWND {
return windows.HWND(r)
}
// hideConsoleWindowOnWindows will hide the console window that is showing when
// hideConsoleWindow will hide the console window that is showing when
// compiling on Windows without specifying the '-ldflags "-Hwindowsgui"' flag.
func hideConsoleWindowOnWindows() {
func hideConsoleWindow() {
// In Xbox, GetWindowThreadProcessId might not exist.
if user32.NewProc("GetWindowThreadProcessId").Find() != nil {
return

View File

@ -36,6 +36,8 @@ func SetPanicOnErrorOnReadingPixelsForTesting(value bool) {
const bigOffscreenScale = 2
type Image struct {
ui *UserInterface
mipmap *mipmap.Mipmap
width int
height int
@ -53,8 +55,9 @@ type Image struct {
tmpVerticesForFill []float32
}
func NewImage(width, height int, imageType atlas.ImageType) *Image {
func (u *UserInterface) NewImage(width, height int, imageType atlas.ImageType) *Image {
return &Image{
ui: u,
mipmap: mipmap.New(width, height, imageType),
width: width,
height: height,
@ -95,7 +98,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
default:
panic(fmt.Sprintf("ui: unexpected image type: %d", imageType))
}
i.bigOffscreenBuffer = newBigOffscreenImage(i, imageType)
i.bigOffscreenBuffer = i.ui.newBigOffscreenImage(i, imageType)
}
i.bigOffscreenBuffer.drawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd, canSkipMipmap, false)
@ -163,7 +166,7 @@ func (i *Image) ReadPixels(pixels []byte, region image.Rectangle) {
i.flushDotsBufferIfNeeded()
}
if err := theUI.readPixels(i.mipmap, pixels, region); err != nil {
if err := i.ui.readPixels(i.mipmap, pixels, region); err != nil {
if panicOnErrorOnReadingPixels {
panic(err)
}
@ -173,7 +176,7 @@ func (i *Image) ReadPixels(pixels []byte, region image.Rectangle) {
func (i *Image) DumpScreenshot(name string, blackbg bool) (string, error) {
i.flushBufferIfNeeded()
return theUI.dumpScreenshot(i.mipmap, name, blackbg)
return i.ui.dumpScreenshot(i.mipmap, name, blackbg)
}
func (i *Image) flushBufferIfNeeded() {
@ -244,7 +247,7 @@ func (i *Image) flushDotsBufferIfNeeded() {
}
i.dotsBuffer = nil
srcs := [graphics.ShaderImageCount]*mipmap.Mipmap{whiteImage.mipmap}
srcs := [graphics.ShaderImageCount]*mipmap.Mipmap{i.ui.whiteImage.mipmap}
dr := image.Rect(0, 0, i.width, i.height)
i.mipmap.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader.shader, nil, false, true)
}
@ -255,21 +258,8 @@ func (i *Image) flushBigOffscreenBufferIfNeeded() {
}
}
func DumpImages(dir string) (string, error) {
return theUI.dumpImages(dir)
}
var (
whiteImage = NewImage(3, 3, atlas.ImageTypeRegular)
)
func init() {
pix := make([]byte, 4*whiteImage.width*whiteImage.height)
for i := range pix {
pix[i] = 0xff
}
// As whiteImage is used at Fill, use WritePixels instead.
whiteImage.WritePixels(pix, image.Rect(0, 0, whiteImage.width, whiteImage.height))
func (u *UserInterface) DumpImages(dir string) (string, error) {
return u.dumpImages(dir)
}
func (i *Image) clear() {
@ -283,17 +273,19 @@ func (i *Image) Fill(r, g, b, a float32, region image.Rectangle) {
// i.tmpVerticesForFill can be reused as this is sent to DrawTriangles immediately.
graphics.QuadVertices(
i.tmpVerticesForFill,
1, 1, float32(whiteImage.width-1), float32(whiteImage.height-1),
1, 1, float32(i.ui.whiteImage.width-1), float32(i.ui.whiteImage.height-1),
float32(i.width), 0, 0, float32(i.height), 0, 0,
r, g, b, a)
is := graphics.QuadIndices()
srcs := [graphics.ShaderImageCount]*Image{whiteImage}
srcs := [graphics.ShaderImageCount]*Image{i.ui.whiteImage}
i.DrawTriangles(srcs, i.tmpVerticesForFill, is, graphicsdriver.BlendCopy, region, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, false, true, false)
}
type bigOffscreenImage struct {
ui *UserInterface
orig *Image
imageType atlas.ImageType
@ -307,8 +299,9 @@ type bigOffscreenImage struct {
tmpVerticesForCopying []float32
}
func newBigOffscreenImage(orig *Image, imageType atlas.ImageType) *bigOffscreenImage {
func (u *UserInterface) newBigOffscreenImage(orig *Image, imageType atlas.ImageType) *bigOffscreenImage {
return &bigOffscreenImage{
ui: u,
orig: orig,
imageType: imageType,
}
@ -340,7 +333,7 @@ func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderImageCount]*Image
}
if i.image == nil {
i.image = NewImage(i.region.Dx()*bigOffscreenScale, i.region.Dy()*bigOffscreenScale, i.imageType)
i.image = i.ui.NewImage(i.region.Dx()*bigOffscreenScale, i.region.Dy()*bigOffscreenScale, i.imageType)
}
// Copy the current rendering result to get the correct blending result.

View File

@ -122,11 +122,7 @@ func (u *UserInterface) updateInputStateImpl() error {
return nil
}
func KeyName(key Key) string {
return theUI.keyName(key)
}
func (u *UserInterface) keyName(key Key) string {
func (u *UserInterface) KeyName(key Key) string {
if !u.isRunning() {
return ""
}

View File

@ -199,11 +199,7 @@ func init() {
})
}
func KeyName(key Key) string {
return theUI.keyName(key)
}
func (u *UserInterface) keyName(key Key) string {
func (u *UserInterface) KeyName(key Key) string {
if !u.running {
return ""
}

View File

@ -61,7 +61,7 @@ func (u *UserInterface) updateInputState() error {
return nil
}
func KeyName(key Key) string {
func (u *UserInterface) KeyName(key Key) string {
// TODO: Implement this.
return ""
}

View File

@ -71,6 +71,6 @@ func (u *UserInterface) updateInputStateImpl() error {
return nil
}
func KeyName(key Key) string {
func (u *UserInterface) KeyName(key Key) string {
return ""
}

View File

@ -67,16 +67,47 @@ const (
)
type UserInterface struct {
whiteImage *Image
userInterfaceImpl
}
var theUI = &UserInterface{}
var (
theUI *UserInterface
)
func init() {
// newUserInterface() must be called in the main goroutine.
u, err := newUserInterface()
if err != nil {
panic(err)
}
theUI = u
}
func Get() *UserInterface {
// TODO: Get is a legacy API to access this package. Remove this.
return theUI
}
// newUserInterface must be called from the main thread.
func newUserInterface() (*UserInterface, error) {
u := &UserInterface{}
u.whiteImage = u.NewImage(3, 3, atlas.ImageTypeRegular)
pix := make([]byte, 4*u.whiteImage.width*u.whiteImage.height)
for i := range pix {
pix[i] = 0xff
}
// As a white image is used at Fill, use WritePixels instead.
u.whiteImage.WritePixels(pix, image.Rect(0, 0, u.whiteImage.width, u.whiteImage.height))
if err := u.init(); err != nil {
return nil, err
}
return u, nil
}
func (u *UserInterface) readPixels(mipmap *mipmap.Mipmap, pixels []byte, region image.Rectangle) error {
return mipmap.ReadPixels(u.graphicsDriver, pixels, region)
}

View File

@ -32,8 +32,7 @@ import (
var class_EbitengineWindowDelegate objc.Class
func init() {
var err error
func (u *UserInterface) initializePlatform() error {
pushResizableState := func(id, win objc.ID) {
window := cocoa.NSWindow{ID: win}
id.Send(sel_setOrigResizable, window.StyleMask()&cocoa.NSWindowStyleMaskResizable != 0)
@ -48,7 +47,7 @@ func init() {
}
id.Send(sel_setOrigResizable, false)
}
class_EbitengineWindowDelegate, err = objc.RegisterClass(
d, err := objc.RegisterClass(
"EbitengineWindowDelegate",
objc.GetClass("NSObject"),
[]*objc.Protocol{objc.GetProtocol("NSWindowDelegate")},
@ -122,7 +121,7 @@ func init() {
{
Cmd: sel_windowWillEnterFullScreen,
Fn: func(id objc.ID, cmd objc.SEL, notification objc.ID) {
if err := theUI.setOrigWindowPosWithCurrentPos(); err != nil {
if err := u.setOrigWindowPosWithCurrentPos(); err != nil {
theGlobalState.setError(err)
return
}
@ -142,7 +141,7 @@ func init() {
// Even a window has a size limitation, a window can be fullscreen by calling SetFullscreen(true).
// In this case, the window size limitation is disabled temporarily.
// When exiting from fullscreen, reset the window size limitation.
if err := theUI.updateWindowSizeLimits(); err != nil {
if err := u.updateWindowSizeLimits(); err != nil {
theGlobalState.setError(err)
return
}
@ -158,8 +157,11 @@ func init() {
},
)
if err != nil {
panic(err)
return err
}
class_EbitengineWindowDelegate = d
return nil
}
type graphicsDriverCreatorImpl struct {

View File

@ -123,8 +123,10 @@ const (
func init() {
// Lock the main thread.
runtime.LockOSThread()
}
theUI.userInterfaceImpl = userInterfaceImpl{
func (u *UserInterface) init() error {
u.userInterfaceImpl = userInterfaceImpl{
runnableOnUnfocused: true,
minWindowWidthInDIP: glfw.DontCare,
minWindowHeightInDIP: glfw.DontCare,
@ -142,25 +144,28 @@ func init() {
savedCursorX: math.NaN(),
savedCursorY: math.NaN(),
}
theUI.iwindow.ui = theUI
u.iwindow.ui = u
hideConsoleWindowOnWindows()
if err := initialize(); err != nil {
panic(err)
if err := u.initializePlatform(); err != nil {
return err
}
if err := u.initializeGLFW(); err != nil {
return err
}
if _, err := glfw.SetMonitorCallback(func(monitor *glfw.Monitor, event glfw.PeripheralEvent) {
if err := theMonitors.update(); err != nil {
theGlobalState.setError(err)
}
}); err != nil {
panic(err)
return err
}
return nil
}
var glfwSystemCursors = map[CursorShape]*glfw.Cursor{}
func initialize() error {
func (u *UserInterface) initializeGLFW() error {
if err := glfw.Init(); err != nil {
return err
}
@ -183,7 +188,7 @@ func initialize() error {
return errors.New("ui: no monitor was found at initialize")
}
theUI.setInitMonitor(m)
u.setInitMonitor(m)
// Create system cursors. These cursors are destroyed at glfw.Terminate().
glfwSystemCursors[CursorShapeDefault] = nil
@ -722,7 +727,7 @@ func (u *UserInterface) IsRunnableOnUnfocused() bool {
return u.isRunnableOnUnfocused()
}
func (u *UserInterface) SetFPSMode(mode FPSModeType) {
func (u *UserInterface) setFPSMode(mode FPSModeType) {
if u.isTerminated() {
return
}
@ -741,7 +746,7 @@ func (u *UserInterface) SetFPSMode(mode FPSModeType) {
u.fpsMode = mode
return
}
if err := u.setFPSMode(mode); err != nil {
if err := u.setFPSModeImpl(mode); err != nil {
theGlobalState.setError(err)
return
}
@ -1285,8 +1290,8 @@ func (u *UserInterface) outsideSize() (float64, float64, error) {
return w, h, nil
}
// setFPSMode must be called from the main thread.
func (u *UserInterface) setFPSMode(fpsMode FPSModeType) error {
// setFPSModeImpl must be called from the main thread.
func (u *UserInterface) setFPSModeImpl(fpsMode FPSModeType) error {
needUpdate := u.fpsMode != fpsMode || !u.fpsModeInited
u.fpsMode = fpsMode
u.fpsModeInited = true
@ -1356,7 +1361,7 @@ func (u *UserInterface) update() (float64, float64, error) {
// Initialize vsync after SetMonitor is called. See the comment in updateVsync.
// Calling this inside setWindowSize didn't work (#1363).
if !u.fpsModeInited {
if err := u.setFPSMode(u.fpsMode); err != nil {
if err := u.setFPSModeImpl(u.fpsMode); err != nil {
return 0, 0, err
}
}
@ -2192,6 +2197,6 @@ func IsScreenTransparentAvailable() bool {
return true
}
func RunOnMainThread(f func()) {
theUI.mainThread.Call(f)
func (u *UserInterface) RunOnMainThread(f func()) {
u.mainThread.Call(f)
}

View File

@ -144,8 +144,8 @@ func (u *UserInterface) SetFullscreen(fullscreen bool) {
return
}
if theUI.cursorMode == CursorModeCaptured {
theUI.saveCursorPosition()
if u.cursorMode == CursorModeCaptured {
u.saveCursorPosition()
}
if fullscreen {
@ -186,7 +186,7 @@ func (u *UserInterface) IsRunnableOnUnfocused() bool {
return u.runnableOnUnfocused
}
func (u *UserInterface) SetFPSMode(mode FPSModeType) {
func (u *UserInterface) setFPSMode(mode FPSModeType) {
u.fpsMode = mode
}
@ -236,7 +236,7 @@ func (u *UserInterface) setCursorMode(mode CursorMode) {
}
func (u *UserInterface) recoverCursorMode() {
if theUI.cursorPrevMode == CursorModeCaptured {
if u.cursorPrevMode == CursorModeCaptured {
panic("ui: cursorPrevMode must not be CursorModeCaptured at recoverCursorMode")
}
u.SetCursorMode(u.cursorPrevMode)
@ -471,8 +471,8 @@ func (u *UserInterface) loop(game Game) <-chan error {
return errCh
}
func init() {
theUI.userInterfaceImpl = userInterfaceImpl{
func (u *UserInterface) init() error {
u.userInterfaceImpl = userInterfaceImpl{
runnableOnUnfocused: true,
savedCursorX: math.NaN(),
savedCursorY: math.NaN(),
@ -480,7 +480,7 @@ func init() {
// docuemnt is undefined on node.js
if !document.Truthy() {
return
return nil
}
if !document.Get("body").Truthy() {
@ -492,7 +492,7 @@ func init() {
<-ch
}
setWindowEventHandlers(window)
u.setWindowEventHandlers(window)
// Adjust the initial scale to 1.
// https://developer.mozilla.org/en/docs/Mozilla/Mobile/Viewport_meta_tag
@ -528,7 +528,7 @@ func init() {
canvas.Call("setAttribute", "tabindex", 1)
canvas.Get("style").Set("outline", "none")
setCanvasEventHandlers(canvas)
u.setCanvasEventHandlers(canvas)
// Pointer Lock
document.Call("addEventListener", "pointerlockchange", js.FuncOf(func(this js.Value, args []js.Value) any {
@ -538,10 +538,10 @@ func init() {
// Recover the state correctly when the pointer lock exits.
// A user can exit the pointer lock by pressing ESC. In this case, sync the cursor mode state.
if theUI.cursorMode == CursorModeCaptured {
theUI.recoverCursorMode()
if u.cursorMode == CursorModeCaptured {
u.recoverCursorMode()
}
theUI.recoverCursorPosition()
u.recoverCursorPosition()
return nil
}))
document.Call("addEventListener", "pointerlockerror", js.FuncOf(func(this js.Value, args []js.Value) any {
@ -556,16 +556,18 @@ func init() {
js.Global().Get("console").Call("error", "webkitfullscreenerror event is fired. 'allow=\"fullscreen\"' or 'allowfullscreen' might be required at an iframe. This function on browsers must be called as a result of a gestural interaction or orientation change.")
return nil
}))
return nil
}
func setWindowEventHandlers(v js.Value) {
func (u *UserInterface) setWindowEventHandlers(v js.Value) {
v.Call("addEventListener", "resize", js.FuncOf(func(this js.Value, args []js.Value) any {
theUI.updateScreenSize()
u.updateScreenSize()
// updateImpl can block. Use goroutine.
// See https://pkg.go.dev/syscall/js#FuncOf.
go func() {
if err := theUI.updateImpl(true); err != nil {
if err := u.updateImpl(true); err != nil {
theGlobalState.setError(err)
return
}
@ -574,7 +576,7 @@ func setWindowEventHandlers(v js.Value) {
}))
}
func setCanvasEventHandlers(v js.Value) {
func (u *UserInterface) setCanvasEventHandlers(v js.Value) {
// Keyboard
v.Call("addEventListener", "keydown", js.FuncOf(func(this js.Value, args []js.Value) any {
// Focus the canvas explicitly to activate tha game (#961).
@ -582,7 +584,7 @@ func setCanvasEventHandlers(v js.Value) {
e := args[0]
e.Call("preventDefault")
if err := theUI.updateInputFromEvent(e); err != nil {
if err := u.updateInputFromEvent(e); err != nil {
theGlobalState.setError(err)
return nil
}
@ -591,7 +593,7 @@ func setCanvasEventHandlers(v js.Value) {
v.Call("addEventListener", "keyup", js.FuncOf(func(this js.Value, args []js.Value) any {
e := args[0]
e.Call("preventDefault")
if err := theUI.updateInputFromEvent(e); err != nil {
if err := u.updateInputFromEvent(e); err != nil {
theGlobalState.setError(err)
return nil
}
@ -605,7 +607,7 @@ func setCanvasEventHandlers(v js.Value) {
e := args[0]
e.Call("preventDefault")
if err := theUI.updateInputFromEvent(e); err != nil {
if err := u.updateInputFromEvent(e); err != nil {
theGlobalState.setError(err)
return nil
}
@ -614,7 +616,7 @@ func setCanvasEventHandlers(v js.Value) {
v.Call("addEventListener", "mouseup", js.FuncOf(func(this js.Value, args []js.Value) any {
e := args[0]
e.Call("preventDefault")
if err := theUI.updateInputFromEvent(e); err != nil {
if err := u.updateInputFromEvent(e); err != nil {
theGlobalState.setError(err)
return nil
}
@ -623,7 +625,7 @@ func setCanvasEventHandlers(v js.Value) {
v.Call("addEventListener", "mousemove", js.FuncOf(func(this js.Value, args []js.Value) any {
e := args[0]
e.Call("preventDefault")
if err := theUI.updateInputFromEvent(e); err != nil {
if err := u.updateInputFromEvent(e); err != nil {
theGlobalState.setError(err)
return nil
}
@ -632,7 +634,7 @@ func setCanvasEventHandlers(v js.Value) {
v.Call("addEventListener", "wheel", js.FuncOf(func(this js.Value, args []js.Value) any {
e := args[0]
e.Call("preventDefault")
if err := theUI.updateInputFromEvent(e); err != nil {
if err := u.updateInputFromEvent(e); err != nil {
theGlobalState.setError(err)
return nil
}
@ -646,7 +648,7 @@ func setCanvasEventHandlers(v js.Value) {
e := args[0]
e.Call("preventDefault")
if err := theUI.updateInputFromEvent(e); err != nil {
if err := u.updateInputFromEvent(e); err != nil {
theGlobalState.setError(err)
return nil
}
@ -655,7 +657,7 @@ func setCanvasEventHandlers(v js.Value) {
v.Call("addEventListener", "touchend", js.FuncOf(func(this js.Value, args []js.Value) any {
e := args[0]
e.Call("preventDefault")
if err := theUI.updateInputFromEvent(e); err != nil {
if err := u.updateInputFromEvent(e); err != nil {
theGlobalState.setError(err)
return nil
}
@ -664,7 +666,7 @@ func setCanvasEventHandlers(v js.Value) {
v.Call("addEventListener", "touchmove", js.FuncOf(func(this js.Value, args []js.Value) any {
e := args[0]
e.Call("preventDefault")
if err := theUI.updateInputFromEvent(e); err != nil {
if err := u.updateInputFromEvent(e); err != nil {
theGlobalState.setError(err)
return nil
}
@ -700,7 +702,7 @@ func setCanvasEventHandlers(v js.Value) {
return nil
}
go theUI.appendDroppedFiles(data)
go u.appendDroppedFiles(data)
return nil
}))
}

View File

@ -29,6 +29,10 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl"
)
func (u *UserInterface) initializePlatform() error {
return nil
}
type graphicsDriverCreatorImpl struct {
transparent bool
}

View File

@ -51,8 +51,8 @@ var (
renderEndCh = make(chan struct{})
)
func init() {
theUI.userInterfaceImpl = userInterfaceImpl{
func (u *UserInterface) init() error {
u.userInterfaceImpl = userInterfaceImpl{
foreground: 1,
graphicsDriverInitCh: make(chan struct{}),
errCh: make(chan error),
@ -61,6 +61,7 @@ func init() {
outsideWidth: 640,
outsideHeight: 480,
}
return nil
}
// Update is called from mobile/ebitenmobileview.
@ -249,11 +250,7 @@ func (u *UserInterface) Run(game Game, options *RunOptions) error {
return nil
}
func RunWithoutMainLoop(game Game, options *RunOptions) {
theUI.runWithoutMainLoop(game, options)
}
func (u *UserInterface) runWithoutMainLoop(game Game, options *RunOptions) {
func (u *UserInterface) RunWithoutMainLoop(game Game, options *RunOptions) {
go func() {
if err := u.run(game, false, options); err != nil {
u.errCh <- err
@ -402,7 +399,7 @@ func (u *UserInterface) SetRunnableOnUnfocused(runnableOnUnfocused bool) {
// Do nothing
}
func (u *UserInterface) SetFPSMode(mode FPSModeType) {
func (u *UserInterface) setFPSMode(mode FPSModeType) {
u.fpsMode = mode
u.updateExplicitRenderingModeIfNeeded()
}

View File

@ -178,7 +178,7 @@ func (*UserInterface) IsRunnableOnUnfocused() bool {
func (*UserInterface) SetRunnableOnUnfocused(runnableOnUnfocused bool) {
}
func (*UserInterface) SetFPSMode(mode FPSModeType) {
func (*UserInterface) setFPSMode(mode FPSModeType) {
}
func (*UserInterface) ScheduleFrame() {

View File

@ -30,6 +30,11 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/winver"
)
func (u *UserInterface) initializePlatform() error {
hideConsoleWindow()
return nil
}
type graphicsDriverCreatorImpl struct {
transparent bool
}

6
run.go
View File

@ -477,9 +477,9 @@ func IsVsyncEnabled() bool {
// the game uses the display's vsync.
func SetVsyncEnabled(enabled bool) {
if enabled {
ui.SetFPSMode(ui.FPSModeVsyncOn)
ui.Get().SetFPSMode(ui.FPSModeVsyncOn)
} else {
ui.SetFPSMode(ui.FPSModeVsyncOffMaximum)
ui.Get().SetFPSMode(ui.FPSModeVsyncOffMaximum)
}
}
@ -536,7 +536,7 @@ func FPSMode() FPSModeType {
//
// Deprecated: as of v2.5. Use SetVsyncEnabled instead.
func SetFPSMode(mode FPSModeType) {
ui.SetFPSMode(mode)
ui.Get().SetFPSMode(mode)
}
// ScheduleFrame schedules a next frame when the current FPS mode is FPSModeVsyncOffMinimum.

View File

@ -29,5 +29,5 @@ import (
// TODO: Remove this. In order to remove this, the gameForUI should be in another package.
func RunGameWithoutMainLoop(game Game, options *RunGameOptions) {
op := toUIRunOptions(options)
ui.RunWithoutMainLoop(newGameForUI(game, op.ScreenTransparent), op)
ui.Get().RunWithoutMainLoop(newGameForUI(game, op.ScreenTransparent), op)
}