From 01e0d42451e93f1e7b94139c15d46bd535e8804a Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 20 Dec 2014 20:54:14 +0900 Subject: [PATCH] Remove GraphicsContext; Add rendering methods to RenderTarget (#26) --- ebitenutil/debugprint.go | 16 ++-- example/alphablending/main.go | 21 +++-- example/blocks/blocks/field.go | 4 +- example/blocks/blocks/font.go | 10 +-- example/blocks/blocks/game.go | 4 +- example/blocks/blocks/gamescene.go | 10 +-- example/blocks/blocks/piece.go | 8 +- example/blocks/blocks/scenemanager.go | 22 +++-- example/blocks/blocks/textures.go | 6 +- example/blocks/blocks/titlescene.go | 16 ++-- example/image/main.go | 4 +- example/mosaic/main.go | 10 +-- example/paint/main.go | 22 ++--- example/perspective/main.go | 4 +- gamecontext.go | 2 +- graphics.go | 31 +------ graphicscontext.go | 61 ++++---------- internal/opengl/rendertarget.go | 10 +-- ids.go => rendertarget.go | 111 ++++++++++++++++++-------- run.go | 2 +- syncgraphicscontext.go | 65 --------------- ui.go | 26 +++--- 22 files changed, 190 insertions(+), 275 deletions(-) rename ids.go => rendertarget.go (51%) delete mode 100644 syncgraphicscontext.go diff --git a/ebitenutil/debugprint.go b/ebitenutil/debugprint.go index 5deaa28d1..c04dbe86d 100644 --- a/ebitenutil/debugprint.go +++ b/ebitenutil/debugprint.go @@ -24,17 +24,17 @@ import ( type debugPrintState struct { textTexture *ebiten.Texture - debugPrintRenderTarget *ebiten.RenderTarget + debugPrintRenderTarget ebiten.RenderTarget y int } var defaultDebugPrintState = new(debugPrintState) -func DebugPrint(gr ebiten.GraphicsContext, str string) { - defaultDebugPrintState.DebugPrint(gr, str) +func DebugPrint(r ebiten.RenderTarget, str string) { + defaultDebugPrintState.DebugPrint(r, str) } -func (d *debugPrintState) drawText(gr ebiten.GraphicsContext, str string, x, y int, clr color.Color) { +func (d *debugPrintState) drawText(r ebiten.RenderTarget, str string, x, y int, clr color.Color) { parts := []ebiten.TexturePart{} locationX, locationY := 0, 0 for _, c := range str { @@ -57,10 +57,10 @@ func (d *debugPrintState) drawText(gr ebiten.GraphicsContext, str string, x, y i geom.Concat(ebiten.TranslateGeometry(float64(x)+1, float64(y))) clrm := ebiten.ColorMatrixI() clrm.Concat(ebiten.ScaleColor(clr)) - gr.DrawTexture(d.textTexture, parts, geom, clrm) + r.DrawTexture(d.textTexture, parts, geom, clrm) } -func (d *debugPrintState) DebugPrint(gr ebiten.GraphicsContext, str string) { +func (d *debugPrintState) DebugPrint(r ebiten.RenderTarget, str string) { if d.textTexture == nil { img, err := assets.TextImage() if err != nil { @@ -79,6 +79,6 @@ func (d *debugPrintState) DebugPrint(gr ebiten.GraphicsContext, str string) { panic(err) } } - 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}) + d.drawText(r, str, 1, d.y+1, &color.RGBA{0x00, 0x00, 0x00, 0x80}) + d.drawText(r, str, 0, d.y, &color.RGBA{0xff, 0xff, 0xff, 0xff}) } diff --git a/example/alphablending/main.go b/example/alphablending/main.go index 1bc3a3740..29bd74153 100644 --- a/example/alphablending/main.go +++ b/example/alphablending/main.go @@ -31,11 +31,11 @@ const ( type Game struct { count int - tmpRenderTarget *ebiten.RenderTarget + tmpRenderTarget ebiten.RenderTarget ebitenTexture *ebiten.Texture } -func (g *Game) Update(gr ebiten.GraphicsContext) error { +func (g *Game) Update(r ebiten.RenderTarget) error { g.count++ g.count %= 600 diff := float64(g.count) * 0.2 @@ -45,21 +45,26 @@ func (g *Game) Update(gr ebiten.GraphicsContext) error { case 240 < g.count: diff = float64(480-g.count) * 0.2 } + _ = diff - gr.PushRenderTarget(g.tmpRenderTarget) - gr.Clear() + if err := g.tmpRenderTarget.Clear(); err != nil { + return err + } for i := 0; i < 10; i++ { geo := ebiten.TranslateGeometry(15+float64(i)*(diff), 20) clr := ebiten.ScaleColor(color.RGBA{0xff, 0xff, 0xff, 0x80}) - ebiten.DrawWholeTexture(gr, g.ebitenTexture, geo, clr) + if err := ebiten.DrawWholeTexture(g.tmpRenderTarget, g.ebitenTexture, geo, clr); err != nil { + return err + } } - gr.PopRenderTarget() - gr.Fill(color.RGBA{0x00, 0x00, 0x80, 0xff}) + r.Fill(color.RGBA{0x00, 0x00, 0x80, 0xff}) for i := 0; i < 10; i++ { geo := ebiten.TranslateGeometry(0, float64(i)*(diff)) clr := ebiten.ColorMatrixI() - ebiten.DrawWholeTexture(gr, g.tmpRenderTarget.Texture(), geo, clr) + if err := ebiten.DrawWholeTexture(r, g.tmpRenderTarget.Texture(), geo, clr); err != nil { + return err + } } return nil } diff --git a/example/blocks/blocks/field.go b/example/blocks/blocks/field.go index e2eb48b45..55aa4d154 100644 --- a/example/blocks/blocks/field.go +++ b/example/blocks/blocks/field.go @@ -112,11 +112,11 @@ func (f *Field) flushLine(j int) bool { return true } -func (f *Field) Draw(context ebiten.GraphicsContext, textures *Textures, geo ebiten.GeometryMatrix) { +func (f *Field) Draw(r ebiten.RenderTarget, textures *Textures, geo ebiten.GeometryMatrix) { blocks := make([][]BlockType, len(f.blocks)) for i, blockCol := range f.blocks { blocks[i] = make([]BlockType, len(blockCol)) copy(blocks[i], blockCol[:]) } - drawBlocks(context, textures, blocks, geo) + drawBlocks(r, textures, blocks, geo) } diff --git a/example/blocks/blocks/font.go b/example/blocks/blocks/font.go index 07b5e9b49..7dcbda173 100644 --- a/example/blocks/blocks/font.go +++ b/example/blocks/blocks/font.go @@ -32,7 +32,7 @@ func textWidth(str string) int { return charWidth * len(str) } -func drawText(context ebiten.GraphicsContext, textures *Textures, str string, ox, oy, scale int, clr color.Color) { +func drawText(r ebiten.RenderTarget, textures *Textures, str string, ox, oy, scale int, clr color.Color) { fontTextureId := textures.GetTexture("font") parts := []ebiten.TexturePart{} @@ -56,10 +56,10 @@ func drawText(context ebiten.GraphicsContext, textures *Textures, str string, ox geoMat := ebiten.ScaleGeometry(float64(scale), float64(scale)) geoMat.Concat(ebiten.TranslateGeometry(float64(ox), float64(oy))) clrMat := ebiten.ScaleColor(clr) - context.DrawTexture(fontTextureId, parts, geoMat, clrMat) + r.DrawTexture(fontTextureId, parts, geoMat, clrMat) } -func drawTextWithShadow(context ebiten.GraphicsContext, textures *Textures, str string, x, y, scale int, clr color.Color) { - drawText(context, textures, str, x+1, y+1, scale, color.RGBA{0, 0, 0, 0x80}) - drawText(context, textures, str, x, y, scale, clr) +func drawTextWithShadow(r ebiten.RenderTarget, textures *Textures, str string, x, y, scale int, clr color.Color) { + drawText(r, textures, str, x+1, y+1, scale, color.RGBA{0, 0, 0, 0x80}) + drawText(r, textures, str, x, y, scale, clr) } diff --git a/example/blocks/blocks/game.go b/example/blocks/blocks/game.go index 841c5982e..0e87e82ef 100644 --- a/example/blocks/blocks/game.go +++ b/example/blocks/blocks/game.go @@ -70,7 +70,7 @@ func (game *Game) isInitialized() bool { return true } -func (game *Game) Update(g ebiten.GraphicsContext) error { +func (game *Game) Update(r ebiten.RenderTarget) error { game.once.Do(func() { game.textures = NewTextures() for name, path := range texturePaths { @@ -88,6 +88,6 @@ func (game *Game) Update(g ebiten.GraphicsContext) error { SceneManager: game.sceneManager, Input: game.input, }) - game.sceneManager.Draw(g, game.textures) + game.sceneManager.Draw(r, game.textures) return nil } diff --git a/example/blocks/blocks/gamescene.go b/example/blocks/blocks/gamescene.go index 782a2cb08..89afa043b 100644 --- a/example/blocks/blocks/gamescene.go +++ b/example/blocks/blocks/gamescene.go @@ -109,21 +109,21 @@ func (s *GameScene) Update(state *GameState) { } } -func (s *GameScene) Draw(context ebiten.GraphicsContext, textures *Textures) { - context.Fill(color.White) +func (s *GameScene) Draw(r ebiten.RenderTarget, textures *Textures) { + r.Fill(color.White) field := textures.GetTexture("empty") w, h := field.Size() geoMat := ebiten.ScaleGeometry(float64(fieldWidth)/float64(w), float64(fieldHeight)/float64(h)) geoMat.Concat(ebiten.TranslateGeometry(20, 20)) // TODO: magic number? colorMat := ebiten.ScaleColor(color.RGBA{0, 0, 0, 0x80}) - ebiten.DrawWholeTexture(context, field, geoMat, colorMat) + ebiten.DrawWholeTexture(r, field, geoMat, colorMat) geoMat = ebiten.GeometryMatrixI() geoMat.Concat(ebiten.TranslateGeometry(20, 20)) - s.field.Draw(context, textures, geoMat) + s.field.Draw(r, textures, geoMat) if s.currentPiece != nil { - s.currentPiece.Draw(context, textures, 20, 20, s.currentPieceX, s.currentPieceY, s.currentPieceAngle) + s.currentPiece.Draw(r, textures, 20, 20, s.currentPieceX, s.currentPieceY, s.currentPieceAngle) } } diff --git a/example/blocks/blocks/piece.go b/example/blocks/blocks/piece.go index cff612387..c53a0bbfc 100644 --- a/example/blocks/blocks/piece.go +++ b/example/blocks/blocks/piece.go @@ -138,7 +138,7 @@ const blockHeight = 10 const fieldBlockNumX = 10 const fieldBlockNumY = 20 -func drawBlocks(context ebiten.GraphicsContext, textures *Textures, blocks [][]BlockType, geo ebiten.GeometryMatrix) { +func drawBlocks(r ebiten.RenderTarget, textures *Textures, blocks [][]BlockType, geo ebiten.GeometryMatrix) { parts := []ebiten.TexturePart{} for i, blockCol := range blocks { for j, block := range blockCol { @@ -153,7 +153,7 @@ func drawBlocks(context ebiten.GraphicsContext, textures *Textures, blocks [][]B } } blocksTexture := textures.GetTexture("blocks") - context.DrawTexture(blocksTexture, parts, geo, ebiten.ColorMatrixI()) + r.DrawTexture(blocksTexture, parts, geo, ebiten.ColorMatrixI()) } func (p *Piece) InitialPosition() (int, int) { @@ -213,7 +213,7 @@ func (p *Piece) AbsorbInto(field *Field, x, y int, angle Angle) { } } -func (p *Piece) Draw(context ebiten.GraphicsContext, textures *Textures, fieldX, fieldY int, pieceX, pieceY int, angle Angle) { +func (p *Piece) Draw(r ebiten.RenderTarget, textures *Textures, fieldX, fieldY int, pieceX, pieceY int, angle Angle) { size := len(p.blocks) blocks := make([][]BlockType, size) for i := range p.blocks { @@ -230,5 +230,5 @@ func (p *Piece) Draw(context ebiten.GraphicsContext, textures *Textures, fieldX, y := fieldY + pieceY*blockHeight geoMat.Concat(ebiten.TranslateGeometry(float64(x), float64(y))) - drawBlocks(context, textures, blocks, geoMat) + drawBlocks(r, textures, blocks, geoMat) } diff --git a/example/blocks/blocks/scenemanager.go b/example/blocks/blocks/scenemanager.go index 14fdba063..1a7d9a47f 100644 --- a/example/blocks/blocks/scenemanager.go +++ b/example/blocks/blocks/scenemanager.go @@ -29,7 +29,7 @@ func init() { type Scene interface { Update(state *GameState) - Draw(context ebiten.GraphicsContext, textures *Textures) + Draw(r ebiten.RenderTarget, textures *Textures) } const transitionMaxCount = 20 @@ -60,29 +60,25 @@ func (s *SceneManager) Update(state *GameState) { } } -func (s *SceneManager) Draw(context ebiten.GraphicsContext, textures *Textures) { +func (s *SceneManager) Draw(r ebiten.RenderTarget, textures *Textures) { if s.transitionCount == -1 { - s.current.Draw(context, textures) + s.current.Draw(r, textures) return } from := textures.GetRenderTarget("scene_manager_transition_from") - context.PushRenderTarget(from) - context.Clear() - s.current.Draw(context, textures) - context.PopRenderTarget() + from.Clear() + s.current.Draw(from, textures) to := textures.GetRenderTarget("scene_manager_transition_to") - context.PushRenderTarget(to) - context.Clear() - s.next.Draw(context, textures) - context.PopRenderTarget() + to.Clear() + s.next.Draw(to, textures) color := ebiten.ColorMatrixI() - ebiten.DrawWholeTexture(context, from.Texture(), ebiten.GeometryMatrixI(), color) + ebiten.DrawWholeTexture(r, from.Texture(), ebiten.GeometryMatrixI(), color) alpha := float64(s.transitionCount) / float64(transitionMaxCount) color.Elements[3][3] = alpha - ebiten.DrawWholeTexture(context, to.Texture(), ebiten.GeometryMatrixI(), color) + ebiten.DrawWholeTexture(r, to.Texture(), ebiten.GeometryMatrixI(), color) } func (s *SceneManager) GoTo(scene Scene) { diff --git a/example/blocks/blocks/textures.go b/example/blocks/blocks/textures.go index 3fe33a426..7f079ef90 100644 --- a/example/blocks/blocks/textures.go +++ b/example/blocks/blocks/textures.go @@ -38,7 +38,7 @@ type Textures struct { texturePaths chan namePath renderTargetSizes chan nameSize textures map[string]*ebiten.Texture - renderTargets map[string]*ebiten.RenderTarget + renderTargets map[string]ebiten.RenderTarget sync.RWMutex } @@ -47,7 +47,7 @@ func NewTextures() *Textures { texturePaths: make(chan namePath), renderTargetSizes: make(chan nameSize), textures: map[string]*ebiten.Texture{}, - renderTargets: map[string]*ebiten.RenderTarget{}, + renderTargets: map[string]ebiten.RenderTarget{}, } go func() { for { @@ -129,7 +129,7 @@ func (t *Textures) GetTexture(name string) *ebiten.Texture { return t.textures[name] } -func (t *Textures) GetRenderTarget(name string) *ebiten.RenderTarget { +func (t *Textures) GetRenderTarget(name string) ebiten.RenderTarget { t.RLock() defer t.RUnlock() return t.renderTargets[name] diff --git a/example/blocks/blocks/titlescene.go b/example/blocks/blocks/titlescene.go index 224d751ab..cd7888d83 100644 --- a/example/blocks/blocks/titlescene.go +++ b/example/blocks/blocks/titlescene.go @@ -40,17 +40,17 @@ func (s *TitleScene) Update(state *GameState) { } } -func (s *TitleScene) Draw(context ebiten.GraphicsContext, textures *Textures) { - drawTitleBackground(context, textures, s.count) - drawLogo(context, textures, "BLOCKS") +func (s *TitleScene) Draw(r ebiten.RenderTarget, textures *Textures) { + drawTitleBackground(r, textures, s.count) + drawLogo(r, textures, "BLOCKS") message := "PRESS SPACE TO START" x := (ScreenWidth - textWidth(message)) / 2 y := ScreenHeight - 48 - drawTextWithShadow(context, textures, message, x, y, 1, color.RGBA{0x80, 0, 0, 0xff}) + drawTextWithShadow(r, textures, message, x, y, 1, color.RGBA{0x80, 0, 0, 0xff}) } -func drawTitleBackground(context ebiten.GraphicsContext, textures *Textures, c int) { +func drawTitleBackground(r ebiten.RenderTarget, textures *Textures, c int) { const textureWidth = 32 const textureHeight = 32 @@ -70,13 +70,13 @@ func drawTitleBackground(context ebiten.GraphicsContext, textures *Textures, c i geo := ebiten.GeometryMatrixI() geo.Concat(ebiten.TranslateGeometry(float64(dx), float64(dy))) clr := ebiten.ColorMatrixI() - context.DrawTexture(backgroundTexture, parts, geo, clr) + r.DrawTexture(backgroundTexture, parts, geo, clr) } -func drawLogo(context ebiten.GraphicsContext, textures *Textures, str string) { +func drawLogo(r ebiten.RenderTarget, textures *Textures, str string) { scale := 4 textWidth := textWidth(str) * scale x := (ScreenWidth - textWidth) / 2 y := 32 - drawTextWithShadow(context, textures, str, x, y, scale, color.RGBA{0x00, 0x00, 0x80, 0xff}) + drawTextWithShadow(r, textures, str, x, y, scale, color.RGBA{0x00, 0x00, 0x80, 0xff}) } diff --git a/example/image/main.go b/example/image/main.go index 4cc125668..62c31d46e 100644 --- a/example/image/main.go +++ b/example/image/main.go @@ -36,7 +36,7 @@ type Game struct { gophersTexture *ebiten.Texture } -func (g *Game) Update(gr ebiten.GraphicsContext) error { +func (g *Game) Update(r ebiten.RenderTarget) error { g.count++ if ebiten.IsKeyPressed(ebiten.KeyLeft) { g.horizontalCount-- @@ -60,7 +60,7 @@ func (g *Game) Update(gr ebiten.GraphicsContext) error { geo.Concat(ebiten.TranslateGeometry(screenWidth/2, screenHeight/2)) //clr := ebiten.RotateHue(float64(g.count%180) * 2 * math.Pi / 180) clr := ebiten.ColorMatrixI() - ebiten.DrawWholeTexture(gr, g.gophersTexture, geo, clr) + ebiten.DrawWholeTexture(r, g.gophersTexture, geo, clr) return nil } diff --git a/example/mosaic/main.go b/example/mosaic/main.go index fabfcf020..ccbab1676 100644 --- a/example/mosaic/main.go +++ b/example/mosaic/main.go @@ -32,17 +32,15 @@ const mosaicRatio = 16 type Game struct { gophersTexture *ebiten.Texture - gophersRenderTarget *ebiten.RenderTarget + gophersRenderTarget ebiten.RenderTarget } -func (g *Game) Update(gr ebiten.GraphicsContext) error { - gr.PushRenderTarget(g.gophersRenderTarget) +func (g *Game) Update(r ebiten.RenderTarget) error { geo := ebiten.ScaleGeometry(1.0/mosaicRatio, 1.0/mosaicRatio) - ebiten.DrawWholeTexture(gr, g.gophersTexture, geo, ebiten.ColorMatrixI()) - gr.PopRenderTarget() + ebiten.DrawWholeTexture(g.gophersRenderTarget, g.gophersTexture, geo, ebiten.ColorMatrixI()) geo = ebiten.ScaleGeometry(mosaicRatio/2.0, mosaicRatio/2.0) - ebiten.DrawWholeTexture(gr, g.gophersRenderTarget.Texture(), geo, ebiten.ColorMatrixI()) + ebiten.DrawWholeTexture(r, g.gophersRenderTarget.Texture(), geo, ebiten.ColorMatrixI()) return nil } diff --git a/example/paint/main.go b/example/paint/main.go index 8c03adb11..9ed6b2fed 100644 --- a/example/paint/main.go +++ b/example/paint/main.go @@ -33,39 +33,33 @@ const ( type Game struct { inited bool count int - brushRenderTarget *ebiten.RenderTarget - canvasRenderTarget *ebiten.RenderTarget + brushRenderTarget ebiten.RenderTarget + canvasRenderTarget ebiten.RenderTarget } -func (g *Game) Update(gr ebiten.GraphicsContext) error { +func (g *Game) Update(r ebiten.RenderTarget) error { if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) { g.count++ } if !g.inited { - gr.PushRenderTarget(g.brushRenderTarget) - gr.Fill(color.White) - gr.PopRenderTarget() - gr.PushRenderTarget(g.canvasRenderTarget) - gr.Fill(color.White) - gr.PopRenderTarget() + g.brushRenderTarget.Fill(color.White) + g.canvasRenderTarget.Fill(color.White) g.inited = true } mx, my := ebiten.CursorPosition() if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) { - gr.PushRenderTarget(g.canvasRenderTarget) geo := ebiten.TranslateGeometry(float64(mx), float64(my)) clr := ebiten.ScaleColor(color.RGBA{0xff, 0x40, 0x40, 0xff}) theta := 2.0 * math.Pi * float64(g.count%60) / 60.0 clr.Concat(ebiten.RotateHue(theta)) - ebiten.DrawWholeTexture(gr, g.brushRenderTarget.Texture(), geo, clr) - gr.PopRenderTarget() + ebiten.DrawWholeTexture(g.canvasRenderTarget, g.brushRenderTarget.Texture(), geo, clr) } - ebiten.DrawWholeTexture(gr, g.canvasRenderTarget.Texture(), ebiten.GeometryMatrixI(), ebiten.ColorMatrixI()) + ebiten.DrawWholeTexture(r, g.canvasRenderTarget.Texture(), ebiten.GeometryMatrixI(), ebiten.ColorMatrixI()) - ebitenutil.DebugPrint(gr, fmt.Sprintf("(%d, %d)", mx, my)) + ebitenutil.DebugPrint(r, fmt.Sprintf("(%d, %d)", mx, my)) return nil } diff --git a/example/perspective/main.go b/example/perspective/main.go index 908c263bc..ec06aa46c 100644 --- a/example/perspective/main.go +++ b/example/perspective/main.go @@ -32,7 +32,7 @@ type Game struct { gophersTexture *ebiten.Texture } -func (g *Game) Update(gr ebiten.GraphicsContext) error { +func (g *Game) Update(r ebiten.RenderTarget) error { parts := []ebiten.TexturePart{} w, h := g.gophersTexture.Size() for i := 0; i < h; i++ { @@ -48,7 +48,7 @@ func (g *Game) Update(gr ebiten.GraphicsContext) error { geo := ebiten.TranslateGeometry(-maxWidth/2, -float64(h)/2) geo.Concat(ebiten.ScaleGeometry(0.4, 0.4)) geo.Concat(ebiten.TranslateGeometry(screenWidth/2, screenHeight/2)) - gr.DrawTexture(g.gophersTexture, parts, geo, ebiten.ColorMatrixI()) + r.DrawTexture(g.gophersTexture, parts, geo, ebiten.ColorMatrixI()) return nil } diff --git a/gamecontext.go b/gamecontext.go index ad88bf0b2..a572d95de 100644 --- a/gamecontext.go +++ b/gamecontext.go @@ -48,7 +48,7 @@ func glFilter(f Filter) int { } // NewRenderTarget returns a new RenderTarget. -func NewRenderTarget(width, height int, filter Filter) (*RenderTarget, error) { +func NewRenderTarget(width, height int, filter Filter) (RenderTarget, error) { return currentUI.newRenderTarget(width, height, glFilter(filter)) } diff --git a/graphics.go b/graphics.go index 2dfc567fa..0f79a5dc0 100644 --- a/graphics.go +++ b/graphics.go @@ -18,7 +18,6 @@ package ebiten import ( "github.com/hajimehoshi/ebiten/internal/opengl" - "image/color" ) // A Rect represents a rectangle. @@ -36,22 +35,12 @@ type TexturePart struct { } // DrawWholeTexture draws the whole texture. -func DrawWholeTexture(g GraphicsContext, texture *Texture, geo GeometryMatrix, color ColorMatrix) error { +func DrawWholeTexture(r RenderTarget, texture *Texture, geo GeometryMatrix, color ColorMatrix) error { w, h := texture.Size() parts := []TexturePart{ {Rect{0, 0, float64(w), float64(h)}, Rect{0, 0, float64(w), float64(h)}}, } - return g.DrawTexture(texture, parts, geo, color) -} - -// A GraphicsContext is the interface that means a context of rendering. -type GraphicsContext interface { - Clear() error - Fill(clr color.Color) error - DrawTexture(texture *Texture, parts []TexturePart, geo GeometryMatrix, color ColorMatrix) error - // TODO: ScreenRenderTarget() Drawer - PushRenderTarget(id *RenderTarget) - PopRenderTarget() + return r.DrawTexture(texture, parts, geo, color) } // Filter represents the type of filter to be used when a texture is maginified or minified. @@ -72,19 +61,3 @@ type Texture struct { func (t *Texture) Size() (width int, height int) { return t.glTexture.Width(), t.glTexture.Height() } - -// RenderTarget represents a render target. -type RenderTarget struct { - glRenderTarget *opengl.RenderTarget - texture *Texture -} - -// Texture returns the texture of the render target. -func (r *RenderTarget) Texture() *Texture { - return r.texture -} - -// Size returns the size of the render target. -func (r *RenderTarget) Size() (width int, height int) { - return r.glRenderTarget.Width(), r.glRenderTarget.Height() -} diff --git a/graphicscontext.go b/graphicscontext.go index 2217df931..132dd0a37 100644 --- a/graphicscontext.go +++ b/graphicscontext.go @@ -19,7 +19,6 @@ package ebiten import ( "github.com/go-gl/gl" "github.com/hajimehoshi/ebiten/internal/opengl" - "image/color" ) func newGraphicsContext(screenWidth, screenHeight, screenScale int) (*graphicsContext, error) { @@ -28,32 +27,24 @@ func newGraphicsContext(screenWidth, screenHeight, screenScale int) (*graphicsCo return nil, err } - screen, err := idsInstance.createRenderTarget(screenWidth, screenHeight, gl.NEAREST) + screen, err := newRenderTarget(screenWidth, screenHeight, gl.NEAREST) if err != nil { return nil, err } c := &graphicsContext{ - currents: make([]*RenderTarget, 1), - defaultR: &RenderTarget{r, nil}, - screen: screen, - screenWidth: screenWidth, - screenHeight: screenHeight, - screenScale: screenScale, + defaultR: &renderTarget{r, nil}, + screen: screen, + screenScale: screenScale, } return c, nil } type graphicsContext struct { - screen *RenderTarget - defaultR *RenderTarget - currents []*RenderTarget - screenWidth int - screenHeight int - screenScale int + screen *renderTarget + defaultR *renderTarget + screenScale int } -var _ GraphicsContext = new(graphicsContext) - func (c *graphicsContext) dispose() { // NOTE: Now this method is not used anywhere. glRenderTarget := c.screen.glRenderTarget @@ -64,44 +55,20 @@ func (c *graphicsContext) dispose() { glTexture.Dispose() } -func (c *graphicsContext) Clear() error { - return c.Fill(color.RGBA{0, 0, 0, 0}) +func (c *graphicsContext) preUpdate() error { + return c.screen.Clear() } -func (c *graphicsContext) Fill(clr color.Color) error { - return idsInstance.fillRenderTarget(c.currents[len(c.currents)-1], clr) -} - -func (c *graphicsContext) DrawTexture(texture *Texture, parts []TexturePart, geo GeometryMatrix, color ColorMatrix) error { - current := c.currents[len(c.currents)-1] - return idsInstance.drawTexture(current, texture, parts, geo, color) -} - -func (c *graphicsContext) PushRenderTarget(renderTarget *RenderTarget) { - c.currents = append(c.currents, renderTarget) -} - -func (c *graphicsContext) PopRenderTarget() { - c.currents = c.currents[:len(c.currents)-1] -} - -func (c *graphicsContext) preUpdate() { - c.currents = c.currents[0:1] - c.currents[0] = c.defaultR - - c.PushRenderTarget(c.screen) - c.Clear() -} - -func (c *graphicsContext) postUpdate() { - c.PopRenderTarget() - +func (c *graphicsContext) postUpdate() error { // We don't need to clear the default render target (framebuffer). // For the default framebuffer, a special shader is used. scale := float64(c.screenScale) geo := ScaleGeometry(scale, scale) clr := ColorMatrixI() - DrawWholeTexture(c, c.screen.texture, geo, clr) + if err := DrawWholeTexture(c.defaultR, c.screen.texture, geo, clr); err != nil { + return err + } gl.Flush() + return nil } diff --git a/internal/opengl/rendertarget.go b/internal/opengl/rendertarget.go index 32c56b048..874f19782 100644 --- a/internal/opengl/rendertarget.go +++ b/internal/opengl/rendertarget.go @@ -73,16 +73,11 @@ func (r *RenderTarget) Height() int { return r.height } -func (r *RenderTarget) FlipY() bool { - return r.flipY -} - func (r *RenderTarget) Dispose() { r.framebuffer.Delete() } func createFramebuffer(nativeTexture gl.Texture) (gl.Framebuffer, error) { - // TODO: Does this affect the current rendering target? framebuffer := gl.GenFramebuffer() framebuffer.Bind() @@ -102,7 +97,10 @@ func (r *RenderTarget) SetAsViewport() error { r.framebuffer.Bind() err := gl.CheckFramebufferStatus(gl.FRAMEBUFFER) if err != gl.FRAMEBUFFER_COMPLETE { - return errors.New(fmt.Sprintf("glBindFramebuffer failed: %d", err)) + if gl.GetError() != 0 { + return errors.New(fmt.Sprintf("glBindFramebuffer failed: %d", gl.GetError())) + } + return errors.New("glBindFramebuffer failed: the context is different?") } width := internal.AdjustSizeForTexture(r.width) diff --git a/ids.go b/rendertarget.go similarity index 51% rename from ids.go rename to rendertarget.go index 0a024cbb7..d83707061 100644 --- a/ids.go +++ b/rendertarget.go @@ -25,72 +25,79 @@ import ( "math" ) -// ids manages the current render target to be used. -// TODO: Change this name. `ids` is not appropriate for now. -type ids struct { - currentRenderTarget *RenderTarget +// TODO: Rename +type RenderTarget interface { + Texture() *Texture + Size() (width, height int) + Clear() error + Fill(clr color.Color) error + DrawTexture(texture *Texture, parts []TexturePart, geo GeometryMatrix, color ColorMatrix) error } -var idsInstance = &ids{} +type renderTarget struct { + glRenderTarget *opengl.RenderTarget + texture *Texture +} -func (i *ids) createRenderTarget(width, height int, filter int) (*RenderTarget, error) { +func newRenderTarget(width, height int, filter int) (*renderTarget, error) { glTexture, err := opengl.NewTexture(width, height, filter) if err != nil { return nil, err } - // The current binded framebuffer can be changed. - i.currentRenderTarget = nil glRenderTarget, err := opengl.NewRenderTargetFromTexture(glTexture) if err != nil { return nil, err } texture := &Texture{glTexture} - // TODO: Is |texture| necessary? - renderTarget := &RenderTarget{glRenderTarget, texture} - i.fillRenderTarget(renderTarget, color.RGBA{0, 0, 0, 0}) - + renderTarget := &renderTarget{glRenderTarget, texture} return renderTarget, nil } -func (i *ids) fillRenderTarget(renderTarget *RenderTarget, clr color.Color) error { - if err := i.setViewportIfNeeded(renderTarget); err != nil { +func (r *renderTarget) Texture() *Texture { + return r.texture +} + +func (r *renderTarget) Size() (width, height int) { + return r.glRenderTarget.Width(), r.glRenderTarget.Height() +} + +func (r *renderTarget) Clear() error { + return r.Fill(color.RGBA{0, 0, 0, 0}) +} + +func (r *renderTarget) Fill(clr color.Color) error { + if err := r.glRenderTarget.SetAsViewport(); err != nil { return err } const max = math.MaxUint16 - r, g, b, a := clr.RGBA() - gl.ClearColor(gl.GLclampf(float64(r)/max), gl.GLclampf(float64(g)/max), gl.GLclampf(float64(b)/max), gl.GLclampf(float64(a)/max)) + cr, cg, cb, ca := clr.RGBA() + rf := gl.GLclampf(float64(cr) / max) + gf := gl.GLclampf(float64(cg) / max) + bf := gl.GLclampf(float64(cb) / max) + af := gl.GLclampf(float64(ca) / max) + gl.ClearColor(rf, gf, bf, af) gl.Clear(gl.COLOR_BUFFER_BIT) return nil } -func (i *ids) drawTexture(target *RenderTarget, texture *Texture, parts []TexturePart, geo GeometryMatrix, color ColorMatrix) error { - glTexture := texture.glTexture - if err := i.setViewportIfNeeded(target); err != nil { +func (r *renderTarget) DrawTexture(texture *Texture, parts []TexturePart, geo GeometryMatrix, color ColorMatrix) error { + if err := r.glRenderTarget.SetAsViewport(); err != nil { return err } - projectionMatrix := target.glRenderTarget.ProjectionMatrix() + glTexture := texture.glTexture quads := textureQuads(parts, glTexture.Width(), glTexture.Height()) - w, h := target.Size() targetNativeTexture := gl.Texture(0) - if target.texture != nil { - targetNativeTexture = target.texture.glTexture.Native() + if r.texture != nil { + targetNativeTexture = r.texture.glTexture.Native() } + w, h := r.Size() + projectionMatrix := r.glRenderTarget.ProjectionMatrix() shader.DrawTexture(glTexture.Native(), targetNativeTexture, w, h, projectionMatrix, quads, &geo, &color) return nil } -func (i *ids) setViewportIfNeeded(renderTarget *RenderTarget) error { - if i.currentRenderTarget != renderTarget { - if err := renderTarget.glRenderTarget.SetAsViewport(); err != nil { - return err - } - i.currentRenderTarget = renderTarget - } - return nil -} - func u(x float64, width int) float32 { return float32(x) / float32(internal.AdjustSizeForTexture(width)) } @@ -115,3 +122,41 @@ func textureQuads(parts []TexturePart, width, height int) []shader.TextureQuad { } return quads } + +type syncer interface { + Sync(func()) +} + +type syncRenderTarget struct { + syncer syncer + inner RenderTarget +} + +func (c *syncRenderTarget) Texture() *Texture { + return c.inner.Texture() +} + +func (c *syncRenderTarget) Size() (width, height int) { + return c.inner.Size() +} + +func (c *syncRenderTarget) Clear() (err error) { + c.syncer.Sync(func() { + err = c.inner.Clear() + }) + return +} + +func (c *syncRenderTarget) Fill(clr color.Color) (err error) { + c.syncer.Sync(func() { + err = c.inner.Fill(clr) + }) + return +} + +func (c *syncRenderTarget) DrawTexture(texture *Texture, parts []TexturePart, geo GeometryMatrix, color ColorMatrix) (err error) { + c.syncer.Sync(func() { + err = c.inner.DrawTexture(texture, parts, geo, color) + }) + return +} diff --git a/run.go b/run.go index f7e2386f3..f0a7ba450 100644 --- a/run.go +++ b/run.go @@ -18,7 +18,7 @@ package ebiten // Run runs the game. // This function must be called from the main thread. -func Run(f func(GraphicsContext) error, width, height, scale int, title string) error { +func Run(f func(RenderTarget) error, width, height, scale int, title string) error { err := startUI(width, height, scale, title) if err != nil { return err diff --git a/syncgraphicscontext.go b/syncgraphicscontext.go deleted file mode 100644 index daa63e78a..000000000 --- a/syncgraphicscontext.go +++ /dev/null @@ -1,65 +0,0 @@ -/* -Copyright 2014 Hajime Hoshi - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package ebiten - -import ( - "image/color" -) - -type syncer interface { - Sync(f func()) -} - -type syncGraphicsContext struct { - syncer syncer - innerGraphicsContext GraphicsContext -} - -var _ GraphicsContext = new(syncGraphicsContext) - -func (c *syncGraphicsContext) Clear() (err error) { - c.syncer.Sync(func() { - err = c.innerGraphicsContext.Clear() - }) - return -} - -func (c *syncGraphicsContext) Fill(clr color.Color) (err error) { - c.syncer.Sync(func() { - err = c.innerGraphicsContext.Fill(clr) - }) - return -} - -func (c *syncGraphicsContext) DrawTexture(texture *Texture, parts []TexturePart, geo GeometryMatrix, color ColorMatrix) (err error) { - c.syncer.Sync(func() { - err = c.innerGraphicsContext.DrawTexture(texture, parts, geo, color) - }) - return -} - -func (c *syncGraphicsContext) PopRenderTarget() { - c.syncer.Sync(func() { - c.innerGraphicsContext.PopRenderTarget() - }) -} - -func (c *syncGraphicsContext) PushRenderTarget(renderTarget *RenderTarget) { - c.syncer.Sync(func() { - c.innerGraphicsContext.PushRenderTarget(renderTarget) - }) -} diff --git a/ui.go b/ui.go index b2eda52ce..cebf7bb0b 100644 --- a/ui.go +++ b/ui.go @@ -110,18 +110,22 @@ func (u *ui) Sync(f func()) { u.use(f) } -func (u *ui) draw(f func(GraphicsContext) error) (err error) { +func (u *ui) draw(f func(RenderTarget) error) (err error) { u.use(func() { - u.graphicsContext.preUpdate() + err = u.graphicsContext.preUpdate() }) - if err = f(&syncGraphicsContext{ - syncer: u, - innerGraphicsContext: u.graphicsContext, - }); err != nil { + if err != nil { + return + } + err = f(&syncRenderTarget{syncer: u, inner: u.graphicsContext.screen}) + if err != nil { return } u.use(func() { - u.graphicsContext.postUpdate() + err = u.graphicsContext.postUpdate() + if err != nil { + return + } u.window.SwapBuffers() }) return @@ -140,13 +144,13 @@ func (u *ui) newTexture(img image.Image, filter int) (*Texture, error) { return texture, err } -func (u *ui) newRenderTarget(width, height int, filter int) (*RenderTarget, error) { - var renderTarget *RenderTarget +func (u *ui) newRenderTarget(width, height int, filter int) (RenderTarget, error) { + var renderTarget RenderTarget var err error u.use(func() { - renderTarget, err = idsInstance.createRenderTarget(width, height, filter) + renderTarget, err = newRenderTarget(width, height, filter) }) - return renderTarget, err + return &syncRenderTarget{u, renderTarget}, err } func (u *ui) run() {