Exemplo n.º 1
0
        /// <summary>
        /// Adds a parameterized set of vertices to the drawing devices rendering schedule.
        /// </summary>
        /// <typeparam name="T">The type of vertex data to add.</typeparam>
        /// <param name="material">The <see cref="Duality.Drawing.BatchInfo"/> to use for rendering the vertices.</param>
        /// <param name="vertexMode">The vertices drawing mode.</param>
        /// <param name="vertexBuffer">
        /// A vertex data buffer that stores the vertices to add. Ownership of the buffer
        /// remains at the callsite, while the <see cref="IDrawDevice"/> copies the required
        /// data into internal storage.
        /// </param>
        /// <param name="vertexCount">The number of vertices to add, from the beginning of the buffer.</param>
        public void AddVertices <T>(BatchInfo material, VertexMode vertexMode, T[] vertexBuffer, int vertexCount) where T : struct, IVertexData
        {
            if (vertexCount == 0)
            {
                return;
            }
            if (vertexBuffer == null || vertexBuffer.Length == 0)
            {
                return;
            }
            if (vertexCount > vertexBuffer.Length)
            {
                vertexCount = vertexBuffer.Length;
            }
            if (material == null)
            {
                material = Material.Checkerboard.Res.Info;
            }

            // In picking mode, override incoming vertices material and vertex colors
            // to generate a lookup texture by which we can retrieve each pixels object.
            if (this.pickingIndex != 0)
            {
                ColorRgba clr = new ColorRgba((this.pickingIndex << 8) | 0xFF);
                for (int i = 0; i < vertexCount; ++i)
                {
                    vertexBuffer[i].Color = clr;
                }

                material           = this.RentMaterial(material);
                material.Technique = DrawTechnique.Picking;
                material.MainColor = ColorRgba.White;
            }
            else if (material.Technique == null || !material.Technique.IsAvailable)
            {
                material           = this.RentMaterial(material);
                material.Technique = DrawTechnique.Solid;
            }

            // Move the added vertices to an internal shared buffer
            VertexSlice <T> slice = this.drawVertices.Rent <T>(vertexCount);

            Array.Copy(vertexBuffer, 0, slice.Data, slice.Offset, slice.Length);

            // Aggregate all info we have about our incoming vertices
            VertexDrawItem drawItem = new VertexDrawItem
            {
                Offset      = (ushort)slice.Offset,
                Count       = (ushort)slice.Length,
                BufferIndex = (byte)(this.drawVertices.GetBatchCount <T>() - 1),
                TypeIndex   = (byte)VertexDeclaration.Get <T>().TypeIndex,
                Mode        = vertexMode,
                Material    = material
            };

            // Determine whether we need depth sorting and calculate a reference depth
            bool sortByDepth = (this.projection == ProjectionMode.Screen) || material.Technique.Res.NeedsZSort;
            RawList <SortItem> sortBuffer = sortByDepth ? this.sortBufferBlended : this.sortBufferSolid;
            SortItem           sortItem   = new SortItem();

            if (sortByDepth)
            {
                sortItem.SortDepth = this.CalcZSortIndex <T>(vertexBuffer, vertexCount);
            }

            // Determine whether we can batch the new vertex item with the previous one
            int prevDrawIndex = -1;

            if (vertexMode.IsBatchableMode() && sortBuffer.Count > 0)
            {
                // Since we require a complete material match to append items, we can
                // assume that the previous items sortByDepth value is the same as ours.
                SortItem prevSortItem = sortBuffer.Data[sortBuffer.Count - 1];

                // Compare the previously added item with the new one. If everything
                // except the vertices themselves is the same, we can append them directly.
                if (this.drawBuffer.Data[prevSortItem.DrawItemIndex].CanAppend(ref drawItem) &&
                    (!sortByDepth || sortItem.CanShareDepth(prevSortItem.SortDepth)))
                {
                    prevDrawIndex = prevSortItem.DrawItemIndex;
                }
            }

            // Append the new item directly to the previous one, or add it as a new one
            if (prevDrawIndex != -1)
            {
                if (sortByDepth)
                {
                    sortBuffer.Data[sortBuffer.Count - 1].MergeDepth(
                        sortItem.SortDepth,
                        this.drawBuffer.Data[prevDrawIndex].Count,
                        drawItem.Count);
                }
                this.drawBuffer.Data[prevDrawIndex].Count += drawItem.Count;
            }
            else
            {
                sortItem.DrawItemIndex = this.drawBuffer.Count;
                sortBuffer.Add(sortItem);
                this.drawBuffer.Add(drawItem);
            }

            ++this.numRawBatches;
        }