/// <summary> /// Draw the vertices group as primitives, using an optional index buffer (indices) and a <see cref="StreamFrequency"/> object to specify Hardware Instancing information (Shader Model 3 and Windows Only) /// </summary> /// <param name="state"></param> /// <param name="indices">(optional) indices to use during drawing</param> /// <param name="primitiveType">Primitive type to draw, eg PrimitiveType.TriangleList</param> /// <param name="frequency">(optional) <see cref="StreamFrequency"/> setting the shader model 3 instance frequency data (used for hardware instancing)</param> /// <param name="primitveCount">The number of primitives to draw</param> /// <param name="startIndex">The start index in the index buffer (defaults to the first index - 0)</param> /// <param name="vertexOffset">Starting offset into the vertex buffer (defaults to the first vertex - 0)</param> /// <remarks></remarks> public void Draw(DrawState state, IIndices indices, PrimitiveType primitiveType, StreamFrequency frequency, int primitveCount, int startIndex, int vertexOffset) { if (frequency != null && !state.SupportsHardwareInstancing) { throw new InvalidOperationException("Only windows devices supporting Shader Model 3.0 or better to can use hardware instancing. Check DrawState.SupportsHardwareInstancing"); } #if XBOX360 if (frequency != null) { #if DEBUG if (frequency.layout != StreamFrequency.DataLayout.Stream0Geometry_Stream1InstanceData) { throw new InvalidOperationException("Only StreamFrequency DataLayout of Stream0Geometry_Stream1InstanceData is emulated on the xbox360"); } if (primitveCount != int.MaxValue || startIndex != 0 || vertexOffset != 0) { throw new ArgumentException("Only default values for primitiveCount, startIndex and vertexOffset may be used when emulating instancing on the xbox"); } if (primitiveType == PrimitiveType.TriangleFan || primitiveType == PrimitiveType.TriangleStrip || primitiveType == PrimitiveType.LineStrip) { throw new ArgumentException("Only Primitive List Types (eg TriangleList) are supported as a primitiveType when emulating instancing on the xbox"); } #endif if (indices != null) { ((IDeviceIndexBuffer)indices).AllocateForInstancing(state); } } #endif GraphicsDevice device = state.graphics; IDeviceIndexBuffer devib = indices as IDeviceIndexBuffer; IndexBuffer ib = null; if (devib != null) { ib = devib.GetIndexBuffer(state); } if (decl == null) { decl = ((IDeviceVertexBuffer)this).GetVertexDeclaration(state.Application); } state.VertexDeclaration = decl; #if DEBUG state.ValidateVertexDeclarationForShader(decl, null); #endif int vertices = 0; for (int i = 0; i < buffers.Length; i++) { IDeviceVertexBuffer dev = buffers[i] as IDeviceVertexBuffer; if (dev != null) { state.SetStream(i, dev.GetVertexBuffer(state), offsets[i], buffers[i].Stride); } else { state.SetStream(i, null, 0, 0); } if (i == 0) { vertices = buffers[i].Count; } else if (frequency == null) { vertices = Math.Min(buffers[i].Count, vertices); } } state.IndexBuffer = ib; if (ib != null) { vertices = indices.Count; } int primitives = 0; switch (primitiveType) { case PrimitiveType.LineList: primitives = vertices / 2; break; case PrimitiveType.LineStrip: primitives = vertices - 1; break; case PrimitiveType.PointList: primitives = vertices; break; case PrimitiveType.TriangleList: primitives = vertices / 3; break; case PrimitiveType.TriangleFan: case PrimitiveType.TriangleStrip: primitives = vertices - 2; break; } int vertexCount = 0; if (indices != null) { vertexCount = indices.MaxIndex + 1; } else { switch (primitiveType) { case PrimitiveType.LineStrip: vertexCount = primitives * 2; break; case PrimitiveType.PointList: case PrimitiveType.LineList: case PrimitiveType.TriangleList: vertexCount = vertices; break; case PrimitiveType.TriangleFan: case PrimitiveType.TriangleStrip: vertexCount = primitives * 3; break; } } state.ApplyRenderStateChanges(vertexCount); #if DEBUG int instances = 1; #endif #if !XBOX360 if (frequency != null && frequency.frequency.Length >= this.buffers.Length) { #if DEBUG if (frequency.indexFrequency.Length > 0) { System.Threading.Interlocked.Increment(ref state.Application.currentFrame.InstancesDrawBatchCount); state.Application.currentFrame.InstancesDrawn += frequency.indexFrequency[0]; instances = frequency.indexFrequency[0]; } #endif for (int i = 0; i < this.buffers.Length; i++) { VertexStream vs = device.Vertices[i]; if (frequency.frequency[i] != 0) { vs.SetFrequency(frequency.frequency[i]); } if (frequency.indexFrequency[i] != 0) { vs.SetFrequencyOfIndexData(frequency.indexFrequency[i]); } if (frequency.dataFrequency[i] != 0) { vs.SetFrequencyOfInstanceData(frequency.dataFrequency[i]); } } } #endif if (primitveCount != int.MaxValue) { if (primitveCount > primitives || primitveCount <= 0) { throw new ArgumentException("primitiveCount"); } } else { primitveCount = primitives; } #if DEBUG state.CalcBoundTextures(); #endif //it is possible to have the debug runtime throw an exception here when using instancing, //as it thinks stream1 doesn't have enough data. //This is most common with sprite groups (however sprite groups will use shader-instancing with small groups) //eg, drawing a single instance requires only 64bytes in stream1, yet the triangle count could be very large //this makes the debug runtime think that stream1 doesn't have enough data if (ib != null) { #if DEBUG System.Threading.Interlocked.Increment(ref state.Application.currentFrame.DrawIndexedPrimitiveCallCount); #endif #if XBOX360 if (frequency != null) { int repeats = frequency.RepeatCount; #if DEBUG System.Threading.Interlocked.Increment(ref state.Application.currentFrame.InstancesDrawBatchCount); state.Application.currentFrame.InstancesDrawn += frequency.indexFrequency[0]; instances = repeats; #endif int maxInstances = ((IDeviceIndexBuffer)indices).MaxInstances; int offset = 0; VertexBuffer vb = ((IDeviceVertexBuffer)buffers[1]).GetVertexBuffer(state); while (repeats - offset > 0) { if (offset != 0) { //read the next set of instances state.SetStream(1, vb, offsets[1] + 64 * offset, buffers[1].Stride); } int count = Math.Min(repeats - offset, maxInstances); device.DrawIndexedPrimitives(primitiveType, vertexOffset, indices.MinIndex, ((indices.MaxIndex) + 1) - indices.MinIndex - vertexOffset, startIndex, primitveCount * count); offset += count; } } else #endif device.DrawIndexedPrimitives(primitiveType, vertexOffset, indices.MinIndex, (indices.MaxIndex - indices.MinIndex) + 1 - vertexOffset, startIndex, primitveCount); } else { #if DEBUG System.Threading.Interlocked.Increment(ref state.Application.currentFrame.DrawPrimitivesCallCount); #endif #if XBOX360 if (frequency != null) { int repeats = frequency.RepeatCount; int maxInstances = ((IDeviceIndexBuffer)indices).MaxInstances; int offset = 0; VertexBuffer vb = ((IDeviceVertexBuffer)buffers[1]).GetVertexBuffer(state); while (repeats - offset > 0) { if (offset != 0) { //read the next set of instances state.SetStream(1, vb, offsets[1] + 64 * offset, buffers[1].Stride); } int count = Math.Min(repeats - offset, maxInstances); device.DrawPrimitives(primitiveType, vertexOffset, primitveCount * count); offset += count; } } else #endif device.DrawPrimitives(primitiveType, vertexOffset, primitveCount); } #if DEBUG switch (primitiveType) { case PrimitiveType.LineList: case PrimitiveType.LineStrip: state.Application.currentFrame.LinesDrawn += primitives * instances; break; case PrimitiveType.PointList: state.Application.currentFrame.PointsDrawn += primitives * instances; break; case PrimitiveType.TriangleList: case PrimitiveType.TriangleFan: case PrimitiveType.TriangleStrip: state.Application.currentFrame.TrianglesDrawn += primitives * instances; break; } #endif #if !XBOX360 if (frequency != null && frequency.frequency.Length >= this.buffers.Length) { device.Vertices[0].SetFrequency(1); } #endif for (int i = 0; i < buffers.Length; i++) { if (i > 0) { state.SetStream(i, null, 0, 0); } } }
/// <summary> /// Draw the vertices as primitives with extended parametres, using an optional index buffer (indices) /// </summary> /// <param name="state"></param> /// <param name="indices">indices to use when drawing (may be null)</param> /// <param name="primitiveType">Primitive type to use when drawing the buffer</param> /// <param name="primitveCount">The number of primitives to draw</param> /// <param name="startIndex">The start index in the index buffer (defaults to the first index - 0)</param> /// <param name="vertexOffset">Starting offset into the vertex buffer (defaults to the first vertex - 0)</param> public void Draw(DrawState state, IIndices indices, PrimitiveType primitiveType, int primitveCount, int startIndex, int vertexOffset) { GraphicsDevice device = state.graphics; if (state.DrawTarget == null) { throw new InvalidOperationException("Vertices Draw calls should be done within the Draw() call of a DrawTarget object. (otherwise the draw target is undefined)"); } ValidateDisposed(); IDeviceIndexBuffer devib = (IDeviceIndexBuffer)indices; IndexBuffer ib = null; if (devib != null) { ib = devib.GetIndexBuffer(state); } if (decl == null) { Warm(state); } VertexBuffer vb = ((IDeviceVertexBuffer)this).GetVertexBuffer(state); VertexDeclaration vd = this.decl; #if DEBUG state.ValidateVertexDeclarationForShader(vd, typeof(VertexType)); #endif state.VertexDeclaration = vd; state.IndexBuffer = ib; state.SetStream(0, vb, 0, buffer.Stride); int vertices = buffer.Count; if (indices != null) { vertices = indices.Count; } int primitives = 0; switch (primitiveType) { case PrimitiveType.LineList: primitives = vertices / 2; break; case PrimitiveType.LineStrip: primitives = vertices - 1; break; case PrimitiveType.PointList: primitives = vertices; break; case PrimitiveType.TriangleList: primitives = vertices / 3; break; case PrimitiveType.TriangleFan: case PrimitiveType.TriangleStrip: primitives = vertices - 2; break; } int vertexCount = 0; if (indices != null) { vertexCount = indices.MaxIndex + 1; } else { switch (primitiveType) { case PrimitiveType.LineStrip: vertexCount = primitives * 2; break; case PrimitiveType.PointList: case PrimitiveType.LineList: case PrimitiveType.TriangleList: vertexCount = vertices; break; case PrimitiveType.TriangleFan: case PrimitiveType.TriangleStrip: vertexCount = primitives * 3; break; } } state.ApplyRenderStateChanges(vertexCount); if (primitveCount > primitives || primitveCount <= 0) { throw new ArgumentException("primitiveCount"); } #if DEBUG state.CalcBoundTextures(); #endif if (indices != null) { #if DEBUG System.Threading.Interlocked.Increment(ref state.Application.currentFrame.DrawIndexedPrimitiveCallCount); #endif device.DrawIndexedPrimitives(primitiveType, vertexOffset, indices.MinIndex, (indices.MaxIndex - indices.MinIndex) + 1 - vertexOffset, startIndex, primitveCount); } else { #if DEBUG System.Threading.Interlocked.Increment(ref state.Application.currentFrame.DrawPrimitivesCallCount); #endif device.DrawPrimitives(primitiveType, vertexOffset, primitveCount); } #if DEBUG switch (primitiveType) { case PrimitiveType.LineList: case PrimitiveType.LineStrip: state.Application.currentFrame.LinesDrawn += primitives; break; case PrimitiveType.PointList: state.Application.currentFrame.PointsDrawn += primitives; break; case PrimitiveType.TriangleList: case PrimitiveType.TriangleFan: case PrimitiveType.TriangleStrip: state.Application.currentFrame.TrianglesDrawn += primitives; break; } #endif }
public void Draw(DrawState state, IIndices indices, PrimitiveType primitiveType, int primitveCount, int startIndex, int vertexOffset) { ValidateDisposed(); IDeviceIndexBuffer devib = (IDeviceIndexBuffer)indices; IndexBuffer ib = null; if (devib != null) { ib = devib.GetIndexBuffer(state); } if (_vertexDeclaration == null) { _vertexDeclaration = Context.VertexDeclarationBuilder.GetDeclaration <TVertexType>(); } VertexBuffer vb = ((IDeviceVertexBuffer)this).GetVertexBuffer(state); VertexDeclaration vd = _vertexDeclaration; state.VertexDeclaration = vd; state.IndexBuffer = ib; state.SetStream(0, vb, 0, _buffer.Stride); int vertices = _buffer.Count; if (indices != null) { vertices = indices.Count; } int primitives = 0; switch (primitiveType) { case PrimitiveType.LineList: primitives = vertices / 2; break; case PrimitiveType.LineStrip: primitives = vertices - 1; break; case PrimitiveType.PointList: primitives = vertices; break; case PrimitiveType.TriangleList: primitives = vertices / 3; break; case PrimitiveType.TriangleFan: case PrimitiveType.TriangleStrip: primitives = vertices - 2; break; } int vertexCount = 0; if (indices != null) { vertexCount = indices.MaxIndex + 1; } else { switch (primitiveType) { case PrimitiveType.LineStrip: vertexCount = primitives * 2; break; case PrimitiveType.PointList: case PrimitiveType.LineList: case PrimitiveType.TriangleList: vertexCount = vertices; break; case PrimitiveType.TriangleFan: case PrimitiveType.TriangleStrip: vertexCount = primitives * 3; break; } } state.ApplyRenderStateChanges(vertexCount); if (primitveCount > primitives || primitveCount <= 0) { throw new ArgumentException("primitiveCount"); } if (indices != null) { Context.DrawIndexedPrimitive(primitiveType, vertexOffset, indices.MinIndex, (indices.MaxIndex - indices.MinIndex) + 1 - vertexOffset, startIndex, primitveCount); } else { Context.DrawPrimitives(primitiveType, vertexOffset, primitveCount); } #if DEBUG switch (primitiveType) { case PrimitiveType.LineList: case PrimitiveType.LineStrip: Context.PerformanceMonitor.IncreaseCounter(DeviceCounters.LinesDrawn, primitives); break; case PrimitiveType.PointList: Context.PerformanceMonitor.IncreaseCounter(DeviceCounters.PointsDrawn, primitives); break; case PrimitiveType.TriangleList: case PrimitiveType.TriangleFan: case PrimitiveType.TriangleStrip: Context.PerformanceMonitor.IncreaseCounter(DeviceCounters.TrianglesDrawn, primitives); break; } #endif }