Пример #1
0
        /// <summary>Create a point cloud plot</summary>
        private ChartGfxPiece CreatePointPlot(RangeI idx_range)
        {
            var n = idx_range.Sizei;

            // Resize the geometry buffers
            m_vbuf.Resize(n);
            m_ibuf.Resize(n);
            m_nbuf.Resize(1);

            // Create the vertex/index data
            var col     = Options.Colour;
            var x_range = RangeF.Invalid;

            for (int i = 0, iend = n; i != iend; ++i)
            {
                var pt = m_data[i + idx_range.Begi];
                m_vbuf[i] = new View3d.Vertex(new v4((float)pt.xf, (float)pt.yf, 0f, 1f), col);
                m_ibuf[i] = (ushort)i;
                x_range.Grow(pt.xf);
            }

            // Create a nugget for the points using the sprite shader
            {
                var mat = View3d.Material.New();
                mat.m_diff_tex = View3d.Texture.FromStock((View3d.EStockTexture)Options.PointStyle)?.Handle ?? IntPtr.Zero;
                mat.Use(View3d.ERenderStep.ForwardRender, View3d.EShaderGS.PointSpritesGS, $"*PointSize {{{Options.PointSize} {Options.PointSize}}} *Depth {{{false}}}");
                m_nbuf[0] = new View3d.Nugget(View3d.ETopo.PointList, View3d.EGeom.Vert | View3d.EGeom.Colr | View3d.EGeom.Tex0, mat: mat);
            }

            // Create the graphics
            var gfx = new View3d.Object($"{Name}-[{idx_range.Beg},{idx_range.End})", 0xFFFFFFFF, m_vbuf.Count, m_ibuf.Count, m_nbuf.Count, m_vbuf.ToArray(), m_ibuf.ToArray(), m_nbuf.ToArray(), Id);

            return(new ChartGfxPiece(gfx, x_range));
        }
Пример #2
0
        /// <summary>Create a step line plot</summary>
        private ChartGfxPiece CreateStepLinePlot(RangeI idx_range)
        {
            var n = idx_range.Sizei;

            // Resize the geometry buffers
            m_vbuf.Resize(2 * n);
            m_ibuf.Resize(2 * n + (Options.PointsOnLinePlot ? n : 0));
            m_nbuf.Resize(1 + (Options.PointsOnLinePlot ? 1 : 0));

            // Create the vertex/index data
            int vert = 0, indx = 0;
            var col     = Options.Colour;
            var x_range = RangeF.Invalid;

            for (int i = 0, iend = Math.Min(n + 1, m_data.Count - idx_range.Begi); i != iend; ++i)
            {
                // Get the point and the next point
                var j    = i + idx_range.Begi;
                var pt   = m_data[j];
                var pt_r = j + 1 != m_data.Count ? m_data[j + 1] : pt;

                var v = vert;
                m_vbuf[vert++] = new View3d.Vertex(new v4((float)pt.xf, (float)pt.yf, 0f, 1f), col);
                m_vbuf[vert++] = new View3d.Vertex(new v4((float)pt_r.xf, (float)pt.yf, 0f, 1f), col);
                m_ibuf[indx++] = (ushort)(v + 0);
                m_ibuf[indx++] = (ushort)(v + 1);

                x_range.Grow(pt.xf);
            }

            // Create a nugget for the list strip using the thick line shader
            {
                var mat = View3d.Material.New();
                mat.Use(View3d.ERenderStep.ForwardRender, View3d.EShaderGS.ThickLineListGS, $"*LineWidth {{{Options.LineWidth}}}");
                m_nbuf[0] = new View3d.Nugget(View3d.ETopo.LineStrip, View3d.EGeom.Vert | View3d.EGeom.Colr, 0, (uint)vert, 0, (uint)indx, View3d.ENuggetFlag.None, false, mat);
            }

            // Create a nugget for the points (if visible)
            if (Options.PointsOnLinePlot)
            {
                // Add indices for the points
                var i0 = indx;
                for (int i = 0, iend = n; i != iend; ++i)
                {
                    m_ibuf[indx++] = (ushort)(i * 2);
                }

                var mat = View3d.Material.New();
                mat.m_diff_tex = View3d.Texture.FromStock((View3d.EStockTexture)Options.PointStyle)?.Handle ?? IntPtr.Zero;
                mat.Use(View3d.ERenderStep.ForwardRender, View3d.EShaderGS.PointSpritesGS, $"*PointSize {{{Options.PointSize} {Options.PointSize}}} *Depth {{{false}}}");
                m_nbuf[1] = new View3d.Nugget(View3d.ETopo.PointList, View3d.EGeom.Vert | View3d.EGeom.Colr | View3d.EGeom.Tex0, 0, (uint)vert, (uint)i0, (uint)indx, View3d.ENuggetFlag.None, false, mat);
            }

            // Create the graphics
            var gfx = new View3d.Object($"{Name}-[{idx_range.Beg},{idx_range.End})", 0xFFFFFFFF, m_vbuf.Count, m_ibuf.Count, m_nbuf.Count, m_vbuf.ToArray(), m_ibuf.ToArray(), m_nbuf.ToArray(), Id);

            return(new ChartGfxPiece(gfx, x_range));
        }
