Add graphics.RenderTarget

This commit is contained in:
Hajime Hoshi 2013-10-12 01:29:19 +09:00
parent e6680eeda9
commit 86eb30c650
5 changed files with 90 additions and 55 deletions

View File

@ -31,9 +31,9 @@ import (
) )
type Rects struct { type Rects struct {
rectTexture graphics.Texture rectTexture graphics.RenderTarget
rectTextureInited bool rectTextureInited bool
offscreen graphics.Texture offscreen graphics.RenderTarget
offscreenInited bool offscreenInited bool
rectBounds *graphics.Rect rectBounds *graphics.Rect
rectColor *color.RGBA rectColor *color.RGBA
@ -49,8 +49,8 @@ func New() *Rects {
} }
func (game *Rects) Init(tf graphics.TextureFactory) { func (game *Rects) Init(tf graphics.TextureFactory) {
game.rectTexture = tf.NewTexture(16, 16) game.rectTexture = tf.NewRenderTarget(16, 16)
game.offscreen = tf.NewTexture(256, 240) game.offscreen = tf.NewRenderTarget(256, 240)
} }
func (game *Rects) Update(context ebiten.GameContext) { func (game *Rects) Update(context ebiten.GameContext) {
@ -104,12 +104,12 @@ func (game *Rects) Draw(g graphics.Context) {
g.Fill(&color.RGBA{0, 0, 0, 255}) g.Fill(&color.RGBA{0, 0, 0, 255})
game.offscreenInited = true game.offscreenInited = true
} }
g.DrawTexture(game.rectTexture.ID(), g.DrawTexture(game.rectTexture.Texture().ID(),
game.rectGeometryMatrix(), game.rectGeometryMatrix(),
game.rectColorMatrix()) game.rectColorMatrix())
g.SetOffscreen(g.Screen().ID()) g.SetOffscreen(g.Screen().ID())
g.DrawTexture(game.offscreen.ID(), g.DrawTexture(game.offscreen.Texture().ID(),
matrix.IdentityGeometry(), matrix.IdentityGeometry(),
matrix.IdentityColor()) matrix.IdentityColor())
} }

View File

@ -40,7 +40,7 @@ type TexturePart struct {
} }
type Context interface { type Context interface {
Screen() Texture Screen() RenderTarget
Clear() Clear()
Fill(clr color.Color) Fill(clr color.Color)
DrawTexture(textureID TextureID, DrawTexture(textureID TextureID,
@ -50,11 +50,11 @@ type Context interface {
parts []TexturePart, parts []TexturePart,
geometryMatrix matrix.Geometry, geometryMatrix matrix.Geometry,
colorMatrix matrix.Color) colorMatrix matrix.Color)
SetOffscreen(textureID TextureID) SetOffscreen(renderTargetID RenderTargetID)
} }
type TextureFactory interface { type TextureFactory interface {
NewTexture(width, height int) Texture NewRenderTarget(width, height int) RenderTarget
NewTextureFromImage(img image.Image) (Texture, error) NewTextureFromImage(img image.Image) (Texture, error)
} }
@ -65,3 +65,13 @@ type Texture interface {
} }
type TextureID int type TextureID int
type RenderTarget interface {
Texture() Texture
ID() RenderTargetID
Width() int
Height() int
}
type RenderTargetID int

View File

