From 54509e42cfc956d1b526caf1998131e9aae5a93e Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Thu, 11 Dec 2014 03:50:35 +0900 Subject: [PATCH] Add GraphicsContext.PushOffscreen / PopOffscreen (#21) --- ebitenutil/debugprint.go | 16 +++++++-------- example/blocks/scenemanager.go | 7 ++++--- example/paint.go | 9 ++++++--- graphics.go | 4 ++-- internal/glfw/canvas.go | 3 ++- internal/glfw/context.go | 8 ++++---- internal/glfw/input.go | 6 +++--- internal/glfw/ui.go | 1 + internal/opengl/context.go | 36 +++++++++++++++++++--------------- 9 files changed, 50 insertions(+), 40 deletions(-) diff --git a/ebitenutil/debugprint.go b/ebitenutil/debugprint.go index 36b1d8918..8ad32a976 100644 --- a/ebitenutil/debugprint.go +++ b/ebitenutil/debugprint.go @@ -34,7 +34,7 @@ func DebugPrint(ga ebiten.GameContext, gr ebiten.GraphicsContext, str string) { defaultDebugPrintState.DebugPrint(ga, gr, str) } -func (d *debugPrintState) drawText(gr ebiten.GraphicsContext, str string, x, y int) { +func (d *debugPrintState) drawText(gr ebiten.GraphicsContext, str string, x, y int, clr color.Color) { parts := []ebiten.TexturePart{} locationX, locationY := 0, 0 for _, c := range str { @@ -54,12 +54,11 @@ func (d *debugPrintState) drawText(gr ebiten.GraphicsContext, str string, x, y i }) locationX += assets.TextImageCharWidth } - geo := ebiten.GeometryMatrixI() - geo.Translate(float64(x)+1, float64(y)) - clr := ebiten.ColorMatrixI() - // TODO: Is this color OK? - clr.Scale(color.RGBA{0x80, 0x80, 0x80, 0xff}) - gr.Texture(d.textTexture).Draw(parts, geo, clr) + geom := ebiten.GeometryMatrixI() + geom.Translate(float64(x)+1, float64(y)) + clrm := ebiten.ColorMatrixI() + clrm.Scale(clr) + gr.Texture(d.textTexture).Draw(parts, geom, clrm) } func (d *debugPrintState) DebugPrint(ga ebiten.GameContext, gr ebiten.GraphicsContext, str string) { @@ -81,5 +80,6 @@ func (d *debugPrintState) DebugPrint(ga ebiten.GameContext, gr ebiten.GraphicsCo panic(err) } } - d.drawText(gr, str, 0, d.y) + d.drawText(gr, str, 1, d.y+1, &color.RGBA{0x00, 0x00, 0x00, 0x80}) + d.drawText(gr, str, 0, d.y, &color.RGBA{0xff, 0xff, 0xff, 0xff}) } diff --git a/example/blocks/scenemanager.go b/example/blocks/scenemanager.go index c9516725b..67d27b427 100644 --- a/example/blocks/scenemanager.go +++ b/example/blocks/scenemanager.go @@ -66,16 +66,17 @@ func (s *SceneManager) Draw(context ebiten.GraphicsContext, textures *Textures) return } from := textures.GetRenderTarget("scene_manager_transition_from") - context.SetOffscreen(from) + context.PushOffscreen(from) context.Clear() s.current.Draw(context, textures) + context.PopOffscreen() to := textures.GetRenderTarget("scene_manager_transition_to") - context.SetOffscreen(to) + context.PushOffscreen(to) context.Clear() s.next.Draw(context, textures) + context.PopOffscreen() - context.ResetOffscreen() color := ebiten.ColorMatrixI() ebiten.DrawWhole( context.RenderTarget(from), diff --git a/example/paint.go b/example/paint.go index e0f42a5a8..ab5a69044 100644 --- a/example/paint.go +++ b/example/paint.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "github.com/hajimehoshi/ebiten" "github.com/hajimehoshi/ebiten/ebitenutil" "github.com/hajimehoshi/ebiten/runner" @@ -35,12 +36,14 @@ func (g *Game) Draw(gr ebiten.GraphicsContext) error { if err != nil { return err } - gr.SetOffscreen(g.canvasRenderTarget) + gr.PushOffscreen(g.canvasRenderTarget) gr.Fill(0xff, 0xff, 0xff) + gr.PopOffscreen() } - gr.ResetOffscreen() ebiten.DrawWhole(gr.RenderTarget(g.canvasRenderTarget), screenWidth, screenHeight, ebiten.GeometryMatrixI(), ebiten.ColorMatrixI()) - ebitenutil.DebugPrint(g.gameContext, gr, "Hello\nWorld!") + + mx, my := g.gameContext.CursorPosition() + ebitenutil.DebugPrint(g.gameContext, gr, fmt.Sprintf("(%d, %d)", mx, my)) return nil } diff --git a/graphics.go b/graphics.go index 739548e6f..8f1c280bd 100644 --- a/graphics.go +++ b/graphics.go @@ -50,8 +50,8 @@ type GraphicsContext interface { Fill(r, g, b uint8) Texture(id TextureID) Drawer RenderTarget(id RenderTargetID) Drawer - ResetOffscreen() - SetOffscreen(id RenderTargetID) + PushOffscreen(id RenderTargetID) + PopOffscreen() } // Filter represents the type of filter to be used when a texture or a render diff --git a/internal/glfw/canvas.go b/internal/glfw/canvas.go index c8365dd48..19450ca77 100644 --- a/internal/glfw/canvas.go +++ b/internal/glfw/canvas.go @@ -26,6 +26,7 @@ import ( type canvas struct { window *glfw.Window + scale int graphicsContext *opengl.GraphicsContext input input funcs chan func() @@ -86,7 +87,7 @@ func (c *canvas) use(f func()) { } func (c *canvas) update() { - c.input.update(c.window) + c.input.update(c.window, c.scale) } func (c *canvas) IsKeyPressed(key ebiten.Key) bool { diff --git a/internal/glfw/context.go b/internal/glfw/context.go index f4dfd7f8d..b00c7b07c 100644 --- a/internal/glfw/context.go +++ b/internal/glfw/context.go @@ -58,15 +58,15 @@ func (c *graphicsContext) RenderTarget(id ebiten.RenderTargetID) (d ebiten.Drawe return } -func (c *graphicsContext) ResetOffscreen() { +func (c *graphicsContext) PopOffscreen() { c.canvas.use(func() { - c.canvas.graphicsContext.ResetOffscreen() + c.canvas.graphicsContext.PopOffscreen() }) } -func (c *graphicsContext) SetOffscreen(id ebiten.RenderTargetID) { +func (c *graphicsContext) PushOffscreen(id ebiten.RenderTargetID) { c.canvas.use(func() { - c.canvas.graphicsContext.SetOffscreen(id) + c.canvas.graphicsContext.PushOffscreen(id) }) } diff --git a/internal/glfw/input.go b/internal/glfw/input.go index 697557b16..951fe8e73 100644 --- a/internal/glfw/input.go +++ b/internal/glfw/input.go @@ -49,7 +49,7 @@ var glfwKeyCodeToKey = map[glfw.Key]ebiten.Key{ glfw.KeyDown: ebiten.KeyDown, } -func (i *input) update(window *glfw.Window) { +func (i *input) update(window *glfw.Window, scale int) { for g, u := range glfwKeyCodeToKey { i.keyPressed[u] = window.GetKey(g) == glfw.Press } @@ -57,6 +57,6 @@ func (i *input) update(window *glfw.Window) { i.mouseButtonPressed[b] = window.GetMouseButton(glfw.MouseButton(b)) == glfw.Press } x, y := window.GetCursorPosition() - i.cursorX = int(math.Floor(x)) - i.cursorY = int(math.Floor(y)) + i.cursorX = int(math.Floor(x)) / scale + i.cursorY = int(math.Floor(y)) / scale } diff --git a/internal/glfw/ui.go b/internal/glfw/ui.go index 4c44d8597..652b7716f 100644 --- a/internal/glfw/ui.go +++ b/internal/glfw/ui.go @@ -46,6 +46,7 @@ func (u *UI) Start(game ebiten.Game, width, height, scale int, title string) err c := &canvas{ window: window, + scale: scale, funcs: make(chan func()), funcsDone: make(chan struct{}), } diff --git a/internal/opengl/context.go b/internal/opengl/context.go index df436424f..aa48f92fc 100644 --- a/internal/opengl/context.go +++ b/internal/opengl/context.go @@ -33,27 +33,29 @@ func Initialize(screenWidth, screenHeight, screenScale int) (*GraphicsContext, e } // The defualt framebuffer should be 0. - c.defaultId = idsInstance.addRenderTarget(&renderTarget{ + c.defaultID = idsInstance.addRenderTarget(&renderTarget{ width: screenWidth * screenScale, height: screenHeight * screenScale, flipY: true, }) var err error - c.screenId, err = idsInstance.createRenderTarget(screenWidth, screenHeight, ebiten.FilterNearest) + c.screenID, err = idsInstance.createRenderTarget(screenWidth, screenHeight, ebiten.FilterNearest) if err != nil { return nil, err } - c.ResetOffscreen() + + // TODO: This is a special stack only for clearing. Can we change this? + c.currentIDs = []ebiten.RenderTargetID{c.screenID} c.Clear() return c, nil } type GraphicsContext struct { - screenId ebiten.RenderTargetID - defaultId ebiten.RenderTargetID - currentId ebiten.RenderTargetID + screenID ebiten.RenderTargetID + defaultID ebiten.RenderTargetID + currentIDs []ebiten.RenderTargetID screenWidth int screenHeight int screenScale int @@ -63,7 +65,7 @@ var _ ebiten.GraphicsContext = new(GraphicsContext) func (c *GraphicsContext) dispose() { // NOTE: Now this method is not used anywhere. - idsInstance.deleteRenderTarget(c.screenId) + idsInstance.deleteRenderTarget(c.screenID) } func (c *GraphicsContext) Clear() { @@ -71,7 +73,7 @@ func (c *GraphicsContext) Clear() { } func (c *GraphicsContext) Fill(r, g, b uint8) { - idsInstance.fillRenderTarget(c.currentId, r, g, b) + idsInstance.fillRenderTarget(c.currentIDs[len(c.currentIDs)-1], r, g, b) } func (c *GraphicsContext) Texture(id ebiten.TextureID) ebiten.Drawer { @@ -82,27 +84,28 @@ func (c *GraphicsContext) RenderTarget(id ebiten.RenderTargetID) ebiten.Drawer { return &textureWithContext{idsInstance.toTexture(id), c} } -func (c *GraphicsContext) ResetOffscreen() { - c.currentId = c.screenId +func (c *GraphicsContext) PushOffscreen(renderTargetID ebiten.RenderTargetID) { + c.currentIDs = append(c.currentIDs, renderTargetID) } -func (c *GraphicsContext) SetOffscreen(renderTargetId ebiten.RenderTargetID) { - c.currentId = renderTargetId +func (c *GraphicsContext) PopOffscreen() { + c.currentIDs = c.currentIDs[:len(c.currentIDs)-1] } func (c *GraphicsContext) PreUpdate() { - c.ResetOffscreen() + c.currentIDs = []ebiten.RenderTargetID{c.defaultID} + c.PushOffscreen(c.screenID) c.Clear() } func (c *GraphicsContext) PostUpdate() { - c.SetOffscreen(c.defaultId) + c.PopOffscreen() c.Clear() scale := float64(c.screenScale) geo := ebiten.GeometryMatrixI() geo.Scale(scale, scale) - ebiten.DrawWhole(c.RenderTarget(c.screenId), c.screenWidth, c.screenHeight, geo, ebiten.ColorMatrixI()) + ebiten.DrawWhole(c.RenderTarget(c.screenID), c.screenWidth, c.screenHeight, geo, ebiten.ColorMatrixI()) gl.Flush() } @@ -113,5 +116,6 @@ type textureWithContext struct { } func (t *textureWithContext) Draw(parts []ebiten.TexturePart, geo ebiten.GeometryMatrix, color ebiten.ColorMatrix) { - idsInstance.drawTexture(t.context.currentId, t.id, parts, geo, color) + currentID := t.context.currentIDs[len(t.context.currentIDs)-1] + idsInstance.drawTexture(currentID, t.id, parts, geo, color) }