feat: implemented layering for DrawableTriangles.

This commit is contained in:
Andrey Parhomenko 2024-01-11 06:39:57 +03:00
parent 08c950a669
commit 0f6732bcf9
9 changed files with 103 additions and 121 deletions

View file

@ -11,17 +11,17 @@ type Debug struct {
gg.Object gg.Object
} }
func (d *Debug) Draw(c *Context) { func (d *Debug) Draw(c *Context) []gg.EVertex {
e := c.Engine e := c.Engine
keyStrs := []string{} keyStrs := []string{}
keyStrs = append(keyStrs, fmt.Sprintf( keyStrs = append(keyStrs, fmt.Sprintf(
"counter: %d", counter, "counter: %d", counter,
)) ))
keyStrs = append(keyStrs, fmt.Sprintf( keyStrs = append(keyStrs, fmt.Sprintf(
"tps: %d", int(c.TPS()), "tps: %d", int(c.Tps()),
)) ))
keyStrs = append(keyStrs, fmt.Sprintf( keyStrs = append(keyStrs, fmt.Sprintf(
"fps: %d", int(c.FPS()), "fps: %d", int(c.Fps()),
)) ))
keyStrs = append(keyStrs, fmt.Sprintf( keyStrs = append(keyStrs, fmt.Sprintf(
"relPlayerPos: %v", player.Position, "relPlayerPos: %v", player.Position,
@ -74,7 +74,8 @@ func (d *Debug) Draw(c *Context) {
e.DebugPrint(c.Image, e.DebugPrint(c.Image,
strings.Join(keyStrs, "\n")) strings.Join(keyStrs, "\n"))
return nil
} }
func (d *Debug) IsVisible() bool { return true } func (d *Debug) IsVisible() bool { return true }

View file

@ -36,27 +36,11 @@ func NewPlayer() *Player {
func (p *Player) Start(c *Context) { func (p *Player) Start(c *Context) {
} }
// Custom drawing function.
func (p *Player) Draw(c *Context) {
p.Sprite.Draw(c)
return
t := p.Transform
t.Scale.X *= 4.
t.Scale.Y *= 4.
r := &gg.DrawableRectangle{}
r.Color = gg.Rgba(0, 0, 1, 1)
r.Rectangle = gg.Rectangle{
Transform: t,
}
r.Draw(c)
}
func (p *Player) Update(c *Context) { func (p *Player) Update(c *Context) {
if p.Spawned { if p.Spawned {
return return
} }
dt := c.DT() dt := c.Dt()
cam := c.Camera cam := c.Camera
keys := c.Keys() keys := c.Keys()
@ -140,7 +124,7 @@ func (p *Player) Update(c *Context) {
c.Camera.Position = pos.Sub(ec.Abs) c.Camera.Position = pos.Sub(ec.Abs)
case *gg.WheelChange: case *gg.WheelChange:
c.Camera.Scale = c.Camera.Scale.Add(gg.V2( c.Camera.Scale = c.Camera.Scale.Add(gg.V2(
ec.Offset.Y * c.DT() * p.ScaleSpeed * 40, ec.Offset.Y * c.Dt() * p.ScaleSpeed * 40,
)) ))
}} }}
} }

View file

@ -32,7 +32,7 @@ func NewTri() *Tri {
} }
func (t *Tri) Update(c *Context) { func (t *Tri) Update(c *Context) {
dt := c.DT() dt := c.Dt()
if t.ContainsPoint(c.AbsCursorPosition()) { if t.ContainsPoint(c.AbsCursorPosition()) {
t.Color = gg.Rgba(0, 1, 0, 1) t.Color = gg.Rgba(0, 1, 0, 1)
} else { } else {
@ -53,12 +53,12 @@ func (t *Tri) Update(c *Context) {
case gg.KeyM: case gg.KeyM:
absPos := t.AbsPosition() absPos := t.AbsPosition()
t.SetAbsPosition( t.SetAbsPosition(
absPos.Add(gg.V(0, 100*c.DT()*d)), absPos.Add(gg.V(0, 100*c.Dt()*d)),
) )
case gg.KeyN: case gg.KeyN:
absPos := t.AbsPosition() absPos := t.AbsPosition()
t.SetAbsPosition( t.SetAbsPosition(
absPos.Add(gg.V(100*c.DT()*d, 0)), absPos.Add(gg.V(100*c.Dt()*d, 0)),
) )
case gg.KeyV: case gg.KeyV:
t.Rotation += d * gg.Pi * 0.3 * dt t.Rotation += d * gg.Pi * 0.3 * dt

View file

@ -11,7 +11,7 @@ import (
) )
const ( const (
LayerBufSize = 0 MaxVertices = 1 << 16
) )
type GraphicsLibrary = ebiten.GraphicsLibrary type GraphicsLibrary = ebiten.GraphicsLibrary
@ -64,7 +64,7 @@ type Engine struct {
// The same delta time for all frames // The same delta time for all frames
// and all objects. // and all objects.
lastTime time.Time lastTime time.Time
dt Float dt, fdt Float
// Temporary stuff // Temporary stuff
keys, prevKeys []Key keys, prevKeys []Key
@ -75,8 +75,8 @@ type Engine struct {
wg sync.WaitGroup wg sync.WaitGroup
//bufs [LayerBufSize]*Image //bufs [LayerBufSize]*Image
vertices []ebiten.Vertex vertices map[Layer] []ebiten.Vertex
vindices []uint16 //vindices []uint16
} }
type engine Engine type engine Engine
@ -297,9 +297,22 @@ func (e *engine) Update() error {
return nil return nil
} }
func (e *engine) Draw(i *ebiten.Image) { var (
e.vindices = []uint16{} fullPageIndexes = func() [MaxVertices]uint16 {
e.vertices = []ebiten.Vertex{} ret := [MaxVertices]uint16{}
for i:=0 ; i<len(ret) ; i++ {
ret[i] = uint16(i)
}
return ret
}()
defaultPageImg = func() *Image {
img := NewImage(1, 1)
img.Set(0, 0, Rgba(1, 1, 1, 1))
return img
}()
defaultTriOptions = &ebiten.DrawTrianglesOptions{}
)
func (e *engine) Draw(img *ebiten.Image) {
e.dt = time.Since(e.lastTime).Seconds() e.dt = time.Since(e.lastTime).Seconds()
eng := (*Engine)(e) eng := (*Engine)(e)
m := map[Layer][]Drawer{} m := map[Layer][]Drawer{}
@ -319,17 +332,39 @@ func (e *engine) Draw(i *ebiten.Image) {
m[l] = append(layer, object) m[l] = append(layer, object)
} }
// Drawing layers. // Drawing layers via the sparse array.
// First drawing via the inside function
// and then the returned []EVertex.
layers := maps.NewSparse[Layer, []Drawer](nil, m) layers := maps.NewSparse[Layer, []Drawer](nil, m)
c := &Context{Engine: eng, typ: drawContext, Image: i} c := &Context{Engine: eng, typ: drawContext, Image: img}
for layer := range layers.Chan() { for layer := range layers.Chan() {
vertices := []EVertex{}
for _, drawer := range layer { for _, drawer := range layer {
drawer.Draw(c) vs := drawer.Draw(c)
if vs != nil {
vertices = append(vertices, vs...)
}
} }
pn := len(vertices) / MaxVertices
mod := len(vertices) % MaxVertices
for i := 0 ; i<pn ; i++ {
cur := i*MaxVertices
img.DrawTriangles(
vertices[cur:cur+MaxVertices],
fullPageIndexes[:],
defaultPageImg,
defaultTriOptions,
)
}
st := pn*MaxVertices
img.DrawTriangles(
vertices[st:],
fullPageIndexes[:mod],
defaultPageImg,
defaultTriOptions,
)
} }
img := NewImage(1, 1)
img.Set(0, 0, Rgba(1, 1, 1, 1))
i.DrawTriangles(e.vertices, e.vindices, img, &ebiten.DrawTrianglesOptions{})
// Empty the buff to generate it again. // Empty the buff to generate it again.
eng.Camera.buffered = false eng.Camera.buffered = false
@ -344,15 +379,21 @@ func (e *engine) Layout(ow, oh int) (int, int) {
return ow, oh return ow, oh
} }
// Return the delta time duration value. // Return the delta time.
func (e *Engine) DT() Float { func (e *Engine) Dt() Float {
return e.dt return e.dt
} }
func (e *Engine) FPS() float64 {
// Return the current fixed delta time.
func (e *Engine) Fdt() Float {
return 1/60
}
func (e *Engine) Fps() float64 {
return ebiten.ActualFPS() return ebiten.ActualFPS()
} }
func (e *Engine) TPS() float64 { func (e *Engine) Tps() float64 {
return ebiten.ActualTPS() return ebiten.ActualTPS()
} }

View file

@ -40,7 +40,7 @@ type Colority struct {
// drawn. It will be drew corresponding to // drawn. It will be drew corresponding to
// the layers order so the layer must be returned. // the layers order so the layer must be returned.
type Drawer interface { type Drawer interface {
Draw(*Context) Draw(*Context) []EVertex
GetLayer() Layer GetLayer() Layer
IsVisible() bool IsVisible() bool
} }
@ -66,6 +66,6 @@ func (o *Object) Input() chan *Context { return o.input }
func (o *Object) Start(c *Context) {} func (o *Object) Start(c *Context) {}
func (o *Object) Update(c *Context) {} func (o *Object) Update(c *Context) {}
func (o *Object) Draw(c *Context) {} func (o *Object) Draw(c *Context) []EVertex { return nil}
func (o *Object) Delete(c *Context) {} func (o *Object) Delete(c *Context) {}

View file

@ -37,12 +37,10 @@ func (p Polygon) MakeTriangles() Triangles {
return ret return ret
} }
func (p *DrawablePolygon) Draw(c *Context) { func (p *DrawablePolygon) Draw(c *Context) []EVertex {
(&DrawableTriangles{ return (&DrawableTriangles{
Visibility: p.Visibility,
Colority: p.Colority, Colority: p.Colority,
ShaderOptions: p.ShaderOptions,
Triangles: p.MakeTriangles(), Triangles: p.MakeTriangles(),
}).Draw(c) }).MakeEVertices(c)
} }

31
rect.go
View file

@ -1,7 +1,7 @@
package gg package gg
import ( import (
"github.com/hajimehoshi/ebiten/v2" //"github.com/hajimehoshi/ebiten/v2"
//"github.com/hajimehoshi/ebiten/v2/vector" //"github.com/hajimehoshi/ebiten/v2/vector"
//"fmt" //"fmt"
//"image" //"image"
@ -48,7 +48,7 @@ func (r Rectangle) Edges() Edges {
} }
// Get 2 triangles that the rectangle consists of. // Get 2 triangles that the rectangle consists of.
func (r Rectangle) Triangles() Triangles { func (r Rectangle) MakeTriangles() Triangles {
pts := r.Vertices() pts := r.Vertices()
p1 := pts[0] p1 := pts[0]
p2 := pts[1] p2 := pts[1]
@ -63,7 +63,7 @@ func (r Rectangle) Triangles() Triangles {
// Check whether the rectangle contains the point. // Check whether the rectangle contains the point.
func (r Rectangle) ContainsPoint(p Point) bool { func (r Rectangle) ContainsPoint(p Point) bool {
return r.Triangles().ContainsPoint(p) return r.MakeTriangles().ContainsPoint(p)
} }
// Check whether the drawable rectangle should be drawn. // Check whether the drawable rectangle should be drawn.
@ -71,23 +71,13 @@ func (r *DrawableRectangle) IsVisible() bool {
return r.Visible return r.Visible
} }
func (r *DrawableRectangle) Draw(c *Context) { func (r *DrawableRectangle) Draw(c *Context) []EVertex {
m := r.Matrix() return (&DrawableTriangles{
rm := c.Camera.RealMatrix() Colority: r.Colority,
m.Concat(rm) Triangles: r.MakeTriangles(),
// Draw solid color if no shader. }).MakeEVertices(c)
if r.Shader == nil {
img := NewImage(1, 1)
img.Set(0, 0, r.Color)
c.DrawImage(img, &ebiten.DrawImageOptions{
GeoM: m,
})
return
}
/*// Use the Color as base image if no is provided.
// Use the Color as base image if no is provided.
//var did bool //var did bool
if r.Images[0] == nil { if r.Images[0] == nil {
r.Images[0] = NewImage(1, 1) r.Images[0] = NewImage(1, 1)
@ -101,6 +91,7 @@ func (r *DrawableRectangle) Draw(c *Context) {
GeoM: m, GeoM: m,
Images: r.Images, Images: r.Images,
Uniforms: r.Uniforms, Uniforms: r.Uniforms,
}) })*/
return nil
} }

View file

@ -17,10 +17,10 @@ var (
//spritesOp DrawImageOptions //spritesOp DrawImageOptions
) )
func (s *Sprite) Draw(c *Context) { func (s *Sprite) Draw(c *Context) []EVertex {
// Nothing to draw. // Nothing to draw.
if s.Images[0] == nil { if s.Images[0] == nil {
return return nil
} }
t := s.Rectangle().Transform t := s.Rectangle().Transform
@ -34,7 +34,7 @@ func (s *Sprite) Draw(c *Context) {
c.DrawImage(s.Images[0], &ebiten.DrawImageOptions{ c.DrawImage(s.Images[0], &ebiten.DrawImageOptions{
GeoM: m, GeoM: m,
}) })
return return nil
} }
w, h := s.Images[0].Size() w, h := s.Images[0].Size()
@ -44,6 +44,7 @@ func (s *Sprite) Draw(c *Context) {
Uniforms: s.Uniforms, Uniforms: s.Uniforms,
GeoM: m, GeoM: m,
}) })
return nil
} }
// Return the rectangle that contains the sprite. // Return the rectangle that contains the sprite.
@ -64,7 +65,7 @@ func (s *Sprite) Rectangle() Rectangle {
// Get triangles of the rectangle that contains the sprite // Get triangles of the rectangle that contains the sprite
// and has the same widght and height. // and has the same widght and height.
func (s *Sprite) Triangles() Triangles { func (s *Sprite) MakeTriangles() Triangles {
return s.Rectangle().Triangles() return s.Rectangle().MakeTriangles()
} }

View file

@ -5,6 +5,8 @@ import (
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
) )
type EVertex = ebiten.Vertex
// Ebitens vector in better abstractions like Vectors. // Ebitens vector in better abstractions like Vectors.
type Vertex struct { type Vertex struct {
Dst Vector Dst Vector
@ -16,14 +18,11 @@ type Triangle [3]Vector
type Triangles []Triangle type Triangles []Triangle
type DrawableTriangles struct { type DrawableTriangles struct {
Triangles Triangles
Visibility
Colority Colority
ShaderOptions
ebiten.DrawTrianglesOptions
} }
func (v Vertex) Ebiten() ebiten.Vertex { func (v Vertex) Ebiten() EVertex {
return ebiten.Vertex { return EVertex {
DstX: float32(v.Dst.X), DstX: float32(v.Dst.X),
DstY: float32(v.Dst.Y), DstY: float32(v.Dst.Y),
SrcX: float32(v.Src.X), SrcX: float32(v.Src.X),
@ -88,50 +87,17 @@ func (ts Triangles) ContainsPoint(p Point) bool {
return false return false
} }
func (r *DrawableTriangles) Draw(c *Context) { func (r *DrawableTriangles) MakeEVertices(c *Context) []EVertex {
m := c.Camera.RealMatrix() m := c.Camera.RealMatrix()
vs := make([]ebiten.Vertex, len(r.Triangles) * 3)
// Draw solid color if no shader. var buf Vertex
if r.Shader == nil { buf.Color = r.Color
vs := make([]ebiten.Vertex, len(r.Triangles) * 3) for i := range r.Triangles {
var buf Vertex for j := range r.Triangles[i] {
buf.Color = r.Color buf.Dst = r.Triangles[i][j].Apply(m)
for i := range r.Triangles { vs[i*3 + j] = buf.Ebiten()
for j := range r.Triangles[i] {
buf.Dst = r.Triangles[i][j].Apply(m)
vs[i*3 + j] = buf.Ebiten()
}
} }
is := make([]uint16, len(r.Triangles) * 3)
start := len(c.Engine.vindices)
for i := 0 ; i < len(is) ; i++ {
is[i] = uint16(start + i)
}
c.Engine.vertices = append(c.Engine.vertices, vs...)
c.Engine.vindices = append(c.Engine.vindices, is...)
return
//c.DrawTriangles(vs, is, img, &r.DrawTrianglesOptions)
return
} }
return vs
// Use the Color as base image if no is provided.
/*if r.Images[0] == nil {
r.Images[0] = NewImage(1, 1)
r.Images[0].Set(0, 0, r.Color)
}
w, h := r.Images[0].Size()
// Drawing with shader.
opts := &ebiten.DrawRectShaderOptions{
GeoM: m,
Images: r.Images,
Uniforms: r.Uniforms,
}
i.DrawRectShader(w, h, r.Shader, opts)*/
} }