mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
parent
7e50ae39c9
commit
f1582c2d73
124
examples/address/main.go
Normal file
124
examples/address/main.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
// +build example jsgo
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"image"
|
||||||
|
_ "image/png"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/hajimehoshi/ebiten"
|
||||||
|
"github.com/hajimehoshi/ebiten/ebitenutil"
|
||||||
|
"github.com/hajimehoshi/ebiten/examples/resources/images"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
screenWidth = 640
|
||||||
|
screenHeight = 480
|
||||||
|
)
|
||||||
|
|
||||||
|
var ebitenImage *ebiten.Image
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Decode image from a byte slice instead of a file so that
|
||||||
|
// this example works in any working directory.
|
||||||
|
// If you want to use a file, there are some options:
|
||||||
|
// 1) Use os.Open and pass the file to the image decoder.
|
||||||
|
// This is a very regular way, but doesn't work on browsers.
|
||||||
|
// 2) Use ebitenutil.OpenFile and pass the file to the image decoder.
|
||||||
|
// This works even on browsers.
|
||||||
|
// 3) Use ebitenutil.NewImageFromFile to create an ebiten.Image directly from a file.
|
||||||
|
// This also works on browsers.
|
||||||
|
img, _, err := image.Decode(bytes.NewReader(images.Ebiten_png))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
ebitenImage, _ = ebiten.NewImageFromImage(img, ebiten.FilterDefault)
|
||||||
|
}
|
||||||
|
|
||||||
|
func drawRect(screen *ebiten.Image, img *ebiten.Image, x, y, width, height float32, address ebiten.Address, msg string) {
|
||||||
|
sx, sy := -width/2, -height/2
|
||||||
|
vs := []ebiten.Vertex{
|
||||||
|
{
|
||||||
|
DstX: x,
|
||||||
|
DstY: y,
|
||||||
|
SrcX: sx,
|
||||||
|
SrcY: sy,
|
||||||
|
ColorR: 1,
|
||||||
|
ColorG: 1,
|
||||||
|
ColorB: 1,
|
||||||
|
ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: x + width,
|
||||||
|
DstY: y,
|
||||||
|
SrcX: sx + width,
|
||||||
|
SrcY: sy,
|
||||||
|
ColorR: 1,
|
||||||
|
ColorG: 1,
|
||||||
|
ColorB: 1,
|
||||||
|
ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: x,
|
||||||
|
DstY: y + height,
|
||||||
|
SrcX: sx,
|
||||||
|
SrcY: sy + height,
|
||||||
|
ColorR: 1,
|
||||||
|
ColorG: 1,
|
||||||
|
ColorB: 1,
|
||||||
|
ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: x + width,
|
||||||
|
DstY: y + height,
|
||||||
|
SrcX: sx + width,
|
||||||
|
SrcY: sy + height,
|
||||||
|
ColorR: 1,
|
||||||
|
ColorG: 1,
|
||||||
|
ColorB: 1,
|
||||||
|
ColorA: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
op := &ebiten.DrawTrianglesOptions{}
|
||||||
|
op.Address = address
|
||||||
|
screen.DrawTriangles(vs, []uint16{0, 1, 2, 1, 2, 3}, img, op)
|
||||||
|
|
||||||
|
ebitenutil.DebugPrintAt(screen, msg, int(x), int(y)-16)
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(screen *ebiten.Image) error {
|
||||||
|
if ebiten.IsDrawingSkipped() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const ox, oy = 40, 60
|
||||||
|
drawRect(screen, ebitenImage, ox, oy, 200, 100, ebiten.AddressClampToZero, "Regular")
|
||||||
|
drawRect(screen, ebitenImage, 220+ox, oy, 200, 100, ebiten.AddressRepeat, "Regular, Repeat")
|
||||||
|
|
||||||
|
subImage := ebitenImage.SubImage(image.Rect(10, 5, 20, 30)).(*ebiten.Image)
|
||||||
|
drawRect(screen, subImage, ox, 200+oy, 200, 100, ebiten.AddressClampToZero, "Subimage")
|
||||||
|
drawRect(screen, subImage, 220+ox, 200+oy, 200, 100, ebiten.AddressRepeat, "Subimage, Repeat")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err := ebiten.Run(update, screenWidth, screenHeight, 1, "Sampler Address (Ebiten Demo)"); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
23
image.go
23
image.go
@ -91,7 +91,7 @@ func (m *mipmap) level(r image.Rectangle, level int) *shareable.Image {
|
|||||||
vs = src.QuadVertices(0, 0, w, h, 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1)
|
vs = src.QuadVertices(0, 0, w, h, 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1)
|
||||||
}
|
}
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
s.DrawImage(src, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterLinear)
|
s.DrawImage(src, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterLinear, graphics.AddressClampToZero)
|
||||||
imgs = append(imgs, s)
|
imgs = append(imgs, s)
|
||||||
w = w2
|
w = w2
|
||||||
h = h2
|
h = h2
|
||||||
@ -387,7 +387,7 @@ func (i *Image) drawImage(img *Image, options *DrawImageOptions) {
|
|||||||
src := img.mipmap.original()
|
src := img.mipmap.original()
|
||||||
vs := src.QuadVertices(bounds.Min.X, bounds.Min.Y, bounds.Max.X, bounds.Max.Y, a, b, c, d, tx, ty, cr, cg, cb, ca)
|
vs := src.QuadVertices(bounds.Min.X, bounds.Min.Y, bounds.Max.X, bounds.Max.Y, a, b, c, d, tx, ty, cr, cg, cb, ca)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
i.mipmap.original().DrawImage(src, vs, is, colorm, mode, filter)
|
i.mipmap.original().DrawImage(src, vs, is, colorm, mode, filter, graphics.AddressClampToZero)
|
||||||
} else if src := img.mipmap.level(bounds, level); src != nil {
|
} else if src := img.mipmap.level(bounds, level); src != nil {
|
||||||
w, h := src.Size()
|
w, h := src.Size()
|
||||||
s := 1 << uint(level)
|
s := 1 << uint(level)
|
||||||
@ -397,7 +397,7 @@ func (i *Image) drawImage(img *Image, options *DrawImageOptions) {
|
|||||||
d *= float32(s)
|
d *= float32(s)
|
||||||
vs := src.QuadVertices(0, 0, w, h, a, b, c, d, tx, ty, cr, cg, cb, ca)
|
vs := src.QuadVertices(0, 0, w, h, a, b, c, d, tx, ty, cr, cg, cb, ca)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
i.mipmap.original().DrawImage(src, vs, is, colorm, mode, filter)
|
i.mipmap.original().DrawImage(src, vs, is, colorm, mode, filter, graphics.AddressClampToZero)
|
||||||
}
|
}
|
||||||
i.disposeMipmaps()
|
i.disposeMipmaps()
|
||||||
}
|
}
|
||||||
@ -425,6 +425,17 @@ type Vertex struct {
|
|||||||
ColorA float32
|
ColorA float32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Address represents a sampler address mode.
|
||||||
|
type Address int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AddressClampToZero means that out-of-range texture coordinates return 0 (transparent).
|
||||||
|
AddressClampToZero = Address(graphics.AddressClampToZero)
|
||||||
|
|
||||||
|
// AddressRepeat means that texture coordinates wrap to the other side of the texture.
|
||||||
|
AddressRepeat = Address(graphics.AddressRepeat)
|
||||||
|
)
|
||||||
|
|
||||||
// DrawTrianglesOptions represents options to render triangles on an image.
|
// DrawTrianglesOptions represents options to render triangles on an image.
|
||||||
//
|
//
|
||||||
// Note that this API is experimental.
|
// Note that this API is experimental.
|
||||||
@ -441,6 +452,10 @@ type DrawTrianglesOptions struct {
|
|||||||
// Filter is a type of texture filter.
|
// Filter is a type of texture filter.
|
||||||
// The default (zero) value is FilterDefault.
|
// The default (zero) value is FilterDefault.
|
||||||
Filter Filter
|
Filter Filter
|
||||||
|
|
||||||
|
// Address is a sampler address mode.
|
||||||
|
// The default (zero) value is AddressClampToZero.
|
||||||
|
Address Address
|
||||||
}
|
}
|
||||||
|
|
||||||
// MaxIndicesNum is the maximum number of indices for DrawTriangles.
|
// MaxIndicesNum is the maximum number of indices for DrawTriangles.
|
||||||
@ -499,7 +514,7 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
|
|||||||
float32(r.Min.X), float32(r.Min.Y), float32(r.Max.X), float32(r.Max.Y),
|
float32(r.Min.X), float32(r.Min.Y), float32(r.Max.X), float32(r.Max.Y),
|
||||||
v.ColorR, v.ColorG, v.ColorB, v.ColorA)
|
v.ColorR, v.ColorG, v.ColorB, v.ColorA)
|
||||||
}
|
}
|
||||||
i.mipmap.original().DrawImage(img.mipmap.original(), vs, indices, options.ColorM.impl, mode, filter)
|
i.mipmap.original().DrawImage(img.mipmap.original(), vs, indices, options.ColorM.impl, mode, filter, graphics.Address(options.Address))
|
||||||
i.disposeMipmaps()
|
i.disposeMipmaps()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1258,3 +1258,84 @@ func TestImageLinearFilterGlitch(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestImageAddressRepeat(t *testing.T) {
|
||||||
|
const w, h = 16, 16
|
||||||
|
src, _ := NewImage(w, h, FilterDefault)
|
||||||
|
dst, _ := NewImage(w, h, FilterDefault)
|
||||||
|
pix := make([]byte, 4*w*h)
|
||||||
|
for j := 0; j < h; j++ {
|
||||||
|
for i := 0; i < w; i++ {
|
||||||
|
idx := 4 * (i + j*w)
|
||||||
|
if 4 <= i && i < 8 && 4 <= j && j < 8 {
|
||||||
|
pix[idx] = byte(i-4) * 0x10
|
||||||
|
pix[idx+1] = byte(j-4) * 0x10
|
||||||
|
pix[idx+2] = 0
|
||||||
|
pix[idx+3] = 0xff
|
||||||
|
} else {
|
||||||
|
pix[idx] = 0
|
||||||
|
pix[idx+1] = 0
|
||||||
|
pix[idx+2] = 0xff
|
||||||
|
pix[idx+3] = 0xff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
src.ReplacePixels(pix)
|
||||||
|
|
||||||
|
vs := []Vertex{
|
||||||
|
{
|
||||||
|
DstX: 0,
|
||||||
|
DstY: 0,
|
||||||
|
SrcX: 0,
|
||||||
|
SrcY: 0,
|
||||||
|
ColorR: 1,
|
||||||
|
ColorG: 1,
|
||||||
|
ColorB: 1,
|
||||||
|
ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: w,
|
||||||
|
DstY: 0,
|
||||||
|
SrcX: w,
|
||||||
|
SrcY: 0,
|
||||||
|
ColorR: 1,
|
||||||
|
ColorG: 1,
|
||||||
|
ColorB: 1,
|
||||||
|
ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: 0,
|
||||||
|
DstY: h,
|
||||||
|
SrcX: 0,
|
||||||
|
SrcY: h,
|
||||||
|
ColorR: 1,
|
||||||
|
ColorG: 1,
|
||||||
|
ColorB: 1,
|
||||||
|
ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: w,
|
||||||
|
DstY: h,
|
||||||
|
SrcX: w,
|
||||||
|
SrcY: h,
|
||||||
|
ColorR: 1,
|
||||||
|
ColorG: 1,
|
||||||
|
ColorB: 1,
|
||||||
|
ColorA: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
is := []uint16{0, 1, 2, 1, 2, 3}
|
||||||
|
op := &DrawTrianglesOptions{}
|
||||||
|
op.Address = AddressRepeat
|
||||||
|
dst.DrawTriangles(vs, is, src.SubImage(image.Rect(4, 4, 8, 8)).(*Image), op)
|
||||||
|
|
||||||
|
for j := 0; j < h; j++ {
|
||||||
|
for i := 0; i < w; i++ {
|
||||||
|
got := dst.At(i, j).(color.RGBA)
|
||||||
|
want := color.RGBA{byte(i%4) * 0x10, byte(j%4) * 0x10, 0, 0xff}
|
||||||
|
if !sameColors(got, want, 1) {
|
||||||
|
t.Errorf("dst.At(%d, %d): got %v, want: %v", i, j, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -22,3 +22,10 @@ const (
|
|||||||
FilterLinear
|
FilterLinear
|
||||||
FilterScreen
|
FilterScreen
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Address int
|
||||||
|
|
||||||
|
const (
|
||||||
|
AddressClampToZero Address = iota
|
||||||
|
AddressRepeat
|
||||||
|
)
|
||||||
|
@ -35,7 +35,7 @@ type command interface {
|
|||||||
NumIndices() int
|
NumIndices() int
|
||||||
AddNumVertices(n int)
|
AddNumVertices(n int)
|
||||||
AddNumIndices(n int)
|
AddNumIndices(n int)
|
||||||
CanMerge(dst, src *Image, color *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter) bool
|
CanMerge(dst, src *Image, color *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter, address graphics.Address) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// commandQueue is a command queue for drawing commands.
|
// commandQueue is a command queue for drawing commands.
|
||||||
@ -87,12 +87,12 @@ func (q *commandQueue) appendIndices(indices []uint16, offset uint16) {
|
|||||||
q.nindices += len(indices)
|
q.nindices += len(indices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *commandQueue) doEnqueueDrawImageCommand(dst, src *Image, nvertices, nindices int, color *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter, forceNewCommand bool) {
|
func (q *commandQueue) doEnqueueDrawImageCommand(dst, src *Image, nvertices, nindices int, color *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter, address graphics.Address, forceNewCommand bool) {
|
||||||
if nindices > graphics.IndicesNum {
|
if nindices > graphics.IndicesNum {
|
||||||
panic("not reached")
|
panic("not reached")
|
||||||
}
|
}
|
||||||
if !forceNewCommand && 0 < len(q.commands) {
|
if !forceNewCommand && 0 < len(q.commands) {
|
||||||
if last := q.commands[len(q.commands)-1]; last.CanMerge(dst, src, color, mode, filter) {
|
if last := q.commands[len(q.commands)-1]; last.CanMerge(dst, src, color, mode, filter, address) {
|
||||||
last.AddNumVertices(nvertices)
|
last.AddNumVertices(nvertices)
|
||||||
last.AddNumIndices(nindices)
|
last.AddNumIndices(nindices)
|
||||||
return
|
return
|
||||||
@ -106,12 +106,13 @@ func (q *commandQueue) doEnqueueDrawImageCommand(dst, src *Image, nvertices, nin
|
|||||||
color: color,
|
color: color,
|
||||||
mode: mode,
|
mode: mode,
|
||||||
filter: filter,
|
filter: filter,
|
||||||
|
address: address,
|
||||||
}
|
}
|
||||||
q.commands = append(q.commands, c)
|
q.commands = append(q.commands, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnqueueDrawImageCommand enqueues a drawing-image command.
|
// EnqueueDrawImageCommand enqueues a drawing-image command.
|
||||||
func (q *commandQueue) EnqueueDrawImageCommand(dst, src *Image, vertices []float32, indices []uint16, color *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter) {
|
func (q *commandQueue) EnqueueDrawImageCommand(dst, src *Image, vertices []float32, indices []uint16, color *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter, address graphics.Address) {
|
||||||
if len(indices) > graphics.IndicesNum {
|
if len(indices) > graphics.IndicesNum {
|
||||||
panic("not reached")
|
panic("not reached")
|
||||||
}
|
}
|
||||||
@ -128,7 +129,7 @@ func (q *commandQueue) EnqueueDrawImageCommand(dst, src *Image, vertices []float
|
|||||||
q.nextIndex += len(vertices) / graphics.VertexFloatNum
|
q.nextIndex += len(vertices) / graphics.VertexFloatNum
|
||||||
q.tmpNumIndices += len(indices)
|
q.tmpNumIndices += len(indices)
|
||||||
|
|
||||||
q.doEnqueueDrawImageCommand(dst, src, len(vertices), len(indices), color, mode, filter, split)
|
q.doEnqueueDrawImageCommand(dst, src, len(vertices), len(indices), color, mode, filter, address, split)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enqueue enqueues a drawing command other than a draw-image command.
|
// Enqueue enqueues a drawing command other than a draw-image command.
|
||||||
@ -215,6 +216,7 @@ type drawImageCommand struct {
|
|||||||
color *affine.ColorM
|
color *affine.ColorM
|
||||||
mode graphics.CompositeMode
|
mode graphics.CompositeMode
|
||||||
filter graphics.Filter
|
filter graphics.Filter
|
||||||
|
address graphics.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *drawImageCommand) String() string {
|
func (c *drawImageCommand) String() string {
|
||||||
@ -230,7 +232,7 @@ func (c *drawImageCommand) Exec(indexOffset int) error {
|
|||||||
|
|
||||||
c.dst.image.SetAsDestination()
|
c.dst.image.SetAsDestination()
|
||||||
c.src.image.SetAsSource()
|
c.src.image.SetAsSource()
|
||||||
if err := Driver().Draw(c.nindices, indexOffset, c.mode, c.color, c.filter); err != nil {
|
if err := Driver().Draw(c.nindices, indexOffset, c.mode, c.color, c.filter, c.address); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -254,7 +256,7 @@ func (c *drawImageCommand) AddNumIndices(n int) {
|
|||||||
|
|
||||||
// CanMerge returns a boolean value indicating whether the other drawImageCommand can be merged
|
// CanMerge returns a boolean value indicating whether the other drawImageCommand can be merged
|
||||||
// with the drawImageCommand c.
|
// with the drawImageCommand c.
|
||||||
func (c *drawImageCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter) bool {
|
func (c *drawImageCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter, address graphics.Address) bool {
|
||||||
if c.dst != dst {
|
if c.dst != dst {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -270,6 +272,9 @@ func (c *drawImageCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode
|
|||||||
if c.filter != filter {
|
if c.filter != filter {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if c.address != address {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,7 +312,7 @@ func (c *replacePixelsCommand) AddNumVertices(n int) {
|
|||||||
func (c *replacePixelsCommand) AddNumIndices(n int) {
|
func (c *replacePixelsCommand) AddNumIndices(n int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *replacePixelsCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter) bool {
|
func (c *replacePixelsCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter, address graphics.Address) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,7 +349,7 @@ func (c *pixelsCommand) AddNumVertices(n int) {
|
|||||||
func (c *pixelsCommand) AddNumIndices(n int) {
|
func (c *pixelsCommand) AddNumIndices(n int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *pixelsCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter) bool {
|
func (c *pixelsCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter, address graphics.Address) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,7 +382,7 @@ func (c *disposeCommand) AddNumVertices(n int) {
|
|||||||
func (c *disposeCommand) AddNumIndices(n int) {
|
func (c *disposeCommand) AddNumIndices(n int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *disposeCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter) bool {
|
func (c *disposeCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter, address graphics.Address) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,7 +421,7 @@ func (c *newImageCommand) AddNumVertices(n int) {
|
|||||||
func (c *newImageCommand) AddNumIndices(n int) {
|
func (c *newImageCommand) AddNumIndices(n int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *newImageCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter) bool {
|
func (c *newImageCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter, address graphics.Address) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,7 +457,7 @@ func (c *newScreenFramebufferImageCommand) AddNumVertices(n int) {
|
|||||||
func (c *newScreenFramebufferImageCommand) AddNumIndices(n int) {
|
func (c *newScreenFramebufferImageCommand) AddNumIndices(n int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *newScreenFramebufferImageCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter) bool {
|
func (c *newScreenFramebufferImageCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter, address graphics.Address) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,8 +70,8 @@ func (i *Image) Size() (int, int) {
|
|||||||
return i.width, i.height
|
return i.width, i.height
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) DrawImage(src *Image, vertices []float32, indices []uint16, clr *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter) {
|
func (i *Image) DrawImage(src *Image, vertices []float32, indices []uint16, clr *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter, address graphics.Address) {
|
||||||
theCommandQueue.EnqueueDrawImageCommand(i, src, vertices, indices, clr, mode, filter)
|
theCommandQueue.EnqueueDrawImageCommand(i, src, vertices, indices, clr, mode, filter, address)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pixels returns the image's pixels.
|
// Pixels returns the image's pixels.
|
||||||
|
@ -49,7 +49,7 @@ func TestClear(t *testing.T) {
|
|||||||
|
|
||||||
vs := graphics.QuadVertices(w/2, h/2, 0, 0, w/2, h/2, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
vs := graphics.QuadVertices(w/2, h/2, 0, 0, w/2, h/2, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
dst.DrawImage(src, vs, is, nil, graphics.CompositeModeClear, graphics.FilterNearest)
|
dst.DrawImage(src, vs, is, nil, graphics.CompositeModeClear, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
|
|
||||||
pix := dst.Pixels()
|
pix := dst.Pixels()
|
||||||
for j := 0; j < h/2; j++ {
|
for j := 0; j < h/2; j++ {
|
||||||
|
@ -26,7 +26,7 @@ type GraphicsDriver 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 graphics.CompositeMode, colorM *affine.ColorM, filter graphics.Filter) error
|
Draw(indexLen int, indexOffset int, mode graphics.CompositeMode, colorM *affine.ColorM, filter graphics.Filter, address graphics.Address) error
|
||||||
SetVsyncEnabled(enabled bool)
|
SetVsyncEnabled(enabled bool)
|
||||||
VDirection() VDirection
|
VDirection() VDirection
|
||||||
IsGL() bool
|
IsGL() bool
|
||||||
|
@ -36,6 +36,9 @@ const source = `#include <metal_stdlib>
|
|||||||
#define FILTER_LINEAR ({{.FilterLinear}})
|
#define FILTER_LINEAR ({{.FilterLinear}})
|
||||||
#define FILTER_SCREEN ({{.FilterScreen}})
|
#define FILTER_SCREEN ({{.FilterScreen}})
|
||||||
|
|
||||||
|
#define ADDRESS_CLAMP_TO_ZERO ({{.AddressClampToZero}})
|
||||||
|
#define ADDRESS_REPEAT ({{.AddressRepeat}})
|
||||||
|
|
||||||
using namespace metal;
|
using namespace metal;
|
||||||
|
|
||||||
struct VertexIn {
|
struct VertexIn {
|
||||||
@ -89,12 +92,37 @@ float2 AdjustTexel(float2 source_size, float2 p0, float2 p1) {
|
|||||||
return p1;
|
return p1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Mod(float x, float y) {
|
||||||
|
if (x < 0.0) {
|
||||||
|
return y - (-x - y * floor(-x/y));
|
||||||
|
}
|
||||||
|
return x - y * floor(x/y);
|
||||||
|
}
|
||||||
|
|
||||||
|
float2 AdjustTexelByAddress(float2 p, float4 tex_region, uint8_t address) {
|
||||||
|
switch (address) {
|
||||||
|
case ADDRESS_CLAMP_TO_ZERO: {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
case ADDRESS_REPEAT: {
|
||||||
|
float2 o = float2(tex_region[0], tex_region[1]);
|
||||||
|
float2 size = float2(tex_region[2] - tex_region[0], tex_region[3] - tex_region[1]);
|
||||||
|
return float2(Mod((p.x - o.x), size.x) + o.x, Mod((p.y - o.y), size.y) + o.y);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// Not reached.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
fragment float4 FragmentShader(VertexOut v [[stage_in]],
|
fragment float4 FragmentShader(VertexOut v [[stage_in]],
|
||||||
texture2d<float> texture [[texture(0)]],
|
texture2d<float> texture [[texture(0)]],
|
||||||
constant float4x4& color_matrix_body [[buffer(2)]],
|
constant float4x4& color_matrix_body [[buffer(2)]],
|
||||||
constant float4& color_matrix_translation [[buffer(3)]],
|
constant float4& color_matrix_translation [[buffer(3)]],
|
||||||
constant uint8_t& filter [[buffer(4)]],
|
constant uint8_t& filter [[buffer(4)]],
|
||||||
constant float& scale [[buffer(5)]]) {
|
constant uint8_t& address [[buffer(5)]],
|
||||||
|
constant float& scale [[buffer(6)]]) {
|
||||||
constexpr sampler texture_sampler(filter::nearest);
|
constexpr sampler texture_sampler(filter::nearest);
|
||||||
float2 source_size = 1;
|
float2 source_size = 1;
|
||||||
while (source_size.x < texture.get_width()) {
|
while (source_size.x < texture.get_width()) {
|
||||||
@ -109,11 +137,12 @@ fragment float4 FragmentShader(VertexOut v [[stage_in]],
|
|||||||
|
|
||||||
switch (filter) {
|
switch (filter) {
|
||||||
case FILTER_NEAREST: {
|
case FILTER_NEAREST: {
|
||||||
c = texture.sample(texture_sampler, v.tex);
|
float2 p = AdjustTexelByAddress(v.tex, v.tex_region, address);
|
||||||
if (v.tex.x < v.tex_region[0] ||
|
c = texture.sample(texture_sampler, p);
|
||||||
v.tex.y < v.tex_region[1] ||
|
if (p.x < v.tex_region[0] ||
|
||||||
(v.tex_region[2] - texel_size.x / 512.0) <= v.tex.x ||
|
p.y < v.tex_region[1] ||
|
||||||
(v.tex_region[3] - texel_size.y / 512.0) <= v.tex.y) {
|
(v.tex_region[2] - texel_size.x / 512.0) <= p.x ||
|
||||||
|
(v.tex_region[3] - texel_size.y / 512.0) <= p.y) {
|
||||||
c = 0;
|
c = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -123,6 +152,8 @@ fragment float4 FragmentShader(VertexOut v [[stage_in]],
|
|||||||
float2 p0 = v.tex - texel_size / 2.0;
|
float2 p0 = v.tex - texel_size / 2.0;
|
||||||
float2 p1 = v.tex + texel_size / 2.0;
|
float2 p1 = v.tex + texel_size / 2.0;
|
||||||
p1 = AdjustTexel(source_size, p0, p1);
|
p1 = AdjustTexel(source_size, p0, p1);
|
||||||
|
p0 = AdjustTexelByAddress(p0, v.tex_region, address);
|
||||||
|
p1 = AdjustTexelByAddress(p1, v.tex_region, address);
|
||||||
|
|
||||||
float4 c0 = texture.sample(texture_sampler, p0);
|
float4 c0 = texture.sample(texture_sampler, p0);
|
||||||
float4 c1 = texture.sample(texture_sampler, float2(p1.x, p0.y));
|
float4 c1 = texture.sample(texture_sampler, float2(p1.x, p0.y));
|
||||||
@ -367,9 +398,11 @@ func (d *Driver) Reset() error {
|
|||||||
d.ml.SetDisplaySyncEnabled(true)
|
d.ml.SetDisplaySyncEnabled(true)
|
||||||
|
|
||||||
replaces := map[string]string{
|
replaces := map[string]string{
|
||||||
"{{.FilterNearest}}": fmt.Sprintf("%d", graphics.FilterNearest),
|
"{{.FilterNearest}}": fmt.Sprintf("%d", graphics.FilterNearest),
|
||||||
"{{.FilterLinear}}": fmt.Sprintf("%d", graphics.FilterLinear),
|
"{{.FilterLinear}}": fmt.Sprintf("%d", graphics.FilterLinear),
|
||||||
"{{.FilterScreen}}": fmt.Sprintf("%d", graphics.FilterScreen),
|
"{{.FilterScreen}}": fmt.Sprintf("%d", graphics.FilterScreen),
|
||||||
|
"{{.AddressClampToZero}}": fmt.Sprintf("%d", graphics.AddressClampToZero),
|
||||||
|
"{{.AddressRepeat}}": fmt.Sprintf("%d", graphics.AddressRepeat),
|
||||||
}
|
}
|
||||||
src := source
|
src := source
|
||||||
for k, v := range replaces {
|
for k, v := range replaces {
|
||||||
@ -452,7 +485,8 @@ func (d *Driver) Reset() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Driver) Draw(indexLen int, indexOffset int, mode graphics.CompositeMode, colorM *affine.ColorM, filter graphics.Filter) error {
|
func (d *Driver) Draw(indexLen int, indexOffset int, mode graphics.CompositeMode, colorM *affine.ColorM, filter graphics.Filter, address graphics.Address) error {
|
||||||
|
// TODO: Use address
|
||||||
if err := mainthread.Run(func() error {
|
if err := mainthread.Run(func() error {
|
||||||
// NSView can be changed anytime (probably). Set this everyframe.
|
// NSView can be changed anytime (probably). Set this everyframe.
|
||||||
cocoaWindow := ns.NewWindow(unsafe.Pointer(d.window))
|
cocoaWindow := ns.NewWindow(unsafe.Pointer(d.window))
|
||||||
@ -509,8 +543,11 @@ func (d *Driver) Draw(indexLen int, indexOffset int, mode graphics.CompositeMode
|
|||||||
f := uint8(filter)
|
f := uint8(filter)
|
||||||
rce.SetFragmentBytes(unsafe.Pointer(&f), 1, 4)
|
rce.SetFragmentBytes(unsafe.Pointer(&f), 1, 4)
|
||||||
|
|
||||||
|
a := uint8(address)
|
||||||
|
rce.SetFragmentBytes(unsafe.Pointer(&a), 1, 5)
|
||||||
|
|
||||||
scale := float32(d.dst.width) / float32(d.src.width)
|
scale := float32(d.dst.width) / float32(d.src.width)
|
||||||
rce.SetFragmentBytes(unsafe.Pointer(&scale), unsafe.Sizeof(scale), 5)
|
rce.SetFragmentBytes(unsafe.Pointer(&scale), unsafe.Sizeof(scale), 6)
|
||||||
|
|
||||||
if d.src != nil {
|
if d.src != nil {
|
||||||
rce.SetFragmentTexture(d.src.texture, 0)
|
rce.SetFragmentTexture(d.src.texture, 0)
|
||||||
|
@ -94,8 +94,8 @@ func (d *Driver) SetVertices(vertices []float32, indices []uint16) {
|
|||||||
d.context.elementArrayBufferSubData(indices)
|
d.context.elementArrayBufferSubData(indices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Driver) Draw(indexLen int, indexOffset int, mode graphics.CompositeMode, colorM *affine.ColorM, filter graphics.Filter) error {
|
func (d *Driver) Draw(indexLen int, indexOffset int, mode graphics.CompositeMode, colorM *affine.ColorM, filter graphics.Filter, address graphics.Address) error {
|
||||||
if err := d.useProgram(mode, colorM, filter); err != nil {
|
if err := d.useProgram(mode, colorM, filter, address); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
d.context.drawElements(indexLen, indexOffset*2) // 2 is uint16 size in bytes
|
d.context.drawElements(indexLen, indexOffset*2) // 2 is uint16 size in bytes
|
||||||
|
@ -130,6 +130,7 @@ type openGLState struct {
|
|||||||
lastSourceWidth int
|
lastSourceWidth int
|
||||||
lastSourceHeight int
|
lastSourceHeight int
|
||||||
lastFilter *graphics.Filter
|
lastFilter *graphics.Filter
|
||||||
|
lastAddress *graphics.Address
|
||||||
|
|
||||||
source *Image
|
source *Image
|
||||||
destination *Image
|
destination *Image
|
||||||
@ -159,6 +160,7 @@ func (s *openGLState) reset(context *context) error {
|
|||||||
s.lastSourceWidth = 0
|
s.lastSourceWidth = 0
|
||||||
s.lastSourceHeight = 0
|
s.lastSourceHeight = 0
|
||||||
s.lastFilter = nil
|
s.lastFilter = nil
|
||||||
|
s.lastAddress = nil
|
||||||
|
|
||||||
// When context lost happens, deleting programs or buffers is not necessary.
|
// When context lost happens, deleting programs or buffers is not necessary.
|
||||||
// However, it is not assumed that reset is called only when context lost happens.
|
// However, it is not assumed that reset is called only when context lost happens.
|
||||||
@ -222,7 +224,7 @@ func areSameFloat32Array(a, b []float32) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// useProgram uses the program (programTexture).
|
// useProgram uses the program (programTexture).
|
||||||
func (d *Driver) useProgram(mode graphics.CompositeMode, colorM *affine.ColorM, filter graphics.Filter) error {
|
func (d *Driver) useProgram(mode graphics.CompositeMode, colorM *affine.ColorM, filter graphics.Filter, address graphics.Address) error {
|
||||||
destination := d.state.destination
|
destination := d.state.destination
|
||||||
if destination == nil {
|
if destination == nil {
|
||||||
panic("destination image is not set")
|
panic("destination image is not set")
|
||||||
@ -297,6 +299,10 @@ func (d *Driver) useProgram(mode graphics.CompositeMode, colorM *affine.ColorM,
|
|||||||
d.context.uniformInt(program, "filter", int(filter))
|
d.context.uniformInt(program, "filter", int(filter))
|
||||||
d.state.lastFilter = &filter
|
d.state.lastFilter = &filter
|
||||||
}
|
}
|
||||||
|
if d.state.lastAddress == nil || *d.state.lastAddress != address {
|
||||||
|
d.context.uniformInt(program, "address", int(address))
|
||||||
|
d.state.lastAddress = &address
|
||||||
|
}
|
||||||
|
|
||||||
if filter == graphics.FilterScreen {
|
if filter == graphics.FilterScreen {
|
||||||
scale := float32(dstW) / float32(srcW)
|
scale := float32(dstW) / float32(srcW)
|
||||||
|
@ -34,9 +34,11 @@ func shaderStr(id shaderID) string {
|
|||||||
return shaderStrVertex
|
return shaderStrVertex
|
||||||
case shaderFragmentColorMatrix:
|
case shaderFragmentColorMatrix:
|
||||||
replaces := map[string]string{
|
replaces := map[string]string{
|
||||||
"{{.FilterNearest}}": fmt.Sprintf("%d", graphics.FilterNearest),
|
"{{.FilterNearest}}": fmt.Sprintf("%d", graphics.FilterNearest),
|
||||||
"{{.FilterLinear}}": fmt.Sprintf("%d", graphics.FilterLinear),
|
"{{.FilterLinear}}": fmt.Sprintf("%d", graphics.FilterLinear),
|
||||||
"{{.FilterScreen}}": fmt.Sprintf("%d", graphics.FilterScreen),
|
"{{.FilterScreen}}": fmt.Sprintf("%d", graphics.FilterScreen),
|
||||||
|
"{{.AddressClampToZero}}": fmt.Sprintf("%d", graphics.AddressClampToZero),
|
||||||
|
"{{.AddressRepeat}}": fmt.Sprintf("%d", graphics.AddressRepeat),
|
||||||
}
|
}
|
||||||
src := shaderStrFragment
|
src := shaderStrFragment
|
||||||
for k, v := range replaces {
|
for k, v := range replaces {
|
||||||
@ -85,6 +87,8 @@ precision mediump float;
|
|||||||
#define FILTER_NEAREST ({{.FilterNearest}})
|
#define FILTER_NEAREST ({{.FilterNearest}})
|
||||||
#define FILTER_LINEAR ({{.FilterLinear}})
|
#define FILTER_LINEAR ({{.FilterLinear}})
|
||||||
#define FILTER_SCREEN ({{.FilterScreen}})
|
#define FILTER_SCREEN ({{.FilterScreen}})
|
||||||
|
#define ADDRESS_CLAMP_TO_ZERO ({{.AddressClampToZero}})
|
||||||
|
#define ADDRESS_REPEAT ({{.AddressRepeat}})
|
||||||
|
|
||||||
uniform sampler2D texture;
|
uniform sampler2D texture;
|
||||||
uniform mat4 color_matrix_body;
|
uniform mat4 color_matrix_body;
|
||||||
@ -92,6 +96,7 @@ uniform vec4 color_matrix_translation;
|
|||||||
|
|
||||||
uniform int filter;
|
uniform int filter;
|
||||||
uniform highp vec2 source_size;
|
uniform highp vec2 source_size;
|
||||||
|
uniform int address;
|
||||||
|
|
||||||
#if defined(FILTER_SCREEN)
|
#if defined(FILTER_SCREEN)
|
||||||
uniform highp float scale;
|
uniform highp float scale;
|
||||||
@ -115,6 +120,26 @@ highp vec2 adjustTexel(highp vec2 p0, highp vec2 p1) {
|
|||||||
return p1;
|
return p1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
highp float mod(highp float x, highp float y) {
|
||||||
|
if (x < 0.0) {
|
||||||
|
return y - (-x - y * floor(-x/y));
|
||||||
|
}
|
||||||
|
return x - y * floor(x/y);
|
||||||
|
}
|
||||||
|
|
||||||
|
highp vec2 adjustTexelByAddress(highp vec2 p, highp vec4 tex_region, int address) {
|
||||||
|
if (address == ADDRESS_CLAMP_TO_ZERO) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
if (address == ADDRESS_REPEAT) {
|
||||||
|
highp vec2 o = vec2(tex_region[0], tex_region[1]);
|
||||||
|
highp vec2 size = vec2(tex_region[2] - tex_region[0], tex_region[3] - tex_region[1]);
|
||||||
|
return vec2(mod((p.x - o.x), size.x) + o.x, mod((p.y - o.y), size.y) + o.y);
|
||||||
|
}
|
||||||
|
// Not reached.
|
||||||
|
return vec2(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
highp vec2 pos = varying_tex;
|
highp vec2 pos = varying_tex;
|
||||||
highp vec2 texel_size = 1.0 / source_size;
|
highp vec2 texel_size = 1.0 / source_size;
|
||||||
@ -122,6 +147,7 @@ void main(void) {
|
|||||||
vec4 color;
|
vec4 color;
|
||||||
|
|
||||||
if (filter == FILTER_NEAREST) {
|
if (filter == FILTER_NEAREST) {
|
||||||
|
pos = adjustTexelByAddress(pos, varying_tex_region, address);
|
||||||
color = texture2D(texture, pos);
|
color = texture2D(texture, pos);
|
||||||
if (pos.x < varying_tex_region[0] ||
|
if (pos.x < varying_tex_region[0] ||
|
||||||
pos.y < varying_tex_region[1] ||
|
pos.y < varying_tex_region[1] ||
|
||||||
@ -134,6 +160,8 @@ void main(void) {
|
|||||||
highp vec2 p1 = pos + texel_size / 2.0;
|
highp vec2 p1 = pos + texel_size / 2.0;
|
||||||
|
|
||||||
p1 = adjustTexel(p0, p1);
|
p1 = adjustTexel(p0, p1);
|
||||||
|
p0 = adjustTexelByAddress(p0, varying_tex_region, address);
|
||||||
|
p1 = adjustTexelByAddress(p1, varying_tex_region, address);
|
||||||
|
|
||||||
vec4 c0 = texture2D(texture, p0);
|
vec4 c0 = texture2D(texture, p0);
|
||||||
vec4 c1 = texture2D(texture, vec2(p1.x, p0.y));
|
vec4 c1 = texture2D(texture, vec2(p1.x, p0.y));
|
||||||
|
@ -32,6 +32,7 @@ type drawImageHistoryItem struct {
|
|||||||
colorm *affine.ColorM
|
colorm *affine.ColorM
|
||||||
mode graphics.CompositeMode
|
mode graphics.CompositeMode
|
||||||
filter graphics.Filter
|
filter graphics.Filter
|
||||||
|
address graphics.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
// Image represents an image that can be restored when GL context is lost.
|
// Image represents an image that can be restored when GL context is lost.
|
||||||
@ -170,7 +171,7 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
|
|||||||
float32(x), float32(y),
|
float32(x), float32(y),
|
||||||
1, 1, 1, 1)
|
1, 1, 1, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
i.image.DrawImage(dummyImage.image, vs, is, nil, graphics.CompositeModeClear, graphics.FilterNearest)
|
i.image.DrawImage(dummyImage.image, vs, is, nil, graphics.CompositeModeClear, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
}
|
}
|
||||||
|
|
||||||
if x == 0 && y == 0 && width == w && height == h {
|
if x == 0 && y == 0 && width == w && height == h {
|
||||||
@ -213,7 +214,7 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DrawImage draws a given image img to the image.
|
// DrawImage draws a given image img to the image.
|
||||||
func (i *Image) DrawImage(img *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter) {
|
func (i *Image) DrawImage(img *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter, address graphics.Address) {
|
||||||
if len(vertices) == 0 {
|
if len(vertices) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -222,13 +223,13 @@ func (i *Image) DrawImage(img *Image, vertices []float32, indices []uint16, colo
|
|||||||
if img.stale || img.volatile || i.screen || !IsRestoringEnabled() {
|
if img.stale || img.volatile || i.screen || !IsRestoringEnabled() {
|
||||||
i.makeStale()
|
i.makeStale()
|
||||||
} else {
|
} else {
|
||||||
i.appendDrawImageHistory(img, vertices, indices, colorm, mode, filter)
|
i.appendDrawImageHistory(img, vertices, indices, colorm, mode, filter, address)
|
||||||
}
|
}
|
||||||
i.image.DrawImage(img.image, vertices, indices, colorm, mode, filter)
|
i.image.DrawImage(img.image, vertices, indices, colorm, mode, filter, address)
|
||||||
}
|
}
|
||||||
|
|
||||||
// appendDrawImageHistory appends a draw-image history item to the image.
|
// appendDrawImageHistory appends a draw-image history item to the image.
|
||||||
func (i *Image) appendDrawImageHistory(image *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter) {
|
func (i *Image) appendDrawImageHistory(image *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter, address graphics.Address) {
|
||||||
if i.stale || i.volatile || i.screen {
|
if i.stale || i.volatile || i.screen {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -246,6 +247,7 @@ func (i *Image) appendDrawImageHistory(image *Image, vertices []float32, indices
|
|||||||
colorm: colorm,
|
colorm: colorm,
|
||||||
mode: mode,
|
mode: mode,
|
||||||
filter: filter,
|
filter: filter,
|
||||||
|
address: address,
|
||||||
}
|
}
|
||||||
i.drawImageHistory = append(i.drawImageHistory, item)
|
i.drawImageHistory = append(i.drawImageHistory, item)
|
||||||
}
|
}
|
||||||
@ -378,7 +380,7 @@ func (i *Image) restore() error {
|
|||||||
if c.image.hasDependency() {
|
if c.image.hasDependency() {
|
||||||
panic("not reached")
|
panic("not reached")
|
||||||
}
|
}
|
||||||
gimg.DrawImage(c.image.image, c.vertices, c.indices, c.colorm, c.mode, c.filter)
|
gimg.DrawImage(c.image.image, c.vertices, c.indices, c.colorm, c.mode, c.filter, c.address)
|
||||||
}
|
}
|
||||||
i.image = gimg
|
i.image = gimg
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ func TestRestoreChain(t *testing.T) {
|
|||||||
w, h := imgs[i].Size()
|
w, h := imgs[i].Size()
|
||||||
vs := graphics.QuadVertices(w, h, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
vs := graphics.QuadVertices(w, h, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
imgs[i+1].DrawImage(imgs[i], vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest)
|
imgs[i+1].DrawImage(imgs[i], vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
}
|
}
|
||||||
ResolveStaleImages()
|
ResolveStaleImages()
|
||||||
if err := Restore(); err != nil {
|
if err := Restore(); err != nil {
|
||||||
@ -178,10 +178,10 @@ func TestRestoreChain2(t *testing.T) {
|
|||||||
|
|
||||||
vs := graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
vs := graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
imgs[8].DrawImage(imgs[7], vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest)
|
imgs[8].DrawImage(imgs[7], vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
imgs[9].DrawImage(imgs[8], vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest)
|
imgs[9].DrawImage(imgs[8], vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
for i := 0; i < 7; i++ {
|
for i := 0; i < 7; i++ {
|
||||||
imgs[i+1].DrawImage(imgs[i], vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest)
|
imgs[i+1].DrawImage(imgs[i], vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolveStaleImages()
|
ResolveStaleImages()
|
||||||
@ -224,10 +224,10 @@ func TestRestoreOverrideSource(t *testing.T) {
|
|||||||
fill(img1, clr0.R, clr0.G, clr0.B, clr0.A)
|
fill(img1, clr0.R, clr0.G, clr0.B, clr0.A)
|
||||||
vs := graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
vs := graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
img2.DrawImage(img1, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest)
|
img2.DrawImage(img1, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
img3.DrawImage(img2, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest)
|
img3.DrawImage(img2, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
fill(img0, clr1.R, clr1.G, clr1.B, clr1.A)
|
fill(img0, clr1.R, clr1.G, clr1.B, clr1.A)
|
||||||
img1.DrawImage(img0, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest)
|
img1.DrawImage(img0, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
ResolveStaleImages()
|
ResolveStaleImages()
|
||||||
if err := Restore(); err != nil {
|
if err := Restore(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -309,23 +309,23 @@ func TestRestoreComplexGraph(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
vs := graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
vs := graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
img3.DrawImage(img0, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest)
|
img3.DrawImage(img0, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
vs = graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1)
|
vs = graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1)
|
||||||
img3.DrawImage(img1, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest)
|
img3.DrawImage(img1, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
vs = graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1)
|
vs = graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1)
|
||||||
img4.DrawImage(img1, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest)
|
img4.DrawImage(img1, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
vs = graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 2, 0, 1, 1, 1, 1)
|
vs = graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 2, 0, 1, 1, 1, 1)
|
||||||
img4.DrawImage(img2, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest)
|
img4.DrawImage(img2, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
vs = graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
vs = graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
||||||
img5.DrawImage(img3, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest)
|
img5.DrawImage(img3, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
vs = graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
vs = graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
||||||
img6.DrawImage(img3, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest)
|
img6.DrawImage(img3, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
vs = graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1)
|
vs = graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1)
|
||||||
img6.DrawImage(img4, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest)
|
img6.DrawImage(img4, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
vs = graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
vs = graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
||||||
img7.DrawImage(img2, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest)
|
img7.DrawImage(img2, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
vs = graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 2, 0, 1, 1, 1, 1)
|
vs = graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 2, 0, 1, 1, 1, 1)
|
||||||
img7.DrawImage(img3, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest)
|
img7.DrawImage(img3, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
ResolveStaleImages()
|
ResolveStaleImages()
|
||||||
if err := Restore(); err != nil {
|
if err := Restore(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -417,8 +417,8 @@ func TestRestoreRecursive(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
vs := graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1)
|
vs := graphics.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
img1.DrawImage(img0, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest)
|
img1.DrawImage(img0, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
img0.DrawImage(img1, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest)
|
img0.DrawImage(img1, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
ResolveStaleImages()
|
ResolveStaleImages()
|
||||||
if err := Restore(); err != nil {
|
if err := Restore(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -505,7 +505,7 @@ func TestDrawImageAndReplacePixels(t *testing.T) {
|
|||||||
|
|
||||||
vs := graphics.QuadVertices(1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
vs := graphics.QuadVertices(1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
img1.DrawImage(img0, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest)
|
img1.DrawImage(img0, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
img1.ReplacePixels([]byte{0xff, 0xff, 0xff, 0xff}, 1, 0, 1, 1)
|
img1.ReplacePixels([]byte{0xff, 0xff, 0xff, 0xff}, 1, 0, 1, 1)
|
||||||
|
|
||||||
ResolveStaleImages()
|
ResolveStaleImages()
|
||||||
@ -537,8 +537,8 @@ func TestDispose(t *testing.T) {
|
|||||||
|
|
||||||
vs := graphics.QuadVertices(1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
vs := graphics.QuadVertices(1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
img1.DrawImage(img2, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest)
|
img1.DrawImage(img2, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
img0.DrawImage(img1, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest)
|
img0.DrawImage(img1, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
img1.Dispose()
|
img1.Dispose()
|
||||||
|
|
||||||
ResolveStaleImages()
|
ResolveStaleImages()
|
||||||
@ -565,7 +565,7 @@ func TestDoubleResolve(t *testing.T) {
|
|||||||
|
|
||||||
vs := graphics.QuadVertices(1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
vs := graphics.QuadVertices(1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
img0.DrawImage(img1, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest)
|
img0.DrawImage(img1, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
img0.ReplacePixels([]uint8{0x00, 0xff, 0x00, 0xff}, 1, 1, 1, 1)
|
img0.ReplacePixels([]uint8{0x00, 0xff, 0x00, 0xff}, 1, 1, 1, 1)
|
||||||
// Now img0 is stale.
|
// Now img0 is stale.
|
||||||
ResolveStaleImages()
|
ResolveStaleImages()
|
||||||
|
@ -135,7 +135,7 @@ func (i *Image) ensureNotShared() {
|
|||||||
vw, vh := i.backend.restorable.Size()
|
vw, vh := i.backend.restorable.Size()
|
||||||
vs := graphics.QuadVertices(vw, vh, x, y, x+w, y+h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
vs := graphics.QuadVertices(vw, vh, x, y, x+w, y+h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
newImg.DrawImage(i.backend.restorable, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest)
|
newImg.DrawImage(i.backend.restorable, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
|
|
||||||
i.dispose(false)
|
i.dispose(false)
|
||||||
i.backend = &backend{
|
i.backend = &backend{
|
||||||
@ -218,7 +218,7 @@ func (i *Image) PutVertex(dest []float32, dx, dy, sx, sy float32, bx0, by0, bx1,
|
|||||||
|
|
||||||
const MaxCountForShare = 10
|
const MaxCountForShare = 10
|
||||||
|
|
||||||
func (i *Image) DrawImage(img *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter) {
|
func (i *Image) DrawImage(img *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter, address graphics.Address) {
|
||||||
backendsM.Lock()
|
backendsM.Lock()
|
||||||
defer backendsM.Unlock()
|
defer backendsM.Unlock()
|
||||||
|
|
||||||
@ -240,7 +240,7 @@ func (i *Image) DrawImage(img *Image, vertices []float32, indices []uint16, colo
|
|||||||
panic("shareable: Image.DrawImage: img must be different from the receiver")
|
panic("shareable: Image.DrawImage: img must be different from the receiver")
|
||||||
}
|
}
|
||||||
|
|
||||||
i.backend.restorable.DrawImage(img.backend.restorable, vertices, indices, colorm, mode, filter)
|
i.backend.restorable.DrawImage(img.backend.restorable, vertices, indices, colorm, mode, filter, address)
|
||||||
|
|
||||||
i.countForShare = 0
|
i.countForShare = 0
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ func TestEnsureNotShared(t *testing.T) {
|
|||||||
// img4.ensureNotShared() should be called.
|
// img4.ensureNotShared() should be called.
|
||||||
vs := img3.QuadVertices(0, 0, size/2, size/2, 1, 0, 0, 1, size/4, size/4, 1, 1, 1, 1)
|
vs := img3.QuadVertices(0, 0, size/2, size/2, 1, 0, 0, 1, size/4, size/4, 1, 1, 1, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
img4.DrawImage(img3, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest)
|
img4.DrawImage(img3, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
want := false
|
want := false
|
||||||
if got := img4.IsSharedForTesting(); got != want {
|
if got := img4.IsSharedForTesting(); got != want {
|
||||||
t.Errorf("got: %v, want: %v", got, want)
|
t.Errorf("got: %v, want: %v", got, want)
|
||||||
@ -108,7 +108,7 @@ func TestEnsureNotShared(t *testing.T) {
|
|||||||
|
|
||||||
// Check further drawing doesn't cause panic.
|
// Check further drawing doesn't cause panic.
|
||||||
// This bug was fixed by 03dcd948.
|
// This bug was fixed by 03dcd948.
|
||||||
img4.DrawImage(img3, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest)
|
img4.DrawImage(img3, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Disabled_TestReshared(t *testing.T) {
|
func Disabled_TestReshared(t *testing.T) {
|
||||||
@ -150,7 +150,7 @@ func Disabled_TestReshared(t *testing.T) {
|
|||||||
// Use img1 as a render target.
|
// Use img1 as a render target.
|
||||||
vs := img2.QuadVertices(0, 0, size, size, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
vs := img2.QuadVertices(0, 0, size, size, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
img1.DrawImage(img2, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest)
|
img1.DrawImage(img2, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
want = false
|
want = false
|
||||||
if got := img1.IsSharedForTesting(); got != want {
|
if got := img1.IsSharedForTesting(); got != want {
|
||||||
t.Errorf("got: %v, want: %v", got, want)
|
t.Errorf("got: %v, want: %v", got, want)
|
||||||
@ -158,7 +158,7 @@ func Disabled_TestReshared(t *testing.T) {
|
|||||||
|
|
||||||
// Use img1 as a render source.
|
// Use img1 as a render source.
|
||||||
for i := 0; i < MaxCountForShare-1; i++ {
|
for i := 0; i < MaxCountForShare-1; i++ {
|
||||||
img0.DrawImage(img1, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest)
|
img0.DrawImage(img1, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
want := false
|
want := false
|
||||||
if got := img1.IsSharedForTesting(); got != want {
|
if got := img1.IsSharedForTesting(); got != want {
|
||||||
t.Errorf("got: %v, want: %v", got, want)
|
t.Errorf("got: %v, want: %v", got, want)
|
||||||
@ -175,7 +175,7 @@ func Disabled_TestReshared(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
img0.DrawImage(img1, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest)
|
img0.DrawImage(img1, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
want = true
|
want = true
|
||||||
if got := img1.IsSharedForTesting(); got != want {
|
if got := img1.IsSharedForTesting(); got != want {
|
||||||
t.Errorf("got: %v, want: %v", got, want)
|
t.Errorf("got: %v, want: %v", got, want)
|
||||||
@ -193,7 +193,7 @@ func Disabled_TestReshared(t *testing.T) {
|
|||||||
|
|
||||||
// Use img3 as a render source. img3 never uses a shared texture.
|
// Use img3 as a render source. img3 never uses a shared texture.
|
||||||
for i := 0; i < MaxCountForShare*2; i++ {
|
for i := 0; i < MaxCountForShare*2; i++ {
|
||||||
img0.DrawImage(img3, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest)
|
img0.DrawImage(img3, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
want := false
|
want := false
|
||||||
if got := img3.IsSharedForTesting(); got != want {
|
if got := img3.IsSharedForTesting(); got != want {
|
||||||
t.Errorf("got: %v, want: %v", got, want)
|
t.Errorf("got: %v, want: %v", got, want)
|
||||||
@ -269,7 +269,7 @@ func TestReplacePixelsAfterDrawImage(t *testing.T) {
|
|||||||
|
|
||||||
vs := src.QuadVertices(0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
vs := src.QuadVertices(0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
dst.DrawImage(src, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest)
|
dst.DrawImage(src, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||||
dst.ReplacePixels(pix)
|
dst.ReplacePixels(pix)
|
||||||
|
|
||||||
for j := 0; j < h; j++ {
|
for j := 0; j < h; j++ {
|
||||||
|
Loading…
Reference in New Issue
Block a user