// Aqsis
// Copyright (c) 1997 - 2001, Paul C. Gregory
//
// Contact: pgregory@aqsis.com
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

/**
 * Copyright (C) 2006-2007  NTT DATA CORPORATION
 * 
 * Version: 1.0.0 2007/04/01
 *  
 */
package net.cellcomputing.himawari.library;

import static net.cellcomputing.himawari.library.RiGlobal.*;
import static net.cellcomputing.himawari.library.CqStats.*;
import static net.cellcomputing.himawari.library.EqIntIndex.*;
import static net.cellcomputing.himawari.library.EqEnvVars.*;
import static net.cellcomputing.himawari.library.EqFloatIndex.*;
import static net.cellcomputing.himawari.library.EqProjection.*;
import static net.cellcomputing.himawari.library.EqDisplayMode.*;
import static net.cellcomputing.himawari.library.Float_h.FLT_EPSILON;
import static net.cellcomputing.himawari.library.types.PublicFunctions.CLAMP;

import java.util.HashMap;
import java.util.Set;

import net.cellcomputing.himawari.accessory.STLArray;
import net.cellcomputing.himawari.accessory.STLVector;
import net.cellcomputing.himawari.accessory.primitive.p_float;
import net.cellcomputing.himawari.library.CqRenderer.SqOutputDataEntry;
import net.cellcomputing.himawari.library.types.CqBitVector;
import net.cellcomputing.himawari.library.types.CqColor;
import net.cellcomputing.himawari.library.types.CqMatrix;
import net.cellcomputing.himawari.library.types.CqVector2D;
import net.cellcomputing.himawari.library.types.CqVector3D;
import net.cellcomputing.himawari.shaderexecenv.CqShaderExecEnv;

/**
 * 
 * グリッドのマイクロポリゴンを保存するクラス
 * 
 * @author NTT DATA Corporation
 */
public class CqMicroPolyGrid extends CqMicroPolyGridBase {
	
	private boolean	m_bShadingNormals;		///< Flag indicating shading normals have been filled in and don't need to be calculated during shading.
	private boolean	m_bGeometricNormals;	///< Flag indicating geometric normals have been filled in and don't need to be calculated during shading.
	private CqSurface m_pSurface;				///< Pointer to the surface for this grid.
	private CqCSGTreeNode m_pCSGNode;			///< Pointer to the CSG tree node this grid belongs to, null if not part of a solid.
	private CqBitVector	m_CulledPolys = new CqBitVector();		///< Bitvector indicating whether the individual micro polygons are culled.
	private STLVector<IqShaderData>	m_apShaderOutputVariables = new STLVector<IqShaderData>(IqShaderData.class);	///< Vector of pointers to shader output variables.
	
	protected IqShaderExecEnv m_pShaderExecEnv;	///< Pointer to the shader execution environment for this grid.
	
	
	//************************************************************************//
	//*** コンストラクタの定義
	//************************************************************************//
	
	/**
	 * デフォルトコンストラクタ
	 */
	public CqMicroPolyGrid()
	{
		super();
		m_bShadingNormals = false;
		m_bGeometricNormals = false;
		
		STATS_INC( GRD_allocated );
	}
	
	
	
	public CqMicroPolyGrid( int cu, int cv, CqSurface pSurface )
	{
		m_bShadingNormals = false;
		m_bGeometricNormals = false;
		m_pShaderExecEnv = new CqShaderExecEnv();
		
		STATS_INC( GRD_created );
		STATS_INC( GRD_current );
		STATS_INC( GRD_allocated );
		int cGRD = STATS_GETI( GRD_current );
		int cPeak = STATS_GETI( GRD_peak );
		STATS_SETI( GRD_peak, cGRD > cPeak ? cGRD : cPeak );
		// Initialise the shader execution environment
		
		Initialise( cu, cv, pSurface );
	}
	
	@Override
	public void destruct()
	{
		assert( RefCount() <= 0 );
		
		STATS_INC( GRD_deallocated );
		STATS_DEC( GRD_current );
		
		// Delete any cloned shader output variables.
		for( IqShaderData outputVar : m_apShaderOutputVariables ){
			outputVar.destruct();
		}
		m_apShaderOutputVariables.clear();
	}
	
	
	
	//************************************************************************//
	//*** メソッドの定義
	//************************************************************************//
	
