//------------------------------------------------------------
// $Id: calcRayTrFRG.cc,v 1.6.2.1 2000/06/14 15:00:10 yamauchi Exp $
//------------------------------------------------------------
//	calcRayTrFRG.cc
//	calculation of First Ray Generation unit for ray tracing 
//	1996/8/2 
//	(C) 1995-1998 Copyright YAMAUCHI Hitoshi 山内 斉
//
//	スクリーンと視点は得ている
//
//	初期レイ発生
//	
//	PEClass のメンバにしたい所であるが、テストを可能にするために分
//	離する 
//------------------------------------------------------------
#include <assert.h>
#include <stdlib.h>
#include <time.h>

#include "Option.h"
#include "rayTrFRGUnit.h"
#include "screenPointer.h"
#include "mpi2_funcs.h"

// stand alone 
#ifdef FOR_STANDALONE
#  include "StandAloneModeObjects.h"
#else
#  include "ProcObj.h"
#endif			// #ifdef FOR_STANDALONE

//------------------------------
// random
//------------------------------
static void initRandom(void)
{
    srand48(time(NULL));
}

// return random value [0.0. 1.0)
static inline double getDRandom(void)
{
    return(drand48());
}

//------------------------------------------------------------
// rayTrFRGUnitClass 
//------------------------------------------------------------
// screen pointer (どのような順でどの pixel を指すかを決める strategy)
// の初期化とそれに伴う member の初期化．
// たとえば，mVpSpcPos などは視点が定義空間の内部か外部かを示すがこれ
// は初期光分散を行うかどうかに深くかかわっているのでここで初期化する．
void rayTrFRGUnitClass::
initForScreenPointer(int scrSizeX, int scrSizeY, int myRank, int totalPENum)
{
    // 視点の位置が定義空間の内部か外部かを判断する
    if(isPosInBox(this->mViewPoint, this->mDefSpcMin, this->mDefSpcMax) == YES)
    {
	// 視点は定義空間内部に存在する: 視点の存在する副空間位置を知る
	this->mIsVpInDefSpc	= YES;
	this->mVpSpcPos 	= this->getSpcposOfaPoint(this->mViewPoint);
    }else
    {
	assert(this->mIsVpInDefSpc == NO);
    }

    // どの初期光発生 method を使うかにより screen pointer を初期化
    switch(this->mScanMethodOnScreen)
    {
    case AllScan_frgm:		// 全体のスキャン (初期光分散はない)
	this->initForAllScanMethod(scrSizeX, scrSizeY);
	break;

    case ScanlineScan_frgm:	// スキャンラインごとに分散する
	this->initForScanlineScanMethod(scrSizeX, scrSizeY, 
					myRank, totalPENum);
	break;
    case DistributedScan_frgm:	// distributed 型の分散 
	this->initForDistributedScanMethod(scrSizeX, scrSizeY,
					   myRank, totalPENum);
	break;
    default:
	cout << "Internal Error! : illegal ray generation method in "
	    "ray-tracing." << endl;
	commMpi2_exit(1);
    }
}


