예제 #1
0
        /// <summary>
        /// Shoots single primary ray only..
        /// </summary>
        /// <param name="x">X-coordinate inside the raster image.</param>
        /// <param name="y">Y-coordinate inside the raster image.</param>
        private void singleSample(int x, int y)
        {
            // determine output image size:
            int width = ImageWidth;

            if (width <= 0)
            {
                width = panel1.Width;
            }
            int height = ImageHeight;

            if (height <= 0)
            {
                height = panel1.Height;
            }

            if (dirty || imfs == null)
            {
                imfs  = getImageFunction(FormSupport.getScene(), width, height);
                dirty = false;
            }

            double[] color = new double[3];
            MT.InitThreadData();
            long hash = imfs.GetSample(x + 0.5, y + 0.5, color);

            labelSample.Text = string.Format(CultureInfo.InvariantCulture, "Sample at [{0},{1}] = [{2:f},{3:f},{4:f}], {5:X}",
                                             x, y, color[0], color[1], color[2], hash);
        }
예제 #2
0
        /// <summary>
        /// Redraws the whole image.
        /// </summary>
        private void RenderImage()
        {
            Cursor.Current = Cursors.WaitCursor;

            EnableRendering(false);

            width = ImageWidth;
            if (width <= 0)
            {
                width = panel1.Width;
            }
            height = ImageHeight;
            if (height <= 0)
            {
                height = panel1.Height;
            }
            superSampling = (int)numericSupersampling.Value;
            outputImage   = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            IRayScene scene = FormSupport.getScene(textParam.Text);  // scene prototype

            IImageFunction imf = FormSupport.getImageFunction(scene);

            imf.Width  = width;
            imf.Height = height;

            IRenderer rend = FormSupport.getRenderer(imf);

            rend.Width        = width;
            rend.Height       = height;
            rend.Adaptive     = 0;
            rend.ProgressData = progress;
            progress.Continue = true;

            // animation:
            ITimeDependent sc = scene as ITimeDependent;

            if (sc != null)
            {
                sc.Time = (double)numTime.Value;
            }

            MT.InitThreadData();
            Stopwatch sw = new Stopwatch();

            sw.Start();

            rend.RenderRectangle(outputImage, 0, 0, width, height);

            sw.Stop();
            labelElapsed.Text = string.Format("Elapsed: {0:f1}s", 1.0e-3 * sw.ElapsedMilliseconds);

            pictureBox1.Image = outputImage;

            EnableRendering(true);

            Cursor.Current = Cursors.Default;
        }
예제 #3
0
        /// <summary>
        /// Routine of one worker-thread.
        /// Result image and rendering progress are the only two shared objects.
        /// </summary>
        /// <param name="spec">Thread-specific data (worker-thread-selector).</param>
        private void RenderWorker(Object spec)
        {
            WorkerThreadInit init = spec as WorkerThreadInit;

            if (init != null)
            {
                MT.InitThreadData();
                rend.RenderRectangle(init.image, 0, 0, init.width, init.height,
                                     init.sel);
            }
        }
예제 #4
0
파일: Form1.cs 프로젝트: maoap1/grcis-1
        /// <summary>
        /// Redraws the whole image.
        /// </summary>
        private void redraw()
        {
            Cursor.Current = Cursors.WaitCursor;

            // determine output image size:
            int width = ImageWidth;

            if (width <= 0)
            {
                width = panel1.Width;
            }
            int height = ImageHeight;

            if (height <= 0)
            {
                height = panel1.Height;
            }
            Bitmap newImage = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            if (imf == null)
            {
                imf = FormSupport.getImageFunction(out scene, brepScene);
            }
            imf.Width  = width;
            imf.Height = height;

            if (rend == null)
            {
                rend = FormSupport.getRenderer(imf);
            }
            rend.Width  = width;
            rend.Height = height;
            CSGInnerNode.ResetStatistics();
            MT.InitThreadData();

            Stopwatch sw = new Stopwatch();

            sw.Start();

            rend.RenderRectangle(newImage, 0, 0, width, height);

            sw.Stop();
            labelElapsed.Text = string.Format(CultureInfo.InvariantCulture, "{0:f1}s  [ {1}x{2}, r{3:#,#}k, i{4:#,#}k, bb{5:#,#}k, t{6:#,#}k ]",
                                              1.0e-3 * sw.ElapsedMilliseconds, width, height,
                                              (Intersection.countRays + 500L) / 1000L,
                                              (Intersection.countIntersections + 500L) / 1000L,
                                              (CSGInnerNode.countBoundingBoxes + 500L) / 1000L,
                                              (CSGInnerNode.countTriangles + 500L) / 1000L);

            setImage(ref outputImage, newImage);

            Cursor.Current = Cursors.Default;
        }
