static PrimitiveManager DecodePrimitivesUnweighted(GeometryEntry geo) { PrimitiveManager manager = DecodePrimitives(geo); Vector3 * pVert = null; ushort * pVInd = (ushort *)manager._indices.Address; int vCount = 0; List <Vertex3> vertList = new List <Vertex3>(manager._pointCount); manager._vertices = vertList; //Find vertex source foreach (SourceEntry s in geo._sources) { if (s._id == geo._verticesInput._source) { UnsafeBuffer b = s._arrayData as UnsafeBuffer; pVert = (Vector3 *)b.Address; vCount = b.Length / 12; break; } } UnsafeBuffer remap = new UnsafeBuffer(vCount * 2); ushort * pRemap = (ushort *)remap.Address; //Create remap table for (int i = 0; i < vCount; i++) { //Create Vertex and look for match Vertex3 v = new Vertex3(pVert[i]); int index = 0; while (index < vertList.Count) { if (v.Equals(vertList[index])) { break; } index++; } if (index == vertList.Count) { vertList.Add(v); } pRemap[i] = (ushort)index; } //Remap vertex indices for (int i = 0; i < manager._pointCount; i++, pVInd++) { *pVInd = pRemap[*pVInd]; } remap.Dispose(); //manager.MergeTempData(); return(manager); }
private static unsafe void WriteNormalGroup(StreamWriter writer, PrimitiveManager p, bool weight) { ushort* pIndex = (ushort*)p._indices.Address; Vector3 v; writer.WriteLine(); writer.WriteLine("#Normals"); Vector3* pVert = (Vector3*)p._faceData[1].Address; for (int i = 0; i < p._faceData[1].Length / 12; i++) { //writer.WriteLine("vn {0} {1} {2}", pVert->_x, pVert->_y, (pVert++)->_z); if (weight && p._vertices[*pIndex]._matrixNode != null) v = p._vertices[*pIndex++]._matrixNode.Matrix.GetRotationMatrix() * *pVert++; else v = *pVert++; writer.WriteLine("vn {0} {1} {2}", v._x, v._y, v._z); } }
static void NullWeight(PrimitiveManager manager, GeometryEntry geo) { Vector3 * pVert = null; ushort * pVInd = (ushort *)manager._indices.Address; List <Vertex3> vertList = new List <Vertex3>(manager._pointCount); //Find vertex source foreach (SourceEntry s in geo._sources) { if (s._id == geo._verticesInput._source) { pVert = (Vector3 *)((UnsafeBuffer)s._arrayData).Address; break; } } //Construct Vertex from new weight for (int i = 0; i < manager._pointCount; i++) { //Create Vertex and look for match Vertex3 v = new Vertex3(pVert[*pVInd]); int index = 0; while (index < vertList.Count) { if (v.Equals(vertList[i])) { break; } index++; } if (index == vertList.Count) { vertList.Add(v); } //Assign new index *pVInd++ = (ushort)index; } }
private unsafe static void WriteNormalGroup(StreamWriter writer, PrimitiveManager p, bool weight) { ushort *pIndex = (ushort *)p._indices.Address; Vector3 v; writer.WriteLine(); writer.WriteLine("#Normals"); Vector3 *pVert = (Vector3 *)p._faceData[1].Address; for (int i = 0; i < p._faceData[1].Length / 12; i++) { //writer.WriteLine("vn {0} {1} {2}", pVert->_x, pVert->_y, (pVert++)->_z); if (weight && p._vertices[*pIndex]._matrixNode != null) { v = p._vertices[*pIndex++]._matrixNode.Matrix.GetRotationMatrix() * *pVert++; } else { v = *pVert++; } writer.WriteLine("vn {0} {1} {2}", v._x, v._y, v._z); } }
static PrimitiveManager DecodePrimitivesWeighted(GeometryEntry geo, SkinEntry skin, SceneEntry scene, InfluenceManager infManager, ref string Error) { PrimitiveManager manager = DecodePrimitives(geo); MDL0BoneNode[] boneList; MDL0BoneNode bone = null; int boneCount; string[] jointStrings = null; byte * pCmd = stackalloc byte[4]; int cmdCount = skin._weightInputs.Count; float weight = 0; float * pWeights = null; Vector3 * pVert = null, pNorms = null; ushort * pVInd = (ushort *)manager._indices.Address; List <Vertex3> vertList = new List <Vertex3>(skin._weightCount); Matrix * pMatrix = null; UnsafeBuffer remap = new UnsafeBuffer(skin._weightCount * 2); ushort * pRemap = (ushort *)remap.Address; pNorms = (Vector3 *)manager._faceData[1].Address; //List<int> FixedIndices = new List<int>(); manager._vertices = vertList; //Find vertex source foreach (SourceEntry s in geo._sources) { if (s._id == geo._verticesInput._source) { pVert = (Vector3 *)((UnsafeBuffer)s._arrayData).Address; break; } } //Find joint source foreach (InputEntry inp in skin._jointInputs) { if (inp._semantic == SemanticType.JOINT) { foreach (SourceEntry src in skin._sources) { if (src._id == inp._source) { jointStrings = src._arrayData as string[]; break; } } } else if (inp._semantic == SemanticType.INV_BIND_MATRIX) { foreach (SourceEntry src in skin._sources) { if (src._id == inp._source) { pMatrix = (Matrix *)((UnsafeBuffer)src._arrayData).Address; break; } } } } Error = "There was a problem creating the list of bones for geometry entry " + geo._name; //Populate bone list boneCount = jointStrings.Length; boneList = new MDL0BoneNode[boneCount]; for (int i = 0; i < boneCount; i++) { boneList[i] = scene.FindNode(jointStrings[i])._node as MDL0BoneNode; } //Build command list foreach (InputEntry inp in skin._weightInputs) { switch (inp._semantic) { case SemanticType.JOINT: pCmd[inp._offset] = 1; break; case SemanticType.WEIGHT: pCmd[inp._offset] = 2; //Get weight source foreach (SourceEntry src in skin._sources) { if (src._id == inp._source) { pWeights = (float *)((UnsafeBuffer)src._arrayData).Address; break; } } break; default: pCmd[inp._offset] = 0; break; } } Error = "There was a problem creating vertex influences for geometry entry " + geo._name; //Build vertex list and remap table for (int i = 0; i < skin._weightCount; i++) { //Create influence int iCount = skin._weights[i].Length / cmdCount; Influence inf = new Influence(iCount); fixed(int *p = skin._weights[i]) { int *iPtr = p; for (int x = 0; x < iCount; x++) { for (int z = 0; z < cmdCount; z++, iPtr++) { if (pCmd[z] == 1) { bone = boneList[*iPtr]; } else if (pCmd[z] == 2) { weight = pWeights[*iPtr]; } } //if (bone != null) // if (bone.Name == "TopN" || bone.Name == "XRotN" || bone.Name == "YRotN" || bone.Name == "TransN" || bone.Name == "ThrowN" || bone.Name == "FacePattern") // Console.WriteLine(bone.Name); // else if (bone.Parent != null) // if (bone.Parent.Name == "FacePattern") // Console.WriteLine(bone.Name); inf._weights[x] = new BoneWeight(bone, weight); } } inf.CalcMatrix(); Error = "There was a problem creating a vertex from the geometry entry " + geo._name + ".\nMake sure that all the vertices are weighted properly."; Vertex3 v; if (inf._weights.Length > 1) { //Match with manager inf = infManager.AddOrCreate(inf); v = new Vertex3(skin._bindMatrix * pVert[i], inf); //World position } else { bone = inf._weights[0].Bone; v = new Vertex3(bone._inverseBindMatrix * skin._bindMatrix * pVert[i], bone); //Local position } ////Create Vertex, set to world position. //v = new Vertex3(skin._bindMatrix * pVert[i], inf); ////Fix single-bind vertices //v.Position = inf._weights[0].Bone._inverseBindMatrix * v.Position; ushort index = 0; while (index < vertList.Count) { if (v.Equals(vertList[index])) { break; } index++; } if (index == vertList.Count) { vertList.Add(v); } pRemap[i] = index; } Error = "There was a problem fixing normal rotations for geometry entry " + geo._name; //Remap vertex indices and fix normals for (int i = 0; i < manager._pointCount; i++, pVInd++) { * pVInd = pRemap[*pVInd]; Vertex3 v = null; if (*pVInd < vertList.Count) { v = vertList[*pVInd]; } if (v != null && v._influence != null) { if (v._influence.Weights.Length > 1) { pNorms[i] = skin._bindMatrix.GetRotationMatrix() * pNorms[i]; } else { pNorms[i] = skin._bindMatrix.GetRotationMatrix() * v._influence.Weights[0].Bone._inverseBindMatrix.GetRotationMatrix() * pNorms[i]; } } } remap.Dispose(); //manager.MergeTempData(); return(manager); }
public override void Dispose() { if (_manager != null) { _manager.Dispose(); _manager = null; } base.Dispose(); }
//private static void WriteTriFan(StreamWriter writer, Primitive p) //{ // if ((p._vertexIndices == null) || (p._normalIndices == null)) // return; // writer.WriteLine(); // writer.WriteLine("#Trifan"); // int count = p._elementCount - 2; // if (p._uvIndices[0] != null) // for (int i = 0; i < count; i++) // writer.WriteLine(String.Format("f {0}/{1}/{2} {3}/{4}/{5} {6}/{7}/{8}", // p._vertexIndices[0] + 1, p._uvIndices[0][0] + 1, p._normalIndices[0] + 1, // p._vertexIndices[i + 1] + 1, p._uvIndices[0][i + 1] + 1, p._normalIndices[i + 1] + 1, // p._vertexIndices[i + 2] + 1, p._uvIndices[0][i + 2] + 1, p._normalIndices[i + 2] + 1)); // else // for (int i = 0; i < count; i++) // writer.WriteLine(String.Format("f {0}//{1} {2}//{3} {4}//{5}", // p._vertexIndices[0] + 1, p._normalIndices[0] + 1, // p._vertexIndices[i + 1] + 1, p._normalIndices[i + 1] + 1, // p._vertexIndices[i + 2] + 1, p._normalIndices[i + 2] + 1)); //} //private static void WriteTriStrip(StreamWriter writer, Primitive p) //{ // if ((p._vertexIndices == null) || (p._normalIndices == null)) // return; // writer.WriteLine(); // writer.WriteLine("#Tristrip"); // int count = p._elementCount - 2; // int l1 = 0, l2 = 2; // if (p._uvIndices[0] != null) // for (int i = 0; i < count; i++) // { // if ((i & 1) == 0) // { // l1 = i; // l2 = i + 1; // } // else // { // l1 = i + 1; // l2 = i; // } // writer.WriteLine(String.Format("f {0}/{1}/{2} {3}/{4}/{5} {6}/{7}/{8}", // p._vertexIndices[l1] + 1, p._uvIndices[0][l1] + 1, p._normalIndices[l1] + 1, // p._vertexIndices[l2] + 1, p._uvIndices[0][l2] + 1, p._normalIndices[l2] + 1, // p._vertexIndices[i + 2] + 1, p._uvIndices[0][i + 2] + 1, p._normalIndices[i + 2] + 1)); // } // else // for (int i = 0; i < count; i++) // { // if ((i & 1) == 0) // { // l1 = i; // l2 = i + 1; // } // else // { // l1 = i + 1; // l2 = i; // } // writer.WriteLine(String.Format("f {0}//{1} {2}//{3} {4}//{5}", // p._vertexIndices[l1] + 1, p._normalIndices[l1] + 1, // p._vertexIndices[l2] + 1, p._normalIndices[l2] + 1, // p._vertexIndices[i + 2] + 1, p._normalIndices[i + 2] + 1)); // } //} //private static void WriteTriList(StreamWriter writer, Primitive p) //{ // if ((p._vertexIndices == null) || (p._normalIndices == null)) // return; // writer.WriteLine(); // writer.WriteLine("#Trilist"); // int count = p._elementCount / 3; // if (p._uvIndices[0] != null) // for (int i = 0, x = 0; i < count; i++, x += 3) // writer.WriteLine(String.Format("f {0}/{1}/{2} {3}/{4}/{5} {6}/{7}/{8}", // p._vertexIndices[x] + 1, p._uvIndices[0][x] + 1, p._normalIndices[x] + 1, // p._vertexIndices[x + 1] + 1, p._uvIndices[0][x + 1] + 1, p._normalIndices[x + 1] + 1, // p._vertexIndices[x + 2] + 1, p._uvIndices[0][x + 2] + 1, p._normalIndices[x + 2] + 1)); // else // for (int i = 0, x = 0; i < count; i++, x += 3) // writer.WriteLine(String.Format("f {0}//{1} {2}//{3} {4}//{5}", // p._vertexIndices[x] + 1, p._normalIndices[x] + 1, // p._vertexIndices[x + 1] + 1, p._normalIndices[x + 1] + 1, // p._vertexIndices[x + 2] + 1, p._normalIndices[x + 2] + 1)); //} private unsafe static void WriteTriList(StreamWriter writer, PrimitiveManager p) { uint[] pData = p._triangles._indices; uint x = 0; ushort *pVert = (ushort *)p._indices.Address; bool hasUVs = p._faceData[4] != null; bool hasNorms = p._faceData[1] != null; writer.WriteLine(); writer.WriteLine("#Trilist"); int count = p._triangles._elementCount / 3; //Loop through triangles for (int tri = 0; tri < count; tri++) { //writer.WriteLine("s " + i); //Smoothing groups don't seem to do anything writer.Write("f "); //Face //Loop through triangle points for (int pt = 0; pt < 3; pt++) { uint index = pData[x++]; //Loop through vertices, uvs, normals for (int asset = 0; asset < 3; asset++) { if (asset != 0) //Not a point start { writer.Write("/"); //Asset divider } //If no UVs, there's a double slash if (!hasUVs && asset == 1) { continue; } if (asset == 0) //Vertex index { writer.Write((pVert[index] + 1).ToString()); } else { writer.Write((index + 1).ToString()); } if (asset == 2) //Point is done { if (pt == 2) //Last point { writer.WriteLine(); } else //Still more points to go { writer.Write(" "); } } } } } }
static PrimitiveManager DecodePrimitives(Matrix nodeMatrix, GeometryEntry geo) { uint[] pTriarr = null, pLinarr = null; uint pTri = 0, pLin = 0; long* pInDataList = stackalloc long[12]; long* pOutDataList = stackalloc long[12]; int* pData = stackalloc int[16]; int faces = 0, lines = 0, points = 0; ushort fIndex = 0, lIndex = 0, temp; PrimitiveDecodeCommand* pCmd = (PrimitiveDecodeCommand*)pData; byte** pInData = (byte**)pInDataList; byte** pOutData = (byte**)pOutDataList; PrimitiveManager manager = new PrimitiveManager(); //Assign vertex source foreach (SourceEntry s in geo._sources) if (s._id == geo._verticesInput._source) { pInData[0] = (byte*)((UnsafeBuffer)s._arrayData).Address; break; } foreach (PrimitiveEntry prim in geo._primitives) { //Get face/line count if (prim._type == PrimitiveType.lines || prim._type == PrimitiveType.linestrips) lines += prim._faceCount; else faces += prim._faceCount; //Get point total points += prim._pointCount; //Signal storage buffers and set type offsets foreach (InputEntry inp in prim._inputs) { int offset = -1; switch (inp._semantic) { case SemanticType.VERTEX: offset = 0; break; case SemanticType.NORMAL: offset = 1; break; case SemanticType.COLOR: if (inp._set < 2) offset = 2 + inp._set; break; case SemanticType.TEXCOORD: if (inp._set < 8) offset = 4 + inp._set; break; } if (offset != -1) manager._dirty[offset] = true; inp._outputOffset = offset; } } manager._pointCount = points; //Create primitives if (faces > 0) { manager._triangles = new NewPrimitive(faces * 3, BeginMode.Triangles); pTriarr = manager._triangles._indices; } if (lines > 0) { manager._lines = new NewPrimitive(lines * 2, BeginMode.Lines); pLinarr = manager._lines._indices; } manager._indices = new UnsafeBuffer(points * 2); //Create face buffers and assign output pointers for (int i = 0; i < 12; i++) if (manager._dirty[i]) { int stride; if (i == 0) stride = 2; else if (i == 1) stride = 12; else if (i < 4) stride = 4; else stride = 8; manager._faceData[i] = new UnsafeBuffer(points * stride); if (i == 0) pOutData[i] = (byte*)manager._indices.Address; else pOutData[i] = (byte*)manager._faceData[i].Address; } //Decode primitives foreach (PrimitiveEntry prim in geo._primitives) { int count = prim._inputs.Count; //Map inputs to command sequence foreach (InputEntry inp in prim._inputs) { if (inp._outputOffset == -1) pCmd[inp._offset].Cmd = 0; else { pCmd[inp._offset].Cmd = (byte)inp._semantic; pCmd[inp._offset].Index = (byte)inp._outputOffset; //Assign input buffer foreach (SourceEntry src in geo._sources) if (src._id == inp._source) { pInData[inp._outputOffset] = (byte*)((UnsafeBuffer)src._arrayData).Address; break; } } } //Decode face data using command list foreach (PrimitiveFace f in prim._faces) fixed (ushort* p = f._pointIndices) RunPrimitiveCmd(nodeMatrix, pInData, pOutData, pCmd, count, p, f._pointCount); //Process point indices switch (prim._type) { case PrimitiveType.triangles: count = prim._faceCount * 3; while (count-- > 0) pTriarr[pTri++] = fIndex++; break; case PrimitiveType.trifans: case PrimitiveType.polygons: case PrimitiveType.polylist: foreach (PrimitiveFace f in prim._faces) { count = f._pointCount - 2; temp = fIndex; fIndex += 2; while (count-- > 0) { pTriarr[pTri++] = temp; pTriarr[pTri++] = (uint)(fIndex - 1); pTriarr[pTri++] = fIndex++; } } break; case PrimitiveType.tristrips: foreach (PrimitiveFace f in prim._faces) { count = f._pointCount; fIndex += 2; for (int i = 2; i < count; i++) { if ((i & 1) == 0) { pTriarr[pTri++] = (uint)(fIndex - 2); pTriarr[pTri++] = (uint)(fIndex - 1); pTriarr[pTri++] = fIndex++; } else { pTriarr[pTri++] = (uint)(fIndex - 2); pTriarr[pTri++] = fIndex; pTriarr[pTri++] = (uint)(fIndex++ - 1); } } } break; case PrimitiveType.linestrips: foreach (PrimitiveFace f in prim._faces) { count = f._pointCount - 1; lIndex++; while (count-- > 0) { pLinarr[pLin++] = (uint)(lIndex - 1); pLinarr[pLin++] = lIndex++; } } break; case PrimitiveType.lines: foreach (PrimitiveFace f in prim._faces) { count = f._pointCount * 2; while (count-- > 0) pLinarr[pLin++] = lIndex++; } break; } } return manager; }
private static PrimitiveManager DecodePrimitivesWeighted( Matrix bindMatrix, GeometryEntry geo, SkinEntry skin, SceneEntry scene, InfluenceManager infManager, Type boneType) { PrimitiveManager manager = DecodePrimitives(geo); IBoneNode[] boneList; IBoneNode bone = null; int boneCount; string[] jointStringArray = null; string jointString = null; byte * pCmd = stackalloc byte[4]; int cmdCount = skin._weightInputs.Count; float weight = 0; float * pWeights = null; Vector3 * pVert = null, pNorms = null; ushort * pVInd = (ushort *)manager._indices.Address; List <Vertex3> vertList = new List <Vertex3>(skin._weightCount); Matrix * pMatrix = null; UnsafeBuffer remap = new UnsafeBuffer(skin._weightCount * 2); ushort * pRemap = (ushort *)remap.Address; if (manager._faceData[1] != null) { pNorms = (Vector3 *)manager._faceData[1].Address; } manager._vertices = vertList; //Find vertex source foreach (SourceEntry s in geo._sources) { if (s._id == geo._verticesInput._source) { pVert = (Vector3 *)((UnsafeBuffer)s._arrayData).Address; break; } } //Find joint source foreach (InputEntry inp in skin._jointInputs) { if (inp._semantic == SemanticType.JOINT) { foreach (SourceEntry src in skin._sources) { if (src._id == inp._source) { jointStringArray = src._arrayData as string[]; jointString = src._arrayDataString; break; } } } else if (inp._semantic == SemanticType.INV_BIND_MATRIX) { foreach (SourceEntry src in skin._sources) { if (src._id == inp._source) { pMatrix = (Matrix *)((UnsafeBuffer)src._arrayData).Address; break; } } } } Error = "There was a problem creating the list of bones for geometry entry " + geo._name; //Populate bone list boneCount = jointStringArray.Length; boneList = new IBoneNode[boneCount]; for (int i = 0; i < boneCount; i++) { NodeEntry entry = scene.FindNode(jointStringArray[i]); if (entry != null && entry._node != null) { boneList[i] = entry._node as IBoneNode; } else { //Search in reverse! foreach (NodeEntry node in scene._nodes) { if ((entry = RecursiveTestNode(jointString, node)) != null) { if (entry._node != null) { boneList[i] = entry._node as IBoneNode; } break; } } //Couldn't find the bone if (boneList[i] == null) { boneList[i] = Activator.CreateInstance(boneType) as IBoneNode; } } } //Build command list foreach (InputEntry inp in skin._weightInputs) { switch (inp._semantic) { case SemanticType.JOINT: pCmd[inp._offset] = 1; break; case SemanticType.WEIGHT: pCmd[inp._offset] = 2; //Get weight source foreach (SourceEntry src in skin._sources) { if (src._id == inp._source) { pWeights = (float *)((UnsafeBuffer)src._arrayData).Address; break; } } break; default: pCmd[inp._offset] = 0; break; } } Error = "There was a problem creating vertex influences for geometry entry " + geo._name; //Build vertex list and remap table for (int i = 0; i < skin._weightCount; i++) { //Create influence int iCount = skin._weights[i].Length / cmdCount; Influence inf = new Influence(); fixed(int *p = skin._weights[i]) { int *iPtr = p; for (int x = 0; x < iCount; x++) { for (int z = 0; z < cmdCount; z++, iPtr++) { if (pCmd[z] == 1) { bone = boneList[*iPtr]; } else if (pCmd[z] == 2) { weight = pWeights[*iPtr]; } } inf.AddWeight(new BoneWeight(bone, weight)); } } inf.CalcMatrix(); Error = "There was a problem creating a vertex from the geometry entry " + geo._name + ".\nMake sure that all the vertices are weighted properly."; Vector3 worldPos = bindMatrix * skin._bindMatrix * pVert[i]; Vertex3 v; if (inf.Weights.Count > 1) { //Match with manager inf = infManager.FindOrCreate(inf); v = new Vertex3(worldPos, inf); //World position } else { bone = inf.Weights[0].Bone; v = new Vertex3(bone.InverseBindMatrix * worldPos, bone); //Local position } ushort index = 0; while (index < vertList.Count) { if (v.Equals(vertList[index])) { break; } index++; } if (index == vertList.Count) { vertList.Add(v); } pRemap[i] = index; } Error = "There was a problem fixing normal rotations for geometry entry " + geo._name; //Remap vertex indices and fix normals for (int i = 0; i < manager._pointCount; i++, pVInd++) { *pVInd = pRemap[*pVInd]; if (pNorms != null) { Vertex3 v = null; if (*pVInd < vertList.Count) { v = vertList[*pVInd]; } if (v != null && v.MatrixNode != null) { if (v.MatrixNode.Weights.Count > 1) { pNorms[i] = (bindMatrix * skin._bindMatrix).GetRotationMatrix() * pNorms[i]; } else { pNorms[i] = (v.MatrixNode.Weights[0].Bone.InverseBindMatrix * bindMatrix * skin._bindMatrix).GetRotationMatrix() * pNorms[i]; } } } } remap.Dispose(); return(manager); }
private static void WriteUVs(string name, PrimitiveManager p, int set, XmlWriter writer) { bool first = true; _uvs[set] = p.GetUVs(set, true); int count = _uvs[set].Length; _uvRemap[set] = new List<int>(); Vector2* ptr = (Vector2*)p._faceData[set + 4].Address; for (int i = 0; i < p._pointCount; i++) _uvRemap[set].Add(Array.IndexOf(_uvs[set], ptr[i])); //Position source writer.WriteStartElement("source"); writer.WriteAttributeString("id", name + "_UVs" + set.ToString()); //Array start writer.WriteStartElement("float_array"); writer.WriteAttributeString("id", name + "_UVArr" + set.ToString()); writer.WriteAttributeString("count", (count * 2).ToString()); for (int i = 0; i < count; i++) { if (first) first = false; else writer.WriteString(" "); //Reverse T component to a top-down form //writer.WriteString(String.Format("{0} {1}", pData->_x, 1.0 - pData->_y)); //pData++; writer.WriteString(String.Format("{0} {1}", _uvs[set][i]._x.ToString(CultureInfo.InvariantCulture.NumberFormat), (1.0f - _uvs[set][i]._y).ToString(CultureInfo.InvariantCulture.NumberFormat))); } writer.WriteEndElement(); //int_array //Technique writer.WriteStartElement("technique_common"); writer.WriteStartElement("accessor"); writer.WriteAttributeString("source", "#" + name + "_UVArr" + set.ToString()); writer.WriteAttributeString("count", count.ToString()); writer.WriteAttributeString("stride", "2"); writer.WriteStartElement("param"); writer.WriteAttributeString("name", "S"); writer.WriteAttributeString("type", "float"); writer.WriteEndElement(); //param writer.WriteStartElement("param"); writer.WriteAttributeString("name", "T"); writer.WriteAttributeString("type", "float"); writer.WriteEndElement(); //param writer.WriteEndElement(); //accessor writer.WriteEndElement(); //technique_common writer.WriteEndElement(); //source }
private static void WriteNormals(string name, XmlWriter writer, PrimitiveManager p) { bool first = true; ushort* pIndex = (ushort*)p._indices.Address; Vector3* pData = (Vector3*)p._faceData[1].Address; Vector3 v; HashSet<Vector3> list = new HashSet<Vector3>(); for (int i = 0; i < p._pointCount; i++) list.Add(p._vertices[pIndex[i]].GetMatrix().GetRotationMatrix() * pData[i]); _normals = new Vector3[list.Count]; list.CopyTo(_normals); int count = _normals.Length; _normRemap = new List<int>(); for (int i = 0; i < p._pointCount; i++) _normRemap.Add(Array.IndexOf(_normals, p._vertices[pIndex[i]].GetMatrix().GetRotationMatrix() * pData[i])); //Position source writer.WriteStartElement("source"); writer.WriteAttributeString("id", name + "_Normals"); //Array start writer.WriteStartElement("float_array"); writer.WriteAttributeString("id", name + "_NormArr"); writer.WriteAttributeString("count", (count * 3).ToString()); for (int i = 0; i < count; i++) { if (first) first = false; else writer.WriteString(" "); v = _normals[i]; writer.WriteString(String.Format("{0} {1} {2}", v._x.ToString(CultureInfo.InvariantCulture.NumberFormat), v._y.ToString(CultureInfo.InvariantCulture.NumberFormat), v._z.ToString(CultureInfo.InvariantCulture.NumberFormat))); } writer.WriteEndElement(); //float_array //Technique writer.WriteStartElement("technique_common"); writer.WriteStartElement("accessor"); writer.WriteAttributeString("source", "#" + name + "_NormArr"); writer.WriteAttributeString("count", 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 }
static PrimitiveManager DecodePrimitivesWeighted(GeometryEntry geo, SkinEntry skin, SceneEntry scene, InfluenceManager infManager) { PrimitiveManager manager = DecodePrimitives(geo); MDL0BoneNode[] boneList; MDL0BoneNode bone = null; int boneCount; string[] jointStrings = null; byte * pCmd = stackalloc byte[4]; int cmdCount = skin._weightInputs.Count; float weight = 0; float * pWeights = null; Vector3 * pVert = null; ushort * pVInd = (ushort *)manager._faceData[0].Address; List <Vertex3> vertList = new List <Vertex3>(skin._weightCount); Matrix * pMatrix = null; UnsafeBuffer remap = new UnsafeBuffer(skin._weightCount * 2); ushort * pRemap = (ushort *)remap.Address; manager._vertices = vertList; //Find vertex source foreach (SourceEntry s in geo._sources) { if (s._id == geo._verticesInput._source) { pVert = (Vector3 *)((UnsafeBuffer)s._arrayData).Address; break; } } //Find joint source foreach (InputEntry inp in skin._jointInputs) { if (inp._semantic == SemanticType.JOINT) { foreach (SourceEntry src in skin._sources) { if (src._id == inp._source) { jointStrings = src._arrayData as string[]; break; } } } else if (inp._semantic == SemanticType.INV_BIND_MATRIX) { foreach (SourceEntry src in skin._sources) { if (src._id == inp._source) { pMatrix = (Matrix *)((UnsafeBuffer)src._arrayData).Address; break; } } } } //Populate bone list boneCount = jointStrings.Length; boneList = new MDL0BoneNode[boneCount]; for (int i = 0; i < boneCount; i++) { boneList[i] = scene.FindNode(jointStrings[i])._node as MDL0BoneNode; } //Build command list foreach (InputEntry inp in skin._weightInputs) { switch (inp._semantic) { case SemanticType.JOINT: pCmd[inp._offset] = 1; break; case SemanticType.WEIGHT: pCmd[inp._offset] = 2; //Get weight source foreach (SourceEntry src in skin._sources) { if (src._id == inp._source) { pWeights = (float *)((UnsafeBuffer)src._arrayData).Address; break; } } break; default: pCmd[inp._offset] = 0; break; } } //Build vertex list and remap table for (int i = 0; i < skin._weightCount; i++) { //Create influence int iCount = skin._weights[i].Length / cmdCount; Influence inf = new Influence(iCount); fixed(int *p = skin._weights[i]) { int *iPtr = p; for (int x = 0; x < iCount; x++) { for (int z = 0; z < cmdCount; z++, iPtr++) { if (pCmd[z] == 1) { bone = boneList[*iPtr]; } else if (pCmd[z] == 2) { weight = pWeights[*iPtr]; } } inf._weights[x] = new BoneWeight(bone, weight); } } Vertex3 v; if (inf._weights.Length > 1) { //Match with manager inf = infManager.AddOrCreate(inf); v = new Vertex3(skin._bindMatrix * pVert[i], inf); //World position } else { bone = inf._weights[0].Bone; v = new Vertex3(bone._inverseBindMatrix * skin._bindMatrix * pVert[i], bone); //Local position } //Create Vertex, set to world position. //Vertex3 v = new Vertex3(skin._bindMatrix * pVert[i], inf); //Fix single-bind vertices //if (inf._weights.Length == 1) // v.Position = inf._weights[0].Bone._inverseBindMatrix * v.Position; ushort index = 0; while (index < vertList.Count) { if (v.Equals(vertList[index])) { break; } index++; } if (index == vertList.Count) { vertList.Add(v); } pRemap[i] = index; } //Remap vertex indices for (int i = 0; i < manager._pointCount; i++, pVInd++) { *pVInd = pRemap[*pVInd]; } remap.Dispose(); return(manager); }
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 static void WriteTriFan(StreamWriter writer, Primitive p) //{ // if ((p._vertexIndices == null) || (p._normalIndices == null)) // return; // writer.WriteLine(); // writer.WriteLine("#Trifan"); // int count = p._elementCount - 2; // if (p._uvIndices[0] != null) // for (int i = 0; i < count; i++) // writer.WriteLine(String.Format("f {0}/{1}/{2} {3}/{4}/{5} {6}/{7}/{8}", // p._vertexIndices[0] + 1, p._uvIndices[0][0] + 1, p._normalIndices[0] + 1, // p._vertexIndices[i + 1] + 1, p._uvIndices[0][i + 1] + 1, p._normalIndices[i + 1] + 1, // p._vertexIndices[i + 2] + 1, p._uvIndices[0][i + 2] + 1, p._normalIndices[i + 2] + 1)); // else // for (int i = 0; i < count; i++) // writer.WriteLine(String.Format("f {0}//{1} {2}//{3} {4}//{5}", // p._vertexIndices[0] + 1, p._normalIndices[0] + 1, // p._vertexIndices[i + 1] + 1, p._normalIndices[i + 1] + 1, // p._vertexIndices[i + 2] + 1, p._normalIndices[i + 2] + 1)); //} //private static void WriteTriStrip(StreamWriter writer, Primitive p) //{ // if ((p._vertexIndices == null) || (p._normalIndices == null)) // return; // writer.WriteLine(); // writer.WriteLine("#Tristrip"); // int count = p._elementCount - 2; // int l1 = 0, l2 = 2; // if (p._uvIndices[0] != null) // for (int i = 0; i < count; i++) // { // if ((i & 1) == 0) // { // l1 = i; // l2 = i + 1; // } // else // { // l1 = i + 1; // l2 = i; // } // writer.WriteLine(String.Format("f {0}/{1}/{2} {3}/{4}/{5} {6}/{7}/{8}", // p._vertexIndices[l1] + 1, p._uvIndices[0][l1] + 1, p._normalIndices[l1] + 1, // p._vertexIndices[l2] + 1, p._uvIndices[0][l2] + 1, p._normalIndices[l2] + 1, // p._vertexIndices[i + 2] + 1, p._uvIndices[0][i + 2] + 1, p._normalIndices[i + 2] + 1)); // } // else // for (int i = 0; i < count; i++) // { // if ((i & 1) == 0) // { // l1 = i; // l2 = i + 1; // } // else // { // l1 = i + 1; // l2 = i; // } // writer.WriteLine(String.Format("f {0}//{1} {2}//{3} {4}//{5}", // p._vertexIndices[l1] + 1, p._normalIndices[l1] + 1, // p._vertexIndices[l2] + 1, p._normalIndices[l2] + 1, // p._vertexIndices[i + 2] + 1, p._normalIndices[i + 2] + 1)); // } //} //private static void WriteTriList(StreamWriter writer, Primitive p) //{ // if ((p._vertexIndices == null) || (p._normalIndices == null)) // return; // writer.WriteLine(); // writer.WriteLine("#Trilist"); // int count = p._elementCount / 3; // if (p._uvIndices[0] != null) // for (int i = 0, x = 0; i < count; i++, x += 3) // writer.WriteLine(String.Format("f {0}/{1}/{2} {3}/{4}/{5} {6}/{7}/{8}", // p._vertexIndices[x] + 1, p._uvIndices[0][x] + 1, p._normalIndices[x] + 1, // p._vertexIndices[x + 1] + 1, p._uvIndices[0][x + 1] + 1, p._normalIndices[x + 1] + 1, // p._vertexIndices[x + 2] + 1, p._uvIndices[0][x + 2] + 1, p._normalIndices[x + 2] + 1)); // else // for (int i = 0, x = 0; i < count; i++, x += 3) // writer.WriteLine(String.Format("f {0}//{1} {2}//{3} {4}//{5}", // p._vertexIndices[x] + 1, p._normalIndices[x] + 1, // p._vertexIndices[x + 1] + 1, p._normalIndices[x + 1] + 1, // p._vertexIndices[x + 2] + 1, p._normalIndices[x + 2] + 1)); //} private static unsafe void WriteTriList(StreamWriter writer, PrimitiveManager p) { uint[] pData = p._triangles._indices; uint x = 0; ushort* pVert = (ushort*)p._indices.Address; bool hasUVs = p._faceData[4] != null; bool hasNorms = p._faceData[1] != null; writer.WriteLine(); writer.WriteLine("#Trilist"); int count = p._triangles._elementCount / 3; //Loop through triangles for (int tri = 0; tri < count; tri++) { //writer.WriteLine("s " + i); //Smoothing groups don't seem to do anything writer.Write("f "); //Face //Loop through triangle points for (int pt = 0; pt < 3; pt++) { uint index = pData[x++]; //Loop through vertices, uvs, normals for (int asset = 0; asset < 3; asset++) { if (asset != 0) //Not a point start writer.Write("/"); //Asset divider //If no UVs, there's a double slash if (!hasUVs && asset == 1) continue; if (asset == 0) //Vertex index writer.Write((pVert[index] + 1).ToString()); else writer.Write((index + 1).ToString()); if (asset == 2) //Point is done if (pt == 2) //Last point writer.WriteLine(); else //Still more points to go writer.Write(" "); } } } }
static void Weight(PrimitiveManager manager, SkinEntry skin, DecoderShell shell, GeometryEntry geo, InfluenceManager iMan) { MDL0BoneNode[] boneList; MDL0BoneNode bone = null; int boneCount; string[] jointStrings = null; byte * pCmd = stackalloc byte[4]; int cmdCount = skin._weightInputs.Count; float weight = 0; float * pWeights = null; Vector3 * pVert = null; ushort * pVInd = (ushort *)manager._indices.Address; List <Vertex3> vertList = new List <Vertex3>(skin._weightCount); manager._vertices = vertList; //Find vertex source foreach (SourceEntry s in geo._sources) { if (s._id == geo._verticesInput._source) { pVert = (Vector3 *)((UnsafeBuffer)s._arrayData).Address; break; } } //Find joint source foreach (InputEntry inp in skin._jointInputs) { if (inp._semantic == SemanticType.JOINT) { foreach (SourceEntry src in skin._sources) { if (src._id == inp._source) { jointStrings = src._arrayData as string[]; break; } } break; } } //Populate bone list boneCount = jointStrings.Length; boneList = new MDL0BoneNode[boneCount]; for (int i = 0; i < boneCount; i++) { boneList[i] = shell.FindNode(jointStrings[i])._node as MDL0BoneNode; } //Build command list foreach (InputEntry inp in skin._weightInputs) { switch (inp._semantic) { case SemanticType.JOINT: pCmd[inp._offset] = 1; break; case SemanticType.WEIGHT: pCmd[inp._offset] = 2; //Get weight source foreach (SourceEntry src in skin._sources) { if (src._id == inp._source) { pWeights = (float *)((UnsafeBuffer)src._arrayData).Address; break; } } break; default: pCmd[inp._offset] = 0; break; } } //Construct Vertex from new weight for (int i = 0; i < skin._weightCount; i++) { //Create influence int iCount = skin._weights.Length / cmdCount; Influence inf = new Influence(iCount); fixed(int *p = skin._weights[i]) { int *iPtr = p; for (int x = 0; x < iCount; x++) { for (int z = 0; z < cmdCount; z++, iPtr++) { if (pCmd[z] == 1) { bone = boneList[*iPtr]; } else if (pCmd[z] == 2) { weight = pWeights[*iPtr]; } } inf._weights[x] = new BoneWeight(bone, weight); } } //Match with manager inf = iMan.AddOrCreateInf(inf); //Create Vertex and look for match Vertex3 v = new Vertex3(pVert[*pVInd], inf); int index = 0; while (index < vertList.Count) { if (v.Equals(vertList[i])) { break; } index++; } if (index == vertList.Count) { vertList.Add(v); } //Assign new index *pVInd++ = (ushort)index; } }
private static PrimitiveManager DecodePrimitives(GeometryEntry geo) { uint[] pTriarr = null, pLinarr = null; uint pTri = 0, pLin = 0; long * pInDataList = stackalloc long[12]; long * pOutDataList = stackalloc long[12]; int * pData = stackalloc int[16]; int faces = 0, lines = 0, points = 0; uint fIndex = 0, lIndex = 0, temp; PrimitiveDecodeCommand *pCmd = (PrimitiveDecodeCommand *)pData; byte **pInData = (byte **)pInDataList; byte **pOutData = (byte **)pOutDataList; PrimitiveManager manager = new PrimitiveManager(); //Assign vertex source foreach (SourceEntry s in geo._sources) { if (s._id == geo._verticesInput._source) { pInData[0] = (byte *)((UnsafeBuffer)s._arrayData).Address; break; } } foreach (PrimitiveEntry prim in geo._primitives) { //Get face/line count if (prim._type == ColladaPrimitiveType.lines || prim._type == ColladaPrimitiveType.linestrips) { lines += prim._faceCount; } else { faces += prim._faceCount; } //Get point total points += prim._pointCount; //Signal storage buffers and set type offsets foreach (InputEntry inp in prim._inputs) { int offset = -1; switch (inp._semantic) { case SemanticType.VERTEX: offset = 0; break; case SemanticType.NORMAL: offset = 1; break; case SemanticType.COLOR: if (inp._set < 2) { offset = 2 + inp._set; } break; case SemanticType.TEXCOORD: if (inp._set < 8) { offset = 4 + inp._set; } break; } if (offset != -1) { manager._dirty[offset] = true; } inp._outputOffset = offset; } } manager._pointCount = points; //Create primitives if (faces > 0) { manager._triangles = new GLPrimitive(faces * 3, OpenTK.Graphics.OpenGL.PrimitiveType.Triangles); pTriarr = manager._triangles._indices; } if (lines > 0) { manager._lines = new GLPrimitive(lines * 2, OpenTK.Graphics.OpenGL.PrimitiveType.Lines); pLinarr = manager._lines._indices; } manager._indices = new UnsafeBuffer(points * 2); //Create face buffers and assign output pointers for (int i = 0; i < 12; i++) { if (manager._dirty[i]) { int stride; if (i == 0) { stride = 2; } else if (i == 1) { stride = 12; } else if (i < 4) { stride = 4; } else { stride = 8; } manager._faceData[i] = new UnsafeBuffer(points * stride); if (i == 0) { pOutData[i] = (byte *)manager._indices.Address; } else { pOutData[i] = (byte *)manager._faceData[i].Address; } } } //Decode primitives foreach (PrimitiveEntry prim in geo._primitives) { int count = prim._inputs.Count; //Map inputs to command sequence foreach (InputEntry inp in prim._inputs) { if (inp._outputOffset == -1) { pCmd[inp._offset].Cmd = 0; } else { pCmd[inp._offset].Cmd = (byte)inp._semantic; pCmd[inp._offset].Index = (byte)inp._outputOffset; //Assign input buffer foreach (SourceEntry src in geo._sources) { if (src._id == inp._source) { pInData[inp._outputOffset] = (byte *)((UnsafeBuffer)src._arrayData).Address; break; } } } } //Decode face data using command list foreach (PrimitiveFace f in prim._faces) { fixed(ushort *p = f._pointIndices) { RunPrimitiveCmd(pInData, pOutData, pCmd, count, p, f._pointCount); } } //Process point indices switch (prim._type) { case ColladaPrimitiveType.triangles: count = prim._faceCount * 3; while (count-- > 0) { pTriarr[pTri++] = fIndex++; } break; case ColladaPrimitiveType.trifans: case ColladaPrimitiveType.polygons: case ColladaPrimitiveType.polylist: foreach (PrimitiveFace f in prim._faces) { count = f._pointCount - 2; temp = fIndex; fIndex += 2; while (count-- > 0) { pTriarr[pTri++] = temp; pTriarr[pTri++] = fIndex - 1; pTriarr[pTri++] = fIndex++; } } break; case ColladaPrimitiveType.tristrips: foreach (PrimitiveFace f in prim._faces) { count = f._pointCount; fIndex += 2; for (int i = 2; i < count; i++) { if ((i & 1) == 0) { pTriarr[pTri++] = fIndex - 2; pTriarr[pTri++] = fIndex - 1; pTriarr[pTri++] = fIndex++; } else { pTriarr[pTri++] = fIndex - 2; pTriarr[pTri++] = fIndex; pTriarr[pTri++] = fIndex++ - 1; } } } break; case ColladaPrimitiveType.linestrips: foreach (PrimitiveFace f in prim._faces) { count = f._pointCount - 1; lIndex++; while (count-- > 0) { pLinarr[pLin++] = lIndex - 1; pLinarr[pLin++] = lIndex++; } } break; case ColladaPrimitiveType.lines: foreach (PrimitiveFace f in prim._faces) { count = f._pointCount; while (count-- > 0) { pLinarr[pLin++] = lIndex++; } } break; } } return(manager); }
private static void WriteColors(string name, PrimitiveManager p, int set, XmlWriter writer) { bool first = true; _colors[set] = p.GetColors(set, true); int count = _colors[set].Length; _colorRemap[set] = new List<int>(); RGBAPixel* ptr = (RGBAPixel*)p._faceData[set + 2].Address; for (int i = 0; i < p._pointCount; i++) _colorRemap[set].Add(Array.IndexOf(_colors[set], ptr[i])); //Position source writer.WriteStartElement("source"); writer.WriteAttributeString("id", name + "_Colors" + set.ToString()); //Array start writer.WriteStartElement("float_array"); writer.WriteAttributeString("id", name + "_ColorArr" + set.ToString()); writer.WriteAttributeString("count", (count * 4).ToString()); for (int i = 0; i < count; i++) { if (first) first = false; else writer.WriteString(" "); RGBAPixel r = _colors[set][i]; writer.WriteString(String.Format("{0} {1} {2} {3}", r.R * cFactor, r.G * cFactor, r.B * cFactor, r.A * cFactor)); } writer.WriteEndElement(); //int_array //Technique writer.WriteStartElement("technique_common"); writer.WriteStartElement("accessor"); writer.WriteAttributeString("source", "#" + name + "_ColorArr" + set.ToString()); writer.WriteAttributeString("count", count.ToString()); writer.WriteAttributeString("stride", "4"); writer.WriteStartElement("param"); writer.WriteAttributeString("name", "R"); writer.WriteAttributeString("type", "float"); writer.WriteEndElement(); //param writer.WriteStartElement("param"); writer.WriteAttributeString("name", "G"); writer.WriteAttributeString("type", "float"); writer.WriteEndElement(); //param writer.WriteStartElement("param"); writer.WriteAttributeString("name", "B"); writer.WriteAttributeString("type", "float"); writer.WriteEndElement(); //param writer.WriteStartElement("param"); writer.WriteAttributeString("name", "A"); writer.WriteAttributeString("type", "float"); writer.WriteEndElement(); //param writer.WriteEndElement(); //accessor writer.WriteEndElement(); //technique_common writer.WriteEndElement(); //source }
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); }
private static unsafe void WriteGeometry(MDL0Node model, XmlWriter writer, bool weightNorms) { ResourceNode grp = model._polyGroup; if (grp == null) { return; } writer.WriteStartElement("library_geometries"); foreach (MDL0PolygonNode 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, 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, (Vector3 *)manager._faceData[i].Address, manager._pointCount, writer, weightNorms, manager); break; case 2: case 3: WriteColors(poly._name, (RGBAPixel *)manager._faceData[i].Address, manager._pointCount, i - 2, writer); break; default: WriteUVs(poly._name, (Vector2 *)manager._faceData[i].Address, manager._pointCount, 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); } //Write primitives //WritePrimitiveType(poly, GLPrimitiveType.Lines, writer); //WritePrimitiveType(poly, GLPrimitiveType.LineStrip, writer); //WritePrimitiveType(poly, GLPrimitiveType.Triangles, writer); //WritePrimitiveType(poly, GLPrimitiveType.TriangleFan, writer); //WritePrimitiveType(poly, GLPrimitiveType.TriangleStrip, writer); writer.WriteEndElement(); //mesh writer.WriteEndElement(); //geometry } writer.WriteEndElement(); }
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 } } } }
private static void WriteNormals(string name, Vector3 *pData, int count, XmlWriter writer, bool weight, PrimitiveManager p) { bool first = true; ushort *pIndex = (ushort *)p._indices.Address; Vector3 v; //Position source writer.WriteStartElement("source"); writer.WriteAttributeString("id", name + "_Normals"); //Array start writer.WriteStartElement("float_array"); writer.WriteAttributeString("id", name + "_NormArr"); writer.WriteAttributeString("count", (count * 3).ToString()); for (int i = 0; i < count; i++) { if (first) { first = false; } else { writer.WriteString(" "); } if (weight && p._vertices[*pIndex]._influence != null) { v = p._vertices[*pIndex++]._influence.Matrix.GetRotationMatrix() * *pData++; } else { v = *pData++; } writer.WriteString(String.Format("{0} {1} {2}", v._x, v._y, v._z)); } writer.WriteEndElement(); //float_array //Technique writer.WriteStartElement("technique_common"); writer.WriteStartElement("accessor"); writer.WriteAttributeString("source", "#" + name + "_NormArr"); writer.WriteAttributeString("count", 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 }
private static unsafe void WritePrimitive(MDL0PolygonNode poly, NewPrimitive prim, XmlWriter writer) { PrimitiveManager manager = poly._manager; int count; int elements = 0, stride = 0; int set; bool first; ushort *pData = (ushort *)prim._indices.Address; ushort *pVert = (ushort *)poly._manager._indices.Address; switch (prim._type) { case GLPrimitiveType.Triangles: writer.WriteStartElement("triangles"); stride = 3; break; case GLPrimitiveType.Lines: writer.WriteStartElement("lines"); stride = 2; break; case GLPrimitiveType.Points: writer.WriteStartElement("points"); stride = 1; break; } count = prim._elementCount / stride; if (poly._material != null) { writer.WriteAttributeString("material", poly._material.Name); } writer.WriteAttributeString("count", count.ToString()); for (int i = 0; i < 12; i++) { if (manager._faceData[i] == null) { continue; } writer.WriteStartElement("input"); switch (i) { case 0: writer.WriteAttributeString("semantic", "VERTEX"); writer.WriteAttributeString("source", "#" + poly._name + "_Vertices"); break; case 1: writer.WriteAttributeString("semantic", "NORMAL"); writer.WriteAttributeString("source", "#" + poly._name + "_Normals"); break; case 2: case 3: set = i - 2; writer.WriteAttributeString("semantic", "COLOR"); writer.WriteAttributeString("source", "#" + poly._name + "_Colors" + set.ToString()); writer.WriteAttributeString("set", set.ToString()); break; default: set = i - 4; writer.WriteAttributeString("semantic", "TEXCOORD"); writer.WriteAttributeString("source", "#" + poly._name + "_UVs" + set.ToString()); writer.WriteAttributeString("set", set.ToString()); break; } writer.WriteAttributeString("offset", elements.ToString()); writer.WriteEndElement(); //input elements++; } for (int i = 0; i < count; i++) { writer.WriteStartElement("p"); first = true; for (int x = 0; x < stride; x++) { int index = *pData++; for (int y = 0; y < elements; y++) { if (first) { first = false; } else { writer.WriteString(" "); } if (y == 0) { writer.WriteString(pVert[index].ToString()); } else { writer.WriteString(index.ToString()); } } } writer.WriteEndElement(); //p } writer.WriteEndElement(); //primitive }
public override bool OnInitialize() { MDL0Object* header = Header; _nodeId = header->_nodeId; SetSizeInternal(_totalLength = header->_totalLength); _mdl0Offset = header->_mdl0Offset; _stringOffset = header->_stringOffset; ModelLinker linker = Model._linker; MatrixNode = (_nodeId >= 0 && _nodeId < Model._linker.NodeCache.Length) ? Model._linker.NodeCache[_nodeId] : null; _vertexFormat = header->_vertexFormat; _vertexSpecs = header->_vertexSpecs; _arrayFlags = header->_arrayFlags; HasPosMatrix = _arrayFlags.HasPosMatrix; for (int i = 0; i < 8; i++) HasTextureMatrix[i] = _arrayFlags.GetHasTexMatrix(i); _numFacepoints = header->_numVertices; _numFaces = header->_numFaces; _flag = header->_flag; _primBufferSize = header->_primitives._bufferSize; _primSize = header->_primitives._size; _primOffset = header->_primitives._offset; _defBufferSize = header->_defintions._bufferSize; _defSize = header->_defintions._size; _defOffset = header->_defintions._offset; _entryIndex = header->_index; //Conditional name assignment if ((_name == null) && (header->_stringOffset != 0)) if (!_replaced) _name = header->ResourceString; else _name = "polygon" + Index; //Link nodes if (header->_vertexId >= 0 && Model._vertList != null) foreach (MDL0VertexNode v in Model._vertList) if (header->_vertexId == v.ID) { (_vertexNode = v)._objects.Add(this); break; } if (header->_normalId >= 0 && Model._normList != null) foreach (MDL0NormalNode n in Model._normList) if (header->_normalId == n.ID) { (_normalNode = n)._objects.Add(this); break; } int id; for (int i = 0; i < 2; i++) if ((id = ((bshort*)header->_colorIds)[i]) >= 0 && Model._colorList != null) foreach (MDL0ColorNode c in Model._colorList) if (id == c.ID) { (_colorSet[i] = c)._objects.Add(this); break; } for (int i = 0; i < 8; i++) if ((id = ((bshort*)header->_uids)[i]) >= 0 && Model._uvList != null) foreach (MDL0UVNode u in Model._uvList) if (id == u.ID) { (_uvSet[i] = u)._objects.Add(this); break; } if (Model._version > 9) { if (header->_furVectorId >= 0) foreach (MDL0FurVecNode v in Model._furVecList) if (header->_furVectorId == v.ID) { (_furVecNode = v)._objects.Add(this); break; } if (header->_furLayerCoordId >= 0) foreach (MDL0FurPosNode n in Model._furPosList) if (header->_furLayerCoordId == n.ID) { (_furPosNode = n)._objects.Add(this); break; } } //Link element indices for rebuild _elementIndices[0] = (short)(_vertexNode != null ? _vertexNode.Index : -1); _elementIndices[1] = (short)(_normalNode != null ? _normalNode.Index : -1); for (int i = 2; i < 4; i++) _elementIndices[i] = (short)(_colorSet[i - 2] != null ? _colorSet[i - 2].Index : -1); for (int i = 4; i < 12; i++) _elementIndices[i] = (short)(_uvSet[i - 4] != null ? _uvSet[i - 4].Index : -1); _elementIndices[12] = (short)(_furVecNode != null ? _furVecNode.Index : -1); _elementIndices[13] = (short)(_furPosNode != null ? _furPosNode.Index : -1); //Create primitive manager if (_parent != null) { int i = 0; _manager = new PrimitiveManager(header, Model._assets, linker.NodeCache, this); if (_manager._vertices != null) foreach (Vertex3 v in _manager._vertices) { v._index = i++; v._object = this; } } //Get polygon UVAT groups MDL0PolygonDefs* Defs = (MDL0PolygonDefs*)header->DefList; UVATGroups = new CPElementSpec( (uint)Defs->UVATA, (uint)Defs->UVATB, (uint)Defs->UVATC); //Read internal object node cache and read influence list if (Model._linker.NodeCache != null) { if (_matrixNode == null) { _influences = new List<IMatrixNode>(); bushort* weights = header->WeightIndices(Model._version); int count = *(bint*)weights; weights += 2; for (int i = 0; i < count; i++) if (*weights < Model._linker.NodeCache.Length) _influences.Add(Model._linker.NodeCache[*weights++]); else weights++; } } //Check for errors if (header->_totalLength % 0x20 != 0) { Model._errors.Add("Object " + Index + " has an improper data length."); SignalPropertyChange(); _rebuild = true; } if ((int)(0x24 + header->_primitives._offset) % 0x20 != 0) { Model._errors.Add("Object " + Index + " has an improper primitives start offset."); SignalPropertyChange(); _rebuild = true; } if (CheckVertexFormat()) { Model._errors.Add("Object " + Index + " has a facepoint descriptor that does not match its linked nodes."); SignalPropertyChange(); _rebuild = true; for (int i = 0; i < 2; i++) if (_colorSet[i] != null && _manager._faceData[i + 2] == null) { _manager._faceData[i + 2] = new UnsafeBuffer(_manager._pointCount * 4); _colorChanged[i] = true; } } if (HasTexMtx && !Weighted) { Model._errors.Add("Object " + Index + " has texture matrices but is not weighted."); for (int i = 0; i < 8; i++) HasTextureMatrix[i] = false; SignalPropertyChange(); _rebuild = true; } //if (!Weighted) //{ // bool notFloat = HasANonFloatAsset; // foreach (PrimitiveGroup p in _primGroups) // { // bool o = false; // foreach (PrimitiveHeader ph in p._headers) // if (ph.Type != WiiPrimitiveType.TriangleList && notFloat) // { // Model._errors.Add("Object " + Index + " will explode in-game due to assets that are not written as float."); // SignalPropertyChange(); // if (_vertexNode.Format != WiiVertexComponentType.Float) // _vertexNode._forceRebuild = _vertexNode._forceFloat = true; // if (_normalNode != null && _normalNode.Format != WiiVertexComponentType.Float) // _normalNode._forceRebuild = _normalNode._forceFloat = true; // for (int i = 4; i < 12; i++) // if (_uvSet[i - 4] != null && _uvSet[i - 4].Format != WiiVertexComponentType.Float) // _uvSet[i - 4]._forceRebuild = _uvSet[i - 4]._forceFloat = true; // o = true; // break; // } // if (o) // break; // } //} return false; }