/************************************************************
  Ninja Sample
  COPYRIGHT (C) SEGA ENTERPRISES, LTD.

  タイトル ： ポリゴンの残像効果
  編集履歴 ： 98-05-07 製作開始
              98-06-19 SET5対応
************************************************************/

#include <shinobi.h>
#include <njdef.h>

void main(void)
{
	njSetBorderColor( 0x00000000 );
    njUserInit();
    while (njUserMain() == NJD_USER_CONTINUE) {
        njWaitVSync();
    }
    njUserExit();
}

#define MAX_MATRIX_DEPTH 20
#define MAX_VERTEXES  30000

#define BALL_MAX 1             	              /* ボールの数             */
#define FRAMES_PER_SECOND 60                  /* １秒間のフレーム数     */
#define FRAME_TIME (1.0F / FRAMES_PER_SECOND) /* １フレームの時間       */

#define BALL_RADIUS    15.0F                  /* 球の半径               */
#define START_SPEED   500.0F                  /* 初期速度               */
#define GRAVITY       980.0F                  /* 重力加速度G            */
#define EFFECTSIZE     21                     /* 保存する残像データの数 */

#define FLOOR_HEIGHT -BALL_RADIUS             /* 地面の高さ             */
#define FLOOR_WIDTH   80.0F                   /* 地面の幅               */
#define FLOOR_LONG  1000.0F                   /* 地面の奥行き           */
#define FLOOR_COLOR 0x77C0C0C0                /* 地面の色               */

void PauseChange(void);
void DrawFloor  (void);
void DrawBall   (void);
void DrawEffect (void);
void DrawShadow (void);

extern NJS_CNK_OBJECT object__sphere3_sphere3[];

typedef struct BallData;
struct BallData {
    Float x;  /* 球のX座標     */
    Float y;  /* 球のY座標     */
    Float z;  /* 球のZ座標     */
    Float vx; /* 球のX方向速度 */
    Float vz; /* 球のY方向速度 */
};

static NJS_MATRIX     *Matrix;
static NJS_VERTEX_BUF *VertexBuffer;

static NJS_VIEW  View;
static NJS_LIGHT Light;

struct BallData   BallPos[BALL_MAX];               /* ボールのデータ */
struct BallData	  BallBackup[BALL_MAX];			   /* 保存用データ */
static NJS_POINT3 BallEffect[BALL_MAX][EFFECTSIZE];/* 座標データ */

Float BallTime = 0.0F; 	/* 時間 */
Float BackupTime;		/* 保存用時間 */

PDS_PERIPHERAL *key;	/* ボタン入力 */

static Bool pause = FALSE;		/* ポーズがかかっているかどうか */

/*----------------------------------------------------------------------
           初期化
----------------------------------------------------------------------*/
void njUserInit(void)
{
    /* システムの初期化 */
    sbInitSystem(NJD_RESOLUTION_640x240_NTSCNI, NJD_FRAMEBUFFER_MODE_RGB565, 1);
    /* ＮＴＳＣ画面の縦横比を補正 */
    njSetAspect(1.0F, 0.45F);
    /* メモリの割り当て */
    Matrix       = syMalloc(sizeof(NJS_MATRIX) * MAX_MATRIX_DEPTH);
    VertexBuffer = syMalloc(sizeof(NJS_VERTEX_BUF) * MAX_VERTEXES);
    /* 背景色の設定 */
    njSetBackColor(ARGB(0, 192, 192, 0), ARGB(0, 192, 0, 192), ARGB(0, 0, 192, 192));
    /* 頂点格納バッファの確保 */
    njInitVertexBuffer(MAX_VERTEXES * 64 / 4, 0, MAX_VERTEXES * 64 / 4, 0, 0);
	njInitPrint( NULL, 0, NJD_TEXFMT_ARGB_1555 );
    /* マトリクススタックの初期化 */
    njInitMatrix(Matrix, MAX_MATRIX_DEPTH, 1);
    /* 3Dシステムの初期化 */
    njInit3D(VertexBuffer, MAX_VERTEXES);
    /* マテリアルを変更できるように設定 */
    njControl3D(NJD_CONTROL_3D_CONSTANT_MATERIAL | NJD_CONTROL_3D_CNK_CONSTANT_ATTR);
    njSetConstantAttr(0xFFFFFFFF, NJD_FST_UA);
    /* 光源の初期化 */
    njCreateLight(&Light, NJD_SPEC_DIR);
    njSetLightIntensity(&Light, 1.0F, 1.0F, 1.0F);
    njSetLightColor(&Light, 1.0F, 1.0F, 1.0F);
    njSetLightDirection(&Light, -1.0F, -1.0F, -1.0F);
    njSetLightAlpha(&Light, 0.5F);
    /* ビューの初期化 */
    njInitView(&View);
    /* ビューの設定 */
    njSetView(&View);
    /* 球の座標の初期化 */
    BallPos[0].x  =    0.0F;
    BallPos[0].y  =    0.0F;
    BallPos[0].z  = -100.0F;
    BallPos[0].vx =    1.0F;
    BallPos[0].vz =    1.0F;
	/* 文字色の設定 */
	njPrintColor(0xFFC0C0C0);
}

