public static List <dynamic> parseTGXAsset(ExpandoObject staticTgxBin) { Console.WriteLine("Parsing model data..."); dynamic tgxBin = staticTgxBin; dynamic metadata = tgxBin.metadata; // Arrangement dynamic meshes = new List <dynamic>(); for (var r = 0; r < metadata.render_model.GetProperty("render_meshes").GetArrayLength(); r++) { Console.WriteLine("Parsing object " + r + "..."); var renderMeshIndex = r; dynamic renderMesh = metadata.render_model.GetProperty("render_meshes")[renderMeshIndex]; // BoB Bunch of Bits // IndexBuffer Console.Write("Parsing object " + r + " index buffer... "); var indexBufferInfo = renderMesh.GetProperty("index_buffer"); byte[] indexBufferData = tgxBin.files[indexBufferInfo.GetProperty("file_name").GetString()].data; dynamic indexBuffer = new List <ushort>(); for (int j = 0; j < indexBufferInfo.GetProperty("byte_size").GetInt32(); j += indexBufferInfo.GetProperty("value_byte_size").GetInt32()) { var indexValue = BitConverter.ToUInt16(indexBufferData, j); indexBuffer.Add(indexValue); } //console.log('IndexBuffer', indexBufferInfo); Console.WriteLine("Done."); // SkinBuffer SkinBufferData skinBuffer = new SkinBufferData("", new List <byte>(), new Dictionary <int, SkinBufferChunk>()); var skinBufferInfo = new JsonElement(); if (renderMesh.TryGetProperty("single_pass_skin_vertex_buffer", out skinBufferInfo) && skinBufferInfo.GetProperty("byte_size").GetInt32() > 0) { Console.Write("Parsing object " + r + " skinning buffer... "); skinBuffer = parseSkinBuffer(skinBufferInfo, tgxBin.files[skinBufferInfo.GetProperty("file_name").GetString()]); Console.WriteLine("Done."); } // VertexBuffer Console.Write("Parsing object " + r + " vertex buffers... "); List <Dictionary <string, dynamic> > vertexBuffer = parseVertexBuffers(staticTgxBin, renderMesh); Console.WriteLine("Done."); // DataDrivenVertexBuffer List <byte[]> dataDrivenVertexBuffer = new List <byte[]>(); var dataDrivenVertexBufferInfo = new JsonElement(); if (renderMesh.TryGetProperty("data_driven_vertex_buffer", out dataDrivenVertexBufferInfo) && dataDrivenVertexBufferInfo.GetProperty("byte_size").GetInt32() > 0) { Console.Write("Parsing object " + r + " data driven vertex buffer... "); byte[] rawBuffer = tgxBin.files[dataDrivenVertexBufferInfo.GetProperty("file_name").GetString()].data; //Console.WriteLine(renderMesh.GetProperty("vertex_buffers")[0].GetProperty("byte_size").GetInt32()/32); for (int b = 0; b < vertexBuffer.Count /*renderMesh.GetProperty("vertex_buffers")[0].GetProperty("byte_size").GetInt32()/32*/; b++) { //int startIndex = b*4; double[] vertBuff = new double[4] { 0, 0, 0, 0 }; //{rawBuffer[b], rawBuffer[b+1], rawBuffer[b+2], rawBuffer[b+3]}; //dataDrivenVertexBuffer.Add(vertBuff); for (int c = 0; c < 4; c++) { if (b >= dataDrivenVertexBufferInfo.GetProperty("byte_size").GetInt32() / 4) { continue; } vertBuff[c] = rawBuffer[(b * 4) + c] / 255.0; } vertexBuffer[b].Add("color0", vertBuff); } Console.WriteLine("Done."); } List <Dictionary <string, dynamic> > parts = new List <Dictionary <string, dynamic> >(); List <int> partIndexList = new List <int>(); int[] stagesToRender = { 0, 7, 15 }; // Hardcoded? //dynamic partOffsets = new JArray(); Console.Write("Parsing object " + r + " stage parts... "); for (int sP = 0; sP < renderMesh.GetProperty("stage_part_list").GetArrayLength(); sP++) { dynamic stagePart = renderMesh.GetProperty("stage_part_list")[sP]; if (stagePart.ValueKind == JsonValueKind.Undefined) { //console.warn('MissingStagePart['+renderMeshIndex+':'+partOffset+']'); //Console.WriteLine("MissingStagePart["+renderMeshIndex+":"+partOffset+"]"); continue; } if (partIndexList.IndexOf(stagePart.GetProperty("start_index").GetInt32()) != -1) { // Skip duplicate parts continue; } partIndexList.Add(stagePart.GetProperty("start_index").GetInt32()); parts.Add(parseStagePart(stagePart)); } Console.WriteLine("Done."); // Spasm.RenderMesh dynamic mesh = new ExpandoObject(); mesh.positionOffset = renderMesh.GetProperty("position_offset"); mesh.positionScale = renderMesh.GetProperty("position_scale"); mesh.texcoordOffset = renderMesh.GetProperty("texcoord_offset"); mesh.texcoordScale = renderMesh.GetProperty("texcoord_scale"); mesh.texcoord0ScaleOffset = renderMesh.GetProperty("texcoord0_scale_offset"); mesh.indexBuffer = indexBuffer; mesh.vertexBuffer = vertexBuffer; mesh.skinBuffer = skinBuffer; //mesh.dataDrivenVertexBuffer = dataDrivenVertexBuffer.ToArray(); mesh.parts = parts; meshes.Add(mesh); } Console.WriteLine("Model data parsed."); return(meshes); }
public static SkinBufferData parseSkinBuffer( dynamic VertexBufferInfo, ExpandoObject TGXFileEntry = null ) { dynamic info = VertexBufferInfo; dynamic file = TGXFileEntry; //debug("TGXLoader:SkinBuffer", VertexBufferInfo); SkinBufferData skinBuffer = new SkinBufferData ( info.GetProperty("file_name").GetString(), //id new List <byte>(), //header new Dictionary <int, SkinBufferChunk>() //data ); if (TGXFileEntry != null) { bool isHeader = true; int chunkWeight = 0; int weightOffset = 0; int stride = info.GetProperty("stride_byte_size").GetInt32(); for (int i = 0; i < info.GetProperty("byte_size").GetInt32(); i += stride) { uint skinVertex = BitConverter.ToUInt32(file.data, i); if (stride != 4) { ConsoleEx.Warn("Skinbuffer stride is not equal to 4."); } byte index0 = (byte)((skinVertex >> 0) & 0xff); byte index1 = (byte)((skinVertex >> 8) & 0xff); byte weight0 = (byte)((skinVertex >> 16) & 0xff); byte weight1 = (byte)((skinVertex >> 24) & 0xff); if (chunkWeight == 0) { weightOffset = i; } int chunkIndex = weightOffset / 4; int strideIndex = i / 4; if (!skinBuffer.data.ContainsKey(strideIndex)) { skinBuffer.data.Add(strideIndex, new SkinBufferChunk( strideIndex, 0, new List <byte>(), new List <byte>() ) ); } SkinBufferChunk chunkData = skinBuffer.data[chunkIndex]; //Console.WriteLine($"{i} {index0} {index1} {weight0} {weight1}"); //if(i>31) // for brute forcing past the header when someone needs an item and I can't figure out a fix quickly. // Odds of a header chunk having unmatched index0+weight0 AND total weight bytes of 255 is very low, // toss in similarly low odds of first weight chunk being 4-bone skinning and it should hopefully never fail. if (isHeader && (index0 != weight0) && (weight0 + weight1 == 255) && i + stride < file.data.Length) { uint nextSkinVertex = BitConverter.ToUInt32(file.data, i + stride); uint nextIndex0 = (nextSkinVertex >> 0) & 0xff; uint nextIndex1 = (nextSkinVertex >> 8) & 0xff; uint nextWeight0 = (nextSkinVertex >> 16) & 0xff; uint nextWeight1 = (nextSkinVertex >> 24) & 0xff; // DENDRITE SHIMMER BOND F*****G BROKE THIS!!!!!!!!!! :)))))))))) if ((nextIndex0 != nextWeight0) && (nextWeight0 + nextWeight1 == 255)) { isHeader = false; ConsoleEx.Warn($"1 {i} {index0} {index1} {weight0} {weight1}"); } } else if (isHeader && i + stride < file.data.Length) { uint nextSkinVertex = BitConverter.ToUInt32(file.data, i + stride); uint nextIndex0 = (nextSkinVertex >> 0) & 0xff; uint nextIndex1 = (nextSkinVertex >> 8) & 0xff; uint nextWeight0 = (nextSkinVertex >> 16) & 0xff; uint nextWeight1 = (nextSkinVertex >> 24) & 0xff; if ((index0 != weight0) && (weight0 + weight1 + nextWeight0 + nextWeight1 == 255)) { ConsoleEx.Warn($"2 {i} {index0} {index1} {weight0} {weight1}"); isHeader = false; } } if (isHeader) { skinBuffer.header.Add(index0); skinBuffer.header.Add(index1); skinBuffer.header.Add(weight0); skinBuffer.header.Add(weight1); } else if (skinVertex == 0) { // Skip empty blocks } else { //{weight0, weight1}.forEach((weight) => { foreach (byte weight in new byte[] { weight0, weight1 }) { if (weight > 0) { chunkData.count++; } chunkWeight += weight; } ; chunkData.indices.Add(index0); chunkData.indices.Add(index1); chunkData.weights.Add(weight0); chunkData.weights.Add(weight1); if (chunkWeight >= 255) { chunkWeight = 0; } } } } return(skinBuffer); }