internal void ReadVertices(BinaryReaderEx br, int dataOffset, List <BufferLayout> layouts, FLVERHeader header, FlverCache cache) { var layoutMembers = layouts.SelectMany(l => l); int uvCap = layoutMembers.Where(m => m.Semantic == FLVER.LayoutSemantic.UV).Count(); int tanCap = layoutMembers.Where(m => m.Semantic == FLVER.LayoutSemantic.Tangent).Count(); int colorCap = layoutMembers.Where(m => m.Semantic == FLVER.LayoutSemantic.VertexColor).Count(); VertexCount = VertexBuffers[0].VertexCount; Vertices = cache.GetCachedVertexArray(VertexCount); if (Vertices == null) { Vertices = new FLVER.Vertex[VertexCount]; for (int i = 0; i < VertexCount; i++) { Vertices[i] = new FLVER.Vertex(uvCap, tanCap, colorCap); } cache.CacheVertexArray(Vertices); } else { for (int i = 0; i < Vertices.Length; i++) { Vertices[i].UVCount = 0; Vertices[i].TangentCount = 0; } } foreach (VertexBuffer buffer in VertexBuffers) { buffer.ReadBuffer(br, layouts, Vertices, VertexCount, dataOffset, header); } }
public ushort[] ToTriangleList() { var converted = new List <ushort>(); bool checkFlip = false; bool flip = false; for (int i = 0; i < VertexIndices.Length - 2; i++) { ushort vi1 = VertexIndices[i]; ushort vi2 = VertexIndices[i + 1]; ushort vi3 = VertexIndices[i + 2]; if (vi1 == 0xFFFF || vi2 == 0xFFFF || vi3 == 0xFFFF) { checkFlip = true; } else { if (vi1 != vi2 && vi1 != vi3 && vi2 != vi3) { // Every time the triangle strip restarts, compare the average vertex normal to the face normal // and flip the starting direction if they're pointing away from each other. // I don't know why this is necessary; in most models they always restart with the same orientation // as you'd expect. But on some, I can't discern any logic to it, thus this approach. // It's probably hideously slow because I don't know anything about math. // Feel free to hit me with a PR. :slight_smile: if (checkFlip) { FLVER.Vertex v1 = Vertices[vi1]; FLVER.Vertex v2 = Vertices[vi2]; FLVER.Vertex v3 = Vertices[vi3]; Vector3 n1 = new Vector3(v1.Normal.X, v1.Normal.Y, v1.Normal.Z); Vector3 n2 = new Vector3(v2.Normal.X, v2.Normal.Y, v2.Normal.Z); Vector3 n3 = new Vector3(v3.Normal.X, v3.Normal.Y, v3.Normal.Z); Vector3 vertexNormal = Vector3.Normalize((n1 + n2 + n3) / 3); Vector3 faceNormal = Vector3.Normalize(Vector3.Cross(v2.Position - v1.Position, v3.Position - v1.Position)); float angle = Vector3.Dot(faceNormal, vertexNormal) / (faceNormal.Length() * vertexNormal.Length()); flip = angle >= 0; checkFlip = false; } if (!flip) { converted.Add(vi1); converted.Add(vi2); converted.Add(vi3); } else { converted.Add(vi3); converted.Add(vi2); converted.Add(vi1); } } flip = !flip; } } return(converted.ToArray()); }
internal Mesh(BinaryReaderEx br, List <Material> materials, int dataOffset) { Dynamic = br.ReadBoolean(); MaterialIndex = br.ReadByte(); Unk02 = br.ReadBoolean(); Unk03 = br.ReadByte(); int vertexIndexCount = br.ReadInt32(); int vertexCount = br.ReadInt32(); DefaultBoneIndex = br.ReadInt16(); BoneIndices = br.ReadInt16s(28); br.AssertInt16(0); br.AssertInt32(vertexIndexCount * 2); int vertexIndicesOffset = br.ReadInt32(); int bufferSize = br.ReadInt32(); int bufferOffset = br.ReadInt32(); br.ReadInt32(); // Buffers header offset br.AssertInt32(0); br.AssertInt32(0); VertexIndices = br.GetUInt16s(dataOffset + vertexIndicesOffset, vertexIndexCount); br.StepIn(dataOffset + bufferOffset); { BufferLayout layout = null; foreach (var bl in materials[MaterialIndex].Layouts) { if (bl.Size * vertexCount == bufferSize) { layout = bl; } } float uvFactor = 1024; // NB hack if (!br.BigEndian) { uvFactor = 2048; } Vertices = new List <FLVER.Vertex>(vertexCount); for (int i = 0; i < vertexCount; i++) { var vert = new FLVER.Vertex(); vert.Read(br, layout, uvFactor); Vertices.Add(vert); } } br.StepOut(); }
internal Mesh(BinaryReaderEx br, FLVER0 flv, int dataOffset) { Dynamic = br.ReadByte(); MaterialIndex = br.ReadByte(); Unk02 = br.ReadBoolean(); Unk03 = br.ReadByte(); int vertexIndexCount = br.ReadInt32(); int vertexCount = br.ReadInt32(); DefaultBoneIndex = br.ReadInt16(); BoneIndices = br.ReadInt16s(28); Unk46 = br.ReadInt16(); br.ReadInt32(); // Vertex indices length int vertexIndicesOffset = br.ReadInt32(); int bufferDataLength = br.ReadInt32(); int bufferDataOffset = br.ReadInt32(); int vertexBuffersOffset1 = br.ReadInt32(); int vertexBuffersOffset2 = br.ReadInt32(); br.AssertInt32(0); if (flv.VertexIndexSize == 16) { VertexIndices = new List <int>(vertexCount); foreach (ushort index in br.GetUInt16s(dataOffset + vertexIndicesOffset, vertexIndexCount)) { VertexIndices.Add(index); } } else if (flv.VertexIndexSize == 32) { VertexIndices = new List <int>(br.GetInt32s(dataOffset + vertexIndicesOffset, vertexIndexCount)); } VertexBuffer buffer; // Stupid hack for old (version F?) flvers; for example DeS o9993. if (vertexBuffersOffset1 == 0) { buffer = new VertexBuffer() { BufferLength = bufferDataLength, BufferOffset = bufferDataOffset, LayoutIndex = 0, }; } else { br.StepIn(vertexBuffersOffset1); { List <VertexBuffer> vertexBuffers1 = VertexBuffer.ReadVertexBuffers(br); if (vertexBuffers1.Count == 0) { throw new NotSupportedException("First vertex buffer list is expected to contain at least 1 buffer."); } for (int i = 1; i < vertexBuffers1.Count; i++) { if (vertexBuffers1[i].BufferLength != 0) { throw new NotSupportedException("Vertex buffers after the first one in the first buffer list are expected to be empty."); } } buffer = vertexBuffers1[0]; } br.StepOut(); } if (vertexBuffersOffset2 != 0) { br.StepIn(vertexBuffersOffset2); { List <VertexBuffer> vertexBuffers2 = VertexBuffer.ReadVertexBuffers(br); if (vertexBuffers2.Count != 0) { throw new NotSupportedException("Second vertex buffer list is expected to contain exactly 0 buffers."); } } br.StepOut(); } br.StepIn(dataOffset + buffer.BufferOffset); { LayoutIndex = buffer.LayoutIndex; BufferLayout layout = flv.Materials[MaterialIndex].Layouts[LayoutIndex]; float uvFactor = 1024; // NB hack if (!br.BigEndian) { uvFactor = 2048; } Vertices = new List <FLVER.Vertex>(vertexCount); for (int i = 0; i < vertexCount; i++) { var vert = new FLVER.Vertex(); vert.Read(br, layout, uvFactor); Vertices.Add(vert); } } br.StepOut(); }