2017-01-20 11:40:48 -06:00
|
|
|
package pixel
|
|
|
|
|
|
|
|
import (
|
2017-01-28 13:01:59 -06:00
|
|
|
"fmt"
|
|
|
|
|
2017-01-20 11:40:48 -06:00
|
|
|
"github.com/faiface/mainthread"
|
|
|
|
"github.com/faiface/pixel/pixelgl"
|
|
|
|
)
|
|
|
|
|
|
|
|
// NewGLTriangles returns OpenGL triangles implemented using pixelgl.VertexSlice. A few notes.
|
|
|
|
//
|
|
|
|
// Triangles returned from this function support TrianglesPosition, TrianglesColor and
|
|
|
|
// TrianglesTexture. If you need to support more, you can "override" Update and Append method.
|
|
|
|
//
|
|
|
|
// Draw method simply draws the underlying pixelgl.VertexSlice. It needs to be called in the main
|
|
|
|
// thread manually. Also, you need to take care of additional Target initialization or setting of
|
|
|
|
// uniform attributes.
|
2017-01-28 13:01:59 -06:00
|
|
|
func NewGLTriangles(shader *pixelgl.Shader, t Triangles) TargetTriangles {
|
2017-01-20 11:40:48 -06:00
|
|
|
var gt *glTriangles
|
|
|
|
mainthread.Call(func() {
|
|
|
|
gt = &glTriangles{
|
|
|
|
vs: pixelgl.MakeVertexSlice(shader, 0, t.Len()),
|
|
|
|
shader: shader,
|
|
|
|
}
|
|
|
|
})
|
2017-01-28 13:01:59 -06:00
|
|
|
gt.SetLen(t.Len())
|
2017-01-20 11:40:48 -06:00
|
|
|
gt.Update(t)
|
|
|
|
return gt
|
|
|
|
}
|
|
|
|
|
|
|
|
type glTriangles struct {
|
|
|
|
vs *pixelgl.VertexSlice
|
|
|
|
data []float32
|
|
|
|
shader *pixelgl.Shader
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gt *glTriangles) Len() int {
|
|
|
|
return len(gt.data) / gt.vs.Stride()
|
|
|
|
}
|
|
|
|
|
2017-01-28 13:01:59 -06:00
|
|
|
func (gt *glTriangles) SetLen(len int) {
|
2017-01-20 11:40:48 -06:00
|
|
|
if len > gt.Len() {
|
|
|
|
needAppend := len - gt.Len()
|
|
|
|
for i := 0; i < needAppend; i++ {
|
|
|
|
gt.data = append(gt.data,
|
|
|
|
0, 0,
|
|
|
|
1, 1, 1, 1,
|
|
|
|
-1, -1,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len < gt.Len() {
|
|
|
|
gt.data = gt.data[:len]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-28 13:01:59 -06:00
|
|
|
func (gt *glTriangles) Slice(i, j int) Triangles {
|
|
|
|
return &glTriangles{
|
|
|
|
vs: gt.vs.Slice(i, j),
|
|
|
|
data: gt.data[i*gt.vs.Stride() : j*gt.vs.Stride()],
|
|
|
|
shader: gt.shader,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gt *glTriangles) updateData(t Triangles) {
|
|
|
|
// glTriangles short path
|
|
|
|
if t, ok := t.(*glTriangles); ok {
|
|
|
|
copy(gt.data, t.data)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-01-25 16:51:27 -06:00
|
|
|
// TrianglesData short path
|
|
|
|
if t, ok := t.(*TrianglesData); ok {
|
2017-01-28 13:01:59 -06:00
|
|
|
for i := 0; i < gt.Len(); i++ {
|
2017-01-25 16:51:27 -06:00
|
|
|
var (
|
|
|
|
px, py = (*t)[i].Position.XY()
|
|
|
|
col = (*t)[i].Color
|
|
|
|
tx, ty = (*t)[i].Texture.XY()
|
|
|
|
)
|
|
|
|
gt.data[i*gt.vs.Stride()+0] = float32(px)
|
|
|
|
gt.data[i*gt.vs.Stride()+1] = float32(py)
|
|
|
|
gt.data[i*gt.vs.Stride()+2] = float32(col.R)
|
|
|
|
gt.data[i*gt.vs.Stride()+3] = float32(col.G)
|
|
|
|
gt.data[i*gt.vs.Stride()+4] = float32(col.B)
|
|
|
|
gt.data[i*gt.vs.Stride()+5] = float32(col.A)
|
|
|
|
gt.data[i*gt.vs.Stride()+6] = float32(tx)
|
|
|
|
gt.data[i*gt.vs.Stride()+7] = float32(ty)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-01-20 11:40:48 -06:00
|
|
|
if t, ok := t.(TrianglesPosition); ok {
|
2017-01-28 13:01:59 -06:00
|
|
|
for i := 0; i < gt.Len(); i++ {
|
2017-01-20 11:40:48 -06:00
|
|
|
px, py := t.Position(i).XY()
|
|
|
|
gt.data[i*gt.vs.Stride()+0] = float32(px)
|
|
|
|
gt.data[i*gt.vs.Stride()+1] = float32(py)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if t, ok := t.(TrianglesColor); ok {
|
2017-01-28 13:01:59 -06:00
|
|
|
for i := 0; i < gt.Len(); i++ {
|
2017-01-20 11:40:48 -06:00
|
|
|
col := t.Color(i)
|
|
|
|
gt.data[i*gt.vs.Stride()+2] = float32(col.R)
|
|
|
|
gt.data[i*gt.vs.Stride()+3] = float32(col.G)
|
|
|
|
gt.data[i*gt.vs.Stride()+4] = float32(col.B)
|
|
|
|
gt.data[i*gt.vs.Stride()+5] = float32(col.A)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if t, ok := t.(TrianglesTexture); ok {
|
2017-01-28 13:01:59 -06:00
|
|
|
for i := 0; i < gt.Len(); i++ {
|
2017-01-20 11:40:48 -06:00
|
|
|
tx, ty := t.Texture(i).XY()
|
|
|
|
gt.data[i*gt.vs.Stride()+6] = float32(tx)
|
|
|
|
gt.data[i*gt.vs.Stride()+7] = float32(ty)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gt *glTriangles) submitData() {
|
|
|
|
data := gt.data // avoid race condition
|
|
|
|
mainthread.CallNonBlock(func() {
|
|
|
|
gt.vs.Begin()
|
|
|
|
dataLen := len(data) / gt.vs.Stride()
|
|
|
|
if dataLen > gt.vs.Len() {
|
|
|
|
gt.vs.Append(make([]float32, (dataLen-gt.vs.Len())*gt.vs.Stride()))
|
|
|
|
}
|
|
|
|
if dataLen < gt.vs.Len() {
|
|
|
|
gt.vs = gt.vs.Slice(0, dataLen)
|
|
|
|
}
|
|
|
|
gt.vs.SetVertexData(gt.data)
|
|
|
|
gt.vs.End()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gt *glTriangles) Update(t Triangles) {
|
2017-01-28 13:01:59 -06:00
|
|
|
if gt.Len() != t.Len() {
|
|
|
|
panic(fmt.Errorf("%T.Update: invalid triangles len", gt))
|
|
|
|
}
|
|
|
|
gt.updateData(t)
|
2017-01-20 11:40:48 -06:00
|
|
|
gt.submitData()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gt *glTriangles) Copy() Triangles {
|
|
|
|
return NewGLTriangles(gt.shader, gt)
|
|
|
|
}
|
|
|
|
|
2017-01-28 13:01:59 -06:00
|
|
|
func (gt *glTriangles) Draw() {
|
|
|
|
gt.vs.Begin()
|
|
|
|
gt.vs.Draw()
|
|
|
|
gt.vs.End()
|
|
|
|
}
|
|
|
|
|
2017-01-20 11:40:48 -06:00
|
|
|
func (gt *glTriangles) Position(i int) Vec {
|
|
|
|
px := gt.data[i*gt.vs.Stride()+0]
|
|
|
|
py := gt.data[i*gt.vs.Stride()+1]
|
|
|
|
return V(float64(px), float64(py))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gt *glTriangles) Color(i int) NRGBA {
|
|
|
|
r := gt.data[i*gt.vs.Stride()+2]
|
|
|
|
g := gt.data[i*gt.vs.Stride()+3]
|
|
|
|
b := gt.data[i*gt.vs.Stride()+4]
|
|
|
|
a := gt.data[i*gt.vs.Stride()+5]
|
|
|
|
return NRGBA{
|
|
|
|
R: float64(r),
|
|
|
|
G: float64(g),
|
|
|
|
B: float64(b),
|
|
|
|
A: float64(a),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gt *glTriangles) Texture(i int) Vec {
|
|
|
|
tx := gt.data[i*gt.vs.Stride()+6]
|
|
|
|
ty := gt.data[i*gt.vs.Stride()+7]
|
|
|
|
return V(float64(tx), float64(ty))
|
|
|
|
}
|