public static List <Dictionary <string, dynamic> > parseVertexBuffers(ExpandoObject staticTgxBin, dynamic staticRenderMesh) { dynamic tgxBin = staticTgxBin; dynamic renderMesh = staticRenderMesh; if (renderMesh.GetProperty("stage_part_vertex_stream_layout_definitions").GetArrayLength() > 1) { ConsoleEx.Warn("Multiple Stage Part Vertex Layout Definitions", renderMesh.GetProperty("stage_part_vertex_stream_layout_definitions")); } dynamic stagePartVertexStreamLayoutDefinition = renderMesh.GetProperty("stage_part_vertex_stream_layout_definitions")[0]; dynamic formats = stagePartVertexStreamLayoutDefinition.GetProperty("formats"); List <Dictionary <string, dynamic> > vertexBuffer = new List <Dictionary <string, dynamic> >(); for (var vertexBufferIndex = 0; vertexBufferIndex < renderMesh.GetProperty("vertex_buffers").GetArrayLength(); vertexBufferIndex++) { dynamic vertexBufferInfo = renderMesh.GetProperty("vertex_buffers")[vertexBufferIndex]; byte[] vertexBufferData = tgxBin.files[vertexBufferInfo.GetProperty("file_name").GetString()].data; dynamic format = formats[vertexBufferIndex]; var vertexIndex = 0; for (var v = 0; v < vertexBufferInfo.GetProperty("byte_size").GetInt32(); v += vertexBufferInfo.GetProperty("stride_byte_size").GetInt32()) { var vertexOffset = v; if (vertexBuffer.Count <= vertexIndex) { vertexBuffer.Add(new Dictionary <string, dynamic>()); //vertexBuffer[vertexIndex] = new JObject(); } for (var e = 0; e < format.GetProperty("elements").GetArrayLength(); e++) { dynamic element = format.GetProperty("elements")[e]; List <dynamic> values = new List <dynamic>(); List <byte> rawBytes = new List <byte>(); string elementType = element.GetProperty("type").GetString().Replace("_vertex_format_attribute_", ""); string[] types = new string[] { "ubyte", "byte", "ushort", "short", "uint", "int", "float" }; foreach (var typeIndex in types) { string type = typeIndex; if (elementType.IndexOf(type) == 0) { var count = Convert.ToInt32(elementType.Replace(type, "")); var j = 0; dynamic value; switch (type) { case "ubyte": for (j = 0; j < count; j++) { value = vertexBufferData[vertexOffset]; if (element.GetProperty("normalized").GetBoolean()) { value = TGXMUtils.unormalize(value, 8); } values.Add(value); rawBytes.Add(vertexBufferData[vertexOffset]); vertexOffset++; } break; case "byte": for (j = 0; j < count; j++) { value = TGXMUtils.Sbyte(vertexBufferData, vertexOffset); if (element.GetProperty("normalized").GetBoolean()) { value = TGXMUtils.normalize(value, 8); } values.Add(value); rawBytes.Add(vertexBufferData[vertexOffset]); vertexOffset++; } break; case "ushort": for (j = 0; j < count; j++) { value = BitConverter.ToUInt16(vertexBufferData, vertexOffset); if (element.GetProperty("normalized").GetBoolean) { value = TGXMUtils.unormalize(value, 16); } values.Add(value); rawBytes.Add(vertexBufferData[vertexOffset]); rawBytes.Add(vertexBufferData[vertexOffset + 1]); vertexOffset += 2; } break; case "short": for (j = 0; j < count; j++) { value = BitConverter.ToInt16(vertexBufferData, vertexOffset); if (element.GetProperty("normalized").GetBoolean()) { value = TGXMUtils.normalize(value, 16); } values.Add(value); rawBytes.Add(vertexBufferData[vertexOffset]); rawBytes.Add(vertexBufferData[vertexOffset + 1]); vertexOffset += 2; } break; case "uint": for (j = 0; j < count; j++) { value = BitConverter.ToUInt32(vertexBufferData, vertexOffset); if (element.GetProperty("normalized").GetBoolean()) { value = TGXMUtils.unormalize(value, 32); } values.Add(value); rawBytes.Add(vertexBufferData[vertexOffset]); rawBytes.Add(vertexBufferData[vertexOffset + 1]); rawBytes.Add(vertexBufferData[vertexOffset + 2]); rawBytes.Add(vertexBufferData[vertexOffset + 3]); vertexOffset += 4; } break; case "int": for (j = 0; j < count; j++) { value = BitConverter.ToInt32(vertexBufferData, vertexOffset); if (element.GetProperty("normalized").GetBoolean()) { value = TGXMUtils.normalize(value, 32); } values.Add(value); rawBytes.Add(vertexBufferData[vertexOffset]); rawBytes.Add(vertexBufferData[vertexOffset + 1]); rawBytes.Add(vertexBufferData[vertexOffset + 2]); rawBytes.Add(vertexBufferData[vertexOffset + 3]); vertexOffset += 4; } break; case "float": for (j = 0; j < count; j++) { value = BitConverter.ToSingle(vertexBufferData, vertexOffset); values.Add(value); rawBytes.Add(vertexBufferData[vertexOffset]); rawBytes.Add(vertexBufferData[vertexOffset + 1]); rawBytes.Add(vertexBufferData[vertexOffset + 2]); rawBytes.Add(vertexBufferData[vertexOffset + 3]); vertexOffset += 4; } break; } break; } } string semantic = element.GetProperty("semantic").GetString().Replace("_tfx_vb_semantic_", ""); switch (semantic) { case "position": case "normal": case "tangent": case "blendweight": // Bone weights 0-1 case "blendindices": // Bone indices, 255=none, index starts at 1? case "color": break; case "texcoord": semantic = "uv"; break; default: Console.WriteLine($"Unknown Vertex Semantic : {semantic} : {element.semantic_index}"); break; } int semantic_index = (int)element.GetProperty("semantic_index").GetInt32(); if (semantic_index != 0) { semantic_index--; } vertexBuffer[vertexIndex].Add(semantic + semantic_index, values.ToArray()); vertexBuffer[vertexIndex].Add(semantic + semantic_index + "_raw", rawBytes.ToArray()); } vertexIndex++; } } return(vertexBuffer); }
public static dynamic loadTGXBin(byte[] data) { Console.WriteLine("Loading model data..."); Console.Write("Reading TGXM header... "); string magic = TGXMUtils.String(data, 0x0, 0x4); // TGXM int version = (int)BitConverter.ToUInt32(data, 0x4); int fileOffset = (int)BitConverter.ToUInt32(data, 0x8); int fileCount = (int)BitConverter.ToUInt32(data, 0xC); string fileIdentifier = TGXMUtils.String(data, 0x10, 0x100); if (magic != "TGXM") { Console.WriteLine("Invalid TGX File, skipping"); return(null); } Console.WriteLine("Done."); Dictionary <string, dynamic> files = new Dictionary <string, dynamic>(); //dynamic fileLookup = new JArray(); dynamic renderMetadata = new Object(); for (var f = 0; f < fileCount; f++) //Parallel.For(0, fileCount, f => { int headerOffset = fileOffset + (0x110 * f); string name = TGXMUtils.String(data, headerOffset, 0x100); int offset = (int)BitConverter.ToUInt32(data, headerOffset + 0x100); int type = (int)BitConverter.ToUInt32(data, headerOffset + 0x104); int size = (int)BitConverter.ToUInt32(data, headerOffset + 0x108); Console.WriteLine("Loading file \"" + name + ".\" File size: " + size + " bytes."); byte[] fileData = new byte[size]; if (!File.Exists(Path.Combine("Tilemaps", $"{name}.dds"))) { Array.ConstrainedCopy(data, offset, fileData, 0, size); } else { fileData = File.ReadAllBytes(Path.Combine("Tilemaps", $"{name}.dds")); } dynamic file = new ExpandoObject(); file.name = name; file.offset = offset; file.type = type; file.size = size; if (name.IndexOf(".js") != -1) { // render_metadata.js renderMetadata = JsonSerializer.Deserialize <RenderMetadata>(TGXMUtils.String(fileData, 0, 0)); files.Add("render_metadata_js", fileData); file.data = renderMetadata; } else { file.data = fileData; } files.Add(name, file); //fileLookup.Add(name); Console.WriteLine("File \"" + name + "\" loaded."); } //); dynamic tgxBin = new ExpandoObject(); tgxBin.fileIdentifier = fileIdentifier; tgxBin.files = files; //tgxBin.lookup = fileLookup; tgxBin.metadata = renderMetadata; Console.WriteLine("Done loading model data."); return(tgxBin); }