/*----------------------------------------------------------------------
         メイン
----------------------------------------------------------------------*/
Sint32 njUserMain(void)
{
    /* サンプル名の表示 */
    njPrintC(NJM_LOCATION(23, 4), "Ninja Sample BOUND");
	if (pause == TRUE) {
	    njPrintC(NJM_LOCATION(30, 5), "PAUSE");
	}
    /* マトリックススタックのクリア */
    njClearMatrix();
	/* ポーズのチェック */
	key = (PDS_PERIPHERAL *) pdGetPeripheral(PDD_PORT_A0);
	if (key->press & PDD_DGT_ST) {
	    PauseChange();
	}
    /* 床の描画 */
    DrawFloor();
    /* 球の処理 */
    DrawBall();
    /* 残像の処理 */
	if (pause == FALSE) {
	    DrawEffect();
	}
    /* 影の処理 */
    DrawShadow();
    /* 時間の経過 */
    BallTime += FRAME_TIME;

    return NJD_USER_CONTINUE;
}

/*----------------------------------------------------------------------
            ポーズの切り替え
----------------------------------------------------------------------*/
void PauseChange(void)
{
    if (pause == FALSE) {
	    pause = TRUE;
		BallBackup[0].x = BallPos[0].x;
		BallBackup[0].y = BallPos[0].y;
		BallBackup[0].z = BallPos[0].z;
		BallBackup[0].vx = BallPos[0].vx;
		BallBackup[0].vz = BallPos[0].vz;
		BackupTime = BallTime;
		BallPos[0].vx = 0.0F;
		BallPos[0].vz = 0.0F;
	} else {
	    pause = FALSE;
		BallPos[0].x = BallBackup[0].x;
		BallPos[0].y = BallBackup[0].y;
		BallPos[0].z = BallBackup[0].z;
		BallPos[0].vx = BallBackup[0].vx;
		BallPos[0].vz = BallBackup[0].vz;
		BallTime = BackupTime;
	}
}

/*----------------------------------------------------------------------
            床の描画
----------------------------------------------------------------------*/
void DrawFloor(void)
{
    NJS_POINT3COL point;
    NJS_POINT3 pointData[4];
    NJS_COLOR  colorData[4];

    /* 頂点座標、色の設定 */
    pointData[0].x = -FLOOR_WIDTH;
    pointData[0].y =  FLOOR_HEIGHT;
    pointData[0].z = -FLOOR_WIDTH;
    colorData[0].color = FLOOR_COLOR;

    pointData[1].x = -FLOOR_WIDTH;
    pointData[1].y =  FLOOR_HEIGHT;
    pointData[1].z = -FLOOR_LONG;
    colorData[1].color = FLOOR_COLOR;

    pointData[2].x =  FLOOR_WIDTH;
    pointData[2].y =  FLOOR_HEIGHT;
    pointData[2].z = -FLOOR_LONG;
    colorData[2].color = FLOOR_COLOR;

    pointData[3].x =  FLOOR_WIDTH;
    pointData[3].y =  FLOOR_HEIGHT;
    pointData[3].z = -FLOOR_WIDTH;
    colorData[3].color = FLOOR_COLOR;

    point.p = pointData;
    point.col = colorData;
    /* 床の表示 */
    njPushMatrix(NULL);
        njDrawPolygon3D(&point, 4, NJD_FILL | NJD_TRANSPARENT);
    njPopMatrix(1);
}

