1- /*
2- * The actual raytracing algorithm
3- */
1+ using CommonGraphics ;
2+
43namespace UnilightRaytracer
54{
65 // 1st = Origin, 2nd = Direction
@@ -15,6 +14,9 @@ public class Raytracer
1514 {
1615 private static int DEFAULT_TRACE_DEPTH = 5 ;
1716
17+ // pixel traversal order
18+ public TraversalOrder TraversalOrder { get ; set ; }
19+
1820 private struct RayTraversalResult
1921 {
2022 public GObject ? Closest { get ; set ; }
@@ -25,11 +27,11 @@ private struct RayTraversalResult
2527 public delegate void UpdateCallback ( int percent ) ;
2628
2729 public UpdateCallback ? Callback { get ; set ; } = null ;
28-
30+
2931 public Camera Camera { get ; set ; } = new Camera ( ) ;
30-
32+
3133 public Scene ? Scene { get ; set ; } = null ;
32-
34+
3335 // Reference to the Bitmap we're drawing to
3436 public Bitmap ? Buffer { get ; set ; } = null ;
3537
@@ -65,7 +67,7 @@ private Color trace(Ray ray, int depth)
6567
6668 GObject ? closest = null ;
6769 float dist = float . MaxValue ;
68- Vector intersectionPoint = new ( ) ;
70+ Vector intersectionPoint = new ( ) ;
6971
7072 for ( int k = 0 ; k < Scene . CountObjects ( ) ; ++ k )
7173 {
@@ -171,45 +173,76 @@ public void Render()
171173 if ( Buffer == null )
172174 return ;
173175
174- int imgWidth = Buffer . Width ;
175- int imgHeight = Buffer . Height ;
176- long total = imgWidth * imgHeight ;
177- if ( total <= 0 ) return ;
176+ List < ( Point start , Point end ) > ? chunks = null ;
177+ Chunks . CreateRenderChunks ( Buffer . Width , Buffer . Height , out chunks ) ;
178178
179- float factor = 100.0f / total ;
180- int lastPercent = 0 ;
181- long count = 0 ;
179+ if ( chunks == null )
180+ return ;
182181
183- Matrix4 i2v = imageToViewportTransform ( imgWidth , imgHeight , Camera ) ;
184-
185- for ( int p = 0 ; ! mStopRender && p < imgWidth ; ++ p )
186- {
187- for ( int q = 0 ; ! mStopRender && q < imgHeight ; ++ q )
188- {
189- int percent = ( int ) ( count * factor ) ;
190- if ( percent != lastPercent && Callback != null ) Callback ( percent ) ;
191- lastPercent = percent ;
182+ // Lock the bitmap once
183+ var rect = new Rectangle ( 0 , 0 , Buffer . Width , Buffer . Height ) ;
184+ var bmpData = Buffer . LockBits ( rect , System . Drawing . Imaging . ImageLockMode . WriteOnly , System . Drawing . Imaging . PixelFormat . Format32bppArgb ) ;
192185
193- Vector mapped = i2v . Multiply ( new Vector ( p , q , 0 ) ) ;
194- Vector dir = mapped - Camera . Eye ;
195- dir . Normalize ( ) ;
196- Ray ray = new Ray ( Camera . Eye , dir ) ;
186+ IntPtr ptr = bmpData . Scan0 ;
187+ int stride = bmpData . Stride ;
188+ byte [ ] pixels = new byte [ stride * Buffer . Height ] ;
197189
198- Color c = trace ( ray , 1 ) ;
190+ //_plottedPixels = 0;
191+ //PixelsToPlotCount = Buffer.Width * Buffer.Height;
199192
200- Buffer . SetPixel ( p , q , System . Drawing . Color . FromArgb (
201- ( int ) Math . Round ( c . r * 255 ) ,
202- ( int ) Math . Round ( c . g * 255 ) ,
203- ( int ) Math . Round ( c . b * 255 )
204- ) ) ;
193+ // Render all chunks in parallel
194+ //Parallel.ForEach(chunks, chunk =>
195+ //{
196+ // RenderChunk(chunk.start, chunk.end, pixels, stride);
197+ //} );
205198
206- ++ count ;
207- }
208- }
199+ RenderChunk ( new Point ( 0 , 0 ) , new Point ( Buffer . Width , Buffer . Height ) , pixels , stride ) ;
200+
201+ // Copy back into bitmap
202+ System . Runtime . InteropServices . Marshal . Copy ( pixels , 0 , ptr , pixels . Length ) ;
203+ Buffer . UnlockBits ( bmpData ) ;
209204
210- Callback ? . Invoke ( 100 ) ;
211- mStopRender = false ;
205+ // 100% progress
206+ //CallbackProgress?.Invoke(100) ;
212207 }
213208
209+ private void RenderChunk ( Point start , Point end , byte [ ] pixels , int stride )
210+ {
211+ if ( Buffer == null )
212+ return ;
213+
214+ // Compute width and height
215+ int width = end . X - start . X ;
216+ int height = end . Y - start . Y ;
217+
218+ PixelIterator iter = new PixelIterator ( start , end , TraversalOrder ) ;
219+
220+ // TBD: Compute this only once, not for every thread
221+ Matrix4 i2v = imageToViewportTransform ( Buffer . Width , Buffer . Height , Camera ) ;
222+
223+ while ( ! iter . Done ( ) )
224+ {
225+ Vector mapped = i2v . Multiply ( new Vector ( iter . Cursor . X , iter . Cursor . Y , 0 ) ) ;
226+ Vector dir = mapped - Camera . Eye ;
227+ dir . Normalize ( ) ;
228+ Ray ray = new Ray ( Camera . Eye , dir ) ;
229+
230+ Color c = trace ( ray , 1 ) ;
231+
232+ // Write into pixel array (thread-safe)
233+ int index = iter . Cursor . Y * stride + iter . Cursor . X * 4 ;
234+ pixels [ index + 0 ] = ( byte ) ( c . b * 255 ) ;
235+ pixels [ index + 1 ] = ( byte ) ( c . g * 255 ) ;
236+ pixels [ index + 2 ] = ( byte ) ( c . r * 255 ) ;
237+ pixels [ index + 3 ] = 255 ; // full opacity
238+
239+ // Thread-safe progress update
240+ //int plotted = Interlocked.Increment(ref _plottedPixels);
241+ //int percent = (int)((plotted / (double)PixelsToPlotCount) * 100);
242+
243+ // Advance iterator
244+ iter . Step ( ) ;
245+ }
246+ }
214247 }
215248}
0 commit comments