// Add a random path. private void CreateRandomPath() { var path = new Path3F(); var point = new Vector3F(0, 0, 0); path.Add(new PathKey3F { Interpolation = SplineInterpolation.CatmullRom, Parameter = 0, Point = point }); for (int i = 1; i < 10; i++) { point += RandomHelper.Random.NextQuaternionF().Rotate(new Vector3F(0, 0.5f, 0)); path.Add(new PathKey3F { Interpolation = SplineInterpolation.CatmullRom, Parameter = i, Point = point }); } var pathFigure = new PathFigure3F(); pathFigure.Segments.Add(path); var pathLineNode = new FigureNode(pathFigure) { Name = "RandomPath", PoseLocal = new Pose(new Vector3F(4, 1, 2)), StrokeThickness = 3, StrokeColor = new Vector3F(0.5f, 0.3f, 1), StrokeAlpha = 1f, DashInWorldSpace = true, StrokeDashPattern = new Vector4F(10, 1, 1, 1) / 100, }; _scene.Children.Add(pathLineNode); }
private static void CacheVertexBuffer(FigureNode node, GraphicsDevice graphicsDevice) { var figureRenderData = node.Figure.RenderData; var nodeRenderData = (FigureNodeRenderData)node.RenderData; Vector3[] positions = figureRenderData.Vertices.Array; var fillIndices = figureRenderData.FillIndices; if (fillIndices != null && fillIndices.Count > 0 && !Numeric.IsZero(node.FillAlpha)) { // This code is similar to the code in Fill(). 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); int numberOfVertices = figureRenderData.Vertices.Count; int numberOfIndices = figureRenderData.FillIndices.Count; VertexPositionColor[] vertices = new VertexPositionColor[numberOfVertices]; // Copy all vertices. for (int i = 0; i < numberOfVertices; i++) { vertices[i].Position = (Vector3)world.TransformPosition(positions[i]); vertices[i].Color = color; } nodeRenderData.FillVertexBuffer = new VertexBuffer( graphicsDevice, VertexPositionColor.VertexDeclaration, numberOfVertices, BufferUsage.WriteOnly); nodeRenderData.FillVertexBuffer.SetData(vertices); if (numberOfVertices <= ushort.MaxValue) { // Copy all indices from int[] to ushort[]. int[] int32Indices = figureRenderData.FillIndices.Array; ushort[] indices = new ushort[numberOfIndices]; for (int i = 0; i < numberOfIndices; i++) indices[i] = (ushort)int32Indices[i]; nodeRenderData.FillIndexBuffer = new IndexBuffer( graphicsDevice, IndexElementSize.SixteenBits, numberOfIndices, BufferUsage.WriteOnly); nodeRenderData.FillIndexBuffer.SetData(indices); } else { nodeRenderData.FillIndexBuffer = new IndexBuffer( graphicsDevice, IndexElementSize.ThirtyTwoBits, numberOfIndices, BufferUsage.WriteOnly); // Note: The FillIndices.Array may contain more than numberOfIndices entries! --> // Specify number of indices explicitly! nodeRenderData.FillIndexBuffer.SetData(figureRenderData.FillIndices.Array, 0, numberOfIndices); } } var strokeIndices = figureRenderData.StrokeIndices; if (strokeIndices != null && strokeIndices.Count > 0 && !Numeric.IsZero(node.StrokeThickness) && !Numeric.IsZero(node.StrokeAlpha)) { // This code is similar to the code in Stroke() and in the ctor. Matrix world = node.PoseWorld * Matrix.CreateScale(node.ScaleWorld); float thickness = node.StrokeThickness; Vector3 color3F = node.StrokeColor * node.StrokeAlpha; HalfVector4 color = new HalfVector4(color3F.X, color3F.Y, color3F.Z, node.StrokeAlpha); Vector4 dash = node.StrokeDashPattern * node.StrokeThickness; bool usesDashPattern = (dash.Y + dash.Z) != 0; HalfVector4 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(); HalfVector4 data0 = new HalfVector4(0, 1, thickness, 0); HalfVector4 data1 = new HalfVector4(0, 0, thickness, 0); HalfVector4 data2 = new HalfVector4(1, 0, thickness, 0); HalfVector4 data3 = new HalfVector4(1, 1, thickness, 0); int[] figureIndices = strokeIndices.Array; int numberOfLineSegments = strokeIndices.Count / 2; int numberOfVertices = numberOfLineSegments * 4; StrokeVertex[] vertices = new StrokeVertex[numberOfVertices]; for (int i = 0; i < numberOfLineSegments; i++) { int startIndex = figureIndices[i * 2 + 0]; int endIndex = figureIndices[i * 2 + 1]; Vector3 start = positions[startIndex]; Vector3 end = positions[endIndex]; bool 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) { Debug.Assert(node.DashInWorldSpace, "Cannot cache vertex buffer for figure with screen-space dash patterns."); 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; } Vector4 s = new Vector4(startWorld.X, startWorld.Y, startWorld.Z, startDistance); Vector4 e = new Vector4(endWorld.X, endWorld.Y, endWorld.Z, endDistance); vertices[i * 4 + 0].Start = s; vertices[i * 4 + 0].End = e; vertices[i * 4 + 0].Data = data0; vertices[i * 4 + 0].Color = color; vertices[i * 4 + 0].Dash = dashSum; vertices[i * 4 + 1].Start = s; vertices[i * 4 + 1].End = e; vertices[i * 4 + 1].Data = data1; vertices[i * 4 + 1].Color = color; vertices[i * 4 + 1].Dash = dashSum; vertices[i * 4 + 2].Start = s; vertices[i * 4 + 2].End = e; vertices[i * 4 + 2].Data = data2; vertices[i * 4 + 2].Color = color; vertices[i * 4 + 2].Dash = dashSum; vertices[i * 4 + 3].Start = s; vertices[i * 4 + 3].End = e; vertices[i * 4 + 3].Data = data3; vertices[i * 4 + 3].Color = color; vertices[i * 4 + 3].Dash = dashSum; } nodeRenderData.StrokeVertexBuffer = new VertexBuffer( graphicsDevice, StrokeVertex.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly); nodeRenderData.StrokeVertexBuffer.SetData(vertices); // Create stroke indices. int numberOfIndices = numberOfLineSegments * 6; if (numberOfVertices <= ushort.MaxValue) { ushort[] indices = new ushort[numberOfIndices]; for (int i = 0; i < numberOfLineSegments; i++) { // Create index buffer for quad (= two triangles, clockwise). // 1--2 // | /| // |/ | // 0--3 indices[i * 6 + 0] = (ushort)(i * 4 + 0); indices[i * 6 + 1] = (ushort)(i * 4 + 1); indices[i * 6 + 2] = (ushort)(i * 4 + 2); indices[i * 6 + 3] = (ushort)(i * 4 + 0); indices[i * 6 + 4] = (ushort)(i * 4 + 2); indices[i * 6 + 5] = (ushort)(i * 4 + 3); } nodeRenderData.StrokeIndexBuffer = new IndexBuffer( graphicsDevice, IndexElementSize.SixteenBits, numberOfIndices, BufferUsage.WriteOnly); nodeRenderData.StrokeIndexBuffer.SetData(indices); } else { int[] indices = new int[numberOfIndices]; for (int i = 0; i < numberOfLineSegments; i++) { // Create index buffer for quad (= two triangles, clockwise). // 1--2 // | /| // |/ | // 0--3 indices[i * 6 + 0] = i * 4 + 0; indices[i * 6 + 1] = i * 4 + 1; indices[i * 6 + 2] = i * 4 + 2; indices[i * 6 + 3] = i * 4 + 0; indices[i * 6 + 4] = i * 4 + 2; indices[i * 6 + 5] = i * 4 + 3; } nodeRenderData.StrokeIndexBuffer = new IndexBuffer( graphicsDevice, IndexElementSize.ThirtyTwoBits, numberOfIndices, BufferUsage.WriteOnly); nodeRenderData.StrokeIndexBuffer.SetData(indices); } } nodeRenderData.IsValid = true; }
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]); } }
private void CreateGate() { // not gate var trianglePath = new Path2F { new PathKey2F { Parameter = 0, Interpolation = SplineInterpolation.Linear, Point = new Vector2F(1, 0), }, new PathKey2F { Parameter = 1, Interpolation = SplineInterpolation.Linear, Point = new Vector2F(-0.25f, 0.5f), }, new PathKey2F { Parameter = 2, Interpolation = SplineInterpolation.Linear, Point = new Vector2F(-0.25f, -0.5f), }, new PathKey2F { Parameter = 3, Interpolation = SplineInterpolation.Linear, Point = new Vector2F(1, 0), } }; var triangle = new PathFigure2F(); triangle.Segments.Add(trianglePath); var outPinFigure = new PathFigure2F { Segments = { new LineSegment2F() { Point1 = new Vector2F(1, 0), Point2 = new Vector2F(1.2f, 0) } } }; // Add figure to the scene. var notGateNode = new FigureNode(triangle) { Name = "Not Gate", StrokeThickness = 2, StrokeColor = new Vector3F(1, 0.2f, 0.2f), FillColor = new Vector3F(1, 0.5f, 0.5f), FillAlpha = 0.5f, PoseLocal = new Pose(new Vector3F(0, 0, 0)), ScaleLocal = new Vector3F(1), Children = new SceneNodeCollection(3), }; var pinFigure = new PathFigure2F { Segments = { new LineSegment2F { Point1 = new Vector2F(0, 0), Point2 = new Vector2F(0.2f, 0) } } }; var pinsFigure = new CompositeFigure(); var output = new TransformedFigure(pinFigure) { Pose = new Pose(new Vector3F(1.0f, 0, 0)) }; pinsFigure.Children.Add(output); var ina = new TransformedFigure(pinFigure) { Pose = new Pose(new Vector3F(-0.25f - 0.2f, -0.25f, 0)) }; pinsFigure.Children.Add(ina); var inb = new TransformedFigure(pinFigure) { Pose = new Pose(new Vector3F(-0.25f - 0.2f, 0.25f, 0)) }; pinsFigure.Children.Add(inb); notGateNode.Children.Add(new FigureNode(pinsFigure) { Name = "Pins", StrokeThickness = 2, StrokeColor = new Vector3F(0, 0, 0), PoseLocal = new Pose(new Vector3F(0, 0, 0)), ScaleLocal = new Vector3F(1f), }); Scene.Children.Add(notGateNode); }
// TODO(matt) - grid creation needs to be able to be customized and should also be to a specific scale // TODO(matt) - should also have an intuitive control panel with presets and real time feedback // Add a grid with thick major grid lines and thin stroked minor grid lines. private void CreateGrid() { var majorGridLines = new PathFigure2F(); for (int i = 0; i <= 100; i++) { majorGridLines.Segments.Add(new LineSegment2F { Point1 = new Vector2F(-50, -50 + i), Point2 = new Vector2F(50, -50 + i), }); majorGridLines.Segments.Add(new LineSegment2F { Point1 = new Vector2F(-50 + i, -50), Point2 = new Vector2F(-50 + i, 50), }); } var minorGridLines = new PathFigure2F(); for (int i = 0; i < 100; i++) { minorGridLines.Segments.Add(new LineSegment2F { Point1 = new Vector2F(-50, -40.5f + i), Point2 = new Vector2F(50, -40.5f + i), }); minorGridLines.Segments.Add(new LineSegment2F { Point1 = new Vector2F(-40.5f + i, -50), Point2 = new Vector2F(-40.5f + i, 50), }); } var majorLinesNode = new FigureNode(majorGridLines) { Name = "Major grid lines", PoseLocal = Pose.Identity, StrokeThickness = 1, StrokeColor = new Vector3F(0.1f), StrokeAlpha = 1f, }; var minorLinesNode = new FigureNode(minorGridLines) { Name = "Minor grid lines", PoseLocal = Pose.Identity, StrokeThickness = 0.5f, StrokeColor = new Vector3F(0.1f), StrokeAlpha = 1f, //DashInWorldSpace = true, //StrokeDashPattern = new Vector4F(10, 4, 0, 0) / 200, }; var gridNode = new SceneNode { Name = "Grid", Children = new SceneNodeCollection(), PoseLocal = new Pose(new Vector3F(0, -0.5f, 0)), }; gridNode.Children.Add(majorLinesNode); gridNode.Children.Add(minorLinesNode); Scene.Children.Add(gridNode); }
// Add some rectangles. private void CreateRectangles() { Figure figure = new RectangleFigure { IsFilled = false, WidthX = 1f, WidthY = 0.5f, }; FigureNode figureNode = new FigureNode(figure) { Name = "Rectangle #1", StrokeThickness = 1, StrokeColor = new Vector3F(0.7f, 0.3f, 0.5f), StrokeAlpha = 1, PoseLocal = new Pose(new Vector3F(-2, 1, 0)) }; _scene.Children.Add(figureNode); figure = new RectangleFigure { IsFilled = false, WidthX = 0.5f, WidthY = 0.8f, }; figureNode = new FigureNode(figure) { Name = "Rectangle #2", StrokeThickness = 3, StrokeColor = new Vector3F(0.2f, 0.3f, 0.3f), StrokeAlpha = 0.5f, StrokeDashPattern = new Vector4F(10, 2, 3, 2), DashInWorldSpace = false, PoseLocal = new Pose(new Vector3F(-1, 1, 0)) }; _scene.Children.Add(figureNode); figure = new RectangleFigure { IsFilled = true, WidthX = 0.6f, WidthY = 0.7f, }; figureNode = new FigureNode(figure) { Name = "Rectangle #3", StrokeThickness = 2, StrokeColor = new Vector3F(0.3f, 0, 0.2f), StrokeAlpha = 1, StrokeDashPattern = new Vector4F(10, 2, 3, 2) / 100, DashInWorldSpace = true, FillColor = new Vector3F(0.7f, 0, 0.5f), FillAlpha = 0.5f, PoseLocal = new Pose(new Vector3F(-0, 1, 0)) }; _scene.Children.Add(figureNode); figure = new RectangleFigure { IsFilled = true, WidthX = 1f, WidthY = 0.2f, }; figureNode = new FigureNode(figure) { Name = "Rectangle #4", StrokeThickness = 2, StrokeColor = new Vector3F(0, 0, 0), StrokeAlpha = 1, StrokeDashPattern = new Vector4F(1, 1, 1, 1) / 100, DashInWorldSpace = true, FillColor = new Vector3F(0.3f, 0.3f, 0.3f), FillAlpha = 0.5f, PoseLocal = new Pose(new Vector3F(1, 1, 0)) }; _scene.Children.Add(figureNode); figure = new RectangleFigure { IsFilled = true, WidthX = 0.4f, WidthY = 0.5f, }; figureNode = new FigureNode(figure) { Name = "Rectangle #5", StrokeThickness = 2, StrokeColor = new Vector3F(0.3f), StrokeAlpha = 1, FillColor = new Vector3F(0.3f), FillAlpha = 1, PoseLocal = new Pose(new Vector3F(2, 1, 0)) }; _scene.Children.Add(figureNode); }
// Add a flower shape. private void CreateFlower() { // Define single flower petal. var petalPath = new Path2F { new PathKey2F { Parameter = 0, Interpolation = SplineInterpolation.Bezier, Point = new Vector2F(0, 0), TangentIn = new Vector2F(0, 0), TangentOut = new Vector2F(-0.2f, 0.2f) }, new PathKey2F { Parameter = 1, Interpolation = SplineInterpolation.Bezier, Point = new Vector2F(0, 1), TangentIn = new Vector2F(-0.3f, 1.1f), TangentOut = new Vector2F(0.3f, 1.1f) }, new PathKey2F { Parameter = 2, Interpolation = SplineInterpolation.Bezier, Point = new Vector2F(0, 0), TangentIn = new Vector2F(0.2f, 0.2f), TangentOut = new Vector2F(0, 0) } }; var petal = new PathFigure2F(); petal.Segments.Add(petalPath); // Duplicate and rotate flower petal several times. const int numberOfPetals = 9; var flower = new CompositeFigure(); flower.Children.Add(petal); for (int i = 1; i < numberOfPetals; i++) { var transformedPetal = new TransformedFigure(petal) { Pose = new Pose(Matrix33F.CreateRotationZ(i * ConstantsF.TwoPi / numberOfPetals)) }; flower.Children.Add(transformedPetal); } var flowerNode = new FigureNode(flower) { Name = "Flower", StrokeThickness = 2, StrokeColor = new Vector3F(1, 0.2f, 0.2f), FillColor = new Vector3F(1, 0.5f, 0.5f), FillAlpha = 1, PoseLocal = new Pose(new Vector3F(3, 1, 0)), ScaleLocal = new Vector3F(0.5f) }; _scene.Children.Add(flowerNode); }
// Add a 3D coordinate cross. private void CreateGizmo(SpriteFont spriteFont) { var gizmoNode = new SceneNode { Name = "Gizmo", Children = new SceneNodeCollection(), PoseLocal = new Pose(new Vector3F(3, 2, 0)), ScaleLocal = new Vector3F(0.5f) }; // Red arrow var arrow = new PathFigure2F(); arrow.Segments.Add(new LineSegment2F { Point1 = new Vector2F(0, 0), Point2 = new Vector2F(1, 0) }); arrow.Segments.Add(new LineSegment2F { Point1 = new Vector2F(1, 0), Point2 = new Vector2F(0.9f, 0.02f) }); arrow.Segments.Add(new LineSegment2F { Point1 = new Vector2F(1, 0), Point2 = new Vector2F(0.9f, -0.02f) }); var figureNode = new FigureNode(arrow) { Name = "Gizmo X", StrokeThickness = 2, StrokeColor = new Vector3F(1, 0, 0), PoseLocal = new Pose(new Vector3F(0, 0, 0)) }; gizmoNode.Children.Add(figureNode); // Green arrow var transformedArrow = new TransformedFigure(arrow) { Pose = new Pose(Matrix33F.CreateRotationZ(MathHelper.ToRadians(90))) }; figureNode = new FigureNode(transformedArrow) { Name = "Gizmo Y", StrokeThickness = 2, StrokeColor = new Vector3F(0, 1, 0), PoseLocal = new Pose(new Vector3F(0, 0, 0)) }; gizmoNode.Children.Add(figureNode); // Blue arrow transformedArrow = new TransformedFigure(arrow) { Pose = new Pose(Matrix33F.CreateRotationY(MathHelper.ToRadians(-90))) }; figureNode = new FigureNode(transformedArrow) { Name = "Gizmo Z", StrokeThickness = 2, StrokeColor = new Vector3F(0, 0, 1), PoseLocal = new Pose(new Vector3F(0, 0, 0)) }; gizmoNode.Children.Add(figureNode); // Red arc var arc = new PathFigure2F(); arc.Segments.Add( new StrokedSegment2F( new LineSegment2F { Point1 = new Vector2F(0, 0), Point2 = new Vector2F(1, 0), }, false)); arc.Segments.Add( new ArcSegment2F { Point1 = new Vector2F(1, 0), Point2 = new Vector2F(0, 1), Radius = new Vector2F(1, 1) }); arc.Segments.Add( new StrokedSegment2F( new LineSegment2F { Point1 = new Vector2F(0, 1), Point2 = new Vector2F(0, 0), }, false)); var transformedArc = new TransformedFigure(arc) { Scale = new Vector3F(0.333f), Pose = new Pose(Matrix33F.CreateRotationY(MathHelper.ToRadians(-90))) }; figureNode = new FigureNode(transformedArc) { Name = "Gizmo YZ", StrokeThickness = 2, StrokeColor = new Vector3F(1, 0, 0), FillColor = new Vector3F(1, 0, 0), FillAlpha = 0.5f, PoseLocal = new Pose(new Vector3F(0, 0, 0)) }; gizmoNode.Children.Add(figureNode); // Green arc transformedArc = new TransformedFigure(arc) { Scale = new Vector3F(0.333f), Pose = new Pose(Matrix33F.CreateRotationX(MathHelper.ToRadians(90))) }; figureNode = new FigureNode(transformedArc) { Name = "Gizmo XZ", StrokeThickness = 2, StrokeColor = new Vector3F(0, 1, 0), FillColor = new Vector3F(0, 1, 0), FillAlpha = 0.5f, PoseLocal = new Pose(new Vector3F(0, 0, 0)) }; gizmoNode.Children.Add(figureNode); // Blue arc transformedArc = new TransformedFigure(arc) { Scale = new Vector3F(0.333f), }; figureNode = new FigureNode(transformedArc) { Name = "Gizmo XY", StrokeThickness = 2, StrokeColor = new Vector3F(0, 0, 1), FillColor = new Vector3F(0, 0, 1), FillAlpha = 0.5f, PoseLocal = new Pose(new Vector3F(0, 0, 0)) }; gizmoNode.Children.Add(figureNode); // Labels "X", "Y", "Z" var spriteNode = new SpriteNode(new TextSprite("X", spriteFont)) { Color = new Vector3F(1, 0, 0), Origin = new Vector2F(0, 1), PoseLocal = new Pose(new Vector3F(1, 0, 0)) }; gizmoNode.Children.Add(spriteNode); spriteNode = new SpriteNode(new TextSprite("Y", spriteFont)) { Color = new Vector3F(0, 1, 0), Origin = new Vector2F(0, 1), PoseLocal = new Pose(new Vector3F(0, 1, 0)) }; gizmoNode.Children.Add(spriteNode); spriteNode = new SpriteNode(new TextSprite("Z", spriteFont)) { Color = new Vector3F(0, 0, 1), Origin = new Vector2F(0, 1), PoseLocal = new Pose(new Vector3F(0, 0, 1)) }; gizmoNode.Children.Add(spriteNode); _scene.Children.Add(gizmoNode); }
// Add some transparent figures to test alpha blending. private void CreateAlphaBlendedFigures() { var rectangle = new RectangleFigure { IsFilled = true, WidthX = 0.5f, WidthY = 0.9f, }; var figureNode = new FigureNode(rectangle) { Name = "Rectangle #6", StrokeThickness = 2, StrokeColor = new Vector3F(0.1f, 0.2f, 0.3f), FillColor = new Vector3F(0.1f, 0.2f, 0.3f), StrokeAlpha = 0.5f, FillAlpha = 0.5f, PoseLocal = new Pose(new Vector3F(-4, 1, -2)) }; _scene.Children.Add(figureNode); figureNode = new FigureNode(rectangle) { Name = "Rectangle #7", StrokeThickness = 2, StrokeColor = new Vector3F(0.1f, 0.2f, 0.3f), FillColor = new Vector3F(0.1f, 0.2f, 0.3f), StrokeAlpha = 0.5f, FillAlpha = 0.5f, PoseLocal = new Pose(new Vector3F(-4, 1, -1)) }; _scene.Children.Add(figureNode); figureNode = new FigureNode(rectangle) { Name = "Rectangle #8", StrokeThickness = 2, StrokeColor = new Vector3F(0.1f, 0.2f, 0.3f), FillColor = new Vector3F(0.1f, 0.2f, 0.3f), StrokeAlpha = 0.5f, FillAlpha = 0.5f, PoseLocal = new Pose(new Vector3F(-4, 1, 0)) }; _scene.Children.Add(figureNode); figureNode = new FigureNode(rectangle) { Name = "Rectangle #9", StrokeThickness = 2, StrokeColor = new Vector3F(0.1f, 0.2f, 0.3f), FillColor = new Vector3F(0.1f, 0.2f, 0.3f), StrokeAlpha = 0.5f, FillAlpha = 0.5f, PoseLocal = new Pose(new Vector3F(-4, 1, 1)) }; _scene.Children.Add(figureNode); figureNode = new FigureNode(rectangle) { Name = "Rectangle #10", StrokeThickness = 2, StrokeColor = new Vector3F(0.1f, 0.2f, 0.3f), FillColor = new Vector3F(0.1f, 0.2f, 0.3f), StrokeAlpha = 0.5f, FillAlpha = 0.5f, PoseLocal = new Pose(new Vector3F(-4, 1, 2)) }; _scene.Children.Add(figureNode); }
// Add some ellipses. private void CreateEllipses() { Figure figure = new EllipseFigure { IsFilled = false, RadiusX = 0.5f, RadiusY = 0.25f, }; FigureNode figureNode = new FigureNode(figure) { Name = "Ellipse #1", StrokeThickness = 1, StrokeColor = new Vector3(0.7f, 0.3f, 0.5f), StrokeAlpha = 1, PoseLocal = new Pose(new Vector3(-2, 2, 0)) }; _scene.Children.Add(figureNode); figure = new EllipseFigure { IsFilled = false, RadiusX = 0.25f, RadiusY = 0.4f, }; figureNode = new FigureNode(figure) { Name = "Ellipse #2", StrokeThickness = 3, StrokeColor = new Vector3(0.2f, 0.3f, 0.3f), StrokeAlpha = 0.5f, StrokeDashPattern = new Vector4(10, 2, 3, 2), DashInWorldSpace = false, PoseLocal = new Pose(new Vector3(-1, 2, 0)) }; _scene.Children.Add(figureNode); figure = new EllipseFigure { IsFilled = true, RadiusX = 0.3f, RadiusY = 0.35f, }; figureNode = new FigureNode(figure) { Name = "Ellipse #3", StrokeThickness = 2, StrokeColor = new Vector3(0.3f, 0, 0.2f), StrokeAlpha = 1, StrokeDashPattern = new Vector4(10, 2, 3, 2) / 100, DashInWorldSpace = true, FillColor = new Vector3(0.7f, 0, 0.5f), FillAlpha = 0.5f, PoseLocal = new Pose(new Vector3(-0, 2, 0)) }; _scene.Children.Add(figureNode); figure = new EllipseFigure { IsFilled = true, RadiusX = 0.5f, RadiusY = 0.1f, }; figureNode = new FigureNode(figure) { Name = "Ellipse #4", StrokeThickness = 2, StrokeColor = new Vector3(0, 0, 0), StrokeAlpha = 1, StrokeDashPattern = new Vector4(1, 1, 1, 1) / 100, DashInWorldSpace = true, FillColor = new Vector3(0.3f, 0.3f, 0.3f), FillAlpha = 0.5f, PoseLocal = new Pose(new Vector3(1, 2, 0)) }; _scene.Children.Add(figureNode); figure = new EllipseFigure { IsFilled = true, RadiusX = 0.2f, RadiusY = 0.25f, }; figureNode = new FigureNode(figure) { Name = "Ellipse #5", StrokeThickness = 2, StrokeColor = new Vector3(0.3f), StrokeAlpha = 1, FillColor = new Vector3(0.3f), FillAlpha = 1, PoseLocal = new Pose(new Vector3(2, 2, 0)) }; _scene.Children.Add(figureNode); }