//------------------------------
// init for AllScan method
//------------------------------
void rayTrFRGUnitClass::
initForAllScanMethod(int scrSizeX, int scrSizeY)
{
    assert(this->mScanMethodOnScreen == AllScan_frgm);
    this->mpScreenPtr = new scrPtrAllScan(scrSizeX, scrSizeY);

    // AllScan の場合には視点位置により発生する ray を担当する PE が変
    // 化する． 
    if(this->mIsVpInDefSpc == YES)
    {
	assert(isPosInBox(this->mViewPoint, this->mDefSpcMin,
			  this->mDefSpcMax) == YES);
	// この PE は視点の存在する副空間を担当しているか? 
	if(GpPE->isDealSpace(this->mVpSpcPos) == NO)
	{
	    // 視点が定義空間内にあるが、視点の存在する部分空間をこの 
	    // PE が担当していないので ray を発生させる必要がない 
	    this->mCanGenerateNextRay = NO; // ray 発生を終了とする
	    if(Option::getInstance()->getDebugMode() == YES)
	    {
		cout << genHd(DEBUGHEAD, this->mPEid) << "generate 0 rays\n" 
		"Because view point is in a define space and this PE "
		"does not deal subspace within a view point" << endl;
	    }	    
	}else
	{
	    if(Option::getInstance()->getDebugMode() == YES)
	    {
		cout << genHd(DEBUGHEAD, this->mPEid) << "AllScan : "
		"view point is in defined space and this PE generate rays."
		<< endl;
	    }
	}
    }else
    {
	assert(isPosInBox(this->mViewPoint, this->mDefSpcMin,
			  this->mDefSpcMax) == NO);
    }
}


void rayTrFRGUnitClass::
initForScanlineScanMethod(int scrSizeX, int scrSizeY, 
			  int myRank, int totalPEnum)
{
    // myRank は PE 0 から PE n-1 となっているはず
    assert(myRank < totalPEnum);
    assert(myRank >= 0);
    this->mpScreenPtr = new scrPtrScanline(scrSizeX, scrSizeY, 
					   totalPEnum, myRank); 
    cout << "DEBUG: GenScreen ScanLine Pointer : myRank is " << 
	myRank << ", skip = " << totalPEnum << endl;
    
}

void rayTrFRGUnitClass::
initForDistributedScanMethod(int scrSizeX, int scrSizeY,
			     int myRank, int totalPEnum)
{
    // 現在 block size の変化がないが，本当は変化がある : 未完成
    this->mpScreenPtr = new scrPtrDistribute(scrSizeX, scrSizeY,
					     totalPEnum, myRank); 
}

//------------------------------
// スクリーン上の pixel 単位の移動。
// pixel 内での指定数の ray を発生したら次の pixel へ移動する
// まだ ray が発生できるのならばそのまま
//------------------------------
inline void rayTrFRGUnitClass::
moveOnScreen(void)
{
    this->mGenRayParPixel++;
    // 1 pixel における発生数を越えたか? loop の基準はこれ
    if(this->mGenRayParPixel >= this->mMaxRaysInAPixel)
    {
	this->mGenRayParPixel = 0;
	// this->mpScreenPtr->next によって移動する．
	// これ以上移動できない場合にはそれを記す
	this->mCanGenerateNextRay = this->mpScreenPtr->next();
	this->mpScreenPtr->getpos(&(this->mScrX), &(this->mScrY));
    }else
    {
	// まだこの pixel で ray が発生可能
    }
}

//------------------------------
// ある点, point の存在する分割空間の指標を点の位置から得る
//
// cp = cell periad, p = point, min, max = partition volume min, max
// k が求める sub space pos とすると
// min + k \frac{max - min}{cp} <= p < min + (k + 1)\frac{max - min}{cp}
//   より
// \frac{cp (p - min)}{max - min} - 1 < k <= \frac{cp (p - min)}{max - min}
//  となる
// \frac{cp}{max - min} = partVolOneSize
//  (partVolOneSize * (p - min)) - 1 
//------------------------------
IntVec3 rayTrFRGUnitClass::
getSpcposOfaPoint(const Vector3& point) const
{
    // partition volume に対する相対位置
    Vector3 relativePos = point - this->mPartVolMinPos;
    int i, spos[3];		// space position
    for(i = 0; i < 3; i++)
    {
	// 位置を空間の大きさで割り、小さい方向へ丸める
	spos[i] = (int)(floor(relativePos.get(i) / this->mPartVolOneSize));
	assert(spos[i] >= 0);

	if(spos[i] == this->mSubDivNum)
	{
	    if((double)(int(relativePos.get(i) / this->mPartVolOneSize)) ==
	       (relativePos.get(i) / this->mPartVolOneSize))
	    {
		// 空間の大きい方の端に正に丁度 point がある 
		spos[i]--;
	    }else
	    {
	 	cout << "Internal Error! : Is this pos in partition volume?"
		     << endl;
	    }
	}
    }
    return(IntVec3(spos[0], spos[1], spos[2]));
}