	/** Build the normals list for the micorpolygons in the grid.
	 */
	public	void	CalcNormals()
	{
		if ( null == pVar(EnvVars_P) || null == pVar(EnvVars_N) ) return ;
		
		// Get the handedness of the coordinate system (at the time of creation) and
		// the coordinate system specified, to check for normal flipping.
		boolean CSO = this.pSurface().pTransform().GetHandedness(this.pSurface().pTransform().Time(0));
		boolean O = pAttributes() .GetIntegerAttribute( "System", "Orientation" ) [ 0 ] != 0;
		final CqVector3D[] vecMP = new CqVector3D[ 4 ];
		CqVector3D	vecN			= new CqVector3D();
//		CqVector3D  vecTemp			= new CqVector3D();
		CqVector3D	vecFailsafeN	= new CqVector3D();

		//nttdata 高速化
//		final STLVector<CqVector3D> pP = new STLVector<CqVector3D>(CqVector3D.class);
//		pVar(EnvVars_P) .GetPointPtr( pP );
		
		//final STLVector<CqVector3D> pP;
		final STLArray<CqVector3D> pP;
		pP = pVar(EnvVars_P) .GetPointPtr_2( );
		IqShaderData pNg = pVar(EnvVars_Ng);
		
		// Calculate each normal from the top left, top right and bottom left points.
		int ur = uGridRes();
		int vr = vGridRes();
	
		// Create a failsafe normal from the corners of the grid, in case we encounter degenerate MP's
		//vecFailsafeN = ( pP.get(ur) .sub( pP.get(0) ) ) .mod( (pP.get((vr*(ur+1))+ur) .sub( pP.get(0) ) ) );
		vecFailsafeN.exterior( pP.get(ur).sub( pP.get(0) ) , (pP.get((vr*(ur+1))+ur) .sub( pP.get(0) ) ) );
		
		//--- start 17.03.06 nttdata
		boolean triangle = false;
		if( pP.get(ur).equals( ( pP.get((vr*(ur+1))+ur) )))
		{
			triangle = true;
			vecFailsafeN = ( pP.get(ur) .sub( pP.get(0) ) ) .mod( (pP.get((vr*(ur+1))) .sub( pP.get(0) ) ) );
		}
		//--- end 17.03.06 nttdata
		vecFailsafeN.Unit();
		
		int igrid = 0;
		int iv;
		for ( iv = 0; iv < vr; iv++ )
		{
			int iu;
			for ( iu = 0; iu < ur; iu++ )
			{
				vecMP[ 0 ] = pP.get( igrid );
				vecMP[ 1 ] = pP.get( igrid + 1 );
				vecMP[ 2 ] = pP.get( igrid + ur + 2 );
				vecMP[ 3 ] = pP.get( igrid + ur + 1 );
				int a=0, b=1, c=2, d=3;
				CqVector3D vecBA = ( vecMP[ b ] ) .sub( ( vecMP[ a ] ) );
				CqVector3D vecCA = ( vecMP[ c ] ) .sub( ( vecMP[ a ] ) );
				float bma = vecBA.Magnitude();
				float cma = vecCA.Magnitude();
				if( bma < FLT_EPSILON )
				{
					b = 3;
					vecBA = ( vecMP[ b ] ) .sub( ( vecMP[ a ] ) );
					bma = vecBA.Magnitude();
				}
				
				//--- start 17.03.06 nttdata
				if( triangle && iu == ur - 1 )
					vecCA = ( vecMP[ d ] ) .sub( ( vecMP[ a ] ) );
				//--- end 17.03.06 nttdata
				
				if( ( bma > FLT_EPSILON ) && ( cma > FLT_EPSILON ) && ( !vecBA.equals(vecCA) ) )
				{
					//vecN = vecBA .mod( vecCA );	// Cross product is normal.*/
					vecN.exterior(vecBA , vecCA );	// Cross product is normal.*/
					vecN.Unit();
					// Flip the normal if the 'current orientation' differs from the 'coordinate system orientation'
					// see RiSpec 'Orientation and Sides'
					vecN = ( O == CSO ) ? vecN : vecN.negative();
				}
				else
				{
					//assert(false);
					vecN = vecFailsafeN; 
				}
				
				pNg.SetNormal( vecN, igrid );
				igrid++;
				// If we are at the last row, last row normal to the same.
				if ( iv == vr - 1 )
				{
					CqVector3D vecNN = new CqVector3D( vecN );
					if ( vr > 2 )
					{
						CqVector3D vecNm1 = new CqVector3D();
						CqVector3D vecNm2 = new CqVector3D();
						pNg.GetNormal( vecNm1, ( ( vr - 1 ) * ( ur + 1 ) ) + iu );
						pNg.GetNormal( vecNm2, ( ( vr - 2 ) * ( ur + 1 ) ) + iu );
						vecNN = ( vecNm1 .sub( vecNm2 ) ) .add( vecN );
					}
					pNg.SetNormal( vecNN, ( vr * ( ur + 1 ) ) + iu );
				}
			}
			// Set the last one on the row to the same.
			CqVector3D vecNN = new CqVector3D( vecN );
			if ( igrid > 2 )
			{
				CqVector3D vecNm1 = new CqVector3D();
				CqVector3D vecNm2 = new CqVector3D();
				pNg.GetNormal( vecNm1, igrid - 1 );
				pNg.GetNormal( vecNm2, igrid - 2 );
				vecNN = ( vecNm1 .sub( vecNm2 ) ) .add( vecN );
			}
			pNg.SetNormal( vecNN, igrid );
			igrid++;
		}
		
		
		// Set the very last corner value to the last normal calculated.
		CqVector3D vecNN = new CqVector3D( vecN );
		if ( vr > 2 && ur > 2 )
		{
			CqVector3D vecNm1 = new CqVector3D();
			CqVector3D vecNm2 = new CqVector3D();
			pNg.GetNormal( vecNm1, ( vr - 1 ) * ( ur - 1 ) - 1 );
			pNg.GetNormal( vecNm2, ( vr - 2 ) * ( ur - 2 ) - 1 );
			vecNN = ( vecNm1 .sub( vecNm2 ) ) .add( vecN );
		}
		pNg.SetNormal( vecNN, ( vr + 1 ) * ( ur + 1 ) - 1 );
		
	}
	
	
	
	/** Set the shading normals flag, indicating this grid has shading (N) normals already specified.
	 * @param f The new state of the flag.
	 */
	public	void	SetbShadingNormals( boolean f )
	{
		m_bShadingNormals = f;
	}
	/** Set the geometric normals flag, indicating this grid has geometric (Ng) normals already specified.
	 * @param f The new state of the flag.
	 */
	public	void	SetbGeometricNormals( boolean f )
	{
		m_bGeometricNormals = f;
	}
	/** Query whether shading (N) normals have been filled in by the surface at dice time.
	 */
	public	boolean bShadingNormals()
	{
		return ( m_bShadingNormals );
	}
	/** Query whether geometric (Ng) normals have been filled in by the surface at dice time.
	 */
	public	boolean bGeometricNormals()
	{
		return ( m_bGeometricNormals );
	}
	