Пример #3
0
        /// <summary>Create a line plot</summary>
        private ChartGfxPiece CreateLinePlot(RangeI idx_range)
        {
            var n = idx_range.Sizei;

            if (n == 0)
            {
                throw new ArgumentException($"{nameof(ChartControl)}.{nameof(CreateLinePlot)} Index range must not be empty");
            }

            // Resize the geometry buffers
            m_vbuf.Resize(n);
            m_ibuf.Resize(n);
            m_nbuf.Resize(1 + (Options.PointsOnLinePlot ? 1 : 0));

            // Create the vertex/index data
            int vert = 0, indx = 0;
            var col     = Options.Colour;
            var x_range = RangeF.Invalid;

            for (int i = 0, iend = Math.Min(n, m_data.Count - idx_range.Begi); i != iend; ++i)
            {
                var j  = i + idx_range.Begi;
                var pt = m_data[j];

                var v = vert;
                m_vbuf[vert++] = new View3d.Vertex(new v4((float)pt.xf, (float)pt.yf, 0f, 1f), col);
                m_ibuf[indx++] = (ushort)(v);

                x_range.Grow(pt.xf);
            }

            // Create a nugget for the list strip using the thick line shader
            {
                var mat = View3d.Material.New();
                mat.Use(View3d.ERenderStep.ForwardRender, View3d.EShaderGS.ThickLineListGS, $"*LineWidth {{{Options.LineWidth}}}");
                m_nbuf[0] = new View3d.Nugget(View3d.ETopo.LineStrip, View3d.EGeom.Vert | View3d.EGeom.Colr, mat: mat);
            }

            // Create a nugget for the points (if visible)
            if (Options.PointsOnLinePlot)
            {
                var mat = View3d.Material.New();
                mat.m_diff_tex = View3d.Texture.FromStock((View3d.EStockTexture)Options.PointStyle)?.Handle ?? IntPtr.Zero;
                mat.Use(View3d.ERenderStep.ForwardRender, View3d.EShaderGS.PointSpritesGS, $"*PointSize {{{Options.PointSize} {Options.PointSize}}} *Depth {{{false}}}");
                m_nbuf[1] = new View3d.Nugget(View3d.ETopo.PointList, View3d.EGeom.Vert | View3d.EGeom.Colr | View3d.EGeom.Tex0, range_overlaps: true, mat: mat);
            }

            // Create the graphics
            var gfx = new View3d.Object($"{Name}-[{idx_range.Beg},{idx_range.End})", 0xFFFFFFFF, m_vbuf.Count, m_ibuf.Count, m_nbuf.Count, m_vbuf.ToArray(), m_ibuf.ToArray(), m_nbuf.ToArray(), Id);

            return(new ChartGfxPiece(gfx, x_range));
        }
Пример #4
0
 /// <summary>Callback for creating the "net" object</summary>
 private void CreateOnlyCB(IntPtr ctx, int vcount, int icount, int ncount, View3d.Vertex[] verts, ushort[] indices, View3d.Nugget[] nuggets, out int new_vcount, out int new_icount, out int new_ncount)
 {
     new_vcount = 0;
     new_icount = 0;
     new_ncount = 0;
     for (int i = 0; i != 10; ++i)
     {
         verts[new_vcount++]   = new View3d.Vertex(new v4(i, 0, 0, 1f));
         verts[new_vcount++]   = new View3d.Vertex(new v4(0, 0, 9 - i, 1f));
         indices[new_icount++] = (ushort)(new_vcount - 2);
         indices[new_icount++] = (ushort)(new_vcount - 1);
     }
     nuggets[new_ncount++] = new View3d.Nugget(View3d.ETopo.LineList, View3d.EGeom.Vert);
 }