//------------------------------
// view vector generator
//------------------------------
inline Vector3 rayTrFRGUnitClass::
genViewVec(void) const
{
    //------------------------------
    // AllScan の場合には格子状のエリアシング模様が発生するが，これは
    // 並列動作時のみであり，1PE 時には正しく動作する．
    // この模様を AllScan mode の並列動作時に取り除くには隣接 pixel を担
    // 当する PE 間で共有するある pixel 上には同一のサンプリングを行わ
    // なくてはならない．共有する場合には 1 つの PE がサンプリングして，
    // 担当する PE へと ray を送信するという手などがあるが， AllScan 
    // mode だけ固有の通信のコードを入れたくないので AllScan の並列動
    // 作時の不都合はそのまま残しておく． 
    //------------------------------
    Vector3 viewVec = 
    	this->mScreenLeftUpFromVp + 
 	((((double)(this->mScrX)) + getDRandom()) * this->mDeltaXscr) +
 	((((double)(this->mScrY)) + getDRandom()) * this->mDeltaYscr);
    viewVec.VNormalize();
    return(viewVec);
}

//------------------------------
// 視点が定義空間内にある場合の ray 発生 
// 1 本 ray を発生させて index を進めておく。
// 全て終了したらそのフラグを立てる。
//      内部で保持している発生レイの位置は移動しない
//------------------------------
Ray *rayTrFRGUnitClass::
newOneRayVpInDefineSpc(void) const
{
    assert(this->mCanGenerateNextRay == YES);
    assert(this->mIsVpInDefSpc == YES);

    // 直接 genViewVec() を書いても良いと思うがちょっと不安がある．
    Vector3 distPixelVec = this->genViewVec();

    assert(fabs((distPixelVec.getNorm()) - 1.0) < D_ERROR_RES);    

    // 視点が定義空間内部にあるので必ず ray は定義空間内部にある．
    Ray *pRay = Ray::newForRayTrace(this->mScrX, this->mScrY,
				    this->mViewPoint, 
				    distPixelVec, // 直接 genViewVec()?
				    this->mVpSpcPos,
				    this->mDistRaysFactor); //, PEid;
    return(pRay);
}

//------------------------------
// 視点が定義空間の外にある場合の ray 発生
//------------------------------
Ray *rayTrFRGUnitClass::
newOneRayVpOutOfDefSpc(void) const
{
    assert(this->mCanGenerateNextRay == YES);
    assert(this->mIsVpInDefSpc == NO);

    Vector3 viewVec = this->genViewVec();

    assert(fabs((viewVec.getNorm()) - 1.0) < D_ERROR_RES);    

    // 定義空間との交差判定 
    // 当たった場合にはどの部分空間にあたったか計算
    static Vector3 hitpos;
    DIR_3D hitSide = isHitBoundingBox(this->mDefSpcMin, this->mDefSpcMax,
				      this->mViewPoint, viewVec,
				      &hitpos);
    if(hitSide != DIR_ILLEGAL)
    {
	// ray が定義空間に hit した場合
	static IntVec3 hitSubSpcPos; 
	hitSubSpcPos = this->getSpcposOfaPoint(hitpos);
	
	switch(this->getScanMethodOnScreen())
	{
	case AllScan_frgm:
	    // AllScan 初期光の分散を行わない
	    // ray がこの PE の担当空間にいない場合には却下する
	    if(GpPE->isDealSpace(hitSubSpcPos) == YES) // 親参照:ちょっとdirty
	    {
		Ray *pRay = Ray::newForRayTrace(this->mScrX, this->mScrY, 
						this->mViewPoint, viewVec,
						hitSubSpcPos, 
						this->mDistRaysFactor); 
		return(pRay);
	    }else 
	    { 
		return(NULL);	// 定義空間にはhitしたが担当空間でないから却下
	    }
	    break;
	    
	case ScanlineScan_frgm:
	case DistributedScan_frgm:
	{
	    // 初期光を分散させる
	    // スクリーンが分割され，各スクリーンがノードに分配される
	    // ので，必ず各ノードは ray を発生する
	    // この ray はこの空間にいるとは限らない．
	    Ray *pRay = Ray::newForRayTrace(this->mScrX, this->mScrY, 
					    this->mViewPoint, viewVec,
					    hitSubSpcPos, 
					    this->mDistRaysFactor); //,PEid
	    return(pRay);		
	    break;
	}
	default:
	    cout << "Internal Error! : No such screen scan method." << endl;
	    commMpi2_exit(1);
	    return(NULL);
	}
    }else
    {
	// 定義空間に hit しないので発生する必要はない．
	return(NULL);
    }
    cout << "never reach. rayTrFRGUnitClass::newOneRayVpOutOfDefSpc()" << endl;
    commMpi2_exit(1);
    return(NULL);
}

