package offscreen // #cgo LDFLAGS: -framework OpenGL // // #include // #include import "C" import ( "fmt" "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/shader" "github.com/hajimehoshi/go-ebiten/graphics/opengl/texture" grendertarget "github.com/hajimehoshi/go-ebiten/graphics/rendertarget" gtexture "github.com/hajimehoshi/go-ebiten/graphics/texture" ) type Offscreen struct { screenHeight int screenScale int mainFramebufferTexture *grendertarget.RenderTarget projectionMatrix [16]float32 } func New(screenWidth, screenHeight, screenScale int) *Offscreen { offscreen := &Offscreen{ screenHeight: screenHeight, screenScale: screenScale, } // The main framebuffer should be created sooner than any other // framebuffers! mainFramebuffer := C.GLint(0) C.glGetIntegerv(C.GL_FRAMEBUFFER_BINDING, &mainFramebuffer) var err error offscreen.mainFramebufferTexture, err = rendertarget.NewWithFramebuffer( screenWidth*screenScale, screenHeight*screenScale, rendertarget.Framebuffer(mainFramebuffer)) if err != nil { panic("creating main framebuffer failed: " + err.Error()) } return offscreen } func (o *Offscreen) Set(rt *grendertarget.RenderTarget) { C.glFlush() rt.SetAsOffscreen(&setter{o, rt == o.mainFramebufferTexture}) } func (o *Offscreen) SetMainFramebuffer() { o.Set(o.mainFramebufferTexture) } func (o *Offscreen) DrawTexture(texture *gtexture.Texture, geometryMatrix matrix.Geometry, colorMatrix matrix.Color) { d := &drawable{o, geometryMatrix, colorMatrix} texture.Draw(d.Draw) } func (o *Offscreen) DrawTextureParts(texture *gtexture.Texture, parts []graphics.TexturePart, geometryMatrix matrix.Geometry, colorMatrix matrix.Color) { d := &drawable{o, geometryMatrix, colorMatrix} texture.DrawParts(parts, d.Draw) } type setter struct { offscreen *Offscreen usingMainFramebuffer bool } func (s *setter) Set(framebuffer interface{}, x, y, width, height int) { f := framebuffer.(rendertarget.Framebuffer) C.glBindFramebuffer(C.GL_FRAMEBUFFER, C.GLuint(f)) err := C.glCheckFramebufferStatus(C.GL_FRAMEBUFFER) if err != C.GL_FRAMEBUFFER_COMPLETE { panic(fmt.Sprintf("glBindFramebuffer failed: %d", err)) } C.glBlendFuncSeparate(C.GL_SRC_ALPHA, C.GL_ONE_MINUS_SRC_ALPHA, C.GL_ZERO, C.GL_ONE) C.glViewport(C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height)) matrix := graphics.OrthoProjectionMatrix(x, width, y, height) if s.usingMainFramebuffer { actualScreenHeight := s.offscreen.screenHeight * s.offscreen.screenScale // Flip Y and move to fit with the top of the window. matrix[1][1] *= -1 matrix[1][3] += float64(actualScreenHeight) / float64(height) * 2 } for j := 0; j < 4; j++ { for i := 0; i < 4; i++ { s.offscreen.projectionMatrix[i+j*4] = float32(matrix[i][j]) } } } type drawable struct { offscreen *Offscreen geometryMatrix matrix.Geometry colorMatrix matrix.Color } func (d *drawable) Draw(native interface{}, quads []gtexture.Quad) { shader.DrawTexture(native.(texture.Native), d.offscreen.projectionMatrix, quads, d.geometryMatrix, d.colorMatrix) }