Пример #5
0
        protected override void UpdateGfxCore()
        {
            var snr_colour = Settings.Colour.ToArgbU();
            var width      = Settings.GraphicsWidth * Chart.XAxis.Span;
            var attr       = Settings.Attribute;
            var power      = Settings.Power;
            var count      = Levels.Count;

            if (count <= 1)
            {
                Gfx = null;
                return;
            }

            // Create graphics for the support and resistance data
            m_vbuf.Resize(count * 2);
            m_ibuf.Resize(count * 2);
            m_nbuf.Resize(1);

            var values =
                attr == EAttribute.MedianCount ? Levels.Select(x => x.Median).Normalise() :
                attr == EAttribute.TradeVolume ? Levels.Select(x => x.Volume).Normalise() :
                attr == EAttribute.TimeAtLevel ? Levels.Select(x => x.Time).Normalise() :
                null;

            int l = 0, v = 0, i = 0;

            foreach (var value in values)
            {
                var x = (float)(Math.Pow(value, power) * width);
                var y = (float)(Levels[l].Price);
                ++l;

                m_ibuf[i++] = (ushort)v;
                m_vbuf[v++] = new View3d.Vertex(new v4(-x, y, 0, 1));
                m_ibuf[i++] = (ushort)v;
                m_vbuf[v++] = new View3d.Vertex(new v4(0, y, 0, 1));
            }
            m_nbuf[0] = new View3d.Nugget(View3d.EPrim.TriStrip, View3d.EGeom.Vert, 0, (uint)v, 0, (uint)i, !Bit.AllSet(snr_colour, 0xFF000000));

            // Create the graphics
            Gfx = new View3d.Object(Name, snr_colour, m_vbuf.Count, m_ibuf.Count, m_nbuf.Count, m_vbuf.ToArray(), m_ibuf.ToArray(), m_nbuf.ToArray());

            base.UpdateGfxCore();
        }
Пример #6
0
        protected override void UpdateGfxCore()
        {
            var line_colour   = (Selected ? Settings.Colour.Lerp(Color.Gray, 0.2f) : Settings.Colour).ToArgbU();
            var region_colour = (Selected ? Settings.RegionColour.Lerp(Color.Gray, 0.2f) : Settings.RegionColour).ToArgbU();
            var width         = (float)Chart.XAxis.Span;

            // Create graphics for the horizontal line
            m_vbuf.Resize(2 + (Level.WidthPips != 0 ? 4 : 0));
            m_ibuf.Resize(2 + (Level.WidthPips != 0 ? 6 : 0));
            m_nbuf.Resize(1 + (Level.WidthPips != 0 ? 1 : 0));

            m_vbuf[0] = new View3d.Vertex(new v4(0, 0, 0, 1), line_colour);
            m_vbuf[1] = new View3d.Vertex(new v4(width, 0, 0, 1), line_colour);
            m_ibuf[0] = 0;
            m_ibuf[1] = 1;

            var mat = new View3d.Material(shader: View3d.EShader.ThickLineListGS, shader_data: new int[4] {
                Settings.LineWidth, 0, 0, 0
            });

            m_nbuf[0] = new View3d.Nugget(View3d.EPrim.LineList, View3d.EGeom.Vert | View3d.EGeom.Colr, 0, 2, 0, 2, !Bit.AllSet(line_colour, 0xFF000000), mat);

            if (Level.WidthPips != 0)
            {
                var hh = (float)(Instrument.PriceData.PipSize * Level.WidthPips / 2.0);
                m_vbuf[2] = new View3d.Vertex(new v4(0, -hh, 0, 1), region_colour);
                m_vbuf[3] = new View3d.Vertex(new v4(width, -hh, 0, 1), region_colour);
                m_vbuf[4] = new View3d.Vertex(new v4(0, +hh, 0, 1), region_colour);
                m_vbuf[5] = new View3d.Vertex(new v4(width, +hh, 0, 1), region_colour);
                m_ibuf[2] = 2;
                m_ibuf[3] = 3;
                m_ibuf[4] = 5;
                m_ibuf[5] = 5;
                m_ibuf[6] = 4;
                m_ibuf[7] = 2;

                m_nbuf[1] = new View3d.Nugget(View3d.EPrim.TriList, View3d.EGeom.Vert | View3d.EGeom.Colr, 2, 6, 2, 8, !Bit.AllSet(region_colour, 0xFF000000));
            }

            // Create the graphics
            Gfx = new View3d.Object(Name, 0xFFFFFFFF, m_vbuf.Count, m_ibuf.Count, m_nbuf.Count, m_vbuf.ToArray(), m_ibuf.ToArray(), m_nbuf.ToArray());

            base.UpdateGfxCore();
        }
