private static void CreateMDL0Object( InstanceEntry inst, NodeEntry node, ResourceNode parent, PrimitiveManager manager, MDL0Node model, DecoderShell shell) { if (manager != null) { Error = "There was a problem creating a new object for " + (node._name != null ? node._name : node._id); MDL0ObjectNode poly = new MDL0ObjectNode() { _manager = manager, _name = node._name != null ? node._name : node._id, _drawCalls = new BindingList <DrawCall>() }; //Attach material if (inst._material != null) { foreach (MaterialEntry mat in shell._materials) { if (mat._id == inst._material._target) { poly._drawCalls.Add(new DrawCall(poly) { MaterialNode = mat._node as MDL0MaterialNode }); } } } model._numTriangles += poly._numFaces = manager._faceCount = manager._pointCount / 3; model._numFacepoints += poly._numFacepoints = manager._pointCount; poly._parent = model._objGroup; model._objList.Add(poly); model.ResetToBindState(); //Attach single-bind if (parent != null && parent is MDL0BoneNode) { MDL0BoneNode bone = (MDL0BoneNode)parent; poly.DeferUpdateAssets(); poly.MatrixNode = bone; foreach (DrawCall c in poly._drawCalls) { c.VisibilityBoneNode = bone; } } else if (model._boneList.Count == 0) { Error = String.Format("There was a problem rigging {0} to a single bone.", poly._name); Box box = poly.GetBox(); MDL0BoneNode bone = new MDL0BoneNode() { Scale = Vector3.One, Translation = (box.Max + box.Min) / 2.0f, _name = "TransN_" + poly.Name, Parent = TempRootBone, }; poly.DeferUpdateAssets(); poly.MatrixNode = bone; ((MDL0BoneNode)TempRootBone).RecalcBindState(true, false, false); foreach (DrawCall c in poly._drawCalls) { c.VisibilityBoneNode = bone; } } else { Error = String.Format("There was a problem checking if {0} is rigged to a single bone.", poly._name); foreach (DrawCall c in poly._drawCalls) { c.VisibilityBoneNode = model._boneList[0] as MDL0BoneNode; } IMatrixNode mtxNode = null; bool singlebind = true; foreach (Vertex3 v in poly._manager._vertices) { if (v.MatrixNode != null) { if (mtxNode == null) { mtxNode = v.MatrixNode; } if (v.MatrixNode != mtxNode) { singlebind = false; break; } } } if (singlebind && poly._matrixNode == null) { //Reassign reference entries if (poly._manager._vertices[0].MatrixNode != null) { poly._manager._vertices[0].MatrixNode.Users.Add(poly); } foreach (Vertex3 v in poly._manager._vertices) { if (v.MatrixNode != null) { v.MatrixNode.Users.Remove(v); } } poly._nodeId = -2; //Continued on polygon rebuild } } } }
public NodeOffset(uint offset, IMatrixNode node) { _offset = offset; _node = node; }
private void GetBaseInfluence() { if (_node != null) { modelPanel1.RemoveReference(_node); } MDL0BoneNode[] boneCache = _externalModel._linker.BoneCache; if ((_node = (MDL0ObjectNode)comboBox1.SelectedItem).Weighted) { int least = int.MaxValue; foreach (IMatrixNode inf in _node.Influences) { if (inf is MDL0BoneNode && ((MDL0BoneNode)inf).BoneIndex < least) { least = ((MDL0BoneNode)inf).BoneIndex; } } if (least != int.MaxValue) { MDL0BoneNode temp = (MDL0BoneNode)boneCache[least]; _baseInf = (IMatrixNode)temp.Parent; } } else { _baseInf = _node.MatrixNode; } if (_baseInf is Influence) { label2.Hide(); comboBox2.Hide(); } else if (_baseInf is MDL0BoneNode) { label2.Show(); comboBox2.Show(); } baseBone.Text = _baseInf.ToString(); if (comboBox3.SelectedIndex == 0 && _baseInf is MDL0BoneNode) { int i = 0; foreach (MDL0BoneNode s in comboBox2.Items) { if (s.Name == baseBone.Text) { comboBox2.SelectedIndex = i; break; } i++; } } _node.IsRendering = true; modelPanel1.ClearTargets(); modelPanel1.AddTarget(_node); modelPanel1.SetCamWithBox(_node.GetBox()); }
public Vertex3(Vector3 position, IMatrixNode influence) { Position = position; MatrixNode = influence; }
private static void WriteVertices(string name, List<Vertex3> vertices, IMatrixNode singleBind, XmlWriter writer) { bool first = true; //Position source writer.WriteStartElement("source"); writer.WriteAttributeString("id", name + "_Positions"); //Array start writer.WriteStartElement("float_array"); writer.WriteAttributeString("id", name + "_PosArr"); writer.WriteAttributeString("count", (vertices.Count * 3).ToString()); foreach (Vertex3 v in vertices) { if (first) first = false; else writer.WriteString(" "); Vector3 p = v.WeightedPosition; writer.WriteString(String.Format("{0} {1} {2}", p._x.ToString(CultureInfo.InvariantCulture.NumberFormat), p._y.ToString(CultureInfo.InvariantCulture.NumberFormat), p._z.ToString(CultureInfo.InvariantCulture.NumberFormat))); } writer.WriteEndElement(); //float_array //Technique writer.WriteStartElement("technique_common"); writer.WriteStartElement("accessor"); writer.WriteAttributeString("source", "#" + name + "_PosArr"); writer.WriteAttributeString("count", vertices.Count.ToString()); writer.WriteAttributeString("stride", "3"); writer.WriteStartElement("param"); writer.WriteAttributeString("name", "X"); writer.WriteAttributeString("type", "float"); writer.WriteEndElement(); //param writer.WriteStartElement("param"); writer.WriteAttributeString("name", "Y"); writer.WriteAttributeString("type", "float"); writer.WriteEndElement(); //param writer.WriteStartElement("param"); writer.WriteAttributeString("name", "Z"); writer.WriteAttributeString("type", "float"); writer.WriteEndElement(); //param writer.WriteEndElement(); //accessor writer.WriteEndElement(); //technique_common writer.WriteEndElement(); //source }
//Returns true if the vertex's matrix node is changed. private bool Weight(float value, Vertex3 vertex, WeightType type) { if (_targetBone == null || _targetBone.Locked) { return(false); } Influence targetInf = null; BoneWeight targetWeight = null; float max = 1.0f; //Get the matrix that influences this vertex IMatrixNode node = vertex.GetMatrixNode(); bool startsAsBone = false; //Convert a single bone into an influence so bones can be added to it later if (node is MDL0BoneNode) { startsAsBone = true; node = new Influence(node as MDL0BoneNode); } //Duplicate the influence if it affects more than just this vertex targetInf = node.Users.Count > 1 ? (node as Influence).Clone() : node as Influence; //Find or add the current bone to the influence List <BoneWeight> weights = targetInf.Weights; int selectedIndex = weights.Select(x => x.Bone).ToArray().IndexOf(TargetBone); if (selectedIndex < 0) { weights.Add(new BoneWeight(TargetBone, 0.0f)); selectedIndex = weights.Count - 1; } //Get the weight at the index of the current bone targetWeight = targetInf.Weights[selectedIndex]; //Can't do anything to a locked weight if (targetWeight.Locked) { return(false); } //Get the sum of all weights that can be edited by subtracting all locked values from 1.0f max = 1.0f; foreach (BoneWeight b in weights) { if (b.Locked) { max -= b.Weight; } } //Get the new value for the target weight //Clamp it between 0.0f and the max value switch (type) { default: value = RoundValue(value, max); break; case WeightType.Add: value = RoundValue(targetWeight.Weight + value, max); break; case WeightType.Multiply: value = RoundValue(targetWeight.Weight * value, max); break; } //Nothing to do if there's no change in value if (targetWeight.Weight == value) { return(false); } //Collect all unlocked weights that are not the current weight //These are weights that will be changed to accomodate the current weight edit List <int> editableWeights = new List <int>(); for (int i = 0; i < targetInf.Weights.Count; i++) { if (!targetInf.Weights[i].Locked && i != selectedIndex) { editableWeights.Add(i); } } //Return if nothing can be edited if (editableWeights.Count == 0) { return(false); } //Set the current weight with the calculated value targetWeight.Weight = value; //Get the change in value, divide it by all other editable weights, //and then add that value to those weights to bring the overall weight sum back to 1.0f float perBoneDiff = (targetWeight.Weight - value) / editableWeights.Count; if (value < max) { foreach (int i in editableWeights) { targetInf.Weights[i].Weight = RoundValue(targetInf.Weights[i].Weight + perBoneDiff, 1.0f); } } else { foreach (int i in editableWeights) { targetInf.Weights[i].Weight = 0.0f; } } //Normalize the influence just in case, this will scale all weights so they add up to 1.0f //Don't let the modified value be normalized, lock it bool locked = targetWeight.Locked; targetWeight.Locked = true; targetInf.Normalize(); targetWeight.Locked = locked; //Clean influence by removing zero weights for (int i = 0; i < targetInf.Weights.Count; i++) { if (targetInf.Weights[i].Weight <= 0.0f) { targetInf.Weights.RemoveAt(i--); } } MDL0ObjectNode obj = vertex.Parent as MDL0ObjectNode; MDL0Node model = obj.Model; IMatrixNode matrixNode; //See if the influence is just one bone if (targetInf.Weights.Count == 1) { matrixNode = targetInf.Weights[0].Bone; if (!startsAsBone && !_anyConverted.Contains(obj)) { _anyConverted.Add(obj); } } else { matrixNode = model._influences.FindOrCreate(targetInf); if (startsAsBone && !_anyConverted.Contains(obj)) { _anyConverted.Add(obj); } } //Move influence to each vertex before modifying the influence of one vertex if (obj.MatrixNode != null) { obj.TryConvertMatrixToVertex(); } vertex.DeferUpdateAssets(); vertex.MatrixNode = matrixNode; return(true); }
public Vertex3(Vector3 position, Vector3 normal, IMatrixNode influence) { Position = position; Normal = normal; Inf = influence; }
internal unsafe List<Vertex3> Finish(Vector3* pVert, IMatrixNode[] nodeTable) { //Create vertex list from remap table List<Vertex3> list = new List<Vertex3>(RemapSize); if (!Weighted) { //Add vertex to list using raw value. for (int i = 0; i < RemapSize; i++) { Vertex3 v = new Vertex3(pVert[RemapTable[i]]) { _facepoints = _points[i] }; foreach (Facepoint f in v._facepoints) f._vertex = v; list.Add(v); } } else if (nodeTable != null) { for (int i = 0; i < RemapSize; i++) { int x = RemapTable[i]; //Create new vertex, assigning the value + influence from the remap table Vertex3 v = new Vertex3(pVert[x & 0xFFFF], nodeTable[x >> 16]) { _facepoints = _points[i] }; foreach (Facepoint f in v._facepoints) f._vertex = v; //Add vertex to list list.Add(v); } } return list; }
//Decode a single primitive using command list public void Run(ref byte* pIn, byte** pAssets, byte** pOut, int count, PrimitiveGroup group, ref ushort* indices, IMatrixNode[] nodeTable) { //pIn is the address in the primitives //pOut is address of the face data buffers //pAssets is the address of the raw asset buffers int weight = 0; int index = 0, outSize; DecodeOp o; ElementDef* pDef; byte* p; byte[] pTexMtx = new byte[8]; byte* tIn, tOut; group._points.Add(new List<Facepoint>()); //Iterate commands in list fixed (ushort* pNode = Nodes) fixed (int* pDefData = Defs) fixed (byte* pCmd = Commands) { for (int i = 0; i < count; i++) { pDef = (ElementDef*)pDefData; p = pCmd; Facepoint f = new Facepoint(); Continue: o = (DecodeOp)(*p++); switch (o) { //Process weight using cache case DecodeOp.PosWeight: weight = pNode[*pIn++ / 3]; goto Continue; case DecodeOp.TexMtx0: case DecodeOp.TexMtx1: case DecodeOp.TexMtx2: case DecodeOp.TexMtx3: case DecodeOp.TexMtx4: case DecodeOp.TexMtx5: case DecodeOp.TexMtx6: case DecodeOp.TexMtx7: index = (int)o - (int)DecodeOp.TexMtx0; //if (*pIn++ == 0x60) //Identity matrix... // Console.WriteLine(); pTexMtx[index] = (byte)(*pIn++ / 3); goto Continue; case DecodeOp.ElementDirect: ElementCodec.Decoders[pDef->Output](ref pIn, ref pOut[pDef->Type], VQuant.DeQuantTable[pDef->Scale]); goto Continue; case DecodeOp.ElementIndexed: //Get asset index if (pDef->Format == 2) { index = *(bushort*)pIn; pIn += 2; } else index = *pIn++; switch (pDef->Type) { case 0: f._vertexIndex = index; break; case 1: f._normalIndex = index; break; case 2: case 3: f._colorIndices[pDef->Type - 2] = index; break; default: f._UVIndices[pDef->Type - 4] = index; break; } if (pDef->Type == 0) //Special processing for vertices { //Match weight and index with remap table int mapEntry = (weight << 16) | index; //Find matching index, starting at end of list //Lower index until a match is found at that index or index is less than 0 index = RemapSize; while ((--index >= 0) && (RemapTable[index] != mapEntry)) ; //No match, create new entry //Will be processed into vertices at the end! if (index < 0) { RemapTable[index = RemapSize++] = mapEntry; _points.Add(new List<Facepoint>()); } //Write index *indices++ = (ushort)index; _points[index].Add(f); } else { //Copy data from buffer outSize = pDef->Output; //Input data from asset cache tIn = pAssets[pDef->Type] + (index * outSize); tOut = pOut[pDef->Type]; if (tIn != null && tOut != null) { //Copy data to output while (outSize-- > 0) *tOut++ = *tIn++; //Increment element output pointer pOut[pDef->Type] = tOut; } } pDef++; goto Continue; default: break; //End } group._points[group._points.Count - 1].Add(f); } } }
private void GetBaseInfluence() { ResourceNode[] boneCache = _externalModel._linker.BoneCache; if ((_node = (MDL0ObjectNode)comboBox1.SelectedItem).Weighted) { int least = int.MaxValue; foreach (IMatrixNode inf in _node.Influences) if (inf is MDL0BoneNode && ((MDL0BoneNode)inf).BoneIndex < least) least = ((MDL0BoneNode)inf).BoneIndex; if (least != int.MaxValue) { MDL0BoneNode temp = (MDL0BoneNode)boneCache[least]; _baseInf = (IMatrixNode)temp.Parent; } } else _baseInf = _node.MatrixNode; if (_baseInf is Influence) { label2.Hide(); comboBox2.Hide(); } else if (_baseInf is MDL0BoneNode) { label2.Show(); comboBox2.Show(); } baseBone.Text = _baseInf.ToString(); if (comboBox3.SelectedIndex == 0 && _baseInf is MDL0BoneNode) { int i = 0; foreach (MDL0BoneNode s in comboBox2.Items) { if (s.Name == baseBone.Text) { comboBox2.SelectedIndex = i; break; } i++; } } modelPanel1.AddTarget(_node); Vector3 min, max; _node.GetBox(out min, out max); modelPanel1.SetCamWithBox(min, max); }
private void checkBox1_CheckedChanged(object sender, EventArgs e) { modelPanel1.ClearTargets(); _mergeModels = checkBox1.Checked; if (_mergeModels) { label1.Hide(); comboBox1.Hide(); _baseInf = (IMatrixNode)_externalModel._linker.BoneCache[0]; baseBone.Text = _baseInf.ToString(); modelPanel1.AddTarget(_externalModel); Vector3 min, max; _externalModel.GetBox(out min, out max); modelPanel1.SetCamWithBox(min, max); } else { label1.Show(); comboBox1.Show(); GetBaseInfluence(); } }
private void Weight(float value, Vertex3 vertex, bool increment) { //LET'S TANGO Influence targetInf = null; BoneWeight targetWeight = null; float max = 1.0f; int selectedIndex = 0; IMatrixNode node = vertex.MatrixNode; if (node == null) { vertex._object.ConvertInf(); node = vertex.MatrixNode; } List <BoneWeight> weights = node.Weights; if (_targetBone == null || _targetBone._locked) { return; } MDL0BoneNode origBone = null; if (node is MDL0BoneNode) { origBone = node as MDL0BoneNode; node = new Influence(origBone); } bool refs = node.Users.Count > 1; if (refs) { targetInf = (node as Influence).Clone(); } else { targetInf = (node as Influence); } weights = targetInf._weights; selectedIndex = vertex.IndexOfBone(TargetBone); if (selectedIndex == -1) { weights.Add(new BoneWeight(TargetBone, 0.0f)); selectedIndex = weights.Count - 1; } targetWeight = targetInf._weights[selectedIndex]; if (targetWeight.Locked) { return; } max = 1.0f; foreach (BoneWeight b in weights) { if (b.Locked) { max -= b.Weight; } } value = increment ? RoundValue(targetWeight.Weight + value, max) : RoundValue(value, max); if (targetWeight.Weight == value) { return; } List <int> editableWeights = new List <int>(); int c = 0; foreach (BoneWeight b in targetInf._weights) { if (!b.Locked && c != selectedIndex) { editableWeights.Add(c); } c++; } if (editableWeights.Count == 0) { return; } float diff = targetWeight.Weight - value; targetWeight.Weight = value; float val = diff / (editableWeights.Count); if (value != max) { foreach (int i in editableWeights) { targetInf._weights[i].Weight = (float)Math.Round((targetInf._weights[i].Weight + val).Clamp(0.0f, 1.0f), 7); } } else { foreach (int i in editableWeights) { targetInf._weights[i].Weight = 0; } } //Don't want the modified value to be normalized bool locked = targetWeight.Locked; targetWeight.Locked = true; targetInf.Normalize(); targetWeight.Locked = locked; vertex.MatrixNode = vertex._object.Model._influences.FindOrCreate(targetInf, false); vertex._object.ConvertInf(); vertex._object.Model.SignalPropertyChange(); _mainWindow.UpdateModel(); }
internal unsafe void RenderVerts(TKContext ctx, IMatrixNode _singleBind, MDL0BoneNode selectedBone, Vector3 cam, bool pass2) { if (!_render) return; foreach (Vertex3 v in _vertices) { Color w = v._highlightColor != Color.Transparent ? v._highlightColor : (_singleBind != null && _singleBind == selectedBone) ? Color.Red : v.GetWeightColor(selectedBone); if (w != Color.Transparent) GL.Color4(w); else GL.Color4(DefaultVertColor); float d = cam.DistanceTo(_singleBind == null ? v.WeightedPosition : _singleBind.Matrix * v.WeightedPosition); if (d == 0) d = 0.000000000001f; GL.PointSize((5000 / d).Clamp(1.0f, !pass2 ? 5.0f : 8.0f)); GL.Begin(BeginMode.Points); GL.Vertex3(v.WeightedPosition._x, v.WeightedPosition._y, v.WeightedPosition._z); GL.End(); } }
public PrimitiveManager(MDL0Object* polygon, AssetStorage assets, IMatrixNode[] nodes, MDL0ObjectNode p) { _polygon = p; byte*[] pAssetList = new byte*[12]; byte*[] pOutList = new byte*[12]; int id; //This relies on the header being accurate! _indices = new UnsafeBuffer(2 * (_pointCount = polygon->_numVertices)); _faceCount = polygon->_numFaces; //Compile decode script by reading the polygon def list //This sets how to read the facepoints ElementDescriptor desc = new ElementDescriptor(polygon); //Grab asset lists in sequential order. if ((id = polygon->_vertexId) >= 0 && desc.HasData[0] && assets.Assets[0] != null) { pOutList[0] = (byte*)(_faceData[0] = new UnsafeBuffer(12 * _pointCount)).Address; pAssetList[0] = (byte*)assets.Assets[0][id].Address; } if ((id = polygon->_normalId) >= 0 && desc.HasData[1] && assets.Assets[1] != null) { pOutList[1] = (byte*)(_faceData[1] = new UnsafeBuffer(12 * _pointCount)).Address; pAssetList[1] = (byte*)assets.Assets[1][id].Address; } for (int i = 0, x = 2; i < 2; i++, x++) if ((id = ((bshort*)polygon->_colorIds)[i]) >= 0 && desc.HasData[x] && assets.Assets[2] != null) { pOutList[x] = (byte*)(_faceData[x] = new UnsafeBuffer(4 * _pointCount)).Address; pAssetList[x] = (byte*)assets.Assets[2][id].Address; } for (int i = 0, x = 4; i < 8; i++, x++) if ((id = ((bshort*)polygon->_uids)[i]) >= 0 && desc.HasData[x] && assets.Assets[3] != null) { pOutList[x] = (byte*)(_faceData[x] = new UnsafeBuffer(8 * _pointCount)).Address; pAssetList[x] = (byte*)assets.Assets[3][id].Address; } //Extract primitives, using our descriptor and asset lists fixed (byte** pOut = pOutList) fixed (byte** pAssets = pAssetList) ExtractPrimitives(polygon, ref desc, pOut, pAssets); //Compile merged vertex list _vertices = desc.Finish((Vector3*)pAssetList[0], nodes); ushort* pIndex = (ushort*)_indices.Address; for (int x = 0; x < _pointCount; x++) if (pIndex[x] >= 0 && pIndex[x] < _vertices.Count) _vertices[pIndex[x]]._faceDataIndices.Add(x); }