/*----------------------------------------------------------------------
            球の処理
----------------------------------------------------------------------*/
void DrawBall(void)
{
    NJS_ARGB argb;

    /* X座標（左右方向）の設定 */
    BallPos[0].x += BallPos[0].vx;
    if (BallPos[0].x > FLOOR_WIDTH || BallPos[0].x < -FLOOR_WIDTH ) {
        BallPos[0].vx = -BallPos[0].vx;
    }/* はねかえり*/
 
    /* Y座標（高さ）の設定 */
    /* h= v0t - 1/2 gt^2 */
    BallPos[0].y = (START_SPEED * BallTime) - (0.5F * GRAVITY * BallTime * BallTime);
    if (BallPos[0].y < (FLOOR_HEIGHT + BALL_RADIUS)) {  
        BallTime = 0.0F;
    }/* はねかえり */

    /* Z座標（奥行き）の設定 */
    BallPos[0].z += BallPos[0].vz;
    if (BallPos[0].z > -FLOOR_WIDTH || BallPos[0].z < -FLOOR_LONG ) {
        BallPos[0].vz = -BallPos[0].vz;
    }/* はねかえり */

    /* マテリアルの設定（球の色は白）*/
    argb.a = 1.0F;
    argb.r = 1.0F;
    argb.g = 1.0F;
    argb.b = 1.0F;
    njSetConstantMaterial(&argb);
    /* 球面の表示 */
    njPushMatrix(NULL);
        njTranslate(NULL, BallPos[0].x, BallPos[0].y, BallPos[0].z);
        njCnkDrawObject( object__sphere3_sphere3 );
    njPopMatrix(1);
}

/*----------------------------------------------------------------
            影の処理
----------------------------------------------------------------*/
void DrawShadow(void)
{
    NJS_ARGB argb;
    /* マテリアルの設定（影の色は黒） */
    argb.a = 1.0F;
    argb.r = 0.0F;
    argb.g = 0.0F;
    argb.b = 0.0F;
    njSetConstantMaterial(&argb);
    /* 影の表示 */
    njPushMatrix(NULL);
        njTranslate(NULL, BallPos[0].x, FLOOR_HEIGHT, BallPos[0].z);
        njScale(NULL, 1.0F, 0.001F, 1.0F);
        njCnkDrawObject( object__sphere3_sphere3 );
    njPopMatrix(1);
}

/*----------------------------------------------------------------- 
            残像の処理
------------------------------------------------------------------*/
void DrawEffect(void)
{
    NJS_ARGB argb;
    int effectnum;                       /* 座標データ保存用カウンタ */

    /* 座標データの保存 */
    for (effectnum = EFFECTSIZE - 2;effectnum >= 0;effectnum --) {
        BallEffect[0][effectnum+1] = BallEffect[0][effectnum];
    }

    BallEffect[0][0].x = BallPos[0].x;
    BallEffect[0][0].y = BallPos[0].y;
    BallEffect[0][0].z = BallPos[0].z;

    /* 残像の表示 */
    for (effectnum = 0;effectnum < EFFECTSIZE;effectnum += 4) {
        njPushMatrix(NULL);
        /* 時間とともに残像が薄くなる */
        argb.a = 0.5F - (((float)effectnum / 2.0F) / EFFECTSIZE);
        /* マテリアルの設定（球の色は白）*/
        argb.r = 1.0F;
        argb.g = 1.0F;
        argb.b = 1.0F;
        njSetConstantMaterial(&argb);
        /* 残像の描画 */
        njTranslate(NULL, BallEffect[0][effectnum].x,
                    BallEffect[0][effectnum].y, BallEffect[0][effectnum].z);
        njCnkDrawObject( object__sphere3_sphere3 );
        njPopMatrix(1);
    }
}

/*----------------------------------------------------------------------
         終了処理
----------------------------------------------------------------------*/
void njUserExit(void)
{
	njExitPrint();
    /* メモリの開放 */
    syFree(Matrix);
    syFree(VertexBuffer);
    /* システムの終了 */
    sbExitSystem();
}
