using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VisiMath;
using VisiMath.Geometry;
using VisimBox.Renderer.RenderObjects;

namespace VisimBox.Renderer
{
    /// <summary>
    /// Rendering context for renderer - either standalone renderer window or embedded renderingguicontrol
    /// </summary>
    public abstract class RenderContext : IDisposable, VisimBox.Renderer.IRenderContext
    {
        #region fields

        /// <summary>
        /// settings for the context
        /// </summary>
        protected RenderContextSettings settings;
        /// <summary>
        /// Renderer associated to the render context
        /// </summary>
        protected IRenderer renderer;

        /// <summary>
        /// main "fullscreen" viewport encompassing the whole area
        /// </summary>
        protected Viewport mainViewport;
        /// <summary>
        /// List containing all other viewports
        /// </summary>
        protected Dictionary<string, Viewport> viewports = new Dictionary<string,Viewport>();

        protected int fps;

        protected System.Diagnostics.Stopwatch RenderTimer;

        protected Render2D.Font _CurrentFont;

        protected Texture _CurrentTexture;  //don't hold as reference

        protected bool _showFPS = false;

        protected UInt64 _RenderFlags = UInt64.MaxValue;

        #endregion

        #region Events


        /// <summary>
        /// Called on the framestart before any rendering starts
        /// </summary>
        public event RendererEvent FrameStart;

        /// <summary>
        /// Called on the end of the frame before showing results of the rendering
        /// </summary>
        public event RendererEvent FrameEnd;



        #endregion

        #region Properties

        public UInt64 RenderFlags { get { return _RenderFlags; } set { _RenderFlags = value; } }

        public IRenderer Renderer
        {
            get
            {
                return this.renderer;
            }
        }

        /// <summary>
        /// Returns pointer to the main camera (camera in main viewport)
        /// </summary>
        public ICamera MainCamera
        {
            get
            {
                return mainViewport.Camera;
            }

            set
            {
                mainViewport.Camera = value;
            }
        }

        /// <summary>
        /// Returns current rendering frames per second for this context
        /// </summary>
        public int CurrentFPS
        {
            get
            {
                return fps;
            }
        }

        /// <summary>
        /// Show fps on screen?
        /// </summary>
        public bool ShowFPS { get { return _showFPS; } set { _showFPS = value; } }


        /// <summary>
        /// Currently selected texture
        /// </summary>
        public virtual Texture CurrentTexture { 
            get
            {
                return _CurrentTexture;
            }
            set
            {
                _CurrentTexture = value;
            }
        }

        /// <summary>
        /// Settings of the render context
        /// </summary>
        public RenderContextSettings Settings
        {
            get
            {
                return settings;
            }

            set
            {
                ChangeSettings(ref value);
            }
        }

        protected virtual void ChangeSettings(ref RenderContextSettings setts)
        {
            settings = setts;
        }


        #endregion

        #region constructors

        public RenderContext(IRenderer ren)
        {
            renderer = ren;
            settings = new RenderContextSettings();
            mainViewport = new Viewport(this, 0, 0, 100, 100);
            Queue = new RenderQueue(this);
            RenderTimer = new System.Diagnostics.Stopwatch();
            DebugPoint = DebugLine1 = DebugLine2 = Vector3.Invalid;
            RenderTimer.Start();
        }

        public RenderContext(IRenderer ren, RenderContextSettings rs)
        {
            renderer = ren;
            settings = rs;
            Queue = new RenderQueue(this);
            mainViewport = new Viewport(this, 0, 0, rs.Width, rs.Height);
            RenderTimer = new System.Diagnostics.Stopwatch();
            DebugPoint = DebugLine1 = DebugLine2 = Vector3.Invalid;
            
            RenderTimer.Start();
        }

        #endregion


        #region Utilities

        public ICamera CreateDefaultCamera()
        {
            float zmax = mainViewport.ViewQual.Visibility;
            if (zmax <= 0)
                zmax = 300.0f;
            //FPSCamera fps = new FPSCamera(MathTools.HalfPi, 0.3f, zmax);
            StandardCamera fps = new StandardCamera(MathTools.QuarterPi, 0.3f, zmax);
            return fps;
        }

        virtual public void Dispose()
        {
        }

        /// <summary>
        /// Grabs actual content of the render context and converts it to bitmap
        /// </summary>
        /// <returns>BMP containg current output on the render context</returns>
        public virtual System.Drawing.Bitmap GetScreenShot()
        {
            return null;
        }

        public System.Drawing.Imaging.ImageFormat GetFormatType(string extension)
        {
            switch (extension)
            {
                case "png": return System.Drawing.Imaging.ImageFormat.Png;
                case "bmp": return System.Drawing.Imaging.ImageFormat.Bmp;
                case "jpg":
                    return System.Drawing.Imaging.ImageFormat.Jpeg;
                default:
                    throw new ArgumentException();
            }
        }

        public string GetExtension(string filename)
        {
            if (filename == null)
                return null;
            int idx = filename.LastIndexOf('.');
            if (idx < 0)
                return null;
            if (idx == filename.Length - 1)
                return null;
            return filename.Substring(idx+1);
        }

        /// <summary>
        /// Saves screenshot with specified name, uses GetScreenShot()
        /// </summary>
        /// <param name="filename">filename to save, if null, creates file ScreenshotDATE-TIME.jpg</param>
        public virtual void SaveScreenShot(string filename = null, string extension = null)
        {

            if (filename == null)
            {
                DateTime dt = DateTime.Now;

                //filename = string.Format("screenshot{0:yyyyMMdd}-{1:HH mm ss}.jpg", dt.Date, dt.TimeOfDay);                
                filename = string.Format("screenshot{0:yyyyMMdd-HHmmss}.jpg", dt);
            }
           
            string fileextension = GetExtension(filename);

            System.Drawing.Imaging.ImageFormat format = System.Drawing.Imaging.ImageFormat.Jpeg;

            if (extension != null)
            {
                if (fileextension != extension)
                {
                    filename += ".extension";
                    fileextension = extension;
                }
            }

            try
            {
                format = GetFormatType(fileextension);
            }
            catch
            {
            }
            
            System.Drawing.Bitmap bmp = GetScreenShot();
            if (bmp == null)
            {
                Console.DebugLine("Screenshot saving failed!");
                return;
            }
            bmp.Save(filename, format);
            bmp.Dispose();
            VisimBox.Console.WriteLine("Screenshot " + filename + "saved.");
        }




        #endregion


        #region Debug

        Vector3 _debugPoint;
        Vector3 _debugPoint1, _debugPoint2, _debugPoint3, _debugPoint4, _debugPoint5, _debugPoint6;

        public Vector3 DebugPoint { 
            get
            {
                return _debugPoint;
            }
            set 
            {
                _debugPoint = value;
                if (value.IsValid())
                {
                    _debugPoint1 = value; _debugPoint1.Substract(0.5f, 0, 0);
                    _debugPoint2 = value; _debugPoint2.Add(0.5f, 0, 0);
                    _debugPoint3 = value; _debugPoint3.Substract(0, 0.5f, 0);
                    _debugPoint4 = value; _debugPoint4.Add(0, 0.5f, 0);
                    _debugPoint5 = value; _debugPoint5.Substract(0, 0, 0.5f);
                    _debugPoint6 = value; _debugPoint6.Add(0, 0, 0.5f);
                }
            } 
        }


