//------------------------------------------------------------
// $Id: ray.cc,v 1.1.1.1 1999/11/25 06:26:12 yamauchi Exp $
//------------------------------------------------------------
//	ray
//	1996/7/21 
//	Copyright (C) 1993--1998 YAMAUCHI Hitoshi 山内 斉
//	光線
//------------------------------------------------------------
#include <assert.h>
#include <iostream.h>
#include "ray.h"

#ifdef TRACE_RAY
static int RayID = 0;

void Ray::
setNextID(void)
{ 
    this->mID = RayID;	//----- debug
    RayID++;
}
#endif

//----------------------------------------
// constructor
//----------------------------------------
Ray::
Ray(void)
{
    //     this->mStartPos;
    //     this->mDir;
#ifndef NDEBUG
    this->mColor.set(   -1.0, -2.0, -3.0); 
    this->mRefCoeff.set(-1.0, -4.0, -9.0); 
#endif
    this->mpRadObj	= NULL;
    // this->mHitPoint;
    this->mSpcPos.set(-1, -2, -3);
    this->mScreenX	= -1;
    this->mScreenY	= -1;
    this->mReflectedNum	= 0;
    
    //     this->mSpcDInfo;
    //     this->mVTinfo;	
#ifdef TRACE_RAY
    this->setNextID();
    // this->mOrgPEID = IllegalPEID;
    //    cout << "#R n0 " << this->mID << endl;
#endif
    // #ifdef COUNT_SKIP_SPACE
    //     this->mNumOfSkipSpaces 	= 0;
    //     this->mNumOfTraverseSpaces 	= 0;    
    // #endif
    //tokunaga changed:
    this->mSide         = OUT;
}

Ray::
Ray(const Ray& rhs)
{
    assert((rhs.mScreenX >= -2) && (rhs.mScreenY >= -2));

    this->mStartPos	= rhs.mStartPos;
    this->mDir		= rhs.mDir;
    this->mColor	= rhs.mColor;
    this->mRefCoeff	= rhs.mRefCoeff;
    this->mpRadObj	= rhs.mpRadObj;
    this->mHitPoint	= rhs.mHitPoint;
    this->mSpcPos	= rhs.mSpcPos;
    this->mScreenX	= rhs.mScreenX;
    this->mScreenY	= rhs.mScreenY;
    this->mReflectedNum	= rhs.mReflectedNum;

    this->mSpcDInfo	= rhs.mSpcDInfo;
    this->mVTinfo	= rhs.mVTinfo;    
#ifdef TRACE_RAY
    this->mID		= rhs.mID; // operator= inherit ID
    // this->mOrgPEID	= rhs.mOrgPEID;
    // cout << "#R n1 " << this->mID << endl;
#endif
    // #ifdef COUNT_SKIP_SPACE
    //     this->mNumOfSkipSpaces 	= rhs.mNumOfSkipSpaces;
    //     this->mNumOfTraverseSpaces 	= rhs.mNumOfTraverseSpaces;
    // #endif
    //tokunaga changed:
    this->mSide         = rhs.mSide;
}

