mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
(Fixed) webgl
This commit is contained in:
parent
fc3a6ed373
commit
55f1a5d32e
@ -102,6 +102,7 @@ type context struct {
|
||||
|
||||
locationCache *locationCache
|
||||
screenFramebuffer framebufferNative // This might not be the default frame buffer '0' (e.g. iOS).
|
||||
mrtFramebuffer framebufferNative // The dynamic framebuffer used for MRT operations
|
||||
lastFramebuffer framebufferNative
|
||||
lastTexture textureNative
|
||||
lastRenderbuffer renderbufferNative
|
||||
@ -110,8 +111,6 @@ type context struct {
|
||||
lastBlend graphicsdriver.Blend
|
||||
maxTextureSize int
|
||||
maxTextureSizeOnce sync.Once
|
||||
highp bool
|
||||
highpOnce sync.Once
|
||||
initOnce sync.Once
|
||||
}
|
||||
|
||||
@ -139,26 +138,25 @@ func (c *context) bindFramebuffer(f framebufferNative) {
|
||||
c.lastFramebuffer = f
|
||||
}
|
||||
|
||||
func (c *context) setViewport(f *framebuffer) {
|
||||
c.bindFramebuffer(f.native)
|
||||
if c.lastViewportWidth == f.width && c.lastViewportHeight == f.height {
|
||||
func (c *context) setViewport(width, height int, screen bool) {
|
||||
if c.lastViewportWidth == width && c.lastViewportHeight == height {
|
||||
return
|
||||
}
|
||||
|
||||
// On some environments, viewport size must be within the framebuffer size.
|
||||
// e.g. Edge (#71), Chrome on GPD Pocket (#420), macOS Mojave (#691).
|
||||
// Use the same size of the framebuffer here.
|
||||
c.ctx.Viewport(0, 0, int32(f.width), int32(f.height))
|
||||
c.ctx.Viewport(0, 0, int32(width), int32(height))
|
||||
|
||||
// glViewport must be called at least at every frame on iOS.
|
||||
// As the screen framebuffer is the last render target, next SetViewport should be
|
||||
// the first call at a frame.
|
||||
if f.native == c.screenFramebuffer {
|
||||
if screen {
|
||||
c.lastViewportWidth = 0
|
||||
c.lastViewportHeight = 0
|
||||
} else {
|
||||
c.lastViewportWidth = f.width
|
||||
c.lastViewportHeight = f.height
|
||||
c.lastViewportWidth = width
|
||||
c.lastViewportHeight = height
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,16 +262,6 @@ func (c *context) framebufferPixels(buf []byte, f *framebuffer, region image.Rec
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *context) framebufferPixelsToBuffer(f *framebuffer, buffer buffer, width, height int) {
|
||||
c.ctx.Flush()
|
||||
|
||||
c.bindFramebuffer(f.native)
|
||||
|
||||
c.ctx.BindBuffer(gl.PIXEL_PACK_BUFFER, uint32(buffer))
|
||||
c.ctx.ReadPixels(nil, 0, 0, int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE)
|
||||
c.ctx.BindBuffer(gl.PIXEL_PACK_BUFFER, 0)
|
||||
}
|
||||
|
||||
func (c *context) deleteTexture(t textureNative) {
|
||||
if c.lastTexture == t {
|
||||
c.lastTexture = 0
|
||||
@ -357,7 +345,7 @@ func (c *context) bindStencilBuffer(f framebufferNative, r renderbufferNative) e
|
||||
|
||||
c.ctx.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, uint32(r))
|
||||
if s := c.ctx.CheckFramebufferStatus(gl.FRAMEBUFFER); s != gl.FRAMEBUFFER_COMPLETE {
|
||||
return errors.New(fmt.Sprintf("opengl: glFramebufferRenderbuffer failed: %d", s))
|
||||
return fmt.Errorf("opengl: glFramebufferRenderbuffer failed: %d", s)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ const (
|
||||
MIN = 0x8007
|
||||
NEAREST = 0x2600
|
||||
NO_ERROR = 0
|
||||
NONE = 0
|
||||
NOTEQUAL = 0x0205
|
||||
ONE = 1
|
||||
ONE_MINUS_DST_ALPHA = 0x0305
|
||||
|
@ -54,6 +54,7 @@ type defaultContext struct {
|
||||
fnDeleteVertexArray js.Value
|
||||
fnDisable js.Value
|
||||
fnDisableVertexAttribArray js.Value
|
||||
fnDrawBuffers js.Value
|
||||
fnDrawElements js.Value
|
||||
fnEnable js.Value
|
||||
fnEnableVertexAttribArray js.Value
|
||||
@ -184,6 +185,7 @@ func NewDefaultContext(v js.Value) (Context, error) {
|
||||
fnDeleteVertexArray: v.Get("deleteVertexArray").Call("bind", v),
|
||||
fnDisable: v.Get("disable").Call("bind", v),
|
||||
fnDisableVertexAttribArray: v.Get("disableVertexAttribArray").Call("bind", v),
|
||||
fnDrawBuffers: v.Get("drawBuffers").Call("bind", v),
|
||||
fnDrawElements: v.Get("drawElements").Call("bind", v),
|
||||
fnEnable: v.Get("enable").Call("bind", v),
|
||||
fnEnableVertexAttribArray: v.Get("enableVertexAttribArray").Call("bind", v),
|
||||
@ -384,6 +386,11 @@ func (c *defaultContext) DisableVertexAttribArray(index uint32) {
|
||||
c.fnDisableVertexAttribArray.Invoke(index)
|
||||
}
|
||||
|
||||
func (c *defaultContext) DrawBuffers(bufs []uint32) {
|
||||
arr := jsutil.NewUint32Array(bufs)
|
||||
c.fnDrawBuffers.Invoke(arr)
|
||||
}
|
||||
|
||||
func (c *defaultContext) DrawElements(mode uint32, count int32, xtype uint32, offset int) {
|
||||
c.fnDrawElements.Invoke(mode, count, xtype, offset)
|
||||
}
|
||||
|
@ -45,8 +45,8 @@ type Graphics struct {
|
||||
// drawCalled is true just after Draw is called. This holds true until WritePixels is called.
|
||||
drawCalled bool
|
||||
|
||||
uniformVariableNameCache map[int]string
|
||||
textureVariableNameCache map[int]string
|
||||
uniformVariableNameCache map[int]string
|
||||
textureVariableNameCache map[int]string
|
||||
|
||||
uniformVars []uniformVariable
|
||||
|
||||
@ -204,9 +204,9 @@ func (g *Graphics) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphicsdr
|
||||
}
|
||||
|
||||
g.drawCalled = true
|
||||
|
||||
g.context.ctx.BindTexture(gl.TEXTURE_2D, 0)
|
||||
dstCount := 0
|
||||
var destinations [graphics.ShaderDstImageCount]*Image
|
||||
var dsts [graphics.ShaderDstImageCount]*Image
|
||||
for i, dstID := range dstIDs {
|
||||
if dstID == graphicsdriver.InvalidImageID {
|
||||
continue
|
||||
@ -215,27 +215,66 @@ func (g *Graphics) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphicsdr
|
||||
if dst == nil {
|
||||
continue
|
||||
}
|
||||
destinations[i] = dst
|
||||
dst.ensureFramebuffer()
|
||||
dsts[i] = dst
|
||||
dstCount++
|
||||
}
|
||||
if dstCount == 0 {
|
||||
return nil
|
||||
}
|
||||
g.context.bindFramebuffer(0)
|
||||
|
||||
// Only necessary for the same shared framebuffer
|
||||
if err := destinations[0].setViewport(); err != nil {
|
||||
return err
|
||||
f := uint32(dsts[0].framebuffer.native)
|
||||
if dstCount > 1 {
|
||||
if g.context.mrtFramebuffer == 0 {
|
||||
f = g.context.ctx.CreateFramebuffer()
|
||||
if f <= 0 {
|
||||
return fmt.Errorf("opengl: creating framebuffer failed: the returned value is not positive but %d", f)
|
||||
}
|
||||
g.context.mrtFramebuffer = framebufferNative(f)
|
||||
} else {
|
||||
f = uint32(g.context.mrtFramebuffer)
|
||||
}
|
||||
|
||||
g.context.bindFramebuffer(framebufferNative(f))
|
||||
//g.context.ctx.BindFramebuffer(gl.FRAMEBUFFER, f)
|
||||
|
||||
// Reset color attachments
|
||||
if s := g.context.ctx.CheckFramebufferStatus(gl.FRAMEBUFFER); s == gl.FRAMEBUFFER_COMPLETE {
|
||||
g.context.ctx.Clear(16384 | gl.STENCIL_BUFFER_BIT)
|
||||
}
|
||||
for i, dst := range dsts {
|
||||
if dst == nil {
|
||||
continue
|
||||
}
|
||||
g.context.ctx.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0+uint32(i), gl.TEXTURE_2D, uint32(dst.texture), 0)
|
||||
}
|
||||
if s := g.context.ctx.CheckFramebufferStatus(gl.FRAMEBUFFER); s != gl.FRAMEBUFFER_COMPLETE {
|
||||
if s != 0 {
|
||||
return fmt.Errorf("opengl: creating framebuffer failed: %v", s)
|
||||
}
|
||||
if e := g.context.ctx.GetError(); e != gl.NO_ERROR {
|
||||
return fmt.Errorf("opengl: creating framebuffer failed: (glGetError) %d", e)
|
||||
}
|
||||
return fmt.Errorf("opengl: creating framebuffer failed: unknown error")
|
||||
}
|
||||
// Color attachments
|
||||
var attached []uint32
|
||||
for i, dst := range dsts {
|
||||
if dst == nil {
|
||||
attached = append(attached, gl.NONE)
|
||||
continue
|
||||
}
|
||||
attached = append(attached, uint32(gl.COLOR_ATTACHMENT0+i))
|
||||
}
|
||||
g.context.ctx.DrawBuffers(attached)
|
||||
} else {
|
||||
g.context.bindFramebuffer(framebufferNative(f))
|
||||
}
|
||||
|
||||
// Color attachments
|
||||
var attached []uint32
|
||||
for i, dst := range destinations {
|
||||
if dst == nil {
|
||||
continue
|
||||
}
|
||||
attached = append(attached, uint32(gl.COLOR_ATTACHMENT0+i))
|
||||
g.context.ctx.FramebufferTexture2D(gl.FRAMEBUFFER, uint32(gl.COLOR_ATTACHMENT0+i), gl.TEXTURE_2D, uint32(dst.texture), 0)
|
||||
}
|
||||
g.context.ctx.DrawBuffers(attached)
|
||||
w, h := dsts[0].framebufferSize()
|
||||
g.context.setViewport(w, h, dsts[0].screen)
|
||||
|
||||
g.context.blend(blend)
|
||||
|
||||
@ -259,7 +298,7 @@ func (g *Graphics) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphicsdr
|
||||
}
|
||||
|
||||
// In OpenGL, the NDC's Y direction is upward, so flip the Y direction for the final framebuffer.
|
||||
if dstCount == 1 && destinations[0] != nil && destinations[0].screen {
|
||||
if dstCount == 1 && dsts[0] != nil && dsts[0].screen {
|
||||
const idx = graphics.ProjectionMatrixUniformVariableIndex
|
||||
// Invert the sign bits as float32 values.
|
||||
g.uniformVars[idx].value[1] ^= 1 << 31
|
||||
@ -287,11 +326,11 @@ func (g *Graphics) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphicsdr
|
||||
g.uniformVars = g.uniformVars[:0]
|
||||
|
||||
if fillRule != graphicsdriver.FillAll {
|
||||
for _, dst := range destinations {
|
||||
for _, dst := range dsts {
|
||||
if dst == nil {
|
||||
continue
|
||||
}
|
||||
if err := dst.ensureStencilBuffer(); err != nil {
|
||||
if err := dst.ensureStencilBuffer(framebufferNative(f)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -336,6 +375,10 @@ func (g *Graphics) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphicsdr
|
||||
g.context.ctx.Disable(gl.STENCIL_TEST)
|
||||
}
|
||||
|
||||
// Detach existing color attachments
|
||||
//g.context.bindFramebuffer(fb)
|
||||
//TODO:
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,6 @@ type Image struct {
|
||||
|
||||
// framebuffer is a wrapper of OpenGL's framebuffer.
|
||||
type framebuffer struct {
|
||||
graphics *Graphics
|
||||
native framebufferNative
|
||||
width int
|
||||
height int
|
||||
@ -61,14 +60,6 @@ func (i *Image) Dispose() {
|
||||
i.graphics.removeImage(i)
|
||||
}
|
||||
|
||||
func (i *Image) setViewport() error {
|
||||
if err := i.ensureFramebuffer(); err != nil {
|
||||
return err
|
||||
}
|
||||
i.graphics.context.setViewport(i.framebuffer)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Image) ReadPixels(args []graphicsdriver.PixelsArgs) error {
|
||||
if err := i.ensureFramebuffer(); err != nil {
|
||||
return err
|
||||
@ -109,14 +100,14 @@ func (i *Image) ensureFramebuffer() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Image) ensureStencilBuffer() error {
|
||||
func (i *Image) ensureStencilBuffer(f framebufferNative) error {
|
||||
if i.stencil != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := i.ensureFramebuffer(); err != nil {
|
||||
/*if err := i.ensureFramebuffer(); err != nil {
|
||||
return err
|
||||
}
|
||||
}*/
|
||||
|
||||
r, err := i.graphics.context.newRenderbuffer(i.framebufferSize())
|
||||
if err != nil {
|
||||
@ -124,7 +115,7 @@ func (i *Image) ensureStencilBuffer() error {
|
||||
}
|
||||
i.stencil = r
|
||||
|
||||
if err := i.graphics.context.bindStencilBuffer(i.framebuffer.native, i.stencil); err != nil {
|
||||
if err := i.graphics.context.bindStencilBuffer(f, i.stencil); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -24,6 +24,7 @@ var (
|
||||
uint8Array = js.Global().Get("Uint8Array")
|
||||
float32Array = js.Global().Get("Float32Array")
|
||||
int32Array = js.Global().Get("Int32Array")
|
||||
uint32Array = js.Global().Get("Uint32Array")
|
||||
)
|
||||
|
||||
var (
|
||||
@ -40,8 +41,11 @@ var (
|
||||
// temporaryFloat32Array is a Float32ArrayBuffer whose underlying buffer is always temporaryArrayBuffer.
|
||||
temporaryFloat32Array = float32Array.New(temporaryArrayBuffer)
|
||||
|
||||
// temporaryInt32Array is a Float32ArrayBuffer whose underlying buffer is always temporaryArrayBuffer.
|
||||
// temporaryInt32Array is a Int32ArrayBuffer whose underlying buffer is always temporaryArrayBuffer.
|
||||
temporaryInt32Array = int32Array.New(temporaryArrayBuffer)
|
||||
|
||||
// temporaryUint32Array is a Uint32ArrayBuffer whose underlying buffer is always temporaryArrayBuffer.
|
||||
temporaryUint32Array = uint32Array.New(temporaryArrayBuffer)
|
||||
)
|
||||
|
||||
func ensureTemporaryArrayBufferSize(byteLength int) {
|
||||
@ -54,6 +58,7 @@ func ensureTemporaryArrayBufferSize(byteLength int) {
|
||||
temporaryUint8Array = uint8Array.New(temporaryArrayBuffer)
|
||||
temporaryFloat32Array = float32Array.New(temporaryArrayBuffer)
|
||||
temporaryInt32Array = int32Array.New(temporaryArrayBuffer)
|
||||
temporaryUint32Array = uint32Array.New(temporaryArrayBuffer)
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,3 +106,11 @@ func TemporaryInt32Array(minLength int, data []int32) js.Value {
|
||||
copySliceToTemporaryArrayBuffer(data)
|
||||
return temporaryInt32Array
|
||||
}
|
||||
|
||||
// NewUint32Array returns a Uint32Array whose length is equal to the length of data.
|
||||
func NewUint32Array(data []uint32) js.Value {
|
||||
ensureTemporaryArrayBufferSize(len(data) * 4)
|
||||
copySliceToTemporaryArrayBuffer(data)
|
||||
a := temporaryUint32Array.Call("slice", 0, len(data))
|
||||
return a
|
||||
}
|
||||
|
@ -229,6 +229,12 @@ func Compile(p *shaderir.Program, version GLSLVersion) (vertexShader, fragmentSh
|
||||
fslines = append(fslines, fmt.Sprintf("in %s;", c.varDecl(p, &t, fmt.Sprintf("V%d", i))))
|
||||
}
|
||||
}
|
||||
// If ES300 out colors need to be defined explicitely
|
||||
if version == GLSLVersionES300 {
|
||||
for i := 0; i < p.ColorsOutCount; i++ {
|
||||
fslines = append(fslines, fmt.Sprintf("layout(location = %d) out vec4 glFragColor%d;", i, i))
|
||||
}
|
||||
}
|
||||
|
||||
var funcs []*shaderir.Func
|
||||
if p.VertexFunc.Block != nil {
|
||||
@ -420,6 +426,9 @@ func (c *compileContext) localVariableName(p *shaderir.Program, topBlock *shader
|
||||
case idx < nv+1:
|
||||
return fmt.Sprintf("V%d", idx-1)
|
||||
default:
|
||||
if c.version == GLSLVersionES300 {
|
||||
return fmt.Sprintf("glFragColor%d", idx-(nv+1))
|
||||
}
|
||||
return fmt.Sprintf("gl_FragData[%d]", idx-(nv+1))
|
||||
}
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user