Bug fix: the default framebuffer can't bind a texture

This commit is contained in:
Hajime Hoshi 2014-12-20 18:07:25 +09:00
parent b50e82f49d
commit df35a0ce1e
7 changed files with 131 additions and 71 deletions

View File

@ -72,7 +72,7 @@ func main() {
if err != nil { if err != nil {
log.Fatal(err) 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) log.Fatal(err)
} }
} }

View File

@ -23,7 +23,7 @@ import (
) )
func newGraphicsContext(screenWidth, screenHeight, screenScale int) (*graphicsContext, error) { 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 { if err != nil {
return nil, err return nil, err
} }
@ -32,18 +32,14 @@ func newGraphicsContext(screenWidth, screenHeight, screenScale int) (*graphicsCo
if err != nil { if err != nil {
return nil, err return nil, err
} }
c := &graphicsContext{ c := &graphicsContext{
currents: make([]*RenderTarget, 1), currents: make([]*RenderTarget, 1),
defaultR: &RenderTarget{r, &Texture{t}}, defaultR: &RenderTarget{r, nil},
screen: screen, screen: screen,
screenWidth: screenWidth, screenWidth: screenWidth,
screenHeight: screenHeight, screenHeight: screenHeight,
screenScale: screenScale, screenScale: screenScale,
} }
idsInstance.fillRenderTarget(c.screen, color.RGBA{0, 0, 0, 0})
return c, nil return c, nil
} }
@ -92,17 +88,18 @@ func (c *graphicsContext) PopRenderTarget() {
func (c *graphicsContext) preUpdate() { func (c *graphicsContext) preUpdate() {
c.currents = c.currents[0:1] c.currents = c.currents[0:1]
c.currents[0] = c.defaultR c.currents[0] = c.defaultR
c.PushRenderTarget(c.screen) c.PushRenderTarget(c.screen)
c.Fill(color.RGBA{0, 0, 0, 0xff}) c.Clear()
} }
func (c *graphicsContext) postUpdate() { func (c *graphicsContext) postUpdate() {
c.PopRenderTarget() c.PopRenderTarget()
c.Clear()
scale := float64(c.screenScale) scale := float64(c.screenScale)
geo := ScaleGeometry(scale, scale) geo := ScaleGeometry(scale, scale)
DrawWholeTexture(c, c.screen.texture, geo, ColorMatrixI()) clr := ColorMatrixI()
DrawWholeTexture(c, c.screen.texture, geo, clr)
gl.Flush() gl.Flush()
} }

7
ids.go
View File

@ -49,6 +49,7 @@ func (i *ids) createRenderTarget(width, height int, filter int) (*RenderTarget,
texture := &Texture{glTexture} texture := &Texture{glTexture}
// TODO: Is |texture| necessary? // TODO: Is |texture| necessary?
renderTarget := &RenderTarget{glRenderTarget, texture} renderTarget := &RenderTarget{glRenderTarget, texture}
i.fillRenderTarget(renderTarget, color.RGBA{0, 0, 0, 0})
return renderTarget, nil return renderTarget, nil
} }
@ -72,7 +73,11 @@ func (i *ids) drawTexture(target *RenderTarget, texture *Texture, parts []Textur
projectionMatrix := target.glRenderTarget.ProjectionMatrix() projectionMatrix := target.glRenderTarget.ProjectionMatrix()
quads := textureQuads(parts, glTexture.Width(), glTexture.Height()) quads := textureQuads(parts, glTexture.Width(), glTexture.Height())
w, h := target.Size() 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 return nil
} }

View File

