mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-26 11:48:55 +01:00
graphics: Specify rect to glTexSubImage2D
This commit is contained in:
parent
9f6fd0db9a
commit
127f6c09c8
7
image.go
7
image.go
@ -283,12 +283,7 @@ func (i *Image) ReplacePixels(p []byte) error {
|
|||||||
if l := 4 * w * h; len(p) != l {
|
if l := 4 * w * h; len(p) != l {
|
||||||
panic(fmt.Sprintf("ebiten: len(p) was %d but must be %d", len(p), l))
|
panic(fmt.Sprintf("ebiten: len(p) was %d but must be %d", len(p), l))
|
||||||
}
|
}
|
||||||
|
i.restorable.ReplacePixels(p, 0, 0, w, h)
|
||||||
// Copy the pixels so that this works even p is modified just after ReplacePixels.
|
|
||||||
pix := make([]byte, len(p))
|
|
||||||
copy(pix, p)
|
|
||||||
|
|
||||||
i.restorable.ReplacePixels(pix)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,6 +269,10 @@ func (c *drawImageCommand) quadsNum() int {
|
|||||||
type replacePixelsCommand struct {
|
type replacePixelsCommand struct {
|
||||||
dst *Image
|
dst *Image
|
||||||
pixels []byte
|
pixels []byte
|
||||||
|
x int
|
||||||
|
y int
|
||||||
|
width int
|
||||||
|
height int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec executes the replacePixelsCommand.
|
// Exec executes the replacePixelsCommand.
|
||||||
@ -283,7 +287,7 @@ func (c *replacePixelsCommand) Exec(indexOffsetInBytes int) error {
|
|||||||
// glTexSubImage2D didn't work without this hack at least on Nexus 5x and NuAns NEO [Reloaded] (#211).
|
// glTexSubImage2D didn't work without this hack at least on Nexus 5x and NuAns NEO [Reloaded] (#211).
|
||||||
opengl.GetContext().Flush()
|
opengl.GetContext().Flush()
|
||||||
opengl.GetContext().BindTexture(c.dst.texture.native)
|
opengl.GetContext().BindTexture(c.dst.texture.native)
|
||||||
opengl.GetContext().TexSubImage2D(c.pixels, c.dst.width, c.dst.height)
|
opengl.GetContext().TexSubImage2D(c.pixels, c.x, c.y, c.width, c.height)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,12 +86,16 @@ func (i *Image) Pixels() ([]byte, error) {
|
|||||||
return opengl.GetContext().FramebufferPixels(f.native, i.width, i.height)
|
return opengl.GetContext().FramebufferPixels(f.native, i.width, i.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) ReplacePixels(p []byte) {
|
func (i *Image) ReplacePixels(p []byte, x, y, width, height int) {
|
||||||
pixels := make([]byte, len(p))
|
pixels := make([]byte, len(p))
|
||||||
copy(pixels, p)
|
copy(pixels, p)
|
||||||
c := &replacePixelsCommand{
|
c := &replacePixelsCommand{
|
||||||
dst: i,
|
dst: i,
|
||||||
pixels: pixels,
|
pixels: pixels,
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
}
|
}
|
||||||
theCommandQueue.Enqueue(c)
|
theCommandQueue.Enqueue(c)
|
||||||
}
|
}
|
||||||
|
@ -165,8 +165,8 @@ func (c *Context) bindFramebufferImpl(f Framebuffer) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) FramebufferPixels(f Framebuffer, width, height int) ([]uint8, error) {
|
func (c *Context) FramebufferPixels(f Framebuffer, width, height int) ([]byte, error) {
|
||||||
var pixels []uint8
|
var pixels []byte
|
||||||
if err := c.runOnContextThread(func() error {
|
if err := c.runOnContextThread(func() error {
|
||||||
gl.Flush()
|
gl.Flush()
|
||||||
return nil
|
return nil
|
||||||
@ -175,7 +175,7 @@ func (c *Context) FramebufferPixels(f Framebuffer, width, height int) ([]uint8,
|
|||||||
}
|
}
|
||||||
c.bindFramebuffer(f)
|
c.bindFramebuffer(f)
|
||||||
if err := c.runOnContextThread(func() error {
|
if err := c.runOnContextThread(func() error {
|
||||||
pixels = make([]uint8, 4*width*height)
|
pixels = make([]byte, 4*width*height)
|
||||||
gl.ReadPixels(0, 0, int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(pixels))
|
gl.ReadPixels(0, 0, int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(pixels))
|
||||||
if e := gl.GetError(); e != gl.NO_ERROR {
|
if e := gl.GetError(); e != gl.NO_ERROR {
|
||||||
pixels = nil
|
pixels = nil
|
||||||
@ -218,9 +218,9 @@ func (c *Context) IsTexture(t Texture) bool {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) TexSubImage2D(p []uint8, width, height int) {
|
func (c *Context) TexSubImage2D(p []byte, x, y, width, height int) {
|
||||||
_ = c.runOnContextThread(func() error {
|
_ = c.runOnContextThread(func() error {
|
||||||
gl.TexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(p))
|
gl.TexSubImage2D(gl.TEXTURE_2D, 0, int32(x), int32(y), int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(p))
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -312,10 +312,10 @@ func (c *Context) NewShader(shaderType ShaderType, source string) (Shader, error
|
|||||||
var v int32
|
var v int32
|
||||||
gl.GetShaderiv(s, gl.COMPILE_STATUS, &v)
|
gl.GetShaderiv(s, gl.COMPILE_STATUS, &v)
|
||||||
if v == gl.FALSE {
|
if v == gl.FALSE {
|
||||||
log := []uint8{}
|
log := []byte{}
|
||||||
gl.GetShaderiv(uint32(s), gl.INFO_LOG_LENGTH, &v)
|
gl.GetShaderiv(uint32(s), gl.INFO_LOG_LENGTH, &v)
|
||||||
if v != 0 {
|
if v != 0 {
|
||||||
log = make([]uint8, int(v))
|
log = make([]byte, int(v))
|
||||||
gl.GetShaderInfoLog(uint32(s), v, nil, (*uint8)(gl.Ptr(log)))
|
gl.GetShaderInfoLog(uint32(s), v, nil, (*uint8)(gl.Ptr(log)))
|
||||||
}
|
}
|
||||||
return fmt.Errorf("opengl: shader compile failed: %s", log)
|
return fmt.Errorf("opengl: shader compile failed: %s", log)
|
||||||
|
@ -143,8 +143,6 @@ func (c *Context) NewTexture(width, height int) (Texture, error) {
|
|||||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
|
||||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
|
||||||
|
|
||||||
// TODO: Can we use glTexSubImage2D with linear filtering?
|
|
||||||
|
|
||||||
// void texImage2D(GLenum target, GLint level, GLenum internalformat,
|
// void texImage2D(GLenum target, GLint level, GLenum internalformat,
|
||||||
// GLsizei width, GLsizei height, GLint border, GLenum format,
|
// GLsizei width, GLsizei height, GLint border, GLenum format,
|
||||||
// GLenum type, ArrayBufferView? pixels);
|
// GLenum type, ArrayBufferView? pixels);
|
||||||
@ -158,7 +156,7 @@ func (c *Context) bindFramebufferImpl(f Framebuffer) {
|
|||||||
gl.BindFramebuffer(gl.FRAMEBUFFER, f.(*js.Object))
|
gl.BindFramebuffer(gl.FRAMEBUFFER, f.(*js.Object))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) FramebufferPixels(f Framebuffer, width, height int) ([]uint8, error) {
|
func (c *Context) FramebufferPixels(f Framebuffer, width, height int) ([]byte, error) {
|
||||||
gl := c.gl
|
gl := c.gl
|
||||||
|
|
||||||
c.bindFramebuffer(f)
|
c.bindFramebuffer(f)
|
||||||
@ -168,7 +166,7 @@ func (c *Context) FramebufferPixels(f Framebuffer, width, height int) ([]uint8,
|
|||||||
if e := gl.GetError(); e != gl.NO_ERROR {
|
if e := gl.GetError(); e != gl.NO_ERROR {
|
||||||
return nil, errors.New(fmt.Sprintf("opengl: error: %d", e))
|
return nil, errors.New(fmt.Sprintf("opengl: error: %d", e))
|
||||||
}
|
}
|
||||||
return pixels.Interface().([]uint8), nil
|
return pixels.Interface().([]byte), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) bindTextureImpl(t Texture) {
|
func (c *Context) bindTextureImpl(t Texture) {
|
||||||
@ -193,12 +191,12 @@ func (c *Context) IsTexture(t Texture) bool {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) TexSubImage2D(p []uint8, width, height int) {
|
func (c *Context) TexSubImage2D(p []byte, x, y, width, height int) {
|
||||||
gl := c.gl
|
gl := c.gl
|
||||||
// void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
|
// void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
|
||||||
// GLsizei width, GLsizei height,
|
// GLsizei width, GLsizei height,
|
||||||
// GLenum format, GLenum type, ArrayBufferView? pixels);
|
// GLenum format, GLenum type, ArrayBufferView? pixels);
|
||||||
gl.Call("texSubImage2D", gl.TEXTURE_2D, 0, 0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, p)
|
gl.Call("texSubImage2D", gl.TEXTURE_2D, 0, x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) NewFramebuffer(t Texture) (Framebuffer, error) {
|
func (c *Context) NewFramebuffer(t Texture) (Framebuffer, error) {
|
||||||
|
@ -144,13 +144,13 @@ func (c *Context) bindFramebufferImpl(f Framebuffer) {
|
|||||||
gl.BindFramebuffer(mgl.FRAMEBUFFER, mgl.Framebuffer(f))
|
gl.BindFramebuffer(mgl.FRAMEBUFFER, mgl.Framebuffer(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) FramebufferPixels(f Framebuffer, width, height int) ([]uint8, error) {
|
func (c *Context) FramebufferPixels(f Framebuffer, width, height int) ([]byte, error) {
|
||||||
gl := c.gl
|
gl := c.gl
|
||||||
gl.Flush()
|
gl.Flush()
|
||||||
|
|
||||||
c.bindFramebuffer(f)
|
c.bindFramebuffer(f)
|
||||||
|
|
||||||
pixels := make([]uint8, 4*width*height)
|
pixels := make([]byte, 4*width*height)
|
||||||
gl.ReadPixels(pixels, 0, 0, width, height, mgl.RGBA, mgl.UNSIGNED_BYTE)
|
gl.ReadPixels(pixels, 0, 0, width, height, mgl.RGBA, mgl.UNSIGNED_BYTE)
|
||||||
if e := gl.GetError(); e != mgl.NO_ERROR {
|
if e := gl.GetError(); e != mgl.NO_ERROR {
|
||||||
return nil, fmt.Errorf("opengl: glReadPixels: %d", e)
|
return nil, fmt.Errorf("opengl: glReadPixels: %d", e)
|
||||||
@ -179,9 +179,9 @@ func (c *Context) IsTexture(t Texture) bool {
|
|||||||
return gl.IsTexture(mgl.Texture(t))
|
return gl.IsTexture(mgl.Texture(t))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) TexSubImage2D(p []uint8, width, height int) {
|
func (c *Context) TexSubImage2D(p []byte, x, y, width, height int) {
|
||||||
gl := c.gl
|
gl := c.gl
|
||||||
gl.TexSubImage2D(mgl.TEXTURE_2D, 0, 0, 0, width, height, mgl.RGBA, mgl.UNSIGNED_BYTE, p)
|
gl.TexSubImage2D(mgl.TEXTURE_2D, 0, x, y, width, height, mgl.RGBA, mgl.UNSIGNED_BYTE, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) NewFramebuffer(texture Texture) (Framebuffer, error) {
|
func (c *Context) NewFramebuffer(texture Texture) (Framebuffer, error) {
|
||||||
@ -351,9 +351,9 @@ func (c *Context) DisableVertexAttribArray(p Program, location string) {
|
|||||||
gl.DisableVertexAttribArray(mgl.Attrib(l))
|
gl.DisableVertexAttribArray(mgl.Attrib(l))
|
||||||
}
|
}
|
||||||
|
|
||||||
func uint16ToBytes(v []uint16) []uint8 {
|
func uint16ToBytes(v []uint16) []byte {
|
||||||
// TODO: Consider endian?
|
// TODO: Consider endian?
|
||||||
b := make([]uint8, len(v)*2)
|
b := make([]byte, len(v)*2)
|
||||||
for i, x := range v {
|
for i, x := range v {
|
||||||
b[2*i] = uint8(x)
|
b[2*i] = uint8(x)
|
||||||
b[2*i+1] = uint8(x >> 8)
|
b[2*i+1] = uint8(x >> 8)
|
||||||
|
@ -16,6 +16,7 @@ package restorable
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"image/color"
|
"image/color"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
@ -155,10 +156,27 @@ func (i *Image) ClearFramebuffer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ReplacePixels replaces the image pixels with the given pixels slice.
|
// ReplacePixels replaces the image pixels with the given pixels slice.
|
||||||
func (i *Image) ReplacePixels(pixels []byte) {
|
func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
|
||||||
|
w, h := i.image.Size()
|
||||||
|
if width <= 0 || height <= 0 {
|
||||||
|
panic("restorable: width/height must be positive")
|
||||||
|
}
|
||||||
|
if x < 0 || y < 0 || w <= x || h <= y || x+width <= 0 || y+height <= 0 || w < x+width || h < y+height {
|
||||||
|
panic(fmt.Sprintf("restorable: out of range x: %d, y: %d, width: %d, height: %d", x, y, width, height))
|
||||||
|
}
|
||||||
theImages.makeStaleIfDependingOn(i)
|
theImages.makeStaleIfDependingOn(i)
|
||||||
i.image.ReplacePixels(pixels)
|
i.image.ReplacePixels(pixels, x, y, width, height)
|
||||||
i.basePixels = pixels
|
|
||||||
|
// Copy the pixels so that this works even p is modified just after ReplacePixels.
|
||||||
|
if i.basePixels == nil {
|
||||||
|
w, h := i.image.Size()
|
||||||
|
i.basePixels = make([]byte, 4*w*h)
|
||||||
|
}
|
||||||
|
idx := 4 * (y*w + x)
|
||||||
|
for j := 0; j < height; j++ {
|
||||||
|
copy(i.basePixels[idx:idx+4*width], pixels[4*j*width:4*(j+1)*width])
|
||||||
|
idx += 4 * w
|
||||||
|
}
|
||||||
i.drawImageHistory = nil
|
i.drawImageHistory = nil
|
||||||
i.stale = false
|
i.stale = false
|
||||||
}
|
}
|
||||||
@ -316,11 +334,11 @@ func (i *Image) restore() error {
|
|||||||
}
|
}
|
||||||
gimg := graphics.NewImage(w, h)
|
gimg := graphics.NewImage(w, h)
|
||||||
if i.basePixels != nil {
|
if i.basePixels != nil {
|
||||||
gimg.ReplacePixels(i.basePixels)
|
gimg.ReplacePixels(i.basePixels, 0, 0, w, h)
|
||||||
} else {
|
} else {
|
||||||
// Clear the image explicitly.
|
// Clear the image explicitly.
|
||||||
pix := make([]uint8, w*h*4)
|
pix := make([]uint8, w*h*4)
|
||||||
gimg.ReplacePixels(pix)
|
gimg.ReplacePixels(pix, 0, 0, w, h)
|
||||||
}
|
}
|
||||||
for _, c := range i.drawImageHistory {
|
for _, c := range i.drawImageHistory {
|
||||||
// All dependencies must be already resolved.
|
// All dependencies must be already resolved.
|
||||||
|
@ -75,7 +75,7 @@ func fill(img *Image, r, g, b, a uint8) {
|
|||||||
pix[4*i+2] = b
|
pix[4*i+2] = b
|
||||||
pix[4*i+3] = a
|
pix[4*i+3] = a
|
||||||
}
|
}
|
||||||
img.ReplacePixels(pix)
|
img.ReplacePixels(pix, 0, 0, w, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRestore(t *testing.T) {
|
func TestRestore(t *testing.T) {
|
||||||
@ -326,7 +326,7 @@ func TestRestoreComplexGraph(t *testing.T) {
|
|||||||
func newImageFromImage(rgba *image.RGBA) *Image {
|
func newImageFromImage(rgba *image.RGBA) *Image {
|
||||||
s := rgba.Bounds().Size()
|
s := rgba.Bounds().Size()
|
||||||
img := NewImage(s.X, s.Y, false)
|
img := NewImage(s.X, s.Y, false)
|
||||||
img.ReplacePixels(rgba.Pix)
|
img.ReplacePixels(rgba.Pix, 0, 0, s.X, s.Y)
|
||||||
return img
|
return img
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,4 +381,32 @@ func TestRestoreRecursive(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReplacePixels(t *testing.T) {
|
||||||
|
const (
|
||||||
|
w = 17
|
||||||
|
h = 31
|
||||||
|
)
|
||||||
|
img := NewImage(17, 31, false)
|
||||||
|
pix := make([]byte, 4*4*4)
|
||||||
|
for i := range pix {
|
||||||
|
pix[i] = 0xff
|
||||||
|
}
|
||||||
|
img.ReplacePixels(pix, 5, 7, 4, 4)
|
||||||
|
for j := 0; j < h; j++ {
|
||||||
|
for i := 0; i < w; i++ {
|
||||||
|
got, err := img.At(i, j)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
want := color.RGBA{}
|
||||||
|
if 5 <= i && i < 9 && 7 <= j && j < 11 {
|
||||||
|
want = color.RGBA{0xff, 0xff, 0xff, 0xff}
|
||||||
|
}
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("img.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: How about volatile/screen images?
|
// TODO: How about volatile/screen images?
|
||||||
|
Loading…
Reference in New Issue
Block a user