        public Vector3 DebugLine1 { get; set; }
        public Vector3 DebugLine2 { get; set; }



        #endregion



        #region Rendering Settings

        /// <summary>
        /// Enables / disables fog drawing
        /// </summary>
        public abstract bool Fog { get; set; }

        /// <summary>
        /// Color of the fog
        /// </summary>
        public abstract ColorByte FogColor { get; set; }

        /// <summary>
        /// Density of the fog
        /// </summary>
        public abstract float FogDensity { get; set; }

        #endregion


        protected bool _zBuffer = true;
        /// <summary>
        /// Use to directly change using of the zbuffer
        /// </summary>
        public virtual bool ZBufferUsing { 
            get
            {
                return _zBuffer;
            }

            set
            {
                _zBuffer = value;
            }
        }


        virtual public void StartFrame()
        {
            RenderTimer.Stop();
            double lasttime = RenderTimer.Elapsed.TotalMilliseconds;
            if (lasttime > 0)
            {
                lasttime = lasttime / 1000; //last time now in seconds

                fps = (int) ( 1.0 / lasttime);
            }

            RenderTimer.Reset();
            RenderTimer.Start();

            if (FrameStart != null)
            {
                FrameStart(this, new RendererEventArgs(this.renderer, this, this.MainCamera));
            }
        }

        virtual public void EndFrame()
        {            
            if (DebugPoint.IsValid())
            {
                SetTransformation(Matrix4.Identitity);
                SetColor(ColorByte.White);
                DrawLine3D(ref _debugPoint1, ref _debugPoint2);
                DrawLine3D(ref _debugPoint3, ref _debugPoint4);
                DrawLine3D(ref _debugPoint5, ref _debugPoint6);
            }

            if (DebugLine1.IsValid() && DebugLine2.IsValid())
            {
                SetTransformation(Matrix4.Identitity);
                SetColor(ColorByte.White);
                DrawLine3D(DebugLine1, DebugLine2);                
            }

            //RenderTimer.Stop();
            if (FrameEnd != null)
            {
                FrameEnd(this, new RendererEventArgs(this.renderer, this, this.MainCamera));
            }            
        }

        virtual public void RenderFrame()
        {
            StartFrame();
            EndFrame();
        }


        #region IRenderContext Members

        /// <summary>
        /// Draws simple skybox
        /// </summary>
        /// <param name="skybox">Skybox data (note, textures in skybox must be initialized!)</param>
        public abstract void DrawSkybox(ref SkyboxData skybox);

        /// <summary>
        /// Renders spefified node hierarchy
        /// </summary>
        /// <param name="scene">Nodes to render</param>
        public void RenderNodes(VisimBox.Scene.Node scene)
        {
            ClearRenderingQueue();
            StartRenderingQueue();
            RendererEventArgs args = new RendererEventArgs(this.renderer, this, this.MainCamera, RenderFlags);
            scene.RenderHierarchy(args);
            FinishRenderQueue();
        }

        protected RenderQueue Queue;

        /// <summary>
        /// Adds render item to the renderer queue
        /// </summary>
        /// <param name="item">Render buffer item</param>
        public virtual void AddRenderItem(RenderBufferItem item)
        {
            Queue.AddItem(item);
        }

        /// <summary>
        /// Clears rendering queue
        /// </summary>
        public virtual void ClearRenderingQueue()
        {
            Queue.Clear();
        }

        /// <summary>
        /// Starts rendering queue (allows adding new items to render queue.
        /// If renderer uses multithreading, queue will be rendered as soon as some queue item will be added, except alpha values
        /// </summary>
        public virtual void StartRenderingQueue()
        {
            Queue.Start();
        }

        /// <summary>
        /// Finishes rendering queue (renders all remaining items in the queue including sorted alpha items)
        /// </summary>
        public virtual void FinishRenderQueue()
        {
            Queue.Finish();
        }




        #region Direct Rendering

        /// <summary>
        /// Sets main rendering color (especially for 2d rendering)
        /// </summary>
        /// <param name="col">Color</param>
        public void SetColor(ColorByte col)
        {
            SetColor(ref col);
        }
        /// <summary>
        /// Sets main rendering color (especially for 2d rendering)
        /// </summary>
        /// <param name="col">Color</param>
        public abstract void SetColor(ref ColorByte col);
        /// <summary>
        /// Sets main rendering color (especially for 2d rendering)
        /// </summary>
        /// <param name="col">Color</param>
        public void SetColor(System.Drawing.Color col)
        {
            ColorByte cb = new ColorByte(col.ToArgb());
            SetColor(ref cb);
        }

        /// <summary>
        /// Sets model transformation (without camera transformation)
        /// </summary>
        /// <param name="mat"></param>
        public abstract void SetTransformation(ref Matrix4 mat);

        /// <summary>
        /// Sets model transformation (without camera transformation)
        /// </summary>
        /// <param name="mat"></param>
        public virtual void SetTransformation(Matrix4 mat)
        {
            SetTransformation(ref mat);
        }



        #region Immediate mode - don't use /overuse, maybe very slow on some implementations

        /// <summary>
        /// Draws one vertex as a point
        /// </summary>
        /// <remarks>This is slow, use only in special circumstances (debug rendering)</remarks>
        public abstract void DrawPoint3D(IVertex point);
        /// <summary>
        /// Draws one vector as a point
        /// </summary>
        /// <remarks>This is slow, use only in special circumstances (debug rendering)</remarks>
        public virtual void DrawPoint3D(ref Vector3 vec)
        {
            DrawPoint3D(new PositionVertex(ref vec));
        }

        /// <summary>
        /// Draws one vector as a point
        /// </summary>
        /// <remarks>This is slow, use only in special circumstances (debug rendering)</remarks>
        public virtual void DrawPoint3D(Vector3 vec)
        {
            DrawPoint3D(ref vec);
        }


        /// <summary>
        /// Draws single line from first to second
        /// </summary>
        /// <remarks>This is slow, use only in special circumstances (debug rendering)</remarks>
        public abstract void DrawLine3D(IVertex first, IVertex second);
        /// <summary>
        /// Draws single line from first to second
        /// </summary>
        /// <remarks>This is slow, use only in special circumstances (debug rendering)</remarks>
        public virtual void DrawLine3D(ref Vector3 first, ref Vector3 second)
        {
            DrawLine3D(new PositionVertex(ref first), new PositionVertex(ref second));
        }

        /// <summary>
        /// Draws single line from first to second
        /// </summary>
        /// <remarks>This is slow, use only in special circumstances (debug rendering)</remarks>
        public virtual void DrawLine3D(Vector3 first, Vector3 second)
        {
            DrawLine3D(ref first, ref second);
        }

