protected override void LoadPosesAndAttachmentPoints(ShapeElement[] elements, List <ElementPose> intoPoses) { // Only load root pose and only the ones that have attachment points if (loadFully) { base.LoadPosesAndAttachmentPoints(elements, intoPoses); return; } ElementPose pose; for (int i = 0; i < elements.Length; i++) { ShapeElement elem = elements[i]; if (elem.AttachmentPoints == null) { continue; } intoPoses.Add(pose = new ElementPose()); pose.AnimModelMatrix = Mat4f.Create(); pose.ForElement = elem; for (int j = 0; j < elem.AttachmentPoints.Length; j++) { AttachmentPoint apoint = elem.AttachmentPoints[j]; AttachmentPointByCode[apoint.Code] = new AttachmentPointAndPose() { AttachPoint = apoint, CachedPose = pose }; } } }
public EntityHeadController(IAnimationManager animator, EntityAgent entity, Shape entityShape) { this.entity = entity; this.animManager = animator; HeadElement = entityShape.GetElementByName("head"); NeckElement = entityShape.GetElementByName("neck"); HeadGlobalMatrix = Mat4f.Create(); HeadGlobalMatrixInverted = Mat4f.Create(); HeadLocalMatrix = Mat4f.Create(); // Head List <ShapeElement> elems = HeadElement.GetParentPath(); for (int i = 0; i < elems.Count; i++) { ShapeElement elem = elems[i]; float[] localTransform = elem.GetLocalTransformMatrix(); Mat4f.Mul(HeadGlobalMatrix, HeadGlobalMatrix, localTransform); } Mat4f.Mul(HeadGlobalMatrix, HeadGlobalMatrix, HeadElement.GetLocalTransformMatrix()); Mat4f.Invert(HeadGlobalMatrixInverted, HeadGlobalMatrix); }
protected virtual void LoadPosesAndAttachmentPoints(ShapeElement[] elements, List <ElementPose> intoPoses) { ElementPose pose; for (int i = 0; i < elements.Length; i++) { ShapeElement elem = elements[i]; intoPoses.Add(pose = new ElementPose()); pose.AnimModelMatrix = Mat4f.Create(); pose.ForElement = elem; if (elem.AttachmentPoints != null) { for (int j = 0; j < elem.AttachmentPoints.Length; j++) { AttachmentPoint apoint = elem.AttachmentPoints[j]; AttachmentPointByCode[apoint.Code] = new AttachmentPointAndPose() { AttachPoint = apoint, CachedPose = pose }; } } if (elem.Children != null) { pose.ChildElementPoses = new List <ElementPose>(elem.Children.Length); LoadPosesAndAttachmentPoints(elem.Children, pose.ChildElementPoses); } } }
private void LoadWeights(ShapeElement[] elements, ShapeElementWeights[] intoList, Dictionary <string, float> elementWeight, Dictionary <string, EnumAnimationBlendMode> elementBlendMode) { for (int i = 0; i < elements.Length; i++) { ShapeElement elem = elements[i]; intoList[i] = new ShapeElementWeights(); float w; if (elementWeight.TryGetValue(elem.Name, out w)) { intoList[i].Weight = w; } else { intoList[i].Weight = meta.Weight; } EnumAnimationBlendMode blendMode; if (elementBlendMode.TryGetValue(elem.Name, out blendMode)) { intoList[i].BlendMode = blendMode; } else { intoList[i].BlendMode = meta.BlendMode; } if (elem.Children != null) { intoList[i].ChildElements = new ShapeElementWeights[elem.Children.Length]; LoadWeights(elem.Children, intoList[i].ChildElements, elementWeight, elementBlendMode); } } }
ShapeElement GetElementByName(string name, ShapeElement[] elems, StringComparison stringComparison) { if (elems == null) { return(null); } foreach (ShapeElement elem in elems) { if (elem.Name.Equals(name, stringComparison)) { return(elem); } if (elem.Children != null) { ShapeElement foundElem = GetElementByName(name, elem.Children, stringComparison); if (foundElem != null) { return(foundElem); } } } return(null); }
protected void GenerateFrame(int indexNumber, AnimationFrame[] resKeyFrames, ShapeElement[] elements, Dictionary <int, AnimationJoint> jointsById, float[] modelMatrix, List <ElementPose> transforms, bool recursive = true) { int frameNumber = resKeyFrames[indexNumber].FrameNumber; for (int i = 0; i < elements.Length; i++) { ShapeElement element = elements[i]; ElementPose animTransform = new ElementPose(); animTransform.ForElement = element; GenerateFrameForElement(frameNumber, element, ref animTransform); transforms.Add(animTransform); float[] animModelMatrix = Mat4f.CloneIt(modelMatrix); Mat4f.Mul(animModelMatrix, animModelMatrix, element.GetLocalTransformMatrix(null, animTransform)); if (element.JointId > 0 && !jointsDone.Contains(element.JointId)) { resKeyFrames[indexNumber].SetTransform(element.JointId, animModelMatrix); jointsDone.Add(element.JointId); } if (recursive && element.Children != null) { GenerateFrame(indexNumber, resKeyFrames, element.Children, jointsById, animModelMatrix, animTransform.ChildElementPoses); } } }
private int seekRightKeyFrame(int aboveFrameNumber, ShapeElement forElement, int forFlag) { int firstIndex = -1; for (int i = 0; i < KeyFrames.Length; i++) { AnimationKeyFrame keyframe = KeyFrames[i]; AnimationKeyFrameElement kelem = keyframe.GetKeyFrameElement(forElement); if (kelem != null && kelem.IsSet(forFlag)) { if (firstIndex == -1) { firstIndex = i; } if (keyframe.Frame <= aboveFrameNumber) { continue; } return(i); } } return(firstIndex); }
private bool applyStepParents(ShapeElement parentElem, ShapeElement[] elements, Shape toShape, string code, CompositeShape cshape, string shapePathForLogging) { bool added = false; foreach (var cElem in elements) { ShapeElement refelem; if (cElem.Children != null) { added |= applyStepParents(cElem, cElem.Children, toShape, code, cshape, shapePathForLogging); } if (cElem.StepParentName != null) { refelem = toShape.GetElementByName(cElem.StepParentName, StringComparison.InvariantCultureIgnoreCase); if (refelem == null) { Api.World.Logger.Warning("Shape {0} requires step parent element with name {1}, but no such element was found in shape {2}. Will not be visible.", cshape.Base, cElem.StepParentName, shapePathForLogging); continue; } } else { if (parentElem == null) { Api.World.Logger.Warning("Entity armor shape element {0} in shape {1} did not define a step parent element. Will not be visible.", cElem.Name, cshape.Base); } continue; } if (parentElem != null) { parentElem.Children = parentElem.Children.Remove(cElem); } if (refelem.Children == null) { refelem.Children = new ShapeElement[] { cElem }; } else { refelem.Children = refelem.Children.Append(cElem); } cElem.SetJointIdRecursive(refelem.JointId); cElem.WalkRecursive((el) => { foreach (var face in el.Faces) { face.Value.Texture = "#" + code + "-" + face.Value.Texture.TrimStart('#'); } }); added = true; } return(added); }
public ShapeElement[] CloneElements() { ShapeElement[] elems = new ShapeElement[Elements.Length]; for (int i = 0; i < elems.Length; i++) { elems[i] = Elements[i].Clone(); } return(elems); }
internal AnimationKeyFrameElement GetKeyFrameElement(ShapeElement forElem) { if (forElem == null) { return(null); } AnimationKeyFrameElement kelem = null; ElementsByShapeElement.TryGetValue(forElem, out kelem); return(kelem); }
private void CollectAttachmentPoints(ShapeElement elem) { for (int j = 0; elem.AttachmentPoints != null && j < elem.AttachmentPoints.Length; j++) { AttachmentPointsByCode[elem.AttachmentPoints[j].Code] = elem.AttachmentPoints[j]; } for (int j = 0; elem.Children != null && j < elem.Children.Length; j++) { CollectAttachmentPoints(elem.Children[j]); } }
public float[] GetLocalTransformMatrix(float[] output = null, ElementPose tf = null) { if (tf == null) { tf = noTransform; } ShapeElement elem = this; if (output == null) { output = Mat4f.Create(); } float[] origin = new float[] { 0f, 0f, 0f }; if (elem.RotationOrigin != null) { origin[0] = (float)elem.RotationOrigin[0] / 16; origin[1] = (float)elem.RotationOrigin[1] / 16; origin[2] = (float)elem.RotationOrigin[2] / 16; } Mat4f.Translate(output, output, origin); if (elem.RotationX + tf.degX != 0) { Mat4f.RotateX(output, output, (float)(elem.RotationX + tf.degX) * GameMath.DEG2RAD); } if (elem.RotationY + tf.degY != 0) { Mat4f.RotateY(output, output, (float)(elem.RotationY + tf.degY) * GameMath.DEG2RAD); } if (elem.RotationZ + tf.degZ != 0) { Mat4f.RotateZ(output, output, (float)(elem.RotationZ + tf.degZ) * GameMath.DEG2RAD); } Mat4f.Scale(output, output, new float[] { (float)elem.ScaleX * tf.scaleX, (float)elem.ScaleY * tf.scaleY, (float)elem.ScaleZ * tf.scaleZ }); Mat4f.Translate(output, output, new float[] { -origin[0], -origin[1], -origin[2] }); Mat4f.Translate(output, output, new float[] { (float)elem.From[0] / 16 + tf.translateX, (float)elem.From[1] / 16 + tf.translateY, (float)elem.From[2] / 16 + tf.translateZ }); return(output); }
/// <summary> /// Walks the element tree and collects all parents, starting with the root element /// </summary> /// <returns></returns> public List <ShapeElement> GetParentPath() { List <ShapeElement> path = new List <ShapeElement>(); ShapeElement parentElem = this.ParentElement; while (parentElem != null) { path.Add(parentElem); parentElem = parentElem.ParentElement; } path.Reverse(); return(path); }
private int seekLeftKeyFrame(int leftOfKeyFrameIndex, ShapeElement forElement, int forFlag) { for (int i = 0; i < KeyFrames.Length; i++) { int index = GameMath.Mod(leftOfKeyFrameIndex - i - 1, KeyFrames.Length); AnimationKeyFrame keyframe = KeyFrames[index]; AnimationKeyFrameElement kelem = keyframe.GetKeyFrameElement(forElement); if (kelem != null && kelem.IsSet(forFlag)) { return(index); } } return(-1); }
/// <summary> /// Collects all the elements in the shape recursively. /// </summary> /// <param name="elements"></param> /// <param name="elementsByName"></param> public void CollectElements(ShapeElement[] elements, Dictionary <string, ShapeElement> elementsByName) { if (elements == null) { return; } for (int i = 0; i < elements.Length; i++) { ShapeElement elem = elements[i]; elementsByName[elem.Name] = elem; CollectElements(elem.Children, elementsByName); } }
AnimationKeyFrameElement FindKeyFrameElement(ShapeElement forElem) { if (forElem == null) { return(null); } foreach (var val in Elements) { if (forElem.Name == val.Key) { return(val.Value); } } return(null); }
public ShapeElement Clone() { ShapeElement elem = new ShapeElement() { AttachmentPoints = (AttachmentPoint[])AttachmentPoints?.Clone(), Faces = new Dictionary <string, ShapeElementFace>(Faces), From = (double[])From?.Clone(), To = (double[])To?.Clone(), inverseModelTransform = (float[])inverseModelTransform?.Clone(), JointId = JointId, RenderPass = RenderPass, RotationX = RotationX, RotationY = RotationY, RotationZ = RotationZ, Reflective = Reflective, RotationOrigin = (double[])RotationOrigin?.Clone(), SeasonColorMap = SeasonColorMap, ClimateColorMap = ClimateColorMap, StepParentName = StepParentName, Shade = Shade, WindMode = WindMode, WindData = WindData, WaterWave = WaterWave, DisableRandomDrawOffset = DisableRandomDrawOffset, ZOffset = ZOffset, GradientShade = GradientShade, ScaleX = ScaleX, ScaleY = ScaleY, ScaleZ = ScaleZ, Name = Name }; if (Children != null) { elem.Children = new ShapeElement[Children.Length]; for (int i = 0; i < Children.Length; i++) { elem.Children[i] = Children[i].Clone(); elem.Children[i].ParentElement = elem; } } return(elem); }
/// <summary> /// Returns the full inverse model matrix (includes all parent transforms) /// </summary> /// <returns></returns> public float[] GetInverseModelMatrix() { List <ShapeElement> elems = GetParentPath(); float[] modelTransform = Mat4f.Create(); for (int i = 0; i < elems.Count; i++) { ShapeElement elem = elems[i]; float[] localTransform = elem.GetLocalTransformMatrix(); Mat4f.Mul(modelTransform, modelTransform, localTransform); } Mat4f.Mul(modelTransform, modelTransform, GetLocalTransformMatrix()); float[] inverseTransformMatrix = Mat4f.Invert(Mat4f.Create(), modelTransform); return(inverseTransformMatrix); }
protected virtual void ApplyTransformToElements(float[] matrix, float[] globMatrix, float[] globMatrixInverted, ShapeElement[] forElems, ShapeElement jointElement, int jointId) { float[] transformationMatrices = animManager.Animator.Matrices; for (int k = 0; k < forElems.Length; k++) { ShapeElement elem = forElems[k]; if (elem == jointElement || elem.JointId != jointId) { for (int i = 0; i < 16; i++) { tmpMatrix[i] = transformationMatrices[16 * elem.JointId + i]; } float[] origin = new float[] { (float)jointElement.RotationOrigin[0] / 16f, (float)jointElement.RotationOrigin[1] / 16f, (float)jointElement.RotationOrigin[2] / 16f }; Mat4f.Mul(tmpMatrix, tmpMatrix, globMatrix); Mat4f.Translate(tmpMatrix, tmpMatrix, origin); Mat4f.Mul(tmpMatrix, tmpMatrix, matrix); origin[0] = -origin[0]; origin[1] = -origin[1]; origin[2] = -origin[2]; Mat4f.Translate(tmpMatrix, tmpMatrix, origin); Mat4f.Mul(tmpMatrix, tmpMatrix, globMatrixInverted); for (int i = 0; i < 16; i++) { transformationMatrices[16 * elem.JointId + i] = tmpMatrix[i]; } } if (elem.Children != null) { ApplyTransformToElements(matrix, globMatrix, globMatrixInverted, elem.Children, jointElement, jointId); } } }
protected void GenerateFrameForElement(int frameNumber, ShapeElement element, ref ElementPose transform) { for (int flag = 0; flag < 3; flag++) { AnimationKeyFrameElement curKelem, nextKelem; getTwoKeyFramesElementForFlag(frameNumber, element, flag, out curKelem, out nextKelem); if (curKelem == null) { continue; } float t; if (nextKelem == null || curKelem == nextKelem) { nextKelem = curKelem; t = 0; } else { if (nextKelem.Frame < curKelem.Frame) { int quantity = nextKelem.Frame + (QuantityFrames - curKelem.Frame); int framePos = GameMath.Mod(frameNumber - curKelem.Frame, QuantityFrames); t = (float)framePos / quantity; } else { t = (float)(frameNumber - curKelem.Frame) / (nextKelem.Frame - curKelem.Frame); } } lerpKeyFrameElement(curKelem, nextKelem, flag, t, ref transform); transform.RotShortestDistance = curKelem.RotShortestDistance; } }
private void ResolveReferences(ILogger errorLogger, string shapeName, Dictionary <string, ShapeElement> elementsByName, AnimationKeyFrame kf) { if (kf == null) { return; } foreach (var val in kf.Elements) { ShapeElement elem = null; elementsByName.TryGetValue(val.Key, out elem); if (elem == null) { errorLogger.Error("Shape {0} has a key frame elmenent for which the referencing shape element {1} cannot be found.", shapeName, val.Key); val.Value.ForElement = new ShapeElement(); continue; } val.Value.ForElement = elem; } }
protected void getTwoKeyFramesElementForFlag(int frameNumber, ShapeElement forElement, int forFlag, out AnimationKeyFrameElement left, out AnimationKeyFrameElement right) { left = null; right = null; int rightKfIndex = seekRightKeyFrame(frameNumber, forElement, forFlag); if (rightKfIndex == -1) { return; } right = KeyFrames[rightKfIndex].GetKeyFrameElement(forElement); int leftKfIndex = seekLeftKeyFrame(rightKfIndex, forElement, forFlag); if (leftKfIndex == -1) { left = right; return; } left = KeyFrames[leftKfIndex].GetKeyFrameElement(forElement); }
/// <summary> /// Attempts to resolve all references within the shape. Logs missing references them to the errorLogger /// </summary> /// <param name="errorLogger"></param> /// <param name="shapeNameForLogging"></param> public void ResolveReferences(ILogger errorLogger, string shapeNameForLogging) { Dictionary <string, ShapeElement> elementsByName = new Dictionary <string, ShapeElement>(); CollectElements(Elements, elementsByName); for (int i = 0; Animations != null && i < Animations.Length; i++) { Animation anim = Animations[i]; for (int j = 0; j < anim.KeyFrames.Length; j++) { AnimationKeyFrame keyframe = anim.KeyFrames[j]; ResolveReferences(errorLogger, shapeNameForLogging, elementsByName, keyframe); foreach (AnimationKeyFrameElement kelem in keyframe.Elements.Values) { kelem.Frame = keyframe.Frame; } } if (anim.Code == null || anim.Code.Length == 0) { anim.Code = anim.Name.ToLowerInvariant().Replace(" ", ""); } AnimationsByCrc32[AnimationMetaData.GetCrc32(anim.Code)] = anim; } for (int i = 0; i < Elements.Length; i++) { ShapeElement elem = Elements[i]; elem.ResolveRefernces(); CollectAttachmentPoints(elem); } }
/// <summary> /// Resolves all joints and loads them. /// </summary> /// <param name="requireJointsForElements"></param> public void ResolveAndLoadJoints(params string[] requireJointsForElements) { if (Animations == null) { return; } Dictionary <string, ShapeElement> elementsByName = new Dictionary <string, ShapeElement>(); CollectElements(Elements, elementsByName); ShapeElement[] allElements = elementsByName.Values.ToArray(); int jointCount = 0; HashSet <string> AnimatedElements = new HashSet <string>(); for (int i = 0; i < Animations.Length; i++) { Animation anim = Animations[i]; for (int j = 0; j < anim.KeyFrames.Length; j++) { AnimationKeyFrame kf = anim.KeyFrames[j]; AnimatedElements.AddRange(kf.Elements.Keys.ToArray()); kf.Resolve(anim, allElements); } } foreach (ShapeElement elem in elementsByName.Values) { elem.JointId = 0; } int maxDepth = 0; foreach (string code in AnimatedElements) { ShapeElement elem; elementsByName.TryGetValue(code, out elem); if (elem == null) { continue; } AnimationJoint joint = new AnimationJoint() { JointId = ++jointCount, Element = elem }; JointsById[joint.JointId] = joint; maxDepth = Math.Max(maxDepth, elem.GetParentPath().Count); } // Currently used to require a joint for the head for head control, but not really used because // the player head also happens to be using in animations so it has a joint anyway foreach (string elemName in requireJointsForElements) { if (!AnimatedElements.Contains(elemName)) { ShapeElement elem = GetElementByName(elemName); if (elem == null) { continue; } AnimationJoint joint = new AnimationJoint() { JointId = ++jointCount, Element = elem }; JointsById[joint.JointId] = joint; maxDepth = Math.Max(maxDepth, elem.GetParentPath().Count); } } // Iteratively and recursively assigns the lowest depth to highest depth joints to all elements // prevents that we overwrite a child joint id with a parent joint id for (int depth = 0; depth <= maxDepth; depth++) { foreach (AnimationJoint joint in JointsById.Values) { if (joint.Element.GetParentPath().Count != depth) { continue; } joint.Element.SetJointId(joint.JointId); } } }
// Careful when changing around stuff in here, this is a recursively called method private void calculateMatrices( float dt, List <ElementPose> currentPoses, ShapeElementWeights[][] weightsByAnimationAndElement, float[] modelMatrix, List <ElementPose>[] transformsByAnimation, List <ElementPose>[] nextFrameTransformsByAnimation, int depth ) { depth++; List <ElementPose>[] childTransformsByAnimation = this.transformsByAnimation[depth]; List <ElementPose>[] nextFrameChildTransformsByAnimation = this.nextFrameTransformsByAnimation[depth]; ShapeElementWeights[][] childWeightsByAnimationAndElement = this.weightsByAnimationAndElement[depth]; for (int i = 0; i < currentPoses.Count; i++) { ElementPose currentPose = currentPoses[i]; ShapeElement elem = currentPose.ForElement; currentPose.SetMat(modelMatrix); Mat4f.Identity(localTransformMatrix); currentPose.Clear(); float weightSum = 0f; for (int j = 0; j < curAnimCount; j++) { RunningAnimation anim = CurAnims[j]; ShapeElementWeights sew = weightsByAnimationAndElement[j][i]; if (sew.BlendMode != EnumAnimationBlendMode.Add) { weightSum += sew.Weight * anim.EasingFactor; } } for (int j = 0; j < curAnimCount; j++) { RunningAnimation anim = CurAnims[j]; ShapeElementWeights sew = weightsByAnimationAndElement[j][i]; //anim.CalcBlendedWeight(sew.Weight weightSum, sew.BlendMode); - that makes no sense for element weights != 1 anim.CalcBlendedWeight(weightSum / sew.Weight, sew.BlendMode); ElementPose prevFramePose = transformsByAnimation[j][i]; ElementPose nextFramePose = nextFrameTransformsByAnimation[j][i]; int prevFrame = this.prevFrame[j]; int nextFrame = this.nextFrame[j]; // May loop around, so nextFrame can be smaller than prevFrame float keyFrameDist = nextFrame > prevFrame ? (nextFrame - prevFrame) : (anim.Animation.QuantityFrames - prevFrame + nextFrame); float curFrameDist = anim.CurrentFrame >= prevFrame ? (anim.CurrentFrame - prevFrame) : (anim.Animation.QuantityFrames - prevFrame + anim.CurrentFrame); float lerp = curFrameDist / keyFrameDist; currentPose.Add(prevFramePose, nextFramePose, lerp, anim.BlendedWeight); childTransformsByAnimation[j] = prevFramePose.ChildElementPoses; childWeightsByAnimationAndElement[j] = sew.ChildElements; nextFrameChildTransformsByAnimation[j] = nextFramePose.ChildElementPoses; } elem.GetLocalTransformMatrix(localTransformMatrix, currentPose); Mat4f.Mul(currentPose.AnimModelMatrix, currentPose.AnimModelMatrix, localTransformMatrix); if (elem.JointId > 0 && !jointsDone.Contains(elem.JointId)) { Mat4f.Mul(tmpMatrix, currentPose.AnimModelMatrix, elem.inverseModelTransform); for (int l = 0; l < 16; l++) { TransformationMatrices[16 * elem.JointId + l] = tmpMatrix[l]; } jointsDone.Add(elem.JointId); } if (currentPose.ChildElementPoses != null) { calculateMatrices( dt, currentPose.ChildElementPoses, childWeightsByAnimationAndElement, currentPose.AnimModelMatrix, childTransformsByAnimation, nextFrameChildTransformsByAnimation, depth ); } } }
/// <summary> /// Applies the transformation to the head element of the entity. /// </summary> /// <param name="matrix"></param> /// <param name="jointElement"></param> public virtual void ApplyTransformToElement(float[] matrix, float[] globMatrix, float[] globMatrixInverted, ShapeElement jointElement) { ApplyTransformToElements(matrix, globMatrix, globMatrixInverted, new ShapeElement[] { jointElement }, jointElement, jointElement.JointId); }