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. // Start returns nil and nil if the current environment doesn't support this package.
func Start(x, y int) (states chan State, close func()) { 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)) 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()) { func (t *textInput) Start(x, y int) (chan State, func()) {
var session *session var session *session
ui.RunOnMainThread(func() { ui.Get().RunOnMainThread(func() {
if t.session != nil { if t.session != nil {
t.session.end() t.session.end()
t.session = nil t.session = nil

View File

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

View File

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

View File

@ -76,7 +76,7 @@ func IsKeyPressed(key Key) bool {
// //
// KeyName is concurrent-safe. // KeyName is concurrent-safe.
func KeyName(key Key) string { 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 // 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) 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) t.Fatal(err)
} }
for j := 0; j < size; j++ { 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. // 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. // Then, img1 requires longer time to recover to be on a texture atlas again.
for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ { for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ {
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
vs := quadVertices(size, size, 0, 0, 1) 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) 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 { if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
@ -203,16 +203,16 @@ func TestReputOnSourceBackend(t *testing.T) {
} }
} }
// Finally, img1 is on a source backend. // Finally, img1 is on a source backend.
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
vs := quadVertices(size, size, 0, 0, 1) 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) 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 { if got, want := img1.IsOnSourceBackendForTesting(), true; got != want {
t.Errorf("got: %v, want: %v", 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) 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) t.Fatal(err)
} }
for j := 0; j < size; j++ { for j := 0; j < size; j++ {
@ -236,7 +236,7 @@ func TestReputOnSourceBackend(t *testing.T) {
} }
pix = make([]byte, 4*size*size) 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) t.Fatal(err)
} }
for j := 0; j < size; j++ { for j := 0; j < size; j++ {
@ -265,7 +265,7 @@ func TestReputOnSourceBackend(t *testing.T) {
// Use img1 as a render source, but call WritePixels. // Use img1 as a render source, but call WritePixels.
// Now use 4x count as img1 became an isolated image again. // Now use 4x count as img1 became an isolated image again.
for i := 0; i < atlas.BaseCountToPutOnSourceBackend*4; i++ { 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)) img1.WritePixels(make([]byte, 4*size*size), image.Rect(0, 0, size, size))
vs := quadVertices(size, size, 0, 0, 1) 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) 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) 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. // img1 is not on an atlas due to WritePixels.
vs = quadVertices(size, size, 0, 0, 1) 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. // Use img3 as a render source. As img3 is volatile, img3 is never on an atlas.
for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ { for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ {
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
vs := quadVertices(size, size, 0, 0, 1) 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) 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 { 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)) img1.WritePixels(p1, image.Rect(0, 0, w1, h1))
pix0 := make([]byte, 4*w0*h0) 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) t.Fatal(err)
} }
for j := 0; j < h0; j++ { for j := 0; j < h0; j++ {
@ -343,7 +343,7 @@ func TestExtend(t *testing.T) {
} }
pix1 := make([]byte, 4*w1*h1) 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) t.Fatal(err)
} }
for j := 0; j < h1; j++ { for j := 0; j < h1; j++ {
@ -385,7 +385,7 @@ func TestWritePixelsAfterDrawTriangles(t *testing.T) {
dst.WritePixels(pix, image.Rect(0, 0, w, h)) dst.WritePixels(pix, image.Rect(0, 0, w, h))
pix = make([]byte, 4*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) t.Fatal(err)
} }
for j := 0; j < h; j++ { 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) 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) 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) t.Fatal(err)
} }
for j := 0; j < h; j++ { 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) 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) 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) t.Fatal(err)
} }
for j := 0; j < h; j++ { for j := 0; j < h; j++ {
@ -586,7 +586,7 @@ func TestDisposedAndReputOnSourceBackend(t *testing.T) {
// Use src as a render source. // Use src as a render source.
for i := 0; i < atlas.BaseCountToPutOnSourceBackend/2; i++ { for i := 0; i < atlas.BaseCountToPutOnSourceBackend/2; i++ {
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
vs := quadVertices(size, size, 0, 0, 1) 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) 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 { if got, want := src.IsOnSourceBackendForTesting(), false; got != want {
@ -601,7 +601,7 @@ func TestDisposedAndReputOnSourceBackend(t *testing.T) {
atlas.FlushDeferredForTesting() atlas.FlushDeferredForTesting()
// Confirm that PutImagesOnSourceBackendForTesting doesn't panic. // Confirm that PutImagesOnSourceBackendForTesting doesn't panic.
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
} }
// Issue #1456 // Issue #1456
@ -634,7 +634,7 @@ func TestImageIsNotReputOnSourceBackendWithoutUsingAsSource(t *testing.T) {
// Update the count without using src2 as a rendering source. // Update the count without using src2 as a rendering source.
// This should not affect whether src2 is on an atlas or not. // This should not affect whether src2 is on an atlas or not.
for i := 0; i < atlas.BaseCountToPutOnSourceBackend; i++ { for i := 0; i < atlas.BaseCountToPutOnSourceBackend; i++ {
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
if got, want := src2.IsOnSourceBackendForTesting(), false; got != want { if got, want := src2.IsOnSourceBackendForTesting(), false; got != want {
t.Errorf("got: %v, want: %v", 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. // Update the count with using src2 as a rendering source.
for i := 0; i < atlas.BaseCountToPutOnSourceBackend; i++ { for i := 0; i < atlas.BaseCountToPutOnSourceBackend; i++ {
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
vs := quadVertices(size, size, 0, 0, 1) 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) 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 { 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 { if got, want := src2.IsOnSourceBackendForTesting(), true; got != want {
t.Errorf("got: %v, want: %v", 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. // Check the pixels are the original ones.
pix = make([]byte, 4*size*size) 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) t.Fatal(err)
} }
for j := 0; j < size; j++ { for j := 0; j < size; j++ {
@ -767,14 +767,14 @@ func TestDestinationCountOverflow(t *testing.T) {
// Use dst0 as a destination for a while. // Use dst0 as a destination for a while.
for i := 0; i < 31; i++ { 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) 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. // 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. // 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++ { 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) 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() { if dst0.IsOnSourceBackendForTesting() {
t.Errorf("dst0 cannot be on a source backend: %d", i) t.Errorf("dst0 cannot be on a source backend: %d", i)
} }
@ -801,7 +801,7 @@ func TestIteratingImagesToPutOnSourceBackend(t *testing.T) {
for _, img := range srcs { for _, img := range srcs {
img.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) 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. // Use srcs as sources. This will register an image to imagesToPutOnSourceBackend.
// Check iterating the registered image works correctly. // Check iterating the registered image works correctly.
@ -809,7 +809,7 @@ func TestIteratingImagesToPutOnSourceBackend(t *testing.T) {
for _, src := range srcs { for _, src := range srcs {
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) 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) vs := quadVertices(w, h, 0, 0, 1)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dr := image.Rect(0, 0, w, h) dr := image.Rect(0, 0, w, h)
g := ui.GraphicsDriverForTesting() g := ui.Get().GraphicsDriverForTesting()
s0 := atlas.NewShader(etesting.ShaderProgramFill(0xff, 0xff, 0xff, 0xff)) 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) 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) 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) 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) 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 { 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) 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) 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, Pixels: pix,
Region: image.Rect(0, 0, w, h), Region: image.Rect(0, 0, w, h),
@ -111,7 +111,7 @@ func TestShader(t *testing.T) {
dr := image.Rect(0, 0, w, h) 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) 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)) 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) 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} clr0 := color.RGBA{A: 0xff}
img0.WritePixels(bytesToManagedBytes([]byte{clr0.R, clr0.G, clr0.B, clr0.A}), image.Rect(0, 0, 1, 1)) 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) t.Fatal(err)
} }
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
want := clr0 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 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) t.Fatal(err)
} }
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -145,10 +145,10 @@ func TestRestoreChain(t *testing.T) {
dr := image.Rect(0, 0, 1, 1) 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) 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) t.Fatal(err)
} }
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
want := clr 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) 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) t.Fatal(err)
} }
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
for i, img := range imgs { 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) 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)) 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) 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) t.Fatal(err)
} }
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
testCases := []struct { 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) 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) 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) 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) t.Fatal(err)
} }
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
testCases := []struct { testCases := []struct {
@ -424,10 +424,10 @@ func TestRestoreRecursive(t *testing.T) {
dr := image.Rect(0, 0, w, h) 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) 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) 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) t.Fatal(err)
} }
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
testCases := []struct { testCases := []struct {
@ -474,7 +474,7 @@ func TestWritePixels(t *testing.T) {
for i := range pix { for i := range pix {
pix[i] = 0 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) t.Fatal(err)
} }
for j := 7; j < 11; j++ { 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) t.Fatal(err)
} }
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) 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) t.Fatal(err)
} }
for j := 7; j < 11; j++ { 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.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)) 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) t.Fatal(err)
} }
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
var pix [4]byte 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) t.Fatal(err)
} }
got := color.RGBA{R: pix[0], G: pix[1], B: pix[2], A: pix[3]} 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) 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() img1.Dispose()
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
var pix [4]byte 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) t.Fatal(err)
} }
got := color.RGBA{R: pix[0], G: pix[1], B: pix[2], A: pix[3]} 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) t.Fatal(err)
} }
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
want := color.RGBA{R: 1, G: 2, B: 3, A: 4} want := color.RGBA{R: 1, G: 2, B: 3, A: 4}
@ -731,7 +731,7 @@ func TestReadPixelsFromVolatileImage(t *testing.T) {
want := byte(0xff) want := byte(0xff)
var result [4]byte 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) t.Fatal(err)
} }
got := result[0] 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)) dst.WritePixels(bytesToManagedBytes(make([]byte, 4*2*2)), image.Rect(0, 0, 2, 2))
// WritePixels for a part of image doesn't panic. // 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) t.Fatal(err)
} }
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
result := make([]byte, 4*w*h) 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) t.Fatal(err)
} }
for j := 0; j < h; j++ { 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. extended := orig.Extend(w*2, h*2) // After this, orig is already disposed.
result := make([]byte, 4*(w*2)*(h*2)) 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) t.Fatal(err)
} }
for j := 0; j < h*2; j++ { 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. extended := orig.Extend(w*2, h*2) // After this, orig is already disposed.
result := make([]byte, 4*(w*2)*(h*2)) 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) t.Fatal(err)
} }
for j := 0; j < h*2; j++ { for j := 0; j < h*2; j++ {
@ -918,19 +918,19 @@ func TestMutateSlices(t *testing.T) {
for i := range is { for i := range is {
is[i] = 0 is[i] = 0
} }
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
srcPix := make([]byte, 4*w*h) 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) t.Fatal(err)
} }
dstPix := make([]byte, 4*w*h) 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) t.Fatal(err)
} }
@ -988,7 +988,7 @@ func TestOverlappedPixels(t *testing.T) {
} }
result := make([]byte, 4*3*3) 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) t.Fatal(err)
} }
for j := 0; j < 3; j++ { for j := 0; j < 3; j++ {
@ -1017,7 +1017,7 @@ func TestOverlappedPixels(t *testing.T) {
{0, 0xff, 0, 0xff}, {0, 0xff, 0, 0xff},
{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) t.Fatal(err)
} }
for j := 0; j < 3; j++ { for j := 0; j < 3; j++ {
@ -1056,7 +1056,7 @@ func TestOverlappedPixels(t *testing.T) {
{0, 0, 0xff, 0xff}, {0, 0, 0xff, 0xff},
{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) t.Fatal(err)
} }
for j := 0; j < 3; j++ { 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) t.Fatal(err)
} }
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) 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) t.Fatal(err)
} }
for j := 0; j < 3; j++ { 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) 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) 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) 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) { 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. // Get the pixels.
pix := make([]byte, 4*2*1) 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) 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) { 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) 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) 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) t.Fatal(err)
} }
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) 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) 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) t.Fatal(err)
} }
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -122,10 +122,10 @@ func TestShaderMultipleSources(t *testing.T) {
// Clear one of the sources after DrawTriangles. dst should not be affected. // Clear one of the sources after DrawTriangles. dst should not be affected.
clearImage(srcs[0], 1, 1) 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) t.Fatal(err)
} }
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -159,10 +159,10 @@ func TestShaderMultipleSourcesOnOneTexture(t *testing.T) {
// Clear one of the sources after DrawTriangles. dst should not be affected. // Clear one of the sources after DrawTriangles. dst should not be affected.
clearImage(srcs[0], 3, 1) 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) t.Fatal(err)
} }
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -185,10 +185,10 @@ func TestShaderDispose(t *testing.T) {
// stale. // stale.
s.Dispose() s.Dispose()
if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := restorable.RestoreIfNeeded(ui.GraphicsDriverForTesting()); err != nil { if err := restorable.RestoreIfNeeded(ui.Get().GraphicsDriverForTesting()); err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

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

View File

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

View File

@ -98,8 +98,8 @@ func newGraphicsDriver(creator graphicsDriverCreator, graphicsLibrary GraphicsLi
} }
} }
func GraphicsDriverForTesting() graphicsdriver.Graphics { func (u *UserInterface) GraphicsDriverForTesting() graphicsdriver.Graphics {
return theUI.graphicsDriver return u.graphicsDriver
} }
type GraphicsLibrary int 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) 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. // compiling on Windows without specifying the '-ldflags "-Hwindowsgui"' flag.
func hideConsoleWindowOnWindows() { func hideConsoleWindow() {
// In Xbox, GetWindowThreadProcessId might not exist. // In Xbox, GetWindowThreadProcessId might not exist.
if user32.NewProc("GetWindowThreadProcessId").Find() != nil { if user32.NewProc("GetWindowThreadProcessId").Find() != nil {
return return

View File

@ -36,6 +36,8 @@ func SetPanicOnErrorOnReadingPixelsForTesting(value bool) {
const bigOffscreenScale = 2 const bigOffscreenScale = 2
type Image struct { type Image struct {
ui *UserInterface
mipmap *mipmap.Mipmap mipmap *mipmap.Mipmap
width int width int
height int height int
@ -53,8 +55,9 @@ type Image struct {
tmpVerticesForFill []float32 tmpVerticesForFill []float32
} }
func NewImage(width, height int, imageType atlas.ImageType) *Image { func (u *UserInterface) NewImage(width, height int, imageType atlas.ImageType) *Image {
return &Image{ return &Image{
ui: u,
mipmap: mipmap.New(width, height, imageType), mipmap: mipmap.New(width, height, imageType),
width: width, width: width,
height: height, height: height,
@ -95,7 +98,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
default: default:
panic(fmt.Sprintf("ui: unexpected image type: %d", imageType)) 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) 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() 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 { if panicOnErrorOnReadingPixels {
panic(err) 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) { func (i *Image) DumpScreenshot(name string, blackbg bool) (string, error) {
i.flushBufferIfNeeded() i.flushBufferIfNeeded()
return theUI.dumpScreenshot(i.mipmap, name, blackbg) return i.ui.dumpScreenshot(i.mipmap, name, blackbg)
} }
func (i *Image) flushBufferIfNeeded() { func (i *Image) flushBufferIfNeeded() {
@ -244,7 +247,7 @@ func (i *Image) flushDotsBufferIfNeeded() {
} }
i.dotsBuffer = nil 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) 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) 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) { func (u *UserInterface) DumpImages(dir string) (string, error) {
return theUI.dumpImages(dir) return u.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 (i *Image) clear() { 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. // i.tmpVerticesForFill can be reused as this is sent to DrawTriangles immediately.
graphics.QuadVertices( graphics.QuadVertices(
i.tmpVerticesForFill, 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, float32(i.width), 0, 0, float32(i.height), 0, 0,
r, g, b, a) r, g, b, a)
is := graphics.QuadIndices() 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) i.DrawTriangles(srcs, i.tmpVerticesForFill, is, graphicsdriver.BlendCopy, region, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, false, true, false)
} }
type bigOffscreenImage struct { type bigOffscreenImage struct {
ui *UserInterface
orig *Image orig *Image
imageType atlas.ImageType imageType atlas.ImageType
@ -307,8 +299,9 @@ type bigOffscreenImage struct {
tmpVerticesForCopying []float32 tmpVerticesForCopying []float32
} }
func newBigOffscreenImage(orig *Image, imageType atlas.ImageType) *bigOffscreenImage { func (u *UserInterface) newBigOffscreenImage(orig *Image, imageType atlas.ImageType) *bigOffscreenImage {
return &bigOffscreenImage{ return &bigOffscreenImage{
ui: u,
orig: orig, orig: orig,
imageType: imageType, imageType: imageType,
} }
@ -340,7 +333,7 @@ func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderImageCount]*Image
} }
if i.image == nil { 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. // Copy the current rendering result to get the correct blending result.

View File

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

View File

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

View File

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

View File

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

View File

@ -67,16 +67,47 @@ const (
) )
type UserInterface struct { type UserInterface struct {
whiteImage *Image
userInterfaceImpl 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 { func Get() *UserInterface {
// TODO: Get is a legacy API to access this package. Remove this.
return theUI 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 { func (u *UserInterface) readPixels(mipmap *mipmap.Mipmap, pixels []byte, region image.Rectangle) error {
return mipmap.ReadPixels(u.graphicsDriver, pixels, region) return mipmap.ReadPixels(u.graphicsDriver, pixels, region)
} }

View File

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

View File

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

View File

@ -144,8 +144,8 @@ func (u *UserInterface) SetFullscreen(fullscreen bool) {
return return
} }
if theUI.cursorMode == CursorModeCaptured { if u.cursorMode == CursorModeCaptured {
theUI.saveCursorPosition() u.saveCursorPosition()
} }
if fullscreen { if fullscreen {
@ -186,7 +186,7 @@ func (u *UserInterface) IsRunnableOnUnfocused() bool {
return u.runnableOnUnfocused return u.runnableOnUnfocused
} }
func (u *UserInterface) SetFPSMode(mode FPSModeType) { func (u *UserInterface) setFPSMode(mode FPSModeType) {
u.fpsMode = mode u.fpsMode = mode
} }
@ -236,7 +236,7 @@ func (u *UserInterface) setCursorMode(mode CursorMode) {
} }
func (u *UserInterface) recoverCursorMode() { func (u *UserInterface) recoverCursorMode() {
if theUI.cursorPrevMode == CursorModeCaptured { if u.cursorPrevMode == CursorModeCaptured {
panic("ui: cursorPrevMode must not be CursorModeCaptured at recoverCursorMode") panic("ui: cursorPrevMode must not be CursorModeCaptured at recoverCursorMode")
} }
u.SetCursorMode(u.cursorPrevMode) u.SetCursorMode(u.cursorPrevMode)
@ -471,8 +471,8 @@ func (u *UserInterface) loop(game Game) <-chan error {
return errCh return errCh
} }
func init() { func (u *UserInterface) init() error {
theUI.userInterfaceImpl = userInterfaceImpl{ u.userInterfaceImpl = userInterfaceImpl{
runnableOnUnfocused: true, runnableOnUnfocused: true,
savedCursorX: math.NaN(), savedCursorX: math.NaN(),
savedCursorY: math.NaN(), savedCursorY: math.NaN(),
@ -480,7 +480,7 @@ func init() {
// docuemnt is undefined on node.js // docuemnt is undefined on node.js
if !document.Truthy() { if !document.Truthy() {
return return nil
} }
if !document.Get("body").Truthy() { if !document.Get("body").Truthy() {
@ -492,7 +492,7 @@ func init() {
<-ch <-ch
} }
setWindowEventHandlers(window) u.setWindowEventHandlers(window)
// Adjust the initial scale to 1. // Adjust the initial scale to 1.
// https://developer.mozilla.org/en/docs/Mozilla/Mobile/Viewport_meta_tag // https://developer.mozilla.org/en/docs/Mozilla/Mobile/Viewport_meta_tag
@ -528,7 +528,7 @@ func init() {
canvas.Call("setAttribute", "tabindex", 1) canvas.Call("setAttribute", "tabindex", 1)
canvas.Get("style").Set("outline", "none") canvas.Get("style").Set("outline", "none")
setCanvasEventHandlers(canvas) u.setCanvasEventHandlers(canvas)
// Pointer Lock // Pointer Lock
document.Call("addEventListener", "pointerlockchange", js.FuncOf(func(this js.Value, args []js.Value) any { 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. // 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. // A user can exit the pointer lock by pressing ESC. In this case, sync the cursor mode state.
if theUI.cursorMode == CursorModeCaptured { if u.cursorMode == CursorModeCaptured {
theUI.recoverCursorMode() u.recoverCursorMode()
} }
theUI.recoverCursorPosition() u.recoverCursorPosition()
return nil return nil
})) }))
document.Call("addEventListener", "pointerlockerror", js.FuncOf(func(this js.Value, args []js.Value) any { 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.") 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
})) }))
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 { v.Call("addEventListener", "resize", js.FuncOf(func(this js.Value, args []js.Value) any {
theUI.updateScreenSize() u.updateScreenSize()
// updateImpl can block. Use goroutine. // updateImpl can block. Use goroutine.
// See https://pkg.go.dev/syscall/js#FuncOf. // See https://pkg.go.dev/syscall/js#FuncOf.
go func() { go func() {
if err := theUI.updateImpl(true); err != nil { if err := u.updateImpl(true); err != nil {
theGlobalState.setError(err) theGlobalState.setError(err)
return return
} }
@ -574,7 +576,7 @@ func setWindowEventHandlers(v js.Value) {
})) }))
} }
func setCanvasEventHandlers(v js.Value) { func (u *UserInterface) setCanvasEventHandlers(v js.Value) {
// Keyboard // Keyboard
v.Call("addEventListener", "keydown", js.FuncOf(func(this js.Value, args []js.Value) any { v.Call("addEventListener", "keydown", js.FuncOf(func(this js.Value, args []js.Value) any {
// Focus the canvas explicitly to activate tha game (#961). // Focus the canvas explicitly to activate tha game (#961).
@ -582,7 +584,7 @@ func setCanvasEventHandlers(v js.Value) {
e := args[0] e := args[0]
e.Call("preventDefault") e.Call("preventDefault")
if err := theUI.updateInputFromEvent(e); err != nil { if err := u.updateInputFromEvent(e); err != nil {
theGlobalState.setError(err) theGlobalState.setError(err)
return nil 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 { v.Call("addEventListener", "keyup", js.FuncOf(func(this js.Value, args []js.Value) any {
e := args[0] e := args[0]
e.Call("preventDefault") e.Call("preventDefault")
if err := theUI.updateInputFromEvent(e); err != nil { if err := u.updateInputFromEvent(e); err != nil {
theGlobalState.setError(err) theGlobalState.setError(err)
return nil return nil
} }
@ -605,7 +607,7 @@ func setCanvasEventHandlers(v js.Value) {
e := args[0] e := args[0]
e.Call("preventDefault") e.Call("preventDefault")
if err := theUI.updateInputFromEvent(e); err != nil { if err := u.updateInputFromEvent(e); err != nil {
theGlobalState.setError(err) theGlobalState.setError(err)
return nil 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 { v.Call("addEventListener", "mouseup", js.FuncOf(func(this js.Value, args []js.Value) any {
e := args[0] e := args[0]
e.Call("preventDefault") e.Call("preventDefault")
if err := theUI.updateInputFromEvent(e); err != nil { if err := u.updateInputFromEvent(e); err != nil {
theGlobalState.setError(err) theGlobalState.setError(err)
return nil 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 { v.Call("addEventListener", "mousemove", js.FuncOf(func(this js.Value, args []js.Value) any {
e := args[0] e := args[0]
e.Call("preventDefault") e.Call("preventDefault")
if err := theUI.updateInputFromEvent(e); err != nil { if err := u.updateInputFromEvent(e); err != nil {
theGlobalState.setError(err) theGlobalState.setError(err)
return nil 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 { v.Call("addEventListener", "wheel", js.FuncOf(func(this js.Value, args []js.Value) any {
e := args[0] e := args[0]
e.Call("preventDefault") e.Call("preventDefault")
if err := theUI.updateInputFromEvent(e); err != nil { if err := u.updateInputFromEvent(e); err != nil {
theGlobalState.setError(err) theGlobalState.setError(err)
return nil return nil
} }
@ -646,7 +648,7 @@ func setCanvasEventHandlers(v js.Value) {
e := args[0] e := args[0]
e.Call("preventDefault") e.Call("preventDefault")
if err := theUI.updateInputFromEvent(e); err != nil { if err := u.updateInputFromEvent(e); err != nil {
theGlobalState.setError(err) theGlobalState.setError(err)
return nil 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 { v.Call("addEventListener", "touchend", js.FuncOf(func(this js.Value, args []js.Value) any {
e := args[0] e := args[0]
e.Call("preventDefault") e.Call("preventDefault")
if err := theUI.updateInputFromEvent(e); err != nil { if err := u.updateInputFromEvent(e); err != nil {
theGlobalState.setError(err) theGlobalState.setError(err)
return nil 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 { v.Call("addEventListener", "touchmove", js.FuncOf(func(this js.Value, args []js.Value) any {
e := args[0] e := args[0]
e.Call("preventDefault") e.Call("preventDefault")
if err := theUI.updateInputFromEvent(e); err != nil { if err := u.updateInputFromEvent(e); err != nil {
theGlobalState.setError(err) theGlobalState.setError(err)
return nil return nil
} }
@ -700,7 +702,7 @@ func setCanvasEventHandlers(v js.Value) {
return nil return nil
} }
go theUI.appendDroppedFiles(data) go u.appendDroppedFiles(data)
return nil return nil
})) }))
} }

View File

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

View File

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

View File

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

View File

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

6
run.go
View File

@ -477,9 +477,9 @@ func IsVsyncEnabled() bool {
// the game uses the display's vsync. // the game uses the display's vsync.
func SetVsyncEnabled(enabled bool) { func SetVsyncEnabled(enabled bool) {
if enabled { if enabled {
ui.SetFPSMode(ui.FPSModeVsyncOn) ui.Get().SetFPSMode(ui.FPSModeVsyncOn)
} else { } 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. // Deprecated: as of v2.5. Use SetVsyncEnabled instead.
func SetFPSMode(mode FPSModeType) { func SetFPSMode(mode FPSModeType) {
ui.SetFPSMode(mode) ui.Get().SetFPSMode(mode)
} }
// ScheduleFrame schedules a next frame when the current FPS mode is FPSModeVsyncOffMinimum. // 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. // TODO: Remove this. In order to remove this, the gameForUI should be in another package.
func RunGameWithoutMainLoop(game Game, options *RunGameOptions) { func RunGameWithoutMainLoop(game Game, options *RunGameOptions) {
op := toUIRunOptions(options) op := toUIRunOptions(options)
ui.RunWithoutMainLoop(newGameForUI(game, op.ScreenTransparent), op) ui.Get().RunWithoutMainLoop(newGameForUI(game, op.ScreenTransparent), op)
} }