go-opengl-pixel/batch.go

180 lines
4.2 KiB
Go
Raw Normal View History

2017-01-12 06:47:44 -06:00
package pixel
import (
2017-02-24 07:25:35 -06:00
"fmt"
2017-01-12 06:47:44 -06:00
"image/color"
)
// Batch is a Target that allows for efficient drawing of many objects with the same Picture (but
// different slices of the same Picture are allowed).
//
// To put an object into a Batch, just draw it onto it:
// object.Draw(batch)
type Batch struct {
2017-02-23 18:21:23 -06:00
cont Drawer
2017-01-12 06:47:44 -06:00
mat Matrix
2017-01-12 06:47:44 -06:00
col NRGBA
}
2017-02-23 18:21:23 -06:00
var _ BasicTarget = (*Batch)(nil)
2017-01-12 06:47:44 -06:00
// NewBatch creates an empty Batch with the specified Picture and container.
//
2017-03-14 16:50:46 -05:00
// The container is where objects get accumulated. Batch will support precisely those Triangles
// properties, that the supplied container supports. If you retain access to the container and
// change it, call Dirty to notify Batch about the change.
2017-01-12 06:47:44 -06:00
//
// Note, that if the container does not support TrianglesColor, color masking will not work.
2017-02-23 18:21:23 -06:00
func NewBatch(container Triangles, pic Picture) *Batch {
2017-03-19 13:49:08 -05:00
b := &Batch{cont: Drawer{Triangles: container, Picture: pic}}
b.SetMatrix(IM)
b.SetColorMask(NRGBA{1, 1, 1, 1})
return b
2017-01-12 06:47:44 -06:00
}
2017-03-14 16:50:46 -05:00
// Dirty notifies Batch about an external modification of it's container. If you retain access to
// the Batch's container and change it, call Dirty to notify Batch about the change.
//
// container := &pixel.TrianglesData{}
// batch := pixel.NewBatch(container, nil)
2017-03-14 16:51:45 -05:00
// container.SetLen(10) // container changed from outside of Batch
2017-03-14 16:50:46 -05:00
// batch.Dirty() // notify Batch about the change
func (b *Batch) Dirty() {
b.cont.Dirty()
}
2017-01-12 06:47:44 -06:00
// Clear removes all objects from the Batch.
func (b *Batch) Clear() {
2017-02-23 18:21:23 -06:00
b.cont.Triangles.SetLen(0)
2017-01-28 13:01:59 -06:00
b.cont.Dirty()
2017-01-12 06:47:44 -06:00
}
// Draw draws all objects that are currently in the Batch onto another Target.
func (b *Batch) Draw(t Target) {
b.cont.Draw(t)
}
// SetMatrix sets a Matrix that every point will be projected by.
func (b *Batch) SetMatrix(m Matrix) {
b.mat = m
2017-01-12 06:47:44 -06:00
}
2017-02-23 18:21:23 -06:00
// SetColorMask sets a mask color used in the following draws onto the Batch.
func (b *Batch) SetColorMask(c color.Color) {
2017-01-12 06:47:44 -06:00
if c == nil {
b.col = NRGBA{1, 1, 1, 1}
return
}
b.col = NRGBAModel.Convert(c).(NRGBA)
}
2017-02-23 18:21:23 -06:00
// MakeTriangles returns a specialized copy of the provided Triangles that draws onto this Batch.
func (b *Batch) MakeTriangles(t Triangles) TargetTriangles {
bt := &batchTriangles{
2017-03-19 13:49:08 -05:00
tri: t.Copy(),
tmp: MakeTrianglesData(t.Len()),
dst: b,
2017-02-23 18:21:23 -06:00
}
return bt
}
// MakePicture returns a specialized copy of the provided Picture that draws onto this Batch.
func (b *Batch) MakePicture(p Picture) TargetPicture {
2017-03-08 16:51:53 -06:00
if p.Original() != b.cont.Picture.Original() {
panic(fmt.Errorf("(%T).MakePicture: Picture is not a slice of Batch's Picture", b))
}
bp := &batchPicture{
2017-03-19 13:49:08 -05:00
pic: p,
dst: b,
2017-02-23 18:21:23 -06:00
}
2017-03-08 09:26:09 -06:00
bp.orig = bp
return bp
2017-02-23 18:21:23 -06:00
}
2017-01-12 06:47:44 -06:00
type batchTriangles struct {
2017-03-19 13:49:08 -05:00
tri Triangles
tmp *TrianglesData
2017-01-12 06:47:44 -06:00
2017-03-08 09:26:09 -06:00
dst *Batch
2017-01-12 06:47:44 -06:00
}
2017-03-19 13:49:08 -05:00
func (bt *batchTriangles) Len() int {
return bt.tri.Len()
}
func (bt *batchTriangles) SetLen(len int) {
bt.tri.SetLen(len)
bt.tmp.SetLen(len)
}
func (bt *batchTriangles) Slice(i, j int) Triangles {
return &batchTriangles{
tri: bt.tri.Slice(i, j),
tmp: bt.tmp.Slice(i, j).(*TrianglesData),
dst: bt.dst,
2017-01-12 06:47:44 -06:00
}
2017-03-19 13:49:08 -05:00
}
2017-01-28 13:01:59 -06:00
2017-03-19 13:49:08 -05:00
func (bt *batchTriangles) Update(t Triangles) {
bt.tri.Update(t)
}
func (bt *batchTriangles) Copy() Triangles {
return &batchTriangles{
tri: bt.tri.Copy(),
tmp: bt.tmp.Copy().(*TrianglesData),
dst: bt.dst,
}
}
func (bt *batchTriangles) draw(bp *batchPicture) {
bt.tmp.Update(bt.tri)
for i := range *bt.tmp {
(*bt.tmp)[i].Position = bt.dst.mat.Project((*bt.tmp)[i].Position)
(*bt.tmp)[i].Color = bt.dst.col.Mul((*bt.tmp)[i].Color)
}
2017-02-23 18:21:23 -06:00
2017-03-08 09:26:09 -06:00
cont := bt.dst.cont.Triangles
2017-03-19 13:49:08 -05:00
cont.SetLen(cont.Len() + bt.tri.Len())
added := cont.Slice(cont.Len()-bt.tri.Len(), cont.Len())
added.Update(bt.tri)
added.Update(bt.tmp)
2017-03-08 09:26:09 -06:00
bt.dst.cont.Dirty()
2017-02-23 18:21:23 -06:00
}
func (bt *batchTriangles) Draw() {
bt.draw(nil)
}
type batchPicture struct {
2017-03-19 13:49:08 -05:00
pic Picture
2017-03-08 09:26:09 -06:00
orig *batchPicture
dst *Batch
2017-02-23 18:21:23 -06:00
}
2017-03-19 13:49:08 -05:00
func (bp *batchPicture) Bounds() Rect {
return bp.pic.Bounds()
}
2017-02-23 18:21:23 -06:00
func (bp *batchPicture) Slice(r Rect) Picture {
return &batchPicture{
2017-03-19 13:49:08 -05:00
pic: bp.pic.Slice(r),
orig: bp.orig,
dst: bp.dst,
2017-02-23 18:21:23 -06:00
}
}
func (bp *batchPicture) Original() Picture {
2017-03-08 09:26:09 -06:00
return bp.orig
}
2017-02-23 18:21:23 -06:00
func (bp *batchPicture) Draw(t TargetTriangles) {
2017-02-24 07:25:35 -06:00
bt := t.(*batchTriangles)
2017-03-08 09:26:09 -06:00
if bp.dst != bt.dst {
2017-03-08 16:51:53 -06:00
panic(fmt.Errorf("(%T).Draw: TargetTriangles generated by different Batch", bp))
2017-02-24 07:25:35 -06:00
}
bt.draw(bp)
2017-01-12 06:47:44 -06:00
}