//----------
// constructor for ray tracing (放射 object などはない)
//----------
Ray::
Ray(int screenX, int screenY, 
    const Vector3& viewPoint, const Vector3& destVecFromVp, 
    const IntVec3& spcpos,    const double distRaysFactor
    //, const IntVec3& PEID
    )
{
    assert((screenX >= 0) && (screenY >= 0));

    this->mStartPos 	= viewPoint; 
    this->mDir	    	= destVecFromVp;	
    assert(fabs(this->mDir.getNorm()) > 1e-5);    // this->mDir.VNrmlize();
    this->mColor.set(   0.0, 0.0, 0.0);	// 最初色はない

    // ray-tracing では減衰率は 1 に初期化されるが、 distributed
    // ray-tracing のため、各 ray の寄与は 1 より小さくなる。その 
    // distributed のための重みをかけて初期化する
    assert((0.0 < distRaysFactor) && (distRaysFactor <= 1.0));
    this->mRefCoeff.set(distRaysFactor, distRaysFactor, distRaysFactor);
    
    this->mpRadObj 	= NULL;	
    // this->mpHitObj 	= NULL;	
    this->mHitPoint.set(PlusInfty, PlusInfty, PlusInfty);
    this->mSpcPos  	= spcpos; 
    this->mScreenX	= screenX;
    this->mScreenY	= screenY;
    this->mReflectedNum	= 0;	// 作成されたばかり

    this->mSpcDInfo.invalidateInit();
    this->mVTinfo.invalidateInit();

#ifdef TRACE_RAY
    this->setNextID();
    //    this->mOrgPEID 	= PEID;
    // cout << "#R n2 " << this->mID << endl;
#endif
// #ifdef COUNT_SKIP_SPACE
//     this->mNumOfSkipSpaces 	= 0;
//     this->mNumOfTraverseSpaces 	= 0;
// #endif
    //tokunaga changed:
    this->mSide         = OUT;
}

//----------
// constructor for radiosity
//----------
Ray::
Ray(const Vector3& viewPoint, const Vector3& destVecFromVp, 
	 const Vector3& radiosityVal, 
	 objBaseClass * pGenerateObject,
	 const IntVec3& spcpos
	 // ,    const IntVec3& PEID
	 )
{
    this->mStartPos 	= viewPoint; 
    this->mDir	    	= destVecFromVp;	
    assert(fabs(this->mDir.getNorm()) > 1e-5); // this->mDir.VNrmlize();

    this->mColor	= radiosityVal;
    this->mRefCoeff.set(1.0, 1.0, 1.0);	// 反射する可能性あり:減衰率は1に初期化
    this->mpRadObj 	= pGenerateObject;	
    this->mHitPoint.set(PlusInfty, PlusInfty, PlusInfty);
    this->mSpcPos  	= spcpos; 
    this->mScreenX	= -2;	// screen は存在しない
    this->mScreenY	= -2;	// screen は存在しない
    this->mReflectedNum	= 0;	// 作成されたばかり

    this->mSpcDInfo.invalidateInit();
    this->mVTinfo.invalidateInit();
#ifdef TRACE_RAY
    this->setNextID();
    //this->mOrgPEID 	= PEID;
    // cout << "#R n3 " << this->mID << endl;
#endif
// #ifdef COUNT_SKIP_SPACE
//     this->mNumOfSkipSpaces 	= 0;
//     this->mNumOfTraverseSpaces	= 0;
// #endif
    //tokunaga changed:
    this->mSide         = OUT;
}

