//------------------------------------------------------------
// $Id: screenPointer.h,v 1.2 2000/06/14 13:29:37 yamauchi Exp $
//------------------------------------------------------------
//	screen pointer class 
//	    scan type : regular 	全画面を順番にスキャンする
//			scanline 	scanline を PE に割り当てる
//			distributed	distributed に PE へ割り当てる
//	初期レイ発生時に screen 上の pixel をスキャンする
//	
//	オブジェクト空間分割型並列計算モデルに基づく並列計算での初期光
//	分散の考えは 1997 に前田隆之によって提案され、最初に前田隆之に
//	よって実装された. 私はそれを統一して扱えるよう rewrite した
//
//	Copyright (C) 1996--1998 MAEDA Takayuki   前田隆之
//	Copyright (C) 1996--1999 YAMAUCHI Hitoshi 山内 斉
//------------------------------------------------------------
#ifndef _screenPointer_h
#define _screenPointer_h 1

#include <assert.h>
#include "YorN.h"

//------------------------------------------------------------
// screen の pixel 位置を保持し、次の位置を発生する
//	base class (interface)
//	virtual の next の効率に心配があるが，，，
//------------------------------------------------------------
class scrPtrIF  {
private:
    scrPtrIF (const scrPtrIF & rhs);
    const scrPtrIF & operator=(const scrPtrIF & rhs);
 
protected:
    int mMaxX;			// screen max X
    int mMaxY;			// 	      Y
    int mX;			// 現在の screen 位置 X
    int mY;			// 		      Y
 
public:
    scrPtrIF(void)
    {
	// ところで : mX(-1) とか書いた場合，subclass で construct し
	// た時に正しく処理されるのだろうか．わからないので書いてしまっ
	// た． 
	this->mX 	= -1;
	this->mY 	= -1;
	this->mMaxX	= -1;
	this->mMaxY 	= -1;
    }
    // virtual ~scrPtrIF(void);
    
    //------------------------------
    // 自分の scan type を返す
    //------------------------------
    virtual const char* getScreenPointerType(void)	= 0;

    //------------------------------
    // 次の screen 位置を取り出す
    //------------------------------
    virtual YorN next(void)		 		= 0;

    //------------------------------
    // 今の screen 位置を取り出す
    //------------------------------
    void getpos(int *pX, int *pY) const
    {
	(*pX) = this->mX;
	(*pY) = this->mY;
    }
};


//------------------------------------------------------------
// All scan on a screen 
//   次々に screen 上で 位置を increment していく生成器
//   (まず X 方向に scan する．)
//------------------------------------------------------------
class scrPtrAllScan : public scrPtrIF {
private:
    scrPtrAllScan(const scrPtrAllScan& rhs);
    const scrPtrAllScan& operator=(const scrPtrAllScan& rhs);
    scrPtrAllScan(void)
    {
	// scrPtrIF::scrPtrIF(); AIX の方は super ができないらしい
	this->mX 	= -1;
	this->mY 	= -1;
	this->mMaxX	= -1;
	this->mMaxY 	= -1;
    }

public:
    scrPtrAllScan(int maxX, int maxY)
    {
	this->initMax(maxX, maxY);
    }
    // ~scrPtrAllScan(void);
    
    // scan 方式名を返す
    virtual const char* getScreenPointerType(void)
    {
	return("ScanType : AllScan (not distributed ray generation)");
    }

    //------------------------------
    // スクリーンの最大値をセットする
    //------------------------------
    void initMax(int maxX, int maxY)
    {
	assert(maxX >  0);
	assert(maxY >  0);
	this->mMaxX = maxX;
	this->mMaxY = maxY; 
	this->mX = -1;	// 最初に x = 0 を返すため
	this->mY =  0;	
    }

    //------------------------------
    // 次の screen 位置を取り出す
    //------------------------------
    // 以下のコードを 1 ステップづつ実行する
    // for(int y = 0; y < maxY; y++)
    // {
    //    for(int x = 0; x < maxX; x++)
    //    {
    //    }
    // }
    virtual YorN next(void)
    {
	this->mX++;
	if(this->mX >= this->mMaxX)
	{
	    this->mX = 0;
	    this->mY++;
	    if(this->mY >= this->mMaxY)	    
	    {
		return(NO);	// これ以上の ray の生成はできない。
	    }
	}
	return(YES);
    }
};

//------------------------------------------------------------
// distributed with scanline
//	PE に scanline を分散して割り当てる
//	scanline ごと飛び飛びに screen を移動する
//------------------------------------------------------------
class scrPtrScanline : public scrPtrIF {
private:
    scrPtrScanline(const scrPtrScanline& rhs);
    const scrPtrScanline& operator=(const scrPtrScanline& rhs);
    scrPtrScanline(void) 
    {
	// scrPtrIF::scrPtrIF(); AIX の方は super ができないらしい
	// 勝手に呼ばれるのかもしれないが不安なので書いておく
	// base class memeber
	this->mX 	= -1;
	this->mY 	= -1;
	this->mMaxX	= -1;
	this->mMaxY 	= -1;

	// members of this class 
	this->mSkipYLines = 10000000; // 不正な数で初期化
    }

protected:
    int mSkipYLines;

public:
    scrPtrScanline(int maxX, int maxY, int skipYLines, int startY)
    {
	this->initMax(maxX, maxY, skipYLines, startY);
    }
    // ~scrPtrScanline(void);
    
