mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 18:58:54 +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)
|
||||
}
|
||||
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)
|
||||
w = w2
|
||||
h = h2
|
||||
@ -387,7 +387,7 @@ func (i *Image) drawImage(img *Image, options *DrawImageOptions) {
|
||||
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)
|
||||
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 {
|
||||
w, h := src.Size()
|
||||
s := 1 << uint(level)
|
||||
@ -397,7 +397,7 @@ func (i *Image) drawImage(img *Image, options *DrawImageOptions) {
|
||||
d *= float32(s)
|
||||
vs := src.QuadVertices(0, 0, w, h, a, b, c, d, tx, ty, cr, cg, cb, ca)
|
||||
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()
|
||||
}
|
||||
@ -425,6 +425,17 @@ type Vertex struct {
|
||||
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.
|
||||
//
|
||||
// Note that this API is experimental.
|
||||
@ -441,6 +452,10 @@ type DrawTrianglesOptions struct {
|
||||
// Filter is a type of texture filter.
|
||||
// The default (zero) value is FilterDefault.
|
||||
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.
|
||||
@ -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),
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
FilterScreen
|
||||
)
|
||||
|
||||
type Address int
|
||||
|
||||
const (
|
||||
AddressClampToZero Address = iota
|
||||
AddressRepeat
|
||||
)
|
||||
|
@ -35,7 +35,7 @@ type command interface {
|
||||
NumIndices() int
|
||||
AddNumVertices(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.
|
||||
@ -87,12 +87,12 @@ func (q *commandQueue) appendIndices(indices []uint16, offset uint16) {
|
||||
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 {
|
||||
panic("not reached")
|
||||
}
|
||||
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.AddNumIndices(nindices)
|
||||
return
|
||||
@ -106,12 +106,13 @@ func (q *commandQueue) doEnqueueDrawImageCommand(dst, src *Image, nvertices, nin
|
||||
color: color,
|
||||
mode: mode,
|
||||
filter: filter,
|
||||
address: address,
|
||||
}
|
||||
q.commands = append(q.commands, c)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
panic("not reached")
|
||||
}
|
||||
@ -128,7 +129,7 @@ func (q *commandQueue) EnqueueDrawImageCommand(dst, src *Image, vertices []float
|
||||
q.nextIndex += len(vertices) / graphics.VertexFloatNum
|
||||
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.
|
||||
@ -215,6 +216,7 @@ type drawImageCommand struct {
|
||||
color *affine.ColorM
|
||||
mode graphics.CompositeMode
|
||||
filter graphics.Filter
|
||||
address graphics.Address
|
||||
}
|
||||
|
||||
func (c *drawImageCommand) String() string {
|
||||
@ -230,7 +232,7 @@ func (c *drawImageCommand) Exec(indexOffset int) error {
|
||||
|
||||
c.dst.image.SetAsDestination()
|
||||
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 nil
|
||||
@ -254,7 +256,7 @@ func (c *drawImageCommand) AddNumIndices(n int) {
|
||||
|
||||
// CanMerge returns a boolean value indicating whether the other drawImageCommand can be merged
|
||||
// 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 {
|
||||
return false
|
||||
}
|
||||
@ -270,6 +272,9 @@ func (c *drawImageCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode
|
||||
if c.filter != filter {
|
||||
return false
|
||||
}
|
||||
if c.address != address {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -307,7 +312,7 @@ func (c *replacePixelsCommand) AddNumVertices(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
|
||||
}
|
||||
|
||||
@ -344,7 +349,7 @@ func (c *pixelsCommand) AddNumVertices(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
|
||||
}
|
||||
|
||||
@ -377,7 +382,7 @@ func (c *disposeCommand) AddNumVertices(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
|
||||
}
|
||||
|
||||
@ -416,7 +421,7 @@ func (c *newImageCommand) AddNumVertices(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
|
||||
}
|
||||
|
||||
@ -452,7 +457,7 @@ func (c *newScreenFramebufferImageCommand) AddNumVertices(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
|
||||
}
|
||||
|
||||
|
@ -70,8 +70,8 @@ func (i *Image) Size() (int, int) {
|
||||
return i.width, i.height
|
||||
}
|
||||
|
||||
func (i *Image) DrawImage(src *Image, vertices []float32, indices []uint16, clr *affine.ColorM, mode graphics.CompositeMode, filter graphics.Filter) {
|
||||
theCommandQueue.EnqueueDrawImageCommand(i, src, vertices, indices, clr, mode, 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, address)
|
||||
}
|
||||
|
||||
// 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)
|
||||
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()
|
||||
for j := 0; j < h/2; j++ {
|
||||
|
@ -26,7 +26,7 @@ type GraphicsDriver interface {
|
||||
NewImage(width, height int) (Image, error)
|
||||
NewScreenFramebufferImage(width, height int) (Image, 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)
|
||||
VDirection() VDirection
|
||||
IsGL() bool
|
||||
|
@ -36,6 +36,9 @@ const source = `#include <metal_stdlib>
|
||||
#define FILTER_LINEAR ({{.FilterLinear}})
|
||||
#define FILTER_SCREEN ({{.FilterScreen}})
|
||||
|
||||
#define ADDRESS_CLAMP_TO_ZERO ({{.AddressClampToZero}})
|
||||
#define ADDRESS_REPEAT ({{.AddressRepeat}})
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct VertexIn {
|
||||
@ -89,12 +92,37 @@ float2 AdjustTexel(float2 source_size, float2 p0, float2 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]],
|
||||
texture2d<float> texture [[texture(0)]],
|
||||
constant float4x4& color_matrix_body [[buffer(2)]],
|
||||
constant float4& color_matrix_translation [[buffer(3)]],
|
||||
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);
|
||||
float2 source_size = 1;
|
||||
while (source_size.x < texture.get_width()) {
|
||||
@ -109,11 +137,12 @@ fragment float4 FragmentShader(VertexOut v [[stage_in]],
|
||||
|
||||
switch (filter) {
|
||||
case FILTER_NEAREST: {
|
||||
c = texture.sample(texture_sampler, v.tex);
|
||||
if (v.tex.x < v.tex_region[0] ||
|
||||
v.tex.y < v.tex_region[1] ||
|
||||
(v.tex_region[2] - texel_size.x / 512.0) <= v.tex.x ||
|
||||
(v.tex_region[3] - texel_size.y / 512.0) <= v.tex.y) {
|
||||
float2 p = AdjustTexelByAddress(v.tex, v.tex_region, address);
|
||||
c = texture.sample(texture_sampler, p);
|
||||
if (p.x < v.tex_region[0] ||
|
||||
p.y < v.tex_region[1] ||
|
||||
(v.tex_region[2] - texel_size.x / 512.0) <= p.x ||
|
||||
(v.tex_region[3] - texel_size.y / 512.0) <= p.y) {
|
||||
c = 0;
|
||||
}
|
||||
break;
|
||||
@ -123,6 +152,8 @@ fragment float4 FragmentShader(VertexOut v [[stage_in]],
|
||||
float2 p0 = v.tex - texel_size / 2.0;
|
||||
float2 p1 = v.tex + texel_size / 2.0;
|
||||
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 c1 = texture.sample(texture_sampler, float2(p1.x, p0.y));
|
||||
@ -370,6 +401,8 @@ func (d *Driver) Reset() error {
|
||||
"{{.FilterNearest}}": fmt.Sprintf("%d", graphics.FilterNearest),
|
||||
"{{.FilterLinear}}": fmt.Sprintf("%d", graphics.FilterLinear),
|
||||
"{{.FilterScreen}}": fmt.Sprintf("%d", graphics.FilterScreen),
|
||||
"{{.AddressClampToZero}}": fmt.Sprintf("%d", graphics.AddressClampToZero),
|
||||
"{{.AddressRepeat}}": fmt.Sprintf("%d", graphics.AddressRepeat),
|
||||
}
|
||||
src := source
|
||||
for k, v := range replaces {
|
||||
@ -452,7 +485,8 @@ func (d *Driver) Reset() error {
|
||||
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 {
|
||||
// NSView can be changed anytime (probably). Set this everyframe.
|
||||
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)
|
||||
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)
|
||||
rce.SetFragmentBytes(unsafe.Pointer(&scale), unsafe.Sizeof(scale), 5)
|
||||
rce.SetFragmentBytes(unsafe.Pointer(&scale), unsafe.Sizeof(scale), 6)
|
||||
|
||||
if d.src != nil {
|
||||
rce.SetFragmentTexture(d.src.texture, 0)
|
||||
|
@ -94,8 +94,8 @@ func (d *Driver) SetVertices(vertices []float32, indices []uint16) {
|
||||
d.context.elementArrayBufferSubData(indices)
|
||||
}
|
||||
|
||||
func (d *Driver) Draw(indexLen int, indexOffset int, mode graphics.CompositeMode, colorM *affine.ColorM, filter graphics.Filter) error {
|
||||
if err := d.useProgram(mode, colorM, filter); err != nil {
|
||||
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, address); err != nil {
|
||||
return err
|
||||
}
|
||||
d.context.drawElements(indexLen, indexOffset*2) // 2 is uint16 size in bytes
|
||||
|
@ -130,6 +130,7 @@ type openGLState struct {
|
||||
lastSourceWidth int
|
||||
lastSourceHeight int
|
||||
lastFilter *graphics.Filter
|
||||
lastAddress *graphics.Address
|
||||
|
||||
source *Image
|
||||
destination *Image
|
||||
@ -159,6 +160,7 @@ func (s *openGLState) reset(context *context) error {
|
||||
s.lastSourceWidth = 0
|
||||
s.lastSourceHeight = 0
|
||||
s.lastFilter = nil
|
||||
s.lastAddress = nil
|
||||
|
||||
// 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.
|
||||
@ -222,7 +224,7 @@ func areSameFloat32Array(a, b []float32) bool {
|
||||
}
|
||||
|
||||
// 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
|
||||
if destination == nil {
|
||||
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.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 {
|
||||
scale := float32(dstW) / float32(srcW)
|
||||
|
@ -37,6 +37,8 @@ func shaderStr(id shaderID) string {
|
||||
"{{.FilterNearest}}": fmt.Sprintf("%d", graphics.FilterNearest),
|
||||
"{{.FilterLinear}}": fmt.Sprintf("%d", graphics.FilterLinear),
|
||||
"{{.FilterScreen}}": fmt.Sprintf("%d", graphics.FilterScreen),
|
||||
"{{.AddressClampToZero}}": fmt.Sprintf("%d", graphics.AddressClampToZero),
|
||||
"{{.AddressRepeat}}": fmt.Sprintf("%d", graphics.AddressRepeat),
|
||||
}
|
||||
src := shaderStrFragment
|
||||
for k, v := range replaces {
|
||||
@ -85,6 +87,8 @@ precision mediump float;
|
||||
#define FILTER_NEAREST ({{.FilterNearest}})
|
||||
#define FILTER_LINEAR ({{.FilterLinear}})
|
||||
#define FILTER_SCREEN ({{.FilterScreen}})
|
||||
#define ADDRESS_CLAMP_TO_ZERO ({{.AddressClampToZero}})
|
||||
#define ADDRESS_REPEAT ({{.AddressRepeat}})
|
||||
|
||||
uniform sampler2D texture;
|
||||
uniform mat4 color_matrix_body;
|
||||
@ -92,6 +96,7 @@ uniform vec4 color_matrix_translation;
|
||||
|
||||
uniform int filter;
|
||||
uniform highp vec2 source_size;
|
||||
uniform int address;
|
||||
|
||||
#if defined(FILTER_SCREEN)
|
||||
uniform highp float scale;
|
||||
@ -115,6 +120,26 @@ highp vec2 adjustTexel(highp vec2 p0, highp vec2 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) {
|
||||
highp vec2 pos = varying_tex;
|
||||
highp vec2 texel_size = 1.0 / source_size;
|
||||
@ -122,6 +147,7 @@ void main(void) {
|
||||
vec4 color;
|
||||
|
||||
if (filter == FILTER_NEAREST) {
|
||||
pos = adjustTexelByAddress(pos, varying_tex_region, address);
|
||||
color = texture2D(texture, pos);
|
||||
if (pos.x < varying_tex_region[0] ||
|
||||
pos.y < varying_tex_region[1] ||
|
||||
@ -134,6 +160,8 @@ void main(void) {
|
||||
highp vec2 p1 = pos + texel_size / 2.0;
|
||||
|
||||
p1 = adjustTexel(p0, p1);
|
||||
p0 = adjustTexelByAddress(p0, varying_tex_region, address);
|
||||
p1 = adjustTexelByAddress(p1, varying_tex_region, address);
|
||||
|
||||
vec4 c0 = texture2D(texture, p0);
|
||||
vec4 c1 = texture2D(texture, vec2(p1.x, p0.y));
|
||||
|
@ -32,6 +32,7 @@ type drawImageHistoryItem struct {
|
||||
colorm *affine.ColorM
|
||||
mode graphics.CompositeMode
|
||||
filter graphics.Filter
|
||||
address graphics.Address
|
||||
}
|
||||
|
||||
// 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),
|
||||
1, 1, 1, 1)
|
||||
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 {
|
||||
@ -213,7 +214,7 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return
|
||||
}
|
||||
@ -222,13 +223,13 @@ func (i *Image) DrawImage(img *Image, vertices []float32, indices []uint16, colo
|
||||
if img.stale || img.volatile || i.screen || !IsRestoringEnabled() {
|
||||
i.makeStale()
|
||||
} 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.
|
||||
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 {
|
||||
return
|
||||
}
|
||||
@ -246,6 +247,7 @@ func (i *Image) appendDrawImageHistory(image *Image, vertices []float32, indices
|
||||
colorm: colorm,
|
||||
mode: mode,
|
||||
filter: filter,
|
||||
address: address,
|
||||
}
|
||||
i.drawImageHistory = append(i.drawImageHistory, item)
|
||||
}
|
||||
@ -378,7 +380,7 @@ func (i *Image) restore() error {
|
||||
if c.image.hasDependency() {
|
||||
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
|
||||
|
||||
|
@ -136,7 +136,7 @@ func TestRestoreChain(t *testing.T) {
|
||||
w, h := imgs[i].Size()
|
||||
vs := graphics.QuadVertices(w, h, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
||||
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()
|
||||
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)
|
||||
is := graphics.QuadIndices()
|
||||
imgs[8].DrawImage(imgs[7], vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest)
|
||||
imgs[9].DrawImage(imgs[8], 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, graphics.AddressClampToZero)
|
||||
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()
|
||||
@ -224,10 +224,10 @@ func TestRestoreOverrideSource(t *testing.T) {
|
||||
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)
|
||||
is := graphics.QuadIndices()
|
||||
img2.DrawImage(img1, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest)
|
||||
img3.DrawImage(img2, 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, graphics.AddressClampToZero)
|
||||
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()
|
||||
if err := Restore(); err != nil {
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
img7.DrawImage(img3, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest)
|
||||
img7.DrawImage(img3, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest, graphics.AddressClampToZero)
|
||||
ResolveStaleImages()
|
||||
if err := Restore(); err != nil {
|
||||
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)
|
||||
is := graphics.QuadIndices()
|
||||
img1.DrawImage(img0, vs, is, nil, graphics.CompositeModeSourceOver, graphics.FilterNearest)
|
||||
img0.DrawImage(img1, 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, graphics.AddressClampToZero)
|
||||
ResolveStaleImages()
|
||||
if err := Restore(); err != nil {
|
||||
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)
|
||||
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)
|
||||
|
||||
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)
|
||||
is := graphics.QuadIndices()
|
||||
img1.DrawImage(img2, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest)
|
||||
img0.DrawImage(img1, 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, graphics.AddressClampToZero)
|
||||
img1.Dispose()
|
||||
|
||||
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)
|
||||
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)
|
||||
// Now img0 is stale.
|
||||
ResolveStaleImages()
|
||||
|
@ -135,7 +135,7 @@ func (i *Image) ensureNotShared() {
|
||||
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)
|
||||
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.backend = &backend{
|
||||
@ -218,7 +218,7 @@ func (i *Image) PutVertex(dest []float32, dx, dy, sx, sy float32, bx0, by0, bx1,
|
||||
|
||||
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()
|
||||
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")
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
|
@ -86,7 +86,7 @@ func TestEnsureNotShared(t *testing.T) {
|
||||
// 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)
|
||||
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
|
||||
if got := img4.IsSharedForTesting(); 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.
|
||||
// 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) {
|
||||
@ -150,7 +150,7 @@ func Disabled_TestReshared(t *testing.T) {
|
||||
// Use img1 as a render target.
|
||||
vs := img2.QuadVertices(0, 0, size, size, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
||||
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
|
||||
if got := img1.IsSharedForTesting(); 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.
|
||||
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
|
||||
if got := img1.IsSharedForTesting(); 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
|
||||
if got := img1.IsSharedForTesting(); 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.
|
||||
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
|
||||
if got := img3.IsSharedForTesting(); 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)
|
||||
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)
|
||||
|
||||
for j := 0; j < h; j++ {
|
||||
|
Loading…
Reference in New Issue
Block a user