// 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.CqStats.IncI;
import static net.cellcomputing.himawari.library.EqDisplayMode.ModeRGB;
import static net.cellcomputing.himawari.library.EqDisplayMode.ModeZ;
import static net.cellcomputing.himawari.library.EqFloatIndex.MPG_max_area;
import static net.cellcomputing.himawari.library.EqFloatIndex.MPG_min_area;
import static net.cellcomputing.himawari.library.EqIntIndex.GPR_created_total;
import static net.cellcomputing.himawari.library.EqIntIndex.GPR_culled;
import static net.cellcomputing.himawari.library.EqIntIndex.MPG_culled;
import static net.cellcomputing.himawari.library.EqIntIndex.MPG_pushed_down;
import static net.cellcomputing.himawari.library.EqIntIndex.MPG_pushed_far_down;
import static net.cellcomputing.himawari.library.EqIntIndex.MPG_pushed_forward;
import static net.cellcomputing.himawari.library.EqIntIndex.SPL_bound_hits;
import static net.cellcomputing.himawari.library.EqIntIndex.SPL_count;
import static net.cellcomputing.himawari.library.EqIntIndex.SPL_hits;
import static net.cellcomputing.himawari.library.EqVariableType.type_color;
import static net.cellcomputing.himawari.library.EqVariableType.type_float;
import static net.cellcomputing.himawari.library.EqVariableType.type_hpoint;
import static net.cellcomputing.himawari.library.EqVariableType.type_integer;
import static net.cellcomputing.himawari.library.EqVariableType.type_matrix;
import static net.cellcomputing.himawari.library.EqVariableType.type_normal;
import static net.cellcomputing.himawari.library.EqVariableType.type_point;
import static net.cellcomputing.himawari.library.EqVariableType.type_vector;
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.Float_h.FLT_MIN;
import static net.cellcomputing.himawari.library.RiGlobal.QGetRenderContext;
import static net.cellcomputing.himawari.library.RiGlobal.QGetRenderContextI;
import static net.cellcomputing.himawari.library.RiGlobal.gColWhite;
import static net.cellcomputing.himawari.library.types.PublicFunctions.CLAMP;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map.Entry;

import net.cellcomputing.himawari.accessory.STLArray;
import net.cellcomputing.himawari.accessory.STLVector;
import net.cellcomputing.himawari.accessory.Valarray;
import net.cellcomputing.himawari.accessory.primitive.p_float;
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.util.HimawariLogger;

/**
 * 
 * 
 * 
 * @author NTT DATA Corporation
 */
