/*---------------------------------------------------------------------------*
  Project:	NITRO-System - build - demos - g3d - samples - TexPatternAnm
  File:     main.c

  Copyright 2004,2005 Nintendo.  All rights reserved.

  These coded instructions, statements, and computer programs contain
  proprietary information of Nintendo of America Inc. and/or Nintendo
  Company Ltd., and are protected by Federal copyright law.  They may
  not be disclosed to third parties or copied or duplicated in any form,
  in whole or in part, without the prior written consent of Nintendo.

  $Log: main.c,v $
  Revision 1.13  02/25/2005 03:11:46  takano_makoto
  Warning measures for signed<->unsigned casts

  Revision 1.12  11/12/2004 05:40:32  nishida
  Revised project name of file header.

  Revision 1.11  11/04/2004 10:43:25  nishida
  Fixed function header of SetCamera function.

  Revision 1.10  09/10/2004 09:55:52  nishida_kenji
  rename NNS_G3dGlbFlush to NNS_G3dGlbFlushP.

  Revision 1.9  08/05/2004 00:12:25  nishida_kenji
  time NNS_G3dDraw only.

  Revision 1.8  08/03/2004 05:27:56  nishida_kenji
  fix comments.

  Revision 1.7  08/03/2004 04:48:09  nishida_kenji
  Use NNS_G3dAnmObjGetNumFrame for simplicity.

  Revision 1.6  08/03/2004 02:21:35  nishida_kenji
  Use NNS_G3dGetAnmByIdx for simplicity.

  Revision 1.5  08/02/2004 12:40:39  nishida_kenji
  add introduction.

  Revision 1.4  07/29/2004 05:07:48  nishida_kenji
  revised

  Revision 1.3  2004/07/26 06:50:29  nakajima_souichi
  (none)

  Revision 1.2  07/26/2004 06:34:08  kitani_toshikazu
  Changed the data used.

  Revision 1.1  07/23/2004 04:36:52  kitani_toshikazu
  Animation-related addition.

  Revision 1.3  07/22/2004 10:49:24  kitani_toshikazu
  Added comment

  Revision 1.2  07/22/2004 09:17:45  kitani_toshikazu
  Renamed NNS_G3dGetTexPatAnm() to NNS_G3dGetTexPatAnmByIdx()

  Revision 1.1  07/22/2004 07:23:58  kitani_toshikazu
  Registration of the initial version

  $NoKeywords: $
 *---------------------------------------------------------------------------*/

//---------------------------------------------------------------------------
//
// Sample of playing texture pattern animation
//
// To play back a texture pattern animation, use a .nsbtp file converted from an .itp file using g3dcvtr.
//     
//
// Sample Operation
// The texture pattern animation is played repeatedly.
//
// HOWTO:
// 1: Load the .nsbtp into main memory.
// 2: Using functions such as NNS_G3dGetAnmByIdx and NNS_G3dGetAnmByName,
//    the pointer to the texture pattern animation you wish to play.
// 3: Use NNS_G3dAllocAnmObj and get the region for NNSG3dAnmObj.
//    When freeing, use NNS_G3dFreeAnmObj.
// 4: Use NNS_G3dAnmObjInit and initialize the acquired region.
// 5: Use NNS_G3dRenderObjAddAnmObj and associate with NNSG3dRenderObj.
//    You cannot associate with multiple NNSG3dRenderObj. In such cases,
//    you must secure separate NNSG3dAnmObj. (The data in the .nsbtp file
//    can be shared.)
//
//---------------------------------------------------------------------------

#include "g3d_demolib.h"

G3DDemoCamera gCamera;        // Camera structure.
G3DDemoGround gGround;        // Ground structure.

static void                InitG3DLib(void);
static BOOL 
LoadG3DModel(const char*            path,
             NNSG3dResMdl**         ppModel,
             NNSG3dResFileHeader**  ppResFile);

static void SetCamera(G3DDemoCamera* camera);


/* -------------------------------------------------------------------------
  Name:         NitroMain

  Description:  Sample main.

  Arguments:    None.

  Returns:      None.
   ------------------------------------------------------------------------- */
