//------------------------------------------------------------
// $Id: viewdata.h,v 1.2 2000/05/15 14:20:43 yamauchi Exp $
//------------------------------------------------------------
//	(M\pi)^2 : view data 
//	1996/7/6 start as `dataCollection.h'
//	ViewData : 視線の情報・radiosity情報
//	Copyright (C) 1996--1998 YAMAUCHI Hitoshi 山内 斉
//------------------------------------------------------------
#ifndef _viewdata_h
#define _viewdata_h 1

#include "constants.h"
#include "Vector3.h"
#include "mpi2exit.h"

//------------------------------
// ViewData
//------------------------------
class ViewDataClass {
protected:
    Vector3 mViewPoint;		// 視点
    Vector3 mViewVector;	// 視線方向ベクトル
    Vector3 mViewUpVector;	// 上方ベクトル
    double  mVfovRad;		// 垂直 field of view radian
    double  mHfovRad;		// 水平 field of view radian
    int	    mScreenX, mScreenY;	// screen size
    // radiosity 法
    double  mMinRadiationEnergy;// radiosity 法における最小放射エネルギ
    int     mHemres;		// hemi cube の解像度

    // ray tracing 法
    int	    mMaxRayRefNum;	// 最大反射回数
    double  mMinRefCoeffNorm;	// 最小減衰率
    int	    mDistributedRayNum;	// distributed ray num
    int     mFrustumResX;	// 四角錐の底面の解像度 X
    //     int     mFrustumResY;	// 四角錐の底面の解像度 Y
    //     double  mFrustumFOVRad;	// 四角錐の field of view
    //     double  mFrustumCosN;	// 四角錐での発生レイの phone 則

public:
    ViewDataClass(void)
    {
	this->init();
    }
    ViewDataClass(const ViewDataClass& rhs)
    {
	this->mViewPoint		= rhs.mViewPoint;
	this->mViewVector		= rhs.mViewVector;
	this->mViewUpVector		= rhs.mViewUpVector;
	this->mVfovRad			= rhs.mVfovRad;
	this->mHfovRad			= rhs.mHfovRad;
	this->mScreenX			= rhs.mScreenX;
	this->mScreenY			= rhs.mScreenY;

	this->mMinRadiationEnergy	= rhs.mMinRadiationEnergy;
	this->mHemres			= rhs.mHemres;

	this->mMaxRayRefNum		= rhs.mMaxRayRefNum;
	this->mMinRefCoeffNorm		= rhs.mMinRefCoeffNorm;
	this->mDistributedRayNum	= rhs.mDistributedRayNum;
	this->mFrustumResX		= rhs.mFrustumResX;
	// 	this->mFrustumResY		= rhs.mFrustumResY;
	// 	this->mFrustumFOVRad		= rhs.mFrustumFOVRad;
	// 	this->mFrustumCosN		= rhs.mFrustumCosN;
    }
    void init(void)
    {
	const double DEFAULT_FOV_RAD = 30.0 * M_PI / 180.0;
	const int    DEFAULT_SCREEN_X = 100;
	const int    DEFAULT_SCREEN_Y = 100;
	this->mViewPoint.set(0.0, 0.0, 0.0);
	this->mViewVector.set(-1.0, 0.0, 0.0);
	this->mViewUpVector.set(0.0, 0.0, 1.0);
	this->mVfovRad	= DEFAULT_FOV_RAD;
	this->mHfovRad	= DEFAULT_FOV_RAD;
	this->mScreenX	= DEFAULT_SCREEN_X;
	this->mScreenY	= DEFAULT_SCREEN_Y;

	this->mMinRadiationEnergy	= DEFAULT_MIN_RAD_ENERGY;
	this->mHemres			= DEFAULT_HEMRES;

	this->mMaxRayRefNum		= DEFAULT_MAX_REFLECTION_RAY_NUM;
	this->mMinRefCoeffNorm		= DEFAULT_MIN_REFLECTION_COEFF_NORM2;
	this->mDistributedRayNum	= DEFAULT_DIST_RAY_NUM;
	this->mFrustumResX		= DEFAULT_FRUSTUM_RES;
	// 	this->mFrustumResY		= DEFAULT_FRUSTUM_RES;
	// 	this->mFrustumFOVRad		= DEFAULT_FRUSTUM_FOV;
	// 	this->mFrustumCosN		= DEFAULT_FRUSTUM_COSN;
    }
    YorN setViewPoint(const Vector3& vp)
    { 
	if(vp.getNorm() != 0.0)
	{
	    this->mViewPoint = vp;	
	    return(YES);
	}else
	{
	    return(NO);
	}
    }
    const Vector3 getViewPoint(void) const { return(this->mViewPoint);	}
    YorN setViewVector(const Vector3& vv)
    {
	if(vv.getNorm() != 0.0)
	{
	    this->mViewVector = vv; 	
	    this->mViewVector.VNormalize(); 	
	    return(YES);
	}else
	{
	    return(NO);
	}
    }
    const Vector3 getViewVector(void) const{ return(this->mViewVector); }
    YorN setViewUpVector(const Vector3& vup)
    {
	if(vup.getNorm() != 0.0)
	{
	    this->mViewUpVector = vup;	
	    this->mViewUpVector.VNormalize();	
	    return(YES);
	}else
	{
	    return(NO);
	}
    }
    const Vector3 getViewUpVector(void) const { return(this->mViewUpVector);}
    YorN setFov(double vfovRad, double hfovRad)
    {
	if((vfovRad <=   0.0) || (hfovRad <=   0.0) ||
	   (vfovRad >= M_PI)  || (hfovRad >= M_PI))
	{
	    cerr << "Warning! : illegal field of view (rad)(vfov, hfov) = " << 
		vfovRad << ", " << hfovRad << " : unchanged" << endl;
	    return(NO);
	}
	this->mVfovRad	= vfovRad;
	this->mHfovRad	= hfovRad;
	return(YES);
    }
    void getFOV(double *vfovRad, double *hfovRad) const
    {
	(*vfovRad) = this->mVfovRad;
	(*hfovRad) = this->mHfovRad;
    }
    void setScreenSize(int scrX, int scrY)
    {
	if((scrX <= 0) || (scrY <= 0))
	{
	    cerr << "Error! : illegal screen size (" << scrX << ", "
		<< scrY << ")" << endl; 
	    commMpi2_exit(1);
	}
	this->mScreenX = scrX;
	this->mScreenY = scrY;	
    }
    void getScreenSize(int *pScrX, int *pScrY) const
    {
	(*pScrX) = this->mScreenX;
	(*pScrY) = this->mScreenY;     
    }
    void setMinRadEnergy(double anEnergy)
    {
	if(anEnergy <= 0.0)
	{
	    cerr << "Error ! : illegal min radiation energy " << 
		anEnergy << endl;
	    commMpi2_exit(1);
	}
	this->mMinRadiationEnergy	= anEnergy;
    }
    double getMinRadEnergy(void) const 	{ return(this->mMinRadiationEnergy); }
    void setHemres(int hemicubeResolution)
    {
	if((hemicubeResolution < 2) || ((hemicubeResolution % 2) != 0))
	{
	    cerr << "Error! : hemicube resolution must be > 1 and % 2 == 0"
		<< " : hemres = " << hemicubeResolution << endl;
	    commMpi2_exit(1);	    
	}
	this->mHemres = hemicubeResolution;
    }
    int getHemres(void) const	{ return(this->mHemres);	}
    void   setMaxRayRefParam(int aRefnum, double aCoefNorm)
    {
	if((aRefnum <= 0) || (aCoefNorm <= 0.0))
	{
	    cerr << "Error ! : illegal max ray reflection param, num = " << 
		aRefnum << ", coeff = " << aCoefNorm << endl;
	    commMpi2_exit(1);
	}
	this->mMaxRayRefNum		= aRefnum;
	this->mMinRefCoeffNorm		= aCoefNorm;
    }
    int    getMaxRayRefNum(void) const	{ return(this->mMaxRayRefNum);	}
    double getMinRayRefCoeffNorm(void) const { return(this->mMinRefCoeffNorm);}
    void   setDistributedRayNum(int aDistRayNum)
    {
	if(aDistRayNum <= 0)
	{
	    cerr << "Error ! : illegal distributted ray num " << 
		aDistRayNum << endl;
	    commMpi2_exit(1);
	}
	this->mDistributedRayNum	= aDistRayNum;
    }
    int    getDistributedRayNum(void) const{ return(this->mDistributedRayNum);}
    void   setFrustumParam(int resolutionX)
    {
	if(resolutionX <= 0)
	{
	    cerr << "Error! : illegal frustum param res(" << resolutionX
	    	 << ")" << endl;
	    commMpi2_exit(1);
	}
	this->mFrustumResX	= resolutionX;
	// 	this->mFrustumResY 	= resY;
	// 	this->mFrustumFOVRad	= fovrad;
	// 	this->mFrustumCosN 	= cosN;
    }
    int    getFrustumResX(void) const	{ return(this->mFrustumResX);	}
    // int    getFrustumResY(void) const{ return(this->mFrustumResY);	}
    // double getFrustumFOV(void)  const{ return(this->mFrustumFOVRad);	}
    // double getFrustumCosN(void) const{ return(this->mFrustumCosN);	}