// reference 格子状のエリアシングバグ
// [0.0, 1.0) の乱数を deltaX, deltaY に掛け、あるピク
// セルの中に random にサンプリング点をばらまく
//	distPixelVec = pixelVecFromVpBase + 
//	    (getDRandom() * deltaX) + (getDRandom() * deltaY);
// しかし、その場合には ray ごとに担当するかどうかを判
// 定しているため、残念ながら空間の境界上ではある1つの
// ピクセルを2つの PE が同時に担当してしまうと考えたり、
// どちらの PE も担当しないということが発生して格子状
// のエリアシングが見えてしまう。そのため、レイを規則
// 的に発生させることにする 

//------------------------------------------------------------
// public functions
//------------------------------------------------------------
// constructor
//------------------------------
rayTrFRGUnitClass::
rayTrFRGUnitClass(void)
{
    Vector3 illegalV(-1.0, -2.0, -3.0);
    IntVec3 illegalIntV(-1, -2, -3);

    this->mScanMethodOnScreen   = ELSE_frgm;
    
    this->mPEid 		= illegalIntV;
    this->mViewPoint		= illegalV;
    this->mpScreenPtr		= NULL;

    this->mScreenLeftUpFromVp	= illegalV;
    this->mDeltaXscr		= illegalV;
    this->mDeltaYscr		= illegalV;

    this->mMaxRaysInAPixel 	= -1;
    this->mGenRayParPixel	= -1;

    this->mCanGenerateNextRay	= NO; // 初期化までは next rays はなし


    this->mDefSpcMin		= illegalV;		
    this->mDefSpcMax		= illegalV;
    this->mPartVolMinPos	= illegalV;	
    
    this->mSubDivNum		= 0.0;	
    this->mPartVolOneSize	= -1.0;

    this->mVpSpcPos   		= illegalIntV;		
    this->mIsVpInDefSpc		= NO;
    this->mNumOfTotalGenRays	= -1;
    this->mDistRaysFactor	= 0.0;

    this->mScrX = -10;
    this->mScrY = -11;
}

