1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015-2020 Mario Luzeiro <mrluzeiro@ua.pt>
5  * Copyright (C) 2015-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
23  */
24 
25 #include <gal/opengl/kiglew.h>    // Must be included first
26 
27 #include <algorithm>
28 #include <atomic>
29 #include <chrono>
30 #include <climits>
31 #include <thread>
32 
33 #include "render_3d_raytrace.h"
34 #include "mortoncodes.h"
35 #include "../color_rgb.h"
36 #include "3d_fastmath.h"
37 #include "3d_math.h"
38 #include "../common_ogl/ogl_utils.h"
39 #include <profile.h>        // To use GetRunningMicroSecs or another profiling utility
40 #include <wx/log.h>
41 
42 
RENDER_3D_RAYTRACE(EDA_3D_CANVAS * aCanvas,BOARD_ADAPTER & aAdapter,CAMERA & aCamera)43 RENDER_3D_RAYTRACE::RENDER_3D_RAYTRACE( EDA_3D_CANVAS* aCanvas, BOARD_ADAPTER& aAdapter, CAMERA& aCamera ) :
44     RENDER_3D_BASE( aCanvas, aAdapter, aCamera ),
45     m_postShaderSsao( aCamera )
46 {
47     wxLogTrace( m_logTrace, wxT( "RENDER_3D_RAYTRACE::RENDER_3D_RAYTRACE" ) );
48 
49     m_openglSupportsVertexBufferObjects = false;
50     m_pboId       = GL_NONE;
51     m_pboDataSize = 0;
52     m_accelerator = nullptr;
53     m_convertedDummyBlockCount = 0;
54     m_converted2dRoundSegmentCount = 0;
55     m_oldWindowsSize.x = 0;
56     m_oldWindowsSize.y = 0;
57     m_outlineBoard2dObjects = nullptr;
58     m_antioutlineBoard2dObjects = nullptr;
59     m_firstHitinfo = nullptr;
60     m_shaderBuffer = nullptr;
61     m_cameraLight = nullptr;
62 
63     m_xoffset = 0;
64     m_yoffset = 0;
65 
66     m_isPreview = false;
67     m_renderState = RT_RENDER_STATE_MAX; // Set to an initial invalid state
68     m_renderStartTime = 0;
69     m_blockRenderProgressCount = 0;
70 }
71 
72 
~RENDER_3D_RAYTRACE()73 RENDER_3D_RAYTRACE::~RENDER_3D_RAYTRACE()
74 {
75     wxLogTrace( m_logTrace, wxT( "RENDER_3D_RAYTRACE::~RENDER_3D_RAYTRACE" ) );
76 
77     delete m_accelerator;
78     m_accelerator = nullptr;
79 
80     delete m_outlineBoard2dObjects;
81     m_outlineBoard2dObjects = nullptr;
82 
83     delete m_antioutlineBoard2dObjects;
84     m_antioutlineBoard2dObjects = nullptr;
85 
86     delete[] m_shaderBuffer;
87     m_shaderBuffer = nullptr;
88 
89     deletePbo();
90 }
91 
92 
GetWaitForEditingTimeOut()93 int RENDER_3D_RAYTRACE::GetWaitForEditingTimeOut()
94 {
95     return 1000; // ms
96 }
97 
98 
deletePbo()99 void RENDER_3D_RAYTRACE::deletePbo()
100 {
101     // Delete PBO if it was created
102     if( m_openglSupportsVertexBufferObjects )
103     {
104         if( glIsBufferARB( m_pboId ) )
105             glDeleteBuffers( 1, &m_pboId );
106 
107         m_pboId = GL_NONE;
108     }
109 }
110 
111 
SetCurWindowSize(const wxSize & aSize)112 void RENDER_3D_RAYTRACE::SetCurWindowSize( const wxSize& aSize )
113 {
114     if( m_windowSize != aSize )
115     {
116         m_windowSize = aSize;
117         glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
118 
119         initializeNewWindowSize();
120     }
121 }
122 
123 
restartRenderState()124 void RENDER_3D_RAYTRACE::restartRenderState()
125 {
126     m_renderStartTime = GetRunningMicroSecs();
127 
128     m_renderState = RT_RENDER_STATE_TRACING;
129     m_blockRenderProgressCount = 0;
130 
131     m_postShaderSsao.InitFrame();
132 
133     m_blockPositionsWasProcessed.resize( m_blockPositions.size() );
134 
135     // Mark the blocks not processed yet
136     std::fill( m_blockPositionsWasProcessed.begin(), m_blockPositionsWasProcessed.end(), 0 );
137 }
138 
139 
SetPixel(GLubyte * p,const COLOR_RGB & v)140 static inline void SetPixel( GLubyte* p, const COLOR_RGB& v )
141 {
142     p[0] = v.c[0];
143     p[1] = v.c[1];
144     p[2] = v.c[2];
145     p[3] = 255;
146 }
147 
148 
Redraw(bool aIsMoving,REPORTER * aStatusReporter,REPORTER * aWarningReporter)149 bool RENDER_3D_RAYTRACE::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
150                                  REPORTER* aWarningReporter )
151 {
152     bool requestRedraw = false;
153 
154     // Initialize openGL if need
155     if( !m_is_opengl_initialized )
156     {
157         if( !initializeOpenGL() )
158             return false;
159 
160         //aIsMoving = true;
161         requestRedraw = true;
162 
163         // It will assign the first time the windows size, so it will now
164         // revert to preview mode the first time the Redraw is called
165         m_oldWindowsSize = m_windowSize;
166         initializeBlockPositions();
167     }
168 
169     std::unique_ptr<BUSY_INDICATOR> busy = CreateBusyIndicator();
170 
171     // Reload board if it was requested
172     if( m_reloadRequested )
173     {
174         if( aStatusReporter )
175             aStatusReporter->Report( _( "Loading..." ) );
176 
177         //aIsMoving = true;
178         requestRedraw = true;
179         Reload( aStatusReporter, aWarningReporter, false );
180     }
181 
182 
183     // Recalculate constants if windows size was changed
184     if( m_windowSize != m_oldWindowsSize )
185     {
186         m_oldWindowsSize = m_windowSize;
187         aIsMoving = true;
188         requestRedraw = true;
189 
190         initializeBlockPositions();
191     }
192 
193 
194     // Clear buffers
195     glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
196     glClearDepth( 1.0f );
197     glClearStencil( 0x00 );
198     glClear( GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
199 
200     // 4-byte pixel alignment
201     glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
202 
203     glDisable( GL_STENCIL_TEST );
204     glDisable( GL_LIGHTING );
205     glDisable( GL_COLOR_MATERIAL );
206     glDisable( GL_DEPTH_TEST );
207     glDisable( GL_TEXTURE_2D );
208     glDisable( GL_BLEND );
209     glDisable( GL_MULTISAMPLE );
210 
211     const bool was_camera_changed = m_camera.ParametersChanged();
212 
213     if( requestRedraw || aIsMoving || was_camera_changed )
214         m_renderState = RT_RENDER_STATE_MAX; // Set to an invalid state,
215                                              // so it will restart again latter
216 
217     // This will only render if need, otherwise it will redraw the PBO on the screen again
218     if( aIsMoving || was_camera_changed )
219     {
220         // Set head light (camera view light) with the opposite direction of the camera
221         if( m_cameraLight )
222             m_cameraLight->SetDirection( -m_camera.GetDir() );
223 
224         OglDrawBackground( SFVEC3F( m_boardAdapter.m_BgColorTop),
225                            SFVEC3F( m_boardAdapter.m_BgColorBot) );
226 
227         // Bind PBO
228         glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboId );
229 
230         // Get the PBO pixel pointer to write the data
231         GLubyte* ptrPBO = (GLubyte *)glMapBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB,
232                                                      GL_WRITE_ONLY_ARB );
233 
234         if( ptrPBO )
235         {
236             renderPreview( ptrPBO );
237 
238             // release pointer to mapping buffer, this initialize the coping to PBO
239             glUnmapBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB );
240         }
241 
242         glWindowPos2i( m_xoffset, m_yoffset );
243     }
244     else
245     {
246         // Bind PBO
247         glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboId );
248 
249         if( m_renderState != RT_RENDER_STATE_FINISH )
250         {
251             // Get the PBO pixel pointer to write the data
252             GLubyte* ptrPBO = (GLubyte *)glMapBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB,
253                                                          GL_WRITE_ONLY_ARB );
254 
255             if( ptrPBO )
256             {
257                 render( ptrPBO, aStatusReporter );
258 
259                 if( m_renderState != RT_RENDER_STATE_FINISH )
260                     requestRedraw = true;
261 
262                 // release pointer to mapping buffer, this initialize the coping to PBO
263                 glUnmapBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB );
264             }
265         }
266 
267         if( m_renderState == RT_RENDER_STATE_FINISH )
268         {
269             glClear( GL_COLOR_BUFFER_BIT );
270         }
271 
272         glWindowPos2i( m_xoffset, m_yoffset );
273     }
274 
275     // This way it will blend the progress rendering with the last buffer. eg:
276     // if it was called after a openGL.
277     glEnable( GL_BLEND );
278     glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
279     glEnable( GL_ALPHA_TEST );
280     glDrawPixels( m_realBufferSize.x, m_realBufferSize.y, GL_RGBA, GL_UNSIGNED_BYTE, 0 );
281     glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, 0 );
282 
283     return requestRedraw;
284 }
285 
286 
render(GLubyte * ptrPBO,REPORTER * aStatusReporter)287 void RENDER_3D_RAYTRACE::render( GLubyte* ptrPBO, REPORTER* aStatusReporter )
288 {
289     if( ( m_renderState == RT_RENDER_STATE_FINISH ) || ( m_renderState >= RT_RENDER_STATE_MAX ) )
290     {
291         restartRenderState();
292 
293         if( m_cameraLight )
294             m_cameraLight->SetDirection( -m_camera.GetDir() );
295 
296         if( m_boardAdapter.GetRenderEngine() == RENDER_ENGINE::OPENGL )
297         {
298             // Set all pixels of PBO transparent (Alpha to 0)
299             // This way it will draw the full buffer but only shows the updated (
300             // already calculated) squares
301             unsigned int nPixels = m_realBufferSize.x * m_realBufferSize.y;
302             GLubyte* tmp_ptrPBO = ptrPBO + 3;   // PBO is RGBA
303 
304             for( unsigned int i = 0; i < nPixels; ++i )
305             {
306                 *tmp_ptrPBO = 0;
307                 tmp_ptrPBO += 4;                // PBO is RGBA
308             }
309         }
310 
311         m_backgroundColorTop = ConvertSRGBToLinear( (SFVEC3F)m_boardAdapter.m_BgColorTop );
312         m_backgroundColorBottom = ConvertSRGBToLinear( (SFVEC3F)m_boardAdapter.m_BgColorBot );
313     }
314 
315     switch( m_renderState )
316     {
317     case RT_RENDER_STATE_TRACING:
318         renderTracing( ptrPBO, aStatusReporter );
319         break;
320 
321     case RT_RENDER_STATE_POST_PROCESS_SHADE:
322         postProcessShading( ptrPBO, aStatusReporter );
323         break;
324 
325     case RT_RENDER_STATE_POST_PROCESS_BLUR_AND_FINISH:
326         postProcessBlurFinish( ptrPBO, aStatusReporter );
327         break;
328 
329     default:
330         wxASSERT_MSG( false, "Invalid state on m_renderState");
331         restartRenderState();
332         break;
333     }
334 
335     if( aStatusReporter && ( m_renderState == RT_RENDER_STATE_FINISH ) )
336     {
337         // Calculation time in seconds
338         const double elapsed_time = (double)( GetRunningMicroSecs() - m_renderStartTime ) / 1e6;
339 
340         aStatusReporter->Report( wxString::Format( _( "Rendering time %.3f s" ), elapsed_time ) );
341     }
342 }
343 
344 
renderTracing(GLubyte * ptrPBO,REPORTER * aStatusReporter)345 void RENDER_3D_RAYTRACE::renderTracing( GLubyte* ptrPBO, REPORTER* aStatusReporter )
346 {
347     m_isPreview = false;
348 
349     auto startTime = std::chrono::steady_clock::now();
350     bool breakLoop = false;
351 
352     std::atomic<size_t> numBlocksRendered( 0 );
353     std::atomic<size_t> currentBlock( 0 );
354     std::atomic<size_t> threadsFinished( 0 );
355 
356     size_t parallelThreadCount = std::min<size_t>(
357             std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
358             m_blockPositions.size() );
359 
360     for( size_t ii = 0; ii < parallelThreadCount; ++ii )
361     {
362         std::thread t = std::thread( [&]()
363         {
364             for( size_t iBlock = currentBlock.fetch_add( 1 );
365                  iBlock < m_blockPositions.size() && !breakLoop;
366                  iBlock = currentBlock.fetch_add( 1 ) )
367             {
368                 if( !m_blockPositionsWasProcessed[iBlock] )
369                 {
370                     renderBlockTracing( ptrPBO, iBlock );
371                     numBlocksRendered++;
372                     m_blockPositionsWasProcessed[iBlock] = 1;
373 
374                     // Check if it spend already some time render and request to exit
375                     // to display the progress
376                     if( std::chrono::duration_cast<std::chrono::milliseconds>(
377                             std::chrono::steady_clock::now() - startTime ).count() > 150 )
378                         breakLoop = true;
379                 }
380             }
381 
382             threadsFinished++;
383         } );
384 
385         t.detach();
386     }
387 
388     while( threadsFinished < parallelThreadCount )
389         std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
390 
391     m_blockRenderProgressCount += numBlocksRendered;
392 
393     if( aStatusReporter )
394         aStatusReporter->Report( wxString::Format( _( "Rendering: %.0f %%" ),
395                                                    (float) ( m_blockRenderProgressCount * 100 )
396                                                    / (float) m_blockPositions.size() ) );
397 
398     // Check if it finish the rendering and if should continue to a post processing
399     // or mark it as finished
400     if( m_blockRenderProgressCount >= m_blockPositions.size() )
401     {
402         if( m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_POST_PROCESSING ) )
403             m_renderState = RT_RENDER_STATE_POST_PROCESS_SHADE;
404         else
405             m_renderState = RT_RENDER_STATE_FINISH;
406     }
407 }
408 
409 
410 #ifdef USE_SRGB_SPACE
411 
412 /// @todo This should be removed in future when KiCad supports a greater version of glm lib.
413 #define SRGB_GAMA 2.4f
414 
415 
416 // This function implements the conversion from linear RGB to sRGB
417 // https://github.com/g-truc/glm/blob/master/glm/gtc/color_space.inl#L12
convertLinearToSRGB(const SFVEC3F & aRGBcolor)418 static SFVEC3F convertLinearToSRGB( const SFVEC3F& aRGBcolor )
419 {
420     const float gammaCorrection = 1.0f / SRGB_GAMA;
421     const SFVEC3F clampedColor = glm::clamp( aRGBcolor, SFVEC3F( 0.0f ), SFVEC3F( 1.0f ) );
422 
423     return glm::mix( glm::pow( clampedColor, SFVEC3F(gammaCorrection) ) * 1.055f - 0.055f,
424                      clampedColor * 12.92f,
425                      glm::lessThan( clampedColor, SFVEC3F(0.0031308f) ) );
426 }
427 
428 
429 // This function implements the conversion from sRGB to linear RGB
430 // https://github.com/g-truc/glm/blob/master/glm/gtc/color_space.inl#L35
ConvertSRGBToLinear(const SFVEC3F & aSRGBcolor)431 SFVEC3F ConvertSRGBToLinear( const SFVEC3F& aSRGBcolor )
432 {
433     const float gammaCorrection = SRGB_GAMA;
434 
435     return glm::mix( glm::pow( ( aSRGBcolor + SFVEC3F( 0.055f ) )
436                                * SFVEC3F( 0.94786729857819905213270142180095f ),
437                                SFVEC3F( gammaCorrection ) ),
438                      aSRGBcolor * SFVEC3F( 0.07739938080495356037151702786378f ),
439                      glm::lessThanEqual( aSRGBcolor, SFVEC3F( 0.04045f ) ) );
440 }
441 
442 #endif
443 
444 
renderFinalColor(GLubyte * ptrPBO,const SFVEC3F & rgbColor,bool applyColorSpaceConversion)445 void RENDER_3D_RAYTRACE::renderFinalColor( GLubyte* ptrPBO, const SFVEC3F& rgbColor,
446                                          bool applyColorSpaceConversion )
447 {
448     SFVEC3F color = rgbColor;
449 
450 #ifdef USE_SRGB_SPACE
451     /// @note This should be used in future when the KiCad support a greater version of glm lib.
452     // if( applyColorSpaceConversion )
453     //    rgbColor = glm::convertLinearToSRGB( rgbColor );
454 
455     if( applyColorSpaceConversion )
456         color = convertLinearToSRGB( rgbColor );
457 #endif
458 
459     ptrPBO[0] = (unsigned int) glm::clamp( (int) ( color.r * 255 ), 0, 255 );
460     ptrPBO[1] = (unsigned int) glm::clamp( (int) ( color.g * 255 ), 0, 255 );
461     ptrPBO[2] = (unsigned int) glm::clamp( (int) ( color.b * 255 ), 0, 255 );
462     ptrPBO[3] = 255;
463 }
464 
465 
HITINFO_PACKET_init(HITINFO_PACKET * aHitPacket)466 static void HITINFO_PACKET_init( HITINFO_PACKET* aHitPacket )
467 {
468     // Initialize hitPacket with a "not hit" information
469     for( unsigned int i = 0; i < RAYPACKET_RAYS_PER_PACKET; ++i )
470     {
471         aHitPacket[i].m_HitInfo.m_tHit = std::numeric_limits<float>::infinity();
472         aHitPacket[i].m_HitInfo.m_acc_node_info = 0;
473         aHitPacket[i].m_hitresult = false;
474         aHitPacket[i].m_HitInfo.m_HitNormal = SFVEC3F( 0.0f );
475         aHitPacket[i].m_HitInfo.m_ShadowFactor = 1.0f;
476     }
477 }
478 
479 
renderRayPackets(const SFVEC3F * bgColorY,const RAY * aRayPkt,HITINFO_PACKET * aHitPacket,bool is_testShadow,SFVEC3F * aOutHitColor)480 void RENDER_3D_RAYTRACE::renderRayPackets( const SFVEC3F* bgColorY, const RAY* aRayPkt,
481                                            HITINFO_PACKET* aHitPacket, bool is_testShadow,
482                                            SFVEC3F* aOutHitColor )
483 {
484     for( unsigned int y = 0, i = 0; y < RAYPACKET_DIM; ++y )
485     {
486         for( unsigned int x = 0; x < RAYPACKET_DIM; ++x, ++i )
487         {
488             if( aHitPacket[i].m_hitresult == true )
489             {
490                 aOutHitColor[i] = shadeHit( bgColorY[y], aRayPkt[i], aHitPacket[i].m_HitInfo,
491                                             false, 0, is_testShadow );
492             }
493             else
494             {
495                 aOutHitColor[i] = bgColorY[y];
496             }
497         }
498     }
499 }
500 
501 
renderAntiAliasPackets(const SFVEC3F * aBgColorY,const HITINFO_PACKET * aHitPck_X0Y0,const HITINFO_PACKET * aHitPck_AA_X1Y1,const RAY * aRayPck,SFVEC3F * aOutHitColor)502 void RENDER_3D_RAYTRACE::renderAntiAliasPackets( const SFVEC3F* aBgColorY,
503                                                  const HITINFO_PACKET* aHitPck_X0Y0,
504                                                  const HITINFO_PACKET* aHitPck_AA_X1Y1,
505                                                  const RAY* aRayPck, SFVEC3F* aOutHitColor )
506 {
507     const bool is_testShadow =  m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_SHADOWS );
508 
509     for( unsigned int y = 0, i = 0; y < RAYPACKET_DIM; ++y )
510     {
511         for( unsigned int x = 0; x < RAYPACKET_DIM; ++x, ++i )
512         {
513             const RAY& rayAA = aRayPck[i];
514 
515             HITINFO hitAA;
516             hitAA.m_tHit = std::numeric_limits<float>::infinity();
517             hitAA.m_acc_node_info = 0;
518 
519             bool hitted = false;
520 
521             const unsigned int idx0y1 = ( x + 0 ) + RAYPACKET_DIM * ( y + 1 );
522             const unsigned int idx1y1 = ( x + 1 ) + RAYPACKET_DIM * ( y + 1 );
523 
524             // Gets the node info from the hit.
525             const unsigned int nodex0y0 = aHitPck_X0Y0[ i ].m_HitInfo.m_acc_node_info;
526             const unsigned int node_AA_x0y0 = aHitPck_AA_X1Y1[ i ].m_HitInfo.m_acc_node_info;
527 
528             unsigned int nodex1y0 = 0;
529 
530             if( x < (RAYPACKET_DIM - 1) )
531                 nodex1y0 = aHitPck_X0Y0[ i + 1 ].m_HitInfo.m_acc_node_info;
532 
533             unsigned int nodex0y1 = 0;
534 
535             if( y < ( RAYPACKET_DIM - 1 ) && idx0y1 < RAYPACKET_RAYS_PER_PACKET )
536                 nodex0y1 = aHitPck_X0Y0[idx0y1].m_HitInfo.m_acc_node_info;
537 
538             unsigned int nodex1y1 = 0;
539 
540             if( ( x < ( RAYPACKET_DIM - 1 ) ) && ( y < ( RAYPACKET_DIM - 1 ) )
541               && idx1y1 < RAYPACKET_RAYS_PER_PACKET )
542                 nodex1y1 = aHitPck_X0Y0[idx1y1].m_HitInfo.m_acc_node_info;
543 
544             // If all notes are equal we assume there was no change on the object hits.
545             if( ( ( nodex0y0 == nodex1y0 ) || ( nodex1y0 == 0 ) )
546               && ( ( nodex0y0 == nodex0y1 ) || ( nodex0y1 == 0 ) )
547               && ( ( nodex0y0 == nodex1y1 ) || ( nodex1y1 == 0 ) )
548               && ( nodex0y0 == node_AA_x0y0 ) )
549             {
550                 /// @todo Either get rid of the if statement above or do something with the
551                 ///       commented out code below.
552                 // Option 1
553                 // This option will give a very good quality on reflections (slow)
554                 /*
555                 if( m_accelerator->Intersect( rayAA, hitAA, nodex0y0 ) )
556                 {
557                     aOutHitColor[i] += shadeHit( aBgColorY[y], rayAA, hitAA, false, 0 );
558                 }
559                 else
560                 {
561                     if( m_accelerator->Intersect( rayAA, hitAA ) )
562                         aOutHitColor[i] += shadeHit( aBgColorY[y], rayAA, hitAA, false, 0 );
563                     else
564                         aOutHitColor[i] += hitColor[i];
565                 }
566                 */
567 
568                 // Option 2
569                 // Trace again with the same node,
570                 // then if miss just give the same color as before
571                 //if( m_accelerator->Intersect( rayAA, hitAA, nodex0y0 ) )
572                 //    aOutHitColor[i] += shadeHit( aBgColorY[y], rayAA, hitAA, false, 0 );
573 
574                 // Option 3
575                 // Use same color
576             }
577             else
578             {
579                 // Try to intersect the different nodes
580                 // It tests the possible combination of hitted or not hitted points
581                 // This will try to get the best hit for this ray
582 
583                 if( nodex0y0 != 0 )
584                     hitted |= m_accelerator->Intersect( rayAA, hitAA, nodex0y0 );
585 
586                 if( ( nodex1y0 != 0 ) && ( nodex0y0 != nodex1y0 ) )
587                     hitted |= m_accelerator->Intersect( rayAA, hitAA, nodex1y0 );
588 
589                 if( ( nodex0y1 != 0 ) && ( nodex0y0 != nodex0y1 ) && ( nodex1y0 != nodex0y1 ) )
590                     hitted |= m_accelerator->Intersect( rayAA, hitAA, nodex0y1 );
591 
592                 if( ( nodex1y1 != 0 ) && ( nodex0y0 != nodex1y1 ) && ( nodex0y1 != nodex1y1 ) &&
593                     ( nodex1y0 != nodex1y1 ) )
594                     hitted |= m_accelerator->Intersect( rayAA, hitAA, nodex1y1 );
595 
596                 if( (node_AA_x0y0 != 0 ) && ( nodex0y0 != node_AA_x0y0 ) &&
597                     ( nodex0y1 != node_AA_x0y0 ) && ( nodex1y0 != node_AA_x0y0 ) &&
598                     ( nodex1y1 != node_AA_x0y0 ) )
599                     hitted |= m_accelerator->Intersect( rayAA, hitAA, node_AA_x0y0 );
600 
601                 if( hitted )
602                 {
603                     // If we got any result, shade it
604                     aOutHitColor[i] = shadeHit( aBgColorY[y], rayAA, hitAA, false, 0,
605                                                 is_testShadow );
606                 }
607                 else
608                 {
609                     // Note: There are very few cases that will end on this situation
610                     // so it is not so expensive to trace a single ray from the beginning
611 
612                     // It was missed the 'last nodes' so, trace a ray from the beginning
613                     if( m_accelerator->Intersect( rayAA, hitAA ) )
614                         aOutHitColor[i] = shadeHit( aBgColorY[y], rayAA, hitAA, false, 0,
615                                                     is_testShadow );
616                 }
617             }
618         }
619     }
620 }
621 
622 
623 #define DISP_FACTOR 0.075f
624 
625 
renderBlockTracing(GLubyte * ptrPBO,signed int iBlock)626 void RENDER_3D_RAYTRACE::renderBlockTracing( GLubyte* ptrPBO, signed int iBlock )
627 {
628     // Initialize ray packets
629     const SFVEC2UI& blockPos = m_blockPositions[iBlock];
630     const SFVEC2I blockPosI = SFVEC2I( blockPos.x + m_xoffset, blockPos.y + m_yoffset );
631 
632     RAYPACKET blockPacket( m_camera, (SFVEC2F) blockPosI + SFVEC2F( DISP_FACTOR, DISP_FACTOR ),
633                            SFVEC2F( DISP_FACTOR, DISP_FACTOR ) /* Displacement random factor */ );
634 
635 
636     HITINFO_PACKET hitPacket_X0Y0[RAYPACKET_RAYS_PER_PACKET];
637 
638     HITINFO_PACKET_init( hitPacket_X0Y0 );
639 
640     // Calculate background gradient color
641     SFVEC3F bgColor[RAYPACKET_DIM];// Store a vertical gradient color
642 
643     for( unsigned int y = 0; y < RAYPACKET_DIM; ++y )
644     {
645         const float posYfactor = (float) ( blockPosI.y + y ) / (float) m_windowSize.y;
646 
647         bgColor[y] = m_backgroundColorTop * SFVEC3F(posYfactor) +
648                      m_backgroundColorBottom * ( SFVEC3F(1.0f) - SFVEC3F(posYfactor) );
649     }
650 
651     // Intersect ray packets (calculate the intersection with rays and objects)
652     if( !m_accelerator->Intersect( blockPacket, hitPacket_X0Y0 ) )
653     {
654         // If block is empty then set shades and continue
655         if( m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_POST_PROCESSING ) )
656         {
657             for( unsigned int y = 0; y < RAYPACKET_DIM; ++y )
658             {
659                 const SFVEC3F& outColor = bgColor[y];
660 
661                 const unsigned int yBlockPos = blockPos.y + y;
662 
663                 for( unsigned int x = 0; x < RAYPACKET_DIM; ++x )
664                 {
665                         m_postShaderSsao.SetPixelData( blockPos.x + x, yBlockPos,
666                                                        SFVEC3F( 0.0f ), outColor,
667                                                        SFVEC3F( 0.0f ), 0, 1.0f );
668                 }
669             }
670         }
671 
672         // This will set the output color to be displayed
673         // If post processing is enabled, it will not reflect the final result
674         // (as the final color will be computed on post processing)
675         // but it is used for report progress
676         const bool isFinalColor = !m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_POST_PROCESSING );
677 
678         for( unsigned int y = 0; y < RAYPACKET_DIM; ++y )
679         {
680             const SFVEC3F& outColor = bgColor[y];
681 
682             const unsigned int yConst = blockPos.x + ( ( y + blockPos.y ) * m_realBufferSize.x );
683 
684             for( unsigned int x = 0; x < RAYPACKET_DIM; ++x )
685             {
686                 GLubyte* ptr = &ptrPBO[( yConst + x ) * 4];
687 
688                 renderFinalColor( ptr, outColor, isFinalColor );
689             }
690         }
691 
692         // There is nothing more here to do.. there are no hits ..
693         // just background so continue
694         return;
695     }
696 
697     SFVEC3F hitColor_X0Y0[RAYPACKET_RAYS_PER_PACKET];
698 
699     // Shade original (0, 0) hits ("paint" the intersected objects)
700     renderRayPackets( bgColor, blockPacket.m_ray, hitPacket_X0Y0,
701                       m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_SHADOWS ), hitColor_X0Y0 );
702 
703     if( m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_ANTI_ALIASING ) )
704     {
705         SFVEC3F hitColor_AA_X1Y1[RAYPACKET_RAYS_PER_PACKET];
706 
707         // Intersect one blockPosI + (0.5, 0.5) used for anti aliasing calculation
708         HITINFO_PACKET hitPacket_AA_X1Y1[RAYPACKET_RAYS_PER_PACKET];
709         HITINFO_PACKET_init( hitPacket_AA_X1Y1 );
710 
711         RAYPACKET blockPacket_AA_X1Y1( m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.5f, 0.5f ),
712                                        SFVEC2F( DISP_FACTOR, DISP_FACTOR ) );
713 
714         if( !m_accelerator->Intersect( blockPacket_AA_X1Y1, hitPacket_AA_X1Y1 ) )
715         {
716             // Missed all the package
717             for( unsigned int y = 0, i = 0; y < RAYPACKET_DIM; ++y )
718             {
719                 const SFVEC3F& outColor = bgColor[y];
720 
721                 for( unsigned int x = 0; x < RAYPACKET_DIM; ++x, ++i )
722                 {
723                     hitColor_AA_X1Y1[i] = outColor;
724                 }
725             }
726         }
727         else
728         {
729             renderRayPackets( bgColor, blockPacket_AA_X1Y1.m_ray, hitPacket_AA_X1Y1,
730                               m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_SHADOWS ),
731                               hitColor_AA_X1Y1 );
732         }
733 
734         SFVEC3F hitColor_AA_X1Y0[RAYPACKET_RAYS_PER_PACKET];
735         SFVEC3F hitColor_AA_X0Y1[RAYPACKET_RAYS_PER_PACKET];
736         SFVEC3F hitColor_AA_X0Y1_half[RAYPACKET_RAYS_PER_PACKET];
737 
738         for( unsigned int i = 0; i < RAYPACKET_RAYS_PER_PACKET; ++i )
739         {
740             const SFVEC3F color_average = ( hitColor_X0Y0[i] +
741                                             hitColor_AA_X1Y1[i] ) * SFVEC3F( 0.5f );
742 
743             hitColor_AA_X1Y0[i] = color_average;
744             hitColor_AA_X0Y1[i] = color_average;
745             hitColor_AA_X0Y1_half[i] = color_average;
746         }
747 
748         RAY blockRayPck_AA_X1Y0[RAYPACKET_RAYS_PER_PACKET];
749         RAY blockRayPck_AA_X0Y1[RAYPACKET_RAYS_PER_PACKET];
750         RAY blockRayPck_AA_X1Y1_half[RAYPACKET_RAYS_PER_PACKET];
751 
752         RAYPACKET_InitRays_with2DDisplacement(
753                 m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.5f - DISP_FACTOR, DISP_FACTOR ),
754                 SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X1Y0 );
755 
756         RAYPACKET_InitRays_with2DDisplacement(
757                 m_camera, (SFVEC2F) blockPosI + SFVEC2F( DISP_FACTOR, 0.5f - DISP_FACTOR ),
758                 SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X0Y1 );
759 
760         RAYPACKET_InitRays_with2DDisplacement(
761                 m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.25f - DISP_FACTOR, 0.25f - DISP_FACTOR ),
762                 SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X1Y1_half );
763 
764         renderAntiAliasPackets( bgColor, hitPacket_X0Y0, hitPacket_AA_X1Y1, blockRayPck_AA_X1Y0,
765                                 hitColor_AA_X1Y0 );
766 
767         renderAntiAliasPackets( bgColor, hitPacket_X0Y0, hitPacket_AA_X1Y1, blockRayPck_AA_X0Y1,
768                                 hitColor_AA_X0Y1 );
769 
770         renderAntiAliasPackets( bgColor, hitPacket_X0Y0, hitPacket_AA_X1Y1,
771                                 blockRayPck_AA_X1Y1_half, hitColor_AA_X0Y1_half );
772 
773         // Average the result
774         for( unsigned int i = 0; i < RAYPACKET_RAYS_PER_PACKET; ++i )
775         {
776             hitColor_X0Y0[i] = ( hitColor_X0Y0[i] + hitColor_AA_X1Y1[i] + hitColor_AA_X1Y0[i] +
777                                  hitColor_AA_X0Y1[i] + hitColor_AA_X0Y1_half[i] ) *
778                     SFVEC3F( 1.0f / 5.0f );
779         }
780     }
781 
782     // Copy results to the next stage
783     GLubyte* ptr = &ptrPBO[( blockPos.x + ( blockPos.y * m_realBufferSize.x ) ) * 4];
784 
785     const uint32_t ptrInc = ( m_realBufferSize.x - RAYPACKET_DIM ) * 4;
786 
787     if( m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_POST_PROCESSING ) )
788     {
789         SFVEC2I bPos;
790         bPos.y = blockPos.y;
791 
792         for( unsigned int y = 0, i = 0; y < RAYPACKET_DIM; ++y )
793         {
794             bPos.x = blockPos.x;
795 
796             for( unsigned int x = 0; x < RAYPACKET_DIM; ++x, ++i )
797             {
798                 const SFVEC3F& hColor = hitColor_X0Y0[i];
799 
800                 if( hitPacket_X0Y0[i].m_hitresult == true )
801                     m_postShaderSsao.SetPixelData( bPos.x, bPos.y,
802                                                    hitPacket_X0Y0[i].m_HitInfo.m_HitNormal,
803                                                    hColor,
804                                                    blockPacket.m_ray[i].at(
805                                                            hitPacket_X0Y0[i].m_HitInfo.m_tHit ),
806                                                    hitPacket_X0Y0[i].m_HitInfo.m_tHit,
807                                                    hitPacket_X0Y0[i].m_HitInfo.m_ShadowFactor );
808                 else
809                     m_postShaderSsao.SetPixelData( bPos.x, bPos.y, SFVEC3F( 0.0f ), hColor,
810                                                    SFVEC3F( 0.0f ), 0, 1.0f );
811 
812                 renderFinalColor( ptr, hColor, false );
813 
814                 bPos.x++;
815                 ptr += 4;
816             }
817 
818             ptr += ptrInc;
819             bPos.y++;
820         }
821     }
822     else
823     {
824         for( unsigned int y = 0, i = 0; y < RAYPACKET_DIM; ++y )
825         {
826             for( unsigned int x = 0; x < RAYPACKET_DIM; ++x, ++i )
827             {
828                 renderFinalColor( ptr, hitColor_X0Y0[i], true );
829                 ptr += 4;
830             }
831 
832             ptr += ptrInc;
833         }
834     }
835 }
836 
837 
postProcessShading(GLubyte *,REPORTER * aStatusReporter)838 void RENDER_3D_RAYTRACE::postProcessShading( GLubyte* /* ptrPBO */, REPORTER* aStatusReporter )
839 {
840     if( m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_POST_PROCESSING ) )
841     {
842         if( aStatusReporter )
843             aStatusReporter->Report( _( "Rendering: Post processing shader" ) );
844 
845         m_postShaderSsao.SetShadowsEnabled(
846                 m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_SHADOWS ) );
847 
848         std::atomic<size_t> nextBlock( 0 );
849         std::atomic<size_t> threadsFinished( 0 );
850 
851         size_t parallelThreadCount = std::max<size_t>( std::thread::hardware_concurrency(), 2 );
852 
853         for( size_t ii = 0; ii < parallelThreadCount; ++ii )
854         {
855             std::thread t = std::thread( [&]()
856             {
857                 for( size_t y = nextBlock.fetch_add( 1 ); y < m_realBufferSize.y;
858                      y = nextBlock.fetch_add( 1 ) )
859                 {
860                     SFVEC3F* ptr = &m_shaderBuffer[ y * m_realBufferSize.x ];
861 
862                     for( signed int x = 0; x < (int)m_realBufferSize.x; ++x )
863                     {
864                         *ptr = m_postShaderSsao.Shade( SFVEC2I( x, y ) );
865                         ptr++;
866                     }
867                 }
868 
869                 threadsFinished++;
870             } );
871 
872             t.detach();
873         }
874 
875         while( threadsFinished < parallelThreadCount )
876             std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
877 
878         m_postShaderSsao.SetShadedBuffer( m_shaderBuffer );
879 
880         // Set next state
881         m_renderState = RT_RENDER_STATE_POST_PROCESS_BLUR_AND_FINISH;
882     }
883     else
884     {
885         // As this was an invalid state, set to finish
886         m_renderState = RT_RENDER_STATE_FINISH;
887     }
888 }
889 
890 
postProcessBlurFinish(GLubyte * ptrPBO,REPORTER *)891 void RENDER_3D_RAYTRACE::postProcessBlurFinish( GLubyte* ptrPBO, REPORTER* /* aStatusReporter */ )
892 {
893     if( m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_POST_PROCESSING ) )
894     {
895         // Now blurs the shader result and compute the final color
896         std::atomic<size_t> nextBlock( 0 );
897         std::atomic<size_t> threadsFinished( 0 );
898 
899         size_t parallelThreadCount = std::max<size_t>( std::thread::hardware_concurrency(), 2 );
900 
901         for( size_t ii = 0; ii < parallelThreadCount; ++ii )
902         {
903             std::thread t = std::thread( [&]()
904             {
905                 for( size_t y = nextBlock.fetch_add( 1 ); y < m_realBufferSize.y;
906                      y = nextBlock.fetch_add( 1 ) )
907                 {
908                     GLubyte* ptr = &ptrPBO[ y * m_realBufferSize.x * 4 ];
909 
910                     for( signed int x = 0; x < (int)m_realBufferSize.x; ++x )
911                     {
912                         const SFVEC3F bluredShadeColor = m_postShaderSsao.Blur( SFVEC2I( x, y ) );
913 
914 #ifdef USE_SRGB_SPACE
915                         const SFVEC3F originColor = convertLinearToSRGB(
916                                 m_postShaderSsao.GetColorAtNotProtected( SFVEC2I( x, y ) ) );
917 #else
918                         const SFVEC3F originColor =
919                                 m_postShaderSsao.GetColorAtNotProtected( SFVEC2I( x, y ) );
920 #endif
921                         const SFVEC3F shadedColor = m_postShaderSsao.ApplyShadeColor(
922                                 SFVEC2I( x, y ), originColor, bluredShadeColor );
923 
924                         renderFinalColor( ptr, shadedColor, false );
925 
926                         ptr += 4;
927                     }
928                 }
929 
930                 threadsFinished++;
931             } );
932 
933             t.detach();
934         }
935 
936         while( threadsFinished < parallelThreadCount )
937             std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
938 
939         // Debug code
940         //m_postShaderSsao.DebugBuffersOutputAsImages();
941     }
942 
943     // End rendering
944     m_renderState = RT_RENDER_STATE_FINISH;
945 }
946 
947 
renderPreview(GLubyte * ptrPBO)948 void RENDER_3D_RAYTRACE::renderPreview( GLubyte* ptrPBO )
949 {
950     m_isPreview = true;
951 
952     std::atomic<size_t> nextBlock( 0 );
953     std::atomic<size_t> threadsFinished( 0 );
954 
955     size_t parallelThreadCount = std::min<size_t>(
956             std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
957             m_blockPositions.size() );
958 
959     for( size_t ii = 0; ii < parallelThreadCount; ++ii )
960     {
961         std::thread t = std::thread( [&]()
962         {
963             for( size_t iBlock = nextBlock.fetch_add( 1 ); iBlock < m_blockPositionsFast.size();
964                  iBlock = nextBlock.fetch_add( 1 ) )
965             {
966                 const SFVEC2UI& windowPosUI = m_blockPositionsFast[ iBlock ];
967                 const SFVEC2I windowsPos = SFVEC2I( windowPosUI.x + m_xoffset,
968                                                     windowPosUI.y + m_yoffset );
969 
970                 RAYPACKET blockPacket( m_camera, windowsPos, 4 );
971 
972                 HITINFO_PACKET hitPacket[RAYPACKET_RAYS_PER_PACKET];
973 
974                 // Initialize hitPacket with a "not hit" information
975                 for( HITINFO_PACKET& packet : hitPacket )
976                 {
977                     packet.m_HitInfo.m_tHit = std::numeric_limits<float>::infinity();
978                     packet.m_HitInfo.m_acc_node_info = 0;
979                     packet.m_hitresult = false;
980                 }
981 
982                 //  Intersect packet block
983                 m_accelerator->Intersect( blockPacket, hitPacket );
984 
985                 // Calculate background gradient color
986                 SFVEC3F bgColor[RAYPACKET_DIM];
987 
988                 for( unsigned int y = 0; y < RAYPACKET_DIM; ++y )
989                 {
990                     const float posYfactor =
991                             (float) ( windowsPos.y + y * 4.0f ) / (float) m_windowSize.y;
992 
993                     bgColor[y] = (SFVEC3F) m_boardAdapter.m_BgColorTop * SFVEC3F( posYfactor )
994                                  + (SFVEC3F) m_boardAdapter.m_BgColorBot
995                                            * ( SFVEC3F( 1.0f ) - SFVEC3F( posYfactor ) );
996                 }
997 
998                 COLOR_RGB hitColorShading[RAYPACKET_RAYS_PER_PACKET];
999 
1000                 for( unsigned int i = 0; i < RAYPACKET_RAYS_PER_PACKET; ++i )
1001                 {
1002                     const SFVEC3F bhColorY = bgColor[i / RAYPACKET_DIM];
1003 
1004                     if( hitPacket[i].m_hitresult == true )
1005                     {
1006                         const SFVEC3F hitColor = shadeHit( bhColorY, blockPacket.m_ray[i],
1007                                                            hitPacket[i].m_HitInfo, false,
1008                                                            0, false );
1009 
1010                         hitColorShading[i] = COLOR_RGB( hitColor );
1011                     }
1012                     else
1013                         hitColorShading[i] = bhColorY;
1014                 }
1015 
1016                 COLOR_RGB cLRB_old[(RAYPACKET_DIM - 1)];
1017 
1018                 for( unsigned int y = 0; y < (RAYPACKET_DIM - 1); ++y )
1019                 {
1020                     const SFVEC3F     bgColorY = bgColor[y];
1021                     const COLOR_RGB   bgColorYRGB = COLOR_RGB( bgColorY );
1022 
1023                     // This stores cRTB from the last block to be reused next time in a cLTB pixel
1024                     COLOR_RGB cRTB_old;
1025 
1026                     //RAY       cRTB_ray;
1027                     //HITINFO   cRTB_hitInfo;
1028 
1029                     for( unsigned int x = 0; x < ( RAYPACKET_DIM - 1 ); ++x )
1030                     {
1031                         //      pxl 0  pxl 1  pxl 2  pxl 3  pxl 4
1032                         //        x0                          x1  ...
1033                         //     .---------------------------.
1034                         // y0  | cLT  | cxxx | cLRT | cxxx | cRT  |
1035                         //     | cxxx | cLTC | cxxx | cRTC | cxxx |
1036                         //     | cLTB | cxxx | cC   | cxxx | cRTB |
1037                         //     | cxxx | cLBC | cxxx | cRBC | cxxx |
1038                         //     '---------------------------'
1039                         // y1  | cLB  | cxxx | cLRB | cxxx | cRB  |
1040 
1041                         const unsigned int iLT = ( ( x + 0 ) + RAYPACKET_DIM * ( y + 0 ) );
1042                         const unsigned int iRT = ( ( x + 1 ) + RAYPACKET_DIM * ( y + 0 ) );
1043                         const unsigned int iLB = ( ( x + 0 ) + RAYPACKET_DIM * ( y + 1 ) );
1044                         const unsigned int iRB = ( ( x + 1 ) + RAYPACKET_DIM * ( y + 1 ) );
1045 
1046                         // !TODO: skip when there are no hits
1047                         const COLOR_RGB& cLT = hitColorShading[ iLT ];
1048                         const COLOR_RGB& cRT = hitColorShading[ iRT ];
1049                         const COLOR_RGB& cLB = hitColorShading[ iLB ];
1050                         const COLOR_RGB& cRB = hitColorShading[ iRB ];
1051 
1052                         // Trace and shade cC
1053                         COLOR_RGB cC = bgColorYRGB;
1054 
1055                         const SFVEC3F& oriLT = blockPacket.m_ray[ iLT ].m_Origin;
1056                         const SFVEC3F& oriRB = blockPacket.m_ray[ iRB ].m_Origin;
1057 
1058                         const SFVEC3F& dirLT = blockPacket.m_ray[ iLT ].m_Dir;
1059                         const SFVEC3F& dirRB = blockPacket.m_ray[ iRB ].m_Dir;
1060 
1061                         SFVEC3F oriC;
1062                         SFVEC3F dirC;
1063 
1064                         HITINFO centerHitInfo;
1065                         centerHitInfo.m_tHit = std::numeric_limits<float>::infinity();
1066 
1067                         bool hittedC = false;
1068 
1069                         if( ( hitPacket[iLT].m_hitresult == true )
1070                           || ( hitPacket[iRT].m_hitresult == true )
1071                           || ( hitPacket[iLB].m_hitresult == true )
1072                           || ( hitPacket[iRB].m_hitresult == true ) )
1073                         {
1074                             oriC = ( oriLT + oriRB ) * 0.5f;
1075                             dirC = glm::normalize( ( dirLT + dirRB ) * 0.5f );
1076 
1077                             // Trace the center ray
1078                             RAY centerRay;
1079                             centerRay.Init( oriC, dirC );
1080 
1081                             const unsigned int nodeLT = hitPacket[ iLT ].m_HitInfo.m_acc_node_info;
1082                             const unsigned int nodeRT = hitPacket[ iRT ].m_HitInfo.m_acc_node_info;
1083                             const unsigned int nodeLB = hitPacket[ iLB ].m_HitInfo.m_acc_node_info;
1084                             const unsigned int nodeRB = hitPacket[ iRB ].m_HitInfo.m_acc_node_info;
1085 
1086                             if( nodeLT != 0 )
1087                                 hittedC |= m_accelerator->Intersect( centerRay, centerHitInfo,
1088                                                                      nodeLT );
1089 
1090                             if( ( nodeRT != 0 ) && ( nodeRT != nodeLT ) )
1091                                 hittedC |= m_accelerator->Intersect( centerRay, centerHitInfo,
1092                                                                      nodeRT );
1093 
1094                             if( ( nodeLB != 0 ) && ( nodeLB != nodeLT ) && ( nodeLB != nodeRT ) )
1095                                 hittedC |= m_accelerator->Intersect( centerRay, centerHitInfo,
1096                                                                      nodeLB );
1097 
1098                             if( ( nodeRB != 0 ) && ( nodeRB != nodeLB ) && ( nodeRB != nodeLT )
1099                               && ( nodeRB != nodeRT ) )
1100                                 hittedC |= m_accelerator->Intersect( centerRay, centerHitInfo,
1101                                                                      nodeRB );
1102 
1103                             if( hittedC )
1104                             {
1105                                 cC = COLOR_RGB( shadeHit( bgColorY, centerRay, centerHitInfo,
1106                                                           false, 0, false ) );
1107                             }
1108                             else
1109                             {
1110                                 centerHitInfo.m_tHit = std::numeric_limits<float>::infinity();
1111                                 hittedC = m_accelerator->Intersect( centerRay, centerHitInfo );
1112 
1113                                 if( hittedC )
1114                                     cC = COLOR_RGB( shadeHit( bgColorY, centerRay, centerHitInfo,
1115                                                               false, 0, false ) );
1116                             }
1117                         }
1118 
1119                         // Trace and shade cLRT
1120                         COLOR_RGB cLRT = bgColorYRGB;
1121 
1122                         const SFVEC3F& oriRT = blockPacket.m_ray[ iRT ].m_Origin;
1123                         const SFVEC3F& dirRT = blockPacket.m_ray[ iRT ].m_Dir;
1124 
1125                         if( y == 0 )
1126                         {
1127                             // Trace the center ray
1128                             RAY rayLRT;
1129                             rayLRT.Init( ( oriLT + oriRT ) * 0.5f,
1130                                          glm::normalize( ( dirLT + dirRT ) * 0.5f ) );
1131 
1132                             HITINFO hitInfoLRT;
1133                             hitInfoLRT.m_tHit = std::numeric_limits<float>::infinity();
1134 
1135                             if( hitPacket[iLT].m_hitresult && hitPacket[iRT].m_hitresult
1136                                 && ( hitPacket[iLT].m_HitInfo.pHitObject
1137                                      == hitPacket[iRT].m_HitInfo.pHitObject ) )
1138                             {
1139                                 hitInfoLRT.pHitObject = hitPacket[ iLT ].m_HitInfo.pHitObject;
1140                                 hitInfoLRT.m_tHit = ( hitPacket[ iLT ].m_HitInfo.m_tHit +
1141                                                       hitPacket[ iRT ].m_HitInfo.m_tHit ) * 0.5f;
1142                                 hitInfoLRT.m_HitNormal =
1143                                         glm::normalize( ( hitPacket[ iLT ].m_HitInfo.m_HitNormal +
1144                                                           hitPacket[ iRT ].m_HitInfo.m_HitNormal ) * 0.5f );
1145 
1146                                 cLRT = COLOR_RGB( shadeHit( bgColorY, rayLRT, hitInfoLRT, false,
1147                                                             0, false ) );
1148                                 cLRT = BlendColor( cLRT, BlendColor( cLT, cRT ) );
1149                             }
1150                             else
1151                             {
1152                                 // If any hits
1153                                 if( hitPacket[ iLT ].m_hitresult || hitPacket[ iRT ].m_hitresult )
1154                                 {
1155                                     const unsigned int nodeLT =
1156                                             hitPacket[ iLT ].m_HitInfo.m_acc_node_info;
1157                                     const unsigned int nodeRT =
1158                                             hitPacket[ iRT ].m_HitInfo.m_acc_node_info;
1159 
1160                                     bool hittedLRT = false;
1161 
1162                                     if( nodeLT != 0 )
1163                                         hittedLRT |= m_accelerator->Intersect( rayLRT, hitInfoLRT,
1164                                                                                nodeLT );
1165 
1166                                     if( ( nodeRT != 0 ) && ( nodeRT != nodeLT ) )
1167                                         hittedLRT |= m_accelerator->Intersect( rayLRT, hitInfoLRT,
1168                                                                                nodeRT );
1169 
1170                                     if( hittedLRT )
1171                                         cLRT = COLOR_RGB( shadeHit( bgColorY, rayLRT, hitInfoLRT,
1172                                                                     false, 0, false ) );
1173                                     else
1174                                     {
1175                                         hitInfoLRT.m_tHit = std::numeric_limits<float>::infinity();
1176 
1177                                         if( m_accelerator->Intersect( rayLRT,hitInfoLRT ) )
1178                                             cLRT = COLOR_RGB( shadeHit( bgColorY, rayLRT,
1179                                                                         hitInfoLRT, false,
1180                                                                         0, false ) );
1181                                     }
1182                                 }
1183                             }
1184                         }
1185                         else
1186                         {
1187                             cLRT = cLRB_old[x];
1188                         }
1189 
1190                         // Trace and shade cLTB
1191                         COLOR_RGB cLTB = bgColorYRGB;
1192 
1193                         if( x == 0 )
1194                         {
1195                             const SFVEC3F &oriLB = blockPacket.m_ray[ iLB ].m_Origin;
1196                             const SFVEC3F& dirLB = blockPacket.m_ray[ iLB ].m_Dir;
1197 
1198                             // Trace the center ray
1199                             RAY rayLTB;
1200                             rayLTB.Init( ( oriLT + oriLB ) * 0.5f,
1201                                             glm::normalize( ( dirLT + dirLB ) * 0.5f ) );
1202 
1203                             HITINFO hitInfoLTB;
1204                             hitInfoLTB.m_tHit = std::numeric_limits<float>::infinity();
1205 
1206                             if( hitPacket[ iLT ].m_hitresult && hitPacket[ iLB ].m_hitresult
1207                               && ( hitPacket[ iLT ].m_HitInfo.pHitObject ==
1208                                    hitPacket[ iLB ].m_HitInfo.pHitObject ) )
1209                             {
1210                                 hitInfoLTB.pHitObject = hitPacket[ iLT ].m_HitInfo.pHitObject;
1211                                 hitInfoLTB.m_tHit = ( hitPacket[ iLT ].m_HitInfo.m_tHit +
1212                                                       hitPacket[ iLB ].m_HitInfo.m_tHit ) * 0.5f;
1213                                 hitInfoLTB.m_HitNormal =
1214                                         glm::normalize( ( hitPacket[ iLT ].m_HitInfo.m_HitNormal +
1215                                                           hitPacket[ iLB ].m_HitInfo.m_HitNormal ) * 0.5f );
1216                                 cLTB = COLOR_RGB( shadeHit( bgColorY, rayLTB, hitInfoLTB, false,
1217                                                             0, false ) );
1218                                 cLTB = BlendColor( cLTB, BlendColor( cLT, cLB) );
1219                             }
1220                             else
1221                             {
1222                                 // If any hits
1223                                 if( hitPacket[ iLT ].m_hitresult || hitPacket[ iLB ].m_hitresult )
1224                                 {
1225                                     const unsigned int nodeLT =
1226                                             hitPacket[ iLT ].m_HitInfo.m_acc_node_info;
1227                                     const unsigned int nodeLB =
1228                                             hitPacket[ iLB ].m_HitInfo.m_acc_node_info;
1229 
1230                                     bool hittedLTB = false;
1231 
1232                                     if( nodeLT != 0 )
1233                                         hittedLTB |= m_accelerator->Intersect( rayLTB, hitInfoLTB,
1234                                                                                nodeLT );
1235 
1236                                     if( ( nodeLB != 0 ) && ( nodeLB != nodeLT ) )
1237                                         hittedLTB |= m_accelerator->Intersect( rayLTB, hitInfoLTB,
1238                                                                                nodeLB );
1239 
1240                                     if( hittedLTB )
1241                                         cLTB = COLOR_RGB( shadeHit( bgColorY, rayLTB, hitInfoLTB,
1242                                                                     false, 0, false ) );
1243                                     else
1244                                     {
1245                                         hitInfoLTB.m_tHit = std::numeric_limits<float>::infinity();
1246 
1247                                         if( m_accelerator->Intersect( rayLTB, hitInfoLTB ) )
1248                                             cLTB = COLOR_RGB( shadeHit( bgColorY, rayLTB,
1249                                                                         hitInfoLTB, false,
1250                                                                         0, false ) );
1251                                     }
1252                                 }
1253                             }
1254                         }
1255                         else
1256                         {
1257                             cLTB = cRTB_old;
1258                         }
1259 
1260                         // Trace and shade cRTB
1261                         COLOR_RGB cRTB = bgColorYRGB;
1262 
1263                         // Trace the center ray
1264                         RAY rayRTB;
1265                         rayRTB.Init( ( oriRT + oriRB ) * 0.5f,
1266                                      glm::normalize( ( dirRT + dirRB ) * 0.5f ) );
1267 
1268                         HITINFO hitInfoRTB;
1269                         hitInfoRTB.m_tHit = std::numeric_limits<float>::infinity();
1270 
1271                         if( hitPacket[ iRT ].m_hitresult && hitPacket[ iRB ].m_hitresult
1272                           && ( hitPacket[ iRT ].m_HitInfo.pHitObject ==
1273                                hitPacket[ iRB ].m_HitInfo.pHitObject ) )
1274                         {
1275                             hitInfoRTB.pHitObject = hitPacket[ iRT ].m_HitInfo.pHitObject;
1276 
1277                             hitInfoRTB.m_tHit = ( hitPacket[ iRT ].m_HitInfo.m_tHit +
1278                                                   hitPacket[ iRB ].m_HitInfo.m_tHit ) * 0.5f;
1279 
1280                             hitInfoRTB.m_HitNormal =
1281                                     glm::normalize( ( hitPacket[ iRT ].m_HitInfo.m_HitNormal +
1282                                                       hitPacket[ iRB ].m_HitInfo.m_HitNormal ) * 0.5f );
1283 
1284                             cRTB = COLOR_RGB( shadeHit( bgColorY, rayRTB, hitInfoRTB, false, 0,
1285                                                         false ) );
1286                             cRTB = BlendColor( cRTB, BlendColor( cRT, cRB ) );
1287                         }
1288                         else
1289                         {
1290                             // If any hits
1291                             if( hitPacket[ iRT ].m_hitresult || hitPacket[ iRB ].m_hitresult )
1292                             {
1293                                 const unsigned int nodeRT =
1294                                         hitPacket[ iRT ].m_HitInfo.m_acc_node_info;
1295                                 const unsigned int nodeRB =
1296                                         hitPacket[ iRB ].m_HitInfo.m_acc_node_info;
1297 
1298                                 bool hittedRTB = false;
1299 
1300                                 if( nodeRT != 0 )
1301                                     hittedRTB |= m_accelerator->Intersect( rayRTB, hitInfoRTB,
1302                                                                            nodeRT );
1303 
1304                                 if( ( nodeRB != 0 ) && ( nodeRB != nodeRT ) )
1305                                     hittedRTB |= m_accelerator->Intersect( rayRTB, hitInfoRTB,
1306                                                                            nodeRB );
1307 
1308                                 if( hittedRTB )
1309                                 {
1310                                     cRTB = COLOR_RGB( shadeHit( bgColorY, rayRTB, hitInfoRTB,
1311                                                                 false, 0, false) );
1312                                 }
1313                                 else
1314                                 {
1315                                     hitInfoRTB.m_tHit = std::numeric_limits<float>::infinity();
1316 
1317                                     if( m_accelerator->Intersect( rayRTB, hitInfoRTB ) )
1318                                         cRTB = COLOR_RGB( shadeHit( bgColorY, rayRTB, hitInfoRTB,
1319                                                                     false, 0, false ) );
1320                                 }
1321                             }
1322                         }
1323 
1324                         cRTB_old = cRTB;
1325 
1326                         // Trace and shade cLRB
1327                         COLOR_RGB cLRB = bgColorYRGB;
1328 
1329                         const SFVEC3F& oriLB = blockPacket.m_ray[ iLB ].m_Origin;
1330                         const SFVEC3F& dirLB = blockPacket.m_ray[ iLB ].m_Dir;
1331 
1332                         // Trace the center ray
1333                         RAY rayLRB;
1334                         rayLRB.Init( ( oriLB + oriRB ) * 0.5f,
1335                                      glm::normalize( ( dirLB + dirRB ) * 0.5f ) );
1336 
1337                         HITINFO hitInfoLRB;
1338                         hitInfoLRB.m_tHit = std::numeric_limits<float>::infinity();
1339 
1340                         if( hitPacket[iLB].m_hitresult && hitPacket[iRB].m_hitresult
1341                             && ( hitPacket[iLB].m_HitInfo.pHitObject ==
1342                                  hitPacket[iRB].m_HitInfo.pHitObject ) )
1343                         {
1344                             hitInfoLRB.pHitObject = hitPacket[ iLB ].m_HitInfo.pHitObject;
1345 
1346                             hitInfoLRB.m_tHit = ( hitPacket[ iLB ].m_HitInfo.m_tHit +
1347                                                   hitPacket[ iRB ].m_HitInfo.m_tHit ) * 0.5f;
1348 
1349                             hitInfoLRB.m_HitNormal =
1350                                     glm::normalize( ( hitPacket[ iLB ].m_HitInfo.m_HitNormal +
1351                                                       hitPacket[ iRB ].m_HitInfo.m_HitNormal ) * 0.5f );
1352 
1353                             cLRB = COLOR_RGB( shadeHit( bgColorY, rayLRB, hitInfoLRB, false, 0,
1354                                                         false ) );
1355                             cLRB = BlendColor( cLRB, BlendColor( cLB, cRB ) );
1356                         }
1357                         else
1358                         {
1359                             // If any hits
1360                             if( hitPacket[ iLB ].m_hitresult || hitPacket[ iRB ].m_hitresult )
1361                             {
1362                                 const unsigned int nodeLB =
1363                                         hitPacket[ iLB ].m_HitInfo.m_acc_node_info;
1364                                 const unsigned int nodeRB =
1365                                         hitPacket[ iRB ].m_HitInfo.m_acc_node_info;
1366 
1367                                 bool hittedLRB = false;
1368 
1369                                 if( nodeLB != 0 )
1370                                     hittedLRB |= m_accelerator->Intersect( rayLRB, hitInfoLRB,
1371                                                                            nodeLB );
1372 
1373                                 if( ( nodeRB != 0 ) && ( nodeRB != nodeLB ) )
1374                                     hittedLRB |= m_accelerator->Intersect( rayLRB, hitInfoLRB,
1375                                                                            nodeRB );
1376 
1377                                 if( hittedLRB )
1378                                 {
1379                                     cLRB = COLOR_RGB( shadeHit( bgColorY, rayLRB, hitInfoLRB,
1380                                                                 false, 0, false ) );
1381                                 }
1382                                 else
1383                                 {
1384                                     hitInfoLRB.m_tHit = std::numeric_limits<float>::infinity();
1385 
1386                                     if( m_accelerator->Intersect( rayLRB, hitInfoLRB ) )
1387                                         cLRB = COLOR_RGB( shadeHit( bgColorY, rayLRB, hitInfoLRB,
1388                                                                     false, 0, false ) );
1389                                 }
1390                             }
1391                         }
1392 
1393                         cLRB_old[x] = cLRB;
1394 
1395                         // Trace and shade cLTC
1396                         COLOR_RGB cLTC = BlendColor( cLT , cC );
1397 
1398                         if( hitPacket[ iLT ].m_hitresult || hittedC )
1399                         {
1400                             // Trace the center ray
1401                             RAY rayLTC;
1402                             rayLTC.Init( ( oriLT + oriC ) * 0.5f,
1403                                          glm::normalize( ( dirLT + dirC ) * 0.5f ) );
1404 
1405                             HITINFO hitInfoLTC;
1406                             hitInfoLTC.m_tHit = std::numeric_limits<float>::infinity();
1407 
1408                             bool hitted = false;
1409 
1410                             if( hittedC )
1411                                 hitted = centerHitInfo.pHitObject->Intersect( rayLTC, hitInfoLTC );
1412                             else if( hitPacket[ iLT ].m_hitresult )
1413                                 hitted = hitPacket[ iLT ].m_HitInfo.pHitObject->Intersect(
1414                                         rayLTC,
1415                                         hitInfoLTC );
1416 
1417                             if( hitted )
1418                                 cLTC = COLOR_RGB( shadeHit( bgColorY, rayLTC, hitInfoLTC, false,
1419                                                             0, false ) );
1420                         }
1421 
1422                         // Trace and shade cRTC
1423                         COLOR_RGB cRTC = BlendColor( cRT , cC );
1424 
1425                         if( hitPacket[ iRT ].m_hitresult || hittedC )
1426                         {
1427                             // Trace the center ray
1428                             RAY rayRTC;
1429                             rayRTC.Init( ( oriRT + oriC ) * 0.5f,
1430                                          glm::normalize( ( dirRT + dirC ) * 0.5f ) );
1431 
1432                             HITINFO hitInfoRTC;
1433                             hitInfoRTC.m_tHit = std::numeric_limits<float>::infinity();
1434 
1435                             bool hitted = false;
1436 
1437                             if( hittedC )
1438                                 hitted = centerHitInfo.pHitObject->Intersect( rayRTC, hitInfoRTC );
1439                             else if( hitPacket[ iRT ].m_hitresult )
1440                                 hitted = hitPacket[ iRT ].m_HitInfo.pHitObject->Intersect( rayRTC,
1441                                                                                            hitInfoRTC );
1442 
1443                             if( hitted )
1444                                 cRTC = COLOR_RGB( shadeHit( bgColorY, rayRTC, hitInfoRTC, false,
1445                                                             0, false ) );
1446                         }
1447 
1448                         // Trace and shade cLBC
1449                         COLOR_RGB cLBC = BlendColor( cLB , cC );
1450 
1451                         if( hitPacket[ iLB ].m_hitresult || hittedC )
1452                         {
1453                             // Trace the center ray
1454                             RAY rayLBC;
1455                             rayLBC.Init( ( oriLB + oriC ) * 0.5f,
1456                                          glm::normalize( ( dirLB + dirC ) * 0.5f ) );
1457 
1458                             HITINFO hitInfoLBC;
1459                             hitInfoLBC.m_tHit = std::numeric_limits<float>::infinity();
1460 
1461                             bool hitted = false;
1462 
1463                             if( hittedC )
1464                                 hitted = centerHitInfo.pHitObject->Intersect( rayLBC, hitInfoLBC );
1465                             else if( hitPacket[ iLB ].m_hitresult )
1466                                 hitted = hitPacket[ iLB ].m_HitInfo.pHitObject->Intersect( rayLBC,
1467                                                                                            hitInfoLBC );
1468 
1469                             if( hitted )
1470                                 cLBC = COLOR_RGB( shadeHit( bgColorY, rayLBC, hitInfoLBC, false,
1471                                                             0, false ) );
1472                         }
1473 
1474                         // Trace and shade cRBC
1475                         COLOR_RGB cRBC = BlendColor( cRB , cC );
1476 
1477                         if( hitPacket[ iRB ].m_hitresult || hittedC )
1478                         {
1479                             // Trace the center ray
1480                             RAY rayRBC;
1481                             rayRBC.Init( ( oriRB + oriC ) * 0.5f,
1482                                          glm::normalize( ( dirRB + dirC ) * 0.5f ) );
1483 
1484                             HITINFO hitInfoRBC;
1485                             hitInfoRBC.m_tHit = std::numeric_limits<float>::infinity();
1486 
1487                             bool hitted = false;
1488 
1489                             if( hittedC )
1490                                 hitted = centerHitInfo.pHitObject->Intersect( rayRBC, hitInfoRBC );
1491                             else if( hitPacket[ iRB ].m_hitresult )
1492                                 hitted = hitPacket[ iRB ].m_HitInfo.pHitObject->Intersect( rayRBC,
1493                                                                                            hitInfoRBC );
1494 
1495                             if( hitted )
1496                                 cRBC = COLOR_RGB( shadeHit( bgColorY, rayRBC, hitInfoRBC, false,
1497                                                             0, false ) );
1498                         }
1499 
1500                         // Set pixel colors
1501                         GLubyte* ptr =
1502                                 &ptrPBO[( 4 * x + m_blockPositionsFast[iBlock].x
1503                                           + m_realBufferSize.x
1504                                           * ( m_blockPositionsFast[iBlock].y + 4 * y ) ) * 4];
1505                         SetPixel( ptr + 0, cLT );
1506                         SetPixel( ptr +  4, BlendColor( cLT, cLRT, cLTC ) );
1507                         SetPixel( ptr +  8, cLRT );
1508                         SetPixel( ptr + 12, BlendColor( cLRT, cRT, cRTC ) );
1509 
1510                         ptr += m_realBufferSize.x * 4;
1511                         SetPixel( ptr +  0, BlendColor( cLT , cLTB, cLTC ) );
1512                         SetPixel( ptr +  4, BlendColor( cLTC, BlendColor( cLT , cC ) ) );
1513                         SetPixel( ptr +  8, BlendColor( cC, BlendColor( cLRT, cLTC, cRTC ) ) );
1514                         SetPixel( ptr + 12, BlendColor( cRTC, BlendColor( cRT , cC ) ) );
1515 
1516                         ptr += m_realBufferSize.x * 4;
1517                         SetPixel( ptr +  0, cLTB );
1518                         SetPixel( ptr +  4, BlendColor( cC, BlendColor( cLTB, cLTC, cLBC ) ) );
1519                         SetPixel( ptr +  8, cC );
1520                         SetPixel( ptr + 12, BlendColor( cC, BlendColor( cRTB, cRTC, cRBC ) ) );
1521 
1522                         ptr += m_realBufferSize.x * 4;
1523                         SetPixel( ptr +  0, BlendColor( cLB , cLTB, cLBC ) );
1524                         SetPixel( ptr +  4, BlendColor( cLBC, BlendColor( cLB , cC ) ) );
1525                         SetPixel( ptr +  8, BlendColor( cC, BlendColor( cLRB, cLBC, cRBC ) ) );
1526                         SetPixel( ptr + 12, BlendColor( cRBC, BlendColor( cRB , cC ) ) );
1527                     }
1528                 }
1529             }
1530 
1531             threadsFinished++;
1532         } );
1533 
1534         t.detach();
1535     }
1536 
1537     while( threadsFinished < parallelThreadCount )
1538         std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
1539 }
1540 
1541 
1542 #define USE_EXPERIMENTAL_SOFT_SHADOWS 1
1543 
shadeHit(const SFVEC3F & aBgColor,const RAY & aRay,HITINFO & aHitInfo,bool aIsInsideObject,unsigned int aRecursiveLevel,bool is_testShadow) const1544 SFVEC3F RENDER_3D_RAYTRACE::shadeHit( const SFVEC3F& aBgColor, const RAY& aRay, HITINFO& aHitInfo,
1545                                       bool aIsInsideObject, unsigned int aRecursiveLevel,
1546                                       bool is_testShadow ) const
1547 {
1548     const MATERIAL* objMaterial = aHitInfo.pHitObject->GetMaterial();
1549     wxASSERT( objMaterial != nullptr );
1550 
1551     SFVEC3F outColor = objMaterial->GetEmissiveColor() + objMaterial->GetAmbientColor();
1552 
1553     if( aRecursiveLevel > 7 )
1554         return outColor;
1555 
1556     SFVEC3F hitPoint = aHitInfo.m_HitPoint;
1557 
1558     hitPoint += aHitInfo.m_HitNormal * m_boardAdapter.GetNonCopperLayerThickness() * 0.6f;
1559 
1560     const SFVEC3F diffuseColorObj = aHitInfo.pHitObject->GetDiffuseColor( aHitInfo );
1561 
1562 #if USE_EXPERIMENTAL_SOFT_SHADOWS
1563     const bool is_aa_enabled = m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_ANTI_ALIASING ) &&
1564                                (!m_isPreview);
1565 #endif
1566 
1567     float shadow_att_factor_sum = 0.0f;
1568 
1569     unsigned int nr_lights_that_can_cast_shadows = 0;
1570 
1571     for( const LIGHT* light : m_lights )
1572     {
1573         SFVEC3F vectorToLight;
1574         SFVEC3F colorOfLight;
1575         float   distToLight;
1576 
1577         light->GetLightParameters( hitPoint, vectorToLight, colorOfLight, distToLight );
1578 
1579         if( m_isPreview )
1580             colorOfLight = SFVEC3F( 1.0f );
1581 
1582         const float NdotL = glm::dot( aHitInfo.m_HitNormal, vectorToLight );
1583 
1584         // Only calc shade if the normal is facing the direction of light,
1585         // otherwise it is in the shadow
1586         if( NdotL >= FLT_EPSILON )
1587         {
1588             float shadow_att_factor_light = 1.0f;
1589 
1590             if( is_testShadow && light->GetCastShadows() )
1591             {
1592                 nr_lights_that_can_cast_shadows++;
1593 #if USE_EXPERIMENTAL_SOFT_SHADOWS
1594                 // For rays that are recursive, just calculate one hit shadow
1595                 if( aRecursiveLevel > 0 )
1596                 {
1597 #endif
1598                     RAY rayToLight;
1599                     rayToLight.Init( hitPoint, vectorToLight );
1600 
1601                     // Test if point is not in the shadow.
1602                     // Test for any hit from the point in the direction of light
1603                     if( m_accelerator->IntersectP( rayToLight, distToLight ) )
1604                         shadow_att_factor_light = 0.0f;
1605 
1606 #if USE_EXPERIMENTAL_SOFT_SHADOWS
1607                 }
1608                 else  // Experimental softshadow calculation
1609                 {
1610 
1611                     const unsigned int shadow_number_of_samples =
1612                             m_boardAdapter.m_RtShadowSampleCount;
1613                     const float shadow_inc_factor = 1.0f / (float) ( shadow_number_of_samples );
1614 
1615                     for( unsigned int i = 0; i < shadow_number_of_samples; ++i )
1616                     {
1617                         RAY rayToLight;
1618 
1619                         if( i == 0 )
1620                         {
1621                             rayToLight.Init( hitPoint, vectorToLight );
1622                         }
1623                         else
1624                         {
1625                             const SFVEC3F unifVector = UniformRandomHemisphereDirection();
1626                             const SFVEC3F disturbed_vector_to_light =
1627                                     glm::normalize( vectorToLight + unifVector *
1628                                                     m_boardAdapter.m_RtSpreadShadows );
1629 
1630                             rayToLight.Init( hitPoint, disturbed_vector_to_light );
1631                         }
1632 
1633                         // !TODO: there are multiple ways that this tests can be
1634                         // optimized. Eg: by packing rays or to test against the
1635                         // latest hit object.
1636                         if( m_accelerator->IntersectP( rayToLight, distToLight ) )
1637                         {
1638                             shadow_att_factor_light -= shadow_inc_factor;
1639                         }
1640                     }
1641                 }
1642 #endif
1643                 shadow_att_factor_sum += shadow_att_factor_light;
1644             }
1645 
1646             outColor += objMaterial->Shade( aRay, aHitInfo, NdotL, diffuseColorObj, vectorToLight,
1647                                             colorOfLight, shadow_att_factor_light );
1648         }
1649 
1650         // Only use the headlight for preview
1651         if( m_isPreview )
1652             break;
1653     }
1654 
1655     // Improvement: this is not taking in account the lightcolor
1656     if( nr_lights_that_can_cast_shadows > 0 )
1657     {
1658         aHitInfo.m_ShadowFactor = glm::max(
1659                 shadow_att_factor_sum / (float) ( nr_lights_that_can_cast_shadows * 1.0f ), 0.0f );
1660     }
1661     else
1662     {
1663         aHitInfo.m_ShadowFactor = 1.0f;
1664     }
1665 
1666     // Clamp color to not be brighter than 1.0f
1667     outColor = glm::min( outColor, SFVEC3F( 1.0f ) );
1668 
1669     if( !m_isPreview )
1670     {
1671         // Reflections
1672         if( ( objMaterial->GetReflection() > 0.0f )
1673           && m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_REFLECTIONS )
1674           && ( aRecursiveLevel < objMaterial->GetReflectionRecursionCount() ) )
1675         {
1676             const unsigned int reflection_number_of_samples =
1677                     objMaterial->GetReflectionRayCount();
1678 
1679             SFVEC3F sum_color = SFVEC3F( 0.0f );
1680 
1681             const SFVEC3F reflectVector = aRay.m_Dir - 2.0f *
1682                     glm::dot( aRay.m_Dir, aHitInfo.m_HitNormal ) * aHitInfo.m_HitNormal;
1683 
1684             for( unsigned int i = 0; i < reflection_number_of_samples; ++i )
1685             {
1686                 RAY reflectedRay;
1687 
1688                 if( i == 0 )
1689                 {
1690                     reflectedRay.Init( hitPoint, reflectVector );
1691                 }
1692                 else
1693                 {
1694                     // Apply some randomize to the reflected vector
1695                     const SFVEC3F random_reflectVector =
1696                             glm::normalize( reflectVector +
1697                                             UniformRandomHemisphereDirection() *
1698                                             m_boardAdapter.m_RtSpreadReflections );
1699 
1700                     reflectedRay.Init( hitPoint, random_reflectVector );
1701                 }
1702 
1703                 HITINFO reflectedHit;
1704                 reflectedHit.m_tHit = std::numeric_limits<float>::infinity();
1705 
1706                 if( m_accelerator->Intersect( reflectedRay, reflectedHit ) )
1707                 {
1708                     sum_color += ( diffuseColorObj + objMaterial->GetSpecularColor() ) *
1709                                  shadeHit( aBgColor, reflectedRay, reflectedHit, false,
1710                                            aRecursiveLevel + 1, is_testShadow ) *
1711                                  SFVEC3F( objMaterial->GetReflection() *
1712                                           // Falloff factor
1713                                           (1.0f / ( 1.0f + 0.75f * reflectedHit.m_tHit *
1714                                                     reflectedHit.m_tHit) ) );
1715                 }
1716             }
1717 
1718             outColor += (sum_color / SFVEC3F( (float)reflection_number_of_samples) );
1719         }
1720 
1721         // Refraction
1722         const float objTransparency = aHitInfo.pHitObject->GetModelTransparency();
1723 
1724         if( ( objTransparency > 0.0f ) && m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_REFRACTIONS )
1725           && ( aRecursiveLevel < objMaterial->GetRefractionRecursionCount() ) )
1726         {
1727             const float airIndex = 1.000293f;
1728             const float glassIndex = 1.49f;
1729             const float air_over_glass = airIndex / glassIndex;
1730             const float glass_over_air = glassIndex / airIndex;
1731 
1732             const float refractionRatio = aIsInsideObject?glass_over_air:air_over_glass;
1733 
1734             SFVEC3F refractedVector;
1735 
1736             if( Refract( aRay.m_Dir, aHitInfo.m_HitNormal, refractionRatio, refractedVector ) )
1737             {
1738                 // This increase the start point by a "fixed" factor so it will work the
1739                 // same for all distances
1740                 const SFVEC3F startPoint =
1741                         aRay.at( aHitInfo.m_tHit + m_boardAdapter.GetNonCopperLayerThickness() *
1742                                  0.25f );
1743 
1744                 const unsigned int refractions_number_of_samples =
1745                         objMaterial->GetRefractionRayCount();
1746 
1747                 SFVEC3F sum_color = SFVEC3F(0.0f);
1748 
1749                 for( unsigned int i = 0; i < refractions_number_of_samples; ++i )
1750                 {
1751                     RAY refractedRay;
1752 
1753                     if( i == 0 )
1754                     {
1755                         refractedRay.Init( startPoint, refractedVector );
1756                     }
1757                     else
1758                     {
1759                         // apply some randomize to the refracted vector
1760                         const SFVEC3F randomizeRefractedVector =
1761                                 glm::normalize( refractedVector +
1762                                                 UniformRandomHemisphereDirection() *
1763                                                 m_boardAdapter.m_RtSpreadRefractions );
1764 
1765                         refractedRay.Init( startPoint, randomizeRefractedVector );
1766                     }
1767 
1768                     HITINFO refractedHit;
1769                     refractedHit.m_tHit = std::numeric_limits<float>::infinity();
1770 
1771                     SFVEC3F refractedColor = aBgColor;
1772 
1773                     if( m_accelerator->Intersect( refractedRay, refractedHit ) )
1774                     {
1775                         refractedColor = shadeHit( aBgColor, refractedRay, refractedHit,
1776                                                    !aIsInsideObject, aRecursiveLevel + 1, false );
1777 
1778                         const SFVEC3F absorbance = ( SFVEC3F(1.0f) - diffuseColorObj ) *
1779                                                    (1.0f - objTransparency ) *
1780                                                    objMaterial->GetAbsorvance() *
1781                                                    refractedHit.m_tHit;
1782 
1783                         const SFVEC3F transparency = 1.0f / ( absorbance + 1.0f );
1784 
1785                         sum_color += refractedColor * transparency;
1786                     }
1787                     else
1788                     {
1789                         sum_color += refractedColor;
1790                     }
1791                 }
1792 
1793                 outColor = outColor * ( 1.0f - objTransparency ) + objTransparency * sum_color
1794                          / SFVEC3F( (float) refractions_number_of_samples );
1795             }
1796             else
1797             {
1798                 outColor = outColor * ( 1.0f - objTransparency ) + objTransparency * aBgColor;
1799             }
1800         }
1801     }
1802 
1803     return outColor;
1804 }
1805 
1806 
initializeNewWindowSize()1807 void RENDER_3D_RAYTRACE::initializeNewWindowSize()
1808 {
1809     initPbo();
1810 }
1811 
1812 
initPbo()1813 void RENDER_3D_RAYTRACE::initPbo()
1814 {
1815     if( GLEW_ARB_pixel_buffer_object )
1816     {
1817         m_openglSupportsVertexBufferObjects = true;
1818 
1819         // Try to delete vbo if it was already initialized
1820         deletePbo();
1821 
1822         // Learn about Pixel buffer objects at:
1823         // http://www.songho.ca/opengl/gl_pbo.html
1824         // http://web.eecs.umich.edu/~sugih/courses/eecs487/lectures/25-PBO+Mipmapping.pdf
1825         // "create 2 pixel buffer objects, you need to delete them when program exits.
1826         // glBufferDataARB with NULL pointer reserves only memory space."
1827 
1828         // This sets the number of RGBA pixels
1829         m_pboDataSize =  m_realBufferSize.x * m_realBufferSize.y * 4;
1830 
1831         glGenBuffersARB( 1, &m_pboId );
1832         glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboId );
1833         glBufferDataARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboDataSize, 0, GL_STREAM_DRAW_ARB );
1834         glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, 0 );
1835 
1836         wxLogTrace( m_logTrace,
1837                     wxT( "RENDER_3D_RAYTRACE:: GLEW_ARB_pixel_buffer_object is supported" ) );
1838     }
1839 }
1840 
1841 
initializeOpenGL()1842 bool RENDER_3D_RAYTRACE::initializeOpenGL()
1843 {
1844     m_is_opengl_initialized = true;
1845 
1846     return true;
1847 }
1848 
1849 
distance(const SFVEC2UI & a,const SFVEC2UI & b)1850 static float distance( const SFVEC2UI& a, const SFVEC2UI& b )
1851 {
1852     const float dx = (float) a.x - (float) b.x;
1853     const float dy = (float) a.y - (float) b.y;
1854     return hypotf( dx, dy );
1855 }
1856 
1857 
initializeBlockPositions()1858 void RENDER_3D_RAYTRACE::initializeBlockPositions()
1859 {
1860     m_realBufferSize = SFVEC2UI( 0 );
1861 
1862     // Calc block positions for fast preview mode
1863     m_blockPositionsFast.clear();
1864 
1865     unsigned int i = 0;
1866 
1867     while(1)
1868     {
1869         const unsigned int mX = DecodeMorton2X(i);
1870         const unsigned int mY = DecodeMorton2Y(i);
1871 
1872         i++;
1873 
1874         const SFVEC2UI blockPos( mX * 4 * RAYPACKET_DIM - mX * 4,
1875                                  mY * 4 * RAYPACKET_DIM - mY * 4 );
1876 
1877         if( ( blockPos.x >= ( (unsigned int)m_windowSize.x - ( 4 * RAYPACKET_DIM + 4 ) ) ) &&
1878             ( blockPos.y >= ( (unsigned int)m_windowSize.y - ( 4 * RAYPACKET_DIM + 4 ) ) ) )
1879             break;
1880 
1881         if( ( blockPos.x < ( (unsigned int)m_windowSize.x - ( 4 * RAYPACKET_DIM + 4 ) ) ) &&
1882             ( blockPos.y < ( (unsigned int)m_windowSize.y - ( 4 * RAYPACKET_DIM + 4 ) ) ) )
1883         {
1884             m_blockPositionsFast.push_back( blockPos );
1885 
1886             if( blockPos.x > m_realBufferSize.x )
1887                 m_realBufferSize.x = blockPos.x;
1888 
1889             if( blockPos.y > m_realBufferSize.y )
1890                 m_realBufferSize.y = blockPos.y;
1891         }
1892     }
1893 
1894     m_fastPreviewModeSize = m_realBufferSize;
1895 
1896     m_realBufferSize.x = ( ( m_realBufferSize.x + RAYPACKET_DIM * 4 ) & RAYPACKET_INVMASK );
1897     m_realBufferSize.y = ( ( m_realBufferSize.y + RAYPACKET_DIM * 4 ) & RAYPACKET_INVMASK );
1898 
1899     m_xoffset = ( m_windowSize.x - m_realBufferSize.x ) / 2;
1900     m_yoffset = ( m_windowSize.y - m_realBufferSize.y ) / 2;
1901 
1902     m_postShaderSsao.UpdateSize( m_realBufferSize );
1903 
1904     // Calc block positions for regular rendering. Choose an 'inside out' style of rendering.
1905     m_blockPositions.clear();
1906     const int blocks_x = m_realBufferSize.x / RAYPACKET_DIM;
1907     const int blocks_y = m_realBufferSize.y / RAYPACKET_DIM;
1908     m_blockPositions.reserve( blocks_x * blocks_y );
1909 
1910     for( int x = 0; x < blocks_x; ++x )
1911     {
1912         for( int y = 0; y < blocks_y; ++y )
1913             m_blockPositions.emplace_back( x * RAYPACKET_DIM, y * RAYPACKET_DIM );
1914     }
1915 
1916     const SFVEC2UI center( m_realBufferSize.x / 2, m_realBufferSize.y / 2 );
1917     std::sort( m_blockPositions.begin(), m_blockPositions.end(),
1918             [&]( const SFVEC2UI& a, const SFVEC2UI& b ) {
1919                 // Sort order: inside out.
1920                 return distance( a, center ) < distance( b, center );
1921             } );
1922 
1923     // Create m_shader buffer
1924     delete[] m_shaderBuffer;
1925     m_shaderBuffer = new SFVEC3F[m_realBufferSize.x * m_realBufferSize.y];
1926 
1927     initPbo();
1928 }
1929 
1930 
IntersectBoardItem(const RAY & aRay)1931 BOARD_ITEM* RENDER_3D_RAYTRACE::IntersectBoardItem( const RAY& aRay )
1932 {
1933     HITINFO hitInfo;
1934     hitInfo.m_tHit = std::numeric_limits<float>::infinity();
1935 
1936     if( m_accelerator )
1937     {
1938         if( m_accelerator->Intersect( aRay, hitInfo ) )
1939         {
1940             if( hitInfo.pHitObject )
1941                 return hitInfo.pHitObject->GetBoardItem();
1942         }
1943     }
1944 
1945     return nullptr;
1946 }
1947