private void DrawGrid(CartesianGraphState <T> state) { GL.UseProgram(_gridShader.Handle); GL.Uniform4(_gridShader.Uniforms["Color"].Location, Color4.Gray); GL.Uniform1(_gridShader.Uniforms["majorXGridSpacing"].Location, state.XGridSpacing.Major); GL.Uniform1(_gridShader.Uniforms["minorXGridSpacing"].Location, state.XGridSpacing.Minor); GL.Uniform1(_gridShader.Uniforms["majorYGridSpacing"].Location, state.YGridSpacing.Major); GL.Uniform1(_gridShader.Uniforms["minorYGridSpacing"].Location, state.YGridSpacing.Minor); GL.Uniform1(_gridShader.Uniforms["majorXAlpha"].Location, _cfg.XAxis.MajorVisibile ? 1.0f : 0.0f); GL.Uniform1(_gridShader.Uniforms["minorXAlpha"].Location, _cfg.XAxis.MinorVisible ? 1.0f : 0.0f); GL.Uniform1(_gridShader.Uniforms["majorYAlpha"].Location, _cfg.YAxis.MajorVisibile ? 1.0f : 0.0f); GL.Uniform1(_gridShader.Uniforms["minorYAlpha"].Location, _cfg.YAxis.MinorVisible ? 1.0f : 0.0f); GL.Uniform1(_gridShader.Uniforms["originXAlpha"].Location, _cfg.XAxis.OriginVisible ? 1.0f : 0.0f); GL.Uniform1(_gridShader.Uniforms["originYAlpha"].Location, _cfg.XAxis.OriginVisible ? 1.0f : 0.0f); var vpMat = state.Camera.Current.ViewProjection; vpMat = Matrix4.CreateScale(1.0f, state.YScale, 1.0f) * vpMat; vpMat.Invert(); GL.UniformMatrix4(_gridShader.Uniforms["InvViewProjectionMatrix"].Location, false, ref vpMat); // GL.Uniform2(_solidShader.Uniforms["Scale"].Location, Vector2.One); GL.BindVertexArray(Primitives.Quad.Handle); GL.DrawElements(PrimitiveType.TriangleStrip, Primitives.Quad.ElementCount, DrawElementsType.UnsignedInt, 0); GL.BindVertexArray(0); GL.UseProgram(0); }
private void DrawLineSeries(CartesianGraphState <T> state) { GL.UseProgram(_solidShader.Handle); var vpMat = state.Camera.Current.ViewProjection; vpMat = Matrix4.CreateScale(1.0f, state.YScale, 1.0f) * vpMat; GL.UniformMatrix4(_solidShader.Uniforms["ViewProjectionMatrix"].Location, false, ref vpMat); GL.Uniform2(_solidShader.Uniforms["Scale"].Location, Vector2.One); GL.Uniform2(_solidShader.Uniforms["Position"].Location, Vector2.Zero); for (var i = 0; i < state.Series.Count; i++) { var series = state.Series[i]; if (series.SeriesType != SeriesType.Line || !series.IsVisible) { continue; } var vao = _seriesVaos[i]; GL.Uniform4(_solidShader.Uniforms["Color"].Location, series.Color); GL.BindVertexArray(vao.Handle); var primitiveType = series.SeriesType == SeriesType.Point ? PrimitiveType.Points : PrimitiveType.LineStrip; GL.DrawArrays(primitiveType, 0, series.Points.Count); GL.BindVertexArray(0); } GL.UseProgram(0); }
private void OnReady() { var graphSettings = CartesianGraphSettings.Default; Graph = new CartesianGraph <T>(graphSettings); _state = Graph.State; _control.Render += OnRender; }
internal void Render(CartesianGraphState <T> state) { if (!_hasSetupGraphics) { _hasSetupGraphics = true; SetupGraphics(); } UpdateVaos(state); DrawRegions(state); DrawGrid(state); DrawLineSeries(state); DrawPointSeries(state); DrawDragBox(state); DrawAxisLabels(state); DrawTooltip(state); }
private void DrawRegions(CartesianGraphState <T> state) { GL.BindVertexArray(Primitives.Quad.Handle); GL.UseProgram(_solidShader.Handle); var vpMat = state.Camera.Current.ViewProjection; GL.UniformMatrix4(_solidShader.Uniforms["ViewProjectionMatrix"].Location, false, ref vpMat); foreach (var sec in state.Regions) { var box = sec.Bounds; var col = sec.Color; GL.Uniform2(_solidShader.Uniforms["Position"].Location, box.Center); GL.Uniform2(_solidShader.Uniforms["Scale"].Location, box.HalfSize); GL.Uniform4(_solidShader.Uniforms["Color"].Location, col); GL.DrawElements(PrimitiveType.TriangleStrip, Primitives.Quad.ElementCount, DrawElementsType.UnsignedInt, 0); } GL.BindVertexArray(0); GL.UseProgram(0); }
private void DrawDragBox(CartesianGraphState <T> state) { var box = state.DragRectangle; if (box == default) { return; } var col = new Color4(1, 1, 1, 0.15f); // rescale into view co-ordinates var pt1 = box.Min * 2.0f - Vector2.One; var pt2 = box.Max * 2.0f - Vector2.One; // project mouse into world var inverseVp = state.Camera.Current.ViewProjection.Inverted(); var minpt = (new Vector4(pt1.X, -pt2.Y, 0, 1) * inverseVp).Xy; var maxPt = (new Vector4(pt2.X, -pt1.Y, 0, 1) * inverseVp).Xy; var center = Vector2.Lerp(minpt, maxPt, 0.5f); var scale = maxPt - minpt; // render the background box GL.BindVertexArray(Primitives.Quad.Handle); GL.UseProgram(_solidShader.Handle); var vpMat = state.Camera.Current.ViewProjection; GL.UniformMatrix4(_solidShader.Uniforms["ViewProjectionMatrix"].Location, false, ref vpMat); GL.Uniform2(_solidShader.Uniforms["Position"].Location, center); GL.Uniform2(_solidShader.Uniforms["Scale"].Location, scale * 0.5f); GL.Uniform4(_solidShader.Uniforms["Color"].Location, col); GL.DrawElements(PrimitiveType.TriangleStrip, Primitives.Quad.ElementCount, DrawElementsType.UnsignedInt, 0); GL.BindVertexArray(0); GL.UseProgram(0); }
private void DrawPointSeries(CartesianGraphState <T> state) { GL.UseProgram(_pointShader.Handle); var vpMat = state.Camera.Current.ViewProjection; vpMat = Matrix4.CreateScale(1.0f, state.YScale, 1.0f) * vpMat; GL.UniformMatrix4(_pointShader.Uniforms["ViewProjectionMatrix"].Location, false, ref vpMat); GL.Uniform2(_pointShader.Uniforms["Scale"].Location, Vector2.One); GL.Uniform2(_pointShader.Uniforms["Position"].Location, Vector2.Zero); GL.Uniform1(_pointShader.Uniforms["Aspect"].Location, state.Camera.Current.AspectRatio); for (var i = 0; i < state.Series.Count; i++) { var series = state.Series[i]; if (series.SeriesType != SeriesType.Point || !series.IsVisible) { continue; } var vao = _seriesVaos[i]; if (series.SeriesType == SeriesType.Point) { var tex = ShapeHelper.TextureFor(series.PointShape); GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, tex.Handle); GL.Uniform1(_pointShader.Uniforms["tex"].Location, 0); } GL.Uniform1(_pointShader.Uniforms["PointSize"].Location, 2 * _cfg.PointSize / state.ViewportHeight); GL.Uniform4(_pointShader.Uniforms["Color"].Location, series.Color); GL.BindVertexArray(vao.Handle); var primitiveType = series.SeriesType == SeriesType.Point ? PrimitiveType.Triangles : PrimitiveType.LineStrip; GL.DrawArrays(primitiveType, 0, series.Points.Count * _stride); GL.BindVertexArray(0); } GL.UseProgram(0); }
private void UpdateVaos(CartesianGraphState <T> state) { for (var i = 0; i < state.Series.Count; i++) { var series = state.Series[i]; if (series.SeriesType == SeriesType.Point) { if (i >= _seriesVaos.Count) { var newVao = CreatePointSeriesVao(series); _seriesVaos.Add(newVao); } var vao = _seriesVaos[i]; if (series.InvalidateRenderCache || series.Points.Count * _stride > vao.ElementCount) { // append the latest data: UpdatePointSeriesVao(vao, series); } } else { if (i >= _seriesVaos.Count) { var newVao = CreateLineSeriesVao(series); _seriesVaos.Add(newVao); } var vao = _seriesVaos[i]; if (series.InvalidateRenderCache || series.Points.Count > vao.ElementCount) { // append the latest data: UpdateLineSeriesVao(vao, series); } } } }
private void DrawTooltip(CartesianGraphState <T> state) { if (!state.MouseoverTarget.HasValue) { return; } var targetPt = state.MouseoverTarget.Value; // rescale into view co-ordinates var(x, y) = state.MousePosition * 2.0f - Vector2.One; // project mouse into world var inverseVp = state.Camera.Current.ViewProjection.Inverted(); var worldPos = (new Vector4(x, -y, 0, 1) * inverseVp).Xy; // screenPos.X *= Camera.Current.AspectRatio; GL.BindVertexArray(Primitives.Quad.Handle); var tooltip = $"{targetPt.X:0.000}, {targetPt.Y:0.000}"; var tex = TextRendering.GetTextTexture(tooltip); var tooltip2 = $"{targetPt.Series.Name}";// - {targetPt.Value}"; var tex2 = TextRendering.GetTextTexture(tooltip2); var scale = 0.1f * new Vector2(tex.AspectRatio, 1.0f) * state.Camera.Current.VerticalSize * 0.15f; var pos = worldPos + new Vector2(scale.X + scale.Y, -scale.Y * 2); GL.UseProgram(_solidShader.Handle); var vpMat = state.Camera.Current.ViewProjection; GL.UniformMatrix4(_solidShader.Uniforms["ViewProjectionMatrix"].Location, false, ref vpMat); // render the background box var bgCol = new Color4(0.25f, 0.25f, 0.25f, 0.5f); GL.Uniform4(_solidShader.Uniforms["Color"].Location, bgCol); var scaleBg = 0.1f * new Vector2(MathF.Max(tex.AspectRatio, tex2.AspectRatio), 1.0f) * state.Camera.Current.VerticalSize * 0.15f; var bgPos = new Vector2(pos.X, pos.Y - scaleBg.Y); GL.Uniform2(_solidShader.Uniforms["Position"].Location, bgPos); scaleBg.Y *= 2; GL.Uniform2(_solidShader.Uniforms["Scale"].Location, scaleBg); GL.DrawElements(PrimitiveType.TriangleStrip, Primitives.Quad.ElementCount, DrawElementsType.UnsignedInt, 0); GL.UseProgram(0); GL.UseProgram(_textShader.Handle); var col = Color4.White; GL.Uniform4(_textShader.Uniforms["Color"].Location, col); GL.UniformMatrix4(_textShader.Uniforms["ViewProjectionMatrix"].Location, false, ref vpMat); GL.Uniform2(_textShader.Uniforms["Position"].Location, pos); GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, tex.Handle); GL.Uniform1(_textShader.Uniforms["tex"].Location, 0); GL.Uniform2(_solidShader.Uniforms["Scale"].Location, scale); GL.DrawElements(PrimitiveType.TriangleStrip, Primitives.Quad.ElementCount, DrawElementsType.UnsignedInt, 0); GL.BindTexture(TextureTarget.Texture2D, tex2.Handle); GL.Uniform1(_textShader.Uniforms["tex"].Location, 0); var scale2 = 0.1f * new Vector2(tex2.AspectRatio, 1.0f) * state.Camera.Current.VerticalSize * 0.15f; GL.Uniform2(_solidShader.Uniforms["Scale"].Location, scale2); var pos2 = pos + new Vector2(0, -scale.Y * 2f); GL.Uniform2(_textShader.Uniforms["Position"].Location, pos2); var series = targetPt.Series; var index = state.Series.IndexOf(series); GL.Uniform4(_textShader.Uniforms["Color"].Location, series.Color); GL.DrawElements(PrimitiveType.TriangleStrip, Primitives.Quad.ElementCount, DrawElementsType.UnsignedInt, 0); GL.BindVertexArray(0); GL.UseProgram(0); }
private void DrawAxisLabels(CartesianGraphState <T> state) { GL.UseProgram(_textShader.Handle); // vp matrix var yScale = state.YScale; var vpMat = state.Camera.Current.ViewProjection; // vpMat = Matrix4.CreateScale(1.0f, yScale, 1.0f) * vpMat; GL.UniformMatrix4(_textShader.Uniforms["ViewProjectionMatrix"].Location, false, ref vpMat); // Color var col = Color4.White; GL.Uniform4(_textShader.Uniforms["Color"].Location, col); // bind var quad = Primitives.Quad; GL.BindVertexArray(quad.Handle); var size = _cfg.TextScale * 0.025f * state.Camera.Current.VerticalSize; var scale = Vector2.One * size; var leftPos = -(state.Camera.Current.HorizontalSize * 0.5f - size) - state.Camera.Current.Position.X; var bottomPos = -(state.Camera.Current.VerticalSize * 0.5f - size) - state.Camera.Current.Position.Y; var minorSpacingY = state.YGridSpacing.Minor; for (int i = 0; i < 100; i++) { var yPos = i * minorSpacingY; var pos = new Vector2(leftPos, yPos * yScale); var label = yPos.ToString("0.###"); var tex = TextRendering.GetTextTexture(label, StringAlignment.Near); GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, tex.Handle); GL.Uniform1(_textShader.Uniforms["tex"].Location, 0); GL.Uniform2(_textShader.Uniforms["Position"].Location, pos); var finalScale = new Vector2(scale.X * tex.AspectRatio, scale.Y); GL.Uniform2(_textShader.Uniforms["Scale"].Location, finalScale); GL.DrawElements(PrimitiveType.TriangleStrip, quad.ElementCount, DrawElementsType.UnsignedInt, 0); } for (int i = 1; i < 100; i++) { var yPos = -i * minorSpacingY; var pos = new Vector2(leftPos, yPos * yScale); var label = yPos.ToString("0.###"); GL.Uniform2(_textShader.Uniforms["Position"].Location, pos); var tex = TextRendering.GetTextTexture(label, StringAlignment.Near); GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, tex.Handle); GL.Uniform1(_textShader.Uniforms["tex"].Location, 0); GL.Uniform2(_textShader.Uniforms["Position"].Location, pos); var finalScale = new Vector2(scale.X * tex.AspectRatio, scale.Y); GL.Uniform2(_textShader.Uniforms["Scale"].Location, finalScale); GL.DrawElements(PrimitiveType.TriangleStrip, quad.ElementCount, DrawElementsType.UnsignedInt, 0); } var minorSpacingX = state.XGridSpacing.Minor; for (int i = 0; i < 100; i++) { var xPos = i * minorSpacingX; var pos = new Vector2(xPos, bottomPos); var label = xPos.ToString("0.###"); GL.Uniform2(_textShader.Uniforms["Position"].Location, pos); var tex = TextRendering.GetTextTexture(label, StringAlignment.Near); GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, tex.Handle); GL.Uniform1(_textShader.Uniforms["tex"].Location, 0); GL.Uniform2(_textShader.Uniforms["Position"].Location, pos); var finalScale = new Vector2(scale.X * tex.AspectRatio, scale.Y); GL.Uniform2(_textShader.Uniforms["Scale"].Location, finalScale); GL.DrawElements(PrimitiveType.TriangleStrip, quad.ElementCount, DrawElementsType.UnsignedInt, 0); } for (int i = 1; i < 100; i++) { var xPos = -i * minorSpacingX; var pos = new Vector2(xPos, bottomPos); var label = xPos.ToString("0.###"); GL.Uniform2(_textShader.Uniforms["Position"].Location, pos); var tex = TextRendering.GetTextTexture(label, StringAlignment.Near); GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, tex.Handle); GL.Uniform1(_textShader.Uniforms["tex"].Location, 0); GL.Uniform2(_textShader.Uniforms["Position"].Location, pos); var finalScale = new Vector2(scale.X * tex.AspectRatio, scale.Y); GL.Uniform2(_textShader.Uniforms["Scale"].Location, finalScale); GL.DrawElements(PrimitiveType.TriangleStrip, quad.ElementCount, DrawElementsType.UnsignedInt, 0); } GL.BindVertexArray(0); GL.UseProgram(0); }