/// <summary> /// Generate a quadratic curve mesh within the render stream. Returns the memory gotten. /// The number of vertices generated is resolution param + 1. /// </summary> /// <param name="start">Curve start.</param> /// <param name="end">Curve end.</param> /// <param name="ctrlP1">Control point.</param> /// <param name="resolution">Mesh detail.</param> /// <returns>RenderStream memory with a generated triangle fan quadratic curve mesh.</returns> public Span <VertexData> GetStreamedQuadraticCurveMesh(Vector3 start, Vector3 end, Vector3 ctrlP1, int resolution = 12) { float incr = 1.0f / (resolution - 1); // Points are denser around curve, so t values work fine. #if false for (var i = 0; i < resolution; i++) { float length = i == resolution - 1 ? 1.0f : incr * i; Vector3 sC = Vector3.Lerp(start, ctrlP1, length); Vector3 cE = Vector3.Lerp(ctrlP1, end, length); Vector3 curveP = Vector3.Lerp(sC, cE, length); RenderCircle(curveP, 2, Emotion.Primitives.Color.Pink, true); } #endif Span <VertexData> memory = RenderStream.GetStreamMemory((uint)(resolution + 1), BatchMode.TriangleFan); memory[0].Vertex = Vector3.Lerp(start, end, 0.5f); for (var i = 0; i < resolution; i++) { float length = i == resolution - 1 ? 1.0f : incr * i; // De Casteljau's algorithm Vector3 sC = Vector3.Lerp(start, ctrlP1, length); Vector3 cE = Vector3.Lerp(ctrlP1, end, length); Vector3 curveP = Vector3.Lerp(sC, cE, length); memory[i + 1].Vertex = curveP; } return(memory); }
internal static CompileResult Compile(RenderStream stream) { CompileResult rs = new CompileResult(); rs.Success = true; return rs; }
/// <summary> /// Invalidates the current batch - flushing it to the current buffer. /// This should be done when the state changes in some way because calls afterwards will differ from those before and /// cannot be batched. /// </summary> public void FlushRenderStream() { if (RenderStream == null || !RenderStream.AnythingMapped) { return; } RenderStream.FlushRender(); }
/// <summary> /// Render an ellipse. /// </summary> /// <param name="position"> /// The top right position of the imaginary rectangle which encompasses the ellipse. Can be modified with "useCenter" /// </param> /// <param name="radius">The radius.</param> /// <param name="color">The color.</param> /// <param name="positionIsCenter">Whether the position should instead be the center of the circle.</param> /// <param name="detail">How many triangles to generate. The more the smoother.</param> /// <param name="colorMiddle">A separate color just for the vertices in the center of the ellipse.</param> public void RenderEllipse(Vector3 position, Vector2 radius, Color color, bool positionIsCenter = false, int detail = 30, Color?colorMiddle = null) { var vertsNeeded = (uint)((detail + 1) * 3); Span <VertexData> vertices = RenderStream.GetStreamMemory(vertsNeeded, BatchMode.SequentialTriangles); Debug.Assert(vertices != null); var vertexIdx = 0; Vector3 posOffset = positionIsCenter ? new Vector3(position.X - radius.X, position.Y - radius.Y, position.Z) : position; float pX = 0; float pY = 0; float fX = 0; float fY = 0; // Generate triangles. for (uint i = 0; i < detail; i++) { var angle = (float)(i * 2 * Math.PI / detail - Math.PI / 2); float x = (float)Math.Cos(angle) * radius.X; float y = (float)Math.Sin(angle) * radius.Y; vertices[vertexIdx++].Vertex = posOffset + new Vector3(radius.X + pX, radius.Y + pY, 0); vertices[vertexIdx++].Vertex = posOffset + new Vector3(radius.X + x, radius.Y + y, 0); vertices[vertexIdx++].Vertex = posOffset + new Vector3(radius.X, radius.Y, 0); pX = x; pY = y; if (i == detail - 1) { vertices[vertexIdx++].Vertex = posOffset + new Vector3(radius.X + pX, radius.Y + pY, 0); vertices[vertexIdx++].Vertex = posOffset + new Vector3(radius.X + fX, radius.Y + fY, 0); vertices[vertexIdx++].Vertex = posOffset + new Vector3(radius.X, radius.Y, 0); } if (i != 0) { continue; } fX = x; fY = y; } uint c = color.ToUint(); uint cM = colorMiddle?.ToUint() ?? c; for (var i = 0; i < vertices.Length; i++) { vertices[i].Color = i % 3 == 2 ? cM : c; vertices[i].UV = Vector2.Zero; } }
/// <summary> /// Render arbitrary vertices. Clockwise order is expected. /// </summary> /// <param name="verts">The vertex to render.</param> /// <param name="colors">The color (or colors) of the vertex/vertices.</param> public void RenderVertices(Vector2[] verts, params Color[] colors) { var vertCount = (uint)verts.Length; Span <VertexData> vertices = RenderStream.GetStreamMemory(vertCount, BatchMode.TriangleFan); Debug.Assert(vertices != null); for (var i = 0; i < verts.Length; i++) { vertices[i].Vertex = verts[i].ToVec3(); vertices[i].Color = i >= colors.Length ? colors.Length == 0 ? Color.WhiteUint : colors[0].ToUint() : colors[i].ToUint(); vertices[i].UV = Vector2.Zero; } }
public static Bitmap Visualize(RenderStream stream) { Visualization.GraphGeneratorVisitor graphGen = new Visualization.GraphGeneratorVisitor(); stream.Expression.Accept(graphGen); var g = graphGen.Graph; using (var ds = new Visualization.DrawingStyle()) { using (var bmp = new Bitmap(2, 2)) using (var graphics = Graphics.FromImage(bmp)) g.Layout(ds, graphics, 0, 0); var image = new Bitmap(g.Bounds.Width + 1, g.Bounds.Height + 3, System.Drawing.Imaging.PixelFormat.Format32bppArgb); using (var graphics = Graphics.FromImage(image)) { graphics.Clear(Color.White); graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.Draw(ds, graphics); return image; } } }
/// <summary> /// Renders a sprite without a texture, but with uploaded UVs. /// If no uvRect is provided 0, 1, 1, 0 is uploaded instead. /// </summary> public void RenderUVRect(Vector3 pos, Vector2 size, Color color, Rectangle?uvRect = null) { Span <VertexData> vertices = RenderStream.GetStreamMemory(4, BatchMode.Quad, Texture.NoTexture); vertices[0].Vertex = pos; vertices[1].Vertex = new Vector3(pos.X + size.X, pos.Y, pos.Z); vertices[2].Vertex = new Vector3(pos.X + size.X, pos.Y + size.Y, pos.Z); vertices[3].Vertex = new Vector3(pos.X, pos.Y + size.Y, pos.Z); uint c = color.ToUint(); vertices[0].Color = c; vertices[1].Color = c; vertices[2].Color = c; vertices[3].Color = c; Rectangle uv = uvRect ?? new Rectangle(0, 1, 1, 0); vertices[0].UV = new Vector2(uv.X, uv.Y); vertices[1].UV = new Vector2(uv.Width, uv.Y); vertices[2].UV = new Vector2(uv.Width, uv.Height); vertices[3].UV = new Vector2(uv.X, uv.Height); }
/// <summary> /// Generate a cubic curve mesh within the render stream. Returns the memory gotten. /// </summary> /// <param name="start">Curve start.</param> /// <param name="end">Curve end.</param> /// <param name="ctrlP1">Control point.</param> /// <param name="ctrlP2">Second control point.</param> /// <param name="resolution">Mesh detail.</param> /// <returns>RenderStream memory with a generated triangle fan cubic curve mesh.</returns> public Span <VertexData> GetStreamedCubicCurveMesh(Vector3 start, Vector3 end, Vector3 ctrlP1, Vector3 ctrlP2, int resolution = 12) { Span <VertexData> memory = RenderStream.GetStreamMemory((uint)(resolution + 1), BatchMode.TriangleFan); memory[0].Vertex = Vector3.Lerp(start, end, 0.5f); float incr = 1.0f / (resolution - 1); for (var i = 0; i < resolution; i++) { float length = i == resolution - 1 ? 1.0f : incr * i; Vector3 sC1 = Vector3.Lerp(start, ctrlP1, length); Vector3 c1C2 = Vector3.Lerp(ctrlP1, ctrlP2, length); Vector3 c2E = Vector3.Lerp(ctrlP2, end, length); Vector3 sC1C1C2 = Vector3.Lerp(sC1, c1C2, length); Vector3 c1C2C2E = Vector3.Lerp(c1C2, c2E, length); Vector3 curveP = Vector3.Lerp(sC1C1C2, c1C2C2E, length); memory[i + 1].Vertex = curveP; } return(memory); }
// save pipeline graph to file public static void Visualize(RenderStream stream, string fileName) { using (var bmp = Visualize(stream)) bmp.Save(fileName); }
/// <summary> /// Render a line made out of quads. /// </summary> /// <param name="pointOne">The point to start the line.</param> /// <param name="pointTwo">The point to end the line at.</param> /// <param name="color">The color of the line.</param> /// <param name="thickness">The thickness of the line in world units. The line will always be at least 1 pixel thick.</param> /// <param name="snapToPixel">Whether to snap the start and ending positions to the nearest pixel.</param> /// <param name="renderMode">How to treat the points given.</param> public void RenderLine(Vector3 pointOne, Vector3 pointTwo, Color color, float thickness = 1f, bool snapToPixel = true, RenderLineMode renderMode = RenderLineMode.Center) { bool cameraWasOn = CurrentState.ViewMatrix !.Value; SetUseViewMatrix(false); ProjectionBehavior oldProjection = CurrentState.ProjectionBehavior !.Value; SetProjectionBehavior(ProjectionBehavior.AlwaysCameraProjection); Matrix4x4 viewMatrix = cameraWasOn ? Camera.ViewMatrix : Matrix4x4.Identity; if (cameraWasOn) { thickness *= Camera.CalculatedScale; } pointOne = Vector3.Transform(pointOne, ModelMatrix * viewMatrix); pointTwo = Vector3.Transform(pointTwo, ModelMatrix * viewMatrix); PushModelMatrix(Matrix4x4.Identity, false); if (snapToPixel) { if (thickness < 1.0f) { thickness = 1.0f; } pointOne = pointOne.IntCastRoundXY(); pointTwo = pointTwo.IntCastRoundXY(); } Vector3 direction = Vector3.Normalize(pointTwo - pointOne); var normal = new Vector3(-direction.Y, direction.X, 0); Vector3 delta = normal * (thickness / 2f); Vector3 deltaNeg = -delta; if (renderMode == RenderLineMode.Inward) { pointOne += delta; pointTwo += delta; } else if (renderMode == RenderLineMode.Outward) { pointOne -= delta; pointTwo -= delta; } Span <VertexData> vertices = RenderStream.GetStreamMemory(4, BatchMode.Quad); vertices[0].Vertex = pointOne + delta; vertices[1].Vertex = pointTwo + delta; vertices[2].Vertex = pointTwo + deltaNeg; vertices[3].Vertex = pointOne + deltaNeg; uint c = color.ToUint(); for (var i = 0; i < vertices.Length; i++) { vertices[i].Color = c; vertices[i].UV = Vector2.Zero; } PopModelMatrix(); SetUseViewMatrix(cameraWasOn); SetProjectionBehavior(oldProjection); }
/// <summary> /// Render a (textured) quad to the screen. /// </summary> /// <param name="position">The position of the quad.</param> /// <param name="size">The size of the quad.</param> /// <param name="color">The color of the quad.</param> /// <param name="texture">The texture of the quad, if any.</param> /// <param name="textureArea">The texture area of the quad's texture, if any.</param> /// <param name="flipX">Whether to flip the texture on the x axis.</param> /// <param name="flipY">Whether to flip the texture on the y axis.</param> public void RenderSprite(Vector3 position, Vector2 size, Color color, Texture texture = null, Rectangle?textureArea = null, bool flipX = false, bool flipY = false) { Span <VertexData> vertices = RenderStream.GetStreamMemory(4, BatchMode.Quad, texture); VertexData.SpriteToVertexData(vertices, position, size, color, texture, textureArea, flipX, flipY); }