private void TransformNodeMethodsAndFields(ModelNodeDefinition node) { var nodesToRemove = new List <ModelNodeDefinition>(); List <MethodDefinition> allMethods = node.Children.OfType <MethodDefinition>().ToList(); foreach (MethodDefinition method in allMethods) { TransformGetterMethod(method, nodesToRemove); } foreach (MethodDefinition method in allMethods) { TransformSetterMethod(method, nodesToRemove); } // If the node has both a field and a getter method with the same // wrapper property, prefer to call the getter. List <FieldDefinition> allFields = node.Children.OfType <FieldDefinition>().ToList(); foreach (FieldDefinition method in allFields) { TransformField(method, nodesToRemove); } foreach (ModelNodeDefinition child in nodesToRemove) { child.Parent.RemoveChild(child); } }
private void SetNodeProperties(ModelNodeDefinition modelNode, TreeNode treeNode) { if (modelNode is NamespaceDefinition) { treeNode.ImageKey = "folder"; treeNode.SelectedImageKey = "folder"; } else if (modelNode is ClassDefinition) { treeNode.ImageKey = "class"; treeNode.SelectedImageKey = "class"; } else if (modelNode is MethodDefinition) { treeNode.ImageKey = "method"; treeNode.SelectedImageKey = "method"; } else if (modelNode is TypeRefDefinition) { treeNode.ImageKey = "typeref"; treeNode.SelectedImageKey = "typeref"; } else { treeNode.ImageIndex = 5; treeNode.SelectedImageIndex = 5; } }
public void AddNode(ModelNodeDefinition node) { if (node is NamespaceDefinition) { throw new InvalidOperationException("Namespaces cannot be header child elements"); } Nodes.Add(node); node.Header = this; }
public void TransformNode(ModelNodeDefinition node) { if (node is ClassDefinition || node is NamespaceDefinition) { TransformNodeMethodsAndFields(node); } foreach (ModelNodeDefinition child in node.Children) { TransformNode(child); } }
public static string Get(ModelNodeDefinition node) { var method = node as MethodDefinition; if (method != null) { var name = method.Name; var parameters = string.Join(", ", method.Parameters.Select(p => p.Name)); return($"{name}({parameters})"); } return(node.Name); }
public void Parse(Cursor cursor, CppParserContext context) { string fieldName = cursor.Spelling; var field = new FieldDefinition(fieldName, new TypeRefDefinition(cursor.Type)); ModelNodeDefinition parent = context.GetContainingClassOrNamespace(); if (parent is NamespaceDefinition) { field.Header = context.Header; } parent.AddChild(field); }
private void CloneNodeWithStructure(ModelNodeDefinition node) { if (IsTopLevelNodeInNamespace(node)) { var headerClone = CloneSourceItem(node.Header) as HeaderDefinition; headerClone.AddNode(node); } foreach (var child in node.Children) { CloneNodeWithStructure(child); } }
private IToken TokenizeNode(ModelNodeDefinition node) { if (node is ClassDefinition @class) { return(_classTokenizer.Tokenize(@class)); } if (node is EnumDefinition @enum) { return(_enumTokenizer.Tokenize(@enum)); } throw new NotImplementedException(); }
private static void Transform(ModelNodeDefinition node) { EnumDefinition @enum = node as EnumDefinition; if (@enum != null) { TransformEnum(@enum); return; } foreach (ModelNodeDefinition child in node.Children) { Transform(child); } }
private IEnumerable <ClassDefinition> EnumerateClasses(ModelNodeDefinition node) { foreach (var child in node.Children) { foreach (var childClass in EnumerateClasses(child)) { yield return(childClass); } } if (node is ClassDefinition @class) { yield return(@class); } }
public static string GetFullName(this ModelNodeDefinition node) { if (!(node is ClassDefinition) || !(node is NamespaceDefinition)) { throw new NotImplementedException(); } ModelNodeDefinition parent = node.Parent; if (parent != null) { return($"{parent.GetFullName()}::{node.Name}"); } return(node.Name); }
private static void Transform(ModelNodeDefinition node) { if (node is MethodDefinition method) { if (IsOperator(method)) { method.IsExcluded = true; } return; } foreach (ModelNodeDefinition child in node.Children) { Transform(child); } }
private static void RenameClasses(ModelNodeDefinition node) { var @class = node as ClassDefinition; if (@class != null && @class.Name == "UnsafeNativeMethods") { return; } if (node.Name.StartsWith("bt")) { node.Name = node.Name.Substring(2); } foreach (var child in node.Children) { RenameClasses(child); } }
private void Order(ModelNodeDefinition node) { if (node is EnumDefinition @enum) { return; } if (node is ClassDefinition @class && @class.Name == "UnsafeNativeMethods") { return; } var newOrder = node.Children.OrderBy(n => n.Name).ToList(); for (int i = 0; i < node.Children.Count; i++) { node.Children[i] = newOrder[i]; Order(node.Children[i]); } }
private void AddModelNode(ModelNodeDefinition modelNode, TreeNode parentTreeNode) { if (parentTreeNode == null) { parentTreeNode = classTree.Nodes.Add("global"); parentTreeNode.Expand(); } else { parentTreeNode = parentTreeNode.Nodes.Add(modelNode.Name); } SetNodeProperties(modelNode, parentTreeNode); foreach (var child in modelNode.Children .OrderBy(GetNodeTypeOrder) .ThenBy(c => c.Name)) { AddModelNode(child, parentTreeNode); } }
public void Parse(Cursor cursor, CppParserContext context) { string className = cursor.Spelling; ModelNodeDefinition parent = context.GetContainingClassOrNamespace(); if (HasNameConflict(className, parent)) { return; } context.Class = new ClassDefinition(className); parent.AddChild(context.Class); if (parent is NamespaceDefinition) { context.Header.AddNode(context.Class); } cursor.VisitChildren(context.NodeVisitor); context.Class = parent as ClassDefinition; }
private IList <IToken> GetClassMembers(ModelNodeDefinition node) { var members = new List <IToken>(); var nodesByType = node.Children.ToLookup(GetNodeType); foreach (var nodeType in _nodeTypeOrder) { if (_tokenizers.TryGetValue(nodeType, out INodeTokenizer tokenizer)) { foreach (var child in nodesByType[nodeType]) { IToken childToken = tokenizer.Tokenize(child); members.Add(childToken); } } else { throw new NotImplementedException(); } } return(members); }
private int GetNodeTypeOrder(ModelNodeDefinition node) { if (node is NamespaceDefinition) { return(0); } if (node is ClassDefinition) { return(1); } var method = node as MethodDefinition; if (method != null) { if (method.IsConstructor) { return(2); } return(3); } return(4); }
public void Merge(ModelNodeDefinition node, IList <NamespaceTreeNode> path) { if (path.Count == 1) { Nodes.Add(node); } else { NamespaceTreeNode nextSource = path[1]; NamespaceTreeNode nextTarget = Children .FirstOrDefault(c => c.Namespace == nextSource.Namespace); if (nextTarget == null) { nextTarget = new NamespaceTreeNode { Namespace = nextSource.Namespace }; Children.Add(nextTarget); } nextTarget.Merge(node, path.Skip(1).ToList()); } }
public void Parse(Cursor cursor, CppParserContext context) { string methodName = cursor.Spelling; var parameters = new ParameterDefinition[cursor.NumArguments]; for (uint i = 0; i < cursor.NumArguments; i++) { Cursor parameterCursor = cursor.GetArgument(i); parameters[i] = ParseParameter(parameterCursor, context); } context.Method = new MethodDefinition(methodName, parameters) { IsConstructor = cursor.Kind == CursorKind.Constructor, IsStatic = cursor.IsStaticCxxMethod, IsAbstract = IsCursorAbstract(cursor, context), ReturnType = new TypeRefDefinition(cursor.ResultType) }; ModelNodeDefinition parent = context.GetContainingClassOrNamespace(); if (parent is NamespaceDefinition) { if (cursor.SemanticParent.Kind == CursorKind.ClassDecl || cursor.SemanticParent.Kind == CursorKind.ClassTemplate || cursor.SemanticParent.Kind == CursorKind.StructDecl) { // FIXME: Clang reports a method definition as a method declaration return; } context.Method.Header = context.Header; } parent.AddChild(context.Method); context.Method = null; }
private NodeType GetNodeType(ModelNodeDefinition node) { if (node is ClassDefinition) { return(NodeType.Class); } if (node is EnumDefinition) { return(NodeType.Enum); } if (node is MethodDefinition method) { if (method.IsConstructor) { return(NodeType.Constructor); } return(NodeType.Method); } if (node is PropertyDefinition) { return(NodeType.Property); } return(NodeType.Unknown); }
public IToken Tokenize(ModelNodeDefinition node) { var @enum = (EnumDefinition)node; var definition = new LineToken($"public enum {@enum.Name}"); IToken headerToken; if (@enum.IsFlags()) { headerToken = new LinesToken(new LineToken[] { new LineToken("[Flags]"), definition } ); } else { headerToken = definition; } var enumerators = new List <IToken>(); var lastEnumerator = @enum.Enumerators.Last(); foreach (EnumeratorDefinition enumerator in @enum.Enumerators) { string comma = enumerator == lastEnumerator ? "" : ","; string enumeratorLine = enumerator.Value != null ? $"{enumerator.Name} = {enumerator.Value}{comma}" : enumerator.Name + comma; enumerators.Add(new LineToken(enumeratorLine)); } BlockToken enumToken = new BlockToken(headerToken, enumerators); return(enumToken); }
private unsafe object ExportAnimation(ICommandContext commandContext, ContentManager contentManager, bool failOnEmptyAnimation) { // Read from model file var modelSkeleton = LoadSkeleton(commandContext, contentManager); // we get model skeleton to compare it to real skeleton we need to map to AdjustSkeleton(modelSkeleton); TimeSpan duration; var animationClips = LoadAnimation(commandContext, contentManager, out duration); // Fix the animation frames double startFrameSeconds = StartFrame.TotalSeconds; double endFrameSeconds = EndFrame.TotalSeconds; var startTime = CompressedTimeSpan.FromSeconds(-startFrameSeconds); foreach (var clip in animationClips) { foreach (var animationCurve in clip.Value.Curves) { animationCurve.ShiftKeys(startTime); } } var durationTimeSpan = TimeSpan.FromSeconds((endFrameSeconds - startFrameSeconds)); if (duration > durationTimeSpan) { duration = durationTimeSpan; } var animationClip = new AnimationClip { Duration = duration }; if (animationClips.Count > 0) { AnimationClip rootMotionAnimationClip = null; // If root motion is explicitely enabled, or if there is no skeleton, try to find root node and apply animation directly on TransformComponent if ((AnimationRootMotion || SkeletonUrl == null) && modelSkeleton.Nodes.Length >= 1) { // No skeleton, map root node only // TODO: For now, it seems to be located on node 1 in FBX files. Need to check if always the case, and what happens with Assimp var rootNode0 = modelSkeleton.Nodes.Length >= 1 ? modelSkeleton.Nodes[0].Name : null; var rootNode1 = modelSkeleton.Nodes.Length >= 2 ? modelSkeleton.Nodes[1].Name : null; if ((rootNode0 != null && animationClips.TryGetValue(rootNode0, out rootMotionAnimationClip)) || (rootNode1 != null && animationClips.TryGetValue(rootNode1, out rootMotionAnimationClip))) { foreach (var channel in rootMotionAnimationClip.Channels) { var curve = rootMotionAnimationClip.Curves[channel.Value.CurveIndex]; // Root motion var channelName = channel.Key; if (channelName.StartsWith("Transform.")) { animationClip.AddCurve($"[TransformComponent.Key]." + channelName.Replace("Transform.", string.Empty), curve); } // Also apply Camera curves // TODO: Add some other curves? if (channelName.StartsWith("Camera.")) { animationClip.AddCurve($"[CameraComponent.Key]." + channelName.Replace("Camera.", string.Empty), curve); } } } } // Load asset reference skeleton if (SkeletonUrl != null) { var skeleton = contentManager.Load <Skeleton>(SkeletonUrl); var skeletonMapping = new SkeletonMapping(skeleton, modelSkeleton); // Process missing nodes foreach (var nodeAnimationClipEntry in animationClips) { var nodeName = nodeAnimationClipEntry.Key; var nodeAnimationClip = nodeAnimationClipEntry.Value; var nodeIndex = modelSkeleton.Nodes.IndexOf(x => x.Name == nodeName); // Node doesn't exist in skeleton? skip it if (nodeIndex == -1 || skeletonMapping.SourceToSource[nodeIndex] != nodeIndex) { continue; } // Skip root motion node (if any) if (nodeAnimationClip == rootMotionAnimationClip) { continue; } // Find parent node var parentNodeIndex = modelSkeleton.Nodes[nodeIndex].ParentIndex; if (parentNodeIndex != -1 && skeletonMapping.SourceToSource[parentNodeIndex] != parentNodeIndex) { // Some nodes were removed, we need to concat the anim curves var currentNodeIndex = nodeIndex; var nodesToMerge = new List <Tuple <ModelNodeDefinition, AnimationBlender, AnimationClipEvaluator> >(); while (currentNodeIndex != -1 && currentNodeIndex != skeletonMapping.SourceToSource[parentNodeIndex]) { AnimationClip animationClipToMerge; AnimationClipEvaluator animationClipEvaluator = null; AnimationBlender animationBlender = null; if (animationClips.TryGetValue(modelSkeleton.Nodes[currentNodeIndex].Name, out animationClipToMerge)) { animationBlender = new AnimationBlender(); animationClipEvaluator = animationBlender.CreateEvaluator(animationClipToMerge); } nodesToMerge.Add(Tuple.Create(modelSkeleton.Nodes[currentNodeIndex], animationBlender, animationClipEvaluator)); currentNodeIndex = modelSkeleton.Nodes[currentNodeIndex].ParentIndex; } // Put them in proper parent to children order nodesToMerge.Reverse(); // Find all key times // TODO: We should detect discontinuities and keep them var animationKeysSet = new HashSet <CompressedTimeSpan>(); foreach (var node in nodesToMerge) { if (node.Item3 != null) { foreach (var curve in node.Item3.Clip.Curves) { foreach (CompressedTimeSpan time in curve.Keys) { animationKeysSet.Add(time); } } } } // Sort key times var animationKeys = animationKeysSet.ToList(); animationKeys.Sort(); var animationOperations = new FastList <AnimationOperation>(); var combinedAnimationClip = new AnimationClip(); var translationCurve = new AnimationCurve <Vector3>(); var rotationCurve = new AnimationCurve <Quaternion>(); var scaleCurve = new AnimationCurve <Vector3>(); // Evaluate at every key frame foreach (var animationKey in animationKeys) { var matrix = Matrix.Identity; // Evaluate node foreach (var node in nodesToMerge) { // Needs to be an array in order for it to be modified by the UpdateEngine, otherwise it would get passed by value var modelNodeDefinitions = new ModelNodeDefinition[1] { node.Item1 }; if (node.Item2 != null && node.Item3 != null) { // Compute AnimationClipResult animationClipResult = null; animationOperations.Clear(); animationOperations.Add(AnimationOperation.NewPush(node.Item3, animationKey)); node.Item2.Compute(animationOperations, ref animationClipResult); var updateMemberInfos = new List <UpdateMemberInfo>(); foreach (var channel in animationClipResult.Channels) { if (channel.IsUserCustomProperty) { continue; } updateMemberInfos.Add(new UpdateMemberInfo { Name = "[0]." + channel.PropertyName, DataOffset = channel.Offset }); } // TODO: Cache this var compiledUpdate = UpdateEngine.Compile(typeof(ModelNodeDefinition[]), updateMemberInfos); fixed(byte *data = animationClipResult.Data) { UpdateEngine.Run(modelNodeDefinitions, compiledUpdate, (IntPtr)data, null); } } Matrix localMatrix; var transformTRS = modelNodeDefinitions[0].Transform; Matrix.Transformation(ref transformTRS.Scale, ref transformTRS.Rotation, ref transformTRS.Position, out localMatrix); matrix = Matrix.Multiply(localMatrix, matrix); } // Done evaluating, let's decompose matrix TransformTRS transform; matrix.Decompose(out transform.Scale, out transform.Rotation, out transform.Position); // Create a key translationCurve.KeyFrames.Add(new KeyFrameData <Vector3>(animationKey, transform.Position)); rotationCurve.KeyFrames.Add(new KeyFrameData <Quaternion>(animationKey, transform.Rotation)); scaleCurve.KeyFrames.Add(new KeyFrameData <Vector3>(animationKey, transform.Scale)); } combinedAnimationClip.AddCurve($"{nameof(ModelNodeTransformation.Transform)}.{nameof(TransformTRS.Position)}", translationCurve); combinedAnimationClip.AddCurve($"{nameof(ModelNodeTransformation.Transform)}.{nameof(TransformTRS.Rotation)}", rotationCurve); combinedAnimationClip.AddCurve($"{nameof(ModelNodeTransformation.Transform)}.{nameof(TransformTRS.Scale)}", scaleCurve); nodeAnimationClip = combinedAnimationClip; } var transformStart = $"{nameof(ModelNodeTransformation.Transform)}."; var transformPosition = $"{nameof(ModelNodeTransformation.Transform)}.{nameof(TransformTRS.Position)}"; foreach (var channel in nodeAnimationClip.Channels) { var curve = nodeAnimationClip.Curves[channel.Value.CurveIndex]; // TODO: Root motion var channelName = channel.Key; if (channelName.StartsWith(transformStart)) { if (channelName == transformPosition) { // Translate node with parent 0 using PivotPosition var keyFrames = ((AnimationCurve <Vector3>)curve).KeyFrames; for (int i = 0; i < keyFrames.Count; ++i) { if (parentNodeIndex == 0) { keyFrames.Items[i].Value -= PivotPosition; } keyFrames.Items[i].Value *= ScaleImport; } } animationClip.AddCurve($"[ModelComponent.Key].Skeleton.NodeTransformations[{skeletonMapping.SourceToTarget[nodeIndex]}]." + channelName, curve); } } } } if (ImportCustomAttributes) { // Add clips clips animating other properties than node transformations foreach (var nodeAnimationClipPair in animationClips) { var nodeName = nodeAnimationClipPair.Key; var nodeAnimationClip = nodeAnimationClipPair.Value; foreach (var channel in nodeAnimationClip.Channels) { var channelName = channel.Key; var channelValue = channel.Value; if (channelValue.IsUserCustomProperty) { animationClip.AddCurve(nodeName + "_" + channelName, nodeAnimationClip.Curves[channel.Value.CurveIndex], true); } } } } } if (animationClip.Channels.Count == 0) { var logString = $"File {SourcePath} doesn't have any animation information."; if (failOnEmptyAnimation) { commandContext.Logger.Error(logString); return(null); } commandContext.Logger.Info(logString); } else { if (animationClip.Duration.Ticks == 0) { commandContext.Logger.Verbose($"File {SourcePath} has a 0 tick long animation."); } // Optimize and set common parameters animationClip.RepeatMode = AnimationRepeatMode; animationClip.Optimize(); } return(animationClip); }
public IToken Tokenize(ModelNodeDefinition node) { return(Tokenize((PropertyDefinition)node)); }
private static bool IsTopLevelNodeInNamespace(ModelNodeDefinition node) { return(!(node is NamespaceDefinition) && node.Parent is NamespaceDefinition); }
public IToken Tokenize(ModelNodeDefinition node) { return(Tokenize((ClassDefinition)node)); }
private static bool HasNameConflict(string className, ModelNodeDefinition parent) { return(parent.Children.Any(c => c.Name == className)); }
public IToken Tokenize(ModelNodeDefinition node) { return(Tokenize((MethodDefinition)node)); }