mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +01:00
driver: Add ImageID and use this
This is a preparation to introduce shaders. Shader programs require images as uniform variables, but the current way would make API complex unnecessarily.
This commit is contained in:
parent
7ccc29e3c7
commit
8fd377f1e3
@ -30,7 +30,7 @@ type Graphics interface {
|
|||||||
NewImage(width, height int) (Image, error)
|
NewImage(width, height int) (Image, error)
|
||||||
NewScreenFramebufferImage(width, height int) (Image, error)
|
NewScreenFramebufferImage(width, height int) (Image, error)
|
||||||
Reset() error
|
Reset() error
|
||||||
Draw(indexLen int, indexOffset int, mode CompositeMode, colorM *affine.ColorM, filter Filter, address Address) error
|
Draw(dst, src ImageID, indexLen int, indexOffset int, mode CompositeMode, colorM *affine.ColorM, filter Filter, address Address) error
|
||||||
SetVsyncEnabled(enabled bool)
|
SetVsyncEnabled(enabled bool)
|
||||||
FramebufferYDirection() YDirection
|
FramebufferYDirection() YDirection
|
||||||
NeedsRestoring() bool
|
NeedsRestoring() bool
|
||||||
@ -43,14 +43,15 @@ type Graphics interface {
|
|||||||
var GraphicsNotReady = errors.New("graphics not ready")
|
var GraphicsNotReady = errors.New("graphics not ready")
|
||||||
|
|
||||||
type Image interface {
|
type Image interface {
|
||||||
|
ID() ImageID
|
||||||
Dispose()
|
Dispose()
|
||||||
IsInvalidated() bool
|
IsInvalidated() bool
|
||||||
Pixels() ([]byte, error)
|
Pixels() ([]byte, error)
|
||||||
SetAsDestination()
|
|
||||||
SetAsSource()
|
|
||||||
ReplacePixels(args []*ReplacePixelsArgs)
|
ReplacePixels(args []*ReplacePixelsArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ImageID int
|
||||||
|
|
||||||
type ReplacePixelsArgs struct {
|
type ReplacePixelsArgs struct {
|
||||||
Pixels []byte
|
Pixels []byte
|
||||||
X int
|
X int
|
||||||
|
@ -374,9 +374,7 @@ func (c *drawTrianglesCommand) Exec(indexOffset int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
c.dst.image.SetAsDestination()
|
if err := theGraphicsDriver.Draw(c.dst.image.ID(), c.src.image.ID(), c.nindices, indexOffset, c.mode, c.color, c.filter, c.address); err != nil {
|
||||||
c.src.image.SetAsSource()
|
|
||||||
if err := theGraphicsDriver.Draw(c.nindices, indexOffset, c.mode, c.color, c.filter, c.address); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -43,6 +43,11 @@ type Image struct {
|
|||||||
internalWidth int
|
internalWidth int
|
||||||
internalHeight int
|
internalHeight int
|
||||||
screen bool
|
screen bool
|
||||||
|
|
||||||
|
// id is an indentifier for the image. This is used only when dummping the information.
|
||||||
|
//
|
||||||
|
// This is duplicated with driver.Image's ID, but this id is still necessary because this image might not
|
||||||
|
// have its driver.Image.
|
||||||
id int
|
id int
|
||||||
|
|
||||||
bufferedRP []*driver.ReplacePixelsArgs
|
bufferedRP []*driver.ReplacePixelsArgs
|
||||||
|
@ -294,6 +294,10 @@ type Graphics struct {
|
|||||||
|
|
||||||
vb mtl.Buffer
|
vb mtl.Buffer
|
||||||
ib mtl.Buffer
|
ib mtl.Buffer
|
||||||
|
|
||||||
|
images map[driver.ImageID]*Image
|
||||||
|
nextImageID driver.ImageID
|
||||||
|
|
||||||
src *Image
|
src *Image
|
||||||
dst *Image
|
dst *Image
|
||||||
|
|
||||||
@ -399,6 +403,12 @@ func (g *Graphics) checkSize(width, height int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *Graphics) genNextImageID() driver.ImageID {
|
||||||
|
id := g.nextImageID
|
||||||
|
g.nextImageID++
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
func (g *Graphics) NewImage(width, height int) (driver.Image, error) {
|
func (g *Graphics) NewImage(width, height int) (driver.Image, error) {
|
||||||
g.checkSize(width, height)
|
g.checkSize(width, height)
|
||||||
td := mtl.TextureDescriptor{
|
td := mtl.TextureDescriptor{
|
||||||
@ -413,12 +423,15 @@ func (g *Graphics) NewImage(width, height int) (driver.Image, error) {
|
|||||||
t = g.view.getMTLDevice().MakeTexture(td)
|
t = g.view.getMTLDevice().MakeTexture(td)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
return &Image{
|
i := &Image{
|
||||||
|
id: g.genNextImageID(),
|
||||||
graphics: g,
|
graphics: g,
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
texture: t,
|
texture: t,
|
||||||
}, nil
|
}
|
||||||
|
g.addImage(i)
|
||||||
|
return i, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Graphics) NewScreenFramebufferImage(width, height int) (driver.Image, error) {
|
func (g *Graphics) NewScreenFramebufferImage(width, height int) (driver.Image, error) {
|
||||||
@ -426,12 +439,29 @@ func (g *Graphics) NewScreenFramebufferImage(width, height int) (driver.Image, e
|
|||||||
g.view.setDrawableSize(width, height)
|
g.view.setDrawableSize(width, height)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
return &Image{
|
i := &Image{
|
||||||
|
id: g.genNextImageID(),
|
||||||
graphics: g,
|
graphics: g,
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
screen: true,
|
screen: true,
|
||||||
}, nil
|
}
|
||||||
|
g.addImage(i)
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Graphics) addImage(img *Image) {
|
||||||
|
if g.images == nil {
|
||||||
|
g.images = map[driver.ImageID]*Image{}
|
||||||
|
}
|
||||||
|
if _, ok := g.images[img.id]; ok {
|
||||||
|
panic(fmt.Sprintf("opengl: image ID %d was already registered", img.id))
|
||||||
|
}
|
||||||
|
g.images[img.id] = img
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Graphics) removeImage(img *Image) {
|
||||||
|
delete(g.images, img.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Graphics) SetTransparent(transparent bool) {
|
func (g *Graphics) SetTransparent(transparent bool) {
|
||||||
@ -579,7 +609,10 @@ func (g *Graphics) Reset() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Graphics) Draw(indexLen int, indexOffset int, mode driver.CompositeMode, colorM *affine.ColorM, filter driver.Filter, address driver.Address) error {
|
func (g *Graphics) Draw(dstID, srcID driver.ImageID, indexLen int, indexOffset int, mode driver.CompositeMode, colorM *affine.ColorM, filter driver.Filter, address driver.Address) error {
|
||||||
|
dst := g.images[dstID]
|
||||||
|
src := g.images[srcID]
|
||||||
|
|
||||||
g.drawCalled = true
|
g.drawCalled = true
|
||||||
|
|
||||||
if err := g.t.Call(func() error {
|
if err := g.t.Call(func() error {
|
||||||
@ -592,7 +625,7 @@ func (g *Graphics) Draw(indexLen int, indexOffset int, mode driver.CompositeMode
|
|||||||
rpd.ColorAttachments[0].StoreAction = mtl.StoreActionStore
|
rpd.ColorAttachments[0].StoreAction = mtl.StoreActionStore
|
||||||
|
|
||||||
var t mtl.Texture
|
var t mtl.Texture
|
||||||
if g.dst.screen {
|
if dst.screen {
|
||||||
if g.screenDrawable == (ca.MetalDrawable{}) {
|
if g.screenDrawable == (ca.MetalDrawable{}) {
|
||||||
drawable := g.view.drawable()
|
drawable := g.view.drawable()
|
||||||
if drawable == (ca.MetalDrawable{}) {
|
if drawable == (ca.MetalDrawable{}) {
|
||||||
@ -602,7 +635,7 @@ func (g *Graphics) Draw(indexLen int, indexOffset int, mode driver.CompositeMode
|
|||||||
}
|
}
|
||||||
t = g.screenDrawable.Texture()
|
t = g.screenDrawable.Texture()
|
||||||
} else {
|
} else {
|
||||||
t = g.dst.texture
|
t = dst.texture
|
||||||
}
|
}
|
||||||
rpd.ColorAttachments[0].Texture = t
|
rpd.ColorAttachments[0].Texture = t
|
||||||
rpd.ColorAttachments[0].ClearColor = mtl.ClearColor{}
|
rpd.ColorAttachments[0].ClearColor = mtl.ClearColor{}
|
||||||
@ -612,11 +645,11 @@ func (g *Graphics) Draw(indexLen int, indexOffset int, mode driver.CompositeMode
|
|||||||
}
|
}
|
||||||
rce := g.cb.MakeRenderCommandEncoder(rpd)
|
rce := g.cb.MakeRenderCommandEncoder(rpd)
|
||||||
|
|
||||||
if g.dst.screen && filter == driver.FilterScreen {
|
if dst.screen && filter == driver.FilterScreen {
|
||||||
rce.SetRenderPipelineState(g.screenRPS)
|
rce.SetRenderPipelineState(g.screenRPS)
|
||||||
} else {
|
} else {
|
||||||
rce.SetRenderPipelineState(g.rpss[rpsKey{
|
rce.SetRenderPipelineState(g.rpss[rpsKey{
|
||||||
screen: g.dst.screen,
|
screen: dst.screen,
|
||||||
useColorM: colorM != nil,
|
useColorM: colorM != nil,
|
||||||
filter: filter,
|
filter: filter,
|
||||||
address: address,
|
address: address,
|
||||||
@ -625,7 +658,7 @@ func (g *Graphics) Draw(indexLen int, indexOffset int, mode driver.CompositeMode
|
|||||||
}
|
}
|
||||||
// In Metal, the NDC's Y direction (upward) and the framebuffer's Y direction (downward) don't
|
// In Metal, the NDC's Y direction (upward) and the framebuffer's Y direction (downward) don't
|
||||||
// match. Then, the Y direction must be inverted.
|
// match. Then, the Y direction must be inverted.
|
||||||
w, h := g.dst.viewportSize()
|
w, h := dst.viewportSize()
|
||||||
rce.SetViewport(mtl.Viewport{
|
rce.SetViewport(mtl.Viewport{
|
||||||
OriginX: 0,
|
OriginX: 0,
|
||||||
OriginY: float64(h),
|
OriginY: float64(h),
|
||||||
@ -640,8 +673,8 @@ func (g *Graphics) Draw(indexLen int, indexOffset int, mode driver.CompositeMode
|
|||||||
rce.SetVertexBytes(unsafe.Pointer(&viewportSize[0]), unsafe.Sizeof(viewportSize), 1)
|
rce.SetVertexBytes(unsafe.Pointer(&viewportSize[0]), unsafe.Sizeof(viewportSize), 1)
|
||||||
|
|
||||||
sourceSize := [...]float32{
|
sourceSize := [...]float32{
|
||||||
float32(graphics.InternalImageSize(g.src.width)),
|
float32(graphics.InternalImageSize(src.width)),
|
||||||
float32(graphics.InternalImageSize(g.src.height)),
|
float32(graphics.InternalImageSize(src.height)),
|
||||||
}
|
}
|
||||||
rce.SetFragmentBytes(unsafe.Pointer(&sourceSize[0]), unsafe.Sizeof(sourceSize), 2)
|
rce.SetFragmentBytes(unsafe.Pointer(&sourceSize[0]), unsafe.Sizeof(sourceSize), 2)
|
||||||
|
|
||||||
@ -649,11 +682,11 @@ func (g *Graphics) Draw(indexLen int, indexOffset int, mode driver.CompositeMode
|
|||||||
rce.SetFragmentBytes(unsafe.Pointer(&esBody[0]), unsafe.Sizeof(esBody[0])*uintptr(len(esBody)), 3)
|
rce.SetFragmentBytes(unsafe.Pointer(&esBody[0]), unsafe.Sizeof(esBody[0])*uintptr(len(esBody)), 3)
|
||||||
rce.SetFragmentBytes(unsafe.Pointer(&esTranslate[0]), unsafe.Sizeof(esTranslate[0])*uintptr(len(esTranslate)), 4)
|
rce.SetFragmentBytes(unsafe.Pointer(&esTranslate[0]), unsafe.Sizeof(esTranslate[0])*uintptr(len(esTranslate)), 4)
|
||||||
|
|
||||||
scale := float32(g.dst.width) / float32(g.src.width)
|
scale := float32(dst.width) / float32(src.width)
|
||||||
rce.SetFragmentBytes(unsafe.Pointer(&scale), unsafe.Sizeof(scale), 5)
|
rce.SetFragmentBytes(unsafe.Pointer(&scale), unsafe.Sizeof(scale), 5)
|
||||||
|
|
||||||
if g.src != nil {
|
if src != nil {
|
||||||
rce.SetFragmentTexture(g.src.texture, 0)
|
rce.SetFragmentTexture(src.texture, 0)
|
||||||
} else {
|
} else {
|
||||||
rce.SetFragmentTexture(mtl.Texture{}, 0)
|
rce.SetFragmentTexture(mtl.Texture{}, 0)
|
||||||
}
|
}
|
||||||
@ -668,13 +701,6 @@ func (g *Graphics) Draw(indexLen int, indexOffset int, mode driver.CompositeMode
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Graphics) ResetSource() {
|
|
||||||
g.t.Call(func() error {
|
|
||||||
g.src = nil
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Graphics) SetVsyncEnabled(enabled bool) {
|
func (g *Graphics) SetVsyncEnabled(enabled bool) {
|
||||||
g.view.setDisplaySyncEnabled(enabled)
|
g.view.setDisplaySyncEnabled(enabled)
|
||||||
}
|
}
|
||||||
@ -733,6 +759,7 @@ func (g *Graphics) MaxImageSize() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Image struct {
|
type Image struct {
|
||||||
|
id driver.ImageID
|
||||||
graphics *Graphics
|
graphics *Graphics
|
||||||
width int
|
width int
|
||||||
height int
|
height int
|
||||||
@ -740,6 +767,10 @@ type Image struct {
|
|||||||
texture mtl.Texture
|
texture mtl.Texture
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Image) ID() driver.ImageID {
|
||||||
|
return i.id
|
||||||
|
}
|
||||||
|
|
||||||
// viewportSize must be called from the main thread.
|
// viewportSize must be called from the main thread.
|
||||||
func (i *Image) viewportSize() (int, int) {
|
func (i *Image) viewportSize() (int, int) {
|
||||||
if i.screen {
|
if i.screen {
|
||||||
@ -756,6 +787,7 @@ func (i *Image) Dispose() {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
i.graphics.removeImage(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) IsInvalidated() bool {
|
func (i *Image) IsInvalidated() bool {
|
||||||
@ -795,20 +827,6 @@ func (i *Image) Pixels() ([]byte, error) {
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) SetAsDestination() {
|
|
||||||
i.graphics.t.Call(func() error {
|
|
||||||
i.graphics.dst = i
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Image) SetAsSource() {
|
|
||||||
i.graphics.t.Call(func() error {
|
|
||||||
i.graphics.src = i
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Image) ReplacePixels(args []*driver.ReplacePixelsArgs) {
|
func (i *Image) ReplacePixels(args []*driver.ReplacePixelsArgs) {
|
||||||
g := i.graphics
|
g := i.graphics
|
||||||
if g.drawCalled {
|
if g.drawCalled {
|
||||||
|
@ -30,8 +30,10 @@ func Get() *Graphics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Graphics struct {
|
type Graphics struct {
|
||||||
|
nextImageID driver.ImageID
|
||||||
state openGLState
|
state openGLState
|
||||||
context context
|
context context
|
||||||
|
images map[driver.ImageID]*Image
|
||||||
|
|
||||||
// drawCalled is true just after Draw is called. This holds true until ReplacePixels is called.
|
// drawCalled is true just after Draw is called. This holds true until ReplacePixels is called.
|
||||||
drawCalled bool
|
drawCalled bool
|
||||||
@ -71,8 +73,15 @@ func (g *Graphics) checkSize(width, height int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *Graphics) genNextImageID() driver.ImageID {
|
||||||
|
id := g.nextImageID
|
||||||
|
g.nextImageID++
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
func (g *Graphics) NewImage(width, height int) (driver.Image, error) {
|
func (g *Graphics) NewImage(width, height int) (driver.Image, error) {
|
||||||
i := &Image{
|
i := &Image{
|
||||||
|
id: g.genNextImageID(),
|
||||||
graphics: g,
|
graphics: g,
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
@ -85,20 +94,37 @@ func (g *Graphics) NewImage(width, height int) (driver.Image, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
i.textureNative = t
|
i.textureNative = t
|
||||||
|
g.addImage(i)
|
||||||
return i, nil
|
return i, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Graphics) NewScreenFramebufferImage(width, height int) (driver.Image, error) {
|
func (g *Graphics) NewScreenFramebufferImage(width, height int) (driver.Image, error) {
|
||||||
g.checkSize(width, height)
|
g.checkSize(width, height)
|
||||||
i := &Image{
|
i := &Image{
|
||||||
|
id: g.genNextImageID(),
|
||||||
graphics: g,
|
graphics: g,
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
screen: true,
|
screen: true,
|
||||||
}
|
}
|
||||||
|
g.addImage(i)
|
||||||
return i, nil
|
return i, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *Graphics) addImage(img *Image) {
|
||||||
|
if g.images == nil {
|
||||||
|
g.images = map[driver.ImageID]*Image{}
|
||||||
|
}
|
||||||
|
if _, ok := g.images[img.id]; ok {
|
||||||
|
panic(fmt.Sprintf("opengl: image ID %d was already registered", img.id))
|
||||||
|
}
|
||||||
|
g.images[img.id] = img
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Graphics) removeImage(img *Image) {
|
||||||
|
delete(g.images, img.id)
|
||||||
|
}
|
||||||
|
|
||||||
// Reset resets or initializes the current OpenGL state.
|
// Reset resets or initializes the current OpenGL state.
|
||||||
func (g *Graphics) Reset() error {
|
func (g *Graphics) Reset() error {
|
||||||
return g.state.reset(&g.context)
|
return g.state.reset(&g.context)
|
||||||
@ -112,15 +138,9 @@ func (g *Graphics) SetVertices(vertices []float32, indices []uint16) {
|
|||||||
g.context.elementArrayBufferSubData(indices)
|
g.context.elementArrayBufferSubData(indices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Graphics) Draw(indexLen int, indexOffset int, mode driver.CompositeMode, colorM *affine.ColorM, filter driver.Filter, address driver.Address) error {
|
func (g *Graphics) Draw(dst, src driver.ImageID, indexLen int, indexOffset int, mode driver.CompositeMode, colorM *affine.ColorM, filter driver.Filter, address driver.Address) error {
|
||||||
destination := g.state.destination
|
destination := g.images[dst]
|
||||||
if destination == nil {
|
source := g.images[src]
|
||||||
panic("destination image is not set")
|
|
||||||
}
|
|
||||||
source := g.state.source
|
|
||||||
if source == nil {
|
|
||||||
panic("source image is not set")
|
|
||||||
}
|
|
||||||
|
|
||||||
g.drawCalled = true
|
g.drawCalled = true
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Image struct {
|
type Image struct {
|
||||||
|
id driver.ImageID
|
||||||
graphics *Graphics
|
graphics *Graphics
|
||||||
textureNative textureNative
|
textureNative textureNative
|
||||||
framebuffer *framebuffer
|
framebuffer *framebuffer
|
||||||
@ -29,6 +30,10 @@ type Image struct {
|
|||||||
screen bool
|
screen bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Image) ID() driver.ImageID {
|
||||||
|
return i.id
|
||||||
|
}
|
||||||
|
|
||||||
func (i *Image) IsInvalidated() bool {
|
func (i *Image) IsInvalidated() bool {
|
||||||
return !i.graphics.context.isTexture(i.textureNative)
|
return !i.graphics.context.isTexture(i.textureNative)
|
||||||
}
|
}
|
||||||
@ -43,10 +48,8 @@ func (i *Image) Dispose() {
|
|||||||
if !i.textureNative.equal(*new(textureNative)) {
|
if !i.textureNative.equal(*new(textureNative)) {
|
||||||
i.graphics.context.deleteTexture(i.textureNative)
|
i.graphics.context.deleteTexture(i.textureNative)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Image) SetAsDestination() {
|
i.graphics.removeImage(i)
|
||||||
i.graphics.state.destination = i
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) setViewport() error {
|
func (i *Image) setViewport() error {
|
||||||
@ -119,7 +122,3 @@ func (i *Image) ReplacePixels(args []*driver.ReplacePixelsArgs) {
|
|||||||
|
|
||||||
i.graphics.context.replacePixelsWithPBO(i.pbo, i.textureNative, w, h, args)
|
i.graphics.context.replacePixelsWithPBO(i.pbo, i.textureNative, w, h, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) SetAsSource() {
|
|
||||||
i.graphics.state.source = i
|
|
||||||
}
|
|
||||||
|
@ -137,9 +137,6 @@ type openGLState struct {
|
|||||||
lastProgram program
|
lastProgram program
|
||||||
lastUniforms map[string]interface{}
|
lastUniforms map[string]interface{}
|
||||||
lastActiveTexture int
|
lastActiveTexture int
|
||||||
|
|
||||||
source *Image
|
|
||||||
destination *Image
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -292,8 +289,5 @@ func (g *Graphics) useProgram(program program, uniforms map[string]interface{})
|
|||||||
g.context.bindTexture(u)
|
g.context.bindTexture(u)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g.state.source = nil
|
|
||||||
g.state.destination = nil
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user