@ -36,13 +36,13 @@ import (
) )
type Context struct { type Context struct {
screen *Texture screen *RenderTarget
screenWidth int screenWidth int
screenHeight int screenHeight int
screenScale int screenScale int
textures map[graphics.TextureID]*Texture textures map[C.GLuint]*Texture
currentOffscreen *Texture currentOffscreen *RenderTarget
mainFramebufferTexture *Texture mainFramebufferTexture *RenderTarget
} }
func newContext(screenWidth, screenHeight, screenScale int) *Context { func newContext(screenWidth, screenHeight, screenScale int) *Context {
@ -50,28 +50,29 @@ func newContext(screenWidth, screenHeight, screenScale int) *Context {
screenWidth: screenWidth, screenWidth: screenWidth,
screenHeight: screenHeight, screenHeight: screenHeight,
screenScale: screenScale, screenScale: screenScale,
textures: map[graphics.TextureID]*Texture{}, textures: map[C.GLuint]*Texture{},
} }
return context return context
} }
func (context *Context) Init() { func (context *Context) Init() {
// main framebuffer should be created sooner than any other framebuffers! // The main framebuffer should be created sooner than any other
// framebuffers!
mainFramebuffer := C.GLint(0) mainFramebuffer := C.GLint(0)
C.glGetIntegerv(C.GL_FRAMEBUFFER_BINDING, &mainFramebuffer) C.glGetIntegerv(C.GL_FRAMEBUFFER_BINDING, &mainFramebuffer)
context.mainFramebufferTexture = newVirtualTexture( context.mainFramebufferTexture = newRenderTargetWithFramebuffer(
context.screenWidth*context.screenScale, context.screenWidth*context.screenScale,
context.screenHeight*context.screenScale) context.screenHeight*context.screenScale,
context.mainFramebufferTexture.framebuffer = C.GLuint(mainFramebuffer) C.GLuint(mainFramebuffer))
initializeShaders() initializeShaders()
context.screen = context.screen = context.NewRenderTarget(
context.NewTexture(context.screenWidth, context.screenHeight).(*Texture) context.screenWidth, context.screenHeight).(*RenderTarget)
} }
func (context *Context) Screen() graphics.Texture { func (context *Context) Screen() graphics.RenderTarget {
return context.screen return context.screen
} }
@ -82,7 +83,7 @@ func (context *Context) Clear() {
func (context *Context) Fill(clr color.Color) { func (context *Context) Fill(clr color.Color) {
r, g, b, a := clr.RGBA() r, g, b, a := clr.RGBA()
max := float64(math.MaxUint16) const max = float64(math.MaxUint16)
C.glClearColor( C.glClearColor(
C.GLclampf(float64(r)/max), C.GLclampf(float64(r)/max),
C.GLclampf(float64(g)/max), C.GLclampf(float64(g)/max),
@ -94,7 +95,7 @@ func (context *Context) Fill(clr color.Color) {
func (context *Context) DrawTexture( func (context *Context) DrawTexture(
textureID graphics.TextureID, textureID graphics.TextureID,
geometryMatrix matrix.Geometry, colorMatrix matrix.Color) { geometryMatrix matrix.Geometry, colorMatrix matrix.Color) {
texture := context.textures[textureID] texture := context.textures[C.GLuint(textureID)]
source := graphics.Rect{0, 0, texture.width, texture.height} source := graphics.Rect{0, 0, texture.width, texture.height}
locations := []graphics.TexturePart{{0, 0, source}} locations := []graphics.TexturePart{{0, 0, source}}
@ -105,7 +106,7 @@ func (context *Context) DrawTexture(
func (context *Context) DrawTextureParts( func (context *Context) DrawTextureParts(
textureID graphics.TextureID, parts []graphics.TexturePart, textureID graphics.TextureID, parts []graphics.TexturePart,
geometryMatrix matrix.Geometry, colorMatrix matrix.Color) { geometryMatrix matrix.Geometry, colorMatrix matrix.Color) {
texture := context.textures[textureID] texture := context.textures[C.GLuint(textureID)]
if texture == nil { if texture == nil {
panic("invalid texture ID") panic("invalid texture ID")
} }
@ -144,9 +145,11 @@ func (context *Context) DrawTextureParts(
tu1, tv2, tu1, tv2,
tu2, tv2, tu2, tv2,
} }
C.glVertexAttribPointer(C.GLuint(vertexAttrLocation), 2, C.GL_FLOAT, C.GL_FALSE, C.glVertexAttribPointer(C.GLuint(vertexAttrLocation), 2,
C.GL_FLOAT, C.GL_FALSE,
0, unsafe.Pointer(&vertex[0])) 0, unsafe.Pointer(&vertex[0]))
C.glVertexAttribPointer(C.GLuint(textureAttrLocation), 2, C.GL_FLOAT, C.GL_FALSE, C.glVertexAttribPointer(C.GLuint(textureAttrLocation), 2,
C.GL_FLOAT, C.GL_FALSE,
0, unsafe.Pointer(&texCoord[0])) 0, unsafe.Pointer(&texCoord[0]))
C.glDrawArrays(C.GL_TRIANGLE_STRIP, 0, 4) C.glDrawArrays(C.GL_TRIANGLE_STRIP, 0, 4)
} }
@ -163,21 +166,23 @@ func abs(x int) int {
return x return x
} }
func (context *Context) SetOffscreen(textureID graphics.TextureID) { func (context *Context) SetOffscreen(renderTargetID graphics.RenderTargetID) {
texture := context.textures[textureID] renderTarget :=
if texture.framebuffer == 0 { (*RenderTarget)(context.textures[C.GLuint(renderTargetID)])
texture.framebuffer = createFramebuffer(texture.id) if renderTarget.framebuffer == 0 {
renderTarget.framebuffer = createFramebuffer(renderTarget.id)
} }
context.setOffscreen(texture) context.setOffscreen(renderTarget)
} }
func (context *Context) setOffscreen(texture *Texture) { func (context *Context) setOffscreen(renderTarget *RenderTarget) {
context.currentOffscreen = texture context.currentOffscreen = renderTarget
C.glFlush() C.glFlush()
C.glBindFramebuffer(C.GL_FRAMEBUFFER, texture.framebuffer) C.glBindFramebuffer(C.GL_FRAMEBUFFER, renderTarget.framebuffer)
if err := C.glCheckFramebufferStatus(C.GL_FRAMEBUFFER); err != C.GL_FRAMEBUFFER_COMPLETE { err := C.glCheckFramebufferStatus(C.GL_FRAMEBUFFER)
if err != C.GL_FRAMEBUFFER_COMPLETE {
panic(fmt.Sprintf("glBindFramebuffer failed: %d", err)) panic(fmt.Sprintf("glBindFramebuffer failed: %d", err))
} }
@ -185,8 +190,8 @@ func (context *Context) setOffscreen(texture *Texture) {
C.glBlendFuncSeparate(C.GL_SRC_ALPHA, C.GL_ONE_MINUS_SRC_ALPHA, C.glBlendFuncSeparate(C.GL_SRC_ALPHA, C.GL_ONE_MINUS_SRC_ALPHA,
C.GL_ZERO, C.GL_ONE) C.GL_ZERO, C.GL_ONE)
C.glViewport(0, 0, C.GLsizei(abs(texture.textureWidth)), C.glViewport(0, 0, C.GLsizei(abs(renderTarget.textureWidth)),
C.GLsizei(abs(texture.textureHeight))) C.GLsizei(abs(renderTarget.textureHeight)))
} }
func (context *Context) resetOffscreen() { func (context *Context) resetOffscreen() {
@ -294,31 +299,32 @@ func createFramebuffer(textureID C.GLuint) C.GLuint {
C.glFramebufferTexture2D(C.GL_FRAMEBUFFER, C.GL_COLOR_ATTACHMENT0, C.glFramebufferTexture2D(C.GL_FRAMEBUFFER, C.GL_COLOR_ATTACHMENT0,
C.GL_TEXTURE_2D, textureID, 0) C.GL_TEXTURE_2D, textureID, 0)
C.glBindFramebuffer(C.GL_FRAMEBUFFER, C.GLuint(origFramebuffer)) C.glBindFramebuffer(C.GL_FRAMEBUFFER, C.GLuint(origFramebuffer))
if C.glCheckFramebufferStatus(C.GL_FRAMEBUFFER) != C.GL_FRAMEBUFFER_COMPLETE { if C.glCheckFramebufferStatus(C.GL_FRAMEBUFFER) !=
C.GL_FRAMEBUFFER_COMPLETE {
panic("creating framebuffer failed") panic("creating framebuffer failed")
} }
return framebuffer return framebuffer
} }
func (context *Context) NewTexture(width, height int) graphics.Texture { func (context *Context) NewRenderTarget(width, height int) (
texture := newTexture(width, height) graphics.RenderTarget) {
id := graphics.TextureID(texture.id) renderTarget := newRenderTarget(width, height)
context.textures[id] = texture context.textures[renderTarget.id] = (*Texture)(renderTarget)
context.SetOffscreen(texture.ID()) context.SetOffscreen(renderTarget.ID())
context.Clear() context.Clear()
context.resetOffscreen() context.resetOffscreen()
return texture return renderTarget
} }
func (context *Context) NewTextureFromImage(img image.Image) (graphics.Texture, error) { func (context *Context) NewTextureFromImage(img image.Image) (
graphics.Texture, error) {
texture, err := newTextureFromImage(img) texture, err := newTextureFromImage(img)
if err != nil { if err != nil {
return nil, err return nil, err
} }
id := graphics.TextureID(texture.id) context.textures[texture.id] = texture
context.textures[id] = texture
return texture, nil return texture, nil
} }

View File

@ -73,7 +73,7 @@ func (device *Device) Update(draw func(graphics.Context)) {
{0, scale, 0}, {0, scale, 0},
}, },
} }
context.DrawTexture(context.Screen().ID(), context.DrawTexture(context.Screen().Texture().ID(),
geometryMatrix, matrix.IdentityColor()) geometryMatrix, matrix.IdentityColor())
context.flush() context.flush()
} }

View File

@ -64,7 +64,6 @@ type Texture struct {
textureWidth int textureWidth int
textureHeight int textureHeight int
framebuffer C.GLuint framebuffer C.GLuint
isVirtual bool
} }
func (texture *Texture) ID() graphics.TextureID { func (texture *Texture) ID() graphics.TextureID {
@ -91,7 +90,6 @@ func createTexture(width, height int, pixels []uint8) *Texture {
height: height, height: height,
textureWidth: textureWidth, textureWidth: textureWidth,
textureHeight: textureHeight, textureHeight: textureHeight,
isVirtual: false,
} }
textureID := C.GLuint(0) textureID := C.GLuint(0)
@ -125,8 +123,9 @@ func (err textureError) Error() string {
return "Texture Error: " + string(err) return "Texture Error: " + string(err)
} }
func newTexture(width, height int) *Texture { func newRenderTarget(width, height int) *RenderTarget {
return createTexture(width, height, nil) renderTarget := createTexture(width, height, nil)
return (*RenderTarget)(renderTarget)
} }
func newTextureFromImage(img image.Image) (*Texture, error) { func newTextureFromImage(img image.Image) (*Texture, error) {
@ -143,13 +142,33 @@ func newTextureFromImage(img image.Image) (*Texture, error) {
return createTexture(size.X, size.Y, pix), nil return createTexture(size.X, size.Y, pix), nil
} }
func newVirtualTexture(width, height int) *Texture { func newRenderTargetWithFramebuffer(width, height int,
return &Texture{ framebuffer C.GLuint) *RenderTarget {
texture := &Texture{
id: 0, id: 0,
width: width, width: width,
height: height, height: height,
textureWidth: int(clp2(uint64(width))), textureWidth: int(clp2(uint64(width))),
textureHeight: int(clp2(uint64(height))), textureHeight: int(clp2(uint64(height))),
isVirtual: true, framebuffer: framebuffer,
} }
return (*RenderTarget)(texture)
}
type RenderTarget Texture
func (renderTarget *RenderTarget) Texture() graphics.Texture {
return (*Texture)(renderTarget)
}
func (renderTarget *RenderTarget) ID() graphics.RenderTargetID {
return graphics.RenderTargetID(renderTarget.id)
}
func (renderTarget *RenderTarget) Width() int {
return renderTarget.width
}
func (renderTarget *RenderTarget) Height() int {
return renderTarget.height
} }