swf2ass-go/types/shapes/StyleRecord.go

262 lines
7.6 KiB
Go

package shapes
import (
"fmt"
swfsubtypes "git.gammaspectra.live/WeebDataHoarder/swf-go/subtypes"
swftypes "git.gammaspectra.live/WeebDataHoarder/swf-go/types"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
math2 "math"
"slices"
)
type StyleRecord interface {
ApplyColorTransform(transform math.ColorTransform) StyleRecord
ApplyMatrixTransform(transform math.MatrixTransform, applyTranslation bool) StyleRecord
}
type Fillable interface {
Fill(shape Shape) DrawPathList
ApplyMatrixTransform(transform math.MatrixTransform, applyTranslation bool) Fillable
ApplyColorTransform(transform math.ColorTransform) Fillable
}
type FillStyleRecord struct {
// Fill can be math.Color or Fillable
Fill any
Border *LineStyleRecord
Blur float64
fillCache struct {
Shape *Shape
List DrawPathList
}
}
func (r *FillStyleRecord) IsFlat() bool {
_, ok := r.Fill.(math.Color)
return ok
}
// Flatten Creates a fill that is only composed of FillStyleRecord with Fill being math.Color
func (r *FillStyleRecord) Flatten(s Shape) DrawPathList {
if _, ok := r.Fill.(math.Color); ok {
return DrawPathList{
{
Style: r,
Shape: s,
},
}
} else if fillable, ok := r.Fill.(Fillable); ok {
//TODO: inherit blur/border
if r.fillCache.Shape != nil && r.fillCache.Shape.Equals(s) {
return r.fillCache.List
}
fill := fillable.Fill(s)
r.fillCache.List = fill
s2 := slices.Clone(s)
r.fillCache.Shape = &s2
return fill
} else {
panic("not supported")
}
}
func (r *FillStyleRecord) ApplyMatrixTransform(transform math.MatrixTransform, applyTranslation bool) StyleRecord {
fill := r.Fill
if color, ok := fill.(math.Color); ok {
fill = color
} else if fillable, ok := r.Fill.(Fillable); ok {
fill = fillable.ApplyMatrixTransform(transform, applyTranslation)
} else {
panic("not supported")
}
if r.Border != nil {
return &FillStyleRecord{
Fill: fill,
Border: r.Border.ApplyMatrixTransform(transform, applyTranslation).(*LineStyleRecord),
Blur: r.Blur, //TODO: scale blur?
}
}
return &FillStyleRecord{
Fill: fill,
Border: nil,
Blur: r.Blur, //TODO: scale blur?
}
}
func (r *FillStyleRecord) ApplyColorTransform(transform math.ColorTransform) StyleRecord {
fill := r.Fill
if color, ok := fill.(math.Color); ok {
fill = transform.ApplyToColor(color)
} else if fillable, ok := r.Fill.(Fillable); ok {
fill = fillable.ApplyColorTransform(transform)
} else {
panic("not supported")
}
return &FillStyleRecord{
Border: r.Border,
Fill: fill,
Blur: r.Blur,
}
}
func FillStyleRecordFromSWF(collection ObjectCollection, fillType swfsubtypes.FillStyleType, color swftypes.Color, gradient swfsubtypes.GRADIENT, focalGradient swfsubtypes.FOCALGRADIENT, gradientMatrix, bitmapMatrix swftypes.MATRIX, bitmapId uint16) (r *FillStyleRecord) {
switch fillType {
case swfsubtypes.FillStyleSolid:
return &FillStyleRecord{
Fill: math.Color{
R: color.R(),
G: color.G(),
B: color.B(),
Alpha: color.A(),
},
}
case swfsubtypes.FillStyleLinearGradient:
return &FillStyleRecord{
Fill: LinearGradientFromSWF(gradient.Records, gradientMatrix, gradient.SpreadMode, gradient.InterpolationMode),
}
case swfsubtypes.FillStyleRadialGradient:
return &FillStyleRecord{
Fill: RadialGradientFromSWF(gradient.Records, gradientMatrix, gradient.SpreadMode, gradient.InterpolationMode),
}
case swfsubtypes.FillStyleFocalRadialGradient:
//TODO: do it properly
return &FillStyleRecord{
Fill: RadialGradientFromSWF(focalGradient.Records, gradientMatrix, gradient.SpreadMode, gradient.InterpolationMode),
}
case swfsubtypes.FillStyleClippedBitmap, swfsubtypes.FillStyleRepeatingBitmap:
if bitmapId == math2.MaxUint16 { //Special case, TODO:???
return &FillStyleRecord{
Fill: math.Color{
R: 0,
G: 0,
B: 0,
Alpha: 0,
},
}
}
bitmap := collection.Get(bitmapId)
if bitmap == nil {
fmt.Printf("bitmap %d not found!\n", bitmapId)
return &FillStyleRecord{
Fill: math.Color{
R: 0,
G: 0,
B: 0,
Alpha: 0,
},
}
}
//TODO: repeating
//TODO: what blur factor should it pick
blurFactor := 0.1
//TODO: extend color
return &FillStyleRecord{
Fill: BitmapFillFromSWF(bitmap.GetShapeList(ObjectProperties{}).ApplyFunction(func(p DrawPath) DrawPath {
if fillStyle, ok := p.Style.(*FillStyleRecord); ok {
return DrawPathFill(&FillStyleRecord{
Fill: fillStyle.Fill,
Border: fillStyle.Border,
Blur: blurFactor,
}, p.Shape)
}
return p
}), bitmapMatrix),
}
case swfsubtypes.FillStyleNonSmoothedClippedBitmap, swfsubtypes.FillStyleNonSmoothedRepeatingBitmap:
if bitmapId == math2.MaxUint16 { //Special case, TODO:???
return &FillStyleRecord{
Fill: math.Color{
R: 0,
G: 0,
B: 0,
Alpha: 0,
},
}
}
//TODO: repeating
bitmap := collection.Get(bitmapId)
if bitmap == nil {
fmt.Printf("bitmap %d not found!\n", bitmapId)
return &FillStyleRecord{
Fill: math.Color{
R: 0,
G: 0,
B: 0,
Alpha: 0,
},
}
}
//TODO: extend color
return &FillStyleRecord{
Fill: BitmapFillFromSWF(bitmap.GetShapeList(ObjectProperties{}), bitmapMatrix),
}
//TODO other styles
}
return &FillStyleRecord{
Fill: math.Color{
R: 0,
G: 0,
B: 0,
Alpha: 0,
},
}
}
func FillStyleRecordFromSWFMORPHFILLSTYLE(collection ObjectCollection, fillStyle swfsubtypes.MORPHFILLSTYLE) (start, end *FillStyleRecord) {
return FillStyleRecordFromSWF(collection, fillStyle.FillStyleType, fillStyle.StartColor, fillStyle.Gradient.StartGradient(), swfsubtypes.FOCALGRADIENT{}, fillStyle.StartGradientMatrix, fillStyle.StartBitmapMatrix, fillStyle.BitmapId),
FillStyleRecordFromSWF(collection, fillStyle.FillStyleType, fillStyle.EndColor, fillStyle.Gradient.EndGradient(), swfsubtypes.FOCALGRADIENT{}, fillStyle.EndGradientMatrix, fillStyle.EndBitmapMatrix, fillStyle.BitmapId)
}
func LineStyleRecordFromSWF(width uint16, blur float64, hasFill bool, c swftypes.Color, fill *FillStyleRecord) (r *LineStyleRecord) {
if hasFill {
//TODO: do this properly
switch fillType := fill.Fill.(type) {
case math.Color:
return &LineStyleRecord{
Width: swftypes.Twip(width).Float64(),
Color: fillType,
Blur: blur,
}
case Gradient:
//TODO: gradient fill of lines
return &LineStyleRecord{
Width: swftypes.Twip(width).Float64(),
Color: fillType.GetItems()[0].Color,
Blur: blur,
}
//TODO: other types, maybe generalize as a Fillable
}
}
return &LineStyleRecord{
Width: swftypes.Twip(width).Float64(),
Color: math.Color{
R: c.R(),
G: c.G(),
B: c.B(),
Alpha: c.A(),
},
Blur: blur,
}
}
func LineStyleRecordFromSWFMORPHLINESTYLE(lineStyle swfsubtypes.MORPHLINESTYLE) (start, end *LineStyleRecord) {
return LineStyleRecordFromSWF(lineStyle.StartWidth, 0, false, lineStyle.StartColor, nil),
LineStyleRecordFromSWF(lineStyle.EndWidth, 0, false, lineStyle.EndColor, nil)
}
func LineStyleRecordFromSWFMORPHLINESTYLE2(collection ObjectCollection, lineStyle swfsubtypes.MORPHLINESTYLE2) (start, end *LineStyleRecord) {
if lineStyle.Flag.HasFill {
startFill, endFill := FillStyleRecordFromSWFMORPHFILLSTYLE(collection, lineStyle.FillType)
return LineStyleRecordFromSWF(lineStyle.StartWidth, 0, lineStyle.Flag.HasFill, lineStyle.StartColor, startFill),
LineStyleRecordFromSWF(lineStyle.EndWidth, 0, lineStyle.Flag.HasFill, lineStyle.EndColor, endFill)
}
return LineStyleRecordFromSWF(lineStyle.StartWidth, 0, false, lineStyle.StartColor, nil),
LineStyleRecordFromSWF(lineStyle.EndWidth, 0, false, lineStyle.EndColor, nil)
}