Merge pull request #284 from dusk125/clipTris
Adding new triangles type: TrianglesClipped
This commit is contained in:
commit
9e8e09f1d7
14
data.go
14
data.go
|
@ -14,6 +14,8 @@ var zeroValueTriangleData = struct {
|
|||
Color RGBA
|
||||
Picture Vec
|
||||
Intensity float64
|
||||
ClipRect Rect
|
||||
IsClipped bool
|
||||
}{Color: RGBA{1, 1, 1, 1}}
|
||||
|
||||
// TrianglesData specifies a list of Triangles vertices with three common properties:
|
||||
|
@ -23,6 +25,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.
|
||||
|
@ -87,6 +91,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.
|
||||
|
@ -121,6 +130,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.
|
||||
//
|
||||
|
|
32
data_test.go
32
data_test.go
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
11
interface.go
11
interface.go
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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: glhf.Attr{Name: "aColor", Type: glhf.Vec4},
|
||||
canvasTexCoords: glhf.Attr{Name: "aTexCoords", Type: glhf.Vec2},
|
||||
canvasIntensity: glhf.Attr{Name: "aIntensity", Type: glhf.Float},
|
||||
canvasClip: glhf.Attr{Name: "aClipRect", Type: glhf.Vec4},
|
||||
}
|
||||
|
||||
// Sets up a base shader with everything needed for a Pixel
|
||||
|
@ -239,11 +242,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;
|
||||
|
@ -252,10 +258,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;
|
||||
}
|
||||
`
|
||||
|
||||
|
@ -265,6 +273,7 @@ var baseCanvasFragmentShader = `
|
|||
in vec4 vColor;
|
||||
in vec2 vTexCoords;
|
||||
in float vIntensity;
|
||||
in vec4 vClipRect;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
|
@ -273,6 +282,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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue