// 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.QGetRenderContext;
import static net.cellcomputing.himawari.library.EqEnvVars.*;
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.types.CqMatrix;
import net.cellcomputing.himawari.library.types.CqVector3D;

/**
 * 
 * CqMotionMicroPolyGridPoints
 * 
 * @author NTT DATA Corporation
 */
public strictfp class CqMotionMicroPolyGridPoints extends CqMotionMicroPolyGrid {

	public CqMotionMicroPolyGridPoints()
	{
		super();
	}
	
	//【改】　aqsis1.01変更*******************************************************
	/** 
	 * Split the micropolygrid into individual MPGs,
	 * @param pImage Pointer to image being rendered into.
	 * @param iBucket Integer index of bucket being processed.
	 * @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, int iBucket, long xmin, long xmax, long ymin, long ymax )
	public	void Split( CqImageBuffer pImage, long xmin, long xmax, long ymin, long ymax )
	{
	    // Get the main object, the one that was shaded.
	    CqMicroPolyGrid pGridA = (CqMicroPolyGridPoints)( GetMotionObject( Time( 0 ) ) );
	    int iTime;

	    assert( null != pGridA.pVar(EnvVars_P) );

	    pGridA.AddRef();

	    int cu = pGridA.uGridRes();	// Only need cu, as we know cv is 1.

	    CqMatrix matCameraToObject0 = QGetRenderContext() .matSpaceToSpace( "camera", "object", new CqMatrix(), pSurface().pTransform().matObjectToWorld(pSurface().pTransform().Time(0)), pSurface().pTransform().Time(0) );
//	    CqMatrix matObjectToCamera = QGetRenderContext() .matSpaceToSpace( "object", "camera", new CqMatrix(), pSurface().pTransform().matObjectToWorld(pSurface().pTransform().Time(0)), pSurface().pTransform().Time(0) );
	    CqMatrix matCameraToRaster = QGetRenderContext() .matSpaceToSpace( "camera", "raster", new CqMatrix(), new CqMatrix(), pSurface().pTransform().Time(0) );

//	    CqMatrix matTx = QGetRenderContext() .matSpaceToSpace( "object", "camera", new CqMatrix(), pSurface().pTransform() .matObjectToWorld(pSurface().pTransform().Time(0)), pSurface().pTransform().Time(0) );
//	    CqMatrix matITTx = QGetRenderContext() .matNSpaceToSpace( "object", "camera", new CqMatrix(), pSurface().pTransform() .matObjectToWorld(pSurface().pTransform().Time(0)), pSurface().pTransform().Time(0) );

//	    CqVector3D vecdefOriginRaster = matCameraToRaster .multiply( new CqVector3D( 0.0f,0.0f,0.0f ) );

	    int NumTimes = iTimes();

	    // Get an array of P's for all time positions.
	    STLVector< STLVector<CqVector3D> > aaPtimes = new STLVector<STLVector<CqVector3D>>( 2, CqVector3D.class );;
	    aaPtimes.resize( NumTimes );

	    // Array of cached object to camera matrices for each time slot.
	    STLVector<CqMatrix>	amatObjectToCameraT = new STLVector<CqMatrix>(CqMatrix.class);
	    amatObjectToCameraT.resize( NumTimes );
	    STLVector<CqMatrix>	amatNObjectToCameraT = new STLVector<CqMatrix>(CqMatrix.class);
	    amatNObjectToCameraT.resize( NumTimes );

//	    CqMatrix matObjectToCameraT = new CqMatrix();
	    int i;
	    int gsmin1;
	    gsmin1 = pGridA.GridSize() - 1;

	    for( iTime = 0; iTime < NumTimes; iTime++ )
	    {
//	        CqMatrix matCameraToObjectT = QGetRenderContext() .matSpaceToSpace( "camera", "object", new CqMatrix(), pSurface().pTransform().matObjectToWorld( pSurface().pTransform().Time( iTime ) ), Time( iTime ) );
	        amatObjectToCameraT.get( iTime ).assignment( QGetRenderContext() .matSpaceToSpace( "object", "camera", new CqMatrix(), pSurface().pTransform().matObjectToWorld( pSurface().pTransform().Time( iTime ) ),  Time( iTime ) ) );
	        amatNObjectToCameraT.get( iTime ).assignment( QGetRenderContext() .matNSpaceToSpace( "object", "camera", new CqMatrix(), pSurface().pTransform().matObjectToWorld( pSurface().pTransform().Time( iTime ) ), Time( iTime ) ) );

	        aaPtimes.get( iTime ).resize( gsmin1 + 1 );

	        CqMicroPolyGridPoints pGridT = (CqMicroPolyGridPoints)( GetMotionObject( Time( iTime ) ) );

	        //nttdata 高速化
//	        STLVector<CqVector3D> pP = new STLVector<CqVector3D>(CqVector3D.class);
//	        pGridT.pVar(EnvVars_P) .GetPointPtr( pP );
	        //STLVector<CqVector3D> pP ;
	        STLArray<CqVector3D> pP ;
	        pP = pGridT.pVar(EnvVars_P) .GetPointPtr_2( );
	        
	        for ( i = gsmin1; i >= 0; i-- )
	        {
	            // This makes sure all our points are in object space.
	            aaPtimes.get( iTime ).get( i ).assignment( matCameraToObject0 .multiply( pP.get( i ) ) );
	        }
	    }

	    int iu;
	    for ( iu = 0; iu < cu; iu++ )
	    {
	        CqMicroPolygonMotionPoints pNew = new CqMicroPolygonMotionPoints();
	        pNew.SetGrid( pGridA );
	        pNew.SetIndex( iu );

	        float radius;
//	        int iTime;
	        for( iTime = 0; iTime < NumTimes; iTime++ )
	        {
	            radius = 1.0f;

	            CqMicroPolyGridPoints pGridT = (CqMicroPolyGridPoints)( GetMotionObject( Time( iTime ) ) );

	            // Get a pointer to the surface, so that we can interrogate the "width" parameters.
	            CqPoints pPoints = (CqPoints)( pGridT.pSurface() );

	            final CqParameterTypedConstant<p_float, p_float> pConstantWidthParam =
	                pPoints.constantwidth( );

	            if( null != pConstantWidthParam )
	                radius = ((p_float)pConstantWidthParam.pValue_get( 0 , 0 )).value;

	            // Find out if the "width" parameter was specified.
	            CqParameterTypedVarying<p_float, p_float> pWidthParam = pPoints.width( 0 );

	            if( null != pWidthParam )
	                radius = ((p_float)pWidthParam.pValue_get( pPoints.KDTree().aLeaves().get( iu ) , 0 )).value;

	            // Get point in camera space.
                CqVector3D Point	= new CqVector3D( amatObjectToCameraT.get( iTime ) .multiply( aaPtimes.get( iTime ).get( iu ) ) );
                CqVector3D pt		= new CqVector3D( amatObjectToCameraT.get( iTime ) .multiply( aaPtimes.get( iTime ).get( iu ) ) );
                CqVector3D vecCamP	= new CqVector3D( amatObjectToCameraT.get( iTime ) .multiply( aaPtimes.get( iTime ).get( iu ) ) );

	            // Ensure z is retained in camera space when we convert to raster.
	            float ztemp = Point.z;
	            Point = matCameraToRaster .multiply( Point );
	            Point.z( ztemp );

	            // first, create a horizontal vector in object space which is
	            //  the length of the current width.
	            CqVector3D horiz = new CqVector3D( 1, 0, 0 );
	            horiz = amatNObjectToCameraT.get( iTime ) .multiply( horiz );
	            horiz .assignMul( radius / horiz.Magnitude() );

	            // Get the current point in object space.
	            CqVector3D pt_delta = pt .add( horiz );
	            pt = amatObjectToCameraT.get( iTime ) .multiply( pt );
	            pt_delta = amatObjectToCameraT.get( iTime ) .multiply( pt_delta );

	            // finally, find the difference between the two points in
	            //  the new space - this is the transformed width
	            CqVector3D widthVector = pt_delta .sub( pt );
	            radius = widthVector.Magnitude();

	            CqVector3D vecCamP2 = vecCamP .add( new CqVector3D( radius, 0.0f, 0.0f ) );
	            ztemp = vecCamP2.z;
	            CqVector3D vecRasP2 = matCameraToRaster .multiply( vecCamP2 );
	            vecRasP2.z( ztemp );
	            float ras_radius = ( vecRasP2 .sub( Point ) ).Magnitude();
	            radius = ras_radius * 0.5f;

	            pNew.AppendKey( Point, radius, Time( iTime ) );
	        }
	        
	        //【改】aqsis1.01変更前**************
	        //pNew.GetTotalBound( true );
	        //【改】aqsis1.01変更後**************
	        pNew.CalculateTotalBound( );
	        pImage.AddMPG( pNew );
	    }

	    pGridA.Release();

	    //【改】aqsis1.01変更 消去されます。*************************************************
	    // Delete the donor motion grids, as their work is done.
//	    for ( iTime = 1; iTime < iTimes(); iTime++ )
//	    {
//	    CqMicroPolyGrid pg = (CqMicroPolyGrid)( GetMotionObject( Time( iTime ) ) );
//	    if ( null != pg )
//	    pg.Release();
//	    }
	    //**********************************************************************
	    //		delete( GetMotionObject( Time( iTime ) ) );

	}
	
}