예제 #5
0
파일: Form1.cs 프로젝트: maoap1/grcis-1
        /// <summary>
        /// Redraws the whole image.
        /// </summary>
        private void redraw()
        {
            Cursor.Current = Cursors.WaitCursor;

            int width  = panel1.Width;
            int height = panel1.Height;

            Bitmap newImage = new Bitmap(width, height, PixelFormat.Format24bppRgb);

            if (imf == null)
            {
                imf = FormSupport.getImageFunction(out scene);
            }
            imf.Width  = width;
            imf.Height = height;

            if (rend == null)
            {
                rend = FormSupport.getRenderer(imf);
            }
            rend.Width    = width;
            rend.Height   = height;
            rend.Adaptive = 0;

            MT.InitThreadData();
            Stopwatch sw = new Stopwatch();

            sw.Start();

            rend.RenderRectangle(newImage, 0, 0, width, height);

            sw.Stop();
            labelElapsed.Text = string.Format(CultureInfo.InvariantCulture, "Elapsed: {0:f2}s",
                                              1.0e-3 * sw.ElapsedMilliseconds);

            setImage(ref outputImage, newImage);

            Cursor.Current = Cursors.Default;
        }
예제 #6
0
파일: Program.cs 프로젝트: Popa611/grcis
            /// <summary>
            /// Consumer-producer based multithreading work distribution
            /// Each thread waits for a new Assignment to be added to availableAssignments queue
            /// Most of the time is number of items in availableAssignments expected to be several times larger than number of threads
            /// </summary>
            private new void Consume()
            {
                MT.InitThreadData();

                while (!finished || !availableAssignments.IsEmpty)
                {
                    availableAssignments.TryDequeue(out Assignment newAssignment);

                    if (newAssignment == null) // TryDequeue was not succesfull
                    {
                        continue;
                    }

                    lock ( consoleLock )
                    {
                        Console.ForegroundColor = ConsoleColor.DarkYellow;
                        Console.WriteLine(@"Start of rendering of assignment [{0}, {1}, {2}, {3}]", newAssignment.x1, newAssignment.y1, newAssignment.x2, newAssignment.y2);
                    }

                    float[] colorArray = newAssignment.Render(true, renderer);

                    lock ( consoleLock )
                    {
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        Console.WriteLine(@"Rendering of assignment [{0}, {1}, {2}, {3}] finished. Sending result to server.", newAssignment.x1, newAssignment.y1, newAssignment.x2, newAssignment.y2);
                    }

                    SendRenderedImage(colorArray, newAssignment.x1, newAssignment.y1);

                    lock ( consoleLock )
                    {
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        Console.WriteLine(@"Result of assignment [{0}, {1}, {2}, {3}] sent.", newAssignment.x1, newAssignment.y1, newAssignment.x2, newAssignment.y2);
                    }
                }
            }
