func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, options *DrawTrianglesOptions) {
	i.copyCheck()
	if i.isDisposed() {
		return
	}

	if i.isSubImage() {
		panic("ebiten: render to a subimage is not implemented (DrawTriangles)")
	}

	img.resolvePendingPixels(true)
	i.resolvePendingPixels(true)

	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 = &DrawTrianglesOptions{}
	}

	mode := graphics.CompositeMode(options.CompositeMode)

	filter := graphics.FilterNearest
	if options.Filter != FilterDefault {
		filter = graphics.Filter(options.Filter)
	} else if img.filter != FilterDefault {
		filter = graphics.Filter(img.filter)
	}

	vs := make([]float32, len(vertices)*graphics.VertexFloatNum)
	src := img.mipmap.original()
	r := img.Bounds()
	for idx, v := range vertices {
		src.PutVertex(vs[idx*graphics.VertexFloatNum:(idx+1)*graphics.VertexFloatNum],
			float32(v.DstX), float32(v.DstY), v.SrcX, v.SrcY,
			float32(r.Min.X), float32(r.Min.Y), float32(r.Max.X), float32(r.Max.Y),
			v.ColorR, v.ColorG, v.ColorB, v.ColorA)
	}
	i.mipmap.original().DrawTriangles(img.mipmap.original(), vs, indices, options.ColorM.impl, mode, filter, graphics.Address(options.Address))
	i.disposeMipmaps()
}
func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, options *DrawTrianglesOptions) {
	i.copyCheck()
	if i.isDisposed() {
		return
	}

	if i.isSubImage() {
		panic("ebiten: render to a subimage is not implemented (DrawTriangles)")
	}

	img.resolvePendingPixels(true)
	i.resolvePendingPixels(true)

	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 = &DrawTrianglesOptions{}
	}

	mode := graphics.CompositeMode(options.CompositeMode)

	filter := graphics.FilterNearest
	if options.Filter != FilterDefault {
		filter = graphics.Filter(options.Filter)
	} else if img.filter != FilterDefault {
		filter = graphics.Filter(img.filter)
	}

	vs := make([]float32, len(vertices)*graphics.VertexFloatNum)
	src := img.mipmap.original()
	r := img.Bounds()
	for idx, v := range vertices {
		src.PutVertex(vs[idx*graphics.VertexFloatNum:(idx+1)*graphics.VertexFloatNum],
			float32(v.DstX), float32(v.DstY), v.SrcX, v.SrcY,
			float32(r.Min.X), float32(r.Min.Y), float32(r.Max.X), float32(r.Max.Y),
			v.ColorR, v.ColorG, v.ColorB, v.ColorA)
	}
	i.mipmap.original().DrawTriangles(img.mipmap.original(), vs, indices, options.ColorM.impl, mode, filter, graphics.Address(options.Address))
	i.disposeMipmaps()
}
// DrawTriangles draws a triangle with the specified vertices and their indices.
//
// If len(indices) is not multiple of 3, DrawTriangles panics.
//
// If len(indices) is more than MaxIndicesNum, DrawTriangles panics.
//
// The rule in which DrawTriangles works effectively is same as DrawImage's.
//
// When the image i is disposed, DrawTriangles does nothing.
//
// Internal mipmap is not used on DrawTriangles.
//
// Note that this API is experimental.