    void print(const char *pH) const 
    {
	cout << pH << "viewPoint\t" 	<< this->mViewPoint   << endl;
	cout << pH << "viewVector\t" 	<< this->mViewVector  << endl;
	cout << pH << "viewUpVector\t"	<< this->mViewUpVector<< endl;
	cout << pH << "fovVHRad\t"	<< this->mVfovRad << " " 
	    << this->mHfovRad << endl;
	cout << pH << "screenSize\t(" 	<< this->mScreenX << " " 
	    << this->mScreenY << ")"    << endl; 
	cout << pH << "maxRayReflectionNum\t"  << this->mMaxRayRefNum << endl;
	cout << pH << "minRayReflectionCoef\t" << this->mMinRefCoeffNorm<<endl;
	cout << pH << "distributedRayNum\t"    << this->mDistributedRayNum
		<< endl;
	cout << pH << "frustum resolution = " << this->mFrustumResX << endl;
	// ", " << this->mFrustumResY  << ")"<< endl;
	// cout << pH << "frustum fov\t" << this->mFrustumFOVRad << endl;
	// cout << pH << "frustumCosN\t" << this->mFrustumCosN   << endl;
	cout << pH << "minRadioEnergy\t"<< this->mMinRadiationEnergy << endl;
	cout << pH << "hemres\t" 	<< this->mHemres	<< endl;
    }
    const ViewDataClass& operator=(const ViewDataClass& rhs)
    {
	if(this != &rhs)
	{
	    this->mViewPoint	= rhs.mViewPoint;
	    this->mViewVector	= rhs.mViewVector;
	    this->mViewUpVector	= rhs.mViewUpVector;
	    this->mVfovRad	= rhs.mVfovRad;
	    this->mHfovRad	= rhs.mHfovRad;
	    this->mScreenX	= rhs.mScreenX;
	    this->mScreenY	= rhs.mScreenY;

	    this->mMinRadiationEnergy	= rhs.mMinRadiationEnergy;
	    this->mHemres		= rhs.mHemres;

	    this->mMaxRayRefNum		= rhs.mMaxRayRefNum;
	    this->mMinRefCoeffNorm	= rhs.mMinRefCoeffNorm;
	    this->mDistributedRayNum	= rhs.mDistributedRayNum;
	    this->mFrustumResX		= rhs.mFrustumResX;
	    // this->mFrustumResY	= rhs.mFrustumResY;
	    // this->mFrustumFOVRad	= rhs.mFrustumFOVRad;
	    // this->mFrustumCosN	= rhs.mFrustumCosN;
	}
	return(*this);
    }
};


#endif				// #define _viewdata_h 1