예제 #7
0
파일: Form1.cs 프로젝트: maoap1/grcis-1
        /// <summary>
        /// [Re]-renders the whole image (in separate thread).
        /// </summary>
        private void RenderImage()
        {
            Cursor.Current = Cursors.WaitCursor;

            // determine output image size:
            int width = ImageWidth;

            if (width <= 0)
            {
                width = panel1.Width;
            }
            int height = ImageHeight;

            if (height <= 0)
            {
                height = panel1.Height;
            }

            Bitmap newImage = new Bitmap(width, height, PixelFormat.Format24bppRgb);

            if (imf == null)
            {
                imf  = FormSupport.getImageFunction(FormSupport.getScene());
                rend = null;
            }
            imf.Width  = width;
            imf.Height = height;

            if (rend == null)
            {
                rend = FormSupport.getRenderer(imf);
            }
            rend.Width        = width;
            rend.Height       = height;
            rend.Adaptive     = 8;
            rend.ProgressData = progress;

            progress.SyncInterval = 5000L;
            progress.Reset();
            CSGInnerNode.ResetStatistics();
            MT.InitThreadData();

            lock ( sw )
            {
                sw.Reset();
                sw.Start();
            }

            rend.RenderRectangle(newImage, 0, 0, width, height);

            long elapsed;

            lock ( sw )
            {
                sw.Stop();
                elapsed = sw.ElapsedMilliseconds;
            }

            string msg = string.Format(CultureInfo.InvariantCulture, "{0:f1}s  [ {1}x{2}, r{3:#,#}k, i{4:#,#}k, bb{5:#,#}k, t{6:#,#}k ]",
                                       1.0e-3 * elapsed, width, height,
                                       (Intersection.countRays + 500L) / 1000L,
                                       (Intersection.countIntersections + 500L) / 1000L,
                                       (CSGInnerNode.countBoundingBoxes + 500L) / 1000L,
                                       (CSGInnerNode.countTriangles + 500L) / 1000L);

            SetText(msg);
            Console.WriteLine("Rendering finished: " + msg);
            SetImage(newImage);

            Cursor.Current = Cursors.Default;

            StopRendering();
        }
예제 #8
0
파일: Form1.cs 프로젝트: maoap1/grcis-1
        /// <summary>
        /// Redraws the whole image.
        /// </summary>
        private void RenderImage()
        {
            Cursor.Current = Cursors.WaitCursor;

            SetGui(false);

            width = ImageWidth;
            if (width <= 0)
            {
                width = panel1.Width;
            }
            height = ImageHeight;
            if (height <= 0)
            {
                height = panel1.Height;
            }
            superSampling = (int)numericSupersampling.Value;
            Bitmap im = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            MT.InitThreadData();

            if (data == null)
            {
                data = FormSupport.getData(textParam.Text);           // animation data
            }
            IImageFunction imf = FormSupport.getImageFunction(textParam.Text, data);

            imf.Width  = width;
            imf.Height = height;

            IRenderer rend = FormSupport.getRenderer(textParam.Text, imf);

            rend.Width        = width;
            rend.Height       = height;
            rend.Adaptive     = 0;
            rend.ProgressData = progress;
            progress.Continue = true;

            // animation:
            ITimeDependent imftd = imf as ITimeDependent;

            if (imftd != null)
            {
                imftd.Time = (double)numTime.Value;
            }

            Stopwatch sw = new Stopwatch();

            sw.Start();

            rend.RenderRectangle(im, 0, 0, width, height);

            sw.Stop();
            labelElapsed.Text = string.Format(CultureInfo.InvariantCulture, "Elapsed: {0:f1}s", 1.0e-3 * sw.ElapsedMilliseconds);

            SetImage((Bitmap)im.Clone());

            string fileName = Util.FileNameString(textParam.Text) + ".png";

            im.Save(fileName, System.Drawing.Imaging.ImageFormat.Png);
            im.Dispose();

            SetGui(true);

            Cursor.Current = Cursors.Default;
        }
