public void DrawLineBresenham(int x0, int y0, int x1, int y1, double3 color, Func <double3, double3, double3> blendFunc = null)
 {
     if (Math3.ClampLine(ref x0, ref y0, ref x1, ref y1, Size.width, Size.height))
     {
         DrawLineBresenhamClamped(x0, y0, x1, y1, color, blendFunc);
     }
 }
        public void RenderRays(double3 xAxis, double3 yAxis, double3 topLeft, double3 bottomLeft)
        {
            int     numRays = NumRaysToDraw.HasValue ? NumRaysToDraw.Value : ViewportSize.height;
            int     maxRays = Math.Max(numRays, ViewportSize.height);
            double3 startP, step;

            if (Orientation == SectionOrientation.Horizontal)
            {
                double    hFovX     = (AlwaysTakeVerticalFov ? Camera.FovY : Camera.FovX) / 2;
                double4x4 rotY      = double4x4.RotY(hFovX);
                double4x4 rotMinusY = double4x4.RotY(-hFovX);
                double3   left      = Camera.ViewInvMatrix.Transform(rotMinusY.Transform(double3.UnitZ));
                double3   right     = Camera.ViewInvMatrix.Transform(rotY.Transform(double3.UnitZ));
                step   = (right - left) * (1.0 / maxRays);
                startP = left + step * 0.5;
            }
            else
            {
                double    hFovY     = Camera.FovY / 2;
                double4x4 rotX      = double4x4.RotX(hFovY);
                double4x4 rotMinusX = double4x4.RotX(-hFovY);
                double3   top       = Camera.ViewInvMatrix.Transform(rotMinusX.Transform(double3.UnitZ));
                double3   bottom    = Camera.ViewInvMatrix.Transform(rotX.Transform(double3.UnitZ));
                step   = (bottom - top) * (1.0 / maxRays);
                startP = top + step * 0.5;
            }

            Scene.TraceCallback = tr => {
                double  sx  = ViewportSize.width / SectionSize.width;
                double  sy  = ViewportSize.height / SectionSize.height;
                double3 pV0 = tr.Ray.p - topLeft;
                double3 pV1 = tr.NearestIntersect.P - topLeft;
                int     x0  = ( int )Math.Round(sx * (pV0 & xAxis));
                int     y0  = ( int )Math.Round(sy * (pV0 & yAxis));
                int     x1  = ( int )Math.Round(sx * (pV1 & xAxis));
                int     y1  = ( int )Math.Round(sy * (pV1 & yAxis));

                if (Math3.ClampLine(ref x0, ref y0, ref x1, ref y1, ViewportSize.width, ViewportSize.height))
                {
                    image.DrawLineBresenhamClamped(x0, y0, x1, y1, tr.Color);
                    //image.Values [x0, y0] = 1 - tr.Color;
                    image.Values [x1, y1] = new double3(1, 1, 0);
                }
            };

            if (numRays == 1)
            {
                double3 p = startP + step * maxRays * 0.5;
                Ray     r = new Ray(Camera.Pos, p.Normalized);
                Scene.Trace(r, new TraceData(InitTraceData));
            }
            else
            {
                ParallelOptions parallelOpts = new ParallelOptions();
                parallelOpts.MaxDegreeOfParallelism = MaxDegreeOfParallelism.HasValue ? MaxDegreeOfParallelism.Value : Environment.ProcessorCount;
                double xInc = ( double )maxRays / (numRays - 1);

                Parallel.For(0, numRays, parallelOpts, x => {
                    double3 p = startP + step * x * xInc;
                    Ray r     = new Ray(Camera.Pos, p.Normalized);
                    Scene.Trace(r, new TraceData(InitTraceData));
                });
            }
        }