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

  タイトル ： マトリクスのプッシュ＆ポップ
              push and pop the matrix stack
  編集履歴 ： 98-05-08 作成開始
              98-06-19 SET5対応
              98-07-08 C0焼き付き問題に対応（ポーズ追加）
              99-04-05 appends the English comments
************************************************************/

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

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

#define MAX_MATRIX_DEPTH 10
#define MAX_VERTEXES 10000

extern NJS_CNK_OBJECT object_cube_root[];

static NJS_MATRIX *Matrix;
static NJS_VERTEX_BUF *VBuf;
static NJS_VIEW View;
static NJS_LIGHT Light;

/* グループの数を設定 */
/* the number of groups */
#define GROUP_NUM 4

/* １つのグループ内の物体数を設定 */
/* the number of the object in a group */
#define OBJECT_NUM 6

/* 全体の回転速度を設定 */
/* speed of whole rotation */
#define ROTATION_SPEED_ALL 1.0F

/* グループの回転速度の範囲を設定 */
/* maximum rotation speed of a group */
#define MAX_SPEED_GROUP 4.0F

/* 物体の回転速度の範囲を設定 */
/* maximum rotation speed of a object */
#define MAX_SPEED_OBJECT 8.0F

/* 回転状態を持つ構造体 */
/* rotation object */
typedef struct {
    Angle ang; /* 角度  */
               /* angle */
    Angle rsp; /* 回転の速さ */
               /* speed */
} RotateState;

static RotateState Group[GROUP_NUM]; /* グループの回転状態 */
                                     /* rotation status of a group  */
static RotateState Object[GROUP_NUM][OBJECT_NUM]; /* 物体の回転状態 */
                                     /* rotation status of a object */

PDS_PERIPHERAL* Per;

void PauseMode(void);

/************************************************************
  初期化関数
  initialize
************************************************************/
void njUserInit(void)
{
    /* システムを初期化 */
    /* Initializes the Dreamcast H/W and readies the SEGA library */
    sbInitSystem(NJD_RESOLUTION_640x240_NTSCNI, NJD_FRAMEBUFFER_MODE_RGB565, 1);

    /* 画面のアスペクト比を補正 */
	/* corrects the screen aspect ratio */
    njSetAspect( 1.0F, 0.45F );

    /* バッファ用メモリをアロケート */
    /* allocates the memory */
    Matrix = syMalloc(sizeof(NJS_MATRIX) * MAX_MATRIX_DEPTH);
    VBuf = syMalloc(sizeof(NJS_VERTEX_BUF) * MAX_VERTEXES);

    /* バックグラウンドカラーを設定 */
	/* sets background color */
    njSetBackColor(ARGB(0, 0, 0, 64), ARGB(0, 0, 0, 64), ARGB(0, 64, 0, 0));

    /* 頂点データ登録用バッファをアロケート（１つの頂点＊６４／４バイト） */
    /* allocates the buffers for registration of vertex data */
    njInitVertexBuffer(MAX_VERTEXES * 64 / 4, 0, MAX_VERTEXES * 64 / 4, 0, 0);
	njInitPrint( NULL, 0, NJD_TEXFMT_ARGB_1555 );

    /* マトリクススタックを初期化（１＝ライト演算用のマトリクスを使用） */
  	/* initializes the matrix stack (1:for the light)*/
    njInitMatrix(Matrix, MAX_MATRIX_DEPTH, 1);

    /* ３Ｄシステムの初期化（モデル描画のためのワークバッファを初期化） */
    /* initializes 3D system  */ 
    njInit3D(VBuf, MAX_VERTEXES);

    /* 光源の種類を定めライトを新たに設置（平行光源を登録）
      （位置＝0,0,0）（向き＝0,0,-1） */
    /* initializes the light source  (Parallel light source ) */
    /* position( 0,0,0)/ direction (0,0,-1) */
    njCreateLight(&Light, NJD_SPEC_DIR);

    /* ビューの初期化（位置＝0,0,0）（向き＝0,0,-1）（傾き＝０度） */
    /* initializes the user-defined view */
    /* position(0,0,0) / direction(0,0,-1) / ( sight tilt = 0)*/
    njInitView(&View);

    /* ユーザの用意したビューをカレントビューに指定 */
	/* specifies the current view */
    njSetView(&View);

    /* デバッグ文字の色 */
    /* sets the text color */
    njPrintColor(ARGB(255, 150, 150, 150));

    /* 乱数の種を設定 */
    /* set the randam seed */
    njRandomSeed(0);

    {
        int grp; /* グループに対するループカウンタ */
                 /* counter of groups */
        int obj; /* 物体に対するループカウンタ */
                 /* counter of object */

        /* グループごとの初期角度と回転の速さを設定 */
        /* sets the initial angle and speed to each group */
        for (grp = 0; grp < GROUP_NUM; grp++) {
            RotateState *grpp = &Group[grp];
            grpp->ang = NJM_DEG_ANG(0.0F);
            grpp->rsp = (Angle)(NJM_DEG_ANG(1.0F) * (njRandom() *
                MAX_SPEED_GROUP * 2.0F - MAX_SPEED_GROUP));
        }

        /* 物体ごとの初期角度と回転の速さを設定 */
        /* sets the initial angle and speed to each object */
        for (grp = 0; grp < GROUP_NUM; grp++) {
            for (obj = 0; obj < OBJECT_NUM; obj++) {
                RotateState *objp = &Object[grp][obj];
                objp->ang = NJM_DEG_ANG(0.0F);
                objp->rsp = (Angle)(NJM_DEG_ANG(1.0F) * (njRandom() *
                    MAX_SPEED_OBJECT * 2.0F - MAX_SPEED_OBJECT));
            }
        }
    }

    /* 全体の回転の中心へ */
    /* move to the center of rotation */
    njTranslate(NULL, 0.0F, -5.0F, -30.0F);
}

