Add TextureFactory

This commit is contained in:
Hajime Hoshi 2013-06-19 23:08:24 +09:00
parent eda572d03e
commit 847b6b80f6
5 changed files with 97 additions and 90 deletions

View File

@ -7,8 +7,9 @@ import (
)
type Game interface {
Init(tf graphics.TextureFactory)
Update()
Draw(g graphics.GraphicsContext, offscreen *graphics.Texture)
Draw(g graphics.GraphicsContext, offscreen graphics.TextureID)
}
type UI interface {
@ -22,7 +23,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.TextureID) {
ticket := <-ch
game.Draw(g, offscreen)
ch<- ticket
@ -38,7 +39,8 @@ func OpenGLRun(game Game, ui UI) {
ch<- ticket
}
}()
ch<- true
game.Init(device.TextureFactory())
ch<- true
ui.Run(device)
}

View File

@ -91,37 +91,34 @@ func (ui *GlutUI) Run(device graphics.Device) {
}
type DemoGame struct {
ebitenTexture *graphics.Texture
ebitenTexture graphics.Texture
x int
}
func (game *DemoGame) Update() {
if game.ebitenTexture == nil {
file, err := os.Open("ebiten.png")
if err != nil {
panic(err)
}
defer file.Close()
img, _, err := image.Decode(file)
if err != nil {
panic(err)
}
game.ebitenTexture = graphics.NewTextureFromImage(img)
func (game *DemoGame) Init(tf graphics.TextureFactory) {
file, err := os.Open("ebiten.png")
if err != nil {
panic(err)
}
defer file.Close()
img, _, err := image.Decode(file)
if err != nil {
panic(err)
}
game.ebitenTexture = tf.NewTextureFromImage(img)
}
func (game *DemoGame) Update() {
game.x++
}
func (game *DemoGame) Draw(g graphics.GraphicsContext, offscreen *graphics.Texture) {
func (game *DemoGame) Draw(g graphics.GraphicsContext, offscreen graphics.TextureID) {
g.Fill(&color.RGBA{R: 128, G: 128, B: 255, A: 255})
if game.ebitenTexture == nil {
return
}
geometryMatrix := graphics.IdentityGeometryMatrix()
geometryMatrix.SetTx(float64(game.x))
geometryMatrix.SetTy(float64(game.x))
g.DrawTexture(game.ebitenTexture,
g.DrawTexture(game.ebitenTexture.ID,
0, 0, game.ebitenTexture.Width, game.ebitenTexture.Height,
geometryMatrix,
graphics.IdentityColorMatrix())

View File

@ -7,28 +7,27 @@ import (
type Device interface {
Update()
TextureFactory() TextureFactory
}
type GraphicsContext interface {
Clear()
Fill(color color.Color)
DrawTexture(texture *Texture,
DrawTexture(textureId TextureID,
srcX, srcY, srcWidth, srcHeight int,
geometryMatrix *GeometryMatrix, colorMatrix *ColorMatrix)
SetOffscreen(texture *Texture)
SetOffscreen(textureId TextureID)
}
type TextureFactory interface {
NewTexture(width, height int) Texture
NewTextureFromImage(img image.Image) Texture
}
type Texture struct {
ID TextureID
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}
}
type TextureID int

View File

@ -14,22 +14,21 @@ type Device struct {
screenHeight int
screenScale int
graphicsContext *GraphicsContext
offscreenTexture *graphics.Texture
drawFunc func(graphics.GraphicsContext, *graphics.Texture)
funcs []func()
offscreenTexture graphics.Texture
drawFunc func(graphics.GraphicsContext, graphics.TextureID)
}
func NewDevice(screenWidth, screenHeight, screenScale int,
drawFunc func(graphics.GraphicsContext, *graphics.Texture)) *Device {
drawFunc func(graphics.GraphicsContext, graphics.TextureID)) *Device {
device := &Device{
screenWidth: screenWidth,
screenHeight: screenHeight,
screenScale: screenScale,
graphicsContext: newGraphicsContext(screenWidth, screenHeight, screenScale),
drawFunc: drawFunc,
funcs: []func(){},
}
device.offscreenTexture = graphics.NewTexture(screenWidth, screenHeight)
device.offscreenTexture =
device.graphicsContext.NewTexture(screenWidth, screenHeight)
return device
}
@ -38,9 +37,9 @@ func (device *Device) Update() {
C.glEnable(C.GL_TEXTURE_2D)
C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MIN_FILTER, C.GL_NEAREST)
C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MAG_FILTER, C.GL_NEAREST)
g.SetOffscreen(device.offscreenTexture)
g.SetOffscreen(device.offscreenTexture.ID)
g.Clear()
device.drawFunc(g, device.offscreenTexture)
device.drawFunc(g, device.offscreenTexture.ID)
g.flush()
C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MIN_FILTER, C.GL_LINEAR)
@ -50,8 +49,12 @@ func (device *Device) Update() {
geometryMatrix := graphics.IdentityGeometryMatrix()
geometryMatrix.SetA(float64(g.screenScale))
geometryMatrix.SetD(float64(g.screenScale))
g.DrawTexture(device.offscreenTexture,
g.DrawTexture(device.offscreenTexture.ID,
0, 0, device.screenWidth, device.screenHeight,
geometryMatrix, graphics.IdentityColorMatrix())
g.flush()
}
func (device *Device) TextureFactory() graphics.TextureFactory {
return device.graphicsContext
}

View File

@ -7,6 +7,7 @@ package opengl
import "C"
import (
"fmt"
"image"
"image/color"
"unsafe"
"github.com/hajimehoshi/go-ebiten/graphics"
@ -16,9 +17,10 @@ type GraphicsContext struct {
screenWidth int
screenHeight int
screenScale int
mainFramebuffer C.GLuint
textures map[graphics.TextureID]*Texture
projectionMatrix [16]float32
currentShaderProgram C.GLuint
mainFramebuffer C.GLuint
framebuffers map[C.GLuint]C.GLuint
}
@ -28,6 +30,7 @@ func newGraphicsContext(screenWidth, screenHeight, screenScale int) *GraphicsCon
screenWidth: screenWidth,
screenHeight: screenHeight,
screenScale: screenScale,
textures: map[graphics.TextureID]*Texture{},
mainFramebuffer: 0,
framebuffers: map[C.GLuint]C.GLuint{},
}
@ -41,23 +44,6 @@ 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)
@ -78,13 +64,14 @@ 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(
textureID graphics.TextureID,
srcX, srcY, srcWidth, srcHeight int,
geometryMatrix *graphics.GeometryMatrix, colorMatrix *graphics.ColorMatrix) {
geometryMatrix = geometryMatrix.Clone()
colorMatrix = colorMatrix.Clone()
texture := glTexture(tex)
texture := context.textures[textureID]
context.setShaderProgram(geometryMatrix, colorMatrix)
C.glBindTexture(C.GL_TEXTURE_2D, texture.id)
@ -136,24 +123,23 @@ func abs(x int) int {
return x
}
func (context *GraphicsContext) SetOffscreen(tex *graphics.Texture) {
func (context *GraphicsContext) SetOffscreen(textureID graphics.TextureID) {
texture := context.textures[textureID]
framebuffer := context.getFramebuffer(texture.id)
if framebuffer == context.mainFramebuffer {
panic("invalid framebuffer")
}
context.setOffscreenFramebuffer(framebuffer,
texture.textureWidth, texture.textureHeight)
}
func (context *GraphicsContext) setOffscreenFramebuffer(framebuffer C.GLuint,
textureWidth, textureHeight int) {
C.glFlush()
var texture *Texture = nil
if tex != nil {
texture = glTexture(tex)
}
framebuffer := C.GLuint(0)
if texture != nil {
framebuffer = context.getFramebuffer(texture)
if framebuffer == context.mainFramebuffer {
panic("invalid framebuffer")
}
} else {
framebuffer = context.mainFramebuffer
}
C.glBindFramebuffer(C.GL_FRAMEBUFFER, framebuffer)
if err := C.glCheckFramebufferStatus(C.GL_FRAMEBUFFER); err != C.GL_FRAMEBUFFER_COMPLETE {
if err := C.glCheckFramebufferStatus(C.GL_FRAMEBUFFER);
err != C.GL_FRAMEBUFFER_COMPLETE {
panic(fmt.Sprintf("glBindFramebuffer failed: %d", err))
}
C.glEnable(C.GL_BLEND)
@ -161,8 +147,8 @@ func (context *GraphicsContext) SetOffscreen(tex *graphics.Texture) {
width, height, tx, ty := 0, 0, 0, 0
if framebuffer != context.mainFramebuffer {
width = texture.textureWidth
height = texture.textureHeight
width = textureWidth
height = textureHeight
tx = -1
ty = -1
} else {
@ -185,7 +171,7 @@ func (context *GraphicsContext) SetOffscreen(tex *graphics.Texture) {
}
func (context *GraphicsContext) resetOffscreen() {
context.SetOffscreen(nil)
context.setOffscreenFramebuffer(context.mainFramebuffer, 0, 0)
}
// This method should be called on the UI thread.
@ -255,9 +241,8 @@ func (context *GraphicsContext) setShaderProgram(
1, (*C.GLfloat)(&glColorMatrixTranslation[0]))
}
// This method should be called on the UI thread.
func (context *GraphicsContext) getFramebuffer(texture *Texture) C.GLuint{
framebuffer, ok := context.framebuffers[texture.id]
func (context *GraphicsContext) getFramebuffer(textureID C.GLuint) C.GLuint{
framebuffer, ok := context.framebuffers[textureID]
if ok {
return framebuffer
}
@ -269,23 +254,44 @@ func (context *GraphicsContext) getFramebuffer(texture *Texture) C.GLuint{
C.glGetIntegerv(C.GL_FRAMEBUFFER_BINDING, &origFramebuffer)
C.glBindFramebuffer(C.GL_FRAMEBUFFER, newFramebuffer)
C.glFramebufferTexture2D(C.GL_FRAMEBUFFER, C.GL_COLOR_ATTACHMENT0,
C.GL_TEXTURE_2D, texture.id, 0)
C.GL_TEXTURE_2D, textureID, 0)
C.glBindFramebuffer(C.GL_FRAMEBUFFER, C.GLuint(origFramebuffer))
if C.glCheckFramebufferStatus(C.GL_FRAMEBUFFER) != C.GL_FRAMEBUFFER_COMPLETE {
panic("creating framebuffer failed")
}
context.framebuffers[texture.id] = newFramebuffer
context.framebuffers[textureID] = newFramebuffer
return newFramebuffer
}
// This method should be called on the UI thread.
func (context *GraphicsContext) deleteFramebuffer(texture *Texture) {
framebuffer, ok := context.framebuffers[texture.id]
func (context *GraphicsContext) deleteFramebuffer(textureID C.GLuint) {
framebuffer, ok := context.framebuffers[textureID]
if !ok {
// TODO: panic?
return
}
C.glDeleteFramebuffers(1, &framebuffer)
delete(context.framebuffers, texture.id)
delete(context.framebuffers, textureID)
}
func (context *GraphicsContext) NewTexture(width, height int) graphics.Texture {
texture := newTexture(width, height)
id := graphics.TextureID(texture.id)
context.textures[id] = texture
return graphics.Texture{
ID: id,
Width: texture.width,
Height: texture.height,
}
}
func (context *GraphicsContext) NewTextureFromImage(img image.Image) graphics.Texture {
texture := newTextureFromImage(img)
id := graphics.TextureID(texture.id)
context.textures[id] = texture
return graphics.Texture{
ID: id,
Width: texture.width,
Height: texture.height,
}
}