Пример #7
0
        protected override void UpdateGfxCore()
        {
            var line_colour   = (Selected ? Settings.Colour.Lerp(Color.Gray, 0.5f) : Settings.Colour).ToArgbU();
            var region_colour = (Selected ? Settings.RegionColour.Lerp(Color.Gray, 0.5f) : Settings.RegionColour).ToArgbU();
            var region_height = Settings.RegionHeight;
            var width         = (float)Chart.XAxis.Span;

            // Create graphics for the horizontal line
            m_vbuf.Resize(2 + (region_height != 0 ? 4 : 0));
            m_ibuf.Resize(2 + (region_height != 0 ? 6 : 0));
            m_nbuf.Resize(1 + (region_height != 0 ? 1 : 0));

            m_vbuf[0] = new View3d.Vertex(new v4(0, 0, 0, 1), line_colour);
            m_vbuf[1] = new View3d.Vertex(new v4(width, 0, 0, 1), line_colour);
            m_ibuf[0] = 0;
            m_ibuf[1] = 1;
            m_nbuf[0] = new View3d.Nugget(View3d.EPrim.LineList, View3d.EGeom.Vert | View3d.EGeom.Colr, 0, 2, 0, 2);

            if (region_height != 0)
            {
                var half_height = (float)(Instrument.PriceData.PipSize * region_height / 2.0);
                m_vbuf[2] = new View3d.Vertex(new v4(0, -half_height, 0, 1), region_colour);
                m_vbuf[3] = new View3d.Vertex(new v4(width, -half_height, 0, 1), region_colour);
                m_vbuf[4] = new View3d.Vertex(new v4(0, +half_height, 0, 1), region_colour);
                m_vbuf[5] = new View3d.Vertex(new v4(width, +half_height, 0, 1), region_colour);
                m_ibuf[2] = 2;
                m_ibuf[3] = 3;
                m_ibuf[4] = 5;
                m_ibuf[5] = 5;
                m_ibuf[6] = 4;
                m_ibuf[7] = 2;
                m_nbuf[1] = new View3d.Nugget(View3d.EPrim.TriList, View3d.EGeom.Vert | View3d.EGeom.Colr, 2, 6, 2, 8, !Bit.AllSet(region_colour, 0xFF000000));
            }

            // Create the graphics
            Gfx = new View3d.Object(Name, 0xFFFFFFFF, m_vbuf.Count, m_ibuf.Count, m_nbuf.Count, m_vbuf.ToArray(), m_ibuf.ToArray(), m_nbuf.ToArray());

            base.UpdateGfxCore();
        }