        /// <summary>
        /// Draws single triangle specified by three vertices
        /// </summary>
        /// <remarks>This is slow, use only in special circumstances (debug rendering)</remarks>
        public abstract void DrawTriangle3D(IVertex first, IVertex second, IVertex third);
        /// <summary>
        /// Draws single triangle specified by three vertices
        /// </summary>
        /// <remarks>This is slow, use only in special circumstances (debug rendering)</remarks>
        public virtual void DrawTriangle3D(ref Vector3 first, ref Vector3 second, ref Vector3 third)
        {
            DrawTriangle3D(new PositionVertex(ref first), new PositionVertex(ref second), new PositionVertex(ref third));
        }

        /// <summary>
        /// Draws single triangle specified by three vertices
        /// </summary>
        /// <remarks>This is slow, use only in special circumstances (debug rendering)</remarks>
        public virtual void DrawTriangle3D(Vector3 first, Vector3 second, Vector3 third)
        {
            DrawTriangle3D(ref first, ref second, ref third);
        }
        /// <summary>
        /// Draws single quad specified by four vertices
        /// </summary>
        /// <remarks>This is slow, use only in special circumstances (debug rendering)</remarks>
        public abstract void DrawQuad3D(IVertex first, IVertex second, IVertex third, IVertex fourth);
        /// <summary>
        /// Draws single quad specified by four vertices
        /// </summary>
        public virtual void DrawQuad3D(ref Vector3 first, ref Vector3 second, ref Vector3 third, ref Vector3 fourth)
        {
            DrawQuad3D(new PositionVertex(ref first), new PositionVertex(ref second), new PositionVertex(ref third), new PositionVertex(ref fourth)); 
        }
        /// <summary>
        /// Draws single quad specified by four vertices
        /// </summary>
        /// <remarks>This is slow, use only in special circumstances (debug rendering)</remarks>
        public virtual void DrawQuad3D(Vector3 first, Vector3 second, Vector3 third, Vector3 fourth)
        {
            DrawQuad3D(ref first, ref second, ref third, ref fourth);
        }



        #endregion

        #region From system memory - faster, but still slower then vertex buffers

        /// <summary>
        /// Renders points from vertex array.
        /// </summary>
        /// <param name="varray">Vertex array with vertices (should be VertexArray, not VertexList)</param>
        /// <param name="startindex">Starting index of elements</param>
        /// <param name="count">Count of elements (if zero, all remaining elements from starting index will be drawn</param>
        /// <remarks>Rendering from system memory is (depending on the implementation, applies for openGL)
        /// much faster then direct rendering, but still slower then vertex buffers.</remarks>
        public abstract void RenderPoints(IVertexArray varray, int startindex = 0, int count = 0);
        /// <summary>
        /// Renders lines from vertex array.
        /// </summary>
        /// <param name="varray">Vertex array with vertices (should be VertexArray, not VertexList)</param>
        /// <param name="startindex">Starting index of elements</param>
        /// <param name="count">Count of elements (if zero, all remaining elements from starting index will be drawn</param>
        /// <remarks>Rendering from system memory is (depending on the implementation, applies for openGL)
        /// much faster then direct rendering, but still slower then vertex buffers.</remarks>
        public abstract void RenderLines(IVertexArray varray, int startindex = 0, int count = 0);
        /// <summary>
        /// Renders polyline from vertex array.
        /// </summary>
        /// <param name="varray">Vertex array with vertices (should be VertexArray, not VertexList)</param>
        /// <param name="startindex">Starting index of elements</param>
        /// <param name="count">Count of elements (if zero, all remaining elements from starting index will be drawn</param>
        /// <remarks>Rendering from system memory is (depending on the implementation, applies for openGL)
        /// much faster then direct rendering, but still slower then vertex buffers.</remarks>
        public abstract void RenderLine(IVertexArray varray, int startindex = 0, int count = 0);
        /// <summary>
        /// Renders triangles from vertex array.
        /// </summary>
        /// <param name="varray">Vertex array with vertices (should be VertexArray, not VertexList)</param>
        /// <param name="startindex">Starting index of elements</param>
        /// <param name="count">Count of elements (if zero, all remaining elements from starting index will be drawn</param>
        /// <remarks>Rendering from system memory is (depending on the implementation, applies for openGL)
        /// much faster then direct rendering, but still slower then vertex buffers.</remarks>
        public abstract void RenderTriangles(IVertexArray varray, int startindex = 0, int count = 0);
        /// <summary>
        /// Renders quads from vertex array.
        /// </summary>
        /// <param name="varray">Vertex array with vertices (should be VertexArray, not VertexList)</param>
        /// <param name="startindex">Starting index of elements</param>
        /// <param name="count">Count of elements (if zero, all remaining elements from starting index will be drawn</param>
        /// <remarks>Rendering from system memory is (depending on the implementation, applies for openGL)
        /// much faster then direct rendering, but still slower then vertex buffers.</remarks>
        public abstract void RenderQuads(IVertexArray varray, int startindex = 0, int count = 0);
        /// <summary>
        /// Renders polygon from vertex array.
        /// </summary>
        /// <param name="varray">Vertex array with vertices (should be VertexArray, not VertexList)</param>
        /// <param name="startindex">Starting index of elements</param>
        /// <param name="count">Count of elements (if zero, all remaining elements from starting index will be drawn</param>
        /// <remarks>Rendering from system memory is (depending on the implementation, applies for openGL)
        /// much faster then direct rendering, but still slower then vertex buffers.</remarks>
        public abstract void RenderPoly(IVertexArray varray, int startindex = 0, int count = 0);
        /// <summary>
        /// Renders indexed mesh from vertex array.
        /// </summary>
        /// <param name="varray">Vertex array with vertices (should be VertexArray, not VertexList)</param>
        /// <param name="indices">Indices for elements</param>
        /// <param name="type">Type of primitive in indexed mesh (valid are Poins, Lines, Triangles and Quads)</param>
        /// <param name="startindex">Starting index of elements</param>
        /// <param name="count">Count of elements (if zero, all remaining elements from starting index will be drawn</param>
        /// <remarks>Rendering from system memory is (depending on the implementation, applies for openGL)
        /// much faster then direct rendering, but still slower then vertex buffers.</remarks>
        public abstract void RenderIndexedMesh(IVertexArray varray, int[] indices, PrimitiveTypes type, int startindex = 0, int count = 0);

