ebiten: Add DrawRectangleWithShader

Updates #1168
This commit is contained in:
Hajime Hoshi 2020-07-20 22:19:28 +09:00
parent 76534fcf5f
commit c567a7b507
2 changed files with 96 additions and 67 deletions

View File

@ -104,64 +104,17 @@ func (g *Game) Draw(screen *ebiten.Image) {
return return
} }
sw, sh := gopherImage.Size()
w, h := screen.Size() w, h := screen.Size()
vs := []ebiten.Vertex{
{
DstX: 0,
DstY: 0,
SrcX: 0,
SrcY: 0,
ColorR: 1,
ColorG: 1,
ColorB: 1,
ColorA: 1,
},
{
DstX: float32(w),
DstY: 0,
SrcX: float32(sw),
SrcY: 0,
ColorR: 1,
ColorG: 1,
ColorB: 1,
ColorA: 1,
},
{
DstX: 0,
DstY: float32(h),
SrcX: 0,
SrcY: float32(sh),
ColorR: 1,
ColorG: 1,
ColorB: 1,
ColorA: 1,
},
{
DstX: float32(w),
DstY: float32(h),
SrcX: float32(sw),
SrcY: float32(sh),
ColorR: 1,
ColorG: 1,
ColorB: 1,
ColorA: 1,
},
}
is := []uint16{0, 1, 2, 1, 2, 3}
cx, cy := ebiten.CursorPosition() cx, cy := ebiten.CursorPosition()
op := &ebiten.DrawTrianglesWithShaderOptions{} op := &ebiten.DrawRectangleWithShaderOptions{}
op.Uniforms = []interface{}{ op.Uniforms = []interface{}{
float32(g.time) / 60, // Time float32(g.time) / 60, // Time
[]float32{float32(cx), float32(cy)}, // Cursor []float32{float32(cx), float32(cy)}, // Cursor
} }
if g.idx != 0 {
op.Images[0] = gopherImage op.Images[0] = gopherImage
op.Images[1] = normalImage op.Images[1] = normalImage
} screen.DrawRectangleWithShader(w, h, s, op)
screen.DrawTrianglesWithShader(vs, is, s, op)
msg := "Press Up/Down to switch the shader." msg := "Press Up/Down to switch the shader."
ebitenutil.DebugPrint(screen, msg) ebitenutil.DebugPrint(screen, msg)

108
image.go
View File