//------------------------------
// initializer
//  @param rayGenerationMethod : 分散 ray 手法(Allscan や ScanlineScan)
//  @param viewDat	: 視点の位置，視線方向などの視点情報
//  @param spcDat	: 空間情報
//  @param PEid	: この初期光発生ユニットの属する PE の ID
//  @param totalPEnum : システムの全 PE 数 (初期光分散時に必要)
//  @param myRank 	: 自分の rank (0 からはじまる)
//------------------------------
void rayTrFRGUnitClass::
init(int 			rayGenerationMethod,
     const ViewDataClass& 	viewDat, 
     const SpaceParam& 		spcDat, 
     const IntVec3& 		PEid,
     int   			totalPEnum,
     int 			myRank // myRank は PE の 0 からはじまる
     )
{
    // 視点に関するパラメータを得る
    Vector3 vp  = viewDat.getViewPoint(); 	// 視点ベクトル
    Vector3 vv  = viewDat.getViewVector();	// 視線ベクトル
    Vector3 vup = viewDat.getViewUpVector();	// スクリーン上方ベクトル
    double  vFovRad, vHovRad;
    int     screenSizeX, screenSizeY;
    viewDat.getFOV(&vFovRad, &vHovRad);
    viewDat.getScreenSize(&screenSizeX, &screenSizeY);

    // スクリーン垂直方向単位ベクトル (既に単位ベクトルのはずだが念のため)
    vup.VNormalize();			     
    vv.VNormalize();			     
    
    // スクリーン水平方向単位ベクトル(vSh)は $vSh = vv  \times vup$
    Vector3 vScreenHoriz = vv.VOut_prd(vup); 
    if(vScreenHoriz.getNorm() <= 1e-4)
    {
	cout << NORMALHEAD << " Warning! : maybe view up vector is illegal. "
	     << "Generated image will not be right." << endl;
    }

    vScreenHoriz.VNormalize();		     // $vSh = \frac{vSh}{|vSh|}$
    const double  halfX  = tan(vHovRad);
    const double  halfY  = tan(vFovRad);
    // = vp + .... - vp が以下の式に加えられている,すると視点からの相対 vec
    Vector3 screenLeftUpFromVp
	= vv - (halfX * vScreenHoriz) + (halfY * vup);
    const Vector3 deltaX = 
	((2.0 * halfX) / double(screenSizeX)) * vScreenHoriz;
    const Vector3 deltaY = ((-2.0 * halfY) / double(screenSizeY)) * vup;
    
    initRandom();		// distributed ray-tracing のための乱数初期化

    // initialize member
    this->mScanMethodOnScreen 	= rayGenerationMethod;
    this->mPEid	 		= PEid;
    this->mViewPoint		= vp;
    this->mpScreenPtr		= NULL;	// 初期化は initForScreenPointer にて
    this->mScreenLeftUpFromVp	= screenLeftUpFromVp;
    this->mDeltaXscr		= deltaX;
    this->mDeltaYscr		= deltaY;
    this->mMaxRaysInAPixel	= viewDat.getDistributedRayNum();
    assert(this->mMaxRaysInAPixel > 0);
    this->mGenRayParPixel	= 0;

    this->mCanGenerateNextRay	= YES; // まだ ray は発生していない

    // [空間情報] ある点の副空間位置を求めるための準備 
    this->mDefSpcMin 	  = spcDat.getAlignedDefSpaceMin();//定義空間をとりだす
    this->mDefSpcMax 	  = spcDat.getAlignedDefSpaceMax();
    this->mPartVolMinPos  = spcDat.getPartVolumeMin();
    Vector3 partVolMaxPos = spcDat.getPartVolumeMax();

    // partition volume の初期化．
    // partition volume は立方体であるので一辺がわかれば良い 
    this->mSubDivNum	  = (double)(spcDat.getSubDivNum());

    this->mPartVolOneSize = 
      (partVolMaxPos.get(Vector3::X) - (this->mPartVolMinPos).get(Vector3::X))
         / this->mSubDivNum;

    // initialize parameter for distributed ray-trace 
    this->mNumOfTotalGenRays	= 0;	// 総 ray 発生数

    // mDistRaysFactor : 各 ray の輝度は distributed のレイの数分の 1  
    // の重みを持つ。そのため coefficient value にその値を掛けておく
    // 4 本の distributed ならば各 ray の 1 つの pixel への寄与は 1/4 
    this->mDistRaysFactor = 1.0 / double(this->mMaxRaysInAPixel);
    
    this->mScrX = 0;
    this->mScrY = 0;

    // screen pointer の初期化
    // 	this->mIsVpInDefSpc, this->mVpSpcPos の初期化
    this->initForScreenPointer(screenSizeX, screenSizeY,  myRank, totalPEnum);
}


