mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 02:38:53 +01:00
internal/affine: Refactoring: Make ColorM interface
This commit is contained in:
parent
5f03f4f195
commit
21aa96f9f5
31
colorm.go
31
colorm.go
@ -32,42 +32,49 @@ const ColorMDim = affine.ColorMDim
|
||||
//
|
||||
// The initial value is identity.
|
||||
type ColorM struct {
|
||||
impl *affine.ColorM
|
||||
impl affine.ColorM
|
||||
|
||||
_ [0]func() // Marks as non-comparable.
|
||||
}
|
||||
|
||||
func (c *ColorM) affineColorM() affine.ColorM {
|
||||
if c.impl != nil {
|
||||
return c.impl
|
||||
}
|
||||
return affine.ColorMIdentity{}
|
||||
}
|
||||
|
||||
// String returns a string representation of ColorM.
|
||||
func (c *ColorM) String() string {
|
||||
return c.impl.String()
|
||||
return affine.ColorMString(c.affineColorM())
|
||||
}
|
||||
|
||||
// Reset resets the ColorM as identity.
|
||||
func (c *ColorM) Reset() {
|
||||
c.impl = nil
|
||||
c.impl = affine.ColorMIdentity{}
|
||||
}
|
||||
|
||||
// Apply pre-multiplies a vector (r, g, b, a, 1) by the matrix
|
||||
// where r, g, b, and a are clr's values in straight-alpha format.
|
||||
// In other words, Apply calculates ColorM * (r, g, b, a, 1)^T.
|
||||
func (c *ColorM) Apply(clr color.Color) color.Color {
|
||||
return c.impl.Apply(clr)
|
||||
return c.affineColorM().Apply(clr)
|
||||
}
|
||||
|
||||
// Concat multiplies a color matrix with the other color matrix.
|
||||
// This is same as muptiplying the matrix other and the matrix c in this order.
|
||||
func (c *ColorM) Concat(other ColorM) {
|
||||
c.impl = c.impl.Concat(other.impl)
|
||||
c.impl = c.affineColorM().Concat(other.impl)
|
||||
}
|
||||
|
||||
// Scale scales the matrix by (r, g, b, a).
|
||||
func (c *ColorM) Scale(r, g, b, a float64) {
|
||||
c.impl = c.impl.Scale(float32(r), float32(g), float32(b), float32(a))
|
||||
c.impl = c.affineColorM().Scale(float32(r), float32(g), float32(b), float32(a))
|
||||
}
|
||||
|
||||
// Translate translates the matrix by (r, g, b, a).
|
||||
func (c *ColorM) Translate(r, g, b, a float64) {
|
||||
c.impl = c.impl.Translate(float32(r), float32(g), float32(b), float32(a))
|
||||
c.impl = c.affineColorM().Translate(float32(r), float32(g), float32(b), float32(a))
|
||||
}
|
||||
|
||||
// RotateHue rotates the hue.
|
||||
@ -83,27 +90,27 @@ func (c *ColorM) RotateHue(theta float64) {
|
||||
//
|
||||
// This conversion uses RGB to/from YCrCb conversion.
|
||||
func (c *ColorM) ChangeHSV(hueTheta float64, saturationScale float64, valueScale float64) {
|
||||
c.impl = c.impl.ChangeHSV(hueTheta, float32(saturationScale), float32(valueScale))
|
||||
c.impl = affine.ChangeHSV(c.affineColorM(), hueTheta, float32(saturationScale), float32(valueScale))
|
||||
}
|
||||
|
||||
// Element returns a value of a matrix at (i, j).
|
||||
func (c *ColorM) Element(i, j int) float64 {
|
||||
return float64(c.impl.Element(i, j))
|
||||
return float64(affine.ColorMElement(c.affineColorM(), i, j))
|
||||
}
|
||||
|
||||
// SetElement sets an element at (i, j).
|
||||
func (c *ColorM) SetElement(i, j int, element float64) {
|
||||
c.impl = c.impl.SetElement(i, j, float32(element))
|
||||
c.impl = affine.ColorMSetElement(c.affineColorM(), i, j, float32(element))
|
||||
}
|
||||
|
||||
// IsInvertible returns a boolean value indicating
|
||||
// whether the matrix c is invertible or not.
|
||||
func (c *ColorM) IsInvertible() bool {
|
||||
return c.impl.IsInvertible()
|
||||
return c.affineColorM().IsInvertible()
|
||||
}
|
||||
|
||||
// Invert inverts the matrix.
|
||||
// If c is not invertible, Invert panics.
|
||||
func (c *ColorM) Invert() {
|
||||
c.impl = c.impl.Invert()
|
||||
c.impl = c.affineColorM().Invert()
|
||||
}
|
||||
|
11
image.go
11
image.go
@ -19,6 +19,7 @@ import (
|
||||
"image"
|
||||
"image/color"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/affine"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/mipmap"
|
||||
@ -213,7 +214,8 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) {
|
||||
is := graphics.QuadIndices()
|
||||
|
||||
srcs := [graphics.ShaderImageNum]*mipmap.Mipmap{img.mipmap}
|
||||
i.mipmap.DrawTriangles(srcs, vs, is, options.ColorM.impl, mode, filter, driver.AddressUnsafe, dstRegion, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false, canSkipMipmap(options.GeoM, filter))
|
||||
|
||||
i.mipmap.DrawTriangles(srcs, vs, is, options.ColorM.affineColorM(), mode, filter, driver.AddressUnsafe, dstRegion, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false, canSkipMipmap(options.GeoM, filter))
|
||||
}
|
||||
|
||||
// Vertex represents a vertex passed to DrawTriangles.
|
||||
@ -362,7 +364,7 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
|
||||
|
||||
srcs := [graphics.ShaderImageNum]*mipmap.Mipmap{img.mipmap}
|
||||
|
||||
i.mipmap.DrawTriangles(srcs, vs, is, options.ColorM.impl, mode, filter, address, dstRegion, sr, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, options.EvenOdd, false)
|
||||
i.mipmap.DrawTriangles(srcs, vs, is, options.ColorM.affineColorM(), mode, filter, address, dstRegion, sr, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, options.EvenOdd, false)
|
||||
}
|
||||
|
||||
// DrawTrianglesShaderOptions represents options for DrawTrianglesShader.
|
||||
@ -511,7 +513,8 @@ func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader
|
||||
}
|
||||
|
||||
us := shader.convertUniforms(options.Uniforms)
|
||||
i.mipmap.DrawTriangles(imgs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, dstRegion, sr, offsets, shader.shader, us, options.EvenOdd, false)
|
||||
|
||||
i.mipmap.DrawTriangles(imgs, vs, is, affine.ColorMIdentity{}, mode, driver.FilterNearest, driver.AddressUnsafe, dstRegion, sr, offsets, shader.shader, us, options.EvenOdd, false)
|
||||
}
|
||||
|
||||
// DrawRectShaderOptions represents options for DrawRectShader.
|
||||
@ -623,7 +626,7 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR
|
||||
}
|
||||
|
||||
us := shader.convertUniforms(options.Uniforms)
|
||||
i.mipmap.DrawTriangles(imgs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, dstRegion, sr, offsets, shader.shader, us, false, canSkipMipmap(options.GeoM, driver.FilterNearest))
|
||||
i.mipmap.DrawTriangles(imgs, vs, is, affine.ColorMIdentity{}, mode, driver.FilterNearest, driver.AddressUnsafe, dstRegion, sr, offsets, shader.shader, us, false, canSkipMipmap(options.GeoM, driver.FilterNearest))
|
||||
}
|
||||
|
||||
// SubImage returns an image representing the portion of the image p visible through r.
|
||||
|
@ -36,33 +36,41 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// A ColorM represents a matrix to transform coloring when rendering an image.
|
||||
// ColorM represents a matrix to transform coloring when rendering an image.
|
||||
//
|
||||
// A ColorM is applied to the source alpha color
|
||||
// ColorM is applied to the source alpha color
|
||||
// while an Image's pixels' format is alpha premultiplied.
|
||||
// Before applying a matrix, a color is un-multiplied, and after applying the matrix,
|
||||
// the color is multiplied again.
|
||||
//
|
||||
// The nil and initial value is identity.
|
||||
type ColorM struct {
|
||||
impl colorMImpl
|
||||
}
|
||||
|
||||
type colorMImpl interface {
|
||||
type ColorM interface {
|
||||
IsIdentity() bool
|
||||
ScaleOnly() bool
|
||||
UnsafeScaleElements() *[4]float32
|
||||
UnsafeElements() (*[16]float32, *[4]float32)
|
||||
Apply(r, g, b, a float32) color.Color
|
||||
Apply(clr color.Color) color.Color
|
||||
|
||||
// IsInvertible returns a boolean value indicating
|
||||
// whether the matrix c is invertible or not.
|
||||
IsInvertible() bool
|
||||
Invert() *ColorM
|
||||
Equals(other *ColorM) bool
|
||||
Concat(other *ColorM) *ColorM
|
||||
Scale(r, g, b, a float32) *ColorM
|
||||
Translate(r, g, b, a float32) *ColorM
|
||||
|
||||
// Invert inverts the matrix.
|
||||
// If c is not invertible, Invert panics.
|
||||
Invert() ColorM
|
||||
|
||||
Equals(other ColorM) bool
|
||||
|
||||
// Concat multiplies a color matrix with the other color matrix.
|
||||
// This is same as muptiplying the matrix other and the matrix c in this order.
|
||||
Concat(other ColorM) ColorM
|
||||
|
||||
// Scale scales the matrix by (r, g, b, a).
|
||||
Scale(r, g, b, a float32) ColorM
|
||||
|
||||
// Translate translates the matrix by (r, g, b, a).
|
||||
Translate(r, g, b, a float32) ColorM
|
||||
}
|
||||
|
||||
func (c *ColorM) String() string {
|
||||
func ColorMString(c ColorM) string {
|
||||
b, t := c.UnsafeElements()
|
||||
return fmt.Sprintf("[[%f, %f, %f, %f, %f], [%f, %f, %f, %f, %f], [%f, %f, %f, %f, %f], [%f, %f, %f, %f, %f]]",
|
||||
b[0], b[4], b[8], b[12], t[0],
|
||||
@ -71,6 +79,8 @@ func (c *ColorM) String() string {
|
||||
b[3], b[7], b[11], b[15], t[3])
|
||||
}
|
||||
|
||||
type ColorMIdentity struct{}
|
||||
|
||||
type colorMImplScale struct {
|
||||
scale [4]float32
|
||||
}
|
||||
@ -90,14 +100,8 @@ func clamp(x float32) float32 {
|
||||
return x
|
||||
}
|
||||
|
||||
func (c *ColorM) isIdentity() bool {
|
||||
if c == nil {
|
||||
return true
|
||||
}
|
||||
if c.impl == nil {
|
||||
return true
|
||||
}
|
||||
return c.impl.IsIdentity()
|
||||
func (c ColorMIdentity) IsIdentity() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *colorMImplScale) IsIdentity() bool {
|
||||
@ -108,11 +112,8 @@ func (c *colorMImplBodyTranslate) IsIdentity() bool {
|
||||
return c.body == colorMIdentityBody && c.translate == colorMIdentityTranslate
|
||||
}
|
||||
|
||||
func (c *ColorM) ScaleOnly() bool {
|
||||
if c.isIdentity() {
|
||||
return true
|
||||
}
|
||||
return c.impl.ScaleOnly()
|
||||
func (c ColorMIdentity) ScaleOnly() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *colorMImplScale) ScaleOnly() bool {
|
||||
@ -164,6 +165,10 @@ func (c *colorMImplBodyTranslate) ScaleOnly() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c ColorMIdentity) UnsafeScaleElements() *[4]float32 {
|
||||
return &[...]float32{1, 1, 1, 1}
|
||||
}
|
||||
|
||||
func (c *colorMImplScale) UnsafeScaleElements() *[4]float32 {
|
||||
return &c.scale
|
||||
}
|
||||
@ -172,11 +177,7 @@ func (c *colorMImplBodyTranslate) UnsafeScaleElements() *[4]float32 {
|
||||
return &[...]float32{c.body[0], c.body[5], c.body[10], c.body[15]}
|
||||
}
|
||||
|
||||
func (c *ColorM) Apply(clr color.Color) color.Color {
|
||||
if c.isIdentity() {
|
||||
return clr
|
||||
}
|
||||
|
||||
func colorToFloat32s(clr color.Color) (float32, float32, float32, float32) {
|
||||
r, g, b, a := clr.RGBA()
|
||||
rf, gf, bf, af := float32(0.0), float32(0.0), float32(0.0), float32(0.0)
|
||||
// Unmultiply alpha
|
||||
@ -186,10 +187,21 @@ func (c *ColorM) Apply(clr color.Color) color.Color {
|
||||
bf = float32(b) / float32(a)
|
||||
af = float32(a) / 0xffff
|
||||
}
|
||||
return c.impl.Apply(rf, gf, bf, af)
|
||||
return rf, gf, bf, af
|
||||
}
|
||||
|
||||
func (c *colorMImplScale) Apply(rf, gf, bf, af float32) color.Color {
|
||||
func (c ColorMIdentity) Apply(clr color.Color) color.Color {
|
||||
rf, gf, bf, af := colorToFloat32s(clr)
|
||||
return color.NRGBA64{
|
||||
R: uint16(rf * 0xffff),
|
||||
G: uint16(gf * 0xffff),
|
||||
B: uint16(bf * 0xffff),
|
||||
A: uint16(af * 0xffff),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *colorMImplScale) Apply(clr color.Color) color.Color {
|
||||
rf, gf, bf, af := colorToFloat32s(clr)
|
||||
rf *= c.scale[0]
|
||||
gf *= c.scale[1]
|
||||
bf *= c.scale[2]
|
||||
@ -206,7 +218,8 @@ func (c *colorMImplScale) Apply(rf, gf, bf, af float32) color.Color {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *colorMImplBodyTranslate) Apply(rf, gf, bf, af float32) color.Color {
|
||||
func (c *colorMImplBodyTranslate) Apply(clr color.Color) color.Color {
|
||||
rf, gf, bf, af := colorToFloat32s(clr)
|
||||
eb := &c.body
|
||||
et := &c.translate
|
||||
rf2 := eb[0]*rf + eb[4]*gf + eb[8]*bf + eb[12]*af + et[0]
|
||||
@ -225,11 +238,8 @@ func (c *colorMImplBodyTranslate) Apply(rf, gf, bf, af float32) color.Color {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ColorM) UnsafeElements() (*[16]float32, *[4]float32) {
|
||||
if c.isIdentity() {
|
||||
return &colorMIdentityBody, &colorMIdentityTranslate
|
||||
}
|
||||
return c.impl.UnsafeElements()
|
||||
func (c ColorMIdentity) UnsafeElements() (*[16]float32, *[4]float32) {
|
||||
return &colorMIdentityBody, &colorMIdentityTranslate
|
||||
}
|
||||
|
||||
func (c *colorMImplScale) UnsafeElements() (*[16]float32, *[4]float32) {
|
||||
@ -276,13 +286,8 @@ func (c *colorMImplBodyTranslate) det() float32 {
|
||||
m03*(m10*b124234-m11*b024234+m12*b014234)
|
||||
}
|
||||
|
||||
// IsInvertible returns a boolean value indicating
|
||||
// whether the matrix c is invertible or not.
|
||||
func (c *ColorM) IsInvertible() bool {
|
||||
if c.isIdentity() {
|
||||
return true
|
||||
}
|
||||
return c.impl.IsInvertible()
|
||||
func (c ColorMIdentity) IsInvertible() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *colorMImplScale) IsInvertible() bool {
|
||||
@ -293,29 +298,22 @@ func (c *colorMImplBodyTranslate) IsInvertible() bool {
|
||||
return c.det() != 0
|
||||
}
|
||||
|
||||
// Invert inverts the matrix.
|
||||
// If c is not invertible, Invert panics.
|
||||
func (c *ColorM) Invert() *ColorM {
|
||||
if c.isIdentity() {
|
||||
return nil
|
||||
}
|
||||
return c.impl.Invert()
|
||||
func (c ColorMIdentity) Invert() ColorM {
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *colorMImplScale) Invert() *ColorM {
|
||||
return &ColorM{
|
||||
impl: &colorMImplScale{
|
||||
scale: [4]float32{
|
||||
1 / c.scale[0],
|
||||
1 / c.scale[1],
|
||||
1 / c.scale[2],
|
||||
1 / c.scale[3],
|
||||
},
|
||||
func (c *colorMImplScale) Invert() ColorM {
|
||||
return &colorMImplScale{
|
||||
scale: [4]float32{
|
||||
1 / c.scale[0],
|
||||
1 / c.scale[1],
|
||||
1 / c.scale[2],
|
||||
1 / c.scale[3],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *colorMImplBodyTranslate) Invert() *ColorM {
|
||||
func (c *colorMImplBodyTranslate) Invert() ColorM {
|
||||
det := c.det()
|
||||
if det == 0 {
|
||||
panic("affine: c is not invertible")
|
||||
@ -417,13 +415,11 @@ func (c *colorMImplBodyTranslate) Invert() *ColorM {
|
||||
m.translate[2] = idet * (m00*b123134 - m01*b023134 + m02*b013134 - m03*b012134)
|
||||
m.translate[3] = idet * -(m00*b123124 - m01*b023124 + m02*b013124 - m03*b012124)
|
||||
|
||||
return &ColorM{
|
||||
impl: m,
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// Element returns a value of a matrix at (i, j).
|
||||
func (c *ColorM) Element(i, j int) float32 {
|
||||
// ColorMElement returns a value of a matrix at (i, j).
|
||||
func ColorMElement(c ColorM, i, j int) float32 {
|
||||
b, t := c.UnsafeElements()
|
||||
if j < ColorMDim-1 {
|
||||
return b[i+j*(ColorMDim-1)]
|
||||
@ -431,13 +427,13 @@ func (c *ColorM) Element(i, j int) float32 {
|
||||
return t[i]
|
||||
}
|
||||
|
||||
// SetElement sets an element at (i, j).
|
||||
func (c *ColorM) SetElement(i, j int, element float32) *ColorM {
|
||||
// ColorMSetElement sets an element at (i, j).
|
||||
func ColorMSetElement(c ColorM, i, j int, element float32) ColorM {
|
||||
newImpl := &colorMImplBodyTranslate{
|
||||
body: colorMIdentityBody,
|
||||
}
|
||||
if !c.isIdentity() {
|
||||
b, t := c.impl.UnsafeElements()
|
||||
if !c.IsIdentity() {
|
||||
b, t := c.UnsafeElements()
|
||||
newImpl.body = *b
|
||||
newImpl.translate = *t
|
||||
}
|
||||
@ -446,26 +442,18 @@ func (c *ColorM) SetElement(i, j int, element float32) *ColorM {
|
||||
} else {
|
||||
newImpl.translate[i] = element
|
||||
}
|
||||
return &ColorM{
|
||||
impl: newImpl,
|
||||
}
|
||||
return newImpl
|
||||
}
|
||||
|
||||
func (c *ColorM) Equals(other *ColorM) bool {
|
||||
if c.isIdentity() {
|
||||
return other.isIdentity()
|
||||
}
|
||||
if other.isIdentity() {
|
||||
return false
|
||||
}
|
||||
return c.impl.Equals(other)
|
||||
func (c ColorMIdentity) Equals(other ColorM) bool {
|
||||
return other.IsIdentity()
|
||||
}
|
||||
|
||||
func (c *colorMImplScale) Equals(other *ColorM) bool {
|
||||
if !other.impl.ScaleOnly() {
|
||||
func (c *colorMImplScale) Equals(other ColorM) bool {
|
||||
if !other.ScaleOnly() {
|
||||
return false
|
||||
}
|
||||
for i, s := range other.impl.UnsafeScaleElements() {
|
||||
for i, s := range other.UnsafeScaleElements() {
|
||||
if c.scale[i] != s {
|
||||
return false
|
||||
}
|
||||
@ -473,92 +461,83 @@ func (c *colorMImplScale) Equals(other *ColorM) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *colorMImplBodyTranslate) Equals(other *ColorM) bool {
|
||||
lhsb, lhst := other.impl.UnsafeElements()
|
||||
func (c *colorMImplBodyTranslate) Equals(other ColorM) bool {
|
||||
lhsb, lhst := other.UnsafeElements()
|
||||
rhsb := &c.body
|
||||
rhst := &c.translate
|
||||
return *lhsb == *rhsb && *lhst == *rhst
|
||||
}
|
||||
|
||||
// Concat multiplies a color matrix with the other color matrix.
|
||||
// This is same as muptiplying the matrix other and the matrix c in this order.
|
||||
func (c *ColorM) Concat(other *ColorM) *ColorM {
|
||||
if c.isIdentity() {
|
||||
return other
|
||||
}
|
||||
if other.isIdentity() {
|
||||
return c
|
||||
}
|
||||
return c.impl.Concat(other)
|
||||
func (c ColorMIdentity) Concat(other ColorM) ColorM {
|
||||
return other
|
||||
}
|
||||
|
||||
func (c *colorMImplScale) Concat(other *ColorM) *ColorM {
|
||||
func (c *colorMImplScale) Concat(other ColorM) ColorM {
|
||||
if other.IsIdentity() {
|
||||
return c
|
||||
}
|
||||
|
||||
if other.ScaleOnly() {
|
||||
s := other.impl.UnsafeScaleElements()
|
||||
s := other.UnsafeScaleElements()
|
||||
return c.Scale(s[0], s[1], s[2], s[3])
|
||||
}
|
||||
|
||||
lhsb, lhst := other.impl.UnsafeElements()
|
||||
lhsb, lhst := other.UnsafeElements()
|
||||
s := &c.scale
|
||||
return &ColorM{
|
||||
impl: &colorMImplBodyTranslate{
|
||||
body: [...]float32{
|
||||
lhsb[0] * s[0], lhsb[1] * s[0], lhsb[2] * s[0], lhsb[3] * s[0],
|
||||
lhsb[4] * s[1], lhsb[5] * s[1], lhsb[6] * s[1], lhsb[7] * s[1],
|
||||
lhsb[8] * s[2], lhsb[9] * s[2], lhsb[10] * s[2], lhsb[11] * s[2],
|
||||
lhsb[12] * s[3], lhsb[13] * s[3], lhsb[14] * s[3], lhsb[15] * s[3],
|
||||
},
|
||||
translate: *lhst,
|
||||
return &colorMImplBodyTranslate{
|
||||
body: [...]float32{
|
||||
lhsb[0] * s[0], lhsb[1] * s[0], lhsb[2] * s[0], lhsb[3] * s[0],
|
||||
lhsb[4] * s[1], lhsb[5] * s[1], lhsb[6] * s[1], lhsb[7] * s[1],
|
||||
lhsb[8] * s[2], lhsb[9] * s[2], lhsb[10] * s[2], lhsb[11] * s[2],
|
||||
lhsb[12] * s[3], lhsb[13] * s[3], lhsb[14] * s[3], lhsb[15] * s[3],
|
||||
},
|
||||
translate: *lhst,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *colorMImplBodyTranslate) Concat(other *ColorM) *ColorM {
|
||||
lhsb, lhst := other.impl.UnsafeElements()
|
||||
func (c *colorMImplBodyTranslate) Concat(other ColorM) ColorM {
|
||||
if other.IsIdentity() {
|
||||
return c
|
||||
}
|
||||
|
||||
lhsb, lhst := other.UnsafeElements()
|
||||
rhsb := &c.body
|
||||
rhst := &c.translate
|
||||
|
||||
return &ColorM{
|
||||
impl: &colorMImplBodyTranslate{
|
||||
// TODO: This is a temporary hack to calculate multiply of transposed matrices.
|
||||
// Fix mulSquare implmentation and swap the arguments.
|
||||
body: mulSquare(rhsb, lhsb, ColorMDim-1),
|
||||
translate: [...]float32{
|
||||
lhsb[0]*rhst[0] + lhsb[4]*rhst[1] + lhsb[8]*rhst[2] + lhsb[12]*rhst[3] + lhst[0],
|
||||
lhsb[1]*rhst[0] + lhsb[5]*rhst[1] + lhsb[9]*rhst[2] + lhsb[13]*rhst[3] + lhst[1],
|
||||
lhsb[2]*rhst[0] + lhsb[6]*rhst[1] + lhsb[10]*rhst[2] + lhsb[14]*rhst[3] + lhst[2],
|
||||
lhsb[3]*rhst[0] + lhsb[7]*rhst[1] + lhsb[11]*rhst[2] + lhsb[15]*rhst[3] + lhst[3],
|
||||
},
|
||||
return &colorMImplBodyTranslate{
|
||||
// TODO: This is a temporary hack to calculate multiply of transposed matrices.
|
||||
// Fix mulSquare implmentation and swap the arguments.
|
||||
body: mulSquare(rhsb, lhsb, ColorMDim-1),
|
||||
translate: [...]float32{
|
||||
lhsb[0]*rhst[0] + lhsb[4]*rhst[1] + lhsb[8]*rhst[2] + lhsb[12]*rhst[3] + lhst[0],
|
||||
lhsb[1]*rhst[0] + lhsb[5]*rhst[1] + lhsb[9]*rhst[2] + lhsb[13]*rhst[3] + lhst[1],
|
||||
lhsb[2]*rhst[0] + lhsb[6]*rhst[1] + lhsb[10]*rhst[2] + lhsb[14]*rhst[3] + lhst[2],
|
||||
lhsb[3]*rhst[0] + lhsb[7]*rhst[1] + lhsb[11]*rhst[2] + lhsb[15]*rhst[3] + lhst[3],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Scale scales the matrix by (r, g, b, a).
|
||||
func (c *ColorM) Scale(r, g, b, a float32) *ColorM {
|
||||
if c.isIdentity() {
|
||||
return getCachedScalingColorM(r, g, b, a)
|
||||
func (c ColorMIdentity) Scale(r, g, b, a float32) ColorM {
|
||||
return getCachedScalingColorM(r, g, b, a)
|
||||
}
|
||||
|
||||
func (c *colorMImplScale) Scale(r, g, b, a float32) ColorM {
|
||||
return &colorMImplScale{
|
||||
scale: [...]float32{
|
||||
c.scale[0] * r,
|
||||
c.scale[1] * g,
|
||||
c.scale[2] * b,
|
||||
c.scale[3] * a,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *colorMImplBodyTranslate) Scale(r, g, b, a float32) ColorM {
|
||||
if c.ScaleOnly() {
|
||||
s := c.impl.UnsafeScaleElements()
|
||||
s := c.UnsafeScaleElements()
|
||||
return getCachedScalingColorM(r*s[0], g*s[1], b*s[2], a*s[3])
|
||||
}
|
||||
return c.impl.Scale(r, g, b, a)
|
||||
}
|
||||
|
||||
func (c *colorMImplScale) Scale(r, g, b, a float32) *ColorM {
|
||||
return &ColorM{
|
||||
impl: &colorMImplScale{
|
||||
scale: [...]float32{
|
||||
c.scale[0] * r,
|
||||
c.scale[1] * g,
|
||||
c.scale[2] * b,
|
||||
c.scale[3] * a,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *colorMImplBodyTranslate) Scale(r, g, b, a float32) *ColorM {
|
||||
eb := c.body
|
||||
for i := 0; i < ColorMDim-1; i++ {
|
||||
eb[i*(ColorMDim-1)] *= r
|
||||
@ -574,52 +553,40 @@ func (c *colorMImplBodyTranslate) Scale(r, g, b, a float32) *ColorM {
|
||||
c.translate[3] * a,
|
||||
}
|
||||
|
||||
return &ColorM{
|
||||
impl: &colorMImplBodyTranslate{
|
||||
body: eb,
|
||||
translate: et,
|
||||
return &colorMImplBodyTranslate{
|
||||
body: eb,
|
||||
translate: et,
|
||||
}
|
||||
}
|
||||
|
||||
func (c ColorMIdentity) Translate(r, g, b, a float32) ColorM {
|
||||
return &colorMImplBodyTranslate{
|
||||
body: colorMIdentityBody,
|
||||
translate: [...]float32{r, g, b, a},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *colorMImplScale) Translate(r, g, b, a float32) ColorM {
|
||||
return &colorMImplBodyTranslate{
|
||||
body: [...]float32{
|
||||
c.scale[0], 0, 0, 0,
|
||||
0, c.scale[1], 0, 0,
|
||||
0, 0, c.scale[2], 0,
|
||||
0, 0, 0, c.scale[3],
|
||||
},
|
||||
translate: [...]float32{r, g, b, a},
|
||||
}
|
||||
}
|
||||
|
||||
// Translate translates the matrix by (r, g, b, a).
|
||||
func (c *ColorM) Translate(r, g, b, a float32) *ColorM {
|
||||
if c.isIdentity() {
|
||||
return &ColorM{
|
||||
impl: &colorMImplBodyTranslate{
|
||||
body: colorMIdentityBody,
|
||||
translate: [...]float32{r, g, b, a},
|
||||
},
|
||||
}
|
||||
}
|
||||
return c.impl.Translate(r, g, b, a)
|
||||
}
|
||||
|
||||
func (c *colorMImplScale) Translate(r, g, b, a float32) *ColorM {
|
||||
return &ColorM{
|
||||
impl: &colorMImplBodyTranslate{
|
||||
body: [...]float32{
|
||||
c.scale[0], 0, 0, 0,
|
||||
0, c.scale[1], 0, 0,
|
||||
0, 0, c.scale[2], 0,
|
||||
0, 0, 0, c.scale[3],
|
||||
},
|
||||
translate: [...]float32{r, g, b, a},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *colorMImplBodyTranslate) Translate(r, g, b, a float32) *ColorM {
|
||||
func (c *colorMImplBodyTranslate) Translate(r, g, b, a float32) ColorM {
|
||||
es := c.translate
|
||||
es[0] += r
|
||||
es[1] += g
|
||||
es[2] += b
|
||||
es[3] += a
|
||||
return &ColorM{
|
||||
impl: &colorMImplBodyTranslate{
|
||||
body: c.body,
|
||||
translate: es,
|
||||
},
|
||||
return &colorMImplBodyTranslate{
|
||||
body: c.body,
|
||||
translate: es,
|
||||
}
|
||||
}
|
||||
|
||||
@ -629,24 +596,20 @@ var (
|
||||
// Cb: [-0.5 - 0.5]
|
||||
// Cr: [-0.5 - 0.5]
|
||||
|
||||
rgbToYCbCr = &ColorM{
|
||||
impl: &colorMImplBodyTranslate{
|
||||
body: [...]float32{
|
||||
0.2990, -0.1687, 0.5000, 0,
|
||||
0.5870, -0.3313, -0.4187, 0,
|
||||
0.1140, 0.5000, -0.0813, 0,
|
||||
0, 0, 0, 1,
|
||||
},
|
||||
rgbToYCbCr = &colorMImplBodyTranslate{
|
||||
body: [...]float32{
|
||||
0.2990, -0.1687, 0.5000, 0,
|
||||
0.5870, -0.3313, -0.4187, 0,
|
||||
0.1140, 0.5000, -0.0813, 0,
|
||||
0, 0, 0, 1,
|
||||
},
|
||||
}
|
||||
yCbCrToRgb = &ColorM{
|
||||
impl: &colorMImplBodyTranslate{
|
||||
body: [...]float32{
|
||||
1, 1, 1, 0,
|
||||
0, -0.34414, 1.77200, 0,
|
||||
1.40200, -0.71414, 0, 0,
|
||||
0, 0, 0, 1,
|
||||
},
|
||||
yCbCrToRgb = &colorMImplBodyTranslate{
|
||||
body: [...]float32{
|
||||
1, 1, 1, 0,
|
||||
0, -0.34414, 1.77200, 0,
|
||||
1.40200, -0.71414, 0, 0,
|
||||
0, 0, 0, 1,
|
||||
},
|
||||
}
|
||||
)
|
||||
@ -657,18 +620,16 @@ var (
|
||||
// valueScale is a value to scale value (a.k.a. brightness).
|
||||
//
|
||||
// This conversion uses RGB to/from YCrCb conversion.
|
||||
func (c *ColorM) ChangeHSV(hueTheta float64, saturationScale float32, valueScale float32) *ColorM {
|
||||
func ChangeHSV(c ColorM, hueTheta float64, saturationScale float32, valueScale float32) ColorM {
|
||||
sin, cos := math.Sincos(hueTheta)
|
||||
s32, c32 := float32(sin), float32(cos)
|
||||
c = c.Concat(rgbToYCbCr)
|
||||
c = c.Concat(&ColorM{
|
||||
impl: &colorMImplBodyTranslate{
|
||||
body: [...]float32{
|
||||
1, 0, 0, 0,
|
||||
0, c32, s32, 0,
|
||||
0, -s32, c32, 0,
|
||||
0, 0, 0, 1,
|
||||
},
|
||||
c = c.Concat(&colorMImplBodyTranslate{
|
||||
body: [...]float32{
|
||||
1, 0, 0, 0,
|
||||
0, c32, s32, 0,
|
||||
0, -s32, c32, 0,
|
||||
0, 0, 0, 1,
|
||||
},
|
||||
})
|
||||
s := saturationScale
|
||||
@ -683,7 +644,7 @@ type cachedScalingColorMKey struct {
|
||||
}
|
||||
|
||||
type cachedScalingColorMValue struct {
|
||||
c *ColorM
|
||||
c *colorMImplScale
|
||||
atime uint64
|
||||
}
|
||||
|
||||
@ -693,7 +654,7 @@ var (
|
||||
cacheMonotonicClock uint64
|
||||
)
|
||||
|
||||
func getCachedScalingColorM(r, g, b, a float32) *ColorM {
|
||||
func getCachedScalingColorM(r, g, b, a float32) ColorM {
|
||||
key := cachedScalingColorMKey{r, g, b, a}
|
||||
|
||||
cachedScalingColorMM.Lock()
|
||||
@ -722,10 +683,8 @@ func getCachedScalingColorM(r, g, b, a float32) *ColorM {
|
||||
}
|
||||
|
||||
v := &cachedScalingColorMValue{
|
||||
c: &ColorM{
|
||||
impl: &colorMImplScale{
|
||||
scale: [...]float32{r, g, b, a},
|
||||
},
|
||||
c: &colorMImplScale{
|
||||
scale: [...]float32{r, g, b, a},
|
||||
},
|
||||
atime: now,
|
||||
}
|
||||
|
@ -24,26 +24,26 @@ import (
|
||||
|
||||
func TestColorMScale(t *testing.T) {
|
||||
cases := []struct {
|
||||
In *ColorM
|
||||
Out *ColorM
|
||||
In ColorM
|
||||
Out ColorM
|
||||
}{
|
||||
{
|
||||
nil,
|
||||
(*ColorM)(nil).Scale(0.25, 0.5, 0.75, 1),
|
||||
ColorMIdentity{},
|
||||
ColorMIdentity{}.Scale(0.25, 0.5, 0.75, 1),
|
||||
},
|
||||
{
|
||||
(*ColorM)(nil).Scale(0.5, 0.5, 0.5, 0.8),
|
||||
(*ColorM)(nil).Scale(0.125, 0.25, 0.375, 0.8),
|
||||
ColorMIdentity{}.Scale(0.5, 0.5, 0.5, 0.8),
|
||||
ColorMIdentity{}.Scale(0.125, 0.25, 0.375, 0.8),
|
||||
},
|
||||
{
|
||||
(*ColorM)(nil).Translate(0, 0, 0, 0),
|
||||
(*ColorM)(nil).Scale(0.25, 0.5, 0.75, 1),
|
||||
ColorMIdentity{}.Translate(0, 0, 0, 0),
|
||||
ColorMIdentity{}.Scale(0.25, 0.5, 0.75, 1),
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
got := c.In.Scale(0.25, 0.5, 0.75, 1)
|
||||
want := c.Out
|
||||
if got != want {
|
||||
if !got.Equals(want) {
|
||||
t.Errorf("%v.Scale(): got: %v, want: %v", c.In, got, want)
|
||||
}
|
||||
}
|
||||
@ -51,51 +51,51 @@ func TestColorMScale(t *testing.T) {
|
||||
|
||||
func TestColorMScaleOnly(t *testing.T) {
|
||||
cases := []struct {
|
||||
In *ColorM
|
||||
In ColorM
|
||||
Out bool
|
||||
}{
|
||||
{
|
||||
nil,
|
||||
ColorMIdentity{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
(*ColorM)(nil).Translate(0, 0, 0, 0),
|
||||
ColorMIdentity{}.Translate(0, 0, 0, 0),
|
||||
true,
|
||||
},
|
||||
{
|
||||
(*ColorM)(nil).Translate(1, 0, 0, 0),
|
||||
ColorMIdentity{}.Translate(1, 0, 0, 0),
|
||||
false,
|
||||
},
|
||||
{
|
||||
(*ColorM)(nil).Translate(0, 0, 0, -1),
|
||||
ColorMIdentity{}.Translate(0, 0, 0, -1),
|
||||
false,
|
||||
},
|
||||
{
|
||||
(*ColorM)(nil).Scale(1, 1, 1, 1),
|
||||
ColorMIdentity{}.Scale(1, 1, 1, 1),
|
||||
true,
|
||||
},
|
||||
{
|
||||
(*ColorM)(nil).Scale(0, 0, 0, 0),
|
||||
ColorMIdentity{}.Scale(0, 0, 0, 0),
|
||||
true,
|
||||
},
|
||||
{
|
||||
(*ColorM)(nil).Scale(0.1, 0.2, 0.3, 0.4),
|
||||
ColorMIdentity{}.Scale(0.1, 0.2, 0.3, 0.4),
|
||||
true,
|
||||
},
|
||||
{
|
||||
(*ColorM)(nil).Scale(0.1, 0.2, 0.3, 0.4).Translate(1, 0, 0, 0),
|
||||
ColorMIdentity{}.Scale(0.1, 0.2, 0.3, 0.4).Translate(1, 0, 0, 0),
|
||||
false,
|
||||
},
|
||||
{
|
||||
(*ColorM)(nil).ChangeHSV(math.Pi/2, 0.5, 0.5),
|
||||
ChangeHSV(ColorMIdentity{}, math.Pi/2, 0.5, 0.5),
|
||||
false,
|
||||
},
|
||||
{
|
||||
(*ColorM)(nil).SetElement(0, 0, 2),
|
||||
ColorMSetElement(ColorMIdentity{}, 0, 0, 2),
|
||||
true,
|
||||
},
|
||||
{
|
||||
(*ColorM)(nil).SetElement(0, 1, 2),
|
||||
ColorMSetElement(ColorMIdentity{}, 0, 1, 2),
|
||||
false,
|
||||
},
|
||||
}
|
||||
@ -109,28 +109,24 @@ func TestColorMScaleOnly(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestColorMIsInvertible(t *testing.T) {
|
||||
m := &ColorM{}
|
||||
m = m.SetElement(1, 0, .5)
|
||||
m = m.SetElement(1, 1, .5)
|
||||
m = m.SetElement(1, 2, .5)
|
||||
m = m.SetElement(1, 3, .5)
|
||||
m = m.SetElement(1, 4, .5)
|
||||
var m ColorM = ColorMIdentity{}
|
||||
m = ColorMSetElement(m, 1, 0, .5)
|
||||
m = ColorMSetElement(m, 1, 1, .5)
|
||||
m = ColorMSetElement(m, 1, 2, .5)
|
||||
m = ColorMSetElement(m, 1, 3, .5)
|
||||
m = ColorMSetElement(m, 1, 4, .5)
|
||||
|
||||
cidentity := &ColorM{}
|
||||
cinvalid := &ColorM{}
|
||||
cinvalid = cinvalid.SetElement(0, 0, 0)
|
||||
cinvalid = cinvalid.SetElement(1, 1, 0)
|
||||
cinvalid = cinvalid.SetElement(2, 2, 0)
|
||||
cinvalid = cinvalid.SetElement(3, 3, 0)
|
||||
var cidentity ColorM = ColorMIdentity{}
|
||||
var cinvalid ColorM = ColorMIdentity{}
|
||||
cinvalid = ColorMSetElement(cinvalid, 0, 0, 0)
|
||||
cinvalid = ColorMSetElement(cinvalid, 1, 1, 0)
|
||||
cinvalid = ColorMSetElement(cinvalid, 2, 2, 0)
|
||||
cinvalid = ColorMSetElement(cinvalid, 3, 3, 0)
|
||||
|
||||
cases := []struct {
|
||||
In *ColorM
|
||||
In ColorM
|
||||
Out bool
|
||||
}{
|
||||
{
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
cidentity,
|
||||
true,
|
||||
@ -153,11 +149,11 @@ func TestColorMIsInvertible(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func arrayToColorM(es [4][5]float32) *ColorM {
|
||||
var a = &ColorM{}
|
||||
func arrayToColorM(es [4][5]float32) ColorM {
|
||||
var a ColorM = ColorMIdentity{}
|
||||
for j := 0; j < 5; j++ {
|
||||
for i := 0; i < 4; i++ {
|
||||
a = a.SetElement(i, j, es[i][j])
|
||||
a = ColorMSetElement(a, i, j, es[i][j])
|
||||
}
|
||||
}
|
||||
return a
|
||||
@ -170,11 +166,11 @@ func abs(x float32) float32 {
|
||||
return x
|
||||
}
|
||||
|
||||
func equalWithDelta(a, b *ColorM, delta float32) bool {
|
||||
func equalWithDelta(a, b ColorM, delta float32) bool {
|
||||
for j := 0; j < 5; j++ {
|
||||
for i := 0; i < 4; i++ {
|
||||
ea := a.Element(i, j)
|
||||
eb := b.Element(i, j)
|
||||
ea := ColorMElement(a, i, j)
|
||||
eb := ColorMElement(b, i, j)
|
||||
if abs(ea-eb) > delta {
|
||||
return false
|
||||
}
|
||||
@ -185,12 +181,12 @@ func equalWithDelta(a, b *ColorM, delta float32) bool {
|
||||
|
||||
func TestColorMInvert(t *testing.T) {
|
||||
cases := []struct {
|
||||
In *ColorM
|
||||
Out *ColorM
|
||||
In ColorM
|
||||
Out ColorM
|
||||
}{
|
||||
{
|
||||
In: nil,
|
||||
Out: nil,
|
||||
In: ColorMIdentity{},
|
||||
Out: ColorMIdentity{},
|
||||
},
|
||||
{
|
||||
In: arrayToColorM([4][5]float32{
|
||||
@ -207,7 +203,7 @@ func TestColorMInvert(t *testing.T) {
|
||||
}),
|
||||
},
|
||||
{
|
||||
In: (*ColorM)(nil).Scale(1, 2, 4, 8),
|
||||
In: ColorMIdentity{}.Scale(1, 2, 4, 8),
|
||||
Out: arrayToColorM([4][5]float32{
|
||||
{1, 0, 0, 0, 0},
|
||||
{0, 0.5, 0, 0, 0},
|
||||
@ -256,8 +252,8 @@ func BenchmarkColorMInvert(b *testing.B) {
|
||||
r := rand.Float32
|
||||
|
||||
b.StopTimer()
|
||||
var m *ColorM
|
||||
for m == nil || !m.IsInvertible() {
|
||||
var m ColorM = ColorMIdentity{}
|
||||
for m.IsIdentity() || !m.IsInvertible() {
|
||||
m = arrayToColorM([4][5]float32{
|
||||
{r(), r(), r(), r(), r() * 10},
|
||||
{r(), r(), r(), r(), r() * 10},
|
||||
@ -274,24 +270,24 @@ func BenchmarkColorMInvert(b *testing.B) {
|
||||
|
||||
func TestColorMConcat(t *testing.T) {
|
||||
cases := []struct {
|
||||
In0 *ColorM
|
||||
In1 *ColorM
|
||||
Out *ColorM
|
||||
In0 ColorM
|
||||
In1 ColorM
|
||||
Out ColorM
|
||||
}{
|
||||
{
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
ColorMIdentity{},
|
||||
ColorMIdentity{},
|
||||
ColorMIdentity{},
|
||||
},
|
||||
{
|
||||
(*ColorM)(nil).Scale(1, 2, 3, 4),
|
||||
(*ColorM)(nil).Scale(5, 6, 7, 8),
|
||||
(*ColorM)(nil).Scale(5, 12, 21, 32),
|
||||
ColorMIdentity{}.Scale(1, 2, 3, 4),
|
||||
ColorMIdentity{}.Scale(5, 6, 7, 8),
|
||||
ColorMIdentity{}.Scale(5, 12, 21, 32),
|
||||
},
|
||||
{
|
||||
(*ColorM)(nil).Scale(5, 6, 7, 8),
|
||||
(*ColorM)(nil).Scale(1, 2, 3, 4),
|
||||
(*ColorM)(nil).Scale(5, 12, 21, 32),
|
||||
ColorMIdentity{}.Scale(5, 6, 7, 8),
|
||||
ColorMIdentity{}.Scale(1, 2, 3, 4),
|
||||
ColorMIdentity{}.Scale(5, 12, 21, 32),
|
||||
},
|
||||
{
|
||||
arrayToColorM([4][5]float32{
|
||||
@ -300,7 +296,7 @@ func TestColorMConcat(t *testing.T) {
|
||||
{4, 5, 1, 2, 3},
|
||||
{3, 4, 5, 1, 2},
|
||||
}),
|
||||
(*ColorM)(nil).Scale(1, 2, 3, 4),
|
||||
ColorMIdentity{}.Scale(1, 2, 3, 4),
|
||||
arrayToColorM([4][5]float32{
|
||||
{1, 2, 3, 4, 5},
|
||||
{10, 2, 4, 6, 8},
|
||||
@ -309,7 +305,7 @@ func TestColorMConcat(t *testing.T) {
|
||||
}),
|
||||
},
|
||||
{
|
||||
(*ColorM)(nil).Scale(1, 2, 3, 4),
|
||||
ColorMIdentity{}.Scale(1, 2, 3, 4),
|
||||
arrayToColorM([4][5]float32{
|
||||
{1, 2, 3, 4, 5},
|
||||
{5, 1, 2, 3, 4},
|
||||
|
@ -298,7 +298,7 @@ func (i *Image) ensureIsolated() {
|
||||
Width: float32(w - 2*paddingSize),
|
||||
Height: float32(h - 2*paddingSize),
|
||||
}
|
||||
newImg.DrawTriangles(srcs, offsets, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dstRegion, driver.Region{}, nil, nil, false)
|
||||
newImg.DrawTriangles(srcs, offsets, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dstRegion, driver.Region{}, nil, nil, false)
|
||||
|
||||
i.dispose(false)
|
||||
i.backend = &backend{
|
||||
@ -354,7 +354,7 @@ func (i *Image) putOnAtlas() error {
|
||||
Width: w,
|
||||
Height: h,
|
||||
}
|
||||
newI.drawTriangles([graphics.ShaderImageNum]*Image{i}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false, true)
|
||||
newI.drawTriangles([graphics.ShaderImageNum]*Image{i}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false, true)
|
||||
}
|
||||
|
||||
newI.moveTo(i)
|
||||
@ -402,13 +402,13 @@ func (i *Image) processSrc(src *Image) {
|
||||
// 5: Color G
|
||||
// 6: Color B
|
||||
// 7: Color Y
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []interface{}, evenOdd bool) {
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []float32, indices []uint16, colorm affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []interface{}, evenOdd bool) {
|
||||
backendsM.Lock()
|
||||
defer backendsM.Unlock()
|
||||
i.drawTriangles(srcs, vertices, indices, colorm, mode, filter, address, dstRegion, srcRegion, subimageOffsets, shader, uniforms, evenOdd, false)
|
||||
}
|
||||
|
||||
func (i *Image) drawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []interface{}, evenOdd bool, keepOnAtlas bool) {
|
||||
func (i *Image) drawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []float32, indices []uint16, colorm affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []interface{}, evenOdd bool, keepOnAtlas bool) {
|
||||
if i.disposed {
|
||||
panic("atlas: the drawing target image must not be disposed (DrawTriangles)")
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/affine"
|
||||
. "github.com/hajimehoshi/ebiten/v2/internal/atlas"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
@ -102,7 +103,7 @@ func TestEnsureIsolated(t *testing.T) {
|
||||
Width: size,
|
||||
Height: size,
|
||||
}
|
||||
img4.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
img4.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
want := false
|
||||
if got := img4.IsOnAtlasForTesting(); got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
@ -132,7 +133,7 @@ func TestEnsureIsolated(t *testing.T) {
|
||||
|
||||
// Check further drawing doesn't cause panic.
|
||||
// This bug was fixed by 03dcd948.
|
||||
img4.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
img4.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
}
|
||||
|
||||
func TestReputOnAtlas(t *testing.T) {
|
||||
@ -179,7 +180,7 @@ func TestReputOnAtlas(t *testing.T) {
|
||||
Width: size,
|
||||
Height: size,
|
||||
}
|
||||
img1.DrawTriangles([graphics.ShaderImageNum]*Image{img2}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
img1.DrawTriangles([graphics.ShaderImageNum]*Image{img2}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
if got, want := img1.IsOnAtlasForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -191,7 +192,7 @@ func TestReputOnAtlas(t *testing.T) {
|
||||
if err := PutImagesOnAtlasForTesting(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
if got, want := img1.IsOnAtlasForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -219,7 +220,7 @@ func TestReputOnAtlas(t *testing.T) {
|
||||
}
|
||||
|
||||
// img1 is on an atlas again.
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
if got, want := img1.IsOnAtlasForTesting(), true; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -243,7 +244,7 @@ func TestReputOnAtlas(t *testing.T) {
|
||||
}
|
||||
|
||||
// Use img1 as a render target again.
|
||||
img1.DrawTriangles([graphics.ShaderImageNum]*Image{img2}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
img1.DrawTriangles([graphics.ShaderImageNum]*Image{img2}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
if got, want := img1.IsOnAtlasForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -255,7 +256,7 @@ func TestReputOnAtlas(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
img1.ReplacePixels(make([]byte, 4*size*size))
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
if got, want := img1.IsOnAtlasForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -265,7 +266,7 @@ func TestReputOnAtlas(t *testing.T) {
|
||||
}
|
||||
|
||||
// img1 is not on an atlas due to ReplacePixels.
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
if got, want := img1.IsOnAtlasForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -275,7 +276,7 @@ func TestReputOnAtlas(t *testing.T) {
|
||||
if err := PutImagesOnAtlasForTesting(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
if got, want := img3.IsOnAtlasForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -375,7 +376,7 @@ func TestReplacePixelsAfterDrawTriangles(t *testing.T) {
|
||||
Width: w,
|
||||
Height: h,
|
||||
}
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
dst.ReplacePixels(pix)
|
||||
|
||||
pix, err := dst.Pixels(0, 0, w, h)
|
||||
@ -423,7 +424,7 @@ func TestSmallImages(t *testing.T) {
|
||||
Width: w,
|
||||
Height: h,
|
||||
}
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
|
||||
pix, err := dst.Pixels(0, 0, w, h)
|
||||
if err != nil {
|
||||
@ -471,7 +472,7 @@ func TestLongImages(t *testing.T) {
|
||||
Width: dstW,
|
||||
Height: dstH,
|
||||
}
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
|
||||
pix, err := dst.Pixels(0, 0, dstW, dstH)
|
||||
if err != nil {
|
||||
@ -559,7 +560,7 @@ func TestDisposedAndReputOnAtlas(t *testing.T) {
|
||||
Width: size,
|
||||
Height: size,
|
||||
}
|
||||
src.DrawTriangles([graphics.ShaderImageNum]*Image{src2}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
src.DrawTriangles([graphics.ShaderImageNum]*Image{src2}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
if got, want := src.IsOnAtlasForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -569,7 +570,7 @@ func TestDisposedAndReputOnAtlas(t *testing.T) {
|
||||
if err := PutImagesOnAtlasForTesting(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
if got, want := src.IsOnAtlasForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -609,7 +610,7 @@ func TestImageIsNotReputOnAtlasWithoutUsingAsSource(t *testing.T) {
|
||||
}
|
||||
|
||||
// Use src2 as a rendering target, and make src2 an independent image.
|
||||
src2.DrawTriangles([graphics.ShaderImageNum]*Image{src}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
src2.DrawTriangles([graphics.ShaderImageNum]*Image{src}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
if got, want := src2.IsOnAtlasForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -630,7 +631,7 @@ func TestImageIsNotReputOnAtlasWithoutUsingAsSource(t *testing.T) {
|
||||
if err := PutImagesOnAtlasForTesting(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src2}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src2}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
if got, want := src2.IsOnAtlasForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ func (i *Image) replacePendingPixels(pix []byte, x, y, width, height int) {
|
||||
// DrawTriangles draws the src image with the given vertices.
|
||||
//
|
||||
// Copying vertices and indices is the caller's responsibility.
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []interface{}, evenOdd bool) {
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []float32, indices []uint16, colorm affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []interface{}, evenOdd bool) {
|
||||
for _, src := range srcs {
|
||||
if i == src {
|
||||
panic("buffered: Image.DrawTriangles: source images must be different from the receiver")
|
||||
|
@ -58,7 +58,7 @@ type Graphics interface {
|
||||
//
|
||||
// * float32
|
||||
// * []float32
|
||||
DrawTriangles(dst ImageID, srcs [graphics.ShaderImageNum]ImageID, offsets [graphics.ShaderImageNum - 1][2]float32, shader ShaderID, indexLen int, indexOffset int, mode CompositeMode, colorM *affine.ColorM, filter Filter, address Address, dstRegion, srcRegion Region, uniforms []interface{}, evenOdd bool) error
|
||||
DrawTriangles(dst ImageID, srcs [graphics.ShaderImageNum]ImageID, offsets [graphics.ShaderImageNum - 1][2]float32, shader ShaderID, indexLen int, indexOffset int, mode CompositeMode, colorM affine.ColorM, filter Filter, address Address, dstRegion, srcRegion Region, uniforms []interface{}, evenOdd bool) error
|
||||
}
|
||||
|
||||
// GraphicsNotReady represents that the graphics driver is not ready for recovering from the context lost.
|
||||
|
@ -128,7 +128,7 @@ func (q *commandQueue) appendIndices(indices []uint16, offset uint16) {
|
||||
}
|
||||
|
||||
// EnqueueDrawTrianglesCommand enqueues a drawing-image command.
|
||||
func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageNum]*Image, offsets [graphics.ShaderImageNum - 1][2]float32, vertices []float32, indices []uint16, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, shader *Shader, uniforms []interface{}, evenOdd bool) {
|
||||
func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageNum]*Image, offsets [graphics.ShaderImageNum - 1][2]float32, vertices []float32, indices []uint16, color affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, shader *Shader, uniforms []interface{}, evenOdd bool) {
|
||||
if len(indices) > graphics.IndicesNum {
|
||||
panic(fmt.Sprintf("graphicscommand: len(indices) must be <= graphics.IndicesNum but not at EnqueueDrawTrianglesCommand: len(indices): %d, graphics.IndicesNum: %d", len(indices), graphics.IndicesNum))
|
||||
}
|
||||
@ -317,7 +317,7 @@ type drawTrianglesCommand struct {
|
||||
offsets [graphics.ShaderImageNum - 1][2]float32
|
||||
vertices []float32
|
||||
nindices int
|
||||
color *affine.ColorM
|
||||
color affine.ColorM
|
||||
mode driver.CompositeMode
|
||||
filter driver.Filter
|
||||
address driver.Address
|
||||
@ -456,7 +456,7 @@ func (c *drawTrianglesCommand) addNumIndices(n int) {
|
||||
|
||||
// CanMergeWithDrawTrianglesCommand returns a boolean value indicating whether the other drawTrianglesCommand can be merged
|
||||
// with the drawTrianglesCommand c.
|
||||
func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageNum]*Image, vertices []float32, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, shader *Shader, evenOdd bool) bool {
|
||||
func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageNum]*Image, vertices []float32, color affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, shader *Shader, evenOdd bool) bool {
|
||||
// If a shader is used, commands are not merged.
|
||||
//
|
||||
// TODO: Merge shader commands considering uniform variables.
|
||||
|
@ -139,7 +139,7 @@ func (i *Image) InternalSize() (int, int) {
|
||||
//
|
||||
// If the source image is not specified, i.e., src is nil and there is no image in the uniform variables, the
|
||||
// elements for the source image are not used.
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, offsets [graphics.ShaderImageNum - 1][2]float32, vertices []float32, indices []uint16, clr *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, shader *Shader, uniforms []interface{}, evenOdd bool) {
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, offsets [graphics.ShaderImageNum - 1][2]float32, vertices []float32, indices []uint16, clr affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, shader *Shader, uniforms []interface{}, evenOdd bool) {
|
||||
if shader == nil {
|
||||
// Fast path for rendering without a shader (#1355).
|
||||
img := srcs[0]
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"image/color"
|
||||
"testing"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/affine"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
. "github.com/hajimehoshi/ebiten/v2/internal/graphicscommand"
|
||||
@ -50,7 +51,7 @@ func TestClear(t *testing.T) {
|
||||
Width: w,
|
||||
Height: h,
|
||||
}
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, nil, driver.CompositeModeClear, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeClear, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
|
||||
pix, err := dst.Pixels()
|
||||
if err != nil {
|
||||
@ -81,8 +82,8 @@ func TestReplacePixelsPartAfterDrawTriangles(t *testing.T) {
|
||||
Width: w,
|
||||
Height: h,
|
||||
}
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{clr}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, nil, driver.CompositeModeClear, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{clr}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeClear, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
dst.ReplacePixels(make([]byte, 4), 0, 0, 1, 1)
|
||||
|
||||
// TODO: Check the result.
|
||||
@ -100,11 +101,11 @@ func TestShader(t *testing.T) {
|
||||
Width: w,
|
||||
Height: h,
|
||||
}
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{clr}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, nil, driver.CompositeModeClear, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{clr}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeClear, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
|
||||
ir := etesting.ShaderProgramFill(0xff, 0, 0, 0xff)
|
||||
s := NewShader(&ir)
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, s, nil, false)
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, s, nil, false)
|
||||
|
||||
pix, err := dst.Pixels()
|
||||
if err != nil {
|
||||
|
@ -868,7 +868,7 @@ func (g *Graphics) draw(rps mtl.RenderPipelineState, dst *Image, dstRegion drive
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderImageNum]driver.ImageID, offsets [graphics.ShaderImageNum - 1][2]float32, shaderID driver.ShaderID, indexLen int, indexOffset int, mode driver.CompositeMode, colorM *affine.ColorM, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, uniforms []interface{}, evenOdd bool) error {
|
||||
func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderImageNum]driver.ImageID, offsets [graphics.ShaderImageNum - 1][2]float32, shaderID driver.ShaderID, indexLen int, indexOffset int, mode driver.CompositeMode, colorM affine.ColorM, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, uniforms []interface{}, evenOdd bool) error {
|
||||
dst := g.images[dstID]
|
||||
|
||||
if dst.screen {
|
||||
@ -893,7 +893,7 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
|
||||
} {
|
||||
rpss[stencil] = g.rpss[rpsKey{
|
||||
screen: dst.screen,
|
||||
useColorM: colorM != nil,
|
||||
useColorM: !colorM.IsIdentity(),
|
||||
filter: filter,
|
||||
address: address,
|
||||
compositeMode: mode,
|
||||
|
@ -146,7 +146,7 @@ func (g *Graphics) SetVertices(vertices []float32, indices []uint16) {
|
||||
g.context.elementArrayBufferSubData(indices)
|
||||
}
|
||||
|
||||
func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderImageNum]driver.ImageID, offsets [graphics.ShaderImageNum - 1][2]float32, shaderID driver.ShaderID, indexLen int, indexOffset int, mode driver.CompositeMode, colorM *affine.ColorM, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, uniforms []interface{}, evenOdd bool) error {
|
||||
func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderImageNum]driver.ImageID, offsets [graphics.ShaderImageNum - 1][2]float32, shaderID driver.ShaderID, indexLen int, indexOffset int, mode driver.CompositeMode, colorM affine.ColorM, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, uniforms []interface{}, evenOdd bool) error {
|
||||
destination := g.images[dstID]
|
||||
|
||||
g.drawCalled = true
|
||||
@ -166,7 +166,7 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
|
||||
var uniformVars []uniformVariable
|
||||
if shaderID == driver.InvalidShaderID {
|
||||
program = g.state.programs[programKey{
|
||||
useColorM: colorM != nil,
|
||||
useColorM: !colorM.IsIdentity(),
|
||||
filter: filter,
|
||||
address: address,
|
||||
}]
|
||||
@ -187,7 +187,7 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
|
||||
typ: shaderir.Type{Main: shaderir.Vec4},
|
||||
})
|
||||
|
||||
if colorM != nil {
|
||||
if !colorM.IsIdentity() {
|
||||
// ColorM's elements are immutable. It's OK to hold the reference without copying.
|
||||
esBody, esTranslate := colorM.UnsafeElements()
|
||||
uniformVars = append(uniformVars, uniformVariable{
|
||||
|
@ -85,7 +85,7 @@ func (m *Mipmap) Pixels(x, y, width, height int) ([]byte, error) {
|
||||
return m.orig.Pixels(x, y, width, height)
|
||||
}
|
||||
|
||||
func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageNum]*Mipmap, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []interface{}, evenOdd bool, canSkipMipmap bool) {
|
||||
func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageNum]*Mipmap, vertices []float32, indices []uint16, colorm affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []interface{}, evenOdd bool, canSkipMipmap bool) {
|
||||
if len(indices) == 0 {
|
||||
return
|
||||
}
|
||||
@ -123,13 +123,13 @@ func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageNum]*Mipmap, vertices [
|
||||
}
|
||||
}
|
||||
|
||||
if colorm != nil && colorm.ScaleOnly() {
|
||||
if colorm.ScaleOnly() {
|
||||
body, _ := colorm.UnsafeElements()
|
||||
cr := body[0]
|
||||
cg := body[5]
|
||||
cb := body[10]
|
||||
ca := body[15]
|
||||
colorm = nil
|
||||
colorm = affine.ColorMIdentity{}
|
||||
const n = graphics.VertexFloatNum
|
||||
for i := 0; i < len(vertices)/n; i++ {
|
||||
vertices[i*n+4] *= cr
|
||||
@ -226,7 +226,7 @@ func (m *Mipmap) level(level int) *buffered.Image {
|
||||
Width: float32(w2),
|
||||
Height: float32(h2),
|
||||
}
|
||||
s.DrawTriangles([graphics.ShaderImageNum]*buffered.Image{src}, vs, is, nil, driver.CompositeModeCopy, filter, driver.AddressUnsafe, dstRegion, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
s.DrawTriangles([graphics.ShaderImageNum]*buffered.Image{src}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, filter, driver.AddressUnsafe, dstRegion, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
m.imgs[level] = s
|
||||
|
||||
return m.imgs[level]
|
||||
|
@ -68,7 +68,7 @@ type drawTrianglesHistoryItem struct {
|
||||
offsets [graphics.ShaderImageNum - 1][2]float32
|
||||
vertices []float32
|
||||
indices []uint16
|
||||
colorm *affine.ColorM
|
||||
colorm affine.ColorM
|
||||
mode driver.CompositeMode
|
||||
filter driver.Filter
|
||||
address driver.Address
|
||||
@ -187,7 +187,7 @@ func (i *Image) Extend(width, height int) *Image {
|
||||
Width: float32(sw),
|
||||
Height: float32(sh),
|
||||
}
|
||||
newImg.DrawTriangles(srcs, offsets, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
newImg.DrawTriangles(srcs, offsets, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
|
||||
// Overwrite the history as if the image newImg is created only by ReplacePixels. Now drawTrianglesHistory
|
||||
// and basePixels cannot be mixed.
|
||||
@ -248,7 +248,7 @@ func clearImage(i *graphicscommand.Image) {
|
||||
Width: float32(dw),
|
||||
Height: float32(dh),
|
||||
}
|
||||
i.DrawTriangles(srcs, offsets, vs, is, nil, driver.CompositeModeClear, driver.FilterNearest, driver.AddressUnsafe, dstRegion, driver.Region{}, nil, nil, false)
|
||||
i.DrawTriangles(srcs, offsets, vs, is, affine.ColorMIdentity{}, driver.CompositeModeClear, driver.FilterNearest, driver.AddressUnsafe, dstRegion, driver.Region{}, nil, nil, false)
|
||||
}
|
||||
|
||||
// BasePixelsForTesting returns the image's basePixels for testing.
|
||||
@ -351,7 +351,7 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
|
||||
// 5: Color G
|
||||
// 6: Color B
|
||||
// 7: Color Y
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, offsets [graphics.ShaderImageNum - 1][2]float32, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, shader *Shader, uniforms []interface{}, evenOdd bool) {
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, offsets [graphics.ShaderImageNum - 1][2]float32, vertices []float32, indices []uint16, colorm affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, shader *Shader, uniforms []interface{}, evenOdd bool) {
|
||||
if i.priority {
|
||||
panic("restorable: DrawTriangles cannot be called on a priority image")
|
||||
}
|
||||
@ -396,7 +396,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, offsets [gra
|
||||
}
|
||||
|
||||
// appendDrawTrianglesHistory appends a draw-image history item to the image.
|
||||
func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderImageNum]*Image, offsets [graphics.ShaderImageNum - 1][2]float32, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, shader *Shader, uniforms []interface{}, evenOdd bool) {
|
||||
func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderImageNum]*Image, offsets [graphics.ShaderImageNum - 1][2]float32, vertices []float32, indices []uint16, colorm affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, shader *Shader, uniforms []interface{}, evenOdd bool) {
|
||||
if i.stale || i.volatile || i.screen {
|
||||
return
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"image/color"
|
||||
"testing"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/affine"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
. "github.com/hajimehoshi/ebiten/v2/internal/restorable"
|
||||
@ -137,7 +138,7 @@ func TestRestoreChain(t *testing.T) {
|
||||
Width: 1,
|
||||
Height: 1,
|
||||
}
|
||||
imgs[i+1].DrawTriangles([graphics.ShaderImageNum]*Image{imgs[i]}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
imgs[i+1].DrawTriangles([graphics.ShaderImageNum]*Image{imgs[i]}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
}
|
||||
if err := ResolveStaleImages(); err != nil {
|
||||
t.Fatal(err)
|
||||
@ -185,10 +186,10 @@ func TestRestoreChain2(t *testing.T) {
|
||||
Width: w,
|
||||
Height: h,
|
||||
}
|
||||
imgs[8].DrawTriangles([graphics.ShaderImageNum]*Image{imgs[7]}, [graphics.ShaderImageNum - 1][2]float32{}, quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
imgs[9].DrawTriangles([graphics.ShaderImageNum]*Image{imgs[8]}, [graphics.ShaderImageNum - 1][2]float32{}, quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
imgs[8].DrawTriangles([graphics.ShaderImageNum]*Image{imgs[7]}, [graphics.ShaderImageNum - 1][2]float32{}, quadVertices(w, h, 0, 0), is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
imgs[9].DrawTriangles([graphics.ShaderImageNum]*Image{imgs[8]}, [graphics.ShaderImageNum - 1][2]float32{}, quadVertices(w, h, 0, 0), is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
for i := 0; i < 7; i++ {
|
||||
imgs[i+1].DrawTriangles([graphics.ShaderImageNum]*Image{imgs[i]}, [graphics.ShaderImageNum - 1][2]float32{}, quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
imgs[i+1].DrawTriangles([graphics.ShaderImageNum]*Image{imgs[i]}, [graphics.ShaderImageNum - 1][2]float32{}, quadVertices(w, h, 0, 0), is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
}
|
||||
|
||||
if err := ResolveStaleImages(); err != nil {
|
||||
@ -234,10 +235,10 @@ func TestRestoreOverrideSource(t *testing.T) {
|
||||
Width: w,
|
||||
Height: h,
|
||||
}
|
||||
img2.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, [graphics.ShaderImageNum - 1][2]float32{}, quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img3.DrawTriangles([graphics.ShaderImageNum]*Image{img2}, [graphics.ShaderImageNum - 1][2]float32{}, quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img2.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, [graphics.ShaderImageNum - 1][2]float32{}, quadVertices(w, h, 0, 0), is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img3.DrawTriangles([graphics.ShaderImageNum]*Image{img2}, [graphics.ShaderImageNum - 1][2]float32{}, quadVertices(w, h, 0, 0), is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img0.ReplacePixels([]byte{clr1.R, clr1.G, clr1.B, clr1.A}, 0, 0, w, h)
|
||||
img1.DrawTriangles([graphics.ShaderImageNum]*Image{img0}, [graphics.ShaderImageNum - 1][2]float32{}, quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img1.DrawTriangles([graphics.ShaderImageNum]*Image{img0}, [graphics.ShaderImageNum - 1][2]float32{}, quadVertices(w, h, 0, 0), is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
if err := ResolveStaleImages(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -323,23 +324,23 @@ func TestRestoreComplexGraph(t *testing.T) {
|
||||
Height: h,
|
||||
}
|
||||
var offsets [graphics.ShaderImageNum - 1][2]float32
|
||||
img3.DrawTriangles([graphics.ShaderImageNum]*Image{img0}, offsets, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img3.DrawTriangles([graphics.ShaderImageNum]*Image{img0}, offsets, vs, is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
vs = quadVertices(w, h, 1, 0)
|
||||
img3.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, offsets, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img3.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, offsets, vs, is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
vs = quadVertices(w, h, 1, 0)
|
||||
img4.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, offsets, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img4.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, offsets, vs, is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
vs = quadVertices(w, h, 2, 0)
|
||||
img4.DrawTriangles([graphics.ShaderImageNum]*Image{img2}, offsets, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img4.DrawTriangles([graphics.ShaderImageNum]*Image{img2}, offsets, vs, is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
vs = quadVertices(w, h, 0, 0)
|
||||
img5.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, offsets, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img5.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, offsets, vs, is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
vs = quadVertices(w, h, 0, 0)
|
||||
img6.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, offsets, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img6.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, offsets, vs, is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
vs = quadVertices(w, h, 1, 0)
|
||||
img6.DrawTriangles([graphics.ShaderImageNum]*Image{img4}, offsets, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img6.DrawTriangles([graphics.ShaderImageNum]*Image{img4}, offsets, vs, is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
vs = quadVertices(w, h, 0, 0)
|
||||
img7.DrawTriangles([graphics.ShaderImageNum]*Image{img2}, offsets, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img7.DrawTriangles([graphics.ShaderImageNum]*Image{img2}, offsets, vs, is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
vs = quadVertices(w, h, 2, 0)
|
||||
img7.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, offsets, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img7.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, offsets, vs, is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
if err := ResolveStaleImages(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -437,8 +438,8 @@ func TestRestoreRecursive(t *testing.T) {
|
||||
Width: w,
|
||||
Height: h,
|
||||
}
|
||||
img1.DrawTriangles([graphics.ShaderImageNum]*Image{img0}, [graphics.ShaderImageNum - 1][2]float32{}, quadVertices(w, h, 1, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, [graphics.ShaderImageNum - 1][2]float32{}, quadVertices(w, h, 1, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img1.DrawTriangles([graphics.ShaderImageNum]*Image{img0}, [graphics.ShaderImageNum - 1][2]float32{}, quadVertices(w, h, 1, 0), is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, [graphics.ShaderImageNum - 1][2]float32{}, quadVertices(w, h, 1, 0), is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
if err := ResolveStaleImages(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -538,7 +539,7 @@ func TestDrawTrianglesAndReplacePixels(t *testing.T) {
|
||||
Width: 2,
|
||||
Height: 1,
|
||||
}
|
||||
img1.DrawTriangles([graphics.ShaderImageNum]*Image{img0}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img1.DrawTriangles([graphics.ShaderImageNum]*Image{img0}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img1.ReplacePixels([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 0, 0, 2, 1)
|
||||
|
||||
if err := ResolveStaleImages(); err != nil {
|
||||
@ -581,8 +582,8 @@ func TestDispose(t *testing.T) {
|
||||
Width: 1,
|
||||
Height: 1,
|
||||
}
|
||||
img1.DrawTriangles([graphics.ShaderImageNum]*Image{img2}, [graphics.ShaderImageNum - 1][2]float32{}, quadVertices(1, 1, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, [graphics.ShaderImageNum - 1][2]float32{}, quadVertices(1, 1, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img1.DrawTriangles([graphics.ShaderImageNum]*Image{img2}, [graphics.ShaderImageNum - 1][2]float32{}, quadVertices(1, 1, 0, 0), is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, [graphics.ShaderImageNum - 1][2]float32{}, quadVertices(1, 1, 0, 0), is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img1.Dispose()
|
||||
|
||||
if err := ResolveStaleImages(); err != nil {
|
||||
@ -696,7 +697,7 @@ func TestReplacePixelsOnly(t *testing.T) {
|
||||
Width: 1,
|
||||
Height: 1,
|
||||
}
|
||||
img1.DrawTriangles([graphics.ShaderImageNum]*Image{img0}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img1.DrawTriangles([graphics.ShaderImageNum]*Image{img0}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img0.ReplacePixels([]byte{5, 6, 7, 8}, 0, 0, 1, 1)
|
||||
|
||||
// BasePixelsForTesting is available without GPU accessing.
|
||||
@ -756,7 +757,7 @@ func TestReadPixelsFromVolatileImage(t *testing.T) {
|
||||
Width: w,
|
||||
Height: h,
|
||||
}
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
|
||||
// Read the pixels. If the implementation is correct, dst tries to read its pixels from GPU due to being
|
||||
// stale.
|
||||
@ -783,7 +784,7 @@ func TestAllowReplacePixelsAfterDrawTriangles(t *testing.T) {
|
||||
Width: w,
|
||||
Height: h,
|
||||
}
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
dst.ReplacePixels(make([]byte, 4*w*h), 0, 0, w, h)
|
||||
// ReplacePixels for a whole image doesn't panic.
|
||||
}
|
||||
@ -807,7 +808,7 @@ func TestDisallowReplacePixelsForPartAfterDrawTriangles(t *testing.T) {
|
||||
Width: w,
|
||||
Height: h,
|
||||
}
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
dst.ReplacePixels(make([]byte, 4), 0, 0, 1, 1)
|
||||
}
|
||||
|
||||
@ -884,7 +885,7 @@ func TestMutateSlices(t *testing.T) {
|
||||
Width: w,
|
||||
Height: h,
|
||||
}
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
for i := range vs {
|
||||
vs[i] = 0
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"image/color"
|
||||
"testing"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/affine"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
. "github.com/hajimehoshi/ebiten/v2/internal/restorable"
|
||||
@ -48,7 +49,7 @@ func clearImage(img *Image, w, h int) {
|
||||
Width: float32(w),
|
||||
Height: float32(h),
|
||||
}
|
||||
img.DrawTriangles([graphics.ShaderImageNum]*Image{emptyImage}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, nil, driver.CompositeModeClear, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
img.DrawTriangles([graphics.ShaderImageNum]*Image{emptyImage}, [graphics.ShaderImageNum - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, driver.CompositeModeClear, driver.FilterNearest, driver.AddressUnsafe, dr, driver.Region{}, nil, nil, false)
|
||||
}
|
||||
|
||||
func TestShader(t *testing.T) {
|
||||
|
Loading…
Reference in New Issue
Block a user