public void ImportFolder(string inFolder) { DirectoryInfo dir = new DirectoryInfo(inFolder); FileInfo[] files; files = dir.GetFiles(); foreach (FileInfo info in files) { string ext = Path.GetExtension(info.FullName).ToUpper(); if (ext == ".PNG" || ext == ".TGA" || ext == ".BMP" || ext == ".JPG" || ext == ".JPEG" || ext == ".GIF" || ext == ".TIF" || ext == ".TIFF") { using (TextureConverterDialog dlg = new TextureConverterDialog()) { dlg.ImageSource = info.FullName; dlg.ShowDialog(null, this); } } else if (ext == ".TEX0") { TEX0Node node = NodeFactory.FromFile(null, info.FullName) as TEX0Node; GetOrCreateFolder <TEX0Node>().AddChild(node); } else if (ext == ".MDL0") { MDL0Node node = NodeFactory.FromFile(null, info.FullName) as MDL0Node; GetOrCreateFolder <MDL0Node>().AddChild(node); } else if (ext == ".CHR0") { CHR0Node node = NodeFactory.FromFile(null, info.FullName) as CHR0Node; GetOrCreateFolder <CHR0Node>().AddChild(node); } else if (ext == ".CLR0") { CLR0Node node = NodeFactory.FromFile(null, info.FullName) as CLR0Node; GetOrCreateFolder <CLR0Node>().AddChild(node); } else if (ext == ".SRT0") { SRT0Node node = NodeFactory.FromFile(null, info.FullName) as SRT0Node; GetOrCreateFolder <SRT0Node>().AddChild(node); } else if (ext == ".SHP0") { SHP0Node node = NodeFactory.FromFile(null, info.FullName) as SHP0Node; GetOrCreateFolder <SHP0Node>().AddChild(node); } else if (ext == ".PAT0") { PAT0Node node = NodeFactory.FromFile(null, info.FullName) as PAT0Node; GetOrCreateFolder <PAT0Node>().AddChild(node); } else if (ext == ".VIS0") { VIS0Node node = NodeFactory.FromFile(null, info.FullName) as VIS0Node; GetOrCreateFolder <VIS0Node>().AddChild(node); } } }
public void AddTarget(MDL0Node model) { if (!_targetModels.Contains(model)) _targetModels.Add(model); modelPanel.AddTarget(model); model.ApplyCHR(null, 0); model._renderBones = true; }
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) { MDL0Node model = (context.Instance as MovesetEntry).Model; if (model != null) { return(new StandardValuesCollection(model._linker.BoneCache.Select(n => n.ToString()).ToList())); } return(null); }
public DialogResult ShowDialog(MDL0Node internalModel, MDL0Node externalModel) { _internalModel = internalModel; _externalModel = externalModel; _externalModel._renderBones = false; comboBox1.Items.AddRange(_externalModel.FindChild("Objects", true).Children.ToArray()); comboBox2.Items.AddRange(_internalModel._linker.BoneCache); comboBox1.SelectedIndex = comboBox2.SelectedIndex = comboBox3.SelectedIndex = 0; _parent = (MDL0BoneNode)comboBox2.SelectedItem; return base.ShowDialog(null); }
public void Port(MDL0Node baseModel) { MDL0Node model; OpenFileDialog dlgOpen = new OpenFileDialog(); dlgOpen.Filter = "MDL0 Model (*.mdl0)|*.mdl0"; dlgOpen.Title = "Select the model this animation is for..."; if (dlgOpen.ShowDialog() == DialogResult.OK) { if ((model = (MDL0Node)NodeFactory.FromFile(null, dlgOpen.FileName)) != null) { Port(baseModel, model); } } }
protected override bool OnInitialize() { //if (_name == null) _name = String.Format("Shader{0}", Index); //Attach to materials MDL0Node model = Model; byte * pHeader = (byte *)Header; if ((model != null) && (model._matList != null)) { foreach (MDL0MaterialNode mat in model._matList) { MDL0Material *mHeader = mat.Header; if (((byte *)mHeader + mHeader->_shaderOffset) == pHeader) { mat._shader = this; _materials.Add(mat); } } } return(false); }
public static unsafe void PMD2MDL0(MDL0Node model) { model._version = 9; model._isImport = true; Collada._importOptions = BrawlLib.Properties.Settings.Default.ColladaImportOptions; Collada._importOptions._forceCCW = true; Collada._importOptions._fltVerts = true; Collada._importOptions._fltNrms = true; Collada._importOptions._fltUVs = true; model.InitGroups(); List<MDL0BoneNode> BoneCache = new List<MDL0BoneNode>(); int index = 0; if (!String.IsNullOrWhiteSpace(_header._modelNameEnglish)) model.Name = _header._modelNameEnglish; else model.Name = _header._modelName; if (!String.IsNullOrWhiteSpace(_header._commentEnglish)) MessageBox.Show(_header._commentEnglish); else MessageBox.Show(_header._comment); ModelBone parent = null; foreach (ModelBone b in _bones) { MDL0BoneNode bone = new MDL0BoneNode(); if (!String.IsNullOrWhiteSpace(b._boneNameEnglish)) bone._name = b._boneNameEnglish; else bone._name = b._boneName; bone._entryIndex = index++; if (b._parentBoneIndex != ushort.MaxValue) { parent = _bones[b._parentBoneIndex]; foreach (MDL0BoneNode v in model._boneGroup._children) AssignParent(v, b, bone, parent); } else { bone.Parent = model._boneGroup; bone._bindState._scale = new Vector3(1.0f); bone._bindState._translate = new Vector3(b._wPos[0], b._wPos[1], b._wPos[2]); bone._bindState.CalcTransforms(); bone.RecalcBindState(); } BoneCache.Add(bone); } MDL0ShaderNode texSpa = null, tex = null, colorSpa = null, color = null; index = 0; foreach (ModelMaterial m in _materials) { MDL0MaterialNode mn = new MDL0MaterialNode(); mn.Name = "Material" + index++; MDL0MaterialRefNode texRef = null; MDL0MaterialRefNode spaRef = null; if (!String.IsNullOrEmpty(m._textureFileName)) if (m._textureFileName.Contains('*')) { string[] names = m._textureFileName.Split('*'); if (!String.IsNullOrEmpty(names[0])) { texRef = new MDL0MaterialRefNode(); texRef.Name = names[0].Substring(0, names[0].IndexOf('.')); } if (!String.IsNullOrEmpty(names[1])) { spaRef = new MDL0MaterialRefNode(); spaRef.Name = names[1].Substring(0, names[1].IndexOf('.')); spaRef.MapMode = MDL0MaterialRefNode.MappingMethod.EnvCamera; spaRef.UWrapMode = MDL0MaterialRefNode.WrapMode.Clamp; spaRef.VWrapMode = MDL0MaterialRefNode.WrapMode.Clamp; spaRef.Projection = Wii.Graphics.TexProjection.STQ; spaRef.InputForm = Wii.Graphics.TexInputForm.ABC1; spaRef.Coordinates = Wii.Graphics.TexSourceRow.Normals; spaRef.Normalize = true; } } else { texRef = new MDL0MaterialRefNode(); texRef.Name = m._textureFileName.Substring(0, m._textureFileName.IndexOf('.')); texRef.Coordinates = Wii.Graphics.TexSourceRow.TexCoord0; } if (texRef != null) { (texRef._texture = model.FindOrCreateTexture(texRef.Name))._references.Add(texRef); texRef._parent = mn; mn._children.Add(texRef); } if (spaRef != null) { (spaRef._texture = model.FindOrCreateTexture(spaRef.Name))._references.Add(spaRef); spaRef._parent = mn; mn._children.Add(spaRef); } mn._chan1._matColor = new RGBAPixel((byte)(m._diffuseColor[0] * 255), (byte)(m._diffuseColor[1] * 255), (byte)(m._diffuseColor[2] * 255), 255); mn._chan1.ColorMaterialSource = GXColorSrc.Register; if (texRef != null && spaRef != null) { if (texSpa == null) { MDL0ShaderNode n = TexSpaShader; n._parent = model._shadGroup; model._shadList.Add(n); texSpa = n; } mn.ShaderNode = texSpa; } else if (texRef != null) { if (tex == null) { MDL0ShaderNode n = TexShader; n._parent = model._shadGroup; model._shadList.Add(n); tex = n; } mn.ShaderNode = tex; } else if (spaRef != null) { if (colorSpa == null) { MDL0ShaderNode n = ColorSpaShader; n._parent = model._shadGroup; model._shadList.Add(n); colorSpa = n; } mn.ShaderNode = colorSpa; } else { if (color == null) { MDL0ShaderNode n = ColorShader; n._parent = model._shadGroup; model._shadList.Add(n); color = n; } mn.ShaderNode = color; } mn._parent = model._matGroup; model._matList.Add(mn); } model._numFaces = 0; model._numFacepoints = 0; int x = 0; int offset = 0; foreach (ModelMaterial m in _materials) { PrimitiveManager manager = new PrimitiveManager() { _pointCount = (int)m._faceVertCount }; MDL0ObjectNode p = new MDL0ObjectNode() { _manager = manager, _opaMaterial = (MDL0MaterialNode)model._matList[x] }; p._opaMaterial._objects.Add(p); p._manager._vertices = new List<Vertex3>(); p.Name = "polygon" + x++; p._parent = model._objGroup; model._numFaces += p._numFaces = manager._faceCount = manager._pointCount / 3; model._numFacepoints += p._numFacepoints = manager._pointCount; p._manager._indices = new UnsafeBuffer((int)m._faceVertCount * 2); p._manager._faceData[0] = new UnsafeBuffer((int)m._faceVertCount * 12); p._manager._faceData[1] = new UnsafeBuffer((int)m._faceVertCount * 12); p._manager._faceData[4] = new UnsafeBuffer((int)m._faceVertCount * 8); p._manager._dirty[0] = true; p._manager._dirty[1] = true; p._manager._dirty[4] = true; ushort* Indices = (ushort*)p._manager._indices.Address; Vector3* Vertices = (Vector3*)p._manager._faceData[0].Address; Vector3* Normals = (Vector3*)p._manager._faceData[1].Address; Vector2* UVs = (Vector2*)p._manager._faceData[4].Address; manager._triangles = new NewPrimitive((int)m._faceVertCount, BeginMode.Triangles); uint[] pTriarr = manager._triangles._indices; uint pTri = 0; index = 0; List<int> usedVertices = new List<int>(); List<int> vertexIndices = new List<int>(); for (int s = offset, l = 0; l < (int)m._faceVertCount; l++, s++) { ushort i = _faceIndices[s]; ModelVertex mv = _vertices[i]; ushort j = 0; if (!usedVertices.Contains(i)) { Influence inf; BoneWeight weight1 = null, weight2 = null; float weight = ((float)mv._boneWeight / 100.0f).Clamp(0.0f, 1.0f); if (weight > 0.0f && weight < 1.0f) { weight1 = new BoneWeight(BoneCache[mv._boneIndex[0]], weight); weight2 = new BoneWeight(BoneCache[mv._boneIndex[1]], 1.0f - weight); } else if (weight == 0.0f) weight1 = new BoneWeight(BoneCache[mv._boneIndex[1]]); else weight1 = new BoneWeight(BoneCache[mv._boneIndex[0]]); if (weight2 != null) inf = new Influence(new List<BoneWeight> { weight1, weight2 }); else inf = new Influence(new List<BoneWeight> { weight1 }); Vector3 t = new Vector3(); Vertex3 v; t._x = mv._position[0]; t._y = mv._position[1]; t._z = mv._position[2]; if (inf._weights.Count > 1) { inf = model._influences.FindOrCreate(inf, true); inf.CalcMatrix(); v = new Vertex3(t, inf); } else { MDL0BoneNode bone = inf._weights[0].Bone; v = new Vertex3(t * bone._inverseBindMatrix, bone); } p._manager._vertices.Add(v); vertexIndices.Add(usedVertices.Count); usedVertices.Add(i); j = (ushort)(usedVertices.Count - 1); } else j = (ushort)vertexIndices[usedVertices.IndexOf(i)]; *Indices++ = j; pTriarr[pTri++] = (uint)l; *Vertices++ = p._manager._vertices[j]._position; *Normals++ = mv._normal; *UVs++ = mv._texCoord; } model._objList.Add(p); offset += (int)m._faceVertCount; } //Check each polygon to see if it can be rigged to a single influence if (model._objList != null && model._objList.Count != 0) foreach (MDL0ObjectNode p in model._objList) { IMatrixNode node = null; bool singlebind = true; foreach (Vertex3 v in p._manager._vertices) if (v._matrixNode != null) { if (node == null) node = v._matrixNode; if (v._matrixNode != node) { singlebind = false; break; } } if (singlebind && p._matrixNode == null) { //Increase reference count ahead of time for rebuild if (p._manager._vertices[0]._matrixNode != null) p._manager._vertices[0]._matrixNode.ReferenceCount++; foreach (Vertex3 v in p._manager._vertices) if (v._matrixNode != null) v._matrixNode.ReferenceCount--; p._nodeId = -2; //Continued on polygon rebuild } } //foreach (MDL0ObjectNode p in model._objList) // foreach (MDL0MaterialNode m in model._matList) // { // MDL0MaterialNode m2 = p.OpaMaterialNode; // if (m2 == null || m2.ShaderNode != m.ShaderNode || m2.Children.Count != m.Children.Count) // continue; // for (int i = 0; i < m.Children.Count; i++) // if (m2.Children[i].Name != m.Children[i].Name) // continue; // p.OpaMaterialNode = m; // break; // } //for (int i = 0; i < model._matList.Count; i++) // if (((MDL0MaterialNode)model._matList[i])._objects.Count == 0) // model._matList.RemoveAt(i--); model.CleanGroups(); model.BuildFromScratch(null); }
public void LoadModel(MDL0Node model) { model.Populate(); model._renderAttribs._renderBones = false; model._renderAttribs._renderPolygons = true; model._renderAttribs._renderWireframe = false; model._renderAttribs._renderVertices = false; model.ApplyCHR(null, 0); model.ApplySRT(null, 0); if (UseExceptions) foreach (string texname in TexturesToDisable) { MDL0TextureNode tex = model.TextureGroup.FindChild(texname, false) as MDL0TextureNode; if (tex != null) { tex.Enabled = false; } } modelPanel1.ClearAll(); modelPanel1.AddTarget((IRenderedObject)model); if (UseExceptions && PolygonsToDisable.ContainsKey(_charString)) { foreach (int polygonNum in PolygonsToDisable[_charString]) { MDL0ObjectNode poly = model.PolygonGroup.FindChild("polygon" + polygonNum, false) as MDL0ObjectNode; if (poly != null) poly.IsRendering = false; } } Box box = model.GetBox(); Vector3 min = box.Min, max = box.Max; if (ZoomOut) { min._x += 20; max._x -= 20; } modelPanel1.SetCamWithBox(min, max); }
private static unsafe void WriteGeometry(MDL0Node model, XmlWriter writer) { ResourceNode grp = model._objGroup; if (grp == null) return; writer.WriteStartElement("library_geometries"); foreach (MDL0ObjectNode poly in grp.Children) { PrimitiveManager manager = poly._manager; //Geometry writer.WriteStartElement("geometry"); writer.WriteAttributeString("id", poly.Name); writer.WriteAttributeString("name", poly.Name); //Mesh writer.WriteStartElement("mesh"); //Write vertex data first WriteVertices(poly.Name, manager._vertices, poly.MatrixNode, writer); //Face assets for (int i = 0; i < 12; i++) { if (manager._faceData[i] == null) continue; switch (i) { case 0: break; case 1: WriteNormals(poly.Name, writer, manager); break; case 2: case 3: WriteColors(poly.Name, manager, i - 2, writer); break; default: WriteUVs(poly.Name, manager, i - 4, writer); break; } } //Vertices writer.WriteStartElement("vertices"); writer.WriteAttributeString("id", poly.Name + "_Vertices"); writer.WriteStartElement("input"); writer.WriteAttributeString("semantic", "POSITION"); writer.WriteAttributeString("source", "#" + poly.Name + "_Positions"); writer.WriteEndElement(); //input writer.WriteEndElement(); //vertices //Faces if (manager._triangles != null) WritePrimitive(poly, manager._triangles, writer); if (manager._lines != null) WritePrimitive(poly, manager._lines, writer); if (manager._points != null) WritePrimitive(poly, manager._points, writer); writer.WriteEndElement(); //mesh writer.WriteEndElement(); //geometry } writer.WriteEndElement(); }
private static unsafe void WriteControllers(MDL0Node model, XmlWriter writer) { if (model._objList == null) return; writer.WriteStartElement("library_controllers"); int g = 0; //List<MDL0BoneNode> boneSet = new List<MDL0BoneNode>(); MDL0BoneNode[] bones = new MDL0BoneNode[model._linker.BoneCache.Length]; model._linker.BoneCache.CopyTo(bones, 0); //foreach (MDL0BoneNode b in model._linker.BoneCache) //{ // b._nodeIndex = g++; // boneSet.Add(b); //} HashSet<float> temp = new HashSet<float>(); Matrix m; bool first; foreach (MDL0ObjectNode poly in model._objList) { List<Vertex3> verts = poly._manager._vertices; writer.WriteStartElement("controller"); writer.WriteAttributeString("id", poly.Name + "_Controller"); writer.WriteStartElement("skin"); writer.WriteAttributeString("source", "#" + poly.Name); writer.WriteStartElement("bind_shape_matrix"); //Set bind pose matrix //if (poly._singleBind != null) // m = poly._singleBind.Matrix; //else m = Matrix.Identity; writer.WriteString(WriteMatrix(m)); writer.WriteEndElement(); //Get list of used bones and weights //int index = 0; if (poly._matrixNode != null) { foreach (BoneWeight w in poly._matrixNode.Weights) { //if (!boneSet.Contains(w.Bone)) //{ // boneSet.Add(w.Bone); // w.Bone._nodeIndex = index++; //} //if (!weightSet.Contains(w.Weight)) temp.Add(w.Weight); } } else { foreach (Vertex3 v in verts) foreach (BoneWeight w in v._matrixNode.Weights) { //if (!boneSet.Contains(w.Bone)) //{ // boneSet.Add(w.Bone); // w.Bone._nodeIndex = index++; //} //if (!weightSet.Contains(w.Weight)) temp.Add(w.Weight); } } float[] weightSet = new float[temp.Count]; temp.CopyTo(weightSet); //Write joint source writer.WriteStartElement("source"); writer.WriteAttributeString("id", poly.Name + "_Joints"); //Node array writer.WriteStartElement("Name_array"); writer.WriteAttributeString("id", poly.Name + "_JointArr"); //writer.WriteAttributeString("count", boneSet.Count.ToString()); writer.WriteAttributeString("count", bones.Length.ToString()); first = true; //foreach (MDL0BoneNode b in boneSet) foreach (MDL0BoneNode b in bones) { if (first) first = false; else writer.WriteString(" "); writer.WriteString(b.Name); } writer.WriteEndElement(); //Name_array //Technique writer.WriteStartElement("technique_common"); writer.WriteStartElement("accessor"); writer.WriteAttributeString("source", String.Format("#{0}_JointArr", poly.Name)); //writer.WriteAttributeString("count", boneSet.Count.ToString()); writer.WriteAttributeString("count", bones.Length.ToString()); writer.WriteStartElement("param"); writer.WriteAttributeString("name", "JOINT"); writer.WriteAttributeString("type", "Name"); writer.WriteEndElement(); //param writer.WriteEndElement(); //accessor writer.WriteEndElement(); //technique writer.WriteEndElement(); //joint source //Inverse matrices source writer.WriteStartElement("source"); writer.WriteAttributeString("id", poly.Name + "_Matrices"); writer.WriteStartElement("float_array"); writer.WriteAttributeString("id", poly.Name + "_MatArr"); //writer.WriteAttributeString("count", (boneSet.Count * 16).ToString()); writer.WriteAttributeString("count", (bones.Length * 16).ToString()); first = true; foreach (MDL0BoneNode b in bones) { if (first) first = false; else writer.WriteString(" "); writer.WriteString(WriteMatrix(b.InverseBindMatrix)); } writer.WriteEndElement(); //float_array //Technique writer.WriteStartElement("technique_common"); writer.WriteStartElement("accessor"); writer.WriteAttributeString("source", String.Format("#{0}_MatArr", poly.Name)); //writer.WriteAttributeString("count", boneSet.Count.ToString()); writer.WriteAttributeString("count", bones.Length.ToString()); writer.WriteAttributeString("stride", "16"); writer.WriteStartElement("param"); writer.WriteAttributeString("type", "float4x4"); writer.WriteEndElement(); //param writer.WriteEndElement(); //accessor writer.WriteEndElement(); //technique writer.WriteEndElement(); //source //Weights source writer.WriteStartElement("source"); writer.WriteAttributeString("id", poly.Name + "_Weights"); writer.WriteStartElement("float_array"); writer.WriteAttributeString("id", poly.Name + "_WeightArr"); writer.WriteAttributeString("count", weightSet.Length.ToString()); first = true; foreach (float f in weightSet) { if (first) first = false; else writer.WriteString(" "); writer.WriteValue(f); } writer.WriteEndElement(); //Technique writer.WriteStartElement("technique_common"); writer.WriteStartElement("accessor"); writer.WriteAttributeString("source", String.Format("#{0}_WeightArr", poly.Name)); writer.WriteAttributeString("count", weightSet.Length.ToString()); writer.WriteStartElement("param"); writer.WriteAttributeString("type", "float"); writer.WriteEndElement(); //param writer.WriteEndElement(); //accessor writer.WriteEndElement(); //technique writer.WriteEndElement(); //source //Joint bindings writer.WriteStartElement("joints"); writer.WriteStartElement("input"); writer.WriteAttributeString("semantic", "JOINT"); writer.WriteAttributeString("source", String.Format("#{0}_Joints", poly.Name)); writer.WriteEndElement(); //input writer.WriteStartElement("input"); writer.WriteAttributeString("semantic", "INV_BIND_MATRIX"); writer.WriteAttributeString("source", String.Format("#{0}_Matrices", poly.Name)); writer.WriteEndElement(); //input writer.WriteEndElement(); //joints //Vertex weights, one for each vertex in geometry writer.WriteStartElement("vertex_weights"); writer.WriteAttributeString("count", verts.Count.ToString()); writer.WriteStartElement("input"); writer.WriteAttributeString("semantic", "JOINT"); writer.WriteAttributeString("offset", "0"); writer.WriteAttributeString("source", String.Format("#{0}_Joints", poly.Name)); writer.WriteEndElement(); //input writer.WriteStartElement("input"); writer.WriteAttributeString("semantic", "WEIGHT"); writer.WriteAttributeString("offset", "1"); writer.WriteAttributeString("source", String.Format("#{0}_Weights", poly.Name)); writer.WriteEndElement(); //input writer.WriteStartElement("vcount"); first = true; if (poly._matrixNode != null) for (int i = 0; i < verts.Count; i++) { if (first) first = false; else writer.WriteString(" "); writer.WriteString(poly._matrixNode.Weights.Count.ToString(CultureInfo.InvariantCulture.NumberFormat)); } else foreach (Vertex3 v in verts) { if (first) first = false; else writer.WriteString(" "); writer.WriteString(v._matrixNode.Weights.Count.ToString(CultureInfo.InvariantCulture.NumberFormat)); } writer.WriteEndElement(); //vcount writer.WriteStartElement("v"); first = true; if (poly._matrixNode != null) for (int i = 0; i < verts.Count; i++) foreach (BoneWeight w in poly._matrixNode.Weights) { if (first) first = false; else writer.WriteString(" "); //writer.WriteString(w.Bone._nodeIndex.ToString()); writer.WriteString(Array.IndexOf(bones, w.Bone).ToString(CultureInfo.InvariantCulture.NumberFormat)); writer.WriteString(" "); writer.WriteString(Array.IndexOf(weightSet, w.Weight).ToString(CultureInfo.InvariantCulture.NumberFormat)); } else foreach (Vertex3 v in verts) foreach (BoneWeight w in v._matrixNode.Weights) { if (first) first = false; else writer.WriteString(" "); //writer.WriteString(w.Bone._nodeIndex.ToString()); writer.WriteString(Array.IndexOf(bones, w.Bone).ToString(CultureInfo.InvariantCulture.NumberFormat)); writer.WriteString(" "); writer.WriteString(Array.IndexOf(weightSet, w.Weight).ToString(CultureInfo.InvariantCulture.NumberFormat)); } writer.WriteEndElement(); //v writer.WriteEndElement(); //vertex_weights writer.WriteEndElement(); //skin writer.WriteEndElement(); //controller //boneSet.Clear(); //weightSet.Clear(); } writer.WriteEndElement(); }
private static unsafe void WriteNodes(MDL0Node model, XmlWriter writer) { if (model._boneList != null) foreach (MDL0BoneNode bone in model._boneList) WriteBone(bone, writer); if (model._objList != null) foreach (MDL0ObjectNode poly in model._objList) //if (poly._singleBind == null) //Single bind objects will be written under their bone WritePolyInstance(poly, writer); }
private static void WriteImages(MDL0Node model, XmlWriter writer) { if (model._texList == null) return; writer.WriteStartElement("library_images"); { foreach (MDL0TextureNode tex in model._texList) { writer.WriteStartElement("image"); { writer.WriteAttributeString("id", tex.Name + "-image"); writer.WriteAttributeString("name", tex.Name); writer.WriteStartElement("init_from"); { writer.WriteStartElement("ref"); { writer.WriteString(String.Format("{0}.png", tex.Name)); } writer.WriteEndElement(); //ref } writer.WriteEndElement(); //init_from } writer.WriteEndElement(); //image } } writer.WriteEndElement(); //library_images }
private void CreateObject(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); int i = 0; foreach (Vertex3 v in manager._vertices) v._index = i++; MDL0ObjectNode poly = new MDL0ObjectNode() { _manager = manager }; poly._manager._polygon = poly; poly._name = node._name != null ? node._name : node._id; //Attach single-bind if (parent != null && parent is MDL0BoneNode) poly.MatrixNode = (MDL0BoneNode)parent; //Attach material if (inst._material != null) foreach (MaterialEntry mat in shell._materials) if (mat._id == inst._material._target) { (poly._opaMaterial = (mat._node as MDL0MaterialNode))._objects.Add(poly); break; } model._numFaces += poly._numFaces = manager._faceCount = manager._pointCount / 3; model._numFacepoints += poly._numFacepoints = manager._pointCount; poly._parent = model._objGroup; model._objList.Add(poly); } }
private void UpdateModel(MDL0Node model) { if (_chr0 != null && playCHR0ToolStripMenuItem.Checked) model.ApplyCHR(_chr0, _animFrame); else model.ApplyCHR(null, 0); if (_srt0 != null && playSRT0ToolStripMenuItem.Checked) model.ApplySRT(_srt0, _animFrame); else model.ApplySRT(null, 0); if (_shp0 != null && playSHP0ToolStripMenuItem.Checked) model.ApplySHP(_shp0, _animFrame); else model.ApplySHP(null, 0); if (_pat0 != null && playPAT0ToolStripMenuItem.Checked) model.ApplyPAT(_pat0, _animFrame); else model.ApplyPAT(null, 0); if (_vis0 != null && playVIS0ToolStripMenuItem.Checked) if (model == TargetModel) ReadVIS0(); else model.ApplyVIS(_vis0, _animFrame); if (_scn0 != null)// && playSCN0ToolStripMenuItem.Checked) model.SetSCN0Frame(_animFrame); else model.SetSCN0Frame(0); if (_clr0 != null && playCLR0ToolStripMenuItem.Checked) model.ApplyCLR(_clr0, _animFrame); else model.ApplyCLR(null, 0); }
public void Show(MDL0Node model) { Show(null, model); }
internal void Parse(MDL0Node model) { Influence inf; ModelLinker linker = model._linker; switch (_type) { case MDLResourceType.Definitions: if (linker.Defs != null) { ExtractGroup(linker.Defs, typeof(MDL0DefNode)); } break; case MDLResourceType.Bones: //Break if there are no bones defined if (linker.Bones == null) { break; } //Parse bones from raw data (flat list). //Bones re-assign parents in their Initialize block, so parents are true. //Parents must be assigned now as bones will be moved in memory when assigned as children. ExtractGroup(linker.Bones, typeof(MDL0BoneNode)); //Cache flat list linker.BoneCache = _children.ToArray(); //Make sure the node cache is the correct size int highest = 0; foreach (MDL0BoneNode b in linker.BoneCache) { if (b._nodeIndex >= linker.NodeCache.Length && b._nodeIndex > highest) { highest = b._nodeIndex; } } if (highest >= linker.NodeCache.Length) { linker.NodeCache = new IMatrixNode[highest + 1]; } //Reset children so we can rebuild _children.Clear(); //Assign children using each bones' parent offset in case NodeTree is corrupted foreach (MDL0BoneNode b in linker.BoneCache) { b._parent._children.Add(b); } //Populate node cache MDL0BoneNode bone = null; int index; int count = linker.BoneCache.Length; for (int i = 0; i < count; i++) { linker.NodeCache[(bone = linker.BoneCache[i] as MDL0BoneNode)._nodeIndex] = bone; } int nullCount = 0; bool nodeTreeError = false; //Now that bones and primary influences have been cached, we can create weighted influences. foreach (ResourcePair p in *linker.Defs) { if (p.Name == "NodeTree") { //Double check bone tree using the NodeTree definition. //If the NodeTree is corrupt, the user will be informed that it needs to be rebuilt. byte *pData = (byte *)p.Data; Top: if (*pData == 2) { bone = linker.BoneCache[*(bushort *)(pData + 1)] as MDL0BoneNode; index = *(bushort *)(pData + 3); if (bone.Header->_parentOffset == 0) { if (!_children.Contains(bone)) { nodeTreeError = true; continue; } } else { ResourceNode n = linker.NodeCache[index] as ResourceNode; if (n == null || bone._parent != n || !n._children.Contains(bone)) { nodeTreeError = true; continue; } } pData += 5; goto Top; } } else if (p.Name == "NodeMix") { //Use node mix to create weight groups byte *pData = (byte *)p.Data; Top: switch (*pData) { //Type 3 is for weighted influences case 3: //Get index/count fields index = *(bushort *)(pData + 1); count = pData[3]; //Get data pointer (offset of 4) MDL0NodeType3Entry *nEntry = (MDL0NodeType3Entry *)(pData + 4); //Create influence with specified count inf = new Influence(); //Iterate through weights, adding each to the influence //Here, we are referring back to the NodeCache to grab the bone. //Note that the weights do not reference other influences, only bones. There is a good reason for this. MDL0BoneNode b = null; List <int> nullIndices = new List <int>(); for (int i = 0; i < count; i++, nEntry++) { if (nEntry->_id < linker.NodeCache.Length && (b = (linker.NodeCache[nEntry->_id] as MDL0BoneNode)) != null) { inf._weights.Add(new BoneWeight(b, nEntry->_value)); } else { nullIndices.Add(i); nullCount++; } } bool d = false; if (nullIndices.Count > 0) { List <BoneWeight> newWeights = new List <BoneWeight>(); for (int i = 0; i < inf._weights.Count; i++) { if (!nullIndices.Contains(i)) { newWeights.Add(inf._weights[i]); } } if (newWeights.Count == 0) { d = true; } else { inf._weights = newWeights; } } //Add influence to model object, while adding it to the cache. if (!d) { ((Influence)(linker.NodeCache[index] = model._influences.FindOrCreate(inf, true)))._index = index; } //Move data pointer to next entry pData = (byte *)nEntry; goto Top; //Type 5 is for primary influences case 5: pData += 5; goto Top; } } } if (nullCount > 0) { model._errors.Add("There were " + nullCount + " null weights in NodeMix."); SignalPropertyChange(); } if (nodeTreeError) { model._errors.Add("The NodeTree definition did not match the bone tree."); SignalPropertyChange(); } break; case MDLResourceType.Materials: if (linker.Materials != null) { ExtractGroup(linker.Materials, typeof(MDL0MaterialNode)); } break; case MDLResourceType.Shaders: if (linker.Shaders != null) { ExtractGroup(linker.Shaders, typeof(MDL0ShaderNode)); } break; case MDLResourceType.Vertices: if (linker.Vertices != null) { ExtractGroup(linker.Vertices, typeof(MDL0VertexNode)); } break; case MDLResourceType.Normals: if (linker.Normals != null) { ExtractGroup(linker.Normals, typeof(MDL0NormalNode)); } break; case MDLResourceType.UVs: if (linker.UVs != null) { ExtractGroup(linker.UVs, typeof(MDL0UVNode)); } break; case MDLResourceType.FurLayerCoords: if (linker.FurLayerCoords != null) { ExtractGroup(linker.FurLayerCoords, typeof(MDL0FurPosNode)); } break; case MDLResourceType.FurVectors: if (linker.FurVectors != null) { ExtractGroup(linker.FurVectors, typeof(MDL0FurVecNode)); } break; case MDLResourceType.Objects: //Break if no polygons defined if (linker.Polygons == null) { break; } //Extract ExtractGroup(linker.Polygons, typeof(MDL0ObjectNode)); //Attach materials to polygons. //This assumes that materials have already been parsed. List <ResourceNode> matList = ((MDL0Node)_parent)._matList; MDL0ObjectNode poly; MDL0MaterialNode mat; //Find DrawOpa or DrawXlu entry in Definition list foreach (ResourcePair p in *linker.Defs) { if ((p.Name == "DrawOpa") || (p.Name == "DrawXlu")) { bool opa = p.Name == "DrawOpa"; ushort dIndex = 0; byte * pData = (byte *)p.Data; while (*pData++ == 4) { //Get polygon from index dIndex = *(bushort *)(pData + 2); if (dIndex >= _children.Count || dIndex < 0) { model._errors.Add("Object index was greater than the actual object count."); SignalPropertyChange(); dIndex = 0; } poly = _children[dIndex] as MDL0ObjectNode; poly._drawIndex = pData[6]; //Get material from index mat = matList[*(bushort *)pData] as MDL0MaterialNode; //Get bone from index and assign int boneIndex = *(bushort *)(pData + 4); if (linker.BoneCache != null && boneIndex >= 0 && boneIndex < linker.BoneCache.Length) { poly.BoneNode = linker.BoneCache[boneIndex] as MDL0BoneNode; } //Assign material to polygon if (opa) { poly.OpaMaterialNode = mat; } else { poly.XluMaterialNode = mat; } //Increment pointer pData += 7; } } } foreach (MDL0ObjectNode m in _children) { int max = Maths.Max( m.OpaMaterialNode != null ? m.OpaMaterialNode.Children.Count : 0, m.XluMaterialNode != null ? m.XluMaterialNode.Children.Count : 0, m.OpaMaterialNode != null && m.OpaMaterialNode.MetalMaterial != null ? m.OpaMaterialNode.MetalMaterial.Children.Count : 0, m.XluMaterialNode != null && m.XluMaterialNode.MetalMaterial != null ? m.XluMaterialNode.MetalMaterial.Children.Count : 0); bool hasUnused = false; for (int i = max; i < 8; i++) { if (m.HasTextureMatrix[i]) { m.HasTextureMatrix[i] = false; m._rebuild = true; hasUnused = true; } } if (hasUnused) { ((MDL0Node)Parent)._errors.Add("Object " + m.Index + " has unused texture matrices."); m.SignalPropertyChange(); } if (m.HasTexMtx && m.HasNonFloatVertices) { ((MDL0Node)Parent)._errors.Add("Object " + m.Index + " has texture matrices and non-float vertices, meaning it will explode in-game."); m.SignalPropertyChange(); } } break; case MDLResourceType.Colors: if (linker.Colors != null) { ExtractGroup(linker.Colors, typeof(MDL0ColorNode)); } break; case MDLResourceType.Textures: if (linker.Textures != null) { ExtractGroup(linker.Textures, typeof(MDL0TextureNode)); } break; case MDLResourceType.Palettes: if (linker.Palettes != null) { ExtractGroup(linker.Palettes, typeof(MDL0TextureNode)); } break; } }
public void Show(IWin32Window owner, MDL0Node model) { _models.Add(model); base.Show(owner); }
private void EnumNode(NodeEntry node, ResourceNode parent, SceneEntry scene, MDL0Node model, DecoderShell shell) { MDL0BoneNode bone = null; Influence inf = null; if (node._type == NodeType.JOINT) { Error = "There was a problem creating a new bone."; bone = new MDL0BoneNode(); bone._name = node._name != null ? node._name : node._id; bone._bindState = node._transform; node._node = bone; parent._children.Add(bone); bone._parent = parent; bone.RecalcBindState(); bone.CalcFlags(); foreach (NodeEntry e in node._children) EnumNode(e, bone, scene, model, shell); inf = new Influence(bone); model._influences._influences.Add(inf); } else foreach (NodeEntry e in node._children) EnumNode(e, parent, scene, model, shell); foreach (InstanceEntry inst in node._instances) { if (inst._type == InstanceType.Controller) { foreach (SkinEntry skin in shell._skins) if (skin._id == inst._url) { foreach (GeometryEntry g in shell._geometry) if (g._id == skin._skinSource) { Error = @" There was a problem decoding weighted primitives for the object " + (node._name != null ? node._name : node._id) + ".\nOne or more vertices may not be weighted correctly."; Say("Decoding weighted primitives for " + (g._name != null ? g._name : g._id) + "..."); CreateObject(inst, node, parent, DecodePrimitivesWeighted(node, g, skin, scene, model._influences, ref Error), model, shell); break; } break; } } else if (inst._type == InstanceType.Geometry) { foreach (GeometryEntry g in shell._geometry) if (g._id == inst._url) { Error = "There was a problem decoding unweighted primitives for the object " + (node._name != null ? node._name : node._id) + "."; Say("Decoding unweighted primitives for " + (g._name != null ? g._name : g._id) + "..."); CreateObject(inst, node, parent, DecodePrimitivesUnweighted(node, g), model, shell); break; } } else { foreach (NodeEntry e in shell._nodes) if (e._id == inst._url) EnumNode(e, parent, scene, model, shell); } } }
public static MDL0Node ImportModel(string filepath) { filepath = Path.GetFullPath(filepath); if (!File.Exists(filepath)) throw new FileNotFoundException("PMD model file " + filepath + " not found."); MDL0Node model = null; using (FileStream fs = new FileStream(filepath, FileMode.Open)) { BinaryReader reader = new BinaryReader(fs); string magic = encoder.GetString(reader.ReadBytes(3)); if (magic != "Pmd") throw new FileLoadException("Model format not recognized."); float version = BitConverter.ToSingle(reader.ReadBytes(4), 0); if (version == 1.0f) model = new MDL0Node(); else throw new Exception("Version " + version.ToString() + " models are not supported."); if (model != null) { Read(reader, CoordinateType.LeftHanded); //Will flip model backwards if right handed PMD2MDL0(model); } fs.Close(); } return model; }
internal void Parse(MDL0Node model) { Influence inf; ModelLinker linker = model._linker; switch (_type) { case MDLResourceType.Bones: //Break if there are no bones defined if (linker.Bones == null) { break; } //Parse bones from raw data (flat list). //Bones re-assign parents in their Initialize block, so parents are true. ExtractGroup(linker.Bones, typeof(MDL0BoneNode)); //Cache flat list linker.BoneCache = _children.ToArray(); //Reset children so we can rebuild _children.Clear(); //Populate node cache MDL0BoneNode bone = null; int index; int count = linker.BoneCache.Length; for (int i = 0; i < count; i++) { //bone = linker.BoneCache[i] as MDL0BoneNode; linker.NodeCache[(bone = linker.BoneCache[i] as MDL0BoneNode)._nodeIndex] = bone; } //Now that bones and primary influences have been cached, we can create weighted influences. foreach (ResourcePair p in *linker.Defs) { if (p.Name == "NodeTree") { //Use node tree to rebuild bone heirarchy byte *pData = (byte *)p.Data; Top: if (*pData == 2) { bone = linker.BoneCache[*(bushort *)(pData + 1)] as MDL0BoneNode; index = *(bushort *)(pData + 3); if (bone.Header->_parentOffset == 0) { _children.Add(bone); } else { (bone._parent = linker.NodeCache[index] as ResourceNode)._children.Add(bone); } pData += 5; goto Top; } } else if (p.Name == "NodeMix") { //Use node mix to create weight groups byte *pData = (byte *)p.Data; Top: switch (*pData) { //Type 3 is for weighted influences case 3: //Get index/count fields index = *(bushort *)(pData + 1); count = pData[3]; //Get data pointer (offset of 4) MDL0NodeType3Entry *nEntry = (MDL0NodeType3Entry *)(pData + 4); //Create influence with specified count inf = new Influence(count); //Iterate through weights, adding each to the influence //Here, we are referring back to the NodeCache to grab the bone. //Note that the weights do not reference other influences, only bones. There is a good reason for this. for (int i = 0; i < count; i++, nEntry++) { inf._weights[i] = new BoneWeight(linker.NodeCache[nEntry->_id] as MDL0BoneNode, nEntry->_value); } //Add influence to model object, while adding it to the cache. linker.NodeCache[index] = model._influences.AddOrCreate(inf); //Move data pointer to next entry pData = (byte *)nEntry; goto Top; //Type 5 is for primary influences case 5: pData += 5; goto Top; } } } break; case MDLResourceType.Materials: if (linker.Materials != null) { ExtractGroup(linker.Materials, typeof(MDL0MaterialNode)); } break; case MDLResourceType.Shaders: if (linker.Shaders != null) { ExtractGroup(linker.Shaders, typeof(MDL0ShaderNode)); } break; case MDLResourceType.Polygons: //Break if no polygons defined if (linker.Polygons == null) { break; } //Extract ExtractGroup(linker.Polygons, typeof(MDL0PolygonNode)); //Attach materials to polygons. //This assumes that materials have already been parsed. List <ResourceNode> matList = ((MDL0Node)_parent)._matList; MDL0PolygonNode poly; MDL0MaterialNode mat; //Find DrawOpa or DrawXlu entry in Definition list foreach (ResourcePair p in *linker.Defs) { if ((p.Name == "DrawOpa") || (p.Name == "DrawXlu")) { byte *pData = (byte *)p.Data; while (*pData++ == 4) { //Get polygon from index poly = _children[*(bushort *)(pData + 2)] as MDL0PolygonNode; //Get material from index mat = matList[*(bushort *)pData] as MDL0MaterialNode; //Assign material to polygon poly._material = mat; //Add polygon to material reference list mat._polygons.Add(poly); //Increment pointer pData += 7; } } } break; } }
public void Port(MDL0Node _targetModel, MDL0Node _extModel) { MDL0BoneNode extBone; MDL0BoneNode bone; KeyframeEntry kfe; float difference = 0; foreach (CHR0EntryNode _target in Children) { extBone = (MDL0BoneNode)_extModel.FindChild(_target.Name, true); //Get external model bone bone = (MDL0BoneNode)_targetModel.FindChild(_target.Name, true); //Get target model bone for (int x = 0; x < _target.FrameCount; x++) for (int i = 0x13; i < 0x19; i++) if ((kfe = _target.GetKeyframe((KeyFrameMode)i, x)) != null) //Check for a keyframe { if (bone != null && extBone != null) switch (i) { //Translations case 0x16: //Trans X if (Math.Round(kfe._value, 4) == Math.Round(extBone._bindState.Translate._x, 4)) kfe._value = bone._bindState.Translate._x; else if (bone._bindState.Translate._x < extBone._bindState.Translate._x) kfe._value -= extBone._bindState.Translate._x - bone._bindState.Translate._x; else if (bone._bindState.Translate._x > extBone._bindState.Translate._x) kfe._value += bone._bindState.Translate._x - extBone._bindState.Translate._x; break; case 0x17: //Trans Y if (Math.Round(kfe._value, 4) == Math.Round(extBone._bindState.Translate._y, 4)) kfe._value = bone._bindState.Translate._y; else if (bone._bindState.Translate._y < extBone._bindState.Translate._y) kfe._value -= extBone._bindState.Translate._y - bone._bindState.Translate._y; else if (bone._bindState.Translate._y > extBone._bindState.Translate._y) kfe._value += bone._bindState.Translate._y - extBone._bindState.Translate._y; break; case 0x18: //Trans Z if (Math.Round(kfe._value, 4) == Math.Round(extBone._bindState.Translate._z, 4)) kfe._value = bone._bindState.Translate._z; else if (bone._bindState.Translate._z < extBone._bindState.Translate._z) kfe._value -= extBone._bindState.Translate._z - bone._bindState.Translate._z; else if (bone._bindState.Translate._z > extBone._bindState.Translate._z) kfe._value += bone._bindState.Translate._z - extBone._bindState.Translate._z; break; //Rotations //case 0x13: //Rot X // difference = bone._bindState.Rotate._x - extBone._bindState.Rotate._x; // kfe._value += difference; // //if (difference != 0) // // FixChildren(bone, 0); // break; //case 0x14: //Rot Y // difference = bone._bindState.Rotate._y - extBone._bindState.Rotate._y; // kfe._value += difference; // //if (difference != 0) // // FixChildren(bone, 1); // break; //case 0x15: //Rot Z // difference = bone._bindState.Rotate._z - extBone._bindState.Rotate._z; // kfe._value += difference; // //if (difference != 0) // // FixChildren(bone, 2); // break; } if (kfe._value == float.NaN || kfe._value == float.PositiveInfinity || kfe._value == float.NegativeInfinity) { kfe.Remove(); _target.Keyframes._keyCounts[i]--; } } } _changed = true; }
public DialogResult ShowDialog(IWin32Window owner, MDL0Node model) { _models.Add(model); try { return base.ShowDialog(owner); } finally { _models = null; } }
internal void Parse(MDL0Node model) { Influence inf; ModelLinker linker = model._linker; int typeIndex = (int)_type; fixed(ResourceGroup **gList = &linker.Defs) if (gList[typeIndex] != null) ExtractGroup(gList[typeIndex], ModelLinker.TypeBank[typeIndex]); else return; //Nothing to read //Special handling for bones and objects if (_type == MDLResourceType.Bones) { //Bones have been parsed from raw data as a flat list. //Bones re-assign parents in their Initialize block, so parents are true. //Parents must be assigned now as bones will be moved in memory when assigned as children. //Cache flat list linker.BoneCache = _children.Select(x => x as MDL0BoneNode).ToArray(); //Reset children so we can rebuild _children.Clear(); //Assign children using each bones' parent offset in case NodeTree is corrupted. //Bone parents are assigned when they are initialized in a flat array. foreach (MDL0BoneNode b in linker.BoneCache) { MDL0Bone *header = b.Header; //Assign true parent using parent header offset int offset = header->_parentOffset; if (offset != 0) { //Get address of parent header MDL0Bone *pHeader = (MDL0Bone *)((byte *)header + offset); //Search bone list for matching header foreach (MDL0BoneNode b2 in linker.BoneCache) { if (pHeader == b2.Header) { b._parent = b2; break; } } } if (b._boneFlags.HasFlag(BoneFlags.HasBillboardParent)) { b._bbRefNode = model._linker.BoneCache[header->_bbIndex] as MDL0BoneNode; } } //Make sure the node cache is the correct size int highest = 0; //Add bones to their parent's child lists and find highest node id foreach (MDL0BoneNode b in linker.BoneCache) { b._parent._children.Add(b); if (b._nodeIndex >= linker.NodeCache.Length && b._nodeIndex > highest) { highest = b._nodeIndex; } } if (highest >= linker.NodeCache.Length) { linker.NodeCache = new IMatrixNode[highest + 1]; } //Populate node cache MDL0BoneNode bone = null; int index; int count = linker.BoneCache.Length; for (int i = 0; i < count; i++) { linker.NodeCache[(bone = linker.BoneCache[i] as MDL0BoneNode)._nodeIndex] = bone; } int nullCount = 0; bool nodeTreeError = false; //Now that bones and primary influences have been cached, we can create weighted influences. foreach (ResourcePair p in *linker.Defs) { if (p.Name == "NodeTree") { //Double check bone tree using the NodeTree definition. //If the NodeTree is corrupt, the user will be informed that it needs to be rebuilt. byte *pData = (byte *)p.Data; bool fixCS0159 = false; List <MDL0BoneNode> bones = linker.BoneCache.ToList(); STop: if (*pData == 2) { bone = linker.BoneCache[*(bushort *)(pData + 1)] as MDL0BoneNode; index = *(bushort *)(pData + 3); //Parent bone node index if (bone.Header->_parentOffset == 0) { if (!_children.Contains(bone)) { nodeTreeError = true; continue; } else { bones.Remove(bone); } } else { MDL0BoneNode parent = linker.NodeCache[index] as MDL0BoneNode; if (parent == null || bone._parent != parent || !parent._children.Contains(bone)) { nodeTreeError = true; continue; } else { bones.Remove(bone); } } pData += 5; fixCS0159 = true; } if (fixCS0159) { fixCS0159 = false; goto STop; } if (bones.Count > 0) { nodeTreeError = true; } } else if (p.Name == "NodeMix") { //Use node mix to create weight groups byte *pData = (byte *)p.Data; bool fixCS0159 = false; TTop: switch (*pData) { //Type 3 is for weighted influences case 3: //Get index/count fields index = *(bushort *)(pData + 1); count = pData[3]; //Get data pointer (offset of 4) MDL0NodeType3Entry *nEntry = (MDL0NodeType3Entry *)(pData + 4); //Create influence with specified count inf = new Influence(); //Iterate through weights, adding each to the influence //Here, we are referring back to the NodeCache to grab the bone. //Note that the weights do not reference other influences, only bones. There is a good reason for this. MDL0BoneNode b = null; List <int> nullIndices = new List <int>(); for (int i = 0; i < count; i++, nEntry++) { if (nEntry->_id < linker.NodeCache.Length && (b = (linker.NodeCache[nEntry->_id] as MDL0BoneNode)) != null) { inf.AddWeight(new BoneWeight(b, nEntry->_value)); } else { nullIndices.Add(i); } } bool noWeights = false; if ((nullCount = nullIndices.Count) > 0) { List <BoneWeight> newWeights = new List <BoneWeight>(); for (int i = 0; i < inf.Weights.Count; i++) { if (!nullIndices.Contains(i)) { newWeights.Add(inf.Weights[i]); } } if (newWeights.Count == 0) { noWeights = true; } else { inf.SetWeights(newWeights); } } //Add influence to model object, while adding it to the cache. //Don't add user references here, they will be added during each object's initialization if (!noWeights) { ((Influence)(linker.NodeCache[index] = model._influences.FindOrCreate(inf)))._index = index; } //Move data pointer to next entry pData = (byte *)nEntry; fixCS0159 = true; break; //Type 5 is for primary influences case 5: pData += 5; fixCS0159 = true; break; } if (fixCS0159) { fixCS0159 = false; goto TTop; } } } if (nullCount > 0) { model._errors.Add("There were " + nullCount + " null weights in NodeMix."); } if (nodeTreeError) { model._errors.Add("The NodeTree definition did not match the bone tree."); } } else if (_type == MDLResourceType.Objects) { //Attach materials to polygons. //This assumes that materials have already been parsed. List <ResourceNode> matList = ((MDL0Node)_parent)._matList; MDL0ObjectNode obj; MDL0MaterialNode mat; //Find DrawOpa or DrawXlu entry in Definition list foreach (ResourcePair p in *linker.Defs) { if ((p.Name == "DrawOpa") || (p.Name == "DrawXlu")) { bool isXLU = p.Name == "DrawXlu"; ushort objectIndex = 0; byte * pData = (byte *)p.Data; while (*pData++ == 4) { //Get object with index objectIndex = *(bushort *)(pData + 2); if (objectIndex >= _children.Count || objectIndex < 0) { model._errors.Add("Object index was greater than the actual object count."); objectIndex = 0; } obj = _children[objectIndex] as MDL0ObjectNode; //Get material with index mat = matList[*(bushort *)pData] as MDL0MaterialNode; //Get bone with index int boneIndex = *(bushort *)(pData + 4); MDL0BoneNode visBone = null; if (linker.BoneCache != null && boneIndex >= 0 && boneIndex < linker.BoneCache.Length) { visBone = linker.BoneCache[boneIndex] as MDL0BoneNode; } obj._drawCalls.Add(new DrawCall(obj) { _drawOrder = pData[6], _isXLU = isXLU, MaterialNode = mat, VisibilityBoneNode = visBone, }); //Increment pointer pData += 7; } } } foreach (MDL0ObjectNode m in _children) { int max = 0; foreach (DrawCall c in m._drawCalls) { max = Maths.Max(max, c.MaterialNode.Children.Count); if (c.MaterialNode.MetalMaterial != null) { max = Maths.Max(max, c.MaterialNode.MetalMaterial.Children.Count); } } bool hasUnused = false; if (m._manager != null) { for (int i = max; i < 8; i++) { if (m._manager.HasTextureMatrix[i]) { m._manager.HasTextureMatrix[i] = false; m._forceRebuild = true; hasUnused = true; } } } if (hasUnused) { ((MDL0Node)Parent)._errors.Add("Object " + m.Index + " has unused texture matrices."); } //This error doesn't seem to always be true for factory models... //if (m.HasTexMtx && m.HasNonFloatVertices) //{ // ((MDL0Node)Parent)._errors.Add("Object " + m.Index + " has texture matrices and non-float vertices, meaning it will explode in-game."); // m.SignalPropertyChange(); //} } } }
public void RemoveTarget(MDL0Node model) { if (_targetModels.Contains(model)) _targetModels.Remove(model); modelPanel.RemoveTarget(model); }
private static unsafe void WriteMaterials(MDL0Node model, XmlWriter writer) { ResourceNode node = model._matGroup; if (node == null) return; writer.WriteStartElement("library_materials"); { foreach (MDL0MaterialNode mat in node.Children) { if (mat._objects.Count == 0) continue; writer.WriteStartElement("material"); { writer.WriteAttributeString("id", mat._name); writer.WriteStartElement("instance_effect"); writer.WriteAttributeString("url", String.Format("#{0}-fx", mat._name)); writer.WriteEndElement(); } writer.WriteEndElement(); } } writer.WriteEndElement(); }
public ArticleInfo(ArticleEntry article, MDL0Node model, bool running) { _article = article; _model = model; _running = running; _chr0List = new List<CHR0Node>(); _srt0List = new List<SRT0Node>(); _shp0List = new List<SHP0Node>(); _vis0List = new List<VIS0Node>(); _pat0List = new List<PAT0Node>(); _clr0List = new List<CLR0Node>(); _article._info = this; }
public static void Serialize(MDL0Node model, string outFile) { model.Populate(); model.ApplyCHR(null, 0); using (FileStream stream = new FileStream(outFile, FileMode.Create, FileAccess.ReadWrite, FileShare.None, 0x1000, FileOptions.SequentialScan)) using (XmlWriter writer = XmlWriter.Create(stream, _writerSettings)) { writer.Flush(); stream.Position = 0; writer.WriteStartDocument(); writer.WriteStartElement("COLLADA", "http://www.collada.org/2008/03/COLLADASchema"); writer.WriteAttributeString("version", "1.5.0"); writer.WriteStartElement("asset"); { writer.WriteStartElement("contributor"); writer.WriteElementString("authoring_tool", Application.ProductName); writer.WriteEndElement(); writer.WriteStartElement("created"); writer.WriteString(DateTime.UtcNow.ToString("s", System.Globalization.CultureInfo.InvariantCulture) + "Z"); writer.WriteEndElement(); writer.WriteStartElement("modified"); writer.WriteString(DateTime.UtcNow.ToString("s", System.Globalization.CultureInfo.InvariantCulture) + "Z"); writer.WriteEndElement(); writer.WriteStartElement("unit"); writer.WriteAttributeString("meter", "0.01"); writer.WriteAttributeString("name", "centimeter"); writer.WriteEndElement(); writer.WriteElementString("up_axis", "Y_UP"); } writer.WriteEndElement(); //Define images WriteImages(model, writer); //Define materials WriteMaterials(model, writer); //Define effects WriteEffects(model, writer); //Define geometry //Create a geometry object for each polygon WriteGeometry(model, writer); //Define controllers //Each weighted polygon needs a controller, which assigns weights to each vertex. WriteControllers(model, writer); //Define scenes writer.WriteStartElement("library_visual_scenes"); { writer.WriteStartElement("visual_scene"); { //Attach nodes/bones to scene, starting with TopN //Specify transform for each node //Weighted polygons must use instance_controller //Standard geometry uses instance_geometry writer.WriteAttributeString("id", "RootNode"); writer.WriteAttributeString("name", "RootNode"); //Define bones and geometry instances WriteNodes(model, writer); } writer.WriteEndElement(); } writer.WriteEndElement(); writer.WriteStartElement("scene"); { writer.WriteStartElement("instance_visual_scene"); writer.WriteAttributeString("url", "#RootNode"); writer.WriteEndElement(); //instance visual scene } writer.WriteEndElement(); //scene writer.Close(); } }
private void UpdateModel(MDL0Node model) { int frame = CurrentFrame; if (_chr0 != null && !(TargetAnimType != AnimType.CHR && !playCHR0ToolStripMenuItem.Checked)) model.ApplyCHR(_chr0, frame); else model.ApplyCHR(null, 0); if (_srt0 != null && !(TargetAnimType != AnimType.SRT && !playSRT0ToolStripMenuItem.Checked)) model.ApplySRT(_srt0, frame); else model.ApplySRT(null, 0); if (_shp0 != null && !(TargetAnimType != AnimType.SHP && !playSHP0ToolStripMenuItem.Checked)) model.ApplySHP(_shp0, frame); else model.ApplySHP(null, 0); if (_pat0 != null && !(TargetAnimType != AnimType.PAT && !playPAT0ToolStripMenuItem.Checked)) model.ApplyPAT(_pat0, frame); else model.ApplyPAT(null, 0); if (_vis0 != null && !(TargetAnimType != AnimType.VIS && !playVIS0ToolStripMenuItem.Checked)) if (model == TargetModel) ReadVIS0(); else model.ApplyVIS(_vis0, frame); if (_clr0 != null && !(TargetAnimType != AnimType.CLR && !playCLR0ToolStripMenuItem.Checked)) model.ApplyCLR(_clr0, frame); else model.ApplyCLR(null, 0); }
private static unsafe void WriteEffects(MDL0Node model, XmlWriter writer) { ResourceNode node = model._matGroup; if (node == null) return; writer.WriteStartElement("library_effects"); foreach (MDL0MaterialNode mat in node.Children) { writer.WriteStartElement("effect"); { writer.WriteAttributeString("id", mat._name + "-fx"); writer.WriteAttributeString("name", mat._name); writer.WriteStartElement("profile_COMMON"); { if (mat.Children.Count > 0) { MDL0MaterialRefNode mr = mat.Children[0] as MDL0MaterialRefNode; if (mr._texture != null) { writer.WriteStartElement("newparam"); writer.WriteAttributeString("sid", mr._texture.Name + "-surface"); { writer.WriteStartElement("surface"); writer.WriteAttributeString("type", "2D"); { writer.WriteStartElement("init_from"); { writer.WriteStartElement("ref"); { writer.WriteString(mr._texture.Name + "-image"); } writer.WriteEndElement(); //ref } writer.WriteEndElement(); //init_from } writer.WriteEndElement(); //surface } writer.WriteEndElement(); //newparam writer.WriteStartElement("newparam"); writer.WriteAttributeString("sid", mr._texture.Name + "-sampler"); { writer.WriteStartElement("sampler2D"); { writer.WriteStartElement("source"); { writer.WriteString(mr._texture.Name + "-surface"); } writer.WriteEndElement(); //source writer.WriteStartElement("instance_image"); writer.WriteAttributeString("url", "#" + mr._texture.Name + "-image"); writer.WriteEndElement(); //instance_image string wrap = "WRAP"; writer.WriteStartElement("wrap_s"); switch (mr._uWrap) { case 0: wrap = "CLAMP"; break; case 1: wrap = "WRAP"; break; case 2: wrap = "MIRROR"; break; } writer.WriteString(wrap); writer.WriteEndElement(); //wrap_s wrap = "REPEAT"; writer.WriteStartElement("wrap_t"); switch (mr._vWrap) { case 0: wrap = "CLAMP"; break; case 1: wrap = "WRAP"; break; case 2: wrap = "MIRROR"; break; } writer.WriteString(wrap); writer.WriteEndElement(); //wrap_t writer.WriteStartElement("minfilter"); writer.WriteString(mr.MinFilter.ToString().ToUpper()); writer.WriteEndElement(); //minfilter writer.WriteStartElement("magfilter"); writer.WriteString(mr.MagFilter.ToString().ToUpper()); writer.WriteEndElement(); //magfilter } writer.WriteEndElement(); //sampler2D } writer.WriteEndElement(); //newparam } } writer.WriteStartElement("technique"); writer.WriteAttributeString("sid", "COMMON"); { writer.WriteStartElement("phong"); { writer.WriteStartElement("diffuse"); { if (mat.Children.Count > 0) { MDL0MaterialRefNode mr = mat.Children[0] as MDL0MaterialRefNode; if (mr._texture != null) { writer.WriteStartElement("texture"); { writer.WriteAttributeString("texture", mr._texture.Name + "-sampler"); writer.WriteAttributeString("texcoord", "TEXCOORD" + (mr.TextureCoordId < 0 ? 0 : mr.TextureCoordId)); } writer.WriteEndElement(); //texture } } else { } } writer.WriteEndElement(); //diffuse } writer.WriteEndElement(); //phong } writer.WriteEndElement(); //technique } writer.WriteEndElement(); //profile } writer.WriteEndElement(); //effect } writer.WriteEndElement(); //library }
private void ModelChanged(MDL0Node model) { if (model != null && !_targetModels.Contains(model)) _targetModels.Add(model); if (_targetModel != null) _targetModel._isTargetModel = false; if (model == null) ModelPanel.RemoveTarget(_targetModel); if ((_targetModel = model) != null) { ModelPanel.AddTarget(_targetModel); leftPanel.VIS0Indices = _targetModel.VIS0Indices; _targetModel._isTargetModel = true; ResetVertexColors(); } else models.SelectedIndex = 0; if (_resetCamera) { ModelPanel.ResetCamera(); SetFrame(0); } else _resetCamera = true; leftPanel.Reset(); rightPanel.Reset(); if (TargetModelChanged != null) TargetModelChanged(this, null); _updating = true; if (_targetModel != null && !_editingAll) models.SelectedItem = _targetModel; _updating = false; if (_targetModel != null) RenderBones = _targetModel._renderBones; }
internal void Port(MDL0Node _targetModel, MDL0Node _extModel) { MDL0BoneNode extBone; MDL0BoneNode bone; KeyframeEntry kfe; float difference = 0; foreach (CHR0EntryNode _target in Children) { extBone = (MDL0BoneNode)_extModel.FindChild(_target.Name, true); //Get external model bone bone = (MDL0BoneNode)_targetModel.FindChild(_target.Name, true); //Get target model bone for (int x = 0; x < _target.FrameCount; x++) //Loop thru each frame { for (int i = 0x13; i < 0x19; i++) //Loop thru trans { if ((kfe = _target.GetKeyframe((KeyFrameMode)i, x)) != null) //Check for a keyframe { if (bone != null && extBone != null) { switch (i) { //Translations case 0x16: //Trans X if (Math.Round(kfe._value, 4) == Math.Round(extBone._bindState.Translate._x, 4)) { kfe._value = bone._bindState.Translate._x; } else if (bone._bindState.Translate._x < extBone._bindState.Translate._x) { kfe._value -= extBone._bindState.Translate._x - bone._bindState.Translate._x; } else if (bone._bindState.Translate._x > extBone._bindState.Translate._x) { kfe._value += bone._bindState.Translate._x - extBone._bindState.Translate._x; } break; case 0x17: //Trans Y if (Math.Round(kfe._value, 4) == Math.Round(extBone._bindState.Translate._y, 4)) { kfe._value = bone._bindState.Translate._y; } else if (bone._bindState.Translate._y < extBone._bindState.Translate._y) { kfe._value -= extBone._bindState.Translate._y - bone._bindState.Translate._y; } else if (bone._bindState.Translate._y > extBone._bindState.Translate._y) { kfe._value += bone._bindState.Translate._y - extBone._bindState.Translate._y; } break; case 0x18: //Trans Z if (Math.Round(kfe._value, 4) == Math.Round(extBone._bindState.Translate._z, 4)) { kfe._value = bone._bindState.Translate._z; } else if (bone._bindState.Translate._z < extBone._bindState.Translate._z) { kfe._value -= extBone._bindState.Translate._z - bone._bindState.Translate._z; } else if (bone._bindState.Translate._z > extBone._bindState.Translate._z) { kfe._value += bone._bindState.Translate._z - extBone._bindState.Translate._z; } break; //Rotations case 0x13: //Rot X difference = bone._bindState.Rotate._x - extBone._bindState.Rotate._x; kfe._value += difference; if (difference != 0) { FixChildren(bone, 0); } break; case 0x14: //Rot Y difference = bone._bindState.Rotate._y - extBone._bindState.Rotate._y; kfe._value += difference; if (difference != 0) { FixChildren(bone, 1); } break; case 0x15: //Rot Z difference = bone._bindState.Rotate._z - extBone._bindState.Rotate._z; kfe._value += difference; if (difference != 0) { FixChildren(bone, 2); } break; } } if (kfe._value == float.NaN || kfe._value == float.PositiveInfinity || kfe._value == float.NegativeInfinity) { kfe.Remove(); _target.Keyframes._keyCounts[i]--; } } } } } _changed = true; IsPorted = true; }
private void ModelChanged(MDL0Node model) { if (model != null && !_targetModels.Contains(model)) _targetModels.Add(model); if (_targetModel != null) _targetModel._isTargetModel = false; if (_targetModel != null) modelPanel.RemoveTarget(_targetModel); if ((_targetModel = model) != null) { modelPanel.AddTarget(_targetModel); listPanel.VIS0Indices = _targetModel.VIS0Indices; _targetModel._isTargetModel = true; ResetVertexColors(); hurtboxEditor._mainControl_TargetModelChanged(null, null); } if (_resetCam) { modelPanel.ResetCamera(); RunTime.SetFrame(0); } else _resetCam = true; modelListsPanel1.Reset(); //if (TargetModelChanged != null) // TargetModelChanged(this, null); //_updating = true; //if (_targetModel != null && !_editingAll) // comboCharacters.SelectedItem = _targetModel; //_updating = false; if (_targetModel != null) RenderBones = _targetModel._renderBones; }
public static unsafe void MDL02PMD(MDL0Node model) { _header = new ModelHeader(); _header._modelName = model.Name; //To do: Add the ability to change the comment _header._comment = "MDL0 model converted to PMD by Brawlbox."; foreach (MDL0MaterialNode m in model._matList) { ModelMaterial mat = new ModelMaterial(); mat._textureFileName = m.Children[0].Name; } _bones = new ModelBone[model._linker.BoneCache.Length]; for (int i = 0; i < model._linker.BoneCache.Length; i++) { ModelBone bone = new ModelBone(); MDL0BoneNode mBone = (MDL0BoneNode)model._linker.BoneCache[i]; Vector3 wPos = mBone._bindMatrix.GetPoint(); bone._wPos[0] = wPos._x; bone._wPos[1] = wPos._y; bone._wPos[2] = wPos._z; bone._boneName = mBone.Name; bone._boneType = 0; bone._parentBoneIndex = (ushort)model._linker.BoneCache.ToList<ResourceNode>().IndexOf(mBone.Parent); _bones[i] = bone; } }
public DialogResult ShowDialog(MDL0Node model) { return ShowDialog(null, model); }
public static void Export(MDL0Node model, string filename) { filename = Path.GetFullPath(filename); using (FileStream fs = new FileStream(filename, FileMode.Create)) { BinaryWriter writer = new BinaryWriter(fs); writer.Write(PMDModel.encoder.GetBytes("Pmd")); writer.Write(1.0f); //Version PMDModel.MDL02PMD(model); PMDModel.Write(writer); fs.Close(); } }
public void Port(MDL0Node _targetModel, MDL0Node _extModel) { MDL0BoneNode extBone; MDL0BoneNode bone; KeyframeEntry kfe; float difference = 0; foreach (CHR0EntryNode _target in Children) { extBone = (MDL0BoneNode)_extModel.FindChild(_target.Name, true); //Get external model bone bone = (MDL0BoneNode)_targetModel.FindChild(_target.Name, true); //Get target model bone for (int x = 0; x < _target.FrameCount; x++) { for (int i = 3; i < 9; i++) { if ((kfe = _target.GetKeyframe(i, x)) != null) //Check for a keyframe { if (bone != null && extBone != null) { switch (i) { //Translations case 6: //Trans X if (Math.Round(kfe._value, 4) == Math.Round(extBone._bindState.Translate._x, 4)) { kfe._value = bone._bindState.Translate._x; } else if (bone._bindState.Translate._x < extBone._bindState.Translate._x) { kfe._value -= extBone._bindState.Translate._x - bone._bindState.Translate._x; } else if (bone._bindState.Translate._x > extBone._bindState.Translate._x) { kfe._value += bone._bindState.Translate._x - extBone._bindState.Translate._x; } break; case 7: //Trans Y if (Math.Round(kfe._value, 4) == Math.Round(extBone._bindState.Translate._y, 4)) { kfe._value = bone._bindState.Translate._y; } else if (bone._bindState.Translate._y < extBone._bindState.Translate._y) { kfe._value -= extBone._bindState.Translate._y - bone._bindState.Translate._y; } else if (bone._bindState.Translate._y > extBone._bindState.Translate._y) { kfe._value += bone._bindState.Translate._y - extBone._bindState.Translate._y; } break; case 8: //Trans Z if (Math.Round(kfe._value, 4) == Math.Round(extBone._bindState.Translate._z, 4)) { kfe._value = bone._bindState.Translate._z; } else if (bone._bindState.Translate._z < extBone._bindState.Translate._z) { kfe._value -= extBone._bindState.Translate._z - bone._bindState.Translate._z; } else if (bone._bindState.Translate._z > extBone._bindState.Translate._z) { kfe._value += bone._bindState.Translate._z - extBone._bindState.Translate._z; } break; //Rotations //case 3: //Rot X // difference = bone._bindState.Rotate._x - extBone._bindState.Rotate._x; // kfe._value += difference; // //if (difference != 0) // // FixChildren(bone, 0); // break; //case 4: //Rot Y // difference = bone._bindState.Rotate._y - extBone._bindState.Rotate._y; // kfe._value += difference; // //if (difference != 0) // // FixChildren(bone, 1); // break; //case 5: //Rot Z // difference = bone._bindState.Rotate._z - extBone._bindState.Rotate._z; // kfe._value += difference; // //if (difference != 0) // // FixChildren(bone, 2); // break; } } if (kfe._value == float.NaN || kfe._value == float.PositiveInfinity || kfe._value == float.NegativeInfinity) { kfe.Remove(); _target.Keyframes._keyArrays[i]._keyCount--; } } } } } _changed = true; }
public void Port(MDL0Node baseModel) { MDL0Node model; OpenFileDialog dlgOpen = new OpenFileDialog(); dlgOpen.Filter = "MDL0 Model (*.mdl0)|*.mdl0"; dlgOpen.Title = "Select the model this animation is for..."; if (dlgOpen.ShowDialog() == DialogResult.OK) if ((model = (MDL0Node)NodeFactory.FromFile(null, dlgOpen.FileName)) != null) Port(baseModel, model); }
internal void Parse(MDL0Node model) { Influence inf; ModelLinker linker = model._linker; switch (_type) { case MDLResourceType.Definitions: if (linker.Defs != null) { ExtractGroup(linker.Defs, typeof(MDL0DefNode)); } break; case MDLResourceType.Bones: //Break if there are no bones defined if (linker.Bones == null) { break; } //Parse bones from raw data (flat list). //Bones re-assign parents in their Initialize block, so parents are true. ExtractGroup(linker.Bones, typeof(MDL0BoneNode)); //Cache flat list linker.BoneCache = _children.ToArray(); //Make sure the node cache is the correct size int highest = 0; foreach (MDL0BoneNode b in _children) { if (b._nodeIndex >= linker.NodeCache.Length && b._nodeIndex > highest) { highest = b._nodeIndex; } } if (highest >= linker.NodeCache.Length) { linker.NodeCache = new IMatrixNode[highest + 1]; } //Reset children so we can rebuild _children.Clear(); //Populate node cache MDL0BoneNode bone = null; int index; int count = linker.BoneCache.Length; for (int i = 0; i < count; i++) { linker.NodeCache[(bone = linker.BoneCache[i] as MDL0BoneNode)._nodeIndex] = bone; } //Now that bones and primary influences have been cached, we can create weighted influences. foreach (ResourcePair p in *linker.Defs) { if (p.Name == "NodeTree") { //Use node tree to rebuild bone heirarchy byte *pData = (byte *)p.Data; Top: if (*pData == 2) { bone = linker.BoneCache[*(bushort *)(pData + 1)] as MDL0BoneNode; index = *(bushort *)(pData + 3); if (bone.Header->_parentOffset == 0) { _children.Add(bone); } else { (bone._parent = linker.NodeCache[index] as ResourceNode)._children.Add(bone); } pData += 5; goto Top; } } else if (p.Name == "NodeMix") { //Use node mix to create weight groups byte *pData = (byte *)p.Data; Top: switch (*pData) { //Type 3 is for weighted influences case 3: //Get index/count fields index = *(bushort *)(pData + 1); count = pData[3]; //Get data pointer (offset of 4) MDL0NodeType3Entry *nEntry = (MDL0NodeType3Entry *)(pData + 4); //Create influence with specified count inf = new Influence(count); //Iterate through weights, adding each to the influence //Here, we are referring back to the NodeCache to grab the bone. //Note that the weights do not reference other influences, only bones. There is a good reason for this. for (int i = 0; i < count; i++, nEntry++) { if ((linker.NodeCache[nEntry->_id] as MDL0BoneNode) == null) { Console.WriteLine("Null bone entry!"); } else { inf._weights[i] = new BoneWeight(linker.NodeCache[nEntry->_id] as MDL0BoneNode, nEntry->_value); } } //Add influence to model object, while adding it to the cache. linker.NodeCache[index] = model._influences.AddOrCreate(inf); //Move data pointer to next entry pData = (byte *)nEntry; goto Top; //Type 5 is for primary influences case 5: pData += 5; goto Top; } } } int z = 0; foreach (IMatrixNode m in linker.NodeCache) { if (!m.IsPrimaryNode) { ((Influence)m)._permanentID = z; break; } z++; } break; case MDLResourceType.Materials: if (linker.Materials != null) { ExtractGroup(linker.Materials, typeof(MDL0MaterialNode)); } break; case MDLResourceType.Shaders: if (linker.Shaders != null) { ExtractGroup(linker.Shaders, typeof(MDL0ShaderNode)); } break; case MDLResourceType.Vertices: if (linker.Vertices != null) { ExtractGroup(linker.Vertices, typeof(MDL0VertexNode)); } break; case MDLResourceType.Normals: if (linker.Normals != null) { ExtractGroup(linker.Normals, typeof(MDL0NormalNode)); } break; case MDLResourceType.UVs: if (linker.UVs != null) { ExtractGroup(linker.UVs, typeof(MDL0UVNode)); } break; case MDLResourceType.Objects: //Break if no polygons defined if (linker.Polygons == null) { break; } //Extract ExtractGroup(linker.Polygons, typeof(MDL0PolygonNode)); //Attach materials to polygons. //This assumes that materials have already been parsed. List <ResourceNode> matList = ((MDL0Node)_parent)._matList; MDL0PolygonNode poly; MDL0MaterialNode mat; //Find DrawOpa or DrawXlu entry in Definition list foreach (ResourcePair p in *linker.Defs) { if ((p.Name == "DrawOpa") || (p.Name == "DrawXlu")) { ushort dIndex = 0; byte * pData = (byte *)p.Data; while (*pData++ == 4) { //Get polygon from index dIndex = *(bushort *)(pData + 2); if (dIndex >= _children.Count || dIndex < 0) { ((MDL0Node)Parent)._errors.Add("Object index was greater than the actual object count."); SignalPropertyChange(); dIndex = 0; } poly = _children[dIndex] as MDL0PolygonNode; //Get material from index mat = matList[*(bushort *)pData] as MDL0MaterialNode; //Get bone from index and assign int boneIndex = *(bushort *)(pData + 4); if (linker.BoneCache != null && boneIndex >= 0 && boneIndex < linker.BoneCache.Length) { poly.BoneNode = linker.BoneCache[boneIndex] as MDL0BoneNode; } //Assign material to polygon and add polygon to material reference list (poly._material = mat)._polygons.Add(poly); //Increment pointer pData += 7; } } } break; case MDLResourceType.Colors: if (linker.Colors != null) { ExtractGroup(linker.Colors, typeof(MDL0ColorNode)); } break; case MDLResourceType.Textures: if (linker.Textures != null) { ExtractGroup(linker.Textures, typeof(MDL0TextureNode)); } break; case MDLResourceType.Palettes: if (linker.Palettes != null) { ExtractGroup(linker.Palettes, typeof(MDL0TextureNode)); } break; } }
internal void Parse(MDL0Node model) { Influence inf; ModelLinker linker = model._linker; switch (_type) { case MDLResourceType.Definitions: if (linker.Defs != null) ExtractGroup(linker.Defs, typeof(MDL0DefNode)); break; case MDLResourceType.Bones: //Break if there are no bones defined if (linker.Bones == null) break; //Parse bones from raw data (flat list). //Bones re-assign parents in their Initialize block, so parents are true. //Parents must be assigned now as bones will be moved in memory when assigned as children. ExtractGroup(linker.Bones, typeof(MDL0BoneNode)); //Cache flat list linker.BoneCache = _children.ToArray(); //Make sure the node cache is the correct size int highest = 0; foreach (MDL0BoneNode b in linker.BoneCache) if (b._nodeIndex >= linker.NodeCache.Length && b._nodeIndex > highest) highest = b._nodeIndex; if (highest >= linker.NodeCache.Length) linker.NodeCache = new IMatrixNode[highest + 1]; //Reset children so we can rebuild _children.Clear(); //Assign children using each bones' parent offset in case NodeTree is corrupted foreach (MDL0BoneNode b in linker.BoneCache) b._parent._children.Add(b); //Populate node cache MDL0BoneNode bone = null; int index; int count = linker.BoneCache.Length; for (int i = 0; i < count; i++) linker.NodeCache[(bone = linker.BoneCache[i] as MDL0BoneNode)._nodeIndex] = bone; int nullCount = 0; bool nodeTreeError = false; //Now that bones and primary influences have been cached, we can create weighted influences. foreach (ResourcePair p in *linker.Defs) if (p.Name == "NodeTree") { //Double check bone tree using the NodeTree definition. //If the NodeTree is corrupt, the user will be informed that it needs to be rebuilt. byte* pData = (byte*)p.Data; Top: if (*pData == 2) { bone = linker.BoneCache[*(bushort*)(pData + 1)] as MDL0BoneNode; index = *(bushort*)(pData + 3); if (bone.Header->_parentOffset == 0) { if (!_children.Contains(bone)) { nodeTreeError = true; continue; } } else { ResourceNode n = linker.NodeCache[index] as ResourceNode; if (n == null || bone._parent != n || !n._children.Contains(bone)) { nodeTreeError = true; continue; } } pData += 5; goto Top; } } else if (p.Name == "NodeMix") { //Use node mix to create weight groups byte* pData = (byte*)p.Data; Top: switch (*pData) { //Type 3 is for weighted influences case 3: //Get index/count fields index = *(bushort*)(pData + 1); count = pData[3]; //Get data pointer (offset of 4) MDL0NodeType3Entry* nEntry = (MDL0NodeType3Entry*)(pData + 4); //Create influence with specified count inf = new Influence(); //Iterate through weights, adding each to the influence //Here, we are referring back to the NodeCache to grab the bone. //Note that the weights do not reference other influences, only bones. There is a good reason for this. MDL0BoneNode b = null; List<int> nullIndices = new List<int>(); for (int i = 0; i < count; i++, nEntry++) if (nEntry->_id < linker.NodeCache.Length && (b = (linker.NodeCache[nEntry->_id] as MDL0BoneNode)) != null) inf._weights.Add(new BoneWeight(b, nEntry->_value)); else { nullIndices.Add(i); nullCount++; } bool d = false; if (nullIndices.Count > 0) { List<BoneWeight> newWeights = new List<BoneWeight>(); for (int i = 0; i < inf._weights.Count; i++) if (!nullIndices.Contains(i)) newWeights.Add(inf._weights[i]); if (newWeights.Count == 0) d = true; else inf._weights = newWeights; } //Add influence to model object, while adding it to the cache. if (!d) ((Influence)(linker.NodeCache[index] = model._influences.FindOrCreate(inf, true)))._index = index; //Move data pointer to next entry pData = (byte*)nEntry; goto Top; //Type 5 is for primary influences case 5: pData += 5; goto Top; } } if (nullCount > 0) { model._errors.Add("There were " + nullCount + " null weights in NodeMix."); SignalPropertyChange(); } if (nodeTreeError) { model._errors.Add("The NodeTree definition did not match the bone tree."); SignalPropertyChange(); } break; case MDLResourceType.Materials: if (linker.Materials != null) ExtractGroup(linker.Materials, typeof(MDL0MaterialNode)); break; case MDLResourceType.Shaders: if (linker.Shaders != null) ExtractGroup(linker.Shaders, typeof(MDL0ShaderNode)); break; case MDLResourceType.Vertices: if (linker.Vertices != null) ExtractGroup(linker.Vertices, typeof(MDL0VertexNode)); break; case MDLResourceType.Normals: if (linker.Normals != null) ExtractGroup(linker.Normals, typeof(MDL0NormalNode)); break; case MDLResourceType.UVs: if (linker.UVs != null) ExtractGroup(linker.UVs, typeof(MDL0UVNode)); break; case MDLResourceType.FurLayerCoords: if (linker.FurLayerCoords != null) ExtractGroup(linker.FurLayerCoords, typeof(MDL0FurPosNode)); break; case MDLResourceType.FurVectors: if (linker.FurVectors != null) ExtractGroup(linker.FurVectors, typeof(MDL0FurVecNode)); break; case MDLResourceType.Objects: //Break if no polygons defined if (linker.Polygons == null) break; //Extract ExtractGroup(linker.Polygons, typeof(MDL0ObjectNode)); //Attach materials to polygons. //This assumes that materials have already been parsed. List<ResourceNode> matList = ((MDL0Node)_parent)._matList; MDL0ObjectNode poly; MDL0MaterialNode mat; //Find DrawOpa or DrawXlu entry in Definition list foreach (ResourcePair p in *linker.Defs) if ((p.Name == "DrawOpa") || (p.Name == "DrawXlu")) { bool opa = p.Name == "DrawOpa"; ushort dIndex = 0; byte* pData = (byte*)p.Data; while (*pData++ == 4) { //Get polygon from index dIndex = *(bushort*)(pData + 2); if (dIndex >= _children.Count || dIndex < 0) { model._errors.Add("Object index was greater than the actual object count."); SignalPropertyChange(); dIndex = 0; } poly = _children[dIndex] as MDL0ObjectNode; poly._drawIndex = pData[6]; //Get material from index mat = matList[*(bushort*)pData] as MDL0MaterialNode; //Get bone from index and assign int boneIndex = *(bushort*)(pData + 4); if (linker.BoneCache != null && boneIndex >= 0 && boneIndex < linker.BoneCache.Length) poly.BoneNode = linker.BoneCache[boneIndex] as MDL0BoneNode; //Assign material to polygon if (opa) poly.OpaMaterialNode = mat; else poly.XluMaterialNode = mat; //Increment pointer pData += 7; } } foreach (MDL0ObjectNode m in _children) { int max = Maths.Max( m.OpaMaterialNode != null ? m.OpaMaterialNode.Children.Count : 0, m.XluMaterialNode != null ? m.XluMaterialNode.Children.Count : 0, m.OpaMaterialNode != null && m.OpaMaterialNode.MetalMaterial != null ? m.OpaMaterialNode.MetalMaterial.Children.Count : 0, m.XluMaterialNode != null && m.XluMaterialNode.MetalMaterial != null ? m.XluMaterialNode.MetalMaterial.Children.Count : 0); bool hasUnused = false; for (int i = max; i < 8; i++) if (m.HasTextureMatrix[i]) { m.HasTextureMatrix[i] = false; m._rebuild = true; hasUnused = true; } if (hasUnused) { ((MDL0Node)Parent)._errors.Add("Object " + m.Index + " has unused texture matrices."); m.SignalPropertyChange(); } if (m.HasTexMtx && m.HasNonFloatVertices) { ((MDL0Node)Parent)._errors.Add("Object " + m.Index + " has texture matrices and non-float vertices, meaning it will explode in-game."); m.SignalPropertyChange(); } } break; case MDLResourceType.Colors: if (linker.Colors != null) ExtractGroup(linker.Colors, typeof(MDL0ColorNode)); break; case MDLResourceType.Textures: if (linker.Textures != null) ExtractGroup(linker.Textures, typeof(MDL0TextureNode)); break; case MDLResourceType.Palettes: if (linker.Palettes != null) ExtractGroup(linker.Palettes, typeof(MDL0TextureNode)); break; } }
public MDL0Node ImportModel(string filePath) { MDL0Node model = new MDL0Node() { _name = Path.GetFileNameWithoutExtension(filePath) }; model.InitGroups(); if (_importOptions._setOrigPath) model._originalPath = filePath; //Parse the collada file and use the data to create an MDL0 using (DecoderShell shell = DecoderShell.Import(filePath)) try { model._version = _importOptions._modelVersion; Error = "There was a problem reading the model."; //Extract images, removing duplicates foreach (ImageEntry img in shell._images) { string name; MDL0TextureNode tex; if (img._path != null) name = Path.GetFileNameWithoutExtension(img._path); else name = img._name != null ? img._name : img._id; tex = model.FindOrCreateTexture(name); img._node = tex; } //Extract materials and create shaders int tempNo = -1; foreach (MaterialEntry mat in shell._materials) { tempNo += 1; MDL0MaterialNode matNode = new MDL0MaterialNode(); matNode._parent = model._matGroup; matNode._name = mat._name != null ? mat._name : mat._id; if (tempNo == 0) { MDL0ShaderNode shadNode = new MDL0ShaderNode(); shadNode._parent = model._shadGroup; shadNode._name = "Shader" + tempNo; model._shadList.Add(shadNode); } matNode.Shader = "Shader0"; matNode.ShaderNode = (MDL0ShaderNode)model._shadGroup.Children[0]; mat._node = matNode; matNode._cull = _importOptions._culling; //Find effect if (mat._effect != null) foreach (EffectEntry eff in shell._effects) if (eff._id == mat._effect) //Attach textures and effects to material if (eff._shader != null) foreach (LightEffectEntry l in eff._shader._effects) if (l._type == LightEffectType.diffuse && l._texture != null) { string path = l._texture; foreach (EffectNewParam p in eff._newParams) if (p._sid == l._texture) { path = p._sampler2D._url; if (!String.IsNullOrEmpty(p._sampler2D._source)) { foreach (EffectNewParam p2 in eff._newParams) if (p2._sid == p._sampler2D._source) path = p2._path; } } foreach (ImageEntry img in shell._images) if (img._id == path) { MDL0MaterialRefNode mr = new MDL0MaterialRefNode(); (mr._texture = img._node as MDL0TextureNode)._references.Add(mr); mr._name = mr._texture.Name; matNode._children.Add(mr); mr._parent = matNode; mr._minFltr = mr._magFltr = 1; mr._index1 = mr._index2 = mr.Index; mr._uWrap = mr._vWrap = (int)_importOptions._wrap; break; } } matNode._numTextures = (byte)matNode.Children.Count; model._matList.Add(matNode); } Say("Extracting scenes..."); //Extract scenes foreach (SceneEntry scene in shell._scenes) { //Parse joints first NodeEntry[] joints = scene._nodes.Where(x => x._type == NodeType.JOINT).ToArray(); NodeEntry[] nodes = scene._nodes.Where(x => x._type != NodeType.JOINT).ToArray(); foreach (NodeEntry node in joints) EnumNode(node, model._boneGroup, scene, model, shell); foreach (NodeEntry node in nodes) EnumNode(node, model._boneGroup, scene, model, shell); } //If there are no bones, rig all objects to a single bind. if (model._boneGroup._children.Count == 0) { for (int i = 0; i < 2; i++) { MDL0BoneNode bone = new MDL0BoneNode(); bone.Scale = new Vector3(1); bone._bindMatrix = bone._inverseBindMatrix = Matrix.Identity; switch (i) { case 0: bone._name = "TopN"; model._boneGroup._children.Add(bone); bone._parent = model._boneGroup; break; case 1: bone._name = "TransN"; model._boneGroup._children[0]._children.Add(bone); bone._parent = model._boneGroup._children[0]; bone.ReferenceCount = model._objList.Count; break; } } if (model._objList != null && model._objList.Count != 0) foreach (MDL0ObjectNode poly in model._objList) { poly._nodeId = 0; poly.MatrixNode = (MDL0BoneNode)model._boneGroup._children[0]._children[0]; } } else { //Check each polygon to see if it can be rigged to a single influence if (model._objList != null && model._objList.Count != 0) foreach (MDL0ObjectNode p in model._objList) { IMatrixNode node = null; bool singlebind = true; foreach (Vertex3 v in p._manager._vertices) if (v._matrixNode != null) { if (node == null) node = v._matrixNode; if (v._matrixNode != node) { singlebind = false; break; } } if (singlebind && p._matrixNode == null) { //Increase reference count ahead of time for rebuild if (p._manager._vertices[0]._matrixNode != null) p._manager._vertices[0]._matrixNode.ReferenceCount++; foreach (Vertex3 v in p._manager._vertices) if (v._matrixNode != null) v._matrixNode.ReferenceCount--; p._nodeId = -2; //Continued on polygon rebuild } } } //Remove original color buffers if option set if (_importOptions._ignoreColors) { if (model._objList != null && model._objList.Count != 0) foreach (MDL0ObjectNode p in model._objList) for (int x = 2; x < 4; x++) if (p._manager._faceData[x] != null) { p._manager._faceData[x].Dispose(); p._manager._faceData[x] = null; } } //Add color buffers if option set if (_importOptions._addClrs) { RGBAPixel pixel = _importOptions._dfltClr; //Add a color buffer to objects that don't have one if (model._objList != null && model._objList.Count != 0) foreach (MDL0ObjectNode p in model._objList) if (p._manager._faceData[2] == null) { RGBAPixel* pIn = (RGBAPixel*)(p._manager._faceData[2] = new UnsafeBuffer(4 * p._manager._pointCount)).Address; for (int i = 0; i < p._manager._pointCount; i++) *pIn++ = pixel; } } //Apply defaults to materials if (model._matList != null) foreach (MDL0MaterialNode p in model._matList) { if (_importOptions._mdlType == 0) { p._lSet = 20; p._fSet = 4; p._ssc = 3; p.C1ColorEnabled = true; p.C1AlphaMaterialSource = GXColorSrc.Vertex; p.C1ColorMaterialSource = GXColorSrc.Vertex; p.C1ColorDiffuseFunction = GXDiffuseFn.Clamped; p.C1ColorAttenuation = GXAttnFn.Spotlight; p.C1AlphaEnabled = true; p.C1AlphaDiffuseFunction = GXDiffuseFn.Clamped; p.C1AlphaAttenuation = GXAttnFn.Spotlight; p.C2ColorDiffuseFunction = GXDiffuseFn.Disabled; p.C2ColorAttenuation = GXAttnFn.None; p.C2AlphaDiffuseFunction = GXDiffuseFn.Disabled; p.C2AlphaAttenuation = GXAttnFn.None; } else { p._lSet = 0; p._fSet = 0; p._ssc = 1; p._chan1.Color = new LightChannelControl(1795); p._chan1.Alpha = new LightChannelControl(1795); p._chan2.Color = new LightChannelControl(1795); p._chan2.Alpha = new LightChannelControl(1795); } } //Set materials to use register color if option set if (_importOptions._useReg && model._objList != null) foreach (MDL0ObjectNode p in model._objList) { MDL0MaterialNode m = p.OpaMaterialNode; if (m != null && p._manager._faceData[2] == null && p._manager._faceData[3] == null) { m.C1MaterialColor = _importOptions._dfltClr; m.C1ColorMaterialSource = GXColorSrc.Register; m.C1AlphaMaterialSource = GXColorSrc.Register; } } //Remap materials if option set if (_importOptions._rmpMats && model._matList != null && model._objList != null) { foreach (MDL0ObjectNode p in model._objList) foreach (MDL0MaterialNode m in model._matList) if (m.Children.Count > 0 && m.Children[0] != null && p.OpaMaterialNode != null && p.OpaMaterialNode.Children.Count > 0 && p.OpaMaterialNode.Children[0] != null && m.Children[0].Name == p.OpaMaterialNode.Children[0].Name && m.C1ColorMaterialSource == p.OpaMaterialNode.C1ColorMaterialSource) { p.OpaMaterialNode = m; break; } //Remove unused materials for (int i = 0; i < model._matList.Count; i++) if (((MDL0MaterialNode)model._matList[i])._objects.Count == 0) model._matList.RemoveAt(i--); } Error = "There was a problem writing the model."; //Clean the model and then build it! if (model != null) { model.CleanGroups(); model.BuildFromScratch(this); } } catch (Exception x) { MessageBox.Show("Cannot continue importing this model.\n" + Error + "\n\nException:\n" + x.ToString()); model = null; Close(); } finally { //Clean up the mess we've made GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); } return model; }