private void ConvertMeshes(List <Mesh> meshes, VertexPositionBuffer positionBuffer, VertexNormalBuffer normalBuffer, VertexColorBuffer colorBuffer, VertexUVBuffer uvBuffer)
        {
            var state = new MeshRenderState();

            for (var i = 0; i < meshes.Count; i++)
            {
                var mesh = meshes[i];

                if (mesh.Parameters != null && mesh.Parameters.Count > 0)
                {
                    ProcessMeshParameters(mesh.Parameters, ref state);
                }

                var stateCopy = state;
                stateCopy.TextureId = 0;
                stateCopy.TileMode  = 0;
                //stateCopy.IndexFlags = 0;
                stateCopy.AmbientColor = new Color();
                sUniqueStates.Add(stateCopy);

                var aiMesh      = new Assimp.Mesh();
                var vertexCache = new List <Vertex>();

                Debug.Assert(state.IndexFlags.HasFlag(IndexAttributeFlags.HasPosition) ? positionBuffer != null : true);
                Debug.Assert(state.IndexFlags.HasFlag(IndexAttributeFlags.HasNormal) ? normalBuffer != null : true);
                Debug.Assert(state.IndexFlags.HasFlag(IndexAttributeFlags.HasColor) ? colorBuffer != null : true);
                Debug.Assert(state.IndexFlags.HasFlag(IndexAttributeFlags.HasUV) ? uvBuffer != null : true);

                // Extract all vertices used by the triangles, and build a new vertex list
                // with each vertex attribute clumped together
                var aiFace = new Assimp.Face();
                foreach (var index in mesh.DisplayLists.SelectMany(x => x.ToTriangles()))
                {
                    var vertex = new Vertex();

                    if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasPosition))
                    {
                        vertex.Position = positionBuffer.Elements[index.PositionIndex];
                    }

                    if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasNormal))
                    {
                        vertex.Normal = normalBuffer.Elements[index.NormalIndex];
                    }

                    if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasColor))
                    {
                        vertex.Color = colorBuffer.Elements[index.ColorIndex];
                    }

                    if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasUV))
                    {
                        vertex.UV = uvBuffer.Elements[index.UVIndex];
                    }

                    // Find index of this vertex in the list in case it already exists
                    var vertexIndex = vertexCache.IndexOf(vertex);
                    if (vertexIndex == -1)
                    {
                        vertexIndex = vertexCache.Count;
                        vertexCache.Add(vertex);
                    }

                    aiFace.Indices.Add(vertexIndex);

                    if (aiFace.IndexCount == 3)
                    {
                        // Done with this face, move on to the next one
                        aiMesh.Faces.Add(aiFace);
                        aiFace = new Assimp.Face();
                    }
                }

                // Convert vertices
                aiMesh.Vertices.AddRange(vertexCache.Select(x => ToAssimp(x.Position)));

                if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasNormal))
                {
                    aiMesh.Normals.AddRange(vertexCache.Select(x => ToAssimp(x.Normal)));
                }

                if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasUV))
                {
                    aiMesh.TextureCoordinateChannels[0].AddRange(vertexCache.Select(x => ToAssimp(UVCodec.Decode1023(x.UV))));
                }

                if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasColor))
                {
                    aiMesh.VertexColorChannels[0].AddRange(vertexCache.Select(x => ToAssimp(x.Color)));
                }

                // Convert material
                if (!mConvertedMaterialCache.TryGetValue(state, out var aiMaterialIndex))
                {
                    // Not in cache, so create a new one and add it
                    aiMaterialIndex = Scene.MaterialCount;
                    Scene.Materials.Add(CreateMaterial(Color.Gray, Color.Gray, Color.Gray, FormatTextureName(state.TextureId), false, false,
                                                       state.TileMode.HasFlag(TileMode.MirrorU),
                                                       state.TileMode.HasFlag(TileMode.MirrorV),
                                                       state.BlendAlphaFlags.HasFlag(BlendAlphaFlags.UseAlpha)));

                    mConvertedMaterialCache[state] = aiMaterialIndex;
                }

                aiMesh.MaterialIndex = aiMaterialIndex;

                // Add mesh to scene.
                Scene.Meshes.Add(aiMesh);
            }
        }
Beispiel #2
0
        private void ReadVertexAttributes(EndianBinaryReader reader)
        {
            VertexBuffers = new List <VertexAttributeBuffer>();

            while (true)
            {
                var type = ( VertexAttributeType )reader.ReadByte();
                if (type == VertexAttributeType.End)
                {
                    break;
                }

                var elementSize  = reader.ReadByte();
                var elementCount = reader.ReadUInt16();
                var field04      = reader.ReadInt32();
                var dataOffset   = reader.ReadUInt32();
                var dataSize     = reader.ReadUInt32();

                VertexAttributeBuffer buffer;

                switch (type)
                {
                case VertexAttributeType.Position:
                case VertexAttributeType.Normal:
                {
                    Vector3[] elements = null;
                    reader.ReadAtOffset(dataOffset, () => elements = reader.ReadVector3s(elementCount));

                    if (type == VertexAttributeType.Position)
                    {
                        buffer = new VertexPositionBuffer(elements);
                    }
                    else
                    {
                        buffer = new VertexNormalBuffer(elements);
                    }
                }
                break;

                case VertexAttributeType.Color:
                {
                    Color[] elements = null;
                    reader.ReadAtOffset(dataOffset, () =>
                        {
                            var endianness    = reader.Endianness;
                            reader.Endianness = Endianness.Big;
                            elements          = reader.ReadColors(elementCount);
                            reader.Endianness = endianness;
                        });
                    buffer = new VertexColorBuffer(elements);
                }
                break;

                case VertexAttributeType.UV:
                {
                    Vector2 <short>[] elements = null;
                    reader.ReadAtOffset(dataOffset, () => elements = reader.ReadVector2Int16s(elementCount));
                    buffer = new VertexUVBuffer(elements);
                }
                break;

                default:
                    throw new InvalidGeometryDataException($"Attempted to read invalid/unknown vertex attribute: {type}");
                }

                Debug.Assert(elementSize == buffer.ElementSize);
                Debug.Assert(elementCount == buffer.ElementCount);
                Debug.Assert(field04 == buffer.Field04);
                Debug.Assert(dataSize == buffer.DataSize);

                VertexBuffers.Add(buffer);
            }
        }