static void Main(string[] args)
        {
            int screenheight = 2160;
            int screenwidth;

            Console.WriteLine("Screen height in pixels?");

            String inputh = Console.ReadLine();

            if (inputh == "")
            {
                screenheight = 2160;
            }
            else
            {
                screenheight = Convert.ToInt32(inputh);
            }

            screenwidth = (int)((double)screenheight / 3 * 4);


            Console.WriteLine("" + screenwidth + " x " + screenheight);



            Raytracer rt = new Raytracer(screenwidth, screenheight);

            rt.SetCamera(new Vector(0, 45, -50), 2.5, 2160 / (double)screenheight * 0.00208);

            rt.AddLight(new Vector(40, 50, -40), new Vector(100, 100, 255));
            rt.AddLight(new Vector(-40, 50, -40), new Vector(255, 100, 100));
            rt.AddLight(new Vector(0, 90, 40), new Vector(100, 255, 100));


            rt.AddSphere(new Vector(0, 15, 16), new Vector(255, 109, 165), "matte", 15);

            rt.AddSphere(new Vector(-32, 32, 22), new Vector(204, 153, 51), "metal", 15);

            rt.AddSphere(new Vector(22, 70, 22), new Vector(255, 109, 165), "mirror", 25);

            rt.AddSphere(new Vector(-16, 28, -8), new Vector(255, 255, 255), "glass", 12.5);



            rt.AddPlaneU(new Vector(0, 0, 0), new Vector(50, 50, 50), "metal", 100, 100);
            rt.AddPlaneD(new Vector(0, 100, 0), new Vector(50, 50, 50), "metal", 100, 100);

            rt.AddWallF(new Vector(0, 50, 50), new Vector(50, 50, 50), "metal", 100, 100);
            rt.AddWallB(new Vector(0, 50, -50), new Vector(50, 50, 50), "metal", 100, 100);

            rt.AddSideWallL(new Vector(-50, 50, 0), new Vector(175, 80, 90), "metal", 100, 100);
            rt.AddSideWallR(new Vector(50, 50, 0), new Vector(90, 80, 175), "metal", 100, 100);



            ///Distribute rendeing in multiple cores and render
            ///
            int threadstospawn = 1;

            Console.WriteLine("How many cores to use?");

            String inputt = Console.ReadLine();

            if (inputt == "")
            {
                threadstospawn = 8;
            }
            else
            {
                threadstospawn = Convert.ToInt32(inputt);
            }
            Console.WriteLine(threadstospawn);

            int sampling = 256;

            Console.WriteLine("Sampling rate?");

            String inputs = Console.ReadLine();

            if (inputs == "")
            {
                sampling = 2;
            }
            else
            {
                sampling = Convert.ToInt32(inputs);
            }
            Console.WriteLine(sampling);


            int slicelog = 0;

            Console.WriteLine("Save individual slices?(0/1)");

            String inputl = Console.ReadLine();

            if (inputl == "")
            {
                slicelog = 0;
            }
            else
            {
                slicelog = Convert.ToInt32(inputl);
            }
            Console.WriteLine(slicelog);

            Console.WriteLine("Started rendering, this might take a while depending on your configuration.");


            Dictionary <int, Bitmap> maps = new Dictionary <int, Bitmap>();



            Task[] tasks = new Task[threadstospawn];

            Bitmap   image = new Bitmap(rt.width, rt.height);
            Graphics graph = Graphics.FromImage(image);

            int slicew = image.Width / threadstospawn;


            for (int i = 0; i < threadstospawn; i++)
            {
                int xb = i * slicew;
                int xe = (i + 1) * slicew;

                if (i == threadstospawn - 1)
                {
                    xe = image.Width;
                }

                tasks[i] = Task.Run(() => Render(xb, 0, xe, rt.height, rt.width, rt.height, ref maps, ref rt, sampling, slicelog));
            }

            Task.WaitAll(tasks);



            while (maps.Count != threadstospawn)
            {
                //extra wait just in case
            }


            foreach (KeyValuePair <int, Bitmap> entry in maps)
            {
                graph.DrawImageUnscaled(entry.Value, entry.Key, 0); // recombine slices
            }

            for (int i = 0; i < threadstospawn; i++)
            {
                tasks[i].Dispose();
            }


            Drawer.Save(ref image, "out");

            //Console.Read();
        }
        public static void Render(int xb, int yb, int xe, int ye, int canvas_w, int canvas_h, ref Dictionary <int, Bitmap> maps, ref Raytracer rt, int sampling, int slicelog)
        {
            Bitmap   i  = new Bitmap(xe - xb, ye - yb);
            Graphics gr = Graphics.FromImage(i);

            double gamma = 2;

            for (int x = 0; x < xe - xb; x++)
            {
                for (int y = 0; y < ye - yb; y++)
                {
                    int tr = 0;
                    int tg = 0;
                    int tb = 0;

                    for (int n = 0; n < sampling; n++)
                    {
                        int r = 0;
                        int g = 0;
                        int b = 0;
                        rt.Render(xb + x, yb + y, ref r, ref g, ref b, n, sampling);

                        tr += r;
                        tg += g;
                        tb += b;
                    }

                    tr = tr / sampling;
                    tg = tg / sampling;
                    tb = tb / sampling;

                    tr = (int)(Math.Pow(((double)tr / 255), (1 / gamma)) * 255);
                    tg = (int)(Math.Pow(((double)tg / 255), (1 / gamma)) * 255);
                    tb = (int)(Math.Pow(((double)tb / 255), (1 / gamma)) * 255);

                    Drawer.DrawPixel(x, y, tr, tg, tb, 255, gr);
                }
            }

            if (slicelog == 1)
            {
                Drawer.Save(ref i, "" + xb);
            }

            lock (maps)
            {
                maps.Add(xb, i);
            }
        }