        /// <summary>
        /// Renders geometry object - List of points
        /// </summary>
        /// <param name="geo">Geometry object</param>
        /// <remarks>Renders from the vertexarray, might be much faster then direct rendering, but still slower then using vertex buffers</remarks>
        public virtual void RenderGeometry(Point3DList geo)
        {
            RenderPoints(geo.Vertices, 0, 0);
        }
        /// <summary>
        /// Renders geometry object - List of lines
        /// </summary>
        /// <param name="geo">Geometry object</param>
        /// <remarks>Renders from the vertexarray, might be much faster then direct rendering, but still slower then using vertex buffers</remarks>
        public virtual void RenderGeometry(LineList geo)
        {
            RenderLines(geo.Vertices, 0, 0);
        }
        /// <summary>
        /// Renders geometry object - PolyLine
        /// </summary>
        /// <param name="geo">Geometry object</param>
        /// <remarks>Renders from the vertexarray, might be much faster then direct rendering, but still slower then using vertex buffers</remarks>
        public virtual void RenderGeometry(PolyLine geo)
        {
            RenderLine(geo.Vertices, 0, 0);
        }
        /// <summary>
        /// Renders geometry object - List of triangles
        /// </summary>
        /// <param name="geo">Geometry object</param>
        /// <remarks>Renders from the vertexarray, might be much faster then direct rendering, but still slower then using vertex buffers</remarks>
        public virtual void RenderGeometry(TriangleList geo)
        {
            RenderTriangles(geo.Vertices, 0, 0);
        }
        /// <summary>
        /// Renders geometry object - List of quads
        /// </summary>
        /// <param name="geo">Geometry object</param>
        /// <remarks>Renders from the vertexarray, might be much faster then direct rendering, but still slower then using vertex buffers</remarks>
        public virtual void RenderGeometry(QuadList geo)
        {
            RenderQuads(geo.Vertices, 0, 0);
        }

        /// <summary>
        /// Renders geometry object - generic indexed geometry
        /// </summary>
        /// <param name="geo">Geometry object</param>
        /// <param name="subset">Subset to render. -1 means current</param>
        /// <remarks>Renders from the vertexarray, might be much faster then direct rendering, but still slower then using vertex buffers</remarks>
        public virtual void RenderGeometry(IndexedGeo geo, int subset = -1)
        {
            int store = 0;
            if (subset != -1)
            {
                store = geo.CurrentSubset;
                geo.CurrentSubset = subset;
            }
            RenderIndexedMesh(geo.Vertices, geo.CurrentIndices, geo.MeshType);
            if (subset != -1)
            {
                geo.CurrentSubset = store;
            }
        }

        /// <summary>
        /// Renders geometry object - Indexed triangle mesh
        /// </summary>
        /// <param name="geo">Geometry object</param>
        /// <remarks>Renders from the vertexarray, might be much faster then direct rendering, but still slower then using vertex buffers</remarks>
        public virtual void RenderGeometry(IndexedMesh geo, int subset = -1)
        {
            RenderGeometry(geo as IndexedGeo, subset);
        }
        /// <summary>
        /// Renders geometry object - Indexed quad mesh
        /// </summary>
        /// <param name="geo">Geometry object</param>
        /// <remarks>Renders from the vertexarray, might be much faster then direct rendering, but still slower then using vertex buffers</remarks>
        public virtual void RenderGeometry(IndexedQuads geo, int subset = -1)
        {
            RenderGeometry(geo as IndexedGeo, subset);
        }
        /// <summary>
        /// Renders geometry object - Indexed list of points
        /// </summary>
        /// <param name="geo">Geometry object</param>
        /// <remarks>Renders from the vertexarray, might be much faster then direct rendering, but still slower then using vertex buffers</remarks>
        public virtual void RenderGeometry(IndexedLines geo, int subset = -1)
        {
            RenderGeometry(geo as IndexedGeo, subset);
        }

        /// <summary>
        /// Renders generic geometry object - uses conversion routines from the object, will be very slow if overused!
        /// </summary>
        /// <param name="geo">Geometry object</param>
        /// <remarks>Renders from the vertexarray, might be much faster then direct rendering, but still slower then using vertex buffers</remarks>
        public virtual void RenderGeometry(IGeometry geometry)
        {
            PrimitiveTypes pt = geometry.PreferredPrimitive;

            switch (pt)
            {
                case PrimitiveTypes.IndexedTriangles:
                    RenderGeometry(geometry.ToIndexedMesh());
                    break;
                case PrimitiveTypes.TriangleList:
                    RenderGeometry(geometry.ToTriangles());
                    break;
                case PrimitiveTypes.LineList:
                    RenderGeometry(geometry.ToLines());
                    break;
                case PrimitiveTypes.PointList:
                    RenderGeometry(geometry.ToPoints());
                    break;

                default:
                    TriangleList tl = geometry.ToTriangles();
                    if (tl != null)
                    {
                        RenderGeometry(tl);
                        return;
                    }
                    LineList ll = geometry.ToLines();
                    if (ll != null)
                    {
                        RenderGeometry(ll);
                    }
                    Point3DList plist = geometry.ToPoints();
                    if (plist != null)
                    {
                        RenderGeometry(plist);
                    }
                    break;
            }
        }




        #endregion

        #region VertexBuffer rendering

        /// <summary>
        /// Render vertex buffer as specified type of primitive (can't be used for indexed meshes!)
        /// </summary>
        /// <param name="vertices">Vertex buffer</param>
        /// <param name="type">Primitive type</param>
        /// <param name="startindex">starting index</param>
        /// <param name="count">Number of elements</param>
        public abstract void RenderVertexBuffer(IVertexBuffer vertices, PrimitiveTypes type, int startindex = 0, int count = 0);


        /// <summary>
        /// Renders indexed mesh from vertex and index buffer
        /// </summary>
        /// <param name="vertices">Vertex buffer</param>
        /// <param name="indices">Index buffer</param>
        /// <param name="type">Primitive type</param>
        /// <param name="startindex">starting index</param>
        /// <param name="count">Number of elements</param>
        public abstract void RenderIndexedMesh(IVertexBuffer vertices, int[] indices, PrimitiveTypes type, int startindex = 0, int count = 0);

        /// <summary>
        /// Renders indexed mesh from vertex and index buffer
        /// </summary>
        /// <param name="vertices">Vertex buffer</param>
        /// <param name="indices">Index buffer</param>
        /// <param name="type">Primitive type</param>
        /// <param name="startindex">starting index</param>
        /// <param name="count">Number of elements</param>
        public abstract void RenderIndexedMesh(IVertexBuffer vertices, IIndexBuffer indices, PrimitiveTypes type, int startindex = 0, int count = 0);

        #endregion

        #region 2D rendering

        /// <summary>
        /// Sets renderer to 2d context, all 2d rendering calls should be done after this call!
        /// </summary>
        public abstract void Start2DRender();

        /// <summary>
        /// Returns renderer to previous (3d) rendering state from the 2d renderer
        /// </summary>
        public abstract void Stop2DRender();

        #region points

        /// <summary>
        /// Draw point in screen coordinates with currently selected color
        /// </summary>
        /// <param name="x">X position</param>
        /// <param name="y">Y position</param>
        public abstract void DrawPoint(int x, int y);
        
        /// <summary>
        /// Draw point in screen coordinates 
        /// </summary>
        /// <param name="x">X position</param>
        /// <param name="y">Y position</param>
        /// <param name="Color">Color of the pixel</param>
        public void DrawPoint(int x, int y, ColorByte Color)
        {
            SetColor(Color);
            DrawPoint(x, y);
        }

        /// <summary>
        /// Draw point in screen coordinates 
        /// </summary>
        /// <param name="x">X position</param>
        /// <param name="y">Y position</param>
        /// <param name="Color">Color of the pixel</param>
        public void DrawPoint(int x, int y, System.Drawing.Color Color)
        {
            SetColor(Color);
            DrawPoint(x, y);
        }

