/// <inheritdoc/> public void DrawBillboard(ref BillboardArgs billboard, PackedTexture texture) { int index, dummy; _renderBatch.Submit(PrimitiveType.TriangleList, 4, 6, out index, out dummy); OnDrawBillboard(ref billboard, texture, _renderBatch.Vertices, index); }
private void Stroke(FigureNode node, ArrayList<Vector3> strokeVertices, ArrayList<int> strokeIndices) { if (_mode != RenderMode.Stroke) { Flush(); _strokeEffect.CurrentTechnique.Passes[0].Apply(); _mode = RenderMode.Stroke; } // Use cached vertex buffer if available. var nodeRenderData = node.RenderData as FigureNodeRenderData; if (nodeRenderData != null && nodeRenderData.IsValid) { Flush(); var graphicsDevice = _graphicsService.GraphicsDevice; graphicsDevice.SetVertexBuffer(nodeRenderData.StrokeVertexBuffer); graphicsDevice.Indices = nodeRenderData.StrokeIndexBuffer; int primitiveCount = nodeRenderData.StrokeIndexBuffer.IndexCount / 3; graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, primitiveCount); #else int vertexCount = nodeRenderData.StrokeVertexBuffer.VertexCount; graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertexCount, 0, primitiveCount); return; } var batchVertices = _strokeBatch.Vertices; var world = node.PoseWorld * Matrix.CreateScale(node.ScaleWorld); var worldView = _view * world; var thickness = node.StrokeThickness; var color3F = node.StrokeColor * node.StrokeAlpha; var color = new HalfVector4(color3F.X, color3F.Y, color3F.Z, node.StrokeAlpha); var dash = node.StrokeDashPattern * node.StrokeThickness; bool usesDashPattern = (dash.Y + dash.Z) != 0; var dashSum = new HalfVector4( dash.X, dash.X + dash.Y, dash.X + dash.Y + dash.Z, dash.X + dash.Y + dash.Z + dash.W); // Convert to vertices. float lastDistance = 0; Vector3 lastPosition = new Vector3(float.NaN); Vector3 lastWorld = new Vector3(); Vector3 lastView = new Vector3(); Vector3 lastProjected = new Vector3(); var data0 = new HalfVector4(0, 1, thickness, 0); var data1 = new HalfVector4(0, 0, thickness, 0); var data2 = new HalfVector4(1, 0, thickness, 0); var data3 = new HalfVector4(1, 1, thickness, 0); Vector3[] figurePoints = strokeVertices.Array; int[] figureIndices = strokeIndices.Array; int numberOfLineSegments = strokeIndices.Count / 2; for (int i = 0; i < numberOfLineSegments; i++) { var startIndex = figureIndices[i * 2 + 0]; var endIndex = figureIndices[i * 2 + 1]; var start = figurePoints[startIndex]; var end = figurePoints[endIndex]; var notConnectedWithLast = start != lastPosition; lastPosition = end; Vector3 startWorld = notConnectedWithLast ? world.TransformPosition(start) : lastWorld; Vector3 endWorld = world.TransformPosition(end); lastWorld = endWorld; // Compute start/end distances of lines from beginning of line strip // for dash patterns. float startDistance = 0; float endDistance = 1; if (usesDashPattern) { if (!node.DashInWorldSpace) { Vector3 startView = notConnectedWithLast ? worldView.TransformPosition(start) : lastView; var endView = worldView.TransformPosition(end); lastView = endView; // Clip to near plane - otherwise lines which end near the camera origin // (where planar z == 0) will disappear. (Projection singularity!) float deltaZ = Math.Abs(startView.Z - endView.Z); float pStart = MathHelper.Clamp((startView.Z - (-_cameraNear)) / deltaZ, 0, 1); startView = InterpolationHelper.Lerp(startView, endView, pStart); float pEnd = MathHelper.Clamp((endView.Z - (-_cameraNear)) / deltaZ, 0, 1); endView = InterpolationHelper.Lerp(endView, startView, pEnd); Vector3 startProjected; if (notConnectedWithLast) { lastDistance = 0; startProjected = _viewport.ProjectToViewport(startView, _projection); } else { startProjected = lastProjected; } var endProjected = _viewport.ProjectToViewport(endView, _projection); lastProjected = endProjected; startDistance = lastDistance; endDistance = startDistance + (endProjected - startProjected).Length; lastDistance = endDistance; } else { if (notConnectedWithLast) lastDistance = 0; startDistance = lastDistance; endDistance = startDistance + (endWorld - startWorld).Length; lastDistance = endDistance; // The shader needs to know that DashInWorldSpace is true. To avoid // effect parameter changes, we store the value in the sign of the distance! startDistance = -startDistance; endDistance = -endDistance; } } var s = new Vector4(startWorld.X, startWorld.Y, startWorld.Z, startDistance); var e = new Vector4(endWorld.X, endWorld.Y, endWorld.Z, endDistance); int index, dummy; _strokeBatch.Submit(PrimitiveType.TriangleList, 4, 6, out index, out dummy); batchVertices[index + 0].Start = s; batchVertices[index + 0].End = e; batchVertices[index + 0].Data = data0; batchVertices[index + 0].Color = color; batchVertices[index + 0].Dash = dashSum; batchVertices[index + 1].Start = s; batchVertices[index + 1].End = e; batchVertices[index + 1].Data = data1; batchVertices[index + 1].Color = color; batchVertices[index + 1].Dash = dashSum; batchVertices[index + 2].Start = s; batchVertices[index + 2].End = e; batchVertices[index + 2].Data = data2; batchVertices[index + 2].Color = color; batchVertices[index + 2].Dash = dashSum; batchVertices[index + 3].Start = s; batchVertices[index + 3].End = e; batchVertices[index + 3].Data = data3; batchVertices[index + 3].Color = color; batchVertices[index + 3].Dash = dashSum; } }
private void Fill(FigureNode node, ArrayList<Vector3> vertices, ArrayList<int> indices) { if (_mode != RenderMode.Fill) { Flush(); _fillEffect.CurrentTechnique.Passes[0].Apply(); _mode = RenderMode.Fill; } // Use cached vertex buffer if available. var nodeRenderData = node.RenderData as FigureNodeRenderData; if (nodeRenderData != null && nodeRenderData.IsValid) { Flush(); var graphicsDevice = _graphicsService.GraphicsDevice; graphicsDevice.SetVertexBuffer(nodeRenderData.FillVertexBuffer); graphicsDevice.Indices = nodeRenderData.FillIndexBuffer; int primitiveCount = nodeRenderData.FillIndexBuffer.IndexCount / 3; graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, primitiveCount); #else int vertexCount = nodeRenderData.FillVertexBuffer.VertexCount; graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertexCount, 0, primitiveCount); return; } Matrix world = node.PoseWorld * Matrix.CreateScale(node.ScaleWorld); Vector3 color3F = node.FillColor * node.FillAlpha; Color color = new Color(color3F.X, color3F.Y, color3F.Z, node.FillAlpha); var numberOfVertices = vertices.Count; var numberOfIndices = indices.Count; VertexPositionColor[] batchVertices = _fillBatch.Vertices; ushort[] batchIndices = _fillBatch.Indices; if (numberOfVertices > batchVertices.Length || numberOfIndices > batchIndices.Length) { string message = string.Format( CultureInfo.InvariantCulture, "The BufferSize of this FigureRenderer is not large enough to render the FigureNode (Name = \"{0}\").", node.Name); throw new GraphicsException(message); } int vertexBufferStartIndex, indexBufferStartIndex; _fillBatch.Submit(PrimitiveType.TriangleList, numberOfVertices, numberOfIndices, out vertexBufferStartIndex, out indexBufferStartIndex); // Copy all vertices. Vector3[] vertexArray = vertices.Array; for (int i = 0; i < numberOfVertices; i++) { batchVertices[vertexBufferStartIndex + i].Position = (Vector3)(world.TransformPosition(vertexArray[i])); batchVertices[vertexBufferStartIndex + i].Color = color; } // Copy all indices. int[] indexArray = indices.Array; for (int i = 0; i < numberOfIndices; i++) { batchIndices[indexBufferStartIndex + i] = (ushort)(vertexBufferStartIndex + indexArray[i]); } }