image.go (3410B)
1 // Copyright 2018 The Ebiten Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package opengl 16 17 import ( 18 "github.com/hajimehoshi/ebiten/v2/internal/driver" 19 "github.com/hajimehoshi/ebiten/v2/internal/graphics" 20 ) 21 22 type Image struct { 23 id driver.ImageID 24 graphics *Graphics 25 textureNative textureNative 26 framebuffer *framebuffer 27 pbo buffer 28 width int 29 height int 30 screen bool 31 } 32 33 func (i *Image) ID() driver.ImageID { 34 return i.id 35 } 36 37 func (i *Image) IsInvalidated() bool { 38 return !i.graphics.context.isTexture(i.textureNative) 39 } 40 41 func (i *Image) Dispose() { 42 if !i.pbo.equal(*new(buffer)) { 43 i.graphics.context.deleteBuffer(i.pbo) 44 } 45 if i.framebuffer != nil { 46 i.framebuffer.delete(&i.graphics.context) 47 } 48 if !i.textureNative.equal(*new(textureNative)) { 49 i.graphics.context.deleteTexture(i.textureNative) 50 } 51 52 i.graphics.removeImage(i) 53 } 54 55 func (i *Image) setViewport() error { 56 if err := i.ensureFramebuffer(); err != nil { 57 return err 58 } 59 i.graphics.context.setViewport(i.framebuffer) 60 return nil 61 } 62 63 func (i *Image) Pixels() ([]byte, error) { 64 if err := i.ensureFramebuffer(); err != nil { 65 return nil, err 66 } 67 p, err := i.graphics.context.framebufferPixels(i.framebuffer, i.width, i.height) 68 if err != nil { 69 return nil, err 70 } 71 return p, nil 72 } 73 74 func (i *Image) framebufferSize() (int, int) { 75 if i.screen { 76 // The (default) framebuffer size can't be converted to a power of 2. 77 // On browsers, i.width and i.height are used as viewport size and 78 // Edge can't treat a bigger viewport than the drawing area (#71). 79 return i.width, i.height 80 } 81 return graphics.InternalImageSize(i.width), graphics.InternalImageSize(i.height) 82 } 83 84 func (i *Image) ensureFramebuffer() error { 85 if i.framebuffer != nil { 86 return nil 87 } 88 89 w, h := i.framebufferSize() 90 if i.screen { 91 i.framebuffer = newScreenFramebuffer(&i.graphics.context, w, h) 92 return nil 93 } 94 f, err := newFramebufferFromTexture(&i.graphics.context, i.textureNative, w, h) 95 if err != nil { 96 return err 97 } 98 i.framebuffer = f 99 return nil 100 } 101 102 func (i *Image) ReplacePixels(args []*driver.ReplacePixelsArgs) { 103 if i.screen { 104 panic("opengl: ReplacePixels cannot be called on the screen, that doesn't have a texture") 105 } 106 if len(args) == 0 { 107 return 108 } 109 110 // glFlush is necessary on Android. 111 // glTexSubImage2D didn't work without this hack at least on Nexus 5x and NuAns NEO [Reloaded] (#211). 112 if i.graphics.drawCalled { 113 i.graphics.context.flush() 114 } 115 i.graphics.drawCalled = false 116 117 w, h := i.width, i.height 118 if !i.graphics.context.canUsePBO() { 119 i.graphics.context.texSubImage2D(i.textureNative, w, h, args) 120 return 121 } 122 if i.pbo.equal(*new(buffer)) { 123 i.pbo = i.graphics.context.newPixelBufferObject(w, h) 124 } 125 if i.pbo.equal(*new(buffer)) { 126 panic("opengl: newPixelBufferObject failed") 127 } 128 129 i.graphics.context.replacePixelsWithPBO(i.pbo, i.textureNative, w, h, args) 130 }