mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
parent
938d78122f
commit
b2f6cc5791
188
image.go
188
image.go
@ -312,36 +312,11 @@ type DrawTrianglesOptions struct {
|
|||||||
|
|
||||||
// Filter is a type of texture filter.
|
// Filter is a type of texture filter.
|
||||||
// The default (zero) value is FilterDefault.
|
// The default (zero) value is FilterDefault.
|
||||||
//
|
|
||||||
// If Shader is not nil, Filter is ignored.
|
|
||||||
Filter Filter
|
Filter Filter
|
||||||
|
|
||||||
// Address is a sampler address mode.
|
// Address is a sampler address mode.
|
||||||
// The default (zero) value is AddressClampToZero.
|
// The default (zero) value is AddressClampToZero.
|
||||||
//
|
|
||||||
// If Shader is not nil, Address is ignored.
|
|
||||||
Address Address
|
Address Address
|
||||||
|
|
||||||
// Shader is a shader.
|
|
||||||
Shader *Shader
|
|
||||||
|
|
||||||
// Uniforms is a set of uniform variables for the shader.
|
|
||||||
//
|
|
||||||
// Uniforms is used only when Shader is not nil.
|
|
||||||
Uniforms map[string]interface{}
|
|
||||||
|
|
||||||
// Images is a set of the additional source images.
|
|
||||||
// All the image must be the same size as the img argument at DrawTriangles.
|
|
||||||
//
|
|
||||||
// Images is used only when Shader is not nil.
|
|
||||||
Images [3]*Image
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
var op DrawTrianglesOptions
|
|
||||||
if got, want := len(op.Images), graphics.ShaderImageNum-1; got != want {
|
|
||||||
panic(fmt.Sprintf("ebiten: len((DrawTrianglesOptions{}).Images) must be %d but %d", want, got))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MaxIndicesNum is the maximum number of indices for DrawTriangles.
|
// MaxIndicesNum is the maximum number of indices for DrawTriangles.
|
||||||
@ -357,11 +332,7 @@ const MaxIndicesNum = graphics.IndicesNum
|
|||||||
//
|
//
|
||||||
// When the given image is disposed, DrawTriangles panics.
|
// When the given image is disposed, DrawTriangles panics.
|
||||||
//
|
//
|
||||||
// The given image can be nil only when a shader is specified at the given options.
|
|
||||||
//
|
|
||||||
// When the image i is disposed, DrawTriangles does nothing.
|
// When the image i is disposed, DrawTriangles does nothing.
|
||||||
//
|
|
||||||
// img can be nil only when options.Shader is not nil.
|
|
||||||
func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, options *DrawTrianglesOptions) {
|
func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, options *DrawTrianglesOptions) {
|
||||||
i.copyCheck()
|
i.copyCheck()
|
||||||
|
|
||||||
@ -390,14 +361,24 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
|
|||||||
|
|
||||||
mode := driver.CompositeMode(options.CompositeMode)
|
mode := driver.CompositeMode(options.CompositeMode)
|
||||||
|
|
||||||
|
address := driver.Address(options.Address)
|
||||||
|
var sr driver.Region
|
||||||
|
if address != driver.AddressUnsafe {
|
||||||
|
b := img.Bounds()
|
||||||
|
sr = driver.Region{
|
||||||
|
X: float32(b.Min.X),
|
||||||
|
Y: float32(b.Min.Y),
|
||||||
|
Width: float32(b.Dx()),
|
||||||
|
Height: float32(b.Dy()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
filter := driver.FilterNearest
|
filter := driver.FilterNearest
|
||||||
if options.Shader == nil {
|
|
||||||
if options.Filter != FilterDefault {
|
if options.Filter != FilterDefault {
|
||||||
filter = driver.Filter(options.Filter)
|
filter = driver.Filter(options.Filter)
|
||||||
} else if img.filter != FilterDefault {
|
} else if img.filter != FilterDefault {
|
||||||
filter = driver.Filter(img.filter)
|
filter = driver.Filter(img.filter)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
vs := make([]float32, len(vertices)*graphics.VertexFloatNum)
|
vs := make([]float32, len(vertices)*graphics.VertexFloatNum)
|
||||||
for i, v := range vertices {
|
for i, v := range vertices {
|
||||||
@ -413,15 +394,114 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
|
|||||||
is := make([]uint16, len(indices))
|
is := make([]uint16, len(indices))
|
||||||
copy(is, indices)
|
copy(is, indices)
|
||||||
|
|
||||||
var sr driver.Region
|
srcs := [graphics.ShaderImageNum]*mipmap.Mipmap{img.mipmap}
|
||||||
var b image.Rectangle
|
|
||||||
if img != nil {
|
i.mipmap.DrawTriangles(srcs, vs, is, options.ColorM.impl, mode, filter, address, sr, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||||
b = img.Bounds()
|
}
|
||||||
|
|
||||||
|
// DrawTrianglesShaderOptions represents options for DrawTrianglesShader
|
||||||
|
//
|
||||||
|
// This API is experimental.
|
||||||
|
type DrawTrianglesShaderOptions struct {
|
||||||
|
// CompositeMode is a composite mode to draw.
|
||||||
|
// The default (zero) value is regular alpha blending.
|
||||||
|
CompositeMode CompositeMode
|
||||||
|
|
||||||
|
// Uniforms is a set of uniform variables for the shader.
|
||||||
|
Uniforms map[string]interface{}
|
||||||
|
|
||||||
|
// Images is a set of the source images.
|
||||||
|
// All the image must be the same size.
|
||||||
|
Images [4]*Image
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var op DrawTrianglesShaderOptions
|
||||||
|
if got, want := len(op.Images), graphics.ShaderImageNum; got != want {
|
||||||
|
panic(fmt.Sprintf("ebiten: len((DrawTrianglesShaderOptions{}).Images) must be %d but %d", want, got))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DrawTrianglesShader draws triangles with the specified vertices and their indices with the specified shader.
|
||||||
|
//
|
||||||
|
// If len(indices) is not multiple of 3, DrawTrianglesShader panics.
|
||||||
|
//
|
||||||
|
// If len(indices) is more than MaxIndicesNum, DrawTrianglesShader panics.
|
||||||
|
//
|
||||||
|
// When a specified image is non-nil and is disposed, DrawTrianglesShader panics.
|
||||||
|
//
|
||||||
|
// When the image i is disposed, DrawTrianglesShader does nothing.
|
||||||
|
//
|
||||||
|
// This API is experimental.
|
||||||
|
func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader *Shader, options *DrawTrianglesShaderOptions) {
|
||||||
|
i.copyCheck()
|
||||||
|
|
||||||
|
if i.isDisposed() {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass the source region only when the shader is used, since this affects the condition of merging graphics
|
if i.isSubImage() {
|
||||||
// commands (#1293).
|
panic("ebiten: render to a sub-image is not implemented (DrawTrianglesShader)")
|
||||||
if options.Shader != nil || options.Address != AddressUnsafe {
|
}
|
||||||
|
|
||||||
|
if len(indices)%3 != 0 {
|
||||||
|
panic("ebiten: len(indices) % 3 must be 0")
|
||||||
|
}
|
||||||
|
if len(indices) > MaxIndicesNum {
|
||||||
|
panic("ebiten: len(indices) must be <= MaxIndicesNum")
|
||||||
|
}
|
||||||
|
// TODO: Check the maximum value of indices and len(vertices)?
|
||||||
|
|
||||||
|
if options == nil {
|
||||||
|
options = &DrawTrianglesShaderOptions{}
|
||||||
|
}
|
||||||
|
|
||||||
|
mode := driver.CompositeMode(options.CompositeMode)
|
||||||
|
|
||||||
|
vs := make([]float32, len(vertices)*graphics.VertexFloatNum)
|
||||||
|
for i, v := range vertices {
|
||||||
|
vs[i*graphics.VertexFloatNum] = v.DstX
|
||||||
|
vs[i*graphics.VertexFloatNum+1] = v.DstY
|
||||||
|
vs[i*graphics.VertexFloatNum+2] = v.SrcX
|
||||||
|
vs[i*graphics.VertexFloatNum+3] = v.SrcY
|
||||||
|
vs[i*graphics.VertexFloatNum+4] = v.ColorR
|
||||||
|
vs[i*graphics.VertexFloatNum+5] = v.ColorG
|
||||||
|
vs[i*graphics.VertexFloatNum+6] = v.ColorB
|
||||||
|
vs[i*graphics.VertexFloatNum+7] = v.ColorA
|
||||||
|
}
|
||||||
|
is := make([]uint16, len(indices))
|
||||||
|
copy(is, indices)
|
||||||
|
|
||||||
|
var imgs [graphics.ShaderImageNum]*mipmap.Mipmap
|
||||||
|
var imgw, imgh int
|
||||||
|
for i, img := range options.Images {
|
||||||
|
if img == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if img.isDisposed() {
|
||||||
|
panic("ebiten: the given image to DrawRectShader must not be disposed")
|
||||||
|
}
|
||||||
|
if i == 0 {
|
||||||
|
imgw, imgh = img.Size()
|
||||||
|
} else {
|
||||||
|
// TODO: Check imgw > 0 && imgh > 0
|
||||||
|
if w, h := img.Size(); imgw != w || imgh != h {
|
||||||
|
panic("ebiten: all the source images must be the same size with the rectangle")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
imgs[i] = img.mipmap
|
||||||
|
}
|
||||||
|
|
||||||
|
var sx, sy float32
|
||||||
|
if options.Images[0] != nil {
|
||||||
|
b := options.Images[0].Bounds()
|
||||||
|
sx = float32(b.Min.X)
|
||||||
|
sy = float32(b.Min.Y)
|
||||||
|
}
|
||||||
|
|
||||||
|
var sr driver.Region
|
||||||
|
if img := options.Images[0]; img != nil {
|
||||||
|
b := img.Bounds()
|
||||||
sr = driver.Region{
|
sr = driver.Region{
|
||||||
X: float32(b.Min.X),
|
X: float32(b.Min.X),
|
||||||
Y: float32(b.Min.Y),
|
Y: float32(b.Min.Y),
|
||||||
@ -430,42 +510,18 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var srcs [graphics.ShaderImageNum]*mipmap.Mipmap
|
|
||||||
|
|
||||||
var imgw, imgh int
|
|
||||||
var sx, sy float32
|
|
||||||
if img != nil {
|
|
||||||
srcs[0] = img.mipmap
|
|
||||||
imgw, imgh = img.Size()
|
|
||||||
sx = float32(b.Min.X)
|
|
||||||
sy = float32(b.Min.Y)
|
|
||||||
}
|
|
||||||
|
|
||||||
var offsets [graphics.ShaderImageNum - 1][2]float32
|
var offsets [graphics.ShaderImageNum - 1][2]float32
|
||||||
for i, img := range options.Images {
|
for i, img := range options.Images[1:] {
|
||||||
if img == nil {
|
if img == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if img.isDisposed() {
|
|
||||||
panic("ebiten: the given image to DrawTriangles must not be disposed")
|
|
||||||
}
|
|
||||||
if w, h := img.Size(); imgw != w || imgh != h {
|
|
||||||
panic("ebiten: all the source images must be the same size")
|
|
||||||
}
|
|
||||||
srcs[i+1] = img.mipmap
|
|
||||||
|
|
||||||
b := img.Bounds()
|
b := img.Bounds()
|
||||||
offsets[i][0] = -sx + float32(b.Min.X)
|
offsets[i][0] = -sx + float32(b.Min.X)
|
||||||
offsets[i][1] = -sy + float32(b.Min.Y)
|
offsets[i][1] = -sy + float32(b.Min.Y)
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.Shader == nil {
|
us := shader.convertUniforms(options.Uniforms)
|
||||||
i.mipmap.DrawTriangles(srcs, vs, is, options.ColorM.impl, mode, filter, driver.Address(options.Address), sr, offsets, nil, nil, false)
|
i.mipmap.DrawTriangles(imgs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, sr, offsets, shader.shader, us, false)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
us := options.Shader.convertUniforms(options.Uniforms)
|
|
||||||
i.mipmap.DrawTriangles(srcs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, sr, offsets, options.Shader.shader, us, false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DrawRectShaderOptions represents options for DrawRectShader
|
// DrawRectShaderOptions represents options for DrawRectShader
|
||||||
@ -534,7 +590,7 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR
|
|||||||
imgs[i] = img.mipmap
|
imgs[i] = img.mipmap
|
||||||
}
|
}
|
||||||
|
|
||||||
sx, sy := float32(0), float32(0)
|
var sx, sy float32
|
||||||
if options.Images[0] != nil {
|
if options.Images[0] != nil {
|
||||||
b := options.Images[0].Bounds()
|
b := options.Images[0].Bounds()
|
||||||
sx = float32(b.Min.X)
|
sx = float32(b.Min.X)
|
||||||
|
@ -100,8 +100,9 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
src, _ := NewImage(w/2, h/2, FilterDefault)
|
src, _ := NewImage(w/2, h/2, FilterDefault)
|
||||||
op := &DrawTrianglesOptions{}
|
op := &DrawTrianglesShaderOptions{}
|
||||||
op.Shader = s
|
op.Images[0] = src
|
||||||
|
|
||||||
vs := []Vertex{
|
vs := []Vertex{
|
||||||
{
|
{
|
||||||
DstX: 0,
|
DstX: 0,
|
||||||
@ -145,7 +146,8 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
is := []uint16{0, 1, 2, 1, 2, 3}
|
is := []uint16{0, 1, 2, 1, 2, 3}
|
||||||
dst.DrawTriangles(vs, is, src, op)
|
|
||||||
|
dst.DrawTrianglesShader(vs, is, s, op)
|
||||||
|
|
||||||
for j := 0; j < h; j++ {
|
for j := 0; j < h; j++ {
|
||||||
for i := 0; i < w; i++ {
|
for i := 0; i < w; i++ {
|
||||||
@ -869,7 +871,7 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
|
|||||||
testPixels("DrawRectShader", dst)
|
testPixels("DrawRectShader", dst)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("DrawTriangles", func(t *testing.T) {
|
t.Run("DrawTrianglesShader", func(t *testing.T) {
|
||||||
dst, _ := NewImage(w, h, FilterDefault)
|
dst, _ := NewImage(w, h, FilterDefault)
|
||||||
vs := []Vertex{
|
vs := []Vertex{
|
||||||
{
|
{
|
||||||
@ -915,10 +917,10 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
|
|||||||
}
|
}
|
||||||
is := []uint16{0, 1, 2, 1, 2, 3}
|
is := []uint16{0, 1, 2, 1, 2, 3}
|
||||||
|
|
||||||
op := &DrawTrianglesOptions{}
|
op := &DrawTrianglesShaderOptions{}
|
||||||
op.Shader = s
|
op.Images[0] = src0
|
||||||
op.Images[0] = src1
|
op.Images[1] = src1
|
||||||
dst.DrawTriangles(vs, is, src0, op)
|
dst.DrawTrianglesShader(vs, is, s, op)
|
||||||
testPixels("DrawTriangles", dst)
|
testPixels("DrawTrianglesShader", dst)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user