//------------------------------------------------------------
// $Id: ray.h,v 1.2 2000/06/14 13:29:37 yamauchi Exp $
//------------------------------------------------------------
//	ray
//	1996/7/21 
//	(C) Copyright Hitoshi Yamauchi
//	光線
//------------------------------------------------------------
#ifndef _ray_h
#define _ray_h 1

#include <assert.h>
#include "IntVec3.h"
#include "Vector3.h"
#include "config.h"
#include "constants.h"
#include "ddaInfo.h"
#include "mpi2.h"
#include "voltravinfo.h"

class objBaseClass;

// #define TRACE_RAY 1
//------------------------------------------------------------
// ray is in or out :tokunaga
//------------------------------------------------------------
enum side_e {
    OUT,
    IN
};

//------------------------------------------------------------
// ray
//------------------------------------------------------------
class Ray {
protected:
    //  ray tracing 初期レイ用
    Ray(int screenX, int screenY,
	const Vector3& viewPoint, const Vector3& destVecFromVp, 
	const IntVec3& spcpos,    const double distRaysFactor
	//,    const IntVec3& PEID
	);
    //  radiosity レイ用
    Ray(const Vector3& viewPoint, const Vector3& destVecFromVp, 
	const Vector3& radioVal,  objBaseClass * pGenerateObject, 
	const IntVec3& spcpos	//,    const IntVec3& PEID
	);

    // 反射 delta-radiosity ray 作成用
    void initForReflectionRadiosity(const Ray *const pOldRay, 
				    const Vector3& reflectedRayDir,
				    const Vector3& newDeltaRadiosity,
				    objBaseClass *pHitObj);
    
    // 反射 ray-tracing ray 作成用
    void initForReflectionRayTracing(const Ray *const pOldRay, 
				     const Vector3& reflectedRayDir,
				     const Vector3& reflectedRayCoef,
				     objBaseClass *pHitObj);
protected:
    // ray そのものの情報
    Vector3 	  mStartPos;	// ray 出発点
    Vector3 	  mDir;		// ray 方向ベクトル
    Vector3 	  mColor;	// ray の輝度 
    Vector3 	  mRefCoeff;	// ray の減衰係数 in radiosity = no mean
    objBaseClass *mpRadObj;	// ray 発生物体 (他空間では NULL)
    Vector3 	  mHitPoint;	// 物体との交差点
    IntVec3 	  mSpcPos;	// 現在存在する空間 index
    int 	  mScreenX, mScreenY; // Display Screen 座標
    int		  mReflectedNum;      // ray 反射回数

    DDAInfoClass  mSpcDInfo;	// 空間 traverse のための DDA 情報を保持する
    volTravInfoClass mVTinfo;	// volume traverse のための情報を保持する
#ifdef TRACE_RAY
    int 	  mID;			//----- debug
    // IntVec3       mOrgPEID;		// 発信 PE
#endif
//------------------------------
// ray が空間をどれだけ skip したかの情報は ray が持つのも良いが、ray 
// 固有の情報として必要ではないので PE に持たせることにする。 
//------------------------------
// #ifdef COUNT_SKIP_SPACE		// ray が空間をどの位スキップしたか
//     int		  mNumOfSkipSpaces;
//     int		  mNumOfTraverseSpaces;
// #endif

public:
    Ray(void);		       // default constructor
    //  ray tracing 初期レイ用
    static Ray* newForRayTrace(int screenX, int screenY,
			       const Vector3& viewPoint, 
			       const Vector3& destVecFromVp, 
			       const IntVec3& spcpos,    
			       const double   distRaysFactor
			       //,    const IntVec3& PEID
			       )
    {
	return(new Ray(screenX, screenY, viewPoint, destVecFromVp, 
		       spcpos,  distRaysFactor
		       //,    const IntVec3& PEID
		       ));
    }
    //  radiosity レイ用
    static Ray *newForRadiosity(const Vector3& viewPoint, 
				const Vector3& destVecFromVp, 
				const Vector3& radioVal,
				objBaseClass * pGenerateObject, 
				const IntVec3& spcpos
				//,    const IntVec3& PEID
				)
    {
	return(new Ray(viewPoint, destVecFromVp, 
		       radioVal,  pGenerateObject, spcpos
		       //,    const IntVec3& PEID
		       ));
    }
    // 反射レイ作成用 (ray-tracing)
    // pOldRay 反射物体(=発生物体)の情報もある
    static Ray *newForReflectionRayTracing(const Ray *const pOldRay, 
					   const Vector3& reflectedRayDir,
					   const Vector3& reflectedRayCoef,
					   objBaseClass *pHitObj)
    {
	Ray *pRay = new Ray();
	pRay->initForReflectionRayTracing(pOldRay, reflectedRayDir,
					  reflectedRayCoef, pHitObj);
	return(pRay);
    }
    // 反射レイ作成用 (radiosity)
    // pOldRay 反射物体(=発生物体)の情報もある
    static Ray *newForReflectionRadiosity(const Ray *const pOldRay, 
					  const Vector3& reflectedRayDir,
					  const Vector3& newDeltaRadiosity,
					  objBaseClass *pHitObj)
    {
	Ray *pRay = new Ray();
	pRay->initForReflectionRadiosity(pOldRay, reflectedRayDir,
					 newDeltaRadiosity, pHitObj);
	return(pRay);
    }
    
