/// <summary> /// Reads Gfx Vertices /// </summary> public static Vertex[] ReadGfxVertices(ProcessReader reader, long address, int count) { // Preallocate vertex array Vertex[] vertices = new Vertex[count]; // Read buffer var byteBuffer = reader.ReadBytes(address, count * 44); // Loop number of vertices we have for (int i = 0; i < count; i++) { // Read Struct var gfxVertex = ByteUtil.BytesToStruct <GfxVertex>(byteBuffer, i * 44); // Create new SEModel Vertex vertices[i] = new Vertex() { // Set offset Position = new Vector3( gfxVertex.X * 2.54, gfxVertex.Y * 2.54, gfxVertex.Z * 2.54), // Decode and set normal (from DTZxPorter - Wraith, same as XModels) Normal = VertexNormalUnpacking.MethodA(gfxVertex.Normal), // Set UV UV = new Vector2(gfxVertex.U, 1 - gfxVertex.V) }; } // Done return(vertices); }
/// <summary> /// Reads Gfx Vertices /// </summary> public static Vertex[] ReadGfxVertices(ProcessReader reader, long positionsAddress, long uvsAddress, long normalsAddress, int count) { // Preallocate vertex array Vertex[] vertices = new Vertex[count]; // Read buffer var positionsBuffer = reader.ReadBytes(positionsAddress, count * 12); var uvsBuffer = reader.ReadBytes(uvsAddress, count * 8); var normalsBuffer = reader.ReadBytes(normalsAddress, count * 4); // Loop number of vertices we have for (int i = 0; i < count; i++) { // Read Struct var gfxVertexPosition = ByteUtil.BytesToStruct <GfxVertexPosition>(positionsBuffer, i * 12); var gfxVertexUV = ByteUtil.BytesToStruct <GfxVertexUV>(uvsBuffer, i * 8); var gfxVertexNormal = ByteUtil.BytesToStruct <PackedUnitVector>(normalsBuffer, i * 4); // Create new SEModel Vertex vertices[i] = new Vertex() { // Set offset Position = new Vector3( gfxVertexPosition.X * 2.54, gfxVertexPosition.Y * 2.54, gfxVertexPosition.Z * 2.54), // Decode and set normal (from DTZxPorter - Wraith, same as XModels) Normal = VertexNormalUnpacking.MethodB(gfxVertexNormal), // Set UV UV = new Vector2(gfxVertexUV.U, 1 - gfxVertexUV.V) }; } // Done return(vertices); }
public unsafe static List <IDictionary> CreateXModelDictionary(ProcessReader reader, long address, int count, List <IDictionary> MapEntities) { Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); // Read buffer var byteBuffer = reader.ReadBytes(address, count * Marshal.SizeOf <GfxStaticModel>()); // Loop number of models we have List <IDictionary> MapModels = new List <IDictionary>(count); for (int i = 0; i < count; i++) { Dictionary <string, string> ModelData = new Dictionary <string, string>(); List <double> Position = new List <double>(); List <double> angles = new List <double>(); // Read Struct var staticModel = ByteUtil.BytesToStruct <GfxStaticModel>(byteBuffer, i * Marshal.SizeOf <GfxStaticModel>()); // Model Name var modelName = reader.ReadNullTerminatedString(reader.ReadInt32(staticModel.ModelPointer)); var matrix = new Rotation.Matrix(); // Copy X Values matrix.Values[0] = staticModel.Matrix[0]; matrix.Values[1] = staticModel.Matrix[1]; matrix.Values[2] = staticModel.Matrix[2]; // Copy Y Values matrix.Values[4] = staticModel.Matrix[3]; matrix.Values[5] = staticModel.Matrix[4]; matrix.Values[6] = staticModel.Matrix[5]; // Copy Z Values matrix.Values[8] = staticModel.Matrix[6]; matrix.Values[9] = staticModel.Matrix[7]; matrix.Values[10] = staticModel.Matrix[8]; // Convert to Euler var euler = matrix.ToEuler(); // Add it if (string.IsNullOrEmpty(modelName) == true || modelName.Contains("?") == true || modelName.Contains("'") == true || modelName.Contains("\\") == true || modelName.Contains("fx") == true || modelName.Contains("viewmodel") == true || staticModel.ModelScale < 0.001 || staticModel.ModelScale > 10) { } else { ModelData.Add("Name", CleanInput(modelName)); ModelData.Add("PosX", string.Format("{0:0.0000}", staticModel.X)); ModelData.Add("PosY", string.Format("{0:0.0000}", staticModel.Y)); ModelData.Add("PosZ", string.Format("{0:0.0000}", staticModel.Z)); ModelData.Add("RotX", string.Format("{0:0.0000}", (float)Rotation.ToDegrees(euler).X).ToString(CultureInfo.InvariantCulture)); ModelData.Add("RotY", string.Format("{0:0.0000}", (float)Rotation.ToDegrees(euler).Y).ToString(CultureInfo.InvariantCulture)); ModelData.Add("RotZ", string.Format("{0:0.0000}", (float)Rotation.ToDegrees(euler).Z).ToString(CultureInfo.InvariantCulture)); ModelData.Add("Scale", string.Format("{0:0.0000}", staticModel.ModelScale).ToString(CultureInfo.InvariantCulture)); MapModels.Add(new Dictionary <string, string>(ModelData)); } } foreach (IDictionary entity in MapEntities) { MapModels.Add(entity); } // Done return(MapModels); }
/// <summary> /// Reads Static Models /// </summary> public unsafe static List <IWMap.Entity> ReadStaticModels(ProcessReader reader, long address, int count) { // Resulting Entities List <IWMap.Entity> entities = new List <IWMap.Entity>(count); // Read buffer var byteBuffer = reader.ReadBytes(address, count * Marshal.SizeOf <GfxStaticModel>()); // Loop number of models we have for (int i = 0; i < count; i++) { // Read Struct var staticModel = ByteUtil.BytesToStruct <GfxStaticModel>(byteBuffer, i * Marshal.SizeOf <GfxStaticModel>()); // Model Name var modelName = reader.ReadNullTerminatedString(reader.ReadInt64(staticModel.ModelPointer)); // New Matrix var matrix = new Rotation.Matrix(); // Copy X Values matrix.Values[0] = staticModel.Matrix[0]; matrix.Values[1] = staticModel.Matrix[1]; matrix.Values[2] = staticModel.Matrix[2]; // Copy Y Values matrix.Values[4] = staticModel.Matrix[3]; matrix.Values[5] = staticModel.Matrix[4]; matrix.Values[6] = staticModel.Matrix[5]; // Copy Z Values matrix.Values[8] = staticModel.Matrix[6]; matrix.Values[9] = staticModel.Matrix[7]; matrix.Values[10] = staticModel.Matrix[8]; // Convert to Euler var euler = matrix.ToEuler(); // Add it if (modelName.Contains("foliage")) { } else { entities.Add(IWMap.Entity.CreateMiscModel(modelName, new Vector3(staticModel.X, staticModel.Y, staticModel.Z), Rotation.ToDegrees(euler), staticModel.ModelScale)); } } // Done return(entities); }
///TODO: Fix this crap public static unsafe List <IWMap.Entity> ReadStaticModels(uint address, int count) { // Resulting Entities var entities = new List <IWMap.Entity>(count); // Read buffer var byteBuffer = console.GetMemory(address, (uint)(count * Marshal.SizeOf <GfxStaticModel>())); // Loop number of models we have for (var i = 0; i < count; i++) { // Read Struct var staticModel = ByteUtil.BytesToStruct <GfxStaticModel>(byteBuffer, i * Marshal.SizeOf <GfxStaticModel>()); // Model Name var modelName = console.ReadString((uint)staticModel.ModelPointer);//reader.ReadNullTerminatedString(reader.ReadInt32(staticModel.ModelPointer)); // New Matrix var matrix = new Rotation.Matrix { Values = { [0] = staticModel.Matrix[0], [1] = staticModel.Matrix[1], [2] = staticModel.Matrix[2], [4] = staticModel.Matrix[3], [5] = staticModel.Matrix[4], [6] = staticModel.Matrix[5], [8] = staticModel.Matrix[6], [9] = staticModel.Matrix[7], [10] = staticModel.Matrix[8] } }; // Copy X Values // Copy Y Values // Copy Z Values // Convert to Euler var euler = matrix.ToEuler(); // Add it entities.Add(IWMap.Entity.CreateMiscModel(modelName, new Vector3(staticModel.X, staticModel.Y, staticModel.Z), Rotation.ToDegrees(euler), staticModel.ModelScale)); } // Done return(entities); }
/// <summary> /// Reads BSP Data /// </summary> public static void ExportBSPData(ProcessReader reader, long assetPoolsAddress, long assetSizesAddress, string gameType, Action <object> printCallback = null) { // Found her printCallback?.Invoke("Found supported game: Call of Duty: Black Ops 2"); // Validate by XModel Name if (reader.ReadNullTerminatedString(reader.ReadInt32(reader.ReadInt32(assetPoolsAddress + 0x14) + 4)) == "defaultvehicle") { // Load BSP Pools (they only have a size of 1 so we have no free header) var gfxMapAsset = reader.ReadStruct <GfxMap>(reader.ReadInt32(assetPoolsAddress + 0x44)); // Name string gfxMapName = reader.ReadNullTerminatedString(gfxMapAsset.NamePointer); string mapName = reader.ReadNullTerminatedString(gfxMapAsset.MapNamePointer); // Verify a BSP is actually loaded (if in base menu, etc, no map is loaded) if (String.IsNullOrWhiteSpace(gfxMapName)) { printCallback?.Invoke("No BSP loaded. Enter Main Menu or a Map to load in the required assets."); } else { // New IW Map var mapFile = new IWMap(); // Print Info printCallback?.Invoke(String.Format("Loaded Gfx Map - {0}", gfxMapName)); printCallback?.Invoke(String.Format("Loaded Map - {0}", mapName)); printCallback?.Invoke(String.Format("Vertex Count - {0}", gfxMapAsset.GfxVertexCount)); printCallback?.Invoke(String.Format("Indices Count - {0}", gfxMapAsset.GfxIndicesCount)); printCallback?.Invoke(String.Format("Surface Count - {0}", gfxMapAsset.SurfaceCount)); printCallback?.Invoke(String.Format("Model Count - {0}", gfxMapAsset.GfxStaticModelsCount)); // Build output Folder string outputName = Path.Combine("exported_maps", "black_ops_2", gameType, mapName, mapName); Directory.CreateDirectory(Path.GetDirectoryName(outputName)); // Stop watch var stopWatch = Stopwatch.StartNew(); // Read Vertices printCallback?.Invoke("Parsing vertex data...."); var vertexBuffer = reader.ReadBytes(gfxMapAsset.GfxVerticesPointer, gfxMapAsset.GfxVertexBufferSize); printCallback?.Invoke(String.Format("Parsed vertex data in {0:0.00} seconds.", stopWatch.ElapsedMilliseconds / 1000.0)); // Reset timer stopWatch.Restart(); // Read Indices printCallback?.Invoke("Parsing surface indices...."); var indices = ReadGfxIndices(reader, gfxMapAsset.GfxIndicesPointer, gfxMapAsset.GfxIndicesCount); printCallback?.Invoke(String.Format("Parsed indices in {0:0.00} seconds.", stopWatch.ElapsedMilliseconds / 1000.0)); // Reset timer stopWatch.Restart(); // Read Indices printCallback?.Invoke("Parsing surfaces...."); var surfaces = ReadGfxSufaces(reader, gfxMapAsset.GfxSurfacesPointer, gfxMapAsset.SurfaceCount); printCallback?.Invoke(String.Format("Parsed surfaces in {0:0.00} seconds.", stopWatch.ElapsedMilliseconds / 1000.0)); // Reset timer stopWatch.Restart(); // Write OBJ printCallback?.Invoke("Converting to OBJ...."); // Create new OBJ var obj = new WavefrontOBJ(); // Image Names (for Search String) HashSet <string> imageNames = new HashSet <string>(); // Vertex Index Tracker int vertexIndex = 0; // Append Faces foreach (var surface in surfaces) { // Create new Material var material = ReadMaterial(reader, surface.MaterialPointer); // Add to images imageNames.Add(material.DiffuseMap); // Add it obj.AddMaterial(material); // Add points for (ushort i = 0; i < surface.FaceCount; i++) { // Face Indices var faceIndex1 = indices[i * 3 + surface.FaceIndex]; var faceIndex2 = indices[i * 3 + surface.FaceIndex + 1]; var faceIndex3 = indices[i * 3 + surface.FaceIndex + 2]; // Validate unique points, and write to OBJ if (faceIndex1 != faceIndex2 && faceIndex1 != faceIndex3 && faceIndex2 != faceIndex3) { // new Obj Face var objFace = new WavefrontOBJ.Face(material.Name); // Unpack vertices var vertex1 = UnpackVertex(ByteUtil.BytesToStruct <GfxVertex>(vertexBuffer, surface.VertexBufferOffset + (faceIndex1 * 36))); var vertex2 = UnpackVertex(ByteUtil.BytesToStruct <GfxVertex>(vertexBuffer, surface.VertexBufferOffset + (faceIndex2 * 36))); var vertex3 = UnpackVertex(ByteUtil.BytesToStruct <GfxVertex>(vertexBuffer, surface.VertexBufferOffset + (faceIndex3 * 36))); // Add Offsets obj.Vertices.Add(vertex1.Position); obj.Vertices.Add(vertex2.Position); obj.Vertices.Add(vertex3.Position); // Add Normals obj.Normals.Add(vertex1.Normal); obj.Normals.Add(vertex2.Normal); obj.Normals.Add(vertex3.Normal); // Add UVs obj.UVs.Add(vertex1.UV); obj.UVs.Add(vertex2.UV); obj.UVs.Add(vertex3.UV); // Add points objFace.Vertices[0] = new WavefrontOBJ.Face.Vertex(vertexIndex, vertexIndex, vertexIndex); objFace.Vertices[2] = new WavefrontOBJ.Face.Vertex(vertexIndex + 1, vertexIndex + 1, vertexIndex + 1); objFace.Vertices[1] = new WavefrontOBJ.Face.Vertex(vertexIndex + 2, vertexIndex + 2, vertexIndex + 2); // Add to OBJ obj.Faces.Add(objFace); vertexIndex += 3; } } } // Save it obj.Save(outputName + ".obj"); // Build search strinmg string searchString = ""; // Loop through images, and append each to the search string (for Wraith/Greyhound) foreach (string imageName in imageNames) { searchString += String.Format("{0},", Path.GetFileNameWithoutExtension(imageName)); } // Dump it File.WriteAllText(outputName + "_search_string.txt", searchString); // Read entities and dump to map mapFile.Entities.AddRange(ReadStaticModels(reader, gfxMapAsset.GfxStaticModelsPointer, gfxMapAsset.GfxStaticModelsCount)); mapFile.DumpToMap(outputName + ".map"); // Done printCallback?.Invoke(String.Format("Converted to OBJ in {0:0.00} seconds.", stopWatch.ElapsedMilliseconds / 1000.0)); } } else { printCallback?.Invoke("Call of Duty: Black Ops 2 is supported, but this EXE is not."); } }