    // scan 方式の名前を返す
    virtual const char* getScreenPointerType(void) 
    {
	return("ScanType : Scanline (distributed first ray generation)");
    }
    
    //------------------------------
    // initialize 
    //------------------------------
    void initMax(int maxX, int maxY, int skipYLines, int startY)
    {
	assert(maxX >  0);
	assert(maxY >  0);
	this->mMaxX = maxX;
	this->mMaxY = maxY; 
	this->mX = -1;	// 最初に x = 0 を返すため
	
	assert(skipYLines > 0);
	this->mSkipYLines = skipYLines;

	assert(startY >= 0);
	this->mY = startY;	// 最初の scanline
    }

    //------------------------------
    // 次の screen 位置を取り出す
    //------------------------------
    // 以下のコードを 1 ステップづつ実行する
    // for(int y = startY; y < maxY; y+= skipYLines)
    // {
    //    for(int x = 0; x < maxX; x++)
    //    {
    //    }
    // }
    virtual YorN next(void)
    {
	this->mX++;
	if(this->mX >= this->mMaxX)
	{
	    this->mX = 0;
	    this->mY += this->mSkipYLines;
	    if(this->mY >= this->mMaxY)	    
	    {
		return(NO);	// これ以上の ray の生成はできない。
	    }
	}
	return(YES);
    }
};

//------------------------------------------------------------
// distributed pixel by pixel
//	いくつかおきに pixel を指す
//------------------------------------------------------------
class scrPtrDistribute : public scrPtrIF {
private:
    scrPtrDistribute(const scrPtrDistribute& rhs);
    const scrPtrDistribute& operator=(const scrPtrDistribute& rhs);
    scrPtrDistribute(void) 
    {
	// scrPtrIF::scrPtrIF(); AIX の方は super ができないらしい
	// 勝手に呼ばれるのかもしれないが不安なので書いておく
	// base class memeber
	this->mX 	= -1;
	this->mY 	= -1;
	this->mMaxX	= -1;
	this->mMaxY 	= -1;

	// members of this class 
	this->mDistributedSizeX = 100000; // 不正値
	this->mDistributedSizeY = 100000;
	this->mStartX		= 100000;
    }

protected:
    int mDistributedSizeX;
    int mDistributedSizeY;
    int mStartX;

public:
    scrPtrDistribute(int maxX, 		int maxY,
		     int distributedX, 	int distributedY, 
		     int startX, 	int startY)
    {
	this->initMax(maxX, maxY, distributedX, distributedY, startX, startY);
    }
    scrPtrDistribute(int maxX, int maxY, int totalPEnum, int thisRank)
    {
	// screen の大きさと total PE Num と myRank (PE id から 
	// distributedX,Y と startX,Y を計算する．)
	cout << "scrPtrDistribute:: Not Implemented Now" << endl;
	abort();
	maxX = maxY = totalPEnum = thisRank; // for -Wall
    }
    // ~scrPtrDistribute(void);

    // scan 方式名を返す
    virtual const char* getScreenPointerType(void) 
    {
	return("ScanType : Distributed (distributed first ray generation)");
    }

    // initialize 
    void initMax(int maxX, int maxY,
		 int distributedX, int distributedY, int startX, int startY)
    {
	assert(maxX >  0);
	assert(maxY >  0);
	this->mMaxX = maxX;
	this->mMaxY = maxY; 

	assert(distributedX > 0);
	assert(distributedY > 0);
	this->mDistributedSizeX = distributedX;
	this->mDistributedSizeY = distributedY;

	assert(startX >= 0);
	assert(startY >= 0);
	this->mStartX	= startX;

	this->mX =  startX - distributedX; // 最初に increment されるため
	this->mY =  startY;
    }

    //------------------------------
    // 次の screen 位置を取り出す
    //------------------------------
    // 以下のコードを 1 ステップづつ実行する
    // for(int y = startY; y < maxY; y+ distributedY)
    // {
    //    for(int x = startX; x < maxX; x += distributedX)
    //    {
    //    }
    // }
    virtual YorN next(void)
    {
	this->mX += this->mDistributedSizeX;
	if(this->mX >= this->mMaxX)
	{
	    this->mX  = this->mStartX;
	    this->mY += this->mDistributedSizeY;
	    if(this->mY >= this->mMaxY)	    
	    {
		return(NO);	// これ以上の ray の生成はできない。
	    }
	}
	return(YES);
    }
};

#endif				// #ifndef _screenPointer_h

