mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
Add TextureFactory
This commit is contained in:
parent
eda572d03e
commit
847b6b80f6
@ -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)
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user