        #endregion

        #region lines

        /// <summary>
        /// Draw line in screen coordinates with currently selected color
        /// </summary>
        /// <param name="x1">x of the start of the line</param>
        /// <param name="y1">y of the start of the line</param>
        /// <param name="x2">X of the end of the line</param>
        /// <param name="y2">y of the end of the line</param>
        public abstract void DrawLine(int x1, int y1, int x2, int y2);


        /// <summary>
        /// Draw line in screen coordinates 
        /// </summary>
        /// <param name="x1">x of the start of the line</param>
        /// <param name="y1">y of the start of the line</param>
        /// <param name="x2">X of the end of the line</param>
        /// <param name="y2">y of the end of the line</param>
        /// <param name="Color">Color of the line</param>
        public void DrawLine(int x1, int y1, int x2, int y2, ColorByte Color)
        {
            SetColor(Color);
            DrawLine(x1, y1, x2, y2);
        }

        /// <summary>
        /// Draw line in screen coordinates 
        /// </summary>
        /// <param name="x1">x of the start of the line</param>
        /// <param name="y1">y of the start of the line</param>
        /// <param name="x2">X of the end of the line</param>
        /// <param name="y2">y of the end of the line</param>
        /// <param name="Color">Color of the line</param>
        public void DrawLine(int x1, int y1, int x2, int y2, System.Drawing.Color Color)
        {
            SetColor(Color);
            DrawLine(x1, y1, x2, y2);
        }

        #endregion

        #region rectangles

        /// <summary>
        /// Draws outlined 2d rectangle with x1 and y1 coordinates of top left and width and height, using current color
        /// </summary>
        /// <param name="x1">left upper corner</param>
        /// <param name="y1">left upper corner</param>
        /// <param name="width">width</param>
        /// <param name="height">height</param>
        public abstract void DrawRectangle(int x1, int y1, int width, int height);

        /// <summary>
        /// Draws outlined 2d rectangle with x1 and y1 coordinates of top left and width and height
        /// </summary>
        /// <param name="x1">left upper corner</param>
        /// <param name="y1">left upper corner</param>
        /// <param name="width">width</param>
        /// <param name="height">height</param>
        /// <param name="color">Color of the outline</param>
        public void DrawRectangle(int x1, int y1, int width, int height, ColorByte color)
        {
            SetColor(color);
            DrawRectangle(x1, y1, width, height);
        }

        /// <summary>
        /// Draws outlined 2d rectangle with x1 and y1 coordinates of top left and width and height
        /// </summary>
        /// <param name="x1">left upper corner</param>
        /// <param name="y1">left upper corner</param>
        /// <param name="width">width</param>
        /// <param name="height">height</param>
        /// <param name="color">Color of the outline</param>
        public void DrawRectangle(int x1, int y1, int width, int height, System.Drawing.Color color)
        {
            SetColor(color);
            DrawRectangle(x1, y1, width, height);
        }

        /// <summary>
        /// Draws outlined 2d rectangle with current color
        /// </summary>
        /// <param name="rect">Rectangle</param>
        public void DrawRectangle(System.Drawing.Rectangle rect)
        {
            DrawRectangle(rect.Left, rect.Top, rect.Width, rect.Height);
        }


        /// <summary>
        /// Draws outlined 2d rectangle
        /// </summary>
        /// <param name="Color">Color of the outline</param>
        /// <param name="rect">Rectangle</param>
        public void DrawRectangle(System.Drawing.Rectangle rect, ColorByte Color)
        {
            SetColor(Color);
            DrawRectangle(rect);
        }

        /// <summary>
        /// Draws outlined 2d rectangle
        /// </summary>
        /// <param name="Color">Color of the outline</param>
        /// <param name="rect">Rectangle</param>
        public void DrawRectangle(System.Drawing.Rectangle rect, System.Drawing.Color Color)
        {
            SetColor(Color);
            DrawRectangle(rect);
        }


        #endregion


        #region filled rectangles

        /// <summary>
        /// Draws filled 2d rectangle with x1 and y1 coordinates of top left and width and height, using current color
        /// </summary>
        /// <param name="x1">left upper corner</param>
        /// <param name="y1">left upper corner</param>
        /// <param name="width">width</param>
        /// <param name="height">height</param>
        public abstract void DrawFilledRectangle(int x1, int y1, int width, int height);

        /// <summary>
        /// Draws filled 2d rectangle with x1 and y1 coordinates of top left and width and height
        /// </summary>
        /// <param name="x1">left upper corner</param>
        /// <param name="y1">left upper corner</param>
        /// <param name="width">width</param>
        /// <param name="height">height</param>
        /// <param name="color">Color of the outline</param>
        public void DrawFilledRectangle(int x1, int y1, int width, int height, ColorByte color)
        {
            SetColor(color);
            DrawFilledRectangle(x1, y1, width, height);
        }

        /// <summary>
        /// Draws filled 2d rectangle with x1 and y1 coordinates of top left and width and height
        /// </summary>
        /// <param name="x1">left upper corner</param>
        /// <param name="y1">left upper corner</param>
        /// <param name="width">width</param>
        /// <param name="height">height</param>
        /// <param name="color">Color of the outline</param>
        public void DrawFilledRectangle(int x1, int y1, int width, int height, System.Drawing.Color color)
        {
            SetColor(color);
            DrawFilledRectangle(x1, y1, width, height);
        }

        /// <summary>
        /// Draws filled 2d rectangle with current color
        /// </summary>
        /// <param name="rect">Rectangle</param>
        public void DrawFilledRectangle(System.Drawing.Rectangle rect)
        {
            DrawFilledRectangle(rect.Left, rect.Top, rect.Width, rect.Height);
        }


        /// <summary>
        /// Draws filled 2d rectangle
        /// </summary>
        /// <param name="Color">Color of the outline</param>
        /// <param name="rect">Rectangle</param>
        public void DrawFilledRectangle(System.Drawing.Rectangle rect, ColorByte Color)
        {
            SetColor(Color);
            DrawFilledRectangle(rect);
        }

        /// <summary>
        /// Draws filled 2d rectangle
        /// </summary>
        /// <param name="Color">Color of the outline</param>
        /// <param name="rect">Rectangle</param>
        public void DrawFilledRectangle(System.Drawing.Rectangle rect, System.Drawing.Color Color)
        {
            SetColor(Color);
            DrawFilledRectangle(rect);
        }


        #endregion


        #region Text rendering

        /// <summary>
        /// Changes current font of the context to specified font (from font manager)
        /// </summary>
        /// <param name="fontname">Name of the font in the font manager</param>
        public void ChangeFont(string fontname)
        {
            Render2D.Font Font = renderer.FontMan[fontname];
            if (Font != null)
                _CurrentFont = Font;
        }

        /// <summary>
        /// Changes current font of the context to the font
        /// </summary>
        /// <param name="font">Rendering font</param>
        public void ChangeFont(Render2D.Font font)
        {            
            if (font!= null)
                _CurrentFont = font;
        }

