mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 18:58:54 +01:00
Show Ebiten
This commit is contained in:
parent
ab558db683
commit
d4fd3adc53
37
ebiten.go
Normal file
37
ebiten.go
Normal file
@ -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)
|
||||
}
|
BIN
examples/glut/ebiten.png
Normal file
BIN
examples/glut/ebiten.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
@ -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
|
||||
})
|
||||
|
||||
go func() {
|
||||
const frameTime = time.Second / 60
|
||||
tick := time.Tick(frameTime)
|
||||
for {
|
||||
<-tick
|
||||
ticket := <-ch
|
||||
game.Update()
|
||||
ch<- ticket
|
||||
}
|
||||
}()
|
||||
ch<- true
|
||||
|
||||
func (ui *GlutUI) ScreenWidth() int {
|
||||
return ui.screenWidth
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
10
game/game.go
10
game/game.go
@ -1,10 +0,0 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
_ "../graphics"
|
||||
)
|
||||
|
||||
type Game interface {
|
||||
Update()
|
||||
Draw()
|
||||
}
|
@ -5,6 +5,9 @@ package graphics
|
||||
// #include <OpenGL/gl.h>
|
||||
// #include <stdlib.h>
|
||||
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)
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ package graphics
|
||||
// #include <OpenGL/gl.h>
|
||||
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)
|
||||
|
@ -5,9 +5,7 @@ package graphics
|
||||
// #include <OpenGL/gl.h>
|
||||
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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user