mirror of
https://github.com/OpenVGLab/OmniLottie.git
synced 2026-09-17 15:46:26 +00:00
Initial Commit
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,120 @@
|
||||
from xml.dom import minidom
|
||||
import enum
|
||||
from lottie.parsers.sif.sif.core import TypeDescriptor, ObjectRegistry, SifNodeMeta, FrameTime
|
||||
from lottie.parsers.sif.xml.utils import xml_child_elements, xml_first_element_child
|
||||
|
||||
|
||||
class SifAstNode:
|
||||
_subclasses = None
|
||||
_tag = None
|
||||
|
||||
@staticmethod
|
||||
def from_dom(xml: minidom.Element, param: TypeDescriptor, registry: ObjectRegistry):
|
||||
if xml.tagName == param.typename:
|
||||
return SifValue.from_dom(xml, param, registry)
|
||||
|
||||
xmltype = xml.getAttribute("type")
|
||||
if xmltype != param.typename and xmltype != "weighted_" + param.typename:
|
||||
raise ValueError("Invalid type %s (should be %s)" % (xmltype, param.typename))
|
||||
|
||||
return SifAstNode.ast_node_types()[xml.tagName].from_dom(xml, param, registry)
|
||||
|
||||
@staticmethod
|
||||
def ast_node_types():
|
||||
if SifAstNode._subclasses is None:
|
||||
from . import nodes
|
||||
SifAstNode._subclasses = {}
|
||||
SifAstNode._gather_ast_types(SifAstNode)
|
||||
return SifAstNode._subclasses
|
||||
|
||||
@staticmethod
|
||||
def _gather_ast_types(cls):
|
||||
for subcls in cls.__subclasses__():
|
||||
if subcls._tag:
|
||||
SifAstNode._subclasses[subcls._tag] = subcls
|
||||
SifAstNode._gather_ast_types(subcls)
|
||||
|
||||
def _prepare_to_dom(self, dom: minidom.Document, param: TypeDescriptor):
|
||||
element = dom.createElement(self._tag)
|
||||
element.setAttribute("type", param.typename)
|
||||
return element
|
||||
|
||||
|
||||
class SifValue(SifAstNode):
|
||||
def __init__(self, value=None):
|
||||
self.value = value
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s %r>" % (self.__class__.__name__, self.value)
|
||||
|
||||
@classmethod
|
||||
def from_dom(cls, xml: minidom.Element, param: TypeDescriptor, registry: ObjectRegistry):
|
||||
return SifValue(param.value_from_xml_element(xml, registry))
|
||||
|
||||
def to_dom(self, dom: minidom.Document, param: TypeDescriptor):
|
||||
return param.value_to_xml_element(self.value, dom)
|
||||
|
||||
|
||||
class Interpolation(enum.Enum):
|
||||
Auto = "auto"
|
||||
Linear = "linear"
|
||||
Clamped = "clamped"
|
||||
Ease = "halt"
|
||||
Constant = "constant"
|
||||
|
||||
|
||||
class SifKeyframe:
|
||||
def __init__(self, value, time: FrameTime, before=Interpolation.Clamped, after=Interpolation.Clamped):
|
||||
self.value = value
|
||||
self.time = time
|
||||
self.before = before
|
||||
self.after = after
|
||||
|
||||
@classmethod
|
||||
def from_dom(cls, xml: minidom.Element, param: TypeDescriptor, registry: ObjectRegistry):
|
||||
return cls(
|
||||
param.value_from_xml_element(xml_first_element_child(xml), registry),
|
||||
FrameTime.parse_string(xml.getAttribute("time"), registry),
|
||||
Interpolation(xml.getAttribute("before")),
|
||||
Interpolation(xml.getAttribute("after"))
|
||||
)
|
||||
|
||||
def to_dom(self, dom: minidom.Document, param: TypeDescriptor):
|
||||
element = dom.createElement("waypoint")
|
||||
element.setAttribute("time", str(self.time))
|
||||
element.setAttribute("before", self.before.value)
|
||||
element.setAttribute("after", self.after.value)
|
||||
element.appendChild(param.value_to_xml_element(self.value, dom))
|
||||
return element
|
||||
|
||||
def __repr__(self):
|
||||
return "<SifKeyframe %s %s>" % (self.time, self.value)
|
||||
|
||||
|
||||
class SifAnimated(SifAstNode):
|
||||
_tag = "animated"
|
||||
|
||||
def __init__(self):
|
||||
self.keyframes = []
|
||||
|
||||
@classmethod
|
||||
def from_dom(cls, xml: minidom.Element, param: TypeDescriptor, registry: ObjectRegistry):
|
||||
obj = SifAnimated()
|
||||
for waypoint in xml_child_elements(xml, "waypoint"):
|
||||
obj.keyframes.append(SifKeyframe.from_dom(waypoint, param, registry))
|
||||
return obj
|
||||
|
||||
def to_dom(self, dom: minidom.Document, param: TypeDescriptor):
|
||||
element = self._prepare_to_dom(dom, param)
|
||||
for kf in self.keyframes:
|
||||
element.appendChild(kf.to_dom(dom, param))
|
||||
return element
|
||||
|
||||
def add_keyframe(self, *args, **kwargs):
|
||||
if not kwargs and len(args) == 1 and isinstance(args[0], SifKeyframe):
|
||||
keyframe = args[0]
|
||||
else:
|
||||
keyframe = SifKeyframe(*args, **kwargs)
|
||||
|
||||
self.keyframes.append(keyframe)
|
||||
return keyframe
|
||||
@@ -0,0 +1,321 @@
|
||||
from xml.dom import minidom
|
||||
import enum
|
||||
|
||||
from lottie.nvector import NVector
|
||||
from lottie.parsers.sif.ast_impl.base import SifAstNode, TypeDescriptor, ObjectRegistry
|
||||
from lottie.parsers.sif.xml.animatable import XmlAnimatable
|
||||
from lottie.parsers.sif.xml.wrappers import XmlBoneReference, XmlSifElement, XmlList
|
||||
from lottie.parsers.sif.sif.nodes import Segment, WeightedVector, Bline
|
||||
from lottie.parsers.sif.sif.enums import Smooth
|
||||
from lottie.parsers.sif.sif.core import SifNodeMeta, FrameTime
|
||||
|
||||
|
||||
class SifAstComplex(SifAstNode, metaclass=SifNodeMeta):
|
||||
_nodes = []
|
||||
|
||||
def __init__(self, **kw):
|
||||
for node in self._nodes:
|
||||
node.initialize_object(kw, self)
|
||||
|
||||
@classmethod
|
||||
def from_dom(cls, xml: minidom.Element, param: TypeDescriptor, registry: ObjectRegistry):
|
||||
outcls = cls.get_class_from_dom(xml, param, registry)
|
||||
instance = outcls()
|
||||
for node in outcls._nodes:
|
||||
node.from_xml(instance, xml, registry)
|
||||
return instance
|
||||
|
||||
@classmethod
|
||||
def get_class_from_dom(cls, xml: minidom.Element, param: TypeDescriptor, registry: ObjectRegistry):
|
||||
return cls
|
||||
|
||||
def to_dom(self, dom: minidom.Document, param: TypeDescriptor):
|
||||
element = self._prepare_to_dom(dom, param)
|
||||
for node in self._nodes:
|
||||
node.to_xml(self, element, dom, param)
|
||||
return element
|
||||
|
||||
|
||||
class SifAstBoneLink(SifAstComplex):
|
||||
_tag = "bone_link"
|
||||
|
||||
_nodes = [
|
||||
XmlBoneReference("bone"),
|
||||
XmlAnimatable("base_value", "vector", NVector(0, 0)),
|
||||
XmlAnimatable("translate", "bool", True),
|
||||
XmlAnimatable("rotate", "bool", True),
|
||||
XmlAnimatable("skew", "bool", True),
|
||||
XmlAnimatable("scale_x", "bool", True),
|
||||
XmlAnimatable("scale_y", "bool", True),
|
||||
]
|
||||
|
||||
|
||||
class SifAstBoneInfluence(SifAstComplex):
|
||||
_tag = "boneinfluence"
|
||||
|
||||
_nodes = [
|
||||
# TODO bone_weight_list
|
||||
XmlAnimatable("link", "vector", NVector(0, 0)),
|
||||
]
|
||||
|
||||
|
||||
class SifSegCalcTangent(SifAstComplex):
|
||||
_tag = "segcalctangent"
|
||||
|
||||
_nodes = [
|
||||
XmlSifElement("segment", Segment),
|
||||
XmlAnimatable("amount", "real", .5),
|
||||
]
|
||||
|
||||
|
||||
class SifSegCalcVertex(SifAstComplex):
|
||||
_tag = "segcalcvertex"
|
||||
|
||||
_nodes = [
|
||||
XmlSifElement("segment", Segment),
|
||||
XmlAnimatable("amount", "real", .5),
|
||||
]
|
||||
|
||||
|
||||
class WeightedAverage(SifAstComplex):
|
||||
_tag = "weighted_average"
|
||||
|
||||
_nodes = [
|
||||
XmlList(WeightedVector, "vectors", "entry"),
|
||||
]
|
||||
|
||||
def _prepare_to_dom(self, dom: minidom.Document, param: TypeDescriptor):
|
||||
element = dom.createElement(self._tag)
|
||||
element.setAttribute("type", "weighted_vector")
|
||||
return element
|
||||
|
||||
|
||||
class SifAdd(SifAstComplex):
|
||||
_tag = "add"
|
||||
|
||||
_nodes = [
|
||||
XmlAnimatable("lhs", "_recurse"),
|
||||
XmlAnimatable("rhs", "_recurse"),
|
||||
XmlAnimatable("scalar", "real", 1.),
|
||||
]
|
||||
|
||||
|
||||
class SifAnimatedFile(SifAstComplex):
|
||||
_tag = "animated_file"
|
||||
|
||||
_nodes = [
|
||||
XmlAnimatable("filename", "string"),
|
||||
]
|
||||
|
||||
|
||||
class Accuracy(enum.Enum):
|
||||
Rough = 0
|
||||
Normal = 1
|
||||
Fine = 2
|
||||
Extreme = 3
|
||||
|
||||
|
||||
class DerivativeOrder:
|
||||
FirstDerivative = 0
|
||||
SecondDerivative = 1
|
||||
|
||||
|
||||
class SifDerivative(SifAstComplex):
|
||||
_tag = "derivative"
|
||||
|
||||
_nodes = [
|
||||
XmlAnimatable("link", "_recurse"),
|
||||
XmlAnimatable("interval", "real", 0.01),
|
||||
XmlAnimatable("accuracy", "integer", Accuracy.Normal, Accuracy),
|
||||
XmlAnimatable("order", "integer", DerivativeOrder.FirstDerivative, DerivativeOrder),
|
||||
]
|
||||
|
||||
|
||||
class SifDynamic(SifAstComplex):
|
||||
_tag = "dynamic"
|
||||
|
||||
_nodes = [
|
||||
XmlAnimatable("tip_static", "vector", NVector(0, 0)),
|
||||
XmlAnimatable("origin", "vector", NVector(0, 0)),
|
||||
XmlAnimatable("force", "vector", NVector(0, 0)),
|
||||
XmlAnimatable("torque", "real", 0.),
|
||||
XmlAnimatable("damping", "real", 0.4),
|
||||
XmlAnimatable("friction", "real", 0.4),
|
||||
XmlAnimatable("spring", "real", 30.),
|
||||
XmlAnimatable("torsion", "real", 30.),
|
||||
XmlAnimatable("mass", "real", 0.3),
|
||||
XmlAnimatable("inertia", "real", 0.3),
|
||||
XmlAnimatable("spring_rigid", "bool", False),
|
||||
XmlAnimatable("torsion_rigid", "bool", False),
|
||||
XmlAnimatable("origin_drags_tip", "bool", True),
|
||||
]
|
||||
|
||||
|
||||
class SifGreyed(SifAstComplex):
|
||||
_tag = "greyed"
|
||||
|
||||
_nodes = [
|
||||
XmlAnimatable("link", "_recurse"),
|
||||
]
|
||||
|
||||
|
||||
class SifLinear(SifAstComplex):
|
||||
_tag = "linear"
|
||||
|
||||
_nodes = [
|
||||
XmlAnimatable("slope", "vector", NVector(0, 0)),
|
||||
XmlAnimatable("offset", "vector", NVector(0, 0)),
|
||||
]
|
||||
|
||||
|
||||
class SifRadialComposite(SifAstComplex):
|
||||
_tag = "radial_composite"
|
||||
|
||||
_nodes = [
|
||||
XmlAnimatable("radius", "real", 0.),
|
||||
XmlAnimatable("theta", "angle", 0.),
|
||||
]
|
||||
|
||||
|
||||
class SifComposite(SifAstComplex):
|
||||
_tag = "composite"
|
||||
|
||||
@classmethod
|
||||
def get_class_from_dom(cls, xml: minidom.Element, param: TypeDescriptor, registry: ObjectRegistry):
|
||||
type = xml.getAttribute("type")
|
||||
if type == "vector":
|
||||
return SifVectorComposite
|
||||
return None
|
||||
|
||||
def _prepare_to_dom(self, dom: minidom.Document, param: TypeDescriptor):
|
||||
element = dom.createElement("composite")
|
||||
element.setAttribute("type", param.typename)
|
||||
return element
|
||||
|
||||
|
||||
class SifVectorComposite(SifComposite):
|
||||
_type = "vector"
|
||||
|
||||
_nodes = [
|
||||
XmlAnimatable("x", "real", 0.),
|
||||
XmlAnimatable("y", "real", 0.),
|
||||
]
|
||||
|
||||
|
||||
class SifRandom(SifAstComplex):
|
||||
_tag = "random"
|
||||
|
||||
_nodes = [
|
||||
XmlAnimatable("link", "_recurse"),
|
||||
XmlAnimatable("radius", "real", 0.),
|
||||
XmlAnimatable("seed", "integer", 0),
|
||||
XmlAnimatable("speed", "real", 1.),
|
||||
XmlAnimatable("smooth", "integer", Smooth.Cubic, Smooth),
|
||||
XmlAnimatable("loop", "real", 0.),
|
||||
]
|
||||
|
||||
|
||||
class SifReference(SifAstComplex):
|
||||
_tag = "link"
|
||||
|
||||
_nodes = [
|
||||
XmlAnimatable("reference", "_recurse"),
|
||||
]
|
||||
|
||||
|
||||
class SifScale(SifAstComplex):
|
||||
_tag = "scale"
|
||||
|
||||
_nodes = [
|
||||
XmlAnimatable("link", "_recurse"),
|
||||
XmlAnimatable("scalar", "real", 1.),
|
||||
]
|
||||
|
||||
|
||||
class SifStep(SifAstComplex):
|
||||
_tag = "step"
|
||||
|
||||
_nodes = [
|
||||
XmlAnimatable("link", "_recurse"),
|
||||
XmlAnimatable("duration", "time", FrameTime(1, FrameTime.Unit.Seconds)),
|
||||
XmlAnimatable("start_time", "time", FrameTime(0, FrameTime.Unit.Seconds)),
|
||||
XmlAnimatable("intersection", "real", 0.5),
|
||||
]
|
||||
|
||||
|
||||
class SifSubtract(SifAstComplex):
|
||||
_tag = "subtract"
|
||||
|
||||
_nodes = [
|
||||
XmlAnimatable("lhs", "_recurse"),
|
||||
XmlAnimatable("rhs", "_recurse"),
|
||||
XmlAnimatable("scalar", "real", 1.),
|
||||
]
|
||||
|
||||
|
||||
class SifSwitch(SifAstComplex):
|
||||
_tag = "switch"
|
||||
|
||||
_nodes = [
|
||||
XmlAnimatable("link_off", "_recurse"),
|
||||
XmlAnimatable("link_on", "_recurse"),
|
||||
XmlAnimatable("switch", "bool", False),
|
||||
]
|
||||
|
||||
|
||||
class SifTimedSwap(SifAstComplex):
|
||||
_tag = "timed_swap"
|
||||
|
||||
_nodes = [
|
||||
XmlAnimatable("before", "_recurse"),
|
||||
XmlAnimatable("after", "_recurse"),
|
||||
XmlAnimatable("time", "time", FrameTime(0, FrameTime.Unit.Seconds)),
|
||||
XmlAnimatable("length", "time", FrameTime(0, FrameTime.Unit.Seconds)),
|
||||
]
|
||||
|
||||
|
||||
class SifTimeLoop(SifAstComplex):
|
||||
_tag = "timeloop"
|
||||
|
||||
_nodes = [
|
||||
XmlAnimatable("link", "_recurse"),
|
||||
XmlAnimatable("link_time", "time", FrameTime(0, FrameTime.Unit.Seconds)),
|
||||
XmlAnimatable("local_time", "time", FrameTime(0, FrameTime.Unit.Seconds)),
|
||||
XmlAnimatable("duration", "time", FrameTime(0, FrameTime.Unit.Seconds)),
|
||||
]
|
||||
|
||||
|
||||
class SifPower(SifAstComplex):
|
||||
_tag = "power"
|
||||
|
||||
_nodes = [
|
||||
XmlAnimatable("base", "real", 1.),
|
||||
XmlAnimatable("power", "real", 1.),
|
||||
XmlAnimatable("epsilon", "real", 0.000001),
|
||||
XmlAnimatable("infinite", "real", 999999.),
|
||||
]
|
||||
|
||||
|
||||
class SifBlineCalcTangent(SifAstComplex):
|
||||
_tag = "blinecalctangent"
|
||||
|
||||
_nodes = [
|
||||
XmlSifElement("bline", Bline),
|
||||
XmlAnimatable("loop", "bool", False),
|
||||
XmlAnimatable("amount", "real", 0.5),
|
||||
XmlAnimatable("offset", "angle", 0.),
|
||||
XmlAnimatable("scale", "real", 1.),
|
||||
XmlAnimatable("fixed_length", "bool", False),
|
||||
XmlAnimatable("homogeneous", "bool", False),
|
||||
]
|
||||
|
||||
|
||||
class SifBlineCalcVertex(SifAstComplex):
|
||||
_tag = "blinecalcvertex"
|
||||
|
||||
_nodes = [
|
||||
XmlSifElement("bline", Bline),
|
||||
XmlAnimatable("loop", "bool", False),
|
||||
XmlAnimatable("amount", "real", 0.5),
|
||||
XmlAnimatable("homogeneous", "bool", False),
|
||||
]
|
||||
Reference in New Issue
Block a user