package pixel import ( "fmt" "image/color" "github.com/go-gl/mathgl/mgl64" ) // 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 { cont Drawer mat Matrix col NRGBA } var _ BasicTarget = (*Batch)(nil) // NewBatch creates an empty Batch with the specified Picture and container. // // 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. // // Note, that if the container does not support TrianglesColor, color masking will not work. func NewBatch(container Triangles, pic Picture) *Batch { return &Batch{ cont: Drawer{Triangles: container, Picture: pic}, mat: IM, col: NRGBA{1, 1, 1, 1}, } } // 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) // container.SetLen(10) // changed container from outside of Batch // batch.Dirty() // notify Batch about the change func (b *Batch) Dirty() { b.cont.Dirty() } // Clear removes all objects from the Batch. func (b *Batch) Clear() { b.cont.Triangles.SetLen(0) b.cont.Dirty() } // 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 } // SetColorMask sets a mask color used in the following draws onto the Batch. func (b *Batch) SetColorMask(c color.Color) { if c == nil { b.col = NRGBA{1, 1, 1, 1} return } b.col = NRGBAModel.Convert(c).(NRGBA) } // MakeTriangles returns a specialized copy of the provided Triangles that draws onto this Batch. func (b *Batch) MakeTriangles(t Triangles) TargetTriangles { bt := &batchTriangles{ Triangles: t.Copy(), orig: MakeTrianglesData(t.Len()), trans: MakeTrianglesData(t.Len()), dst: b, } bt.orig.Update(t) bt.trans.Update(bt.orig) return bt } // MakePicture returns a specialized copy of the provided Picture that draws onto this Batch. func (b *Batch) MakePicture(p Picture) TargetPicture { if p.Original() != b.cont.Picture.Original() { panic(fmt.Errorf("(%T).MakePicture: Picture is not a slice of Batch's Picture", b)) } bp := &batchPicture{ Picture: p, dst: b, } bp.orig = bp return bp } type batchTriangles struct { Triangles orig, trans *TrianglesData dst *Batch } func (bt *batchTriangles) draw(bp *batchPicture) { for i := range *bt.trans { transPos := mgl64.Mat3(bt.dst.mat).Mul3x1(mgl64.Vec3{ (*bt.orig)[i].Position.X(), (*bt.orig)[i].Position.Y(), 1, }) (*bt.trans)[i].Position = V(float64(transPos.X()), float64(transPos.Y())) (*bt.trans)[i].Color = (*bt.orig)[i].Color.Mul(bt.dst.col) (*bt.trans)[i].Picture = (*bt.orig)[i].Picture (*bt.trans)[i].Intensity = (*bt.orig)[i].Intensity } bt.Triangles.Update(bt.trans) cont := bt.dst.cont.Triangles cont.SetLen(cont.Len() + bt.Triangles.Len()) cont.Slice(cont.Len()-bt.Triangles.Len(), cont.Len()).Update(bt.Triangles) bt.dst.cont.Dirty() } func (bt *batchTriangles) Draw() { bt.draw(nil) } type batchPicture struct { Picture orig *batchPicture dst *Batch } func (bp *batchPicture) Slice(r Rect) Picture { return &batchPicture{ Picture: bp.Picture.Slice(r), orig: bp.orig, dst: bp.dst, } } func (bp *batchPicture) Original() Picture { return bp.orig } func (bp *batchPicture) Draw(t TargetTriangles) { bt := t.(*batchTriangles) if bp.dst != bt.dst { panic(fmt.Errorf("(%T).Draw: TargetTriangles generated by different Batch", bp)) } bt.draw(bp) }