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