*Shape to Shape

This commit is contained in:
DataHoarder 2023-11-26 20:34:44 +01:00
parent c09f81ee4e
commit 909506fab6
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk
30 changed files with 162 additions and 214 deletions

View file

@ -77,8 +77,8 @@ func (l *EventLine) Transition(frameInfo types.FrameInformation, object *types.R
return nil
}
}
if colorTag, ok := t.(tag.ClipPathTag); ok {
t = colorTag.TransitionClipPath(&line, object.Clip)
if clipTag, ok := t.(tag.ClipPathTag); ok {
t = clipTag.TransitionClipPath(&line, object.Clip)
if t == nil {
return nil
}

View file

@ -24,28 +24,25 @@ func NewClipTag(clip *shapes.ClipPath, scale int) *ClipTag {
}
} else {
shape := clip.GetShape()
if len(shape.Edges) == 0 { //full clip
shape = &shapes.Shape{
Edges: []records.Record{
&records.LineRecord{
//TODO: ??? why TwipFactor here???
To: math.NewVector2[float64](0, swftypes.Twip(swftypes.TwipFactor).Float64()),
Start: math.NewVector2[float64](0, 0),
},
if len(shape) == 0 { //full clip
shape = shapes.Shape{
&records.LineRecord{
//TODO: ??? why TwipFactor here???
To: math.NewVector2[float64](0, swftypes.Twip(swftypes.TwipFactor).Float64()),
Start: math.NewVector2[float64](0, 0),
},
IsFlat: true,
}
}
return &ClipTag{
Scale: scale,
BaseDrawingTag: BaseDrawingTag(*shape),
BaseDrawingTag: BaseDrawingTag(shape),
}
}
}
func (t *ClipTag) ApplyMatrixTransform(transform math.MatrixTransform, applyTranslation bool) DrawingTag {
return &ClipTag{
BaseDrawingTag: BaseDrawingTag(*t.AsShape().ApplyMatrixTransform(transform, applyTranslation)),
BaseDrawingTag: BaseDrawingTag(t.AsShape().ApplyMatrixTransform(transform, applyTranslation)),
Scale: t.Scale,
}
}

View file

@ -88,7 +88,7 @@ func (t *ContainerTag) TransitionStyleRecord(event Event, record shapes.StyleRec
return container
}
func (t *ContainerTag) TransitionShape(event Event, shape *shapes.Shape) PathTag {
func (t *ContainerTag) TransitionShape(event Event, shape shapes.Shape) PathTag {
container := t.Clone(false)
index := event.GetEnd() - event.GetStart()
@ -292,7 +292,7 @@ func ContainerTagFromPathEntry(path shapes.DrawPath, clip *shapes.ClipPath, colo
}
*/
if len(path.Commands.Edges) == 0 {
if len(path.Commands) == 0 {
return nil
}

View file

@ -13,21 +13,21 @@ type DrawTag struct {
Scale int
}
func NewDrawTag(shape *shapes.Shape, scale int) *DrawTag {
func NewDrawTag(shape shapes.Shape, scale int) *DrawTag {
return &DrawTag{
Scale: scale,
BaseDrawingTag: BaseDrawingTag(*shape),
BaseDrawingTag: BaseDrawingTag(shape),
}
}
func (t *DrawTag) ApplyMatrixTransform(transform math.MatrixTransform, applyTranslation bool) DrawingTag {
return &DrawTag{
BaseDrawingTag: BaseDrawingTag(*t.AsShape().ApplyMatrixTransform(transform, applyTranslation)),
BaseDrawingTag: BaseDrawingTag(t.AsShape().ApplyMatrixTransform(transform, applyTranslation)),
Scale: t.Scale,
}
}
func (t *DrawTag) TransitionShape(event Event, shape *shapes.Shape) PathTag {
func (t *DrawTag) TransitionShape(event Event, shape shapes.Shape) PathTag {
if t.AsShape().Equals(shape) {
return t
}

View file

@ -10,7 +10,7 @@ import (
type DrawingTag interface {
Tag
ApplyMatrixTransform(transform math.MatrixTransform, applyTranslation bool) DrawingTag
AsShape() *shapes.Shape
AsShape() shapes.Shape
GetCommands(scale, precision int) string
}
@ -41,15 +41,15 @@ func vectorToPrecisionAndScale(buf []byte, scale, precision int, v math.Vector2[
return buf
}
func (b *BaseDrawingTag) AsShape() *shapes.Shape {
return (*shapes.Shape)(b)
func (b *BaseDrawingTag) AsShape() shapes.Shape {
return *(*shapes.Shape)(b)
}
func (b *BaseDrawingTag) GetCommands(scale, precision int) string {
var lastEdge records.Record
commands := make([]byte, 0, len(b.Edges)*2*10)
for _, edge := range b.Edges {
commands := make([]byte, 0, len(*b)*2*10)
for _, edge := range *b {
moveRecord, isMoveRecord := edge.(*records.MoveRecord)
if !isMoveRecord {
if lastEdge == nil {

View file

@ -30,7 +30,7 @@ type PositioningTag interface {
type PathTag interface {
Tag
TransitionShape(event Event, shape *shapes.Shape) PathTag
TransitionShape(event Event, shape shapes.Shape) PathTag
}
type ClipPathTag interface {

View file

@ -175,11 +175,11 @@ func main() {
}
if object.Clip != nil {
clipCalls++
clipItems += len(object.Clip.GetShape().Edges)
clipItems += len(object.Clip.GetShape())
}
for _, p := range object.DrawPathList {
drawCalls++
drawItems += len(p.Commands.Edges)
drawItems += len(p.Commands)
}
filteredRendered = append(filteredRendered, object)
}

View file

@ -34,7 +34,7 @@ func (d *MorphShapeDefinition) GetShapeList(p shapes.ObjectProperties) (list sha
var shape shapes.Shape
for _, recordPair := range shapes.IterateMorphShape(c1.Commands, c2.Commands) {
shape.AddRecord(records.LerpRecord(recordPair[0], recordPair[1], p.Ratio))
shape = append(shape, records.LerpRecord(recordPair[0], recordPair[1], p.Ratio))
}
//TODO: morph styles properly
@ -44,9 +44,9 @@ func (d *MorphShapeDefinition) GetShapeList(p shapes.ObjectProperties) (list sha
c2LineStyle, c2IsLineStyle := c2.Style.(*shapes.LineStyleRecord)
if c1IsFillStyle && c2IsFillStyle {
list = append(list, shapes.DrawPathFill(shapes.LerpFillStyle(c1FillStyle, c2FillStyle, p.Ratio), &shape, c1.Clip))
list = append(list, shapes.DrawPathFill(shapes.LerpFillStyle(c1FillStyle, c2FillStyle, p.Ratio), shape, c1.Clip))
} else if c1IsLineStyle && c2IsLineStyle {
list = append(list, shapes.DrawPathStroke(shapes.LerpLineStyle(c1LineStyle, c2LineStyle, p.Ratio), &shape, c1.Clip))
list = append(list, shapes.DrawPathStroke(shapes.LerpLineStyle(c1LineStyle, c2LineStyle, p.Ratio), shape, c1.Clip))
} else {
panic("unsupported")
}

View file

@ -94,7 +94,7 @@ func (p *SWFProcessor) NextFrameOutput() *FrameInformation {
//TODO: actions?
frame.AddChild(BackgroundObjectDepth, NewViewFrame(BackgroundObjectId, &shapes.DrawPathList{shapes.DrawPathFill(p.Background, shapes.NewShape(p.ViewPort.Draw()), nil)}))
frame.AddChild(BackgroundObjectDepth, NewViewFrame(BackgroundObjectId, &shapes.DrawPathList{shapes.DrawPathFill(p.Background, p.ViewPort.Draw(), nil)}))
return &FrameInformation{
FrameNumber: p.Frame - 1,
FrameRate: p.FrameRate,

View file

@ -115,7 +115,7 @@ func (f *ViewFrame) Render(baseDepth uint16, depthChain Depth, parentColor *math
}
}
if len(clipShape.GetShape().Edges) > 0 {
if len(clipShape.GetShape()) > 0 {
clipShape = clipShape.ApplyMatrixTransform(clipObject.MatrixTransform, true)
if clipPath == nil {
clipPath = clipShape

View file

@ -77,11 +77,11 @@ func (r *CubicCurveRecord) ToSingleQuadraticRecord() *QuadraticCurveRecord {
return nil
}
func (r *CubicCurveRecord) ToLineRecords(scale int64) []*LineRecord {
func (r *CubicCurveRecord) ToLineRecords(scale int64) []Record {
distanceToleranceSquare := math.Pow(0.5/float64(scale), 2)
points := CubicRecursiveBezier(nil, 0.0, BezierCurveAngleTolerance, distanceToleranceSquare, r.Start, r.Control1, r.Control2, r.Anchor, 0)
result := make([]*LineRecord, 0, len(points)+1)
result := make([]Record, 0, len(points)+1)
var current = r.Start

View file

@ -61,11 +61,11 @@ func QuadraticCurveFromLineRecord(l *LineRecord) *QuadraticCurveRecord {
}
}
func (r *QuadraticCurveRecord) ToLineRecords(scale int64) []*LineRecord {
func (r *QuadraticCurveRecord) ToLineRecords(scale int64) []Record {
distanceToleranceSquare := math.Pow(0.5/float64(scale), 2)
points := QuadraticRecursiveBezier(nil, BezierCurveAngleTolerance, distanceToleranceSquare, r.Start, r.Control, r.Anchor, 0)
result := make([]*LineRecord, 0, len(points)+1)
result := make([]Record, 0, len(points)+1)
var current = r.Start

View file

@ -19,4 +19,9 @@ type Record interface {
IsFlat() bool
}
type CurvedRecord interface {
Record
ToLineRecords(scale int64) []Record
}
type RecordPair [2]Record

12
types/records/flatten.go Normal file
View file

@ -0,0 +1,12 @@
package records
func FlattenRecord(r Record, scale int64) []Record {
if cr, ok := r.(CurvedRecord); ok {
return cr.ToLineRecords(scale)
} else if lr, ok := r.(*LineRecord); ok {
return []Record{lr}
} else {
panic("not supported")
return nil
}
}

View file

@ -18,7 +18,7 @@ func (b Bitmap) ApplyColorTransform(transform math2.ColorTransform) Fillable {
return b2
}
func (b Bitmap) Fill(shape *Shape) DrawPathList {
func (b Bitmap) Fill(shape Shape) DrawPathList {
return b.List.Fill(shape)
}

View file

@ -178,7 +178,7 @@ func ConvertBitmapToDrawPathList(i image.Image) (r DrawPathList) {
{float64(iX + 1), float64(y)},
}}
if existingColor, ok := myResults[p]; ok {
u := existingColor.Union(poly).Simplify(0.01).(geom.Polygonal)
u := existingColor.Union(poly).Simplify(PolygonSimplifyTolerance).(geom.Polygonal)
myResults[p] = u
} else {
myResults[p] = poly
@ -204,10 +204,10 @@ func ConvertBitmapToDrawPathList(i image.Image) (r DrawPathList) {
continue
}
if existingColor, ok := colors[k]; ok {
u := existingColor.Union(c).Simplify(0.01).(geom.Polygonal)
u := existingColor.Union(c).Simplify(PolygonSimplifyTolerance).(geom.Polygonal)
colors[k] = u
} else {
colors[k] = c.Simplify(0.01).(geom.Polygonal)
colors[k] = c.Simplify(PolygonSimplifyTolerance).(geom.Polygonal)
}
}
}
@ -246,17 +246,17 @@ func ConvertBitmapToDrawPathList(i image.Image) (r DrawPathList) {
r = append(r, DrawPathFill(&FillStyleRecord{
Fill: k.Color(),
}, ComplexPolygon{
Pol: pol.Simplify(0.01).(geom.Polygonal),
Pol: pol.Simplify(PolygonSimplifyTolerance).(geom.Polygonal),
}.GetShape(), nil))
}*/
//make a rectangle covering the whole first area to optimize this case
r = append(r, DrawPathFill(&FillStyleRecord{
Fill: keys[0].Color(),
}, NewShape(Rectangle[float64]{
}, Rectangle[float64]{
TopLeft: math.NewVector2[float64](0, 0),
BottomRight: math.NewVector2(float64(size.X+1), float64(size.Y+1)),
}.Draw()), nil))
}.Draw(), nil))
for _, k := range keys[1:] {
pol := colors[k]

View file

@ -9,14 +9,7 @@ type ClipPath struct {
Clip ComplexPolygon
}
func NewClipPath(shape *Shape) *ClipPath {
if shape == nil {
return &ClipPath{
Clip: ComplexPolygon{
Pol: NewPolygonFromShape(&Shape{}),
},
}
}
func NewClipPath(shape Shape) *ClipPath {
return &ClipPath{
Clip: ComplexPolygon{
Pol: NewPolygonFromShape(shape),
@ -24,11 +17,11 @@ func NewClipPath(shape *Shape) *ClipPath {
}
}
func (c *ClipPath) AddShape(shape *Shape) {
func (c *ClipPath) AddShape(shape Shape) {
c.Clip.Pol = c.Clip.Pol.Union(NewPolygonFromShape(shape))
}
func (c *ClipPath) GetShape() *Shape {
func (c *ClipPath) GetShape() Shape {
return c.Clip.GetShape()
}
@ -57,7 +50,7 @@ func (c *ClipPath) Merge(o *ClipPath) *ClipPath {
}
}
func (c *ClipPath) ClipShape(o *Shape) *Shape {
func (c *ClipPath) ClipShape(o Shape) Shape {
return c.Clip.Intersect(ComplexPolygon{
Pol: NewPolygonFromShape(o),
}).GetShape()

View file

@ -24,37 +24,33 @@ func (p ComplexPolygon) Intersect(o ComplexPolygon) ComplexPolygon {
const PolygonSimplifyTolerance = 0.01
func (p ComplexPolygon) GetShape() (r *Shape) {
var edges []records.Record
func (p ComplexPolygon) GetShape() (r Shape) {
for _, pol := range p.Pol.Polygons() {
for _, path := range pol.Simplify(0.01).(geom.Polygon) {
for _, path := range pol.Simplify(PolygonSimplifyTolerance).(geom.Polygon) {
//pol = pol.Simplify(PolygonSimplifyTolerance).(geom.Polygon)
edges = append(edges, &records.LineRecord{
r = append(r, &records.LineRecord{
To: math.NewVector2(path[1].X, path[1].Y),
Start: math.NewVector2(path[0].X, path[0].Y),
})
for _, point := range path[2:] {
edges = append(edges, &records.LineRecord{
r = append(r, &records.LineRecord{
To: math.NewVector2(point.X, point.Y),
Start: edges[len(edges)-1].GetEnd(),
Start: r[len(r)-1].GetEnd(),
})
}
}
}
return &Shape{
Edges: edges,
IsFlat: true,
}
return r
}
func NewPolygonFromShape(shape *Shape) (g geom.Polygon) {
func NewPolygonFromShape(shape Shape) (g geom.Polygon) {
flat := shape.Flatten()
var edges []*records.LineRecord
var lastEdge *records.LineRecord
for _, record := range flat.Edges {
for _, record := range flat {
if lastEdge != nil && !lastEdge.GetEnd().Equals(record.GetStart()) {
g = append(g, NewPathFromEdges(edges))
edges = edges[:0]
@ -102,6 +98,6 @@ func NewPathFromEdges(edges []*records.LineRecord) (p geom.Path) {
return p
}
func (p ComplexPolygon) Draw() []records.Record {
return p.GetShape().Edges
func (p ComplexPolygon) Draw() Shape {
return p.GetShape()
}

View file

@ -5,7 +5,7 @@ import "git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
type DrawPath struct {
Style StyleRecord
Clip *ClipPath
Commands *Shape
Commands Shape
}
func (p DrawPath) ApplyMatrixTransform(transform math.MatrixTransform, applyTranslation bool) (r DrawPath) {
@ -36,7 +36,7 @@ func (p DrawPath) ApplyColorTransform(transform math.ColorTransform) (r DrawPath
}
}
func DrawPathFill(record *FillStyleRecord, shape *Shape, clip *ClipPath) DrawPath {
func DrawPathFill(record *FillStyleRecord, shape Shape, clip *ClipPath) DrawPath {
return DrawPath{
Style: record,
Commands: shape,
@ -44,7 +44,7 @@ func DrawPathFill(record *FillStyleRecord, shape *Shape, clip *ClipPath) DrawPat
}
}
func DrawPathStroke(record *LineStyleRecord, shape *Shape, clip *ClipPath) DrawPath {
func DrawPathStroke(record *LineStyleRecord, shape Shape, clip *ClipPath) DrawPath {
return DrawPath{
Style: record,
Commands: shape,

View file

@ -22,7 +22,7 @@ func (l DrawPathList) ApplyFunction(f func(p DrawPath) DrawPath) (r DrawPathList
return r
}
func (l DrawPathList) Fill(shape *Shape) (r DrawPathList) {
func (l DrawPathList) Fill(shape Shape) (r DrawPathList) {
if false { //TODO
clipShape := NewClipPath(shape)
@ -32,7 +32,7 @@ func (l DrawPathList) Fill(shape *Shape) (r DrawPathList) {
Style: innerPath.Style,
Commands: clipShape.ClipShape(innerPath.Commands),
}
if len(newPath.Commands.Edges) == 0 {
if len(newPath.Commands) == 0 {
continue
}
@ -50,7 +50,7 @@ func (l DrawPathList) Fill(shape *Shape) (r DrawPathList) {
Commands: innerPath.Commands,
Clip: clipShape,
}
if len(newPath.Commands.Edges) == 0 {
if len(newPath.Commands) == 0 {
continue
}

View file

@ -51,7 +51,7 @@ func (g Gradient) ApplyColorTransform(transform math2.ColorTransform) Fillable {
return &g2
}
func (g Gradient) Fill(shape *Shape) DrawPathList {
func (g Gradient) Fill(shape Shape) DrawPathList {
return g.GetInterpolatedDrawPaths(settings.GlobalSettings.GradientOverlap, settings.GlobalSettings.GradientBlur, settings.GlobalSettings.GradientSlices).Fill(shape)
}

View file

@ -33,10 +33,10 @@ func LinearGradientFromSWF(records []swfsubtypes.GRADRECORD, transform types.MAT
Fill: item.Color,
Blur: blur,
},
NewShape(Rectangle[float64]{
Rectangle[float64]{
TopLeft: math.NewVector2(GradientBounds.TopLeft.X+item.Start*size-overlap/2, GradientBounds.TopLeft.Y),
BottomRight: math.NewVector2(GradientBounds.TopLeft.X+item.End*size+overlap/2, GradientBounds.BottomRight.Y),
}.Draw()),
}.Draw(),
nil, //TODO: clip here instead of outside
).ApplyMatrixTransform(self.Transform, true))
}

View file

@ -76,14 +76,12 @@ func (s *PathSegment[T]) TryMerge(o *PathSegment[T], isDirected bool) bool {
return false
}
func (s *PathSegment[T]) GetShape() *Shape {
func (s *PathSegment[T]) GetShape() (shape Shape) {
if s.IsEmpty() {
panic("not possible")
}
shape := &Shape{
Edges: make([]records.Record, 0, len(*s)-1),
}
shape = make(Shape, 0, len(*s)-1)
points := *s
@ -100,7 +98,7 @@ func (s *PathSegment[T]) GetShape() *Shape {
point := next()
if !point.IsBezierControl {
shape.AddRecord(&records.LineRecord{
shape = append(shape, &records.LineRecord{
To: point.Pos.Float64(),
Start: lastPos,
})
@ -111,7 +109,7 @@ func (s *PathSegment[T]) GetShape() *Shape {
}
end := next()
shape.AddRecord(&records.QuadraticCurveRecord{
shape = append(shape, &records.QuadraticCurveRecord{
Control: point.Pos.Float64(),
Anchor: end.Pos.Float64(),
Start: lastPos,

View file

@ -36,8 +36,7 @@ func (p *PendingPath[T]) MergePath(newSegment *PathSegment[T], directed bool) {
}
}
func (p *PendingPath[T]) GetShape() *Shape {
shape := &Shape{}
func (p *PendingPath[T]) GetShape() (shape Shape) {
for _, segment := range *p {
shape = shape.Merge(segment.GetShape())
}

View file

@ -37,14 +37,14 @@ func RadialGradientFromSWF(records []swfsubtypes.GRADRECORD, transform types.MAT
start = nil
}
end := NewCircle(math.NewVector2[float64](0, 0), radiusEnd).Draw()
shape.Edges = append(shape.Edges, end...)
shape.Edges = append(shape.Edges, NewShape(start).Reverse().Edges...)
shape = append(shape, end...)
shape = append(shape, start.Reverse()...)
paths = append(paths, DrawPathFill(
&FillStyleRecord{
Fill: item.Color,
Blur: blur,
},
&shape,
shape,
nil, //TODO: clip here instead of outside
))
}

View file

@ -5,138 +5,92 @@ import (
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/records"
)
type Shape struct {
Edges []records.Record
type Shape []records.Record
IsFlat bool
}
func NewShape(edges []records.Record) *Shape {
s := &Shape{
IsFlat: true,
}
s.Edges = make([]records.Record, 0, len(edges))
for i := range edges {
s.AddRecord(edges[i])
}
return s
}
func (s *Shape) AddRecord(record records.Record) {
if !record.IsFlat() {
s.IsFlat = false
}
s.Edges = append(s.Edges, record)
}
func (s *Shape) ApplyMatrixTransform(transform math.MatrixTransform, applyTranslation bool) *Shape {
newShape := NewShape(nil)
newShape.Edges = make([]records.Record, 0, len(s.Edges))
for _, edge := range s.Edges {
newShape.AddRecord(edge.ApplyMatrixTransform(transform, applyTranslation))
func (s Shape) ApplyMatrixTransform(transform math.MatrixTransform, applyTranslation bool) (newShape Shape) {
newShape = make(Shape, 0, len(s))
for _, edge := range s {
newShape = append(newShape, edge.ApplyMatrixTransform(transform, applyTranslation))
}
return newShape
}
func (s *Shape) Start() math.Vector2[float64] {
if len(s.Edges) == 0 {
func (s Shape) Start() math.Vector2[float64] {
if len(s) == 0 {
return math.NewVector2[float64](0, 0)
}
return s.Edges[0].GetStart()
return s[0].GetStart()
}
func (s *Shape) End() math.Vector2[float64] {
if len(s.Edges) == 0 {
func (s Shape) End() math.Vector2[float64] {
if len(s) == 0 {
return math.NewVector2[float64](0, 0)
}
return s.Edges[len(s.Edges)-1].GetEnd()
return s[len(s)-1].GetEnd()
}
func (s *Shape) IsClosed() bool {
return s.Start().Equals(s.End())
}
func (s *Shape) Reverse() *Shape {
r := &Shape{
Edges: make([]records.Record, len(s.Edges)),
IsFlat: s.IsFlat,
}
for i, e := range s.Edges {
r.Edges[len(s.Edges)-1-i] = e.Reverse()
}
return r
}
func (s *Shape) Merge(o *Shape) *Shape {
r := &Shape{
Edges: make([]records.Record, 0, len(s.Edges)+len(o.Edges)),
}
if s.IsFlat == o.IsFlat {
r.IsFlat = s.IsFlat
}
r.Edges = append(r.Edges, s.Edges...)
r.Edges = append(r.Edges, o.Edges...)
return r
}
// Flatten Converts all non-linear records into line segments and returns a new Shape
func (s *Shape) Flatten() *Shape {
if s.IsFlat {
return s
}
r := &Shape{
Edges: make([]records.Record, 0, len(s.Edges)*4),
IsFlat: true,
}
for _, e := range s.Edges {
func (s Shape) IsFlat() bool {
for _, e := range s {
if !e.IsFlat() {
switch ce := e.(type) {
case *records.QuadraticCurveRecord:
for _, lr := range ce.ToLineRecords(1) {
rec := lr
r.Edges = append(r.Edges, rec)
}
case *records.CubicCurveRecord:
for _, lr := range ce.ToLineRecords(1) {
rec := lr
r.Edges = append(r.Edges, rec)
}
default:
panic("not implemented")
}
} else {
r.Edges = append(r.Edges, e)
}
}
return r
}
func (s *Shape) Equals(o *Shape) bool {
if len(s.Edges) != len(o.Edges) && s.IsFlat == o.IsFlat /* todo: check this last condition */ {
return false
}
for i := range s.Edges {
if !s.Edges[i].Equals(o.Edges[i]) {
return false
}
}
return true
}
func IterateMorphShape(start, end *Shape) (r []records.RecordPair) {
func (s Shape) IsClosed() bool {
return s.Start().Equals(s.End())
}
startEdges := start.Edges
endEdges := end.Edges
func (s Shape) Reverse() (r Shape) {
r = make(Shape, len(s))
for i, e := range s {
r[len(s)-1-i] = e.Reverse()
}
return r
}
func (s Shape) Merge(o Shape) (r Shape) {
r = make(Shape, 0, len(s)+len(o))
r = append(r, s...)
r = append(r, o...)
return r
}
// Flatten Converts all non-linear records into line segments and returns a new Shape
func (s Shape) Flatten() (r Shape) {
if s.IsFlat() {
return s
}
r = make(Shape, 0, len(s)*4)
for _, e := range s {
r = append(r, records.FlattenRecord(e, 1)...)
}
return r
}
func (s Shape) Equals(o Shape) bool {
if len(s) != len(o) {
return false
}
for i := range s {
if !s[i].Equals(o[i]) {
return false
}
}
return true
}
func IterateMorphShape(start, end Shape) (r []records.RecordPair) {
var prevStart, prevEnd records.Record
for len(startEdges) > 0 && len(endEdges) > 0 {
startEdge := startEdges[0]
endEdge := endEdges[0]
for len(start) > 0 && len(end) > 0 {
startEdge := start[0]
endEdge := end[0]
advanceStart := true
advanceEnd := true
@ -193,18 +147,18 @@ func IterateMorphShape(start, end *Shape) (r []records.RecordPair) {
}
if advanceStart {
startEdges = startEdges[1:]
start = start[1:]
}
if advanceEnd {
endEdges = endEdges[1:]
end = end[1:]
}
prevStart = startEdge
prevEnd = endEdge
}
if len(startEdges) != 0 || len(endEdges) != 0 {
if len(start) != 0 || len(end) != 0 {
panic("incompatible result")
}

View file

@ -15,7 +15,7 @@ type StyleRecord interface {
}
type Fillable interface {
Fill(shape *Shape) DrawPathList
Fill(shape Shape) DrawPathList
ApplyColorTransform(transform math.ColorTransform) Fillable
}
@ -36,7 +36,7 @@ func (r *FillStyleRecord) IsFlat() bool {
}
// Flatten Creates a fill that is only composed of FillStyleRecord with Fill being math.Color
func (r *FillStyleRecord) Flatten(s *Shape) DrawPathList {
func (r *FillStyleRecord) Flatten(s Shape) DrawPathList {
if _, ok := r.Fill.(math.Color); ok {
return DrawPathList{
{
@ -51,10 +51,8 @@ func (r *FillStyleRecord) Flatten(s *Shape) DrawPathList {
}
fill := fillable.Fill(s)
r.fillCache.List = fill
r.fillCache.Shape = &Shape{
Edges: slices.Clone(s.Edges),
IsFlat: s.IsFlat,
}
s2 := slices.Clone(s)
r.fillCache.Shape = &s2
return fill
} else {
panic("not supported")

View file

@ -1,9 +1,5 @@
package shapes
import (
types2 "git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/records"
)
type Complex interface {
Draw() []types2.Record
Draw() Shape
}

View file

@ -29,10 +29,10 @@ func ellipseDrawQuarter(center, size math.Vector2[float64]) *records.CubicCurveR
}
}
func (r Ellipse[T]) Draw() []records.Record {
func (r Ellipse[T]) Draw() Shape {
center := r.Center.Float64()
radius := r.Radius.Float64()
return []records.Record{
return Shape{
ellipseDrawQuarter(center, math.NewVector2(-radius.X, radius.Y)),
ellipseDrawQuarter(center, radius).Reverse(), //Reverse so paths connect
ellipseDrawQuarter(center, math.NewVector2(radius.X, -radius.Y)),

View file

@ -47,10 +47,10 @@ func (r Rectangle[T]) Multiply(size T) Rectangle[T] {
}
}
func (r Rectangle[T]) Draw() []records.Record {
func (r Rectangle[T]) Draw() Shape {
tl := r.TopLeft.Float64()
br := r.BottomRight.Float64()
return []records.Record{
return Shape{
&records.LineRecord{
To: math.NewVector2(tl.X, br.Y),
Start: tl,