public GX_Vertex this[int i] { get { switch (i) { case 0: return(_x); case 1: return(_y); case 2: return(_z); } return(new GX_Vertex()); } set { switch (i) { case 0: _x = value; break; case 1: _y = value; break; case 2: _z = value; break; } } }
public bool Contains(GX_Vertex f) { if (_x == f) { return(true); } if (_y == f) { return(true); } if (_z == f) { return(true); } return(false); }
/// <summary> /// /// </summary> /// <param name="PrimitiveGroup"></param> /// <param name="Attributes"></param> /// <returns></returns> private static GX_Vertex[] GetDecodedVertices(GX_PrimitiveGroup PrimitiveGroup, GX_Attribute[] Attributes) { // Create Vertex List List <GX_Vertex> Vertices = new List <GX_Vertex>(); // Decode foreach (GX_IndexGroup ig in PrimitiveGroup.Indices) { GX_Vertex Vertex = new GX_Vertex(); for (int i = 0; i < Attributes.Length; i++) { var attribute = Attributes[i]; int index = ig.Indices[i]; float[] f = new float[4]; if (attribute.AttributeType != GXAttribType.GX_DIRECT) { var values = attribute.GetDecodedDataAt(index); // convert to float f = new float[values.Length]; for (int j = 0; j < f.Length; j++) { f[j] = (float)values[j]; } } switch (attribute.AttributeName) { case GXAttribName.GX_VA_NULL: break; case GXAttribName.GX_VA_PNMTXIDX: if (attribute.AttributeType == GXAttribType.GX_DIRECT) { Vertex.PNMTXIDX = (ushort)index; } break; case GXAttribName.GX_VA_TEX0MTXIDX: if (attribute.AttributeType == GXAttribType.GX_DIRECT) { Vertex.TEX0MTXIDX = (ushort)index; } break; case GXAttribName.GX_VA_TEX1MTXIDX: if (attribute.AttributeType == GXAttribType.GX_DIRECT) { Vertex.TEX1MTXIDX = (ushort)index; } break; case GXAttribName.GX_VA_POS: if (attribute.AttributeType != GXAttribType.GX_DIRECT) { if (f.Length > 0) { Vertex.POS.X = f[0]; } if (f.Length > 1) { Vertex.POS.Y = f[1]; } if (f.Length > 2) { Vertex.POS.Z = f[2]; } } break; case GXAttribName.GX_VA_NRM: if (attribute.AttributeType != GXAttribType.GX_DIRECT) { Vertex.NRM.X = f[0]; Vertex.NRM.Y = f[1]; Vertex.NRM.Z = f[2]; } break; case GXAttribName.GX_VA_NBT: if (attribute.AttributeType != GXAttribType.GX_DIRECT) { Vertex.NRM.X = f[0]; Vertex.NRM.Y = f[1]; Vertex.NRM.Z = f[2]; Vertex.BITAN.X = f[3]; Vertex.BITAN.Y = f[4]; Vertex.BITAN.Z = f[5]; Vertex.TAN.X = f[6]; Vertex.TAN.Y = f[7]; Vertex.TAN.Z = f[8]; } break; case GXAttribName.GX_VA_TEX0: if (attribute.AttributeType != GXAttribType.GX_DIRECT) { Vertex.TEX0.X = f[0]; Vertex.TEX0.Y = f[1]; } break; case GXAttribName.GX_VA_TEX1: if (attribute.AttributeType != GXAttribType.GX_DIRECT) { Vertex.TEX1.X = f[0]; Vertex.TEX1.Y = f[1]; } break; case GXAttribName.GX_VA_CLR0: if (attribute.AttributeType == GXAttribType.GX_DIRECT) { Vertex.CLR0.R = ig.Clr0[0] / 255f; Vertex.CLR0.G = ig.Clr0[1] / 255f; Vertex.CLR0.B = ig.Clr0[2] / 255f; Vertex.CLR0.A = ig.Clr0[3] / 255f; } else { Vertex.CLR0.R = f[0]; Vertex.CLR0.G = f[1]; Vertex.CLR0.B = f[2]; Vertex.CLR0.A = f[3]; } break; case GXAttribName.GX_VA_CLR1: if (attribute.AttributeType == GXAttribType.GX_DIRECT) { Vertex.CLR1.R = ig.Clr1[0] / 255f; Vertex.CLR1.G = ig.Clr1[1] / 255f; Vertex.CLR1.B = ig.Clr1[2] / 255f; Vertex.CLR1.A = ig.Clr1[3] / 255f; } else { Vertex.CLR1.R = f[0]; Vertex.CLR1.G = f[1]; Vertex.CLR1.B = f[2]; Vertex.CLR1.A = f[3]; } break; default: Console.WriteLine("To be implemented: " + attribute.AttributeName); break; } } Vertices.Add(Vertex); } return(Vertices.ToArray()); }
/// <summary> /// /// </summary> /// <returns></returns> private void ProcessMesh(IOScene scene, IOMesh mesh, HSD_JOBJ rootnode) { HSD_JOBJ parent = rootnode; HashSet <HSD_JOBJ> nodes = new HashSet <HSD_JOBJ>(); foreach (var j in rootnode.BreathFirstList) { nodes.Add(j); } if (mesh.ParentBone != null && _cache.NameToJOBJ.ContainsKey(mesh.ParentBone.Name)) { parent = _cache.NameToJOBJ[mesh.ParentBone.Name]; } HSD_DOBJ root = null; HSD_DOBJ prev = null; //var skeleton = rootnode.BreathFirstList; Console.WriteLine("Processing " + mesh.Name); bool singleBinded = mesh.Name.Contains("SINGLE"); foreach (var poly in mesh.Polygons) { // Skip Empty Polygon if (poly.Indicies.Count == 0) { continue; } // convert to triangles poly.ToTriangles(mesh); if (poly.PrimitiveType != IOPrimitive.TRIANGLE) { continue; } // Generate DOBJ HSD_DOBJ dobj = new HSD_DOBJ(); if (Settings.ImportMeshNames) { dobj.ClassName = mesh.Name; } if (root == null) { root = dobj; } else { prev.Next = dobj; } prev = dobj; // generate material var material = scene.Materials.Find(e => e.Name == poly.MaterialName); dobj.Mobj = GenerateMaterial(material); Console.WriteLine(mesh.Name + " " + material?.Name); // reflective mobjs do not use uvs var hasReflection = false; // bump maps need tangents and bitangents var hasBump = false; // Assess needed attributes based on the material MOBJ if (mesh.Name.Contains("REFLECTIVE")) { hasReflection = true; } #if DEBUG if (Settings.MetalModel) { hasReflection = true; } #endif if (mesh.Name.Contains("BUMP")) { hasBump = true; } if (dobj.Mobj.Textures != null) { foreach (var t in dobj.Mobj.Textures.List) { if (t.Flags.HasFlag(TOBJ_FLAGS.COORD_REFLECTION)) { hasReflection = true; } if (t.Flags.HasFlag(TOBJ_FLAGS.BUMP)) { hasBump = true; } } } // assess attributes List <GXAttribName> Attributes = new List <GXAttribName>(); if (mesh.HasEnvelopes() && Settings.ImportRigging && !singleBinded) { Attributes.Add(GXAttribName.GX_VA_PNMTXIDX); if (hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX0MTXIDX); if (dobj.Mobj.Textures != null && dobj.Mobj.Textures.List.Count > 1) { Attributes.Add(GXAttribName.GX_VA_TEX1MTXIDX); } #if DEBUG if (Settings.MetalModel && !Attributes.Contains(GXAttribName.GX_VA_TEX1MTXIDX)) { Attributes.Add(GXAttribName.GX_VA_TEX1MTXIDX); } #endif } } Attributes.Add(GXAttribName.GX_VA_POS); if (hasBump) { Attributes.Add(GXAttribName.GX_VA_NBT); } else if (mesh.HasNormals && Settings.ImportNormals) { Attributes.Add(GXAttribName.GX_VA_NRM); } if (mesh.HasColorSet(0) && Settings.ImportVertexColor) { Attributes.Add(GXAttribName.GX_VA_CLR0); } if (mesh.HasColorSet(1) && Settings.ImportVertexColor) { Attributes.Add(GXAttribName.GX_VA_CLR1); } if (mesh.HasUVSet(0) && !hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX0); } if ((mesh.HasUVSet(1) || (dobj.Mobj.Textures != null && dobj.Mobj.Textures.List.Count > 1)) && !hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX1); } if ((mesh.HasUVSet(2) || (dobj.Mobj.Textures != null && dobj.Mobj.Textures.List.Count > 2)) && !hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX2); } if ((mesh.HasUVSet(3) || (dobj.Mobj.Textures != null && dobj.Mobj.Textures.List.Count > 3)) && !hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX3); } if ((mesh.HasUVSet(4) || (dobj.Mobj.Textures != null && dobj.Mobj.Textures.List.Count > 4)) && !hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX4); } if ((mesh.HasUVSet(5) || (dobj.Mobj.Textures != null && dobj.Mobj.Textures.List.Count > 5)) && !hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX5); } if ((mesh.HasUVSet(6) || (dobj.Mobj.Textures != null && dobj.Mobj.Textures.List.Count > 6)) && !hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX6); } if ((mesh.HasUVSet(7) || (dobj.Mobj.Textures != null && dobj.Mobj.Textures.List.Count > 7)) && !hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX7); } var vertices = new List <GX_Vertex>(); var jobjList = new List <HSD_JOBJ[]>(); var weightList = new List <float[]>(); foreach (var face in poly.Indicies) { var v = mesh.Vertices[face]; GX_Vertex vertex = new GX_Vertex(); var tkvert = new Vector3(v.Position.X, v.Position.Y, v.Position.Z); var tknrm = new Vector3(v.Normal.X, v.Normal.Y, v.Normal.Z); var tktan = new Vector3(v.Tangent.X, v.Tangent.Y, v.Tangent.Z); var tkbitan = new Vector3(v.Binormal.X, v.Binormal.Y, v.Binormal.Z); var parentTransform = _cache.jobjToWorldTransform[parent].Inverted(); if (_cache.jobjToWorldTransform[parent] != Matrix4.Identity) { tkvert = Vector3.TransformPosition(tkvert, parentTransform); tknrm = Vector3.TransformNormal(tknrm, parentTransform).Normalized(); tktan = Vector3.TransformNormal(tktan, parentTransform).Normalized(); tkbitan = Vector3.TransformNormal(tkbitan, parentTransform).Normalized(); } if (mesh.HasEnvelopes() && Settings.ImportRigging) { // create weighting lists List <float> weight = new List <float>(); List <HSD_JOBJ> bones = new List <HSD_JOBJ>(); if (v.Envelope.Weights.Count == 0) { weight.Add(1); bones.Add(rootnode); } if (v.Envelope.Weights.Count > 4) { throw new Exception($"Too many weights! {v.Envelope.Weights.Count} in {mesh.Name}"); } foreach (var bw in v.Envelope.Weights) { // check if skeleton actually contains bone if (_cache.NameToJOBJ.ContainsKey(bw.BoneName) && nodes.Contains(_cache.NameToJOBJ[bw.BoneName])) { // add envelope bones.Add(_cache.NameToJOBJ[bw.BoneName]); weight.Add(bw.Weight); // indicate enveloped jobjs if (!_cache.EnvelopedJOBJs.Contains(_cache.NameToJOBJ[bw.BoneName])) { _cache.EnvelopedJOBJs.Add(_cache.NameToJOBJ[bw.BoneName]); } } else { throw new Exception($"Bone not found \"{bw.BoneName}\" Weight: {bw.Weight} in {mesh.Name}"); } } jobjList.Add(bones.ToArray()); weightList.Add(weight.ToArray()); // invert single binds if (v.Envelope.Weights.Count == 1) { var inv = _cache.jobjToWorldTransform[_cache.NameToJOBJ[v.Envelope.Weights[0].BoneName]].Inverted(); tkvert = Vector3.TransformPosition(tkvert, inv); tknrm = Vector3.TransformNormal(tknrm, inv).Normalized(); tktan = Vector3.TransformNormal(tknrm, inv).Normalized(); tkbitan = Vector3.TransformNormal(tknrm, inv).Normalized(); } } vertex.POS = GXTranslator.fromVector3(tkvert); vertex.NRM = GXTranslator.fromVector3(tknrm.Normalized()); vertex.TAN = GXTranslator.fromVector3(tktan); vertex.BITAN = GXTranslator.fromVector3(tkbitan); if (Settings.InvertNormals) { vertex.NRM.X *= -1; vertex.NRM.Y *= -1; vertex.NRM.Z *= -1; vertex.TAN.X *= -1; vertex.TAN.Y *= -1; vertex.TAN.Z *= -1; vertex.BITAN.X *= -1; vertex.BITAN.Y *= -1; vertex.BITAN.Z *= -1; } if (mesh.HasUVSet(0)) { vertex.TEX0 = new GXVector2(v.UVs[0].X, v.UVs[0].Y); } if (mesh.HasUVSet(1)) { vertex.TEX1 = new GXVector2(v.UVs[1].X, v.UVs[1].Y); } if (mesh.HasUVSet(2)) { vertex.TEX2 = new GXVector2(v.UVs[2].X, v.UVs[2].Y); } if (mesh.HasUVSet(3)) { vertex.TEX3 = new GXVector2(v.UVs[3].X, v.UVs[3].Y); } if (mesh.HasUVSet(4)) { vertex.TEX4 = new GXVector2(v.UVs[4].X, v.UVs[4].Y); } if (mesh.HasUVSet(5)) { vertex.TEX5 = new GXVector2(v.UVs[5].X, v.UVs[5].Y); } if (mesh.HasUVSet(6)) { vertex.TEX6 = new GXVector2(v.UVs[6].X, v.UVs[6].Y); } if (mesh.HasUVSet(7)) { vertex.TEX7 = new GXVector2(v.UVs[7].X, v.UVs[7].Y); } if (mesh.HasColorSet(0)) { vertex.CLR0 = new GXColor4( v.Colors[0].X * (Settings.MultiplyVertexColorBy2 ? 2 : 1), v.Colors[0].Y * (Settings.MultiplyVertexColorBy2 ? 2 : 1), v.Colors[0].Z * (Settings.MultiplyVertexColorBy2 ? 2 : 1), Settings.ImportVertexAlpha ? v.Colors[0].W : 1); } if (mesh.HasColorSet(1)) { vertex.CLR1 = new GXColor4( v.Colors[1].X * (Settings.MultiplyVertexColorBy2 ? 2 : 1), v.Colors[1].Y * (Settings.MultiplyVertexColorBy2 ? 2 : 1), v.Colors[1].Z * (Settings.MultiplyVertexColorBy2 ? 2 : 1), Settings.ImportVertexAlpha ? v.Colors[1].W : 1); } vertices.Add(vertex); } // generate pobjs HSD_POBJ pobj = null; if (mesh.HasEnvelopes() && Settings.ImportRigging && !singleBinded) { pobj = _cache.POBJGen.CreatePOBJsFromTriangleList(vertices, Attributes.ToArray(), jobjList, weightList); } else { pobj = _cache.POBJGen.CreatePOBJsFromTriangleList(vertices, Attributes.ToArray(), null); } if (singleBinded && jobjList.Count > 0 && jobjList[0].Length > 0) { parent = jobjList[0][0]; } if (pobj != null) { if (dobj.Pobj == null) { dobj.Pobj = pobj; } else { dobj.Pobj.Add(pobj); } } } if (parent.Dobj == null) { parent.Dobj = root; } else { parent.Dobj.Add(root); } }
public PointTriangle(GX_Vertex x, GX_Vertex y, GX_Vertex z) { _x = x; _y = y; _z = z; }
/// <summary> /// /// </summary> /// <returns></returns> private static HSD_DOBJ GetMeshes(ProcessingCache cache, ModelImportSettings settings, Scene scene, Node node) { HSD_DOBJ root = null; HSD_DOBJ prev = null; Console.WriteLine("Processing " + node.Name); foreach (int index in node.MeshIndices) { Mesh mesh = scene.Meshes[index]; var material = scene.Materials[mesh.MaterialIndex]; Console.WriteLine(mesh.Name + " " + material.Name); // Generate DOBJ HSD_DOBJ dobj = new HSD_DOBJ(); // hack to make dobjs merged by texture if (settings.ImportTexture && settings.ForceMergeObjects == ForceGroupModes.Texture && material.HasTextureDiffuse && cache.TextureToDOBJ.ContainsKey(material.TextureDiffuse.FilePath)) { dobj = cache.TextureToDOBJ[material.TextureDiffuse.FilePath]; } else { if (root == null) { root = dobj; } else { prev.Next = dobj; } prev = dobj; dobj.Mobj = GenerateMaterial(cache, settings, material); if (settings.ForceMergeObjects == ForceGroupModes.Texture && material.HasTextureDiffuse && settings.ImportTexture) { cache.TextureToDOBJ.Add(material.TextureDiffuse.FilePath, dobj); } } if (root != null && settings.ForceMergeObjects == ForceGroupModes.MeshGroup) { dobj = root; } // Assessment if (!mesh.HasFaces) { continue; } // Assess needed attributes based on the material MOBJ // reflective mobjs do not use uvs var hasReflection = false; // bump maps need tangents and bitangents var hasBump = false; if (dobj.Mobj.Textures != null) { foreach (var t in dobj.Mobj.Textures.List) { if (t.Flags.HasFlag(TOBJ_FLAGS.COORD_REFLECTION)) { hasReflection = true; } if (t.Flags.HasFlag(TOBJ_FLAGS.BUMP)) { hasBump = true; } } } List <GXAttribName> Attributes = new List <GXAttribName>(); // todo: rigging List <HSD_JOBJ>[] jobjs = new List <HSD_JOBJ> [mesh.Vertices.Count]; List <float>[] weights = new List <float> [mesh.Vertices.Count]; if (mesh.HasBones) { Attributes.Add(GXAttribName.GX_VA_PNMTXIDX); foreach (var v in mesh.Bones) { var jobj = cache.NameToJOBJ[v.Name]; if (!cache.EnvelopedJOBJs.Contains(jobj)) { cache.EnvelopedJOBJs.Add(jobj); } if (v.HasVertexWeights) { foreach (var vw in v.VertexWeights) { if (jobjs[vw.VertexID] == null) { jobjs[vw.VertexID] = new List <HSD_JOBJ>(); } if (weights[vw.VertexID] == null) { weights[vw.VertexID] = new List <float>(); } if (vw.Weight > 0) { jobjs[vw.VertexID].Add(jobj); weights[vw.VertexID].Add(vw.Weight); } } } } } if (hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX0MTXIDX); } if (mesh.HasVertices) { Attributes.Add(GXAttribName.GX_VA_POS); } if (mesh.HasVertexColors(0) && settings.ShadingType == ShadingType.VertexColor) { Attributes.Add(GXAttribName.GX_VA_CLR0); } //if (mesh.HasVertexColors(1) && settings.ImportVertexColors) // Attributes.Add(GXAttribName.GX_VA_CLR1); if (!hasBump && mesh.HasNormals && settings.ShadingType == ShadingType.Material) { Attributes.Add(GXAttribName.GX_VA_NRM); } if (hasBump) { Attributes.Add(GXAttribName.GX_VA_NBT); } if (mesh.HasTextureCoords(0) && !hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX0); } //if (mesh.HasTextureCoords(1)) // Attributes.Add(GXAttribName.GX_VA_TEX1); var vertices = new List <GX_Vertex>(); var jobjList = new List <HSD_JOBJ[]>(vertices.Count); var wList = new List <float[]>(vertices.Count); foreach (var face in mesh.Faces) { PrimitiveType faceMode; switch (face.IndexCount) { case 1: faceMode = PrimitiveType.Point; break; case 2: faceMode = PrimitiveType.Line; break; case 3: faceMode = PrimitiveType.Triangle; break; default: faceMode = PrimitiveType.Polygon; break; } if (faceMode != PrimitiveType.Triangle) { continue; //throw new NotSupportedException($"Non triangle primitive types not supported at this time {faceMode}"); } for (int i = 0; i < face.IndexCount; i++) { int indicie = face.Indices[i]; GX_Vertex vertex = new GX_Vertex(); if (mesh.HasBones) { jobjList.Add(jobjs[indicie].ToArray()); wList.Add(weights[indicie].ToArray()); // Single Binds Get Inverted var tkvert = new Vector3(mesh.Vertices[indicie].X, mesh.Vertices[indicie].Y, mesh.Vertices[indicie].Z) * settings.Scale; var tknrm = new Vector3(mesh.Normals[indicie].X, mesh.Normals[indicie].Y, mesh.Normals[indicie].Z); Vector3 tktan = Vector3.Zero; Vector3 tkbitan = Vector3.Zero; if (mesh.HasTangentBasis) { tktan = new Vector3(mesh.Tangents[indicie].X, mesh.Tangents[indicie].Y, mesh.Tangents[indicie].Z); tkbitan = new Vector3(mesh.BiTangents[indicie].X, mesh.BiTangents[indicie].Y, mesh.BiTangents[indicie].Z); } if (jobjs[indicie].Count == 1 || weights[indicie][0] == 1) { tkvert = Vector3.TransformPosition(tkvert, cache.jobjToInverseTransform[jobjs[indicie][0]]); tknrm = Vector3.TransformNormal(tknrm, cache.jobjToInverseTransform[jobjs[indicie][0]]); if (mesh.HasTangentBasis) { tktan = Vector3.TransformNormal(tktan, cache.jobjToInverseTransform[jobjs[indicie][0]]); tkbitan = Vector3.TransformNormal(tkbitan, cache.jobjToInverseTransform[jobjs[indicie][0]]); } } vertex.POS = GXTranslator.fromVector3(tkvert); vertex.NRM = GXTranslator.fromVector3(tknrm); vertex.TAN = GXTranslator.fromVector3(tktan); vertex.BITAN = GXTranslator.fromVector3(tkbitan); } else { if (mesh.HasVertices) { vertex.POS = new GXVector3(mesh.Vertices[indicie].X * settings.Scale, mesh.Vertices[indicie].Y * settings.Scale, mesh.Vertices[indicie].Z * settings.Scale); } if (mesh.HasNormals) { vertex.NRM = new GXVector3(mesh.Normals[indicie].X, mesh.Normals[indicie].Y, mesh.Normals[indicie].Z); } if (mesh.HasTangentBasis) { vertex.TAN = new GXVector3(mesh.Tangents[indicie].X, mesh.Tangents[indicie].Y, mesh.Tangents[indicie].Z); vertex.BITAN = new GXVector3(mesh.BiTangents[indicie].X, mesh.BiTangents[indicie].Y, mesh.BiTangents[indicie].Z); } } if (settings.InvertNormals) { vertex.NRM.X *= -1; vertex.NRM.Y *= -1; vertex.NRM.Z *= -1; } if (mesh.HasTextureCoords(0)) { vertex.TEX0 = new GXVector2( mesh.TextureCoordinateChannels[0][indicie].X, mesh.TextureCoordinateChannels[0][indicie].Y); } if (mesh.HasTextureCoords(1)) { vertex.TEX1 = new GXVector2( mesh.TextureCoordinateChannels[1][indicie].X, mesh.TextureCoordinateChannels[1][indicie].Y); } if (mesh.HasVertexColors(0)) { vertex.CLR0 = new GXColor4( mesh.VertexColorChannels[0][indicie].R, mesh.VertexColorChannels[0][indicie].G, mesh.VertexColorChannels[0][indicie].B, settings.ImportVertexAlpha ? mesh.VertexColorChannels[0][indicie].A : 1); } if (mesh.HasVertexColors(1)) { vertex.CLR0 = new GXColor4( mesh.VertexColorChannels[1][indicie].R, mesh.VertexColorChannels[1][indicie].G, mesh.VertexColorChannels[1][indicie].B, settings.ImportVertexAlpha ? mesh.VertexColorChannels[1][indicie].A : 1); } vertices.Add(vertex); } } HSD_POBJ pobj = null; if (mesh.HasBones) { pobj = cache.POBJGen.CreatePOBJsFromTriangleList(vertices, Attributes.ToArray(), jobjList, wList); } else { pobj = cache.POBJGen.CreatePOBJsFromTriangleList(vertices, Attributes.ToArray(), null); } if (pobj != null) { if (dobj.Pobj == null) { dobj.Pobj = pobj; } else { dobj.Pobj.Add(pobj); } } } return(root); }
/// <summary> /// /// </summary> /// <param name="PrimitiveGroup"></param> /// <param name="Attributes"></param> /// <returns></returns> private static GX_Vertex[] GetDecodedVertices(GX_PrimitiveGroup PrimitiveGroup, List <GX_Attribute> Attributes, HSD_POBJ Polygon, int shapeset) { // Create Vertex List List <GX_Vertex> Vertices = new List <GX_Vertex>(); // Decode foreach (GX_IndexGroup ig in PrimitiveGroup.Indices) { GX_Vertex Vertex = new GX_Vertex(); for (int i = 0; i < Attributes.Count; i++) { var attribute = Attributes[i]; int index = ig.Indices[i]; float[] f = new float[4]; // check if index is in range of buffer if (attribute.AttributeType != GXAttribType.GX_DIRECT && attribute.Buffer != null && index >= attribute.Count) { System.Diagnostics.Debug.WriteLine($"Warning: Attribute index out of range {index} >= {attribute.Count}"); continue; } // check if data is direct if (attribute.AttributeType != GXAttribType.GX_DIRECT) { f = attribute.GetDecodedDataAt(index); } switch (attribute.AttributeName) { case GXAttribName.GX_VA_NULL: break; case GXAttribName.GX_VA_PNMTXIDX: if (attribute.AttributeType == GXAttribType.GX_DIRECT) { Vertex.PNMTXIDX = (ushort)index; } break; case GXAttribName.GX_VA_TEX0MTXIDX: if (attribute.AttributeType == GXAttribType.GX_DIRECT) { Vertex.TEX0MTXIDX = (ushort)index; } break; case GXAttribName.GX_VA_TEX1MTXIDX: if (attribute.AttributeType == GXAttribType.GX_DIRECT) { Vertex.TEX1MTXIDX = (ushort)index; } break; case GXAttribName.GX_VA_POS: if (attribute.AttributeType != GXAttribType.GX_DIRECT) { if (Polygon.ShapeSet != null) { var ss = Polygon.ShapeSet.VertexIndices[shapeset]; f = attribute.GetDecodedDataAt(ss[index]); } if (f.Length > 0) { Vertex.POS.X = f[0]; } if (f.Length > 1) { Vertex.POS.Y = f[1]; } if (f.Length > 2) { Vertex.POS.Z = f[2]; } } break; case GXAttribName.GX_VA_NRM: if (attribute.AttributeType != GXAttribType.GX_DIRECT) { if (Polygon.ShapeSet != null) { var ss = Polygon.ShapeSet.NormalIndicies[shapeset]; f = attribute.GetDecodedDataAt(ss[index]); } Vertex.NRM.X = f[0]; Vertex.NRM.Y = f[1]; Vertex.NRM.Z = f[2]; } break; case GXAttribName.GX_VA_NBT: if (attribute.AttributeType != GXAttribType.GX_DIRECT) { Vertex.NRM.X = f[0]; Vertex.NRM.Y = f[1]; Vertex.NRM.Z = f[2]; Vertex.BITAN.X = f[3]; Vertex.BITAN.Y = f[4]; Vertex.BITAN.Z = f[5]; Vertex.TAN.X = f[6]; Vertex.TAN.Y = f[7]; Vertex.TAN.Z = f[8]; } break; case GXAttribName.GX_VA_TEX0: if (attribute.AttributeType != GXAttribType.GX_DIRECT) { Vertex.TEX0.X = f[0]; Vertex.TEX0.Y = f[1]; } break; case GXAttribName.GX_VA_TEX1: if (attribute.AttributeType != GXAttribType.GX_DIRECT) { Vertex.TEX1.X = f[0]; Vertex.TEX1.Y = f[1]; } break; case GXAttribName.GX_VA_TEX2: if (attribute.AttributeType != GXAttribType.GX_DIRECT) { Vertex.TEX2.X = f[0]; Vertex.TEX2.Y = f[1]; } break; case GXAttribName.GX_VA_TEX3: if (attribute.AttributeType != GXAttribType.GX_DIRECT) { Vertex.TEX3.X = f[0]; Vertex.TEX3.Y = f[1]; } break; case GXAttribName.GX_VA_TEX4: if (attribute.AttributeType != GXAttribType.GX_DIRECT) { Vertex.TEX4.X = f[0]; Vertex.TEX4.Y = f[1]; } break; case GXAttribName.GX_VA_TEX5: if (attribute.AttributeType != GXAttribType.GX_DIRECT) { Vertex.TEX5.X = f[0]; Vertex.TEX5.Y = f[1]; } break; case GXAttribName.GX_VA_TEX6: if (attribute.AttributeType != GXAttribType.GX_DIRECT) { Vertex.TEX6.X = f[0]; Vertex.TEX6.Y = f[1]; } break; case GXAttribName.GX_VA_TEX7: if (attribute.AttributeType != GXAttribType.GX_DIRECT) { Vertex.TEX7.X = f[0]; Vertex.TEX7.Y = f[1]; } break; case GXAttribName.GX_VA_CLR0: if (attribute.AttributeType == GXAttribType.GX_DIRECT) { Vertex.CLR0.R = ig.Clr0[0] / 255f; Vertex.CLR0.G = ig.Clr0[1] / 255f; Vertex.CLR0.B = ig.Clr0[2] / 255f; Vertex.CLR0.A = ig.Clr0[3] / 255f; } else { Vertex.CLR0.R = f[0]; Vertex.CLR0.G = f[1]; Vertex.CLR0.B = f[2]; Vertex.CLR0.A = f[3]; } break; case GXAttribName.GX_VA_CLR1: if (attribute.AttributeType == GXAttribType.GX_DIRECT) { Vertex.CLR1.R = ig.Clr1[0] / 255f; Vertex.CLR1.G = ig.Clr1[1] / 255f; Vertex.CLR1.B = ig.Clr1[2] / 255f; Vertex.CLR1.A = ig.Clr1[3] / 255f; } else { Vertex.CLR1.R = f[0]; Vertex.CLR1.G = f[1]; Vertex.CLR1.B = f[2]; Vertex.CLR1.A = f[3]; } break; default: Console.WriteLine("To be implemented: " + attribute.AttributeName); break; } } Vertices.Add(Vertex); } return(Vertices.ToArray()); }