@ -142,7 +142,7 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) error {
// TODO: Implement this. // TODO: Implement this.
if i.isSubImage() { if i.isSubImage() {
panic("ebiten: render to a subimage is not implemented (drawImage)") panic("ebiten: render to a subimage is not implemented (DrawImage)")
} }
// Calculate vertices before locking because the user can do anything in // Calculate vertices before locking because the user can do anything in
@ -188,7 +188,6 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) error {
} }
} }
geom := &options.GeoM
mode := driver.CompositeMode(options.CompositeMode) mode := driver.CompositeMode(options.CompositeMode)
filter := driver.FilterNearest filter := driver.FilterNearest
@ -198,7 +197,7 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) error {
filter = driver.Filter(img.filter) filter = driver.Filter(img.filter)
} }
a, b, c, d, tx, ty := geom.elements32() a, b, c, d, tx, ty := options.GeoM.elements32()
sx0 := float32(bounds.Min.X) sx0 := float32(bounds.Min.X)
sy0 := float32(bounds.Min.Y) sy0 := float32(bounds.Min.Y)
@ -245,7 +244,7 @@ const (
AddressUnsafe Address = Address(driver.AddressUnsafe) AddressUnsafe Address = Address(driver.AddressUnsafe)
) )
// DrawTrianglesOptions represents options to render triangles on an image. // DrawTrianglesOptions represents options for DrawTriangles.
type DrawTrianglesOptions struct { type DrawTrianglesOptions struct {
// ColorM is a color matrix to draw. // ColorM is a color matrix to draw.
// The default (zero) value is identity, which doesn't change any color. // The default (zero) value is identity, which doesn't change any color.
@ -276,6 +275,8 @@ const MaxIndicesNum = graphics.IndicesNum
// //
// The rule in which DrawTriangles works effectively is same as DrawImage's. // The rule in which DrawTriangles works effectively is same as DrawImage's.
// //
// When the given image is disposed, DrawTriangles panics.
//
// When the image i is disposed, DrawTriangles does nothing. // When the image i is disposed, DrawTriangles does nothing.
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()
@ -340,20 +341,93 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
i.buffered.DrawTriangles([graphics.ShaderImageNum]*buffered.Image{img.buffered}, vs, is, options.ColorM.impl, mode, filter, driver.Address(options.Address), sr, nil, nil) i.buffered.DrawTriangles([graphics.ShaderImageNum]*buffered.Image{img.buffered}, vs, is, options.ColorM.impl, mode, filter, driver.Address(options.Address), sr, nil, nil)
} }
// DrawTrianglesOptionsWithShaderOptions represents options to render triangles on an image with a shader. // DrawRectangleOptionsWithShaderOptions represents options for DrawRectangleOptionsWithShader
// //
// Note that this API is experimental. // This API is experimental.
type DrawRectangleWithShaderOptions struct {
// GeoM is a geometry matrix to draw.
// The default (zero) value is identify, which draws the rectangle at (0, 0).
GeoM GeoM
// 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 []interface{}
// Images is a set of the source images.
// All the image must be the same size with the rectangle.
Images [4]*Image
}
func init() {
var op DrawRectangleWithShaderOptions
if got, want := len(op.Images), graphics.ShaderImageNum; got != want {
panic(fmt.Sprintf("ebiten: len((DrawRectangleWithShaderOptions{}).Images) must be %d but %d", want, got))
}
}
// DrawRectangleWithShader draws a rectangle with the specified width and height with the specified shader.
//
// When one of the specified image is non-nil and is disposed, DrawRectangleWithShader panics.
//
// When the image i is disposed, DrawRectangleWithShader does nothing.
//
// This API is experimental.
func (i *Image) DrawRectangleWithShader(width, height int, shader *Shader, options *DrawRectangleWithShaderOptions) {
i.copyCheck()
if i.isDisposed() {
return
}
// TODO: Implement this.
if i.isSubImage() {
panic("ebiten: render to a subimage is not implemented (DrawRectangleWithShader)")
}
if options == nil {
options = &DrawRectangleWithShaderOptions{}
}
mode := driver.CompositeMode(options.CompositeMode)
var imgs [graphics.ShaderImageNum]*buffered.Image
for i, img := range options.Images {
if img == nil {
continue
}
if img.isDisposed() {
panic("ebiten: the given image to DrawRectangleWithShader must not be disposed")
}
if w, h := img.Size(); width != w || height != h {
panic("ebiten: all the source images must be the same size with the rectangle")
}
imgs[i] = img.buffered
}
a, b, c, d, tx, ty := options.GeoM.elements32()
vs := graphics.QuadVertices(0, 0, float32(width), float32(height), a, b, c, d, tx, ty, 1, 1, 1, 1, false)
is := graphics.QuadIndices()
i.buffered.DrawTriangles(imgs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, shader.shader, options.Uniforms)
}
// DrawTrianglesOptionsWithShaderOptions represents options for DrawTrianglesOptionsWithShader
//
// This API is experimental.
type DrawTrianglesWithShaderOptions struct { type DrawTrianglesWithShaderOptions struct {
// Uniforms is a set of uniform variables for a shader. // 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 []interface{} Uniforms []interface{}
// Images is a set of the source images. // Images is a set of the source images.
// All the image must be the same size. // All the image must be the same size.
Images [4]*Image Images [4]*Image
// CompositeMode is a composite mode to draw.
// The default (zero) value is regular alpha blending.
CompositeMode CompositeMode
} }
func init() { func init() {
@ -371,7 +445,9 @@ func init() {
// //
// When a specified image is non-nil and is disposed, DrawTrianglesWithShader panics. // When a specified image is non-nil and is disposed, DrawTrianglesWithShader panics.
// //
// Note that this API is experimental. // When the image i is disposed, DrawTrianglesWithShader does nothing.
//
// This API is experimental.
func (i *Image) DrawTrianglesWithShader(vertices []Vertex, indices []uint16, shader *Shader, options *DrawTrianglesWithShaderOptions) { func (i *Image) DrawTrianglesWithShader(vertices []Vertex, indices []uint16, shader *Shader, options *DrawTrianglesWithShaderOptions) {
i.copyCheck() i.copyCheck()
@ -380,7 +456,7 @@ func (i *Image) DrawTrianglesWithShader(vertices []Vertex, indices []uint16, sha
} }
if i.isSubImage() { if i.isSubImage() {
panic("ebiten: render to a subimage is not implemented (DrawTriangles)") panic("ebiten: render to a subimage is not implemented (DrawTrianglesWithShader)")
} }
if len(indices)%3 != 0 { if len(indices)%3 != 0 {
@ -403,7 +479,7 @@ func (i *Image) DrawTrianglesWithShader(vertices []Vertex, indices []uint16, sha
continue continue
} }
if img.isDisposed() { if img.isDisposed() {
panic("ebiten: the given image to DrawTriangles must not be disposed") panic("ebiten: the given image to DrawTrianglesWithShader must not be disposed")
} }
if imgw == 0 || imgh == 0 { if imgw == 0 || imgh == 0 {
imgw, imgh = img.Size() imgw, imgh = img.Size()
@ -486,7 +562,7 @@ func (i *Image) ColorModel() color.Model {
// //
// At always returns a transparent color if the image is disposed. // At always returns a transparent color if the image is disposed.
// //
// Note that important logic should not rely on values returned by At, since // Note that an important logic should not rely on values returned by At, since
// the returned values can include very slight differences between some machines. // the returned values can include very slight differences between some machines.
// //
// At can't be called outside the main loop (ebiten.Run's updating function) starts (as of version 1.4.0). // At can't be called outside the main loop (ebiten.Run's updating function) starts (as of version 1.4.0).
@ -583,7 +659,7 @@ func (i *Image) ReplacePixels(pixels []byte) error {
return nil return nil
} }
// A DrawImageOptions represents options to render an image on an image. // DrawImageOptions represents options for DrawImage.
type DrawImageOptions struct { type DrawImageOptions struct {
// GeoM is a geometry matrix to draw. // GeoM is a geometry matrix to draw.
// The default (zero) value is identify, which draws the image at (0, 0). // The default (zero) value is identify, which draws the image at (0, 0).