// 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 net.cellcomputing.himawari.accessory.STLVector;
import net.cellcomputing.himawari.accessory.primitive.p_String;
import net.cellcomputing.himawari.accessory.primitive.p_float;
import net.cellcomputing.himawari.accessory.primitive.p_int;
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.library.types.CqVector4D;
import static net.cellcomputing.himawari.library.RiGlobal.QGetRenderContext;
import static net.cellcomputing.himawari.library.RendermanInterface.*;
import static net.cellcomputing.himawari.library.EqIntIndex.*;
import static net.cellcomputing.himawari.library.CqStats.*;
import static net.cellcomputing.himawari.library.EqVariableType.*;
import static net.cellcomputing.himawari.library.EqVariableClass.*;
import static net.cellcomputing.himawari.library.EqSplitDir.*;
import static net.cellcomputing.himawari.library.types.PublicFunctions.*;
import static net.cellcomputing.himawari.library.Float_h.*;
import static java.lang.Float.*;
import static java.lang.StrictMath.*;

/**
 * Bicubic spline patch
 * 双3次なスプラインパッチ
 * 
 * @author NTT DATA Corporation
 */
public strictfp class CqSurfacePatchBicubic extends CqSurface {
	
	
	
	/**
	 * デフォルトコンストラクタ
	 * Constructor both u and vbasis matrices default to bezier.
	 */
	public CqSurfacePatchBicubic()
	{
		STATS_INC( GPR_patch );
	}
	
	/**
	 * コピーコンストラクタ
	 * 
	 * @param From	コピー元
	 */
	public CqSurfacePatchBicubic( final CqSurfacePatchBicubic From )
	{
		super( From );
		this.assignment( From );
		STATS_INC( GPR_patch );
	}
	
	/* (non-Javadoc)
	 * @see net.cellcomputing.himawari.library.CqBasicSurface#destruct()
	 */
	public void destruct()
	{}
	
	/* (non-Javadoc)
	 * @see net.cellcomputing.himawari.library.CqSurface#TypedNaturalDice(float, float, net.cellcomputing.himawari.library.CqParameterTyped, net.cellcomputing.himawari.library.IqShaderData)
	 */
	@SuppressWarnings("unchecked")
	public <T, SLT> void TypedNaturalDice( float uSize, float vSize, CqParameterTyped<T, SLT> pParam, IqShaderData pData )
	{
		CqForwardDiffBezier<T> vFD0 = new CqForwardDiffBezier<T>( 1.0f / vSize, pParam.TClass );
		CqForwardDiffBezier<T> vFD1 = new CqForwardDiffBezier<T>( 1.0f / vSize, pParam.TClass );
		CqForwardDiffBezier<T> vFD2 = new CqForwardDiffBezier<T>( 1.0f / vSize, pParam.TClass );
		CqForwardDiffBezier<T> vFD3 = new CqForwardDiffBezier<T>( 1.0f / vSize, pParam.TClass );
		CqForwardDiffBezier<T> uFD0 = new CqForwardDiffBezier<T>( 1.0f / uSize, pParam.TClass );

		vFD0.CalcForwardDiff( (T)pParam.pValue_get( 0 , 0 ), (T)pParam.pValue_get( 0 , 4 ), (T)pParam.pValue_get( 0 , 8 ), (T)pParam.pValue_get( 0 , 12 ) );
		vFD1.CalcForwardDiff( (T)pParam.pValue_get( 0 , 1 ), (T)pParam.pValue_get( 0 , 5 ), (T)pParam.pValue_get( 0 , 9 ), (T)pParam.pValue_get( 0 , 13 ) );
		vFD2.CalcForwardDiff( (T)pParam.pValue_get( 0 , 2 ), (T)pParam.pValue_get( 0 , 6 ), (T)pParam.pValue_get( 0 , 10 ), (T)pParam.pValue_get( 0 , 14 ) );
		vFD3.CalcForwardDiff( (T)pParam.pValue_get( 0 , 3 ), (T)pParam.pValue_get( 0 , 7 ), (T)pParam.pValue_get( 0 , 11 ), (T)pParam.pValue_get( 0 , 15 ) );
	
		for ( int iv = 0; iv <= vSize; iv++ )
		{
			T vA = (T)vFD0.GetValue();
			T vB = (T)vFD1.GetValue();
			T vC = (T)vFD2.GetValue();
			T vD = (T)vFD3.GetValue();
			uFD0.CalcForwardDiff( vA, vB, vC, vD );
			
			for ( int iu = 0; iu <= uSize; iu++ )
			{
				T vec = (T)uFD0.GetValue();
				int igrid = (int)( iv * ( uSize + 1 )) + iu;
				pData.SetValue( vec, igrid, vec.getClass() );
			}
		}
	}
	
	/* (non-Javadoc)
	 * @see net.cellcomputing.himawari.library.CqSurface#TypedNaturalSubdivide(net.cellcomputing.himawari.library.CqParameterTyped, net.cellcomputing.himawari.library.CqParameterTyped, net.cellcomputing.himawari.library.CqParameterTyped, boolean)
	 */
	@SuppressWarnings("unchecked")
	public <T, SLT> void TypedNaturalSubdivide( CqParameterTyped<T, SLT> pParam, CqParameterTyped<T, SLT> pResult1, CqParameterTyped<T, SLT> pResult2, boolean u )
	{
		int iu, iv;
		
		CqParameterTyped<T, SLT> pTParam = ( CqParameterTyped<T, SLT> ) pParam ;
		CqParameterTyped<T, SLT> pTResult1 = ( CqParameterTyped<T, SLT> ) pResult1 ;
		CqParameterTyped<T, SLT> pTResult2 = ( CqParameterTyped<T, SLT> ) pResult2 ;
		
		T t = (T)pParam.pValue_get( 0 , 0 );
		if( t instanceof p_float )
		{
			if ( u ){
				for ( iv = 0; iv < 4; iv++ )
				{
					int ivo = ( iv * 4 );
					((p_float)pTResult1.pValue_get( 0 , ivo + 0 )).value = ((p_float)pTParam.pValue_get( 0 , ivo + 0 )).value;
					((p_float)pTResult1.pValue_get( 0 , ivo + 1 )).value = ( ((p_float)pTParam.pValue_get( 0 , ivo + 0 )).value + ((p_float)pTParam.pValue_get( 0 , ivo + 1 )).value ) / 2.0f ;
					((p_float)pTResult1.pValue_get( 0 , ivo + 2 )).value = ((p_float)pTResult1.pValue_get( 0 , ivo + 1 )).value / 2.0f + ( ((p_float)pTParam.pValue_get( 0 , ivo + 1 )).value + ((p_float)pTParam.pValue_get( 0 , ivo + 2 )).value ) / 4.0f ;
					
					((p_float)pTResult2.pValue_get( 0 , ivo + 3 )).value = ((p_float)pTParam.pValue_get( 0 , ivo + 3 )).value;
					((p_float)pTResult2.pValue_get( 0 , ivo + 2 )).value = ( ((p_float)pTParam.pValue_get( 0 , ivo + 2 )).value + ((p_float)pTParam.pValue_get( 0 , ivo + 3 )).value ) / 2.0f ;
					((p_float)pTResult2.pValue_get( 0 , ivo + 1 )).value = ((p_float)pTResult2.pValue_get( 0 , ivo + 2 )).value / 2.0f + ( ((p_float)pTParam.pValue_get( 0 , ivo + 1 )).value + ((p_float)pTParam.pValue_get( 0 , ivo + 2 )).value ) / 4.0f ;
					
					((p_float)pTResult1.pValue_get( 0 , ivo + 3 )).value = ( ((p_float)pTResult1.pValue_get( 0 , ivo + 2 )).value + ((p_float)pTResult2.pValue_get( 0 , ivo + 1 )).value ) / 2.0f ;
					((p_float)pTResult2.pValue_get( 0 , ivo + 0 )).value = ((p_float)pTResult1.pValue_get( 0 , ivo + 3 )).value;
				}
			}
			else{
				for ( iu = 0; iu < 4; iu++ )
				{
					((p_float)pTResult1.pValue_get( 0 , 0 + iu )).value = ((p_float)pTParam.pValue_get( 0 , 0 + iu )).value;
					((p_float)pTResult1.pValue_get( 0 , 4 + iu )).value = ( ((p_float)pTParam.pValue_get( 0 , 0 + iu )).value + ((p_float)pTParam.pValue_get( 0 , 4 + iu )).value ) / 2.0f ;
					((p_float)pTResult1.pValue_get( 0 , 8 + iu )).value = ((p_float)pTResult1.pValue_get( 0 , 4 + iu )).value / 2.0f + ( ((p_float)pTParam.pValue_get( 0 , 4 + iu )).value + ((p_float)pTParam.pValue_get( 0 , 8 + iu )).value ) / 4.0f ;
					
					((p_float)pTResult2.pValue_get( 0 , 12 + iu )).value = ((p_float)pTParam.pValue_get(0 , 12 + iu )).value;
					((p_float)pTResult2.pValue_get( 0 , 8 + iu )).value = ( ((p_float)pTParam.pValue_get( 0 , 8 + iu )).value + ((p_float)pTParam.pValue_get( 0 , 12 + iu )).value ) / 2.0f ;
					((p_float)pTResult2.pValue_get( 0 , 4 + iu )).value = ((p_float)pTResult2.pValue_get( 0 , 8 + iu )).value / 2.0f + ( ((p_float)pTParam.pValue_get( 0 , 4 + iu )).value + ((p_float)pTParam.pValue_get( 0 , 8 + iu )).value ) / 4.0f ;
					
					((p_float)pTResult1.pValue_get( 0 , 12 + iu )).value = ( ((p_float)pTResult1.pValue_get( 0 , 8 + iu )).value + ((p_float)pTResult2.pValue_get( 0 , 4 + iu )).value ) / 2.0f ;
					((p_float)pTResult2.pValue_get( 0 , 0 + iu )).value = ((p_float)pTResult1.pValue_get( 0 , 12 + iu )).value;
				}
			}
		}
		else if( t instanceof CqVector3D ) 
		{
			if ( u ){
				for ( iv = 0; iv < 4; iv++ )
				{
					int ivo = ( iv * 4 );
					((CqVector3D)pTResult1.pValue_get( 0 , ivo + 0 )).assignment( (CqVector3D)pTParam.pValue_get( 0 , ivo + 0 ) );
					((CqVector3D)pTResult1.pValue_get( 0 , ivo + 1 )).assignment( ( ((CqVector3D)pTParam.pValue_get( 0 , ivo + 0 )).add( (CqVector3D)pTParam.pValue_get( 0 , ivo + 1 )) ).div( 2.0f ));
					((CqVector3D)pTResult1.pValue_get( 0 , ivo + 2 )).assignment( ( (((CqVector3D)pTResult1.pValue_get( 0 , ivo + 1 )).div( 2.0f )).add(( ((CqVector3D)pTParam.pValue_get( 0 , ivo + 1 )).add( (CqVector3D)pTParam.pValue_get( 0 , ivo + 2 )) ).div( 4.0f ) )));
					
					((CqVector3D)pTResult2.pValue_get( 0 , ivo + 3 )).assignment( (CqVector3D)pTParam.pValue_get( 0 , ivo + 3 ) );
					((CqVector3D)pTResult2.pValue_get( 0 , ivo + 2 )).assignment( (((CqVector3D)pTParam.pValue_get( 0 , ivo + 2 )).add( (CqVector3D)pTParam.pValue_get( 0 , ivo + 3 ) )).div( 2.0f ));
					((CqVector3D)pTResult2.pValue_get( 0 , ivo + 1 )).assignment( (((CqVector3D)pTResult2.pValue_get( 0 , ivo + 2 )).div( 2.0f )).add( (((CqVector3D)pTParam.pValue_get( 0 , ivo + 1 )).add( (CqVector3D)pTParam.pValue_get( 0 , ivo + 2 ))).div( 4.0f ) ));
					
					((CqVector3D)pTResult1.pValue_get( 0 , ivo + 3 )).assignment( ((((CqVector3D)pTResult1.pValue_get( 0 , ivo + 2 )).add( (CqVector3D)pTResult2.pValue_get( 0 , ivo + 1 ) )).div( 2.0f ) ));
					((CqVector3D)pTResult2.pValue_get( 0 , ivo + 0 )).assignment( (CqVector3D)pTResult1.pValue_get( 0 , ivo + 3 ) );
				}
			}
			else{
				for ( iu = 0; iu < 4; iu++ )
				{
					((CqVector3D)pTResult1.pValue_get( 0 , 0 + iu )).assignment( (CqVector3D)pTParam.pValue_get( 0 , 0 + iu ) );
					((CqVector3D)pTResult1.pValue_get( 0 , 4 + iu )).assignment( (((CqVector3D)pTParam.pValue_get( 0 , 0 + iu )).add( (CqVector3D)pTParam.pValue_get( 0 , 4 + iu )) ).div( 2.0f ) );
					((CqVector3D)pTResult1.pValue_get( 0 , 8 + iu )).assignment( (((CqVector3D)pTResult1.pValue_get( 0 , 4 + iu )).div( 2.0f )).add( (((CqVector3D)pTParam.pValue_get( 0 , 4 + iu )).add( (CqVector3D)pTParam.pValue_get( 0 , 8 + iu ))).div( 4.0f )) );
					
					((CqVector3D)pTResult2.pValue_get( 0 , 12 + iu )).assignment( (CqVector3D)pTParam.pValue_get( 0 , 12 + iu ) );
					((CqVector3D)pTResult2.pValue_get( 0 , 8 + iu )).assignment( (((CqVector3D)pTParam.pValue_get( 0 , 8 + iu )).add( (CqVector3D)pTParam.pValue_get( 0 , 12 + iu ))).div( 2.0f ) );
					((CqVector3D)pTResult2.pValue_get( 0 , 4 + iu )).assignment( (((CqVector3D)pTResult2.pValue_get( 0 , 8 + iu )).div( 2.0f )).add( (((CqVector3D)pTParam.pValue_get( 0 , 4 + iu )).add( (CqVector3D)pTParam.pValue_get( 0 , 8 + iu ) )).div( 4.0f ) ));
					
					((CqVector3D)pTResult1.pValue_get( 0 , 12 + iu )).assignment( (((CqVector3D)pTResult1.pValue_get( 0 , 8 + iu )).add( (CqVector3D)pTResult2.pValue_get( 0 , 4 + iu ) )).div( 2.0f ) );
					((CqVector3D)pTResult2.pValue_get( 0 , 0 + iu )).assignment( (CqVector3D)pTResult1.pValue_get( 0 , 12 + iu ) );
				}
			}
		}
		if( t instanceof CqVector4D ) 
		{
			if ( u ){
				for ( iv = 0; iv < 4; iv++ )
				{
					int ivo = ( iv * 4 );
					((CqVector4D)pTResult1.pValue_get( 0 , ivo + 0 )).assignment( (CqVector4D)pTParam.pValue_get( 0 , ivo + 0 ) );
					((CqVector4D)pTResult1.pValue_get( 0 , ivo + 1 )).assignment( ( ((CqVector4D)pTParam.pValue_get( 0 , ivo + 0 )).add( (CqVector4D)pTParam.pValue_get( 0 , ivo + 1 )) ).div( 2.0f ));
					((CqVector4D)pTResult1.pValue_get( 0 , ivo + 2 )).assignment( ( (((CqVector4D)pTResult1.pValue_get( 0 , ivo + 1 )).div( 2.0f )).add(( ((CqVector4D)pTParam.pValue_get( 0 , ivo + 1 )).add( (CqVector4D)pTParam.pValue_get( 0 , ivo + 2 )) ).div( 4.0f ) )));
					
					((CqVector4D)pTResult2.pValue_get( 0 , ivo + 3 )).assignment( (CqVector4D)pTParam.pValue_get( 0 , ivo + 3 ) );
					((CqVector4D)pTResult2.pValue_get( 0 , ivo + 2 )).assignment( (((CqVector4D)pTParam.pValue_get( 0 , ivo + 2 )).add( (CqVector4D)pTParam.pValue_get( 0 , ivo + 3 ) )).div( 2.0f ));
					((CqVector4D)pTResult2.pValue_get( 0 , ivo + 1 )).assignment( (((CqVector4D)pTResult2.pValue_get( 0 , ivo + 2 )).div( 2.0f )).add( (((CqVector4D)pTParam.pValue_get( 0 , ivo + 1 )).add( (CqVector4D)pTParam.pValue_get( 0 , ivo + 2 ))).div( 4.0f ) ));
					
					((CqVector4D)pTResult1.pValue_get( 0 , ivo + 3 )).assignment( ((((CqVector4D)pTResult1.pValue_get( 0 , ivo + 2 )).add( (CqVector4D)pTResult2.pValue_get( 0 , ivo + 1 ) )).div( 2.0f ) ));
					((CqVector4D)pTResult2.pValue_get( 0 , ivo + 0 )).assignment( (CqVector4D)pTResult1.pValue_get( 0 , ivo + 3 ) );
				}
			}
			else{
				for ( iu = 0; iu < 4; iu++ )
				{
					((CqVector4D)pTResult1.pValue_get( 0 , 0 + iu )).assignment( (CqVector4D)pTParam.pValue_get( 0 , 0 + iu ) );
					((CqVector4D)pTResult1.pValue_get( 0 , 4 + iu )).assignment( (((CqVector4D)pTParam.pValue_get( 0 , 0 + iu )).add( (CqVector4D)pTParam.pValue_get( 0 , 4 + iu )) ).div( 2.0f ) );
					((CqVector4D)pTResult1.pValue_get( 0 , 8 + iu )).assignment( (((CqVector4D)pTResult1.pValue_get( 0 , 4 + iu )).div( 2.0f )).add( (((CqVector4D)pTParam.pValue_get( 0 , 4 + iu )).add( (CqVector4D)pTParam.pValue_get( 0 , 8 + iu ))).div( 4.0f )) );
					
					((CqVector4D)pTResult2.pValue_get( 0 , 12 + iu )).assignment( (CqVector4D)pTParam.pValue_get( 0 , 12 + iu ) );
					((CqVector4D)pTResult2.pValue_get( 0 , 8 + iu )).assignment( (((CqVector4D)pTParam.pValue_get( 0 , 8 + iu )).add( (CqVector4D)pTParam.pValue_get( 0 , 12 + iu ))).div( 2.0f ) );
					((CqVector4D)pTResult2.pValue_get( 0 , 4 + iu )).assignment( (((CqVector4D)pTResult2.pValue_get( 0 , 8 + iu )).div( 2.0f )).add( (((CqVector4D)pTParam.pValue_get( 0 , 4 + iu )).add( (CqVector4D)pTParam.pValue_get( 0 , 8 + iu ) )).div( 4.0f ) ));
					
					((CqVector4D)pTResult1.pValue_get( 0 , 12 + iu )).assignment( (((CqVector4D)pTResult1.pValue_get( 0 , 8 + iu )).add( (CqVector4D)pTResult2.pValue_get( 0 , 4 + iu ) )).div( 2.0f ) );
					((CqVector4D)pTResult2.pValue_get( 0 , 0 + iu )).assignment( (CqVector4D)pTResult1.pValue_get( 0 , 12 + iu ) );
				}
			}
		}
		if( t instanceof CqColor ) 
		{
			if ( u ){
				for ( iv = 0; iv < 4; iv++ )
				{
					int ivo = ( iv * 4 );
					((CqColor)pTResult1.pValue_get( 0 , ivo + 0 )).assignment( (CqColor)pTParam.pValue_get( 0 , ivo + 0 ) );
					((CqColor)pTResult1.pValue_get( 0 , ivo + 1 )).assignment( ( ((CqColor)pTParam.pValue_get( 0 , ivo + 0 )).add( (CqColor)pTParam.pValue_get( 0 , ivo + 1 )) ).div( 2.0f ));
					((CqColor)pTResult1.pValue_get( 0 , ivo + 2 )).assignment( ( (((CqColor)pTResult1.pValue_get( 0 , ivo + 1 )).div( 2.0f )).add(( ((CqColor)pTParam.pValue_get( 0 , ivo + 1 )).add( (CqColor)pTParam.pValue_get( 0 , ivo + 2 )) ).div( 4.0f ) )));
					
					((CqColor)pTResult2.pValue_get( 0 , ivo + 3 )).assignment( (CqColor)pTParam.pValue_get( 0 , ivo + 3 ) );
					((CqColor)pTResult2.pValue_get( 0 , ivo + 2 )).assignment( (((CqColor)pTParam.pValue_get( 0 , ivo + 2 )).add( (CqColor)pTParam.pValue_get( 0 , ivo + 3 ) )).div( 2.0f ));
					((CqColor)pTResult2.pValue_get( 0 , ivo + 1 )).assignment( (((CqColor)pTResult2.pValue_get( 0 , ivo + 2 )).div( 2.0f )).add( (((CqColor)pTParam.pValue_get( 0 , ivo + 1 )).add( (CqColor)pTParam.pValue_get( 0 , ivo + 2 ))).div( 4.0f ) ));
					
					((CqColor)pTResult1.pValue_get( 0 , ivo + 3 )).assignment( ((((CqColor)pTResult1.pValue_get( 0 , ivo + 2 )).add( (CqColor)pTResult2.pValue_get( 0 , ivo + 1 ) )).div( 2.0f ) ));
					((CqColor)pTResult2.pValue_get( 0 , ivo + 0 )).assignment( (CqColor)pTResult1.pValue_get( 0 , ivo + 3 ) );
				}
			}
			else{
				for ( iu = 0; iu < 4; iu++ )
				{
					((CqColor)pTResult1.pValue_get( 0 , 0 + iu )).assignment( (CqColor)pTParam.pValue_get( 0 , 0 + iu ) );
					((CqColor)pTResult1.pValue_get( 0 , 4 + iu )).assignment( (((CqColor)pTParam.pValue_get( 0 , 0 + iu )).add( (CqColor)pTParam.pValue_get( 0 , 4 + iu )) ).div( 2.0f ) );
					((CqColor)pTResult1.pValue_get( 0 , 8 + iu )).assignment( (((CqColor)pTResult1.pValue_get( 0 , 4 + iu )).div( 2.0f )).add( (((CqColor)pTParam.pValue_get( 0 , 4 + iu )).add( (CqColor)pTParam.pValue_get( 0 , 8 + iu ))).div( 4.0f )) );
					
					((CqColor)pTResult2.pValue_get( 0 , 12 + iu )).assignment( (CqColor)pTParam.pValue_get( 0 , 12 + iu ) );
					((CqColor)pTResult2.pValue_get( 0 , 8 + iu )).assignment( (((CqColor)pTParam.pValue_get( 0 , 8 + iu )).add( (CqColor)pTParam.pValue_get( 0 , 12 + iu ))).div( 2.0f ) );
					((CqColor)pTResult2.pValue_get( 0 , 4 + iu )).assignment( (((CqColor)pTResult2.pValue_get( 0 , 8 + iu )).div( 2.0f )).add( (((CqColor)pTParam.pValue_get( 0 , 4 + iu )).add( (CqColor)pTParam.pValue_get( 0 , 8 + iu ) )).div( 4.0f ) ));
					
					((CqColor)pTResult1.pValue_get( 0 , 12 + iu )).assignment( (((CqColor)pTResult1.pValue_get( 0 , 8 + iu )).add( (CqColor)pTResult2.pValue_get( 0 , 4 + iu ) )).div( 2.0f ) );
					((CqColor)pTResult2.pValue_get( 0 , 0 + iu )).assignment( (CqColor)pTResult1.pValue_get( 0 , 12 + iu ) );
				}
			}
		}
		if( t instanceof CqMatrix ) 
		{
			if ( u ){
				for ( iv = 0; iv < 4; iv++ )
				{
					int ivo = ( iv * 4 );
					((CqMatrix)pTResult1.pValue_get( 0 , ivo + 0 )).assignment( (CqMatrix)pTParam.pValue_get( 0 , ivo + 0 ) );
					((CqMatrix)pTResult1.pValue_get( 0 , ivo + 1 )).assignment( ( ((CqMatrix)pTParam.pValue_get( 0 , ivo + 0 )).add( (CqMatrix)pTParam.pValue_get( 0 , ivo + 1 )) ).mulInv( 0.5f ));
					((CqMatrix)pTResult1.pValue_get( 0 , ivo + 2 )).assignment( ( (((CqMatrix)pTResult1.pValue_get( 0 , ivo + 1 )).mulInv( 0.5f )).add(( ((CqMatrix)pTParam.pValue_get( 0 , ivo + 1 )).add( (CqMatrix)pTParam.pValue_get( 0 , ivo + 2 )) ).mulInv( 0.25f ) )));
					
					((CqMatrix)pTResult2.pValue_get( 0 , ivo + 3 )).assignment( (CqMatrix)pTParam.pValue_get( 0 , ivo + 3 ) );
					((CqMatrix)pTResult2.pValue_get( 0 , ivo + 2 )).assignment( (((CqMatrix)pTParam.pValue_get( 0 , ivo + 2 )).add( (CqMatrix)pTParam.pValue_get( 0 , ivo + 3 ) )).mulInv( 0.5f ));
					((CqMatrix)pTResult2.pValue_get( 0 , ivo + 1 )).assignment( (((CqMatrix)pTResult2.pValue_get( 0 , ivo + 2 )).mulInv( 0.5f )).add( (((CqMatrix)pTParam.pValue_get( 0 , ivo + 1 )).add( (CqMatrix)pTParam.pValue_get( 0 , ivo + 2 ))).mulInv( 0.25f ) ));
					
					((CqMatrix)pTResult1.pValue_get( 0 , ivo + 3 )).assignment( ((((CqMatrix)pTResult1.pValue_get( 0 , ivo + 2 )).add( (CqMatrix)pTResult2.pValue_get( 0 , ivo + 1 ) )).mulInv( 0.5f ) ));
					((CqMatrix)pTResult2.pValue_get( 0 , ivo + 0 )).assignment( (CqMatrix)pTResult1.pValue_get( 0 , ivo + 3 ) );
				}
			}
			else{
				for ( iu = 0; iu < 4; iu++ )
				{
					((CqMatrix)pTResult1.pValue_get( 0 , 0 + iu )).assignment( (CqMatrix)pTParam.pValue_get( 0 , 0 + iu ) );
					((CqMatrix)pTResult1.pValue_get( 0 , 4 + iu )).assignment( (((CqMatrix)pTParam.pValue_get( 0 , 0 + iu )).add( (CqMatrix)pTParam.pValue_get( 0 , 4 + iu )) ).mulInv( 0.5f ) );
					((CqMatrix)pTResult1.pValue_get( 0 , 8 + iu )).assignment( (((CqMatrix)pTResult1.pValue_get( 0 , 4 + iu )).mulInv( 0.5f )).add( (((CqMatrix)pTParam.pValue_get( 0 , 4 + iu )).add( (CqMatrix)pTParam.pValue_get( 0 , 8 + iu ))).mulInv( 0.25f )) );
					
					((CqMatrix)pTResult2.pValue_get( 0 , 12 + iu )).assignment( (CqMatrix)pTParam.pValue_get( 0 , 12 + iu ) );
					((CqMatrix)pTResult2.pValue_get( 0 , 8 + iu )).assignment( (((CqMatrix)pTParam.pValue_get( 0 , 8 + iu )).add( (CqMatrix)pTParam.pValue_get( 0 , 12 + iu ))).mulInv( 0.5f ) );
					((CqMatrix)pTResult2.pValue_get( 0 , 4 + iu )).assignment( (((CqMatrix)pTResult2.pValue_get( 0 , 8 + iu )).mulInv( 0.5f )).add( (((CqMatrix)pTParam.pValue_get( 0 , 4 + iu )).add( (CqMatrix)pTParam.pValue_get( 0 , 8 + iu ) )).mulInv( 0.25f ) ));
					
					((CqMatrix)pTResult1.pValue_get( 0 , 12 + iu )).assignment( (((CqMatrix)pTResult1.pValue_get( 0 , 8 + iu )).add( (CqMatrix)pTResult2.pValue_get( 0 , 4 + iu ) )).mulInv( 0.5f ) );
					((CqMatrix)pTResult2.pValue_get( 0 , 0 + iu )).assignment( (CqMatrix)pTResult1.pValue_get( 0 , 12 + iu ) );
				}
			}
		}
		if( t instanceof p_int )
		{
			if ( u ){
				for ( iv = 0; iv < 4; iv++ )
				{
					int ivo = ( iv * 4 );
					((p_int)pTResult1.pValue_get( 0 , ivo + 0 )).value = ((p_int)pTParam.pValue_get( 0 , ivo + 0 )).value;
					((p_int)pTResult1.pValue_get( 0 , ivo + 1 )).value = (int)( ( ((p_int)pTParam.pValue_get( 0 , ivo + 0 )).value + ((p_int)pTParam.pValue_get( 0 , ivo + 1 )).value ) / 2.0f ) ;
					((p_int)pTResult1.pValue_get( 0 , ivo + 2 )).value = (int)(((p_int)pTResult1.pValue_get( 0 , ivo + 1 )).value / 2.0f + ( ((p_int)pTParam.pValue_get( 0 , ivo + 1 )).value + ((p_int)pTParam.pValue_get( 0 , ivo + 2 )).value ) / 4.0f ) ;
					
					((p_int)pTResult2.pValue_get( 0 , ivo + 3 )).value = ((p_int)pTParam.pValue_get( 0 , ivo + 3 )).value;
					((p_int)pTResult2.pValue_get( 0 , ivo + 2 )).value = (int)( ( ((p_int)pTParam.pValue_get( 0 , ivo + 2 )).value + ((p_int)pTParam.pValue_get( 0 , ivo + 3 )).value ) / 2.0f ) ;
					((p_int)pTResult2.pValue_get( 0 , ivo + 1 )).value = (int)(((p_int)pTResult2.pValue_get( 0 , ivo + 2 )).value / 2.0f + ( ((p_int)pTParam.pValue_get( 0 , ivo + 1 )).value + ((p_int)pTParam.pValue_get( 0 , ivo + 2 )).value ) / 4.0f ) ;
					
					((p_int)pTResult1.pValue_get( 0 , ivo + 3 )).value = (int)( ( ((p_int)pTResult1.pValue_get( 0 , ivo + 2 )).value + ((p_int)pTResult2.pValue_get( 0 , ivo + 1 )).value ) / 2.0f ) ;
					((p_int)pTResult2.pValue_get( 0 , ivo + 0 )).value = ((p_int)pTResult1.pValue_get( 0 , ivo + 3 )).value;
				}
			}
			else{
				for ( iu = 0; iu < 4; iu++ )
				{
					((p_int)pTResult1.pValue_get( 0 , 0 + iu )).value = ((p_int)pTParam.pValue_get( 0 , 0 + iu )).value;
					((p_int)pTResult1.pValue_get( 0 , 4 + iu )).value = (int)( ( ((p_int)pTParam.pValue_get( 0 , 0 + iu )).value + ((p_int)pTParam.pValue_get( 0 , 4 + iu )).value ) / 2.0f ) ;
					((p_int)pTResult1.pValue_get( 0 , 8 + iu )).value = (int)(((p_int)pTResult1.pValue_get( 0 , 4 + iu )).value / 2.0f + ( ((p_int)pTParam.pValue_get( 0 , 4 + iu )).value + ((p_int)pTParam.pValue_get( 0 , 8 + iu )).value ) / 4.0f );
					
					((p_int)pTResult2.pValue_get( 0 , 12 + iu )).value = ((p_int)pTParam.pValue_get( 0 , 12 + iu )).value;
					((p_int)pTResult2.pValue_get( 0 , 8 + iu )).value = (int)( ( ((p_int)pTParam.pValue_get( 0 , 8 + iu )).value + ((p_int)pTParam.pValue_get( 0 , 12 + iu )).value ) / 2.0f ) ;
					((p_int)pTResult2.pValue_get( 0 , 4 + iu )).value = (int)(((p_int)pTResult2.pValue_get( 0 , 8 + iu )).value / 2.0f + ( ((p_int)pTParam.pValue_get( 0 , 4 + iu )).value + ((p_int)pTParam.pValue_get( 0 , 8 + iu )).value ) / 4.0f );
					
					((p_int)pTResult1.pValue_get( 0 , 12 + iu )).value = (int)( ( ((p_int)pTResult1.pValue_get( 0 , 8 + iu )).value + ((p_int)pTResult2.pValue_get( 0 , 4 + iu )).value ) / 2.0f ) ;
					((p_int)pTResult2.pValue_get( 0 , 0 + iu )).value = ((p_int)pTResult1.pValue_get( 0 , 12 + iu )).value;
				}
			}
		}
		if( t instanceof p_String )
		{
			if ( u ){
				for ( iv = 0; iv < 4; iv++ )
				{
					int ivo = ( iv * 4 );
					((p_String)pTResult1.pValue_get( 0 , ivo + 0 )).value = ((p_String)pTParam.pValue_get( 0 , ivo + 0 )).value;
					((p_String)pTResult1.pValue_get( 0 , ivo + 1 )).value = ((p_String)pTParam.pValue_get( 0 , ivo + 0 )).value + ((p_String)pTParam.pValue_get( 0 , ivo + 1 )).value ;
					((p_String)pTResult1.pValue_get( 0 , ivo + 2 )).value = ((p_String)pTResult1.pValue_get( 0 , ivo + 1 )).value + ((p_String)pTParam.pValue_get( 0 , ivo + 1 )).value + ((p_String)pTParam.pValue_get( 0 , ivo + 2 )).value ;
					
					((p_String)pTResult2.pValue_get( 0 , ivo + 3 )).value = ((p_String)pTParam.pValue_get( 0 , ivo + 3 )).value;
					((p_String)pTResult2.pValue_get( 0 , ivo + 2 )).value = ((p_String)pTParam.pValue_get( 0 , ivo + 2 )).value + ((p_String)pTParam.pValue_get( 0 , ivo + 3 )).value ;
					((p_String)pTResult2.pValue_get( 0 , ivo + 1 )).value = ((p_String)pTResult2.pValue_get( 0 , ivo + 2 )).value + ((p_String)pTParam.pValue_get( 0 , ivo + 1 )).value + ((p_String)pTParam.pValue_get( 0 , ivo + 2 )).value ;
					
					((p_String)pTResult1.pValue_get( 0 , ivo + 3 )).value = ((p_String)pTResult1.pValue_get( 0 , ivo + 2 )).value + ((p_String)pTResult2.pValue_get( 0 , ivo + 1 )).value ;
					((p_String)pTResult2.pValue_get( 0 , ivo + 0 )).value = ((p_String)pTResult1.pValue_get( 0 , ivo + 3 )).value;
				}
			}
			else{
				for ( iu = 0; iu < 4; iu++ )
				{
					((p_String)pTResult1.pValue_get( 0 , 0 + iu )).value = ((p_String)pTParam.pValue_get( 0 , 0 + iu )).value;
					((p_String)pTResult1.pValue_get( 0 , 4 + iu )).value = ((p_String)pTParam.pValue_get( 0 , 0 + iu )).value + ((p_String)pTParam.pValue_get( 0 , 4 + iu )).value ;
					((p_String)pTResult1.pValue_get( 0 , 8 + iu )).value = ((p_String)pTResult1.pValue_get( 0 , 4 + iu )).value + ((p_String)pTParam.pValue_get( 0 , 4 + iu )).value + ((p_String)pTParam.pValue_get( 0 , 8 + iu )).value ;
					
					((p_String)pTResult2.pValue_get( 0 , 12 + iu )).value = ((p_String)pTParam.pValue_get( 0 , 12 + iu )).value;
					((p_String)pTResult2.pValue_get( 0 , 8 + iu )).value = ((p_String)pTParam.pValue_get( 0 , 8 + iu )).value + ((p_String)pTParam.pValue_get( 0 , 12 + iu )).value ;
					((p_String)pTResult2.pValue_get( 0 , 4 + iu )).value = ((p_String)pTResult2.pValue_get( 0 , 8 + iu )).value + ((p_String)pTParam.pValue_get( 0 , 4 + iu )).value + ((p_String)pTParam.pValue_get( 0 , 8 + iu )).value ;
					
					((p_String)pTResult1.pValue_get( 0 , 12 + iu )).value = ((p_String)pTResult1.pValue_get( 0 , 8 + iu )).value + ((p_String)pTResult2.pValue_get( 0 , 4 + iu )).value ;
					((p_String)pTResult2.pValue_get( 0 , 0 + iu )).value = ((p_String)pTResult1.pValue_get( 0 , 12 + iu )).value;
				}
			}
		}
	}
	
	/** 
	 * Get a reference to the indexed control point.
	 * 
	 * @param iRow Integer row index.
	 * @param iCol Integer column index.
	 * @return CqVector4D reference.
	 */
	public final CqVector4D CP( int iRow, int iCol ) 
	{
		return ((CqVector4D) P().pValue_get( ( iRow * 4 ) + iCol , 0 ) );
	}
	
	/**
	 * 代入演算子のオーバーロード
	 * 
	 * @param From	代入元
	 * @return	自身
	 */
	public CqSurfacePatchBicubic assignment( final CqSurfacePatchBicubic From )
	{
		// Perform per surface copy function
		super.assignment( From );
		
		//	TqInt i;
		//	for(i=0; i<16; i++)
		//		P()[i]=From.P()[i];
		
		return ( this );
	}
	
	/**
	 *  Get the boundary extents in camera space of the surface patch
	 * @see net.cellcomputing.himawari.library.IqSurface#Bound()
	 */
	public	CqBound	Bound() 
	{
		// Get the boundary in camera space.
		CqVector3D	vecA = new CqVector3D( MAX_VALUE, MAX_VALUE, MAX_VALUE );
		CqVector3D	vecB = new CqVector3D( -MAX_VALUE, -MAX_VALUE, -MAX_VALUE );
		
		for ( int i = 0; i < 16; i++ )
		{
			CqVector3D	vecV = new CqVector3D( (CqVector4D)P().pValue_get( i , 0 ) );
			if ( vecV.x < vecA.x ) vecA.x( vecV.x );
			if ( vecV.y < vecA.y ) vecA.y( vecV.y );
			if ( vecV.x > vecB.x ) vecB.x( vecV.x );
			if ( vecV.y > vecB.y ) vecB.y( vecV.y );
			if ( vecV.z < vecA.z ) vecA.z( vecV.z );
			if ( vecV.z > vecB.z ) vecB.z( vecV.z );
		}
		CqBound	B = new CqBound();
		B.vecMin().assignment( vecA );
		B.vecMax().assignment( vecB );
		return ( AdjustBoundForTransformationMotion( B ) );
	}
	
	/**
	 * Determine whether or not the patch is diceable
	 * @see net.cellcomputing.himawari.library.CqBasicSurface#Diceable()
	 */
	public boolean	 Diceable()
	{
		assert( null != P() );
		// If the cull check showed that the primitive cannot be diced due to crossing the e and hither planes,
		// then we can return immediately.
		if ( !m_fDiceable )
			return ( false );
		
		// Otherwise we should continue to try to find the most advantageous split direction, OR the dice size.
		final CqMatrix  matCtoR = QGetRenderContext().matSpaceToSpace( "camera", "raster", new CqMatrix(), new CqMatrix(), QGetRenderContext().Time() );
	
		// Convert the control hull to raster space.
		CqVector2D avecHull[] = new CqVector2D[ 16 ];
		
		float ShadingRate = pAttributes().GetFloatAttribute( "System", "ShadingRate" ) [ 0 ];
		
		int i = 0;
		for ( i = 0; i < 16; i++ ) 
			avecHull[ i ] = new CqVector2D( matCtoR.multiply( ((CqVector4D)P().pValue_get( i , 0 ) ))) ;
			
			// First check flatness, a curve which is too far off flat will
			// produce unreliable results when the length is approximated below.
			m_SplitDir.setValue( SplitDir_U );
		int u;
		for ( u = 0; u < 16; u += 4 )
		{
			// Find an initial line
			float Len = 0;
			CqVector2D	vec0 = new CqVector2D( avecHull[ u ] );
			CqVector2D	vecL = new CqVector2D();
			i = 4;
			while ( i-- > 0 && Len < Float_h.FLT_EPSILON)
			{
				vecL = avecHull[ u + i ].sub( vec0 );
				Len = vecL.Magnitude();
			}
			vecL.assignDiv( Len );	// Normalise 
			i = 0;
			while ( ++i < 4 )
			{
				// Get the distance to the line for each point
				if( u + i == 16 ) break;
				CqVector3D	vec = new CqVector3D( avecHull[ u + i ].sub( vec0 ));
				vec.Unit();
				vec.assignMod( new CqVector3D( vecL )); 
				if ( vec.Magnitude() > 1 ) return ( false );
			}
		}
		m_SplitDir.setValue( SplitDir_V );
		int v;
		for ( v = 0; v < 4; v++ )
		{
			// Find an initial line
			float Len = 0;
			CqVector2D	vec0 = new CqVector2D( avecHull[ v ] );
			CqVector2D	vecL = new CqVector2D();
			i = 4;
			while ( i-- > 0 && Len < Float_h.FLT_EPSILON)
			{
				vecL = avecHull[ v + ( i * 4 ) ].sub( vec0 );
				Len = vecL.Magnitude();
			}
			vecL.assignDiv( Len );	// Normalise
			i = 0;
			while ( ++i < 4 )
			{
				// Get the distance to the line for each point
				if( v + ( i * 4 ) >= 16 ) break;
				CqVector3D	vec = new CqVector3D( avecHull[ v + ( i * 4 )].sub( vec0 ));
				vec.Unit();
				vec.assignMod( new CqVector3D( vecL ));
				if ( vec.Magnitude() > 1 ) 
					return ( false );
			}
		}
		
		float uLen = 0;
		float vLen = 0;
		for ( u = 0; u < 16; u += 4 )
		{
			CqVector2D	Vec1 = new CqVector2D( avecHull[ u + 1 ].sub( avecHull[ u ] ));
			CqVector2D	Vec2 = new CqVector2D( avecHull[ u + 2 ].sub( avecHull[ u + 1 ] ));
			CqVector2D	Vec3 = new CqVector2D( avecHull[ u + 3 ].sub( avecHull[ u + 2 ] ));
			if ( Vec1.Magnitude2() > uLen ) uLen = Vec1.Magnitude2();
			if ( Vec2.Magnitude2() > uLen ) uLen = Vec2.Magnitude2();
			if ( Vec3.Magnitude2() > uLen ) uLen = Vec3.Magnitude2();
		}
		for ( v = 0; v < 4; v++ )
		{
			CqVector2D	Vec1 = new CqVector2D( avecHull[ v + 4 ].sub( avecHull[ v ] ));
			CqVector2D	Vec2 = new CqVector2D( avecHull[ v + 8 ].sub( avecHull[ v + 4 ] ));
			CqVector2D	Vec3 = new CqVector2D( avecHull[ v + 12 ].sub( avecHull[ v + 8 ] ));
			if ( Vec1.Magnitude2() > vLen ) vLen = Vec1.Magnitude2();
			if ( Vec2.Magnitude2() > vLen ) vLen = Vec2.Magnitude2();
			if ( Vec3.Magnitude2() > vLen ) vLen = Vec3.Magnitude2();
		}
		
		if( ShadingRate>0 ){
			uLen = (float) sqrt( uLen  / ShadingRate);
			vLen = (float) sqrt( vLen  / ShadingRate);
		}
		else{
			uLen = 0;
			vLen = 0;
		}
		
		m_SplitDir.setValue( ( uLen > vLen ) ? SplitDir_U : SplitDir_V );
		// TODO: Should ensure powers of half to prevent cracking.
		uLen *= 3;
		vLen *= 3;
		m_uDiceSize = max( round( uLen ), 1 ) ;
		m_vDiceSize = max( round( vLen ), 1 ) ;
		
		// Ensure power of 2 to avoid cracking
		final int[] binary = pAttributes().GetIntegerAttribute( "dice", "binary" );
		if ( binary != null && binary[0] != 0)
		{
			m_uDiceSize = (int) CEIL_POW2( m_uDiceSize );
			m_vDiceSize = (int) CEIL_POW2( m_vDiceSize );
		}
		if ( uLen < FLT_EPSILON || vLen < FLT_EPSILON )
		{
			m_fDiscard = true;
			return ( false );
		}
		
		float gs = 16.0f;
		final float poptGridSize[] = QGetRenderContext().optCurrent().GetFloatOption( "System", "SqrtGridSize" );
		if( null != poptGridSize )
			gs = poptGridSize[0];
		
		if( m_uDiceSize * m_vDiceSize > gs * gs )
			return false;
		
		return ( true );
	}
	
	/**
	 * Determine whether the passed surface is valid to be used as a
	 * frame in motion blur for this surface.
	 * @see net.cellcomputing.himawari.library.CqBasicSurface#IsMotionBlurMatch(net.cellcomputing.himawari.library.CqBasicSurface)
	 */
	public boolean IsMotionBlurMatch( CqBasicSurface pSurf )
	{
		return( false );
	}
	
	public int cUniform() 
	{
		return ( 1 );
	}
	public int cVarying() 
	{
		return ( 4 );
	}
	public int cVertex() 
	{
		return ( 16 );
	}
	public int cFaceVarying() 
	{
		//TODO Must work out what this value should be.
		return ( 1 );
	}
	
	/**
	 * Dice the patch into a mesh of micropolygons.
	 * @see net.cellcomputing.himawari.library.IqSurface#NaturalDice(net.cellcomputing.himawari.library.CqParameter, int, int, net.cellcomputing.himawari.library.IqShaderData)
	 */
	@SuppressWarnings("unchecked")
	public void NaturalDice( CqParameter pParameter, int uDiceSize, int vDiceSize, IqShaderData pData )
	{
		switch ( pParameter.Type().getValue() )
		{
		case type_float:
		{
			CqParameterTyped<p_float, p_float> pTParam = ( CqParameterTyped<p_float, p_float> ) pParameter ;
			TypedNaturalDice( uDiceSize, vDiceSize, pTParam, pData );
			break;
		}
		case type_integer:
		{
			CqParameterTyped<p_int, p_float> pTParam = ( CqParameterTyped<p_int, p_float> ) pParameter ;
			TypedNaturalDice( uDiceSize, vDiceSize, pTParam, pData );
			break;
		}
		case type_point:
		case type_vector:
		case type_normal:
		{
			CqParameterTyped<CqVector3D, CqVector3D> pTParam = ( CqParameterTyped<CqVector3D, CqVector3D> ) pParameter ;
			TypedNaturalDice( uDiceSize, vDiceSize, pTParam, pData );
			break;
		}
		case type_hpoint:
		{
			CqParameterTyped<CqVector4D, CqVector3D> pTParam = ( CqParameterTyped<CqVector4D, CqVector3D> ) pParameter ;
			TypedNaturalDice( uDiceSize, vDiceSize, pTParam, pData );
			break;
		}
		case type_color:
		{
			CqParameterTyped<CqColor, CqColor> pTParam = ( CqParameterTyped<CqColor, CqColor> ) pParameter ;
			TypedNaturalDice( uDiceSize, vDiceSize, pTParam, pData );
			break;
		}
		case type_string:
		{
			CqParameterTyped<p_String, p_String> pTParam = ( CqParameterTyped<p_String, p_String> ) pParameter ;
			TypedNaturalDice( uDiceSize, vDiceSize, pTParam, pData );
			break;
		}
		case type_matrix:
		{
			CqParameterTyped<CqMatrix, CqMatrix> pTParam = ( CqParameterTyped<CqMatrix, CqMatrix> ) pParameter ;
			TypedNaturalDice( uDiceSize, vDiceSize, pTParam, pData );
			break;
		}
		default:
		{
			// left blank to avoid compiler warnings about unhandled types
			break;
		}
		}
	}
	
	/**
	 *  Split the patch into smaller patches.
	 * @see net.cellcomputing.himawari.library.IqSurface#PreSubdivide(net.cellcomputing.himawari.accessory.STLVector, boolean)
	 */
	public int PreSubdivide( STLVector<CqBasicSurface> aSplits, boolean u )
	{
		// Create two new surface of the appropriate type
		aSplits.add( new CqSurfacePatchBicubic() );
		aSplits.add( new CqSurfacePatchBicubic() );
		
		return ( 2 );
	}
	
	/* (non-Javadoc)
	 * @see net.cellcomputing.himawari.library.IqSurface#NaturalSubdivide(net.cellcomputing.himawari.library.CqParameter, net.cellcomputing.himawari.library.CqParameter, net.cellcomputing.himawari.library.CqParameter, boolean)
	 */
	@SuppressWarnings("unchecked")
	public void NaturalSubdivide( CqParameter pParam, CqParameter pParam1, CqParameter pParam2, boolean u )
	{
		switch ( pParam.Type().getValue() )
		{
		case type_float:
		{
			CqParameterTyped<p_float, p_float> pTParam = ( CqParameterTyped<p_float, p_float> ) pParam ;
			CqParameterTyped<p_float, p_float> pTResult1 = ( CqParameterTyped<p_float, p_float> ) pParam1 ;
			CqParameterTyped<p_float, p_float> pTResult2 = ( CqParameterTyped<p_float, p_float> ) pParam2 ;
			TypedNaturalSubdivide( pTParam, pTResult1, pTResult2, u );
			break;
		}
		case type_integer:
		{
			CqParameterTyped<p_int, p_float> pTParam = ( CqParameterTyped<p_int, p_float> ) pParam ;
			CqParameterTyped<p_int, p_float> pTResult1 = ( CqParameterTyped<p_int, p_float> ) pParam1 ;
			CqParameterTyped<p_int, p_float> pTResult2 = ( CqParameterTyped<p_int, p_float> ) pParam2 ;
			TypedNaturalSubdivide( pTParam, pTResult1, pTResult2, u );
			break;
		}
		case type_point:
		case type_vector:
		case type_normal:
		{
			CqParameterTyped<CqVector3D, CqVector3D> pTParam = ( CqParameterTyped<CqVector3D, CqVector3D> ) pParam ;
			CqParameterTyped<CqVector3D, CqVector3D> pTResult1 = ( CqParameterTyped<CqVector3D, CqVector3D> ) pParam1 ;
			CqParameterTyped<CqVector3D, CqVector3D> pTResult2 = ( CqParameterTyped<CqVector3D, CqVector3D> ) pParam2 ;
			TypedNaturalSubdivide( pTParam, pTResult1, pTResult2, u );
			break;
		}
		case type_hpoint:
		{
			CqParameterTyped<CqVector4D, CqVector3D> pTParam = ( CqParameterTyped<CqVector4D, CqVector3D> ) pParam ;
			CqParameterTyped<CqVector4D, CqVector3D> pTResult1 = ( CqParameterTyped<CqVector4D, CqVector3D> ) pParam1 ;
			CqParameterTyped<CqVector4D, CqVector3D> pTResult2 = ( CqParameterTyped<CqVector4D, CqVector3D> ) pParam2 ;
			TypedNaturalSubdivide( pTParam, pTResult1, pTResult2, u );
			break;
		}
		case type_color:
		{
			CqParameterTyped<CqColor, CqColor> pTParam = ( CqParameterTyped<CqColor, CqColor> ) pParam ;
			CqParameterTyped<CqColor, CqColor> pTResult1 = ( CqParameterTyped<CqColor, CqColor> ) pParam1 ;
			CqParameterTyped<CqColor, CqColor> pTResult2 = ( CqParameterTyped<CqColor, CqColor> ) pParam2 ;
			TypedNaturalSubdivide( pTParam, pTResult1, pTResult2, u );
			break;
		}
		case type_string:
		{
			CqParameterTyped<p_String, p_String> pTParam = ( CqParameterTyped<p_String, p_String> ) pParam ;
			CqParameterTyped<p_String, p_String> pTResult1 = ( CqParameterTyped<p_String, p_String> ) pParam1 ;
			CqParameterTyped<p_String, p_String> pTResult2 = ( CqParameterTyped<p_String, p_String> ) pParam2 ;
			TypedNaturalSubdivide( pTParam, pTResult1, pTResult2, u );
			break;
		}
		case type_matrix:
		{
			//			CqParameterTyped<CqMatrix, CqMatrix>* pTParam = static_cast<CqParameterTyped<CqMatrix, CqMatrix>*>( pParam );
			//			CqParameterTyped<CqMatrix, CqMatrix>* pTResult1 = static_cast<CqParameterTyped<CqMatrix, CqMatrix>*>( pParam1 );
			//			CqParameterTyped<CqMatrix, CqMatrix>* pTResult2 = static_cast<CqParameterTyped<CqMatrix, CqMatrix>*>( pParam2 );
			//			TypedNaturalSubdivide( pTParam, pTResult1, pTResult2, u );
			//			break;
		}
		default:
		{
			// left blank to avoid compiler warnings about unhandled types
			break;
		}
		}
	}
	
	/**
	 * Convert from the current basis into Bezier for processing.
	 * 
	 * 
	 * @param matuBasis
	 * @param matvBasis
	 */
	@SuppressWarnings("unchecked")
	public void	ConvertToBezierBasis( CqMatrix matuBasis, CqMatrix matvBasis )
	{
//		static CqMatrix matMim1 = new CqMatrix();
		CqMatrix matMim1 = new CqMatrix();
		int i, j;
		
		if ( matMim1.fIdentity() )
		{
			for ( i = 0; i < 4; i++ )
				for ( j = 0; j < 4; j++ )
					matMim1.m_aaElement[ i ][ j ]  = RiBezierBasis[ i ][ j ] ;
			matMim1.SetfIdentity( false );
			matMim1 = matMim1.Inverse();
		}
		
		CqMatrix matuMj = matuBasis;
		CqMatrix matvMj = matvBasis;
		
		CqMatrix matuConv = matuMj.multiply( matMim1 );
		CqMatrix matvConv = matvMj.multiply( matMim1 );
		
		for ( CqParameter iUP : aUserParams() )
		{
			if ( iUP.Class().getValue() == class_vertex )
			{
				int ptype = iUP.Type().getValue();
				switch( ptype )
				{
				case type_point:
				case type_vector:	///! \todo Not sure if this is correct, do vectors and normals need to be treated differently?
				case type_normal:	///! \todo Not sure if this is correct, do vectors and normals need to be treated differently?
				{
					// Get the parameter pointer as the correct type.
					CqParameterTyped<CqVector3D, CqVector3D> pParam = ( CqParameterTyped<CqVector3D, CqVector3D> ) iUP ;
					
					// Store the data into a matrix for conversion.
					CqMatrix matCPx = new CqMatrix();
					CqMatrix matCPy = new CqMatrix();
					CqMatrix matCPz = new CqMatrix();
					CqMatrix matCPh = new CqMatrix();
					for ( i = 0; i < 4; i++ )
					{
						for ( j = 0; j < 4; j++ )
						{
							matCPx.m_aaElement[ i ][ j ] = ((CqVector3D)pParam.pValue_get( i*4 + j ,0)).valueAt(0) ;
							matCPy.m_aaElement[ i ][ j ] =  ((CqVector3D)pParam.pValue_get( i*4 + j ,0)).valueAt(1) ;
							matCPz.m_aaElement[ i ][ j ] =  ((CqVector3D)pParam.pValue_get( i*4 + j ,0)).valueAt(2) ;
							matCPh.m_aaElement[ i ][ j ] =  1.0f ;
						}
					}
					matCPx.SetfIdentity( false );	matCPy.SetfIdentity( false );
					matCPz.SetfIdentity( false );	matCPh.SetfIdentity( false );
					
					matCPx = matuConv.Transpose().multiply( matCPx ).multiply( matvConv );
					matCPy = matuConv.Transpose().multiply( matCPy ).multiply( matvConv );
					matCPz = matuConv.Transpose().multiply( matCPz ).multiply( matvConv ); 
					matCPh = matuConv.Transpose().multiply( matCPh ).multiply( matvConv ); 
					
					for ( i = 0; i < 4; i++ )
					{
						for ( j = 0; j < 4; j++ )
						{
							((CqVector3D)pParam.pValue_get( i*4 + j ,0)).x( matCPx.m_aaElement[ i ][ j ] );
							((CqVector3D)pParam.pValue_get( i*4 + j ,0)).y( matCPy.m_aaElement[ i ][ j ] );
							((CqVector3D)pParam.pValue_get( i*4 + j ,0)).z( matCPz.m_aaElement[ i ][ j ] );
						}
					}
				}
				break;
				
				case type_hpoint:
				{
					// Get the parameter pointer as the correct type.
					CqParameterTyped<CqVector4D, CqVector3D> pParam = ( CqParameterTyped<CqVector4D, CqVector3D> ) iUP ;
					
					// Store the data into a matrix for conversion.
					CqMatrix matCPx = new CqMatrix();
					CqMatrix matCPy = new CqMatrix();
					CqMatrix matCPz = new CqMatrix();
					CqMatrix matCPh = new CqMatrix();
					for ( i = 0; i < 4; i++ )
					{
						for ( j = 0; j < 4; j++ )
						{
							matCPx.m_aaElement[ i ][ j ] = ((CqVector4D)pParam.pValue_get( i*4 + j ,0)).valueAt(0) ;
							matCPy.m_aaElement[ i ][ j ] = ((CqVector4D)pParam.pValue_get( i*4 + j ,0)).valueAt(1) ;
							matCPz.m_aaElement[ i ][ j ] = ((CqVector4D)pParam.pValue_get( i*4 + j ,0)).valueAt(2) ;
							matCPh.m_aaElement[ i ][ j ] = ((CqVector4D)pParam.pValue_get( i*4 + j ,0)).valueAt(3) ;
						}
					}
					matCPx.SetfIdentity( false );	matCPy.SetfIdentity( false );
					matCPz.SetfIdentity( false );	matCPh.SetfIdentity( false );
					
					matCPx = matuConv.Transpose().multiply( matCPx ).multiply( matvConv );
					matCPy = matuConv.Transpose().multiply( matCPy ).multiply( matvConv );
					matCPz = matuConv.Transpose().multiply( matCPz ).multiply( matvConv );
					matCPh = matuConv.Transpose().multiply( matCPh ).multiply( matvConv );
					
					for ( i = 0; i < 4; i++ )
					{
						for ( j = 0; j < 4; j++ )
						{
							((CqVector4D)pParam.pValue_get( i*4 + j ,0)).x( matCPx.m_aaElement[ i ][ j ] );
							((CqVector4D)pParam.pValue_get( i*4 + j ,0)).y( matCPy.m_aaElement[ i ][ j ]);
							((CqVector4D)pParam.pValue_get( i*4 + j ,0)).z( matCPz.m_aaElement[ i ][ j ] );
							((CqVector4D)pParam.pValue_get( i*4 + j ,0)).h( matCPh.m_aaElement[ i ][ j ] );
						}
					}
				}
				break;
				
				case type_color:
				{
					// Get the parameter pointer as the correct type.
					CqParameterTyped<CqColor, CqColor> pParam = ( CqParameterTyped<CqColor, CqColor> ) iUP ;
					
					// Store the data into a matrix for conversion.
					CqMatrix matRed = new CqMatrix();
					CqMatrix matGreen = new CqMatrix();
					CqMatrix matBlue = new CqMatrix();
					for ( i = 0; i < 4; i++ )
					{
						for ( j = 0; j < 4; j++ )
						{
							matRed.m_aaElement[ i ][ j ] = ((CqColor)pParam.pValue_get( i*4 + j ,0)).valueAt(0) ;
							matGreen.m_aaElement[ i ][ j ] = ((CqColor)pParam.pValue_get( i*4 + j ,0)).valueAt(1);
							matBlue.m_aaElement[ i ][ j ] = ((CqColor)pParam.pValue_get( i*4 + j ,0)).valueAt(2);
						}
					}
					matRed.SetfIdentity( false );
					matGreen.SetfIdentity( false );
					matBlue.SetfIdentity( false );
					
					matRed = matuConv.Transpose().multiply( matRed ).multiply( matvConv );
					matGreen = matuConv.Transpose().multiply( matGreen ).multiply( matvConv );
					matBlue = matuConv.Transpose().multiply( matBlue ).multiply( matvConv );
					
					for ( i = 0; i < 4; i++ )
					{
						for ( j = 0; j < 4; j++ )
						{
							((CqColor)pParam.pValue_get( i*4 + j ,0)).setValueAt( 0, matRed.m_aaElement[ i ][ j ] );
							((CqColor)pParam.pValue_get( i*4 + j ,0)).setValueAt( 1, matGreen.m_aaElement[ i ][ j ] );
							((CqColor)pParam.pValue_get( i*4 + j ,0)).setValueAt( 2, matBlue.m_aaElement[ i ][ j ]  );
						}
					}
				}
				break;
				
				case type_float:
				{
					// Get the parameter pointer as the correct type.
					CqParameterTyped<p_float, p_float> pParam = ( CqParameterTyped<p_float, p_float> ) iUP ;
					
					// Store the data into a matrix for conversion.
					CqMatrix matCPx = new CqMatrix();
					for ( i = 0; i < 4; i++ )
					{
						for ( j = 0; j < 4; j++ )
							matCPx.m_aaElement[ i ][ j ] = ((p_float)pParam.pValue_get( i*4 + j ,0)).value ;
					}
					matCPx.SetfIdentity( false );
					matCPx = matuConv.Transpose().multiply( matCPx ).multiply( matvConv );
					
					for ( i = 0; i < 4; i++ )
					{
						for ( j = 0; j < 4; j++ )
							pParam.pValue_get( i*4 + j ,0).value = matCPx.m_aaElement[ i ][ j ];
					}
				}
				break;
				
				//TODO Need to work out how to convert Matrix types to Bezier as well at some point.
				}
			}
		}
		
		/*	for ( i = 0; i < 4; i++ )
		 {
		 for ( j = 0; j < 4; j++ )
		 {
		 CP( i, j ).x( matCPx[ i ][ j ] );
		 CP( i, j ).y( matCPy[ i ][ j ] );
		 CP( i, j ).z( matCPz[ i ][ j ] );
		 CP( i, j ).h( matCPh[ i ][ j ] );
		 }
		 }*/
	}
	
}
