mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 02:38:53 +01:00
Add internal/ui module
This commit is contained in:
parent
5f4aa33edf
commit
96f5315c49
@ -15,30 +15,60 @@
|
||||
package ebiten
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/internal/opengl"
|
||||
"github.com/hajimehoshi/ebiten/internal/ui"
|
||||
"image"
|
||||
)
|
||||
|
||||
// IsKeyPressed returns a boolean indicating whether key is pressed.
|
||||
func IsKeyPressed(key Key) bool {
|
||||
return currentUI.input.isKeyPressed(key)
|
||||
return ui.Current().Input().IsKeyPressed(ui.Key(key))
|
||||
}
|
||||
|
||||
// CursorPosition returns a position of a mouse cursor.
|
||||
func CursorPosition() (x, y int) {
|
||||
return currentUI.input.cursorPosition()
|
||||
return ui.Current().Input().CursorPosition()
|
||||
}
|
||||
|
||||
// IsMouseButtonPressed returns a boolean indicating whether mouseButton is pressed.
|
||||
func IsMouseButtonPressed(mouseButton MouseButton) bool {
|
||||
return currentUI.input.isMouseButtonPressed(mouseButton)
|
||||
return ui.Current().Input().IsMouseButtonPressed(ui.MouseButton(mouseButton))
|
||||
}
|
||||
|
||||
// NewImage returns an empty image.
|
||||
func NewImage(width, height int, filter Filter) (*Image, error) {
|
||||
return currentUI.newImage(width, height, filter)
|
||||
var innerImage *innerImage
|
||||
var err error
|
||||
ui.Current().Use(func(c *opengl.Context) {
|
||||
var texture *graphics.Texture
|
||||
texture, err = graphics.NewTexture(c, width, height, glFilter(c, filter))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
innerImage, err = newInnerImage(c, texture)
|
||||
innerImage.Clear(c)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Image{ui: ui.Current(), inner: innerImage}, nil
|
||||
}
|
||||
|
||||
// NewImageFromImage creates a new image with the given image (img).
|
||||
func NewImageFromImage(img image.Image, filter Filter) (*Image, error) {
|
||||
return currentUI.newImageFromImage(img, filter)
|
||||
var innerImage *innerImage
|
||||
var err error
|
||||
ui.Current().Use(func(c *opengl.Context) {
|
||||
var texture *graphics.Texture
|
||||
texture, err = graphics.NewTextureFromImage(c, img, glFilter(c, filter))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
innerImage, err = newInnerImage(c, texture)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Image{ui: ui.Current(), inner: innerImage}, nil
|
||||
}
|
||||
|
@ -34,13 +34,12 @@ func newGraphicsContext(c *opengl.Context, screenWidth, screenHeight, screenScal
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gc := &graphicsContext{
|
||||
return &graphicsContext{
|
||||
glContext: c,
|
||||
defaultR: &innerImage{f, nil},
|
||||
screen: screen,
|
||||
screenScale: screenScale,
|
||||
}
|
||||
return gc, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
type graphicsContext struct {
|
||||
|
19
image.go
19
image.go
@ -18,6 +18,7 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/internal"
|
||||
"github.com/hajimehoshi/ebiten/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/internal/opengl"
|
||||
"github.com/hajimehoshi/ebiten/internal/ui"
|
||||
"image"
|
||||
"image/color"
|
||||
)
|
||||
@ -102,7 +103,7 @@ func (t *textureQuads) Texture(i int) (u0, v0, u1, v1 float32) {
|
||||
// The pixel format is alpha-premultiplied.
|
||||
// Image implements image.Image.
|
||||
type Image struct {
|
||||
ui *ui
|
||||
ui *ui.UI
|
||||
inner *innerImage
|
||||
pixels []uint8
|
||||
}
|
||||
@ -115,8 +116,8 @@ func (i *Image) Size() (width, height int) {
|
||||
// Clear resets the pixels of the image into 0.
|
||||
func (i *Image) Clear() (err error) {
|
||||
i.pixels = nil
|
||||
i.ui.use(func() {
|
||||
err = i.inner.Clear(i.ui.glContext)
|
||||
i.ui.Use(func(c *opengl.Context) {
|
||||
err = i.inner.Clear(c)
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -124,8 +125,8 @@ func (i *Image) Clear() (err error) {
|
||||
// Fill fills the image with a solid color.
|
||||
func (i *Image) Fill(clr color.Color) (err error) {
|
||||
i.pixels = nil
|
||||
i.ui.use(func() {
|
||||
err = i.inner.Fill(i.ui.glContext, clr)
|
||||
i.ui.Use(func(c *opengl.Context) {
|
||||
err = i.inner.Fill(c, clr)
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -147,8 +148,8 @@ func (i *Image) DrawImage(image *Image, options *DrawImageOptions) (err error) {
|
||||
|
||||
func (i *Image) drawImage(image *innerImage, option *DrawImageOptions) (err error) {
|
||||
i.pixels = nil
|
||||
i.ui.use(func() {
|
||||
err = i.inner.drawImage(i.ui.glContext, image, option)
|
||||
i.ui.Use(func(c *opengl.Context) {
|
||||
err = i.inner.drawImage(c, image, option)
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -169,9 +170,9 @@ func (i *Image) ColorModel() color.Model {
|
||||
// This method loads pixels from GPU to VRAM if necessary.
|
||||
func (i *Image) At(x, y int) color.Color {
|
||||
if i.pixels == nil {
|
||||
i.ui.use(func() {
|
||||
i.ui.Use(func(c *opengl.Context) {
|
||||
var err error
|
||||
i.pixels, err = i.inner.texture.Pixels(i.ui.glContext)
|
||||
i.pixels, err = i.inner.texture.Pixels(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2014 Hajime Hoshi
|
||||
// Copyright 2015 Hajime Hoshi
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -12,13 +12,33 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package ebiten
|
||||
package ui
|
||||
|
||||
import (
|
||||
glfw "github.com/go-gl/glfw3"
|
||||
"math"
|
||||
)
|
||||
|
||||
type Key int
|
||||
|
||||
const (
|
||||
KeyUp Key = iota
|
||||
KeyDown
|
||||
KeyLeft
|
||||
KeyRight
|
||||
KeySpace
|
||||
KeyMax
|
||||
)
|
||||
|
||||
type MouseButton int
|
||||
|
||||
const (
|
||||
MouseButtonLeft MouseButton = iota
|
||||
MouseButtonRight
|
||||
MouseButtonMiddle
|
||||
MouseButtonMax
|
||||
)
|
||||
|
||||
type input struct {
|
||||
keyPressed [KeyMax]bool
|
||||
mouseButtonPressed [MouseButtonMax]bool
|
||||
@ -26,15 +46,15 @@ type input struct {
|
||||
cursorY int
|
||||
}
|
||||
|
||||
func (i *input) isKeyPressed(key Key) bool {
|
||||
func (i *input) IsKeyPressed(key Key) bool {
|
||||
return i.keyPressed[key]
|
||||
}
|
||||
|
||||
func (i *input) isMouseButtonPressed(button MouseButton) bool {
|
||||
func (i *input) IsMouseButtonPressed(button MouseButton) bool {
|
||||
return i.mouseButtonPressed[button]
|
||||
}
|
||||
|
||||
func (i *input) cursorPosition() (x, y int) {
|
||||
func (i *input) CursorPosition() (x, y int) {
|
||||
return i.cursorX, i.cursorY
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2014 Hajime Hoshi
|
||||
// Copyright 2015 Hajime Hoshi
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -12,18 +12,20 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package ebiten
|
||||
package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
glfw "github.com/go-gl/glfw3"
|
||||
"github.com/hajimehoshi/ebiten/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/internal/opengl"
|
||||
"image"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var currentUI *ui
|
||||
var currentUI *UI
|
||||
|
||||
func Current() *UI {
|
||||
return currentUI
|
||||
}
|
||||
|
||||
func init() {
|
||||
runtime.LockOSThread()
|
||||
@ -42,28 +44,32 @@ func init() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
u := &ui{
|
||||
u := &UI{
|
||||
window: window,
|
||||
funcs: make(chan func()),
|
||||
}
|
||||
u.run()
|
||||
u.use(func() {
|
||||
go func() {
|
||||
runtime.LockOSThread()
|
||||
u.window.MakeContextCurrent()
|
||||
u.glContext = opengl.NewContext()
|
||||
glfw.SwapInterval(1)
|
||||
})
|
||||
for f := range u.funcs {
|
||||
f()
|
||||
}
|
||||
}()
|
||||
currentUI = u
|
||||
}
|
||||
|
||||
type ui struct {
|
||||
window *glfw.Window
|
||||
scale int
|
||||
glContext *opengl.Context
|
||||
graphicsContext *graphicsContext
|
||||
input input
|
||||
funcs chan func()
|
||||
type UI struct {
|
||||
window *glfw.Window
|
||||
scale int
|
||||
realScale int
|
||||
glContext *opengl.Context
|
||||
input input
|
||||
funcs chan func()
|
||||
}
|
||||
|
||||
func startUI(width, height, scale int, title string) (*ui, error) {
|
||||
func New(width, height, scale int, title string) (*UI, error) {
|
||||
monitor, err := glfw.GetPrimaryMonitor()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -103,101 +109,41 @@ func startUI(width, height, scale int, title string) (*ui, error) {
|
||||
|
||||
// For retina displays, recalculate the scale with the framebuffer size.
|
||||
windowWidth, _ := window.GetFramebufferSize()
|
||||
realScale := windowWidth / width
|
||||
ui.use(func() {
|
||||
ui.graphicsContext, err = newGraphicsContext(ui.glContext, width, height, realScale)
|
||||
})
|
||||
ui.realScale = windowWidth / width
|
||||
|
||||
return ui, err
|
||||
}
|
||||
|
||||
func (u *ui) doEvents() {
|
||||
glfw.PollEvents()
|
||||
u.update()
|
||||
func (u *UI) RealScale() int {
|
||||
return u.realScale
|
||||
}
|
||||
|
||||
func (u *ui) terminate() {
|
||||
func (u *UI) DoEvents() {
|
||||
glfw.PollEvents()
|
||||
u.input.update(u.window, u.scale)
|
||||
}
|
||||
|
||||
func (u *UI) Terminate() {
|
||||
glfw.Terminate()
|
||||
}
|
||||
|
||||
func (u *ui) isClosed() bool {
|
||||
func (u *UI) IsClosed() bool {
|
||||
return u.window.ShouldClose()
|
||||
}
|
||||
|
||||
func (u *ui) draw(f func(*Image) error) (err error) {
|
||||
u.use(func() {
|
||||
err = u.graphicsContext.preUpdate()
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = f(&Image{ui: u, inner: u.graphicsContext.screen})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
u.use(func() {
|
||||
err = u.graphicsContext.postUpdate()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
u.window.SwapBuffers()
|
||||
})
|
||||
return
|
||||
func (u *UI) SwapBuffers() {
|
||||
u.window.SwapBuffers()
|
||||
}
|
||||
|
||||
func (u *ui) newImageFromImage(img image.Image, filter Filter) (*Image, error) {
|
||||
var innerImage *innerImage
|
||||
var err error
|
||||
u.use(func() {
|
||||
var texture *graphics.Texture
|
||||
texture, err = graphics.NewTextureFromImage(u.glContext, img, glFilter(u.glContext, filter))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
innerImage, err = newInnerImage(u.glContext, texture)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Image{ui: u, inner: innerImage}, nil
|
||||
func (u *UI) Input() *input {
|
||||
return &u.input
|
||||
}
|
||||
|
||||
func (u *ui) newImage(width, height int, filter Filter) (*Image, error) {
|
||||
var innerImage *innerImage
|
||||
var err error
|
||||
u.use(func() {
|
||||
var texture *graphics.Texture
|
||||
texture, err = graphics.NewTexture(u.glContext, width, height, glFilter(u.glContext, filter))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
innerImage, err = newInnerImage(u.glContext, texture)
|
||||
innerImage.Clear(u.glContext)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Image{ui: u, inner: innerImage}, nil
|
||||
}
|
||||
|
||||
func (u *ui) run() {
|
||||
go func() {
|
||||
runtime.LockOSThread()
|
||||
u.window.MakeContextCurrent()
|
||||
for f := range u.funcs {
|
||||
f()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (u *ui) use(f func()) {
|
||||
func (u *UI) Use(f func(*opengl.Context)) {
|
||||
ch := make(chan struct{})
|
||||
u.funcs <- func() {
|
||||
defer close(ch)
|
||||
f()
|
||||
f(u.glContext)
|
||||
}
|
||||
<-ch
|
||||
}
|
||||
|
||||
func (u *ui) update() {
|
||||
u.input.update(u.window, u.scale)
|
||||
}
|
26
keys.go
26
keys.go
@ -14,19 +14,25 @@
|
||||
|
||||
package ebiten
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten/internal/ui"
|
||||
)
|
||||
|
||||
// A Key represents a keyboard key.
|
||||
type Key int
|
||||
|
||||
// TODO: Add more keys.
|
||||
|
||||
// TODO: Generate this automatically.
|
||||
|
||||
// Keys
|
||||
const (
|
||||
KeyUp Key = iota
|
||||
KeyDown
|
||||
KeyLeft
|
||||
KeyRight
|
||||
KeySpace
|
||||
KeyMax
|
||||
KeyUp = Key(ui.KeyUp)
|
||||
KeyDown = Key(ui.KeyDown)
|
||||
KeyLeft = Key(ui.KeyLeft)
|
||||
KeyRight = Key(ui.KeyRight)
|
||||
KeySpace = Key(ui.KeySpace)
|
||||
KeyMax = Key(ui.KeyMax)
|
||||
)
|
||||
|
||||
// A MouseButton represents a mouse button.
|
||||
@ -34,8 +40,8 @@ type MouseButton int
|
||||
|
||||
// MouseButtons
|
||||
const (
|
||||
MouseButtonLeft MouseButton = iota
|
||||
MouseButtonRight
|
||||
MouseButtonMiddle
|
||||
MouseButtonMax
|
||||
MouseButtonLeft = MouseButton(ui.MouseButtonLeft)
|
||||
MouseButtonRight = MouseButton(ui.MouseButtonRight)
|
||||
MouseButtonMiddle = MouseButton(ui.MouseButtonMiddle)
|
||||
MouseButtonMax = MouseButton(ui.MouseButtonMax)
|
||||
)
|
||||
|
36
run.go
36
run.go
@ -15,6 +15,8 @@
|
||||
package ebiten
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten/internal/opengl"
|
||||
"github.com/hajimehoshi/ebiten/internal/ui"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -28,20 +30,44 @@ import (
|
||||
// but this is not strictly guaranteed.
|
||||
// If you need to care about time, you need to check current time every time f is called.
|
||||
func Run(f func(*Image) error, width, height, scale int, title string) error {
|
||||
ui, err := startUI(width, height, scale, title)
|
||||
ui, err := ui.New(width, height, scale, title)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer ui.Terminate()
|
||||
|
||||
var graphicsContext *graphicsContext
|
||||
ui.Use(func(c *opengl.Context) {
|
||||
graphicsContext, err = newGraphicsContext(c, width, height, ui.RealScale())
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer ui.terminate()
|
||||
|
||||
for {
|
||||
// To avoid busy loop when the window is inactive, wait 1/120 [sec] at least.
|
||||
ch := time.After(1 * time.Second / 120)
|
||||
ui.doEvents()
|
||||
if ui.isClosed() {
|
||||
ui.DoEvents()
|
||||
if ui.IsClosed() {
|
||||
return nil
|
||||
}
|
||||
if err := ui.draw(f); err != nil {
|
||||
ui.Use(func(*opengl.Context) {
|
||||
err = graphicsContext.preUpdate()
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := f(&Image{ui: ui, inner: graphicsContext.screen}); err != nil {
|
||||
return err
|
||||
}
|
||||
ui.Use(func(*opengl.Context) {
|
||||
err = graphicsContext.postUpdate()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ui.SwapBuffers()
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
<-ch
|
||||
|
Loading…
Reference in New Issue
Block a user