public override object Execute(List <string> args) { if (args.Count != 2) { return(false); } var fileType = args[0]; var fileName = args[1]; if (fileType != "obj") { throw new NotSupportedException(fileType); } if (Definition.Geometry.Resource == null) { Console.WriteLine("ERROR: Render geometry does not have a resource associated with it."); return(true); } // // Deserialize the resource definition // var definition = Cache.ResourceCache.GetRenderGeometryApiResourceDefinition(Definition.Geometry.Resource); Definition.Geometry.SetResourceBuffers(definition); using (var resourceStream = new MemoryStream()) { // // Extract the resource data // var file = new FileInfo(fileName); if (!file.Directory.Exists) { file.Directory.Create(); } using (var objFile = new StreamWriter(file.Create())) { var objExtractor = new ObjExtractor(objFile); foreach (var mesh in Definition.Geometry.Meshes) { var vertexCompressor = new VertexCompressor(Definition.Geometry.Compression[0]); var meshReader = new MeshReader(Cache.Version, mesh); objExtractor.ExtractMesh(meshReader, vertexCompressor); } objExtractor.Finish(); } } Console.WriteLine("Done!"); return(true); }
private RenderGeometryCompression CompressVertexBuffer(VertexBufferDefinition vertexBuffer) { Debug.Assert(vertexBuffer.Format == VertexBufferFormat.Rigid); var compression = new RenderGeometryCompression(); var rigidVertices = new List <RigidVertex>(); using (var stream = new MemoryStream(vertexBuffer.Data.Data)) { var vertexStream = VertexStreamFactory.Create(DestCache.Version, stream); for (int i = 0; i < vertexBuffer.Count; i++) { var vertex = vertexStream.ReadRigidVertex(); rigidVertices.Add(vertex); } } var positions = rigidVertices.Select(v => v.Position); var texCoords = rigidVertices.Select(v => v.Texcoord); if (positions != null && positions.Count() > 0) { compression.X.Lower = Math.Min(compression.X.Lower, positions.Min(v => v.I)); compression.Y.Lower = Math.Min(compression.Y.Lower, positions.Min(v => v.J)); compression.Z.Lower = Math.Min(compression.Z.Lower, positions.Min(v => v.K)); compression.X.Upper = Math.Max(compression.X.Upper, positions.Max(v => v.I)); compression.Y.Upper = Math.Max(compression.Y.Upper, positions.Max(v => v.J)); compression.Z.Upper = Math.Max(compression.Z.Upper, positions.Max(v => v.K)); } if (texCoords != null && texCoords.Count() > 0) { compression.U.Lower = Math.Min(compression.U.Lower, texCoords.Min(v => v.I)); compression.V.Lower = Math.Min(compression.V.Lower, texCoords.Min(v => v.J)); compression.U.Upper = Math.Max(compression.U.Upper, texCoords.Max(v => v.I)); compression.V.Upper = Math.Max(compression.V.Upper, texCoords.Max(v => v.J)); } var compressor = new VertexCompressor(compression); using (var outStream = new MemoryStream()) { var outVertexStream = VertexStreamFactory.Create(DestCache.Version, outStream); foreach (var vertex in rigidVertices) { vertex.Position = compressor.CompressPosition(vertex.Position); vertex.Texcoord = compressor.CompressUv(vertex.Texcoord); outVertexStream.WriteRigidVertex(vertex); } vertexBuffer.Data.Data = outStream.ToArray(); } return(compression); }
private bool ExtractObj(string variantName, FileInfo modelFile, RenderModel renderModel, RenderGeometryApiResourceDefinition resourceDefinition, Stream resourceStream) { var meshes = new Dictionary <string, Mesh>(); var vertexCompressor = new VertexCompressor(renderModel.Geometry.Compression[0]); foreach (var region in renderModel.Regions) { var regionName = CacheContext.GetString(region.Name); foreach (var permutation in region.Permutations) { var permutationName = CacheContext.GetString(permutation.Name); if (variantName != "*" && variantName != permutationName) { continue; } for (var i = 0; i < permutation.MeshCount; i++) { var name = $"{regionName}_{permutationName}_{i}"; meshes[name] = renderModel.Geometry.Meshes[permutation.MeshIndex + i]; } } } if (meshes.Count == 0) { Console.WriteLine($"ERROR: No meshes found under variant '{variantName}'!"); return(false); } Console.Write("Extracting {0} mesh(es)...", meshes.Count); using (var objFile = new StreamWriter(modelFile.Create())) { var objExtractor = new ObjExtractor(objFile); foreach (var entry in meshes) { var meshReader = new MeshReader(CacheContext.Version, entry.Value, resourceDefinition); objExtractor.ExtractMesh(meshReader, vertexCompressor, resourceStream, entry.Key); } objExtractor.Finish(); } Console.WriteLine("done!"); return(true); }
public override bool Execute(List <string> args) { if (args.Count != 3) { return(false); } var variantName = args[0]; var fileType = args[1]; var fileName = args[2]; if (fileType != "obj") { return(false); } // Find the variant to extract if (Definition.RenderModel == null) { Console.WriteLine("The model does not have a render model associated with it."); return(true); } var variant = Definition.Variants.FirstOrDefault(v => (Info.StringIds.GetString(v.Name) ?? v.Name.ToString()) == variantName); if (variant == null && Definition.Variants.Count > 0) { Console.WriteLine("Unable to find variant \"{0}\"", variantName); Console.WriteLine("Use \"listvariants\" to list available variants."); return(true); } // Load resource caches Console.WriteLine("Loading resource caches..."); var resourceManager = new ResourceDataManager(); try { resourceManager.LoadCachesFromDirectory(Info.CacheFile.DirectoryName); } catch { Console.WriteLine("Unable to load the resource .dat files."); Console.WriteLine("Make sure that they all exist and are valid."); return(true); } // Deserialize the render model tag Console.WriteLine("Reading model data..."); RenderModel renderModel; using (var cacheStream = Info.CacheFile.OpenRead()) { var renderModelContext = new TagSerializationContext(cacheStream, Info.Cache, Info.StringIds, Definition.RenderModel); renderModel = Info.Deserializer.Deserialize <RenderModel>(renderModelContext); } if (renderModel.Geometry.Resource == null) { Console.WriteLine("Render model does not have a resource associated with it"); return(true); } // Deserialize the resource definition var resourceContext = new ResourceSerializationContext(renderModel.Geometry.Resource); var definition = Info.Deserializer.Deserialize <RenderGeometryResourceDefinition>(resourceContext); using (var resourceStream = new MemoryStream()) { // Extract the resource data resourceManager.Extract(renderModel.Geometry.Resource, resourceStream); using (var objFile = new StreamWriter(File.Open(fileName, FileMode.Create, FileAccess.Write))) { var objExtractor = new ObjExtractor(objFile); var vertexCompressor = new VertexCompressor(renderModel.Geometry.Compression[0]); // Create a (de)compressor from the first compression block if (variant != null) { // Extract each region in the variant foreach (var region in variant.Regions) { // Get the corresonding region in the render model tag if (region.RenderModelRegionIndex >= renderModel.Regions.Count) { continue; } var renderModelRegion = renderModel.Regions[region.RenderModelRegionIndex]; // Get the corresponding permutation in the render model tag // (Just extract the first permutation for now) if (region.Permutations.Count == 0) { continue; } var permutation = region.Permutations[0]; if (permutation.RenderModelPermutationIndex < 0 || permutation.RenderModelPermutationIndex >= renderModelRegion.Permutations.Count) { continue; } var renderModelPermutation = renderModelRegion.Permutations[permutation.RenderModelPermutationIndex]; // Extract each mesh in the permutation var meshIndex = renderModelPermutation.MeshIndex; var meshCount = renderModelPermutation.MeshCount; var regionName = Info.StringIds.GetString(region.Name) ?? region.Name.ToString(); var permutationName = Info.StringIds.GetString(permutation.Name) ?? permutation.Name.ToString(); Console.WriteLine("Extracting {0} mesh(es) for {1}:{2}...", meshCount, regionName, permutationName); for (var i = 0; i < meshCount; i++) { // Create a MeshReader for the mesh and pass it to the obj extractor var meshReader = new MeshReader(Info.Version, renderModel.Geometry.Meshes[meshIndex + i], definition); objExtractor.ExtractMesh(meshReader, vertexCompressor, resourceStream); } } } else { // No variant - just extract every mesh Console.WriteLine("Extracting {0} mesh(es)...", renderModel.Geometry.Meshes.Count); foreach (var mesh in renderModel.Geometry.Meshes) { // Create a MeshReader for the mesh and pass it to the obj extractor var meshReader = new MeshReader(Info.Version, mesh, definition); objExtractor.ExtractMesh(meshReader, vertexCompressor, resourceStream); } } objExtractor.Finish(); } } Console.WriteLine("Done!"); return(true); }
private void ExtractObj(FileInfo modelFile, RenderModel renderModel, Model.Variant modelVariant, RenderGeometryApiResourceDefinition resourceDefinition, Stream resourceStream) { using (var objFile = new StreamWriter(modelFile.Create())) { var objExtractor = new ObjExtractor(objFile); // Create a (de)compressor from the first compression block var vertexCompressor = new VertexCompressor(renderModel.Geometry.Compression[0]); if (modelVariant != null) { // Extract each region in the variant foreach (var region in modelVariant.Regions) { // Get the corresonding region in the render model tag if (region.RenderModelRegionIndex >= renderModel.Regions.Count) { continue; } var renderModelRegion = renderModel.Regions[region.RenderModelRegionIndex]; // Get the corresponding permutation in the render model tag // (Just extract the first permutation for now) if (region.Permutations.Count == 0) { continue; } var permutation = region.Permutations[0]; if (permutation.RenderModelPermutationIndex < 0 || permutation.RenderModelPermutationIndex >= renderModelRegion.Permutations.Count) { continue; } var renderModelPermutation = renderModelRegion.Permutations[permutation.RenderModelPermutationIndex]; // Extract each mesh in the permutation var meshIndex = renderModelPermutation.MeshIndex; var meshCount = renderModelPermutation.MeshCount; var regionName = CacheContext.GetString(region.Name) ?? region.Name.ToString(); var permutationName = CacheContext.GetString(permutation.Name) ?? permutation.Name.ToString(); Console.WriteLine("Extracting {0} mesh(es) for {1}:{2}...", meshCount, regionName, permutationName); for (var i = 0; i < meshCount; i++) { // Create a MeshReader for the mesh and pass it to the obj extractor var meshReader = new MeshReader(CacheContext.Version, renderModel.Geometry.Meshes[meshIndex + i], resourceDefinition); objExtractor.ExtractMesh(meshReader, vertexCompressor, resourceStream); } } } else { // No variant - just extract every mesh Console.WriteLine("Extracting {0} mesh(es)...", renderModel.Geometry.Meshes.Count); foreach (var mesh in renderModel.Geometry.Meshes) { // Create a MeshReader for the mesh and pass it to the obj extractor var meshReader = new MeshReader(CacheContext.Version, mesh, resourceDefinition); objExtractor.ExtractMesh(meshReader, vertexCompressor, resourceStream); } } objExtractor.Finish(); } }
private static List <BMFVertex> ConvertGeometryVertices(VertexCompressor vertexCompressor, VertexBufferDefinition vertexBuffer, CacheVersion version, int vertexCount, int rigidNodeIndex) { var vertices = new List <BMFVertex>(); using (var vertexDataStream = new MemoryStream(vertexBuffer.Data.Data)) { var vertexStream = VertexStreamFactory.Create(version, vertexDataStream); for (int j = 0; j < vertexCount; j++) { var vertex = new BMFVertex(); RealVector2d texcoordTemp; switch (vertexBuffer.Format) { case VertexBufferFormat.Rigid: var rigid = vertexStream.ReadRigidVertex(); vertex.Position = vertexCompressor.DecompressPosition(rigid.Position).IJK; texcoordTemp = vertexCompressor.DecompressUv(rigid.Texcoord); vertex.Texcoord = new RealVector3d(texcoordTemp.I, texcoordTemp.J, 0.0f); vertex.Normal = rigid.Normal; vertex.Tangent = rigid.Tangent.IJK; vertex.Binormal = rigid.Binormal; vertex.Weights[0] = new BMFVertexWeight { NodeIndex = rigidNodeIndex, Weight = 1.0f }; for (int i = 1; i < 4; i++) { vertex.Weights[i] = new BMFVertexWeight(); } break; case VertexBufferFormat.Skinned: var skinned = vertexStream.ReadSkinnedVertex(); vertex.Position = vertexCompressor.DecompressPosition(skinned.Position).IJK; texcoordTemp = vertexCompressor.DecompressUv(skinned.Texcoord); vertex.Texcoord = new RealVector3d(texcoordTemp.I, texcoordTemp.J, 0.0f); vertex.Normal = skinned.Normal; vertex.Tangent = skinned.Tangent.IJK; vertex.Binormal = skinned.Binormal; for (int i = 0; i < 4; i++) { vertex.Weights[i] = new BMFVertexWeight { NodeIndex = skinned.BlendIndices[i], Weight = skinned.BlendWeights[i] }; } break; default: throw new InvalidOperationException("Unsupported vertex buffer type: " + vertexBuffer.Format); } vertices.Add(vertex); } } return(vertices); }
public bool InitGen3(GameCache cache, RenderModel mode) { Header = new BMFHeader(); Name = cache.StringTable.GetString(mode.Name); Regions = new List <BMFRegion>(); Dictionary <int, string> meshNames = new Dictionary <int, string>(); Dictionary <int, int> meshRegionIndex = new Dictionary <int, int>(); // build mesh index -> name mapping for (int i = 0; i < mode.Regions.Count; i++) { var region = mode.Regions[i]; var regionName = cache.StringTable.GetString(region.Name); Regions.Add(new BMFRegion { Name = regionName }); foreach (var permutation in region.Permutations) { var permutationName = cache.StringTable.GetString(permutation.Name); if (permutation.MeshCount > 1) { Console.WriteLine("Multi mesh per permutation not supported yet"); return(false); } var name = $"{permutationName}"; if (!meshNames.ContainsKey(permutation.MeshIndex)) { meshNames[permutation.MeshIndex] = name; } else { Console.WriteLine("Mesh is used twice for different permutations, not supported"); return(false); } meshRegionIndex[permutation.MeshIndex] = i; } } // build markers Markers = new List <BMFMarkers>(); foreach (var markerGroup in mode.MarkerGroups) { var groupName = cache.StringTable.GetString(markerGroup.Name); foreach (var marker in markerGroup.Markers) { string name = ""; if (marker.RegionIndex == -1 || marker.PermutationIndex == -1) { name = $"#{groupName}"; } else { var regionName = cache.StringTable.GetString(mode.Regions[marker.RegionIndex].Name); var permutationName = cache.StringTable.GetString(mode.Regions[marker.RegionIndex].Permutations[marker.PermutationIndex].Name); name = $"#{groupName}:{regionName}:{permutationName}"; } Markers.Add(new BMFMarkers { Name = name, NodeIndex = marker.NodeIndex, Translation = marker.Translation, Rotation = marker.Rotation, Scale = marker.Scale }); } } // build list of nodes Nodes = new List <BMFNode>(); foreach (var node in mode.Nodes) { var geometryNode = new BMFNode { Name = cache.StringTable.GetString(node.Name), ParentNodeIndex = node.ParentNode, NextSiblingNodeIndex = node.NextSiblingNode, FirstChildNodeIndex = node.FirstChildNode, Translation = node.DefaultTranslation, Rotation = node.DefaultRotation, Scale = node.DefaultScale }; Nodes.Add(geometryNode); } // build list of materials Materials = new List <BMFMaterial>(); for (int i = 0; i < mode.Materials.Count; i++) { var material = mode.Materials[i]; string name = $"material_{i}"; if (material.RenderMethod.Name != null) { name = material.RenderMethod.Name.Split('\\').Last(); } Materials.Add(new BMFMaterial { Name = name }); } // set SH coefficients DefaultLighting = new BMFGlobalLighting { SHRed = mode.SHRed, SHBlue = mode.SHBlue, SHGreen = mode.SHGreen }; LightProbes = new List <BMFLightProbe>(); foreach (var lightProbe in mode.UnknownSHProbes) { LightProbes.Add(new BMFLightProbe { Position = lightProbe.Position, Coefficients = lightProbe.Coefficients }); } BoundingSpheres = mode.Geometry.BoundingSpheres; Meshes = new List <BMFMesh>(); for (int i = 0; i < mode.Geometry.Meshes.Count; i++) { int vertexCount = 0; var mesh = mode.Geometry.Meshes[i]; var geometryMesh = new BMFMesh() { Name = meshNames[i], Vertices = new List <BMFVertex>(), Faces = new List <BMFFace>(), PerVertexLighting = new List <BMFVertexLighting>(), RegionIndex = meshRegionIndex[i], }; // // Build vertices and faces // if (mesh.ResourceIndexBuffers[0] != null) { var indexBuffer = mesh.ResourceIndexBuffers[0]; using (var indexDataStream = new MemoryStream(indexBuffer.Data.Data)) { var indexStream = new IndexBufferStream(indexDataStream, cache.Endianness); foreach (var part in mesh.Parts) { indexStream.Position = part.FirstIndexOld; ushort[] indices = new ushort[0]; vertexCount += part.VertexCount; switch (indexBuffer.Format) { case IndexBufferFormat.TriangleList: indices = indexStream.ReadIndices(part.IndexCountOld); break; case IndexBufferFormat.TriangleStrip: indices = indexStream.ReadTriangleStrip(part.IndexCountOld); break; default: throw new InvalidOperationException("Unsupported index buffer type: " + indexBuffer.Format); } // add faces for (int j = 0; j < indices.Length; j += 3) { var face = new BMFFace { MaterialIndex = part.MaterialIndex, Indices = new ushort[] { indices[j], indices[j + 1], indices[j + 2] } }; geometryMesh.Faces.Add(face); } } } } else { throw new Exception("No index buffer to create faces!"); } if (mesh.ResourceVertexBuffers[0] != null) { var vertexBuffer = mesh.ResourceVertexBuffers[0]; var vertexCompressor = new VertexCompressor(mode.Geometry.Compression[0]); geometryMesh.Vertices = ConvertGeometryVertices(vertexCompressor, vertexBuffer, cache.Version, vertexCount, mesh.RigidNodeIndex); } if (mesh.ResourceVertexBuffers[3] != null) { var vertexBuffer = mesh.ResourceVertexBuffers[3]; geometryMesh.PerVertexLighting = ConvertLightingVertices(vertexBuffer, cache.Version, vertexCount); } Meshes.Add(geometryMesh); } return(true); }
public override object Execute(List <string> args) { if (args.Count != 2) { return(false); } var fileType = args[0]; var fileName = args[1]; if (fileType != "obj") { throw new NotSupportedException(fileType); } if (Definition.Geometry2.Resource == null) { Console.WriteLine("ERROR: Render geometry does not have a resource associated with it."); return(true); } // // Deserialize the resource definition // var resourceContext = new ResourceSerializationContext(CacheContext, Definition.Geometry2.Resource); var definition = CacheContext.Deserializer.Deserialize <RenderGeometryApiResourceDefinition>(resourceContext); using (var resourceStream = new MemoryStream()) { // // Extract the resource data // CacheContext.ExtractResource(Definition.Geometry2.Resource, resourceStream); var file = new FileInfo(fileName); if (!file.Directory.Exists) { file.Directory.Create(); } using (var objFile = new StreamWriter(file.Create())) { var objExtractor = new ObjExtractor(objFile); foreach (var cluster in Definition.Clusters) { var meshReader = new MeshReader(CacheContext.Version, Definition.Geometry2.Meshes[cluster.MeshIndex], definition); objExtractor.ExtractMesh(meshReader, null, resourceStream); } foreach (var instance in Definition.InstancedGeometryInstances) { var vertexCompressor = new VertexCompressor(Definition.Geometry2.Compression[0]); var meshReader = new MeshReader(CacheContext.Version, Definition.Geometry2.Meshes[instance.InstanceDefinition], definition); objExtractor.ExtractMesh(meshReader, vertexCompressor, resourceStream); } objExtractor.Finish(); } } Console.WriteLine("Done!"); return(true); }