mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 02:38:53 +01:00
opengl: Hide OpenGL context usages into internal/graphics package
This commit is contained in:
parent
62b364de2d
commit
7d181e3182
@ -16,12 +16,9 @@ package ebiten
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/internal/opengl"
|
||||
"github.com/hajimehoshi/ebiten/internal/restorable"
|
||||
"github.com/hajimehoshi/ebiten/internal/ui"
|
||||
)
|
||||
|
||||
func newGraphicsContext(f func(*Image) error) *graphicsContext {
|
||||
@ -36,17 +33,10 @@ type graphicsContext struct {
|
||||
offscreen2 *Image // TODO: better name
|
||||
screen *Image
|
||||
screenScale float64
|
||||
initialized int32
|
||||
initialized bool
|
||||
invalidated bool // browser only
|
||||
}
|
||||
|
||||
func (c *graphicsContext) GLContext() *opengl.Context {
|
||||
if atomic.LoadInt32(&c.initialized) == 0 {
|
||||
return nil
|
||||
}
|
||||
return ui.GLContext()
|
||||
}
|
||||
|
||||
func (c *graphicsContext) Invalidate() {
|
||||
// Note that this is called only on browsers so far.
|
||||
// TODO: On mobiles, this function is not called and instead IsTexture is called
|
||||
@ -100,21 +90,21 @@ func (c *graphicsContext) SetSize(screenWidth, screenHeight int, screenScale flo
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *graphicsContext) initializeIfNeeded(context *opengl.Context) error {
|
||||
if atomic.LoadInt32(&c.initialized) == 0 {
|
||||
if err := graphics.Reset(context); err != nil {
|
||||
func (c *graphicsContext) initializeIfNeeded() error {
|
||||
if !c.initialized {
|
||||
if err := graphics.Reset(); err != nil {
|
||||
return err
|
||||
}
|
||||
atomic.StoreInt32(&c.initialized, 1)
|
||||
c.initialized = true
|
||||
}
|
||||
r, err := c.needsRestoring(context)
|
||||
r, err := c.needsRestoring()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !r {
|
||||
return nil
|
||||
}
|
||||
if err := c.restore(context); err != nil {
|
||||
if err := c.restore(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -130,17 +120,17 @@ func drawWithFittingScale(dst *Image, src *Image) {
|
||||
_ = dst.DrawImage(src, op)
|
||||
}
|
||||
|
||||
func (c *graphicsContext) drawToDefaultRenderTarget(context *opengl.Context) error {
|
||||
func (c *graphicsContext) drawToDefaultRenderTarget() error {
|
||||
_ = c.screen.Clear()
|
||||
drawWithFittingScale(c.screen, c.offscreen2)
|
||||
if err := graphics.FlushCommands(context); err != nil {
|
||||
if err := graphics.FlushCommands(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *graphicsContext) UpdateAndDraw(context *opengl.Context, updateCount int) error {
|
||||
if err := c.initializeIfNeeded(context); err != nil {
|
||||
func (c *graphicsContext) UpdateAndDraw(updateCount int) error {
|
||||
if err := c.initializeIfNeeded(); err != nil {
|
||||
return err
|
||||
}
|
||||
for i := 0; i < updateCount; i++ {
|
||||
@ -153,21 +143,21 @@ func (c *graphicsContext) UpdateAndDraw(context *opengl.Context, updateCount int
|
||||
if 0 < updateCount {
|
||||
drawWithFittingScale(c.offscreen2, c.offscreen)
|
||||
}
|
||||
if err := c.drawToDefaultRenderTarget(context); err != nil {
|
||||
if err := c.drawToDefaultRenderTarget(); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: Add tests to check if this behavior is correct (#357)
|
||||
if err := restorable.ResolveStalePixels(context); err != nil {
|
||||
if err := restorable.ResolveStalePixels(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *graphicsContext) restore(context *opengl.Context) error {
|
||||
if err := graphics.Reset(context); err != nil {
|
||||
func (c *graphicsContext) restore() error {
|
||||
if err := graphics.Reset(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := restorable.Restore(context); err != nil {
|
||||
if err := restorable.Restore(); err != nil {
|
||||
return err
|
||||
}
|
||||
c.invalidated = false
|
||||
|
@ -16,10 +16,6 @@
|
||||
|
||||
package ebiten
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten/internal/opengl"
|
||||
)
|
||||
|
||||
func (c *graphicsContext) needsRestoring(context *opengl.Context) (bool, error) {
|
||||
func (c *graphicsContext) needsRestoring() (bool, error) {
|
||||
return c.invalidated, nil
|
||||
}
|
||||
|
@ -18,13 +18,12 @@ package ebiten
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/internal/opengl"
|
||||
)
|
||||
|
||||
func (c *graphicsContext) needsRestoring(context *opengl.Context) (bool, error) {
|
||||
func (c *graphicsContext) needsRestoring() (bool, error) {
|
||||
// FlushCommands is required because c.offscreen.impl might not have an actual texture.
|
||||
if err := graphics.FlushCommands(context); err != nil {
|
||||
if err := graphics.FlushCommands(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return c.offscreen.restorable.IsInvalidated(context), nil
|
||||
return c.offscreen.restorable.IsInvalidated(), nil
|
||||
}
|
||||
|
14
image.go
14
image.go
@ -25,18 +25,6 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/internal/restorable"
|
||||
)
|
||||
|
||||
func glContext() *opengl.Context {
|
||||
// This is called from finalizers even when the context or the program is not set.
|
||||
g, ok := theGraphicsContext.Load().(*graphicsContext)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if g == nil {
|
||||
return nil
|
||||
}
|
||||
return g.GLContext()
|
||||
}
|
||||
|
||||
// Image represents an image.
|
||||
// The pixel format is alpha-premultiplied.
|
||||
// Image implements image.Image.
|
||||
@ -166,7 +154,7 @@ func (i *Image) At(x, y int) color.Color {
|
||||
return color.Transparent
|
||||
}
|
||||
// TODO: Error should be delayed until flushing. Do not panic here.
|
||||
clr, err := i.restorable.At(x, y, glContext())
|
||||
clr, err := i.restorable.At(x, y)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ import (
|
||||
)
|
||||
|
||||
type command interface {
|
||||
Exec(context *opengl.Context, indexOffsetInBytes int) error
|
||||
Exec(indexOffsetInBytes int) error
|
||||
}
|
||||
|
||||
type commandQueue struct {
|
||||
@ -113,11 +113,11 @@ func (q *commandQueue) commandGroups() [][]command {
|
||||
return gs
|
||||
}
|
||||
|
||||
func (q *commandQueue) Flush(context *opengl.Context) error {
|
||||
func (q *commandQueue) Flush() error {
|
||||
q.m.Lock()
|
||||
defer q.m.Unlock()
|
||||
// glViewport must be called at least at every frame on iOS.
|
||||
context.ResetViewportSize()
|
||||
opengl.GetContext().ResetViewportSize()
|
||||
n := 0
|
||||
lastN := 0
|
||||
for _, g := range q.commandGroups() {
|
||||
@ -128,7 +128,7 @@ func (q *commandQueue) Flush(context *opengl.Context) error {
|
||||
}
|
||||
}
|
||||
if 0 < n-lastN {
|
||||
context.BufferSubData(opengl.ArrayBuffer, q.vertices[lastN:n])
|
||||
opengl.GetContext().BufferSubData(opengl.ArrayBuffer, q.vertices[lastN:n])
|
||||
}
|
||||
// NOTE: WebGL doesn't seem to have Check gl.MAX_ELEMENTS_VERTICES or gl.MAX_ELEMENTS_INDICES so far.
|
||||
// Let's use them to compare to len(quads) in the future.
|
||||
@ -138,7 +138,7 @@ func (q *commandQueue) Flush(context *opengl.Context) error {
|
||||
numc := len(g)
|
||||
indexOffsetInBytes := 0
|
||||
for _, c := range g {
|
||||
if err := c.Exec(context, indexOffsetInBytes); err != nil {
|
||||
if err := c.Exec(indexOffsetInBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
if c, ok := c.(*drawImageCommand); ok {
|
||||
@ -148,7 +148,7 @@ func (q *commandQueue) Flush(context *opengl.Context) error {
|
||||
}
|
||||
if 0 < numc {
|
||||
// Call glFlush to prevent black flicking (especially on Android (#226) and iOS).
|
||||
context.Flush()
|
||||
opengl.GetContext().Flush()
|
||||
}
|
||||
lastN = n
|
||||
}
|
||||
@ -157,8 +157,8 @@ func (q *commandQueue) Flush(context *opengl.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func FlushCommands(context *opengl.Context) error {
|
||||
return theCommandQueue.Flush(context)
|
||||
func FlushCommands() error {
|
||||
return theCommandQueue.Flush()
|
||||
}
|
||||
|
||||
type fillCommand struct {
|
||||
@ -166,12 +166,12 @@ type fillCommand struct {
|
||||
color color.RGBA
|
||||
}
|
||||
|
||||
func (c *fillCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
|
||||
f, err := c.dst.createFramebufferIfNeeded(context)
|
||||
func (c *fillCommand) Exec(indexOffsetInBytes int) error {
|
||||
f, err := c.dst.createFramebufferIfNeeded()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := f.setAsViewport(context); err != nil {
|
||||
if err := f.setAsViewport(); err != nil {
|
||||
return err
|
||||
}
|
||||
cr, cg, cb, ca := c.color.R, c.color.G, c.color.B, c.color.A
|
||||
@ -180,7 +180,7 @@ func (c *fillCommand) Exec(context *opengl.Context, indexOffsetInBytes int) erro
|
||||
g := float64(cg) / max
|
||||
b := float64(cb) / max
|
||||
a := float64(ca) / max
|
||||
return context.FillFramebuffer(r, g, b, a)
|
||||
return opengl.GetContext().FillFramebuffer(r, g, b, a)
|
||||
}
|
||||
|
||||
type drawImageCommand struct {
|
||||
@ -195,15 +195,15 @@ func QuadVertexSizeInBytes() int {
|
||||
return 4 * theArrayBufferLayout.totalBytes()
|
||||
}
|
||||
|
||||
func (c *drawImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
|
||||
f, err := c.dst.createFramebufferIfNeeded(context)
|
||||
func (c *drawImageCommand) Exec(indexOffsetInBytes int) error {
|
||||
f, err := c.dst.createFramebufferIfNeeded()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := f.setAsViewport(context); err != nil {
|
||||
if err := f.setAsViewport(); err != nil {
|
||||
return err
|
||||
}
|
||||
context.BlendFunc(c.mode)
|
||||
opengl.GetContext().BlendFunc(c.mode)
|
||||
|
||||
n := c.quadsNum()
|
||||
if n == 0 {
|
||||
@ -214,7 +214,6 @@ func (c *drawImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int)
|
||||
p := &programContext{
|
||||
state: &theOpenGLState,
|
||||
program: theOpenGLState.programTexture,
|
||||
context: context,
|
||||
projectionMatrix: proj,
|
||||
texture: c.src.texture.native,
|
||||
colorM: c.color,
|
||||
@ -224,7 +223,7 @@ func (c *drawImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int)
|
||||
}
|
||||
// TODO: We should call glBindBuffer here?
|
||||
// The buffer is already bound at begin() but it is counterintuitive.
|
||||
context.DrawElements(opengl.Triangles, 6*n, indexOffsetInBytes)
|
||||
opengl.GetContext().DrawElements(opengl.Triangles, 6*n, indexOffsetInBytes)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -263,29 +262,29 @@ type replacePixelsCommand struct {
|
||||
pixels []uint8
|
||||
}
|
||||
|
||||
func (c *replacePixelsCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
|
||||
f, err := c.dst.createFramebufferIfNeeded(context)
|
||||
func (c *replacePixelsCommand) Exec(indexOffsetInBytes int) error {
|
||||
f, err := c.dst.createFramebufferIfNeeded()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := f.setAsViewport(context); err != nil {
|
||||
if err := f.setAsViewport(); err != nil {
|
||||
return err
|
||||
}
|
||||
// Filling with non black or white color is required here for glTexSubImage2D.
|
||||
// Very mysterious but this actually works (Issue #186).
|
||||
// This is needed even after fixing a shader bug at f537378f2a6a8ef56e1acf1c03034967b77c7b51.
|
||||
if err := context.FillFramebuffer(0, 0, 0.5, 1); err != nil {
|
||||
if err := opengl.GetContext().FillFramebuffer(0, 0, 0.5, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
// This is necessary on Android. We can't call glClear just before glTexSubImage2D without
|
||||
// glFlush. glTexSubImage2D didn't work without this hack at least on Nexus 5x (#211).
|
||||
// This also happens when a fillCommand precedes a replacePixelsCommand.
|
||||
// TODO: Can we have a better way like optimizing commands?
|
||||
context.Flush()
|
||||
if err := context.BindTexture(c.dst.texture.native); err != nil {
|
||||
opengl.GetContext().Flush()
|
||||
if err := opengl.GetContext().BindTexture(c.dst.texture.native); err != nil {
|
||||
return err
|
||||
}
|
||||
context.TexSubImage2D(c.pixels, NextPowerOf2Int(c.dst.width), NextPowerOf2Int(c.dst.height))
|
||||
opengl.GetContext().TexSubImage2D(c.pixels, NextPowerOf2Int(c.dst.width), NextPowerOf2Int(c.dst.height))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -293,12 +292,12 @@ type disposeCommand struct {
|
||||
target *Image
|
||||
}
|
||||
|
||||
func (c *disposeCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
|
||||
func (c *disposeCommand) Exec(indexOffsetInBytes int) error {
|
||||
if c.target.framebuffer != nil {
|
||||
context.DeleteFramebuffer(c.target.framebuffer.native)
|
||||
opengl.GetContext().DeleteFramebuffer(c.target.framebuffer.native)
|
||||
}
|
||||
if c.target.texture != nil {
|
||||
context.DeleteTexture(c.target.texture.native)
|
||||
opengl.GetContext().DeleteTexture(c.target.texture.native)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -309,7 +308,7 @@ type newImageFromImageCommand struct {
|
||||
filter opengl.Filter
|
||||
}
|
||||
|
||||
func (c *newImageFromImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
|
||||
func (c *newImageFromImageCommand) Exec(indexOffsetInBytes int) error {
|
||||
origSize := c.img.Bounds().Size()
|
||||
if origSize.X < 1 {
|
||||
return errors.New("graphics: width must be equal or more than 1.")
|
||||
@ -321,7 +320,7 @@ func (c *newImageFromImageCommand) Exec(context *opengl.Context, indexOffsetInBy
|
||||
if c.img.Bounds() != image.Rect(0, 0, NextPowerOf2Int(w), NextPowerOf2Int(h)) {
|
||||
panic(fmt.Sprintf("graphics: invalid image bounds: %v", c.img.Bounds()))
|
||||
}
|
||||
native, err := context.NewTexture(w, h, c.img.Pix, c.filter)
|
||||
native, err := opengl.GetContext().NewTexture(w, h, c.img.Pix, c.filter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -338,7 +337,7 @@ type newImageCommand struct {
|
||||
filter opengl.Filter
|
||||
}
|
||||
|
||||
func (c *newImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
|
||||
func (c *newImageCommand) Exec(indexOffsetInBytes int) error {
|
||||
w := NextPowerOf2Int(c.width)
|
||||
h := NextPowerOf2Int(c.height)
|
||||
if w < 1 {
|
||||
@ -347,7 +346,7 @@ func (c *newImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int)
|
||||
if h < 1 {
|
||||
return errors.New("graphics: height must be equal or more than 1.")
|
||||
}
|
||||
native, err := context.NewTexture(w, h, nil, c.filter)
|
||||
native, err := opengl.GetContext().NewTexture(w, h, nil, c.filter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -363,7 +362,7 @@ type newScreenFramebufferImageCommand struct {
|
||||
height int
|
||||
}
|
||||
|
||||
func (c *newScreenFramebufferImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error {
|
||||
func (c *newScreenFramebufferImageCommand) Exec(indexOffsetInBytes int) error {
|
||||
if c.width < 1 {
|
||||
return errors.New("graphics: width must be equal or more than 1.")
|
||||
}
|
||||
@ -371,7 +370,7 @@ func (c *newScreenFramebufferImageCommand) Exec(context *opengl.Context, indexOf
|
||||
return errors.New("graphics: height must be equal or more than 1.")
|
||||
}
|
||||
f := &framebuffer{
|
||||
native: context.ScreenFramebuffer(),
|
||||
native: opengl.GetContext().ScreenFramebuffer(),
|
||||
flipY: true,
|
||||
}
|
||||
c.result.framebuffer = f
|
||||
|
@ -38,8 +38,8 @@ type framebuffer struct {
|
||||
proMatrix []float32
|
||||
}
|
||||
|
||||
func newFramebufferFromTexture(context *opengl.Context, texture *texture) (*framebuffer, error) {
|
||||
native, err := context.NewFramebuffer(opengl.Texture(texture.native))
|
||||
func newFramebufferFromTexture(texture *texture) (*framebuffer, error) {
|
||||
native, err := opengl.GetContext().NewFramebuffer(opengl.Texture(texture.native))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -50,10 +50,10 @@ func newFramebufferFromTexture(context *opengl.Context, texture *texture) (*fram
|
||||
|
||||
const viewportSize = 4096
|
||||
|
||||
func (f *framebuffer) setAsViewport(context *opengl.Context) error {
|
||||
func (f *framebuffer) setAsViewport() error {
|
||||
width := viewportSize
|
||||
height := viewportSize
|
||||
return context.SetViewport(f.native, width, height)
|
||||
return opengl.GetContext().SetViewport(f.native, width, height)
|
||||
}
|
||||
|
||||
func (f *framebuffer) projectionMatrix(height int) []float32 {
|
||||
|
@ -145,16 +145,16 @@ func (i *Image) DrawImage(src *Image, vertices []float32, clr *affine.ColorM, mo
|
||||
theCommandQueue.EnqueueDrawImageCommand(i, src, vertices, clr, mode)
|
||||
}
|
||||
|
||||
func (i *Image) Pixels(context *opengl.Context) ([]uint8, error) {
|
||||
func (i *Image) Pixels() ([]uint8, error) {
|
||||
// Flush the enqueued commands so that pixels are certainly read.
|
||||
if err := theCommandQueue.Flush(context); err != nil {
|
||||
if err := theCommandQueue.Flush(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err := i.createFramebufferIfNeeded(context)
|
||||
f, err := i.createFramebufferIfNeeded()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return context.FramebufferPixels(f.native, NextPowerOf2Int(i.width), NextPowerOf2Int(i.height))
|
||||
return opengl.GetContext().FramebufferPixels(f.native, NextPowerOf2Int(i.width), NextPowerOf2Int(i.height))
|
||||
}
|
||||
|
||||
func (i *Image) ReplacePixels(p []uint8) {
|
||||
@ -167,15 +167,15 @@ func (i *Image) ReplacePixels(p []uint8) {
|
||||
theCommandQueue.Enqueue(c)
|
||||
}
|
||||
|
||||
func (i *Image) IsInvalidated(context *opengl.Context) bool {
|
||||
return !context.IsTexture(i.texture.native)
|
||||
func (i *Image) IsInvalidated() bool {
|
||||
return !opengl.GetContext().IsTexture(i.texture.native)
|
||||
}
|
||||
|
||||
func (i *Image) createFramebufferIfNeeded(context *opengl.Context) (*framebuffer, error) {
|
||||
func (i *Image) createFramebufferIfNeeded() (*framebuffer, error) {
|
||||
if i.framebuffer != nil {
|
||||
return i.framebuffer, nil
|
||||
}
|
||||
f, err := newFramebufferFromTexture(context, i.texture)
|
||||
f, err := newFramebufferFromTexture(i.texture)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -46,26 +46,26 @@ func (a *arrayBufferLayout) totalBytes() int {
|
||||
return a.total
|
||||
}
|
||||
|
||||
func (a *arrayBufferLayout) newArrayBuffer(c *opengl.Context) opengl.Buffer {
|
||||
return c.NewBuffer(opengl.ArrayBuffer, a.totalBytes()*4*maxQuads, opengl.DynamicDraw)
|
||||
func (a *arrayBufferLayout) newArrayBuffer() opengl.Buffer {
|
||||
return opengl.GetContext().NewBuffer(opengl.ArrayBuffer, a.totalBytes()*4*maxQuads, opengl.DynamicDraw)
|
||||
}
|
||||
|
||||
func (a *arrayBufferLayout) enable(c *opengl.Context, program opengl.Program) {
|
||||
func (a *arrayBufferLayout) enable(program opengl.Program) {
|
||||
for _, p := range a.parts {
|
||||
c.EnableVertexAttribArray(program, p.name)
|
||||
opengl.GetContext().EnableVertexAttribArray(program, p.name)
|
||||
}
|
||||
total := a.totalBytes()
|
||||
offset := 0
|
||||
for _, p := range a.parts {
|
||||
c.VertexAttribPointer(program, p.name, p.num, p.dataType, p.normalize, total, offset)
|
||||
opengl.GetContext().VertexAttribPointer(program, p.name, p.num, p.dataType, p.normalize, total, offset)
|
||||
offset += p.dataType.SizeInBytes() * p.num
|
||||
}
|
||||
}
|
||||
|
||||
func (a *arrayBufferLayout) disable(c *opengl.Context, program opengl.Program) {
|
||||
func (a *arrayBufferLayout) disable(program opengl.Program) {
|
||||
// TODO: Disabling should be done in reversed order?
|
||||
for _, p := range a.parts {
|
||||
c.DisableVertexAttribArray(program, p.name)
|
||||
opengl.GetContext().DisableVertexAttribArray(program, p.name)
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,12 +125,12 @@ const (
|
||||
maxQuads = indicesNum / 6
|
||||
)
|
||||
|
||||
func Reset(context *opengl.Context) error {
|
||||
return theOpenGLState.reset(context)
|
||||
func Reset() error {
|
||||
return theOpenGLState.reset()
|
||||
}
|
||||
|
||||
func (s *openGLState) reset(context *opengl.Context) error {
|
||||
if err := context.Reset(); err != nil {
|
||||
func (s *openGLState) reset() error {
|
||||
if err := opengl.GetContext().Reset(); err != nil {
|
||||
return err
|
||||
}
|
||||
s.lastProgram = zeroProgram
|
||||
@ -138,19 +138,19 @@ func (s *openGLState) reset(context *opengl.Context) error {
|
||||
s.lastColorMatrix = nil
|
||||
s.lastColorMatrixTranslation = nil
|
||||
|
||||
shaderVertexModelviewNative, err := context.NewShader(opengl.VertexShader, shader(context, shaderVertexModelview))
|
||||
shaderVertexModelviewNative, err := opengl.GetContext().NewShader(opengl.VertexShader, shader(shaderVertexModelview))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("graphics: shader compiling error:\n%s", err))
|
||||
}
|
||||
defer context.DeleteShader(shaderVertexModelviewNative)
|
||||
defer opengl.GetContext().DeleteShader(shaderVertexModelviewNative)
|
||||
|
||||
shaderFragmentTextureNative, err := context.NewShader(opengl.FragmentShader, shader(context, shaderFragmentTexture))
|
||||
shaderFragmentTextureNative, err := opengl.GetContext().NewShader(opengl.FragmentShader, shader(shaderFragmentTexture))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("graphics: shader compiling error:\n%s", err))
|
||||
}
|
||||
defer context.DeleteShader(shaderFragmentTextureNative)
|
||||
defer opengl.GetContext().DeleteShader(shaderFragmentTextureNative)
|
||||
|
||||
s.programTexture, err = context.NewProgram([]opengl.Shader{
|
||||
s.programTexture, err = opengl.GetContext().NewProgram([]opengl.Shader{
|
||||
shaderVertexModelviewNative,
|
||||
shaderFragmentTextureNative,
|
||||
})
|
||||
@ -158,7 +158,7 @@ func (s *openGLState) reset(context *opengl.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
s.arrayBuffer = theArrayBufferLayout.newArrayBuffer(context)
|
||||
s.arrayBuffer = theArrayBufferLayout.newArrayBuffer()
|
||||
|
||||
indices := make([]uint16, 6*maxQuads)
|
||||
for i := uint16(0); i < maxQuads; i++ {
|
||||
@ -169,7 +169,7 @@ func (s *openGLState) reset(context *opengl.Context) error {
|
||||
indices[6*i+4] = 4*i + 2
|
||||
indices[6*i+5] = 4*i + 3
|
||||
}
|
||||
s.indexBufferQuads = context.NewBuffer(opengl.ElementArrayBuffer, indices, opengl.StaticDraw)
|
||||
s.indexBufferQuads = opengl.GetContext().NewBuffer(opengl.ElementArrayBuffer, indices, opengl.StaticDraw)
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -189,20 +189,19 @@ func areSameFloat32Array(a, b []float32) bool {
|
||||
type programContext struct {
|
||||
state *openGLState
|
||||
program opengl.Program
|
||||
context *opengl.Context
|
||||
projectionMatrix []float32
|
||||
texture opengl.Texture
|
||||
colorM affine.ColorM
|
||||
}
|
||||
|
||||
func (p *programContext) begin() error {
|
||||
c := p.context
|
||||
c := opengl.GetContext()
|
||||
if p.state.lastProgram != p.program {
|
||||
c.UseProgram(p.program)
|
||||
if p.state.lastProgram != zeroProgram {
|
||||
theArrayBufferLayout.disable(c, p.state.lastProgram)
|
||||
theArrayBufferLayout.disable(p.state.lastProgram)
|
||||
}
|
||||
theArrayBufferLayout.enable(c, p.program)
|
||||
theArrayBufferLayout.enable(p.program)
|
||||
|
||||
p.state.lastProgram = p.state.programTexture
|
||||
p.state.lastProjectionMatrix = nil
|
||||
|
@ -27,9 +27,9 @@ const (
|
||||
shaderFragmentTexture
|
||||
)
|
||||
|
||||
func shader(c *opengl.Context, id shaderId) string {
|
||||
func shader(id shaderId) string {
|
||||
str := shaders[id]
|
||||
if !c.GlslHighpSupported() {
|
||||
if !opengl.GetContext().GlslHighpSupported() {
|
||||
str = strings.Replace(str, "highp ", "", -1)
|
||||
str = strings.Replace(str, "lowp ", "", -1)
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/internal/opengl"
|
||||
"github.com/hajimehoshi/ebiten/internal/sync"
|
||||
"github.com/hajimehoshi/ebiten/internal/ui"
|
||||
)
|
||||
@ -76,7 +75,7 @@ func (c *runContext) updateFPS(fps float64) {
|
||||
|
||||
type GraphicsContext interface {
|
||||
SetSize(width, height int, scale float64) error
|
||||
UpdateAndDraw(context *opengl.Context, updateCount int) error
|
||||
UpdateAndDraw(updateCount int) error
|
||||
Invalidate()
|
||||
}
|
||||
|
||||
@ -150,7 +149,7 @@ func (c *runContext) render(g GraphicsContext) error {
|
||||
if tt == 0 && (int64(time.Second)/int64(fps)-int64(5*time.Millisecond)) < t {
|
||||
tt = 1
|
||||
}
|
||||
if err := g.UpdateAndDraw(ui.GLContext(), tt); err != nil {
|
||||
if err := g.UpdateAndDraw(tt); err != nil {
|
||||
return err
|
||||
}
|
||||
c.lastUpdated += int64(tt) * int64(time.Second) / int64(fps)
|
||||
|
@ -47,6 +47,12 @@ type Context struct {
|
||||
context
|
||||
}
|
||||
|
||||
var theContext *Context
|
||||
|
||||
func GetContext() *Context {
|
||||
return theContext
|
||||
}
|
||||
|
||||
func (c *Context) BindTexture(t Texture) error {
|
||||
if c.lastTexture == t {
|
||||
return nil
|
||||
|
@ -73,10 +73,10 @@ type context struct {
|
||||
runOnMainThread func(func() error) error
|
||||
}
|
||||
|
||||
func NewContext(runOnMainThread func(func() error) error) (*Context, error) {
|
||||
func Init(runOnMainThread func(func() error) error) {
|
||||
c := &Context{}
|
||||
c.runOnMainThread = runOnMainThread
|
||||
return c, nil
|
||||
theContext = c
|
||||
}
|
||||
|
||||
func (c *Context) runOnContextThread(f func() error) error {
|
||||
|
@ -91,7 +91,7 @@ type context struct {
|
||||
lastProgramID programID
|
||||
}
|
||||
|
||||
func NewContext() (*Context, error) {
|
||||
func Init() error {
|
||||
var gl *webgl.Context
|
||||
|
||||
if js.Global.Get("require") == js.Undefined {
|
||||
@ -103,7 +103,7 @@ func NewContext() (*Context, error) {
|
||||
PremultipliedAlpha: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// TODO: Now Ebiten with headless-gl doesn't work well (#141).
|
||||
@ -126,7 +126,8 @@ func NewContext() (*Context, error) {
|
||||
c.loseContext.Call("loseContext")
|
||||
})
|
||||
}
|
||||
return c, nil
|
||||
theContext = c
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Context) Reset() error {
|
||||
|
@ -72,10 +72,10 @@ type context struct {
|
||||
worker mgl.Worker
|
||||
}
|
||||
|
||||
func NewContext() (*Context, error) {
|
||||
func Init() {
|
||||
c := &Context{}
|
||||
c.gl, c.worker = mgl.NewContext()
|
||||
return c, nil
|
||||
theContext = c
|
||||
}
|
||||
|
||||
func (c *Context) DoWork(chError <-chan error, chDone <-chan struct{}) error {
|
||||
|
@ -167,14 +167,14 @@ func (p *Image) appendDrawImageHistory(image *Image, vertices []float32, colorm
|
||||
// At returns a color value at (x, y).
|
||||
//
|
||||
// Note that this must not be called until context is available.
|
||||
func (p *Image) At(x, y int, context *opengl.Context) (color.RGBA, error) {
|
||||
func (p *Image) At(x, y int) (color.RGBA, error) {
|
||||
w, h := p.image.Size()
|
||||
w2, h2 := graphics.NextPowerOf2Int(w), graphics.NextPowerOf2Int(h)
|
||||
if x < 0 || y < 0 || w2 <= x || h2 <= y {
|
||||
return color.RGBA{}, nil
|
||||
}
|
||||
if p.basePixels == nil || p.drawImageHistory != nil || p.stale {
|
||||
if err := p.readPixelsFromGPU(p.image, context); err != nil {
|
||||
if err := p.readPixelsFromGPU(p.image); err != nil {
|
||||
return color.RGBA{}, err
|
||||
}
|
||||
}
|
||||
@ -195,9 +195,9 @@ func (p *Image) makeStaleIfDependingOn(target *Image) {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Image) readPixelsFromGPU(image *graphics.Image, context *opengl.Context) error {
|
||||
func (p *Image) readPixelsFromGPU(image *graphics.Image) error {
|
||||
var err error
|
||||
p.basePixels, err = image.Pixels(context)
|
||||
p.basePixels, err = image.Pixels()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -207,14 +207,14 @@ func (p *Image) readPixelsFromGPU(image *graphics.Image, context *opengl.Context
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Image) resolveStalePixels(context *opengl.Context) error {
|
||||
func (p *Image) resolveStalePixels() error {
|
||||
if p.volatile {
|
||||
return nil
|
||||
}
|
||||
if !p.stale {
|
||||
return nil
|
||||
}
|
||||
return p.readPixelsFromGPU(p.image, context)
|
||||
return p.readPixelsFromGPU(p.image)
|
||||
}
|
||||
|
||||
func (p *Image) hasDependency() bool {
|
||||
@ -225,7 +225,7 @@ func (p *Image) hasDependency() bool {
|
||||
}
|
||||
|
||||
// Restore restores *graphics.Image from the pixels using its state.
|
||||
func (p *Image) restore(context *opengl.Context) error {
|
||||
func (p *Image) restore() error {
|
||||
w, h := p.image.Size()
|
||||
if p.screen {
|
||||
// The screen image should also be recreated because framebuffer might
|
||||
@ -273,7 +273,7 @@ func (p *Image) restore(context *opengl.Context) error {
|
||||
p.image = gimg
|
||||
|
||||
var err error
|
||||
p.basePixels, err = gimg.Pixels(context)
|
||||
p.basePixels, err = gimg.Pixels()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -295,6 +295,6 @@ func (p *Image) Dispose() {
|
||||
runtime.SetFinalizer(p, nil)
|
||||
}
|
||||
|
||||
func (p *Image) IsInvalidated(context *opengl.Context) bool {
|
||||
return p.image.IsInvalidated(context)
|
||||
func (p *Image) IsInvalidated() bool {
|
||||
return p.image.IsInvalidated()
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
package restorable
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten/internal/opengl"
|
||||
"github.com/hajimehoshi/ebiten/internal/sync"
|
||||
)
|
||||
|
||||
@ -29,12 +28,12 @@ var theImages = &images{
|
||||
images: map[*Image]struct{}{},
|
||||
}
|
||||
|
||||
func ResolveStalePixels(context *opengl.Context) error {
|
||||
return theImages.resolveStalePixels(context)
|
||||
func ResolveStalePixels() error {
|
||||
return theImages.resolveStalePixels()
|
||||
}
|
||||
|
||||
func Restore(context *opengl.Context) error {
|
||||
return theImages.restore(context)
|
||||
func Restore() error {
|
||||
return theImages.restore()
|
||||
}
|
||||
|
||||
func ClearVolatileImages() {
|
||||
@ -53,12 +52,12 @@ func (i *images) remove(img *Image) {
|
||||
delete(i.images, img)
|
||||
}
|
||||
|
||||
func (i *images) resolveStalePixels(context *opengl.Context) error {
|
||||
func (i *images) resolveStalePixels() error {
|
||||
i.m.Lock()
|
||||
defer i.m.Unlock()
|
||||
i.lastChecked = nil
|
||||
for img := range i.images {
|
||||
if err := img.resolveStalePixels(context); err != nil {
|
||||
if err := img.resolveStalePixels(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -86,7 +85,7 @@ func (i *images) resetPixelsIfDependingOn(target *Image) {
|
||||
i.m.Unlock()
|
||||
}
|
||||
|
||||
func (i *images) restore(context *opengl.Context) error {
|
||||
func (i *images) restore() error {
|
||||
i.m.Lock()
|
||||
defer i.m.Unlock()
|
||||
// Framebuffers/textures cannot be disposed since framebuffers/textures that
|
||||
@ -102,12 +101,12 @@ func (i *images) restore(context *opengl.Context) error {
|
||||
}
|
||||
// Images depending on other images should be processed first.
|
||||
for _, img := range imagesWithoutDependency {
|
||||
if err := img.restore(context); err != nil {
|
||||
if err := img.restore(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, img := range imagesWithDependency {
|
||||
if err := img.restore(context); err != nil {
|
||||
if err := img.restore(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
// Copyright 2016 The Ebiten Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package ui
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten/internal/opengl"
|
||||
)
|
||||
|
||||
var glContext *opengl.Context
|
||||
|
||||
func GLContext() *opengl.Context {
|
||||
return glContext
|
||||
}
|
@ -178,11 +178,7 @@ func Run(width, height int, scale float64, title string, g GraphicsContext) erro
|
||||
u := currentUI
|
||||
// GLContext must be created before setting the screen size, which requires
|
||||
// swapping buffers.
|
||||
var err error
|
||||
glContext, err = opengl.NewContext(currentUI.runOnMainThread)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opengl.Init(currentUI.runOnMainThread)
|
||||
if err := u.runOnMainThread(func() error {
|
||||
m := glfw.GetPrimaryMonitor()
|
||||
v := m.GetVideoMode()
|
||||
@ -275,7 +271,7 @@ func (u *userInterface) loop(g GraphicsContext) error {
|
||||
return err
|
||||
}
|
||||
// The bound framebuffer must be the default one (0) before swapping buffers.
|
||||
if err := glContext.BindScreenFramebuffer(); err != nil {
|
||||
if err := opengl.GetContext().BindScreenFramebuffer(); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = u.runOnMainThread(func() error {
|
||||
|
@ -72,8 +72,8 @@ func (u *userInterface) update(g GraphicsContext) error {
|
||||
if !u.windowFocus {
|
||||
return nil
|
||||
}
|
||||
if glContext.IsContextLost() {
|
||||
glContext.RestoreContext()
|
||||
if opengl.GetContext().IsContextLost() {
|
||||
opengl.GetContext().RestoreContext()
|
||||
g.Invalidate()
|
||||
}
|
||||
currentInput.updateGamepads()
|
||||
@ -280,9 +280,7 @@ func Run(width, height int, scale float64, title string, g GraphicsContext) erro
|
||||
doc.Set("title", title)
|
||||
u.setScreenSize(width, height, scale)
|
||||
canvas.Call("focus")
|
||||
var err error
|
||||
glContext, err = opengl.NewContext()
|
||||
if err != nil {
|
||||
if err := opengl.Init(); err != nil {
|
||||
return err
|
||||
}
|
||||
return u.loop(g)
|
||||
|
@ -38,7 +38,7 @@ func Render(chError <-chan error) error {
|
||||
// TODO: Check this is called on the rendering thread
|
||||
select {
|
||||
case chRender <- struct{}{}:
|
||||
return glContext.DoWork(chError, chRenderEnd)
|
||||
return opengl.GetContext().DoWork(chError, chRenderEnd)
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
// This function must not be blocked. We need to break for timeout.
|
||||
return nil
|
||||
@ -66,11 +66,7 @@ func Run(width, height int, scale float64, title string, g GraphicsContext) erro
|
||||
u.height = height
|
||||
u.scale = scale
|
||||
// title is ignored?
|
||||
var err error
|
||||
glContext, err = opengl.NewContext()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opengl.Init()
|
||||
for {
|
||||
if err := u.update(g); err != nil {
|
||||
return err
|
||||
|
Loading…
Reference in New Issue
Block a user