Hide members of RenderTarget (again)

This commit is contained in:
Hajime Hoshi 2014-12-14 18:34:47 +09:00
parent d0c0dea2be
commit 60aad4326e
8 changed files with 112 additions and 101 deletions

View File

@ -17,7 +17,6 @@ limitations under the License.
package ebiten package ebiten
import ( import (
"github.com/go-gl/gl"
glfw "github.com/go-gl/glfw3" glfw "github.com/go-gl/glfw3"
"image" "image"
"runtime" "runtime"
@ -32,6 +31,29 @@ type canvas struct {
funcsDone chan struct{} funcsDone chan struct{}
} }
func newCanvas(window *glfw.Window, width, height, scale int) (*canvas, error) {
c := &canvas{
window: window,
scale: scale,
funcs: make(chan func()),
funcsDone: make(chan struct{}),
}
c.run(width, height, scale)
// For retina displays, recalculate the scale with the framebuffer size.
windowWidth, _ := window.GetFramebufferSize()
realScale := windowWidth / width
var err error
c.use(func() {
c.graphicsContext, err = newGraphicsContext(width, height, realScale)
})
if err != nil {
return nil, err
}
return c, nil
}
func (c *canvas) draw(game Game) (err error) { func (c *canvas) draw(game Game) (err error) {
c.use(func() { c.use(func() {
c.graphicsContext.PreUpdate() c.graphicsContext.PreUpdate()
@ -50,38 +72,20 @@ func (c *canvas) isClosed() bool {
return c.window.ShouldClose() return c.window.ShouldClose()
} }
func (c *canvas) NewTextureID(img image.Image, filter Filter) (TextureID, error) { func (c *canvas) newTextureID(img image.Image, filter int) (TextureID, error) {
var id TextureID var id TextureID
var err error var err error
c.use(func() { c.use(func() {
glFilter := 0 id, err = newTextureID(img, filter)
switch filter {
case FilterNearest:
glFilter = gl.NEAREST
case FilterLinear:
glFilter = gl.LINEAR
default:
panic("not reached")
}
id, err = newTextureID(img, glFilter)
}) })
return id, err return id, err
} }
func (c *canvas) NewRenderTargetID(width, height int, filter Filter) (RenderTargetID, error) { func (c *canvas) newRenderTargetID(width, height int, filter int) (RenderTargetID, error) {
var id RenderTargetID var id RenderTargetID
var err error var err error
c.use(func() { c.use(func() {
glFilter := 0 id, err = newRenderTargetID(width, height, filter)
switch filter {
case FilterNearest:
glFilter = gl.NEAREST
case FilterLinear:
glFilter = gl.LINEAR
default:
panic("not reached")
}
id, err = newRenderTargetID(width, height, glFilter)
}) })
return id, err return id, err
} }
@ -104,17 +108,5 @@ func (c *canvas) use(f func()) {
} }
func (c *canvas) update() { func (c *canvas) update() {
c.input.Update(c.window, c.scale) c.input.update(c.window, c.scale)
}
func (c *canvas) IsKeyPressed(key Key) bool {
return c.input.IsKeyPressed(key)
}
func (c *canvas) IsMouseButtonPressed(button MouseButton) bool {
return c.input.IsMouseButtonPressed(button)
}
func (c *canvas) CursorPosition() (x, y int) {
return c.input.CursorPosition()
} }

View File

@ -17,30 +17,37 @@ limitations under the License.
package ebiten package ebiten
import ( import (
"github.com/go-gl/gl"
"image" "image"
) )
type Game interface {
Update() error
Draw(gr GraphicsContext) error
}
func IsKeyPressed(key Key) bool { func IsKeyPressed(key Key) bool {
return currentUI.canvas.input.IsKeyPressed(key) return currentUI.canvas.input.isKeyPressed(key)
} }
func CursorPosition() (x, y int) { func CursorPosition() (x, y int) {
return currentUI.canvas.input.CursorPosition() return currentUI.canvas.input.cursorPosition()
} }
func IsMouseButtonPressed(mouseButton MouseButton) bool { func IsMouseButtonPressed(mouseButton MouseButton) bool {
return currentUI.canvas.input.IsMouseButtonPressed(mouseButton) return currentUI.canvas.input.isMouseButtonPressed(mouseButton)
}
func glFilter(f Filter) int {
switch f {
case FilterNearest:
return gl.NEAREST
case FilterLinear:
return gl.LINEAR
default:
panic("not reached")
}
} }
func NewRenderTargetID(width, height int, filter Filter) (RenderTargetID, error) { func NewRenderTargetID(width, height int, filter Filter) (RenderTargetID, error) {
return currentUI.canvas.NewRenderTargetID(width, height, filter) return currentUI.canvas.newRenderTargetID(width, height, glFilter(filter))
} }
func NewTextureID(img image.Image, filter Filter) (TextureID, error) { func NewTextureID(img image.Image, filter Filter) (TextureID, error) {
return currentUI.canvas.NewTextureID(img, filter) return currentUI.canvas.newTextureID(img, glFilter(filter))
} }

View File

@ -21,7 +21,7 @@ import (
"github.com/hajimehoshi/ebiten/internal/opengl" "github.com/hajimehoshi/ebiten/internal/opengl"
) )
func initialize(screenWidth, screenHeight, screenScale int) (*graphicsContext, error) { func newGraphicsContext(screenWidth, screenHeight, screenScale int) (*graphicsContext, error) {
gl.Init() gl.Init()
gl.Enable(gl.TEXTURE_2D) gl.Enable(gl.TEXTURE_2D)
gl.Enable(gl.BLEND) gl.Enable(gl.BLEND)
@ -33,11 +33,8 @@ func initialize(screenWidth, screenHeight, screenScale int) (*graphicsContext, e
} }
// The defualt framebuffer should be 0. // The defualt framebuffer should be 0.
c.defaultID = idsInstance.addRenderTarget(&opengl.RenderTarget{ r := opengl.NewRenderTarget(screenWidth*screenScale, screenHeight*screenScale, true)
Width: screenWidth * screenScale, c.defaultID = idsInstance.addRenderTarget(r)
Height: screenHeight * screenScale,
FlipY: true,
})
var err error var err error
c.screenID, err = idsInstance.createRenderTarget(screenWidth, screenHeight, gl.NEAREST) c.screenID, err = idsInstance.createRenderTarget(screenWidth, screenHeight, gl.NEAREST)

8
ids.go
View File

@ -86,14 +86,10 @@ func (i *ids) createRenderTarget(width, height int, filter int) (RenderTargetID,
if err != nil { if err != nil {
return 0, err return 0, err
} }
framebuffer := opengl.CreateFramebuffer(texture.Native())
// The current binded framebuffer can be changed. // The current binded framebuffer can be changed.
i.currentRenderTargetId = -1 i.currentRenderTargetId = -1
r := &opengl.RenderTarget{ r := opengl.NewRenderTargetFromTexture(texture)
Framebuffer: framebuffer,
Width: texture.Width(),
Height: texture.Height(),
}
i.Lock() i.Lock()
defer i.Unlock() defer i.Unlock()

View File

@ -28,15 +28,15 @@ type input struct {
cursorY int cursorY int
} }
func (i *input) IsKeyPressed(key Key) bool { func (i *input) isKeyPressed(key Key) bool {
return i.keyPressed[key] return i.keyPressed[key]
} }
func (i *input) IsMouseButtonPressed(button MouseButton) bool { func (i *input) isMouseButtonPressed(button MouseButton) bool {
return i.mouseButtonPressed[button] return i.mouseButtonPressed[button]
} }
func (i *input) CursorPosition() (x, y int) { func (i *input) cursorPosition() (x, y int) {
return i.cursorX, i.cursorY return i.cursorX, i.cursorY
} }
@ -48,7 +48,7 @@ var glfwKeyCodeToKey = map[glfw.Key]Key{
glfw.KeyDown: KeyDown, glfw.KeyDown: KeyDown,
} }
func (i *input) Update(window *glfw.Window, scale int) { func (i *input) update(window *glfw.Window, scale int) {
for g, u := range glfwKeyCodeToKey { for g, u := range glfwKeyCodeToKey {
i.keyPressed[u] = window.GetKey(g) == glfw.Press i.keyPressed[u] = window.GetKey(g) == glfw.Press
} }

View File

@ -36,17 +36,46 @@ func orthoProjectionMatrix(left, right, bottom, top int) [4][4]float64 {
} }
type RenderTarget struct { type RenderTarget struct {
Framebuffer gl.Framebuffer framebuffer gl.Framebuffer
Width int width int
Height int height int
FlipY bool flipY bool
}
func NewRenderTarget(width, height int, flipY bool) *RenderTarget {
return &RenderTarget{
width: width,
height: height,
flipY: flipY,
}
}
func NewRenderTargetFromTexture(texture *Texture) *RenderTarget {
framebuffer := createFramebuffer(texture.Native())
return &RenderTarget{
framebuffer: framebuffer,
width: texture.Width(),
height: texture.Height(),
}
}
func (r *RenderTarget) Width() int {
return r.width
}
func (r *RenderTarget) Height() int {
return r.height
}
func (r *RenderTarget) FlipY() bool {
return r.flipY
} }
func (r *RenderTarget) Dispose() { func (r *RenderTarget) Dispose() {
r.Framebuffer.Delete() r.framebuffer.Delete()
} }
func CreateFramebuffer(nativeTexture gl.Texture) gl.Framebuffer { func createFramebuffer(nativeTexture gl.Texture) gl.Framebuffer {
framebuffer := gl.GenFramebuffer() framebuffer := gl.GenFramebuffer()
framebuffer.Bind() framebuffer.Bind()
@ -65,7 +94,7 @@ func CreateFramebuffer(nativeTexture gl.Texture) gl.Framebuffer {
func (r *RenderTarget) SetAsViewport() { func (r *RenderTarget) SetAsViewport() {
gl.Flush() gl.Flush()
r.Framebuffer.Bind() r.framebuffer.Bind()
err := gl.CheckFramebufferStatus(gl.FRAMEBUFFER) err := gl.CheckFramebufferStatus(gl.FRAMEBUFFER)
if err != gl.FRAMEBUFFER_COMPLETE { if err != gl.FRAMEBUFFER_COMPLETE {
panic(fmt.Sprintf("glBindFramebuffer failed: %d", err)) panic(fmt.Sprintf("glBindFramebuffer failed: %d", err))
@ -73,18 +102,18 @@ func (r *RenderTarget) SetAsViewport() {
gl.BlendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE) gl.BlendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE)
width := AdjustSizeForTexture(r.Width) width := AdjustSizeForTexture(r.width)
height := AdjustSizeForTexture(r.Height) height := AdjustSizeForTexture(r.height)
gl.Viewport(0, 0, width, height) gl.Viewport(0, 0, width, height)
} }
func (r *RenderTarget) ProjectionMatrix() [4][4]float64 { func (r *RenderTarget) ProjectionMatrix() [4][4]float64 {
width := AdjustSizeForTexture(r.Width) width := AdjustSizeForTexture(r.width)
height := AdjustSizeForTexture(r.Height) height := AdjustSizeForTexture(r.height)
m := orthoProjectionMatrix(0, width, 0, height) m := orthoProjectionMatrix(0, width, 0, height)
if r.FlipY { if r.flipY {
m[1][1] *= -1 m[1][1] *= -1
m[1][3] += float64(r.Height) / float64(AdjustSizeForTexture(r.Height)) * 2 m[1][3] += float64(r.height) / float64(AdjustSizeForTexture(r.height)) * 2
} }
return m return m
} }

15
run.go
View File

@ -23,6 +23,11 @@ import (
"time" "time"
) )
type Game interface {
Update() error
Draw(gr GraphicsContext) error
}
var currentUI *ui var currentUI *ui
// Run runs the game. // Run runs the game.
@ -34,10 +39,10 @@ func Run(game Game, width, height, scale int, title string, fps int) error {
currentUI = nil currentUI = nil
}() }()
if err := ui.Start(game, width, height, scale, title); err != nil { if err := ui.start(game, width, height, scale, title); err != nil {
return err return err
} }
defer ui.Terminate() defer ui.terminate()
frameTime := time.Duration(int64(time.Second) / int64(fps)) frameTime := time.Duration(int64(time.Second) / int64(fps))
tick := time.Tick(frameTime) tick := time.Tick(frameTime)
@ -45,13 +50,13 @@ func Run(game Game, width, height, scale int, title string, fps int) error {
signal.Notify(sigterm, os.Interrupt, syscall.SIGTERM) signal.Notify(sigterm, os.Interrupt, syscall.SIGTERM)
for { for {
ui.DoEvents() ui.doEvents()
if ui.IsClosed() { if ui.isClosed() {
return nil return nil
} }
select { select {
default: default:
if err := ui.DrawGame(game); err != nil { if err := ui.drawGame(game); err != nil {
return err return err
} }
case <-tick: case <-tick:

27
ui.go
View File

@ -32,7 +32,7 @@ type ui struct {
canvas *canvas canvas *canvas
} }
func (u *ui) Start(game Game, width, height, scale int, title string) error { func (u *ui) start(game Game, width, height, scale int, title string) error {
if !glfw.Init() { if !glfw.Init() {
return errors.New("glfw.Init() fails") return errors.New("glfw.Init() fails")
} }
@ -42,43 +42,28 @@ func (u *ui) Start(game Game, width, height, scale int, title string) error {
return err return err
} }
c := &canvas{ c, err := newCanvas(window, width, height, scale)
window: window,
scale: scale,
funcs: make(chan func()),
funcsDone: make(chan struct{}),
}
c.run(width, height, scale)
// For retina displays, recalculate the scale with the framebuffer size.
windowWidth, _ := window.GetFramebufferSize()
realScale := windowWidth / width
c.use(func() {
c.graphicsContext, err = initialize(width, height, realScale)
})
if err != nil { if err != nil {
return err return err
} }
u.canvas = c u.canvas = c
return nil return nil
} }
func (u *ui) DoEvents() { func (u *ui) doEvents() {
glfw.PollEvents() glfw.PollEvents()
u.canvas.update() u.canvas.update()
} }
func (u *ui) Terminate() { func (u *ui) terminate() {
glfw.Terminate() glfw.Terminate()
} }
func (u *ui) IsClosed() bool { func (u *ui) isClosed() bool {
return u.canvas.isClosed() return u.canvas.isClosed()
} }
func (u *ui) DrawGame(game Game) error { func (u *ui) drawGame(game Game) error {
return u.canvas.draw(game) return u.canvas.draw(game)
} }