Adding new triangles type: TrianglesClipped

This commit is contained in:
Allen Ray 2020-07-01 17:15:11 -04:00
parent 842ae8d470
commit 798c6c2a48
6 changed files with 179 additions and 43 deletions

14
data.go
View File

@ -15,6 +15,8 @@ var (
Color RGBA
Picture Vec
Intensity float64
ClipRect Rect
IsClipped bool
}{Color: RGBA{1, 1, 1, 1}}
)
@ -25,6 +27,8 @@ type TrianglesData []struct {
Color RGBA
Picture Vec
Intensity float64
ClipRect Rect
IsClipped bool
}
// MakeTrianglesData creates TrianglesData of length len initialized with default property values.
@ -89,6 +93,11 @@ func (td *TrianglesData) updateData(t Triangles) {
(*td)[i].Picture, (*td)[i].Intensity = t.Picture(i)
}
}
if t, ok := t.(TrianglesClipped); ok {
for i := range *td {
(*td)[i].ClipRect, (*td)[i].IsClipped = t.ClipRect(i)
}
}
}
// Update copies vertex properties from the supplied Triangles into this TrianglesData.
@ -123,6 +132,11 @@ func (td *TrianglesData) Picture(i int) (pic Vec, intensity float64) {
return (*td)[i].Picture, (*td)[i].Intensity
}
// ClipRect returns the clipping rectangle property of the i-th vertex.
func (td *TrianglesData) ClipRect(i int) (rect Rect, has bool) {
return (*td)[i].ClipRect, (*td)[i].IsClipped
}
// PictureData specifies an in-memory rectangular area of pixels and implements Picture and
// PictureColor.
//

View File

@ -266,3 +266,35 @@ func BenchmarkTrianglesData_Picture(b *testing.B) {
})
}
}
func BenchmarkTrianglesData_ClipRect(b *testing.B) {
tests := []struct {
name string
tData *pixel.TrianglesData
position int
}{
{
name: "Getting beginning position",
tData: pixel.MakeTrianglesData(1000),
position: 2,
},
{
name: "Getting middle position",
tData: pixel.MakeTrianglesData(1000),
position: 500,
},
{
name: "Getting end position",
tData: pixel.MakeTrianglesData(1000),
position: 999,
},
}
for _, tt := range tests {
b.Run(tt.name, func(b *testing.B) {
for i := 0; i < b.N; i++ {
_, _ = tt.tData.ClipRect(tt.position)
}
})
}
}

View File