void
NitroMain(void)
{
    NNSG3dRenderObj      object;
    NNSG3dResMdl*        pModel;
    NNSG3dResTex*        pTexture;
    NNSG3dResFileHeader* fileHeader;
    BOOL                 bResult;
    void*                pAnmRes;
    NNSFndAllocator      allocator;
    NNSG3dAnmObj*        pAnmObj;

    G3DDemo_InitSystem();
    G3DDemo_InitMemory();
    G3DDemo_InitVRAM();

    InitG3DLib();
    G3DDemo_InitDisplay();

    //
    // create allocator with 4-byte alignment
    //
    NNS_FndInitAllocatorForExpHeap(&allocator, G3DDemo_AppHeap, 4);
    
    // Makes the manager able to manage 4 slots of texture image slots,
    // and sets to the default manager.
    NNS_GfdInitFrmTexVramManager(4, TRUE);

    // Makes the manager able to manage 32 KB of palettes,
    // and sets to the default manager.
    NNS_GfdInitFrmPlttVramManager(0x8000, TRUE);

    bResult = LoadG3DModel("data/itp_sample.nsbmd", &pModel, &fileHeader );
    SDK_ASSERTMSG( bResult, "load failed");
    
    //
    // Get texture data.
    //
    pTexture = NNS_G3dGetTex(fileHeader);
    
    //
    // G3D: NNSG3dRenderObj initialization
    //
    // NNSG3dRenderObj is a structure that holds every type of information relating to one model and
    // animation applied to that model.
    // The area specified by the internal member pointer must be obtained and released by the user.
    // Here mdl can be NULL. (It must be set during NNS_G3dDraw.)
    //
    NNS_G3dRenderObjInit(&object, pModel);
    
    //
    // Read texture pattern/animation and associate.
    //
    {
        //
        // read file
        //
        const u8* pFile = G3DDemo_LoadFile("data/itp_sample.nsbtp");
        SDK_ASSERTMSG( pFile, "anm load failed" );
        {
            // initialize animation, add to rendering object
            // 
            // Allocate and initialize the animation object (NNSG3dAnmObj) that goes between
            // the loaded animation file and NNSG3dRenderObj.
            // All animation is set up with the same code.
            //

            //
            // Allocates from the allocator the memory necessary for the animation object.
            // You must specify and allocate model resources and animation resources.
            //

            // specify index #0 animation
            pAnmRes = NNS_G3dGetAnmByIdx(pFile, 0);
            SDK_NULL_ASSERT(pAnmRes);

            // Allocates the necessary amount of memory. Initialize must be separate.
            pAnmObj = NNS_G3dAllocAnmObj(&allocator, // specify the allocator to use
                                         pAnmRes,    // specify animation resource
                                         pModel);    // specify model resource
            SDK_NULL_ASSERT(pAnmObj);

            //
            // Initialize AnmObj.
            //
            NNS_G3dAnmObjInit(pAnmObj,    // pointer to animation object
                              pAnmRes,    // pointer to animation resource
                              pModel,     // pointer to NNSG3dResMdl
                              pTexture ); // pointer to NNSG3dResTex (NULL is OK except for texture pattern animation)

            //
            // Add AnmObj to RenderObj.
            //
            NNS_G3dRenderObjAddAnmObj( &object, pAnmObj );
        }
    }

    //
    // demo common initialization
    //
    G3DDemo_InitCamera(&gCamera, 5*FX32_ONE, 16*FX32_ONE);
    G3DDemo_InitGround(&gGround, (fx32)(1.5*FX32_ONE));

	G3DDemo_InitConsole();
	G3DDemo_Print(0,0, G3DDEMO_COLOR_YELLOW, "TEX PATTERN ANM");

    for(;;)
    {
        OSTick time;

        SVC_WaitVBlankIntr();

        G3DDemo_PrintApplyToHW();
        G3DDemo_ReadGamePad();

        G3DDemo_MoveCamera(&gCamera);
        G3DDemo_CalcCamera(&gCamera);

        G3X_Reset();
        G3X_ResetMtxStack();

        SetCamera(&gCamera);

        // Update animation frame.
        pAnmObj->frame += FX32_ONE;
        if( pAnmObj->frame >= NNS_G3dAnmObjGetNumFrame(pAnmObj))
        {
            pAnmObj->frame = 0;
        }

        {
            // adjust position and size
            VecFx32 scale = {FX32_ONE << 1, FX32_ONE << 1, FX32_ONE << 1};
            VecFx32 trans = {0, FX32_ONE * 5, 0};
            NNS_G3dGlbSetBaseScale(&scale);
            NNS_G3dGlbSetBaseTrans(&trans);

            //
            // G3D:
            // Collects and transfers the state set with G3dGlbXXXX.
            // Camera and projection matrix, and the like, are set.
            //
            NNS_G3dGlbFlushP();

            //  Start time measurement
            time = OS_GetTick();
            {
                //
                // G3D: NNS_G3dDraw
                // Performs drawing for all instances by passing the
                // NNSG3dRenderObj that was set up.
                //
                NNS_G3dDraw(&object);
            }
            // Time measurement result
            time = OS_GetTick() - time;
        }

        {
            // restore scale and trans (for drawing ground mesh)
            VecFx32 scale = {FX32_ONE, FX32_ONE, FX32_ONE};
            VecFx32 trans = {0, 0, 0};
            NNS_G3dGlbSetBaseScale(&scale);
            NNS_G3dGlbSetBaseTrans(&trans);

            //
            // G3D: Before calling normal G3_XXX, NNS_G3dGeComFlushBuffer()
            //      must be called and synchronized
            //
            NNS_G3dGlbFlushP();
            NNS_G3dGeFlushBuffer();
            G3DDemo_DrawGround(&gGround);
        }

        /* memory swap relating to geometry and rendering engine*/
        G3_SwapBuffers(GX_SORTMODE_AUTO, GX_BUFFERMODE_W);

        G3DDemo_Printf(16,0, G3DDEMO_COLOR_YELLOW, "TIME:%06d usec", OS_TicksToMicroSeconds(time));
    }
}