        /// <summary>
        /// Simple text drawing on selected coordinate. Uses currently selected font
        /// </summary>
        /// <param name="x">X coordinate</param>
        /// <param name="y">Y coordinate</param>
        /// <param name="text">text </param>
        public void DrawText(int x, int y, string text)
        {
            _CurrentFont.DrawText(this, x, y, text);
        }

        /// <summary>
        /// Simple text drawing on selected coordinate. Uses currently selected font
        /// </summary>
        /// <param name="x">X coordinate</param>
        /// <param name="y">Y coordinate</param>
        /// <param name="text">text </param>
        /// <param name="color">Color of the text</param>
        public void DrawText(int x, int y, string text, ColorByte color)
        {
            SetColor(color);
            _CurrentFont.DrawText(this, x, y, text);
        }

        /// <summary>
        /// Simple text drawing on selected coordinate. Uses currently selected font
        /// </summary>
        /// <param name="x">X coordinate</param>
        /// <param name="y">Y coordinate</param>
        /// <param name="text">text </param>
        /// <param name="color">Color of the text</param>
        public void DrawText(int x, int y, string text, System.Drawing.Color color)
        {
            SetColor(color);
            _CurrentFont.DrawText(this, x, y, text);
        }


        /// <summary>
        /// Draw text on selected coordinate with specified max size of the text block. Uses currently selected font
        /// </summary>
        /// <param name="x">X coordinate</param>
        /// <param name="y">Y coordinate</param>
        /// <param name="maxheight">Maximal height of the text block</param>
        /// <param name="maxwidth">Maximal width of the text block</param>
        /// <param name="text">text </param>
        public void DrawText(int x, int y, int maxwidth, int maxheight, string text)
        {
            _CurrentFont.DrawText(this, x, y, maxwidth, maxheight, text);
        }

        /// <summary>
        /// Draw text on selected coordinate with specified max size of the text block. Uses currently selected font
        /// </summary>
        /// <param name="x">X coordinate</param>
        /// <param name="y">Y coordinate</param>
        /// <param name="maxheight">Maximal height of the text block</param>
        /// <param name="maxwidth">Maximal width of the text block</param>
        /// <param name="text">text </param>
        /// <param name="color">Color of the text</param>
        public void DrawText(int x, int y, int maxwidth, int maxheight, string text, ColorByte color)
        {
            SetColor(color);
            _CurrentFont.DrawText(this, x, y, maxwidth, maxheight, text);
        }

        /// <summary>
        /// Draw text on selected coordinate with specified max size of the text block. Uses currently selected font
        /// </summary>
        /// <param name="x">X coordinate</param>
        /// <param name="y">Y coordinate</param>
        /// <param name="maxheight">Maximal height of the text block</param>
        /// <param name="maxwidth">Maximal width of the text block</param>
        /// <param name="text">text </param>
        /// <param name="color">Color of the text</param>
        public void DrawText(int x, int y, int maxwidth, int maxheight, string text, System.Drawing.Color color)
        {
            SetColor(color);
            _CurrentFont.DrawText(this, x, y, maxwidth, maxheight, text);
        }


        /// <summary>
        /// Draw text on selected coordinate with specified max size of the text block. Uses currently selected font
        /// </summary>
        /// <param name="rect">Rectangle to write text to</param>
        /// <param name="text">text </param>
        public void DrawText(System.Drawing.Rectangle rect, string text)
        {
            _CurrentFont.DrawText(this, rect.Left, rect.Top, rect.Width, rect.Height, text);
        }


        /// <summary>
        /// Draw text on selected coordinate with specified max size of the text block. Uses currently selected font
        /// </summary>
        /// <param name="rect">Rectangle to write text to</param>
        /// <param name="text">text </param>
        /// <param name="color">Color of the text</param>
        public void DrawText(System.Drawing.Rectangle rect, string text, ColorByte color)
        {
            SetColor(color);
            _CurrentFont.DrawText(this, rect.Left, rect.Top, rect.Width, rect.Height, text);
        }

        /// <summary>
        /// Draw text on selected coordinate with specified max size of the text block. Uses currently selected font
        /// </summary>
        /// <param name="rect">Rectangle to write text to</param>
        /// <param name="text">text </param>
        /// <param name="color">Color of the text</param>
        public void DrawText(System.Drawing.Rectangle rect, string text, System.Drawing.Color color)
        {
            SetColor(color);
            _CurrentFont.DrawText(this, rect.Left, rect.Top, rect.Width, rect.Height, text);
        }

        #endregion


        #region Images and sprites

        /// <summary>
        /// Draws currently selected texture in real size to specified place on screen.
        /// NOTE - uses current color, don't forget to set it to white unless you want colored image
        /// </summary>
        /// <param name="x">X coordinate of top left corner</param>
        /// <param name="y">Y coordinate of top left corner</param>
        public abstract void DrawImage(int x, int y);
        /// <summary>
        /// Draws selected texture in real size to specified place on screen.
        /// NOTE - uses current color, don't forget to set it to white unless you want colored image
        /// </summary>
        /// <param name="x">X coordinate of top left corner</param>
        /// <param name="y">Y coordinate of top left corner</param>        
        /// <param name="texture">Name of the texture in the texture manager</param>
        public void DrawImage(int x, int y, string texture)
        {
            renderer.TextureMan.SetTexture(texture, this);
            DrawImage(x, y);
        }
        /// <summary>
        /// Draws selected texture in real size to specified place on screen.
        /// NOTE - uses current color, don't forget to set it to white unless you want colored image
        /// </summary>
        /// <param name="x">X coordinate of top left corner</param>
        /// <param name="y">Y coordinate of top left corner</param>
        /// <param name="tex">Texture to be set</param>
        public void DrawImage(int x, int y, Texture tex)
        {
            tex.Activate(this);
            DrawImage(x, y);
        }

        /// <summary>
        /// Draws currently selected texture scaled to specified width and height
        /// </summary>
        /// <param name="x">X coordinate of top left corner</param>
        /// <param name="y">Y coordinate of top left corner</param>
        /// <param name="width">Width of the drawn image</param>
        /// <param name="height">Height of the drawn image</param>
        public abstract void DrawImage(int x, int y, int width, int height);
        /// <summary>
        /// Draws selected texture scaled to specified width and height
        /// </summary>
        /// <param name="x">X coordinate of top left corner</param>
        /// <param name="y">Y coordinate of top left corner</param>
        /// <param name="width">Width of the drawn image</param>
        /// <param name="height">Height of the drawn image</param>
        /// <param name="texture">Name of the texture in the texture manager</param>
        public void DrawImage(int x, int y, int width, int height, string texture)
        {
            renderer.TextureMan.SetTexture(texture, this);
            DrawImage(x, y, width, height);
        }
        /// <summary>
        /// Draws selected texture scaled to specified width and height
        /// </summary>
        /// <param name="x">X coordinate of top left corner</param>
        /// <param name="y">Y coordinate of top left corner</param>
        /// <param name="width">Width of the drawn image</param>
        /// <param name="height">Height of the drawn image</param>
        /// <param name="tex">Texture to be set</param>
        public void DrawImage(int x, int y, int width, int height, Texture tex)
        {
            tex.Activate(this);
            DrawImage(x, y, width, height);
        }


