mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +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 {
|
||||
panic(fmt.Sprintf("ebiten: len(p) was %d but must be %d", len(p), l))
|
||||
}
|
||||
|
||||
// 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)
|
||||
i.restorable.ReplacePixels(p, 0, 0, w, h)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -269,6 +269,10 @@ func (c *drawImageCommand) quadsNum() int {
|
||||
type replacePixelsCommand struct {
|
||||
dst *Image
|
||||
pixels []byte
|
||||
x int
|
||||
y int
|
||||
width int
|
||||
height int
|
||||
}
|
||||
|
||||
// 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).
|
||||
opengl.GetContext().Flush()
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -86,12 +86,16 @@ func (i *Image) Pixels() ([]byte, error) {
|
||||
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))
|
||||
copy(pixels, p)
|
||||
c := &replacePixelsCommand{
|
||||
dst: i,
|
||||
pixels: pixels,
|
||||
x: x,
|
||||
y: y,
|
||||
width: width,
|
||||
height: height,
|
||||
}
|
||||
theCommandQueue.Enqueue(c)
|
||||
}
|
||||
|
@ -165,8 +165,8 @@ func (c *Context) bindFramebufferImpl(f Framebuffer) {
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Context) FramebufferPixels(f Framebuffer, width, height int) ([]uint8, error) {
|
||||
var pixels []uint8
|
||||
func (c *Context) FramebufferPixels(f Framebuffer, width, height int) ([]byte, error) {
|
||||
var pixels []byte
|
||||
if err := c.runOnContextThread(func() error {
|
||||
gl.Flush()
|
||||
return nil
|
||||
@ -175,7 +175,7 @@ func (c *Context) FramebufferPixels(f Framebuffer, width, height int) ([]uint8,
|
||||
}
|
||||
c.bindFramebuffer(f)
|
||||
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))
|
||||
if e := gl.GetError(); e != gl.NO_ERROR {
|
||||
pixels = nil
|
||||
@ -218,9 +218,9 @@ func (c *Context) IsTexture(t Texture) bool {
|
||||
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 {
|
||||
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
|
||||
})
|
||||
}
|
||||
@ -312,10 +312,10 @@ func (c *Context) NewShader(shaderType ShaderType, source string) (Shader, error
|
||||
var v int32
|
||||
gl.GetShaderiv(s, gl.COMPILE_STATUS, &v)
|
||||
if v == gl.FALSE {
|
||||
log := []uint8{}
|
||||
log := []byte{}
|
||||
gl.GetShaderiv(uint32(s), gl.INFO_LOG_LENGTH, &v)
|
||||
if v != 0 {
|
||||
log = make([]uint8, int(v))
|
||||
log = make([]byte, int(v))
|
||||
gl.GetShaderInfoLog(uint32(s), v, nil, (*uint8)(gl.Ptr(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_MIN_FILTER, gl.NEAREST)
|
||||
|
||||
// TODO: Can we use glTexSubImage2D with linear filtering?
|
||||
|
||||
// void texImage2D(GLenum target, GLint level, GLenum internalformat,
|
||||
// GLsizei width, GLsizei height, GLint border, GLenum format,
|
||||
// GLenum type, ArrayBufferView? pixels);
|
||||
@ -158,7 +156,7 @@ func (c *Context) bindFramebufferImpl(f Framebuffer) {
|
||||
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
|
||||
|
||||
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 {
|
||||
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) {
|
||||
@ -193,12 +191,12 @@ func (c *Context) IsTexture(t Texture) bool {
|
||||
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
|
||||
// void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
|
||||
// GLsizei width, GLsizei height,
|
||||
// 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) {
|
||||
|
@ -144,13 +144,13 @@ func (c *Context) bindFramebufferImpl(f Framebuffer) {
|
||||
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.Flush()
|
||||
|
||||
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)
|
||||
if e := gl.GetError(); e != mgl.NO_ERROR {
|
||||
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))
|
||||
}
|
||||
|
||||
func (c *Context) TexSubImage2D(p []uint8, width, height int) {
|
||||
func (c *Context) TexSubImage2D(p []byte, x, y, width, height int) {
|
||||
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) {
|
||||
@ -351,9 +351,9 @@ func (c *Context) DisableVertexAttribArray(p Program, location string) {
|
||||
gl.DisableVertexAttribArray(mgl.Attrib(l))
|
||||
}
|
||||
|
||||
func uint16ToBytes(v []uint16) []uint8 {
|
||||
func uint16ToBytes(v []uint16) []byte {
|
||||
// TODO: Consider endian?
|
||||
b := make([]uint8, len(v)*2)
|
||||
b := make([]byte, len(v)*2)
|
||||
for i, x := range v {
|
||||
b[2*i] = uint8(x)
|
||||
b[2*i+1] = uint8(x >> 8)
|
||||
|
@ -16,6 +16,7 @@ package restorable
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"runtime"
|
||||
|
||||
@ -155,10 +156,27 @@ func (i *Image) ClearFramebuffer() {
|
||||
}
|
||||
|
||||
// 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)
|
||||
i.image.ReplacePixels(pixels)
|
||||
i.basePixels = pixels
|
||||
i.image.ReplacePixels(pixels, x, y, width, height)
|
||||
|
||||
// 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.stale = false
|
||||
}
|
||||
@ -316,11 +334,11 @@ func (i *Image) restore() error {
|
||||
}
|
||||
gimg := graphics.NewImage(w, h)
|
||||
if i.basePixels != nil {
|
||||
gimg.ReplacePixels(i.basePixels)
|
||||
gimg.ReplacePixels(i.basePixels, 0, 0, w, h)
|
||||
} else {
|
||||
// Clear the image explicitly.
|
||||
pix := make([]uint8, w*h*4)
|
||||
gimg.ReplacePixels(pix)
|
||||
gimg.ReplacePixels(pix, 0, 0, w, h)
|
||||
}
|
||||
for _, c := range i.drawImageHistory {
|
||||
// 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+3] = a
|
||||
}
|
||||
img.ReplacePixels(pix)
|
||||
img.ReplacePixels(pix, 0, 0, w, h)
|
||||
}
|
||||
|
||||
func TestRestore(t *testing.T) {
|
||||
@ -326,7 +326,7 @@ func TestRestoreComplexGraph(t *testing.T) {
|
||||
func newImageFromImage(rgba *image.RGBA) *Image {
|
||||
s := rgba.Bounds().Size()
|
||||
img := NewImage(s.X, s.Y, false)
|
||||
img.ReplacePixels(rgba.Pix)
|
||||
img.ReplacePixels(rgba.Pix, 0, 0, s.X, s.Y)
|
||||
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?
|
||||
|
Loading…
Reference in New Issue
Block a user