// 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.CqVector3D;
import net.cellcomputing.himawari.library.types.CqVector4D;

import static net.cellcomputing.himawari.library.Float_h.FLT_EPSILON;
import static net.cellcomputing.himawari.library.Float_h.FLT_MAX;
import static net.cellcomputing.himawari.library.EqVariableType.*;
import static net.cellcomputing.himawari.library.EqVariableClass.*;
import static net.cellcomputing.himawari.library.EqEnvVars.*;
import static net.cellcomputing.himawari.library.RiGlobal.USES;
import static net.cellcomputing.himawari.library.RiGlobal.*;
import static net.cellcomputing.himawari.library.EqIntIndex.*;

/**
 * 
 * 
 * 
 * @author NTT DATA Corporation
 */
public strictfp class CqSurfacePolygon extends CqSurface implements CqPolygonBase
{
	/**
	 * コンストラクタ
	 * @param cVertices 頂点数
	 */
	public CqSurfacePolygon( int cVertices )
	{
		super();
		//CqPolygonBaseのコンストラクタ
		CqStats.STATS_INC( GPR_poly );
        //
		m_cVertices = cVertices;
	}
	
	/**
	 * コピーコンストラクタ
	 * @param From コピー元
	 */
	public CqSurfacePolygon( CqSurfacePolygon From )
	{
	    this.assignment( From );
	    //CqPolygonBaseのコンストラクタ
		CqStats.STATS_INC( GPR_poly );
	}
	
	/**
	 * デストラクタ
	 */
	public	void destruct(){
		super.destruct();
	}

	/**
	 * 「=」演算子のオーバーロード
	 * @param From 代入元
	 * @return 代入後のオブジェクト
	 */
	public CqSurfacePolygon assignment( CqSurfacePolygon From )
	{
	    super.assignment( From );
	    m_cVertices = From.m_cVertices;
	    return ( this );
	}
	
	/**
	 * ポリゴンが生成不可能かどうかを返すメソッド。
	 * すなわち全ての点またはほとんどの点が同じ場所に
	 * 存在しているかどうかを判定する。
	 * 
	 * @return ポリゴンが生成不可能であればtrue
	 */
	public boolean	CheckDegenerate()
	{
	    // Check if all points are within a minute distance of each other.
	    boolean	fDegen = true;
	    int i, n;
	    n = NumVertices();
	    for ( i = 1; i < n; i++ )
	    {
	        if ( ( PolyP( i ).sub( PolyP( i - 1 )) ).Magnitude() > FLT_EPSILON )
	        {
	            fDegen = false;
	            break;
	        }
	    }
	    return ( fDegen );
	}

	/**
	 *
	 * @return CqBoundを返す
	 */
    public CqBound	Bound()
    {
        return ( AdjustBoundForTransformationMotion( PBBound() ) );
    }
    
    /**
     * 
     */
	public int	Split( STLVector<CqBasicSurface> aSplits )
    {
        return ( PBSplit( aSplits ) );
    }

	/** 
	 * サーフェスがモーションブラーとして利用されることが
	 * 妥当かどうかを決定する。
	 * フレームにおけるモーションブラーとして利用されるかどうか。
	 * ただし、ここでは常にfalseが返る。
	 * Determine whether the passed surface is valid to be used as a
	 *  frame in motion blur for this surface.
	 *  @return falseが返る
	 */
	public boolean	IsMotionBlurMatch( CqBasicSurface pSurf )
    {
        return( false );
    }
	
	/**
	 * 常に1を返すメソッド
	 * @return 1
	 */
    public int	cUniform()
    {
        return ( 1 );
    }
    
    /**
     * 頂点の数を返すメソッド
     * @return m_cVertices 頂点数
     */
	public int	cVarying()
    {
        return ( m_cVertices );
    }

    /**
     * 頂点の数を返すメソッド
     * @return m_cVertices 頂点数
     */
	public	int cVertex()
    {
        return ( m_cVertices );
    }
	
	/**
	 * 常に1を返すメソッド
	 * @return 1
	 */
    public int cFaceVarying()
    {
        /// \todo Must work out what this value should be.
        return ( 1 );
    }

	    // Overridden from CqPolygonBase
    public CqSurface Surface() 
    {
        return ( this );
    }
//    public CqSurface Surface()
//    {
//        return ( this );
//    }
    /**
     * ポリゴンに設定されている"P"のパラメタ値を取得する
     * 
     * iが負の場合はArrayIndexOutofExceptionが返る。
     * またパラメタが設定されていない場合はNullPointerExceptionが返る。
     * 
     * @param i インデックス
     * @return Pのパラメタ値
     */
    public CqVector4D PolyP( int i )
    {
        return ( (CqVector4D)P().pValue_get( i ,0) );
    }
    /**
     * ポリゴンに設定されている"N"のパラメタ値を取得する
     * 
     * iが負の場合はArrayIndexOutofExceptionが返る。
     * またパラメタが設定されていない場合はNullPointerExceptionが返る。
     * 
     * @param i インデックス
     * @return Nのパラメタ値
     */
    public CqVector3D PolyN( int i )
    {
        return (CqVector3D) ( N().pValue_get( i ,0) );
    }
    
    /**
     * ポリゴンに設定されている"Cs"のパラメタ値を取得する(色情報)
     * 
     * iが負の場合はArrayIndexOutofExceptionが返る。
     * 
     * @param i インデックス
     * @return Csのパラメタ値
     * 
     */
    public CqColor PolyCs( int i )
    {
        return (CqColor) ( Cs().pValue_get( i ,0) );
    }
    
    /**
     * ポリゴンに設定されている"Os"のパラメタ値を取得する
     * 
     * iが負の場合はArrayIndexOutofExceptionが返る。
     * またパラメタが設定されていない場合はNullPointerExceptionが返る。
     * 
     * @param i インデックス
     * @return Osのパラメタ値
     */
    public CqColor PolyOs( int i )
    {
        return (CqColor) ( Os().pValue_get( i ,0) );
    }
    
    /**
     * ポリゴンに設定されている"s"のパラメタ値を取得する
     * 
     * iが負の場合はArrayIndexOutofExceptionが返る。
     * またパラメタが設定されていない場合はNullPointerExceptionが返る。
     * 
     * @param i インデックス
     * @return sのパラメタ値
     */
    public p_float Polys( int i )
    {
        return (p_float) ( s().pValue_get( i ,0) );
    }
    
    /**
     * ポリゴンに設定されている"t"のパラメタ値を取得する
     * 
     * iが負の場合はArrayIndexOutofExceptionが返る。
     * またパラメタが設定されていない場合はNullPointerExceptionが返る。
     * 
     * @param i インデックス
     * @return tのパラメタ値
     */
    public	p_float Polyt( int i )
    {
        return (p_float) ( t().pValue_get( i ,0) );
    }
    
    /**
     * ポリゴンに設定されている"u"のパラメタ値を取得する
     * 
     * iが負の場合はArrayIndexOutofExceptionが返る。
     * またパラメタが設定されていない場合はNullPointerExceptionが返る。
     * 
     * @param i インデックス
     * @return uのパラメタ値
     */
    public p_float Polyu( int i )
    {
        return (p_float) ( u().pValue_get( i ,0) );
    }
    
    /**
     * ポリゴンに設定されている"v"のパラメタ値を取得する
     * 
     * iが負の場合はArrayIndexOutofExceptionが返る。
     * またパラメタが設定されていない場合はNullPointerExceptionが返る。
     * 
     * @param i インデックス
     * @return vのパラメタ値
     */
    public p_float Polyv( int i )
    {
        return (p_float) ( v().pValue_get( i ,0) );
    }
    
    /**
     * 常に引数で与えられた数値が返る
     */
    public int PolyIndex( int i )
    {
        return ( i );
    }
    
    /**
     * 常に引数で与えられた数値が返る
     * 
     */
    public int FaceVaryingIndex( int i )
    {
        return( i );
    }
    
    /**
     * 引数で指定された値を持っているかどうかを判定する。
     * 引数にはEqEnvVarsで指定される値をとる。
     * EqEnvVars.EnvVars_Cs L<= index < EqEnvVars.EnvVars_Lastの間以外は不正な値である。
     * 
     * @param index 変数のインデックス(EqEnvVars.EnvVars_Pなど） 
     */
    public boolean	bHasVar(int index)
    {
        return ( super.bHasVar(index) );
    }

    /**
     * 頂点数を返す
     * @return 頂点数
     */
    public	int	NumVertices()
    {
        return ( (int)cVertex() );
    }

    /**
     * 
     */
    public	IqAttributes	pAttributes()
    {
        return ( super.pAttributes() );
    }
    /**
     * 
     */
    public IqTransform	pTransform()
    {
        return ( super.pTransform() );
    }
    
    /**
     * ポリゴンの頂点数
     */
	protected int m_cVertices;	///< Count of vertices in this polygon.
	
	
	//***************** CqPolygonBaseの継承 ********************
	public CqBound	PBBound()
	{
	    CqVector3D vecA = new CqVector3D( FLT_MAX, FLT_MAX, FLT_MAX );
	    CqVector3D vecB = new CqVector3D( -FLT_MAX, -FLT_MAX, -FLT_MAX );
	    int i, n;
	    n = NumVertices();
	    for ( i = 0; i < n; i++ )
	    {
	        CqVector3D	vecV = new CqVector3D(); 
	        vecV.assignment( PolyP( i ) );
	        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 ( B );
	}
	//public int	Split( STLVector<CqBasicSurface> aSplits );
	public int	PBSplit( STLVector<CqBasicSurface> aSplits ){
	    CqVector3D	vecN = new CqVector3D();
	    int indexA, indexB, indexC, indexD;

	    // We need to take into account Orientation here, even though most other
	    // primitives leave it up to the CalcNormals function on the MPGrid, because we
	    // are forcing N to be setup here, so clockwise nature is important.
	    boolean CSO = pTransform().GetHandedness(pTransform().Time(0));
	    boolean O = pAttributes().GetIntegerAttribute( "System", "Orientation" ) [ 0 ] != 0;

	    indexA = 0;
	    indexB = 1;

	    int iUses = PolyUses();
	    int n = NumVertices();

	    // Get the normals, or calculate the facet normal if not specified.
	    if ( !bHasVar(EnvVars_N) )
	    {
	        CqVector3D vecA = new CqVector3D(); 
	        vecA.assignment( PolyP( indexA ) );
	        // Find two suitable vectors, and produce a geometric normal to use.
	        int i = 1;
	        CqVector3D	vecN0, vecN1,tmp;
	        vecN0 = new CqVector3D();
	        vecN1 = new CqVector3D();
	        tmp = new CqVector3D(); 
	        
	        while ( i < n )
	        {
	        	//CqVector3D tmp = new CqVector3D( PolyP( i ) );
	            tmp.assignment(PolyP( i ));
	        	vecN0.assignment( tmp.sub( vecA ) );
	            if ( vecN0.Magnitude() > FLT_EPSILON )
	                break;
	            i++;
	        }
	        i++;
	        while ( i < n )
	        {
	        	//CqVector3D tmp = new CqVector3D( PolyP( i ) );
	        	tmp.assignment(PolyP( i ));
	        	vecN1.assignment( tmp.sub( vecA ) );
	            if ( vecN1.Magnitude() > FLT_EPSILON && vecN1 != vecN0 )
	                break;
	            i++;
	        }
	        vecN.assignment( vecN0.mod( vecN1 ) );
	        vecN.assignment( ( O == CSO ) ? vecN : vecN.mul(-1) );
	        vecN.Unit();
	    }

	    // Start by splitting the polygon into 4 point patches.
	    // Get the normals, or calculate the facet normal if not specified.

	    int cNew = 0;
	    int i;
	    for ( i = 2; i < n; i += 2 )
	    {
	        indexC = indexD = i;
	        if ( n > i + 1 )
	            indexD = i + 1;

	        // Create bilinear patches
			CqSurfacePatchBilinear pNew = new CqSurfacePatchBilinear();
	        //ADDREF( pNew );
	        pNew.SetSurfaceParameters( Surface() );

	/* Comment this out for now as it breaks Bug948827 in a strange way, needs more investigation */
	/*        if ( indexC == indexD )
			{
				// Calculate which point in the triangle produces an angle with it's neighbours that is closest to 90 degrees.
				// Placing the phantom point opposite this point will ensure the best orientation of the final grids, reducing
				// shading artefacts.
				CqVector3D pointA = PolyP(indexA);
				CqVector3D pointB = PolyP(indexB);
				CqVector3D pointC = PolyP(indexC);
				TqFloat aA = 1.5707f - acosf((pointB - pointA).Unit()*(pointC - pointA).Unit());
				TqFloat aB = 1.5707f - acosf((pointA - pointB).Unit()*(pointC - pointB).Unit());
				TqFloat aC = 1.5707f - acosf((pointA - pointC).Unit()*(pointB - pointC).Unit());
				TqInt cycle = 0;
				if( aB < aA && aB < aC )		cycle = 1;
				else if( aC < aA && aC < aB)	cycle = 2;
				for(; cycle>0; --cycle)
				{
					TqInt temp = indexA;
					indexA = indexB;
					indexB = indexC;
					indexC = indexD = temp;
				}
			}
	*/
	        int iUPA, iUPB, iUPC, iUPD;
	        int iUPAf, iUPBf, iUPCf, iUPDf;
			// Get the indices for varying variables.
			iUPA = PolyIndex( indexA );
			iUPB = PolyIndex( indexB );
			iUPC = PolyIndex( indexC );
			iUPD = PolyIndex( indexD );

			// Get the indices for facevarying variables.
			iUPAf = FaceVaryingIndex( indexA );
			iUPBf = FaceVaryingIndex( indexB );
			iUPCf = FaceVaryingIndex( indexC );
			iUPDf = FaceVaryingIndex( indexD );

	        // Copy any user specified primitive variables.
//	        STLVector<CqParameter*>::iterator iUP;
//	        STLVector<CqParameter*>::iterator end = Surface().aUserParams().end();
//	        for ( iUP = Surface().aUserParams().begin(); iUP != end; iUP++ )
	        for( CqParameter iUP : Surface().aUserParams() )
	        {
	            CqParameter pNewUP = ( iUP ).CloneType( ( iUP ).strName(), ( iUP ).Count() );

	            if ( pNewUP.Class().getValue() == class_varying || pNewUP.Class().getValue() == class_vertex )
	            {
	                pNewUP.SetSize( (int)pNew.cVarying() );
	                pNewUP.SetValue( ( iUP ), 0, iUPA );
	                pNewUP.SetValue( ( iUP ), 1, iUPB );
	                pNewUP.SetValue( ( iUP ), 2, iUPD );
	                pNewUP.SetValue( ( iUP ), 3, iUPC );
	                if ( indexC == indexD )
	                    CreatePhantomData( pNewUP );
	            }
	            else if ( pNewUP.Class().getValue() == class_uniform )
	            {
	                pNewUP.SetSize( (int)pNew.cUniform() );
	                pNewUP.SetValue( ( iUP ), 0, MeshIndex() );
	            }
	            else if ( pNewUP.Class().getValue() == class_constant )
	            {
	                pNewUP.SetSize( 1 );
	                pNewUP.SetValue( ( iUP ), 0, 0 );
	            }
	            else if ( pNewUP.Class().getValue() == class_facevarying )
	            {
	                pNewUP.SetSize( (int)pNew.cVarying() );
	                pNewUP.SetValue( ( iUP ), 0, iUPAf );
	                pNewUP.SetValue( ( iUP ), 1, iUPBf );
	                pNewUP.SetValue( ( iUP ), 2, iUPDf );
	                pNewUP.SetValue( ( iUP ), 3, iUPCf );
	                if ( indexC == indexD )
	                    CreatePhantomData( pNewUP );
	            }

	            pNew.AddPrimitiveVariable( pNewUP );
	        }

	        // If this is a triangle, then mark the patch as a special case. See function header comment for more details.
	        if ( indexC == indexD ) pNew.SetfHasPhantomFourthVertex( true );

	        // If there are no smooth normals specified, then fill in the facet normal at each vertex.
	        if ( !bHasVar(EnvVars_N) && USES( iUses, EnvVars_N ) )
	        {
	            CqParameterTypedVarying<CqVector3D,CqVector3D> pNewUP = new CqParameterTypedVarying<CqVector3D, CqVector3D>("N", 1,new EqVariableType(type_normal), CqVector3D.class ,CqVector3D.class);
	            pNewUP.SetSize( (int)pNew.cVarying() );

//	            assignmentに変更  ただし、Aqsisではブレークポイントにひっかからなかった。
//	            でも代入されていた　2005/12/22 nttdata
//	            pNewUP.pValue() [ 0 ] = vecN;
//	            pNewUP.pValue() [ 1 ] = vecN;
//	            pNewUP.pValue() [ 2 ] = vecN;
//	            pNewUP.pValue() [ 3 ] = vecN;

	            ((CqVector3D)(pNewUP.pValue_get( 0 , 0 ))).assignment(vecN);
	            ((CqVector3D)(pNewUP.pValue_get( 0 , 1 ))).assignment(vecN);
	            ((CqVector3D)(pNewUP.pValue_get( 0 , 2 ))).assignment(vecN);
	            ((CqVector3D)(pNewUP.pValue_get( 0 , 3 ))).assignment(vecN);
	            
	            pNew.AddPrimitiveVariable( pNewUP );
	        }

	        // If the shader needs s/t or u/v, and s/t is not specified, then at this point store the object space x,y coordinates.
	        if ( USES( iUses, EnvVars_s ) || USES( iUses, EnvVars_t ) || USES( iUses, EnvVars_u ) || USES( iUses, EnvVars_v ) )
	        {
	            CqVector3D PA, PB, PC, PD;
	            PA = new CqVector3D();
	            PB = new CqVector3D();
	            PC = new CqVector3D();
	            PD = new CqVector3D();
	            CqMatrix matID = new CqMatrix();
	            CqMatrix matCurrentToWorld = QGetRenderContext().matSpaceToSpace( "current", "object", matID, Surface().pTransform() .matObjectToWorld(Surface().pTransform().Time(0)), Surface().pTransform() .Time(0) );
	            PA.assignment( matCurrentToWorld.multiply( (CqVector4D)pNew.P().pValue_get( 0 , 0 ) ) );
	            PB.assignment( matCurrentToWorld.multiply( (CqVector4D) pNew.P().pValue_get( 0 , 1 ) ) );
	            PC.assignment( matCurrentToWorld.multiply( (CqVector4D) pNew.P().pValue_get( 0 , 3 ) ) );
	            PD.assignment( matCurrentToWorld.multiply( (CqVector4D)pNew.P().pValue_get( 0 , 2 ) ) );

	            if ( USES( iUses, EnvVars_s ) && !bHasVar(EnvVars_s) )
	            {
	                CqParameterTypedVarying<p_float, p_float> pNewUP = new CqParameterTypedVarying<p_float,p_float>( "s" ,new EqVariableType(type_float),p_float.class,p_float.class);
	                pNewUP.SetSize( (int)pNew.cVarying() );

	                ((p_float)pNewUP.pValue_get( 0 , 0 )).value = PA.x;
	                ((p_float)pNewUP.pValue_get( 0 , 1 )).value = PB.x;
	                ((p_float)pNewUP.pValue_get( 0 , 2 )).value = PD.x;
	                ((p_float)pNewUP.pValue_get( 0 , 3 )).value = PC.x;

	                pNew.AddPrimitiveVariable( pNewUP );
	            }

	            if ( USES( iUses, EnvVars_t ) && !bHasVar(EnvVars_t) )
	            {
	                CqParameterTypedVarying<p_float, p_float> pNewUP = new CqParameterTypedVarying<p_float, p_float>( "t",new EqVariableType(type_float),p_float.class,p_float.class);
	                pNewUP.SetSize( (int)pNew.cVarying() );

	                ((p_float)pNewUP.pValue_get( 0 , 0 )).value = PA.y;
	                ((p_float)pNewUP.pValue_get( 0 , 1 )).value = PB.y;
	                ((p_float)pNewUP.pValue_get( 0 , 2 )).value = PD.y;
	                ((p_float)pNewUP.pValue_get( 0 , 3 )).value = PC.y;

	                pNew.AddPrimitiveVariable( pNewUP );
	            }

	            if ( USES( iUses, EnvVars_u ) && !bHasVar(EnvVars_u) )
	            {
	                CqParameterTypedVarying<p_float, p_float> pNewUP = new CqParameterTypedVarying<p_float, p_float>( "u" ,new EqVariableType(type_float),p_float.class,p_float.class);
	                pNewUP.SetSize( (int)pNew.cVarying() );

	                ((p_float)pNewUP.pValue_get( 0 , 0 )).value = PA.x;
	                ((p_float)pNewUP.pValue_get( 0 , 1 )).value = PB.x;
	                ((p_float)pNewUP.pValue_get( 0 , 2 )).value = PD.x;
	                ((p_float)pNewUP.pValue_get( 0 , 3 )).value = PC.x;

	                pNew.AddPrimitiveVariable( pNewUP );
	            }

	            if ( USES( iUses, EnvVars_v ) && !bHasVar(EnvVars_v) )
	            {
	                CqParameterTypedVarying<p_float, p_float> pNewUP = new CqParameterTypedVarying<p_float,  p_float>( "v" ,new EqVariableType(type_float),p_float.class,p_float.class);
	                pNewUP.SetSize( (int)pNew.cVarying() );

	                ((p_float)pNewUP.pValue_get( 0 , 0 )).value = PA.y;
	                ((p_float)pNewUP.pValue_get( 0 , 1 )).value = PB.y;
	                ((p_float)pNewUP.pValue_get( 0 , 2 )).value = PD.y;
	                ((p_float)pNewUP.pValue_get( 0 , 3 )).value = PC.y;

	                pNew.AddPrimitiveVariable( pNewUP );
	            }

	        }

	        aSplits.add( pNew );
	        cNew++;

	        // Move onto the next quad
	        indexB = indexD;
	    }
	    return ( cNew );
	}
	
//	---------------------------------------------------------------------
	/** 
	 * 三角の形の継ぎ目を平行四辺形にひき伸ばすためのデータを生成する。
	 * 生成したデータは引数の持つ変数に格納される。
	 * 引数が持つデータ長が4未満の場合はExceptionが発生する。
	 * Generate phanton data to 'stretch' the triangle patch into a parallelogram.
	 * 
	 * @param pParam 元データ
	 */

	@SuppressWarnings("unchecked")
	public void CreatePhantomData( CqParameter pParam )
	{
	    assert( pParam.Class().getValue() == class_varying || pParam.Class().getValue() == class_vertex || pParam.Class().getValue() == class_facevarying );

	    int iArrayCount = 1;
	    int iArray;
	    if( pParam.Count() > 0)
	        iArrayCount = pParam.Count();

	    switch ( pParam.Type().getValue() )
	    {
	    case type_point:
	    case type_vector:
	    case type_normal:
	        {
	            CqParameterTyped<CqVector3D, CqVector3D> pTParam = (CqParameterTyped<CqVector3D, CqVector3D>)( pParam );
	            for( iArray = 0; iArray < iArrayCount; iArray++ )
	                //pTParam.pValue( 3 ) [ iArray ] = ( pTParam.pValue( 1 ) [ iArray ] - pTParam.pValue( 0 ) [ iArray ] ) + pTParam.pValue( 2 ) [ iArray ];
	            	((CqVector3D)pTParam.pValue_get( 3 , iArray )).assignment(( ((CqVector3D)pTParam.pValue_get( 1 , iArray )).sub( (CqVector3D) pTParam.pValue_get( 0 , iArray ) ) ).add( (CqVector3D)pTParam.pValue_get( 2 , iArray )));
	            break;
	        }

	    case type_hpoint:
	        {
	            CqParameterTyped<CqVector4D, CqVector3D> pTParam = (CqParameterTyped<CqVector4D, CqVector3D>)( pParam );
	            for( iArray = 0; iArray < iArrayCount; iArray++ )
	                //pTParam.pValue_get( 3 , iArray ) = ( pTParam.pValue_get( 1 , iArray ) - pTParam.pValue_get( 0 , iArray ) ) + pTParam.pValue_get( 2 , iArray );
	            	((CqVector4D)pTParam.pValue_get( 3 , iArray )).assignment( ( ((CqVector4D)pTParam.pValue_get( 1 , iArray )).sub((CqVector4D)pTParam.pValue_get( 0 , iArray )) ).add((CqVector4D)pTParam.pValue_get( 2 , iArray )) );
	            break;
	        }

	    case type_float:
	        {
	            CqParameterTyped<p_float, p_float> pTParam = (CqParameterTyped<p_float, p_float>)( pParam );
	            for( iArray = 0; iArray < iArrayCount; iArray++ )
	                //pTParam.pValue_get( 3 , iArray ) = ( pTParam.pValue_get( 1 , iArray ) - pTParam.pValue_get( 0 , iArray ) ) + pTParam.pValue_get( 2 , iArray );
	            	((p_float)pTParam.pValue_get( 3 , iArray )).value = ( ((p_float)pTParam.pValue_get( 1 , iArray )).value - ((p_float)pTParam.pValue_get( 0 , iArray )).value ) + ((p_float)pTParam.pValue_get( 2 , iArray )).value;
	            break;
	        }

	    case type_integer:
	        {
	            CqParameterTyped<p_int, p_float> pTParam =(CqParameterTyped<p_int, p_float>)( pParam );
	            for( iArray = 0; iArray < iArrayCount; iArray++ )
	                ((p_int)pTParam.pValue_get( 3 , iArray )).value = ( ((p_int)pTParam.pValue_get( 1 , iArray )).value - ((p_int)pTParam.pValue_get( 0 , iArray )).value ) + ((p_int)pTParam.pValue_get( 2 , iArray )).value;
	            break;
	        }

	    case type_color:
	        {
	            CqParameterTyped<CqColor, CqColor> pTParam = (CqParameterTyped<CqColor, CqColor>)( pParam );
	            for( iArray = 0; iArray < iArrayCount; iArray++ )
	                ((CqColor)pTParam.pValue_get( 3 , iArray )).assignment( ( ((CqColor)pTParam.pValue_get( 1 , iArray )).sub((CqColor)pTParam.pValue_get( 0 , iArray )) ).add((CqColor)pTParam.pValue_get( 2 , iArray )) );
	            break;
	        }

	    case type_matrix:
	        {
	            CqParameterTyped<CqMatrix, CqMatrix> pTParam = (CqParameterTyped<CqMatrix, CqMatrix>)( pParam );
	            for( iArray = 0; iArray < iArrayCount; iArray++ )
	                ((CqMatrix)pTParam.pValue_get( 3 , iArray )).assignment( ( ((CqMatrix)pTParam.pValue_get( 1 , iArray )).sub((CqMatrix)pTParam.pValue_get( 0 , iArray )) ).add((CqMatrix)pTParam.pValue_get( 2 , iArray )) );
	            break;
	        }

	    case type_string:
	        {
	            CqParameterTyped<p_String, p_String> pTParam = (CqParameterTyped<p_String, p_String>)( pParam );
	            for( iArray = 0; iArray < iArrayCount; iArray++ )
	                //pTParam.pValue_get( 3 , iArray ) = ( pTParam.pValue_get( 1 , iArray )) - pTParam.pValue_get( 0 , iArray ) ) + pTParam.pValue_get( 2 , iArray );
	                ((p_String)pTParam.pValue_get( 3 , iArray )).value = ( ((p_String)pTParam.pValue_get( 1 , iArray )) ).value + ((p_String)pTParam.pValue_get( 2 , iArray )).value;
	            break;
	        }

	    default:
	        {
	            // left blank to avoid compiler warnings about unhandled types
	            break;
	        }
	    }
	}
	  /** 
	   * 常に0が返る。
	   * Get the index of this polygon if it is a member of a polygon mesh
     */
    public	int	MeshIndex()
    {
        return ( 0 );
    }

    /** 
     * Get a bit vector representing the standard shader variables this polygon needs.
     */
    public int	PolyUses()
    {
        return ( Surface().Uses() );
    }
	//****************************************************
}