예제 #9
0
파일: Form1.cs 프로젝트: maoap1/grcis-1
        /// <summary>
        /// Worker thread (picks up individual frames and renders them one by one).
        /// </summary>
        protected void RenderWorker()
        {
            // thread-specific data:
            ITimeDependent datatd = data as ITimeDependent;
            object         myData = (datatd == null) ? data : datatd.Clone();

            MT.InitThreadData();

            IImageFunction imf = FormSupport.getImageFunction(textParam.Text, myData);

            imf.Width  = width;
            imf.Height = height;
            ITimeDependent imftd = imf as ITimeDependent;

            IRenderer rend = FormSupport.getRenderer(textParam.Text, imf);

            rend.Width        = width;
            rend.Height       = height;
            rend.Adaptive     = 0;          // turn off adaptive bitmap synthesis completely (interactive preview not needed)
            rend.ProgressData = progress;

            // worker loop:
            while (true)
            {
                double myTime;
                int    myFrameNumber;

                lock ( progress )
                {
                    if (!progress.Continue ||
                        time > end)
                    {
                        sem.Release();      // chance for the main animation thread to give up as well..
                        return;
                    }

                    // got a frame to compute:
                    myTime        = time;
                    time         += dt;
                    myFrameNumber = frameNumber++;
                }

                // set up the new result record:
                Result r = new Result();
                r.image       = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                r.frameNumber = myFrameNumber;

                // set specific time to my image function:
                if (imftd != null)
                {
                    imftd.Time = myTime;
                }

                // render the whole frame:
                rend.RenderRectangle(r.image, 0, 0, width, height);

                // ... and put the result into the output queue:
                lock ( queue )
                {
                    queue.Enqueue(r);
                }
                sem.Release();              // notify the main animation thread
            }
        }