	/** Get a reference to the bitvector representing the culled status of each u-poly in this grid.
	 */
	public	CqBitVector CulledPolys()
	{
		return ( m_CulledPolys );
	}

	
	/** 
	 * Initialise the grid ready for processing.
	 * @param cu Integer grid resolution.
	 * @param cv Integer grid resolution.
	 * @param pSurface CqSurface pointer to associated GPrim.
	 */
	public	void	Initialise( int cu, int cv, final CqSurface pSurface )
	{
		// Initialise the shader execution environment
	    int lUses = -1;
	    if ( pSurface!=null )
	    {
	        lUses = pSurface.Uses();
	        m_pSurface = pSurface;

	        m_pCSGNode = pSurface.pCSGNode();
	    }
	    lUses |= QGetRenderContext().pDDmanager().Uses();

	    /// \note This should delete through the interface that created it.

	    m_pShaderExecEnv.Initialise( cu, cv, pSurface.pAttributes(), pSurface.pTransform(), pSurface.pAttributes().pshadSurface(QGetRenderContext().Time()), lUses );

	    IqShader pshadSurface = pSurface .pAttributes() .pshadSurface(QGetRenderContext().Time());
	    IqShader pshadDisplacement = pSurface .pAttributes() .pshadDisplacement(QGetRenderContext().Time());
	    IqShader pshadAtmosphere = pSurface .pAttributes() .pshadAtmosphere(QGetRenderContext().Time());

	    if ( pshadSurface != null ) pshadSurface.Initialise( cu, cv, m_pShaderExecEnv );
	    if ( pshadDisplacement!= null ) pshadDisplacement.Initialise( cu, cv, m_pShaderExecEnv );
	    if ( pshadAtmosphere != null) pshadAtmosphere.Initialise( cu, cv, m_pShaderExecEnv );

	    // Initialise the local/public culled variable.
	    m_CulledPolys.SetSize( ( cu + 1 ) * ( cv + 1 ) );
	    m_CulledPolys.SetAll( false );

	    int size = ( cu + 1 ) * ( cv + 1 );

	    STATS_INC( GRD_size_4 + (int)CLAMP( CqStats.log2( size ) - 2, 0, 7 ) );
	}
	