Пример #8
0
        public FormView3d()
        {
            InitializeComponent();
            m_view3d = new View3dControl
            {
                Name        = "m_view3d",
                BorderStyle = BorderStyle.FixedSingle,
                Dock        = DockStyle.Fill,
            };
            Controls.Add(m_view3d);
            m_demo_objs = m_view3d.Window.CreateDemoScene();

            m_view3d.Camera.ResetView();
            m_view3d.Camera.Lookat(new v4(10f, 10f, 5f, 1f), v4.Origin, v4.YAxis);

            // Simple create object
            m_obj0     = new View3d.Object("*Box test FFFFFFFF {1 2 3}", false, null);
            m_obj0.O2P = m4x4.Transform(0.5f, -0.3f, 0.2f, new v4(-0.3f, 1.2f, 0.5f, 1f));
            m_view3d.Window.AddObject(m_obj0);

            m_obj0.ShowNormals = true;
            m_view3d.Window.Diag.NormalsLength = 0.5f;
            m_view3d.Window.Diag.NormalsColour = Colour32.Yellow;

            // Create a texture and assign it to an object
            m_tex0 = new View3d.Texture(100, 100, new View3d.TextureOptions {
                GdiCompatible = true
            });
            using (var tex = new View3d.Texture.Lock(m_tex0, discard: true))
            {
                tex.Gfx.Clear(Color.DarkBlue);
                tex.Gfx.FillEllipse(Brushes.RoyalBlue, 10, 10, 80, 80);
                tex.Gfx.DrawString("Paul Rulz", SystemFonts.DefaultFont, Brushes.Black, new PointF(30, 40));
            }
            m_view3d.Window.RestoreRT();
            m_obj0.SetTexture(m_tex0);

            // Create object via callback
            m_obj1 = new View3d.Object("net", 0xFF0000FF, 20, 20, 1, CreateOnlyCB, null);
            m_view3d.Window.AddObject(m_obj1);

            // Create an object with a texture from a rendered scene
            m_obj2     = new View3d.Object("*Box Rt FFFFFFFF {0.7 0.9 0.4}", false, null);
            m_obj2.O2P = m4x4.Transform(-0.5f, 0.4f, 0.6f, new v4(0.5f, -0.2f, -0.3f, 1f));
            m_view3d.Window.AddObject(m_obj2);

            // Create a texture and use it as a render target
            m_tex2 = new View3d.Texture(200, 200, new View3d.TextureOptions
            {
                Format        = View3d.EFormat.DXGI_FORMAT_R8G8B8A8_UNORM,
                Mips          = 1U,
                Filter        = View3d.EFilter.D3D11_FILTER_MIN_MAG_MIP_LINEAR,
                AddrU         = View3d.EAddrMode.D3D11_TEXTURE_ADDRESS_CLAMP,
                AddrV         = View3d.EAddrMode.D3D11_TEXTURE_ADDRESS_CLAMP,
                BindFlags     = View3d.EBindFlags.D3D11_BIND_SHADER_RESOURCE | View3d.EBindFlags.D3D11_BIND_RENDER_TARGET,
                MiscFlags     = View3d.EResMiscFlags.NONE,
                ColourKey     = 0,
                HasAlpha      = false,
                GdiCompatible = false,
                DbgName       = "Test RT",
            });
            m_view3d.Paint += (s, a) =>
            {
                // Make sure 'm_obj' is not rendered (because it uses the texture we're rendering to)
                m_view3d.Window.RemoveObject(m_obj2);
                m_view3d.Window.SetRT(m_tex2, null, false);
                m_view3d.Window.AddObject(m_obj2);
            };
            m_obj2.SetTexture(m_tex2);

            // Create a gizmo for moving objects in the scene
            // Position it at the origin of m_obj0 and scale by 2
            m_giz = new View3d.Gizmo(View3d.Gizmo.EMode.Scale, m_obj0.O2P * m4x4.Scale(0.1f, v4.Origin));
            m_giz.Attach(m_obj0);
            m_giz.Moved += (s, a) =>
            {
                m_status.SetStatusMessage(msg: "Gizmo", display_time: TimeSpan.FromSeconds(2));
            };
            m_view3d.Window.AddGizmo(m_giz);

            m_btn_translate.Click += (s, a) => m_giz.Mode = View3d.Gizmo.EMode.Translate;
            m_btn_rotate.Click    += (s, a) => m_giz.Mode = View3d.Gizmo.EMode.Rotate;
            m_btn_scale.Click     += (s, a) => m_giz.Mode = View3d.Gizmo.EMode.Scale;

            // Create an object from buffers created in C#
            {
                var verts = new View3d.Vertex[]
                {
                    new View3d.Vertex(new v4(1f, 1f, 0f, 1f), 0xFFFF0000),
                    new View3d.Vertex(new v4(2f, 0f, 0f, 1f), 0xFF00FF00),
                    new View3d.Vertex(new v4(3f, 1f, 0f, 1f), 0xFF0000FF),
                };
                var indcs = new ushort[]
                {
                    0, 1, 2
                };
                var nuggets = new View3d.Nugget[]
                {
                    new View3d.Nugget(View3d.ETopo.TriList, View3d.EGeom.Vert | View3d.EGeom.Colr)
                };
                m_obj3 = new View3d.Object("Obj3", 0xFFFFFFFF, 3, 3, 1, verts, indcs, nuggets, null);
                m_view3d.Window.AddObject(m_obj3);
            }
        }
