/// <summary> /// Reads a sequence from a stream and assigns it a name. /// </summary> /// <param name="stream">The stream to read from.</param> /// <param name="seqName">The name to assign.</param> /// <returns>The shape.</returns> public Shape ImportSequence(Stream stream, string seqName) { BinaryReader bin = new BinaryReader(stream); int readVersion = bin.ReadInt32(); int exporterVersion = readVersion >> 16; readVersion &= 0xFF; if (readVersion > Shape.WriteVersion || readVersion < 22) return null; Shape.ReadVersion = readVersion; Assert.Fatal(Shape.ReadVersion >= 22, "TSShapeReader.ImportSequence - Old shape formats are not supported."); int[] nodeMap; // node index of each node from imported sequences List<int> checkForDups = new List<int>(); // Read node names // -- this is how we will map imported _sequence nodes to our nodes int sz = bin.ReadInt32(); nodeMap = new int[sz]; for (int i = 0; i < sz; i++) { int startSize = _shape.Names.Length; int nameIndex = _ReadName(bin, true); int count = 0; if (nameIndex >= 0) { while (checkForDups.Count < nameIndex + 1) checkForDups.Add(0); count = checkForDups[nameIndex]++; } if (count != 0) { // not first time this Name came up...look for later instance of the node nodeMap[i] = -1; for (int j = 0; j < _shape.Nodes.Length; j++) { if (_shape.Nodes[j].NameIndex == nameIndex && count-- == 0) { nodeMap[i] = j; if (j == _shape.Nodes.Length) return null; break; } } } else { nodeMap[i] = _shape.FindNode(nameIndex); } if (nodeMap[i] < 0) { // error -- node found in _sequence but not shape if (_shape.Names.Length != startSize) Assert.Fatal(_shape.Names.Length == startSize, "Shape.ImportSequence - Invalid node in sequence."); return null; } } // Read the following size, but won't do anything with it...legacy: was going to support // import of sequences that Animate objects...we don't... sz = bin.ReadInt32(); // before reading keyframes, take note of a couple numbers int oldShapeNumObjects = bin.ReadInt32(); // adjust all the new keyframes int adjNodeRots = _shape.NodeRotations.Length; int adjNodeTrans = _shape.NodeTranslations.Length; int adjNodeScales1 = _shape.NodeUniformScales.Length; int adjNodeScales2 = _shape.NodeAlignedScales.Length; int adjNodeScales3 = _shape.NodeArbitraryScaleFactors.Length; int adjObjectStates = _shape.ObjectStates.Length - oldShapeNumObjects; int adjGroundStates = _shape.GroundTranslations.Length; // groundTrans==groundRot // add these node states to our own int addNum = bin.ReadInt32(); _readAndExtendArray(bin, ref _shape.NodeRotations, addNum); addNum = bin.ReadInt32(); _readAndExtendArray(bin, ref _shape.NodeTranslations, addNum); addNum = bin.ReadInt32(); _readAndExtendArray(bin, ref _shape.NodeUniformScales, addNum); addNum = bin.ReadInt32(); _readAndExtendArray(bin, ref _shape.NodeAlignedScales, addNum); addNum = bin.ReadInt32(); _readAndExtendArray(bin, ref _shape.NodeArbitraryScaleRotations, addNum); _readAndExtendArray(bin, ref _shape.NodeArbitraryScaleFactors, addNum); addNum = bin.ReadInt32(); _readAndExtendArray(bin, ref _shape.GroundTranslations, addNum); _readAndExtendArray(bin, ref _shape.GroundRotations, addNum); // add these object states to our own -- shouldn't be any...assume it bin.ReadInt32(); // Read sequences sz = bin.ReadInt32(); int startSeqNum = _shape.Sequences.Length; TorqueUtil.ResizeArray<Sequence>(ref _shape.Sequences, startSeqNum + sz); for (int i = startSeqNum; i < startSeqNum + sz; i++) { _shape.Sequences[i] = new Sequence(); Sequence seq = _shape.Sequences[i]; // Read Name seq.NameIndex = _ReadName(bin, true); // Read the rest of the _sequence _ReadSequence(bin, ref seq, false); seq.BaseRotation += adjNodeRots; seq.BaseTranslation += adjNodeTrans; if (seq.IsUniformScaleAnimated()) seq.BaseScale += adjNodeScales1; else if (seq.IsAlignedScaleAnimated()) seq.BaseScale += adjNodeScales2; else if (seq.IsArbitraryScaleAnimated()) seq.BaseScale += adjNodeScales3; // not quite so easy... // now we have to remap nodes from shape the _sequence came from to this shape // that's where nodeMap comes in handy... // ditto for the objects. // first the nodes BitVector newMembership1 = new BitVector(); BitVector newMembership2 = new BitVector(); BitVector newMembership3 = new BitVector(); newMembership1.SetSize(_shape.Nodes.Length); newMembership2.SetSize(_shape.Nodes.Length); newMembership3.SetSize(_shape.Nodes.Length); for (int j = 0; j < nodeMap.Length; j++) { if (seq.DoesTranslationMatter.Test(j)) newMembership1.Set(nodeMap[j]); if (seq.DoesRotationMatter.Test(j)) newMembership2.Set(nodeMap[j]); if (seq.DoesScaleMatter.Test(j)) newMembership3.Set(nodeMap[j]); } seq.DoesTranslationMatter = newMembership1; seq.DoesRotationMatter = newMembership2; seq.DoesScaleMatter = newMembership3; // adjust trigger numbers...we'll Read triggers after sequences... seq.FirstTrigger += _shape.Triggers.Length; // finally, adjust ground transform's nodes states seq.FirstGroundFrame += adjGroundStates; } // Do we need to rename the last loaded sequence? if (seqName != null && _shape.Sequences.Length != 0) { Sequence seq = _shape.Sequences[_shape.Sequences.Length - 1]; int nameIndex = _shape.FindName(seqName); if (nameIndex < 0) { nameIndex = _shape.Names.Length; TorqueUtil.ResizeArray(ref _shape.Names, _shape.Names.Length + 1); _shape.Names[_shape.Names.Length - 1] = seqName; } seq.NameIndex = nameIndex; } // add the new triggers sz = bin.ReadInt32(); int startNum = _shape.Triggers.Length; TorqueUtil.ResizeArray<Trigger>(ref _shape.Triggers, sz + startNum); for (int i = startNum; i < startNum + sz; i++) { _shape.Triggers[i].State = bin.ReadInt32(); _shape.Triggers[i].Pos = bin.ReadSingle(); } _shape.Initialize(); return _shape; }
/// <summary> /// Creates a shape instance for a specified shape. /// </summary> /// <param name="inShape">The shape to wrap in this instance.</param> /// <param name="loadMaterials"></param> public ShapeInstance(Shape inShape, bool loadMaterials) { _shape = inShape; _currentDetailLevel = 0; // Set up subtree data int ss = _shape.SubShapeFirstNode.Length; _dirtyFlags = new DirtyFlags[ss]; // Set up node data int numNodes = _shape.Nodes.Length; _nodeTransforms = new Matrix[numNodes]; // add objects to trees int numObjects = _shape.Objects.Length; _meshObjects = new ObjectInstance[numObjects]; for (int i = 0; i < numObjects; i++) { _meshObjects[i].Object = _shape.Objects[i]; _meshObjects[i].Visibility = 1.0f; } // initialize bitvectors _transitionRotationNodes = new BitVector(); _transitionRotationNodes.SetSize(numNodes); _transitionTranslationNodes = new BitVector(); _transitionTranslationNodes.SetSize(numNodes); _transitionScaleNodes = new BitVector(); _transitionScaleNodes.SetSize(numNodes); _disableBlendNodes = new BitVector(); _disableBlendNodes.SetSize(numNodes); _handsOffNodes = new BitVector(); _handsOffNodes.SetSize(numNodes); // make sure we have a thread list _threadList = new List<Thread>(); _transitionThreads = new List<Thread>(); // construct ifl material objects _iflMaterialInstances = new IflMaterialInstance[_shape.IflMaterials.Length]; for (int i = 0; i < _shape.IflMaterials.Length; i++) { _iflMaterialInstances[i].IflMaterial = _shape.IflMaterials[i]; _iflMaterialInstances[i].Frame = -1; } if (loadMaterials) _SetMaterialList(_shape.MaterialList); _AnimateSubtrees(true); }
void _AnimateNodes(int ss) { if (_shape.Nodes.Length == 0) return; // temporary storage for node transforms int numNodes = _shape.Nodes.Length; if (_nodeCurrentRotations == null || _nodeCurrentRotations.Length < numNodes) { // grow all these arrays together...no need to check each individually TorqueUtil.GrowArray<Quaternion>(ref _nodeCurrentRotations, numNodes); TorqueUtil.GrowArray<Vector3>(ref _nodeCurrentTranslations, numNodes); TorqueUtil.GrowArray<Thread>(ref _workRotationThreads, numNodes); TorqueUtil.GrowArray<Thread>(ref _workTranslationThreads, numNodes); } BitVector rotBeenSet = new BitVector(); BitVector tranBeenSet = new BitVector(); BitVector scaleBeenSet = new BitVector(); rotBeenSet.SetSize(numNodes); rotBeenSet.SetAll(); tranBeenSet.SetSize(numNodes); tranBeenSet.SetAll(); scaleBeenSet.SetSize(numNodes); scaleBeenSet.SetAll(); int firstBlend = _threadList.Count; for (int i = 0; i < _threadList.Count; i++) { Thread th = _threadList[i]; if (th.Sequence.IsBlend()) { // blend sequences need default (if not Set by other _sequence) // break rather than continue because the rest will be blends too firstBlend = i; break; } rotBeenSet.TakeAway(th.Sequence.DoesRotationMatter); tranBeenSet.TakeAway(th.Sequence.DoesTranslationMatter); scaleBeenSet.TakeAway(th.Sequence.DoesScaleMatter); } rotBeenSet.TakeAway(_handsOffNodes); tranBeenSet.TakeAway(_handsOffNodes); // all the nodes marked above need to have the default transform int a = _shape.SubShapeFirstNode[ss]; int b = a + _shape.SubShapeNodeCount[ss]; for (int i = a; i < b; i++) { if (rotBeenSet.Test(i)) { _shape.DefaultRotations[i].Get(out _nodeCurrentRotations[i]); _workRotationThreads[i] = null; } if (tranBeenSet.Test(i)) { _nodeCurrentTranslations[i] = _shape.DefaultTranslations[i]; _workTranslationThreads[i] = null; } } // don't want a transform in these cases... rotBeenSet.Overlap(_handsOffNodes); tranBeenSet.Overlap(_handsOffNodes); // default Scale if (ScaleCurrentlyAnimated()) _HandleDefaultScale(a, b, ref scaleBeenSet); // handle non-blend sequences for (int i = 0; i < firstBlend; i++) { Thread th = _threadList[i]; int nodeIndex = th.Sequence.DoesRotationMatter.Start(); int end = b; for (int j = 0; nodeIndex < end; th.Sequence.DoesRotationMatter.Next(ref nodeIndex), j++) { // skip nodes outside of this detail if (nodeIndex < a) continue; if (!rotBeenSet.Test(nodeIndex)) { Quaternion q1, q2; _shape.GetRotation(th.Sequence, th._keyNum1, j, out q1); _shape.GetRotation(th.Sequence, th._keyNum2, j, out q2); Transform.Interpolate(q1, q2, th._keyPos, out _nodeCurrentRotations[nodeIndex]); rotBeenSet.Set(nodeIndex); _workRotationThreads[nodeIndex] = th; } } nodeIndex = th.Sequence.DoesTranslationMatter.Start(); end = b; for (int j = 0; nodeIndex < end; th.Sequence.DoesTranslationMatter.Next(ref nodeIndex), j++) { if (nodeIndex < a) continue; if (!tranBeenSet.Test(nodeIndex)) { Vector3 p1 = _shape.GetTranslation(th.Sequence, th._keyNum1, j); Vector3 p2 = _shape.GetTranslation(th.Sequence, th._keyNum2, j); Transform.Interpolate(p1, p2, th._keyPos, out _nodeCurrentTranslations[nodeIndex]); _workTranslationThreads[nodeIndex] = th; tranBeenSet.Set(nodeIndex); } } if (ScaleCurrentlyAnimated()) _HandleAnimatedScale(th, a, b, ref scaleBeenSet); } // transitions... if (InTransition()) _HandleTransitionNodes(a, b); // compute transforms for (int i = a; i < b; i++) if (!_handsOffNodes.Test(i)) Transform.SetMatrix(_nodeCurrentRotations[i], _nodeCurrentTranslations[i], out _nodeTransforms[i]); // add Scale onto transforms if (ScaleCurrentlyAnimated()) _HandleNodeScale(a, b); // get callback transforms... if (_callbackNodes != null) for (int i = 0; i < _callbackNodes.Count; i++) _callbackNodes[i].Transform.GetLocalMatrix(out _nodeTransforms[_callbackNodes[i].NodeIndex], true); // handle blend sequences for (int i = firstBlend; i < _threadList.Count; i++) { Thread th = _threadList[i]; if (th._blendDisabled) continue; _HandleBlendSequence(th, a, b); } // multiply transforms... for (int i = a; i < b; i++) { int parentIdx = _shape.Nodes[i].ParentIndex; if (parentIdx >= 0) _nodeTransforms[i] = Matrix.Multiply(_nodeTransforms[i], _nodeTransforms[parentIdx]); } }
void _AnimateVisibility(int ss) { if (_meshObjects.Length == 0) return; // find out who needs default values Set BitVector beenSet = new BitVector(); beenSet.SetSize(_meshObjects.Length); beenSet.SetAll(); for (int i = 0; i < _threadList.Count; i++) beenSet.TakeAway(_threadList[i].Sequence.DoesVisibilityMatter); // Set defaults int a = _shape.SubShapeFirstObject[ss]; int b = a + _shape.SubShapeObjectCount[ss]; for (int i = a; i < b; i++) { if (beenSet.Test(i)) _meshObjects[i].Visibility = _shape.ObjectStates[i].Visibility; } // go through each thread and Set visibility on those objects that // are not Set yet and are controlled by that thread BitVector objectMatters = new BitVector(); for (int i = 0; i < _threadList.Count; i++) { Thread th = _threadList[i]; objectMatters.Copy(ref th.Sequence.DoesFrameMatter); objectMatters.Overlap(th.Sequence.DoesMaterialFrameMatter); objectMatters.Overlap(th.Sequence.DoesVisibilityMatter); // skip to beginining of this sub-shape int j = 0; int start = objectMatters.Start(); int end = b; for (int objectIndex = start; objectIndex < b; objectMatters.Next(ref objectIndex), j++) { if (!beenSet.Test(objectIndex) && th.Sequence.DoesVisibilityMatter.Test(objectIndex)) { float state1 = _shape.GetObjectState(th.Sequence, th._keyNum1, j).Visibility; float state2 = _shape.GetObjectState(th.Sequence, th._keyNum2, j).Visibility; if ((state1 - state2) * (state1 - state2) > 0.99f) // goes from 0 to 1 -- discreet jump _meshObjects[objectIndex].Visibility = th._keyPos < 0.5f ? state1 : state2; else // Interpolate between keyframes when visibility change is gradual _meshObjects[objectIndex].Visibility = (1.0f - th._keyPos) * state1 + th._keyPos * state2; // record change so that later threads don't over-write us... beenSet.Set(objectIndex); } } } }
void _AnimateMatFrame(int ss) { if (_meshObjects.Length == 0) return; // find out who needs default values Set BitVector beenSet = new BitVector(); beenSet.SetSize(_meshObjects.Length); beenSet.SetAll(); for (int i = 0; i < _threadList.Count; i++) beenSet.TakeAway(_threadList[i].Sequence.DoesMaterialFrameMatter); // Set defaults int a = _shape.SubShapeFirstObject[ss]; int b = a + _shape.SubShapeObjectCount[ss]; for (int i = a; i < b; i++) { if (beenSet.Test(i)) _meshObjects[i].MaterialFrame = _shape.ObjectStates[i].MaterialFrameIndex; } // go through each thread and Set matFrame on those objects that // are not Set yet and are controlled by that thread BitVector objectMatters = new BitVector(); for (int i = 0; i < _threadList.Count; i++) { Thread th = _threadList[i]; objectMatters.Copy(ref th.Sequence.DoesFrameMatter); objectMatters.Overlap(th.Sequence.DoesMaterialFrameMatter); objectMatters.Overlap(th.Sequence.DoesVisibilityMatter); // skip to beginining of this sub-shape int j = 0; int start = objectMatters.Start(); int end = b; for (int objectIndex = start; objectIndex < end; objectMatters.Next(ref objectIndex), j++) { if (!beenSet.Test(objectIndex) && th.Sequence.DoesMaterialFrameMatter.Test(objectIndex)) { int key = (th._keyPos < 0.5f) ? th._keyNum1 : th._keyNum2; _meshObjects[objectIndex].MaterialFrame = _shape.GetObjectState(th.Sequence, key, j).MaterialFrameIndex; // record change so that later threads don't over-write us... beenSet.Set(objectIndex); } } } }