@ -92,7 +92,7 @@ type TrianglesColor interface {
Color(i int) RGBA
}
// TrianglesPicture specifies Triangles with Picture propery.
// TrianglesPicture specifies Triangles with Picture property.
//
// The first value returned from Picture method is Picture coordinates. The second one specifies the
// weight of the Picture. Value of 0 means, that Picture should be completely ignored, 1 means that
@ -102,6 +102,15 @@ type TrianglesPicture interface {
Picture(i int) (pic Vec, intensity float64)
}
// TrianglesClipped specifies Triangles with Clipping Rectangle property.
//
// The first value returned from ClipRect method is the clipping rectangle. The second one specifies
// if the triangle is clipped.
type TrianglesClipped interface {
Triangles
ClipRect(i int) (rect Rect, is bool)
}
// Picture represents a rectangular area of raster data, such as a color. It has Bounds which
// specify the rectangle where data is located.
type Picture interface {

View File

@ -4,8 +4,6 @@ import (
"fmt"
"image/color"
"github.com/go-gl/gl/v3.3-core/gl"
"github.com/faiface/glhf"
"github.com/faiface/mainthread"
"github.com/faiface/pixel"
@ -322,10 +320,6 @@ func (ct *canvasTriangles) draw(tex *glhf.Texture, bounds pixel.Rect) {
ct.shader.s.SetUniformAttr(loc, u.Value())
}
if clip, has := ct.ClipRect(); has {
gl.Scissor(int32(clip.Min.X), int32(clip.Min.Y), int32(clip.W()), int32(clip.H()))
}
if tex == nil {
ct.vs.Begin()
ct.vs.Draw()

View File

@ -22,6 +22,7 @@ type GLShader struct {
colormask mgl32.Vec4
bounds mgl32.Vec4
texbounds mgl32.Vec4
cliprect mgl32.Vec4
}
}
@ -37,6 +38,7 @@ const (
canvasColor
canvasTexCoords
canvasIntensity
canvasClip
)
var defaultCanvasVertexFormat = glhf.AttrFormat{
@ -44,6 +46,7 @@ var defaultCanvasVertexFormat = glhf.AttrFormat{
canvasColor: {Name: "aColor", Type: glhf.Vec4},
canvasTexCoords: {Name: "aTexCoords", Type: glhf.Vec2},
canvasIntensity: {Name: "aIntensity", Type: glhf.Float},
canvasClip: {Name: "aClipRect", Type: glhf.Vec4},
}
// Sets up a base shader with everything needed for a Pixel
@ -238,11 +241,14 @@ in vec2 aPosition;
in vec4 aColor;
in vec2 aTexCoords;
in float aIntensity;
in vec4 aClipRect;
in float aIsClipped;
out vec4 vColor;
out vec2 vTexCoords;
out float vIntensity;
out vec2 vPosition;
out vec4 vClipRect;
uniform mat3 uTransform;
uniform vec4 uBounds;
@ -251,10 +257,12 @@ void main() {
vec2 transPos = (uTransform * vec3(aPosition, 1.0)).xy;
vec2 normPos = (transPos - uBounds.xy) / uBounds.zw * 2 - vec2(1, 1);
gl_Position = vec4(normPos, 0.0, 1.0);
vColor = aColor;
vPosition = aPosition;
vTexCoords = aTexCoords;
vIntensity = aIntensity;
vClipRect = aClipRect;
}
`
@ -264,6 +272,7 @@ var baseCanvasFragmentShader = `
in vec4 vColor;
in vec2 vTexCoords;
in float vIntensity;
in vec4 vClipRect;
out vec4 fragColor;
@ -272,6 +281,9 @@ uniform vec4 uTexBounds;
uniform sampler2D uTexture;
void main() {
if ((vClipRect != vec4(0,0,0,0)) && (gl_FragCoord.x < vClipRect.x || gl_FragCoord.y < vClipRect.y || gl_FragCoord.x > vClipRect.z || gl_FragCoord.y > vClipRect.w))
discard;
if (vIntensity == 0) {
fragColor = uColorMask * vColor;
} else {

View File

@ -16,13 +16,32 @@ type GLTriangles struct {
vs *glhf.VertexSlice
data []float32
shader *GLShader
clip pixel.Rect
}
var (
_ pixel.TrianglesPosition = (*GLTriangles)(nil)
_ pixel.TrianglesColor = (*GLTriangles)(nil)
_ pixel.TrianglesPicture = (*GLTriangles)(nil)
_ pixel.TrianglesClipped = (*GLTriangles)(nil)
)
// The following is a helper so that the indices of
// each of these items is easier to see/debug.
const (
triPosX = iota
triPosY
triColorR
triColorG
triColorB
triColorA
triPicX
triPicY
triIntensity
triClipMinX
triClipMinY
triClipMaxX
triClipMaxY
trisAttrLen
)
// NewGLTriangles returns GLTriangles initialized with the data from the supplied Triangles.
@ -71,6 +90,7 @@ func (gt *GLTriangles) SetLen(length int) {
1, 1, 1, 1,
0, 0,
0,
0, 0, 0, 0,
)
}
case length < gt.Len():
@ -111,17 +131,22 @@ func (gt *GLTriangles) updateData(t pixel.Triangles) {
col = (*t)[i].Color
tx, ty = (*t)[i].Picture.XY()
in = (*t)[i].Intensity
rec = (*t)[i].ClipRect
)
d := gt.data[i*stride : i*stride+9]
d[0] = float32(px)
d[1] = float32(py)
d[2] = float32(col.R)
d[3] = float32(col.G)
d[4] = float32(col.B)
d[5] = float32(col.A)
d[6] = float32(tx)
d[7] = float32(ty)
d[8] = float32(in)
d := gt.data[i*stride : i*stride+trisAttrLen]
d[triPosX] = float32(px)
d[triPosY] = float32(py)
d[triColorR] = float32(col.R)
d[triColorG] = float32(col.G)
d[triColorB] = float32(col.B)
d[triColorA] = float32(col.A)
d[triPicX] = float32(tx)
d[triPicY] = float32(ty)
d[triIntensity] = float32(in)
d[triClipMinX] = float32(rec.Min.X)
d[triClipMinY] = float32(rec.Min.Y)
d[triClipMaxX] = float32(rec.Max.X)
d[triClipMaxY] = float32(rec.Max.Y)
}
return
}
@ -129,25 +154,34 @@ func (gt *GLTriangles) updateData(t pixel.Triangles) {
if t, ok := t.(pixel.TrianglesPosition); ok {
for i := 0; i < length; i++ {
px, py := t.Position(i).XY()
gt.data[i*stride+0] = float32(px)
gt.data[i*stride+1] = float32(py)
gt.data[i*stride+triPosX] = float32(px)
gt.data[i*stride+triPosY] = float32(py)
}
}
if t, ok := t.(pixel.TrianglesColor); ok {
for i := 0; i < length; i++ {
col := t.Color(i)
gt.data[i*stride+2] = float32(col.R)
gt.data[i*stride+3] = float32(col.G)
gt.data[i*stride+4] = float32(col.B)
gt.data[i*stride+5] = float32(col.A)
gt.data[i*stride+triColorR] = float32(col.R)
gt.data[i*stride+triColorG] = float32(col.G)
gt.data[i*stride+triColorB] = float32(col.B)
gt.data[i*stride+triColorA] = float32(col.A)
}
}
if t, ok := t.(pixel.TrianglesPicture); ok {
for i := 0; i < length; i++ {
pic, intensity := t.Picture(i)
gt.data[i*stride+6] = float32(pic.X)
gt.data[i*stride+7] = float32(pic.Y)
gt.data[i*stride+8] = float32(intensity)
gt.data[i*stride+triPicX] = float32(pic.X)
gt.data[i*stride+triPicY] = float32(pic.Y)
gt.data[i*stride+triIntensity] = float32(intensity)
}
}
if t, ok := t.(pixel.TrianglesClipped); ok {
for i := 0; i < length; i++ {
rect, _ := t.ClipRect(i)
gt.data[i*stride+triClipMinX] = float32(rect.Min.X)
gt.data[i*stride+triClipMinY] = float32(rect.Min.Y)
gt.data[i*stride+triClipMaxX] = float32(rect.Max.X)
gt.data[i*stride+triClipMaxY] = float32(rect.Max.Y)
}
}
}
@ -161,6 +195,12 @@ func (gt *GLTriangles) Update(t pixel.Triangles) {
}
gt.updateData(t)
// Copy the verteces down to the glhf.VertexData
gt.CopyVertices()
}
// CopyVertices copies the GLTriangle data down to the vertex data.
func (gt *GLTriangles) CopyVertices() {
// this code is supposed to copy the vertex data and CallNonBlock the update if
// the data is small enough, otherwise it'll block and not copy the data
if len(gt.data) < 256 { // arbitrary heurestic constant
@ -186,19 +226,31 @@ func (gt *GLTriangles) Copy() pixel.Triangles {
return NewGLTriangles(gt.shader, gt)
}
// index is a helper function that returns the index in the data
// slice given the i-th vertex and the item index.
func (gt *GLTriangles) index(i, idx int) int {
return i*gt.vs.Stride() + idx
}
// Position returns the Position property of the i-th vertex.
func (gt *GLTriangles) Position(i int) pixel.Vec {
px := gt.data[i*gt.vs.Stride()+0]
py := gt.data[i*gt.vs.Stride()+1]
px := gt.data[gt.index(i, triPosX)]
py := gt.data[gt.index(i, triPosY)]
return pixel.V(float64(px), float64(py))
}
// SetPosition sets the position property of the i-th vertex.
func (gt *GLTriangles) SetPosition(i int, p pixel.Vec) {
gt.data[gt.index(i, triPosX)] = float32(p.X)
gt.data[gt.index(i, triPosY)] = float32(p.Y)
}
// Color returns the Color property of the i-th vertex.
func (gt *GLTriangles) Color(i int) pixel.RGBA {
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]
r := gt.data[gt.index(i, triColorR)]
g := gt.data[gt.index(i, triColorG)]
b := gt.data[gt.index(i, triColorB)]
a := gt.data[gt.index(i, triColorA)]
return pixel.RGBA{
R: float64(r),
G: float64(g),
@ -207,21 +259,44 @@ func (gt *GLTriangles) Color(i int) pixel.RGBA {
}
}
// SetColor sets the color property of the i-th vertex.
func (gt *GLTriangles) SetColor(i int, c pixel.RGBA) {
gt.data[gt.index(i, triColorR)] = float32(c.R)
gt.data[gt.index(i, triColorG)] = float32(c.G)
gt.data[gt.index(i, triColorB)] = float32(c.B)
gt.data[gt.index(i, triColorA)] = float32(c.A)
}
// Picture returns the Picture property of the i-th vertex.
func (gt *GLTriangles) Picture(i int) (pic pixel.Vec, intensity float64) {
tx := gt.data[i*gt.vs.Stride()+6]
ty := gt.data[i*gt.vs.Stride()+7]
intensity = float64(gt.data[i*gt.vs.Stride()+8])
tx := gt.data[gt.index(i, triPicX)]
ty := gt.data[gt.index(i, triPicY)]
intensity = float64(gt.data[gt.index(i, triIntensity)])
return pixel.V(float64(tx), float64(ty)), intensity
}
// SetClipRect sets the rectangle to scissor the triangles by
func (gt *GLTriangles) SetClipRect(r pixel.Rect) {
gt.clip = r.Norm()
// SetPicture sets the picture property of the i-th vertex.
func (gt *GLTriangles) SetPicture(i int, pic pixel.Vec, intensity float64) {
gt.data[gt.index(i, triPicX)] = float32(pic.X)
gt.data[gt.index(i, triPicY)] = float32(pic.Y)
gt.data[gt.index(i, triIntensity)] = float32(intensity)
}
// ClipRect gets the clipping rectangle and returns true if that
// rectangle is not the Zero Rectangle
func (gt *GLTriangles) ClipRect() (pixel.Rect, bool) {
return gt.clip, gt.clip.Area() != 0
// ClipRect returns the Clipping rectangle property of the i-th vertex.
func (gt *GLTriangles) ClipRect(i int) (rect pixel.Rect, is bool) {
mx := gt.data[gt.index(i, triClipMinX)]
my := gt.data[gt.index(i, triClipMinY)]
ax := gt.data[gt.index(i, triClipMaxX)]
ay := gt.data[gt.index(i, triClipMaxY)]
rect = pixel.R(float64(mx), float64(my), float64(ax), float64(ay))
is = rect.Area() != 0.0
return
}
// SetClipRect sets the Clipping rectangle property of the i-th vertex.
func (gt *GLTriangles) SetClipRect(i int, rect pixel.Rect) {
gt.data[gt.index(i, triClipMinX)] = float32(rect.Min.X)
gt.data[gt.index(i, triClipMinY)] = float32(rect.Min.Y)
gt.data[gt.index(i, triClipMaxX)] = float32(rect.Max.X)
gt.data[gt.index(i, triClipMaxY)] = float32(rect.Max.Y)
}