mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
parent
7f2be42410
commit
f927e09f56
9
image.go
9
image.go
@ -198,7 +198,14 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) error {
|
||||
}
|
||||
|
||||
a, b, c, d, tx, ty := geom.elements32()
|
||||
i.buffered.DrawImage(img.buffered, img.Bounds(), a, b, c, d, tx, ty, options.ColorM.impl, mode, filter)
|
||||
|
||||
sx0 := float32(bounds.Min.X)
|
||||
sy0 := float32(bounds.Min.Y)
|
||||
sx1 := float32(bounds.Max.X)
|
||||
sy1 := float32(bounds.Max.Y)
|
||||
vs := graphics.QuadVertices(sx0, sy0, sx1, sy1, a, b, c, d, tx, ty, 1, 1, 1, 1, filter == driver.FilterScreen)
|
||||
is := graphics.QuadIndices()
|
||||
i.buffered.DrawTriangles(img.buffered, vs, is, options.ColorM.impl, mode, filter, driver.AddressUnsafe, driver.Region{}, nil, nil, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -978,7 +978,8 @@ func TestImageSprites(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageMipmap(t *testing.T) {
|
||||
// Disabled: it does not make sense to expect deterministic mipmap results (#909).
|
||||
func Disabled_TestImageMipmap(t *testing.T) {
|
||||
src, _, err := openEbitenImage()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -1022,7 +1023,8 @@ func TestImageMipmap(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageMipmapNegativeDet(t *testing.T) {
|
||||
// Disabled: it does not make sense to expect deterministic mipmap results (#909).
|
||||
func Disabled_TestImageMipmapNegativeDet(t *testing.T) {
|
||||
src, _, err := openEbitenImage()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -232,39 +232,6 @@ func (i *Image) replacePendingPixels(pix []byte, x, y, width, height int) {
|
||||
i.needsToResolvePixels = true
|
||||
}
|
||||
|
||||
func (i *Image) DrawImage(src *Image, bounds image.Rectangle, a, b, c, d, tx, ty float32, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter) {
|
||||
if i == src {
|
||||
panic("buffered: Image.DrawImage: src must be different from the receiver")
|
||||
}
|
||||
|
||||
g := mipmap.GeoM{
|
||||
A: a,
|
||||
B: b,
|
||||
C: c,
|
||||
D: d,
|
||||
Tx: tx,
|
||||
Ty: ty,
|
||||
}
|
||||
|
||||
if maybeCanAddDelayedCommand() {
|
||||
if tryAddDelayedCommand(func() error {
|
||||
i.drawImage(src, bounds, g, colorm, mode, filter)
|
||||
return nil
|
||||
}) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
i.drawImage(src, bounds, g, colorm, mode, filter)
|
||||
}
|
||||
|
||||
func (i *Image) drawImage(src *Image, bounds image.Rectangle, g mipmap.GeoM, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter) {
|
||||
src.resolvePendingPixels(true)
|
||||
i.resolvePendingPixels(false)
|
||||
i.img.DrawImage(src.img, bounds, g, colorm, mode, filter)
|
||||
i.invalidatePendingPixels()
|
||||
}
|
||||
|
||||
// DrawTriangles draws the src image with the given vertices.
|
||||
//
|
||||
// Copying vertices and indices is the caller's responsibility.
|
||||
|
@ -12,16 +12,28 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package mipmap
|
||||
package graphics
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/internal/web"
|
||||
)
|
||||
|
||||
const (
|
||||
IndicesNum = (1 << 16) / 3 * 3 // Adjust num for triangles.
|
||||
VertexFloatNum = 8
|
||||
)
|
||||
|
||||
var (
|
||||
quadIndices = []uint16{0, 1, 2, 1, 2, 3}
|
||||
)
|
||||
|
||||
func QuadIndices() []uint16 {
|
||||
return quadIndices
|
||||
}
|
||||
|
||||
var (
|
||||
theVerticesBackend = &verticesBackend{
|
||||
backend: make([]float32, graphics.VertexFloatNum*1024),
|
||||
backend: make([]float32, VertexFloatNum*1024),
|
||||
}
|
||||
)
|
||||
|
||||
@ -33,7 +45,7 @@ type verticesBackend struct {
|
||||
func (v *verticesBackend) slice(n int, last bool) []float32 {
|
||||
// As this is called only from GopherJS, mutex is not required.
|
||||
|
||||
need := n * graphics.VertexFloatNum
|
||||
need := n * VertexFloatNum
|
||||
if l := len(v.backend); v.head+need > l {
|
||||
for v.head+need > l {
|
||||
l *= 2
|
||||
@ -57,10 +69,10 @@ func vertexSlice(n int, last bool) []float32 {
|
||||
// In GopherJS, allocating memory by make is expensive. Use the backend instead.
|
||||
return theVerticesBackend.slice(n, last)
|
||||
}
|
||||
return make([]float32, n*graphics.VertexFloatNum)
|
||||
return make([]float32, n*VertexFloatNum)
|
||||
}
|
||||
|
||||
func quadVertices(sx0, sy0, sx1, sy1 float32, a, b, c, d, tx, ty float32, cr, cg, cb, ca float32, last bool) []float32 {
|
||||
func QuadVertices(sx0, sy0, sx1, sy1 float32, a, b, c, d, tx, ty float32, cr, cg, cb, ca float32, last bool) []float32 {
|
||||
x := sx1 - sx0
|
||||
y := sy1 - sy0
|
||||
ax, by, cx, dy := a*x, b*y, c*x, d*y
|
@ -1,28 +0,0 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
package graphics
|
||||
|
||||
const (
|
||||
IndicesNum = (1 << 16) / 3 * 3 // Adjust num for triangles.
|
||||
VertexFloatNum = 8
|
||||
)
|
||||
|
||||
var (
|
||||
quadIndices = []uint16{0, 1, 2, 1, 2, 3}
|
||||
)
|
||||
|
||||
func QuadIndices() []uint16 {
|
||||
return quadIndices
|
||||
}
|
@ -16,7 +16,6 @@ package mipmap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"math"
|
||||
|
||||
@ -41,19 +40,6 @@ func EndFrame() error {
|
||||
return shareable.EndFrame()
|
||||
}
|
||||
|
||||
type GeoM struct {
|
||||
A float32
|
||||
B float32
|
||||
C float32
|
||||
D float32
|
||||
Tx float32
|
||||
Ty float32
|
||||
}
|
||||
|
||||
func (g *GeoM) det() float32 {
|
||||
return g.A*g.D - g.B*g.C
|
||||
}
|
||||
|
||||
// Mipmap is a set of shareable.Image sorted by the order of mipmap level.
|
||||
// The level 0 image is a regular image and higher-level images are used for mipmap.
|
||||
type Mipmap struct {
|
||||
@ -101,56 +87,6 @@ func (m *Mipmap) Pixels(x, y, width, height int) ([]byte, error) {
|
||||
return m.orig.Pixels(x, y, width, height)
|
||||
}
|
||||
|
||||
func (m *Mipmap) DrawImage(src *Mipmap, bounds image.Rectangle, geom GeoM, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter) {
|
||||
if det := geom.det(); det == 0 {
|
||||
return
|
||||
} else if math.IsNaN(float64(det)) {
|
||||
return
|
||||
}
|
||||
|
||||
level := src.mipmapLevelFromGeoM(&geom, float32(bounds.Dx()), float32(bounds.Dy()), filter)
|
||||
|
||||
cr, cg, cb, ca := float32(1), float32(1), float32(1), float32(1)
|
||||
if colorm != nil && colorm.ScaleOnly() {
|
||||
body, _ := colorm.UnsafeElements()
|
||||
cr = body[0]
|
||||
cg = body[5]
|
||||
cb = body[10]
|
||||
ca = body[15]
|
||||
colorm = nil
|
||||
}
|
||||
|
||||
screen := filter == driver.FilterScreen
|
||||
if screen && level != 0 {
|
||||
panic("ebiten: Mipmap must not be used when the filter is FilterScreen")
|
||||
}
|
||||
|
||||
a, b, c, d, tx, ty := geom.A, geom.B, geom.C, geom.D, geom.Tx, geom.Ty
|
||||
if level == 0 {
|
||||
sx0 := float32(bounds.Min.X)
|
||||
sy0 := float32(bounds.Min.Y)
|
||||
sx1 := float32(bounds.Max.X)
|
||||
sy1 := float32(bounds.Max.Y)
|
||||
vs := quadVertices(sx0, sy0, sx1, sy1, a, b, c, d, tx, ty, cr, cg, cb, ca, screen)
|
||||
is := graphics.QuadIndices()
|
||||
m.orig.DrawTriangles(src.orig, vs, is, colorm, mode, filter, driver.AddressUnsafe, driver.Region{}, nil, nil, nil)
|
||||
} else if buf := src.level(level); buf != nil {
|
||||
s := pow2(level)
|
||||
sx0 := float32(sizeForLevel(bounds.Min.X, level))
|
||||
sy0 := float32(sizeForLevel(bounds.Min.Y, level))
|
||||
sx1 := float32(sizeForLevel(bounds.Max.X, level))
|
||||
sy1 := float32(sizeForLevel(bounds.Max.Y, level))
|
||||
a *= s
|
||||
b *= s
|
||||
c *= s
|
||||
d *= s
|
||||
vs := quadVertices(sx0, sy0, sx1, sy1, a, b, c, d, tx, ty, cr, cg, cb, ca, false)
|
||||
is := graphics.QuadIndices()
|
||||
m.orig.DrawTriangles(buf, vs, is, colorm, mode, filter, driver.AddressUnsafe, driver.Region{}, nil, nil, nil)
|
||||
}
|
||||
m.disposeMipmaps()
|
||||
}
|
||||
|
||||
func (m *Mipmap) DrawTriangles(src *Mipmap, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, shader *Shader, uniforms []interface{}, images []*Mipmap) {
|
||||
level := math.MaxInt32
|
||||
for i := 0; i < len(indices)/3; i++ {
|
||||
@ -245,7 +181,7 @@ func (m *Mipmap) level(level int) *shareable.Image {
|
||||
switch {
|
||||
case level == 1:
|
||||
src = m.orig
|
||||
vs = quadVertices(0, 0, float32(m.width), float32(m.height), 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1, false)
|
||||
vs = graphics.QuadVertices(0, 0, float32(m.width), float32(m.height), 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1, false)
|
||||
filter = driver.FilterLinear
|
||||
case level > 1:
|
||||
src = m.level(level - 1)
|
||||
@ -255,11 +191,11 @@ func (m *Mipmap) level(level int) *shareable.Image {
|
||||
}
|
||||
w := sizeForLevel(m.width, level-1)
|
||||
h := sizeForLevel(m.height, level-1)
|
||||
vs = quadVertices(0, 0, float32(w), float32(h), 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1, false)
|
||||
vs = graphics.QuadVertices(0, 0, float32(w), float32(h), 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1, false)
|
||||
filter = driver.FilterLinear
|
||||
case level == -1:
|
||||
src = m.orig
|
||||
vs = quadVertices(0, 0, float32(m.width), float32(m.height), 2, 0, 0, 2, 0, 0, 1, 1, 1, 1, false)
|
||||
vs = graphics.QuadVertices(0, 0, float32(m.width), float32(m.height), 2, 0, 0, 2, 0, 0, 1, 1, 1, 1, false)
|
||||
filter = driver.FilterNearest
|
||||
case level < -1:
|
||||
src = m.level(level + 1)
|
||||
@ -269,7 +205,7 @@ func (m *Mipmap) level(level int) *shareable.Image {
|
||||
}
|
||||
w := sizeForLevel(m.width, level-1)
|
||||
h := sizeForLevel(m.height, level-1)
|
||||
vs = quadVertices(0, 0, float32(w), float32(h), 2, 0, 0, 2, 0, 0, 1, 1, 1, 1, false)
|
||||
vs = graphics.QuadVertices(0, 0, float32(w), float32(h), 2, 0, 0, 2, 0, 0, 1, 1, 1, 1, false)
|
||||
filter = driver.FilterNearest
|
||||
default:
|
||||
panic(fmt.Sprintf("ebiten: invalid level: %d", level))
|
||||
@ -320,31 +256,6 @@ func (m *Mipmap) disposeMipmaps() {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Mipmap) mipmapLevelFromGeoM(geom *GeoM, sw, sh float32, filter driver.Filter) int {
|
||||
sx0 := float32(0)
|
||||
sy0 := float32(0)
|
||||
sx1 := sw
|
||||
sy1 := float32(0)
|
||||
sx2 := float32(0)
|
||||
sy2 := sh
|
||||
|
||||
a, b, c, d := geom.A, geom.B, geom.C, geom.D
|
||||
dx0 := float32(0)
|
||||
dy0 := float32(0)
|
||||
dx1 := sx1*a + sy1*b
|
||||
dy1 := sx1*c + sy1*d
|
||||
dx2 := sx2*a + sy2*b
|
||||
dy2 := sx2*c + sy2*d
|
||||
|
||||
l0 := m.mipmapLevelFromDistance(dx0, dy0, dx1, dy1, sx0, sy0, sx1, sy1, filter)
|
||||
l1 := m.mipmapLevelFromDistance(dx0, dy0, dx2, dy2, sx0, sy0, sx2, sy2, filter)
|
||||
|
||||
if l0 < l1 {
|
||||
return l0
|
||||
}
|
||||
return l1
|
||||
}
|
||||
|
||||
// mipmapLevel returns an appropriate mipmap level for the given distance.
|
||||
func (m *Mipmap) mipmapLevelFromDistance(dx0, dy0, dx1, dy1, sx0, sy0, sx1, sy1 float32, filter driver.Filter) int {
|
||||
if filter == driver.FilterScreen {
|
||||
|
Loading…
Reference in New Issue
Block a user