From 0f8ac490557858116ca82a19da8fbef0c1609036 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Mon, 22 Dec 2014 10:36:42 +0900 Subject: [PATCH] Unify RenderTarget and Image into Image (#34) --- ebitenutil/debugprint.go | 18 ++++----- ebitenutil/image.go | 4 +- example/alphablending/main.go | 8 ++-- example/blocks/blocks/field.go | 2 +- example/blocks/blocks/font.go | 4 +- example/blocks/blocks/game.go | 2 +- example/blocks/blocks/gamescene.go | 2 +- example/blocks/blocks/images.go | 10 ++--- example/blocks/blocks/piece.go | 4 +- example/blocks/blocks/scenemanager.go | 8 ++-- example/blocks/blocks/titlescene.go | 6 +-- example/image/main.go | 6 ++- example/mosaic/main.go | 8 ++-- example/paint/main.go | 14 +++---- example/perspective/main.go | 2 +- gamecontext.go | 12 +++--- graphics.go | 17 +------- graphicscontext.go | 19 +++++---- rendertarget.go => image.go | 57 ++++++++++++--------------- internal/opengl/rendertarget.go | 21 +++++----- run.go | 5 ++- ui.go | 35 ++++++++++------ 22 files changed, 131 insertions(+), 133 deletions(-) rename rendertarget.go => image.go (65%) diff --git a/ebitenutil/debugprint.go b/ebitenutil/debugprint.go index b162732e9..778ec75e7 100644 --- a/ebitenutil/debugprint.go +++ b/ebitenutil/debugprint.go @@ -24,18 +24,18 @@ import ( ) type debugPrintState struct { - textTexture *ebiten.Image - debugPrintRenderTarget *ebiten.RenderTarget + textImage *ebiten.Image + debugPrintRenderTarget *ebiten.Image y int } var defaultDebugPrintState = new(debugPrintState) -func DebugPrint(r *ebiten.RenderTarget, str string) { +func DebugPrint(r *ebiten.Image, str string) { defaultDebugPrintState.DebugPrint(r, str) } -func (d *debugPrintState) drawText(rt *ebiten.RenderTarget, str string, x, y int, c color.Color) { +func (d *debugPrintState) drawText(rt *ebiten.Image, str string, x, y int, c color.Color) { parts := []ebiten.ImagePart{} locationX, locationY := 0, 0 for _, c := range str { @@ -57,16 +57,16 @@ func (d *debugPrintState) drawText(rt *ebiten.RenderTarget, str string, x, y int geo := ebiten.TranslateGeometry(float64(x)+1, float64(y)) r, g, b, a := internal.RGBA(c) clr := ebiten.ScaleColor(r, g, b, a) - rt.DrawImage(d.textTexture, parts, geo, clr) + rt.DrawImage(d.textImage, parts, geo, clr) } -func (d *debugPrintState) DebugPrint(r *ebiten.RenderTarget, str string) { - if d.textTexture == nil { +func (d *debugPrintState) DebugPrint(r *ebiten.Image, str string) { + if d.textImage == nil { img, err := assets.TextImage() if err != nil { panic(err) } - d.textTexture, err = ebiten.NewImage(img, ebiten.FilterNearest) + d.textImage, err = ebiten.NewImageFromImage(img, ebiten.FilterNearest) if err != nil { panic(err) } @@ -74,7 +74,7 @@ func (d *debugPrintState) DebugPrint(r *ebiten.RenderTarget, str string) { if d.debugPrintRenderTarget == nil { width, height := 256, 256 var err error - d.debugPrintRenderTarget, err = ebiten.NewRenderTarget(width, height, ebiten.FilterNearest) + d.debugPrintRenderTarget, err = ebiten.NewImage(width, height, ebiten.FilterNearest) if err != nil { panic(err) } diff --git a/ebitenutil/image.go b/ebitenutil/image.go index f20def0a1..fe8d00939 100644 --- a/ebitenutil/image.go +++ b/ebitenutil/image.go @@ -32,9 +32,9 @@ func NewImageFromFile(path string, filter ebiten.Filter) (*ebiten.Image, image.I if err != nil { return nil, nil, err } - texture, err := ebiten.NewImage(img, filter) + img2, err := ebiten.NewImageFromImage(img, filter) if err != nil { return nil, nil, err } - return texture, img, err + return img2, img, err } diff --git a/example/alphablending/main.go b/example/alphablending/main.go index fc231af7a..f87a2c5e3 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.Image ebitenImage *ebiten.Image } -func (g *Game) Update(r *ebiten.RenderTarget) error { +func (g *Game) Update(r *ebiten.Image) error { g.count++ g.count %= 600 diff := float64(g.count) * 0.2 @@ -62,7 +62,7 @@ func (g *Game) Update(r *ebiten.RenderTarget) error { for i := 0; i < 10; i++ { geo := ebiten.TranslateGeometry(0, float64(i)*(diff)) clr := ebiten.ColorMatrixI() - if err := ebiten.DrawWholeImage(r, g.tmpRenderTarget.Image(), geo, clr); err != nil { + if err := ebiten.DrawWholeImage(r, g.tmpRenderTarget, geo, clr); err != nil { return err } } @@ -76,7 +76,7 @@ func main() { if err != nil { log.Fatal(err) } - g.tmpRenderTarget, err = ebiten.NewRenderTarget(screenWidth, screenHeight, ebiten.FilterNearest) + g.tmpRenderTarget, err = ebiten.NewImage(screenWidth, screenHeight, ebiten.FilterNearest) if err != nil { log.Fatal(err) } diff --git a/example/blocks/blocks/field.go b/example/blocks/blocks/field.go index e8427673b..56856ab3d 100644 --- a/example/blocks/blocks/field.go +++ b/example/blocks/blocks/field.go @@ -112,7 +112,7 @@ func (f *Field) flushLine(j int) bool { return true } -func (f *Field) Draw(r *ebiten.RenderTarget, images *Images, geo ebiten.GeometryMatrix) { +func (f *Field) Draw(r *ebiten.Image, images *Images, geo ebiten.GeometryMatrix) { blocks := make([][]BlockType, len(f.blocks)) for i, blockCol := range f.blocks { blocks[i] = make([]BlockType, len(blockCol)) diff --git a/example/blocks/blocks/font.go b/example/blocks/blocks/font.go index 8611d8f4d..8897ce10b 100644 --- a/example/blocks/blocks/font.go +++ b/example/blocks/blocks/font.go @@ -33,7 +33,7 @@ func textWidth(str string) int { return charWidth * len(str) } -func drawText(rt *ebiten.RenderTarget, images *Images, str string, ox, oy, scale int, c color.Color) { +func drawText(rt *ebiten.Image, images *Images, str string, ox, oy, scale int, c color.Color) { fontImageId := images.GetImage("font") parts := []ebiten.ImagePart{} @@ -66,7 +66,7 @@ func drawText(rt *ebiten.RenderTarget, images *Images, str string, ox, oy, scale rt.DrawImage(fontImageId, parts, geo, clr) } -func drawTextWithShadow(rt *ebiten.RenderTarget, images *Images, str string, x, y, scale int, clr color.Color) { +func drawTextWithShadow(rt *ebiten.Image, images *Images, str string, x, y, scale int, clr color.Color) { drawText(rt, images, str, x+1, y+1, scale, color.NRGBA{0, 0, 0, 0x80}) drawText(rt, images, str, x, y, scale, clr) } diff --git a/example/blocks/blocks/game.go b/example/blocks/blocks/game.go index 80bf0ce6e..c1094d434 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(r *ebiten.RenderTarget) error { +func (game *Game) Update(r *ebiten.Image) error { game.once.Do(func() { game.images = NewImages() for name, path := range imagePaths { diff --git a/example/blocks/blocks/gamescene.go b/example/blocks/blocks/gamescene.go index c4a5eb3a8..2f4db9be8 100644 --- a/example/blocks/blocks/gamescene.go +++ b/example/blocks/blocks/gamescene.go @@ -109,7 +109,7 @@ func (s *GameScene) Update(state *GameState) { } } -func (s *GameScene) Draw(r *ebiten.RenderTarget, images *Images) { +func (s *GameScene) Draw(r *ebiten.Image, images *Images) { r.Fill(color.White) field := images.GetImage("empty") diff --git a/example/blocks/blocks/images.go b/example/blocks/blocks/images.go index dc159eced..1627f060e 100644 --- a/example/blocks/blocks/images.go +++ b/example/blocks/blocks/images.go @@ -38,7 +38,7 @@ type Images struct { imagePaths chan namePath renderTargetSizes chan nameSize images map[string]*ebiten.Image - renderTargets map[string]*ebiten.RenderTarget + renderTargets map[string]*ebiten.Image sync.RWMutex } @@ -47,7 +47,7 @@ func NewImages() *Images { imagePaths: make(chan namePath), renderTargetSizes: make(chan nameSize), images: map[string]*ebiten.Image{}, - renderTargets: map[string]*ebiten.RenderTarget{}, + renderTargets: map[string]*ebiten.Image{}, } go func() { for { @@ -81,7 +81,7 @@ func (i *Images) loopMain() { if err != nil { panic(err) } - id, err := ebiten.NewImage(img, ebiten.FilterNearest) + id, err := ebiten.NewImageFromImage(img, ebiten.FilterNearest) if err != nil { panic(err) } @@ -93,7 +93,7 @@ func (i *Images) loopMain() { name := s.name size := s.size go func() { - id, err := ebiten.NewRenderTarget(size.Width, size.Height, ebiten.FilterNearest) + id, err := ebiten.NewImage(size.Width, size.Height, ebiten.FilterNearest) if err != nil { panic(err) } @@ -129,7 +129,7 @@ func (i *Images) GetImage(name string) *ebiten.Image { return i.images[name] } -func (i *Images) GetRenderTarget(name string) *ebiten.RenderTarget { +func (i *Images) GetRenderTarget(name string) *ebiten.Image { i.RLock() defer i.RUnlock() return i.renderTargets[name] diff --git a/example/blocks/blocks/piece.go b/example/blocks/blocks/piece.go index 36652886e..fb6c3ff10 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(r *ebiten.RenderTarget, images *Images, blocks [][]BlockType, geo ebiten.GeometryMatrix) { +func drawBlocks(r *ebiten.Image, images *Images, blocks [][]BlockType, geo ebiten.GeometryMatrix) { parts := []ebiten.ImagePart{} for i, blockCol := range blocks { for j, block := range blockCol { @@ -213,7 +213,7 @@ func (p *Piece) AbsorbInto(field *Field, x, y int, angle Angle) { } } -func (p *Piece) Draw(r *ebiten.RenderTarget, images *Images, fieldX, fieldY int, pieceX, pieceY int, angle Angle) { +func (p *Piece) Draw(r *ebiten.Image, images *Images, fieldX, fieldY int, pieceX, pieceY int, angle Angle) { size := len(p.blocks) blocks := make([][]BlockType, size) for i := range p.blocks { diff --git a/example/blocks/blocks/scenemanager.go b/example/blocks/blocks/scenemanager.go index 33d3ae040..36682b657 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(r *ebiten.RenderTarget, images *Images) + Draw(r *ebiten.Image, images *Images) } const transitionMaxCount = 20 @@ -60,7 +60,7 @@ func (s *SceneManager) Update(state *GameState) { } } -func (s *SceneManager) Draw(r *ebiten.RenderTarget, images *Images) { +func (s *SceneManager) Draw(r *ebiten.Image, images *Images) { if s.transitionCount == -1 { s.current.Draw(r, images) return @@ -74,11 +74,11 @@ func (s *SceneManager) Draw(r *ebiten.RenderTarget, images *Images) { s.next.Draw(to, images) color := ebiten.ColorMatrixI() - ebiten.DrawWholeImage(r, from.Image(), ebiten.GeometryMatrixI(), color) + ebiten.DrawWholeImage(r, from, ebiten.GeometryMatrixI(), color) alpha := float64(s.transitionCount) / float64(transitionMaxCount) color.Elements[3][3] = alpha - ebiten.DrawWholeImage(r, to.Image(), ebiten.GeometryMatrixI(), color) + ebiten.DrawWholeImage(r, to, ebiten.GeometryMatrixI(), color) } func (s *SceneManager) GoTo(scene Scene) { diff --git a/example/blocks/blocks/titlescene.go b/example/blocks/blocks/titlescene.go index e79ace295..cb0f54481 100644 --- a/example/blocks/blocks/titlescene.go +++ b/example/blocks/blocks/titlescene.go @@ -40,7 +40,7 @@ func (s *TitleScene) Update(state *GameState) { } } -func (s *TitleScene) Draw(r *ebiten.RenderTarget, images *Images) { +func (s *TitleScene) Draw(r *ebiten.Image, images *Images) { drawTitleBackground(r, images, s.count) drawLogo(r, images, "BLOCKS") @@ -50,7 +50,7 @@ func (s *TitleScene) Draw(r *ebiten.RenderTarget, images *Images) { drawTextWithShadow(r, images, message, x, y, 1, color.NRGBA{0x80, 0, 0, 0xff}) } -func drawTitleBackground(r *ebiten.RenderTarget, images *Images, c int) { +func drawTitleBackground(r *ebiten.Image, images *Images, c int) { const imageWidth = 32 const imageHeight = 32 @@ -73,7 +73,7 @@ func drawTitleBackground(r *ebiten.RenderTarget, images *Images, c int) { r.DrawImage(backgroundImage, parts, geo, clr) } -func drawLogo(r *ebiten.RenderTarget, images *Images, str string) { +func drawLogo(r *ebiten.Image, images *Images, str string) { scale := 4 textWidth := textWidth(str) * scale x := (ScreenWidth - textWidth) / 2 diff --git a/example/image/main.go b/example/image/main.go index f21bfc6dc..d8b0f02d0 100644 --- a/example/image/main.go +++ b/example/image/main.go @@ -36,7 +36,7 @@ type Game struct { gophersImage *ebiten.Image } -func (g *Game) Update(r *ebiten.RenderTarget) error { +func (g *Game) Update(r *ebiten.Image) error { g.count++ if ebiten.IsKeyPressed(ebiten.KeyLeft) { g.horizontalCount-- @@ -60,7 +60,9 @@ func (g *Game) Update(r *ebiten.RenderTarget) error { geo.Concat(ebiten.TranslateGeometry(screenWidth/2, screenHeight/2)) //clr := ebiten.RotateHue(float64(g.count%180) * 2 * math.Pi / 180) clr := ebiten.ColorMatrixI() - ebiten.DrawWholeImage(r, g.gophersImage, geo, clr) + if err := ebiten.DrawWholeImage(r, g.gophersImage, geo, clr); err != nil { + return err + } return nil } diff --git a/example/mosaic/main.go b/example/mosaic/main.go index 378d4ab24..3957ad7d7 100644 --- a/example/mosaic/main.go +++ b/example/mosaic/main.go @@ -32,15 +32,15 @@ const mosaicRatio = 16 type Game struct { gophersImage *ebiten.Image - gophersRenderTarget *ebiten.RenderTarget + gophersRenderTarget *ebiten.Image } -func (g *Game) Update(r *ebiten.RenderTarget) error { +func (g *Game) Update(r *ebiten.Image) error { geo := ebiten.ScaleGeometry(1.0/mosaicRatio, 1.0/mosaicRatio) ebiten.DrawWholeImage(g.gophersRenderTarget, g.gophersImage, geo, ebiten.ColorMatrixI()) geo = ebiten.ScaleGeometry(mosaicRatio/2.0, mosaicRatio/2.0) - ebiten.DrawWholeImage(r, g.gophersRenderTarget.Image(), geo, ebiten.ColorMatrixI()) + ebiten.DrawWholeImage(r, g.gophersRenderTarget, geo, ebiten.ColorMatrixI()) return nil } @@ -52,7 +52,7 @@ func main() { log.Fatal(err) } w, h := g.gophersImage.Size() - g.gophersRenderTarget, err = ebiten.NewRenderTarget(w/mosaicRatio, h/mosaicRatio, ebiten.FilterNearest) + g.gophersRenderTarget, err = ebiten.NewImage(w/mosaicRatio, h/mosaicRatio, ebiten.FilterNearest) if err != nil { log.Fatal(err) } diff --git a/example/paint/main.go b/example/paint/main.go index c834be56d..fb7fe0761 100644 --- a/example/paint/main.go +++ b/example/paint/main.go @@ -33,11 +33,11 @@ const ( type Game struct { inited bool count int - brushRenderTarget *ebiten.RenderTarget - canvasRenderTarget *ebiten.RenderTarget + brushRenderTarget *ebiten.Image + canvasRenderTarget *ebiten.Image } -func (g *Game) Update(r *ebiten.RenderTarget) error { +func (g *Game) Update(r *ebiten.Image) error { if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) { g.count++ } @@ -54,10 +54,10 @@ func (g *Game) Update(r *ebiten.RenderTarget) error { clr := ebiten.ScaleColor(1.0, 0.25, 0.25, 1.0) theta := 2.0 * math.Pi * float64(g.count%60) / 60.0 clr.Concat(ebiten.RotateHue(theta)) - ebiten.DrawWholeImage(g.canvasRenderTarget, g.brushRenderTarget.Image(), geo, clr) + ebiten.DrawWholeImage(g.canvasRenderTarget, g.brushRenderTarget, geo, clr) } - ebiten.DrawWholeImage(r, g.canvasRenderTarget.Image(), ebiten.GeometryMatrixI(), ebiten.ColorMatrixI()) + ebiten.DrawWholeImage(r, g.canvasRenderTarget, ebiten.GeometryMatrixI(), ebiten.ColorMatrixI()) ebitenutil.DebugPrint(r, fmt.Sprintf("(%d, %d)", mx, my)) return nil @@ -66,11 +66,11 @@ func (g *Game) Update(r *ebiten.RenderTarget) error { func main() { g := new(Game) var err error - g.brushRenderTarget, err = ebiten.NewRenderTarget(1, 1, ebiten.FilterNearest) + g.brushRenderTarget, err = ebiten.NewImage(1, 1, ebiten.FilterNearest) if err != nil { log.Fatal(err) } - g.canvasRenderTarget, err = ebiten.NewRenderTarget(screenWidth, screenHeight, ebiten.FilterNearest) + g.canvasRenderTarget, err = ebiten.NewImage(screenWidth, screenHeight, ebiten.FilterNearest) if err != nil { log.Fatal(err) } diff --git a/example/perspective/main.go b/example/perspective/main.go index 98b0c21d4..83f155492 100644 --- a/example/perspective/main.go +++ b/example/perspective/main.go @@ -32,7 +32,7 @@ type Game struct { gophersImage *ebiten.Image } -func (g *Game) Update(r *ebiten.RenderTarget) error { +func (g *Game) Update(r *ebiten.Image) error { parts := []ebiten.ImagePart{} w, h := g.gophersImage.Size() for i := 0; i < h; i++ { diff --git a/gamecontext.go b/gamecontext.go index b993f9dcc..1abd61dd5 100644 --- a/gamecontext.go +++ b/gamecontext.go @@ -47,12 +47,12 @@ func glFilter(f Filter) int { } } -// NewRenderTarget returns a new RenderTarget. -func NewRenderTarget(width, height int, filter Filter) (*RenderTarget, error) { - return currentUI.newRenderTarget(width, height, glFilter(filter)) +// NewImage returns an empty image. +func NewImage(width, height int, filter Filter) (*Image, error) { + return currentUI.newImage(width, height, glFilter(filter)) } -// NewImage returns a new image. -func NewImage(img image.Image, filter Filter) (*Image, error) { - return currentUI.newImage(img, glFilter(filter)) +// NewImage creates a new image with the given image (img). +func NewImageFromImage(img image.Image, filter Filter) (*Image, error) { + return currentUI.newImageFromImage(img, glFilter(filter)) } diff --git a/graphics.go b/graphics.go index 9f0168ac4..70acb961e 100644 --- a/graphics.go +++ b/graphics.go @@ -16,10 +16,6 @@ limitations under the License. package ebiten -import ( - "github.com/hajimehoshi/ebiten/internal/opengl" -) - // A Rect represents a rectangle. type Rect struct { X float64 @@ -35,7 +31,7 @@ type ImagePart struct { } // DrawWholeImage draws the whole image. -func DrawWholeImage(r *RenderTarget, image *Image, geo GeometryMatrix, color ColorMatrix) error { +func DrawWholeImage(r *Image, image *Image, geo GeometryMatrix, color ColorMatrix) error { w, h := image.Size() parts := []ImagePart{ {Rect{0, 0, float64(w), float64(h)}, Rect{0, 0, float64(w), float64(h)}}, @@ -51,14 +47,3 @@ const ( FilterNearest Filter = iota FilterLinear ) - -// An Image represents an image to be rendered. -// An image's pixels are stored as non alpha-premultiplied. -type Image struct { - glTexture *opengl.Texture -} - -// Size returns the size of the image. -func (i *Image) Size() (width int, height int) { - return i.glTexture.Size() -} diff --git a/graphicscontext.go b/graphicscontext.go index 67d40c554..53926bec4 100644 --- a/graphicscontext.go +++ b/graphicscontext.go @@ -27,12 +27,17 @@ func newGraphicsContext(screenWidth, screenHeight, screenScale int) (*graphicsCo return nil, err } - screen, err := newInnerRenderTarget(screenWidth, screenHeight, gl.NEAREST) + texture, err := opengl.NewTexture(screenWidth, screenHeight, gl.NEAREST) if err != nil { return nil, err } + screen, err := newInnerImage(texture, gl.NEAREST) + if err != nil { + return nil, err + } + c := &graphicsContext{ - defaultR: &innerRenderTarget{r, nil}, + defaultR: &innerImage{r, nil}, screen: screen, screenScale: screenScale, } @@ -40,15 +45,15 @@ func newGraphicsContext(screenWidth, screenHeight, screenScale int) (*graphicsCo } type graphicsContext struct { - screen *innerRenderTarget - defaultR *innerRenderTarget + screen *innerImage + defaultR *innerImage screenScale int } func (c *graphicsContext) dispose() { // NOTE: Now this method is not used anywhere. glRenderTarget := c.screen.glRenderTarget - glTexture := c.screen.image.glTexture + glTexture := c.screen.glTexture glRenderTarget.Dispose() glTexture.Dispose() @@ -64,11 +69,11 @@ func (c *graphicsContext) postUpdate() error { scale := float64(c.screenScale) geo := ScaleGeometry(scale, scale) clr := ColorMatrixI() - w, h := c.screen.image.Size() + w, h := c.screen.size() parts := []ImagePart{ {Rect{0, 0, float64(w), float64(h)}, Rect{0, 0, float64(w), float64(h)}}, } - if err := c.defaultR.DrawImage(c.screen.image, parts, geo, clr); err != nil { + if err := c.defaultR.drawImage(c.screen, parts, geo, clr); err != nil { return err } diff --git a/rendertarget.go b/image.go similarity index 65% rename from rendertarget.go rename to image.go index bd728e59f..71cd842ef 100644 --- a/rendertarget.go +++ b/image.go @@ -24,35 +24,29 @@ import ( "image/color" ) -type innerRenderTarget struct { - glRenderTarget *opengl.RenderTarget - image *Image +type innerImage struct { + // TODO: Rename them later. + glRenderTarget *opengl.Image + glTexture *opengl.Texture } -func newInnerRenderTarget(width, height int, filter int) (*innerRenderTarget, error) { - glTexture, err := opengl.NewTexture(width, height, filter) - if err != nil { - return nil, err - } - +func newInnerImage(glTexture *opengl.Texture, filter int) (*innerImage, error) { glRenderTarget, err := opengl.NewRenderTargetFromTexture(glTexture) if err != nil { return nil, err } - - image := &Image{glTexture} - return &innerRenderTarget{glRenderTarget, image}, nil + return &innerImage{glRenderTarget, glTexture}, nil } -func (r *innerRenderTarget) size() (width, height int) { +func (r *innerImage) size() (width, height int) { return r.glRenderTarget.Size() } -func (r *innerRenderTarget) Clear() error { +func (r *innerImage) Clear() error { return r.Fill(color.Transparent) } -func (r *innerRenderTarget) Fill(clr color.Color) error { +func (r *innerImage) Fill(clr color.Color) error { if err := r.glRenderTarget.SetAsViewport(); err != nil { return err } @@ -62,20 +56,19 @@ func (r *innerRenderTarget) Fill(clr color.Color) error { return nil } -func (r *innerRenderTarget) DrawImage(image *Image, parts []ImagePart, geo GeometryMatrix, color ColorMatrix) error { +func (r *innerImage) drawImage(image *innerImage, parts []ImagePart, geo GeometryMatrix, color ColorMatrix) error { if err := r.glRenderTarget.SetAsViewport(); err != nil { return err } - glTexture := image.glTexture - w, h := glTexture.Size() + w, h := image.glTexture.Size() quads := textureQuads(parts, w, h) targetNativeTexture := gl.Texture(0) - if r.image != nil { - targetNativeTexture = r.image.glTexture.Native() + if r.glTexture != nil { + targetNativeTexture = r.glTexture.Native() } w2, h2 := r.size() projectionMatrix := r.glRenderTarget.ProjectionMatrix() - shader.DrawTexture(glTexture.Native(), targetNativeTexture, w2, h2, projectionMatrix, quads, &geo, &color) + shader.DrawTexture(image.glTexture.Native(), targetNativeTexture, w2, h2, projectionMatrix, quads, &geo, &color) return nil } @@ -108,36 +101,36 @@ type syncer interface { Sync(func()) } -type RenderTarget struct { +type Image struct { syncer syncer - inner *innerRenderTarget + inner *innerImage } -func (r *RenderTarget) Image() *Image { - return r.inner.image -} - -func (r *RenderTarget) Size() (width, height int) { +func (r *Image) Size() (width, height int) { return r.inner.size() } -func (r *RenderTarget) Clear() (err error) { +func (r *Image) Clear() (err error) { r.syncer.Sync(func() { err = r.inner.Clear() }) return } -func (r *RenderTarget) Fill(clr color.Color) (err error) { +func (r *Image) Fill(clr color.Color) (err error) { r.syncer.Sync(func() { err = r.inner.Fill(clr) }) return } -func (r *RenderTarget) DrawImage(image *Image, parts []ImagePart, geo GeometryMatrix, color ColorMatrix) (err error) { +func (r *Image) DrawImage(image *Image, parts []ImagePart, geo GeometryMatrix, color ColorMatrix) (err error) { + return r.drawImage(image.inner, parts, geo, color) +} + +func (r *Image) drawImage(image *innerImage, parts []ImagePart, geo GeometryMatrix, color ColorMatrix) (err error) { r.syncer.Sync(func() { - err = r.inner.DrawImage(image, parts, geo, color) + err = r.inner.drawImage(image, parts, geo, color) }) return } diff --git a/internal/opengl/rendertarget.go b/internal/opengl/rendertarget.go index dd1a0933c..3eddc5fef 100644 --- a/internal/opengl/rendertarget.go +++ b/internal/opengl/rendertarget.go @@ -37,15 +37,15 @@ func orthoProjectionMatrix(left, right, bottom, top int) [4][4]float64 { } } -type RenderTarget struct { +type Image struct { framebuffer gl.Framebuffer width int height int flipY bool } -func NewZeroRenderTarget(width, height int) (*RenderTarget, error) { - r := &RenderTarget{ +func NewZeroRenderTarget(width, height int) (*Image, error) { + r := &Image{ width: width, height: height, flipY: true, @@ -53,24 +53,24 @@ func NewZeroRenderTarget(width, height int) (*RenderTarget, error) { return r, nil } -func NewRenderTargetFromTexture(texture *Texture) (*RenderTarget, error) { +func NewRenderTargetFromTexture(texture *Texture) (*Image, error) { framebuffer, err := createFramebuffer(texture.Native()) if err != nil { return nil, err } w, h := texture.Size() - return &RenderTarget{ + return &Image{ framebuffer: framebuffer, width: w, height: h, }, nil } -func (r *RenderTarget) Size() (width, height int) { +func (r *Image) Size() (width, height int) { return r.width, r.height } -func (r *RenderTarget) Dispose() { +func (r *Image) Dispose() { r.framebuffer.Delete() } @@ -83,13 +83,10 @@ func createFramebuffer(nativeTexture gl.Texture) (gl.Framebuffer, error) { return 0, errors.New("creating framebuffer failed") } - gl.ClearColor(0, 0, 0, 0) - gl.Clear(gl.COLOR_BUFFER_BIT) - return framebuffer, nil } -func (r *RenderTarget) SetAsViewport() error { +func (r *Image) SetAsViewport() error { gl.Flush() r.framebuffer.Bind() err := gl.CheckFramebufferStatus(gl.FRAMEBUFFER) @@ -106,7 +103,7 @@ func (r *RenderTarget) SetAsViewport() error { return nil } -func (r *RenderTarget) ProjectionMatrix() [4][4]float64 { +func (r *Image) ProjectionMatrix() [4][4]float64 { width := internal.NextPowerOf2Int(r.width) height := internal.NextPowerOf2Int(r.height) m := orthoProjectionMatrix(0, width, 0, height) diff --git a/run.go b/run.go index 7a48532fa..b3c344862 100644 --- a/run.go +++ b/run.go @@ -17,8 +17,11 @@ limitations under the License. package ebiten // Run runs the game. +// f is a function which is called at every frame. +// The argument (*Image) is the render target that represents the screen. +// // This function must be called from the main thread. -func Run(f func(*RenderTarget) error, width, height, scale int, title string) error { +func Run(f func(*Image) error, width, height, scale int, title string) error { err := startUI(width, height, scale, title) if err != nil { return err diff --git a/ui.go b/ui.go index a3ea90714..3eed25cb4 100644 --- a/ui.go +++ b/ui.go @@ -110,14 +110,14 @@ func (u *ui) Sync(f func()) { u.use(f) } -func (u *ui) draw(f func(*RenderTarget) error) (err error) { +func (u *ui) draw(f func(*Image) error) (err error) { u.use(func() { err = u.graphicsContext.preUpdate() }) if err != nil { return } - err = f(&RenderTarget{syncer: u, inner: u.graphicsContext.screen}) + err = f(&Image{syncer: u, inner: u.graphicsContext.screen}) if err != nil { return } @@ -131,26 +131,39 @@ func (u *ui) draw(f func(*RenderTarget) error) (err error) { return } -func (u *ui) newImage(img image.Image, filter int) (*Image, error) { - var i *Image +func (u *ui) newImageFromImage(img image.Image, filter int) (*Image, error) { + var innerImage *innerImage var err error u.use(func() { - glTexture, err := opengl.NewTextureFromImage(img, filter) + var texture *opengl.Texture + texture, err = opengl.NewTextureFromImage(img, filter) if err != nil { return } - i = &Image{glTexture} + innerImage, err = newInnerImage(texture, filter) }) - return i, err + if err != nil { + return nil, err + } + return &Image{u, innerImage}, nil } -func (u *ui) newRenderTarget(width, height int, filter int) (*RenderTarget, error) { - var innerRenderTarget *innerRenderTarget +func (u *ui) newImage(width, height int, filter int) (*Image, error) { + var innerImage *innerImage var err error u.use(func() { - innerRenderTarget, err = newInnerRenderTarget(width, height, filter) + var texture *opengl.Texture + texture, err = opengl.NewTexture(width, height, filter) + if err != nil { + return + } + innerImage, err = newInnerImage(texture, filter) + innerImage.Clear() }) - return &RenderTarget{u, innerRenderTarget}, err + if err != nil { + return nil, err + } + return &Image{u, innerImage}, nil } func (u *ui) run() {