commit
6a9211310a
13
geometry.go
13
geometry.go
|
@ -49,6 +49,11 @@ func (u Vec) XY() (x, y float64) {
|
||||||
return u.X, u.Y
|
return u.X, u.Y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Normal returns a vector normal to u (rotated by math.pi/2)
|
||||||
|
func (u Vec) Normal() Vec {
|
||||||
|
return Vec{X: u.Y, Y: -u.X}
|
||||||
|
}
|
||||||
|
|
||||||
// Add returns the sum of vectors u and v.
|
// Add returns the sum of vectors u and v.
|
||||||
func (u Vec) Add(v Vec) Vec {
|
func (u Vec) Add(v Vec) Vec {
|
||||||
return Vec{
|
return Vec{
|
||||||
|
@ -65,6 +70,14 @@ func (u Vec) Sub(v Vec) Vec {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To returns the vector from vector u to vector v, equivalent to v.Sub(u).
|
||||||
|
func (u Vec) To(v Vec) Vec {
|
||||||
|
return Vec{
|
||||||
|
v.X - u.X,
|
||||||
|
v.Y - u.Y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Scaled returns the vector u multiplied by c.
|
// Scaled returns the vector u multiplied by c.
|
||||||
func (u Vec) Scaled(c float64) Vec {
|
func (u Vec) Scaled(c float64) Vec {
|
||||||
return Vec{u.X * c, u.Y * c}
|
return Vec{u.X * c, u.Y * c}
|
||||||
|
|
|
@ -128,7 +128,9 @@ func (imd *IMDraw) Draw(t pixel.Target) {
|
||||||
// Push adds some points to the IM queue. All Pushed points will have the same properties except for
|
// Push adds some points to the IM queue. All Pushed points will have the same properties except for
|
||||||
// the position.
|
// the position.
|
||||||
func (imd *IMDraw) Push(pts ...pixel.Vec) {
|
func (imd *IMDraw) Push(pts ...pixel.Vec) {
|
||||||
imd.Color = pixel.ToRGBA(imd.Color)
|
if _, ok := imd.Color.(pixel.RGBA); !ok {
|
||||||
|
imd.Color = pixel.ToRGBA(imd.Color)
|
||||||
|
}
|
||||||
opts := point{
|
opts := point{
|
||||||
col: imd.Color.(pixel.RGBA),
|
col: imd.Color.(pixel.RGBA),
|
||||||
pic: imd.Picture,
|
pic: imd.Picture,
|
||||||
|
@ -495,12 +497,12 @@ func (imd *IMDraw) outlineEllipseArc(radius pixel.Vec, low, high, thickness floa
|
||||||
thick := pixel.V(thickness/2, 0).Rotated(normalLow)
|
thick := pixel.V(thickness/2, 0).Rotated(normalLow)
|
||||||
imd.pushPt(lowCenter.Add(thick), pt)
|
imd.pushPt(lowCenter.Add(thick), pt)
|
||||||
imd.pushPt(lowCenter.Sub(thick), pt)
|
imd.pushPt(lowCenter.Sub(thick), pt)
|
||||||
imd.pushPt(lowCenter.Sub(thick.Rotated(math.Pi/2*orientation)), pt)
|
imd.pushPt(lowCenter.Sub(thick.Normal().Scaled(orientation)), pt)
|
||||||
imd.fillPolygon()
|
imd.fillPolygon()
|
||||||
thick = pixel.V(thickness/2, 0).Rotated(normalHigh)
|
thick = pixel.V(thickness/2, 0).Rotated(normalHigh)
|
||||||
imd.pushPt(highCenter.Add(thick), pt)
|
imd.pushPt(highCenter.Add(thick), pt)
|
||||||
imd.pushPt(highCenter.Sub(thick), pt)
|
imd.pushPt(highCenter.Sub(thick), pt)
|
||||||
imd.pushPt(highCenter.Add(thick.Rotated(math.Pi/2*orientation)), pt)
|
imd.pushPt(highCenter.Add(thick.Normal().Scaled(orientation)), pt)
|
||||||
imd.fillPolygon()
|
imd.fillPolygon()
|
||||||
case RoundEndShape:
|
case RoundEndShape:
|
||||||
imd.pushPt(lowCenter, pt)
|
imd.pushPt(lowCenter, pt)
|
||||||
|
@ -528,29 +530,27 @@ func (imd *IMDraw) polyline(thickness float64, closed bool) {
|
||||||
|
|
||||||
// first point
|
// first point
|
||||||
j, i := 0, 1
|
j, i := 0, 1
|
||||||
normal := points[i].pos.Sub(points[j].pos).Rotated(math.Pi / 2).Unit().Scaled(thickness / 2)
|
ijNormal := points[0].pos.To(points[1].pos).Normal().Unit().Scaled(thickness / 2)
|
||||||
|
|
||||||
if !closed {
|
if !closed {
|
||||||
switch points[j].endshape {
|
switch points[j].endshape {
|
||||||
case NoEndShape:
|
case NoEndShape:
|
||||||
// nothing
|
// nothing
|
||||||
case SharpEndShape:
|
case SharpEndShape:
|
||||||
imd.pushPt(points[j].pos.Add(normal), points[j])
|
imd.pushPt(points[j].pos.Add(ijNormal), points[j])
|
||||||
imd.pushPt(points[j].pos.Sub(normal), points[j])
|
imd.pushPt(points[j].pos.Sub(ijNormal), points[j])
|
||||||
imd.pushPt(points[j].pos.Add(normal.Rotated(math.Pi/2)), points[j])
|
imd.pushPt(points[j].pos.Add(ijNormal.Normal()), points[j])
|
||||||
imd.fillPolygon()
|
imd.fillPolygon()
|
||||||
case RoundEndShape:
|
case RoundEndShape:
|
||||||
imd.pushPt(points[j].pos, points[j])
|
imd.pushPt(points[j].pos, points[j])
|
||||||
imd.fillEllipseArc(pixel.V(thickness/2, thickness/2), normal.Angle(), normal.Angle()+math.Pi)
|
imd.fillEllipseArc(pixel.V(thickness/2, thickness/2), ijNormal.Angle(), ijNormal.Angle()+math.Pi)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
imd.pushPt(points[j].pos.Add(normal), points[j])
|
imd.pushPt(points[j].pos.Add(ijNormal), points[j])
|
||||||
imd.pushPt(points[j].pos.Sub(normal), points[j])
|
imd.pushPt(points[j].pos.Sub(ijNormal), points[j])
|
||||||
|
|
||||||
// middle points
|
// middle points
|
||||||
// compute "previous" normal:
|
|
||||||
ijNormal := points[1].pos.Sub(points[0].pos).Rotated(math.Pi / 2).Unit().Scaled(thickness / 2)
|
|
||||||
for i := 0; i < len(points); i++ {
|
for i := 0; i < len(points); i++ {
|
||||||
j, k := i+1, i+2
|
j, k := i+1, i+2
|
||||||
|
|
||||||
|
@ -566,7 +566,7 @@ func (imd *IMDraw) polyline(thickness float64, closed bool) {
|
||||||
k %= len(points)
|
k %= len(points)
|
||||||
}
|
}
|
||||||
|
|
||||||
jkNormal := points[k].pos.Sub(points[j].pos).Rotated(math.Pi / 2).Unit().Scaled(thickness / 2)
|
jkNormal := points[j].pos.To(points[k].pos).Normal().Unit().Scaled(thickness / 2)
|
||||||
|
|
||||||
orientation := 1.0
|
orientation := 1.0
|
||||||
if ijNormal.Cross(jkNormal) > 0 {
|
if ijNormal.Cross(jkNormal) > 0 {
|
||||||
|
@ -602,10 +602,10 @@ func (imd *IMDraw) polyline(thickness float64, closed bool) {
|
||||||
|
|
||||||
// last point
|
// last point
|
||||||
i, j = len(points)-2, len(points)-1
|
i, j = len(points)-2, len(points)-1
|
||||||
normal = points[j].pos.Sub(points[i].pos).Rotated(math.Pi / 2).Unit().Scaled(thickness / 2)
|
ijNormal = points[i].pos.To(points[j].pos).Normal().Unit().Scaled(thickness / 2)
|
||||||
|
|
||||||
imd.pushPt(points[j].pos.Sub(normal), points[j])
|
imd.pushPt(points[j].pos.Sub(ijNormal), points[j])
|
||||||
imd.pushPt(points[j].pos.Add(normal), points[j])
|
imd.pushPt(points[j].pos.Add(ijNormal), points[j])
|
||||||
imd.fillPolygon()
|
imd.fillPolygon()
|
||||||
|
|
||||||
if !closed {
|
if !closed {
|
||||||
|
@ -613,13 +613,13 @@ func (imd *IMDraw) polyline(thickness float64, closed bool) {
|
||||||
case NoEndShape:
|
case NoEndShape:
|
||||||
// nothing
|
// nothing
|
||||||
case SharpEndShape:
|
case SharpEndShape:
|
||||||
imd.pushPt(points[j].pos.Add(normal), points[j])
|
imd.pushPt(points[j].pos.Add(ijNormal), points[j])
|
||||||
imd.pushPt(points[j].pos.Sub(normal), points[j])
|
imd.pushPt(points[j].pos.Sub(ijNormal), points[j])
|
||||||
imd.pushPt(points[j].pos.Add(normal.Rotated(-math.Pi/2)), points[j])
|
imd.pushPt(points[j].pos.Add(ijNormal.Normal().Scaled(-1)), points[j])
|
||||||
imd.fillPolygon()
|
imd.fillPolygon()
|
||||||
case RoundEndShape:
|
case RoundEndShape:
|
||||||
imd.pushPt(points[j].pos, points[j])
|
imd.pushPt(points[j].pos, points[j])
|
||||||
imd.fillEllipseArc(pixel.V(thickness/2, thickness/2), normal.Angle(), normal.Angle()-math.Pi)
|
imd.fillEllipseArc(pixel.V(thickness/2, thickness/2), ijNormal.Angle(), ijNormal.Angle()-math.Pi)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -380,7 +380,7 @@ var canvasUniformFormat = glhf.AttrFormat{
|
||||||
}
|
}
|
||||||
|
|
||||||
var canvasVertexShader = `
|
var canvasVertexShader = `
|
||||||
#version 330 core
|
#version 130
|
||||||
|
|
||||||
in vec2 position;
|
in vec2 position;
|
||||||
in vec4 color;
|
in vec4 color;
|
||||||
|
@ -405,7 +405,7 @@ void main() {
|
||||||
`
|
`
|
||||||
|
|
||||||
var canvasFragmentShader = `
|
var canvasFragmentShader = `
|
||||||
#version 330 core
|
#version 130
|
||||||
|
|
||||||
in vec4 Color;
|
in vec4 Color;
|
||||||
in vec2 TexCoords;
|
in vec2 TexCoords;
|
||||||
|
|
|
@ -60,9 +60,10 @@ func (gt *GLTriangles) Len() int {
|
||||||
// SetLen efficiently resizes GLTriangles to len.
|
// SetLen efficiently resizes GLTriangles to len.
|
||||||
//
|
//
|
||||||
// Time complexity is amortized O(1).
|
// Time complexity is amortized O(1).
|
||||||
func (gt *GLTriangles) SetLen(len int) {
|
func (gt *GLTriangles) SetLen(length int) {
|
||||||
if len > gt.Len() {
|
switch {
|
||||||
needAppend := len - gt.Len()
|
case length > gt.Len():
|
||||||
|
needAppend := length - gt.Len()
|
||||||
for i := 0; i < needAppend; i++ {
|
for i := 0; i < needAppend; i++ {
|
||||||
gt.data = append(gt.data,
|
gt.data = append(gt.data,
|
||||||
0, 0,
|
0, 0,
|
||||||
|
@ -71,11 +72,16 @@ func (gt *GLTriangles) SetLen(len int) {
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
case length < gt.Len():
|
||||||
|
gt.data = gt.data[:length*gt.vs.Stride()]
|
||||||
|
default:
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if len < gt.Len() {
|
mainthread.CallNonBlock(func() {
|
||||||
gt.data = gt.data[:len*gt.vs.Stride()]
|
gt.vs.Begin()
|
||||||
}
|
gt.vs.SetLen(length)
|
||||||
gt.submitData()
|
gt.vs.End()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slice returns a sub-Triangles of this GLTriangles in range [i, j).
|
// Slice returns a sub-Triangles of this GLTriangles in range [i, j).
|
||||||
|
@ -95,16 +101,17 @@ func (gt *GLTriangles) updateData(t pixel.Triangles) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrianglesData short path
|
// TrianglesData short path
|
||||||
|
stride := gt.vs.Stride()
|
||||||
|
length := gt.Len()
|
||||||
if t, ok := t.(*pixel.TrianglesData); ok {
|
if t, ok := t.(*pixel.TrianglesData); ok {
|
||||||
for i := 0; i < gt.Len(); i++ {
|
for i := 0; i < length; i++ {
|
||||||
var (
|
var (
|
||||||
px, py = (*t)[i].Position.XY()
|
px, py = (*t)[i].Position.XY()
|
||||||
col = (*t)[i].Color
|
col = (*t)[i].Color
|
||||||
tx, ty = (*t)[i].Picture.XY()
|
tx, ty = (*t)[i].Picture.XY()
|
||||||
in = (*t)[i].Intensity
|
in = (*t)[i].Intensity
|
||||||
)
|
)
|
||||||
s := gt.vs.Stride()
|
d := gt.data[i*stride : i*stride+9]
|
||||||
d := gt.data[i*s : i*s+9]
|
|
||||||
d[0] = float32(px)
|
d[0] = float32(px)
|
||||||
d[1] = float32(py)
|
d[1] = float32(py)
|
||||||
d[2] = float32(col.R)
|
d[2] = float32(col.R)
|
||||||
|
@ -119,54 +126,31 @@ func (gt *GLTriangles) updateData(t pixel.Triangles) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if t, ok := t.(pixel.TrianglesPosition); ok {
|
if t, ok := t.(pixel.TrianglesPosition); ok {
|
||||||
for i := 0; i < gt.Len(); i++ {
|
for i := 0; i < length; i++ {
|
||||||
px, py := t.Position(i).XY()
|
px, py := t.Position(i).XY()
|
||||||
gt.data[i*gt.vs.Stride()+0] = float32(px)
|
gt.data[i*stride+0] = float32(px)
|
||||||
gt.data[i*gt.vs.Stride()+1] = float32(py)
|
gt.data[i*stride+1] = float32(py)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if t, ok := t.(pixel.TrianglesColor); ok {
|
if t, ok := t.(pixel.TrianglesColor); ok {
|
||||||
for i := 0; i < gt.Len(); i++ {
|
for i := 0; i < length; i++ {
|
||||||
col := t.Color(i)
|
col := t.Color(i)
|
||||||
gt.data[i*gt.vs.Stride()+2] = float32(col.R)
|
gt.data[i*stride+2] = float32(col.R)
|
||||||
gt.data[i*gt.vs.Stride()+3] = float32(col.G)
|
gt.data[i*stride+3] = float32(col.G)
|
||||||
gt.data[i*gt.vs.Stride()+4] = float32(col.B)
|
gt.data[i*stride+4] = float32(col.B)
|
||||||
gt.data[i*gt.vs.Stride()+5] = float32(col.A)
|
gt.data[i*stride+5] = float32(col.A)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if t, ok := t.(pixel.TrianglesPicture); ok {
|
if t, ok := t.(pixel.TrianglesPicture); ok {
|
||||||
for i := 0; i < gt.Len(); i++ {
|
for i := 0; i < length; i++ {
|
||||||
pic, intensity := t.Picture(i)
|
pic, intensity := t.Picture(i)
|
||||||
gt.data[i*gt.vs.Stride()+6] = float32(pic.X)
|
gt.data[i*stride+6] = float32(pic.X)
|
||||||
gt.data[i*gt.vs.Stride()+7] = float32(pic.Y)
|
gt.data[i*stride+7] = float32(pic.Y)
|
||||||
gt.data[i*gt.vs.Stride()+8] = float32(intensity)
|
gt.data[i*stride+8] = float32(intensity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gt *GLTriangles) submitData() {
|
|
||||||
// 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
|
|
||||||
data := append([]float32{}, gt.data...)
|
|
||||||
mainthread.CallNonBlock(func() {
|
|
||||||
gt.vs.Begin()
|
|
||||||
dataLen := len(data) / gt.vs.Stride()
|
|
||||||
gt.vs.SetLen(dataLen)
|
|
||||||
gt.vs.SetVertexData(data)
|
|
||||||
gt.vs.End()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
mainthread.Call(func() {
|
|
||||||
gt.vs.Begin()
|
|
||||||
dataLen := len(gt.data) / gt.vs.Stride()
|
|
||||||
gt.vs.SetLen(dataLen)
|
|
||||||
gt.vs.SetVertexData(gt.data)
|
|
||||||
gt.vs.End()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update copies vertex properties from the supplied Triangles into this GLTriangles.
|
// Update copies vertex properties from the supplied Triangles into this GLTriangles.
|
||||||
//
|
//
|
||||||
// The two Triangles (gt and t) must be of the same len.
|
// The two Triangles (gt and t) must be of the same len.
|
||||||
|
@ -175,7 +159,23 @@ func (gt *GLTriangles) Update(t pixel.Triangles) {
|
||||||
panic(fmt.Errorf("(%T).Update: invalid triangles len", gt))
|
panic(fmt.Errorf("(%T).Update: invalid triangles len", gt))
|
||||||
}
|
}
|
||||||
gt.updateData(t)
|
gt.updateData(t)
|
||||||
gt.submitData()
|
|
||||||
|
// 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
|
||||||
|
data := append([]float32{}, gt.data...)
|
||||||
|
mainthread.CallNonBlock(func() {
|
||||||
|
gt.vs.Begin()
|
||||||
|
gt.vs.SetVertexData(data)
|
||||||
|
gt.vs.End()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
mainthread.Call(func() {
|
||||||
|
gt.vs.Begin()
|
||||||
|
gt.vs.SetVertexData(gt.data)
|
||||||
|
gt.vs.End()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy returns an independent copy of this GLTriangles.
|
// Copy returns an independent copy of this GLTriangles.
|
||||||
|
|
|
@ -90,10 +90,8 @@ func NewWindow(cfg WindowConfig) (*Window, error) {
|
||||||
err := mainthread.CallErr(func() error {
|
err := mainthread.CallErr(func() error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
glfw.WindowHint(glfw.ContextVersionMajor, 3)
|
glfw.WindowHint(glfw.ContextVersionMajor, 2)
|
||||||
glfw.WindowHint(glfw.ContextVersionMinor, 3)
|
glfw.WindowHint(glfw.ContextVersionMinor, 1)
|
||||||
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
|
|
||||||
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
|
|
||||||
|
|
||||||
glfw.WindowHint(glfw.Resizable, bool2int[cfg.Resizable])
|
glfw.WindowHint(glfw.Resizable, bool2int[cfg.Resizable])
|
||||||
glfw.WindowHint(glfw.Decorated, bool2int[!cfg.Undecorated])
|
glfw.WindowHint(glfw.Decorated, bool2int[!cfg.Undecorated])
|
||||||
|
|
Loading…
Reference in New Issue