/************************************************************
  定期実行されるメイン処理
************************************************************/
Sint32 njUserMain(void)
{
    static Angle angAll = NJM_DEG_ANG(0.0F); /* 全体の回転角*/
                                             /* rotation angle of the whole objects */

    static Bool pauseMode = FALSE;

    /* サンプル名の表示 */
    /* prints the sample program name */
    njPrintC(NJM_LOCATION(4, 2), "Ninja Sample MATRIX STACK");
    njPrintC(NJM_LOCATION(4, 4), "Press Start Button To Pause");

    /* ペリフェラルチェック */
    /* gets the peripheral information */
    Per = pdGetPeripheral(PDD_PORT_A0);
    if (Per->press & PDD_DGT_ST) { /* スタートボタンが押された */
                                   /* pressing the start button ? */
        pauseMode = !pauseMode;
    }

    /* ポーズ画面を作る */
    /* pause */
    if (pauseMode == TRUE) {
        njLightOff(&Light);
        PauseMode();
    }
    else {
        njLightOn(&Light);
    }

    { /* オブジェクト表示 */
      /* draws objects */
        int grp; /* グループに対するループカウンタ */
                 /* counter of group  */
        int obj; /* 物体に対するループカウンタ */
                 /* counter of object */

        for (grp = 0; grp < GROUP_NUM; grp++) {
            njPushMatrix(NULL);
            /* グループの回転の中心へ */
            /* moves to center of the group */
            njRotateY(NULL, angAll + (Angle)(NJM_DEG_ANG(1.0F) *
                grp * (360.0F / GROUP_NUM)));
            njTranslate(NULL, 0.0F, 0.0F, 10.0F);

            for (obj = 0; obj < OBJECT_NUM; obj++) {
                njPushMatrix(NULL);
                /* 物体の回転の中心へ */
                /* moves to center of the object */
                njRotateY(NULL, Group[grp].ang + (Angle)(NJM_DEG_ANG(1.0F) *
                    obj * (360.0F / OBJECT_NUM)));
                njTranslate(NULL, 0.0F, 0.0F, 4.0F);
                njRotateY(NULL, Object[grp][obj].ang);
                
                /* 物体を表示 */
                /* draws the object */
                njCnkDrawObject(object_cube_root);
                njPopMatrix(1);
            }
            njPopMatrix(1);
        }
    }

    if (pauseMode == FALSE) {
        /* 全体の回転角を更新 */
        /* updates the angle of whole objects */
        angAll += NJM_DEG_ANG(ROTATION_SPEED_ALL);

        {
            int grp; /* グループに対するループカウンタ */
                     /* counter of group  */
            int obj; /* 物体に対するループカウンタ */
                     /* counter of object */
                     
            /* グループの回転角を更新 */
            /* updates the angle of groups */
            for (grp = 0; grp < GROUP_NUM; grp++) {
                RotateState *grpp = &Group[grp];
                grpp->ang += grpp->rsp;
            }
            /* 物体の回転角を更新 */
            /* updates the angle of objects */
            for (grp = 0; grp < GROUP_NUM; grp++) {
                for (obj = 0; obj < OBJECT_NUM; obj++) {
                    RotateState *objp = &Object[grp][obj];
                    objp->ang += objp->rsp;
                }
            }
        }
    }

    return NJD_USER_CONTINUE;
}

/************************************************************
  実行終了時に呼び出される終了処理
  exit
************************************************************/
void njUserExit(void)
{
	njExitPrint();

    /* メモリを解放 */
	/* frees the memory area */
    syFree(Matrix);
    syFree(VBuf);

    /* システムの終了 */
    /* exits the system    */
    sbExitSystem();
}

/************************************************************
  ポーズ時に呼び出される処理
  pause
************************************************************/
void PauseMode(void)
{
    static Sint16 interval = 0;
    static Bool display = TRUE;

    interval++;
    if (interval >= 30) {
        display = !display;
        interval = 0;
    }
    if (display == TRUE) {
        njPrintSize(32);
        njPrintC(NJM_LOCATION(7, 6),"PAUSE!");
        njPrintSize(8);
    }
}
