mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 10:48:53 +01:00
Add TextureFactory
This commit is contained in:
parent
eda572d03e
commit
847b6b80f6
@ -7,8 +7,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Game interface {
|
type Game interface {
|
||||||
|
Init(tf graphics.TextureFactory)
|
||||||
Update()
|
Update()
|
||||||
Draw(g graphics.GraphicsContext, offscreen *graphics.Texture)
|
Draw(g graphics.GraphicsContext, offscreen graphics.TextureID)
|
||||||
}
|
}
|
||||||
|
|
||||||
type UI interface {
|
type UI interface {
|
||||||
@ -22,7 +23,7 @@ func OpenGLRun(game Game, ui UI) {
|
|||||||
ch := make(chan bool, 1)
|
ch := make(chan bool, 1)
|
||||||
device := opengl.NewDevice(
|
device := opengl.NewDevice(
|
||||||
ui.ScreenWidth(), ui.ScreenHeight(), ui.ScreenScale(),
|
ui.ScreenWidth(), ui.ScreenHeight(), ui.ScreenScale(),
|
||||||
func(g graphics.GraphicsContext, offscreen *graphics.Texture) {
|
func(g graphics.GraphicsContext, offscreen graphics.TextureID) {
|
||||||
ticket := <-ch
|
ticket := <-ch
|
||||||
game.Draw(g, offscreen)
|
game.Draw(g, offscreen)
|
||||||
ch<- ticket
|
ch<- ticket
|
||||||
@ -38,7 +39,8 @@ func OpenGLRun(game Game, ui UI) {
|
|||||||
ch<- ticket
|
ch<- ticket
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
ch<- true
|
|
||||||
|
|
||||||
|
game.Init(device.TextureFactory())
|
||||||
|
ch<- true
|
||||||
ui.Run(device)
|
ui.Run(device)
|
||||||
}
|
}
|
||||||
|
@ -91,37 +91,34 @@ func (ui *GlutUI) Run(device graphics.Device) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DemoGame struct {
|
type DemoGame struct {
|
||||||
ebitenTexture *graphics.Texture
|
ebitenTexture graphics.Texture
|
||||||
x int
|
x int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (game *DemoGame) Update() {
|
func (game *DemoGame) Init(tf graphics.TextureFactory) {
|
||||||
if game.ebitenTexture == nil {
|
file, err := os.Open("ebiten.png")
|
||||||
file, err := os.Open("ebiten.png")
|
if err != nil {
|
||||||
if err != nil {
|
panic(err)
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
img, _, err := image.Decode(file)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
game.ebitenTexture = graphics.NewTextureFromImage(img)
|
|
||||||
}
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
img, _, err := image.Decode(file)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
game.ebitenTexture = tf.NewTextureFromImage(img)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (game *DemoGame) Update() {
|
||||||
game.x++
|
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})
|
g.Fill(&color.RGBA{R: 128, G: 128, B: 255, A: 255})
|
||||||
if game.ebitenTexture == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
geometryMatrix := graphics.IdentityGeometryMatrix()
|
geometryMatrix := graphics.IdentityGeometryMatrix()
|
||||||
geometryMatrix.SetTx(float64(game.x))
|
geometryMatrix.SetTx(float64(game.x))
|
||||||
geometryMatrix.SetTy(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,
|
0, 0, game.ebitenTexture.Width, game.ebitenTexture.Height,
|
||||||
geometryMatrix,
|
geometryMatrix,
|
||||||
graphics.IdentityColorMatrix())
|
graphics.IdentityColorMatrix())
|
||||||
|
@ -7,28 +7,27 @@ import (
|
|||||||
|
|
||||||
type Device interface {
|
type Device interface {
|
||||||
Update()
|
Update()
|
||||||
|
TextureFactory() TextureFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
type GraphicsContext interface {
|
type GraphicsContext interface {
|
||||||
Clear()
|
Clear()
|
||||||
Fill(color color.Color)
|
Fill(color color.Color)
|
||||||
DrawTexture(texture *Texture,
|
DrawTexture(textureId TextureID,
|
||||||
srcX, srcY, srcWidth, srcHeight int,
|
srcX, srcY, srcWidth, srcHeight int,
|
||||||
geometryMatrix *GeometryMatrix, colorMatrix *ColorMatrix)
|
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 {
|
type Texture struct {
|
||||||
|
ID TextureID
|
||||||
Width int
|
Width int
|
||||||
Height int
|
Height int
|
||||||
Image image.Image
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTexture(width, height int) *Texture {
|
type TextureID int
|
||||||
return &Texture{width, height, nil}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTextureFromImage(img image.Image) *Texture {
|
|
||||||
size := img.Bounds().Size()
|
|
||||||
return &Texture{size.X, size.Y, img}
|
|
||||||
}
|
|
||||||
|
@ -14,22 +14,21 @@ type Device struct {
|
|||||||
screenHeight int
|
screenHeight int
|
||||||
screenScale int
|
screenScale int
|
||||||
graphicsContext *GraphicsContext
|
graphicsContext *GraphicsContext
|
||||||
offscreenTexture *graphics.Texture
|
offscreenTexture graphics.Texture
|
||||||
drawFunc func(graphics.GraphicsContext, *graphics.Texture)
|
drawFunc func(graphics.GraphicsContext, graphics.TextureID)
|
||||||
funcs []func()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDevice(screenWidth, screenHeight, screenScale int,
|
func NewDevice(screenWidth, screenHeight, screenScale int,
|
||||||
drawFunc func(graphics.GraphicsContext, *graphics.Texture)) *Device {
|
drawFunc func(graphics.GraphicsContext, graphics.TextureID)) *Device {
|
||||||
device := &Device{
|
device := &Device{
|
||||||
screenWidth: screenWidth,
|
screenWidth: screenWidth,
|
||||||
screenHeight: screenHeight,
|
screenHeight: screenHeight,
|
||||||
screenScale: screenScale,
|
screenScale: screenScale,
|
||||||
graphicsContext: newGraphicsContext(screenWidth, screenHeight, screenScale),
|
graphicsContext: newGraphicsContext(screenWidth, screenHeight, screenScale),
|
||||||
drawFunc: drawFunc,
|
drawFunc: drawFunc,
|
||||||
funcs: []func(){},
|
|
||||||
}
|
}
|
||||||
device.offscreenTexture = graphics.NewTexture(screenWidth, screenHeight)
|
device.offscreenTexture =
|
||||||
|
device.graphicsContext.NewTexture(screenWidth, screenHeight)
|
||||||
return device
|
return device
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,9 +37,9 @@ func (device *Device) Update() {
|
|||||||
C.glEnable(C.GL_TEXTURE_2D)
|
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_MIN_FILTER, C.GL_NEAREST)
|
||||||
C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MAG_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()
|
g.Clear()
|
||||||
device.drawFunc(g, device.offscreenTexture)
|
device.drawFunc(g, device.offscreenTexture.ID)
|
||||||
g.flush()
|
g.flush()
|
||||||
|
|
||||||
C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MIN_FILTER, C.GL_LINEAR)
|
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 := graphics.IdentityGeometryMatrix()
|
||||||
geometryMatrix.SetA(float64(g.screenScale))
|
geometryMatrix.SetA(float64(g.screenScale))
|
||||||
geometryMatrix.SetD(float64(g.screenScale))
|
geometryMatrix.SetD(float64(g.screenScale))
|
||||||
g.DrawTexture(device.offscreenTexture,
|
g.DrawTexture(device.offscreenTexture.ID,
|
||||||
0, 0, device.screenWidth, device.screenHeight,
|
0, 0, device.screenWidth, device.screenHeight,
|
||||||
geometryMatrix, graphics.IdentityColorMatrix())
|
geometryMatrix, graphics.IdentityColorMatrix())
|
||||||
g.flush()
|
g.flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (device *Device) TextureFactory() graphics.TextureFactory {
|
||||||
|
return device.graphicsContext
|
||||||
|
}
|
||||||
|
@ -7,6 +7,7 @@ package opengl
|
|||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
"github.com/hajimehoshi/go-ebiten/graphics"
|
"github.com/hajimehoshi/go-ebiten/graphics"
|
||||||
@ -16,9 +17,10 @@ type GraphicsContext struct {
|
|||||||
screenWidth int
|
screenWidth int
|
||||||
screenHeight int
|
screenHeight int
|
||||||
screenScale int
|
screenScale int
|
||||||
mainFramebuffer C.GLuint
|
textures map[graphics.TextureID]*Texture
|
||||||
projectionMatrix [16]float32
|
projectionMatrix [16]float32
|
||||||
currentShaderProgram C.GLuint
|
currentShaderProgram C.GLuint
|
||||||
|
mainFramebuffer C.GLuint
|
||||||
framebuffers map[C.GLuint]C.GLuint
|
framebuffers map[C.GLuint]C.GLuint
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,6 +30,7 @@ func newGraphicsContext(screenWidth, screenHeight, screenScale int) *GraphicsCon
|
|||||||
screenWidth: screenWidth,
|
screenWidth: screenWidth,
|
||||||
screenHeight: screenHeight,
|
screenHeight: screenHeight,
|
||||||
screenScale: screenScale,
|
screenScale: screenScale,
|
||||||
|
textures: map[graphics.TextureID]*Texture{},
|
||||||
mainFramebuffer: 0,
|
mainFramebuffer: 0,
|
||||||
framebuffers: map[C.GLuint]C.GLuint{},
|
framebuffers: map[C.GLuint]C.GLuint{},
|
||||||
}
|
}
|
||||||
@ -41,23 +44,6 @@ func newGraphicsContext(screenWidth, screenHeight, screenScale int) *GraphicsCon
|
|||||||
return context
|
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() {
|
func (context *GraphicsContext) Clear() {
|
||||||
C.glClearColor(0, 0, 0, 1)
|
C.glClearColor(0, 0, 0, 1)
|
||||||
C.glClear(C.GL_COLOR_BUFFER_BIT)
|
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!
|
// TODO: implement!
|
||||||
}
|
}
|
||||||
|
|
||||||
func (context *GraphicsContext) DrawTexture(tex *graphics.Texture,
|
func (context *GraphicsContext) DrawTexture(
|
||||||
|
textureID graphics.TextureID,
|
||||||
srcX, srcY, srcWidth, srcHeight int,
|
srcX, srcY, srcWidth, srcHeight int,
|
||||||
geometryMatrix *graphics.GeometryMatrix, colorMatrix *graphics.ColorMatrix) {
|
geometryMatrix *graphics.GeometryMatrix, colorMatrix *graphics.ColorMatrix) {
|
||||||
geometryMatrix = geometryMatrix.Clone()
|
geometryMatrix = geometryMatrix.Clone()
|
||||||
colorMatrix = colorMatrix.Clone()
|
colorMatrix = colorMatrix.Clone()
|
||||||
|
|
||||||
texture := glTexture(tex)
|
texture := context.textures[textureID]
|
||||||
|
|
||||||
context.setShaderProgram(geometryMatrix, colorMatrix)
|
context.setShaderProgram(geometryMatrix, colorMatrix)
|
||||||
C.glBindTexture(C.GL_TEXTURE_2D, texture.id)
|
C.glBindTexture(C.GL_TEXTURE_2D, texture.id)
|
||||||
@ -136,24 +123,23 @@ func abs(x int) int {
|
|||||||
return x
|
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()
|
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)
|
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))
|
panic(fmt.Sprintf("glBindFramebuffer failed: %d", err))
|
||||||
}
|
}
|
||||||
C.glEnable(C.GL_BLEND)
|
C.glEnable(C.GL_BLEND)
|
||||||
@ -161,8 +147,8 @@ func (context *GraphicsContext) SetOffscreen(tex *graphics.Texture) {
|
|||||||
|
|
||||||
width, height, tx, ty := 0, 0, 0, 0
|
width, height, tx, ty := 0, 0, 0, 0
|
||||||
if framebuffer != context.mainFramebuffer {
|
if framebuffer != context.mainFramebuffer {
|
||||||
width = texture.textureWidth
|
width = textureWidth
|
||||||
height = texture.textureHeight
|
height = textureHeight
|
||||||
tx = -1
|
tx = -1
|
||||||
ty = -1
|
ty = -1
|
||||||
} else {
|
} else {
|
||||||
@ -185,7 +171,7 @@ func (context *GraphicsContext) SetOffscreen(tex *graphics.Texture) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (context *GraphicsContext) resetOffscreen() {
|
func (context *GraphicsContext) resetOffscreen() {
|
||||||
context.SetOffscreen(nil)
|
context.setOffscreenFramebuffer(context.mainFramebuffer, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method should be called on the UI thread.
|
// This method should be called on the UI thread.
|
||||||
@ -255,9 +241,8 @@ func (context *GraphicsContext) setShaderProgram(
|
|||||||
1, (*C.GLfloat)(&glColorMatrixTranslation[0]))
|
1, (*C.GLfloat)(&glColorMatrixTranslation[0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method should be called on the UI thread.
|
func (context *GraphicsContext) getFramebuffer(textureID C.GLuint) C.GLuint{
|
||||||
func (context *GraphicsContext) getFramebuffer(texture *Texture) C.GLuint{
|
framebuffer, ok := context.framebuffers[textureID]
|
||||||
framebuffer, ok := context.framebuffers[texture.id]
|
|
||||||
if ok {
|
if ok {
|
||||||
return framebuffer
|
return framebuffer
|
||||||
}
|
}
|
||||||
@ -269,23 +254,44 @@ func (context *GraphicsContext) getFramebuffer(texture *Texture) C.GLuint{
|
|||||||
C.glGetIntegerv(C.GL_FRAMEBUFFER_BINDING, &origFramebuffer)
|
C.glGetIntegerv(C.GL_FRAMEBUFFER_BINDING, &origFramebuffer)
|
||||||
C.glBindFramebuffer(C.GL_FRAMEBUFFER, newFramebuffer)
|
C.glBindFramebuffer(C.GL_FRAMEBUFFER, newFramebuffer)
|
||||||
C.glFramebufferTexture2D(C.GL_FRAMEBUFFER, C.GL_COLOR_ATTACHMENT0,
|
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))
|
C.glBindFramebuffer(C.GL_FRAMEBUFFER, C.GLuint(origFramebuffer))
|
||||||
if C.glCheckFramebufferStatus(C.GL_FRAMEBUFFER) != C.GL_FRAMEBUFFER_COMPLETE {
|
if C.glCheckFramebufferStatus(C.GL_FRAMEBUFFER) != C.GL_FRAMEBUFFER_COMPLETE {
|
||||||
panic("creating framebuffer failed")
|
panic("creating framebuffer failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
context.framebuffers[texture.id] = newFramebuffer
|
context.framebuffers[textureID] = newFramebuffer
|
||||||
return newFramebuffer
|
return newFramebuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method should be called on the UI thread.
|
func (context *GraphicsContext) deleteFramebuffer(textureID C.GLuint) {
|
||||||
func (context *GraphicsContext) deleteFramebuffer(texture *Texture) {
|
framebuffer, ok := context.framebuffers[textureID]
|
||||||
framebuffer, ok := context.framebuffers[texture.id]
|
|
||||||
if !ok {
|
if !ok {
|
||||||
// TODO: panic?
|
// TODO: panic?
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
C.glDeleteFramebuffers(1, &framebuffer)
|
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