//------------------------------
// ray を一本発生させる
// 	初期光を分散法の適用時には，発生した ray の部分空間番号が，発
// 	生させた PE の担当でない場合がある．
//------------------------------
Ray *rayTrFRGUnitClass::
newNextRay(void)
{
    // この関数を呼ぶ前に一本は発生可能であることを調べてあるはず
    assert(this->canGenerateNextRay() == YES);
    Ray *pRay = NULL;
    if(this->mIsVpInDefSpc == YES)
    {
	// 視点が空間のどこにあるか関係するのは初期光分散なしの All
	// scan の時のみ
	assert(this->getScanMethodOnScreen() == AllScan_frgm);

	// 視点が定義空間内部に存在する
	// この場合にはある pixel 位置の ray を発生できないということ
	// はないので、初期光分散にかかわらず必ず1本は ray を発生する
	pRay = this->newOneRayVpInDefineSpc();
	this->moveOnScreen();	// 次の発生位置へ移動
	assert(pRay != NULL);
	this->mNumOfTotalGenRays++; // 発生 ray 数をカウントする
    }else
    {				
	// 視点は定義空間内部にはない
	// 発生可能状態であっても現在の screen 位置でこの PE が ray 発
	// 生を担当するかどうか不明なので、1 本発生させるまで screen 
	// 上の pixel を移動させてみる。
	// つまりまだスクリーンを走査可能(canGenerateNextRay() == YES) 
	// でかつ現在の pixel がこの PE 担当でない場合には次々とスクリー
	// ンを走査させてみる 
	while(this->canGenerateNextRay() == YES)
	{
	    // この pixel は発生可能か? 
	    pRay = this->newOneRayVpOutOfDefSpc();
	    this->moveOnScreen();	// 次の発生位置へ移動
	    if(pRay != NULL)
	    {   
		this->mNumOfTotalGenRays++; // 発生 ray 数をカウントする
		break;		// ray 発生
	    }
	}
    }

    // 初期光を分散させた場合には ray の spcpos を実際に担当している 
    // PE の所に ray は存在しない可能性がある．
    return(pRay);
}

//#if 0
//------------------------------
// 交差判定 bounding box 
//	Graphics GEMS p.p.736
// 注意 bounding box の中に視点があると、必ず Hit するのでそれで判定を
// 終了し、交差点は視点とする。
// しかしこの方法では交差点がおかしいようである。あくまで交差判定ルー
// チンである。 
//------------------------------
// enum quadrant_e {
//     RIGHT,
//     LEFT,
//     MIDDLE			// xlC のおかげで,を外さなくてはならん.ひどい
// 
// };
// 
// YorN isHitBoundingBox(const Vector3& minBox,    const Vector3& maxBox, 
// 		      const Vector3& rayOrigin, const Vector3& rayDir,
// 		      Vector3 *pHitPoint)
// {
//     const int NUMDIM = 3;	// 3-dimension
//     enum quadrant_e quadrant[NUMDIM]; 
//     int i;
//     double candidatePlane[NUMDIM];
//     double coord[NUMDIM];	// hit point
// 	
//     // find candidate planes. This loop can avoided is rays cast all
//     // from the eye (assume perpsective view)  
//     YorN isInside = YES;
//     for(i = 0; i < NUMDIM; i++)
//     {
// 	if(rayOrigin.get(i) < minBox.get(i)) // 視点が箱の最小値より小さい
// 	{
// 	    quadrant[i] 	= LEFT;
// 	    candidatePlane[i] 	= minBox.get(i);
// 	    isInside		= NO;
// 	}else if(rayOrigin.get(i) > maxBox.get(i)) // 視点が箱の最大値より大
// 	{
// 	    quadrant[i] 	= RIGHT;
// 	    candidatePlane[i] 	= minBox.get(i);
// 	    isInside		= NO;
// 	}else
// 	{
// 	    quadrant[i] 	= MIDDLE;	    
// 	    // isInside 	= YES; 初期値が YES
// 	}
//     }
//     
//     // ray origin inside bounding box
//     if(isInside == YES)
//     {
// 	(*pHitPoint) = rayOrigin;
// 	return(YES);
//     }
//     
//     // calculate T distance to candidate planes
//     double distT[NUMDIM];
//     for(i = 0; i < NUMDIM; i++)
//     {
// 	// 視点の各座標が bounding ext.の中でなく、方向ベクトルの成分がある場合
// 	if((quadrant[i] != MIDDLE) && (rayDir.get(i) != 0.0))
// 	{
// 	    distT[i] = (candidatePlane[i] - rayOrigin.get(i)) / rayDir.get(i);
// 	}else
// 	{
// 	    distT[i] = -1.0;
// 	}
//     }
//     
//     // get largest of the distT's for final choice of intersection
//     int whichPlane = 0;
//     for(i = 1; i < NUMDIM; i++)
//     {
// 	if(distT[whichPlane] < distT[i])
// 	{
// 	    whichPlane = i;
// 	}
//     }
//     
//     // chech final candidate actually inside box
//     if(distT[whichPlane] < 0.0)
//     {
// 	return(NO);
//     }
//     
//     for(i = 0; i < NUMDIM; i++)
//     {
// 	coord[i] = 
// 	    rayOrigin.get(i) + distT[whichPlane] * rayDir.get(i);
// 	if(whichPlane != i)
// 	{
// 	    if(((quadrant[i] == RIGHT) && (coord[i] < minBox.get(i))) || 
// 	       ((quadrant[i] == LEFT)  && (coord[i] > maxBox.get(i))))
// 	    {
// 		return(NO);	// outside box
// 	    }else
// 	    {
// 		coord[i] = candidatePlane[i];
// 	    }
// 	}
//     }
//     pHitPoint->set(coord[0], coord[1], coord[2]);
//     return(YES);
// }
//#endif
//
// #endif				// #ifndef TEST_isHitBoundingBox
// #ifdef TEST_isHitBoundingBox
// main()
// {
//     Vector3 minB( 0,  0,  0);
//     Vector3 maxB(32, 32, 32);
//     Vector3 rayOrg(16,16,-10);    
//     Vector3 rayDir( 0, 0, 1);
//     Vector3 hitpos(-1, -2, -3);
// 
//     DIR_3D dir = isHitBoundingBox(minB, maxB, rayOrg, rayDir, &hitpos);
//     cout << "minB(" << minB   << "), maxB(" << maxB     << ")" << endl;
//     cout << "rayO(" << rayOrg << "), rayDir(" << rayDir << ")" << endl;
//     cout << "hit(" << hitpos << ")" << endl;
// }
// g++ -g -DTEST_isHitBoundingBox calcRayTrFRG.cc Vector3.o IntVec3.o -lm
// #endif				// #ifdef TEST_isHitBoundingBox


#ifdef TEST_FRG
void main()
{
//     rayTrFRGUnitClass 	frgUnit;
//     ViewDataClass   	viewDat; 
//     SpaceParam 	spcDat;
//    IntVec3		PEid(0, 0, 1);

//    frgUnit.init(viewDat, spcDat, PEid);

    while(frgUnit.canGenerateNextRay() == YES)
    {
	Ray *pRay = getTotalGenRays();
    }
}    
// g++ -g -DTEST_FRG calcRayTrFRG.cc Vector3.o IntVec3.o -lm
#endif				// #ifdef TEST_FRG
