Ejemplo n.º 1
0
        /// <summary>
        /// Converts input channels that are used for colors from Vector3/Vector4
        /// to single float format, if necessary.
        /// </summary>
        /// <param name="inputChannels">Vertex Channels as read from COLLADA file</param>
        private void ConvertColorChannels(List <VertexChannel> inputChannels)
        {
            foreach (VertexChannel channel in inputChannels)
            {
                var usage  = channel.Description.VertexElementUsage;
                var format = channel.Description.VertexElementFormat;

                if (usage != VertexElementUsage.Color)
                {
                    continue;                                    // only relevant for colors
                }
                if (format == VertexElementFormat.Single)
                {
                    continue;                                       // nothing to do
                }
                // Create updated vertex element description where each element is a single
                VertexElement newDesc = new VertexElement()
                {
                    Offset              = 0,
                    UsageIndex          = channel.Description.UsageIndex,
                    VertexElementFormat = VertexElementFormat.Single,
                    VertexElementUsage  = VertexElementUsage.Color
                };

                // Old stride is 3 or 4 (corresponding to Vector3 or Vector4)
                int     oldStride = channel.Source.Stride;
                float[] oldData   = channel.Source.Data;

                // Create new source where each color is only represented by one single
                VertexSource newSource = new VertexSource();
                newSource.Stride = 1; // one float per color
                newSource.Data   = new float[oldData.Length / oldStride];

                for (int i = 0; i < newSource.Data.Length; i++)
                {
                    // project start index to old data set (with $oldStride components per color)
                    int j = i * oldStride;

                    // Construct color from three or four floats in range [0,1]
                    Color color = (oldStride == 3) ?
                                  new Color(oldData[j + 0], oldData[j + 1], oldData[j + 2]) :
                                  new Color(oldData[j + 0], oldData[j + 1], oldData[j + 2], oldData[j + 3]);

                    newSource.Data[i] = ConvertColorToSingle(color);
                }

                // Update description and source of channel
                channel.Description = newDesc;
                channel.Source      = newSource;
            }
        }
Ejemplo n.º 2
0
 /// <summary>
 /// Creates a new Vertex Channel
 /// </summary>
 /// <param name="source">Used vertex source</param>
 /// <param name="description">Vertex element description</param>
 /// <param name="indices">Indices</param>
 public VertexChannel(VertexSource source, VertexElement description)
 {
     Source      = source;
     Description = description;
 }
Ejemplo n.º 3
0
        /// <summary>
        /// Creates a vertex container from a set of "raw" vertex channels as read from the COLLADA file.
        /// Hence, it is assumed that each channel uses its own source (rather than every channel using
        /// the same single source).
        /// </summary>
        /// <param name="inputChannels">Original Input Channels from COLLADA file</param>
        public VertexContainer(List <VertexChannel> inputChannels)
        {
            // Check for basic requirements
            if (inputChannels.Any(c => c.Description.VertexElementUsage == VertexElementUsage.Position) == false)
            {
                throw new ArgumentException("Geometry has not all needed information. At least Positions are necessary!");
            }

            // Convert Colors to single values, if necessary
            ConvertColorChannels(inputChannels);

            // Number of floats per vertex
            _vertexSize = CalculateVertexSize(inputChannels);

            // Expected number of indices
            int numIndices = inputChannels.First().Indices.Length;

            // vertex buffer with an expected number of 3/4 of the number of indices
            List <float> vbuffer = new List <float>(numIndices * 3 / 4);

            // Remember the position of distinct vertices to avoid duplicates
            Dictionary <VertexKey, int> usedVertices = new Dictionary <VertexKey, int>(numIndices * 3 / 4);

            // Indices referencing the new vertex buffer (vbuffer)
            List <int> indexList = new List <int>(numIndices);

            // Go through all indices to create vertices
            for (int i = 0; i < numIndices; i++)
            {
                VertexKey key       = new VertexKey(inputChannels, i);
                int       usedIndex = 0;

                if (usedVertices.TryGetValue(key, out usedIndex))
                {
                    // This vertex was already used, its index is "usedIndex"
                    indexList.Add(usedIndex);
                }
                else
                {
                    // If the vertex is unknown, add it to the vertex container (channel-wise)
                    // and remember that is has been used and the corresponding index
                    int index = vbuffer.Count / _vertexSize;

                    // Add all elements of the current vertex to the vertex buffer
                    foreach (VertexChannel channel in inputChannels)
                    {
                        float[] elementData = new float[channel.Source.Stride];
                        channel.GetValue(i, ref elementData, 0);

                        // origin of texture coordinates in XNA is top left, while
                        // in COLLADA it is bottom left. Therefore they need to be
                        // converted here
                        if (channel.Description.VertexElementUsage == VertexElementUsage.TextureCoordinate)
                        {
                            elementData[1] = 1 - elementData[1];
                        }

                        vbuffer.AddRange(elementData);
                    }

                    // Remember that this vertex combination was used before
                    // and store the index where it can be found in the
                    // vertex container
                    usedVertices.Add(key, index);

                    // Add reference to the just created vertex to the index list / buffer
                    indexList.Add(index);
                }
            }

            // Create adequate vertex channels
            int offset = 0;

            foreach (VertexChannel inputChannel in inputChannels)
            {
                VertexSource newSource = new VertexSource()
                {
                    Offset = offset // the element-offset within the vertex buffer
                };

                VertexElement desc = new VertexElement(offset, inputChannel.Description.VertexElementFormat,
                                                       inputChannel.Description.VertexElementUsage, inputChannel.Description.UsageIndex);

                VertexChannel newChannel = new VertexChannel(newSource, desc);
                _vertexChannels.Add(newChannel);

                offset += inputChannel.Source.Stride;
            }

            // Swap winding order
            for (int i = 0; i < indexList.Count; i += 3)
            {
                int swap = indexList[i + 1];
                indexList[i + 1] = indexList[i + 2];
                indexList[i + 2] = swap;
            }

            _data    = vbuffer.ToArray();
            _indices = indexList.ToArray();

            // Update Source Data reference off all vertex channels
            foreach (VertexChannel channel in _vertexChannels)
            {
                // Every channel uses the same source now (global vertex buffer)
                channel.Source.Data = _data;

                // Every channel also uses the same indices
                channel.Indices = _indices;

                // The stride of one entry containing all elements for one vertex
                channel.Source.Stride = _vertexSize;
            }
        }