	/**
	 * Delete unneeded variables so that we don't use up unnecessary memory
	 */
	public	void DeleteVariables( boolean all )
	{
		if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "Cs" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_Cs );
	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "Os" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_Os );
	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "du" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_du );
	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "dv" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_dv );
	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "L" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_L );
	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "Cl" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_Cl );
	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "Ol" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_Ol );
	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "dPdu" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_dPdu );
	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "dPdv" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_dPdv );

	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "s" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_s );
	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "t" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_t );
	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "I" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_I );

	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "Ps" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_Ps );
	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "E" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_E );
	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "ncomps" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_ncomps );
	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "time" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_time );
	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "alpha" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_alpha );

	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "N" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_N );
	    if (  /*!QGetRenderContext() .pDDmanager().fDisplayNeeds( "u" ) ||*/ all ) 		// \note: Needed by trim curves, need to work out how to check for their existence.
	        m_pShaderExecEnv.DeleteVariable( EnvVars_u );
	    if (  /*!QGetRenderContext() .pDDmanager().fDisplayNeeds( "v" ) ||*/ all ) 		// \note: Needed by trim curves, need to work out how to check for their existence.
	        m_pShaderExecEnv.DeleteVariable( EnvVars_v );
	    if ( all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_P );
	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "Ng" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_Ng );
	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "Ci" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_Ci );
	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "Oi" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_Oi );

	    if ( !QGetRenderContext() .pDDmanager() .fDisplayNeeds( "Ns" ) || all )
	        m_pShaderExecEnv.DeleteVariable( EnvVars_Ns );
	}
	
	/** Split the shaded grid into microploygons, and insert them into the relevant buckets in the image buffer.
	 * \param pImage Pointer to image being rendered into.
	 * \param xmin Integer minimum extend of the image part being rendered, takes into account buckets and clipping.
	 * \param xmax Integer maximum extend of the image part being rendered, takes into account buckets and clipping.
	 * \param ymin Integer minimum extend of the image part being rendered, takes into account buckets and clipping.
	 * \param ymax Integer maximum extend of the image part being rendered, takes into account buckets and clipping.
	 */
	public	void	Split( CqImageBuffer pImage, long xmin, long xmax, long ymin, long ymax )
	{
		if ( null == pVar(EnvVars_P) )
			return ;
		
		int cu = uGridRes();
		int cv = vGridRes();
		
		QGetRenderContext() .Stats().MakeProject().Start();
		CqMatrix matCameraToRaster = QGetRenderContext() .matSpaceToSpace( "camera", "raster", new CqMatrix(), new CqMatrix(), QGetRenderContext().Time() );
		CqMatrix matCameraToObject0 = QGetRenderContext() .matSpaceToSpace( "camera", "object", new CqMatrix(), pSurface() .pTransform() .matObjectToWorld( pSurface() .pTransform() .Time( 0 ) ), QGetRenderContext().Time() );
		
		// Transform the whole grid to hybrid camera/raster space
		//nttdata 高速化
//		STLVector<CqVector3D> pP = new STLVector<CqVector3D>(CqVector3D.class);
//		pVar(EnvVars_P) .GetPointPtr( pP );
		//STLVector<CqVector3D> pP;
		STLArray<CqVector3D> pP;
		pP = pVar(EnvVars_P) .GetPointPtr_2( );
		
		// Get an array of P's for all time positions.
//		std::vector<std::vector<CqVector3D> > aaPtimes;
		//nttdata 高速化
//		STLVector<STLVector<CqVector3D>> aaPtimes = new STLVector<STLVector<CqVector3D>>( 2, CqVector3D.class );
//		aaPtimes.resize( pSurface() .pTransform() .cTimes() );
		CqVector3D[][] aaPtimes;
		aaPtimes = new CqVector3D[ pSurface() .pTransform() .cTimes() ][];
		
		int iTime, tTime = pSurface() .pTransform() .cTimes();
		CqMatrix matObjectToCameraT ;
		int i;
		int gsmin1;
		gsmin1 = GridSize() - 1;
		
		for ( iTime = 1; iTime < tTime; iTime++ )
		{
			matObjectToCameraT = QGetRenderContext() .matSpaceToSpace( "object", "camera", new CqMatrix(), pSurface() .pTransform() .matObjectToWorld( pSurface() .pTransform() .Time( iTime ) ), QGetRenderContext().Time() );
//			aaPtimes.get( iTime ).resize( gsmin1 + 1 );
			if(aaPtimes[ iTime ] == null || aaPtimes[ iTime ].length < gsmin1 + 1 )
			aaPtimes[ iTime ] = new CqVector3D[ gsmin1 + 1 ];
			for(int ii=0;ii<aaPtimes[ iTime ].length;ii++)
				aaPtimes[ iTime ][ii] = new CqVector3D();
			
			for ( i = gsmin1; i >= 0; i-- )
			{
				CqVector3D Point = new CqVector3D( pP.get( i ) );
				
				// Only do the complex transform if motion blurred.
				//Point = matObjectToCameraT * matCameraToObject0 * Point;
				Point.assignment( matCameraToObject0 .multiply( Point ) );
				Point.assignment( matObjectToCameraT .multiply( Point ) );
				
				// Make sure to retain camera space 'z' coordinate.
				float zdepth = Point.z;
//				aaPtimes.get( iTime ).set( i, matCameraToRaster .multiply( Point ) );
//				aaPtimes.get( iTime ).get( i ).z = ( zdepth );
				aaPtimes[ iTime ][ i ].assignment( matCameraToRaster .multiply( Point ) );
				aaPtimes[ iTime ][ i ].z = ( zdepth );
			}
			SqTriangleSplitLine sl = new SqTriangleSplitLine();
//			CqVector3D v0 = new CqVector3D();
//			CqVector3D v1 = new CqVector3D(); 
//			CqVector3D v2 = new CqVector3D();
//			
//			v0.assignment( aaPtimes.get( iTime ).get( 0 ) );
//			v1.assignment( aaPtimes.get( iTime ).get( cu ) );
//			v2.assignment( aaPtimes.get( iTime ).get( cv * ( cu + 1 ) ) );
			CqVector3D v0;
			CqVector3D v1; 
			CqVector3D v2;
			
//			v0 = aaPtimes.get( iTime ).get( 0 ) ;
//			v1 = aaPtimes.get( iTime ).get( cu ) ;
//			v2 = aaPtimes.get( iTime ).get( cv * ( cu + 1 ) );
			v0 = ( aaPtimes[ iTime ][ 0 ] );
			v1 = ( aaPtimes[ iTime ][ cu ] );
			v2 = ( aaPtimes[ iTime ][ cv * ( cu + 1 ) ] );
			// Check for clockwise, swap if not.
			if( ( ( v1.x - v0.x ) * ( v2.y - v0.y ) - ( v1.y - v0.y ) * ( v2.x - v0.x ) ) >= 0 )
			{
				sl.m_TriangleSplitPoint1.assignment( v1 );
				sl.m_TriangleSplitPoint2.assignment( v2 );
			}
			else
			{
				sl.m_TriangleSplitPoint1.assignment( v2 );
				sl.m_TriangleSplitPoint2.assignment( v1 );
			}
			m_TriangleSplitLine.AddTimeSlot(pSurface().pTransform().Time( iTime ), sl ); 
		}
		
		for ( i = gsmin1; i >= 0; i-- )
		{
//			aaPtimes.get( 0 ).resize( gsmin1 + 1 );
//			// Make sure to retain camera space 'z' coordinate.
//			float zdepth = pP.get( i ).z;
//			aaPtimes.get( 0 ).get( i ).assignment( matCameraToRaster .multiply( pP.get( i ) ) );
//			aaPtimes.get( 0 ).get( i ).z = ( zdepth );
//			pP.get( i ).assignment( aaPtimes.get( 0 ).get( i ) );
			if(aaPtimes[ 0 ] == null ||  aaPtimes[ 0 ].length < gsmin1 + 1)
			{
				aaPtimes[ 0 ] = new CqVector3D[ gsmin1 + 1 ];
				for(int ii=0;ii<aaPtimes[ 0 ].length;ii++)
					aaPtimes[ 0 ][ii] = new CqVector3D();
			}
			
			// Make sure to retain camera space 'z' coordinate.
			float zdepth = pP.get( i ).z;
			aaPtimes[ 0 ][ i ].assignment( matCameraToRaster .multiply( pP.get( i ) ) );
			aaPtimes[ 0 ][ i ].z = ( zdepth );
			pP.get( i ).assignment( aaPtimes[ 0 ][ i ] );
		}
		
		SqTriangleSplitLine sl = new SqTriangleSplitLine();
//		CqVector3D vec0 = new CqVector3D();
//		CqVector3D vec1 = new CqVector3D();
//		CqVector3D vec2 = new CqVector3D();
//		vec0.assignment( aaPtimes.get( 0 ).get( 0 ) );
//		vec1.assignAdd( aaPtimes.get( 0 ).get( cu ) );
//		vec2.assignment( aaPtimes.get( 0 ).get( cv * ( cu + 1 ) ) );
		CqVector3D vec0 ;
		CqVector3D vec1 ;
		CqVector3D vec2 ;
//		vec0 = aaPtimes.get( 0 ).get( 0 );
//		vec1 = aaPtimes.get( 0 ).get( cu );
//		vec2 = aaPtimes.get( 0 ).get( cv * ( cu + 1 ) );
		vec0 = ( aaPtimes[ 0 ][ 0 ] );
		vec1 = ( aaPtimes[ 0 ][ cu ] );
		vec2 = ( aaPtimes[ 0 ][ cv * ( cu + 1 ) ] );
		
		// Check for clockwise, swap if not.
		if( ( ( vec1.x - vec0.x ) * ( vec2.y - vec0.y ) - ( vec1.y - vec0.y ) * ( vec2.x - vec0.x ) ) >= 0 )
		{
			sl.m_TriangleSplitPoint1.assignment( vec1 );
			sl.m_TriangleSplitPoint2.assignment( vec2 );
		}
		else
		{
			sl.m_TriangleSplitPoint1.assignment( vec2 );
			sl.m_TriangleSplitPoint2.assignment( vec1 );
		}
		m_TriangleSplitLine.AddTimeSlot(pSurface().pTransform().Time( 0 ), sl ); 
		
		QGetRenderContext() .Stats().MakeProject().Stop();
		
		// Get the required trim curve sense, if specified, defaults to "inside".
		String[] pattrTrimSense = pAttributes() .GetStringAttribute( "trimcurve", "sense" );
		String strTrimSense = ( "inside" );
		if ( pattrTrimSense != null ) strTrimSense = pattrTrimSense[ 0 ];
		boolean bOutside = ( strTrimSense.equals( "outside" ) );
		
		// Determine whether we need to bother with trimming or not.
		boolean bCanBeTrimmed = pSurface() .bCanBeTrimmed() && null != pVar(EnvVars_u) && null != pVar(EnvVars_v);
		
		this.AddRef();
		
		int iv;
		for ( iv = 0; iv < cv; iv++ )
		{
			int iu;
			for ( iu = 0; iu < cu; iu++ )
			{
				int iIndex = ( iv * ( cu + 1 ) ) + iu;
				
				// If culled don't bother.
				if ( m_CulledPolys.Value( iIndex ) )
				{
					STATS_INC(MPG_culled);
					continue;
				}
				
				// If the MPG is trimmed then don't add it.
				boolean fTrimmed = false;
				if ( bCanBeTrimmed )
				{
					p_float u1, v1, u2, v2, u3, v3, u4, v4;
					
					pVar(EnvVars_u) .GetFloat( u1 = new p_float(), iIndex );
					pVar(EnvVars_v) .GetFloat( v1 = new p_float(), iIndex );
					pVar(EnvVars_u) .GetFloat( u2 = new p_float(), iIndex + 1 );
					pVar(EnvVars_v) .GetFloat( v2 = new p_float(), iIndex + 1 );
					pVar(EnvVars_u) .GetFloat( u3 = new p_float(), iIndex + cu + 2 );
					pVar(EnvVars_v) .GetFloat( v3 = new p_float(), iIndex + cu + 2 );
					pVar(EnvVars_u) .GetFloat( u4 = new p_float(), iIndex + cu + 1 );
					pVar(EnvVars_v) .GetFloat( v4 = new p_float(), iIndex + cu + 1 );
					
					CqVector2D vecA = new CqVector2D(u1.value, v1.value);
					CqVector2D vecB = new CqVector2D(u2.value, v2.value);
					CqVector2D vecC = new CqVector2D(u3.value, v3.value);
					CqVector2D vecD = new CqVector2D(u4.value, v4.value);
					
					boolean fTrimA = pSurface() .bIsPointTrimmed( vecA );
					boolean fTrimB = pSurface() .bIsPointTrimmed( vecB );
					boolean fTrimC = pSurface() .bIsPointTrimmed( vecC );
					boolean fTrimD = pSurface() .bIsPointTrimmed( vecD );
				
					if ( bOutside )
					{
						fTrimA = !fTrimA;
						fTrimB = !fTrimB;
						fTrimC = !fTrimC;
						fTrimD = !fTrimD;
					}
					
					// If all points are trimmed, need to check if the MP spans the trim curve at all, if not, then
					// we can discard it altogether.
					if ( fTrimA && fTrimB && fTrimC && fTrimD )
					{
						if(!pSurface().bIsLineIntersecting(vecA, vecB) && 
								!pSurface().bIsLineIntersecting(vecB, vecC) && 
								!pSurface().bIsLineIntersecting(vecC, vecD) && 
								!pSurface().bIsLineIntersecting(vecD, vecA) )
						{
							STATS_INC( MPG_trimmedout );
							continue;
						}
					}
					
					// If any points are trimmed mark the MPG as needing to be trim checked.
					//fTrimmed = fTrimA || fTrimB || fTrimC || fTrimD;
					if ( fTrimA || fTrimB || fTrimC || fTrimD )
						fTrimmed = true;
				}
				
 				if ( tTime > 1 )
				{
					CqMicroPolygonMotion pNew = new CqMicroPolygonMotion();
					pNew.SetGrid( this );
					pNew.SetIndex( iIndex );
					if ( fTrimmed ) 
						pNew.MarkTrimmed();
					for ( iTime = 0; iTime < tTime; iTime++ )
//						pNew.AppendKey( aaPtimes.get( iTime ).get( iIndex ), aaPtimes.get( iTime ).get( iIndex + 1 ), aaPtimes.get( iTime ).get( iIndex + cu + 2 ), aaPtimes.get( iTime ).get( iIndex + cu + 1 ), pSurface() .pTransform() .Time( iTime ) );
						pNew.AppendKey( aaPtimes[ iTime ][ iIndex ], aaPtimes[ iTime ][ iIndex + 1 ], aaPtimes[ iTime ][ iIndex + cu + 2 ], aaPtimes[ iTime ][ iIndex + cu + 1 ], pSurface() .pTransform() .Time( iTime ) );
					pImage.AddMPG( pNew );
				}
				else
				{
					CqMicroPolygon pNew = new CqMicroPolygon();
					pNew.SetGrid( this );
					pNew.SetIndex( iIndex );
					if ( fTrimmed ) 
						pNew.MarkTrimmed();
					pNew.Initialise();
					pNew.CalculateTotalBound();
					pImage.AddMPG( pNew );
				}
				
				// Calculate MPG area
				float area = 0.0f;
//				area += ( aaPtimes.get( 0 ).get( iIndex ).x * aaPtimes.get( 0 ).get(iIndex + 1 ).y ) - ( aaPtimes.get( 0 ).get( iIndex ).y * aaPtimes.get( 0 ).get( iIndex + 1 ).x );
//				area += ( aaPtimes.get( 0 ).get( iIndex + 1 ).x * aaPtimes.get( 0 ).get(iIndex + cu + 2 ).y ) - ( aaPtimes.get( 0 ).get( iIndex + 1 ).y * aaPtimes.get( 0 ).get( iIndex + cu + 2 ).x );
//				area += ( aaPtimes.get( 0 ).get( iIndex + cu + 2 ).x * aaPtimes.get( 0 ).get( iIndex + cu + 1 ).y ) - ( aaPtimes.get( 0 ).get( iIndex + cu + 2 ).y * aaPtimes.get( 0 ).get( iIndex + cu + 1 ).x );
//				area += ( aaPtimes.get( 0 ).get( iIndex + cu + 1 ).x * aaPtimes.get( 0 ).get( iIndex ).y ) - ( aaPtimes.get( 0 ).get( iIndex + cu + 1 ).y * aaPtimes.get( 0 ).get( iIndex ).x );
				area += ( aaPtimes[ 0 ][ iIndex ].x * aaPtimes[ 0 ][iIndex + 1 ].y ) - ( aaPtimes[ 0 ][ iIndex ].y * aaPtimes[ 0 ][ iIndex + 1 ].x );
				area += ( aaPtimes[ 0 ][ iIndex + 1 ].x * aaPtimes[ 0 ][iIndex + cu + 2 ].y ) - ( aaPtimes[ 0 ][ iIndex + 1 ].y * aaPtimes[ 0 ][ iIndex + cu + 2 ].x );
				area += ( aaPtimes[ 0 ][ iIndex + cu + 2 ].x * aaPtimes[ 0 ][ iIndex + cu + 1 ].y ) - ( aaPtimes[ 0 ][ iIndex + cu + 2 ].y * aaPtimes[ 0 ][ iIndex + cu + 1 ].x );
				area += ( aaPtimes[ 0 ][ iIndex + cu + 1 ].x * aaPtimes[ 0 ][ iIndex ].y ) - ( aaPtimes[ 0 ][ iIndex + cu + 1 ].y * aaPtimes[ 0 ][ iIndex ].x );
				area *= 0.5f;
				area = Math.abs(area);
				
				STATS_SETF( MPG_average_area, STATS_GETF( MPG_average_area ) + area );
				if( area < STATS_GETF( MPG_min_area ) )
					STATS_SETF( MPG_min_area, area );
				if( area > STATS_GETF( MPG_max_area ) )
					STATS_SETF( MPG_max_area, area );
			}
		}
		
		this.Release();
	}
	
	static CqVector3D	vecE = new CqVector3D( 0, 0, 0 );
	static CqVector3D	Defvec = new CqVector3D( 0, 0, 0 );
    
	/** Shade the grid using the surface parameters of the surface passed and store the color values for each micropolygon.
	 */
	public	void	Shade()
	{
	    int i;

	    // Sanity checks
	    if ( null == pVar(EnvVars_P) || null == pVar(EnvVars_I) ) return ;

//	    static CqVector3D	vecE = new CqVector3D( 0, 0, 0 );
//	    static CqVector3D	Defvec = new CqVector3D( 0, 0, 0 );

	    CqStats theStats = QGetRenderContext() .Stats();

	    IqShader pshadSurface = pSurface() .pAttributes() .pshadSurface(QGetRenderContext().Time());
	    IqShader pshadDisplacement = pSurface() .pAttributes() .pshadDisplacement(QGetRenderContext().Time());
	    IqShader pshadAtmosphere = pSurface() .pAttributes() .pshadAtmosphere(QGetRenderContext().Time());

	    int lUses = pSurface() .Uses();
	    int gs = GridSize();
	    int uRes = uGridRes();
	    int vRes = vGridRes();
	    int gsmin1 = gs - 1;
	    long cCulled = 0;


	    //nttdata 高速化
//	    STLVector<CqVector3D> pP = new STLVector<CqVector3D>(CqVector3D.class);
//	    pVar(EnvVars_P) .GetPointPtr( pP );
//	    STLVector<CqColor> pOs = new STLVector<CqColor>(CqColor.class);
//	    if ( USES( lUses, EnvVars_Os ) ) 
//	    	pVar(EnvVars_Os) .GetColorPtr( pOs );
//	    STLVector<CqColor> pCs = new STLVector<CqColor>(CqColor.class);
//	    if ( USES( lUses, EnvVars_Cs ) ) 
//	    	pVar(EnvVars_Cs) .GetColorPtr( pCs );
//	    IqShaderData pI = pVar(EnvVars_I);
//	    // CqVector3D pN = new CqVector3D();
//	    STLVector<CqVector3D> pN = new STLVector<CqVector3D>(CqVector3D.class);
//	    if ( USES( lUses, EnvVars_N ) ) 
//	    	pVar(EnvVars_N).GetNormalPtr( pN );
	    
	    //STLVector<CqVector3D> pP ;
	    STLArray<CqVector3D> pP ;
	    pP = pVar(EnvVars_P) .GetPointPtr_2( );
	    
	    //STLVector<CqColor> pOs = null;
	    STLArray<CqColor> pOs = null;
	    if ( USES( lUses, EnvVars_Os ) ) 
	    	pOs = pVar(EnvVars_Os) .GetColorPtr_2( );
	    
	    //STLVector<CqColor> pCs = null;
	    STLArray<CqColor> pCs = null;
	    if ( USES( lUses, EnvVars_Cs ) ) 
	    	pCs = pVar(EnvVars_Cs) .GetColorPtr_2( );
	    
	    IqShaderData pI = pVar(EnvVars_I);
	    // CqVector3D pN = new CqVector3D();
	    //STLVector<CqVector3D> pN = null;
	    STLArray<CqVector3D> pN = null;
	    if ( USES( lUses, EnvVars_N ) ) 
	    	pN = pVar(EnvVars_N).GetNormalPtr_2( );

	    // Calculate geometric normals if not specified by the surface.
	    if ( !bGeometricNormals() && USES( lUses, EnvVars_Ng ) )
	        CalcNormals();

	    // If shading normals are not explicitly specified, they default to the geometric normal.
	    if ( !bShadingNormals() && USES( lUses, EnvVars_N ) && null != pVar(EnvVars_Ng) && null != pVar(EnvVars_N) )
	        pVar(EnvVars_N) .SetValueFromVariable( pVar(EnvVars_Ng) );

	    // Setup uniform variables.
	    if ( USES( lUses, EnvVars_E ) ) pVar(EnvVars_E) .SetVector( vecE );

	    // Setup varying variables.
	    boolean bdpu, bdpv;
	    bdpu = ( USES( lUses, EnvVars_dPdu ) );
	    bdpv = ( USES( lUses, EnvVars_dPdv ) );
	    IqShaderData pSDP = pVar(EnvVars_P);
	    int proj = QGetRenderContext().GetIntegerOption( "System", "Projection" ) [ 0 ];

	    for ( i = gsmin1; i >= 0; i-- )
	    {
	    	if ( USES( lUses, EnvVars_du ) )
	    	{
	    		p_float v1 = new p_float();
	    		p_float v2 = new p_float();
	    		int GridX = i % ( uRes + 1 );
	    		
	    		if ( GridX < uRes )
	    		{
	    			pVar(EnvVars_u) .GetValue( v1, i + 1 );
	    			pVar(EnvVars_u) .GetValue( v2, i );
//	    			pVar(EnvVars_du) .SetFloat( v1.value - v2.value, i ); //変更あり
	    			//******【改】Aqsis1.0.1の変更後はこちら ****************************
	    			pVar(EnvVars_du) .SetFloat( 1.0f );
	    			//**********************************************************
	    		}
	    		else
	    		{
	    			pVar(EnvVars_u) .GetValue( v1, i );
	    			pVar(EnvVars_u) .GetValue( v2, i - 1 );
//	    			pVar(EnvVars_du) .SetFloat( v1.value - v2.value, i );
	    			//******【改】Aqsis1.0.1の変更後はこちら ****************************
	    			pVar(EnvVars_du) .SetFloat( 1.0f );
	    			//**********************************************************
	    		}
	    	}
	    	if ( USES( lUses, EnvVars_dv ) )
	    	{
	    		p_float v1 = new p_float();
	    		p_float v2 = new p_float();
	    		int GridY = ( i / ( uRes + 1 ) );
	    		
	    		if ( GridY < vRes )
	    		{
	    			pVar(EnvVars_v) .GetValue( v1, i + uRes + 1 );
	    			pVar(EnvVars_v) .GetValue( v2, i );
//	    			pVar(EnvVars_dv) .SetFloat( v1.value - v2.value, i );
	    			//******【改】Aqsis1.0.1の変更後はこちら ****************************
	    			pVar(EnvVars_dv) .SetFloat( 1.0f );
	    			//**********************************************************
	    		}
	    		else
	    		{
	    			pVar(EnvVars_v) .GetValue( v1, i );
	    			pVar(EnvVars_v) .GetValue( v2, i - ( uRes + 1 ) );
//	    			pVar(EnvVars_dv) .SetFloat( v1.value - v2.value, i );
	    			//******【改】Aqsis1.0.1の変更後はこちら ****************************
	    			pVar(EnvVars_dv) .SetFloat( 1.0f );
	    			//**********************************************************
	    		}
	    	}
	    	switch ( proj )
	    	{
		    	case	ProjectionOrthographic:
		    		pI.SetVector( new CqVector3D(0,0,1), i );
		    		break;
		    		
		    	case	ProjectionPerspective:
		    	default:
		    		pI.SetVector( pP.get( i ), i );
		    	break;
	    	}
	    }
	    	//*****【改】Aqsis1.0.1にて変更　変更後のソースはしたへ *******************************************************
//	    	if ( bdpu )
//	    	{
//	    		pVar(EnvVars_dPdu) .SetVector( SO_DuType_CqVector3D( pSDP, i, m_pShaderExecEnv, Defvec ), i );
//	    	}
//	    	if ( bdpv )
//	    	{
//	    		pVar(EnvVars_dPdv) .SetVector( SO_DvType_CqVector3D( pSDP, i, m_pShaderExecEnv, Defvec ), i );
//	    	}
	    	//*****************************************************************************************************
	    	//*****　【改】Aqsis1.0.1変更後のソース***************************************************************************

	    	/// \note: This second pass over the grid is necessary, as the "P" primitive variable isn't fully populated
	    	/// until the previous loop is complete, making it impossible to calculate derivatives.
	        if ( bdpu || bdpv )
	    	{
	    		for ( i = gsmin1; i >= 0; i-- )
	    		{
	    			if ( bdpu )
	    			{
	    				pVar(EnvVars_dPdu).SetVector( SO_DuType_CqVector3D( pSDP, i, m_pShaderExecEnv, Defvec ), i );
	    			}
	    			if ( bdpv )
	    			{
	    				pVar(EnvVars_dPdv).SetVector( SO_DvType_CqVector3D( pSDP, i, m_pShaderExecEnv, Defvec ), i );
	    			}
	    		}
	        }

	    	//*****************************************************************************************************
	    
	    
	    if ( USES( lUses, EnvVars_Ci ) ) pVar(EnvVars_Ci) .SetColor( gColBlack );
	    if ( USES( lUses, EnvVars_Oi ) ) pVar(EnvVars_Oi) .SetColor( gColWhite );
	    
	    // Now try and cull any transparent MPs
	    cCulled = 0;
	    if ( USES( lUses, EnvVars_Os ) && ( QGetRenderContext() .optCurrent().GetIntegerOptionIndex( "System", "DisplayMode" , 0 ).value & ModeZ ) != 0)
	    {
	    	theStats.OcclusionCullTimer().Start();
	    	for ( i = gsmin1; i >= 0; i-- )
	    	{
	    		if ( !( pOs.elementAt( i ).equals( gColWhite )) )
	    		{
	    			cCulled ++;
	    			m_CulledPolys.SetValue( i, true );
	    		}
	    		else
	    			break;
	    	}
	    	theStats.OcclusionCullTimer().Stop();
	    	
	    	if ( cCulled == gs )
	    	{
	    		m_fCulled = true;
	    		STATS_INC( GRD_culled );
	    		DeleteVariables( true );
	    		return ;
	    	}
	    	
	    }
	    
	    
	    // Now try and cull any true transparent MPs
	    cCulled = 0;
	    if ( USES( lUses, EnvVars_Os ) && ( QGetRenderContext() .optCurrent().GetIntegerOptionIndex( "System", "DisplayMode" , 0 ).value & ModeRGB ) != 0 )
	    {
	    	theStats.OcclusionCullTimer().Start();
	    	for ( i = gsmin1; i >= 0; i-- )
	    	{
	    		if ( pOs.elementAt( i ).equals( gColBlack ))
	    		{
	    			cCulled ++;
	    			m_CulledPolys.SetValue( i, true );
	    		}
	    		else
	    			break;
	    	}
	    	theStats.OcclusionCullTimer().Stop();
	    	
	    	if ( cCulled == gs )
	    	{
	    		m_fCulled = true;
	    		STATS_INC( GRD_culled );
	    		DeleteVariables( true );
	    		return ;
	    	}
	    }
	    
	    if ( pshadDisplacement!=null )
	    {
	    	theStats.DisplacementTimer().Start();
	    	pshadDisplacement.Evaluate( m_pShaderExecEnv );
	    	theStats.DisplacementTimer().Stop();
	    }
	    
	    // Now try and cull any hidden MPs if Sides==1
	    cCulled = 0;
	    if ( ( pAttributes().GetIntegerAttribute( "System", "Sides" ) [ 0 ] == 1 ) && m_pCSGNode == null )
	    {
	    	theStats.OcclusionCullTimer().Start();
	    	for ( i = gsmin1; i >= 0; i-- )
	    	{
	    		// Calulate the direction the MPG is facing.
	            if ( ( pN.elementAt( i ).mul( pP.elementAt( i ) ) ) >= 0 )
	            {
	                cCulled++;
	                m_CulledPolys.SetValue( i, true );
	            }
	        }
	        theStats.OcclusionCullTimer().Stop();

	        // If the whole grid is culled don't bother going any further.
	        if ( cCulled == gs )
	        {
	            m_fCulled = true;
	            STATS_INC( GRD_culled );
	            DeleteVariables( true );
	            return ;
	        }
	    }

	    // Now shade the grid.
	    theStats.SurfaceTimer().Start();
	    if ( pshadSurface!=null )
	    {
			//boost::shared_ptr<CqSurface> surf(pSurface());
			m_pShaderExecEnv.SetCurrentSurface(pSurface());
	        pshadSurface.Evaluate( m_pShaderExecEnv );
	    }
	    theStats.SurfaceTimer().Stop();

	    // Now try and cull any true transparent MPs (assigned by the shader code

	    cCulled = 0;
	    if ( USES( lUses, EnvVars_Os ) && ( QGetRenderContext() .optCurrent().GetIntegerOptionIndex( "System", "DisplayMode" , 0 ).value & ModeRGB ) != 0 )
	    {
	        theStats.OcclusionCullTimer().Start();
	        for ( i = gsmin1; i >= 0; i-- )
	        {
	            if ( pOs.elementAt( i ).equals( gColBlack ))
	            {
	                cCulled ++;
	                m_CulledPolys.SetValue( i, true );
	            }
	            else
	                break;
	        }
	        theStats.OcclusionCullTimer().Stop();

	        if ( cCulled == gs )
	        {
	            m_fCulled = true;
	            STATS_INC( GRD_culled );
	            DeleteVariables( true );
	            return ;
	        }
	    }
	    
	    // Now perform atmosphere shading
	    if ( pshadAtmosphere!=null )
	    {
	        theStats.AtmosphereTimer().Start();
	        pshadAtmosphere.Evaluate( m_pShaderExecEnv );
	        theStats.AtmosphereTimer().Stop();
	    }

	    DeleteVariables( false );

	    int	size = GridSize();

	    STATS_INC( GRD_shd_size_4 + (int)CLAMP( log2( size ) - 2, 0, 7 ) );

	}
	
	/** Transfer any shader variables marked as "otuput" as they may be needed by the display devices.
	 */
	public void TransferOutputVariables()
	{
	    IqShader pShader = this.pAttributes().pshadSurface(QGetRenderContext().Time());

	    // Only bother transferring ones that have been used in a RiDisplay request.
	    HashMap<String, SqOutputDataEntry> outputVars = QGetRenderContext().GetMapOfOutputDataEntries();
	    Set<String> outputVar;
	    
	    outputVar = outputVars.keySet();
	    for( String value : outputVar )
	    {
	        IqShaderData outputData = pShader.FindArgument( value );
	        if( null != outputData )
	        {
	            IqShaderData newOutputData = outputData.Clone();
	            m_apShaderOutputVariables.add( newOutputData );
	        }
	    }
	}
	
	/** Get a pointer to the surface which this grid belongs.
	 * @return Surface pointer, only valid during shading.
	 */
	public CqSurface	pSurface()
	{
		return ( m_pSurface );
	}
	public	final IqAttributes pAttributes()
	{
		assert( m_pShaderExecEnv!=null );
		return ( m_pShaderExecEnv.pAttributes() );
	}
	public	CqCSGTreeNode pCSGNode()
	{
		return ( m_pCSGNode );
	}
	
	// Redirect acces via IqShaderExecEnv
	public	int	uGridRes()
	{
		assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.uGridRes() );
	}
	public	int	vGridRes()
	{
		assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.vGridRes() );
	}
	public	int	GridSize()
	{
		assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.GridSize() );
	}
	public	final CqMatrix	matObjectToWorld()
	{
		assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.matObjectToWorld() );
	}
	public IqShaderData pVar(int index)
	{
		assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.pVar(index) );
	}
	public	IqShaderData FindStandardVar( final String pname )
	{
		IqShaderData pVar = null;
		if( ( pVar = m_pShaderExecEnv.FindStandardVar( pname ) ) == null )
		{
			for( IqShaderData outputVar : m_apShaderOutputVariables )
			{
				if( (outputVar).strName().equals( pname ) )
				{
					pVar = (outputVar);
					break;
				}
			}
		}
		return( pVar );
	}
	
	
}