/* -------------------------------------------------------------------------
  Name:         InitG3DLib

  Description:  Initializes G3D library.

  Arguments:    None.

  Returns:      None.
   ------------------------------------------------------------------------- */
static void
InitG3DLib(void)
{
    //
    // G3D:
    // performs default initialization
    // ------------------------------------------------------------------------
    NNS_G3dInit();
}


/* -------------------------------------------------------------------------
  Name:         LoadG3DModel

  Description:  Reads model data from file.

  Arguments:    path:       Model data path name.
                ppModel:    pointer to model
                ppResFile: pointer to load data file
                
  Returns:      success/failure of read
   ------------------------------------------------------------------------- */
static BOOL 
LoadG3DModel(const char* path, NNSG3dResMdl** ppModel, NNSG3dResFileHeader** ppResFile )
{
    *ppResFile = G3DDemo_LoadFile(path);

    if(*ppResFile != NULL)
    {
        // when calling the default initialization function and setting up
        BOOL    status;
        status = NNS_G3dResDefaultSetup(*ppResFile);
        NNS_G3D_ASSERTMSG(status, "NNS_G3dResDefaultSetup failed");

        //
        // G3D: get model
        // nsbmd can include multiple models, so sets the index (0 when there is one model)
        // and gets the pointer to the one model.
        // --------------------------------------------------------------------
        *ppModel = NNS_G3dGetMdlByIdx(NNS_G3dGetMdlSet(*ppResFile), 0);
        
        return TRUE;
    }

    return FALSE;
}


/* -------------------------------------------------------------------------
  Name:         SetCamera

  Description:  Sets camera matrix and projection matrix in G3D global state.

  Arguments:    camera:		pointer to the G3DDemoCamera structure

  Returns:      None.
   ------------------------------------------------------------------------- */
static void
SetCamera(G3DDemoCamera* camera)
{
    G3DDemoLookAt* lookat = &camera->lookat;
    G3DDemoPersp*  persp  = &camera->persp;

    NNS_G3dGlbPerspective(persp->fovySin, persp->fovyCos, persp->aspect, persp->nearClip, persp->farClip);
    NNS_G3dGlbLookAt(&lookat->camPos, &lookat->camUp, &lookat->target);
}