    Ray(const Ray& rhs);     // buff から取り出すためにcopy construct
    ~Ray(void);
    // const Ray& operator=(const Ray& rhs);
    void operator=(const Ray& rhs);
    void setPosDir(const Vector3& aStartPos, const Vector3& aDir)
    {
	this->mStartPos = aStartPos;
	this->mDir 	= aDir;
    }
    // void setPos(const Vector3& aPos)    { this->mStartPos = aPos;	}
    Vector3 getPos(void) const		   
    {
	return(this->mStartPos); 	
    }
    void    setDir(const Vector3& aDir)    
    {
	this->mDir = aDir;		
    }
    Vector3 getDir(void) const	   	   
    {
	return(this->mDir);	
    }
    void    setColor(const Vector3& aCol)  
    {
	this->mColor = aCol;	
    }
    Vector3 getColor(void) const	   
    {
	return(this->mColor);	
    }
    void    setRefCoeff(const Vector3& aRef)
    {
	this->mRefCoeff = aRef;	
    }
    Vector3 getRefCoeff(void) const	   
    { 
	return(this->mRefCoeff);	
    }
    void    setRadObj(objBaseClass * apObj)
    {
	this->mpRadObj = apObj;	
    }
    objBaseClass *getRadObj(void) const    
    {
	return(this->mpRadObj);	
    }
    void    setHitPos(const Vector3& aHPos)
    {
	this->mHitPoint = aHPos;	
    }
    Vector3 getHitPos(void) const	   
    {
	return(this->mHitPoint);	
    }
    void    setSpcPos(const IntVec3& aSpc) 
    {
	this->mSpcPos  = aSpc;	}   
    
    const IntVec3 getSpcPos(void) const    
    {
	return(this->mSpcPos);    	}   
    
    int     getScreenPosX() const	
    {
	return(this->mScreenX);
    }
    int     getScreenPosY() const
    {
	return(this->mScreenY);
    }
    int	 getReflectedNum(void) const 	   
    {
	return(this->mReflectedNum); 
    }
    void incReflectedNum(void) 		   
    {
	this->mReflectedNum++;	
    }

    // DDA 関係 
    //----- 空間 traverse 用 DDA
    void   setSpcDDAInfo(const DDAInfoClass& dinfo) 
    {
	this->mSpcDInfo = dinfo; 
    }
    DDAInfoClass getSpcDDAInfo(void) const 
    {
	return(this->mSpcDInfo);	 
    }
    DDAInfoClass* getSpcDDAInfoPtr(void)   
    {
	return(&(this->mSpcDInfo)); 
    }
    void   setSpcDinfoIllegalDir(void)	
    { 
	this->mSpcDInfo.setGoingDir(DIR_ILLEGAL); 
    }

    //-----  voxel traverse 用 DDA
    void    invalidateVolData(void) 
    {
	this->mVTinfo.invalidateInit();	 
    }
    // volume DDA
    YorN   isVolDDAinited(void) const 	
    {
	// improve いちいちコンストラクトするので効率が悪い
	return((this->mVTinfo.getVolDDA()).isDDAinited());
    }
    void   setVolDDAInfo(const DDAInfoClass& dinfo) 
    {
	this->mVTinfo.setVolDDA(dinfo);
    }
    DDAInfoClass getVolDDAInfo(void) const 
    {
	return(this->mVTinfo.getVolDDA());
    }
    //    volume ID
    void   setVolID(int vid) 		
    {
	this->mVTinfo.setVolID(vid);	
    }
    int    getVolID(void) const		
    {
	return(this->mVTinfo.getVolID()); 
    }
    //    volume index
    void    setVoxelIdx(const IntVec3& voxelIdx) 
    {
	this->mVTinfo.setVolIdx(voxelIdx);
    }
    IntVec3 getVoxelIdx(void) const 
    {
	return(this->mVTinfo.getVolIdx()); 
    }
    void    setAccumOpacity(double accumOpacity)
    {
	this->mVTinfo.setAccumOpacity(accumOpacity);
    }
    double getAccumOpacity(void)const
    {
	return(this->mVTinfo.getAccumOpacity());
    }
				       
    //----- その他
    void print(const char *pLineHead) const;
    void printDDA(const char *pLineHead) const;
    int  isOK(void) const 
    {
	return((this->mSpcPos.get(Vector3::X) >= 0) ? 1 : 0);
    }
    

#ifdef TRACE_RAY
    int  getID(void) const 
    {
	return(this->mID); 
    }
protected:
    void setNextID(void);
    //void setOrgPE(const IntVec3& aOrgPEID); // 直前にいた PE
    //YorN isSameToOrgPE(const IntVec3& aHerePEID) const; // 比較用
#endif
// #ifdef COUNT_SKIP_SPACE
// public:
//     void incSkipSpaceNum(void)		{ this->mNumOfSkipSpaces++; }
//     int  getSkipSpaceNum(void) const	{ return(this->mNumOfSkipSpaces);}
//     // number of traverse spaces は updateSpc で増加する
// #endif    

    // tokunaga changed:
    // 透過光用:レイの位置の判定    
protected:
     side_e mSide;

public:
    // 物体内か外か
    void changeSide(void) 
    {	
	this->mSide = (this->mSide == OUT) ? IN : OUT;
    }
    YorN  isInside(void)  const {
	if(this->mSide == IN)
	{
	    return(YES); 
	}
	else
	{
	    return(NO);
	}
    }

public:
    // タグを返す
    static communication_tags_e getTAG(void) 
    {
	return(TAG_RAY_e);	
    }
};

#endif				// #ifndef _ray_h 
