From 86eb30c650ebaff267f477f40455c263728b799f Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 12 Oct 2013 01:29:19 +0900 Subject: [PATCH] Add graphics.RenderTarget --- example/game/rects/rects.go | 12 +++--- graphics/graphics.go | 16 ++++++-- graphics/opengl/context.go | 82 ++++++++++++++++++++----------------- graphics/opengl/device.go | 2 +- graphics/opengl/texture.go | 33 +++++++++++---- 5 files changed, 90 insertions(+), 55 deletions(-) diff --git a/example/game/rects/rects.go b/example/game/rects/rects.go index 1442f0486..c82280ccc 100644 --- a/example/game/rects/rects.go +++ b/example/game/rects/rects.go @@ -31,9 +31,9 @@ import ( ) type Rects struct { - rectTexture graphics.Texture + rectTexture graphics.RenderTarget rectTextureInited bool - offscreen graphics.Texture + offscreen graphics.RenderTarget offscreenInited bool rectBounds *graphics.Rect rectColor *color.RGBA @@ -49,8 +49,8 @@ func New() *Rects { } func (game *Rects) Init(tf graphics.TextureFactory) { - game.rectTexture = tf.NewTexture(16, 16) - game.offscreen = tf.NewTexture(256, 240) + game.rectTexture = tf.NewRenderTarget(16, 16) + game.offscreen = tf.NewRenderTarget(256, 240) } 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}) game.offscreenInited = true } - g.DrawTexture(game.rectTexture.ID(), + g.DrawTexture(game.rectTexture.Texture().ID(), game.rectGeometryMatrix(), game.rectColorMatrix()) g.SetOffscreen(g.Screen().ID()) - g.DrawTexture(game.offscreen.ID(), + g.DrawTexture(game.offscreen.Texture().ID(), matrix.IdentityGeometry(), matrix.IdentityColor()) } diff --git a/graphics/graphics.go b/graphics/graphics.go index 9cf8c86bd..d1bfd02cb 100644 --- a/graphics/graphics.go +++ b/graphics/graphics.go @@ -40,7 +40,7 @@ type TexturePart struct { } type Context interface { - Screen() Texture + Screen() RenderTarget Clear() Fill(clr color.Color) DrawTexture(textureID TextureID, @@ -50,11 +50,11 @@ type Context interface { parts []TexturePart, geometryMatrix matrix.Geometry, colorMatrix matrix.Color) - SetOffscreen(textureID TextureID) + SetOffscreen(renderTargetID RenderTargetID) } type TextureFactory interface { - NewTexture(width, height int) Texture + NewRenderTarget(width, height int) RenderTarget NewTextureFromImage(img image.Image) (Texture, error) } @@ -65,3 +65,13 @@ type Texture interface { } type TextureID int + +type RenderTarget interface { + Texture() Texture + ID() RenderTargetID + Width() int + Height() int +} + +type RenderTargetID int + diff --git a/graphics/opengl/context.go b/graphics/opengl/context.go index 6b2b5f159..6fff8720e 100644 --- a/graphics/opengl/context.go +++ b/graphics/opengl/context.go @@ -36,13 +36,13 @@ import ( ) type Context struct { - screen *Texture + screen *RenderTarget screenWidth int screenHeight int screenScale int - textures map[graphics.TextureID]*Texture - currentOffscreen *Texture - mainFramebufferTexture *Texture + textures map[C.GLuint]*Texture + currentOffscreen *RenderTarget + mainFramebufferTexture *RenderTarget } func newContext(screenWidth, screenHeight, screenScale int) *Context { @@ -50,28 +50,29 @@ func newContext(screenWidth, screenHeight, screenScale int) *Context { screenWidth: screenWidth, screenHeight: screenHeight, screenScale: screenScale, - textures: map[graphics.TextureID]*Texture{}, + textures: map[C.GLuint]*Texture{}, } return context } 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) C.glGetIntegerv(C.GL_FRAMEBUFFER_BINDING, &mainFramebuffer) - context.mainFramebufferTexture = newVirtualTexture( + context.mainFramebufferTexture = newRenderTargetWithFramebuffer( context.screenWidth*context.screenScale, - context.screenHeight*context.screenScale) - context.mainFramebufferTexture.framebuffer = C.GLuint(mainFramebuffer) + context.screenHeight*context.screenScale, + C.GLuint(mainFramebuffer)) initializeShaders() - context.screen = - context.NewTexture(context.screenWidth, context.screenHeight).(*Texture) + context.screen = context.NewRenderTarget( + context.screenWidth, context.screenHeight).(*RenderTarget) } -func (context *Context) Screen() graphics.Texture { +func (context *Context) Screen() graphics.RenderTarget { return context.screen } @@ -82,7 +83,7 @@ func (context *Context) Clear() { func (context *Context) Fill(clr color.Color) { r, g, b, a := clr.RGBA() - max := float64(math.MaxUint16) + const max = float64(math.MaxUint16) C.glClearColor( C.GLclampf(float64(r)/max), C.GLclampf(float64(g)/max), @@ -94,7 +95,7 @@ func (context *Context) Fill(clr color.Color) { func (context *Context) DrawTexture( textureID graphics.TextureID, 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} locations := []graphics.TexturePart{{0, 0, source}} @@ -105,7 +106,7 @@ func (context *Context) DrawTexture( func (context *Context) DrawTextureParts( textureID graphics.TextureID, parts []graphics.TexturePart, geometryMatrix matrix.Geometry, colorMatrix matrix.Color) { - texture := context.textures[textureID] + texture := context.textures[C.GLuint(textureID)] if texture == nil { panic("invalid texture ID") } @@ -144,9 +145,11 @@ func (context *Context) DrawTextureParts( tu1, 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])) - 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])) C.glDrawArrays(C.GL_TRIANGLE_STRIP, 0, 4) } @@ -163,21 +166,23 @@ func abs(x int) int { return x } -func (context *Context) SetOffscreen(textureID graphics.TextureID) { - texture := context.textures[textureID] - if texture.framebuffer == 0 { - texture.framebuffer = createFramebuffer(texture.id) +func (context *Context) SetOffscreen(renderTargetID graphics.RenderTargetID) { + renderTarget := + (*RenderTarget)(context.textures[C.GLuint(renderTargetID)]) + if renderTarget.framebuffer == 0 { + renderTarget.framebuffer = createFramebuffer(renderTarget.id) } - context.setOffscreen(texture) + context.setOffscreen(renderTarget) } -func (context *Context) setOffscreen(texture *Texture) { - context.currentOffscreen = texture +func (context *Context) setOffscreen(renderTarget *RenderTarget) { + context.currentOffscreen = renderTarget C.glFlush() - C.glBindFramebuffer(C.GL_FRAMEBUFFER, texture.framebuffer) - if err := C.glCheckFramebufferStatus(C.GL_FRAMEBUFFER); err != C.GL_FRAMEBUFFER_COMPLETE { + C.glBindFramebuffer(C.GL_FRAMEBUFFER, renderTarget.framebuffer) + err := C.glCheckFramebufferStatus(C.GL_FRAMEBUFFER) + if err != C.GL_FRAMEBUFFER_COMPLETE { 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.GL_ZERO, C.GL_ONE) - C.glViewport(0, 0, C.GLsizei(abs(texture.textureWidth)), - C.GLsizei(abs(texture.textureHeight))) + C.glViewport(0, 0, C.GLsizei(abs(renderTarget.textureWidth)), + C.GLsizei(abs(renderTarget.textureHeight))) } 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.GL_TEXTURE_2D, textureID, 0) 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") } return framebuffer } -func (context *Context) NewTexture(width, height int) graphics.Texture { - texture := newTexture(width, height) - id := graphics.TextureID(texture.id) - context.textures[id] = texture +func (context *Context) NewRenderTarget(width, height int) ( + graphics.RenderTarget) { + renderTarget := newRenderTarget(width, height) + context.textures[renderTarget.id] = (*Texture)(renderTarget) - context.SetOffscreen(texture.ID()) + context.SetOffscreen(renderTarget.ID()) context.Clear() 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) if err != nil { return nil, err } - id := graphics.TextureID(texture.id) - context.textures[id] = texture + context.textures[texture.id] = texture return texture, nil } diff --git a/graphics/opengl/device.go b/graphics/opengl/device.go index e10b89bee..92d229d0d 100644 --- a/graphics/opengl/device.go +++ b/graphics/opengl/device.go @@ -73,7 +73,7 @@ func (device *Device) Update(draw func(graphics.Context)) { {0, scale, 0}, }, } - context.DrawTexture(context.Screen().ID(), + context.DrawTexture(context.Screen().Texture().ID(), geometryMatrix, matrix.IdentityColor()) context.flush() } diff --git a/graphics/opengl/texture.go b/graphics/opengl/texture.go index ee8092fb4..bcb616583 100644 --- a/graphics/opengl/texture.go +++ b/graphics/opengl/texture.go @@ -64,7 +64,6 @@ type Texture struct { textureWidth int textureHeight int framebuffer C.GLuint - isVirtual bool } func (texture *Texture) ID() graphics.TextureID { @@ -91,7 +90,6 @@ func createTexture(width, height int, pixels []uint8) *Texture { height: height, textureWidth: textureWidth, textureHeight: textureHeight, - isVirtual: false, } textureID := C.GLuint(0) @@ -125,8 +123,9 @@ func (err textureError) Error() string { return "Texture Error: " + string(err) } -func newTexture(width, height int) *Texture { - return createTexture(width, height, nil) +func newRenderTarget(width, height int) *RenderTarget { + renderTarget := createTexture(width, height, nil) + return (*RenderTarget)(renderTarget) } 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 } -func newVirtualTexture(width, height int) *Texture { - return &Texture{ +func newRenderTargetWithFramebuffer(width, height int, + framebuffer C.GLuint) *RenderTarget { + texture := &Texture{ id: 0, width: width, height: height, textureWidth: int(clp2(uint64(width))), 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 }