Пример #9
0
        protected override void UpdateGfxCore()
        {
            // Generate the EMA line for the visible area of the chart
            var ema_colour = Settings.ColourEMA.ToArgbU();
            var bol_colour = Settings.ColourBollingerBands.ToArgbU();

            // Get the visible X axis range, and convert it to positive indices
            var first_idx = Instrument.FirstIdx;
            var rng       = Instrument.IndexRange((int)(Chart.XAxis.Min - 1), (int)(Chart.XAxis.Max + 1));

            rng.Beg = Maths.Clamp(rng.Beg - first_idx, 0, m_ema.Count);
            rng.End = Maths.Clamp(rng.End - first_idx, 0, m_ema.Count);
            if (rng.Counti == 0)
            {
                Gfx = null;
                return;
            }

            var count = rng.Counti;

            m_vbuf.Resize(count);
            m_ibuf.Resize((count - 1) * 2);
            m_nbuf.Resize(1);

            // EMA model
            var v = 0; var i = 0;

            foreach (var candle_index in rng)
            {
                var ema = m_ema[(int)candle_index];
                m_vbuf[v++] = new View3d.Vertex(new v4(candle_index + first_idx, (float)ema.Mean, ChartUI.Z.Indicators, 1f), ema_colour);
            }
            for (var vi = 0; i != m_ibuf.Count; ++vi)
            {
                m_ibuf[i++] = (ushort)(vi);
                m_ibuf[i++] = (ushort)(vi + 1);
            }
            var mat = new View3d.Material(shader: View3d.EShader.ThickLineListGS, shader_data: new[] { Settings.Width, 0, 0, 0 });

            m_nbuf[0] = new View3d.Nugget(View3d.EPrim.LineList, View3d.EGeom.Vert | View3d.EGeom.Colr, 0, (uint)v, 0, (uint)i, false, mat);

            // Add geometry for Bollinger bands
            if (Settings.BollingerBands != 0)
            {
                m_vbuf.Resize(m_vbuf.Count + 2 * count);
                m_ibuf.Resize(m_ibuf.Count + 2 * count);
                m_nbuf.Resize(m_nbuf.Count + 2);

                // Lower/Upper band
                foreach (var candle_index in rng)
                {
                    var ema = m_ema[(int)candle_index];
                    m_vbuf[v++] = new View3d.Vertex(new v4(candle_index + first_idx, (float)(ema.Mean - Settings.BollingerBands * ema.PopStdDev), ChartUI.Z.Indicators, 1f), bol_colour);
                    m_ibuf[i++] = (ushort)(v - 1);
                }
                m_nbuf[1] = new View3d.Nugget(View3d.EPrim.LineStrip, View3d.EGeom.Vert | View3d.EGeom.Colr, (uint)(v - count), (uint)v, (uint)(i - count), (uint)i);
                foreach (var candle_index in rng)
                {
                    var ema = m_ema[(int)candle_index];
                    m_vbuf[v++] = new View3d.Vertex(new v4(candle_index + first_idx, (float)(ema.Mean + Settings.BollingerBands * ema.PopStdDev), ChartUI.Z.Indicators, 1f), bol_colour);
                    m_ibuf[i++] = (ushort)(v - 1);
                }
                m_nbuf[2] = new View3d.Nugget(View3d.EPrim.LineStrip, View3d.EGeom.Vert | View3d.EGeom.Colr, (uint)(v - count), (uint)v, (uint)(i - count), (uint)i);
            }

            // Create the graphics
            Gfx = new View3d.Object(Name, 0xFFFFFFFF, m_vbuf.Count, m_ibuf.Count, m_nbuf.Count, m_vbuf.ToArray(), m_ibuf.ToArray(), m_nbuf.ToArray());

            base.UpdateGfxCore();
        }