//------------------------------------------------------------
// 2 次レイの初期化関数 
//------------------------------------------------------------
// Raldiosity 法
//   @param pOldRay 		新しい ray を作成する物体と反射した元の ray 
//   @param dirR    		反射方向
//   @param newDeltaRadiosity 	反射して減衰した radiosity 値
//   @param pHitObj 		交差した物体へのポインタ(同じ object 
//   				に 2 重の交差判定を行わないように)
//------------------------------
void Ray::
initForReflectionRadiosity(const Ray *const pOldRay, const Vector3& dirR, 
			   const Vector3& newDeltaRadiosity, 
			   objBaseClass *pHitObj)
{
    this->mStartPos	= pOldRay->mHitPoint; // 反射 ray の視点は交差点
    this->mDir		= dirR;		      // 方向ベクトルは反射・透過方向
    this->mColor        = newDeltaRadiosity;  // 新 delta-radiosity 値
    // this->mRefCoeff;	      	              // 減衰係数はradiosityでは無関係
    assert(pHitObj != NULL); 		      // 交差物体は 2 次レイなので存在
    this->mpRadObj	= pHitObj;	      // ray 発生物体は旧交差物体
#ifndef NDEBUG
    this->mHitPoint.set(-1.0, -1.0, -1.0);    // 物体との交差点はまだない
#endif
    this->mSpcPos	= pOldRay->mSpcPos;   // 現在存在する空間indexは同じ
    // this->mScreenX;  		      // Display Screen座標は無関係
    // this->mScreenY;

    // ray 反射回数は PEClass::calcNsetIntensityRadiosity にて既に増加した
    this->mReflectedNum	= pOldRay->mReflectedNum;	

    // 3DDDA のための情報は全て計算しなおす必要あり
    this->mSpcDInfo.invalidateInit();
    this->mVTinfo.invalidateInit();

#ifdef TRACE_RAY
    this->setNextID();
    // this->mOrgPEID	= pOldRay->mOrgPEID;  // 発信 PE も旧と同じ
    // cout << "#R n4 " << this->mID << endl;
#endif
    // #ifdef COUNT_SKIP_SPACE
    //     this->mNumOfSkipSpaces 	= 0;
    //     this->mNumOfTraverseSpaces 	= 0;
    // #endif
    //tokunaga changed:
    this->mSide           = pOldRay->mSide;
}

//------------------------------
// Ray Tracing 法
//   @param pOldRay 		新しい ray を作成する物体と反射した元の ray 
//   @param dirR    		反射方向
//   @param reflectedRayCoef 	減衰係数の累積(累積乗算)
//   @param pHitObj 		交差した物体へのポインタ(同じ object 
//   				に 2 重の交差判定を行わないように)
//------------------------------
void Ray::
initForReflectionRayTracing(const Ray *const pOldRay, const Vector3& dirR, 
			    const Vector3& reflectedRayCoef, 
			    objBaseClass *pHitObj)
{
    this->mStartPos	= pOldRay->getHitPos(); // 反射 ray の視点は交差点
    this->mDir		= dirR;			// 方向ベクトルは反射・透過方向
    this->mColor.set(0.0, 0.0, 0.0);		// IC で輝度計算,セットは後
    this->mRefCoeff	= reflectedRayCoef;	// ray の減衰係数は更新

    assert(pHitObj != NULL);
    this->mpRadObj	= pHitObj; 		// ray 発生物体は旧交差物体
#ifndef NDEBUG
    this->mHitPoint.set(-1.0, -1.0, -1.0); 	// 物体との交差点はまだない
#endif
    this->mSpcPos	= pOldRay->mSpcPos;   	// 現在存在する空間indexは同じ
    this->mScreenX	= pOldRay->mScreenX; 	// Display Screen座標も旧と同じ
    this->mScreenY	= pOldRay->mScreenY;

    // ray 反射回数を増加させている場所がなかった．
    this->mReflectedNum	= (pOldRay->mReflectedNum + 1);	

    // 3DDDA のための情報は全て計算しなおす必要あり
    this->mSpcDInfo.invalidateInit();
    this->mVTinfo.invalidateInit();

#ifdef TRACE_RAY
    this->setNextID();
    // this->mOrgPEID	= pOldRay->mOrgPEID;  // 発信 PE も旧と同じ
    // cout << "#R n4 " << this->mID << endl;
#endif
    // #ifdef COUNT_SKIP_SPACE
    //     this->mNumOfSkipSpaces 	= 0;
    //     this->mNumOfTraverseSpaces 	= 0;
    // #endif
    //tokunaga changed:
    this->mSide           = pOldRay->mSide;
}			

//------------------------------
// constructor for radiosity (放射 object などがある)
//------------------------------
// Ray::
// Ray(const Vector3& viewPoint, const Vector3& destVecFromVp, 
// 	 const IntVec3&PEID);

