*Shape to Shape
This commit is contained in:
parent
c09f81ee4e
commit
909506fab6
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
12
types/records/flatten.go
Normal 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
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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
|
||||
))
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
package shapes
|
||||
|
||||
import (
|
||||
types2 "git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/records"
|
||||
)
|
||||
|
||||
type Complex interface {
|
||||
Draw() []types2.Record
|
||||
Draw() Shape
|
||||
}
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue