// 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 java.util.Collections;
import java.util.Iterator;

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.CqRandom;
import net.cellcomputing.himawari.library.types.CqVector2D;
import net.cellcomputing.himawari.util.HimawariLogger;


import static net.cellcomputing.himawari.library.Float_h.*;
import static net.cellcomputing.himawari.library.RiGlobal.*;

//-----------------------------------------------------------------------
/** Storage class for all data relating to a single pixel in the image.<br>
 * イメージで1画素に関連するすべてのデータのための記憶域クラス。
 */
public strictfp class CqImagePixel {
	
	
//	----------------------------------------------------------------------
	/** コンストラクタ
	 */
	public CqImagePixel()
	{
		m_XSamples =  0 ;
		m_YSamples =  0 ;
		m_MaxDepth = FLT_MAX ;
		m_MinDepth = FLT_MAX ;
		m_OcclusionBoxId = -1 ;
		m_NeedsZUpdate = false ;
	}
	
	/** コピーコンストラクタ
	 */
	public CqImagePixel( CqImagePixel ieFrom )
	{
		this.m_AnySampleUsesSampleList = ieFrom.m_AnySampleUsesSampleList;
		this.m_aValues = ieFrom.m_aValues;
		this.m_Data = ieFrom.m_Data;
		this.m_DofOffsetIndices = ieFrom.m_DofOffsetIndices;
		this.m_MaxDepth = ieFrom.m_MaxDepth;
		this.m_MinDepth = ieFrom.m_MinDepth;
		this.m_NeedsZUpdate = ieFrom.m_NeedsZUpdate;
		this.m_OcclusionBoxId = ieFrom.m_OcclusionBoxId;
		this.m_OpaqueSampleCount = ieFrom.m_OpaqueSampleCount;
		this.m_Samples = ieFrom.m_Samples;
		this.m_XSamples = ieFrom.m_XSamples;
		this.m_YSamples = ieFrom.m_YSamples;
		this.random = ieFrom.random;
	}
//	----------------------------------------------------------------------
	/** デストラクタ
	 */
	public void destruct()
	{
		
	}
	
	/** 水平方向のサンプル数を返す。
	 * @return int型の数字を返す。
	 */
	public int	XSamples()
	{
		return ( m_XSamples );
	}
	/** 垂直方向のサンプル数を返す。
	 * @return int型の数字を返す。
	 */
	public int	YSamples()
	{
		return ( m_YSamples );
	}
	
//	----------------------------------------------------------------------
	/** 
	 * ピクセルのサイズを指定して、その分のメモリを確保する。
	 * @param XSamples XのIntegerがたのカウント数。
	 * @param YSamples ＹのIntegerがたのカウント数。
	 */
	public void	AllocateSamples( int XSamples, int YSamples )
	{
		if( m_XSamples != XSamples || m_YSamples != YSamples )
		{
			m_XSamples = XSamples;
			m_YSamples = YSamples;
			int numSamples = m_XSamples * m_YSamples;
			
			if ( XSamples > 0 && YSamples > 0 )
			{
				m_aValues.resize( numSamples );
				// Initialise the OpaqueSampleEntries to the correct depth for the data we are
				// rendering, including any AOV data.
				
//				m_OpaqueValues.setSize( numSamples, def );
				for(int i = m_OpaqueValues.size() ; i< numSamples ;i++)
					m_OpaqueValues.add(new SqImageSample( QGetRenderContext().GetOutputDataTotalSize() ) );
				
				m_Samples.setSize( numSamples );
				m_DofOffsetIndices.setSize( numSamples );
			}
		}
	}
	
//	----------------------------------------------------------------------
	/** 
	 * サンプル配列をマルチジッター機能を使って満たす。初期化機能
	 * @param vecPixel Cq2DVector このイメージ要素でピクセルをコーディネートしてください。サンプルポイントが確実に相対的であるのではなく、絶対になるようにするのにおいて、
	 * 使用されています。
	 * @param fJitter ジッタリングをサンプルポイントに適用するかどうかを示して、弛んでください。
	 */
	private CqRandom random = new CqRandom( 53 );
	
	public void	InitialiseSamples( STLVector<CqVector2D> vecSamples )
	{
		InitialiseSamples(vecSamples,true);
	}
	public void	InitialiseSamples( STLVector<CqVector2D> vecSamples, boolean fJitter )
	{
		p_float opentime = new p_float( QGetRenderContext().optCurrent().GetFloatOptionIndex( "System", "Shutter" , 0 ).value );
		p_float closetime = new p_float( QGetRenderContext().optCurrent().GetFloatOptionIndex( "System", "Shutter" , 1 ).value );
		
		int numSamples = m_XSamples * m_YSamples;
		float subcell_width = 1.0f / numSamples;
		int m = m_XSamples;
		int n = m_YSamples;
		int i, j;
		
		vecSamples.setSize(numSamples);
		
		if ( !fJitter )
		{
			//　真ん中のポイントを使ってサンプルを初期化する。
			float XInc = ( 1.0f / m_XSamples ) / 2.0f;
			float YInc = ( 1.0f / m_YSamples ) / 2.0f;
			int y;
			for ( y = 0; y < m_YSamples; y++ )
			{
				float YSam = YInc + ( YInc * y );
				int x;
				for ( x = 0; x < m_XSamples; x++ )
//					vecSamples.set( ( y * m_XSamples ) + x ,new CqVector2D( XInc + ( XInc * x ), YSam ) );
					vecSamples.get( ( y * m_XSamples ) + x ).assignment( new CqVector2D( XInc + ( XInc * x ), YSam ) );
			}
			
			// モーションブラーと、LODとサブセルのための時間を代入する。
			float time = 0;
			int nSamples = m_XSamples*m_YSamples;
			float dtime = 1.0f / nSamples;
			
			for ( i = 0; i < nSamples; i++ )
			{
				m_Samples.get( i ).m_SubCellIndex = 0;
				m_Samples.get( i ).m_DetailLevel = m_Samples.get( i ).m_Time = time;
				time += dtime;
			}
			
			
		}
		else
		{
//			static CqRandom random = new CqRandom( 53 );プライベートにして上へ出した。
			
			// ポイントを「canonical」マルチジッターパターンに初期化してください。
			for ( i = 0; i < n; i++ )
			{
				for ( j = 0; j < m; j++ )
				{
					int which = i * m + j;
					vecSamples.get(which).x( i );
					vecSamples.get(which).y( j );
				}
			}
			
			//　それぞれの列のセルの中でy座標をシャッフルしてください。
			for ( i = 0; i < n; i++ )
			{
				for ( j = 0; j < m; j++ )
				{
					float t;
					int k;
					
					k = (int)random.RandomInt( n - 1 - i ) + i;
					int i1 = i * m + j;
					int i2 = k * m + j;
					assert( i1 < vecSamples.size() && i2 < vecSamples.size() );
					t = vecSamples.get( i1 ).y;
					vecSamples.get( i1 ).y( vecSamples.get( i2 ).y );
					vecSamples.get( i2 ).y( t );
				}
			}
			
			//　それぞれのカラムのセルの中でx座標をシャッフルしてください。
			for ( i = 0; i < m; i++ )
			{
				for ( j = 0; j < n; j++ )
				{
					float t;
					int k;
					
					k = (int)random.RandomInt( n - 1 - j ) + j;
					int i1 = j * m + i;
					int i2 = k * m + i;
					assert( i1 < vecSamples.size() && i2 < vecSamples.size() );
					t = vecSamples.get( i1 ).x;
					vecSamples.get( i1 ).x( vecSamples.get( i2 ).x );
					vecSamples.get( i2 ).x( t );
					
				}
			}
			
			
			float subpixelheight = 1.0f / m_YSamples;
			float subpixelwidth = 1.0f / m_XSamples;
			
			int which = 0;
			for ( i = 0; i < n; i++ )
			{
				float sy = i * subpixelheight;
				for ( j = 0; j < m; j++ )
				{
					float sx = j * subpixelwidth;
					float xindex = vecSamples.get( which ).x;
					float yindex = vecSamples.get( which ).y;
					vecSamples.get( which ).x( xindex * subcell_width + ( subcell_width * 0.5f ) + sx );
					vecSamples.get( which ).y( yindex * subcell_width + ( subcell_width * 0.5f ) + sy );
					m_Samples.get( which ).m_SubCellIndex = (int)( ( yindex * m_YSamples ) + xindex );
					which++;
				}
			}
			
			// モーションブラーのためのサンプル時間、LODのための詳細レベル、およびDoFに記入してください。
			float time = 0;
			float dtime = 1.0f / numSamples;
			
			// 私たちは画素の中の各サンプルに同じ無作為のオフセットを使用します。
			// これはまだエイリアシングを避けている間、最も良い可能な適用範囲を確実にします。
			// (私が数える、). 雑音を最小とならせるべきです。					
			float randomTime = random.RandomFloat( dtime );
			
			float lod = 0;
			float dlod = dtime;
			
			for ( i = 0; i < numSamples; i++ )
			{
				// Scale the value of time to the shutter time.
				float t = time + randomTime;
				t = ( closetime.value - opentime.value ) * t + opentime.value;
				m_Samples.get( i ).m_Time = t;
				time += dtime;
				
				m_Samples.get( i ).m_DetailLevel = lod + random.RandomFloat( dlod );
				lod += dlod;
			}
			
			// we calculate dof offsets in a grid inside the unit cube and then
			// project them into the unit circle. This means that the offset
			// positions match the offset bounding boxes calculated in CqBucket.
			// The sample test in RenderMicroPoly then can be split into a number
			// of smaller bounding boxes where we know in advance which samples
			// fall into each. (This is analagous to what we do for mb now as well).
			// note that there is an implied symmetry to the way we number the bounding
			// boxes here and in the bucket code where the bb's are created (it
			// should be left to right, top to bottom).
			float dx = 2.0f / m_XSamples;
			float dy = 2.0f / m_YSamples;
			
			// 私たちは画素の中の各サンプルに同じ無作為のオフセットを使用します。
			// これはまだエイリアシングを避けている間、最も良い可能な適用範囲を確実にします。
			// (私が数える、). 雑音を最小とならせるべきです。							
			float sx = random.RandomFloat(dx);
			float sy = random.RandomFloat(dy);
			float xOffset = -1.0f + sx;
			float yOffset = -1.0f + sy;
			which = 0;
			STLVector<CqVector2D> tmpDofOffsets = new STLVector<CqVector2D>(CqVector2D.class,numSamples);
			for ( i = 0; i < m_YSamples; ++i )
			{
				for ( j = 0; j < m_XSamples; ++j )
				{
					tmpDofOffsets.get( which ).x(xOffset);
					tmpDofOffsets.get( which ).y(yOffset);
					ProjectToCircle( tmpDofOffsets.get(which) );
					
					m_DofOffsetIndices.set(which , which);
					
					xOffset += dx;
					which++;
				}
				yOffset += dy;
				xOffset = -1.0f + sx;
			}
			
			// 私たちはDofオフセットをシャッフルするが、どこへ行ったかは覚えている。
//			std::random_shuffle(m_DofOffsetIndices.begin(), m_DofOffsetIndices.end());
			Collections.shuffle(m_DofOffsetIndices, rand);
			for( i = 0; i < numSamples; ++i)
			{
				m_Samples.get(m_DofOffsetIndices.get(i).intValue() ).m_DofOffset = tmpDofOffsets.get(i);
			}
		}
		m_Data.m_Data.resize( QGetRenderContext().GetOutputDataTotalSize() );
	}
	
	
//	----------------------------------------------------------------------
	/** Shuffle the sample data to avoid repeating patterns in the sampling.
	 * 標本化の中で、繰り返しのパターンを避けるために、サンプルデータをシャッフルする。
	 */
	public void	ShuffleSamples()
	{
		int numSamples = m_XSamples * m_YSamples;
		
		// DoFのオフセットインデックスリストをシャッフルしてください。
//		int which = 0;
		STLVector<CqVector2D> tmpDofOffsets = new STLVector<CqVector2D>(CqVector2D.class,numSamples);
		
		// 標本抽出の間注文することに関してされた仮定がまだ成立しているのを保証する正準な命令におけるDoFオフセットを格納してください。
		
		int i;
		for( i = 0; i < numSamples; ++i)
		{
//			tmpDofOffsets.set(i,m_Samples.get(m_DofOffsetIndices.get(i)).m_DofOffset);
			tmpDofOffsets.get(i).assignment( m_Samples.get(m_DofOffsetIndices.get(i)).m_DofOffset );
			m_DofOffsetIndices.set(i,i);
		}
		
//		私たちはDofオフセットをシャッフルするが、どこへ行ったかは覚えている。
//		std::random_shuffle(m_DofOffsetIndices.begin(), m_DofOffsetIndices.end());
//		Collections.shuffle(m_DofOffsetIndices);//2005/12/20 修正 Random
		Collections.shuffle(m_DofOffsetIndices,rand);

		for( i = 0; i < numSamples; ++i)
		{
			m_Samples.get(m_DofOffsetIndices.get(i).intValue()).m_DofOffset.assignment( tmpDofOffsets.get(i));
		}
	}
	
	/** 
	 * ピクセルの表示系の座標系が違うので、表示系と保持しているデータでの画像の座標変換
	 * 
	 * @param vecPixel　変更する値
	 * @param vecSamples　元のヴェクター
	 */
	public void	OffsetSamples(CqVector2D vecPixel, STLVector<CqVector2D> vecSamples)
	{
		// ピクセル・オフセットに加えてください。
		final int numSamples = m_XSamples * m_YSamples;
		for ( int i = 0; i < numSamples; i++ )
		{
			m_Samples.get( i ).m_Position.assignment( vecSamples.get( i ) );
			m_Samples.get( i ).m_Position.assignAdd( vecPixel );
		}
	}
//	nttdata 高速化
	public void	OffsetSamples(CqVector2D vecPixel, CqVector2D[] vecSamples)
	{
		// ピクセル・オフセットに加えてください。
		final int numSamples = m_XSamples * m_YSamples;
		for ( int i = 0; i < numSamples; i++ )
		{
			m_Samples.get( i ).m_Position.assignment( vecSamples[ i ] );
			m_Samples.get( i ).m_Position.assignAdd( vecPixel );
		}
	}
	
	/** この画素の大体の適用範囲を手に入れてください。
	 * @return Float カバーされた画素の何分の一。
	 */
	public float	Coverage()
	{
		return ( m_Data.Coverage() );
	}
	public void	SetCoverage( float c )
	{
		m_Data.SetCoverage( c );
	}
	/** この画素の平均した色を得てください。
	 * @return この画素で平均した色を表す色。
	 * @attention すでにFilterBucket()を読み込んでいる場合にのみ使ってください。
	 */
	public CqColor	Color()
	{
		return ( m_Data.Cs() );
	}
	public void	SetColor(final CqColor col)
	{
		m_Data.SetCs( col );
	}
	/** この画素の平均した透明度を得てください
	 * @return この画素で平均した透明度を表す色。
	 * @attention すでにFilterBucket()を読み込んでいる場合にのみ使ってください。
	 */
	public CqColor	Opacity()
	{
		return ( m_Data.Os() );
	}
	public void	SetOpacity(final CqColor col)
	{
		m_Data.SetOs( col );
	}
	/** この画素の平均した深さを得てください。
	 * @return この画素で平均した深さを表すFloat。
	 * @attention すでにFilterBucket()を読み込んでいる場合にのみ使ってください。
	 */
	public float	Depth()
	{
		return ( m_Data.Depth() );
	}
	public void	SetDepth( float d )
	{
		m_Data.SetDepth( d );
	}
	/** この画素の前掛け算をさせられたアルファを得てください。
	 * @return この画素の前掛け算をさせられた文字値を表しますfloat。
	 * @attention すでにFilterBucket()を読み込んでいる場合にのみ使ってください。
	 */
	public float	Alpha()
	{
		return ( m_Data.Alpha() );
	}
	public void	SetAlpha( float a )
	{
		m_Data.SetAlpha( a );
	}
	/** 指針を標本データに得てください。
	 * @return 標本データへの一定の指針。
	 */
	public Valarray Data()
	{
		return ( m_Data.m_Data );
	}
	
	public SqImageSample	GetPixelSample()
	{
		return ( m_Data );
	}
	/** データの数を取得する。
	 * @return この画素におけるサンプルの数。
	 */
	public int	DataSize()
	{
		return ( m_Data.m_Data.size() );
	}
	/** この画素の最大の深さを得てください。
	 * @return この画素で最大の深さを表すFloat。
	 */
	public float	MaxDepth()
	{
		return ( m_MaxDepth );
	}
	public void	SetMaxDepth( float d )
	{
		m_MaxDepth = d;
	}
	/** この画素の最小の深さを得てください。
	 * @return この画素で最小の深さを表すFloat。
	 */
	public float	MinDepth()
	{
		return ( m_MinDepth );
	}
	public void	SetMinDepth( float d )
	{
		m_MinDepth = d;
	}
	/**このピクセルをカバーするオキュリュージョンボックスのidを取得してください
	 * @return オキュリュージョンボックスのid
	 */
	public int	OcclusionBoxId()
	{
		return ( m_OcclusionBoxId );
	}
	public void	SetOcclusionBoxId( int id )
	{
		m_OcclusionBoxId = id;
	}
	/** このピクセルを、ピクセルの最小値と最大値のｚ値の再計算として記録する。
	 */
	public void	MarkForZUpdate()
	{
		m_NeedsZUpdate = true;
	}
	public boolean	NeedsZUpdating()
	{
		return m_NeedsZUpdate;
	}
	/** すべてのサンプルを通してスキャンして、最小と最大z値を見つけてください。
	 */
//	----------------------------------------------------------------------
	/** ReCalculateはこの画素の最小と最大z値です。
	 */
	public void	UpdateZValues()
	{
		float currentMax = 0.0f;
		float currentMin = FLT_MAX;
		int sampleIndex = 0;
		int sx, sy;
		for ( sy = 0; sy < m_YSamples; sy++ )
		{
			for ( sx = 0; sx < m_XSamples; sx++ )
			{
				SqImageSample opaqueSample = m_OpaqueValues.get( sampleIndex );
				if( (opaqueSample.m_flags & SqImageSample.Flag_Valid ) != 0)
				{
					if ( opaqueSample.Depth() > currentMax )
					{
						currentMax = opaqueSample.Depth();
					}
					if ( opaqueSample.Depth() < currentMin )
					{
						currentMin = opaqueSample.Depth();
					}
				}
				else
				{
					currentMax = FLT_MAX;
				}
				
				sampleIndex++;
			}
		}
		
		m_MaxDepth = currentMax;
		m_MinDepth = currentMin;
	}
	
//	----------------------------------------------------------------------
	/** 次に使うためにそれを準備するイメージ要素からの関連データをクリアしてください。
	 */
	public void	Clear()
	{
		int i;
		for ( i = ( m_XSamples * m_YSamples ) - 1; i >= 0; i-- )
		{
			if(!m_aValues.get(i).isEmpty())
				m_aValues.get( i ).clear( );
			
			m_OpaqueValues.get( i ).m_flags = 0;
		}
		
		m_OpaqueSampleCount = 0;
		m_AnySampleUsesSampleList = false;
		m_MaxDepth = FLT_MAX;
		m_MinDepth =  FLT_MAX;
		m_OcclusionBoxId = -1;
		m_NeedsZUpdate = false;
	}
	
	/** 指定されたサンプルのために参照をすべて得てください。
	 * @return SqImageSampleデータのベクトルへの参照
	 */
	public STLVector<SqImageSample>	Values( int index )
	{
		assert( index < m_XSamples*m_YSamples );
		return ( m_aValues.get( index ) );
	}
	
	public SqImageSample OpaqueValues( int index )
	{
		assert( index < m_XSamples*m_YSamples );
		return ( m_OpaqueValues.get( index ) );
	}
	
	public void IncOpaqueSampleCount()
	{
		m_OpaqueSampleCount++;
	}
	
	public void SetUsesSampleList()
	{
		m_AnySampleUsesSampleList = true;
	}
	
	
//	----------------------------------------------------------------------
	/** 指定されたサンプルポイントでその時現れる色を混合することによって、色を得てください。
	 */
	public void	Combine()
	{
		int depthfilter = 0;
		HimawariLogger logger = HimawariLogger.getLogger();
		final String[] pstrDepthFilter = QGetRenderContext().optCurrent().GetStringOption( "Hider", "depthfilter" );//シャドウマップの時に出力するピクセルの奥行き値を最小、最大、平均から選択できる。    
		final CqColor[] pzThreshold = QGetRenderContext().optCurrent().GetColorOption( "limits", "zthreshold" );//シャドウマップの時透明なものを影にするかの設定に使う
		
		CqColor zThreshold = new CqColor(1.0f, 1.0f, 1.0f);	// Default threshold of 1,1,1 means that any objects that are partially transparent won't appear in shadow maps.
		if(null != pzThreshold)
			zThreshold = pzThreshold[0];
		
		if ( null != pstrDepthFilter )
		{
			if( (pstrDepthFilter[ 0 ].compareTo( "min" ) == 0) )
				depthfilter = 0;
			else if ( pstrDepthFilter[ 0 ].compareTo( "midpoint" ) == 0)
				depthfilter = 1;
			else if ( pstrDepthFilter[ 0 ].compareTo( "max" ) == 0)
				depthfilter = 2;
			else if ( pstrDepthFilter[ 0 ].compareTo( "average" ) == 0 )
				depthfilter = 3;
			else
				logger.warning( "Invalid depthfilter \"" + pstrDepthFilter[ 0 ] + "\", depthfilter set to \"min\"" );
		}
		
		int samplecount = 0;
//		int numsamples = XSamples() * YSamples();
		if(m_AnySampleUsesSampleList)//透明な物体だとこのif文に入るらしい。
		{
			int sampleIndex = 0;
//			Vector<Vector<SqImageSample> >.iterator end = m_aValues.end();
//			for ( Vector<Vctor<SqImageSample> >.iterator samples = m_aValues.begin(); samples != end; ++samples )
			Iterator<STLVector<SqImageSample>> Firstsamples = m_aValues.iterator();
			
			while(Firstsamples.hasNext())
			{
				STLVector<SqImageSample> samples =  (STLVector<SqImageSample>) Firstsamples.next();
				
				SqImageSample opaqueValue = m_OpaqueValues.get( sampleIndex );
				sampleIndex++;
				
				
				if(!samples.isEmpty())
				{
					if( (opaqueValue.m_flags & SqImageSample.Flag_Valid) != 0)
					{
						//	正しい位置にopaqueValueをサンプルに挿入してください。
//						Vector<SqImageSample>.iterator isi = samples.begin();
//						Vector<SqImageSample>.iterator isend = samples.end();
						Iterator isi = samples.iterator();
						int index = 0;
						while( isi.hasNext() )
						{
							SqImageSample tmp = (SqImageSample) isi.next();
							
							if( tmp.Depth() >= opaqueValue.Depth())
								break;
							
//							++isi;
							++index;
						}
//						samples.insert(isi, opaqueValue);
						samples.insertElementAt( opaqueValue ,index );
					}
					
					// サンプルのどれかがCSG木にあるか調べる。
					boolean bProcessed;
					boolean CqCSGRequired = CqCSGTreeNode.IsRequired();
					if (CqCSGRequired)
						do
						{
							bProcessed = false;
							//Warning ProcessTree add or remove elements in samples list
							//We could not optimized the for loop here at all.
							for( SqImageSample isample : samples )
							{
								if( isample.m_pCSGNode != null )
								{
									isample.m_pCSGNode.ProcessTree( samples );
									bProcessed = true;
									break;
								}
							}
						} while ( bProcessed );
					
					CqColor samplecolor = new CqColor( gColBlack );
					CqColor sampleopacity = new CqColor( gColBlack );
					boolean samplehit = false;
					float[] opaqueDepths = { FLT_MAX, FLT_MAX };
					float maxOpaqueDepth = FLT_MAX;

					//reverse iterator
					int Size = samples.size();
					
					for(int index = Size-1;index >= 0 ; index--)
					{
						SqImageSample sample = samples.get(index);
						
						if ( ( sample.m_flags & SqImageSample.Flag_Matte ) != 0 )
						{
							if ( ( sample.m_flags & SqImageSample.Flag_Occludes ) != 0 )
							{
								// Optimise common case
								samplecolor.assignment( gColBlack );
								sampleopacity.assignment( gColBlack );
							}
							else
							{
								samplecolor.SetColorRGB(
										LERP( sample.Os().fRed(), samplecolor.fRed(), 0 ),
										LERP( sample.Os().fGreen(), samplecolor.fGreen(), 0 ),
										LERP( sample.Os().fBlue(), samplecolor.fBlue(), 0 )
								);
								sampleopacity.SetColorRGB(
										LERP( sample.Os().fRed(), sampleopacity.fRed(), 0 ),
										LERP( sample.Os().fGreen(), sampleopacity.fGreen(), 0 ),
										LERP( sample.Os().fBlue(), sampleopacity.fBlue(), 0 )
								);
							}
						}
						else
						{
//							samplecolor = ( samplecolor * ( gColWhite - sample.Os() ) ) + sample.Cs();
//							sampleopacity = ( ( gColWhite - sampleopacity ) * sample.Os() ) + sampleopacity;
							samplecolor.assignment(  samplecolor.mul( gColWhite.sub( sample.Os() ) ).add( sample.Cs()) );
							sampleopacity.assignment( gColWhite.sub( sampleopacity ).mul( sample.Os() ).add( sampleopacity ) );
						}
						
						// Now determine if the sample opacity meets the limit for depth mapping.
						// If so, store the depth in the appropriate nearest opaque sample slot.
						// The test is, if any channel of the opacity color is greater or equal to the threshold.
						if(sample.Os().fRed() >= zThreshold.fRed() || sample.Os().fGreen() >= zThreshold.fGreen() || sample.Os().fBlue() >= zThreshold.fBlue())
						{
							// Make sure we store the nearest and second nearest depth values.
							opaqueDepths[1] = opaqueDepths[0];
							opaqueDepths[0] = sample.Depth();
							// Store the max opaque depth too, if not already stored.
							if(!(maxOpaqueDepth < FLT_MAX))
								maxOpaqueDepth = sample.Depth();
						}
						samplehit = true;
					}
					
					if ( samplehit )
					{
						samplecount++;
					}
					
					// Write the collapsed color values back into the opaque entry.
					//　不透明なエントリーにある色の値の返事を書いてください。
					if ( !samples.isEmpty() )
					{
						// 色の透明度を設定してください。
						opaqueValue.SetCs( samplecolor );
						opaqueValue.SetOs( sampleopacity );
						opaqueValue.m_flags |= SqImageSample.Flag_Valid;
						
						if ( depthfilter != 0)
						{
							if ( depthfilter == 1 )
							{
								//std::cerr << debug << "OpaqueDepths: " << opaqueDepths[0] << " - " << opaqueDepths[1] << std::endl;
								// Use midpoint for depth
								if ( samples.size() > 1 )
									opaqueValue.SetDepth( ( opaqueDepths[0] + opaqueDepths[1] ) * 0.5f );
								else
									opaqueValue.SetDepth( FLT_MAX );
							}
							else if ( depthfilter == 2)
							{
								opaqueValue.SetDepth( maxOpaqueDepth );
							}
							else if ( depthfilter == 3 )
							{
//								Vector<SqImageSample>.iterator sample;
								Iterator sample = samples.iterator();
								float totDepth = 0.0f;
								int totCount = 0;
//								for ( sample = samples.begin(); sample != samples.end(); sample++ )
								while(sample.hasNext())
								{
									SqImageSample tmp = (SqImageSample) sample.next();
									if(tmp.Os().fRed() >= zThreshold.fRed() || tmp.Os().fGreen() >= zThreshold.fGreen() || tmp.Os().fBlue() >= zThreshold.fBlue())
									{
										totDepth += tmp.Depth();
										totCount++;
									}
								}
								totDepth /= totCount;
								
								opaqueValue.SetDepth( totDepth );
							}
							// 初期値は "min"
						}
						else
							opaqueValue.SetDepth( opaqueDepths[0] );
					}
				}
				else
				{
					if( (opaqueValue.m_flags & SqImageSample.Flag_Valid ) != 0)
					{
						samplecount++;
					}
				}
			}
		}
		else
		{
			samplecount = m_OpaqueSampleCount;
		}
	}
	
	/** 指定されたサンプルインデックスのための標本データを得てください。
	 * @param 必要なサンプルポイントのインデックス。
	 * @return 標本データの参照。
	 */
	public final SqSampleData SampleData( int index )
	{
//		assert( index < m_XSamples*m_YSamples );
		if( index < m_XSamples*m_YSamples )
			return ( m_Samples.get( index ) );
		else
			return new SqSampleData();
	}
	
	/** iにあるdofオフセットを含むサンプルのインデックスを得てください。
	 * @param わからないバウンディングボックスの索引をつけます。
	 * @return BBと呼ばれるdofオフセットに含まれるsample のインデックス。
	 */
	public	int GetDofOffsetIndex(int i)
	{
		return m_DofOffsetIndices.get(i).intValue();
	}
	
	/** 
	 * ユニット正方形でcoordをユニット円の中の1つに変換してください。
	 * dofサンプル位置を発生させる際に、使用されています。
	 */
	public static void ProjectToCircle(CqVector2D pos)
	{
		float r = pos.Magnitude();
		if( r == 0.0 )
			return;
		
		float adj = (float)Math.max((float)Math.abs(pos.x), (float)Math.abs(pos.y)) / r;
		pos.x(pos.x * adj);
		pos.y(pos.y * adj);
	}
	
	//---Himawari add start ----
	/**
	 * 量子化前の色情報を現在もっている
	 * SqImageSampleに設定する
	 * @param col
	 */
	public void setfColor(CqColor col){
		m_Data.setFColor(col);
	}
	
	/**
	 * 量子化前の色情報を取得する
	 * @return 量子化前の色情報を持つCqColor
	 */
	public CqColor getFColor(){
		return m_Data.getFColor();
	}
	//---Himawari add end   ----
	
	private int	m_XSamples;							///< 水平方向のサンプル数を格納
	private int	m_YSamples;							///< 垂直方向のサンプル数を格納
	private STLVector<STLVector<SqImageSample> > m_aValues = new STLVector<STLVector<SqImageSample>>(2,SqImageSample.class);	///< Vector の vectorです。：サンプルポイントのデータ
	private STLVector<SqImageSample> m_OpaqueValues = new STLVector<SqImageSample>(SqImageSample.class);	///< 不透明なサンプルのためのサンプル点データのVector　(one per sample position, no need for list).
	private STLVector<SqSampleData> m_Samples = new STLVector<SqSampleData>(SqSampleData.class);	///< サンプルの Vector。全てのサンプルの位置、時間、被写界深度オフセットの情報などを持つ。
	private STLVector<Integer> m_DofOffsetIndices = new STLVector<Integer>(Integer.class);	///< A mapping from dof bounding-box index to the sample that contains a dof offset in that bb.
	private SqImageSample	m_Data = new SqImageSample();
	
	private int	m_OpaqueSampleCount;				///< 有効な不透明なサンプルの数。
	private boolean	m_AnySampleUsesSampleList;		///< もし、全てのサンプルがサンプルリストから使われたら、ただ一つの対照的な不透明な値としてTrueを返す。
	
	private float m_MaxDepth;						///< オクルージョンカリングで使われる。すべてのサンプルピクセルの深度の上限。
	private float m_MinDepth;						///< オクルージョンカリングで使われる。すべてのサンプルピクセルの深度の下限。
	private int m_OcclusionBoxId;					///< この画素をカバーするCqOcclusionBox
	private boolean m_NeedsZUpdate;					///< 最小か最大の深度の値を更新する。
	
}
