mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 18:58:54 +01:00
graphics: Use source-border check even at DrawTriangles
DrawTriangles can now take a sub-image.
This commit is contained in:
parent
4149a56524
commit
189b8a17e9
16
image.go
16
image.go
@ -411,6 +411,7 @@ type Vertex struct {
|
|||||||
DstY float32
|
DstY float32
|
||||||
|
|
||||||
// SrcX and SrcY represents a point on a source image.
|
// SrcX and SrcY represents a point on a source image.
|
||||||
|
// Note that SrcX/SrcY on a sub-image should be in its bounds.
|
||||||
SrcX float32
|
SrcX float32
|
||||||
SrcY float32
|
SrcY float32
|
||||||
|
|
||||||
@ -452,11 +453,6 @@ const MaxIndicesNum = graphics.IndicesNum
|
|||||||
//
|
//
|
||||||
// The rule in which DrawTriangles works effectively is same as DrawImage's.
|
// The rule in which DrawTriangles works effectively is same as DrawImage's.
|
||||||
//
|
//
|
||||||
// In contrast to DrawImage, DrawTriangles doesn't care source image edges.
|
|
||||||
// This means that you might need to add 1px gap on a source region when you render an image by DrawTriangles.
|
|
||||||
// Note that Ebiten creates texture atlases internally, so you still have to care this even when
|
|
||||||
// you render a single image.
|
|
||||||
//
|
|
||||||
// When the image i is disposed, DrawTriangles does nothing.
|
// When the image i is disposed, DrawTriangles does nothing.
|
||||||
//
|
//
|
||||||
// Internal mipmap is not used on DrawTriangles.
|
// Internal mipmap is not used on DrawTriangles.
|
||||||
@ -468,10 +464,6 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement this.
|
|
||||||
if img.isSubimage() {
|
|
||||||
panic("using a subimage at DrawTriangles is not implemented")
|
|
||||||
}
|
|
||||||
if i.isSubimage() {
|
if i.isSubimage() {
|
||||||
panic("render to a subimage is not implemented")
|
panic("render to a subimage is not implemented")
|
||||||
}
|
}
|
||||||
@ -499,8 +491,12 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
|
|||||||
|
|
||||||
vs := make([]float32, len(vertices)*graphics.VertexFloatNum)
|
vs := make([]float32, len(vertices)*graphics.VertexFloatNum)
|
||||||
src := img.mipmap.original()
|
src := img.mipmap.original()
|
||||||
|
r := img.Bounds()
|
||||||
for idx, v := range vertices {
|
for idx, v := range vertices {
|
||||||
src.PutVertex(vs[idx*graphics.VertexFloatNum:(idx+1)*graphics.VertexFloatNum], float32(v.DstX), float32(v.DstY), v.SrcX, v.SrcY, v.ColorR, v.ColorG, v.ColorB, v.ColorA)
|
src.PutVertex(vs[idx*graphics.VertexFloatNum:(idx+1)*graphics.VertexFloatNum],
|
||||||
|
float32(v.DstX), float32(v.DstY), v.SrcX, v.SrcY,
|
||||||
|
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)
|
||||||
i.disposeMipmaps()
|
i.disposeMipmaps()
|
||||||
|
118
image_test.go
118
image_test.go
@ -606,38 +606,96 @@ func TestImageEdge(t *testing.T) {
|
|||||||
for _, s := range []float64{1, 0.5, 0.25} {
|
for _, s := range []float64{1, 0.5, 0.25} {
|
||||||
for _, f := range []Filter{FilterNearest, FilterLinear} {
|
for _, f := range []Filter{FilterNearest, FilterLinear} {
|
||||||
for _, a := range angles {
|
for _, a := range angles {
|
||||||
img1.Clear()
|
for _, testDrawTriangles := range []bool{false, true} {
|
||||||
op := &DrawImageOptions{}
|
img1.Clear()
|
||||||
w, h := img0Sub.Size()
|
w, h := img0Sub.Size()
|
||||||
op.GeoM.Translate(-float64(w)/2, -float64(h)/2)
|
b := img0Sub.Bounds()
|
||||||
op.GeoM.Scale(s, s)
|
var geo GeoM
|
||||||
op.GeoM.Rotate(a)
|
geo.Translate(-float64(w)/2, -float64(h)/2)
|
||||||
op.GeoM.Translate(img1Width/2, img1Height/2)
|
geo.Scale(s, s)
|
||||||
op.Filter = f
|
geo.Rotate(a)
|
||||||
img1.DrawImage(img0Sub, op)
|
geo.Translate(img1Width/2, img1Height/2)
|
||||||
allTransparent := true
|
if !testDrawTriangles {
|
||||||
for j := 0; j < img1Height; j++ {
|
op := &DrawImageOptions{}
|
||||||
for i := 0; i < img1Width; i++ {
|
op.GeoM = geo
|
||||||
c := img1.At(i, j)
|
op.Filter = f
|
||||||
if c == transparent {
|
img1.DrawImage(img0Sub, op)
|
||||||
continue
|
} else {
|
||||||
|
op := &DrawTrianglesOptions{}
|
||||||
|
dx0, dy0 := geo.Apply(0, 0)
|
||||||
|
dx1, dy1 := geo.Apply(float64(w), 0)
|
||||||
|
dx2, dy2 := geo.Apply(0, float64(h))
|
||||||
|
dx3, dy3 := geo.Apply(float64(w), float64(h))
|
||||||
|
vs := []Vertex{
|
||||||
|
{
|
||||||
|
DstX: float32(dx0),
|
||||||
|
DstY: float32(dy0),
|
||||||
|
SrcX: float32(b.Min.X),
|
||||||
|
SrcY: float32(b.Min.Y),
|
||||||
|
ColorR: 1,
|
||||||
|
ColorG: 1,
|
||||||
|
ColorB: 1,
|
||||||
|
ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: float32(dx1),
|
||||||
|
DstY: float32(dy1),
|
||||||
|
SrcX: float32(b.Max.X),
|
||||||
|
SrcY: float32(b.Min.Y),
|
||||||
|
ColorR: 1,
|
||||||
|
ColorG: 1,
|
||||||
|
ColorB: 1,
|
||||||
|
ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: float32(dx2),
|
||||||
|
DstY: float32(dy2),
|
||||||
|
SrcX: float32(b.Min.X),
|
||||||
|
SrcY: float32(b.Max.Y),
|
||||||
|
ColorR: 1,
|
||||||
|
ColorG: 1,
|
||||||
|
ColorB: 1,
|
||||||
|
ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: float32(dx3),
|
||||||
|
DstY: float32(dy3),
|
||||||
|
SrcX: float32(b.Max.X),
|
||||||
|
SrcY: float32(b.Max.Y),
|
||||||
|
ColorR: 1,
|
||||||
|
ColorG: 1,
|
||||||
|
ColorB: 1,
|
||||||
|
ColorA: 1,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
allTransparent = false
|
is := graphics.QuadIndices()
|
||||||
switch f {
|
op.Filter = f
|
||||||
case FilterNearest:
|
img1.DrawTriangles(vs, is, img0Sub, op)
|
||||||
if c == red {
|
}
|
||||||
continue
|
allTransparent := true
|
||||||
}
|
for j := 0; j < img1Height; j++ {
|
||||||
case FilterLinear:
|
for i := 0; i < img1Width; i++ {
|
||||||
if _, g, b, _ := c.RGBA(); g == 0 && b == 0 {
|
c := img1.At(i, j)
|
||||||
continue
|
if c == transparent {
|
||||||
}
|
continue
|
||||||
}
|
}
|
||||||
t.Fatalf("img1.At(%d, %d) (filter: %d, scale: %f, angle: %f) want: red or transparent, got: %v", i, j, f, s, a, c)
|
allTransparent = false
|
||||||
|
switch f {
|
||||||
|
case FilterNearest:
|
||||||
|
if c == red {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
case FilterLinear:
|
||||||
|
if _, g, b, _ := c.RGBA(); g == 0 && b == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Fatalf("img1.At(%d, %d) (filter: %d, scale: %f, angle: %f, draw-triangles?: %t) want: red or transparent, got: %v", i, j, f, s, a, testDrawTriangles, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if allTransparent {
|
||||||
|
t.Fatalf("img1 (filter: %d, scale: %f, angle: %f, draw-triangles?: %t) is transparent but should not", f, s, a, testDrawTriangles)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if allTransparent {
|
|
||||||
t.Fatalf("img1 (filter: %d, scale: %f, angle: %f) is transparent but should not", f, s, a)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,7 @@ func QuadIndices() []uint16 {
|
|||||||
return quadIndices
|
return quadIndices
|
||||||
}
|
}
|
||||||
|
|
||||||
func PutVertex(vs []float32, width, height int, dx, dy, sx, sy float32, cr, cg, cb, ca float32) {
|
func PutVertex(vs []float32, width, height int, dx, dy, su, sv float32, u0, v0, u1, v1 float32, cr, cg, cb, ca float32) {
|
||||||
if !isPowerOf2(width) {
|
if !isPowerOf2(width) {
|
||||||
panic("not reached")
|
panic("not reached")
|
||||||
}
|
}
|
||||||
@ -163,21 +163,14 @@ func PutVertex(vs []float32, width, height int, dx, dy, sx, sy float32, cr, cg,
|
|||||||
panic("not reached")
|
panic("not reached")
|
||||||
}
|
}
|
||||||
|
|
||||||
wf := float32(width)
|
|
||||||
hf := float32(height)
|
|
||||||
|
|
||||||
// Specify -1 for the source region, which means the source region is ignored.
|
|
||||||
//
|
|
||||||
// NaN would make more sense to represent an invalid state, but vertices including NaN values doesn't work on
|
|
||||||
// some machines (#696). Let's use negative numbers to represent such state.
|
|
||||||
vs[0] = dx
|
vs[0] = dx
|
||||||
vs[1] = dy
|
vs[1] = dy
|
||||||
vs[2] = sx / wf
|
vs[2] = su
|
||||||
vs[3] = sy / hf
|
vs[3] = sv
|
||||||
vs[4] = 0
|
vs[4] = u0
|
||||||
vs[5] = 0
|
vs[5] = v0
|
||||||
vs[6] = 1
|
vs[6] = u1
|
||||||
vs[7] = 1
|
vs[7] = v1
|
||||||
vs[8] = cr
|
vs[8] = cr
|
||||||
vs[9] = cg
|
vs[9] = cg
|
||||||
vs[10] = cb
|
vs[10] = cb
|
||||||
|
@ -197,13 +197,23 @@ func (i *Image) QuadVertices(sx0, sy0, sx1, sy1 int, a, b, c, d, tx, ty float32,
|
|||||||
return graphics.QuadVertices(w, h, sx0+ox, sy0+oy, sx1+ox, sy1+oy, a, b, c, d, tx, ty, cr, cg, cb, ca)
|
return graphics.QuadVertices(w, h, sx0+ox, sy0+oy, sx1+ox, sy1+oy, a, b, c, d, tx, ty, cr, cg, cb, ca)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) PutVertex(dest []float32, dx, dy, sx, sy float32, cr, cg, cb, ca float32) {
|
func (i *Image) PutVertex(dest []float32, dx, dy, sx, sy float32, bx0, by0, bx1, by1 float32,
|
||||||
|
cr, cg, cb, ca float32) {
|
||||||
if i.backend == nil {
|
if i.backend == nil {
|
||||||
i.allocate(true)
|
i.allocate(true)
|
||||||
}
|
}
|
||||||
ox, oy, _, _ := i.region()
|
ox, oy, _, _ := i.region()
|
||||||
|
oxf, oyf := float32(ox), float32(oy)
|
||||||
w, h := i.backend.restorable.SizePowerOf2()
|
w, h := i.backend.restorable.SizePowerOf2()
|
||||||
graphics.PutVertex(dest, w, h, dx, dy, sx+float32(ox), sy+float32(oy), cr, cg, cb, ca)
|
|
||||||
|
su := (sx + oxf) / float32(w)
|
||||||
|
sv := (sy + oyf) / float32(h)
|
||||||
|
u0 := (bx0 + oxf) / float32(w)
|
||||||
|
v0 := (by0 + oyf) / float32(h)
|
||||||
|
u1 := (bx1 + oxf) / float32(w)
|
||||||
|
v1 := (by1 + oyf) / float32(h)
|
||||||
|
|
||||||
|
graphics.PutVertex(dest, w, h, dx, dy, su, sv, u0, v0, u1, v1, cr, cg, cb, ca)
|
||||||
}
|
}
|
||||||
|
|
||||||
const MaxCountForShare = 10
|
const MaxCountForShare = 10
|
||||||
|
Loading…
Reference in New Issue
Block a user