public void DrawPoints(string name, int pointCount, float pointSize)
 {
     if (!_objectsHandleDictionary.ContainsKey(name))
     {
         throw new ApplicationException("Object must be added to the renderer before drawing");
     }
     GL.BindVertexArray(_objectsHandleDictionary[name].ObjectHandle);
     GL.PointSize(pointSize);
     GL.DrawElements(BeginMode.Points, pointCount, DrawElementsType.UnsignedInt, IntPtr.Zero);
 }
        public void DrawBackBuffer(GraphScaleData scaleData)
        {
            if (Hide || _backData == null)
            {
                return;
            }
            float height = ScaleFunction.ScaledHeight(scaleData);

            Matrix4 transform = Matrix4.CreateTranslation(scaleData.XShift, 0, 0) * Matrix4.Scale(2 / scaleData.BaseScale, 2 / height, 1) * Matrix4.CreateTranslation(-1, -1, 0);

            GL.UniformMatrix4(_shaderProgram.UniformTransform, false, ref transform);

            if (_drawMode == BeginMode.Lines || _drawMode == BeginMode.LineLoop || _drawMode == BeginMode.LineStrip)
            {
                GL.LineWidth(2f);
            }
            else if (_drawMode == BeginMode.Points)
            {
                GL.PointSize(2f);
            }

            if (_alphaBlend > 0)
            {
                Color4 col = Color;
                col.A = 1 - _alphaBlend;
                GL.Uniform4(_shaderProgram.UniformColor, col);
            }
            else
            {
                GL.Uniform4(_shaderProgram.UniformColor, Color);
            }

            if (_graphType == GraphType.SolidGraph)
            {
                _backBuffer.SetAttributeInfo(_shaderProgram.AttributeCoord2D, 2);

                _backBuffer.BeginDraw();
                _backBuffer.Draw(_drawMode);
                _backBuffer.EndDraw();

                _backBuffer.SetAttributeInfo(_shaderProgram.AttributeCoord2D, 2, false, 2 * Vector2.SizeInBytes);
                GL.Uniform4(_shaderProgram.UniformColor, Color4.Black);
                GL.LineWidth(1f);

                _backBuffer.BeginDraw();
                _backBuffer.Draw(BeginMode.LineStrip, _backData.Length / 2);
                _backBuffer.EndDraw();
            }
            else
            {
                _backBuffer.BeginDraw();
                _backBuffer.Draw(_drawMode, _backData.Length / 2);
                _backBuffer.EndDraw();
            }
        }
        public void Draw(RenderQueueItem queueItem, ICamera camera, float aspectRatio)
        {
            var glContext = infra.GlContext;
            var visual    = (IModelVisualElement)queueItem.VisualElement;
            var node      = queueItem.Node;

            if (visual.Hide)
            {
                return;
            }

            var renderStateData = visual.RenderState.GetFallbackData();

            glContext.Bindings.Program.Set(commonObjects.StandardShaderProgram);

            switch (renderStateData.PolygonMode)
            {
            case PolygonMode.Fill:
                glContext.States.Rasterizer.PolygonModeFront.Set(ObjectGL.Api.Context.States.Rasterizer.PolygonMode.Fill);
                break;

            case PolygonMode.Line:
                glContext.States.Rasterizer.PolygonModeFront.Set(ObjectGL.Api.Context.States.Rasterizer.PolygonMode.Line);
                break;

            case PolygonMode.Point:
                glContext.States.Rasterizer.PolygonModeFront.Set(ObjectGL.Api.Context.States.Rasterizer.PolygonMode.Point);
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            switch (renderStateData.CullFace)
            {
            case CullFace.None:
                glContext.States.Rasterizer.CullFaceEnable.Set(false);
                break;

            case CullFace.Back:
                glContext.States.Rasterizer.CullFaceEnable.Set(true);
                glContext.States.Rasterizer.CullFace.Set(CullFaceMode.Back);
                break;

            case CullFace.Front:
                glContext.States.Rasterizer.CullFaceEnable.Set(true);
                glContext.States.Rasterizer.CullFace.Set(CullFaceMode.Front);
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            glContext.States.DepthStencil.StencilTestEnable.Set(true);
            var stencilFunctionSettings = new StencilFunctionSettings
            {
                Function  = StencilFunction.Always,
                Mask      = 0xff,
                Reference = 1
            };
            var stencilOperationSettings = new StencilOperationSettings
            {
                DepthPass   = queueItem.IsHighlighted ? StencilOp.Replace : StencilOp.Keep,
                DepthFail   = queueItem.IsHighlighted ? StencilOp.Replace : StencilOp.Keep,
                StencilFail = StencilOp.Keep
            };

            glContext.States.DepthStencil.Front.StencilWriteMask.Set(0xff);
            glContext.States.DepthStencil.Back.StencilWriteMask.Set(0xff);
            glContext.States.DepthStencil.Front.StencilFunctionSettings.Set(stencilFunctionSettings);
            glContext.States.DepthStencil.Back.StencilFunctionSettings.Set(stencilFunctionSettings);
            glContext.States.DepthStencil.Front.StencilOperationSettings.Set(stencilOperationSettings);
            glContext.States.DepthStencil.Back.StencilOperationSettings.Set(stencilOperationSettings);

            var material     = visual.Material as IStandardMaterial ?? commonObjects.UndefinedMaterial;
            var diffuseColor = material.DiffuseColor;
            var glDiffuseMap = material.DiffuseMap
                               ?.CacheContainer
                               .GetOrAddCache(Tuples.Pair(infra, material.DiffuseMap),
                                              x => new CgImageCache(x.First, x.Second))
                               .GetGlTexture2D();
            var glNormalMap = material.NormalMap
                              ?.CacheContainer
                              .GetOrAddCache(Tuples.Pair(infra, material.NormalMap),
                                             x => new CgImageCache(x.First, x.Second))
                              .GetGlTexture2D();

            glContext.Bindings.Textures.Units[0].Set(glDiffuseMap);
            glContext.Bindings.Textures.Units[1].Set(glNormalMap);
            var sampler = samplerCache.GetGlSampler(material.Sampler);

            glContext.Bindings.Samplers[0].Set(sampler);
            glContext.Bindings.Samplers[1].Set(sampler);

            var cWarpScroll = node.SearchComponent <IWarpScrollComponent>();

            commonObjects.MaterialUb.SetData(new MaterialUniform
            {
                Color              = diffuseColor.SrgbToLinear(),
                IsEdited           = (Bool32)(material.HighlightEffect == HighlightEffect.BlackWhiteBorder),
                IgnoreLighting     = (Bool32)material.IgnoreLighting,
                IsSelected         = (Bool32)(material.HighlightEffect == HighlightEffect.RainbowBorder),
                UseTexture         = (Bool32)(glDiffuseMap != null),
                UseNormalMap       = (Bool32)(glNormalMap != null),
                NoSpecular         = (Bool32)material.NoSpecular,
                ScrollingEnabled   = (Bool32)(cWarpScroll != null),
                ScrollingAmount    = cWarpScroll?.VisibleScrollAmount ?? 0.0f,
                BlackIsTransparent = (Bool32)(material.RtTransparencyMode == RtTransparencyMode.BlackIsTransparent),
                WhiteIsTransparent = (Bool32)(material.RtTransparencyMode == RtTransparencyMode.WhiteIsTransparent),
                IsPulsating        = (Bool32)(material.HighlightEffect == HighlightEffect.Pulsating),
                PulsatingColor     = Color4.Orange
            });

            // todo: Use ObjectGL bindings
            GL.PointSize(renderStateData.PointSize);
            GL.LineWidth(renderStateData.LineWidth);

            // todo: switch (visual.TransformSpace)
            var       transform = visual.Transform * node.GlobalTransform;
            Matrix4x4 world;

            if (visual.TransformSpace == TransformSpace.ScreenAlighned)
            {
                var globalViewFrame = camera.GetGlobalFrame();
                transform.Rotation =
                    Quaternion.RotationToFrame(globalViewFrame.Right, globalViewFrame.Up);
                world = Matrix4x4.Scaling(visual.NonUniformScale) * transform.ToMatrix4x4();
            }
            else if (visual.TransformSpace == TransformSpace.Ortho)
            {
                var props = camera.GetProps();

                var viewMat      = camera.GetViewMat();
                var orthoProjMat = Matrix4x4.OrthoFromPerspective((props.Target - props.Frame.Eye).Length(),
                                                                  props.Projection.Fov, aspectRatio, -10f, 5f);

                var viewProjInverse = camera.GetViewProjInverse(aspectRatio);

                world  = Matrix4x4.Scaling(visual.NonUniformScale) * transform.ToMatrix4x4();
                world *= viewMat * orthoProjMat * viewProjInverse;
            }
            else
            {
                world = Matrix4x4.Scaling(visual.NonUniformScale) * transform.ToMatrix4x4();
            }

            var zOffset = renderStateData.ZOffset +
                          GraphicsHelper.MinZOffset * (node.ChildNodes.IsEmptyL()
                            ? (node.ParentNode?.ChildNodes.IndexOf(node) ?? 0)
                            : 0);

            commonObjects.TransformUb.SetData(new TransformUniform {
                World = world, WorldInverseTranspose = world.Invert().Transpose(), ZOffset = zOffset
            });

            switch (visual.Model)
            {
            case IFlexibleModel flexibleModel:
            {
                var modelPart      = flexibleModel.Parts[visual.ModelPartIndex];
                var vertexSet      = flexibleModel.VertexSets[modelPart.VertexSetIndex];
                var vertexSetCache = vertexSet.CacheContainer.GetOrAddCache(Tuples.Pair(infra, vertexSet), x => new VertexSetCache(x.First, x.Second));

                var glVao = vertexSetCache.GetGlVao();

                glContext.Bindings.VertexArray.Set(glVao);

                var beginMode = GetBeginMode(modelPart.PrimitiveTopology);
                if (vertexSet.IndicesInfo == null)
                {
                    glContext.Actions.Draw.Arrays(beginMode, modelPart.FirstIndex + modelPart.VertexOffset, modelPart.IndexCount);
                }
                else
                {
                    AnalyzeIndexType(vertexSet.IndicesInfo.Format, out var drawElementsType, out var offsetMultiplier);
                    var indexBufferOffset = modelPart.FirstIndex * offsetMultiplier;
                    if (modelPart.VertexOffset == 0)
                    {
                        glContext.Actions.Draw.Elements(beginMode, modelPart.IndexCount, drawElementsType, indexBufferOffset);
                    }
                    else
                    {
                        glContext.Actions.Draw.ElementsBaseVertex(beginMode, modelPart.IndexCount, drawElementsType, indexBufferOffset, modelPart.VertexOffset);
                    }
                }
                break;
            }

            case IExplicitModel explicitModel:
            {
                var modelPart = explicitModel.IndexSubranges[visual.ModelPartIndex];
                var cache     = explicitModel.CacheContainer.GetOrAddCache(
                    Tuples.Pair(infra, explicitModel),
                    x => new ExplicitModelCache(x.First, x.Second));
                var glObjects = cache.GetGlObjects();
                glContext.Bindings.VertexArray.Set(glObjects.Vao);
                var beginMode = GetBeginMode(explicitModel.Topology);
                if (glObjects.IndexBuffer == null)
                {
                    glContext.Actions.Draw.Arrays(beginMode, modelPart.FirstIndex, modelPart.IndexCount);
                }
                else
                {
                    var drawElementsType  = glObjects.SixteenBitIndices ? DrawElementsType.UnsignedShort : DrawElementsType.UnsignedInt;
                    var indexSize         = glObjects.SixteenBitIndices ? sizeof(ushort) : sizeof(int);
                    var indexBufferOffset = modelPart.FirstIndex * indexSize;
                    glContext.Actions.Draw.Elements(beginMode, modelPart.IndexCount, drawElementsType, indexBufferOffset);
                }
                break;
            }

            default:
                throw new NotImplementedException();
            }
        }