/// <summary>
        /// Renders a single rectangular chunk of the scene
        /// </summary>
        /// <param name="worldRef">Reference to the world</param>
        /// <param name="xCoord1">Smallest x coordinate</param>
        /// <param name="xCoord2">Largest x coordinate</param>
        /// <param name="yCoord1">Smallest y coordinate</param>
        /// <param name="yCoord2">Largest y coordinate</param>
        /// <param name="threadNum">Thread number</param>
        public override void RenderSceneFragment(World worldRef, int xCoord1, int xCoord2, int yCoord1, int yCoord2, int threadNum)
        {
            RGBColor L = new RGBColor();
            Ray ray = new Ray();
            ViewPlane vp = worldRef.CurrentViewPlane;
            int depth = 0;

            Point2D samplePoint = new Point2D();
            Point2D samplePointPixelSpace = new Point2D();
            Point2D samplePointOnDisk = new Point2D();
            Point2D samplePointOnLens = new Point2D();

            Sampler screenSamplerClone = GlobalVars.VIEWPLANE_SAMPLER.Clone();
            Sampler lensSamplerClone = depthSampler.Clone();

            //vp.s /= zoom;
            //Vector2 tmp2 = new Vector2(vp.hres * 0.5f, vp.vres*0.5f);
            for (int r = yCoord1; r < yCoord2; r++)
            {
                for (int c = xCoord1; c < xCoord2; c++)
                {
                    L = GlobalVars.COLOR_BLACK;

                    for (int n = 0; n < vp.NumSamples; n++)
                    {
                        //Sample on unit square
                        samplePoint = screenSamplerClone.SampleUnitSquare();
                        //Sample in screenspace
                        //Vector2 tmp1 = new Vector2(c, r);
                        //pp.coords = vp.s * (tmp1 - tmp2 * sp.coords);
                        samplePointPixelSpace.coords.X = vp.PixelSize * (c - vp.HorizontalResolution * 0.5f + samplePoint.coords.X);
                        samplePointPixelSpace.coords.Y = vp.PixelSize * (r - vp.VerticalResolution * 0.5f + samplePoint.coords.Y);

                        samplePointOnDisk = lensSamplerClone.SampleDisk();
                        samplePointOnLens.coords.X = samplePointOnDisk.coords.X * radius;
                        samplePointOnLens.coords.Y = samplePointOnDisk.coords.Y * radius;
                        //lp.coords = dp.coords * radius;

                        ray.Origin = _eye + samplePointOnLens.coords.X * u + samplePointOnLens.coords.Y * v;
                        ray.Direction = GetRayDirection(samplePointPixelSpace, samplePointOnLens);
                        L += worldRef.CurrentTracer.TraceRay(ray, depth);
                    }
                    L /= vp.NumSamples;
                    L *= _exposureTime;
                    worldRef.DisplayPixel(r, c, L);
                }
            }

            DequeueNextRenderFragment();
        }
        /// <summary>
        /// Renders the world on a single thread [deprecated, use RenderSceneMultiThreaded]
        /// </summary>
        /// <param name="world">World reference</param>
        public override void RenderScene(World worldRef)
        {
            RGBColor lightingSum;
            ViewPlane vp = worldRef.CurrentViewPlane;
            Ray ray = new Ray(_eye,new Vect3D(0,0,0));
            int depth = 0; //Depth of recursion
            Point2D sp = new Point2D(); //Sample point on a unit square
            Point2D pp = new Point2D(); ; //Sample point translated into screen space

            worldRef.OpenWindow(vp.HorizontalResolution, vp.VerticalResolution);
            vp.PixelSize /= _zoom;

            for(int row = 0; row < vp.VerticalResolution; row++)
            {
                for(int column = 0; column < vp.HorizontalResolution; column++)
                {
                    lightingSum = GlobalVars.COLOR_BLACK; //Start with no color, everything is additive

                    for(int sample = 0; sample < vp.NumSamples; sample ++)
                    {
                        sp = worldRef.CurrentViewPlane.ViewPlaneSampler.SampleUnitSquare();
                        pp.coords.X = worldRef.CurrentViewPlane.PixelSize * (column - 0.5f * vp.HorizontalResolution + sp.coords.X);
                        pp.coords.Y = worldRef.CurrentViewPlane.PixelSize * (row - 0.5f * vp.VerticalResolution + sp.coords.Y);
                        ray.Direction = GetRayDirection(pp);
                        lightingSum = lightingSum + worldRef.CurrentTracer.TraceRay(ray, depth);
                    }

                    lightingSum /= vp.NumSamples;
                    lightingSum *= _exposureTime;
                    worldRef.DisplayPixel(row, column, lightingSum);

                    //Poll events in live render view
                    worldRef.PollEvents();
                }
            }
        }
        public override void RenderScene(World w)
        {
            RGBColor L = new RGBColor();
            Ray ray = new Ray();
            ViewPlane vp = w.CurrentViewPlane;
            int depth = 0;

            Point2D sp = new Point2D();
            Point2D pp = new Point2D();
            Point2D dp = new Point2D();
            Point2D lp = new Point2D();

            //w.open_window(vp.hres, vp.vres);
            vp.PixelSize /= _zoom;

            for(int r = 0; r < vp.VerticalResolution-1; r++)
            {
                for(int c = 0; c < vp.HorizontalResolution-1; c++)
                {
                    L = GlobalVars.COLOR_BLACK;

                    for(int n = 0; n < vp.NumSamples; n++)
                    {
                        //Sample on unit square
                        sp = vp.ViewPlaneSampler.SampleUnitSquare();
                        //Sample in screenspace
                        pp.coords.X = vp.PixelSize * (c - vp.HorizontalResolution * 0.5f + sp.coords.X);
                        pp.coords.Y = vp.PixelSize * (r - vp.VerticalResolution * 0.5f + sp.coords.Y);

                        dp = depthSampler.SampleDisk();
                        lp.coords.X = dp.coords.X * radius;
                        lp.coords.Y = dp.coords.Y * radius;

                        ray.Origin = _eye + lp.coords.X * u + lp.coords.Y * v;
                        ray.Direction = GetRayDirection(pp, lp);
                        L += w.CurrentTracer.TraceRay(ray, depth);
                    }
                    L /= vp.NumSamples;
                    L *= _exposureTime;
                    w.DisplayPixel(r, c, L);
                    w.PollEvents();
                }
            }
        }
        /// <summary>
        /// Renders a single rectangular chunk of the scene
        /// </summary>
        /// <param name="worldRef">Reference to the world</param>
        /// <param name="xCoord1">Smallest x coordinate</param>
        /// <param name="xCoord2">Largest x coordinate</param>
        /// <param name="yCoord1">Smallest y coordinate</param>
        /// <param name="yCoord2">Largest y coordinate</param>
        /// <param name="threadNum">Thread number</param>
        public override void RenderSceneFragment(World worldRef, int xCoord1, int xCoord2, int yCoord1, int yCoord2, int threadNum)
        {
            //To avoid clashes with other threads accessing sampler, clone the main world sampler
            Sampler localSampler = worldRef.CurrentViewPlane.ViewPlaneSampler.Clone();

            RGBColor L;
            ViewPlane vp = worldRef.CurrentViewPlane;
            Ray ray = new Ray(_eye, new Vect3D(0, 0, 0));
            int depth = 0; //Depth of recursion
            Point2D unitSquareSample = new Point2D(); //Sample point on a unit square
            Point2D sampleInScreenSpace = new Point2D(); ; //Sample point translated into screen space
            int height = yCoord2 - yCoord1;
            int width = xCoord2 - xCoord1;

            for (int row = 0; row < height; row++)
            {
                for (int column = 0; column < width; column++)
                {
                    L = GlobalVars.COLOR_BLACK; //Start with no color, everything is additive

                    for (int sample = 0; sample < vp.NumSamples; sample++)
                    {
                        unitSquareSample = localSampler.SampleUnitSquare();
                        sampleInScreenSpace.coords.X = worldRef.CurrentViewPlane.PixelSize * (column + xCoord1 - 0.5f * vp.HorizontalResolution + unitSquareSample.coords.X);
                        sampleInScreenSpace.coords.Y = worldRef.CurrentViewPlane.PixelSize * (row + yCoord1 - 0.5f * vp.VerticalResolution + unitSquareSample.coords.Y);
                        ray.Direction = GetRayDirection(sampleInScreenSpace);
                        L = L + worldRef.CurrentTracer.TraceRay(ray, depth);
                    }

                    L /= vp.NumSamples;
                    L *= _exposureTime;

                    worldRef.DisplayPixel(row + yCoord1, column + xCoord1, L);
                }
            }

            DequeueNextRenderFragment();
        }