From d4fd3adc536453fa7ee8d5e03be41a3912cf4d74 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Wed, 19 Jun 2013 00:48:41 +0900 Subject: [PATCH] Show Ebiten --- ebiten.go | 37 ++++++++++++ examples/glut/ebiten.png | Bin 0 -> 2149 bytes examples/glut/main.go | 106 +++++++++++++++++++++++------------ game/game.go | 10 ---- graphics/device.go | 34 ++++++++++- graphics/graphics_context.go | 5 +- graphics/texture.go | 23 ++------ ui/ui.go | 11 ++++ 8 files changed, 158 insertions(+), 68 deletions(-) create mode 100644 ebiten.go create mode 100644 examples/glut/ebiten.png delete mode 100644 game/game.go diff --git a/ebiten.go b/ebiten.go new file mode 100644 index 000000000..d16099431 --- /dev/null +++ b/ebiten.go @@ -0,0 +1,37 @@ +package ebiten + +import ( + "time" + "github.com/hajimehoshi/go-ebiten/graphics" + "github.com/hajimehoshi/go-ebiten/ui" +) + +type Game interface { + Update() + Draw(g *graphics.GraphicsContext, offscreen *graphics.Texture) +} + +func Run(game Game, u ui.UI) { + ch := make(chan bool, 1) + device := graphics.NewDevice( + u.ScreenWidth(), u.ScreenHeight(), u.ScreenScale(), + func(g *graphics.GraphicsContext, offscreen *graphics.Texture) { + ticket := <-ch + game.Draw(g, offscreen) + ch<- ticket + }) + + go func() { + const frameTime = time.Second / 60 + tick := time.Tick(frameTime) + for { + <-tick + ticket := <-ch + game.Update() + ch<- ticket + } + }() + ch<- true + + u.Run(device) +} diff --git a/examples/glut/ebiten.png b/examples/glut/ebiten.png new file mode 100644 index 0000000000000000000000000000000000000000..72f89c8b221fee3811905ee2fdbe824e94bce79a GIT binary patch literal 2149 zcmV-r2%7haP)3-|7Yx02e8$AWWZJju+@BIz*Yya)oiu_9#GzdaYCR7m=9{`U;kMC zPAO^5-`83>|MSYg_?!XLh@N1v$|KVHGy^7W&bybRHX zy*JZEMiDLJ*C)R0RY0OVP zk*=OS;L=8aCmdY0Uh#XC-qD|i<=&?tJ+SoRqmLw~U%E}gJ~UgQeex9Lu{!q1x8Er5 z+y8wwHWvVMjY?sgB&(mti5J8iDZ~`3TJvz8=$5e z?aZQifNdwxXdv@vNW%f#<+Ip$84nLXiLtrGxK&JVjd0gNN?-ip=loLjx%U(BA1{Gq z^~!f8y)u@^vwK{&G(z)C&1#0?fi0p2#13MU8EiI%(FAM}$sJ+}7#Ab5jBQU~$xxyw zZ7b^7NDAtK6~xOhp2E;RY$wNTzZu^c%-jXsv7=~M!>iYcMt8p$ z?znZrFIA7Or{k(KAWfTJiq5KO!2xi}H@chfN{4998pE}ec+jV&XqFB4|Rk-`B?HitEWm$~~8(1GTA>wbxY6B6AEWM062Pn3(57V^+ z;&-4qfl3Q4-;T5{Ae}|X6Yz@|zd%qZL0CanC((2f3PTX>L>y?+#O7C^cE@6|ch^I` zAN$O2K8*19Sa%8Jo#q{RvUGP6FYQv-@-%IrIBa$f6^l5426zR?&x5^;3wI;Q0xoqB zPh&{2eMb;=n6MWOx2+xVMI>8BjSrrODc*oBRFJ42)S*!uTn0fOYH}^f>5ArOJbH7oP_8@Z1vG}R2QTbJ{W@MW@KUK~{QgSZbB^(w z(rYb#eFKulV0-?}`;`crP2#k?R-&n*em};G&~O+RUxdanw77z5gm`r{TS5Kqwc;ln zL~R{S=aKjlDjBvgh>3@w;MY9iG4(Rdcg9ZHCjU<-99+=%fiXs&49!bVksLU+?I4E)-UYG?ee zzGJn~J6-@}GevI1x=#UTE$a0kHUz(bnlj=Xn&&viOB=@NFIbi)MN~uBsHibo{ZmHDB1Pc@vkW3)U+x2VJ9? zjRt=~RDH64?DpABi1oT~)$al;)6YLHF2@9=$7>_mGjJro&arI@*XoPV|12N<7}@Fo bwwk{Iw`MFuQA#B|00000NkvXXu0mjf)^#I} literal 0 HcmV?d00001 diff --git a/examples/glut/main.go b/examples/glut/main.go index f1a8293e6..1c321f86e 100644 --- a/examples/glut/main.go +++ b/examples/glut/main.go @@ -15,28 +15,27 @@ package main // import "C" import ( + "image" "image/color" + _ "image/png" "os" - "time" "unsafe" + "github.com/hajimehoshi/go-ebiten" "github.com/hajimehoshi/go-ebiten/graphics" ) -var device *graphics.Device - -type DemoGame struct { +type GlutUI struct{ + screenWidth int + screenHeight int + screenScale int + device *graphics.Device } -func (game *DemoGame) Update() { -} - -func (game *DemoGame) Draw(g *graphics.GraphicsContext, offscreen *graphics.Texture) { - g.Fill(&color.RGBA{R: 128, G: 128, B: 255, A: 255}) -} +var currentUI *GlutUI //export display func display() { - device.Update() + currentUI.device.Update() C.glutSwapBuffers() } @@ -45,7 +44,7 @@ func idle() { C.glutPostRedisplay() } -func main() { +func (ui *GlutUI) Init() { cargs := []*C.char{} for _, arg := range os.Args { cargs = append(cargs, C.CString(arg)) @@ -57,41 +56,76 @@ func main() { }() cargc := C.int(len(cargs)) - screenWidth := 256 - screenHeight := 240 - screenScale := 2 + ui.screenWidth = 256 + ui.screenHeight = 240 + ui.screenScale = 2 C.glutInit(&cargc, &cargs[0]) C.glutInitDisplayMode(C.GLUT_RGBA); - C.glutInitWindowSize(C.int(screenWidth * screenScale), - C.int(screenHeight * screenScale)) + C.glutInitWindowSize( + C.int(ui.screenWidth * ui.screenScale), + C.int(ui.screenHeight * ui.screenScale)) title := C.CString("Ebiten Demo") defer C.free(unsafe.Pointer(title)) C.glutCreateWindow(title) C.setGlutFuncs() +} - ch := make(chan bool, 1) - game := &DemoGame{} - device = graphics.NewDevice(screenWidth, screenHeight, screenScale, - func(g *graphics.GraphicsContext, offscreen *graphics.Texture) { - ticket := <-ch - game.Draw(g, offscreen) - ch<- ticket - }) +func (ui *GlutUI) ScreenWidth() int { + return ui.screenWidth +} - go func() { - const frameTime = time.Second / 60 - tick := time.Tick(frameTime) - for { - <-tick - ticket := <-ch - game.Update() - ch<- ticket - } - }() - ch<- true +func (ui *GlutUI) ScreenHeight() int { + return ui.screenHeight +} +func (ui *GlutUI) ScreenScale() int { + return ui.screenScale +} + +func (ui *GlutUI) Run(device *graphics.Device) { + ui.device = device C.glutMainLoop() } + +type DemoGame struct { + ebitenTexture *graphics.Texture +} + +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 = currentUI.device.NewTextureFromImage(img) + } +} + +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 + } + g.DrawTexture(game.ebitenTexture, + 0, 0, game.ebitenTexture.Width, game.ebitenTexture.Height, + graphics.IdentityGeometryMatrix(), + graphics.IdentityColorMatrix()) +} + +func main() { + game := &DemoGame{} + currentUI = &GlutUI{} + currentUI.Init() + + ebiten.Run(game, currentUI) +} diff --git a/game/game.go b/game/game.go deleted file mode 100644 index e56fd2a4b..000000000 --- a/game/game.go +++ /dev/null @@ -1,10 +0,0 @@ -package game - -import ( - _ "../graphics" -) - -type Game interface { - Update() - Draw() -} diff --git a/graphics/device.go b/graphics/device.go index 47f9e38ab..5398c28aa 100644 --- a/graphics/device.go +++ b/graphics/device.go @@ -5,6 +5,9 @@ package graphics // #include // #include import "C" +import ( + "image" +) type Device struct { screenWidth int @@ -13,6 +16,7 @@ type Device struct { graphicsContext *GraphicsContext offscreenTexture *Texture drawFunc func(*GraphicsContext, *Texture) + funcs []func() } func NewDevice(screenWidth, screenHeight, screenScale int, @@ -22,13 +26,19 @@ func NewDevice(screenWidth, screenHeight, screenScale int, screenHeight: screenHeight, screenScale: screenScale, graphicsContext: newGraphicsContext(screenWidth, screenHeight, screenScale), - offscreenTexture: NewTexture(screenWidth, screenHeight), drawFunc: drawFunc, + funcs: []func(){}, } + device.offscreenTexture = device.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) @@ -50,3 +60,25 @@ func (device *Device) Update() { geometryMatrix, IdentityColorMatrix()) g.flush() } + +func (device *Device) NewTexture(width, height int) *Texture { + return createTexture(device, width, height, nil) +} + +func (device *Device) 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(device, size.X, size.Y, pix) +} + +func (device *Device) executeWhenDrawing(f func()) { + device.funcs = append(device.funcs, f) +} diff --git a/graphics/graphics_context.go b/graphics/graphics_context.go index 6c994557b..b6baaef3b 100644 --- a/graphics/graphics_context.go +++ b/graphics/graphics_context.go @@ -6,6 +6,7 @@ package graphics // #include import "C" import ( + "fmt" "image/color" "math" "unsafe" @@ -117,8 +118,8 @@ func (context *GraphicsContext) SetOffscreen(texture *Texture) { framebuffer = context.mainFramebuffer } C.glBindFramebuffer(C.GL_FRAMEBUFFER, framebuffer) - if C.glCheckFramebufferStatus(C.GL_FRAMEBUFFER) != C.GL_FRAMEBUFFER_COMPLETE { - panic("glBindFramebuffer failed") + if err := C.glCheckFramebufferStatus(C.GL_FRAMEBUFFER); err != C.GL_FRAMEBUFFER_COMPLETE { + panic(fmt.Sprintf("glBindFramebuffer failed: %d", err)) } C.glEnable(C.GL_BLEND) C.glBlendFunc(C.GL_SRC_ALPHA, C.GL_ONE_MINUS_SRC_ALPHA) diff --git a/graphics/texture.go b/graphics/texture.go index 996e63cd4..9601ca183 100644 --- a/graphics/texture.go +++ b/graphics/texture.go @@ -5,9 +5,7 @@ package graphics // #include import "C" import ( - "image" "unsafe" - "github.com/hajimehoshi/go-ebiten/ui" ) func Clp2(x uint64) uint64 { @@ -29,7 +27,7 @@ type Texture struct { TextureHeight int } -func createTexture(width, height int, pixels []uint8) *Texture{ +func createTexture(device *Device, width, height int, pixels []uint8) *Texture{ textureWidth := int(Clp2(uint64(width))) textureHeight := int(Clp2(uint64(height))) if pixels != nil { @@ -48,12 +46,7 @@ func createTexture(width, height int, pixels []uint8) *Texture{ TextureHeight: textureHeight, } - ch := make(chan C.GLuint) - // TODO: should wait? - go func() { - texture.id = <-ch - }() - ui.ExecuteOnUIThread(func() { + device.executeWhenDrawing(func() { textureID := C.GLuint(0) C.glGenTextures(1, (*C.GLuint)(&textureID)) if textureID == 0 { @@ -74,21 +67,13 @@ func createTexture(width, height int, pixels []uint8) *Texture{ C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MIN_FILTER, C.GL_LINEAR) C.glBindTexture(C.GL_TEXTURE_2D, 0) - ch<- textureID - close(ch) + // TODO: lock? + texture.id = textureID }) return texture } -func NewTexture(width, height int) *Texture { - return createTexture(width, height, nil) -} - -func NewTextureFromRGBA(image *image.RGBA) *Texture { - return createTexture(image.Rect.Size().X, image.Rect.Size().Y, image.Pix) -} - func (texture *Texture) IsAvailable() bool { return texture.id != 0 } diff --git a/ui/ui.go b/ui/ui.go index c4c63def3..c3447577b 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -1,5 +1,16 @@ package ui +import ( + "github.com/hajimehoshi/go-ebiten/graphics" +) + +type UI interface { + ScreenWidth() int + ScreenHeight() int + ScreenScale() int + Run(device *graphics.Device) +} + func ExecuteOnUIThread(f func()) { // TODO: implement! f()