//------------------------------
// destructor
//------------------------------
Ray::
~Ray(void)
{
    // cout << "#R d " << this->mID << endl;
#ifndef NDEBUG
    Vector3 destructedVector(-1.0, -2.0, -3.0);
    IntVec3 destructedIntVec(-1, -2, -3);
    this->mStartPos	= destructedVector;
    this->mDir		= destructedVector;
    this->mColor	= destructedVector;
    this->mRefCoeff	= destructedVector;
    this->mpRadObj	= NULL;
    this->mSpcPos	= destructedIntVec;
    this->mScreenX	= -3;
    this->mScreenY	= -3;
#endif
}

//------------------------------
// operator=
//------------------------------
// const Ray& Ray::
void Ray::
operator=(const Ray& rhs)
{
    if(this != &rhs)
    {
	this->mStartPos		= rhs.mStartPos;
	this->mDir		= rhs.mDir;
	this->mColor		= rhs.mColor;
	this->mRefCoeff		= rhs.mRefCoeff;
	this->mpRadObj		= rhs.mpRadObj;
	this->mHitPoint		= rhs.mHitPoint;
	this->mSpcPos		= rhs.mSpcPos;
	this->mScreenX		= rhs.mScreenX;
	this->mScreenY		= rhs.mScreenY;
	this->mReflectedNum	= rhs.mReflectedNum;

	this->mSpcDInfo		= rhs.mSpcDInfo;
	this->mVTinfo		= rhs.mVTinfo;
#ifdef TRACE_RAY
	this->mID		= rhs.mID;
	//	this->mOrgPEID		= rhs.mOrgPEID;
#endif
// #ifdef COUNT_SKIP_SPACE
// 	this->mNumOfSkipSpaces 	= rhs.mNumOfSkipSpaces;
// 	this->mNumOfTraverseSpaces	= rhs.mNumOfTraverseSpaces;
// #endif
	//tokunaga changed:
	this->mSide             = rhs.mSide;
    }
    // return(*this);
}

//------------------------------
// その他
//------------------------------
void Ray::
print(const char *pHead) const
{
    cout << pHead << "----- Ray -----\n";
    cout << pHead << " startpos( " << this->mStartPos
	<< " ) dir( " << this->mDir << " )\n";        
    cout << pHead << " color   (" << this->mColor << ")\n";
    cout << pHead << " reflectance coefficient (" << this->mRefCoeff << ")\n";
    cout << pHead << " ray org object: "
	<< ((this->mpRadObj != NULL) ?  "There is, " : "NO, ");
    cout << pHead << " ray in spcpos(" << this->mSpcPos << ")\n";
    cout << pHead << " voxel idx    (" << this->mVTinfo.getVolIdx() << ")\n";
    cout << pHead << ((this->mSide == IN) ? "in" : "out") << " of object\n";
#ifdef TRACE_RAY
    cout << pHead << " ray ID = " << this->getID() << endl;
#endif
    // #ifdef COUNT_SKIP_SPACE
    //     cout << pHead << " skip/total " << this->mNumOfSkipSpaces << 
    // 	"/" << this->mNumOfTraverseSpaces << endl;
    // #endif
}

void Ray::
printDDA(const char *pHead) const
{
#ifndef READTEST		// READ TEST では ddainfo の出力はない
    this->mSpcDInfo.print(pHead);
    this->mVTinfo.getVolDDA().print(pHead);
#else
    cout << "Error! : Ray::printDDA() is not implemented "
	"in READTEST. : pHead = " << pHead << endl;
#endif
}

//----- Ray が空間をトラバースする時に PE id をセットして次へいく
#ifdef TRACE_RAY
// void Ray::
// setOrgPE(const IntVec3& anOrgPEID)
// {
//     this->mOrgPEID = anOrgPEID;
// }
// 
// YorN Ray::
// isSameToOrgPE(const IntVec3& aHerePEID) const
// {
//     if(this->mOrgPEID == aHerePEID)
//     {
// 	return(YES);
//     }else
//     {
// 	return(NO);
//     }
// }
#endif
