/*---------------------------------------------------------------------------*
  Project:	NITRO-System - build - demos - g3d - samples - SeparateTex
  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.9  02/25/2005 03:11:17  takano_makoto
  Warning measures for signed<->unsigned casts

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

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

  Revision 1.6  09/10/2004 09:53:50  nishida_kenji
  rename NNS_G3dGlbFlush to NNS_G3dGlbFlushP.

  Revision 1.5  08/05/2004 00:12:19  nishida_kenji
  time NNS_G3dDraw only.

  Revision 1.4  08/02/2004 11:43:08  nishida_kenji
  add introduction.

  Revision 1.3  07/28/2004 08:15:45  nishida_kenji
  revised

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

//---------------------------------------------------------------------------
//
// Sample of binding and displaying models and textures stored in different files
// 
// It is possible to separate model resource and texture resource when converting.
// In such cases, model and texture cannot be bound with NNS_G3dResDefaultSetup
// so the user must do so explicitly.
//
// Sample Operation
// human_run_t.nsbmd is a .nsbmd file that does not have a texture block created
// with the g3dcvtr -emdl option. Also, human_run_t.nsbtx is a .nsbtx file with only
// texture block created with the -etex option. Bind and display when executing
// the above two separate files.
//
// HOWTO:
// - Use NNS_G3dBindMdlSet and bind model resource set and texture resource.
//   (When you apply sample NNS_G3dResDefaultSetup to the .nsbtx file, the texture
//    is loaded in VRAM.)
// - When you use NNS_G3dBindMdlTex, you can bind individual model resources
//   to texture resources.
//
//---------------------------------------------------------------------------

#include "g3d_demolib.h"

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

static void          InitG3DLib(void);
static NNSG3dResMdl* LoadG3DModel(const char* mdlPath,const char* texPath);
static void          SetCamera(G3DDemoCamera* camera);


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

  Description:  Sample main.

  Arguments:    None.

  Returns:      None.
   ------------------------------------------------------------------------- */
void
NitroMain(void)
{
    NNSG3dRenderObj object;
    NNSG3dResMdl*   model;
    NNSG3dResTex*   tex;
    NNSG3dResFileHeader* resNsbmd;
    NNSG3dResFileHeader* resNsbtx;

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

    InitG3DLib();
    G3DDemo_InitDisplay();

    // 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);

    {
        //
        // Bind model and texture that are in different resource files.
        //

        // read .nsbmd file and .nsbtx file
        resNsbmd = G3DDemo_LoadFile("data/human_run_t.nsbmd");
        SDK_ASSERTMSG(resNsbmd, "load failed");
        (void)NNS_G3dResDefaultSetup(resNsbmd);

        resNsbtx = G3DDemo_LoadFile("data/human_run_t.nsbtx");
        SDK_ASSERTMSG(resNsbtx, "load failed");
        (void)NNS_G3dResDefaultSetup(resNsbtx); // Texture is loaded in VRAM inside this.

        // get first model in model set
        model = NNS_G3dGetMdlByIdx(NNS_G3dGetMdlSet(resNsbmd), 0);
        SDK_NULL_ASSERT(model);

        // get .nsbtx texture block
        tex = NNS_G3dGetTex(resNsbtx);
        SDK_NULL_ASSERT(tex);

        // Bind the model in resNsbmd and texture/palette in resNsbtx.
        // Commenting out this matrix makes the texture of the pants the unstuck image.
        (void)NNS_G3dBindMdlSet(NNS_G3dGetMdlSet(resNsbmd), tex);
    }
    
    //
    // 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, model);

    G3DDemo_InitCamera(&gCamera, 10*FX32_ONE, 16*FX32_ONE);
    G3DDemo_InitGround(&gGround, (fx32)(1.5*FX32_ONE));

    G3DDemo_InitConsole();
    G3DDemo_Print(0,0, G3DDEMO_COLOR_YELLOW, "SeparateTex");

    for(;;)
    {
        OSTick time;

        SVC_WaitVBlankIntr();
        G3DDemo_PrintApplyToHW();
        G3DDemo_ReadGamePad();
        
        G3DDemo_MoveCamera(&gCamera);
        G3DDemo_CalcCamera(&gCamera);

        G3X_Reset();
        G3X_ResetMtxStack();

        SetCamera(&gCamera);

        {
            //
            // apply scaling to display object
            //
            VecFx32 scale = {FX32_ONE >> 2, FX32_ONE >> 2, FX32_ONE >> 2};
            NNS_G3dGlbSetBaseScale(&scale);

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

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

        {
            // restore scale for drawing ground
            VecFx32 scale = {FX32_ONE, FX32_ONE, FX32_ONE};
            NNS_G3dGlbSetBaseScale(&scale);
        }
        
        //
        // 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:         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);
}

