func renderer( width, height int, renderedImages chan *hdrimage.Image, scene *scene.Scene, seed int64, totalSamples int, threads int, quiet bool, ) { randomGen := random.New(seed) sampleCounter := rpc.NewSampleCounter(totalSamples) var bar *progress.ProgressBar if !quiet { bar = progress.StartProgressBar(totalSamples, "rendering samples") } wg := sync.WaitGroup{} wg.Add(threads) defer func() { wg.Wait() if !quiet { bar.Done() } }() for i := 0; i < threads; i++ { go func(seed int64) { defer wg.Done() raytracer := raytracer.Raytracer{ Scene: scene, Random: random.New(seed), } image := hdrimage.New(width, height) image.Divisor = 0 for { if sampleCounter.Dec(1) == 0 { renderedImages <- image return } raytracer.Sample(image) if !quiet { bar.Add(1) } } }(randomGen.NewSeed()) } }
// RenderLoop renders samples of an image until the sample counter reaches // 0, and then returns the combined result. If synchronous is set, images // will be transferred from the worker after every sample. Otherwise, // the image is transferred at the end. func RenderLoop( sampleCounter *rpc.SampleCounter, client *rpc.RemoteRaytracerCaller, renderedImages chan<- *hdrimage.Image, globalSettings *rpc.SampleSettings, synchronous bool, bar *progress.ProgressBar, ) { settings := *globalSettings for { settings.SamplesAtOnce = sampleCounter.Dec(globalSettings.SamplesAtOnce) if settings.SamplesAtOnce == 0 { return } var err error var image *hdrimage.Image if synchronous { image, err = client.Sample(&settings) } else { err = client.StoreSample(&settings) } //both samples log the error, but only synchronous sample pushes //image into the channel if err == nil { if synchronous { renderedImages <- image } if bar != nil { bar.Add(1) } } else { log.Printf("No sample :( %s\n", err) } } }