public strictfp class CqImageBuffer {

	public static int bucketmodulo = -1;
	
	/** 
	 * コンストラクタ
	 */
	public CqImageBuffer()
	{
            m_fQuit = false;
            m_fDone = true;
            m_iXRes = 0;
            m_iYRes = 0;
            m_cXBuckets = 0;
            m_cYBuckets = 0;
            m_XBucketSize = 0;
            m_YBucketSize = 0;
            m_PixelXSamples = 0;
            m_PixelYSamples = 0;
            m_FilterXWidth = 0;
            m_FilterYWidth = 0;            
            m_CropWindowXMin = 0;
            m_CropWindowYMin = 0;
            m_CropWindowXMax = 0;
            m_CropWindowYMax = 0;
            m_DisplayMode = ModeRGB;
            m_CurrentBucketCol = 0;
            m_CurrentBucketRow = 0;
	 
	}
	
//	----------------------------------------------------------------------
	/** Destructor
	 * デストラクタ
	 */
	public	void destract()
	{
		DeleteImage();
	}

//	----------------------------------------------------------------------
	/** 　現在バケットのスクリーンポジションを取得する。
	 * @return 2dのベクタとして、バケットの位置を返す。
	 */
	public   CqVector2D		BucketPosition()
	{
		return( BucketPosition( CurrentBucketCol(), CurrentBucketRow() ) );
	}
	
//	----------------------------------------------------------------------
	/** ｘとｙからバケットの位置を取得する
	 * @return バケットの位置を２Dのベクタから取得する。
	 * @param x:
	 * @param y:
	 */

	public   CqVector2D		BucketPosition(int x, int y)
	{
		CqVector2D	vecA = new CqVector2D();
//	    vecA.x( x );
//	    vecA.y( y );
//	    vecA.x( vecA.x * XBucketSize() );
//	    vecA.y( vecA.y * YBucketSize() );
		vecA.x = x * XBucketSize();
		vecA.y = y * YBucketSize();

	    return ( vecA );
	}
	
//	----------------------------------------------------------------------
	/** 現在のバケットのバケットのサイズを取得する。
	 * たいていは右と下のサイドの小さい方の画像を除いた値を返す。クロップウィンドは考慮に入れません・
	 * @return 2Dベクタのバケットサイズを返す。
	 */
	
	public   CqVector2D		BucketSize()
	{
		return( BucketSize( CurrentBucketCol(), CurrentBucketRow() ) );  
	}
	
//	----------------------------------------------------------------------
	/** 現在のバケットのｘとｙからバケットのサイズを取得する。
	 * たいていは右と下のサイドの小さい方の画像を除いた値を返す。クロップウィンドは考慮に入れません・
	 * @return 2Dベクタのバケットサイズを返す。
	 */
	public   CqVector2D		BucketSize( int x, int y)
	{
		CqVector2D	vecA = BucketPosition(x,y);
	    vecA.x( m_iXRes - vecA.x );
	    if ( vecA.x > m_XBucketSize ) vecA.x( m_XBucketSize );
	    vecA.y( m_iYRes - vecA.y );
	    if ( vecA.y > m_YBucketSize ) vecA.y( m_YBucketSize );

	    return ( vecA );
	}

    /** このイメージの水平方向の解像度を得てください。
     * @return 水平方向の解像度
     */
	public    int	iXRes()
    {
        return ( m_iXRes );
    }
    /** このイメージの垂直方向の解像度を得てください。
     * @return 垂直方向の解像度
     */
	public    int	iYRes()
    {
        return ( m_iYRes );
    }
    /** レンダリングする水平方向の最小のピクセルを取得する。
     * @return 最小のピクセルのインデックス
     */
	public    int	CropWindowXMin()
    {
        return ( m_CropWindowXMin );
    }
    /** レンダリングする垂直方向の最小のピクセルを取得する。
     * @return 最小のピクセルのインデックス
     */
	public    int	CropWindowYMin()
    {
        return ( m_CropWindowYMin );
    }
    /** レンダリングする水平方向の最大のピクセルを取得する。
     * @return 最大のピクセルのインデックス
     */
	public   int	CropWindowXMax()
    {
        return ( m_CropWindowXMax );
    }
    /** レンダリングする垂直方向の最大のピクセルを取得する。
     * @return 最大のピクセルのインデックス
     */
	public   int	CropWindowYMax()
    {
        return ( m_CropWindowYMax );
    }
    /** 水平方向のバケットの数を取得する。 
     * @return 水平方向のバケットの数
     */
	public   int	cXBuckets()
    {
        return ( m_cXBuckets );
    }
    /** 垂直方向のバケットの数を取得する。
     * @return 垂直方向のバケットの数
     */
	public  int	cYBuckets()
    {
        return ( m_cYBuckets );
    }
    /** 水平方向のバケットのサイズを取得する。
     * @return 水平方向のサイズ
     */
	public  int	XBucketSize()
    {
        return ( m_XBucketSize );
    }
    /** 垂直方向のバケットのサイズを取得する。
     * @return 水平方向のサイズ
     */
	public  int	YBucketSize()
    {
        return ( m_YBucketSize );
    }
    /** 水平方向の平均サンプルの数
     * @return サンプルの数
     */
	public   int	PixelXSamples()
    {
        return ( m_PixelXSamples );
    }
    /** 垂直方向の平均サンプルの数
     * @return サンプルの数
     */
	public int	PixelYSamples()
    {
        return ( m_PixelYSamples );
    }
    /** 水平方向のフィルターの幅を取得する。
     * @return フィルターの幅のピクセルの数
     */
	public  float	FilterXWidth()
    {
        return ( m_FilterXWidth );
    }
    /** 垂直方向のフィルターの縦を取得する。
     * @return フィルターの縦のピクセルの数
     */
	public   float	FilterYWidth()
    {
        return ( m_FilterYWidth );
    }
    
	/** 近い側のクリッピング平面との距離を取得する。
     * @return カメラからオブジェクトが見えるまでの距離
     */
	public   float	ClippingNear()
    {
        return ( m_ClippingNear );
    }

	/**　遠い側のクリッピング平面との距離を返す。 
     * Get the far clipping distance.
     * @return カメラからオブジェクトが見えるまでの距離
     */
	public  float	ClippingFar() 
    {
        return ( m_ClippingFar );
    }
    
	/** ディスプレイを取得する。
     * @return enumモードでディスプレイのモードを取得する。
     */
	public   int	DisplayMode() 
    {
        return ( m_DisplayMode );
    }
    /** 現在、バケツの列番号を分類調査させてください。
     * @return バケットのインデックス
     */
	public   int	CurrentBucketCol() 
    {
        return ( m_CurrentBucketCol );
    }
    /** 現在、バケツの列のインデックスを分類調査させてください。
     * @return バケットのインデックス
     */
	public int	CurrentBucketRow() 
    {
        return ( m_CurrentBucketRow );
    }
	
    /**
     * 処理するために次のバケツに移行してください。 
     */
	public  boolean NextBucket()
    {
        m_CurrentBucketCol++;
        if( m_CurrentBucketCol >= m_cXBuckets )
        {
            m_CurrentBucketCol = 0;
            m_CurrentBucketRow++;
            if( m_CurrentBucketRow >= m_cYBuckets )
                return( false );
        }
        return( true );
    }
    /** Get a pointer to the current bucket<br>
     * 現在のバケットのポインタを返す。
     */
	public  CqBucket CurrentBucket()
    {
//        return( m_Buckets[CurrentBucketRow()][CurrentBucketCol()] );
		//return( m_Buckets.get(CurrentBucketRow()).get(CurrentBucketCol()) );
		return( m_Buckets.get(m_CurrentBucketRow).get(m_CurrentBucketCol) );
    }
    /** ポインタを位置のx、格子のyのバケツに手に入れてください。
     */
	public  CqBucket Bucket( int x, int y)
    {
//        return( m_Buckets[y][x] );
        return( m_Buckets.get(y).get(x) );
    }

//	----------------------------------------------------------------------
	/** イメージバッファのための割り当てられたメモリを削除してください。
	 */
	public   	void	DeleteImage()
	{
	    m_iXRes = 0;
	    m_iYRes = 0;
	}
	
	public  	void	SaveImage( final String strName ){};

//	----------------------------------------------------------------------
	/** 待ち行列のリストの前部に新しい表面を加えてください。
	 * @param pSurface CqBasicSurfaceを引き継いだクラスのポインタ。をカメラ空間にサーフェースのポイントがなくてはならない。
	 */
	public  	void	PostSurface( final CqBasicSurface pSurface )
	{
		
		//　全てのGprimsの数を数える。
	    CqStats.STATS_INC( GPR_created_total );

	    // Bound the primitive in its current space (camera) space taking into account any motion specification.
	    //　どんな動き仕様も考慮に入れる現在のスペースのプリミティブ(カメラ)のスペースをバウンドする。
	    CqBound Bound = new CqBound( pSurface.Bound() );

	    // Take into account the displacement bound extension.
	    //　ディスプレートのバウンドを考慮してください。
	    float db = 0.0f;
	    String strCoordinateSystem =  "object" ;
	    final float[] pattrDispclacementBound = pSurface.pAttributes().GetFloatAttribute( "displacementbound", "sphere" );
	    final String[] pattrCoordinateSystem = pSurface.pAttributes().GetStringAttribute( "displacementbound", "coordinatesystem" );
	    if ( pattrDispclacementBound != null ) db = pattrDispclacementBound[ 0 ];
	    if ( pattrCoordinateSystem != null ) strCoordinateSystem = pattrCoordinateSystem[ 0 ];

	    if ( db != 0.0f )//ディスプレートメントするなら
	    {
	        CqVector3D	vecDB = new CqVector3D( db, 0, 0 );
	        CqMatrix matShaderToWorld = new CqMatrix();
			// Default "shader" space to the displacement shader, unless there isn't one, in which
			// case use the surface shader.
	        if ( pSurface.pAttributes().pshadDisplacement(QGetRenderContextI().Time()) != null)
	            matShaderToWorld.assignment( pSurface.pAttributes().pshadDisplacement(QGetRenderContextI().Time()).matCurrent() );
	        else if ( pSurface.pAttributes().pshadSurface(QGetRenderContextI().Time()) != null)
	            matShaderToWorld.assignment( pSurface.pAttributes().pshadSurface(QGetRenderContextI().Time()).matCurrent() );
	        vecDB.assignment( QGetRenderContext().matVSpaceToSpace( strCoordinateSystem, "camera", matShaderToWorld, pSurface.pTransform().matObjectToWorld(pSurface.pTransform().Time(0)), QGetRenderContextI().Time() ).multiply(vecDB) );
	        db = vecDB.Magnitude();

	        Bound.vecMax().assignAdd(db);
	        Bound.vecMin().assignSub(db);
	    }

	    //　サーフェースがカルできるかをチェックする。（また、DOFのために適応して、Boundをラスタ空間に変換します。）
	    if ( CullSurface( Bound, pSurface ) )
	    {
	        CqStats.STATS_INC( GPR_culled );
	        return ;
	    }

	    // If the primitive has been marked as undiceable by the eyeplane check, then we cannot get a valid
	    // bucket index from it as the projection of the bound would cross the camera plane and therefore give a false
	    // result, so just put it back in the current bucket for further splitting.
	    //　もしプリミティブがeyeplaneによってダイシングできないとマークされていたら、バウンドの映像がカメラ平面に交差していて、
	    // したがって、間違った結果を与えるように私たちがそれから有効なバケツインデックスを得ることができないので、さらに分かれるための現在のバケツの中にただそれを戻してください。

	    int XMinb = CurrentBucketCol(), YMinb = CurrentBucketRow();
	    if ( !pSurface.IsUndiceable() )//まだダイシングできるならば
	    {
	        // Find out which bucket(s) the surface belongs to.
	        if ( Bound.vecMin().x < 0 ) Bound.vecMin().x( 0.0f );
	        if ( Bound.vecMin().y < 0 ) Bound.vecMin().y( 0.0f );

	        XMinb = (int)( Bound.vecMin().x / XBucketSize() );
	        YMinb = (int)( Bound.vecMin().y / YBucketSize() );

	        if ( XMinb >= cXBuckets() || YMinb >= cYBuckets() )
	            return;

	        XMinb = (int) CLAMP( XMinb, 0, cXBuckets() );
	        YMinb = (int) CLAMP( YMinb, 0, cYBuckets() );

	        if( Bucket(XMinb, YMinb).IsProcessed() )
	        {
	            XMinb = CurrentBucketCol();
	            YMinb = CurrentBucketRow();
	        }
	    }
	    // Sanity check we are not putting into a bucket that has already been processed.
	    assert( !Bucket(XMinb, YMinb).IsProcessed() );
	    Bucket(XMinb, YMinb).AddGPrim( pSurface );

	    return ;
	}
	
//	----------------------------------------------------------------------
	/**サーフェースがカルでくるかどうか調べてバウンドをトランスフォームしてください。
	 * ※カルというのは見えないオブジェクトをレンダリング対象にしないこと。
	 * 
	 * このメソッドは可視ボリュームの外にあるかを判定してもしそうであればtrueを返す。
	 * もしサーフェースのスパンがアイプレーンでありundiceableとしてマークされていたらそれを行う（それは消去されるようにマークされる）
	 * それはまたバウンドをフィルターの幅の半分まで拡張し、それをラスタスペースへ移動させる。
	 * 
	 * @param Bound CqBound カメラ空間のジオメトリックバウンドへ内包される。
	 * @param pSurface CqBasicSurfaceのポインタ進行中のクラスに渡される。
	 * @return Boolean GPrimを選別することができるのを示します。
	 *
	 * @bug If the gprim spans the eye plane the bound is not transformed into raster
	 * space (how could it anyway), but PostSurface() relies on this behaviour and
	 * inserts EVERY gprim into buckets (using a bound that is still in camera space).
	 */	
	public boolean	CullSurface( CqBound Bound,final CqBasicSurface pSurface )
	{
//		 If the primitive is completely outside of the hither-yon z range, cull it.
	    if ( Bound.vecMin().z >= QGetRenderContext().optCurrent().GetFloatOptionIndex( "System", "Clipping" , 1 ).value ||
	            Bound.vecMax().z <= QGetRenderContext().optCurrent().GetFloatOptionIndex( "System", "Clipping" , 0 ).value )
	        return ( true );

	    // If the primitive spans the epsilon plane and the hither plane and can be split,
	    if ( Bound.vecMin().z <= 0.0f && Bound.vecMax().z > FLT_EPSILON )
	    {
	        // Mark the primitive as not dicable.
	        pSurface.ForceUndiceable();
	        int MaxEyeSplits = 10;
	        final int[] poptEyeSplits = QGetRenderContext().optCurrent().GetIntegerOption( "limits", "eyesplits" );
	        if ( poptEyeSplits != null )	     
	            MaxEyeSplits = poptEyeSplits[ 0 ];

	        if ( pSurface.EyeSplitCount() > MaxEyeSplits )
	        {
	            String objname = "unnamed" ;
	            String pattrName[] = pSurface.pAttributes().GetStringAttribute( "identifier", "name" );
	            if ( pattrName != null ) objname = pattrName[ 0 ];
//				std::cerr << warning << "Max eyesplits for object \"" << objname.c_str() << "\" exceeded" << std::endl;
	            HimawariLogger logger = HimawariLogger.getLogger();
	            logger.warning("Max eyesplits for object \"" + objname + "\" exceeded\n");
				return( true );
	        }
	        return ( false );
	    }

	    float minz = Bound.vecMin().z;
	    float maxz = Bound.vecMax().z;


	    // Convert the bounds to raster space.
	    Bound.Transform( QGetRenderContext().matSpaceToSpace( "camera", "raster", new CqMatrix(),new CqMatrix(), QGetRenderContext().Time() ) );

	    // Take into account depth-of-field
	    if ( QGetRenderContext().UsingDepthOfField() )
	    {
	        final CqVector2D minZCoc = QGetRenderContext().GetCircleOfConfusion( minz );
	        final CqVector2D maxZCoc = QGetRenderContext().GetCircleOfConfusion( maxz );
	        float cocX = Math.max( minZCoc.x, maxZCoc.x );
	        float cocY = Math.max( minZCoc.y, maxZCoc.y );
	        Bound.vecMin().x( Bound.vecMin().x - cocX );
	        Bound.vecMin().y( Bound.vecMin().y - cocY );
	        Bound.vecMax().x( Bound.vecMax().x + cocX );
	        Bound.vecMax().y( Bound.vecMax().y + cocY );
	    }

	    // And expand to account for filter size.
	    Bound.vecMin().x( Bound.vecMin().x - m_FilterXWidth / 2.0f );
	    Bound.vecMin().y( Bound.vecMin().y - m_FilterYWidth / 2.0f );
	    Bound.vecMax().x( Bound.vecMax().x + m_FilterXWidth / 2.0f );
	    Bound.vecMax().y( Bound.vecMax().y + m_FilterYWidth / 2.0f );

	    // If the bounds are completely outside the viewing frustum, cull the primitive.
	    if ( Bound.vecMin().x > CropWindowXMax() ||
	         Bound.vecMin().y > CropWindowYMax() ||
	         Bound.vecMax().x < CropWindowXMin() ||
	         Bound.vecMax().y < CropWindowYMin() )
	        return ( true );

	    // Restore Z-Values to camera space.
	    Bound.vecMin().z( minz );
	    Bound.vecMax().z( maxz );

	    // Cache the Bound.
	    pSurface.CacheRasterBound( Bound );
	    return ( false );
	}
	
//	----------------------------------------------------------------------
	/** もし、こｍｐサーフェースがオクルージョンカルを使えるかをテストする。
	 *もし、サーフェースを 次のバケットに移すことができるなら、それを覆う、もしくは、それを削除してください。
	 * @param pSurface クラスに渡されるCqBasicSurfaceのポインタ.
	 * @return Boolean 選別されたGPrim
	*/

	public  	boolean	OcclusionCullSurface( final CqBasicSurface pSurface )
	{
		CqBound RasterBound = new CqBound( pSurface.GetCachedRasterBound() );

//	    int nBuckets = m_cXBuckets * m_cYBuckets;

	    if ( CqOcclusionBox.CanCull( RasterBound ) )
	    {
	        // pSurface is behind everying in this bucket but it may be
	        // visible in other buckets it overlaps.
	        // bucket to the right
	        int nextBucket = CurrentBucketCol() + 1;
	        CqVector2D pos = BucketPosition( nextBucket, CurrentBucketRow() );
	        if ( ( nextBucket < cXBuckets() ) &&
	                ( RasterBound.vecMax().x >= pos.x ) )
	        {
				Bucket( nextBucket, CurrentBucketRow() ).AddGPrim( pSurface );
	            return true;
	        }

	        // next row
	        nextBucket = CurrentBucketRow() + 1;
	        // find bucket containing left side of bound
	        int nextBucketX = (int)( RasterBound.vecMin().x ) / XBucketSize();
	        nextBucketX = Math.max( nextBucketX, 0 );
	        pos = BucketPosition( nextBucketX, nextBucket );

	        if ( ( nextBucketX < cXBuckets() ) &&
	                ( nextBucket  < cYBuckets() ) &&
	                ( RasterBound.vecMax().y >= pos.y ) )
	        {
	            Bucket( nextBucketX, nextBucket ).AddGPrim( pSurface );
	            return true;
	        }

	        // Bound covers no more buckets therefore we can delete the surface completely.
	        String objname = "unnamed" ;
	        final String[] pattrName = pSurface.pAttributes().GetStringAttribute( "identifier", "name" );
	        if( pattrName != null)	objname = pattrName[0];
//	        std::cerr << info << "GPrim: \"" << objname << "\" occlusion culled" << std::endl;
	        HimawariLogger logger = HimawariLogger.getLogger();
			logger.info( "GPrim: \"" + objname + "\" occlusion culled\n" );
	        CqStats.STATS_INC( GPR_culled );
	        return true;
	    }
	    else
	    {
	        return false;
	    }
	}
	
//	----------------------------------------------------------------------
	/** 新しいマイクロポリゴンを待ち行列のリストに追加する。 
	 * @param pmpgNew CqMicroPolygonの引き出されたクラスのポインタ。
	 */
	public void	AddMPG( CqMicroPolygon pmpgNew )
	{
//		 Quick check for outside crop window.
//	    CqBound	B = new CqBound( pmpgNew.GetTotalBound() ); //2005/12/13 newする必要はない
	    CqBound	B =  pmpgNew.GetTotalBound();
	    
//	    ADDREF( pmpgNew );
	    pmpgNew.AddRef();
	    
	    if ( B.vecMax().x < m_CropWindowXMin - m_FilterXWidth / 2.0f || B.vecMax().y < m_CropWindowYMin - m_FilterYWidth / 2.0f ||
	         B.vecMin().x > m_CropWindowXMax + m_FilterXWidth / 2.0f || B.vecMin().y > m_CropWindowYMax + m_FilterYWidth / 2.0f )
	    {
//	        RELEASEREF( pmpgNew );
	    	pmpgNew.Release();
	        return ;
	    }

		////////// Dump the micro polygon into a dump file //////////
//	    #ifdef DEBUG_MPDUMP
//		mpdump.dump(*pmpgNew);
//	    #endif
		/////////////////////////////////////////////////////////////


	    // Find out the minimum bucket touched by the micropoly bound.
//	    int iBkt = m_cXBuckets * m_cYBuckets;

	    B.vecMin().x( B.vecMin().x - m_FilterXWidth / 2.0f );
	    B.vecMin().y( B.vecMin().y - m_FilterYWidth / 2.0f );
	    B.vecMax().x( B.vecMax().x + m_FilterXWidth / 2.0f );
	    B.vecMax().y( B.vecMax().y + m_FilterYWidth / 2.0f );

	    int iXBa = (int)( B.vecMin().x / ( m_XBucketSize ) );
	    int iYBa = (int)( B.vecMin().y / ( m_YBucketSize ) );
	    int iXBb = (int)( B.vecMax().x / ( m_XBucketSize ) );
	    int iYBb = (int)( B.vecMax().y / ( m_YBucketSize ) );

	    if ( ( iXBb < 0 ) || ( iYBb < 0 ) ||
	         ( iXBa >= m_cXBuckets ) || ( iYBa >= m_cYBuckets ) )
	    {
//	        RELEASEREF( pmpgNew );
	    	pmpgNew.Release();
	        return ;
	    }

	    if ( iXBa < 0 ) iXBa = 0;
	    if ( iYBa < 0 ) iYBa = 0;

	    // If the ideal bucket has already been processed we need to work out why we have got into this
	    // situation.
	    if ( Bucket(iXBa,iYBa).IsProcessed() )
	    {
	        PushMPGDown( pmpgNew, iXBa, iYBa );
	        PushMPGForward( pmpgNew, iXBa, iYBa );
//	        RELEASEREF( pmpgNew );
	        pmpgNew.Release();
	        return ;
	    }
	    assert( !Bucket(iXBa, iYBa).IsProcessed() );
	    Bucket(iXBa, iYBa).AddMPG( pmpgNew );
//	    ADDREF( pmpgNew );
	    pmpgNew.AddRef();

//	    RELEASEREF( pmpgNew );
	    pmpgNew.Release();
	}
	
//	----------------------------------------------------------------------
	/** 新しいマイクロポリゴンを待ち行列のリストに追加する。
	 * @param pmpg CqMicroPolygonの引き出されたクラスのポインタ。
	 */
	public 		boolean	PushMPGForward( CqMicroPolygon pmpg, int Col, int Row )
	{
//		 Should always mark as pushed forward even if not. As this is an idicator
	    // that the attempt has been made, used by the PushDown function. If this wasn't set
	    // then the mpg would be pushed down again when the next row is hit.
	    pmpg.MarkPushedForward();

	    // Check if there is anywhere to push forward to.
	    if ( Col == ( cXBuckets() - 1 ) )
	        return ( false );

	    int NextBucketForward = Col + 1;

	    // If the next bucket forward has already been processed, try the one following that.
	    if( Bucket( NextBucketForward, Row ).IsProcessed() )
	        return( PushMPGForward( pmpg, NextBucketForward, Row ) );

	    // Find out if any of the subbounds touch this bucket.
	    CqVector2D BucketMin = BucketPosition( NextBucketForward, Row );
	    CqVector2D BucketMax = BucketMin.add( BucketSize( NextBucketForward, Row ) );
	    CqVector2D FilterWidth = new CqVector2D( m_FilterXWidth * 0.5f, m_FilterYWidth * 0.5f );
	    BucketMin.assignSub( FilterWidth );
	    BucketMax.assignAdd( FilterWidth );

//	    CqBound	B = new CqBound( pmpg.GetTotalBound() );//new する必要はない2005/12/13
	    CqBound	B = pmpg.GetTotalBound();
	    final CqVector3D vMin = B.vecMin();
	    final CqVector3D vMax = B.vecMax();
	    if ( ( vMin.x > BucketMax.x ) ||
	            ( vMin.y > BucketMax.y ) ||
	            ( vMax.x < BucketMin.x ) ||
	            ( vMax.y < BucketMin.y ) )
	    {
	        return ( false );
	    }
	    else
	    {
//	        ADDREF( pmpg );
	        pmpg.AddRef();
	        Bucket( NextBucketForward, Row ).AddMPG( pmpg );
	        return ( true );
	    }
//	    return ( false );
	}
//	----------------------------------------------------------------------
	/** 待ち行列に新しいマイクロポリゴンを追加する。
	 * @param pmpg クラスに渡される CqMicroPolygon のポインタ
	 * @param CurrBucketIndex 私たちがプッシュとダウンしているバケットのインデックス
	 */
	public    	boolean	PushMPGDown( CqMicroPolygon pmpg, int Col, int Row )
	{
		if ( pmpg.IsPushedForward() ) return ( false );

	    // Check if there is anywhere to push down to.
	    if ( Row == ( m_cYBuckets - 1 ) )
	        return ( false );

	    int NextBucketDown = Row + 1;

	    // If the next bucket down has already been processed,
	    // try pushing forward from there.
	    if( Bucket( Col, NextBucketDown ).IsProcessed() )
	    {
	        if( PushMPGForward( pmpg, Col, NextBucketDown ) )
	            return( true );
	        else
	            // If that fails, push down again.
	            return( PushMPGDown( pmpg, Col, NextBucketDown ) );
	    }

	    // Find out if any of the subbounds touch this bucket.
	    CqVector2D BucketMin = BucketPosition( Col, NextBucketDown );
	    CqVector2D BucketMax = BucketMin.add( BucketSize( Col, NextBucketDown ) );
	    CqVector2D FilterWidth = new CqVector2D( m_FilterXWidth * 0.5f, m_FilterYWidth * 0.5f );
	    BucketMin.assignSub( FilterWidth );
	    BucketMax.assignAdd( FilterWidth );

//	    CqBound	B = new CqBound( pmpg.GetTotalBound( ) );//2005/12/13 newする必要はない
	    CqBound	B = pmpg.GetTotalBound( );
	    final CqVector3D vMin = B.vecMin();
	    final CqVector3D vMax = B.vecMax();
	    if ( ( vMin.x > BucketMax.x ) ||
	            ( vMin.y > BucketMax.y ) ||
	            ( vMax.x < BucketMin.x ) ||
	            ( vMax.y < BucketMin.y ) )
	    {
	        return ( false );
	    }
	    else
	    {
//	        ADDREF( pmpg );
	        pmpg.AddRef();
	        Bucket(Col, NextBucketDown ).AddMPG( pmpg );
	        // See if it needs to be pushed further down (extreme Motion Blur)
	        if ( PushMPGDown( pmpg, Col, NextBucketDown ) )
	            CqStats.STATS_INC( MPG_pushed_far_down );
	        return ( true );
	    }
//	    return ( false );
	}
	
//	----------------------------------------------------------------------
	/** まっている全てのマイクロポリゴングリッドをレンダリングする。
	 * 
	 * すべての指定されたバケットに入っているマイクロポリゴングリッドは適切な格子のバケットに
	 * 割り当てられた個々のマイクロポリゴンは分割されている。
	 * それから、RenderMicroPoly()は現在のバケツの中のそれぞれのマイクロ多角形のために呼ばれます。
	 * 
	 * @param xmin　最小のレンダリングされた一部のイメージの展開、アカウントバケットとクリッピングを伴う。
	 * @param xmax 最大のレンダリングされた一部のイメージの展開、アカウントバケットとクリッピングを伴う。
	 * @param ymin 最小のレンダリングされた一部のイメージの展開、アカウントバケットとクリッピングを伴う。
	 * @param ymax 最大のレンダリングされた一部のイメージの展開、アカウントバケットとクリッピングを伴う。
	 */
	public    	void	RenderMPGs( long xmin, long xmax, long ymin, long ymax )
	{
//		 Render any waiting MPGs
//	    std::vector<CqMicroPolygon*>::iterator lastmpg = CurrentBucket().aMPGs().end();
		
		CqMicroPolyGridBase pPrevGrid = null;
//		for ( std::vector<CqMicroPolygon>::iterator impg = CurrentBucket().aMPGs().begin(); impg != lastmpg; impg++ )
		for ( CqMicroPolygon impg : CurrentBucket().aMPGs() )
	    {
			CqMicroPolygon pMpg = impg;

			if(pMpg.pGrid() != pPrevGrid)
			{
				pPrevGrid = pMpg.pGrid();
				CacheGridInfo(pPrevGrid);
			}

	        RenderMicroPoly( pMpg, xmin, xmax, ymin, ymax );
	        if ( PushMPGDown( ( pMpg ), CurrentBucketCol(), CurrentBucketRow() ) )
	            CqStats.STATS_INC( MPG_pushed_down );
	        if ( PushMPGForward( ( pMpg ), CurrentBucketCol(), CurrentBucketRow() ) )
	        	CqStats.STATS_INC( MPG_pushed_forward );
//	        RELEASEREF( ( pMpg ) );
	        pMpg.Release();
	    }
	    CurrentBucket().aMPGs().clear();
	    
	   // Split any grids in this bucket waiting to be processed.
	    if ( !CurrentBucket().aGrids().isEmpty() )
	    {
//	        std::vector<CqMicroPolyGridBase*>::iterator lastgrid = CurrentBucket().aGrids().end();

//	        for ( std::vector<CqMicroPolyGridBase>::iterator igrid = CurrentBucket().aGrids().begin(); igrid != lastgrid; igrid++ )
	    	for ( CqMicroPolyGridBase igrid : CurrentBucket().aGrids()  )
	        {
				CqMicroPolyGridBase pGrid = igrid;
	            pGrid.Split( this, xmin, xmax, ymin, ymax );

				CacheGridInfo(pGrid);

	            // Render any waiting MPGs
//	            std::vector<CqMicroPolygon>::iterator lastmpg = CurrentBucket().aMPGs().end();
//	            for ( std::vector<CqMicroPolygon*>::iterator impg = CurrentBucket().aMPGs().begin(); impg != lastmpg; impg++ )
	            for ( CqMicroPolygon impg : CurrentBucket().aMPGs() )
	            {
					CqMicroPolygon pMpg = impg;
	                RenderMicroPoly( pMpg, xmin, xmax, ymin, ymax );
	                if ( PushMPGDown( ( pMpg ), CurrentBucketCol(), CurrentBucketRow() ) )
	                	CqStats.STATS_INC( MPG_pushed_down );
	                if ( PushMPGForward( ( pMpg ), CurrentBucketCol(), CurrentBucketRow() ) )
	                	CqStats.STATS_INC( MPG_pushed_forward );
//	                RELEASEREF( ( pMpg ) );
	                pMpg.Release();
	            }
	            CurrentBucket().aMPGs().clear();
	        }
		    CurrentBucket().aGrids().clear();
	    }
	}
	
//	----------------------------------------------------------------------
	/** 指定されたmicropolygonをレンダリングしてください。
	 * @param pMPG プロセスのmicropolygonのポインタ
	 * @param xmin Integer レンダリングの画像の部分のx最小値, アカウントバケツと切り取ります。
	 * @param xmax Integer レンダリングの画像の部分のx最大値, アカウントバケツと切り取ります。
	 * @param ymin Integer レンダリングの画像の部分のy最小値, アカウントバケツと切り取ります。
	 * @param ymax Integer レンダリングの画像の部分のy最大値, アカウントバケツと切り取ります。
	 
	   @see CqBucket, CqImagePixel
	 */
	public    void	RenderMicroPoly( CqMicroPolygon pMPG, long xmin, long xmax, long ymin, long ymax )
	{		
		CqBound Bound = pMPG.GetTotalBound();

		// if bounding box is outside our viewing range, then cull it.
		if ( Bound.vecMax().x < xmin || Bound.vecMax().y < ymin ||
			Bound.vecMin().x > xmax || Bound.vecMin().y > ymax ||
			Bound.vecMin().z > ClippingFar() || Bound.vecMax().z < ClippingNear())
		{
			CqStats.STATS_INC( MPG_culled );
			return;
		}

	    // fill in sample info for this mpg so we don't have to keep fetching it for each sample.
	    // Must check if colour is needed, as if not, the variable will have been deleted from the grid.
	    if ( QGetRenderContext().pDDmanager().fDisplayNeeds( "Ci" ) )
	    {
	        m_CurrentMpgSampleInfo.m_Colour = pMPG.colColor();
	    }
	    else
	    {
	        m_CurrentMpgSampleInfo.m_Colour = new CqColor( gColWhite );
	    }

	    // Must check if opacity is needed, as if not, the variable will have been deleted from the grid.
	    if ( QGetRenderContext().pDDmanager().fDisplayNeeds( "Oi" ) )
	    {
	        m_CurrentMpgSampleInfo.m_Opacity = pMPG.colOpacity();
	        m_CurrentMpgSampleInfo.m_Occludes = pMPG.colOpacity().ge( gColWhite );
	    }
	    else
	    {
	        m_CurrentMpgSampleInfo.m_Opacity = new CqColor( gColWhite );
	        m_CurrentMpgSampleInfo.m_Occludes = true;
	    }

		// use the single imagesample rather than the list if possible.
		// transparent, matte or csg samples, or if we need more than the first depth
		// value have to use the (slower) list.
		m_CurrentMpgSampleInfo.m_IsOpaque = m_CurrentMpgSampleInfo.m_Occludes &&
											pMPG.pGrid().pCSGNode() == null &&
											( DisplayMode() & ModeZ ) == 0&&
											!m_CurrentGridInfo.m_IsMatte;

	    boolean UsingDof = QGetRenderContext().UsingDepthOfField();
		boolean IsMoving = pMPG.IsMoving();

		if(IsMoving || UsingDof)
		{
			RenderMPG_MBOrDof( pMPG, xmin, xmax, ymin, ymax, IsMoving, UsingDof );
		}
		else
		{
			RenderMPG_Static( pMPG, xmin, xmax, ymin, ymax );
		}
	}
	
	/**モーションブラーか、Depth of fieldを使用しているときのレンダリング処理の部分
	 * 
	 * @param pMPG　レンダリングするマイクロポリゴン
	 * @param xmin　レンダリングの画像の部分のx最小値, アカウントバケツと切り取ります。
	 * @param xmax レンダリングの画像の部分のx最大値, アカウントバケツと切り取ります。
	 * @param ymin レンダリングの画像の部分のy最小値, アカウントバケツと切り取ります。
	 * @param ymax レンダリングの画像の部分のy最大値, アカウントバケツと切り取ります。
	 * @param IsMoving　モーションブラーが使用されているかのフラグ
	 * @param UsingDof Depth of fieldが使用されているかのフラグ
	 */
	public	void	RenderMPG_MBOrDof( CqMicroPolygon pMPG, long xmin, long xmax, long ymin, long ymax, boolean IsMoving, boolean UsingDof )
	{
		CqBucket Bucket = CurrentBucket();
//	    CqStats theStats = QGetRenderContext().Stats();

	    final float[] LodBounds = m_CurrentGridInfo.m_LodBounds;
	    boolean UsingLevelOfDetail = LodBounds[ 0 ] >= 0.0f;

	    int sample_hits = 0;
//	    float shd_rate = m_CurrentGridInfo.m_ShadingRate;

		CqHitTestCache hitTestCache;// = new CqHitTestCache();
		boolean cachedHitData = false;

		boolean mustDraw = !m_CurrentGridInfo.m_IsCullable;

		int iXSamples = PixelXSamples();
	    int iYSamples = PixelYSamples();

		float opentime = m_CurrentGridInfo.m_ShutterOpenTime;
		float closetime = m_CurrentGridInfo.m_ShutterCloseTime;
		float timePerSample = 0;
		if(IsMoving)
		{
			int numSamples = iXSamples * iYSamples;
			timePerSample = (float)numSamples / ( closetime - opentime );
		}

	    int bound_maxMB = pMPG.cSubBounds();
	    int bound_maxMB_1 = bound_maxMB - 1;
//		int currentIndex = 0;
	    for ( int bound_numMB = 0; bound_numMB < bound_maxMB; bound_numMB++ )
	    {
	        p_float time0 = new p_float();
	        p_float time1 = new p_float();
	        final CqBound Bound = pMPG.SubBound( bound_numMB, time0 );

			// get the index of the first and last samples that can fall inside
			// the time range of this bound
			int indexT0 = 0;
			int indexT1 = 0;
			if(IsMoving)
			{
				if ( bound_numMB != bound_maxMB_1 )
					pMPG.SubBound( bound_numMB + 1, time1 );
				else
					time1.value = closetime;//QGetRenderContext() ->optCurrent().GetFloatOptionWrite( "System", "Shutter" ) [ 1 ];

				indexT0 = (int)(Math.floor((time0.value - opentime) * timePerSample));
				indexT1 = (int)(Math.ceil((time1.value - opentime) * timePerSample));
			}

			float maxCocX = 0;
			float maxCocY = 0;

			float bminx = 0;
			float bmaxx = 0;
			float bminy = 0;
			float bmaxy = 0;
			float bminz = 0;
			float bmaxz = 0;
			// these values are the bound of the mpg not including dof extension.
			// reduce the mpg bound so it doesn't include the coc.
			float mpgbminx = 0;
			float mpgbmaxx = 0;
			float mpgbminy = 0;
			float mpgbmaxy = 0;
			int bound_maxDof;
			if(UsingDof)
			{
				final CqVector2D minZCoc = QGetRenderContext().GetCircleOfConfusion( Bound.vecMin().z );
				final CqVector2D maxZCoc = QGetRenderContext().GetCircleOfConfusion( Bound.vecMax().z );
				maxCocX = Math.max( minZCoc.x, maxZCoc.x );
				maxCocY = Math.max( minZCoc.y, maxZCoc.y );

				mpgbminx = Bound.vecMin().x + maxCocX;
				mpgbmaxx = Bound.vecMax().x - maxCocX;
				mpgbminy = Bound.vecMin().y + maxCocY;
				mpgbmaxy = Bound.vecMax().y - maxCocY;
				bminz = Bound.vecMin().z;
				bmaxz = Bound.vecMax().z;

				bound_maxDof = CqBucket.NumDofBounds();
			}
			else
			{
				bminx = Bound.vecMin().x;
				bmaxx = Bound.vecMax().x;
				bminy = Bound.vecMin().y;
				bmaxy = Bound.vecMax().y;
				bminz = Bound.vecMin().z;
				bmaxz = Bound.vecMax().z;

				bound_maxDof = 1;
			}

			for ( int bound_numDof = 0; bound_numDof < bound_maxDof; bound_numDof++ )
			{
				if(UsingDof)
				{
					// now shift the bounding box to cover only a given range of
					// lens positions.
					final CqBound DofBound = CqBucket.DofSubBound( bound_numDof );
					float leftOffset = DofBound.vecMax().x * maxCocX;
					float rightOffset = DofBound.vecMin().x * maxCocX;
					float topOffset = DofBound.vecMax().y * maxCocY;
					float bottomOffset = DofBound.vecMin().y * maxCocY;

					bminx = mpgbminx - leftOffset;
					bmaxx = mpgbmaxx - rightOffset;
					bminy = mpgbminy - topOffset;
					bmaxy = mpgbmaxy - bottomOffset;
				}

				// if bounding box is outside our viewing range, then cull it.
				if ( bmaxx < (float)xmin || bmaxy < (float)ymin ||
					bminx > (float)xmax || bminy > (float)ymax ||
					bminz > ClippingFar() || bmaxz < ClippingNear())
				{
					continue;
				}

				// Now go across all pixels touched by the micropolygon bound.
				// The first pixel position is at (sX, sY), the last one
				// at (eX, eY).
				int eX = (int)Math.ceil( bmaxx );
				int eY = (int)Math.ceil( bmaxy );
				if ( eX > xmax ) eX = (int)xmax;
				if ( eY > ymax ) eY = (int)ymax;

				int sX = (int)Math.floor( bminx );
				int sY = (int)Math.floor( bminy );
				if ( sY < ymin ) sY = (int)ymin;
				if ( sX < xmin ) sX = (int)xmin;

//				CqImagePixel pie, pie2;
				int pie, pie2;

				int nextx = Bucket.RealWidth();
				pie = CqBucket.ImageElement( sX, sY );

				for( int iY = sY; iY < eY; ++iY)
				{
					pie2 = pie;
					pie += nextx;

					for(int iX = sX; iX < eX; ++iX, ++pie2)
					{
						// only bother sampling if the mpg is not occluded in this pixel.
						if(mustDraw || bminz <= CqBucket.aieImage(pie2).MaxDepth())
						{
							int index;
							if(UsingDof)
							{
								// when using dof only one sample per pixel can
								// possibbly hit (the one corresponding to the
								// current bounding box).
								index = CqBucket.aieImage(pie2).GetDofOffsetIndex(bound_numDof);
							}
							else
							{
								// when using mb without dof, a range of samples
								// may have times within the current mb bounding box.
								index = indexT0;
							}

							// loop over potential samples
							do
							{
								final SqSampleData sampleData = CqBucket.aieImage(pie2).SampleData( index );
								final CqVector2D vecP = sampleData.m_Position;
								final float time = sampleData.m_Time;

								index++;

								CqStats.IncI( SPL_count );

								if(IsMoving && (time < time0.value || time > time1.value))
								{
									continue;
								}
							    //**【改】Aqsis 1.0.1では削除　***********************************	
//								CqDetachedMicroPolygon mp = new CqDetachedMicroPolygon(pMPG, time);
								//*************************************************************
								
								// check if sample lies inside mpg bounding box.
								if ( UsingDof )
								{
									//*******【改】Aqsis1.0.1大幅変更 *　変更後のソースは下へ********************************
									/* Create a new MP detatched from the grid so that we can
									 * shift the vertices to account for the CoC of DoF.
									 */
//									CqVector3D vA = mp.PointA();
//									CqVector2D coc = QGetRenderContext().GetCircleOfConfusion(vA.z);
//									vA.x(vA.x - ( coc.x * sampleData.m_DofOffset.x ));
//									vA.y(vA.y - ( coc.y * sampleData.m_DofOffset.y ));
//
//									CqVector3D vB = mp.PointB();
//									coc = QGetRenderContext().GetCircleOfConfusion(vB.z);
//									vB.x(vB.x - ( coc.x * sampleData.m_DofOffset.x ));
//									vB.y(vB.y - ( coc.y * sampleData.m_DofOffset.y ));
//
//									CqVector3D vC = mp.PointC();
//									coc = QGetRenderContext().GetCircleOfConfusion(vC.z);
//									vC.x(vC.x - ( coc.x * sampleData.m_DofOffset.x ));
//									vC.y(vC.y - ( coc.y * sampleData.m_DofOffset.y ));
//
//									CqVector3D vD = mp.PointD();
//									coc = QGetRenderContext().GetCircleOfConfusion(vD.z);
//									vD.x(vD.x - ( coc.x * sampleData.m_DofOffset.x ));
//									vD.y(vD.y - ( coc.y * sampleData.m_DofOffset.y ));
//				
//									CqBound DofBound = new CqBound(Bound);
//									DofBound.vecMin().x(DofBound.vecMin().x - (coc.x * sampleData.m_DofOffset.x ));
//									DofBound.vecMin().y(DofBound.vecMin().y - (coc.y * sampleData.m_DofOffset.y ));
//									DofBound.vecMax().x(DofBound.vecMax().x - (coc.x * sampleData.m_DofOffset.x ));
//									DofBound.vecMax().y(DofBound.vecMax().y - (coc.y * sampleData.m_DofOffset.y ));
//
//									if(!DofBound.Contains2D( vecP ))
//										continue;
//
//									mp.CacheHitTestValues(hitTestCache);
//									cachedHitData = true;
									//***********ここまで *********************************************************************
//************************************:******** 【改】Aqsis1.0.1のソースはこちら ************************************************

									CqBound DofBound = new CqBound(bminx, bminy, bminz, bmaxx, bmaxy, bmaxz);

									if(!DofBound.Contains2D( vecP ))
										continue;

									// Check to see if the sample is within the sample's level of detail
									if ( UsingLevelOfDetail )
									{
										float LevelOfDetail = sampleData.m_DetailLevel;
										if ( LodBounds[ 0 ] > LevelOfDetail || LevelOfDetail >= LodBounds[ 1 ] )
										{
											continue;
										}
									}


									IncI( SPL_bound_hits );

									// Now check if the subsample hits the micropoly
									boolean SampleHit;
									p_float D = new p_float();

									SampleHit = pMPG.Sample( sampleData, D, time, UsingDof );
									if ( SampleHit )
									{
										sample_hits++;
										// note index has already been incremented, so we use the previous value.
										StoreSample( pMPG, pie2, index-1, D );
									}
									
//*********************************************ここまで *********************************************************************
									
								}
								//*******【改】Aqsis1.0.1大幅変更 *　変更後のソースは下へ********************************
//								else
//								{
//									if(!Bound.Contains2D( vecP ))
//										continue;
//								}
//
//								// Check to see if the sample is within the sample's level of detail
//								if ( UsingLevelOfDetail)
//								{
//									float LevelOfDetail = sampleData.m_DetailLevel;
//									if ( LodBounds[ 0 ] > LevelOfDetail || LevelOfDetail >= LodBounds[ 1 ] )
//									{
//										continue;
//									}
//								}
//
//
//								CqStats.IncI( SPL_bound_hits );
//
//
//								// Now check if the subsample hits the micropoly
//								boolean SampleHit;
//								p_float D = new p_float();
//
//								if(!cachedHitData)
//								{
//									pMPG.CacheHitTestValues(hitTestCache);
//									cachedHitData = true;
//								}
//
//								if( UsingDof )
//								{
//									SampleHit = mp.Sample( vecP, D, time );
//								}
//								else
//								{
//									SampleHit = pMPG.Sample( vecP, D, time );
//								}
//
//								if ( SampleHit )
//								{
//									sample_hits++;
//									// note index has already been incremented, so we use the previous value.
//									StoreSample( pMPG, pie2, index-1, D );
//								}

								//***********ここまで *********************************************************************
//******************************************** 【改】Aqsis1.0.1のソースはこちら ************************************************
								else
								{
									if(!Bound.Contains2D( vecP ))
										continue;
									// Check to see if the sample is within the sample's level of detail
									if ( UsingLevelOfDetail)
									{
										float LevelOfDetail = sampleData.m_DetailLevel;
										if ( LodBounds[ 0 ] > LevelOfDetail || LevelOfDetail >= LodBounds[ 1 ] )
										{
											continue;
										}
									}


									IncI( SPL_bound_hits );

									// Now check if the subsample hits the micropoly
									boolean SampleHit;
									p_float D = new p_float();
									hitTestCache = new CqHitTestCache();
									pMPG.CacheHitTestValues( hitTestCache );
									cachedHitData = true;

									SampleHit = pMPG.Sample( sampleData, D, time, false );
									if ( SampleHit )
									{
										sample_hits++;
										// note index has already been incremented, so we use the previous value.
										StoreSample( pMPG, pie2, index-1, D );
									}
								}
//*********************************************ここまで *********************************************************************
							} while (!UsingDof && index < indexT1);
						}
					}
				}
			}
	    }
	}
	
	/**
	 * モーションブラーもDepth of fieldも使用していないときに使用するレンダリングメイン
	 * 
	 * @param pMPG　レンダリングするマイクロポリゴン
	 * @param xmin　レンダリングの画像の部分のx最小値, アカウントバケツと切り取ります。
	 * @param xmax レンダリングの画像の部分のx最大値, アカウントバケツと切り取ります。
	 * @param ymin レンダリングの画像の部分のy最小値, アカウントバケツと切り取ります。
	 * @param ymax レンダリングの画像の部分のy最大値, アカウントバケツと切り取ります。
	 */
	public	void	RenderMPG_Static( CqMicroPolygon pMPG, long xmin, long xmax, long ymin, long ymax )
	{
		CqBucket  Bucket = CurrentBucket();
//	    CqStats theStats = QGetRenderContext().Stats();

	    final float[] LodBounds = m_CurrentGridInfo.m_LodBounds;
	    boolean UsingLevelOfDetail = LodBounds[ 0 ] >= 0.0f;

	    int sample_hits = 0;
//	    float shd_rate = m_CurrentGridInfo.m_ShadingRate;

		//CqHitTestCache hitTestCache = new CqHitTestCache();
	    CqHitTestCache hitTestCache = null;
		boolean cachedHitData = false;

		boolean mustDraw = !m_CurrentGridInfo.m_IsCullable;

	    CqBound Bound = pMPG.GetTotalBound();

		float bminx = Bound.vecMin().x;
		float bmaxx = Bound.vecMax().x;
		float bminy = Bound.vecMin().y;
		float bmaxy = Bound.vecMax().y;
		float bminz = Bound.vecMin().z;

		// Now go across all pixels touched by the micropolygon bound.
		// The first pixel position is at (sX, sY), the last one
		// at (eX, eY).
		int eX = (int)Math.ceil( bmaxx );
		int eY = (int)Math.ceil( bmaxy );
		if ( eX > xmax ) eX = (int) xmax;
		if ( eY > ymax ) eY = (int) ymax;

		int sX = (int)Math.floor( bminx );
		int sY = (int)Math.floor( bminy );
		if ( sY < ymin ) sY = (int) ymin;
		if ( sX < xmin ) sX = (int) xmin;

//		CqImagePixel pie, pie2;
		int pie,pie2;

		int iXSamples = PixelXSamples();
		int iYSamples = PixelYSamples();

		int im = ( bminx < sX ) ? 0 : (int)Math.floor( ( bminx - sX ) * iXSamples );
		int in = ( bminy < sY ) ? 0 : (int)Math.floor( ( bminy - sY ) * iYSamples );
		int em = ( bmaxx > eX ) ? iXSamples : (int)Math.ceil( ( bmaxx - ( eX - 1 ) ) * iXSamples );
		int en = ( bmaxy > eY ) ? iYSamples : (int)Math.ceil( ( bmaxy - ( eY - 1 ) ) * iYSamples );

		int nextx = Bucket.RealWidth();
		pie = CqBucket.ImageElement( sX, sY );
		for( int iY = sY; iY < eY; ++iY)
		{
			pie2 = pie;
			pie += nextx;

			for(int iX = sX; iX < eX; ++iX, ++pie2)
			{
				// only bother sampling if the mpg is not occluded in this pixel.
				if(mustDraw || bminz <= CqBucket.aieImage(pie2).MaxDepth())
				{
					if(!cachedHitData)
					{
						if( hitTestCache == null)
						hitTestCache = new CqHitTestCache();
						pMPG.CacheHitTestValues(hitTestCache);
						cachedHitData = true;
					}

					// Now sample the micropolygon at several subsample positions
					// within the pixel. The subsample indices range from (start_m, n)
					// to (end_m-1, end_n-1).
					int m, n;
					n = ( iY == sY ) ? in : 0;
					int end_n = ( iY == ( eY - 1 ) ) ? en : iYSamples;
					int start_m = ( iX == sX ) ? im : 0;
					int end_m = ( iX == ( eX - 1 ) ) ? em : iXSamples;
					int index_start = n*iXSamples + start_m;

					for ( ; n < end_n; n++ )
					{
						int index = index_start;
						for ( m = start_m; m < end_m; m++, index++ )
						{
							//取得されたSampleDataのm_subCellIndexの値がCとJavaで違う 2005/12/13
							final SqSampleData sampleData = CqBucket.aieImage(pie2).SampleData( index );
							//final CqVector2D vecP = sampleData.m_Position;

							CqStats.IncI( SPL_count );
							//if(!Bound.Contains2D( vecP ))
							if(!Bound.Contains2D( sampleData.m_Position ))
								continue;
							
							final float time = 0.0f;
							
							// Check to see if the sample is within the sample's level of detail
							if ( UsingLevelOfDetail)
							{
								float LevelOfDetail = sampleData.m_DetailLevel;
								if ( LodBounds[ 0 ] > LevelOfDetail || LevelOfDetail >= LodBounds[ 1 ] )
								{
									continue;
								}
							}

							CqStats.IncI( SPL_bound_hits );

							// Now check if the subsample hits the micropoly
							boolean SampleHit;
							p_float D = new p_float();
							
//							SampleHit = pMPG.Sample( vecP, D, time ); //変更前
							//***【改】Aqsis1.0.1でこちらに変更 ************************
							SampleHit = pMPG.Sample( sampleData, D, time, false ); 
							//**************************************************
							if ( SampleHit )
							{
								sample_hits++;
								StoreSample( pMPG, pie2, index, D );
							}
						}
						index_start += iXSamples;
					}
				}
		/*        // Now compute the % of samples that hit...
				int scount = iXSamples * iYSamples;
				float max_hits = scount * shd_rate;
				int hit_rate = ( sample_hits / max_hits ) / 0.125;
				STATS_INC( MPG_sample_coverage0_125 + CLAMP( hit_rate - 1 , 0, 7 ) );
		*/  }
		}
	}
	
//	----------------------------------------------------------------------
	/**　すべての待っているサーフェースをレンダリングする
	 * レンダリングの処理のメイン部分 

	    This method loops through all the gprims stored in the specified bucket
	    and checks if the gprim can be diced and turned into a grid of micro
	    polygons or if it is still too large and has to be split (this check
	    is done in CqBasicSurface::Diceable()).

	    The dicing is done by the gprim in CqBasicSurface::Dice(). After that
	    the entire grid is shaded by calling CqMicroPolyGridBase::Shade().
	    The shaded grid is then stored in the current bucket and will eventually
	    be further processed by RenderMPGs().

	    If the gprim could not yet be diced, it is split into a number of
	    smaller gprims (CqBasicSurface::Split()) which are again assigned to
	    buckets (this doesn't necessarily have to be the current one again)
	    by calling PostSurface() (just as if it were regular gprims).

	    Finally, when all the gprims are diced and the resulting micro polygons
	    are rendered, the individual subpixel samples are combined into one
	    pixel color and opacity which is then exposed and quantized.
	    After that the method BucketComplete() and IqDDManager::DisplayBucket()
	    is called which can be used to display the bucket inside a window or
	    save it to disk.

	 * @param xmin Integer レンダリングの画像の部分のx最小値, アカウントバケツと切り取ります。
	 * @param xmax Integer レンダリングの画像の部分のx最大値, アカウントバケツと切り取ります。
	 * @param ymin Integer レンダリングの画像の部分のy最小値, アカウントバケツと切り取ります。
	 * @param ymax Integer レンダリングの画像の部分のy最大値, アカウントバケツと切り取ります。
	 */
	public  	void	RenderSurfaces( long xmin, long xmax, long ymin, long ymax )
	{
		boolean bIsEmpty = IsCurrentBucketEmpty();

	    // Render any waiting micro polygon grids.
	    QGetRenderContext().Stats().RenderMPGsTimer().Start();
	    RenderMPGs( xmin, xmax, ymin, ymax );
	    QGetRenderContext().Stats().RenderMPGsTimer().Stop();

	    QGetRenderContext().Stats().OcclusionCullTimer().Start();
	    // Update our occlusion hierarchy after drawing.
	    if ( !bIsEmpty )
	        CqOcclusionBox.Update();
	    QGetRenderContext().Stats().OcclusionCullTimer().Stop();

		CqBucket Bucket = CurrentBucket();

	    // Render any waiting subsurfaces.
	    CqBasicSurface pSurface = Bucket.pTopSurface();
	    
	    while ( pSurface != null)
	    {
	        if ( m_fQuit ) return ;

	        // If the epsilon check has deemed this surface to be undiceable, don't bother asking.
	        boolean fDiceable = false;
	        // Dice & shade the surface if it's small enough...
	        QGetRenderContext().Stats().DiceableTimer().Start();
	        fDiceable = pSurface.Diceable();
	        QGetRenderContext().Stats().DiceableTimer().Stop();

	        if ( fDiceable )
	        {
	            //Cull surface if it's hidden
	            if ( ( DisplayMode() & ModeZ ) == 0 && pSurface.pCSGNode() == null )
	            {
	                QGetRenderContext() .Stats().OcclusionCullTimer().Start();
	                boolean fCull = false;
	                if ( !bIsEmpty && pSurface.fCachedBound() )
	                    fCull = OcclusionCullSurface( pSurface );
	                QGetRenderContext().Stats().OcclusionCullTimer().Stop();
	                if ( fCull )
	                {
						Bucket.popSurface();
	                    pSurface = Bucket.pTopSurface();
	                    continue;
	                }
	            }

			    Bucket.popSurface();	
	            CqMicroPolyGridBase pGrid;
	            QGetRenderContext().Stats().DicingTimer().Start();
	            pGrid = pSurface.Dice();
	            QGetRenderContext().Stats().DicingTimer().Stop();
	            if ( null != pGrid )
	            {
//	                ADDREF( pGrid );
	            	pGrid.AddRef();
	              
	                // Only shade in all cases since the Displacement could be called in the shadow map creation too.
					pGrid.Shade();
	                pGrid.TransferOutputVariables();

					if ( pGrid.vfCulled() == false )
	                {
	                    // Only project micropolygon not culled
	                    Bucket.AddGrid( pGrid );
	                    // Render any waiting micro polygon grids.
	                    QGetRenderContext().Stats().RenderMPGsTimer().Start();
	                    RenderMPGs( xmin, xmax, ymin, ymax );
	                    QGetRenderContext().Stats().RenderMPGsTimer().Stop();
	                }
//	                RELEASEREF( pGrid );
					pGrid.Release();
	            }
	        }
	        // The surface is not small enough, so split it...
	        else if ( !pSurface.fDiscard() )
	        {
	            Bucket.popSurface();

	            // Decrease the total gprim count since this gprim is replaced by other gprims
	            CqStats.STATS_DEC( GPR_created_total );

	            // Split it
	            QGetRenderContext() .Stats().SplitsTimer().Start();
	            STLVector<CqBasicSurface > aSplits = new STLVector< CqBasicSurface >(CqBasicSurface.class);
	            int cSplits = pSurface.Split( aSplits );
	            int i;
	            for ( i = 0; i < cSplits; i++ )
	                PostSurface( aSplits.get( i ) );
 
	            QGetRenderContext().Stats().SplitsTimer().Stop();
	        } else if ( pSurface == Bucket.pTopSurface() ) 
	        {
	             // Make sure we will break the while() 
	             //   e.g.  !fDiceable  &&  pSurface->fDiscard()
	             Bucket.popSurface();
	        }

	        pSurface = Bucket.pTopSurface();
	        // Render any waiting micro polygon grids.
	        QGetRenderContext() .Stats().RenderMPGsTimer().Start();
	        RenderMPGs( xmin, xmax, ymin, ymax );
	        QGetRenderContext() .Stats().RenderMPGsTimer().Stop();

	        QGetRenderContext() .Stats().OcclusionCullTimer().Start();
	        // Update our occlusion hierarchy after each grid that gets drawn.
	        if ( !bIsEmpty )
	            CqOcclusionBox.Update();
	        QGetRenderContext() .Stats().OcclusionCullTimer().Stop();
	        
	    }
	    
	    // Now combine the colors at each pixel sample for any micropolygons rendered to that pixel.
	    if ( m_fQuit ) return ;

	    if(!bIsEmpty)
	    {
	        QGetRenderContext() .Stats().MakeCombine().Start();
	        CqBucket.CombineElements();
	        QGetRenderContext().Stats().MakeCombine().Stop();
	    }

	    QGetRenderContext() .Stats().MakeFilterBucket().Start();

	    boolean fImager = false;
	    String[] systemOptions;
	    if( ( systemOptions = QGetRenderContext().optCurrent().GetStringOption( "System", "Imager" ) ) != null )
	    	if( systemOptions[ 0 ].compareTo("null") != 0 )
			fImager = true;

	    if (fImager)
	        bIsEmpty = false;
	    
	    Bucket.FilterBucket(bIsEmpty);
	    if(!bIsEmpty)
	    {
	        Bucket.ExposeBucket();
	        Bucket.QuantizeBucket();
	    }

	    QGetRenderContext().Stats().MakeFilterBucket().Stop();
	    
	    BucketComplete();
	    Bucket.destract();
	    QGetRenderContext().Stats().MakeDisplayBucket().Start();
	    QGetRenderContext().pDDmanager().DisplayBucket( CurrentBucket() );//ここでドライバに渡す。
	    QGetRenderContext().Stats().MakeDisplayBucket().Stop();
	    
	}
	
//	----------------------------------------------------------------------
	/** 
	 * 　すべての待っているサーフェースをレンダリングする。
	 * 
	 * 画像の左上から初めて、RenderSurfaceを呼ぶことによって、すべてのバケットを計算していく。
	 * その後ImageCompleteから呼ばれる。
	 * 要求のときにOcclusionを取り外すことができるのは良いでしょう。
	 * しかしながら、Occlusionが閉塞なしで時間がかかったとき、私はケースを見ませんでした。
	 */
	public  	void	RenderImage()
	{
//////////Create a new dump file  //////////
//		#ifdef DEBUG_MPDUMP
//		mpdump.open();
//		mpdump.dumpImageInfo();
//	    #endif
		/////////////////////////////////////////////

		CqStats.STATS_SETF( MPG_min_area, FLT_MAX );
		CqStats.STATS_SETF( MPG_max_area, FLT_MIN );

	    if ( bucketmodulo == -1 )
	    {
	        // Small change which allows full control of virtual memory on NT swapping
	        bucketmodulo = m_cXBuckets;
	        int[] poptModulo = ( int[] ) QGetRenderContext().optCurrent().GetIntegerOption( "limits", "bucketmodulo" );
	        if ( poptModulo != null )
	        {
	            bucketmodulo = poptModulo[ 0 ];
	        }
	        if ( bucketmodulo <= 0 ) bucketmodulo = m_cXBuckets;
	    }



	    // Render the surface at the front of the list.
	    m_fDone = false;

	    CqVector2D bHalf = new CqVector2D( (float)(Math.floor(m_FilterXWidth / 2.0f)), (float)(Math.floor(m_FilterYWidth / 2.0f) ) );

	    // Setup the hierarchy of boxes for occlusion culling
	    CqOcclusionBox.CreateHierarchy( m_XBucketSize, m_YBucketSize, (int)m_FilterXWidth, (int)m_FilterYWidth );

	    Method pProgressHandler = null;
	    pProgressHandler = QGetRenderContext().pProgressHandler();

	    do
	    {
	        boolean bIsEmpty = IsCurrentBucketEmpty();
	        QGetRenderContext().Stats().Others().Start();
	        // Prepare the bucket.
	        CqVector2D bPos = BucketPosition();
	        CqVector2D bSize = BucketSize();
	        // TODO: fix non jittered bucket initialisation.
	        // Warning Jitter must be True is all cases; the InitialiseBucket when it is not in jittering mode
	        // doesn't initialise correctly so later we have problem in the FilterBucket()
	        boolean fImager = false;
	        String[] systemOptions;
	        if( ( systemOptions = QGetRenderContext().optCurrent().GetStringOption( "System", "Imager" ) ) != null )
	    	if( systemOptions[0].compareTo("null") != 0 )
			fImager = true;

	        if (fImager)
	            bIsEmpty = false;

	        CqBucket.InitialiseBucket( (int)( bPos.x ), (int)( bPos.y ), (int)( bSize.x ), (int)( bSize.y ), true, bIsEmpty );
	        CqBucket.InitialiseFilterValues();

			////////// Dump the pixel sample positions into a dump file //////////
//			#ifdef DEBUG_MPDUMP
//			mpdump.dumpPixelSamples();
//		    #endif
			/////////////////////////////////////////////////////////////////////////

	        // Set up some bounds for the bucket.
	        CqVector2D vecMin = bPos;
	        CqVector2D vecMax = bPos.add( bSize );
	        vecMin.assignSub( bHalf );
	        vecMax.assignAdd( bHalf );

	        long xmin = (long)( vecMin.x );
	        long ymin = (long)( vecMin.y );
	        long xmax = (long)( vecMax.x );
	        long ymax = (long)( vecMax.y );

	        if ( xmin < CropWindowXMin() - m_FilterXWidth / 2 )
				xmin = (long)(CropWindowXMin() - m_FilterXWidth / 2.0f);
	        if ( ymin < CropWindowYMin() - m_FilterYWidth / 2 )
				ymin = (long)(CropWindowYMin() - m_FilterYWidth / 2.0f);
	        if ( xmax > CropWindowXMax() + m_FilterXWidth / 2 )
				xmax = (long)(CropWindowXMax() + m_FilterXWidth / 2.0f);
	        if ( ymax > CropWindowYMax() + m_FilterYWidth / 2 )
				ymax = (long)(CropWindowYMax() + m_FilterYWidth / 2.0f);

	        QGetRenderContext().Stats().Others().Stop();

	        if ( !bIsEmpty )
	        {
	            QGetRenderContext().Stats().OcclusionCullTimer().Start();
	            CqOcclusionBox.SetupHierarchy( CurrentBucket(), (int)xmin, (int)ymin, (int)xmax, (int)ymax );
	            QGetRenderContext().Stats().OcclusionCullTimer().Stop();
	        }

	        int iBucket = ( CurrentBucketRow() * cXBuckets() ) + CurrentBucketCol();
	        if ( pProgressHandler != null )
	        {
	            // Inform the status class how far we have got, and update UI.
	            float Complete = ( float ) ( cXBuckets() * cYBuckets() );
	            Complete /= iBucket;
	            Complete = 100.0f / Complete;
	            QGetRenderContext().Stats().SetComplete( Complete );
	            
	            try {
					pProgressHandler.invoke( QGetRenderContext(), Complete, QGetRenderContext().CurrentFrame() );
				} catch (Exception e) {
					HimawariLogger.outputException( e );
				}
	        }

	        RenderSurfaces( xmin, xmax, ymin, ymax );
	        if ( m_fQuit )
	        {
	            m_fDone = true;
	            return ;
	        }
//	#ifdef WIN32
//	        if ( !( iBucket % bucketmodulo ) )
//	             SetProcessWorkingSetSize( GetCurrentProcess(), 0xffffffff, 0xffffffff );
//	#endif
//	#if defined(REQUIRED)
//	        int iB2, NumGrids = 0, NumPolys = 0;
//	        for ( iB2 = 0; iB2 < nBuckets; iB2++ )
//	        {
//	            NumGrids += m_aBuckets[ iB2 ].aGrids().size();
//	            NumPolys += m_aBuckets[ iB2 ].aMPGs().size();
//	        }
//	#endif
	        CurrentBucket().SetProcessed();
	    } while( NextBucket() );

	    ImageComplete();

	    CqBucket.ShutdownBucket();

	    CqOcclusionBox.DeleteHierarchy();
	    // Pass >100 through to progress to allow it to indicate completion.

	    if ( pProgressHandler != null)
	    {
	    	try
	    	{
	    		pProgressHandler.invoke( QGetRenderContext() ,100.0f, QGetRenderContext().CurrentFrame() );
		    } catch (Exception e) {
		    	HimawariLogger.outputException( e );
			}
	    }
	    m_fDone = true;
	}
	
	private static SqImageSample localImageVal = null;
//	public  	void	StoreSample( CqMicroPolygon pMPG, CqImagePixel pie2, int index, float D )
	public void	StoreSample( CqMicroPolygon pMPG, int pie2, int index, p_float D )
	{
		boolean Occludes = m_CurrentMpgSampleInfo.m_Occludes;
		boolean opaque =  m_CurrentMpgSampleInfo.m_IsOpaque;

		SqImageSample currentOpaqueSample = CqBucket.aieImage(pie2).OpaqueValues(index);
		if(localImageVal == null)
		{
			localImageVal = new SqImageSample( QGetRenderContext().GetOutputDataTotalSize() );
		}
		
		SqImageSample ImageVal = opaque ? currentOpaqueSample : localImageVal;

		STLVector<SqImageSample> aValues = CqBucket.aieImage(pie2).Values( index );//不透明なものを格納するベクタ
		int itecount,iteend;
		itecount = 0;
		iteend = aValues.size();
		
		SqImageSample sample = null;
//		SqImageSample end = null;

		if(itecount < iteend)
		{
			sample = aValues.get(itecount);
		}
		
//		Vector<SqImageSample>::iterator sample = aValues.begin();
//		Vector<SqImageSample>::iterator end = aValues.end();

		// return if the sample is occluded and can be culled.
		if(opaque)
		{
			if((currentOpaqueSample.m_flags & SqImageSample.Flag_Valid) != 0 &&
				currentOpaqueSample.Depth() <= D.value)
			{
				return;
			}
		}
		else
		{
			// Sort the color/opacity into the visible point list
			// return if the sample is occluded and can be culled.
//			while( sample != end )
//			while( ite.hasNext() )
			while( itecount < iteend )
			{
				if((sample).Depth() >= D.value)
					break;

				if(((sample).m_flags & SqImageSample.Flag_Occludes) != 0&&
					((sample).m_pCSGNode == null )&& m_CurrentGridInfo.m_IsCullable)
					return;

				++itecount;
				if( itecount < iteend )
				{
					sample = aValues.get(itecount);
				}
				else
				{
					sample = null;
				}
			}
		}

	    ImageVal.SetDepth( D.value );

		CqStats.IncI( SPL_hits );
		pMPG.MarkHit();

	    Valarray val = ImageVal.m_Data;
	    val.setValueAt( 0 , m_CurrentMpgSampleInfo.m_Colour.fRed() );
	    val.setValueAt( 1 , m_CurrentMpgSampleInfo.m_Colour.fGreen() );
	    val.setValueAt( 2 , m_CurrentMpgSampleInfo.m_Colour.fBlue() );
	    val.setValueAt( 3 , m_CurrentMpgSampleInfo.m_Opacity.fRed() );
	    val.setValueAt( 4 , m_CurrentMpgSampleInfo.m_Opacity.fGreen() );
	    val.setValueAt( 5 , m_CurrentMpgSampleInfo.m_Opacity.fBlue() );
	    val.setValueAt( 6 , D.value );

	    // Now store any other data types that have been registered.
		if(m_CurrentGridInfo.m_UsesDataMap)
		{
			StoreExtraData(pMPG, val);
		}

		if(!opaque)
		{
			// If depth is exactly the same as previous sample, chances are we've
			// hit a MPG grid line.
			// \note: Cannot do this if there is CSG involved, as all samples must be taken and kept the same.
//			if ( sample != end && (sample).Depth() == ImageVal.Depth() && (sample).m_pCSGNode == null)
			//if ( itecount != iteend && (sample).Depth() == ImageVal.Depth() && (sample).m_pCSGNode == null)
			if ( itecount != iteend && (sample).Depth() == ImageVal.Depth() && (sample).m_pCSGNode == null)
			{
				(sample).m_Data.assignment( (sample).m_Data.add( val ).mul( 0.5f ) );
				return;
			}
		}

	    // Update max depth values
	    if ( ( DisplayMode() & ModeZ ) == 0 && Occludes )
	    {
	        CqOcclusionBox.MarkForUpdate( CqBucket.aieImage(pie2).OcclusionBoxId() );
	        CqBucket.aieImage(pie2).MarkForZUpdate();
	    }

	    ImageVal.m_pCSGNode = pMPG.pGrid().pCSGNode();

	    ImageVal.m_flags = 0;
	    if ( Occludes )
	    {
	        ImageVal.m_flags |= SqImageSample.Flag_Occludes;
	    }
	    if( m_CurrentGridInfo.m_IsMatte )
	    {
	        ImageVal.m_flags |= SqImageSample.Flag_Matte;
	    }

		if(!opaque)
		{
			aValues.add( itecount, new SqImageSample( ImageVal ) );
			
			// mark this pixel as using the visible point list.
			CqBucket.aieImage(pie2).SetUsesSampleList();
		}
		else
		{
			// increment the sample count if we havn't already.
			if((ImageVal.m_flags & SqImageSample.Flag_Valid) == 0)
				CqBucket.aieImage(pie2).IncOpaqueSampleCount();

			// mark this sample as having been written into.
			ImageVal.m_flags |= SqImageSample.Flag_Valid;
		}
	}
	
	public		void	StoreExtraData( CqMicroPolygon pMPG, Valarray val)
	{
//		 std::map<std::string, CqRenderer::SqOutputDataEntry>& DataMap = QGetRenderContext().GetMapOfOutputDataEntries();
//		  std::map<std::string, CqRenderer::SqOutputDataEntry>::iterator entry;
		HashMap<String, CqRenderer.SqOutputDataEntry> DataMap = QGetRenderContext().GetMapOfOutputDataEntries();
		
//		  for ( entry = DataMap.begin(); entry != DataMap.end(); ++entry )
			for ( Entry<String, CqRenderer.SqOutputDataEntry> entry :  DataMap.entrySet() )
		    {
		        IqShaderData pData;
		        if ( ( pData = pMPG.pGrid().FindStandardVar( entry.getKey() ) ) != null )
		        {
		            switch ( pData.Type().getValue() )
		            {
		            case type_float:
		            case type_integer:
		                {
		                    p_float f = new p_float();
		                    pData.GetFloat( f, pMPG.GetIndex() );
		                    val.setValueAt( entry.getValue().m_Offset , f.value);
		                    break;
		                }
		            case type_point:
		            case type_normal:
		            case type_vector:
		            case type_hpoint:
		                {
		                    CqVector3D v = new CqVector3D();
		                    pData.GetPoint( v, pMPG.GetIndex() );
		                    val.setValueAt( entry.getValue().m_Offset , v.x );
		                    val.setValueAt( entry.getValue().m_Offset + 1 ,v.y );
		                    val.setValueAt( entry.getValue().m_Offset + 2 , v.z );
		                    break;
		                }
		            case type_color:
		                {
		                    CqColor c = new CqColor();
		                    pData.GetColor( c, pMPG.GetIndex() );
		                    val.setValueAt( entry.getValue().m_Offset , c.fRed() );
		                    val.setValueAt( entry.getValue().m_Offset + 1 , c.fGreen() );
		                    val.setValueAt( entry.getValue().m_Offset + 2 , c.fBlue() );
		                    break;
		                }
		            case type_matrix:
		                {
		                    CqMatrix m = new CqMatrix();
		                    pData.GetMatrix( m, pMPG.GetIndex() );
//		                    float pElements = m.pElements();
		                    val.setValueAt( entry.getValue().m_Offset , m.m_aaElement[0][0] );
		                    val.setValueAt( entry.getValue().m_Offset + 1 , m.m_aaElement[0][1] );
		                    val.setValueAt( entry.getValue().m_Offset + 2 , m.m_aaElement[0][2] );
		                    val.setValueAt( entry.getValue().m_Offset + 3 , m.m_aaElement[0][3] );
		                    val.setValueAt( entry.getValue().m_Offset + 4 , m.m_aaElement[1][0] );
		                    val.setValueAt( entry.getValue().m_Offset + 5 , m.m_aaElement[1][1] );
		                    val.setValueAt( entry.getValue().m_Offset + 6 , m.m_aaElement[1][2] );
		                    val.setValueAt( entry.getValue().m_Offset + 7 , m.m_aaElement[1][3] );
		                    val.setValueAt( entry.getValue().m_Offset + 8 , m.m_aaElement[2][0] );
		                    val.setValueAt( entry.getValue().m_Offset + 9 , m.m_aaElement[2][1] );
		                    val.setValueAt( entry.getValue().m_Offset + 10 , m.m_aaElement[2][2] ) ;
		                    val.setValueAt( entry.getValue().m_Offset + 11 , m.m_aaElement[2][3] );
		                    val.setValueAt( entry.getValue().m_Offset + 12 , m.m_aaElement[3][0] );
		                    val.setValueAt( entry.getValue().m_Offset + 13 , m.m_aaElement[3][1] );
		                    val.setValueAt( entry.getValue().m_Offset + 14 , m.m_aaElement[3][2] );
		                    val.setValueAt( entry.getValue().m_Offset + 15 , m.m_aaElement[3][3] );
		                    break;
		                }
		            default:
		                // left blank to avoid compiler warnings about unhandled
		                //  types
		                break;
		            }
		        }
		    }
	}

	/** Get completion status of this rendered image.
     * \return bool indicating finished or not.
     */
	public    boolean	fDone()
    {
        return ( m_fDone );
    }

//	----------------------------------------------------------------------
	/** Construct the image buffer to an initial state using the current options.
	 */
	public 	void	SetImage()
	{
		
			HimawariLogger logger = HimawariLogger.getLogger();
			
			DeleteImage();
		    
			m_XBucketSize = 16;
		    m_YBucketSize = 16;
		    int[] poptBucketSize = QGetRenderContext().optCurrent().GetIntegerOption( "limits", "bucketsize" );
		    if ( poptBucketSize != null )
		    {
		    	if( poptBucketSize[ 0 ] > 0)
		    	{
		    		m_XBucketSize = poptBucketSize[ 0 ];
		    	}
		    	else
		    	{
		    		logger.warning("X BucketSize under 0 cast to 16\n");
		    	}
		    	if( poptBucketSize[ 1 ] > 0)
		    	{
		    		m_YBucketSize = poptBucketSize[ 1 ];
		    	}
		    	else
		    	{
		    		logger.warning("Y BucketSize under 0 cast to 16\n");
		    	}
		    }
		    /* add artificially a border around based on the current filterwidth so the diced primitives
		        * may fit better within a bucket */
		    m_FilterXWidth = QGetRenderContext().optCurrent().GetFloatOptionIndex( "System", "FilterWidth" , 0 ).value;
		    m_FilterYWidth = QGetRenderContext().optCurrent().GetFloatOptionIndex( "System", "FilterWidth" , 1 ).value;

		    m_iXRes = QGetRenderContext().optCurrent().GetIntegerOptionIndex( "System", "Resolution" , 0 ).value;
		    m_iYRes = QGetRenderContext().optCurrent().GetIntegerOptionIndex( "System", "Resolution" , 1 ).value;
		    m_CropWindowXMin = (int)( CLAMP( (float)Math.ceil( m_iXRes * QGetRenderContext() .optCurrent().GetFloatOptionIndex( "System", "CropWindow" , 0 ).value ), 0.0f, (float)m_iXRes ) );
		    m_CropWindowXMax = (int)( CLAMP( (float)Math.ceil( m_iXRes * QGetRenderContext() .optCurrent().GetFloatOptionIndex( "System", "CropWindow" , 1 ).value ), 0.0f, (float)m_iXRes ) );
		    m_CropWindowYMin = (int)( CLAMP( (float)Math.ceil( m_iYRes * QGetRenderContext() .optCurrent().GetFloatOptionIndex( "System", "CropWindow" , 2 ).value ), 0.0f, (float)m_iYRes ) );
		    m_CropWindowYMax = (int)( CLAMP( (float)Math.ceil( m_iYRes * QGetRenderContext() .optCurrent().GetFloatOptionIndex( "System", "CropWindow" , 3 ).value ), 0.0f, (float)m_iYRes ) );
		    m_cXBuckets = ( m_iXRes / m_XBucketSize ) + 1;
		    m_cYBuckets = ( m_iYRes / m_YBucketSize ) + 1;
		    m_PixelXSamples = QGetRenderContext() .optCurrent().GetIntegerOptionIndex( "System", "PixelSamples" , 0 ).value;
		    m_PixelYSamples = QGetRenderContext() .optCurrent().GetIntegerOptionIndex( "System", "PixelSamples" , 1 ).value;

		    m_ClippingNear = (float)( QGetRenderContext().optCurrent().GetFloatOptionIndex( "System", "Clipping" , 0 ).value );
		    m_ClippingFar = (float)( QGetRenderContext().optCurrent().GetFloatOptionIndex( "System", "Clipping" , 1 ).value );
		    m_DisplayMode = QGetRenderContext().optCurrent().GetIntegerOptionIndex( "System", "DisplayMode" , 0 ).value;

			CqBucket.SetImageBuffer(this);
		    m_Buckets.setSize( m_cYBuckets );
//		    Vctor<Vector<CqBucket> >::iterator i;
//		    for( i = m_Buckets.begin(); i!=m_Buckets.end(); i++)
		    for( STLVector<CqBucket> i : m_Buckets)
		    {
		        i.setSize( m_cXBuckets );
//		        std::vector<CqBucket>::iterator b;
		        for( CqBucket b: i)
		            b.SetProcessed( false );
		    }

		    m_CurrentBucketCol = m_CurrentBucketRow = 0;
	}
	
//	----------------------------------------------------------------------
	/** Stop rendering.
	 */

	public void Quit()
	{
	    m_fQuit = true;
	}

//	----------------------------------------------------------------------
	/** This is called by the renderer to inform an image buffer it is no longer needed.
	 */
	public void Release()
	{
//	    delete( this );
	}


	    // Callbacks to overridden image buffer class to allow display/processing etc.
	public void	BucketComplete()
    {}
	
	public void	ImageComplete()
	{}
	
//	----------------------------------------------------------------------
	/** Return if a certain bucket is completely empty.
	 
	    True or False.
	 
	     It is empty only when this bucket doesn't contain any surface, 
		 micropolygon or grids.
	 */
	public boolean	IsCurrentBucketEmpty()
	{
		boolean retval = false;

	    CqBucket Bucket = CurrentBucket();

	    if ( ( Bucket.pTopSurface() == null) &&
	            Bucket.aGrids().isEmpty() &&
	            Bucket.aMPGs().isEmpty() )
	        retval = true;

	    return retval;
	}

	private 	boolean	m_fQuit;			///< もし、システムにより終了が要求されていたら設定する。Set by system if a quit has been requested.
	private 	boolean	m_fDone;			///< このレンダーのイメージが完成した時に設定される。Set when the render of this image has completed.

	private 	int		m_iXRes;			///< イメージリソリューションのinteger型の横の長さ　Integer horizontal image resolution.
	private 	int		m_iYRes;			///< イメージリソリューションのinteger型の縦の長さ　Integer vertical image resolution.
	private 	int		m_cXBuckets;		///< バケットカウントのinteger型の横の長さ　Integer horizontal bucket count.
	private 	int		m_cYBuckets;		///< バケットカウントのinteger型の縦の長さ　Integer vertical bucket count.
	private 	int		m_XBucketSize;		///< integer型の横のバケットサイズ　Integer horizontal bucket size.
	private    	int		m_YBucketSize;		///< integer型の縦のバケットサイズ　Integer vertical bucket size.
	private    	int		m_PixelXSamples;	///< integer型の横のピクセル毎サンプル　Integer horizontal sample per pixel count.
	private    	int		m_PixelYSamples;	///< integer型の縦のピクセル毎サンプル　Integer vertical sample per pixel count.
	private    	float	m_FilterXWidth;		///< integer型の横のピクセルフィルターのピクセルの中のワイド　Integer horizontal pixel filter width in pixels.
	private    	float	m_FilterYWidth;		///< integer型の縦のピクセルフィルターのピクセルの中のワイド　Integer vertical pixel filter width in pixels.
	private   	int		m_CropWindowXMin;	///< integer型の横のレンダリングされる最小の値　Integer minimum horizontal pixel to render.
	private    	int		m_CropWindowYMin;	///< integer型の縦のレンダリングされる最小の値　Integer minimum vertical pixel to render.
	private    	int		m_CropWindowXMax;	///< integer型の横のレンダリングされる最大の値　Integer maximum horizontal pixel to render.
	private    	int		m_CropWindowYMax;	///< integer型の縦のレンダリングされる最大の値　Integer maximum vertical pixel to render.
	private		float	m_ClippingNear;		///< 近い方のクリッピング平面の距離　Near clipping distance.
	private    	float	m_ClippingFar;		///< 遠い方のクリッピング平面の距離　Far clipping distance.
	private    	int		m_DisplayMode;		///< ディスプレイモードのInteger型の列挙型　Integer display mode, a member of the enum Mode.

	private    	STLVector<STLVector<CqBucket>>	m_Buckets = new STLVector<STLVector<CqBucket>>(2,CqBucket.class); ///< Array of bucket storage classes (row/col)
	private    	int	m_CurrentBucketCol;	///< Column index of the bucket currently being processed.
	private    	int	m_CurrentBucketRow;	///< Row index of the bucket currently being processed.

	    // This struct is used to hold info about a mpg that is used when rendering the mpg.
	    // It caches the info for use by multiple samples.
	private    class SqMpgSampleInfo
    {
        CqColor		m_Colour;
        CqColor		m_Opacity;
        boolean		m_Occludes;		// whether the opacity is full.
		boolean		m_IsOpaque;		// whether the mpg can use the faster StoreOpaqueSample routine that assumes a few things.
    }
    private    SqMpgSampleInfo m_CurrentMpgSampleInfo = new SqMpgSampleInfo();

		// This struct holds info about a grid that can be cached and used for all its mpgs.
    private class SqGridInfo
	{
		float			m_ShadingRate;
		float			m_ShutterOpenTime;
		float			m_ShutterCloseTime;
		boolean		m_IsMatte;
		boolean		m_IsCullable;
		boolean		m_UsesDataMap;
		float[]			m_LodBounds ;
	}
    private SqGridInfo m_CurrentGridInfo = new SqGridInfo();

    /** Cache some info about the given grid so it can be referenced by multiple mpgs.
	 * @param pGrid grid to cache info of.
	 */
	private void CacheGridInfo( CqMicroPolyGridBase pGrid )
	{
		m_CurrentGridInfo.m_IsMatte = pGrid.pAttributes().GetIntegerAttribute( "System", "Matte" ) [ 0 ] == 1;

		// this is true if the mpgs can safely be occlusion culled.
		m_CurrentGridInfo.m_IsCullable = (( DisplayMode() & ModeZ ) == 0) && (pGrid.pCSGNode() == null);

		m_CurrentGridInfo.m_UsesDataMap = !(QGetRenderContext() .GetMapOfOutputDataEntries().isEmpty());

	    m_CurrentGridInfo.m_ShadingRate = pGrid.pAttributes() .GetFloatAttribute( "System", "ShadingRate" ) [ 0 ];
		m_CurrentGridInfo.m_ShutterOpenTime = QGetRenderContext() .optCurrent().GetFloatOptionIndex( "System", "Shutter" , 0 ).value;
		m_CurrentGridInfo.m_ShutterCloseTime = QGetRenderContext() .optCurrent().GetFloatOptionIndex( "System", "Shutter" , 1 ).value;

		m_CurrentGridInfo.m_LodBounds = pGrid.pAttributes() .GetFloatAttribute( "System", "LevelOfDetailBounds" );
	}
}
