public NJS_MESHSET Clone() { NJS_MESHSET result = (NJS_MESHSET)MemberwiseClone(); List <Poly> polys = new List <Poly>(Poly.Count); foreach (Poly item in Poly) { polys.Add(item.Clone()); } result.Poly = new ReadOnlyCollection <Poly>(polys); if (PolyNormal != null) { result.PolyNormal = new Vertex[PolyNormal.Length]; for (int i = 0; i < PolyNormal.Length; i++) { result.PolyNormal[i] = PolyNormal[i].Clone(); } } if (VColor != null) { result.VColor = (Color[])VColor.Clone(); } if (UV != null) { result.UV = new UV[UV.Length]; for (int i = 0; i < UV.Length; i++) { result.UV[i] = UV[i].Clone(); } } return(result); }
public BasicAttach(byte[] file, int address, uint imageBase, bool DX, Dictionary <int, string> labels) : this() { if (labels.ContainsKey(address)) { Name = labels[address]; } else { Name = "attach_" + address.ToString("X8"); } Vertex = new Vertex[ByteConverter.ToInt32(file, address + 8)]; Normal = new Vertex[Vertex.Length]; int tmpaddr = (int)(ByteConverter.ToUInt32(file, address) - imageBase); if (labels.ContainsKey(tmpaddr)) { VertexName = labels[tmpaddr]; } else { VertexName = "vertex_" + tmpaddr.ToString("X8"); } for (int i = 0; i < Vertex.Length; i++) { Vertex[i] = new Vertex(file, tmpaddr); tmpaddr += SAModel.Vertex.Size; } tmpaddr = ByteConverter.ToInt32(file, address + 4); if (tmpaddr != 0) { tmpaddr = (int)((uint)tmpaddr - imageBase); if (labels.ContainsKey(tmpaddr)) { NormalName = labels[tmpaddr]; } else { NormalName = "normal_" + tmpaddr.ToString("X8"); } for (int i = 0; i < Vertex.Length; i++) { Normal[i] = new Vertex(file, tmpaddr); tmpaddr += SAModel.Vertex.Size; } } else { for (int i = 0; i < Vertex.Length; i++) { Normal[i] = new Vertex(0, 1, 0); } } int maxmat = -1; int meshcnt = ByteConverter.ToInt16(file, address + 0x14); tmpaddr = ByteConverter.ToInt32(file, address + 0xC); if (tmpaddr != 0) { tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase); if (labels.ContainsKey(tmpaddr)) { MeshName = labels[tmpaddr]; } else { MeshName = "meshlist_" + tmpaddr.ToString("X8"); } for (int i = 0; i < meshcnt; i++) { Mesh.Add(new NJS_MESHSET(file, tmpaddr, imageBase, labels)); maxmat = Math.Max(maxmat, Mesh[i].MaterialID); tmpaddr += NJS_MESHSET.Size(DX); } } // fixes case where model declares material array as shorter than it really is int matcnt = Math.Max(ByteConverter.ToInt16(file, address + 0x16), maxmat + 1); tmpaddr = ByteConverter.ToInt32(file, address + 0x10); if (tmpaddr != 0) { tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase); if (labels.ContainsKey(tmpaddr)) { MaterialName = labels[tmpaddr]; } else { MaterialName = "matlist_" + tmpaddr.ToString("X8"); } for (int i = 0; i < matcnt; i++) { Material.Add(new NJS_MATERIAL(file, tmpaddr, labels)); tmpaddr += NJS_MATERIAL.Size; } } Bounds = new BoundingSphere(file, address + 0x18); }
public BasicAttach(List <NJS_MATERIAL> materials, List <Mesh> meshes) { Name = "attach_" + Extensions.GenerateIdentifier(); Bounds = new BoundingSphere(); Material = new List <NJS_MATERIAL>(); MaterialName = "matlist_" + Extensions.GenerateIdentifier(); Mesh = new List <NJS_MESHSET>(); MeshName = "meshlist_" + Extensions.GenerateIdentifier(); Vertex = new Vertex[0]; VertexName = "vertex_" + Extensions.GenerateIdentifier(); Normal = new Vertex[0]; NormalName = "normal_" + Extensions.GenerateIdentifier(); List <Vertex> vertices = new List <Vertex>(); foreach (Mesh m in meshes) { foreach (Vector3D ve in m.Vertices) { vertices.Add(new Vertex(ve.X, ve.Y, ve.Z)); } } Vertex = vertices.ToArray(); List <Vertex> normals = new List <Vertex>(); foreach (Mesh m in meshes) { foreach (Vector3D ve in m.Normals) { normals.Add(new Vertex(ve.X, ve.Y, ve.Z)); } } Normal = normals.ToArray(); Material = materials; int polyIndex = 0; List <NJS_MESHSET> meshsets = new List <NJS_MESHSET>(); for (int i = 0; i < meshes.Count; i++) { NJS_MESHSET meshset; //= new NJS_MESHSET(polyType, meshes[i].Faces.Count, false, meshes[i].HasTextureCoords(0), meshes[i].HasVertexColors(0)); List <Poly> polys = new List <Poly>(); //i noticed the primitiveType of the Assimp Mesh is always triangles so... foreach (Face f in meshes[i].Faces) { Triangle triangle = new Triangle(); triangle.Indexes[0] = (ushort)(f.Indices[0] + polyIndex); triangle.Indexes[1] = (ushort)(f.Indices[1] + polyIndex); triangle.Indexes[2] = (ushort)(f.Indices[2] + polyIndex); polys.Add(triangle); } meshset = new NJS_MESHSET(polys.ToArray(), false, meshes[i].HasTextureCoords(0), false); //hasVColor = meshes[i].HasVertexColors(0); meshset.PolyName = "poly_" + Extensions.GenerateIdentifier(); meshset.MaterialID = (ushort)meshes[i].MaterialIndex; if (meshes[i].HasTextureCoords(0)) { meshset.UVName = "uv_" + Extensions.GenerateIdentifier(); for (int x = 0; x < meshes[i].TextureCoordinateChannels[0].Count; x++) { meshset.UV[x] = new UV() { U = meshes[i].TextureCoordinateChannels[0][x].X, V = meshes[i].TextureCoordinateChannels[0][x].Y }; } } if (meshes[i].HasVertexColors(0)) { throw new NotImplementedException(); } polyIndex += meshes[i].VertexCount; meshsets.Add(meshset); //4B4834 } Mesh = meshsets; Bounds = new BoundingSphere() { Radius = 1.0f }; }
static void Main(string[] args) { string filename; if (args.Length > 0) { filename = args[0]; Console.WriteLine("File: {0}", filename); } else { Console.Write("File: "); filename = Console.ReadLine(); } LandTable level = LandTable.LoadFromFile(filename); switch (level.Format) { case LandTableFormat.SA1: { List<COL> newcollist = new List<COL>(); foreach (COL col in level.COL.Where((col) => col.Model != null && col.Model.Attach != null)) { if ((col.SurfaceFlags & SurfaceFlags.Visible) == SurfaceFlags.Visible) { COL newcol = new COL() { Bounds = col.Bounds }; newcol.SurfaceFlags = SurfaceFlags.Visible; newcol.Model = new SonicRetro.SAModel.NJS_OBJECT() { Name = col.Model.Name + "_cnk" }; newcol.Model.Position = col.Model.Position; newcol.Model.Rotation = col.Model.Rotation; newcol.Model.Scale = col.Model.Scale; BasicAttach basatt = (BasicAttach)col.Model.Attach; ChunkAttach cnkatt = new ChunkAttach(true, true) { Name = basatt.Name + "_cnk", Bounds = basatt.Bounds }; newcol.Model.Attach = cnkatt; VertexChunk vcnk; if (basatt.Normal != null && basatt.Normal.Length > 0) vcnk = new VertexChunk(ChunkType.Vertex_VertexNormal); else vcnk = new VertexChunk(ChunkType.Vertex_Vertex); vcnk.Vertices = new List<Vertex>(basatt.Vertex); if (basatt.Normal != null) vcnk.Normals = new List<Vertex>(basatt.Normal); vcnk.VertexCount = (ushort)basatt.Vertex.Length; vcnk.Size = (ushort)((vcnk.Type == ChunkType.Vertex_VertexNormal ? vcnk.VertexCount * 6 : vcnk.VertexCount * 3) + 1); cnkatt.Vertex.Add(vcnk); foreach (NJS_MESHSET mesh in basatt.Mesh) { if (mesh.PolyType != Basic_PolyType.Strips) { Console.WriteLine("Warning: Skipping non-strip mesh in {0} ({1}).", basatt.MeshName, mesh.PolyType); continue; } NJS_MATERIAL mat = null; if (basatt.Material != null && mesh.MaterialID < basatt.Material.Count) { mat = basatt.Material[mesh.MaterialID]; cnkatt.Poly.Add(new PolyChunkBitsBlendAlpha() { SourceAlpha = mat.SourceAlpha, DestinationAlpha = mat.DestinationAlpha }); cnkatt.Poly.Add(new PolyChunkTinyTextureID() { ClampU = mat.ClampU, ClampV = mat.ClampV, FilterMode = mat.FilterMode, FlipU = mat.FlipU, FlipV = mat.FlipV, SuperSample = mat.SuperSample, TextureID = (ushort)mat.TextureID }); cnkatt.Poly.Add(new PolyChunkMaterial() { Diffuse = mat.DiffuseColor, Specular = mat.SpecularColor, SpecularExponent = (byte)mat.Exponent }); } PolyChunkStrip strip; if (mesh.UV != null & mesh.VColor != null) strip = new PolyChunkStrip(ChunkType.Strip_StripUVNColor); else if (mesh.UV != null) strip = new PolyChunkStrip(ChunkType.Strip_StripUVN); else if (mesh.VColor != null) strip = new PolyChunkStrip(ChunkType.Strip_StripColor); else strip = new PolyChunkStrip(ChunkType.Strip_Strip); if (mat != null) { strip.IgnoreLight = mat.IgnoreLighting; strip.IgnoreSpecular = mat.IgnoreSpecular; strip.UseAlpha = mat.UseAlpha; strip.DoubleSide = mat.DoubleSided; strip.FlatShading = mat.FlatShading; strip.EnvironmentMapping = mat.EnvironmentMap; } int striptotal = 0; foreach (Strip item in mesh.Poly.Cast<Strip>()) { UV[] uvs = null; if (mesh.UV != null) { uvs = new UV[item.Indexes.Length]; Array.Copy(mesh.UV, striptotal, uvs, 0, item.Indexes.Length); } Color[] vcolors = null; if (mesh.VColor != null) { vcolors = new Color[item.Indexes.Length]; Array.Copy(mesh.VColor, striptotal, vcolors, 0, item.Indexes.Length); } strip.Strips.Add(new PolyChunkStrip.Strip(item.Reversed, item.Indexes, uvs, vcolors)); striptotal += item.Indexes.Length; } cnkatt.Poly.Add(strip); } newcollist.Add(newcol); } if ((col.SurfaceFlags & ~SurfaceFlags.Visible) != 0) { col.SurfaceFlags &= ~SurfaceFlags.Visible; newcollist.Add(col); } } level.COL = newcollist; } level.Anim = new List<GeoAnimData>(); level.Tool = "SA Tools Level Converter"; level.SaveToFile(System.IO.Path.ChangeExtension(filename, "sa2lvl"), LandTableFormat.SA2); break; case LandTableFormat.SA2: Vertex[] VertexBuffer = new Vertex[0]; Vertex[] NormalBuffer = new Vertex[0]; foreach (COL col in level.COL.Where((col) => col.Model != null && col.Model.Attach is ChunkAttach)) { ChunkAttach cnkatt = (ChunkAttach)col.Model.Attach; BasicAttach basatt = new BasicAttach() { Name = cnkatt.Name, Bounds = cnkatt.Bounds }; if (cnkatt.Vertex != null) foreach (VertexChunk chunk in cnkatt.Vertex) { if (VertexBuffer.Length < chunk.IndexOffset + chunk.VertexCount) { Array.Resize(ref VertexBuffer, chunk.IndexOffset + chunk.VertexCount); Array.Resize(ref NormalBuffer, chunk.IndexOffset + chunk.VertexCount); } Array.Copy(chunk.Vertices.ToArray(), 0, VertexBuffer, chunk.IndexOffset, chunk.Vertices.Count); Array.Copy(chunk.Normals.ToArray(), 0, NormalBuffer, chunk.IndexOffset, chunk.Normals.Count); } NJS_MATERIAL material = new NJS_MATERIAL() { UseTexture = true }; int minVtx = int.MaxValue; int maxVtx = int.MinValue; foreach (PolyChunk chunk in cnkatt.Poly) switch (chunk.Type) { case ChunkType.Bits_BlendAlpha: { PolyChunkBitsBlendAlpha c2 = (PolyChunkBitsBlendAlpha)chunk; material.SourceAlpha = c2.SourceAlpha; material.DestinationAlpha = c2.DestinationAlpha; } break; case ChunkType.Bits_MipmapDAdjust: break; case ChunkType.Bits_SpecularExponent: material.Exponent = ((PolyChunkBitsSpecularExponent)chunk).SpecularExponent; break; case ChunkType.Tiny_TextureID: case ChunkType.Tiny_TextureID2: { PolyChunkTinyTextureID c2 = (PolyChunkTinyTextureID)chunk; material.ClampU = c2.ClampU; material.ClampV = c2.ClampV; material.FilterMode = c2.FilterMode; material.FlipU = c2.FlipU; material.FlipV = c2.FlipV; material.SuperSample = c2.SuperSample; material.TextureID = c2.TextureID; } break; case ChunkType.Material_Diffuse: case ChunkType.Material_Ambient: case ChunkType.Material_DiffuseAmbient: case ChunkType.Material_Specular: case ChunkType.Material_DiffuseSpecular: case ChunkType.Material_AmbientSpecular: case ChunkType.Material_DiffuseAmbientSpecular: case ChunkType.Material_Diffuse2: case ChunkType.Material_Ambient2: case ChunkType.Material_DiffuseAmbient2: case ChunkType.Material_Specular2: case ChunkType.Material_DiffuseSpecular2: case ChunkType.Material_AmbientSpecular2: case ChunkType.Material_DiffuseAmbientSpecular2: { PolyChunkMaterial c2 = (PolyChunkMaterial)chunk; if (c2.Diffuse.HasValue) material.DiffuseColor = c2.Diffuse.Value; if (c2.Specular.HasValue) { material.SpecularColor = c2.Specular.Value; material.Exponent = c2.SpecularExponent; } } break; case ChunkType.Strip_Strip: case ChunkType.Strip_StripUVN: case ChunkType.Strip_StripUVH: case ChunkType.Strip_StripNormal: case ChunkType.Strip_StripUVNNormal: case ChunkType.Strip_StripUVHNormal: case ChunkType.Strip_StripColor: case ChunkType.Strip_StripUVNColor: case ChunkType.Strip_StripUVHColor: case ChunkType.Strip_Strip2: case ChunkType.Strip_StripUVN2: case ChunkType.Strip_StripUVH2: { PolyChunkStrip c2 = (PolyChunkStrip)chunk; material.DoubleSided = c2.DoubleSide; material.EnvironmentMap = c2.EnvironmentMapping; material.FlatShading = c2.FlatShading; material.IgnoreLighting = c2.IgnoreLight; material.IgnoreSpecular = c2.IgnoreSpecular; material.UseAlpha = c2.UseAlpha; bool hasVColor = false; switch (chunk.Type) { case ChunkType.Strip_StripColor: case ChunkType.Strip_StripUVNColor: case ChunkType.Strip_StripUVHColor: hasVColor = true; break; } bool hasUV = false; switch (chunk.Type) { case ChunkType.Strip_StripUVN: case ChunkType.Strip_StripUVH: case ChunkType.Strip_StripUVNColor: case ChunkType.Strip_StripUVHColor: case ChunkType.Strip_StripUVN2: case ChunkType.Strip_StripUVH2: hasUV = true; break; } List<Strip> strips = new List<Strip>(c2.StripCount); List<UV> uvs = hasUV ? new List<UV>() : null; List<Color> vcolors = hasVColor ? new List<Color>() : null; foreach (PolyChunkStrip.Strip strip in c2.Strips) { minVtx = Math.Min(minVtx, strip.Indexes.Min()); maxVtx = Math.Max(maxVtx, strip.Indexes.Max()); strips.Add(new Strip(strip.Indexes, strip.Reversed)); if (hasUV) uvs.AddRange(strip.UVs); if (hasVColor) vcolors.AddRange(strip.VColors); } NJS_MESHSET mesh = new NJS_MESHSET(strips.ToArray(), false, hasUV, hasVColor); if (hasUV) uvs.CopyTo(mesh.UV); if (hasVColor) vcolors.CopyTo(mesh.VColor); mesh.MaterialID = (ushort)basatt.Material.Count; basatt.Mesh.Add(mesh); basatt.Material.Add(material); material = new NJS_MATERIAL(material.GetBytes(), 0); } break; } int numVtx = maxVtx - minVtx + 1; basatt.ResizeVertexes(numVtx); Array.Copy(VertexBuffer, minVtx, basatt.Vertex, 0, numVtx); Array.Copy(NormalBuffer, minVtx, basatt.Normal, 0, numVtx); foreach (NJS_MESHSET mesh in basatt.Mesh) foreach (Poly poly in mesh.Poly) for (int i = 0; i < poly.Indexes.Length; i++) poly.Indexes[i] = (ushort)(poly.Indexes[i] - minVtx); col.Model.Attach = basatt; } level.Anim = new List<GeoAnimData>(); level.Tool = "SA Tools Level Converter"; level.SaveToFile(System.IO.Path.ChangeExtension(filename, "sa1lvl"), LandTableFormat.SA1); break; } }
public BasicAttach(List <Material> materials, List <Mesh> meshes, string[] textures = null) { Name = "attach_" + Extensions.GenerateIdentifier(); Bounds = new BoundingSphere(); Material = new List <NJS_MATERIAL>(); MaterialName = "matlist_" + Extensions.GenerateIdentifier(); Mesh = new List <NJS_MESHSET>(); MeshName = "meshlist_" + Extensions.GenerateIdentifier(); Vertex = new Vertex[0]; VertexName = "vertex_" + Extensions.GenerateIdentifier(); Normal = new Vertex[0]; NormalName = "normal_" + Extensions.GenerateIdentifier(); List <Vertex> vertices = new List <Vertex>(); List <Vertex> normals = new List <Vertex>(); Dictionary <int, int> lookupMaterial = new Dictionary <int, int>(); foreach (Mesh m in meshes) { foreach (Vector3D ve in m.Vertices) { vertices.Add(new Vertex(ve.X, ve.Y, ve.Z)); } foreach (Vector3D ve in m.Normals) { normals.Add(new Vertex(ve.X, ve.Y, ve.Z)); } lookupMaterial.Add(m.MaterialIndex, Material.Count); Material.Add(new NJS_MATERIAL(materials[m.MaterialIndex])); if (materials[m.MaterialIndex].HasTextureDiffuse) { if (textures != null) { Material[Material.Count - 1].UseTexture = true; for (int i = 0; i < textures.Length; i++) { if (textures[i] == Path.GetFileNameWithoutExtension(materials[m.MaterialIndex].TextureDiffuse.FilePath)) { Material[Material.Count - 1].TextureID = i; } } } } } Vertex = vertices.ToArray(); Normal = normals.ToArray(); int polyIndex = 0; List <NJS_MESHSET> meshsets = new List <NJS_MESHSET>(); for (int i = 0; i < meshes.Count; i++) { NJS_MESHSET meshset; //= new NJS_MESHSET(polyType, meshes[i].Faces.Count, false, meshes[i].HasTextureCoords(0), meshes[i].HasVertexColors(0)); List <Poly> polys = new List <Poly>(); //i noticed the primitiveType of the Assimp Mesh is always triangles so... foreach (Face f in meshes[i].Faces) { Triangle triangle = new Triangle(); triangle.Indexes[0] = (ushort)(f.Indices[0] + polyIndex); triangle.Indexes[1] = (ushort)(f.Indices[1] + polyIndex); triangle.Indexes[2] = (ushort)(f.Indices[2] + polyIndex); polys.Add(triangle); } meshset = new NJS_MESHSET(polys.ToArray(), false, meshes[i].HasTextureCoords(0), meshes[i].HasVertexColors(0)); meshset.PolyName = "poly_" + Extensions.GenerateIdentifier(); meshset.MaterialID = (ushort)lookupMaterial[meshes[i].MaterialIndex]; if (meshes[i].HasTextureCoords(0)) { meshset.UVName = "uv_" + Extensions.GenerateIdentifier(); for (int x = 0; x < meshes[i].TextureCoordinateChannels[0].Count; x++) { meshset.UV[x] = new UV() { U = meshes[i].TextureCoordinateChannels[0][x].X, V = meshes[i].TextureCoordinateChannels[0][x].Y }; } } if (meshes[i].HasVertexColors(0)) { meshset.VColorName = "vcolor_" + Extensions.GenerateIdentifier(); for (int x = 0; x < meshes[i].VertexColorChannels[0].Count; x++) { meshset.VColor[x] = Color.FromArgb((int)(meshes[i].VertexColorChannels[0][x].A * 255.0f), (int)(meshes[i].VertexColorChannels[0][x].R * 255.0f), (int)(meshes[i].VertexColorChannels[0][x].G * 255.0f), (int)(meshes[i].VertexColorChannels[0][x].B * 255.0f)); } } polyIndex += meshes[i].VertexCount; meshsets.Add(meshset); //4B4834 } Mesh = meshsets; Bounds = new BoundingSphere() { Radius = 1.0f }; }