private IImageFunction getImageFunction(IImageFunction imf) { if (imf == null) // The script didn't define an image-function.. { imf = FormSupport.getImageFunction(TextParam.Text); } if (imf is RayTracing rt) { rt.DoShadows = checkShadows.Checked; rt.DoReflections = checkReflections.Checked; rt.DoRefractions = checkRefractions.Checked; rt.rayRegisterer = new MainRayRegisterer(additionalViews, rayVisualizer); } return(imf); }
/// <summary> /// Initialize image synthesizer (responsible for raster image computation). /// </summary> public static IRenderer getRenderer(IImageFunction imf, int superSampling, double jittering, string param) { Dictionary <string, string> p = Util.ParseKeyValueList(param); string isType; IRenderer r = null; if (p.TryGetValue("sampling", out isType) && superSampling > 1) { switch (isType) { case "adapt1": double threshold = 0.004; Util.TryParse(p, "threshold", ref threshold); r = new AdaptiveSupersamplingJR(threshold) { ImageFunction = imf, Supersampling = superSampling, Jittering = jittering }; break; case "adapt2": r = new AdaptiveSupersampling { ImageFunction = imf, Supersampling = superSampling, Jittering = jittering }; break; } } if (r == null) { r = new SupersamplingImageSynthesizer { ImageFunction = imf, Supersampling = superSampling, Jittering = jittering }; } return(r); }
/// <summary> /// Initialize the ray-scene. /// </summary> public static IRayScene getScene( out IImageFunction imf, out IRenderer rend, ref int width, ref int height, ref int superSampling, string param) { // 'superSampling' not used here but it could be if IRenderer is created here. // 'param' - ditto - // ActualWidth & ActualHeight can be modified by this call! return(Form1.singleton.SceneByComboBox( out imf, out rend, ref width, ref height, ref superSampling)); }
private IImageFunction getImageFunction(IRayScene sc, int width, int height) { IImageFunction imf = FormSupport.getImageFunction(sc, TextParam.Text); 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; } return(imf); }
/// <summary> /// Initialize image synthesizer (responsible for raster image computation). /// </summary> public static IRenderer getRenderer(IImageFunction imf) { Form1 f = Form1.singleton; if (f.superSampling > 1) { SupersamplingImageSynthesizer sis = new SupersamplingImageSynthesizer(); sis.ImageFunction = imf; sis.Supersampling = f.superSampling; sis.Jittering = 1.0; return(sis); } SimpleImageSynthesizer s = new SimpleImageSynthesizer(); s.ImageFunction = imf; return(s); }
private IRenderer getRenderer(IImageFunction imf, int width, int height) { IRenderer 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; } return(rend); }
private void SetGui(bool render) { IImageFunction imf = FormSupport.getImageFunction(textParam.Text, data); bool canAnimate = (imf != null) && (imf is ITimeDependent); buttonRenderAnim.Enabled = render && canAnimate; buttonRender.Enabled = render; buttonRes.Enabled = render; buttonStop.Enabled = !render; numTime.Enabled = canAnimate; numFrom.Enabled = canAnimate; numTo.Enabled = canAnimate; numFps.Enabled = canAnimate; label1.Enabled = canAnimate; label2.Enabled = canAnimate; label3.Enabled = canAnimate; label4.Enabled = canAnimate; }
/// <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; }
/// <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) { if (imf == null) { imf = FormSupport.getImageFunction(FormSupport.getScene()); rend = null; } // determine output image size: int width = ImageWidth; if (width <= 0) { width = panel1.Width; } int height = ImageHeight; if (height <= 0) { height = panel1.Height; } 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; } double[] color = new double[3]; long hash = imf.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); }
/// <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) { MT.singleRayTracing = true; rayVisualizer.Reset(); // 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]; 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); rayVisualizer.AddingRaysFinished(); MT.singleRayTracing = false; }
/// <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; IRayScene sc = FormSupport.getScene(); IImageFunction imf = getImageFunction(sc, width, height); IRenderer r = getRenderer(imf, width, height); rayVisualizer.UpdateScene(sc); master = new Master(newImage, sc, r, RenderClientsForm.instance?.clients, threads, pointCloudCheckBox.Checked, ref AdditionalViews.singleton.pointCloud); master.progressData = progress; master.InitializeAssignments(newImage, sc, r); if (pointCloudCheckBox.Checked) { master.pointCloud?.SetNecessaryFields(PointCloudSavingStart, PointCloudSavingEnd, Notification, Invoke); } progress.SyncInterval = ((width * (long)height) > (2L << 20)) ? 3000L : 1000L; progress.Reset(); CSGInnerNode.ResetStatistics(); lock (sw) sw.Restart(); master.StartThreads(); 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(); }
/// <summary> /// Main animation rendering thread. /// Initializes worker threads and collects the results. /// </summary> protected void RenderAnimation() { IImageFunction imf = FormSupport.getImageFunction(textParam.Text, data); if (imf == null || !(imf is ITimeDependent)) { return; } Cursor.Current = Cursors.WaitCursor; int threads = Environment.ProcessorCount; initQueue(); sem = new Semaphore(0, 10 * threads); // pool of working threads: Thread[] pool = new Thread[threads]; int t; for (t = 0; t < threads; t++) { pool[t] = new Thread(new ThreadStart(RenderWorker)); pool[t].Start(); } // loop for collection of computed frames: int frames = 0; int lastDisplayedFrame = -1; const long DISPLAY_GAP = 10000L; long lastDisplayedTime = -DISPLAY_GAP; Stopwatch sw = new Stopwatch(); sw.Start(); while (true) { sem.WaitOne(); // wait until a frame is finished lock ( progress ) // regular finish, escape, user break? { if (!progress.Continue || time >= end && frames >= frameNumber) { break; } } // there could be a frame to process: Result r; lock ( queue ) { if (queue.Count == 0) { continue; } r = queue.Dequeue(); } // GUI progress indication: double seconds = 1.0e-3 * sw.ElapsedMilliseconds; double fps = ++frames / seconds; SetText(string.Format(CultureInfo.InvariantCulture, "Frames (mt{0}): {1} ({2:f0} s, {3:f2} fps)", threads, frames, seconds, fps)); if (r.frameNumber > lastDisplayedFrame && sw.ElapsedMilliseconds > lastDisplayedTime + DISPLAY_GAP) { lastDisplayedFrame = r.frameNumber; lastDisplayedTime = sw.ElapsedMilliseconds; SetImage((Bitmap)r.image.Clone()); } // save the image file: string fileName = string.Format("{0}{1:0000}.png", prefix, r.frameNumber); r.image.Save(fileName, System.Drawing.Imaging.ImageFormat.Png); r.image.Dispose(); } for (t = 0; t < threads; t++) { pool[t].Join(); pool[t] = null; } Cursor.Current = Cursors.Default; StopAnimation(); }
/// <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) { MT.singleRayTracing = true; rayVisualizer.Reset(); // determine output image size: ActualWidth = ImageWidth; if (ActualWidth <= 0) { ActualWidth = panel1.Width; } ActualHeight = ImageHeight; if (ActualHeight <= 0) { ActualHeight = panel1.Height; } if (dirty || imfs == null) { int ss = 1; // Force preprocess. ctx = null; _ = FormSupport.getScene( out _, out _, ref ActualWidth, ref ActualHeight, ref ss, TextParam.Text); sc = FormSupport.getScene( out imfs, out rend, ref ActualWidth, ref ActualHeight, ref ss, TextParam.Text); // IImageFunction. if (imfs == null) // not defined in the script { imfs = getImageFunction(imfs, sc); } else if (imfs is RayCasting imfray) { imfray.Scene = sc; } imfs.Width = ActualWidth; imfs.Height = ActualHeight; // IRenderer. if (rend == null) // not defined in the script { rend = getRenderer(); } rend.ImageFunction = imfs; rend.Width = ActualWidth; rend.Height = ActualHeight; rend.Adaptive = 0; // 8? rend.ProgressData = progress; dirty = false; } // Set TLS. MT.SetRendering(sc, imfs, rend); double[] color = new double[3]; 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); // Reset TLS. MT.ResetRendering(); rayVisualizer.AddingRaysFinished(); MT.singleRayTracing = false; }
/// <summary> /// [Re]-renders the whole image (in separate thread). OLD VERSION!!! /// </summary> private void RenderImage_OLD() { 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)) ? 3000L : 1000L; progress.Reset(); CSGInnerNode.ResetStatistics(); lock (sw) sw.Restart(); 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(); }
private void textParam_TextChanged(object sender, EventArgs e) { imf = null; }
/// <summary> /// Default behavior - create scene selected in the combo-box. /// Can handle InitSceneDelegate, InitSceneParamDelegate or CSscript file-name /// </summary> public IRayScene SceneByComboBox( out IImageFunction imf, out IRenderer rend, ref int width, ref int height, ref int superSampling) { string sceneName = (string)ComboScene.Items[selectedScene]; if (sceneRepository.TryGetValue(sceneName, out object definition)) { // Try the CS-script file. if (ctx == null) { ctx = new ScriptContext(); // we need a new context object for each computing batch.. Dictionary <string, string> p = Util.ParseKeyValueList(TextParam.Text); double time = 0.0; if (Util.TryParse(p, "time", ref time)) { Scripts.SetScene(ctx, new AnimatedRayScene()); } } if (Scripts.ContextInit( ctx, sceneName, width, height, superSampling)) { // Script needs to be called. Scripts.SceneFromObject( ctx, definition, TextParam.Text, (sc) => Scenes.DefaultScene(sc), SetText); } double minTime = 0.0; double maxTime = 10.0; double fps = 25.0; return(Scripts.ContextMining( ctx, out imf, out rend, out tooltip, ref width, ref height, ref superSampling, ref minTime, ref maxTime, ref fps)); } // Fallback to a default scene. imf = null; rend = null; return(Scenes.DefaultScene()); }
/// <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(); }
private void comboScene_SelectedIndexChanged(object sender, EventArgs e) { selectedScene = comboScene.SelectedIndex; imf = null; }
/// <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; }
/// <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(); }
/// <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 } }
/// <summary> /// Main animation rendering thread. /// Initializes worker threads and collects the results. /// </summary> protected void RenderAnimation() { Cursor.Current = Cursors.WaitCursor; int threads = Environment.ProcessorCount; int t; // thread ordinal number WorkerThreadInit[] wti = new WorkerThreadInit[threads]; for (t = 0; t < threads; t++) { IRayScene sc = FormSupport.getScene(textParam.Text); IImageFunction imf = FormSupport.getImageFunction(sc); imf.Width = width; imf.Height = height; IRenderer r = FormSupport.getRenderer(imf); r.Width = width; r.Height = height; r.Adaptive = 0; // turn off adaptive bitmap synthesis completely (interactive preview not needed) r.ProgressData = progress; wti[t] = new WorkerThreadInit(r, sc as ITimeDependent, imf as ITimeDependent, width, height); } initQueue(); sem = new Semaphore(0, 10 * threads); // pool of working threads: 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]); } // loop for collection of computed frames: int frames = 0; int lastDisplayedFrame = -1; const long DISPLAY_GAP = 10000L; long lastDisplayedTime = -DISPLAY_GAP; Stopwatch sw = new Stopwatch(); sw.Start(); while (true) { sem.WaitOne(); // wait until a frame is finished lock ( progress ) // regular finish, escape, user break? { if (!progress.Continue || time >= end && frames >= frameNumber) { break; } } // there could be a frame to process: Result r; lock ( queue ) { if (queue.Count == 0) { continue; } r = queue.Dequeue(); } // GUI progress indication: double seconds = 1.0e-3 * sw.ElapsedMilliseconds; double fps = ++frames / seconds; SetText(string.Format(CultureInfo.InvariantCulture, "Frames (mt{0}): {1} ({2:f0} s, {3:f2} fps)", threads, frames, seconds, fps)); if (r.frameNumber > lastDisplayedFrame && sw.ElapsedMilliseconds > lastDisplayedTime + DISPLAY_GAP) { lastDisplayedFrame = r.frameNumber; lastDisplayedTime = sw.ElapsedMilliseconds; SetImage((Bitmap)r.image.Clone()); } // save the image file: string fileName = string.Format("out{0:0000}.png", r.frameNumber); r.image.Save(fileName, System.Drawing.Imaging.ImageFormat.Png); r.image.Dispose(); } for (t = 0; t < threads; t++) { pool[t].Join(); pool[t] = null; } Cursor.Current = Cursors.Default; StopAnimation(); }
/// <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; 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; buttonRender.Enabled = true; buttonRenderAnim.Enabled = true; buttonRes.Enabled = true; Cursor.Current = Cursors.Default; }