Remove GraphicsContext; Add rendering methods to RenderTarget (#26)

This commit is contained in:
Hajime Hoshi 2014-12-20 20:54:14 +09:00
parent d4cd858eeb
commit 01e0d42451
22 changed files with 190 additions and 275 deletions

View File

@ -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})
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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) {

View File

@ -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]

View File

@ -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})
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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))
}

View File

@ -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()
}

View File

@ -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},
defaultR: &renderTarget{r, nil},
screen: screen,
screenWidth: screenWidth,
screenHeight: screenHeight,
screenScale: screenScale,
}
return c, nil
}
type graphicsContext struct {
screen *RenderTarget
defaultR *RenderTarget
currents []*RenderTarget
screenWidth int
screenHeight 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
}

View File

@ -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)

View File

@ -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 {
func (r *renderTarget) DrawTexture(texture *Texture, parts []TexturePart, geo GeometryMatrix, color ColorMatrix) error {
if err := r.glRenderTarget.SetAsViewport(); err != nil {
return err
}
glTexture := texture.glTexture
if err := i.setViewportIfNeeded(target); err != nil {
return err
}
projectionMatrix := target.glRenderTarget.ProjectionMatrix()
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
}

2
run.go
View File

@ -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

View File

@ -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)
})
}

26
ui.go
View File

@ -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() {