diff --git a/graphics/opengl/context.go b/graphics/opengl/context.go index e48aa741f..791a423da 100644 --- a/graphics/opengl/context.go +++ b/graphics/opengl/context.go @@ -9,6 +9,7 @@ import ( "github.com/hajimehoshi/go-ebiten/graphics" "github.com/hajimehoshi/go-ebiten/graphics/matrix" "github.com/hajimehoshi/go-ebiten/graphics/opengl/offscreen" + "github.com/hajimehoshi/go-ebiten/graphics/opengl/rendertarget" "math" ) @@ -20,9 +21,12 @@ type Context struct { } func newContext(ids *ids, screenWidth, screenHeight, screenScale int) *Context { + mainFramebuffer := rendertarget.NewWithCurrentFramebuffer( + screenWidth*screenScale, + screenHeight*screenScale) context := &Context{ ids: ids, - offscreen: offscreen.New(screenWidth, screenHeight, screenScale), + offscreen: offscreen.New(mainFramebuffer), screenScale: screenScale, } diff --git a/graphics/opengl/offscreen/offscreen.go b/graphics/opengl/offscreen/offscreen.go index 1a455d433..962ee99db 100644 --- a/graphics/opengl/offscreen/offscreen.go +++ b/graphics/opengl/offscreen/offscreen.go @@ -3,67 +3,49 @@ package offscreen import ( "github.com/hajimehoshi/go-ebiten/graphics" "github.com/hajimehoshi/go-ebiten/graphics/matrix" - "github.com/hajimehoshi/go-ebiten/graphics/opengl/rendertarget" - "github.com/hajimehoshi/go-ebiten/graphics/opengl/texture" ) +type Texture interface { + Draw(projectionMatrix [4][4]float64, + geometryMatrix matrix.Geometry, colorMatrix matrix.Color) + DrawParts(parts []graphics.TexturePart, projectionMatrix [4][4]float64, + geometryMatrix matrix.Geometry, colorMatrix matrix.Color) +} + +type RenderTarget interface { + SetAsViewport() + ProjectionMatrix() [4][4]float64 +} + type Offscreen struct { - screenHeight int - screenScale int - currentRenderTarget *rendertarget.RenderTarget - mainFramebufferTexture *rendertarget.RenderTarget + currentRenderTarget RenderTarget + mainFramebuffer RenderTarget } -func New(screenWidth, screenHeight, screenScale int) *Offscreen { - offscreen := &Offscreen{ - screenHeight: screenHeight, - screenScale: screenScale, +func New(mainFramebuffer RenderTarget) *Offscreen { + return &Offscreen{ + mainFramebuffer: mainFramebuffer, } - - offscreen.mainFramebufferTexture = rendertarget.NewWithCurrentFramebuffer( - screenWidth*screenScale, - screenHeight*screenScale) - - return offscreen } -func (o *Offscreen) Set(rt *rendertarget.RenderTarget) { +func (o *Offscreen) Set(rt RenderTarget) { o.currentRenderTarget = rt rt.SetAsViewport() } func (o *Offscreen) SetMainFramebuffer() { - o.Set(o.mainFramebufferTexture) + o.Set(o.mainFramebuffer) } -func (o *Offscreen) DrawTexture(texture *texture.Texture, +func (o *Offscreen) DrawTexture(texture Texture, geometryMatrix matrix.Geometry, colorMatrix matrix.Color) { - projectionMatrix := o.projectionMatrix() + projectionMatrix := o.currentRenderTarget.ProjectionMatrix() texture.Draw(projectionMatrix, geometryMatrix, colorMatrix) } -func (o *Offscreen) DrawTextureParts(texture *texture.Texture, +func (o *Offscreen) DrawTextureParts(texture Texture, parts []graphics.TexturePart, geometryMatrix matrix.Geometry, colorMatrix matrix.Color) { - projectionMatrix := o.projectionMatrix() + projectionMatrix := o.currentRenderTarget.ProjectionMatrix() texture.DrawParts(parts, projectionMatrix, geometryMatrix, colorMatrix) } - -func (o *Offscreen) projectionMatrix() [16]float32 { - matrix := o.currentRenderTarget.ProjectionMatrix() - if o.currentRenderTarget == o.mainFramebufferTexture { - actualScreenHeight := o.screenHeight * o.screenScale - // Flip Y and move to fit with the top of the window. - matrix[1][1] *= -1 - matrix[1][3] += float64(actualScreenHeight) / - float64(graphics.AdjustSizeForTexture(actualScreenHeight)) * 2 - } - - projectionMatrix := [16]float32{} - for j := 0; j < 4; j++ { - for i := 0; i < 4; i++ { - projectionMatrix[i+j*4] = float32(matrix[i][j]) - } - } - return projectionMatrix -} diff --git a/graphics/opengl/rendertarget/render_target.go b/graphics/opengl/rendertarget/render_target.go index 7fc33d41e..80a11ae33 100644 --- a/graphics/opengl/rendertarget/render_target.go +++ b/graphics/opengl/rendertarget/render_target.go @@ -15,12 +15,15 @@ type RenderTarget struct { framebuffer C.GLuint width int height int + flipY bool } func NewWithCurrentFramebuffer(width, height int) *RenderTarget { framebuffer := C.GLint(0) C.glGetIntegerv(C.GL_FRAMEBUFFER_BINDING, &framebuffer) - return &RenderTarget{C.GLuint(framebuffer), width, height} + rt := &RenderTarget{C.GLuint(framebuffer), width, height, true} + rt.setAsViewport() + return rt } func createFramebuffer(nativeTexture C.GLuint) C.GLuint { @@ -50,10 +53,10 @@ func createFramebuffer(nativeTexture C.GLuint) C.GLuint { func CreateFromTexture(native NativeTexture, width, height int) *RenderTarget { framebuffer := createFramebuffer(C.GLuint(native)) - return &RenderTarget{framebuffer, width, height} + return &RenderTarget{framebuffer, width, height, false} } -func (r *RenderTarget) SetAsViewport() { +func (r *RenderTarget) setAsViewport() { C.glFlush() C.glBindFramebuffer(C.GL_FRAMEBUFFER, C.GLuint(r.framebuffer)) @@ -70,10 +73,26 @@ func (r *RenderTarget) SetAsViewport() { C.glViewport(0, 0, C.GLsizei(width), C.GLsizei(height)) } +func (r *RenderTarget) SetAsViewport() { + current := C.GLint(0) + C.glGetIntegerv(C.GL_FRAMEBUFFER_BINDING, ¤t) + if C.GLuint(current) == r.framebuffer { + return + } + r.setAsViewport() +} + func (r *RenderTarget) ProjectionMatrix() [4][4]float64 { width := graphics.AdjustSizeForTexture(r.width) height := graphics.AdjustSizeForTexture(r.height) - return graphics.OrthoProjectionMatrix(0, width, 0, height) + matrix := graphics.OrthoProjectionMatrix(0, width, 0, height) + if r.flipY { + // Flip Y and move to fit with the top of the window. + matrix[1][1] *= -1 + matrix[1][3] += float64(r.height) / + float64(graphics.AdjustSizeForTexture(r.height)) * 2 + } + return matrix } func (r *RenderTarget) Dispose() { diff --git a/graphics/opengl/texture/texture.go b/graphics/opengl/texture/texture.go index 90a6dd5b5..52c02432c 100644 --- a/graphics/opengl/texture/texture.go +++ b/graphics/opengl/texture/texture.go @@ -19,6 +19,16 @@ type Texture struct { height int } +func glMatrix(matrix [4][4]float64) [16]float32 { + result := [16]float32{} + for j := 0; j < 4; j++ { + for i := 0; i < 4; i++ { + result[i+j*4] = float32(matrix[i][j]) + } + } + return result +} + func createNativeTexture(textureWidth, textureHeight int, pixels []uint8, filter graphics.Filter) C.GLuint { nativeTexture := C.GLuint(0) @@ -73,18 +83,18 @@ func (t *Texture) CreateRenderTarget() *rendertarget.RenderTarget { rendertarget.NativeTexture(t.native), t.width, t.height) } -func (t *Texture) Draw(projectionMatrix [16]float32, geometryMatrix matrix.Geometry, colorMatrix matrix.Color) { +func (t *Texture) Draw(projectionMatrix [4][4]float64, geometryMatrix matrix.Geometry, colorMatrix matrix.Color) { quad := graphics.TextureQuadForTexture(t.width, t.height) shader.DrawTexture(shader.NativeTexture(t.native), - projectionMatrix, []graphics.TextureQuad{quad}, + glMatrix(projectionMatrix), []graphics.TextureQuad{quad}, geometryMatrix, colorMatrix) } -func (t *Texture) DrawParts(parts []graphics.TexturePart, projectionMatrix [16]float32, +func (t *Texture) DrawParts(parts []graphics.TexturePart, projectionMatrix [4][4]float64, geometryMatrix matrix.Geometry, colorMatrix matrix.Color) { quads := graphics.TextureQuadsForTextureParts(parts, t.width, t.height) shader.DrawTexture(shader.NativeTexture(t.native), - projectionMatrix, quads, + glMatrix(projectionMatrix), quads, geometryMatrix, colorMatrix) }