public void render(EIn objIn)
        {

            //screen rotation()
            //screen translation()

            float[] tmp_colour0 = { 0, 0, 0 };
            Sphere sph_tmp = new Sphere(0, 0, 0, -1, tmp_colour0);
            Plane plane_tmp = new Plane(0, 0, 0, -1, tmp_colour0);
            Sphere sph_tmp2 = new Sphere(0, 0, 0, -1, tmp_colour0);
            Plane plane_tmp2 = new Plane(0, 0, 0, -1, tmp_colour0);

            int startx = objIn.start % 2001;
            int starty = objIn.start / 2001;
            int endx = objIn.end % 2001;
            int endy = objIn.end / 2001;

            //camera translation()
            for (int y_dir = starty - 1000; y_dir <= endy - 1000; y_dir++)
            {
                int row_start, row_end;

                if (y_dir == starty)
                    row_start = startx;
                else
                    row_start = 0;

                if (y_dir == endy)
                    row_end = endx;
                else
                    row_end = 2000;


                for (int x_dir = row_start - 1000; x_dir <= row_end - 1000; x_dir++)
                {
                    float intensity = 1;
                    float reflectionValue = 1;

                    bool temp_pixel_val = true;
                    int reflectDepth = 0;
                    float lightingMultiplier;
                    double[] reflectedRay = { 0, 0, 0 };

                    //ambient Lighting
                    float[] pixelColour = { 0, 0, 0 };

                    double[] t_in = { 0, 0, 0, 0, 0, 0, 0 };

                    double[] t_in_tmp = { 0, 0, 0, 0, 0, 0, 0 };

                    foreach (Sphere sph in scene.spheres)
                    {
                        t_in_tmp = sphereIntersect(x_dir, y_dir, sph);
                        if (t_in_tmp[3] != 0 && ((t_in_tmp[3] < t_in[3]) || t_in[3] == 0))
                        {
                            Array.Copy(t_in_tmp, t_in, 7);

                            sph_tmp = (Sphere)sph.clone();
                            //1st is not plane
                            plane_tmp.dist = -1;
                        }
                    }
                    foreach (Plane plane in scene.planes)
                    {
                        t_in_tmp = planeIntersect(x_dir, y_dir, plane);
                        if (t_in_tmp[3] != 0 && ((t_in_tmp[3] < t_in[3]) || t_in[3] == 0))
                        {
                            Array.Copy(t_in_tmp, t_in, 7);

                            plane_tmp = (Plane)plane.clone();
                            //1st is not sphere
                            sph_tmp.radius = -1;
                        }
                    }

                    if (t_in[3] != 0)
                    {
                        intensity = (float)Math.Pow(0.9995, t_in[3] + 1);
                        foreach (Sphere sph in scene.spheres)
                        {
                            temp_pixel_val &= ShadowRaySph(t_in, sph);

                        }
                        foreach (Plane plane in scene.planes)
                        {
                            temp_pixel_val &= ShadowRayPlane(t_in, plane);
                        }
                        //no obstruction between first intersection and light source
                        if (temp_pixel_val)
                        {
                            //if the first object intersected is a sphere
                            if (sph_tmp.radius != -1)
                            {

                                lightingMultiplier = scene.light.intensity * intensity;
                                pixelColour[0] += lightingMultiplier * sph_tmp.colour[0];
                                pixelColour[1] += lightingMultiplier * sph_tmp.colour[1];
                                pixelColour[2] += lightingMultiplier * sph_tmp.colour[2];
                            }
                            //if the first object intersected is a plane
                            else if (plane_tmp.dist != -1)
                            {
                                lightingMultiplier = scene.light.intensity * intensity;
                                pixelColour[0] += lightingMultiplier * plane_tmp.colour[0];
                                pixelColour[1] += lightingMultiplier * plane_tmp.colour[1];
                                pixelColour[2] += lightingMultiplier * plane_tmp.colour[2];
                            }

                        }
                        //obstruction between first intersection and light source
                        else
                        {
                            if (sph_tmp.radius != -1)
                            {
                                lightingMultiplier = scene.light.intensity * 0.65f * intensity;
                                pixelColour[0] += lightingMultiplier * sph_tmp.colour[0];
                                pixelColour[1] += lightingMultiplier * sph_tmp.colour[1];
                                pixelColour[2] += lightingMultiplier * sph_tmp.colour[2];
                            }
                            else if (plane_tmp.dist != -1)
                            {
                                lightingMultiplier = scene.light.intensity * 0.65f * intensity;
                                pixelColour[0] += lightingMultiplier * plane_tmp.colour[0];
                                pixelColour[1] += lightingMultiplier * plane_tmp.colour[1];
                                pixelColour[2] += lightingMultiplier * plane_tmp.colour[2];
                            }
                        }
                        temp_pixel_val = true;
                    }

                    while (reflectDepth < 3)
                    {
                        double[] t_in_new = { 0, 0, 0, 0, 0, 0, 0 };

                        if (sph_tmp.radius != -1)
                            reflectedRay = FindReflectedRaySph(t_in, sph_tmp);
                        else if (plane_tmp.dist != -1)
                            reflectedRay = FindReflectedRayPlane(t_in, plane_tmp);


                        foreach (Sphere sph in scene.spheres)
                        {

                            t_in_tmp = reflectionRecursiveSph(t_in, sph, reflectedRay);


                            if (t_in_tmp[3] != 0 && (t_in_tmp[3] < t_in_new[3] || t_in_new[3] == 0))
                            {
                                Array.Copy(t_in_tmp, t_in_new, 7);

                                sph_tmp2 = (Sphere)sph.clone();

                                plane_tmp2.dist = -1;
                            }
                        }
                        foreach (Plane plane in scene.planes)
                        {
                            t_in_tmp = reflectionRecursivePlane(t_in, plane, reflectedRay);

                            if (t_in_tmp[3] != 0 && (t_in_tmp[3] < t_in_new[3] || t_in_new[3] == 0))
                            {
                                Array.Copy(t_in_tmp, t_in_new, 7);

                                plane_tmp2 = (Plane)plane.clone();

                                sph_tmp2.radius = -1;
                            }
                        }

                        Array.Copy(t_in_new, t_in, 7);

                        for (int i = 0; i < 7; i++)
                            t_in_new[i] = 0;

                        plane_tmp = (Plane)plane_tmp2.clone();
                        sph_tmp = (Sphere)sph_tmp2.clone();

                        plane_tmp2.dist = -1;
                        sph_tmp2.radius = -1;


                        if (!isNearZero(t_in[3]))
                        {
                            intensity = intensity * (float)Math.Pow(0.9995, t_in[3] + 1);
                            foreach (Sphere sph in scene.spheres)
                            {
                                temp_pixel_val &= ShadowRaySph(t_in, sph);
                            }
                            foreach (Plane plane in scene.planes)
                            {
                                temp_pixel_val &= ShadowRayPlane(t_in, plane);
                            }
                            if (temp_pixel_val)
                            {
                                if (sph_tmp.radius != -1)
                                {
                                    reflectionValue = reflectionValue * sph_tmp.attributes[0];
                                    lightingMultiplier = scene.light.intensity * reflectionValue * intensity;
                                    pixelColour[0] += lightingMultiplier * sph_tmp.colour[0];
                                    pixelColour[1] += lightingMultiplier * sph_tmp.colour[1];
                                    pixelColour[2] += lightingMultiplier * sph_tmp.colour[2];
                                }
                                else if (plane_tmp.dist != -1)
                                {
                                    reflectionValue = reflectionValue * plane_tmp.attributes[0];
                                    lightingMultiplier = scene.light.intensity * reflectionValue * intensity;
                                    pixelColour[0] += lightingMultiplier * plane_tmp.colour[0];
                                    pixelColour[1] += lightingMultiplier * plane_tmp.colour[1];
                                    pixelColour[2] += lightingMultiplier * plane_tmp.colour[2];
                                }
                            }
                            else
                            {
                                if (sph_tmp.radius != -1)
                                {
                                    reflectionValue = reflectionValue * sph_tmp.attributes[0];
                                    lightingMultiplier = scene.light.intensity * reflectionValue * 0.65f * intensity;
                                    pixelColour[0] += lightingMultiplier * sph_tmp.colour[0];
                                    pixelColour[1] += lightingMultiplier * sph_tmp.colour[1];
                                    pixelColour[2] += lightingMultiplier * sph_tmp.colour[2];
                                }
                                else if (plane_tmp.dist != -1)
                                {
                                    reflectionValue = reflectionValue * plane_tmp.attributes[0];
                                    lightingMultiplier = scene.light.intensity * reflectionValue * 0.65f * intensity;
                                    pixelColour[0] += lightingMultiplier * plane_tmp.colour[0];
                                    pixelColour[1] += lightingMultiplier * plane_tmp.colour[1];
                                    pixelColour[2] += lightingMultiplier * plane_tmp.colour[2];
                                }

                            }
                            temp_pixel_val = true;

                            reflectDepth++;
                        }
                        else
                            reflectDepth = 99;
                    }

                    //inversion from crossing plane
                    //pixelb[x_dir + 1000, -y_dir + 1000, 0] = Convert.ToByte(pixelColour[2]);
                    //pixelb[x_dir + 1000, -y_dir + 1000, 1] = Convert.ToByte(pixelColour[1]);
                    //pixelb[x_dir + 1000, -y_dir + 1000, 2] = Convert.ToByte(pixelColour[0]);
                    pixelb[-y_dir + 1000, x_dir + 1000 , 0] = Convert.ToByte(pixelColour[2]);
                    pixelb[-y_dir + 1000, x_dir + 1000, 1] = Convert.ToByte(pixelColour[1]);
                    pixelb[-y_dir + 1000, x_dir + 1000, 2] = Convert.ToByte(pixelColour[0]);
                }
            }
        }
        //direct ray from intersect to light source
        //gives intensity if clear
        //else give 0,0,0
        private bool ShadowRaySph(double[] t_in, Sphere s_in)
        {
            double[] ray_dir = new double[3];
            ray_dir[0] = -t_in[0] + scene.light.pos[0]; //temp
            ray_dir[1] = -t_in[1] + scene.light.pos[1]; //temp
            ray_dir[2] = -t_in[2] + scene.light.pos[2]; //temp

            float[] ret = { 0, 0, 0 };

            double a = ray_dir[0] * ray_dir[0] + ray_dir[1] * ray_dir[1] + ray_dir[2] * ray_dir[2];
            //double b = -2 * (ray_dir[0] * (s_in.pos[0]) + ray_dir[1] * (s_in.pos[1]) + ray_dir[2] * (s_in.pos[2] ));//check sign

            double b = -2 * (ray_dir[0] * (s_in.pos[0] - t_in[0]) + ray_dir[1] * (s_in.pos[1] - t_in[1]) + ray_dir[2] * (s_in.pos[2] - t_in[2]));//check sign
            double c = (s_in.pos[0] - t_in[0]) * (s_in.pos[0] - t_in[0]) + (s_in.pos[1] - t_in[1]) * (s_in.pos[1] - t_in[1]) + (s_in.pos[2] - t_in[2]) * (s_in.pos[2] - t_in[2]) - s_in.radius * s_in.radius;

            double d = b * b - 4 * a * c;

            if (d < 0)
                return true;

            double t1 = (-b - Math.Sqrt(d)) / (2 * a);
            double t2 = (-b + Math.Sqrt(d)) / (2 * a);

            if (t1 < -0.00001 || t2 < -0.00001)// take into account NaN
            {
                return true;
                //ret[0] = scene.light.intensity * s_in.attributes[0];
                //ret[1] = scene.light.intensity * s_in.attributes[0];
                //ret[2] = scene.light.intensity * s_in.attributes[0];
            }

            return false;
        }
        private double[] FindReflectedRaySph(double[] sur_in, Sphere sph_in)
        {
            double[] ret = new double[3];

            double[] normal = new double[3];

            normal[0] = sur_in[0] - sph_in.pos[0];
            normal[1] = sur_in[1] - sph_in.pos[1];
            normal[2] = sur_in[2] - sph_in.pos[2];

            double normal_unit_multiplier = 1 / Math.Sqrt(normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]);

            //unit normal
            normal[0] = normal_unit_multiplier * normal[0];
            normal[1] = normal_unit_multiplier * normal[1];
            normal[2] = normal_unit_multiplier * normal[2];


            double n_dot_d = normal[0] * sur_in[4] + normal[1] * sur_in[5] + normal[2] * sur_in[6];
            ret[0] = sur_in[4] - 2 * n_dot_d * normal[0];
            ret[1] = sur_in[5] - 2 * n_dot_d * normal[1];
            ret[2] = sur_in[6] - 2 * n_dot_d * normal[2];

            double ret_unit_multiplier = 1 / Math.Sqrt(ret[0] * ret[0] + ret[1] * ret[1] + ret[2] * ret[2]);
            ret[0] = ret[0] * ret_unit_multiplier;
            ret[1] = ret[1] * ret_unit_multiplier;
            ret[2] = ret[2] * ret_unit_multiplier;


            return ret;
        }
        private double[] reflectionRecursiveSph(double[] t_in, Sphere s_in, double[] ray_dir)
        {

            double[] ret = { 0, 0, 0, 0, ray_dir[0], ray_dir[1], ray_dir[2] };

            double a = ray_dir[0] * ray_dir[0] + ray_dir[1] * ray_dir[1] + ray_dir[2] * ray_dir[2];
            double b = -2 * (ray_dir[0] * (s_in.pos[0] - t_in[0]) + ray_dir[1] * (s_in.pos[1] - t_in[1]) + ray_dir[2] * (s_in.pos[2] - t_in[2]));//check sign
            double c = (s_in.pos[0] - t_in[0]) * (s_in.pos[0] - t_in[0]) + (s_in.pos[1] - t_in[1]) * (s_in.pos[1] - t_in[1]) + (s_in.pos[2] - t_in[2]) * (s_in.pos[2] - t_in[2]) - s_in.radius * s_in.radius;

            double d = b * b - 4 * a * c;
            if (d < 0)
                return ret;

            double t1 = -0.5 * (b - Math.Sqrt(d)) / a;
            double t2 = -0.5 * (b + Math.Sqrt(d)) / a;

            if (isPositive(t1) && isPositive(t2))
            {
                if (t1 < t2)
                {
                    ret[0] = t1 * ray_dir[0] + t_in[0];
                    ret[1] = t1 * ray_dir[1] + t_in[1];
                    ret[2] = t1 * ray_dir[2] + t_in[2];
                    ret[3] = t1;
                }
                else
                {
                    ret[0] = t2 * ray_dir[0] + t_in[0];
                    ret[1] = t2 * ray_dir[1] + t_in[1];
                    ret[2] = t2 * ray_dir[2] + t_in[2];
                    ret[3] = t2;
                }
            }
            else if (isPositive(t1))
            {
                ret[0] = t1 * ray_dir[0] + t_in[0];
                ret[1] = t1 * ray_dir[1] + t_in[1];
                ret[2] = t1 * ray_dir[2] + t_in[2];
                ret[3] = t1;
            }
            else if (isPositive(t2))
            {
                ret[0] = t2 * ray_dir[0] + t_in[0];
                ret[1] = t2 * ray_dir[1] + t_in[1];
                ret[2] = t2 * ray_dir[2] + t_in[2];
                ret[3] = t2;
            }


            return ret;
        }
        private double[] sphereIntersect(int x_count, int y_count, Sphere s_in)
        {
            double[] ray_dir = new double[3];
            ray_dir[0] = x_count; //temp
            ray_dir[1] = 1000; //temp
            ray_dir[2] = y_count; //temp

            double unit_mult = 1 / Math.Sqrt(ray_dir[0] * ray_dir[0] + ray_dir[1] * ray_dir[1] + ray_dir[2] * ray_dir[2]);

            ray_dir[0] = ray_dir[0] * unit_mult;
            ray_dir[1] = ray_dir[1] * unit_mult;
            ray_dir[2] = ray_dir[2] * unit_mult;

            //surface point co-ord, 1 t_length, 3 ray direction
            double[] ret = { 0, 0, 0, 0, ray_dir[0], ray_dir[1], ray_dir[2] };

            double a = ray_dir[0] * ray_dir[0] + ray_dir[1] * ray_dir[1] + ray_dir[2] * ray_dir[2];
            double b = -2 * (ray_dir[0] * s_in.pos[0] + ray_dir[1] * s_in.pos[1] + ray_dir[2] * s_in.pos[2]);
            double c = s_in.pos[0] * s_in.pos[0] + s_in.pos[1] * s_in.pos[1] + s_in.pos[2] * s_in.pos[2] - s_in.radius * s_in.radius;

            //b*b -4ac
            double d = b * b - 4 * a * c;
            if (d < 0)
                return ret;

            double t1 = -0.5 * (b - Math.Sqrt(d)) / a;
            double t2 = -0.5 * (b + Math.Sqrt(d)) / a;

            if (isPositive(t1))
            {
                if (isPositive(t2))
                {
                    if (t1 < t2)
                    {
                        ret[0] = t1 * ray_dir[0];
                        ret[1] = t1 * ray_dir[1];
                        ret[2] = t1 * ray_dir[2];
                        ret[3] = t1;
                    }
                    else
                    {
                        ret[0] = t2 * ray_dir[0];
                        ret[1] = t2 * ray_dir[1];
                        ret[2] = t2 * ray_dir[2];
                        ret[3] = t2;
                    }
                }
                else
                {
                    ret[0] = t1 * ray_dir[0];
                    ret[1] = t1 * ray_dir[1];
                    ret[2] = t1 * ray_dir[2];
                    ret[3] = t1;
                }
            }
            else if (isPositive(t2))
            {
                ret[0] = t2 * ray_dir[0];
                ret[1] = t2 * ray_dir[1];
                ret[2] = t2 * ray_dir[2];
                ret[3] = t2;
            }


            return ret;
        }