        /// <summary>
        /// Draws currently selected texture scaled to specified rectangle
        /// </summary>
        /// <param name="rect">Rectangle on screen</param>
        public void DrawImage(System.Drawing.Rectangle rect)
        {
            DrawImage(rect.Left, rect.Top, rect.Width, rect.Height);
        }

        /// <summary>
        /// Draws currently selected texture scaled to specified rectangle
        /// </summary>
        /// <param name="rect">Rectangle on screen</param>
        /// <param name="texture">Name of the texture in the texture manager</param>
        public void DrawImage(System.Drawing.Rectangle rect, string texture)
        {
            renderer.TextureMan.SetTexture(texture, this);
            DrawImage(rect.Left, rect.Top, rect.Width, rect.Height);
        }
        /// <summary>
        /// Draws currently selected texture scaled to specified rectangle
        /// </summary>
        /// <param name="rect">Rectangle on screen</param>
        /// <param name="tex">Texture to be set</param>
        public void DrawImage(System.Drawing.Rectangle rect, Texture tex)
        {
            tex.Activate(this);
            DrawImage(rect.Left, rect.Top, rect.Width, rect.Height);
        }

        /// <summary>
        /// Draws unscaled part of the currently selected texture on the screen.
        /// </summary>
        /// <param name="x">X coordinate of top left corner</param>
        /// <param name="y">Y coordinate of top left corner</param>
        /// <param name="sourcex">X coordinate of top left corner inside the texture</param>
        /// <param name="sourcey">Y coordinate of top left corner inside the texture</param>
        /// <param name="sourcewidth">Width of the texture part</param>
        /// <param name="sourceheight">Height of the texture part</param>
        public void DrawImagePart(int x, int y, int sourcex, int sourcey, int sourcewidth, int sourceheight)
        {
            DrawImagePart(x, y, sourcewidth, sourceheight, sourcex, sourcey, sourcewidth, sourceheight);
        }

        /// <summary>
        /// Draws unscaled part of the selected texture on the screen.
        /// </summary>
        /// <param name="x">X coordinate of top left corner</param>
        /// <param name="y">Y coordinate of top left corner</param>
        /// <param name="sourcex">X coordinate of top left corner inside the texture</param>
        /// <param name="sourcey">Y coordinate of top left corner inside the texture</param>
        /// <param name="sourcewidth">Width of the texture part</param>
        /// <param name="sourceheight">Height of the texture part</param>
        /// <param name="texture">Name of the texture in the texture manager</param>
        public void DrawImagePart(int x, int y, int sourcex, int sourcey, int sourcewidth, int sourceheight, string texture)
        {
            renderer.TextureMan.SetTexture(texture, this);
            DrawImagePart(x, y, sourcewidth, sourceheight, sourcex, sourcey, sourcewidth, sourceheight);
        }

        /// <summary>
        /// Draws unscaled part of the selected texture on the screen.
        /// </summary>
        /// <param name="x">X coordinate of top left corner</param>
        /// <param name="y">Y coordinate of top left corner</param>
        /// <param name="sourcex">X coordinate of top left corner inside the texture</param>
        /// <param name="sourcey">Y coordinate of top left corner inside the texture</param>
        /// <param name="sourcewidth">Width of the texture part</param>
        /// <param name="sourceheight">Height of the texture part</param>
        /// <param name="tex">Texture to be set</param>
        public void DrawImagePart(int x, int y, int sourcex, int sourcey, int sourcewidth, int sourceheight, Texture tex)
        {
            tex.Activate(this);
            DrawImagePart(x, y, sourcewidth, sourceheight, sourcex, sourcey, sourcewidth, sourceheight);
        }


        /// <summary>
        /// Draws unscaled part of the currently selected texture on the screen.
        /// </summary>
        /// <param name="x">X coordinate of top left corner</param>
        /// <param name="y">Y coordinate of top left corner</param>
        /// <param name="source">Source rectangle in the texture</param>
        public void DrawImagePart(int x, int y, System.Drawing.Rectangle source)
        {
            DrawImagePart(x, y, source.Width, source.Height, source.Left, source.Top, source.Width, source.Height);
        }

        /// <summary>
        /// Draws unscaled part of the selected texture on the screen.
        /// </summary>
        /// <param name="x">X coordinate of top left corner</param>
        /// <param name="y">Y coordinate of top left corner</param>
        /// <param name="source">Source rectangle in the texture</param>
        /// <param name="texture">Name of the texture in the texture manager</param>
        public void DrawImagePart(int x, int y, System.Drawing.Rectangle source, string texture)
        {
            renderer.TextureMan.SetTexture(texture, this);
            DrawImagePart(x, y, source.Width, source.Height, source.Left, source.Top, source.Width, source.Height);
        }

        /// <summary>
        /// Draws unscaled part of the selected texture on the screen.
        /// </summary>
        /// <param name="x">X coordinate of top left corner</param>
        /// <param name="y">Y coordinate of top left corner</param>
        /// <param name="source">Source rectangle in the texture</param>
        /// <param name="tex">Texture to be set</param>
        public void DrawImagePart(int x, int y, System.Drawing.Rectangle source, Texture tex)
        {
            tex.Activate(this);
            DrawImagePart(x, y, source.Width, source.Height, source.Left, source.Top, source.Width, source.Height);
        }

        /// <summary>
        /// Draws scaled part of the currently selected texture on the screen.
        /// </summary>
        /// <param name="x">X coordinate of top left corner</param>
        /// <param name="y">Y coordinate of top left corner</param>
        /// <param name="width">Width of the drawn image</param>
        /// <param name="height">Height of the drawn image</param>
        /// <param name="sourcex">X coordinate of top left corner inside the texture</param>
        /// <param name="sourcey">Y coordinate of top left corner inside the texture</param>
        /// <param name="sourcewidth">Width of the texture part</param>
        /// <param name="sourceheight">Height of the texture part</param>
        public abstract void DrawImagePart(int x, int y, int width, int height, int sourcex, int sourcey, int sourcewidth, int sourceheight);

        /// <summary>
        /// Draws scaled part of the selected texture on the screen.
        /// </summary>
        /// <param name="x">X coordinate of top left corner</param>
        /// <param name="y">Y coordinate of top left corner</param>
        /// <param name="width">Width of the drawn image</param>
        /// <param name="height">Height of the drawn image</param>
        /// <param name="sourcex">X coordinate of top left corner inside the texture</param>
        /// <param name="sourcey">Y coordinate of top left corner inside the texture</param>
        /// <param name="sourcewidth">Width of the texture part</param>
        /// <param name="sourceheight">Height of the texture part</param>
        /// <param name="texture">Name of the texture in the texture manager</param>
        public void DrawImagePart(int x, int y, int width, int height, int sourcex, int sourcey, int sourcewidth, int sourceheight, string texture)
        {
            renderer.TextureMan.SetTexture(texture, this);
            DrawImagePart(x, y, width, height, sourcex, sourcey, sourcewidth, sourceheight);
        }