Пример #10
0
        /// <summary>Create a bar graph</summary>
        private ChartGfxPiece CreateBarPlot(RangeI idx_range)
        {
            var n = idx_range.Sizei;

            // Resize the geometry buffers
            m_vbuf.Resize(4 * n);
            m_ibuf.Resize(6 * n);
            m_nbuf.Resize(1);

            // Create the vertex/index data
            int vidx = 0, iidx = 0, nidx = 0;
            var col     = Options.Colour;
            var lwidth  = (0.0 - Options.BarHorizontalAlignment) * Options.BarWidth;
            var rwidth  = (1.0 - Options.BarHorizontalAlignment) * Options.BarWidth;
            var x_range = RangeF.Invalid;

            for (int i = 0; i != n; ++i)
            {
                // Get the points on either side of 'i'
                var j    = i + idx_range.Begi;
                var pt_l = j != 0 ? m_data[j - 1] : null;
                var pt   = m_data[j];
                var pt_r = j + 1 != m_data.Count ? m_data[j + 1] : null;

                // Get the distance to the left and right of 'pt.x'
                var l = pt_l != null ? lwidth * (pt_l.xf - pt.xf) : 0;
                var r = pt_r != null ? rwidth * (pt_r.xf - pt.xf) : 0;
                if (j == 0 && j + 1 != m_data.Count && pt_r != null)
                {
                    l = -lwidth * (pt_r.xf - pt.xf);
                }
                if (j + 1 == m_data.Count && j != 0 && pt_l != null)
                {
                    r = -rwidth * (pt_l.xf - pt.xf);
                }

                var v = vidx;
                m_vbuf[vidx++] = new View3d.Vertex(new v4((float)(pt.xf + r), (float)(pt.yf >= 0f ? pt.yf : 0f), 0f, 1f), col);
                m_vbuf[vidx++] = new View3d.Vertex(new v4((float)(pt.xf - l), (float)(pt.yf >= 0f ? pt.yf : 0f), 0f, 1f), col);
                m_vbuf[vidx++] = new View3d.Vertex(new v4((float)(pt.xf - l), (float)(pt.yf >= 0f ? 0f : pt.yf), 0f, 1f), col);
                m_vbuf[vidx++] = new View3d.Vertex(new v4((float)(pt.xf + r), (float)(pt.yf >= 0f ? 0f : pt.yf), 0f, 1f), col);

                m_ibuf[iidx++] = (ushort)(v + 0);
                m_ibuf[iidx++] = (ushort)(v + 1);
                m_ibuf[iidx++] = (ushort)(v + 2);
                m_ibuf[iidx++] = (ushort)(v + 2);
                m_ibuf[iidx++] = (ushort)(v + 3);
                m_ibuf[iidx++] = (ushort)(v + 0);

                x_range.Grow(pt.xf);
            }

            // Create a nugget for the tri list
            uint v0 = 0, v1 = (uint)vidx;
            uint i0 = 0, i1 = (uint)iidx;
            var  flags = col.A != 0xff ? View3d.ENuggetFlag.GeometryHasAlpha : View3d.ENuggetFlag.None;

            m_nbuf[nidx++] = new View3d.Nugget(View3d.ETopo.TriList, View3d.EGeom.Vert | View3d.EGeom.Colr, v0, v1, i0, i1, flags);

            // Add the bar 'tops'
            if (Options.LinesOnBarPlot)
            {
                // Use line strips
                m_vbuf.Resize(m_vbuf.Count + n * 2);
                m_ibuf.Resize(m_ibuf.Count + n * 2);
                m_nbuf.Resize(m_nbuf.Count + 1);

                var line_colour = col.Darken(0.25f).Alpha(1f);
                for (int i = 0; i != n; ++i)
                {
                    var vert0 = m_vbuf[i * 4 + 0];
                    var vert1 = m_vbuf[i * 4 + 1];
                    var v     = vidx;

                    m_vbuf[vidx++] = new View3d.Vertex(vert0.m_pos, line_colour);
                    m_vbuf[vidx++] = new View3d.Vertex(vert1.m_pos, line_colour);

                    m_ibuf[iidx++] = (ushort)(v + 0);
                    m_ibuf[iidx++] = (ushort)(v + 1);
                }

                // Create a nugget for the bar tops
                v0             = v1; v1 += (uint)(n * 2);
                i0             = i1; i1 += (uint)(n * 2);
                m_nbuf[nidx++] = new View3d.Nugget(View3d.ETopo.LineList, View3d.EGeom.Vert | View3d.EGeom.Colr, v0, v1, i0, i1);
            }

            // Create the graphics
            var gfx = new View3d.Object($"{Name}-[{idx_range.Beg},{idx_range.End})", 0xFFFFFFFF, m_vbuf.Count, m_ibuf.Count, m_nbuf.Count, m_vbuf.ToArray(), m_ibuf.ToArray(), m_nbuf.ToArray(), Id);

            return(new ChartGfxPiece(gfx, x_range));
        }