// split VBE by stream private VertexElementDescriptor[][] SplitVBE(VertexElementDescriptor[] input) { VertexElementDescriptor[][] elements = new VertexElementDescriptor[2][]; // pass 1 byte[] sizes = { 0, 0 }; for (int i = 0; i < input.Length; ++i) { sizes[input[i].Stream] += 1; } // pass 2 elements[0] = new VertexElementDescriptor[sizes[0]]; elements[1] = new VertexElementDescriptor[sizes[1]]; sizes = new byte[] { 0, 0 }; for (int i = 0; i < input.Length; ++i) { byte stream = input[i].Stream; elements[stream][sizes[stream]] = input[i]; sizes[stream] += 1; } return(elements); }
/// <summary>Generate <see cref="Submesh"/> objects</summary> private void GenerateMeshes(BinaryReader reader) { Submeshes = new Submesh[SubmeshDescriptors.Length]; for (int i = 0; i < SubmeshDescriptors.Length; ++i) { SubmeshDescriptor submeshDescriptor = SubmeshDescriptors[i]; //VertexBufferDescriptor vbo = VertexBuffers[submeshDescriptor.VertexBuffer]; IndexBufferDescriptor ibo = IndexBuffers[submeshDescriptor.IndexBuffer]; byte uvCount = GetMaxIndex(VertexElements[submeshDescriptor.VertexBuffer], teShaderInstance.ShaderInputUse.TexCoord); Submesh submesh = new Submesh(submeshDescriptor, uvCount); reader.BaseStream.Position = ibo.DataStreamPointer + submeshDescriptor.IndexStart * 2; Dictionary <int, ushort> indexRemap = new Dictionary <int, ushort>(); Dictionary <int, int> indexRemapInvert = new Dictionary <int, int>(); // todo: make this cleaner for (int j = 0; j < submeshDescriptor.IndicesToDraw; j++) { ushort index = reader.ReadUInt16(); ushort newIndex; if (indexRemap.ContainsKey(index)) { newIndex = indexRemap[index]; // "index of", value = fake index } else { newIndex = (ushort)indexRemap.Count; indexRemap[index] = newIndex; indexRemapInvert[newIndex] = index; } submesh.Indices[j] = newIndex; } VertexElementDescriptor[][] elements = SplitVBE(VertexElements[submeshDescriptor.VertexBuffer]); for (int j = 0; j < Stride[submeshDescriptor.VertexBuffer].Length; ++j) { for (int k = 0; k < submeshDescriptor.VerticesToDraw; ++k) { long offset = submeshDescriptor.VertexStart + indexRemapInvert[k]; for (int l = 0; l < elements[j].Length; ++l) { VertexElementDescriptor element = elements[j][l]; if (element.Format == SemanticFormat.NONE) { break; } object value = Stride[submeshDescriptor.VertexBuffer][j][offset][l]; switch (element.Type) { case teShaderInstance.ShaderInputUse.Position: if (element.Index == 0) { float[] position = (float[])value; submesh.Vertices[k] = new teVec3(position); } else { Debugger.Log(2, "teModelChunk_RenderMesh", $"Unhandled vertex layer {element.Index:X} for type {element.Type}!\n"); } break; case teShaderInstance.ShaderInputUse.Normal: if (element.Index == 0) { float[] normal = (float[])value; submesh.Normals[k] = new teVec3(normal.Take(3).ToArray()); } else { Debugger.Log(2, "teModelChunk_RenderMesh", $"Unhandled vertex layer {element.Index:X} for type {element.Type}!\n"); } break; case teShaderInstance.ShaderInputUse.TexCoord: { ushort[] uv = (ushort[])value; submesh.UV[k][element.Index] = teVec2.FromHalf(uv); } break; case teShaderInstance.ShaderInputUse.BlendIndices: if (element.Index == 0) { byte[] boneIndex = (byte[])value; submesh.BoneIndices[k] = new ushort[boneIndex.Length]; for (int m = 0; m < boneIndex.Length; ++m) { submesh.BoneIndices[k][m] = (ushort)(boneIndex[m] + submeshDescriptor.BoneIdOffset); } } else { Debugger.Log(2, "teModelChunk_RenderMesh", $"Unhandled vertex layer {element.Index:X} for type {element.Type}!\n"); } break; case teShaderInstance.ShaderInputUse.BlendWeights: if (element.Index == 0) { submesh.BoneWeights[k] = (float[])value; } else { Debugger.Log(2, "teModelChunk_RenderMesh", $"Unhandled vertex layer {element.Index:X} for type {element.Type}!\n"); } break; case teShaderInstance.ShaderInputUse.Tangent: float[] tangent = (float[])value; submesh.Tangents[k] = new teVec4(tangent); break; case teShaderInstance.ShaderInputUse.VertexIndex: // todo: lolno uint id = (uint)value; submesh.IDs[k] = id; break; case teShaderInstance.ShaderInputUse.Color: float[] col = (float[])value; if (element.Index == 0) { submesh.Color1[k] = new teColorRGBA(col); } else if (element.Index == 1) { submesh.Color2[k] = new teColorRGBA(col); } else { Debugger.Log(2, "teModelChunk_RenderMesh", $"Unhandled vertex color index: {element.Index:X}\n"); } break; default: if (UnhandledSemanticTypes.Add(element.Type) && Debugger.IsAttached) { Debugger.Log(2, "teModelChunk_RenderMesh", $"Unhandled vertex type {element.Type}!\n"); } break; } } } } Submeshes[i] = submesh; } }