"Fossies" - the Fresh Open Source Software Archive

Member "aqsis-1.8.2/libs/shadervm/shaderexecenv/shadeops_illum.cpp" (24 Aug 2012, 38869 Bytes) of package /linux/privat/aqsis-1.8.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 // Aqsis
    2 // Copyright (C) 1997 - 2001, Paul C. Gregory
    3 //
    4 // Contact: pgregory@aqsis.org
    5 //
    6 // This library is free software; you can redistribute it and/or
    7 // modify it under the terms of the GNU General Public
    8 // License as published by the Free Software Foundation; either
    9 // version 2 of the License, or (at your option) any later version.
   10 //
   11 // This library is distributed in the hope that it will be useful,
   12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
   13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   14 // General Public License for more details.
   15 //
   16 // You should have received a copy of the GNU General Public
   17 // License along with this library; if not, write to the Free Software
   18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   19 
   20 
   21 /** \file
   22         \brief Implements the basic shader operations. (Lights related)
   23         \author Paul C. Gregory (pgregory@aqsis.org)
   24 */
   25 
   26 
   27 #include    <string>
   28 #include    <stdio.h>
   29 
   30 #include    <aqsis/math/math.h>
   31 #include    "shaderexecenv.h"
   32 #include    <aqsis/core/ilightsource.h>
   33 
   34 #include    "../../pointrender/microbuffer.h"
   35 
   36 namespace Aqsis {
   37 
   38 //----------------------------------------------------------------------
   39 // init_illuminance()
   40 // NOTE: There is duplication here between SO_init_illuminance and 
   41 // SO_advance_illuminance. This is required to ensure that the 
   42 // first light is not skipped.
   43 bool CqShaderExecEnv::SO_init_illuminance()
   44 {
   45     // Check if lighting is turned off.
   46     if(getRenderContext())
   47     {
   48         const TqInt* enableLightingOpt = getRenderContext()->GetIntegerOption("EnableShaders", "lighting");
   49         if(NULL != enableLightingOpt && enableLightingOpt[0] == 0)
   50             return(false);
   51     }
   52 
   53     m_li = 0;
   54     while ( m_li < m_pAttributes ->cLights() &&
   55             m_pAttributes ->pLight( m_li ) ->pShader() ->fAmbient() )
   56     {
   57         m_li++;
   58     }
   59     if ( m_li < m_pAttributes ->cLights() )
   60         return ( true );
   61     else
   62         return ( false );
   63 }
   64 
   65 
   66 //----------------------------------------------------------------------
   67 // advance_illuminance()
   68 bool CqShaderExecEnv::SO_advance_illuminance()
   69 {
   70     // Check if lighting is turned off, should never need this check as SO_init_illuminance will catch first.
   71     if(getRenderContext())
   72     {
   73         const TqInt* enableLightingOpt = getRenderContext()->GetIntegerOption("EnableShaders", "lighting");
   74         if(NULL != enableLightingOpt && enableLightingOpt[0] == 0)
   75             return(false);
   76     }
   77 
   78     m_li++;
   79     while ( m_li < m_pAttributes ->cLights() &&
   80             m_pAttributes ->pLight( m_li ) ->pShader() ->fAmbient() )
   81     {
   82         m_li++;
   83     }
   84     if ( m_li < m_pAttributes ->cLights() )
   85         return ( true );
   86     else
   87         return ( false );
   88 }
   89 
   90 
   91 //----------------------------------------------------------------------
   92 // init_gather()
   93 void CqShaderExecEnv::SO_init_gather(IqShaderData* samples, IqShader* pShader)
   94 {
   95     bool __fVarying;
   96     TqUint __iGrid = 0;
   97 
   98     __fVarying=(samples)->Class()==class_varying;
   99 
  100     TqFloat _aq_samples;
  101     (samples)->GetFloat(_aq_samples,__iGrid);
  102 
  103     // Check if lighting is turned off.
  104     if(getRenderContext())
  105     {
  106         const TqInt* enableLightingOpt = getRenderContext()->GetIntegerOption("EnableShaders", "lighting");
  107         if(NULL != enableLightingOpt && enableLightingOpt[0] == 0)
  108             return;
  109     }
  110 
  111     m_gatherSample = static_cast<TqUint> (_aq_samples);
  112 }
  113 
  114 
  115 //----------------------------------------------------------------------
  116 // advance_illuminance()
  117 bool CqShaderExecEnv::SO_advance_gather()
  118 {
  119     // Check if lighting is turned off, should never need this check as SO_init_illuminance will catch first.
  120     if(getRenderContext())
  121     {
  122         const TqInt* enableLightingOpt = getRenderContext()->GetIntegerOption("EnableShaders", "lighting");
  123         if(NULL != enableLightingOpt && enableLightingOpt[0] == 0)
  124             return(false);
  125     }
  126 
  127     return((--m_gatherSample) > 0);
  128 }
  129 
  130 
  131 void CqShaderExecEnv::ValidateIlluminanceCache( IqShaderData* pP, IqShaderData* pN, IqShader* pShader )
  132 {
  133     // If this is the first call to illuminance this time round, call all lights and setup the Cl and L caches.
  134     if ( !m_IlluminanceCacheValid )
  135     {
  136         // Check if lighting is turned off.
  137         if(getRenderContext())
  138         {
  139             const TqInt* enableLightingOpt = getRenderContext()->GetIntegerOption("EnableShaders", "lighting");
  140             if(NULL != enableLightingOpt && enableLightingOpt[0] == 0)
  141             {
  142                 m_IlluminanceCacheValid = true;
  143                 return;
  144             }
  145         }
  146 
  147         IqShaderData* Ns = (pN != NULL )? pN : N();
  148         IqShaderData* Ps = (pP != NULL )? pP : P();
  149         TqUint li = 0;
  150         while ( li < m_pAttributes ->cLights() )
  151         {
  152             IqLightsource * lp = m_pAttributes ->pLight( li );
  153             // Initialise the lightsource
  154             lp->Initialise( uGridRes(), vGridRes(), microPolygonCount(), shadingPointCount(), m_hasValidDerivatives );
  155             m_Illuminate = 0;
  156             // Evaluate the lightsource
  157             lp->Evaluate( Ps, Ns, m_pCurrentSurface );
  158             li++;
  159         }
  160         m_IlluminanceCacheValid = true;
  161     }
  162 }
  163 
  164 //----------------------------------------------------------------------
  165 // reflect(I,N)
  166 void CqShaderExecEnv::SO_reflect( IqShaderData* I, IqShaderData* N, IqShaderData* Result, IqShader* pShader )
  167 {
  168     bool __fVarying;
  169     TqUint __iGrid;
  170 
  171     __fVarying=(I)->Class()==class_varying;
  172     __fVarying=(N)->Class()==class_varying||__fVarying;
  173     __fVarying=(Result)->Class()==class_varying||__fVarying;
  174 
  175     __iGrid = 0;
  176     const CqBitVector& RS = RunningState();
  177     do
  178     {
  179         if(!__fVarying || RS.Value( __iGrid ) )
  180         {
  181             CqVector3D _aq_I;
  182             (I)->GetVector(_aq_I,__iGrid);
  183             CqVector3D _aq_N;
  184             (N)->GetNormal(_aq_N,__iGrid);
  185             TqFloat idn = 2.0f * ( _aq_I * _aq_N );
  186             CqVector3D res = _aq_I - ( idn * _aq_N );
  187             (Result)->SetVector(res,__iGrid);
  188         }
  189     }
  190     while( ( ++__iGrid < shadingPointCount() ) && __fVarying);
  191 }
  192 
  193 
  194 //----------------------------------------------------------------------
  195 // reftact(I,N,eta)
  196 void CqShaderExecEnv::SO_refract( IqShaderData* I, IqShaderData* N, IqShaderData* eta, IqShaderData* Result, IqShader* pShader )
  197 {
  198     bool __fVarying;
  199     TqUint __iGrid;
  200 
  201     __fVarying=(I)->Class()==class_varying;
  202     __fVarying=(N)->Class()==class_varying||__fVarying;
  203     __fVarying=(eta)->Class()==class_varying||__fVarying;
  204     __fVarying=(Result)->Class()==class_varying||__fVarying;
  205 
  206     __iGrid = 0;
  207     const CqBitVector& RS = RunningState();
  208     do
  209     {
  210         if(!__fVarying || RS.Value( __iGrid ) )
  211         {
  212             CqVector3D _aq_I;
  213             (I)->GetVector(_aq_I,__iGrid);
  214             CqVector3D _aq_N;
  215             (N)->GetNormal(_aq_N,__iGrid);
  216             TqFloat _aq_eta;
  217             (eta)->GetFloat(_aq_eta,__iGrid);
  218             TqFloat IdotN = _aq_I * _aq_N;
  219             TqFloat feta = _aq_eta;
  220             TqFloat k = 1 - feta * feta * ( 1 - IdotN * IdotN );
  221             (Result)->SetVector(( k < 0.0f ) ? CqVector3D( 0, 0, 0 ) : CqVector3D( feta * _aq_I - ( feta * IdotN + sqrt( k ) ) * _aq_N ),__iGrid);
  222         }
  223     }
  224     while( ( ++__iGrid < shadingPointCount() ) && __fVarying);
  225 }
  226 
  227 
  228 //----------------------------------------------------------------------
  229 // fresnel(I,N,eta,Kr,Kt)
  230 
  231 void CqShaderExecEnv::SO_fresnel( IqShaderData* I, IqShaderData* N, IqShaderData* eta, IqShaderData* Kr, IqShaderData* Kt, IqShader* pShader )
  232 {
  233     bool __fVarying;
  234     TqUint __iGrid;
  235 
  236     __fVarying=(I)->Class()==class_varying;
  237     __fVarying=(N)->Class()==class_varying||__fVarying;
  238     __fVarying=(eta)->Class()==class_varying||__fVarying;
  239     __fVarying=(Kr)->Class()==class_varying||__fVarying;
  240     __fVarying=(Kt)->Class()==class_varying||__fVarying;
  241 
  242     __iGrid = 0;
  243     const CqBitVector& RS = RunningState();
  244     do
  245     {
  246         if(!__fVarying || RS.Value( __iGrid ) )
  247         {
  248             CqVector3D _aq_I;
  249             (I)->GetVector(_aq_I,__iGrid);
  250             CqVector3D _aq_N;
  251             (N)->GetNormal(_aq_N,__iGrid);
  252             TqFloat _aq_eta;
  253             (eta)->GetFloat(_aq_eta,__iGrid);
  254             TqFloat _aq_Kr;
  255             (Kr)->GetFloat(_aq_Kr,__iGrid);
  256             TqFloat _aq_Kt;
  257             (Kt)->GetFloat(_aq_Kt,__iGrid);
  258             TqFloat cos_theta = -_aq_I * _aq_N;
  259             TqFloat fuvA = ((1.0f / _aq_eta)*(1.0f / _aq_eta)) - ( 1.0f - ((cos_theta)*(cos_theta)) );
  260             TqFloat fuvB = fabs( fuvA );
  261             TqFloat fu2 = ( fuvA + fuvB ) / 2;
  262             TqFloat fv2 = ( -fuvA + fuvB ) / 2;
  263             TqFloat fv2sqrt = ( fv2 == 0.0f ) ? 0.0f : sqrt( fabs( fv2 ) );
  264             TqFloat fu2sqrt = ( fu2 == 0.0f ) ? 0.0f : sqrt( fabs( fu2 ) );
  265             TqFloat fperp2 = ( ((cos_theta - fu2sqrt)*(cos_theta - fu2sqrt)) + fv2 ) / ( ((cos_theta + fu2sqrt)*(cos_theta + fu2sqrt)) + fv2 );
  266             TqFloat feta = _aq_eta;
  267             TqFloat fpara2 = ( ((((1.0f / feta)*(1.0f / feta)) * cos_theta - fu2sqrt)*(((1.0f / feta)*(1.0f / feta)) * cos_theta - fu2sqrt)) + ((-fv2sqrt)*(-fv2sqrt)) ) /
  268                              ( ((((1.0f / feta)*(1.0f / feta)) * cos_theta + fu2sqrt)*(((1.0f / feta)*(1.0f / feta)) * cos_theta + fu2sqrt)) + ((fv2sqrt)*(fv2sqrt)) );
  269 
  270             TqFloat __Kr = 0.5f * ( fperp2 + fpara2 );
  271             (Kr)->SetFloat(__Kr,__iGrid);
  272             (Kt)->SetFloat(1.0f - __Kr,__iGrid);
  273         }
  274     }
  275     while( ( ++__iGrid < shadingPointCount() ) && __fVarying);
  276 }
  277 
  278 //----------------------------------------------------------------------
  279 // fresnel(I,N,eta,Kr,Kt,R,T)
  280 void CqShaderExecEnv::SO_fresnel( IqShaderData* I, IqShaderData* N, IqShaderData* eta, IqShaderData* Kr, IqShaderData* Kt, IqShaderData* R, IqShaderData* T, IqShader* pShader )
  281 {
  282     bool __fVarying;
  283     TqUint __iGrid;
  284 
  285     __fVarying=(I)->Class()==class_varying;
  286     __fVarying=(N)->Class()==class_varying||__fVarying;
  287     __fVarying=(eta)->Class()==class_varying||__fVarying;
  288     __fVarying=(Kr)->Class()==class_varying||__fVarying;
  289     __fVarying=(Kt)->Class()==class_varying||__fVarying;
  290     __fVarying=(R)->Class()==class_varying||__fVarying;
  291     __fVarying=(T)->Class()==class_varying||__fVarying;
  292 
  293     __iGrid = 0;
  294     const CqBitVector& RS = RunningState();
  295     do
  296     {
  297         if(!__fVarying || RS.Value( __iGrid ) )
  298         {
  299             CqVector3D _aq_I;
  300             (I)->GetVector(_aq_I,__iGrid);
  301             CqVector3D _aq_N;
  302             (N)->GetNormal(_aq_N,__iGrid);
  303             TqFloat _aq_eta;
  304             (eta)->GetFloat(_aq_eta,__iGrid);
  305             TqFloat _aq_Kr;
  306             (Kr)->GetFloat(_aq_Kr,__iGrid);
  307             TqFloat _aq_Kt;
  308             (Kt)->GetFloat(_aq_Kt,__iGrid);
  309             CqVector3D _aq_R;
  310             (R)->GetVector(_aq_R,__iGrid);
  311             CqVector3D _aq_T;
  312             (T)->GetVector(_aq_T,__iGrid);
  313             TqFloat cos_theta = -_aq_I * _aq_N;
  314             TqFloat fuvA = ((1.0f / _aq_eta)*(1.0f / _aq_eta)) - ( 1.0f - ((cos_theta)*(cos_theta)) );
  315             TqFloat fuvB = fabs( fuvA );
  316             TqFloat fu2 = ( fuvA + fuvB ) / 2;
  317             TqFloat fv2 = ( -fuvA + fuvB ) / 2;
  318             TqFloat feta = _aq_eta;
  319             TqFloat fv2sqrt = ( fv2 == 0.0f ) ? 0.0f : sqrt( fabs( fv2 ) );
  320             TqFloat fu2sqrt = ( fu2 == 0.0f ) ? 0.0f : sqrt( fabs( fu2 ) );
  321             TqFloat fperp2 = ( ((cos_theta - fu2sqrt)*(cos_theta - fu2sqrt)) + fv2 ) / ( ((cos_theta + fu2sqrt)*(cos_theta + fu2sqrt)) + fv2 );
  322             TqFloat fpara2 = ( ((((1.0f / feta)*(1.0f / feta)) * cos_theta - fu2sqrt)*(((1.0f / feta)*(1.0f / feta)) * cos_theta - fu2sqrt)) + ((-fv2sqrt)*(-fv2sqrt)) ) /
  323                              ( ((((1.0f / feta)*(1.0f / feta)) * cos_theta + fu2sqrt)*(((1.0f / feta)*(1.0f / feta)) * cos_theta + fu2sqrt)) + ((fv2sqrt)*(fv2sqrt)) );
  324             TqFloat __Kr = 0.5f * ( fperp2 + fpara2 );
  325             (Kr)->SetFloat(__Kr,__iGrid);
  326             (Kt)->SetFloat(1.0f - __Kr,__iGrid);
  327         }
  328     }
  329     while( ( ++__iGrid < shadingPointCount() ) && __fVarying);
  330 
  331     SO_reflect( I, N, R );
  332     SO_refract( I, N, eta, T );
  333 }
  334 
  335 
  336 //----------------------------------------------------------------------
  337 // depth(P)
  338 void CqShaderExecEnv::SO_depth( IqShaderData* p, IqShaderData* Result, IqShader* pShader )
  339 {
  340     bool __fVarying;
  341     TqUint __iGrid;
  342 
  343     if (!getRenderContext() )
  344         return ;
  345 
  346     __fVarying=(p)->Class()==class_varying;
  347     __fVarying=(Result)->Class()==class_varying||__fVarying;
  348 
  349     __iGrid = 0;
  350     const CqBitVector& RS = RunningState();
  351 
  352     TqFloat ClippingNear = getRenderContext() ->GetFloatOption( "System", "Clipping" ) [ 0 ] ;
  353     TqFloat ClippingFar = getRenderContext() ->GetFloatOption( "System", "Clipping" ) [ 1 ] ;
  354     TqFloat DeltaClipping = ClippingFar - ClippingNear;
  355 
  356     do
  357     {
  358         if(!__fVarying || RS.Value( __iGrid ) )
  359         {
  360             CqVector3D _aq_p;
  361             (p)->GetPoint(_aq_p,__iGrid);
  362             TqFloat d = _aq_p.z();
  363             d = ( d - ClippingNear)/DeltaClipping;
  364             (Result)->SetFloat(d,__iGrid);
  365         }
  366     }
  367     while( ( ++__iGrid < shadingPointCount() ) && __fVarying);
  368 }
  369 
  370 
  371 //----------------------------------------------------------------------
  372 // ambient()
  373 
  374 void CqShaderExecEnv::SO_ambient( IqShaderData* Result, IqShader* pShader )
  375 {
  376     bool __fVarying;
  377     TqUint __iGrid;
  378 
  379     // Check if lighting is turned off.
  380     if(getRenderContext())
  381     {
  382         const TqInt* enableLightingOpt = getRenderContext()->GetIntegerOption("EnableShaders", "lighting");
  383         if(NULL != enableLightingOpt && enableLightingOpt[0] == 0)
  384             return;
  385     }
  386 
  387     // Use the lightsource stack on the current surface
  388     if ( m_pAttributes != 0 )
  389     {
  390         // If this is the first call to illuminance this time round, call all lights and setup the Cl and L caches.
  391         if ( !m_IlluminanceCacheValid )
  392         {
  393             ValidateIlluminanceCache( NULL, NULL, pShader );
  394         }
  395 
  396         Result->SetColor( gColBlack );
  397 
  398         for ( TqUint light_index = 0; light_index < m_pAttributes ->cLights(); light_index++ )
  399         {
  400             __fVarying = true;
  401 
  402             IqLightsource* lp = m_pAttributes ->pLight( light_index );
  403             if ( lp->pShader() ->fAmbient() )
  404             {
  405                 __iGrid = 0;
  406                 const CqBitVector& RS = RunningState();
  407                 do
  408                 {
  409                     if(!__fVarying || RS.Value( __iGrid ) )
  410                     {
  411                         // Now Combine the color of all ambient lightsources.
  412                         CqColor _aq_Result;
  413                         (Result)->GetColor(_aq_Result,__iGrid);
  414                         CqColor colCl;
  415                         if ( NULL != lp->Cl() )
  416                             lp->Cl() ->GetColor( colCl, __iGrid );
  417                         (Result)->SetColor(_aq_Result + colCl,__iGrid);
  418 
  419                     }
  420                 }
  421                 while( ( ++__iGrid < shadingPointCount() ) && __fVarying);
  422             }
  423         }
  424     }
  425 }
  426 
  427 
  428 //----------------------------------------------------------------------
  429 // diffuse(N)
  430 void CqShaderExecEnv::SO_diffuse( IqShaderData* N, IqShaderData* Result, IqShader* pShader )
  431 {
  432     bool __fVarying;
  433     TqUint __iGrid;
  434 
  435     // If the illuminance cache is already OK, then we don't need to bother filling in the illuminance parameters.
  436     if ( !m_IlluminanceCacheValid )
  437     {
  438         ValidateIlluminanceCache( NULL, N, pShader );
  439     }
  440 
  441     IqShaderData* pDefAngle = pShader->CreateTemporaryStorage( type_float, class_uniform );
  442     if ( NULL == pDefAngle )
  443         return ;
  444 
  445     pDefAngle->SetFloat( M_PI_2 );
  446 
  447     Result->SetColor( gColBlack );
  448 
  449     __fVarying = true;
  450     IqShaderData* __nondiffuse = NULL;
  451     __nondiffuse = pShader->CreateTemporaryStorage( type_float, class_varying );
  452 
  453     // SO_init_illuminance returns TRUE if there are any non ambient ligthsources available.
  454     if ( SO_init_illuminance() )
  455     {
  456         boost::shared_ptr<IqShader> pLightsource;
  457         do
  458         {
  459             // Get the "__nondiffuse" setting from the current lightsource, if specified.
  460             TqFloat __nondiffuse_val;
  461             if ( m_li < m_pAttributes ->cLights() )
  462                 pLightsource = m_pAttributes ->pLight( m_li ) ->pShader();
  463             if ( pLightsource )
  464             {
  465                 pLightsource->GetVariableValue( "__nondiffuse", __nondiffuse );
  466                 /// \note: This is OK here, outside the BEGIN_VARYING_SECTION as, varying in terms of lightsources
  467                 /// is not valid.
  468                 if( NULL != __nondiffuse )
  469                 {
  470                     __nondiffuse->GetFloat( __nondiffuse_val, 0 );
  471                     if( __nondiffuse_val != 0.0f )
  472                         continue;
  473                 }
  474             }
  475 
  476             // SO_illuminance sets the current state to whether the lightsource illuminates the points or not.
  477             SO_illuminance( NULL, NULL, N, pDefAngle, NULL );
  478 
  479             PushState();
  480             GetCurrentState();
  481 
  482             __iGrid = 0;
  483             const CqBitVector& RS = RunningState();
  484             do
  485             {
  486                 if(!__fVarying || RS.Value( __iGrid ) )
  487                 {
  488 
  489                     // Get the light vector and color from the lightsource.
  490                     CqVector3D Ln;
  491                     L() ->GetVector( Ln, __iGrid );
  492                     Ln.Unit();
  493 
  494                     // Combine the light color into the result
  495                     CqColor _aq_Result;
  496                     (Result)->GetColor(_aq_Result,__iGrid);
  497                     CqVector3D _aq_N;
  498                     (N)->GetNormal(_aq_N,__iGrid);
  499                     CqColor colCl;
  500                     Cl() ->GetColor( colCl, __iGrid );
  501                     (Result)->SetColor(_aq_Result + colCl * ( Ln * _aq_N ),__iGrid);
  502 
  503                 }
  504             }
  505             while( ( ++__iGrid < shadingPointCount() ) && __fVarying);
  506             PopState();
  507             // SO_advance_illuminance returns TRUE if there are any more non ambient lightsources.
  508         }
  509         while ( SO_advance_illuminance() );
  510     }
  511     pShader->DeleteTemporaryStorage( __nondiffuse );
  512     pShader->DeleteTemporaryStorage( pDefAngle );
  513 }
  514 
  515 
  516 //----------------------------------------------------------------------
  517 // specular(N,V,roughness)
  518 void CqShaderExecEnv::SO_specular( IqShaderData* N, IqShaderData* V, IqShaderData* roughness, IqShaderData* Result, IqShader* pShader )
  519 {
  520     bool __fVarying;
  521     TqUint __iGrid;
  522 
  523     // If the illuminance cache is already OK, then we don't need to bother filling in the illuminance parameters.
  524     if ( !m_IlluminanceCacheValid )
  525     {
  526         ValidateIlluminanceCache( NULL, N, pShader );
  527     }
  528 
  529     IqShaderData* pDefAngle = pShader->CreateTemporaryStorage( type_float, class_uniform );
  530     if ( NULL == pDefAngle )
  531         return ;
  532 
  533     pDefAngle->SetFloat( M_PI_2 );
  534 
  535     Result->SetColor( gColBlack );
  536     __fVarying = true;
  537 
  538     IqShaderData* __nonspecular = NULL;
  539     __nonspecular = pShader->CreateTemporaryStorage( type_float, class_varying );
  540 
  541     // SO_init_illuminance returns TRUE if there are any non ambient ligthsources available.
  542     if ( SO_init_illuminance() )
  543     {
  544         boost::shared_ptr<IqShader> pLightsource;
  545         do
  546         {
  547             // Get the "__nonspecular" setting from the current lightsource, if specified.
  548             TqFloat __nonspecular_val;
  549             if ( m_li < m_pAttributes ->cLights() )
  550                 pLightsource = m_pAttributes ->pLight( m_li ) ->pShader();
  551             if ( pLightsource )
  552             {
  553                 pLightsource->GetVariableValue( "__nonspecular", __nonspecular );
  554                 /// \note: This is OK here, outside the BEGIN_VARYING_SECTION as, varying in terms of lightsources
  555                 /// is not valid.
  556                 if( NULL != __nonspecular )
  557                 {
  558                     __nonspecular->GetFloat( __nonspecular_val, 0 );
  559                     if( __nonspecular_val != 0.0f )
  560                         continue;
  561                 }
  562             }
  563 
  564             // SO_illuminance sets the current state to whether the lightsource illuminates the points or not.
  565             SO_illuminance( NULL, NULL, N, pDefAngle, NULL );
  566 
  567             PushState();
  568             GetCurrentState();
  569             __iGrid = 0;
  570             const CqBitVector& RS = RunningState();
  571             do
  572             {
  573                 if(!__fVarying || RS.Value( __iGrid ) )
  574                 {
  575 
  576                     CqVector3D _aq_V;
  577                     (V)->GetVector(_aq_V,__iGrid);
  578                     // Get the ligth vector and color from the lightsource
  579                     CqVector3D Ln;
  580                     L() ->GetVector( Ln, __iGrid );
  581                     Ln.Unit();
  582                     CqVector3D  H = Ln + _aq_V;
  583                     H.Unit();
  584 
  585                     // Combine the color into the result.
  586                     /// \note The (roughness/8) term emulates the BMRT behaviour for prmanspecular.
  587                     CqColor _aq_Result;
  588                     (Result)->GetColor(_aq_Result,__iGrid);
  589                     CqVector3D _aq_N;
  590                     (N)->GetNormal(_aq_N,__iGrid);
  591                     TqFloat _aq_roughness;
  592                     (roughness)->GetFloat(_aq_roughness,__iGrid);
  593                     CqColor colCl;
  594                     Cl() ->GetColor( colCl, __iGrid );
  595                     (Result)->SetColor(_aq_Result + colCl * pow( max( 0.0f, _aq_N * H ), 1.0f / ( _aq_roughness / 8.0f ) ),__iGrid);
  596 
  597                 }
  598             }
  599             while( ( ++__iGrid < shadingPointCount() ) && __fVarying);
  600             PopState();
  601             // SO_advance_illuminance returns TRUE if there are any more non ambient lightsources.
  602         }
  603         while ( SO_advance_illuminance() );
  604     }
  605     pShader->DeleteTemporaryStorage( __nonspecular );
  606     pShader->DeleteTemporaryStorage( pDefAngle );
  607 }
  608 
  609 
  610 //----------------------------------------------------------------------
  611 // phong(N,V,size)
  612 void CqShaderExecEnv::SO_phong( IqShaderData* N, IqShaderData* V, IqShaderData* size, IqShaderData* Result, IqShader* pShader )
  613 {
  614     bool __fVarying;
  615     TqUint __iGrid;
  616 
  617     IqShaderData * pnV = pShader ->CreateTemporaryStorage( type_vector, class_varying );
  618     IqShaderData* pnN = pShader ->CreateTemporaryStorage( type_normal, class_varying );
  619     IqShaderData* pR = pShader ->CreateTemporaryStorage( type_vector, class_varying );
  620 
  621     /// note: Not happy about this, the shader should take care of this at construction time,
  622     /// but at the moment, it can't guarantee the validity of the m_u/vGridRes data members.
  623     pnV->Initialise( shadingPointCount() );
  624     pnN->Initialise( shadingPointCount() );
  625     pR->Initialise( shadingPointCount() );
  626 
  627     SO_normalize( V, pnV );
  628     SO_normalize( N, pnN );
  629 
  630     __fVarying = true;
  631     __iGrid = 0;
  632     const CqBitVector& RS = RunningState();
  633     do
  634     {
  635         if(!__fVarying || RS.Value( __iGrid ) )
  636         {
  637             CqVector3D vecnV;
  638             pnV->GetVector( vecnV, __iGrid );
  639             pnV->SetVector( -vecnV, __iGrid );
  640         }
  641     }
  642     while( ( ++__iGrid < shadingPointCount() ) && __fVarying);
  643 
  644     SO_reflect( pnV, pnN, pR );
  645 
  646     pShader->DeleteTemporaryStorage( pnV );
  647     pShader->DeleteTemporaryStorage( pnN );
  648 
  649     // If the illuminance cache is already OK, then we don't need to bother filling in the illuminance parameters.
  650     if ( !m_IlluminanceCacheValid )
  651     {
  652         ValidateIlluminanceCache( NULL, N, pShader );
  653     }
  654 
  655     IqShaderData* pDefAngle = pShader->CreateTemporaryStorage( type_float, class_uniform );
  656     if ( NULL == pDefAngle )
  657         return ;
  658 
  659     pDefAngle->SetFloat( M_PI_2 );
  660 
  661     // Initialise the return value
  662     Result->SetColor( gColBlack );
  663 
  664     // SO_init_illuminance returns TRUE if there are any non ambient ligthsources available.
  665     if ( SO_init_illuminance() )
  666     {
  667         do
  668         {
  669             // SO_illuminance sets the current state to whether the lightsource illuminates the points or not.
  670             SO_illuminance( NULL, NULL, N, pDefAngle, NULL );
  671 
  672             PushState();
  673             GetCurrentState();
  674 
  675             __iGrid = 0;
  676             const CqBitVector& RS = RunningState();
  677             do
  678             {
  679                 if(!__fVarying || RS.Value( __iGrid ) )
  680                 {
  681 
  682                     // Get the light vector and color from the light source.
  683                     CqVector3D Ln;
  684                     L() ->GetVector( Ln, __iGrid );
  685                     Ln.Unit();
  686 
  687                     // Now combine the color into the result.
  688                     CqColor _aq_Result;
  689                     (Result)->GetColor(_aq_Result,__iGrid);
  690                     CqVector3D vecR;
  691                     pR->GetVector( vecR, __iGrid );
  692                     TqFloat _aq_size;
  693                     (size)->GetFloat(_aq_size,__iGrid);
  694                     CqColor colCl;
  695                     Cl() ->GetColor( colCl, __iGrid );
  696                     (Result)->SetColor(_aq_Result + colCl * pow( max( 0.0f, vecR * Ln ), _aq_size ),__iGrid);
  697 
  698                 }
  699             }
  700             while( ( ++__iGrid < shadingPointCount() ) && __fVarying);
  701 
  702             PopState();
  703             // SO_advance_illuminance returns TRUE if there are any more non ambient lightsources.
  704         }
  705         while ( SO_advance_illuminance() );
  706     }
  707     pShader->DeleteTemporaryStorage( pDefAngle );
  708     pShader->DeleteTemporaryStorage( pR );
  709 }
  710 
  711 
  712 //----------------------------------------------------------------------
  713 // trace(P,R)
  714 void CqShaderExecEnv::SO_trace( IqShaderData* P, IqShaderData* R, IqShaderData* Result, IqShader* pShader )
  715 {
  716     bool __fVarying;
  717     TqUint __iGrid;
  718 
  719     __fVarying=(P)->Class()==class_varying;
  720     __fVarying=(R)->Class()==class_varying||__fVarying;
  721     __fVarying=(Result)->Class()==class_varying||__fVarying;
  722 
  723     __iGrid = 0;
  724     const CqBitVector& RS = RunningState();
  725     do
  726     {
  727         if(!__fVarying || RS.Value( __iGrid ) )
  728         {
  729             (Result)->SetColor(CqColor( 0, 0, 0 ),__iGrid);
  730         }
  731     }
  732     while( ( ++__iGrid < shadingPointCount() ) && __fVarying);
  733 }
  734 
  735 
  736 //----------------------------------------------------------------------
  737 // illuminance(P,nsamples)
  738 void CqShaderExecEnv::SO_illuminance( IqShaderData* Category, IqShaderData* P, IqShaderData* Axis, IqShaderData* Angle, IqShader* pShader )
  739 {
  740     bool __fVarying;
  741     TqUint __iGrid;
  742 
  743     __iGrid = 0;
  744     CqString cat( "" );
  745     if ( NULL != Category )
  746         Category->GetString( cat );
  747 
  748 
  749     __fVarying = true;
  750 
  751     // Fill in the lightsource information, and transfer the results to the shader variables,
  752     if ( m_pAttributes != 0 )
  753     {
  754         IqLightsource * lp = m_pAttributes ->pLight( m_li );
  755 
  756         if ( NULL != Axis )
  757             __fVarying=(Axis)->Class()==class_varying||__fVarying;
  758         if ( NULL != Angle )
  759             __fVarying=(Angle)->Class()==class_varying||__fVarying;
  760 
  761         bool exec = true;
  762 
  763         if( cat.size() )
  764         {
  765 
  766             bool exclude = false;
  767             CqString lightcategories;
  768             CqString catname;
  769 
  770 
  771             if( cat.find( "-" ) == 0 )
  772             {
  773                 exclude = true;
  774                 catname = cat.substr( 1, cat.size() );
  775             }
  776             else
  777             {
  778                 catname = cat;
  779             }
  780 
  781             IqShaderData* pcats = lp->pShader()->FindArgument("__category");
  782             if( pcats )
  783             {
  784                 pcats->GetString( lightcategories );
  785 
  786                 exec = false;
  787                 // While no matching category has been found...
  788                 CqString::size_type tokenpos = 0, tokenend;
  789                 while( 1 )
  790                 {
  791                     tokenend = lightcategories.find(',', tokenpos);
  792                     CqString token = lightcategories.substr( tokenpos, tokenend );
  793                     if( catname.compare( token ) == 0 )
  794                     {
  795                         if( !exclude )
  796                         {
  797                             exec = true;
  798                             break;
  799                         }
  800                     }
  801                     if( tokenend == std::string::npos )
  802                         break;
  803                     else
  804                         tokenpos = tokenend+1;
  805                 }
  806             }
  807         }
  808 
  809         if( exec )
  810         {
  811             __iGrid = 0;
  812             const CqBitVector& RS = RunningState();
  813             do
  814             {
  815                 if(!__fVarying || RS.Value( __iGrid ) )
  816                 {
  817 
  818                     CqVector3D Ln;
  819                     lp->L() ->GetVector( Ln, __iGrid );
  820                     Ln = -Ln;
  821 
  822                     // Store them locally on the surface.
  823                     L() ->SetVector( Ln, __iGrid );
  824                     CqColor colCl;
  825                     lp->Cl() ->GetColor( colCl, __iGrid );
  826                     Cl() ->SetColor( colCl, __iGrid );
  827 
  828                     // Check if its within the cone.
  829                     Ln.Unit();
  830                     CqVector3D vecAxis( 0, 1, 0 );
  831                     if ( NULL != Axis )
  832                         Axis->GetVector( vecAxis, __iGrid );
  833                     TqFloat fAngle = M_PI;
  834                     if ( NULL != Angle )
  835                         Angle->GetFloat( fAngle, __iGrid );
  836 
  837                     TqFloat cosangle = Ln * vecAxis;
  838                     cosangle = clamp(cosangle, -1.0f, 1.0f);
  839                     if ( acos( cosangle ) > fAngle )
  840                         m_CurrentState.SetValue( __iGrid, false );
  841                     else
  842                         m_CurrentState.SetValue( __iGrid, true );
  843                 }
  844             }
  845             while( ( ++__iGrid < shadingPointCount() ) && __fVarying);
  846         }
  847     }
  848 }
  849 
  850 
  851 void    CqShaderExecEnv::SO_illuminance( IqShaderData* Category, IqShaderData* P, IqShader* pShader )
  852 {
  853     SO_illuminance( Category, P, NULL, NULL );
  854 }
  855 
  856 
  857 //----------------------------------------------------------------------
  858 // illuminate(P)
  859 void CqShaderExecEnv::SO_illuminate( IqShaderData* P, IqShaderData* Axis, IqShaderData* Angle, IqShader* pShader )
  860 {
  861     bool __fVarying;
  862     TqUint __iGrid;
  863 
  864     bool res = true;
  865     if ( m_Illuminate > 0 )
  866         res = false;
  867 
  868     __fVarying = true;
  869     if ( res )
  870     {
  871         __iGrid = 0;
  872         const CqBitVector& RS = RunningState();
  873         do
  874         {
  875             if(!__fVarying || RS.Value( __iGrid ) )
  876             {
  877                 // Get the point being lit and set the ligth vector.
  878                 CqVector3D _aq_P;
  879                 (P)->GetPoint(_aq_P,__iGrid);
  880                 CqVector3D vecPs;
  881                 Ps() ->GetPoint( vecPs, __iGrid );
  882                 L() ->SetVector( vecPs - _aq_P, __iGrid );
  883 
  884                 // Check if its within the cone.
  885                 CqVector3D Ln;
  886                 L() ->GetVector( Ln, __iGrid );
  887                 Ln.Unit();
  888 
  889                 CqVector3D vecAxis( 0.0f, 1.0f, 0.0f );
  890                 if ( NULL != Axis )
  891                     Axis->GetVector( vecAxis, __iGrid );
  892                 TqFloat fAngle = M_PI;
  893                 if ( NULL != Angle )
  894                     Angle->GetFloat( fAngle, __iGrid );
  895                 TqFloat cosangle = Ln * vecAxis;
  896                 cosangle = clamp(cosangle, -1.0f, 1.0f);
  897                 if ( acos( cosangle ) > fAngle )
  898                 {
  899                     // Make sure we set the light color to zero in the areas that won't be lit.
  900                     Cl() ->SetColor( CqColor( 0, 0, 0 ), __iGrid );
  901                     m_CurrentState.SetValue( __iGrid, false );
  902                 }
  903                 else
  904                     m_CurrentState.SetValue( __iGrid, true );
  905             }
  906         }
  907         while( ( ++__iGrid < shadingPointCount() ) && __fVarying);
  908     }
  909 
  910     m_Illuminate++;
  911 }
  912 
  913 
  914 void    CqShaderExecEnv::SO_illuminate( IqShaderData* P, IqShader* pShader )
  915 {
  916     SO_illuminate( P, NULL, NULL, pShader );
  917 }
  918 
  919 
  920 //----------------------------------------------------------------------
  921 // solar()
  922 void CqShaderExecEnv::SO_solar( IqShaderData* Axis, IqShaderData* Angle, IqShader* pShader )
  923 {
  924     // TODO: Check light cone, and exclude points outside.
  925     bool __fVarying;
  926     TqUint __iGrid;
  927 
  928     bool res = true;
  929     if ( m_Illuminate > 0 )
  930         res = false;
  931 
  932     __fVarying = true;
  933     __iGrid = 0;
  934     const CqBitVector& RS = RunningState();
  935     do
  936     {
  937         if(!__fVarying || RS.Value( __iGrid ) )
  938         {
  939             if ( res )
  940             {
  941                 CqVector3D vecAxis;
  942                 Ns()->GetNormal(vecAxis,__iGrid);
  943                 vecAxis = -vecAxis;
  944                 if ( NULL != Axis )
  945                     Axis->GetVector( vecAxis, __iGrid );
  946                 L() ->SetVector( vecAxis, __iGrid );
  947                 m_CurrentState.SetValue( __iGrid, true );
  948             }
  949         }
  950     }
  951     while( ( ++__iGrid < shadingPointCount() ) && __fVarying);
  952 
  953     m_Illuminate++;
  954 }
  955 
  956 
  957 void    CqShaderExecEnv::SO_solar( IqShader* pShader )
  958 {
  959     SO_solar( NULL, NULL, pShader );
  960 }
  961 
  962 //----------------------------------------------------------------------
  963 // gather(category,P,N,angle,nsamples)
  964 void CqShaderExecEnv::SO_gather( IqShaderData* category, IqShaderData* P, IqShaderData* N, IqShaderData* angle, IqShaderData* samples, IqShader* pShader, int cParams, IqShaderData** apParams)
  965 {
  966     bool __fVarying;
  967     TqUint __iGrid;
  968 
  969     __iGrid = 0;
  970     __fVarying = true;
  971     const CqBitVector& RS = RunningState();
  972     do
  973     {
  974         if(!__fVarying || RS.Value( __iGrid ) )
  975         {
  976             m_CurrentState.SetValue( __iGrid, false );
  977         }
  978         else
  979             m_CurrentState.SetValue( __iGrid, false );
  980     }
  981     while( ( ++__iGrid < shadingPointCount() ) && __fVarying);
  982 }
  983 
  984 //----------------------------------------------------------------------
  985 // incident
  986 
  987 void CqShaderExecEnv::SO_incident( IqShaderData* name, IqShaderData* pV, IqShaderData* Result, IqShader* pShader )
  988 {
  989     TqUint __iGrid;
  990 
  991     __iGrid = 0;
  992     Result->SetValue( 0.0f, 0 );
  993 
  994 }
  995 
  996 
  997 //----------------------------------------------------------------------
  998 // opposite
  999 
 1000 void CqShaderExecEnv::SO_opposite( IqShaderData* name, IqShaderData* pV, IqShaderData* Result, IqShader* pShader )
 1001 {
 1002     TqUint __iGrid;
 1003 
 1004     __iGrid = 0;
 1005     Result->SetValue( 0.0f, 0 );
 1006 
 1007 }
 1008 
 1009 //----------------------------------------------------------------------
 1010 // specularbrdf(L,N,V,rough)
 1011 void CqShaderExecEnv::SO_specularbrdf( IqShaderData* L, IqShaderData* N, IqShaderData* V, IqShaderData* rough, IqShaderData* Result, IqShader* pShader )
 1012 {
 1013     bool __fVarying;
 1014     TqUint __iGrid;
 1015 
 1016     __fVarying=(L)->Class()==class_varying;
 1017     __fVarying=(N)->Class()==class_varying||__fVarying;
 1018     __fVarying=(V)->Class()==class_varying||__fVarying;
 1019     __fVarying=(rough)->Class()==class_varying||__fVarying;
 1020     __fVarying=(Result)->Class()==class_varying||__fVarying;
 1021 
 1022     __iGrid = 0;
 1023     const CqBitVector& RS = RunningState();
 1024     do
 1025     {
 1026         if(!__fVarying || RS.Value( __iGrid ) )
 1027         {
 1028             CqVector3D _aq_L;
 1029             (L)->GetVector(_aq_L,__iGrid);
 1030             CqVector3D _aq_V;
 1031             (V)->GetVector(_aq_V,__iGrid);
 1032             _aq_L.Unit();
 1033 
 1034             CqVector3D  H = _aq_L + _aq_V;
 1035             H.Unit();
 1036             /// \note The (roughness/8) term emulates the BMRT behaviour for prmanspecular.
 1037             CqVector3D _aq_N;
 1038             (N)->GetNormal(_aq_N,__iGrid);
 1039             TqFloat _aq_rough;
 1040             (rough)->GetFloat(_aq_rough,__iGrid);
 1041             CqColor colCl;
 1042             Cl() ->GetColor( colCl, __iGrid );
 1043             (Result)->SetColor(colCl * pow( max( 0.0f, _aq_N * H ), 1.0f / ( _aq_rough / 8.0f ) ),__iGrid);
 1044         }
 1045     }
 1046     while( ( ++__iGrid < shadingPointCount() ) && __fVarying);
 1047 }
 1048 
 1049 //----------------------------------------------------------------------
 1050 // calculatenormal(P)
 1051 void CqShaderExecEnv::SO_calculatenormal( IqShaderData* p, IqShaderData* Result, IqShader* pShader )
 1052 {
 1053     bool __fVarying;
 1054     TqUint __iGrid;
 1055 
 1056     // Find out if the orientation is inverted.
 1057     bool CSO = pTransform()->GetHandedness(getRenderContext()->Time());
 1058     bool O = false;
 1059     if( pAttributes() )
 1060         O = pAttributes() ->GetIntegerAttribute( "System", "Orientation" ) [ 0 ] != 0;
 1061     TqFloat neg = 1;
 1062     if ( !( (O && CSO) || (!O && !CSO) ) )
 1063         neg = -1;
 1064 
 1065     __fVarying=(p)->Class()==class_varying;
 1066     __fVarying=(Result)->Class()==class_varying||__fVarying;
 1067 
 1068     __iGrid = 0;
 1069     const CqBitVector& RS = RunningState();
 1070     do
 1071     {
 1072         if(!__fVarying || RS.Value( __iGrid ) )
 1073         {
 1074             CqVector3D N = diffU<CqVector3D>(p, __iGrid)
 1075                 % diffV<CqVector3D>(p, __iGrid);
 1076             N.Unit();
 1077             N *= neg;
 1078             (Result)->SetNormal(N,__iGrid);
 1079         }
 1080     }
 1081     while( ( ++__iGrid < shadingPointCount() ) && __fVarying);
 1082 }
 1083 
 1084 
 1085 // FIXME: It's pretty ugly to have a global cache here!
 1086 //
 1087 // Missing cache features:
 1088 // * Ri search paths
 1089 static PointOctreeCache g_pointOctreeCache;
 1090 
 1091 void clearPointCloudCache()
 1092 {
 1093     g_pointOctreeCache.clear();
 1094 }
 1095 
 1096 
 1097 namespace {
 1098 /// Store zeros in shader variable, depending on integrator type:
 1099 /// OcclusionIntegrator has result type float, whereas RadiosityIntegrator has
 1100 /// result type Color.
 1101 template<typename T>
 1102 void storeZeroResult(IqShaderData* result, int igrid)
 1103 {
 1104     result->SetFloat(0.0f,igrid);
 1105 }
 1106 template<>
 1107 void storeZeroResult<RadiosityIntegrator>(IqShaderData* result, int igrid)
 1108 {
 1109     result->SetColor(CqColor(0.0f),igrid);
 1110 }
 1111 }
 1112 
 1113 
 1114 template<typename IntegratorT>
 1115 void CqShaderExecEnv::pointCloudIntegrate(IqShaderData* P, IqShaderData* N,
 1116                                           IqShaderData* result, int cParams,
 1117                                           IqShaderData** apParams,
 1118                                           IqShader* pShader)
 1119 {
 1120     if(!getRenderContext())
 1121         return;
 1122 
 1123     // Extract options
 1124     CqString paramName;
 1125     const PointOctree* pointTree = 0;
 1126     int faceRes = 10;
 1127     float maxSolidAngle = 0.03;
 1128     float coneAngle = M_PI_2;
 1129     float bias = 0;
 1130     CqString coordSystem = "world";
 1131     IqShaderData* occlusionResult = 0;
 1132     for(int i = 0; i < cParams; i+=2)
 1133     {
 1134         apParams[i]->GetString(paramName, 0);
 1135         IqShaderData* paramValue = apParams[i+1];
 1136         if(paramName == "coneangle")
 1137         {
 1138             if(paramValue->Type() == type_float)
 1139                 paramValue->GetFloat(coneAngle);
 1140         }
 1141         else if(paramName == "filename")
 1142         {
 1143             if(paramValue->Type() == type_string)
 1144             {
 1145                 CqString fileName;
 1146                 paramValue->GetString(fileName, 0);
 1147                 pointTree = g_pointOctreeCache.find(fileName);
 1148             }
 1149         }
 1150         else if(paramName == "maxsolidangle")
 1151         {
 1152             if(paramValue->Type() == type_float)
 1153                 paramValue->GetFloat(maxSolidAngle);
 1154         }
 1155         else if(paramName == "bias")
 1156         {
 1157             if(paramValue->Type() == type_float)
 1158                 paramValue->GetFloat(bias);
 1159         }
 1160         else if(paramName == "microbufres")
 1161         {
 1162             if(paramValue->Type() == type_float)
 1163             {
 1164                 float res = 10;
 1165                 paramValue->GetFloat(res);
 1166                 faceRes = std::max(1, static_cast<int>(res));
 1167             }
 1168         }
 1169         else if(paramName == "coordsystem")
 1170         {
 1171             if(paramValue->Type() == type_string)
 1172                 paramValue->GetString(coordSystem);
 1173         }
 1174         else if(paramName == "occlusion")
 1175         {
 1176             if(paramValue->Type() == type_float)
 1177                 occlusionResult = paramValue;
 1178         }
 1179         // Interesting arguments which could be implemented:
 1180         //   "hitsides"    - sidedness culling: "front", "back", "both"
 1181         //   "falloff", "falloffmode" - falloff of occlusion with distance
 1182         //   ... more!
 1183         //
 1184         // Other arguments we may not bother with:
 1185         //   "pointbased"  - we don't support any other method...
 1186     }
 1187 
 1188     // Compute transform from current to appropriate space.
 1189     CqMatrix positionTrans;
 1190     getRenderContext()->matSpaceToSpace("current", coordSystem.c_str(),
 1191                                         pShader->getTransform(),
 1192                                         pTransform().get(), 0, positionTrans);
 1193     CqMatrix normalTrans = normalTransform(positionTrans);
 1194 
 1195     // TODO: interpolation.  3delight uses Attribute "irradiance"
 1196     // "shadingrate" to control interpolation; PRMan uses the "maxvariation"
 1197     // parameter.
 1198 
 1199     // Number of vertices in u-direction of grid
 1200     int uSize = m_uGridRes+1;
 1201 
 1202     bool varying = result->Class() == class_varying;
 1203     const CqBitVector& RS = RunningState();
 1204     if(pointTree)
 1205     {
 1206         int npoints = varying ? shadingPointCount() : 1;
 1207 #pragma omp parallel
 1208         {
 1209         // Compute occlusion for each point
 1210         IntegratorT integrator(faceRes);
 1211 #pragma omp for
 1212         for(int igrid = 0; igrid < npoints; ++igrid)
 1213         {
 1214             if(!varying || RS.Value(igrid))
 1215             {
 1216                 CqVector3D Pval;
 1217                 // TODO: What about RiPoints?  They're not a 2D grid!
 1218                 int v = igrid/uSize;
 1219                 int u = igrid - v*uSize;
 1220                 float uinterp = 0;
 1221                 float vinterp = 0;
 1222                 // Microgrids sometimes meet each other at an acute angle.
 1223                 // Computing occlusion at the vertices where the grids meet is
 1224                 // then rather difficult because an occluding disk passes
 1225                 // exactly through the point to be occluded.  This usually
 1226                 // results in obvious light leakage from the other side of the
 1227                 // surface.
 1228                 //
 1229                 // To avoid this problem, we modify the position of any
 1230                 // vertices at the edges of grids by moving them inward
 1231                 // slightly.
 1232                 //
 1233                 // TODO: Make adjustable?
 1234                 const float edgeShrink = 0.2f;
 1235                 if(u == 0)
 1236                     uinterp = edgeShrink;
 1237                 else if(u == m_uGridRes)
 1238                 {
 1239                     uinterp = 1 - edgeShrink;
 1240                     --u;
 1241                 }
 1242                 if(v == 0)
 1243                     vinterp = edgeShrink;
 1244                 else if(v == m_vGridRes)
 1245                 {
 1246                     vinterp = 1 - edgeShrink;
 1247                     --v;
 1248                 }
 1249                 if(uinterp != 0 || vinterp != 0)
 1250                 {
 1251                     CqVector3D _P1; CqVector3D _P2;
 1252                     CqVector3D _P3; CqVector3D _P4;
 1253                     int uSize = m_uGridRes + 1;
 1254                     P->GetPoint(_P1, v*uSize + u);
 1255                     P->GetPoint(_P2, v*uSize + u+1);
 1256                     P->GetPoint(_P3, (v+1)*uSize + u);
 1257                     P->GetPoint(_P4, (v+1)*uSize + u+1);
 1258                     Pval = (1-vinterp)*(1-uinterp) * _P1 +
 1259                            (1-vinterp)*uinterp     * _P2 +
 1260                            vinterp*(1-uinterp)     * _P3 +
 1261                            vinterp*uinterp         * _P4;
 1262                 }
 1263                 else
 1264                     P->GetVector(Pval, igrid);
 1265                 CqVector3D Nval;   N->GetVector(Nval, igrid);
 1266                 Pval = positionTrans * Pval;
 1267                 Nval = normalTrans * Nval;
 1268                 V3f Pval2(Pval.x(), Pval.y(), Pval.z());
 1269                 V3f Nval2(Nval.x(), Nval.y(), Nval.z());
 1270                 // TODO: It may make more sense to scale bias by the current
 1271                 // micropolygon radius - that way we avoid problems with an
 1272                 // absolute length scale.
 1273                 if(bias != 0)
 1274                     Pval2 += Nval2*bias;
 1275                 integrator.clear();
 1276                 microRasterize(integrator, Pval2, Nval2, coneAngle,
 1277                                maxSolidAngle, *pointTree);
 1278                 storeIntegratedResult(integrator, Nval2, coneAngle, result,
 1279                                       occlusionResult, igrid);
 1280             }
 1281         }
 1282         }
 1283     }
 1284     else
 1285     {
 1286         // Couldn't find point cloud, set result to zero.
 1287         TqUint igrid = 0;
 1288         do
 1289         {
 1290             if(!varying || RS.Value(igrid))
 1291             {
 1292                 storeZeroResult<IntegratorT>(result, igrid);
 1293             }
 1294         }
 1295         while( ( ++igrid < shadingPointCount() ) && varying);
 1296     }
 1297 }
 1298 
 1299 
 1300 //----------------------------------------------------------------------
 1301 static void storeIntegratedResult(const OcclusionIntegrator& integrator,
 1302                                   const V3f& N, float coneAngle,
 1303                                   IqShaderData* result,
 1304                                   IqShaderData* /*occlusionResult*/, int igrid)
 1305 {
 1306     result->SetFloat(integrator.occlusion(N, coneAngle), igrid);
 1307 }
 1308 
 1309 // occlusion(P,N,samples)
 1310 void CqShaderExecEnv::SO_occlusion_rt( IqShaderData* P, IqShaderData* N, IqShaderData* samples, IqShaderData* Result, IqShader* pShader, int cParams, IqShaderData** apParams )
 1311 {
 1312     pointCloudIntegrate<OcclusionIntegrator>(P, N, Result, cParams, apParams,
 1313                                              pShader);
 1314 }
 1315 
 1316 
 1317 //----------------------------------------------------------------------
 1318 // indirectdiffuse(P, N, samples, ...)
 1319 static void storeIntegratedResult(const RadiosityIntegrator& integrator,
 1320                                   const V3f& N, float coneAngle,
 1321                                   IqShaderData* result,
 1322                                   IqShaderData* occlusionResult, int igrid)
 1323 {
 1324     float occ = 0;
 1325     C3f col = integrator.radiosity(N, coneAngle, &occ);
 1326     result->SetColor(CqColor(col.x, col.y, col.z), igrid);
 1327     if(occlusionResult)
 1328         occlusionResult->SetFloat(occ, igrid);
 1329 }
 1330 
 1331 void CqShaderExecEnv::SO_indirectdiffuse(IqShaderData* P, IqShaderData* N,
 1332                                          IqShaderData* samples,
 1333                                          IqShaderData* Result,
 1334                                          IqShader* pShader, int cParams,
 1335                                          IqShaderData** apParams)
 1336 {
 1337     pointCloudIntegrate<RadiosityIntegrator>(P, N, Result, cParams, apParams,
 1338                                              pShader);
 1339 }
 1340 
 1341 
 1342 //----------------------------------------------------------------------
 1343 // rayinfo
 1344 //
 1345 
 1346 void CqShaderExecEnv::SO_rayinfo( IqShaderData* dataname, IqShaderData* pV, IqShaderData* Result, IqShader* pShader )
 1347 {
 1348     TqUint __iGrid;
 1349 
 1350     if ( !getRenderContext() )
 1351         return ;
 1352 
 1353     TqFloat Ret = 0.0f;
 1354 
 1355     __iGrid = 0;
 1356 
 1357     (Result)->SetFloat(Ret,__iGrid);
 1358 }
 1359 
 1360 } // namespace Aqsis
 1361 //---------------------------------------------------------------------