mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
parent
58f4feda8d
commit
8b82667df1
@ -41,6 +41,7 @@ const (
|
|||||||
var (
|
var (
|
||||||
gophersImage *ebiten.Image
|
gophersImage *ebiten.Image
|
||||||
rotate = false
|
rotate = false
|
||||||
|
clip = false
|
||||||
counter = 0
|
counter = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -53,13 +54,20 @@ func update(screen *ebiten.Image) error {
|
|||||||
if inpututil.IsKeyJustPressed(ebiten.KeyR) {
|
if inpututil.IsKeyJustPressed(ebiten.KeyR) {
|
||||||
rotate = !rotate
|
rotate = !rotate
|
||||||
}
|
}
|
||||||
|
if inpututil.IsKeyJustPressed(ebiten.KeyC) {
|
||||||
|
clip = !clip
|
||||||
|
}
|
||||||
|
|
||||||
if ebiten.IsDrawingSkipped() {
|
if ebiten.IsDrawingSkipped() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
s := 1.5 / math.Pow(1.01, float64(counter))
|
s := 1.5 / math.Pow(1.01, float64(counter))
|
||||||
ebitenutil.DebugPrint(screen, fmt.Sprintf("Minifying images (Nearest filter vs Linear filter): Press R to rotate the images.\nScale: %0.2f", s))
|
msg := fmt.Sprintf(`Minifying images (Nearest filter vs Linear filter):
|
||||||
|
Press R to rotate the images.
|
||||||
|
Press C to clip the images.
|
||||||
|
Scale: %0.2f`, s)
|
||||||
|
ebitenutil.DebugPrint(screen, msg)
|
||||||
|
|
||||||
for i, f := range []ebiten.Filter{ebiten.FilterNearest, ebiten.FilterLinear} {
|
for i, f := range []ebiten.Filter{ebiten.FilterNearest, ebiten.FilterLinear} {
|
||||||
w, h := gophersImage.Size()
|
w, h := gophersImage.Size()
|
||||||
@ -73,6 +81,10 @@ func update(screen *ebiten.Image) error {
|
|||||||
op.GeoM.Scale(s, s)
|
op.GeoM.Scale(s, s)
|
||||||
op.GeoM.Translate(32+float64(i*w)*s+float64(i*4), 64)
|
op.GeoM.Translate(32+float64(i*w)*s+float64(i*4), 64)
|
||||||
op.Filter = f
|
op.Filter = f
|
||||||
|
if clip {
|
||||||
|
r := image.Rect(10, 10, 100, 100)
|
||||||
|
op.SourceRect = &r
|
||||||
|
}
|
||||||
screen.DrawImage(gophersImage, op)
|
screen.DrawImage(gophersImage, op)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
75
image.go
75
image.go
@ -37,12 +37,13 @@ func init() {
|
|||||||
|
|
||||||
type mipmap struct {
|
type mipmap struct {
|
||||||
orig *shareable.Image
|
orig *shareable.Image
|
||||||
imgs []*shareable.Image
|
imgs map[image.Rectangle][]*shareable.Image
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMipmap(s *shareable.Image) *mipmap {
|
func newMipmap(s *shareable.Image) *mipmap {
|
||||||
return &mipmap{
|
return &mipmap{
|
||||||
orig: s,
|
orig: s,
|
||||||
|
imgs: map[image.Rectangle][]*shareable.Image{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,18 +51,26 @@ func (m *mipmap) original() *shareable.Image {
|
|||||||
return m.orig
|
return m.orig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mipmap) level(level int) *shareable.Image {
|
func (m *mipmap) level(r image.Rectangle, level int) *shareable.Image {
|
||||||
if level == 0 {
|
if level == 0 {
|
||||||
return m.orig
|
return m.orig
|
||||||
}
|
}
|
||||||
|
|
||||||
idx := level - 1
|
imgs, ok := m.imgs[r]
|
||||||
w, h := m.orig.Size()
|
if !ok {
|
||||||
if len(m.imgs) > 0 {
|
imgs = []*shareable.Image{}
|
||||||
w, h = m.imgs[len(m.imgs)-1].Size()
|
m.imgs[r] = imgs
|
||||||
}
|
}
|
||||||
for len(m.imgs) < idx+1 {
|
idx := level - 1
|
||||||
src := m.level(len(m.imgs))
|
|
||||||
|
size := r.Size()
|
||||||
|
w, h := size.X, size.Y
|
||||||
|
if len(imgs) > 0 {
|
||||||
|
w, h = imgs[len(imgs)-1].Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
for len(imgs) < idx+1 {
|
||||||
|
src := m.level(r, len(imgs))
|
||||||
w2 := w / 2
|
w2 := w / 2
|
||||||
h2 := h / 2
|
h2 := h / 2
|
||||||
if w2 == 0 || h2 == 0 {
|
if w2 == 0 || h2 == 0 {
|
||||||
@ -73,17 +82,24 @@ func (m *mipmap) level(level int) *shareable.Image {
|
|||||||
} else {
|
} else {
|
||||||
s = shareable.NewImage(w2, h2)
|
s = shareable.NewImage(w2, h2)
|
||||||
}
|
}
|
||||||
vs := src.QuadVertices(0, 0, w, h, 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1)
|
var vs []float32
|
||||||
|
if len(imgs) == 0 {
|
||||||
|
vs = src.QuadVertices(r.Min.X, r.Min.Y, r.Max.X, r.Max.Y, 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1)
|
||||||
|
} else {
|
||||||
|
vs = src.QuadVertices(0, 0, w, h, 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1)
|
||||||
|
}
|
||||||
is := graphicsutil.QuadIndices()
|
is := graphicsutil.QuadIndices()
|
||||||
s.DrawImage(src, vs, is, nil, opengl.CompositeModeCopy, graphics.FilterLinear)
|
s.DrawImage(src, vs, is, nil, opengl.CompositeModeCopy, graphics.FilterLinear)
|
||||||
m.imgs = append(m.imgs, s)
|
imgs = append(imgs, s)
|
||||||
w = w2
|
w = w2
|
||||||
h = h2
|
h = h2
|
||||||
}
|
}
|
||||||
if len(m.imgs) <= idx {
|
m.imgs[r] = imgs
|
||||||
|
|
||||||
|
if len(imgs) <= idx {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return m.imgs[idx]
|
return imgs[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mipmap) isDisposed() bool {
|
func (m *mipmap) isDisposed() bool {
|
||||||
@ -97,10 +113,12 @@ func (m *mipmap) dispose() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *mipmap) disposeMipmaps() {
|
func (m *mipmap) disposeMipmaps() {
|
||||||
for _, img := range m.imgs {
|
for _, a := range m.imgs {
|
||||||
|
for _, img := range a {
|
||||||
img.Dispose()
|
img.Dispose()
|
||||||
}
|
}
|
||||||
m.imgs = nil
|
}
|
||||||
|
m.imgs = map[image.Rectangle][]*shareable.Image{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Image represents a rectangle set of pixels.
|
// Image represents a rectangle set of pixels.
|
||||||
@ -346,19 +364,8 @@ func (i *Image) drawImage(img *Image, options *DrawImageOptions) {
|
|||||||
level = 6
|
level = 6
|
||||||
}
|
}
|
||||||
|
|
||||||
if level > 0 {
|
// TODO: Move this logic to mipmap?
|
||||||
s := 1 << uint(level)
|
if src := img.mipmap.level(image.Rect(sx0, sy0, sx1, sy1), level); src != nil {
|
||||||
a *= float32(s)
|
|
||||||
b *= float32(s)
|
|
||||||
c *= float32(s)
|
|
||||||
d *= float32(s)
|
|
||||||
sx0 = sx0 / s
|
|
||||||
sy0 = sy0 / s
|
|
||||||
sx1 = sx1 / s
|
|
||||||
sy1 = sy1 / s
|
|
||||||
}
|
|
||||||
|
|
||||||
if src := img.mipmap.level(level); src != nil {
|
|
||||||
colorm := options.ColorM.impl
|
colorm := options.ColorM.impl
|
||||||
cr, cg, cb, ca := float32(1), float32(1), float32(1), float32(1)
|
cr, cg, cb, ca := float32(1), float32(1), float32(1), float32(1)
|
||||||
if colorm.ScaleOnly() {
|
if colorm.ScaleOnly() {
|
||||||
@ -368,12 +375,24 @@ func (i *Image) drawImage(img *Image, options *DrawImageOptions) {
|
|||||||
cb = body[10]
|
cb = body[10]
|
||||||
ca = body[15]
|
ca = body[15]
|
||||||
}
|
}
|
||||||
vs := src.QuadVertices(sx0, sy0, sx1, sy1, a, b, c, d, tx, ty, cr, cg, cb, ca)
|
var vs []float32
|
||||||
|
if level == 0 {
|
||||||
|
vs = src.QuadVertices(sx0, sy0, sx1, sy1, a, b, c, d, tx, ty, cr, cg, cb, ca)
|
||||||
|
} else {
|
||||||
|
w, h := src.Size()
|
||||||
|
s := 1 << uint(level)
|
||||||
|
a *= float32(s)
|
||||||
|
b *= float32(s)
|
||||||
|
c *= float32(s)
|
||||||
|
d *= float32(s)
|
||||||
|
vs = src.QuadVertices(0, 0, w, h, a, b, c, d, tx, ty, cr, cg, cb, ca)
|
||||||
|
}
|
||||||
is := graphicsutil.QuadIndices()
|
is := graphicsutil.QuadIndices()
|
||||||
|
|
||||||
if colorm.ScaleOnly() {
|
if colorm.ScaleOnly() {
|
||||||
colorm = nil
|
colorm = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
i.mipmap.original().DrawImage(src, vs, is, colorm, mode, filter)
|
i.mipmap.original().DrawImage(src, vs, is, colorm, mode, filter)
|
||||||
}
|
}
|
||||||
i.disposeMipmaps()
|
i.disposeMipmaps()
|
||||||
|
@ -508,11 +508,16 @@ func TestImageFill(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issue #317, #558
|
// Issue #317, #558, #724
|
||||||
func TestImageEdge(t *testing.T) {
|
func TestImageEdge(t *testing.T) {
|
||||||
const (
|
const (
|
||||||
img0Width = 16
|
img0Width = 16
|
||||||
img0Height = 16
|
img0Height = 16
|
||||||
|
img0InnerWidth = 6
|
||||||
|
img0InnerHeight = 6
|
||||||
|
img0OffsetWidth = (img0Width - img0InnerWidth) / 2
|
||||||
|
img0OffsetHeight = (img0Height - img0InnerHeight) / 2
|
||||||
|
|
||||||
img1Width = 32
|
img1Width = 32
|
||||||
img1Height = 32
|
img1Height = 32
|
||||||
)
|
)
|
||||||
@ -522,7 +527,8 @@ func TestImageEdge(t *testing.T) {
|
|||||||
for i := 0; i < img0Width; i++ {
|
for i := 0; i < img0Width; i++ {
|
||||||
idx := 4 * (i + j*img0Width)
|
idx := 4 * (i + j*img0Width)
|
||||||
switch {
|
switch {
|
||||||
case j < img0Height/2:
|
case img0OffsetWidth <= i && i < img0Width-img0OffsetWidth &&
|
||||||
|
img0InnerHeight <= j && j < img0Height-img0InnerHeight:
|
||||||
pixels[idx] = 0xff
|
pixels[idx] = 0xff
|
||||||
pixels[idx+1] = 0
|
pixels[idx+1] = 0
|
||||||
pixels[idx+2] = 0
|
pixels[idx+2] = 0
|
||||||
@ -544,18 +550,22 @@ func TestImageEdge(t *testing.T) {
|
|||||||
for a := 0; a < 1440; a++ {
|
for a := 0; a < 1440; a++ {
|
||||||
angles = append(angles, float64(a)/1440*2*math.Pi)
|
angles = append(angles, float64(a)/1440*2*math.Pi)
|
||||||
}
|
}
|
||||||
for a := 0; a < 4096; a++ {
|
for a := 0; a < 4096; a += 3 {
|
||||||
|
// a++ should be fine, but it takes long to test.
|
||||||
angles = append(angles, float64(a)/4096*2*math.Pi)
|
angles = append(angles, float64(a)/4096*2*math.Pi)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()
|
img1.Clear()
|
||||||
op := &DrawImageOptions{}
|
op := &DrawImageOptions{}
|
||||||
w, h := img0.Size()
|
r := image.Rect(img0OffsetWidth, img0InnerHeight, img0Width-img0OffsetWidth, img0Height-img0InnerHeight)
|
||||||
r := image.Rect(0, 0, w, h/2)
|
|
||||||
op.SourceRect = &r
|
op.SourceRect = &r
|
||||||
op.GeoM.Translate(-float64(img0Width)/2, -float64(img0Height)/2)
|
|
||||||
|
w, h := img0.Size()
|
||||||
|
op.GeoM.Translate(-float64(w)/2, -float64(h)/2)
|
||||||
|
op.GeoM.Scale(s, s)
|
||||||
op.GeoM.Rotate(a)
|
op.GeoM.Rotate(a)
|
||||||
op.GeoM.Translate(img1Width/2, img1Height/2)
|
op.GeoM.Translate(img1Width/2, img1Height/2)
|
||||||
op.Filter = f
|
op.Filter = f
|
||||||
@ -577,7 +587,8 @@ func TestImageEdge(t *testing.T) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.Errorf("img1.At(%d, %d) (filter: %d, angle: %f) want: red or transparent, got: %v", i, j, f, a, c)
|
t.Errorf("img1.At(%d, %d) (filter: %d, scale: %f, angle: %f) want: red or transparent, got: %v", i, j, f, s, a, c)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user