mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08: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 "C"
|
||||||
import (
|
import (
|
||||||
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
_ "image/png"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
"github.com/hajimehoshi/go-ebiten"
|
||||||
"github.com/hajimehoshi/go-ebiten/graphics"
|
"github.com/hajimehoshi/go-ebiten/graphics"
|
||||||
)
|
)
|
||||||
|
|
||||||
var device *graphics.Device
|
type GlutUI struct{
|
||||||
|
screenWidth int
|
||||||
type DemoGame struct {
|
screenHeight int
|
||||||
|
screenScale int
|
||||||
|
device *graphics.Device
|
||||||
}
|
}
|
||||||
|
|
||||||
func (game *DemoGame) Update() {
|
var currentUI *GlutUI
|
||||||
}
|
|
||||||
|
|
||||||
func (game *DemoGame) Draw(g *graphics.GraphicsContext, offscreen *graphics.Texture) {
|
|
||||||
g.Fill(&color.RGBA{R: 128, G: 128, B: 255, A: 255})
|
|
||||||
}
|
|
||||||
|
|
||||||
//export display
|
//export display
|
||||||
func display() {
|
func display() {
|
||||||
device.Update()
|
currentUI.device.Update()
|
||||||
C.glutSwapBuffers()
|
C.glutSwapBuffers()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +44,7 @@ func idle() {
|
|||||||
C.glutPostRedisplay()
|
C.glutPostRedisplay()
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func (ui *GlutUI) Init() {
|
||||||
cargs := []*C.char{}
|
cargs := []*C.char{}
|
||||||
for _, arg := range os.Args {
|
for _, arg := range os.Args {
|
||||||
cargs = append(cargs, C.CString(arg))
|
cargs = append(cargs, C.CString(arg))
|
||||||
@ -57,41 +56,76 @@ func main() {
|
|||||||
}()
|
}()
|
||||||
cargc := C.int(len(cargs))
|
cargc := C.int(len(cargs))
|
||||||
|
|
||||||
screenWidth := 256
|
ui.screenWidth = 256
|
||||||
screenHeight := 240
|
ui.screenHeight = 240
|
||||||
screenScale := 2
|
ui.screenScale = 2
|
||||||
|
|
||||||
C.glutInit(&cargc, &cargs[0])
|
C.glutInit(&cargc, &cargs[0])
|
||||||
C.glutInitDisplayMode(C.GLUT_RGBA);
|
C.glutInitDisplayMode(C.GLUT_RGBA);
|
||||||
C.glutInitWindowSize(C.int(screenWidth * screenScale),
|
C.glutInitWindowSize(
|
||||||
C.int(screenHeight * screenScale))
|
C.int(ui.screenWidth * ui.screenScale),
|
||||||
|
C.int(ui.screenHeight * ui.screenScale))
|
||||||
|
|
||||||
title := C.CString("Ebiten Demo")
|
title := C.CString("Ebiten Demo")
|
||||||
defer C.free(unsafe.Pointer(title))
|
defer C.free(unsafe.Pointer(title))
|
||||||
C.glutCreateWindow(title)
|
C.glutCreateWindow(title)
|
||||||
|
|
||||||
C.setGlutFuncs()
|
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()
|
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 <OpenGL/gl.h>
|
||||||
// #include <stdlib.h>
|
// #include <stdlib.h>
|
||||||
import "C"
|
import "C"
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
)
|
||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
screenWidth int
|
screenWidth int
|
||||||
@ -13,6 +16,7 @@ type Device struct {
|
|||||||
graphicsContext *GraphicsContext
|
graphicsContext *GraphicsContext
|
||||||
offscreenTexture *Texture
|
offscreenTexture *Texture
|
||||||
drawFunc func(*GraphicsContext, *Texture)
|
drawFunc func(*GraphicsContext, *Texture)
|
||||||
|
funcs []func()
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDevice(screenWidth, screenHeight, screenScale int,
|
func NewDevice(screenWidth, screenHeight, screenScale int,
|
||||||
@ -22,13 +26,19 @@ func NewDevice(screenWidth, screenHeight, screenScale int,
|
|||||||
screenHeight: screenHeight,
|
screenHeight: screenHeight,
|
||||||
screenScale: screenScale,
|
screenScale: screenScale,
|
||||||
graphicsContext: newGraphicsContext(screenWidth, screenHeight, screenScale),
|
graphicsContext: newGraphicsContext(screenWidth, screenHeight, screenScale),
|
||||||
offscreenTexture: NewTexture(screenWidth, screenHeight),
|
|
||||||
drawFunc: drawFunc,
|
drawFunc: drawFunc,
|
||||||
|
funcs: []func(){},
|
||||||
}
|
}
|
||||||
|
device.offscreenTexture = device.NewTexture(screenWidth, screenHeight)
|
||||||
return device
|
return device
|
||||||
}
|
}
|
||||||
|
|
||||||
func (device *Device) Update() {
|
func (device *Device) Update() {
|
||||||
|
for _, f := range device.funcs {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
device.funcs = []func(){}
|
||||||
|
|
||||||
g := device.graphicsContext
|
g := device.graphicsContext
|
||||||
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)
|
||||||
@ -50,3 +60,25 @@ func (device *Device) Update() {
|
|||||||
geometryMatrix, IdentityColorMatrix())
|
geometryMatrix, IdentityColorMatrix())
|
||||||
g.flush()
|
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>
|
// #include <OpenGL/gl.h>
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"image/color"
|
"image/color"
|
||||||
"math"
|
"math"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
@ -117,8 +118,8 @@ func (context *GraphicsContext) SetOffscreen(texture *Texture) {
|
|||||||
framebuffer = context.mainFramebuffer
|
framebuffer = context.mainFramebuffer
|
||||||
}
|
}
|
||||||
C.glBindFramebuffer(C.GL_FRAMEBUFFER, framebuffer)
|
C.glBindFramebuffer(C.GL_FRAMEBUFFER, framebuffer)
|
||||||
if C.glCheckFramebufferStatus(C.GL_FRAMEBUFFER) != C.GL_FRAMEBUFFER_COMPLETE {
|
if err := C.glCheckFramebufferStatus(C.GL_FRAMEBUFFER); err != C.GL_FRAMEBUFFER_COMPLETE {
|
||||||
panic("glBindFramebuffer failed")
|
panic(fmt.Sprintf("glBindFramebuffer failed: %d", err))
|
||||||
}
|
}
|
||||||
C.glEnable(C.GL_BLEND)
|
C.glEnable(C.GL_BLEND)
|
||||||
C.glBlendFunc(C.GL_SRC_ALPHA, C.GL_ONE_MINUS_SRC_ALPHA)
|
C.glBlendFunc(C.GL_SRC_ALPHA, C.GL_ONE_MINUS_SRC_ALPHA)
|
||||||
|
@ -5,9 +5,7 @@ package graphics
|
|||||||
// #include <OpenGL/gl.h>
|
// #include <OpenGL/gl.h>
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
"image"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
"github.com/hajimehoshi/go-ebiten/ui"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Clp2(x uint64) uint64 {
|
func Clp2(x uint64) uint64 {
|
||||||
@ -29,7 +27,7 @@ type Texture struct {
|
|||||||
TextureHeight int
|
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)))
|
textureWidth := int(Clp2(uint64(width)))
|
||||||
textureHeight := int(Clp2(uint64(height)))
|
textureHeight := int(Clp2(uint64(height)))
|
||||||
if pixels != nil {
|
if pixels != nil {
|
||||||
@ -48,12 +46,7 @@ func createTexture(width, height int, pixels []uint8) *Texture{
|
|||||||
TextureHeight: textureHeight,
|
TextureHeight: textureHeight,
|
||||||
}
|
}
|
||||||
|
|
||||||
ch := make(chan C.GLuint)
|
device.executeWhenDrawing(func() {
|
||||||
// TODO: should wait?
|
|
||||||
go func() {
|
|
||||||
texture.id = <-ch
|
|
||||||
}()
|
|
||||||
ui.ExecuteOnUIThread(func() {
|
|
||||||
textureID := C.GLuint(0)
|
textureID := C.GLuint(0)
|
||||||
C.glGenTextures(1, (*C.GLuint)(&textureID))
|
C.glGenTextures(1, (*C.GLuint)(&textureID))
|
||||||
if textureID == 0 {
|
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.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MIN_FILTER, C.GL_LINEAR)
|
||||||
C.glBindTexture(C.GL_TEXTURE_2D, 0)
|
C.glBindTexture(C.GL_TEXTURE_2D, 0)
|
||||||
|
|
||||||
ch<- textureID
|
// TODO: lock?
|
||||||
close(ch)
|
texture.id = textureID
|
||||||
})
|
})
|
||||||
|
|
||||||
return texture
|
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 {
|
func (texture *Texture) IsAvailable() bool {
|
||||||
return texture.id != 0
|
return texture.id != 0
|
||||||
}
|
}
|
||||||
|
11
ui/ui.go
11
ui/ui.go
@ -1,5 +1,16 @@
|
|||||||
package ui
|
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()) {
|
func ExecuteOnUIThread(f func()) {
|
||||||
// TODO: implement!
|
// TODO: implement!
|
||||||
f()
|
f()
|
||||||
|
Loading…
Reference in New Issue
Block a user