예제 #10
0
        /// <summary>
        /// Worker thread (picks up individual frames and renders them one by one).
        /// </summary>
        protected void RenderWorker(object spec)
        {
            // thread-specific data:
            WorkerThreadInit init = spec as WorkerThreadInit;

            if (init == null)
            {
                return;
            }

            MT.InitThreadData();

            // worker loop:
            while (true)
            {
                double myTime;
                double myEndTime;
                int    myFrameNumber;

                lock ( progress )
                {
                    if (!progress.Continue ||
                        time > end)
                    {
                        sem.Release();      // chance for the main animation thread to give up as well..
                        return;
                    }

                    // got a frame to compute:
                    myTime        = time;
                    myEndTime     = (time += dt);
                    myFrameNumber = frameNumber++;
                }

                // set up the new result record:
                Result r = new Result();
                r.image       = new Bitmap(init.width, init.height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                r.frameNumber = myFrameNumber;

                // set specific time to my scene:
                if (init.scene != null)
                {
                    init.scene.Time = myTime;
                }

                ITimeDependent anim = init.rend as ITimeDependent;
                if (anim != null)
                {
                    anim.Start = myTime;
                    anim.End   = myEndTime;
                }

                if (init.imfunc != null)
                {
                    init.imfunc.Start = myTime;
                    init.imfunc.End   = myEndTime;
                }

                // render the whole frame:
                init.rend.RenderRectangle(r.image, 0, 0, init.width, init.height);

                // ... and put the result into the output queue:
                lock ( queue )
                {
                    queue.Enqueue(r);
                }
                sem.Release();              // notify the main animation thread
            }
        }
예제 #11
0
        /// <summary>
        /// [Re]-renders the whole image (in separate thread).
        /// </summary>
        private void RenderImage()
        {
            Cursor.Current = Cursors.WaitCursor;

            // determine output image size:
            int width = ImageWidth;

            if (width <= 0)
            {
                width = panel1.Width;
            }
            int height = ImageHeight;

            if (height <= 0)
            {
                height = panel1.Height;
            }

            Bitmap newImage = new Bitmap(width, height, PixelFormat.Format24bppRgb);

            if (imf == null)
            {
                imf  = FormSupport.getImageFunction(FormSupport.getScene());
                rend = null;
            }
            imf.Width  = width;
            imf.Height = height;
            RayTracing rt = imf as RayTracing;

            if (rt != null)
            {
                rt.DoShadows     = checkShadows.Checked;
                rt.DoReflections = checkReflections.Checked;
                rt.DoRefractions = checkRefractions.Checked;
            }

            if (rend == null)
            {
                rend = FormSupport.getRenderer(imf);
            }
            rend.Width        = width;
            rend.Height       = height;
            rend.Adaptive     = 8;
            rend.ProgressData = progress;

            SupersamplingImageSynthesizer ss = rend as SupersamplingImageSynthesizer;

            if (ss != null)
            {
                ss.Supersampling = (int)numericSupersampling.Value;
                ss.Jittering     = checkJitter.Checked ? 1.0 : 0.0;
            }
            progress.SyncInterval = ((width * (long)height) > (2L << 20)) ? 30000L : 10000L;
            progress.Reset();
            CSGInnerNode.ResetStatistics();

            lock ( sw )
            {
                sw.Reset();
                sw.Start();
            }

            if (checkMultithreading.Checked && Environment.ProcessorCount > 1)
            {
                Thread[] pool = new Thread[Environment.ProcessorCount];
                int      t;
                for (t = 0; t < pool.Length; t++)
                {
                    pool[t] = new Thread(new ParameterizedThreadStart(this.RenderWorker));
                }
                for (t = pool.Length; --t >= 0;)
                {
                    pool[t].Start(new WorkerThreadInit(newImage, width, height, t, pool.Length));
                }

                for (t = 0; t < pool.Length; t++)
                {
                    pool[t].Join();
                    pool[t] = null;
                }
            }
            else
            {
                MT.InitThreadData();
                rend.RenderRectangle(newImage, 0, 0, width, height);
            }

            long elapsed;

            lock ( sw )
            {
                sw.Stop();
                elapsed = sw.ElapsedMilliseconds;
            }

            string msg = string.Format(CultureInfo.InvariantCulture,
                                       "{0:f1}s  [ {1}x{2}, f{3:#,#}, mt{4}, r{5:#,#}k, i{6:#,#}k, bb{7:#,#}k, t{8:#,#}k ]",
                                       1.0e-3 * elapsed, width, height, CSGInnerNode.countFaces,
                                       checkMultithreading.Checked ? Environment.ProcessorCount : 1,
                                       (Intersection.countRays + 500L) / 1000L,
                                       (Intersection.countIntersections + 500L) / 1000L,
                                       (CSGInnerNode.countBoundingBoxes + 500L) / 1000L,
                                       (CSGInnerNode.countTriangles + 500L) / 1000L);

            SetText(msg);
            Console.WriteLine("Rendering finished: " + msg);
            SetImage(newImage);

            Cursor.Current = Cursors.Default;

            StopRendering();
        }
예제 #12
0
        /// <summary>
        /// [Re]-renders the whole image (in separate thread).
        /// </summary>
        private void RenderImage()
        {
            Cursor.Current = Cursors.WaitCursor;

            // determine output image size:
            int width = ImageWidth;

            if (width <= 0)
            {
                width = panel1.Width;
            }
            int height = ImageHeight;

            if (height <= 0)
            {
                height = panel1.Height;
            }

            Bitmap newImage = new Bitmap(width, height, PixelFormat.Format24bppRgb);

            int threads = checkMultithreading.Checked ? Environment.ProcessorCount : 1;
            int t; // thread ordinal number

            WorkerThreadInit[] wti = new WorkerThreadInit[threads];

            // separate renderer, image function and the scene for each thread (safety precaution)
            for (t = 0; t < threads; t++)
            {
                IRayScene      sc  = FormSupport.getScene();
                IImageFunction imf = getImageFunction(sc, width, height);
                IRenderer      r   = getRenderer(imf, width, height);
                wti[t] = new WorkerThreadInit(r, sc as ITimeDependent, imf as ITimeDependent, newImage, width, height, t, threads);
            }

            progress.SyncInterval = ((width * (long)height) > (2L << 20)) ? 30000L : 10000L;
            progress.Reset();
            CSGInnerNode.ResetStatistics();

            lock ( sw )
            {
                sw.Reset();
                sw.Start();
            }

            if (threads > 1)
            {
                Thread[] pool = new Thread[threads];
                for (t = 0; t < threads; t++)
                {
                    pool[t] = new Thread(new ParameterizedThreadStart(RenderWorker));
                }
                for (t = threads; --t >= 0;)
                {
                    pool[t].Start(wti[t]);
                }

                for (t = 0; t < threads; t++)
                {
                    pool[t].Join();
                    pool[t] = null;
                }
            }
            else
            {
                MT.InitThreadData();
                wti[0].rend.RenderRectangle(newImage, 0, 0, width, height);
            }

            long elapsed;

            lock ( sw )
            {
                sw.Stop();
                elapsed = sw.ElapsedMilliseconds;
            }

            string msg = string.Format(CultureInfo.InvariantCulture, "{0:f1}s  [ {1}x{2}, mt{3}, r{4:#,#}k, i{5:#,#}k, bb{6:#,#}k, t{7:#,#}k ]",
                                       1.0e-3 * elapsed, width, height, threads,
                                       (Intersection.countRays + 500L) / 1000L,
                                       (Intersection.countIntersections + 500L) / 1000L,
                                       (CSGInnerNode.countBoundingBoxes + 500L) / 1000L,
                                       (CSGInnerNode.countTriangles + 500L) / 1000L);

            SetText(msg);
            Console.WriteLine("Rendering finished: " + msg);
            SetImage(newImage);

            Cursor.Current = Cursors.Default;

            StopRendering();
        }
예제 #13
0
파일: Form1.cs 프로젝트: maoap1/grcis-1
        /// <summary>
        /// Redraws the whole image.
        /// </summary>
        private void RenderImage()
        {
            Cursor.Current = Cursors.WaitCursor;

            buttonRender.Enabled     = false;
            buttonRenderAnim.Enabled = false;
            buttonRes.Enabled        = false;

            width = ImageWidth;
            if (width <= 0)
            {
                width = panel1.Width;
            }
            height = ImageHeight;
            if (height <= 0)
            {
                height = panel1.Height;
            }
            superSampling = (int)numericSupersampling.Value;
            Bitmap newImage = new Bitmap(width, height, PixelFormat.Format24bppRgb);

            if (scene == null)
            {
                scene = FormSupport.getScene();         // scene prototype
            }
            IImageFunction imf = FormSupport.getImageFunction(scene);

            imf.Width  = width;
            imf.Height = height;

            IRenderer rend = FormSupport.getRenderer(imf, superSampling);

            rend.Width        = width;
            rend.Height       = height;
            rend.Adaptive     = 0;
            rend.ProgressData = progress;
            progress.Continue = true;

            // animation:
            ITimeDependent sc = scene as ITimeDependent;

            if (sc != null)
            {
                sc.Time = (double)numTime.Value;
            }
            MT.InitThreadData();

            Stopwatch sw = new Stopwatch();

            sw.Start();

            rend.RenderRectangle(newImage, 0, 0, width, height);

            sw.Stop();
            labelElapsed.Text = string.Format(CultureInfo.InvariantCulture, "Elapsed: {0:f1}s",
                                              1.0e-3 * sw.ElapsedMilliseconds);

            setImage(ref outputImage, newImage);

            buttonRender.Enabled     = true;
            buttonRenderAnim.Enabled = true;
            buttonRes.Enabled        = true;

            Cursor.Current = Cursors.Default;
        }
예제 #14
0
        /// <summary>
        /// Worker thread (picks up individual frames and renders them one by one).
        /// </summary>
        protected void RenderWorker(object spec)
        {
            // Thread-specific data.
            WorkerThreadInit init = spec as WorkerThreadInit;

            if (init == null)
            {
                return;
            }

            MT.InitThreadData();

            // Worker loop.
            while (true)
            {
                double myTime;
                double myEndTime;
                int    myFrameNumber;

                lock (progress)
                {
                    if (!progress.Continue ||
                        time > end)
                    {
                        sem.Release();      // chance for the main animation thread to give up as well..
                        return;
                    }

                    // I've got a frame to compute.
                    myTime        = time;
                    myEndTime     = (time += dt);
                    myFrameNumber = frameNumber++;
                }

                // Set up the new result record.
                Result r = new Result();
                r.image       = new Bitmap(init.width, init.height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                r.frameNumber = myFrameNumber;

                // Set specific time to my scene.
                if (init.scene != null)
                {
#if DEBUG
                    Debug.WriteLine($"Scene #{init.scene.getSerial()} setTime({myTime})");
#endif
                    init.scene.Time = myTime;
                }

                if (init.rend is ITimeDependent arend)
                {
                    arend.Start = myTime;
                    arend.End   = myEndTime;
                }

                if (init.imfunc != null)
                {
                    init.imfunc.Start = myTime;
                    init.imfunc.End   = myEndTime;
                }

                // Render the whole frame...
                init.rend.RenderRectangle(r.image, 0, 0, init.width, init.height);

                // ...and put the result into the output queue.
                lock (queue)
                {
                    queue.Enqueue(r);
                }
                sem.Release();              // notify the main animation thread
            }
        }
예제 #15
0
        /// <summary>
        /// Redraws the whole image.
        /// </summary>
        private void RenderImage()
        {
            Cursor.Current = Cursors.WaitCursor;

            EnableRendering(false);

            ActualWidth = ImageWidth;
            if (ActualWidth <= 0)
            {
                ActualWidth = panel1.Width;
            }
            ActualHeight = ImageHeight;
            if (ActualHeight <= 0)
            {
                ActualHeight = panel1.Height;
            }

            superSampling = (int)numericSupersampling.Value;
            double minTime = (double)numFrom.Value;
            double maxTime = (double)numTo.Value;
            double fps     = (double)numFps.Value;

            // 1. preprocessing - compute simulation, animation data, etc.
            _ = FormSupport.getScene(
                true,
                out _, out _,
                ref ActualWidth,
                ref ActualHeight,
                ref superSampling,
                ref minTime,
                ref maxTime,
                ref fps,
                textParam.Text);

            // 2. compute regular frame (using the pre-computed context).
            IRayScene scene = FormSupport.getScene(
                false,
                out IImageFunction imf,
                out IRenderer rend,
                ref ActualWidth,
                ref ActualHeight,
                ref superSampling,
                ref minTime,
                ref maxTime,
                ref fps,
                textParam.Text);

            // Update GUI.
            if (ImageWidth > 0) // preserving default (form-size) resolution
            {
                ImageWidth  = ActualWidth;
                ImageHeight = ActualHeight;
                UpdateResolutionButton();
            }
            UpdateSupersampling(superSampling);
            UpdateAnimationTiming(minTime, maxTime, fps);

            // IImageFunction.
            if (imf == null) // not defined in the script
            {
                imf = FormSupport.getImageFunction(scene);
            }
            else
            if (imf is RayCasting imfrc)
            {
                imfrc.Scene = scene;
            }
            imf.Width  = ActualWidth;
            imf.Height = ActualHeight;

            // IRenderer.
            if (rend == null)  // not defined in the script
            {
                rend = FormSupport.getRenderer(superSampling);
            }
            rend.ImageFunction = imf;
            rend.Width         = ActualWidth;
            rend.Height        = ActualHeight;
            rend.Adaptive      = 0;
            rend.ProgressData  = progress;
            progress.Continue  = true;

            // Animation time has to be set.
            if (scene is ITimeDependent sc)
            {
                sc.Time = (double)numTime.Value;
            }

            // Output image.
            outputImage = new Bitmap(ActualWidth, ActualHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            MT.InitThreadData();
            Stopwatch sw = new Stopwatch();

            sw.Start();

            rend.RenderRectangle(outputImage, 0, 0, ActualWidth, ActualHeight);

            sw.Stop();
            labelElapsed.Text = string.Format("Elapsed: {0:f1}s", 1.0e-3 * sw.ElapsedMilliseconds);

            pictureBox1.Image = outputImage;

            EnableRendering(true);

            Cursor.Current = Cursors.Default;
        }