feat: implemented layering for DrawableTriangles.
This commit is contained in:
parent
08c950a669
commit
0f6732bcf9
9 changed files with 103 additions and 121 deletions
|
@ -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,
|
||||||
|
@ -75,6 +75,7 @@ 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 }
|
||||||
|
|
|
@ -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,
|
||||||
))
|
))
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
75
engine.go
75
engine.go
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {}
|
||||||
|
|
||||||
|
|
|
@ -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
31
rect.go
|
@ -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{
|
/*// Use the Color as base image if no is provided.
|
||||||
GeoM: m,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
sprite.go
11
sprite.go
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
60
triangle.go
60
triangle.go
|
@ -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)*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue