diff --git a/ebiten.go b/ebiten.go index d77ca455c..53940c3b6 100644 --- a/ebiten.go +++ b/ebiten.go @@ -8,7 +8,7 @@ import ( type Game interface { Update() - Draw(g graphics.GraphicsContext, offscreen graphics.Texture) + Draw(g graphics.GraphicsContext, offscreen *graphics.Texture) } type UI interface { @@ -22,7 +22,7 @@ func OpenGLRun(game Game, ui UI) { ch := make(chan bool, 1) device := opengl.NewDevice( ui.ScreenWidth(), ui.ScreenHeight(), ui.ScreenScale(), - func(g graphics.GraphicsContext, offscreen graphics.Texture) { + func(g graphics.GraphicsContext, offscreen *graphics.Texture) { ticket := <-ch game.Draw(g, offscreen) ch<- ticket diff --git a/examples/glut/main.go b/examples/glut/main.go index b6ff8ee8d..c9736a08d 100644 --- a/examples/glut/main.go +++ b/examples/glut/main.go @@ -91,7 +91,7 @@ func (ui *GlutUI) Run(device graphics.Device) { } type DemoGame struct { - ebitenTexture graphics.Texture + ebitenTexture *graphics.Texture x int } @@ -108,13 +108,12 @@ func (game *DemoGame) Update() { panic(err) } - // TODO: It looks strange to get a texture from the device. - game.ebitenTexture = currentUI.device.NewTextureFromImage(img) + game.ebitenTexture = graphics.NewTextureFromImage(img) } game.x++ } -func (game *DemoGame) Draw(g graphics.GraphicsContext, offscreen graphics.Texture) { +func (game *DemoGame) Draw(g graphics.GraphicsContext, offscreen *graphics.Texture) { g.Fill(&color.RGBA{R: 128, G: 128, B: 255, A: 255}) if game.ebitenTexture == nil { return @@ -123,7 +122,7 @@ func (game *DemoGame) Draw(g graphics.GraphicsContext, offscreen graphics.Textur geometryMatrix.SetTx(float64(game.x)) geometryMatrix.SetTy(float64(game.x)) g.DrawTexture(game.ebitenTexture, - 0, 0, game.ebitenTexture.Width(), game.ebitenTexture.Height(), + 0, 0, game.ebitenTexture.Width, game.ebitenTexture.Height, geometryMatrix, graphics.IdentityColorMatrix()) } diff --git a/graphics/graphics.go b/graphics/graphics.go index f3ce2a4bd..f1a723fff 100644 --- a/graphics/graphics.go +++ b/graphics/graphics.go @@ -7,23 +7,28 @@ import ( type Device interface { Update() - // TODO: Move somewhere - NewTexture(width, height int) Texture - NewTextureFromImage(img image.Image) Texture } type GraphicsContext interface { Clear() Fill(color color.Color) - DrawTexture(texture Texture, + DrawTexture(texture *Texture, srcX, srcY, srcWidth, srcHeight int, geometryMatrix *GeometryMatrix, colorMatrix *ColorMatrix) - SetOffscreen(texture Texture) + SetOffscreen(texture *Texture) } -type Texture interface { - Width() int - Height() int - TextureWidth() int - TextureHeight() int +type Texture struct { + Width int + Height int + Image image.Image +} + +func NewTexture(width, height int) *Texture { + return &Texture{width, height, nil} +} + +func NewTextureFromImage(img image.Image) *Texture { + size := img.Bounds().Size() + return &Texture{size.X, size.Y, img} } diff --git a/graphics/opengl/device.go b/graphics/opengl/device.go index d061eafa0..57d6f2010 100644 --- a/graphics/opengl/device.go +++ b/graphics/opengl/device.go @@ -6,7 +6,6 @@ package opengl // #include import "C" import ( - "image" "github.com/hajimehoshi/go-ebiten/graphics" ) @@ -15,13 +14,13 @@ type Device struct { screenHeight int screenScale int graphicsContext *GraphicsContext - offscreenTexture *Texture - drawFunc func(graphics.GraphicsContext, graphics.Texture) + offscreenTexture *graphics.Texture + drawFunc func(graphics.GraphicsContext, *graphics.Texture) funcs []func() } func NewDevice(screenWidth, screenHeight, screenScale int, - drawFunc func(graphics.GraphicsContext, graphics.Texture)) *Device { + drawFunc func(graphics.GraphicsContext, *graphics.Texture)) *Device { device := &Device{ screenWidth: screenWidth, screenHeight: screenHeight, @@ -30,16 +29,11 @@ func NewDevice(screenWidth, screenHeight, screenScale int, drawFunc: drawFunc, funcs: []func(){}, } - device.offscreenTexture = device.NewTexture(screenWidth, screenHeight).(*Texture) + device.offscreenTexture = graphics.NewTexture(screenWidth, screenHeight) return device } func (device *Device) Update() { - for _, f := range device.funcs { - f() - } - device.funcs = []func(){} - g := device.graphicsContext C.glEnable(C.GL_TEXTURE_2D) C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MIN_FILTER, C.GL_NEAREST) @@ -61,25 +55,3 @@ func (device *Device) Update() { geometryMatrix, graphics.IdentityColorMatrix()) g.flush() } - -func (device *Device) NewTexture(width, height int) graphics.Texture { - return createTexture(device, width, height, nil) -} - -func (device *Device) NewTextureFromImage(img image.Image) graphics.Texture { - var pix []uint8 - switch img.(type) { - case *image.RGBA: - pix = img.(*image.RGBA).Pix - case *image.NRGBA: - pix = img.(*image.NRGBA).Pix - default: - panic("image should be RGBA or NRGBA") - } - size := img.Bounds().Size() - return createTexture(device, size.X, size.Y, pix) -} - -func (device *Device) executeWhenDrawing(f func()) { - device.funcs = append(device.funcs, f) -} diff --git a/graphics/opengl/graphics_context.go b/graphics/opengl/graphics_context.go index c5f22119b..564958cf8 100644 --- a/graphics/opengl/graphics_context.go +++ b/graphics/opengl/graphics_context.go @@ -41,6 +41,23 @@ func newGraphicsContext(screenWidth, screenHeight, screenScale int) *GraphicsCon return context } +var glTextureCache = map[*graphics.Texture]*Texture{} + +func glTexture(tex *graphics.Texture) *Texture { + if glTex, ok := glTextureCache[tex]; ok { + return glTex + } + + var glTex *Texture = nil + if tex.Image != nil { + glTex = newTextureFromImage(tex.Image) + } else { + glTex = newTexture(tex.Width, tex.Height) + } + glTextureCache[tex] = glTex + return glTex +} + func (context *GraphicsContext) Clear() { C.glClearColor(0, 0, 0, 1) C.glClear(C.GL_COLOR_BUFFER_BIT) @@ -61,13 +78,13 @@ func (context *GraphicsContext) DrawRect(x, y, width, height int, clr color.Colo // TODO: implement! } -func (context *GraphicsContext) DrawTexture(tex graphics.Texture, +func (context *GraphicsContext) DrawTexture(tex *graphics.Texture, srcX, srcY, srcWidth, srcHeight int, geometryMatrix *graphics.GeometryMatrix, colorMatrix *graphics.ColorMatrix) { geometryMatrix = geometryMatrix.Clone() colorMatrix = colorMatrix.Clone() - texture := tex.(*Texture) + texture := glTexture(tex) context.setShaderProgram(geometryMatrix, colorMatrix) C.glBindTexture(C.GL_TEXTURE_2D, texture.id) @@ -119,12 +136,12 @@ func abs(x int) int { return x } -func (context *GraphicsContext) SetOffscreen(tex graphics.Texture) { +func (context *GraphicsContext) SetOffscreen(tex *graphics.Texture) { C.glFlush() var texture *Texture = nil if tex != nil { - texture = tex.(*Texture) + texture = glTexture(tex) } framebuffer := C.GLuint(0) if texture != nil { diff --git a/graphics/opengl/texture.go b/graphics/opengl/texture.go index 567da56a1..ccc42bea9 100644 --- a/graphics/opengl/texture.go +++ b/graphics/opengl/texture.go @@ -5,6 +5,7 @@ package opengl // #include import "C" import ( + "image" "unsafe" ) @@ -27,7 +28,7 @@ type Texture struct { textureHeight int } -func createTexture(device *Device, width, height int, pixels []uint8) *Texture{ +func createTexture(width, height int, pixels []uint8) *Texture { textureWidth := int(Clp2(uint64(width))) textureHeight := int(Clp2(uint64(height))) if pixels != nil { @@ -46,50 +47,46 @@ func createTexture(device *Device, width, height int, pixels []uint8) *Texture{ textureHeight: textureHeight, } - device.executeWhenDrawing(func() { - textureID := C.GLuint(0) - C.glGenTextures(1, (*C.GLuint)(&textureID)) - if textureID == 0 { - panic("glGenTexture failed") - } - C.glPixelStorei(C.GL_UNPACK_ALIGNMENT, 4) - C.glBindTexture(C.GL_TEXTURE_2D, C.GLuint(textureID)) - - ptr := unsafe.Pointer(nil) - if pixels != nil { - ptr = unsafe.Pointer(&pixels[0]) - } - C.glTexImage2D(C.GL_TEXTURE_2D, 0, C.GL_RGBA, - C.GLsizei(textureWidth), C.GLsizei(textureHeight), - 0, C.GL_RGBA, C.GL_UNSIGNED_BYTE, ptr) + textureID := C.GLuint(0) + C.glGenTextures(1, (*C.GLuint)(&textureID)) + if textureID == 0 { + panic("glGenTexture failed") + } + C.glPixelStorei(C.GL_UNPACK_ALIGNMENT, 4) + C.glBindTexture(C.GL_TEXTURE_2D, C.GLuint(textureID)) + + ptr := unsafe.Pointer(nil) + if pixels != nil { + ptr = unsafe.Pointer(&pixels[0]) + } + C.glTexImage2D(C.GL_TEXTURE_2D, 0, C.GL_RGBA, + C.GLsizei(textureWidth), C.GLsizei(textureHeight), + 0, C.GL_RGBA, C.GL_UNSIGNED_BYTE, ptr) - C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MAG_FILTER, C.GL_LINEAR) - C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MIN_FILTER, C.GL_LINEAR) - C.glBindTexture(C.GL_TEXTURE_2D, 0) + C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MAG_FILTER, C.GL_LINEAR) + C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MIN_FILTER, C.GL_LINEAR) + C.glBindTexture(C.GL_TEXTURE_2D, 0) - // TODO: lock? - texture.id = textureID - }) + // TODO: lock? + texture.id = textureID return texture } -func (texture *Texture) Width() int { - return texture.width +func newTexture(width, height int) *Texture { + return createTexture(width, height, nil) } -func (texture *Texture) Height() int { - return texture.height -} - -func (texture *Texture) TextureWidth() int { - return texture.textureWidth -} - -func (texture *Texture) TextureHeight() int { - return texture.textureHeight -} - -func (texture *Texture) IsAvailable() bool { - return texture.id != 0 +func newTextureFromImage(img image.Image) *Texture { + var pix []uint8 + switch img.(type) { + case *image.RGBA: + pix = img.(*image.RGBA).Pix + case *image.NRGBA: + pix = img.(*image.NRGBA).Pix + default: + panic("image should be RGBA or NRGBA") + } + size := img.Bounds().Size() + return createTexture(size.X, size.Y, pix) }