Add AsyncGraphicsContext; Use goroutines in the main routine

This commit is contained in:
Hajime Hoshi 2013-06-26 00:56:01 +09:00
parent 6e584eb642
commit 6b1e76b669
4 changed files with 101 additions and 22 deletions

View File

@ -30,29 +30,35 @@ type InputState struct {
Y int Y int
} }
func OpenGLRun(game Game, ui UI, screenScale int, input chan InputState) { func OpenGLRun(game Game, ui UI, screenScale int, input <-chan InputState) {
ch := make(chan bool, 1) deviceUpdate := make(chan bool)
commandSet := make(chan chan func(graphics.GraphicsContext))
graphicsDevice := opengl.NewDevice( graphicsDevice := opengl.NewDevice(
game.ScreenWidth(), game.ScreenHeight(), screenScale, game.ScreenWidth(), game.ScreenHeight(), screenScale, deviceUpdate, commandSet)
func(g graphics.GraphicsContext, offscreen graphics.Texture) {
ticket := <-ch game.Init(graphicsDevice.TextureFactory())
game.Draw(g, offscreen)
ch <- ticket
})
go func() { go func() {
frameTime := time.Duration(int64(time.Second) / int64(game.Fps())) frameTime := time.Duration(int64(time.Second) / int64(game.Fps()))
tick := time.Tick(frameTime) updateTick := time.Tick(frameTime)
for { for {
<-tick select {
ticket := <-ch case <-updateTick:
inputState := <-input inputState := <-input
game.Update(inputState) game.Update(inputState)
ch <- ticket case <-deviceUpdate:
commands := make(chan func(graphics.GraphicsContext))
commandSet <- commands
g := graphics.NewAsyncGraphicsContext(commands)
// TODO: graphicsDevice is shared by multiple goroutines.
game.Draw(g, graphicsDevice.OffscreenTexture())
close(commands)
}
} }
}() }()
game.Init(graphicsDevice.TextureFactory())
ch <- true // UI should be executed on the main thread.
ui.Run(graphicsDevice) ui.Run(graphicsDevice)
} }

View File

@ -0,0 +1,57 @@
package graphics
import (
"github.com/hajimehoshi/go.ebiten/graphics/matrix"
"image/color"
)
type AsyncGraphicsContext struct {
ch chan<- func(GraphicsContext)
}
func NewAsyncGraphicsContext(ch chan<- func(GraphicsContext)) *AsyncGraphicsContext {
return &AsyncGraphicsContext{
ch: ch,
}
}
func (g *AsyncGraphicsContext) Clear() {
g.ch <- func(g2 GraphicsContext) {
g2.Clear()
}
}
func (g *AsyncGraphicsContext) Fill(clr color.Color) {
g.ch <- func(g2 GraphicsContext) {
g2.Fill(clr)
}
}
func (g *AsyncGraphicsContext) DrawRect(rect Rect, clr color.Color) {
g.ch <- func(g2 GraphicsContext) {
g2.DrawRect(rect, clr)
}
}
func (g *AsyncGraphicsContext) DrawTexture(textureID TextureID,
geometryMatrix matrix.Geometry,
colorMatrix matrix.Color) {
g.ch <- func(g2 GraphicsContext) {
g2.DrawTexture(textureID, geometryMatrix, colorMatrix)
}
}
func (g *AsyncGraphicsContext) DrawTextureParts(textureID TextureID,
locations []TexturePart,
geometryMatrix matrix.Geometry,
colorMatrix matrix.Color) {
g.ch <- func(g2 GraphicsContext) {
g2.DrawTextureParts(textureID, locations, geometryMatrix, colorMatrix)
}
}
func (g *AsyncGraphicsContext) SetOffscreen(textureID TextureID) {
g.ch <- func(g2 GraphicsContext) {
g2.SetOffscreen(textureID)
}
}

View File

@ -9,6 +9,7 @@ import (
type Device interface { type Device interface {
Update() Update()
TextureFactory() TextureFactory TextureFactory() TextureFactory
OffscreenTexture() Texture
} }
type Rect struct { type Rect struct {
@ -26,7 +27,7 @@ type TexturePart struct {
type GraphicsContext interface { type GraphicsContext interface {
Clear() Clear()
Fill(color color.Color) Fill(clr color.Color)
DrawRect(rect Rect, clr color.Color) DrawRect(rect Rect, clr color.Color)
DrawTexture(textureID TextureID, DrawTexture(textureID TextureID,
geometryMatrix matrix.Geometry, geometryMatrix matrix.Geometry,

View File

@ -16,23 +16,32 @@ type Device struct {
screenScale int screenScale int
graphicsContext *GraphicsContext graphicsContext *GraphicsContext
offscreenTexture graphics.Texture offscreenTexture graphics.Texture
drawFunc func(graphics.GraphicsContext, graphics.Texture) deviceUpdate chan<- bool
commandSet <-chan chan func(graphics.GraphicsContext)
} }
func NewDevice(screenWidth, screenHeight, screenScale int, func NewDevice(screenWidth, screenHeight, screenScale int,
drawFunc func(graphics.GraphicsContext, graphics.Texture)) *Device { deviceUpdate chan<- bool,
commandSet <-chan chan func(graphics.GraphicsContext)) *Device {
graphicsContext := newGraphicsContext(screenWidth, screenHeight, screenScale)
device := &Device{ device := &Device{
screenWidth: screenWidth, screenWidth: screenWidth,
screenHeight: screenHeight, screenHeight: screenHeight,
screenScale: screenScale, screenScale: screenScale,
graphicsContext: newGraphicsContext(screenWidth, screenHeight, screenScale), deviceUpdate: deviceUpdate,
drawFunc: drawFunc, commandSet: commandSet,
graphicsContext: graphicsContext,
} }
device.offscreenTexture = device.offscreenTexture =
device.graphicsContext.NewTexture(screenWidth, screenHeight) device.graphicsContext.NewTexture(screenWidth, screenHeight)
return device return device
} }
func (device *Device) OffscreenTexture() graphics.Texture {
return device.offscreenTexture
}
func (device *Device) Update() { func (device *Device) Update() {
g := device.graphicsContext g := device.graphicsContext
C.glEnable(C.GL_TEXTURE_2D) C.glEnable(C.GL_TEXTURE_2D)
@ -40,7 +49,13 @@ func (device *Device) Update() {
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.ID) g.SetOffscreen(device.offscreenTexture.ID)
g.Clear() g.Clear()
device.drawFunc(g, device.offscreenTexture)
device.deviceUpdate <- true
commands := <-device.commandSet
for command := range commands {
command(g)
}
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)