@ -48,30 +48,39 @@ func DrawTexture(native gl.Texture, target gl.Texture, width, height int, projec
return return
} }
// TODO: Check performance // 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) gl.ActiveTexture(gl.TEXTURE0)
native.Bind(gl.TEXTURE_2D) native.Bind(gl.TEXTURE_2D)
gl.ActiveTexture(gl.TEXTURE1) if 0 < target {
target.Bind(gl.TEXTURE_2D) gl.ActiveTexture(gl.TEXTURE1)
target.Bind(gl.TEXTURE_2D)
}
texture0UniformLocation := getUniformLocation(shaderProgram, "texture0") vertexAttrLocation := getAttributeLocation(program, "vertex")
texture1UniformLocation := getUniformLocation(shaderProgram, "texture1") texCoord0AttrLocation := getAttributeLocation(program, "tex_coord0")
texture0UniformLocation.Uniform1i(0) texCoord1AttrLocation := gl.AttribLocation(0)
texture1UniformLocation.Uniform1i(1) if program == programColorMatrix.native {
texCoord1AttrLocation = getAttributeLocation(program, "tex_coord1")
vertexAttrLocation := getAttributeLocation(shaderProgram, "vertex") }
texCoord0AttrLocation := getAttributeLocation(shaderProgram, "tex_coord0")
texCoord1AttrLocation := getAttributeLocation(shaderProgram, "tex_coord1")
gl.EnableClientState(gl.VERTEX_ARRAY) gl.EnableClientState(gl.VERTEX_ARRAY)
gl.EnableClientState(gl.TEXTURE_COORD_ARRAY) gl.EnableClientState(gl.TEXTURE_COORD_ARRAY)
vertexAttrLocation.EnableArray() vertexAttrLocation.EnableArray()
texCoord0AttrLocation.EnableArray() texCoord0AttrLocation.EnableArray()
texCoord1AttrLocation.EnableArray() if program == programColorMatrix.native {
texCoord1AttrLocation.EnableArray()
}
defer func() { defer func() {
texCoord1AttrLocation.DisableArray() if program == programColorMatrix.native {
texCoord1AttrLocation.DisableArray()
}
texCoord0AttrLocation.DisableArray() texCoord0AttrLocation.DisableArray()
vertexAttrLocation.DisableArray() vertexAttrLocation.DisableArray()
gl.DisableClientState(gl.TEXTURE_COORD_ARRAY) gl.DisableClientState(gl.TEXTURE_COORD_ARRAY)
@ -104,18 +113,20 @@ func DrawTexture(native gl.Texture, target gl.Texture, width, height int, projec
u1, v2, u1, v2,
u2, v2, u2, v2,
) )
w := float32(internal.AdjustSizeForTexture(width)) if program == programColorMatrix.native {
h := float32(internal.AdjustSizeForTexture(height)) w := float32(internal.AdjustSizeForTexture(width))
xx1 := x1 / w h := float32(internal.AdjustSizeForTexture(height))
xx2 := x2 / w xx1 := x1 / w
yy1 := y1 / h xx2 := x2 / w
yy2 := y2 / h yy1 := y1 / h
texCoords1 = append(texCoords1, yy2 := y2 / h
xx1, yy1, texCoords1 = append(texCoords1,
xx2, yy1, xx1, yy1,
xx1, yy2, xx2, yy1,
xx2, yy2, xx1, yy2,
) xx2, yy2,
)
}
base := uint32(i * 4) base := uint32(i * 4)
indicies = append(indicies, indicies = append(indicies,
base, base+1, base+2, 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) vertexAttrLocation.AttribPointer(2, gl.FLOAT, false, 0, vertices)
texCoord0AttrLocation.AttribPointer(2, gl.FLOAT, false, 0, texCoords0) 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.DrawElements(gl.TRIANGLES, len(indicies), gl.UNSIGNED_INT, indicies)
gl.Flush() gl.Flush()

View File

@ -30,6 +30,10 @@ var programColorMatrix = program{
shaderIds: []shaderId{shaderVertex, shaderColorMatrix}, shaderIds: []shaderId{shaderVertex, shaderColorMatrix},
} }
var programColorFinal = program{
shaderIds: []shaderId{shaderVertexFinal, shaderColorFinal},
}
func (p *program) create() { func (p *program) create() {
p.native = gl.CreateProgram() p.native = gl.CreateProgram()
if p.native == 0 { if p.native == 0 {
@ -56,32 +60,24 @@ func initialize() {
}() }()
programColorMatrix.create() 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 { func getAttributeLocation(program gl.Program, name string) gl.AttribLocation {
if location, ok := attribLocationCache[name]; ok { return program.GetAttribLocation(name)
return location
}
location := program.GetAttribLocation(name)
attribLocationCache[name] = location
return location
} }
func getUniformLocation(program gl.Program, name string) gl.UniformLocation { func getUniformLocation(program gl.Program, name string) gl.UniformLocation {
if location, ok := uniformLocationCache[name]; ok { return program.GetUniformLocation(name)
return location
}
location := program.GetUniformLocation(name)
uniformLocationCache[name] = location
return location
} }
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. // TODO: Check the performance.
program := programColorMatrix program := programColorMatrix
@ -100,6 +96,7 @@ func use(projectionMatrix [16]float32, width, height int, geo Matrix, color Matr
tx, ty, 0, 1, tx, ty, 0, 1,
} }
getUniformLocation(program.native, "modelview_matrix").UniformMatrix4fv(false, glModelviewMatrix) getUniformLocation(program.native, "modelview_matrix").UniformMatrix4fv(false, glModelviewMatrix)
txn := tx / float32(internal.AdjustSizeForTexture(width)) txn := tx / float32(internal.AdjustSizeForTexture(width))
tyn := ty / float32(internal.AdjustSizeForTexture(height)) tyn := ty / float32(internal.AdjustSizeForTexture(height))
glModelviewMatrixN := [...]float32{ 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, "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{} e := [4][5]float32{}
for i := 0; i < 4; i++ { 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 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
}

View File

@ -31,9 +31,9 @@ type shaderId int
const ( const (
shaderVertex shaderId = iota shaderVertex shaderId = iota
shaderFragment shaderVertexFinal
shaderColorMatrix shaderColorMatrix
shaderSolidColor shaderColorFinal
) )
var shaders = map[shaderId]*shader{ 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; vertex_out_tex_coord1 = (modelview_matrix_n * vec4(tex_coord1, 0, 1)).xy;
gl_Position = projection_matrix * modelview_matrix * vec4(vertex, 0, 1); 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: { shaderColorMatrix: {
@ -74,6 +89,19 @@ void main(void) {
gl_FragColor.a = color0.a + color1.a - color0.a * color1.a; 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; 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;
}
`, `,
}, },
} }

View File

@ -44,23 +44,13 @@ type RenderTarget struct {
flipY bool flipY bool
} }
func NewZeroRenderTarget(width, height int, flipY bool) (*RenderTarget, *Texture, error) { func NewZeroRenderTarget(width, height int) (*RenderTarget, error) {
r := &RenderTarget{ r := &RenderTarget{
width: width, width: width,
height: height, height: height,
flipY: flipY, flipY: true,
} }
// The framebuffer 0 can't be enlarged, so any filter is acceptable. return r, nil
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
} }
func NewRenderTargetFromTexture(texture *Texture) (*RenderTarget, error) { func NewRenderTargetFromTexture(texture *Texture) (*RenderTarget, error) {