Made all vectors float64 instead of twip for enhanced precision, fixed containertag matrix transition

This commit is contained in:
DataHoarder 2023-11-22 11:08:09 +01:00
parent ecd58890fe
commit a77b91a618
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk
27 changed files with 160 additions and 153 deletions

View file

@ -4,11 +4,11 @@ import (
"fmt"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/ass/line"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/settings"
swftypes "git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/types"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/shapes"
"slices"
"strconv"
)
type Renderer struct {
@ -16,9 +16,7 @@ type Renderer struct {
RunningBuffer []*line.EventLine
}
func NewRenderer(frameRate float64, viewPort shapes.Rectangle[swftypes.Twip]) *Renderer {
display := shapes.RectangleToType[swftypes.Twip, float64](viewPort)
func NewRenderer(frameRate float64, display shapes.Rectangle[float64]) *Renderer {
width := int64(display.Width() * settings.GlobalSettings.VideoScaleMultiplier)
height := int64(display.Height() * settings.GlobalSettings.VideoScaleMultiplier)
@ -40,11 +38,12 @@ func NewRenderer(frameRate float64, viewPort shapes.Rectangle[swftypes.Twip]) *R
fmt.Sprintf("PlayResX: %d", width),
fmt.Sprintf("PlayResY: %d", height),
"",
"",
"[Aegisub Project Garbage]",
"Last Style Storage: f",
fmt.Sprintf("Video File: ?dummy:%f:10000:%d:%d:160:160:160:c", frameRate, width, height),
fmt.Sprintf("Video AR Value: %.4F", ar),
"Active EventLine: 0",
fmt.Sprintf("Video File: ?dummy:%s:10000:%d:%d:160:160:160:c", strconv.FormatFloat(frameRate, 'f', -1, 64), width, height),
fmt.Sprintf("Video AR Value: %.6F", ar),
"Active Line: 0",
"Video Zoom Percent: 2.000000",
"",
"[V4+ Styles]",
@ -63,8 +62,7 @@ func (r *Renderer) RenderFrame(frameInfo types.FrameInformation, frame types.Ren
r.Header = nil
}
objects := slices.Clone(frame)
slices.SortStableFunc(objects, RenderedObjectDepthSort)
slices.SortStableFunc(frame, RenderedObjectDepthSort)
var runningBuffer []*line.EventLine
@ -72,7 +70,7 @@ func (r *Renderer) RenderFrame(frameInfo types.FrameInformation, frame types.Ren
animated := 0
for _, object := range objects {
for _, object := range frame {
obEntry := *BakeRenderedObjectGradients(object)
object = &obEntry
@ -119,7 +117,7 @@ func (r *Renderer) RenderFrame(frameInfo types.FrameInformation, frame types.Ren
}
}
fmt.Printf("[ASS] Total %d objects, %d flush, %d buffer, %d animated tags.\n", len(objects), len(r.RunningBuffer), len(runningBuffer), animated)
fmt.Printf("[ASS] Total %d objects, %d flush, %d buffer, %d animated tags.\n", len(frame), len(r.RunningBuffer), len(runningBuffer), animated)
//Flush non dupes
for _, l := range r.RunningBuffer {

View file

@ -3,22 +3,21 @@ package tag
import (
"fmt"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/ass/time"
swftypes "git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/types"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/shapes"
)
type BorderTag struct {
Size math.Vector2[swftypes.Twip]
Size math.Vector2[float64]
}
func (t *BorderTag) FromStyleRecord(record shapes.StyleRecord) StyleTag {
if lineStyleRecord, ok := record.(*shapes.LineStyleRecord); ok {
t.Size = math.NewVector2[swftypes.Twip](lineStyleRecord.Width, lineStyleRecord.Width)
t.Size = math.NewVector2(lineStyleRecord.Width, lineStyleRecord.Width)
} else if fillStyleRecord, ok := record.(*shapes.FillStyleRecord); ok && fillStyleRecord.Border != nil {
t.Size = math.NewVector2[swftypes.Twip](fillStyleRecord.Border.Width, fillStyleRecord.Border.Width)
t.Size = math.NewVector2(fillStyleRecord.Border.Width, fillStyleRecord.Border.Width)
} else {
t.Size = math.NewVector2[swftypes.Twip](0, 0)
t.Size = math.NewVector2[float64](0, 0)
}
return t
}
@ -38,8 +37,8 @@ func (t *BorderTag) Equals(tag Tag) bool {
func (t *BorderTag) Encode(event time.EventTime) string {
if t.Size.X == t.Size.Y {
return fmt.Sprintf("\\bord%.02F", t.Size.X.Float64())
return fmt.Sprintf("\\bord%.02F", t.Size.X)
} else {
return fmt.Sprintf("\\xbord%.02F\\ybord%.02F", t.Size.X.Float64(), t.Size.Y.Float64())
return fmt.Sprintf("\\xbord%.02F\\ybord%.02F", t.Size.X, t.Size.Y)
}
}

View file

@ -30,9 +30,9 @@ func NewClipTag(clip *types.ClipPath, scale int64) *ClipTag {
shape = &shapes.Shape{
Edges: []records.Record{
&records.LineRecord{
//TODO: ??? why swftypes.TwipFactor here???
To: math.NewVector2[swftypes.Twip](0, swftypes.TwipFactor),
Start: math.NewVector2[swftypes.Twip](0, 0),
//TODO: ??? why TwipFactor here???
To: math.NewVector2[float64](0, swftypes.Twip(swftypes.TwipFactor).Float64()),
Start: math.NewVector2[float64](0, 0),
},
},
IsFlat: true,

View file

@ -38,7 +38,7 @@ func (t *ContainerTag) TransitionColor(event Event, transform math.ColorTransfor
return container
}
func (t *ContainerTag) TransitionMatrixTransform(event Event, transform math.MatrixTransform) ColorTag {
func (t *ContainerTag) TransitionMatrixTransform(event Event, transform math.MatrixTransform) PositioningTag {
if t.BakeTransforms != nil {
//Do not allow matrix changes, except moves
if !transform.EqualsWithoutTranslation(*t.BakeTransforms, math.TransformCompareEpsilon) {

View file

@ -2,7 +2,6 @@ package tag
import (
"fmt"
swftypes "git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/types"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/records"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/shapes"
@ -18,20 +17,20 @@ type DrawingTag interface {
type BaseDrawingTag shapes.Shape
func twipEntryToPrecisionAndScaleTag(tag string, scale, precision int64, vectors ...math.Vector2[swftypes.Twip]) string {
func entryToPrecisionAndScaleTag(tag string, scale, precision int64, vectors ...math.Vector2[float64]) string {
result := make([]string, 0, len(vectors)+1)
if len(tag) > 0 {
result = append(result, tag)
}
for _, v := range vectors {
result = append(result, twipVectorToPrecisionAndScale(scale, precision, v))
result = append(result, vectorToPrecisionAndScale(scale, precision, v))
}
return strings.Join(result, " ")
}
func twipVectorToPrecisionAndScale(scale, precision int64, v math.Vector2[swftypes.Twip]) string {
coords := v.Multiply(swftypes.Twip(scale))
return fmt.Sprintf("%.*f %.*f", precision, coords.X.Float64(), precision, coords.Y.Float64())
func vectorToPrecisionAndScale(scale, precision int64, v math.Vector2[float64]) string {
coords := v.Multiply(float64(scale))
return fmt.Sprintf("%.*f %.*f", precision, coords.X, precision, coords.Y)
}
func (b *BaseDrawingTag) AsShape() *shapes.Shape {
@ -46,20 +45,20 @@ func (b *BaseDrawingTag) GetCommands(scale, precision int64) []string {
moveRecord, isMoveRecord := edge.(*records.MoveRecord)
if !isMoveRecord {
if lastEdge == nil {
commands = append(commands, twipEntryToPrecisionAndScaleTag("m", scale, precision, edge.GetStart()))
commands = append(commands, entryToPrecisionAndScaleTag("m", scale, precision, edge.GetStart()))
} else if !lastEdge.GetEnd().Equals(edge.GetStart()) {
commands = append(commands, twipEntryToPrecisionAndScaleTag("m", scale, precision, edge.GetStart()))
commands = append(commands, entryToPrecisionAndScaleTag("m", scale, precision, edge.GetStart()))
lastEdge = nil
}
}
if isMoveRecord {
commands = append(commands, twipEntryToPrecisionAndScaleTag("m", scale, precision, moveRecord.To))
commands = append(commands, entryToPrecisionAndScaleTag("m", scale, precision, moveRecord.To))
} else if lineRecord, ok := edge.(*records.LineRecord); ok {
if _, ok = lastEdge.(*records.LineRecord); ok {
commands = append(commands, twipEntryToPrecisionAndScaleTag("", scale, precision, lineRecord.To))
commands = append(commands, entryToPrecisionAndScaleTag("", scale, precision, lineRecord.To))
} else {
commands = append(commands, twipEntryToPrecisionAndScaleTag("l", scale, precision, lineRecord.To))
commands = append(commands, entryToPrecisionAndScaleTag("l", scale, precision, lineRecord.To))
}
} else if quadraticRecord, ok := edge.(*records.QuadraticCurveRecord); ok {
edge = records.CubicCurveFromQuadraticRecord(quadraticRecord)
@ -67,9 +66,9 @@ func (b *BaseDrawingTag) GetCommands(scale, precision int64) []string {
if cubicRecord, ok := edge.(*records.CubicCurveRecord); ok {
if _, ok = lastEdge.(*records.CubicCurveRecord); ok {
commands = append(commands, twipEntryToPrecisionAndScaleTag("", scale, precision, cubicRecord.Control1, cubicRecord.Control2, cubicRecord.Anchor))
commands = append(commands, entryToPrecisionAndScaleTag("", scale, precision, cubicRecord.Control1, cubicRecord.Control2, cubicRecord.Anchor))
} else {
commands = append(commands, twipEntryToPrecisionAndScaleTag("b", scale, precision, cubicRecord.Control1, cubicRecord.Control2, cubicRecord.Anchor))
commands = append(commands, entryToPrecisionAndScaleTag("b", scale, precision, cubicRecord.Control1, cubicRecord.Control2, cubicRecord.Anchor))
}
} else if cubicSplineRecord, ok := edge.(*records.CubicSplineCurveRecord); ok {
_ = cubicSplineRecord

View file

@ -4,18 +4,17 @@ import (
"fmt"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/ass/time"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/settings"
swftypes "git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/types"
math2 "git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
"math"
)
type PositionTag struct {
From, To math2.Vector2[swftypes.Twip]
From, To math2.Vector2[float64]
Start, End int64
}
func (t *PositionTag) TransitionMatrixTransform(event Event, transform math2.MatrixTransform) PositioningTag {
translation := math2.MatrixTransformApplyToVector(transform, math2.NewVector2[swftypes.Twip](0, 0), true)
translation := math2.MatrixTransformApplyToVector(transform, math2.NewVector2[float64](0, 0), true)
frame := event.GetEnd() - event.GetStart()
@ -56,8 +55,8 @@ func (t *PositionTag) TransitionMatrixTransform(event Event, transform math2.Mat
direction := t.To.SubVector(t.From).Normalize()
//TODO: maybe use larger epsilon?
if math.Abs(direction.Dot(translation.Normalize())-1) <= math.SmallestNonzeroFloat64 { //Same direction, extend
length := t.To.SubVector(t.From).Divide(swftypes.Twip(duration)).SquaredLength().Float64()
length2 := translation.SubVector(t.To).SquaredLength().Float64()
length := t.To.SubVector(t.From).Divide(float64(duration)).SquaredLength()
length2 := translation.SubVector(t.To).SquaredLength()
if math.Abs(length-length2) <= math.SmallestNonzeroFloat64 { //same length
return &PositionTag{
@ -91,11 +90,11 @@ func (t *PositionTag) Encode(event time.EventTime) string {
end = event.GetDurationFromStartOffset(t.Start).Milliseconds()
}
//TODO: precision?
return fmt.Sprintf("\\move(%f,%f,%f,%f,%d,%d)", t.From.X.Float64(), t.From.Y.Float64(), t.To.X.Float64(), t.To.Y.Float64(), start, end)
return fmt.Sprintf("\\move(%f,%f,%f,%f,%d,%d)", t.From.X, t.From.Y, t.To.X, t.To.Y, start, end)
}
//TODO: precision?
return fmt.Sprintf("\\pos(%f,%f)", t.From.X.Float64(), t.From.Y.Float64())
return fmt.Sprintf("\\pos(%f,%f)", t.From.X, t.From.Y)
}
func (t *PositionTag) Equals(tag Tag) bool {
@ -106,7 +105,7 @@ func (t *PositionTag) Equals(tag Tag) bool {
}
func (t *PositionTag) FromMatrixTransform(transform math2.MatrixTransform) PositioningTag {
translation := math2.MatrixTransformApplyToVector(transform, math2.NewVector2[swftypes.Twip](0, 0), true)
translation := math2.MatrixTransformApplyToVector(transform, math2.NewVector2[float64](0, 0), true)
t.From = translation
t.To = translation
t.Start = 1

View file

@ -3,12 +3,11 @@ package tag
import (
"fmt"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/ass/time"
swftypes "git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/types"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/shapes"
)
type ShadowTag struct {
Depth swftypes.Twip
Depth float64
}
func (t *ShadowTag) FromStyleRecord(record shapes.StyleRecord) StyleTag {
@ -31,5 +30,5 @@ func (t *ShadowTag) Equals(tag Tag) bool {
}
func (t *ShadowTag) Encode(event time.EventTime) string {
return fmt.Sprintf("\\shad%.02F", t.Depth.Float64())
return fmt.Sprintf("\\shad%.02F", t.Depth)
}

View file

@ -21,6 +21,7 @@ type Settings struct {
// BakeMatrixTransforms Transforms the shapes directly instead of writing ASS override tags
// Reduces compressibility, but not affect positioning. \pos tags will still be emitted
// Enabling this is very expensive on players, also increases output size.
BakeMatrixTransforms bool
// SmoothTransitions Attempt to merge multiple fixed transitions into a single long one if they happen at constant rate

View file

@ -2,7 +2,6 @@ package types
import (
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/tag/subtypes"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/types"
math2 "git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/records"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/shapes"
@ -11,7 +10,7 @@ import (
type MorphShapeDefinition struct {
ObjectId uint16
StartBounds, EndBounds shapes.Rectangle[types.Twip]
StartBounds, EndBounds shapes.Rectangle[float64]
StartShapeList, EndShapeList shapes.DrawPathList
}
@ -106,7 +105,7 @@ func (d *MorphShapeDefinition) GetSafeObject() ObjectDefinition {
return d
}
func MorphShapeDefinitionFromSWF(shapeId uint16, startBounds, endBounds shapes.Rectangle[types.Twip], startRecords, endRecords subtypes.SHAPERECORDS, fillStyles subtypes.MORPHFILLSTYLEARRAY, lineStyles subtypes.MORPHLINESTYLEARRAY) *MorphShapeDefinition {
func MorphShapeDefinitionFromSWF(shapeId uint16, startBounds, endBounds shapes.Rectangle[float64], startRecords, endRecords subtypes.SHAPERECORDS, fillStyles subtypes.MORPHFILLSTYLEARRAY, lineStyles subtypes.MORPHLINESTYLEARRAY) *MorphShapeDefinition {
startStyles, endStyles := shapes.StyleListFromSWFMorphItems(fillStyles, lineStyles)
start := shapes.DrawPathListFromSWFMorph(startRecords, endRecords, startStyles, false)

View file

@ -2,7 +2,6 @@ package types
import (
swftag "git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/tag"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/types"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/shapes"
)
@ -15,14 +14,14 @@ type SWFProcessor struct {
SWFTreeProcessor
Background *shapes.FillStyleRecord
ViewPort shapes.Rectangle[types.Twip]
ViewPort shapes.Rectangle[float64]
FrameRate float64
ExpectedFrameCount int64
Audio *AudioStream
}
func NewSWFProcessor(tags []swftag.Tag, viewPort shapes.Rectangle[types.Twip], frameRate float64, frameCount int64) *SWFProcessor {
func NewSWFProcessor(tags []swftag.Tag, viewPort shapes.Rectangle[float64], frameRate float64, frameCount int64) *SWFProcessor {
p := &SWFProcessor{
SWFTreeProcessor: *NewSWFTreeProcessor(0, tags, make(ObjectCollection)),
Background: &shapes.FillStyleRecord{

View file

@ -2,13 +2,12 @@ package types
import (
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/tag/subtypes"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/types"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/shapes"
)
type ShapeDefinition struct {
ObjectId uint16
Bounds shapes.Rectangle[types.Twip]
Bounds shapes.Rectangle[float64]
ShapeList shapes.DrawPathList
}
@ -24,7 +23,7 @@ func (d *ShapeDefinition) GetSafeObject() ObjectDefinition {
return d
}
func ShapeDefinitionFromSWF(shapeId uint16, bounds shapes.Rectangle[types.Twip], records subtypes.SHAPERECORDS, fillStyles subtypes.FILLSTYLEARRAY, lineStyles subtypes.LINESTYLEARRAY) *ShapeDefinition {
func ShapeDefinitionFromSWF(shapeId uint16, bounds shapes.Rectangle[float64], records subtypes.SHAPERECORDS, fillStyles subtypes.FILLSTYLEARRAY, lineStyles subtypes.LINESTYLEARRAY) *ShapeDefinition {
styles := shapes.StyleListFromSWFItems(fillStyles, lineStyles)
drawPathList := shapes.DrawPathListFromSWF(records, styles)

View file

@ -18,7 +18,7 @@ const (
Trans
)
func TestMatrixTransform_Translate(t *testing.T) {
func TestMatrixTransform(t *testing.T) {
testVectors := []testVector{
{{0, 0}, {1, 1}, {0, 0}, {1000, -1000}},
{{1, 1}, {1, 1}, {0, 0}, {-1000, 1000}},
@ -75,7 +75,25 @@ func TestMatrixTransform_Translate(t *testing.T) {
t.Logf("[#%d] Expected\t%s", i, outputAlt.String())
t.Logf("[#%d] Matrix\n%s", i, m.String())
if !outputAlt.Equals(output) {
t.Errorf("[#%d] Failed!\n\n", i)
t.Errorf("[#%d] Failed: output mismatch!\n\n", i)
}
if m.GetA() != s[Scale][X] {
t.Fatal()
}
if m.GetB() != s[RotSkew][X] {
t.Fatal()
}
if m.GetC() != s[RotSkew][Y] {
t.Fatal()
}
if m.GetD() != s[Scale][Y] {
t.Fatal()
}
if m.GetTX() != s[Trans][X] {
t.Fatal()
}
if m.GetTY() != s[Trans][Y] {
t.Fatal()
}
}
}

View file

@ -1,22 +1,21 @@
package records
import (
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/types"
math2 "git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
"math"
)
type CubicCurveRecord struct {
Control1, Control2 math2.Vector2[types.Twip]
Anchor math2.Vector2[types.Twip]
Start math2.Vector2[types.Twip]
Control1, Control2 math2.Vector2[float64]
Anchor math2.Vector2[float64]
Start math2.Vector2[float64]
}
func (r *CubicCurveRecord) GetStart() math2.Vector2[types.Twip] {
func (r *CubicCurveRecord) GetStart() math2.Vector2[float64] {
return r.Start
}
func (r *CubicCurveRecord) GetEnd() math2.Vector2[types.Twip] {
func (r *CubicCurveRecord) GetEnd() math2.Vector2[float64] {
return r.Anchor
}
@ -80,19 +79,18 @@ func (r *CubicCurveRecord) ToSingleQuadraticRecord() *QuadraticCurveRecord {
func (r *CubicCurveRecord) ToLineRecords(scale int64) []*LineRecord {
distanceToleranceSquare := math.Pow(0.5/float64(scale), 2)
points := CubicRecursiveBezier(nil, 0.0, 0.0, distanceToleranceSquare, r.Start.Float64(), r.Control1.Float64(), r.Control2.Float64(), r.Anchor.Float64(), 0)
points := CubicRecursiveBezier(nil, 0.0, 0.0, distanceToleranceSquare, r.Start, r.Control1, r.Control2, r.Anchor, 0)
result := make([]*LineRecord, 0, len(points)+1)
var current = r.Start
for _, point := range points {
tp := math2.Vector2ToType[float64, types.Twip](point)
result = append(result, &LineRecord{
To: tp,
To: point,
Start: current,
})
current = tp
current = point
}
result = append(result, &LineRecord{

View file

@ -1,23 +1,22 @@
package records
import (
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/types"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
"reflect"
"slices"
)
type CubicSplineCurveRecord struct {
Control []math.Vector2[types.Twip]
Anchor math.Vector2[types.Twip]
Start math.Vector2[types.Twip]
Control []math.Vector2[float64]
Anchor math.Vector2[float64]
Start math.Vector2[float64]
}
func (r *CubicSplineCurveRecord) GetStart() math.Vector2[types.Twip] {
func (r *CubicSplineCurveRecord) GetStart() math.Vector2[float64] {
return r.Start
}
func (r *CubicSplineCurveRecord) GetEnd() math.Vector2[types.Twip] {
func (r *CubicSplineCurveRecord) GetEnd() math.Vector2[float64] {
return r.Anchor
}
@ -33,7 +32,7 @@ func (r *CubicSplineCurveRecord) Reverse() Record {
func (r *CubicSplineCurveRecord) ApplyMatrixTransform(transform math.MatrixTransform, applyTranslation bool) Record {
//TODO: see how accurate this is
controls := make([]math.Vector2[types.Twip], 0, len(r.Control))
controls := make([]math.Vector2[float64], 0, len(r.Control))
for _, c := range r.Control {
controls = append(controls, math.MatrixTransformApplyToVector(transform, c, applyTranslation))
}

View file

@ -1,20 +1,19 @@
package records
import (
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/types"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
)
type LineRecord struct {
To, Start math.Vector2[types.Twip]
To, Start math.Vector2[float64]
//TODO: intersections
}
func (r *LineRecord) GetStart() math.Vector2[types.Twip] {
func (r *LineRecord) GetStart() math.Vector2[float64] {
return r.Start
}
func (r *LineRecord) GetEnd() math.Vector2[types.Twip] {
func (r *LineRecord) GetEnd() math.Vector2[float64] {
return r.To
}
@ -25,11 +24,11 @@ func (r *LineRecord) Reverse() Record {
}
}
func (r *LineRecord) Delta() math.Vector2[types.Twip] {
func (r *LineRecord) Delta() math.Vector2[float64] {
return r.To.SubVector(r.Start)
}
func fake2DCross(a, b math.Vector2[types.Twip]) types.Twip {
func fake2DCross(a, b math.Vector2[float64]) float64 {
return a.X*b.Y - a.Y + b.X
}

View file

@ -1,19 +1,18 @@
package records
import (
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/types"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
)
type MoveRecord struct {
To, Start math.Vector2[types.Twip]
To, Start math.Vector2[float64]
}
func (r *MoveRecord) GetStart() math.Vector2[types.Twip] {
func (r *MoveRecord) GetStart() math.Vector2[float64] {
return r.Start
}
func (r *MoveRecord) GetEnd() math.Vector2[types.Twip] {
func (r *MoveRecord) GetEnd() math.Vector2[float64] {
return r.To
}

View file

@ -1,22 +1,21 @@
package records
import (
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/types"
math2 "git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
"math"
)
type QuadraticCurveRecord struct {
Control math2.Vector2[types.Twip]
Anchor math2.Vector2[types.Twip]
Start math2.Vector2[types.Twip]
Control math2.Vector2[float64]
Anchor math2.Vector2[float64]
Start math2.Vector2[float64]
}
func (r *QuadraticCurveRecord) GetStart() math2.Vector2[types.Twip] {
func (r *QuadraticCurveRecord) GetStart() math2.Vector2[float64] {
return r.Start
}
func (r *QuadraticCurveRecord) GetEnd() math2.Vector2[types.Twip] {
func (r *QuadraticCurveRecord) GetEnd() math2.Vector2[float64] {
return r.Anchor
}
@ -64,19 +63,18 @@ func QuadraticCurveFromLineRecord(l *LineRecord) *QuadraticCurveRecord {
func (r *QuadraticCurveRecord) ToLineRecords(scale int64) []*LineRecord {
distanceToleranceSquare := math.Pow(0.5/float64(scale), 2)
points := QuadraticRecursiveBezier(nil, 0.0, distanceToleranceSquare, r.Start.Float64(), r.Control.Float64(), r.Anchor.Float64(), 0)
points := QuadraticRecursiveBezier(nil, 0.0, distanceToleranceSquare, r.Start, r.Control, r.Anchor, 0)
result := make([]*LineRecord, 0, len(points)+1)
var current = r.Start
for _, point := range points {
tp := math2.Vector2ToType[float64, types.Twip](point)
result = append(result, &LineRecord{
To: tp,
To: point,
Start: current,
})
current = tp
current = point
}
result = append(result, &LineRecord{

View file

@ -1,13 +1,12 @@
package records
import (
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/types"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
)
type Record interface {
GetStart() math.Vector2[types.Twip]
GetEnd() math.Vector2[types.Twip]
GetStart() math.Vector2[float64]
GetEnd() math.Vector2[float64]
Reverse() Record

View file

@ -1,7 +1,6 @@
package shapes
import (
swftypes "git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/types"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/records"
"github.com/ctessum/geom"
@ -22,12 +21,12 @@ func (p ComplexPolygon) GetShape() (r *Shape) {
for _, pol := range p.Pol.Polygons() {
for _, path := range pol {
edges = append(edges, &records.LineRecord{
To: math.Vector2ToType[float64, swftypes.Twip](math.NewVector2(path[1].X, path[1].Y)),
Start: math.Vector2ToType[float64, swftypes.Twip](math.NewVector2(path[0].X, path[0].Y)),
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{
To: math.Vector2ToType[float64, swftypes.Twip](math.NewVector2(point.X, point.Y)),
To: math.NewVector2(point.X, point.Y),
Start: edges[len(edges)-1].GetEnd(),
})
}
@ -69,8 +68,8 @@ func NewPolygonFromShape(shape *Shape) (g geom.Polygon) {
func NewPathFromEdges(edges []*records.LineRecord) (p geom.Path) {
p = make(geom.Path, 0, len(edges)+1)
start := edges[0].Start.Float64()
to := edges[0].To.Float64()
start := edges[0].Start
to := edges[0].To
p = append(p, geom.Point{
X: start.X,
Y: start.Y,
@ -79,7 +78,7 @@ func NewPathFromEdges(edges []*records.LineRecord) (p geom.Path) {
Y: to.Y,
})
for _, e := range edges[1:] {
to = e.To.Float64()
to = e.To
p = append(p, geom.Point{
X: to.X,
Y: to.Y,

View file

@ -29,6 +29,16 @@ type GradientSlice struct {
Color math2.Color
}
const GradientBoundsMin = math.MinInt16 / 2
const GradientBoundsMax = -GradientBoundsMin
var GradientBounds = Rectangle[float64]{
TopLeft: math2.NewVector2[float64](GradientBoundsMin, GradientBoundsMin),
BottomRight: math2.NewVector2[float64](GradientBoundsMax, GradientBoundsMax),
}
const GradientRatioDivisor = math.MaxUint8
func LerpGradient(gradient Gradient, gradientSlices int) (result []GradientSlice) {
items := gradient.GetItems()
//TODO: spread modes
@ -46,9 +56,9 @@ func LerpGradient(gradient Gradient, gradientSlices int) (result []GradientSlice
items = slices.Insert(items, 0, first)
}
if last.Ratio != 255 {
if last.Ratio != GradientRatioDivisor {
last = GradientItem{
Ratio: 255,
Ratio: GradientRatioDivisor,
Color: last.Color,
}
items = append(items, last)
@ -56,7 +66,6 @@ func LerpGradient(gradient Gradient, gradientSlices int) (result []GradientSlice
prevItem := items[0]
for _, item := range items[1:] {
prevItem = item
prevColor := prevItem.Color
currentColor := item.Color
if interpolationMode == swfsubtypes.GradientInterpolationLinearRGB {
@ -68,15 +77,15 @@ func LerpGradient(gradient Gradient, gradientSlices int) (result []GradientSlice
prevPosition := float64(prevItem.Ratio)
currentPosition := float64(item.Ratio)
distance := math.Abs(prevPosition - currentPosition)
distance := math.Abs(currentPosition - prevPosition)
var partitions int
if maxColorDistance < math.SmallestNonzeroFloat64 {
partitions = 1
} else if gradientSlices == GradientAutoSlices {
partitions = max(1, int(math.Ceil(min(255/float64(len(items)+1), max(1, math.Ceil(maxColorDistance))))))
partitions = max(1, int(math.Ceil(min(GradientRatioDivisor/float64(len(items)+1), max(1, math.Ceil(maxColorDistance))))))
} else {
partitions = max(1, int(math.Ceil((distance/255)*float64(gradientSlices))))
partitions = max(1, int(math.Ceil((distance/GradientRatioDivisor)*float64(gradientSlices))))
}
fromPos := prevPosition
@ -91,12 +100,13 @@ func LerpGradient(gradient Gradient, gradientSlices int) (result []GradientSlice
toPos := math2.Lerp(prevPosition, currentPosition, ratio)
result = append(result, GradientSlice{
Start: fromPos / 255,
End: toPos / 255,
Start: fromPos / GradientRatioDivisor,
End: toPos / GradientRatioDivisor,
Color: color,
})
fromPos = toPos
}
prevItem = item
}
return result
}

View file

@ -29,9 +29,7 @@ func (g *LinearGradient) GetItems() []GradientItem {
func (g *LinearGradient) GetInterpolatedDrawPaths(overlap int, gradientSlices int) DrawPathList {
//items is max size 8 to 15 depending on SWF version
const minPosition = -16384
const maxPosition = 16384
const diffPosition = maxPosition - minPosition
size := GradientBounds.Width()
//TODO spreadMode
@ -41,9 +39,9 @@ func (g *LinearGradient) GetInterpolatedDrawPaths(overlap int, gradientSlices in
&FillStyleRecord{
Fill: item.Color,
},
NewShape(Rectangle[types.Twip]{
TopLeft: math.NewVector2[types.Twip](types.Twip(minPosition+item.Start*diffPosition-float64(overlap)/2), minPosition),
BottomRight: math.NewVector2[types.Twip](types.Twip(minPosition+item.End*diffPosition+float64(overlap)/2), maxPosition),
NewShape(Rectangle[float64]{
TopLeft: math.NewVector2(GradientBounds.TopLeft.X+item.Start*size-float64(overlap)/2, GradientBounds.TopLeft.Y),
BottomRight: math.NewVector2(GradientBounds.BottomRight.X+item.End*size+float64(overlap)/2, GradientBounds.BottomRight.Y),
}.Draw()),
))
}

View file

@ -95,17 +95,17 @@ func (s *PathSegment) GetShape() *Shape {
}
//lastPos := next().Pos
lastPos := points[0].Pos
lastPos := points[0].Pos.Float64()
for len(points) > 0 {
point := next()
if !point.IsBezierControl {
shape.AddRecord(&records.LineRecord{
To: point.Pos,
To: point.Pos.Float64(),
Start: lastPos,
})
lastPos = point.Pos
lastPos = point.Pos.Float64()
} else {
if len(points) == 0 {
panic("Bezier without endpoint")
@ -113,11 +113,11 @@ func (s *PathSegment) GetShape() *Shape {
end := next()
shape.AddRecord(&records.QuadraticCurveRecord{
Control: point.Pos,
Anchor: end.Pos,
Control: point.Pos.Float64(),
Anchor: end.Pos.Float64(),
Start: lastPos,
})
lastPos = end.Pos
lastPos = end.Pos.Float64()
}
}

View file

@ -1,7 +1,6 @@
package shapes
import (
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/types"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/records"
)
@ -40,16 +39,16 @@ func (s *Shape) ApplyMatrixTransform(transform math.MatrixTransform, applyTransl
return newShape
}
func (s *Shape) Start() math.Vector2[types.Twip] {
func (s *Shape) Start() math.Vector2[float64] {
if len(s.Edges) == 0 {
return math.NewVector2[types.Twip](0, 0)
return math.NewVector2[float64](0, 0)
}
return s.Edges[0].GetStart()
}
func (s *Shape) End() math.Vector2[types.Twip] {
func (s *Shape) End() math.Vector2[float64] {
if len(s.Edges) == 0 {
return math.NewVector2[types.Twip](0, 0)
return math.NewVector2[float64](0, 0)
}
return s.Edges[len(s.Edges)-1].GetEnd()
}

View file

@ -34,7 +34,7 @@ func StyleListFromSWFItems(fillStyles subtypes.FILLSTYLEARRAY, lineStyles subtyp
for _, s := range lineStyles.LineStyles {
r.LineStyles = append(r.LineStyles, &LineStyleRecord{
//TODO: any reason for max(types.TwipFactor)?
Width: max(types.Twip(s.Width), types.TwipFactor),
Width: max(types.Twip(s.Width), types.TwipFactor).Float64(),
Color: math.Color{
R: s.Color.R(),
G: s.Color.G(),
@ -48,7 +48,7 @@ func StyleListFromSWFItems(fillStyles subtypes.FILLSTYLEARRAY, lineStyles subtyp
if !s.Flag.HasFill {
r.LineStyles = append(r.LineStyles, &LineStyleRecord{
//TODO: any reason for max(types.TwipFactor)?
Width: max(types.Twip(s.Width), types.TwipFactor),
Width: max(types.Twip(s.Width), types.TwipFactor).Float64(),
Color: math.Color{
R: s.Color.R(),
G: s.Color.G(),
@ -62,7 +62,7 @@ func StyleListFromSWFItems(fillStyles subtypes.FILLSTYLEARRAY, lineStyles subtyp
case types.Color:
r.LineStyles = append(r.LineStyles, &LineStyleRecord{
//TODO: any reason for max(types.TwipFactor)?
Width: max(types.Twip(s.Width), types.TwipFactor),
Width: max(types.Twip(s.Width), types.TwipFactor).Float64(),
Color: math.Color{
R: fillEntry.R(),
G: fillEntry.G(),
@ -75,7 +75,7 @@ func StyleListFromSWFItems(fillStyles subtypes.FILLSTYLEARRAY, lineStyles subtyp
color := fillEntry.GetItems()[0].Color
r.LineStyles = append(r.LineStyles, &LineStyleRecord{
//TODO: any reason for max(types.TwipFactor)?
Width: max(types.Twip(s.Width), types.TwipFactor),
Width: max(types.Twip(s.Width), types.TwipFactor).Float64(),
Color: color,
})
}
@ -96,7 +96,7 @@ func StyleListFromSWFMorphItems(fillStyles subtypes.MORPHFILLSTYLEARRAY, lineSty
for _, s := range lineStyles.LineStyles {
start.LineStyles = append(start.LineStyles, &LineStyleRecord{
//TODO: any reason for max(types.TwipFactor)?
Width: max(types.Twip(s.StartWidth), types.TwipFactor),
Width: max(types.Twip(s.StartWidth), types.TwipFactor).Float64(),
Color: math.Color{
R: s.StartColor.R(),
G: s.StartColor.G(),
@ -107,7 +107,7 @@ func StyleListFromSWFMorphItems(fillStyles subtypes.MORPHFILLSTYLEARRAY, lineSty
end.LineStyles = append(end.LineStyles, &LineStyleRecord{
//TODO: any reason for max(types.TwipFactor)?
Width: max(types.Twip(s.EndWidth), types.TwipFactor),
Width: max(types.Twip(s.EndWidth), types.TwipFactor).Float64(),
Color: math.Color{
R: s.EndColor.R(),
G: s.EndColor.G(),
@ -121,7 +121,7 @@ func StyleListFromSWFMorphItems(fillStyles subtypes.MORPHFILLSTYLEARRAY, lineSty
if !s.Flag.HasFill {
start.LineStyles = append(start.LineStyles, &LineStyleRecord{
//TODO: any reason for max(types.TwipFactor)?
Width: max(types.Twip(s.StartWidth), types.TwipFactor),
Width: max(types.Twip(s.StartWidth), types.TwipFactor).Float64(),
Color: math.Color{
R: s.StartColor.R(),
G: s.StartColor.G(),
@ -131,7 +131,7 @@ func StyleListFromSWFMorphItems(fillStyles subtypes.MORPHFILLSTYLEARRAY, lineSty
})
end.LineStyles = append(end.LineStyles, &LineStyleRecord{
//TODO: any reason for max(types.TwipFactor)?
Width: max(types.Twip(s.EndWidth), types.TwipFactor),
Width: max(types.Twip(s.EndWidth), types.TwipFactor).Float64(),
Color: math.Color{
R: s.EndColor.R(),
G: s.EndColor.G(),
@ -146,7 +146,7 @@ func StyleListFromSWFMorphItems(fillStyles subtypes.MORPHFILLSTYLEARRAY, lineSty
case types.Color:
start.LineStyles = append(start.LineStyles, &LineStyleRecord{
//TODO: any reason for max(types.TwipFactor)?
Width: max(types.Twip(s.StartWidth), types.TwipFactor),
Width: max(types.Twip(s.StartWidth), types.TwipFactor).Float64(),
Color: math.Color{
R: fillEntry.R(),
G: fillEntry.G(),
@ -159,7 +159,7 @@ func StyleListFromSWFMorphItems(fillStyles subtypes.MORPHFILLSTYLEARRAY, lineSty
color := fillEntry.GetItems()[0].Color
start.LineStyles = append(start.LineStyles, &LineStyleRecord{
//TODO: any reason for max(types.TwipFactor)?
Width: max(types.Twip(s.StartWidth), types.TwipFactor),
Width: max(types.Twip(s.StartWidth), types.TwipFactor).Float64(),
Color: color,
})
}
@ -167,7 +167,7 @@ func StyleListFromSWFMorphItems(fillStyles subtypes.MORPHFILLSTYLEARRAY, lineSty
case types.Color:
end.LineStyles = append(end.LineStyles, &LineStyleRecord{
//TODO: any reason for max(types.TwipFactor)?
Width: max(types.Twip(s.EndWidth), types.TwipFactor),
Width: max(types.Twip(s.EndWidth), types.TwipFactor).Float64(),
Color: math.Color{
R: fillEntry.R(),
G: fillEntry.G(),
@ -180,7 +180,7 @@ func StyleListFromSWFMorphItems(fillStyles subtypes.MORPHFILLSTYLEARRAY, lineSty
color := fillEntry.GetItems()[0].Color
end.LineStyles = append(end.LineStyles, &LineStyleRecord{
//TODO: any reason for max(types.TwipFactor)?
Width: max(types.Twip(s.EndWidth), types.TwipFactor),
Width: max(types.Twip(s.EndWidth), types.TwipFactor).Float64(),
Color: color,
})
}

View file

@ -11,7 +11,7 @@ type StyleRecord interface {
}
type LineStyleRecord struct {
Width swftypes.Twip
Width float64
Color math.Color
}

View file

@ -1,7 +1,6 @@
package shapes
import (
swftypes "git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/types"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/records"
)
@ -21,10 +20,10 @@ func ellipseDrawQuarter(center, size math.Vector2[float64]) *records.CubicCurveR
const c = 0.55228474983 // (4/3) * (sqrt(2) - 1)
return &records.CubicCurveRecord{
Control1: math.Vector2ToType[float64, swftypes.Twip](math.NewVector2(center.X-size.X, center.Y-c*size.Y)),
Control2: math.Vector2ToType[float64, swftypes.Twip](math.NewVector2(center.X-c*size.X, center.Y-size.Y)),
Anchor: math.Vector2ToType[float64, swftypes.Twip](math.NewVector2(center.X, center.Y-size.Y)),
Start: math.Vector2ToType[float64, swftypes.Twip](math.NewVector2(center.X-size.X, center.Y)),
Control1: math.NewVector2(center.X-size.X, center.Y-c*size.Y),
Control2: math.NewVector2(center.X-c*size.X, center.Y-size.Y),
Anchor: math.NewVector2(center.X, center.Y-size.Y),
Start: math.NewVector2(center.X-size.X, center.Y),
}
}

View file

@ -48,8 +48,8 @@ func (r Rectangle[T]) Multiply(size T) Rectangle[T] {
}
func (r Rectangle[T]) Draw() []records.Record {
tl := math.Vector2ToType[T, types.Twip](r.TopLeft)
br := math.Vector2ToType[T, types.Twip](r.BottomRight)
tl := r.TopLeft.Float64()
br := r.BottomRight.Float64()
return []records.Record{
&records.LineRecord{
To: math.NewVector2(tl.X, br.Y),
@ -81,9 +81,9 @@ func (r Rectangle[T]) DrawOpen() []records.Record {
return r.Draw()[:3]
}
func RectangleFromSWF(rect types.Rectangle) Rectangle[types.Twip] {
return Rectangle[types.Twip]{
TopLeft: math.NewVector2(rect.Xmin, rect.Ymin),
BottomRight: math.NewVector2(rect.Xmax, rect.Ymax),
func RectangleFromSWF(rect types.Rectangle) Rectangle[float64] {
return Rectangle[float64]{
TopLeft: math.NewVector2(rect.Xmin.Float64(), rect.Ymin.Float64()),
BottomRight: math.NewVector2(rect.Xmax.Float64(), rect.Ymax.Float64()),
}
}