        /// <summary>
        /// Draws scaled part of the selected texture on the screen.
        /// </summary>
        /// <param name="x">X coordinate of top left corner</param>
        /// <param name="y">Y coordinate of top left corner</param>
        /// <param name="width">Width of the drawn image</param>
        /// <param name="height">Height of the drawn image</param>
        /// <param name="sourcex">X coordinate of top left corner inside the texture</param>
        /// <param name="sourcey">Y coordinate of top left corner inside the texture</param>
        /// <param name="sourcewidth">Width of the texture part</param>
        /// <param name="sourceheight">Height of the texture part</param>
        /// <param name="tex">Texture to be set</param>
        public void DrawImagePart(int x, int y, int width, int height, int sourcex, int sourcey, int sourcewidth, int sourceheight, Texture tex)
        {
            tex.Activate(this);
            DrawImagePart(x, y, width, height, sourcex, sourcey, sourcewidth, sourceheight);
        }


        /// <summary>
        /// Draws scaled part of the currently selected texture on the screen.
        /// </summary>
        /// <param name="target">Target rectangle on the screen</param>
        /// <param name="source">Source rectangle in the texture</param>
        public void DrawImagePart(System.Drawing.Rectangle target, System.Drawing.Rectangle source)
        {
            DrawImagePart(target.Left, target.Top, target.Width, target.Height, source.Left, source.Top, source.Width, source.Height);
        }

        /// <summary>
        /// Draws scaled part of the selected texture on the screen.
        /// </summary>
        /// <param name="target">Target rectangle on the screen</param>
        /// <param name="source">Source rectangle in the texture</param>
        /// <param name="texture">Name of the texture in the texture manager</param>
        public void DrawImagePart(System.Drawing.Rectangle target, System.Drawing.Rectangle source, string texture)
        {
            renderer.TextureMan.SetTexture(texture, this);
            DrawImagePart(target.Left, target.Top, target.Width, target.Height, source.Left, source.Top, source.Width, source.Height);
        }

        /// <summary>
        /// Draws scaled part of the selected texture on the screen.
        /// </summary>
        /// <param name="target">Target rectangle on the screen</param>
        /// <param name="source">Source rectangle in the texture</param>
        /// <param name="tex">Texture to be set</param>
        public void DrawImagePart(System.Drawing.Rectangle target, System.Drawing.Rectangle source, Texture tex)
        {
            tex.Activate(this);
            DrawImagePart(target.Left, target.Top, target.Width, target.Height, source.Left, source.Top, source.Width, source.Height);
        }



        /// <summary>
        /// Draws sprite with currently selected texture
        /// </summary>
        /// <param name="x">X position (screen coords) for the sprite</param>
        /// <param name="y">Y position (screen coords) for the sprite</param>
        /// <param name="sprite">Sprite information</param>
        public abstract void DrawSprite(int x, int y, ref Render2D.SpriteInfo sprite);

        /// <summary>
        /// Draws sprite with currently selected texture
        /// </summary>
        /// <param name="x">X position (screen coords) for the sprite</param>
        /// <param name="y">Y position (screen coords) for the sprite</param>
        /// <param name="sprite">Sprite information</param>
        public void DrawSprite(int x, int y, Render2D.SpriteInfo sprite)
        {
            DrawSprite(x, y, ref sprite);
        }

        /// <summary>
        /// Draws sprite with currently selected texture
        /// </summary>
        /// <param name="x">X position (screen coords) for the sprite</param>
        /// <param name="y">Y position (screen coords) for the sprite</param>
        /// <param name="texture">Texture name</param>
        /// <param name="sprite">Sprite information</param>
        public void DrawSprite(int x, int y, Render2D.SpriteInfo sprite, string texture)
        {
            renderer.TextureMan.SetTexture(texture, this);
            DrawSprite(x, y, sprite);
        }
        /// <summary>
        /// Draws sprite with currently selected texture
        /// </summary>
        /// <param name="x">X position (screen coords) for the sprite</param>
        /// <param name="y">Y position (screen coords) for the sprite</param>
        /// <param name="tex">Texture to be set</param>
        /// <param name="sprite">Sprite information</param>
        public void DrawSprite(int x, int y, Render2D.SpriteInfo sprite, Texture tex)
        {
            tex.Activate(this);
            DrawSprite(x, y, sprite);
        }
        /// <summary>
        /// Draws array of sprites with currently selected texture
        /// </summary>
        /// <param name="x">X position (screen coords) for the sprite</param>
        /// <param name="y">Y position (screen coords) for the sprite</param>
        /// <param name="sprites">Sprite information</param>
        public abstract void DrawSprites(int x, int y, Render2D.SpriteInfo[] sprites);

        /// <summary>
        /// Draws array of sprites with currently selected texture
        /// </summary>
        /// <param name="x">X position (screen coords) for the sprite</param>
        /// <param name="y">Y position (screen coords) for the sprite</param>
        /// <param name="sprites">Sprite information</param>
        /// <param name="texture">Texture name</param>
        public void DrawSprites(int x, int y, Render2D.SpriteInfo[] sprites, string texture)
        {
            renderer.TextureMan.SetTexture(texture, this);
            DrawSprites(x, y, sprites);
        }
        /// <summary>
        /// Draws array of sprites with currently selected texture
        /// </summary>
        /// <param name="x">X position (screen coords) for the sprite</param>
        /// <param name="y">Y position (screen coords) for the sprite</param>
        /// <param name="tex">Texture to be set</param>
        /// <param name="sprites">Sprite information</param>
        public void DrawSprites(int x, int y, Render2D.SpriteInfo[] sprites, Texture tex)
        {
            tex.Activate(this);
            DrawSprites(x, y, sprites);
        }

        /// <summary>
        /// Draws batch of sprites
        /// </summary>
        /// <param name="x">X position (screen coords) for the sprite</param>
        /// <param name="y">Y position (screen coords) for the sprite</param>
        /// <param name="sprites">SpriteBatch (should contain valid texture!)</param>
        public void DrawSprites(int x, int y, Render2D.SpriteBatch sprites)
        {
            DrawSprites(x, y, ref sprites);
        }
        
        /// <summary>
        /// Draws batch of sprites
        /// </summary>
        /// <param name="x">X position (screen coords) for the sprite</param>
        /// <param name="y">Y position (screen coords) for the sprite</param>
        /// <param name="sprites">SpriteBatch (should contain valid texture!)</param>
        public void DrawSprites(int x, int y, ref Render2D.SpriteBatch sprites)
        {
            sprites.Texture.Activate(this);
            Draw2DArray(x, y, sprites.Vertices);
        }

        /// <summary>
        /// Draws array of 2D vertices
        /// </summary>
        /// <param name="x">X position (screen coords) for the sprite</param>
        /// <param name="y">Y position (screen coords) for the sprite</param>
        /// <param name="vertices"></param>
        public abstract void Draw2DArray(int x, int y, Render2D.Vertex2D[] vertices);


        #endregion





        #endregion


        #endregion

        #endregion
    }
}
