diff --git a/example/alphablending/main.go b/example/alphablending/main.go index 10b3a640e..9104c4e05 100644 --- a/example/alphablending/main.go +++ b/example/alphablending/main.go @@ -72,7 +72,7 @@ func main() { if err != nil { log.Fatal(err) } - if err := ebiten.Run(g.Update, screenWidth, screenHeight, 2, "Perspective (Ebiten Demo)"); err != nil { + if err := ebiten.Run(g.Update, screenWidth, screenHeight, 2, "Alpha Blending (Ebiten Demo)"); err != nil { log.Fatal(err) } } diff --git a/graphicscontext.go b/graphicscontext.go index ef18b2037..a600d0f0b 100644 --- a/graphicscontext.go +++ b/graphicscontext.go @@ -23,7 +23,7 @@ import ( ) func newGraphicsContext(screenWidth, screenHeight, screenScale int) (*graphicsContext, error) { - r, t, err := opengl.NewZeroRenderTarget(screenWidth*screenScale, screenHeight*screenScale, true) + r, err := opengl.NewZeroRenderTarget(screenWidth*screenScale, screenHeight*screenScale) if err != nil { return nil, err } @@ -32,18 +32,14 @@ func newGraphicsContext(screenWidth, screenHeight, screenScale int) (*graphicsCo if err != nil { return nil, err } - c := &graphicsContext{ currents: make([]*RenderTarget, 1), - defaultR: &RenderTarget{r, &Texture{t}}, + defaultR: &RenderTarget{r, nil}, screen: screen, screenWidth: screenWidth, screenHeight: screenHeight, screenScale: screenScale, } - - idsInstance.fillRenderTarget(c.screen, color.RGBA{0, 0, 0, 0}) - return c, nil } @@ -92,17 +88,18 @@ func (c *graphicsContext) PopRenderTarget() { func (c *graphicsContext) preUpdate() { c.currents = c.currents[0:1] c.currents[0] = c.defaultR + c.PushRenderTarget(c.screen) - c.Fill(color.RGBA{0, 0, 0, 0xff}) + c.Clear() } func (c *graphicsContext) postUpdate() { c.PopRenderTarget() - c.Clear() scale := float64(c.screenScale) geo := ScaleGeometry(scale, scale) - DrawWholeTexture(c, c.screen.texture, geo, ColorMatrixI()) + clr := ColorMatrixI() + DrawWholeTexture(c, c.screen.texture, geo, clr) gl.Flush() } diff --git a/ids.go b/ids.go index 354428cf6..0a024cbb7 100644 --- a/ids.go +++ b/ids.go @@ -49,6 +49,7 @@ func (i *ids) createRenderTarget(width, height int, filter int) (*RenderTarget, texture := &Texture{glTexture} // TODO: Is |texture| necessary? renderTarget := &RenderTarget{glRenderTarget, texture} + i.fillRenderTarget(renderTarget, color.RGBA{0, 0, 0, 0}) return renderTarget, nil } @@ -72,7 +73,11 @@ func (i *ids) drawTexture(target *RenderTarget, texture *Texture, parts []Textur projectionMatrix := target.glRenderTarget.ProjectionMatrix() quads := textureQuads(parts, glTexture.Width(), glTexture.Height()) w, h := target.Size() - shader.DrawTexture(glTexture.Native(), target.texture.glTexture.Native(), w, h, projectionMatrix, quads, &geo, &color) + targetNativeTexture := gl.Texture(0) + if target.texture != nil { + targetNativeTexture = target.texture.glTexture.Native() + } + shader.DrawTexture(glTexture.Native(), targetNativeTexture, w, h, projectionMatrix, quads, &geo, &color) return nil } diff --git a/internal/opengl/internal/shader/drawtexture.go b/internal/opengl/internal/shader/drawtexture.go index 5f561387e..db8cbc942 100644 --- a/internal/opengl/internal/shader/drawtexture.go +++ b/internal/opengl/internal/shader/drawtexture.go @@ -48,30 +48,39 @@ func DrawTexture(native gl.Texture, target gl.Texture, width, height int, projec return } // TODO: Check performance - shaderProgram := use(glMatrix(projectionMatrix), width, height, geo, color) + program := gl.Program(0) + if 0 < target { + program = useProgramColorMatrix(glMatrix(projectionMatrix), width, height, geo, color) + } else { + program = useProgramColorFinal(glMatrix(projectionMatrix), geo) + } gl.ActiveTexture(gl.TEXTURE0) native.Bind(gl.TEXTURE_2D) - gl.ActiveTexture(gl.TEXTURE1) - target.Bind(gl.TEXTURE_2D) + if 0 < target { + gl.ActiveTexture(gl.TEXTURE1) + target.Bind(gl.TEXTURE_2D) + } - texture0UniformLocation := getUniformLocation(shaderProgram, "texture0") - texture1UniformLocation := getUniformLocation(shaderProgram, "texture1") - texture0UniformLocation.Uniform1i(0) - texture1UniformLocation.Uniform1i(1) - - vertexAttrLocation := getAttributeLocation(shaderProgram, "vertex") - texCoord0AttrLocation := getAttributeLocation(shaderProgram, "tex_coord0") - texCoord1AttrLocation := getAttributeLocation(shaderProgram, "tex_coord1") + vertexAttrLocation := getAttributeLocation(program, "vertex") + texCoord0AttrLocation := getAttributeLocation(program, "tex_coord0") + texCoord1AttrLocation := gl.AttribLocation(0) + if program == programColorMatrix.native { + texCoord1AttrLocation = getAttributeLocation(program, "tex_coord1") + } gl.EnableClientState(gl.VERTEX_ARRAY) gl.EnableClientState(gl.TEXTURE_COORD_ARRAY) vertexAttrLocation.EnableArray() texCoord0AttrLocation.EnableArray() - texCoord1AttrLocation.EnableArray() + if program == programColorMatrix.native { + texCoord1AttrLocation.EnableArray() + } defer func() { - texCoord1AttrLocation.DisableArray() + if program == programColorMatrix.native { + texCoord1AttrLocation.DisableArray() + } texCoord0AttrLocation.DisableArray() vertexAttrLocation.DisableArray() gl.DisableClientState(gl.TEXTURE_COORD_ARRAY) @@ -104,18 +113,20 @@ func DrawTexture(native gl.Texture, target gl.Texture, width, height int, projec u1, v2, u2, v2, ) - w := float32(internal.AdjustSizeForTexture(width)) - h := float32(internal.AdjustSizeForTexture(height)) - xx1 := x1 / w - xx2 := x2 / w - yy1 := y1 / h - yy2 := y2 / h - texCoords1 = append(texCoords1, - xx1, yy1, - xx2, yy1, - xx1, yy2, - xx2, yy2, - ) + if program == programColorMatrix.native { + w := float32(internal.AdjustSizeForTexture(width)) + h := float32(internal.AdjustSizeForTexture(height)) + xx1 := x1 / w + xx2 := x2 / w + yy1 := y1 / h + yy2 := y2 / h + texCoords1 = append(texCoords1, + xx1, yy1, + xx2, yy1, + xx1, yy2, + xx2, yy2, + ) + } base := uint32(i * 4) indicies = append(indicies, base, base+1, base+2, @@ -124,7 +135,9 @@ func DrawTexture(native gl.Texture, target gl.Texture, width, height int, projec } vertexAttrLocation.AttribPointer(2, gl.FLOAT, false, 0, vertices) texCoord0AttrLocation.AttribPointer(2, gl.FLOAT, false, 0, texCoords0) - texCoord1AttrLocation.AttribPointer(2, gl.FLOAT, false, 0, texCoords1) + if program == programColorMatrix.native { + texCoord1AttrLocation.AttribPointer(2, gl.FLOAT, false, 0, texCoords1) + } gl.DrawElements(gl.TRIANGLES, len(indicies), gl.UNSIGNED_INT, indicies) gl.Flush() diff --git a/internal/opengl/internal/shader/program.go b/internal/opengl/internal/shader/program.go index cf905a0c2..b5745ec34 100644 --- a/internal/opengl/internal/shader/program.go +++ b/internal/opengl/internal/shader/program.go @@ -30,6 +30,10 @@ var programColorMatrix = program{ shaderIds: []shaderId{shaderVertex, shaderColorMatrix}, } +var programColorFinal = program{ + shaderIds: []shaderId{shaderVertexFinal, shaderColorFinal}, +} + func (p *program) create() { p.native = gl.CreateProgram() if p.native == 0 { @@ -56,32 +60,24 @@ func initialize() { }() programColorMatrix.create() - programColorMatrix.native.Use() + programColorFinal.create() } -// NOTE: This caches are now used only for programColorMatrix -var attribLocationCache = map[string]gl.AttribLocation{} -var uniformLocationCache = map[string]gl.UniformLocation{} - func getAttributeLocation(program gl.Program, name string) gl.AttribLocation { - if location, ok := attribLocationCache[name]; ok { - return location - } - location := program.GetAttribLocation(name) - attribLocationCache[name] = location - return location + return program.GetAttribLocation(name) } func getUniformLocation(program gl.Program, name string) gl.UniformLocation { - if location, ok := uniformLocationCache[name]; ok { - return location - } - location := program.GetUniformLocation(name) - uniformLocationCache[name] = location - return location + return program.GetUniformLocation(name) } -func use(projectionMatrix [16]float32, width, height int, geo Matrix, color Matrix) gl.Program { +var lastProgram gl.Program = 0 + +func useProgramColorMatrix(projectionMatrix [16]float32, width, height int, geo Matrix, color Matrix) gl.Program { + if lastProgram != programColorMatrix.native { + programColorMatrix.native.Use() + lastProgram = programColorMatrix.native + } // TODO: Check the performance. program := programColorMatrix @@ -100,6 +96,7 @@ func use(projectionMatrix [16]float32, width, height int, geo Matrix, color Matr tx, ty, 0, 1, } getUniformLocation(program.native, "modelview_matrix").UniformMatrix4fv(false, glModelviewMatrix) + txn := tx / float32(internal.AdjustSizeForTexture(width)) tyn := ty / float32(internal.AdjustSizeForTexture(height)) glModelviewMatrixN := [...]float32{ @@ -110,7 +107,8 @@ func use(projectionMatrix [16]float32, width, height int, geo Matrix, color Matr } getUniformLocation(program.native, "modelview_matrix_n").UniformMatrix4fv(false, glModelviewMatrixN) - getUniformLocation(program.native, "texture").Uniform1i(0) + getUniformLocation(program.native, "texture0").Uniform1i(0) + getUniformLocation(program.native, "texture1").Uniform1i(1) e := [4][5]float32{} for i := 0; i < 4; i++ { @@ -133,3 +131,32 @@ func use(projectionMatrix [16]float32, width, height int, geo Matrix, color Matr return program.native } + +func useProgramColorFinal(projectionMatrix [16]float32, geo Matrix) gl.Program { + if lastProgram != programColorFinal.native { + programColorFinal.native.Use() + lastProgram = programColorFinal.native + } + + program := programColorFinal + + getUniformLocation(program.native, "projection_matrix").UniformMatrix4fv(false, projectionMatrix) + + a := float32(geo.Element(0, 0)) + b := float32(geo.Element(0, 1)) + c := float32(geo.Element(1, 0)) + d := float32(geo.Element(1, 1)) + tx := float32(geo.Element(0, 2)) + ty := float32(geo.Element(1, 2)) + glModelviewMatrix := [...]float32{ + a, c, 0, 0, + b, d, 0, 0, + 0, 0, 1, 0, + tx, ty, 0, 1, + } + getUniformLocation(program.native, "modelview_matrix").UniformMatrix4fv(false, glModelviewMatrix) + + getUniformLocation(program.native, "texture0").Uniform1i(0) + + return program.native +} diff --git a/internal/opengl/internal/shader/shader.go b/internal/opengl/internal/shader/shader.go index fde890a87..c16ad794a 100644 --- a/internal/opengl/internal/shader/shader.go +++ b/internal/opengl/internal/shader/shader.go @@ -31,9 +31,9 @@ type shaderId int const ( shaderVertex shaderId = iota - shaderFragment + shaderVertexFinal shaderColorMatrix - shaderSolidColor + shaderColorFinal ) var shaders = map[shaderId]*shader{ @@ -54,6 +54,21 @@ void main(void) { vertex_out_tex_coord1 = (modelview_matrix_n * vec4(tex_coord1, 0, 1)).xy; gl_Position = projection_matrix * modelview_matrix * vec4(vertex, 0, 1); } +`, + }, + shaderVertexFinal: { + shaderType: gl.VERTEX_SHADER, + source: ` +uniform mat4 projection_matrix; +uniform mat4 modelview_matrix; +attribute vec2 vertex; +attribute vec2 tex_coord0; +varying vec2 vertex_out_tex_coord0; + +void main(void) { + vertex_out_tex_coord0 = tex_coord0; + gl_Position = projection_matrix * modelview_matrix * vec4(vertex, 0, 1); +} `, }, shaderColorMatrix: { @@ -74,6 +89,19 @@ void main(void) { gl_FragColor.a = color0.a + color1.a - color0.a * color1.a; gl_FragColor.rgb = (color0.a * color0.rgb + (1.0 - color0.a) * color1.a * color1.rgb) / gl_FragColor.a; } +`, + }, + shaderColorFinal: { + shaderType: gl.FRAGMENT_SHADER, + source: ` +uniform sampler2D texture0; +varying vec2 vertex_out_tex_coord0; + +void main(void) { + vec4 color0 = texture2D(texture0, vertex_out_tex_coord0); + gl_FragColor.rgb = color0.a * color0.rgb; + gl_FragColor.a = 1.0; +} `, }, } diff --git a/internal/opengl/rendertarget.go b/internal/opengl/rendertarget.go index eb77b3e03..6534b3bfc 100644 --- a/internal/opengl/rendertarget.go +++ b/internal/opengl/rendertarget.go @@ -44,23 +44,13 @@ type RenderTarget struct { flipY bool } -func NewZeroRenderTarget(width, height int, flipY bool) (*RenderTarget, *Texture, error) { +func NewZeroRenderTarget(width, height int) (*RenderTarget, error) { r := &RenderTarget{ width: width, height: height, - flipY: flipY, + flipY: true, } - // The framebuffer 0 can't be enlarged, so any filter is acceptable. - t, err := NewTexture(width, height, gl.NEAREST) - if err != nil { - return nil, nil, err - } - // TODO: Does this affect the current rendering target? - gl.Framebuffer(0).Bind() - if err := framebufferTexture(t.native); err != nil { - return nil, nil, err - } - return r, t, err + return r, nil } func NewRenderTargetFromTexture(texture *Texture) (*RenderTarget, error) {