font/sfnt: flip the Y axis for LoadGlyph's Segments.
The underlying font format's Y axis increases up. The Go standard graphics libraries' Y axis increases down. This change makes the Go API consistent with the other Go libraries. Also change Segment.Args from [6]fixed.Int26_6 to [3]fixed.Point26_6 to emphasize that the Args are consistent with other fixed.Point26_6 use. Change-Id: Idd7b89eb4d86890dea477ac2ef96ff8f6b1dee8d Reviewed-on: https://go-review.googlesource.com/39072 Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
parent
f36ba34967
commit
ce0faa1867
|
@ -50,29 +50,29 @@ func ExampleRasterizeGlyph() {
|
||||||
switch seg.Op {
|
switch seg.Op {
|
||||||
case sfnt.SegmentOpMoveTo:
|
case sfnt.SegmentOpMoveTo:
|
||||||
r.MoveTo(
|
r.MoveTo(
|
||||||
originX+float32(seg.Args[0])/64,
|
originX+float32(seg.Args[0].X)/64,
|
||||||
originY-float32(seg.Args[1])/64,
|
originY+float32(seg.Args[0].Y)/64,
|
||||||
)
|
)
|
||||||
case sfnt.SegmentOpLineTo:
|
case sfnt.SegmentOpLineTo:
|
||||||
r.LineTo(
|
r.LineTo(
|
||||||
originX+float32(seg.Args[0])/64,
|
originX+float32(seg.Args[0].X)/64,
|
||||||
originY-float32(seg.Args[1])/64,
|
originY+float32(seg.Args[0].Y)/64,
|
||||||
)
|
)
|
||||||
case sfnt.SegmentOpQuadTo:
|
case sfnt.SegmentOpQuadTo:
|
||||||
r.QuadTo(
|
r.QuadTo(
|
||||||
originX+float32(seg.Args[0])/64,
|
originX+float32(seg.Args[0].X)/64,
|
||||||
originY-float32(seg.Args[1])/64,
|
originY+float32(seg.Args[0].Y)/64,
|
||||||
originX+float32(seg.Args[2])/64,
|
originX+float32(seg.Args[1].X)/64,
|
||||||
originY-float32(seg.Args[3])/64,
|
originY+float32(seg.Args[1].Y)/64,
|
||||||
)
|
)
|
||||||
case sfnt.SegmentOpCubeTo:
|
case sfnt.SegmentOpCubeTo:
|
||||||
r.CubeTo(
|
r.CubeTo(
|
||||||
originX+float32(seg.Args[0])/64,
|
originX+float32(seg.Args[0].X)/64,
|
||||||
originY-float32(seg.Args[1])/64,
|
originY+float32(seg.Args[0].Y)/64,
|
||||||
originX+float32(seg.Args[2])/64,
|
originX+float32(seg.Args[1].X)/64,
|
||||||
originY-float32(seg.Args[3])/64,
|
originY+float32(seg.Args[1].Y)/64,
|
||||||
originX+float32(seg.Args[4])/64,
|
originX+float32(seg.Args[2].X)/64,
|
||||||
originY-float32(seg.Args[5])/64,
|
originY+float32(seg.Args[2].Y)/64,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -999,46 +999,39 @@ func t2CMask(p *psInterpreter) error {
|
||||||
func t2CAppendMoveto(p *psInterpreter) {
|
func t2CAppendMoveto(p *psInterpreter) {
|
||||||
p.type2Charstrings.b.segments = append(p.type2Charstrings.b.segments, Segment{
|
p.type2Charstrings.b.segments = append(p.type2Charstrings.b.segments, Segment{
|
||||||
Op: SegmentOpMoveTo,
|
Op: SegmentOpMoveTo,
|
||||||
Args: [6]fixed.Int26_6{
|
Args: [3]fixed.Point26_6{{
|
||||||
0: fixed.Int26_6(p.type2Charstrings.x),
|
X: fixed.Int26_6(p.type2Charstrings.x),
|
||||||
1: fixed.Int26_6(p.type2Charstrings.y),
|
Y: fixed.Int26_6(p.type2Charstrings.y),
|
||||||
},
|
}},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func t2CAppendLineto(p *psInterpreter) {
|
func t2CAppendLineto(p *psInterpreter) {
|
||||||
p.type2Charstrings.b.segments = append(p.type2Charstrings.b.segments, Segment{
|
p.type2Charstrings.b.segments = append(p.type2Charstrings.b.segments, Segment{
|
||||||
Op: SegmentOpLineTo,
|
Op: SegmentOpLineTo,
|
||||||
Args: [6]fixed.Int26_6{
|
Args: [3]fixed.Point26_6{{
|
||||||
0: fixed.Int26_6(p.type2Charstrings.x),
|
X: fixed.Int26_6(p.type2Charstrings.x),
|
||||||
1: fixed.Int26_6(p.type2Charstrings.y),
|
Y: fixed.Int26_6(p.type2Charstrings.y),
|
||||||
},
|
}},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func t2CAppendCubeto(p *psInterpreter, dxa, dya, dxb, dyb, dxc, dyc int32) {
|
func t2CAppendCubeto(p *psInterpreter, dxa, dya, dxb, dyb, dxc, dyc int32) {
|
||||||
p.type2Charstrings.x += dxa
|
p.type2Charstrings.x += dxa
|
||||||
p.type2Charstrings.y += dya
|
p.type2Charstrings.y += dya
|
||||||
xa := p.type2Charstrings.x
|
xa := fixed.Int26_6(p.type2Charstrings.x)
|
||||||
ya := p.type2Charstrings.y
|
ya := fixed.Int26_6(p.type2Charstrings.y)
|
||||||
p.type2Charstrings.x += dxb
|
p.type2Charstrings.x += dxb
|
||||||
p.type2Charstrings.y += dyb
|
p.type2Charstrings.y += dyb
|
||||||
xb := p.type2Charstrings.x
|
xb := fixed.Int26_6(p.type2Charstrings.x)
|
||||||
yb := p.type2Charstrings.y
|
yb := fixed.Int26_6(p.type2Charstrings.y)
|
||||||
p.type2Charstrings.x += dxc
|
p.type2Charstrings.x += dxc
|
||||||
p.type2Charstrings.y += dyc
|
p.type2Charstrings.y += dyc
|
||||||
xc := p.type2Charstrings.x
|
xc := fixed.Int26_6(p.type2Charstrings.x)
|
||||||
yc := p.type2Charstrings.y
|
yc := fixed.Int26_6(p.type2Charstrings.y)
|
||||||
p.type2Charstrings.b.segments = append(p.type2Charstrings.b.segments, Segment{
|
p.type2Charstrings.b.segments = append(p.type2Charstrings.b.segments, Segment{
|
||||||
Op: SegmentOpCubeTo,
|
Op: SegmentOpCubeTo,
|
||||||
Args: [6]fixed.Int26_6{
|
Args: [3]fixed.Point26_6{{X: xa, Y: ya}, {X: xb, Y: yb}, {X: xc, Y: yc}},
|
||||||
0: fixed.Int26_6(xa),
|
|
||||||
1: fixed.Int26_6(ya),
|
|
||||||
2: fixed.Int26_6(xb),
|
|
||||||
3: fixed.Int26_6(yb),
|
|
||||||
4: fixed.Int26_6(xc),
|
|
||||||
5: fixed.Int26_6(yc),
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -902,6 +902,8 @@ type LoadGlyphOptions struct {
|
||||||
//
|
//
|
||||||
// If b is non-nil, the segments become invalid to use once b is re-used.
|
// If b is non-nil, the segments become invalid to use once b is re-used.
|
||||||
//
|
//
|
||||||
|
// In the returned Segments' (x, y) coordinates, the Y axis increases down.
|
||||||
|
//
|
||||||
// It returns ErrNotFound if the glyph index is out of range.
|
// It returns ErrNotFound if the glyph index is out of range.
|
||||||
func (f *Font) LoadGlyph(b *Buffer, x GlyphIndex, ppem fixed.Int26_6, opts *LoadGlyphOptions) ([]Segment, error) {
|
func (f *Font) LoadGlyph(b *Buffer, x GlyphIndex, ppem fixed.Int26_6, opts *LoadGlyphOptions) ([]Segment, error) {
|
||||||
if b == nil {
|
if b == nil {
|
||||||
|
@ -932,10 +934,14 @@ func (f *Font) LoadGlyph(b *Buffer, x GlyphIndex, ppem fixed.Int26_6, opts *Load
|
||||||
// loading code, such as the appendGlyfSegments body, since TrueType
|
// loading code, such as the appendGlyfSegments body, since TrueType
|
||||||
// hinting bytecode works on the scaled glyph vectors. For now, though,
|
// hinting bytecode works on the scaled glyph vectors. For now, though,
|
||||||
// it's simpler to scale as a post-processing step.
|
// it's simpler to scale as a post-processing step.
|
||||||
|
//
|
||||||
|
// We also flip the Y coordinates. OpenType's Y axis increases up. Go's
|
||||||
|
// standard graphics libraries' Y axis increases down.
|
||||||
for i := range b.segments {
|
for i := range b.segments {
|
||||||
s := &b.segments[i]
|
a := &b.segments[i].Args
|
||||||
for j := range s.Args {
|
for j := range a {
|
||||||
s.Args[j] = scale(s.Args[j]*ppem, f.cached.unitsPerEm)
|
a[j].X = +scale(a[j].X*ppem, f.cached.unitsPerEm)
|
||||||
|
a[j].Y = -scale(a[j].Y*ppem, f.cached.unitsPerEm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1194,8 +1200,10 @@ func (b *Buffer) view(src *source, offset, length int) ([]byte, error) {
|
||||||
|
|
||||||
// Segment is a segment of a vector path.
|
// Segment is a segment of a vector path.
|
||||||
type Segment struct {
|
type Segment struct {
|
||||||
|
// Op is the operator.
|
||||||
Op SegmentOp
|
Op SegmentOp
|
||||||
Args [6]fixed.Int26_6
|
// Args is up to three (x, y) coordinates. The Y axis increases down.
|
||||||
|
Args [3]fixed.Point26_6
|
||||||
}
|
}
|
||||||
|
|
||||||
// SegmentOp is a vector path segment's operator.
|
// SegmentOp is a vector path segment's operator.
|
||||||
|
@ -1209,30 +1217,31 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// translateArgs applies a translation to args.
|
// translateArgs applies a translation to args.
|
||||||
func translateArgs(args *[6]fixed.Int26_6, dx, dy fixed.Int26_6) {
|
func translateArgs(args *[3]fixed.Point26_6, dx, dy fixed.Int26_6) {
|
||||||
args[0] += dx
|
args[0].X += dx
|
||||||
args[1] += dy
|
args[0].Y += dy
|
||||||
args[2] += dx
|
args[1].X += dx
|
||||||
args[3] += dy
|
args[1].Y += dy
|
||||||
args[4] += dx
|
args[2].X += dx
|
||||||
args[5] += dy
|
args[2].Y += dy
|
||||||
}
|
}
|
||||||
|
|
||||||
// transformArgs applies an affine transformation to args. The t?? arguments
|
// transformArgs applies an affine transformation to args. The t?? arguments
|
||||||
// are 2.14 fixed point values.
|
// are 2.14 fixed point values.
|
||||||
func transformArgs(args *[6]fixed.Int26_6, txx, txy, tyx, tyy int16, dx, dy fixed.Int26_6) {
|
func transformArgs(args *[3]fixed.Point26_6, txx, txy, tyx, tyy int16, dx, dy fixed.Int26_6) {
|
||||||
args[0], args[1] = tform(txx, txy, tyx, tyy, dx, dy, args[0], args[1])
|
args[0] = tform(txx, txy, tyx, tyy, dx, dy, args[0])
|
||||||
args[2], args[3] = tform(txx, txy, tyx, tyy, dx, dy, args[2], args[3])
|
args[1] = tform(txx, txy, tyx, tyy, dx, dy, args[1])
|
||||||
args[4], args[5] = tform(txx, txy, tyx, tyy, dx, dy, args[4], args[5])
|
args[2] = tform(txx, txy, tyx, tyy, dx, dy, args[2])
|
||||||
}
|
}
|
||||||
|
|
||||||
func tform(txx, txy, tyx, tyy int16, dx, dy, x, y fixed.Int26_6) (newX, newY fixed.Int26_6) {
|
func tform(txx, txy, tyx, tyy int16, dx, dy fixed.Int26_6, p fixed.Point26_6) fixed.Point26_6 {
|
||||||
const half = 1 << 13
|
const half = 1 << 13
|
||||||
newX = dx +
|
return fixed.Point26_6{
|
||||||
fixed.Int26_6((int64(x)*int64(txx)+half)>>14) +
|
X: dx +
|
||||||
fixed.Int26_6((int64(y)*int64(tyx)+half)>>14)
|
fixed.Int26_6((int64(p.X)*int64(txx)+half)>>14) +
|
||||||
newY = dy +
|
fixed.Int26_6((int64(p.Y)*int64(tyx)+half)>>14),
|
||||||
fixed.Int26_6((int64(x)*int64(txy)+half)>>14) +
|
Y: dy +
|
||||||
fixed.Int26_6((int64(y)*int64(tyy)+half)>>14)
|
fixed.Int26_6((int64(p.X)*int64(txy)+half)>>14) +
|
||||||
return newX, newY
|
fixed.Int26_6((int64(p.Y)*int64(tyy)+half)>>14),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,31 +15,35 @@ import (
|
||||||
"golang.org/x/image/math/fixed"
|
"golang.org/x/image/math/fixed"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func pt(x, y fixed.Int26_6) fixed.Point26_6 {
|
||||||
|
return fixed.Point26_6{X: x, Y: y}
|
||||||
|
}
|
||||||
|
|
||||||
func moveTo(xa, ya fixed.Int26_6) Segment {
|
func moveTo(xa, ya fixed.Int26_6) Segment {
|
||||||
return Segment{
|
return Segment{
|
||||||
Op: SegmentOpMoveTo,
|
Op: SegmentOpMoveTo,
|
||||||
Args: [6]fixed.Int26_6{xa, ya},
|
Args: [3]fixed.Point26_6{pt(xa, ya)},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func lineTo(xa, ya fixed.Int26_6) Segment {
|
func lineTo(xa, ya fixed.Int26_6) Segment {
|
||||||
return Segment{
|
return Segment{
|
||||||
Op: SegmentOpLineTo,
|
Op: SegmentOpLineTo,
|
||||||
Args: [6]fixed.Int26_6{xa, ya},
|
Args: [3]fixed.Point26_6{pt(xa, ya)},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func quadTo(xa, ya, xb, yb fixed.Int26_6) Segment {
|
func quadTo(xa, ya, xb, yb fixed.Int26_6) Segment {
|
||||||
return Segment{
|
return Segment{
|
||||||
Op: SegmentOpQuadTo,
|
Op: SegmentOpQuadTo,
|
||||||
Args: [6]fixed.Int26_6{xa, ya, xb, yb},
|
Args: [3]fixed.Point26_6{pt(xa, ya), pt(xb, yb)},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func cubeTo(xa, ya, xb, yb, xc, yc fixed.Int26_6) Segment {
|
func cubeTo(xa, ya, xb, yb, xc, yc fixed.Int26_6) Segment {
|
||||||
return Segment{
|
return Segment{
|
||||||
Op: SegmentOpCubeTo,
|
Op: SegmentOpCubeTo,
|
||||||
Args: [6]fixed.Int26_6{xa, ya, xb, yb, xc, yc},
|
Args: [3]fixed.Point26_6{pt(xa, ya), pt(xb, yb), pt(xc, yc)},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +58,16 @@ func transform(txx, txy, tyx, tyy int16, dx, dy fixed.Int26_6, s Segment) Segmen
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkSegmentsEqual(got, want []Segment) error {
|
func checkSegmentsEqual(got, want []Segment) error {
|
||||||
|
// Flip got's Y axis. The test cases' coordinates are given with the Y axis
|
||||||
|
// increasing up, as that is what the ttx tool gives, and is the model for
|
||||||
|
// the underlying font format. The Go API returns coordinates with the Y
|
||||||
|
// axis increasing down, the same as the standard graphics libraries.
|
||||||
|
for i := range got {
|
||||||
|
for j := range got[i].Args {
|
||||||
|
got[i].Args[j].Y *= -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(got) != len(want) {
|
if len(got) != len(want) {
|
||||||
return fmt.Errorf("got %d elements, want %d\noverall:\ngot %v\nwant %v",
|
return fmt.Errorf("got %d elements, want %d\noverall:\ngot %v\nwant %v",
|
||||||
len(got), len(want), got, want)
|
len(got), len(want), got, want)
|
||||||
|
|
|
@ -415,43 +415,27 @@ func (g *glyfIter) close() {
|
||||||
g.closed = true
|
g.closed = true
|
||||||
g.seg = Segment{
|
g.seg = Segment{
|
||||||
Op: SegmentOpLineTo,
|
Op: SegmentOpLineTo,
|
||||||
Args: [6]fixed.Int26_6{
|
Args: [3]fixed.Point26_6{g.firstOnCurve},
|
||||||
g.firstOnCurve.X,
|
|
||||||
g.firstOnCurve.Y,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
case !g.firstOffCurveValid && g.lastOffCurveValid:
|
case !g.firstOffCurveValid && g.lastOffCurveValid:
|
||||||
g.closed = true
|
g.closed = true
|
||||||
g.seg = Segment{
|
g.seg = Segment{
|
||||||
Op: SegmentOpQuadTo,
|
Op: SegmentOpQuadTo,
|
||||||
Args: [6]fixed.Int26_6{
|
Args: [3]fixed.Point26_6{g.lastOffCurve, g.firstOnCurve},
|
||||||
g.lastOffCurve.X,
|
|
||||||
g.lastOffCurve.Y,
|
|
||||||
g.firstOnCurve.X,
|
|
||||||
g.firstOnCurve.Y,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
case g.firstOffCurveValid && !g.lastOffCurveValid:
|
case g.firstOffCurveValid && !g.lastOffCurveValid:
|
||||||
g.closed = true
|
g.closed = true
|
||||||
g.seg = Segment{
|
g.seg = Segment{
|
||||||
Op: SegmentOpQuadTo,
|
Op: SegmentOpQuadTo,
|
||||||
Args: [6]fixed.Int26_6{
|
Args: [3]fixed.Point26_6{g.firstOffCurve, g.firstOnCurve},
|
||||||
g.firstOffCurve.X,
|
|
||||||
g.firstOffCurve.Y,
|
|
||||||
g.firstOnCurve.X,
|
|
||||||
g.firstOnCurve.Y,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
case g.firstOffCurveValid && g.lastOffCurveValid:
|
case g.firstOffCurveValid && g.lastOffCurveValid:
|
||||||
mid := midPoint(g.lastOffCurve, g.firstOffCurve)
|
|
||||||
g.lastOffCurveValid = false
|
g.lastOffCurveValid = false
|
||||||
g.seg = Segment{
|
g.seg = Segment{
|
||||||
Op: SegmentOpQuadTo,
|
Op: SegmentOpQuadTo,
|
||||||
Args: [6]fixed.Int26_6{
|
Args: [3]fixed.Point26_6{
|
||||||
g.lastOffCurve.X,
|
g.lastOffCurve,
|
||||||
g.lastOffCurve.Y,
|
midPoint(g.lastOffCurve, g.firstOffCurve),
|
||||||
mid.X,
|
|
||||||
mid.Y,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -485,10 +469,7 @@ func (g *glyfIter) nextSegment() (ok bool) {
|
||||||
g.firstOnCurveValid = true
|
g.firstOnCurveValid = true
|
||||||
g.seg = Segment{
|
g.seg = Segment{
|
||||||
Op: SegmentOpMoveTo,
|
Op: SegmentOpMoveTo,
|
||||||
Args: [6]fixed.Int26_6{
|
Args: [3]fixed.Point26_6{p},
|
||||||
p.X,
|
|
||||||
p.Y,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
} else if !g.firstOffCurveValid {
|
} else if !g.firstOffCurveValid {
|
||||||
|
@ -496,17 +477,13 @@ func (g *glyfIter) nextSegment() (ok bool) {
|
||||||
g.firstOffCurveValid = true
|
g.firstOffCurveValid = true
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
midp := midPoint(g.firstOffCurve, p)
|
g.firstOnCurve = midPoint(g.firstOffCurve, p)
|
||||||
g.firstOnCurve = midp
|
|
||||||
g.firstOnCurveValid = true
|
g.firstOnCurveValid = true
|
||||||
g.lastOffCurve = p
|
g.lastOffCurve = p
|
||||||
g.lastOffCurveValid = true
|
g.lastOffCurveValid = true
|
||||||
g.seg = Segment{
|
g.seg = Segment{
|
||||||
Op: SegmentOpMoveTo,
|
Op: SegmentOpMoveTo,
|
||||||
Args: [6]fixed.Int26_6{
|
Args: [3]fixed.Point26_6{g.firstOnCurve},
|
||||||
midp.X,
|
|
||||||
midp.Y,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -519,24 +496,18 @@ func (g *glyfIter) nextSegment() (ok bool) {
|
||||||
} else {
|
} else {
|
||||||
g.seg = Segment{
|
g.seg = Segment{
|
||||||
Op: SegmentOpLineTo,
|
Op: SegmentOpLineTo,
|
||||||
Args: [6]fixed.Int26_6{
|
Args: [3]fixed.Point26_6{p},
|
||||||
p.X,
|
|
||||||
p.Y,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if !g.on {
|
if !g.on {
|
||||||
midp := midPoint(g.lastOffCurve, p)
|
|
||||||
g.seg = Segment{
|
g.seg = Segment{
|
||||||
Op: SegmentOpQuadTo,
|
Op: SegmentOpQuadTo,
|
||||||
Args: [6]fixed.Int26_6{
|
Args: [3]fixed.Point26_6{
|
||||||
g.lastOffCurve.X,
|
g.lastOffCurve,
|
||||||
g.lastOffCurve.Y,
|
midPoint(g.lastOffCurve, p),
|
||||||
midp.X,
|
|
||||||
midp.Y,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
g.lastOffCurve = p
|
g.lastOffCurve = p
|
||||||
|
@ -545,12 +516,7 @@ func (g *glyfIter) nextSegment() (ok bool) {
|
||||||
} else {
|
} else {
|
||||||
g.seg = Segment{
|
g.seg = Segment{
|
||||||
Op: SegmentOpQuadTo,
|
Op: SegmentOpQuadTo,
|
||||||
Args: [6]fixed.Int26_6{
|
Args: [3]fixed.Point26_6{g.lastOffCurve, p},
|
||||||
g.lastOffCurve.X,
|
|
||||||
g.lastOffCurve.Y,
|
|
||||||
p.X,
|
|
||||||
p.Y,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
g.lastOffCurveValid = false
|
g.lastOffCurveValid = false
|
||||||
return true
|
return true
|
||||||
|
|
Loading…
Reference in New Issue
Block a user