/*---------------------------------------------------------------------------*
  Project:  NITRO-System - build - demos - g3d - samples - DisposeTex
  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.15  02/25/2005 03:09:34  takano_makoto
  Warning measures for signed<->unsigned casts

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

  Revision 1.13  11/09/2004 02:59:21  nishida_kenji
  Add TextureZeroClear.
  Call CollapseResourceMemory.

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

  Revision 1.11  09/10/2004 09:34:43  nishida_kenji
  rename NNS_G3dGlbFlush to NNS_G3dGlbFlushP.

  Revision 1.10  08/31/2004 05:11:40  nishida_kenji
  small fix

  Revision 1.9  08/31/2004 02:09:08  nishida_kenji
  change resource file name.

  Revision 1.8  08/05/2004 00:11:47  nishida_kenji
  time NNS_G3dDraw only.

  Revision 1.7  08/02/2004 05:50:14  nishida_kenji
  add introduction.

  Revision 1.6  07/29/2004 04:08:15  nishida_kenji
  revised

  Revision 1.5  2004/07/26 06:50:33  nakajima_souichi
  (none)

  Revision 1.4  07/23/2004 05:35:37  kitamurs
  Changed things so texture image worth of memory gets returned to heap

  Revision 1.2  2004/07/22 08:54:23  morimun
  Added comment

  Revision 1.1  2004/07/22 06:34:46  morimun
  (none)

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

//---------------------------------------------------------------------------
//
// Sample that destroys the texture/palette region on main memory after the VRAM transfer
//
// When the texture/palette of a model such as for the main character is made to reside in VRAM,
// it is not necessary to maintain the texture/palette of the model in main memory.
// In cases like this, memory can be conserved by freeing the texture/palette memory at the end of a resource file.
//  
//
// Sample Operation
// The CollapseResourceMemory function in the sample gets the texture/palette from NNSG3dResTex
// and returns the region starting from that address back to the heap.
//
// HOWTO
// If tex is used as the pointer to the NNSG3dResTex structure, 
// (u8*)tex + tex->texInfo.ofsTex becomes the starting address to the texture/palette data.
// Memory after this address can be overwritten.
//
//---------------------------------------------------------------------------


#include "g3d_demolib.h"

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

static void InitG3DLib(void);
static NNSG3dResMdl* LoadG3DModel(const char* path);
static void SetCamera(G3DDemoCamera* camera);
static void CollapseResourceMemory(void* memBlock, NNSG3dResTex* texture);
static void TextureZeroClear(NNSG3dResTex* pTex);

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

  Description:  Sample main.
                Zero-clears the texture region with TextureZeroClear.
                Indicates that there will be no problem even if texture region is zero-cleared after RAM transfer.

  Arguments:    None.

  Returns:      None.
   ------------------------------------------------------------------------- */
void
NitroMain(void)
{
    NNSG3dRenderObj object;
    NNSG3dResMdl*   model;

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

    //
    // After initialization where data has been loaded and the texture set in VRAM within LoadG3DModel,
    // memory for the texture data part is cleared to all zeros,
    // and the heap is collapsed to release the texture data part.
    //
    model = LoadG3DModel("data/human_run_t.nsbmd");
    SDK_ASSERTMSG(model, "load failed");

    //
    // 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, "DisposeTex");

    for(;;)
    {
        OSTick time;

        SVC_WaitVBlankIntr();
        G3DDemo_PrintApplyToHW();
        G3DDemo_ReadGamePad();

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

        G3X_Reset();
        G3X_ResetMtxStack();

        SetCamera(&gCamera);

        {
            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 scaling
            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:         LoadG3DModel

  Description:  Reads model data from file.

  Arguments:    path: Model data path name.

  Returns:      Pointer to model.
   ------------------------------------------------------------------------- */
static NNSG3dResMdl*
LoadG3DModel(const char* path)
{
    NNSG3dResMdl* model   = NULL;
    NNSG3dResTex* texture = NULL;
    NNSG3dResFileHeader* resFile = G3DDemo_LoadFile(path);
    BOOL status;

    SDK_NULL_ASSERT(resFile);

    status = NNS_G3dResDefaultSetup(resFile);
    NNS_G3D_ASSERTMSG(status, "NNS_G3dResDefaultSetup failed");

    //
    // Zero-clear the texture data part of the texture block.
    //
    TextureZeroClear(NNS_G3dGetTex(resFile));

    //
    // Collapse the heap and release the texture data part.
    //
    CollapseResourceMemory(resFile, NNS_G3dGetTex(resFile));

    //
    // 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.
    // --------------------------------------------------------------------
    model = NNS_G3dGetMdlByIdx(NNS_G3dGetMdlSet(resFile), 0);
    return model;
}


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


/* -------------------------------------------------------------------------
  Name:         CollapseResourceMemory

  Description:  Collapse memory block by the size of texture image.

                This assumes that only texture image is at the tail-end
                of the memory block.

  Arguments:    memBlock:  The block to be collapsed.
                texture:   Pointer to the texture data.

  Returns:      None.
   ------------------------------------------------------------------------- */
static void
CollapseResourceMemory(void* memBlock, NNSG3dResTex* texture)
{
    u8* texImgStartAddr;
    u32 newSize;

    // Textures/palettes are stored in the order:
    // Non-4x4COMP textures -- 4x4COMP textures -- palettes Thus, the starting address for non-4x4COMP textures is the
    // only address that is needed. An appropriate value is placed
    // in texture->texInfo.ofsTex even if there are non-4x4COMP format texture images.
    SDK_ASSERT(texture->texInfo.ofsTex != 0);
    texImgStartAddr = (u8*)texture + texture->texInfo.ofsTex;

    // Size from start of heap to texture image
    newSize = (u32)(texImgStartAddr - (u8*)memBlock);

    // Memory block collapses.
    // As a result, texture image's worth of memory gets returned  to the heap.
    (void)NNS_FndResizeForMBlockExpHeap(G3DDemo_AppHeap, memBlock, newSize);

}


/*-------------------------------------------------------------------------
    TextureZeroClear

    Zero-clear the texture data part of the texture block.
    Dictionaries and other information remains, so can bind and release.
  ------------------------------------------------------------------------- */
static void
TextureZeroClear(NNSG3dResTex* pTex)
{
    MI_CpuClearFast((u8*)pTex + pTex->texInfo.ofsTex,
                    pTex->header.size - pTex->texInfo.ofsTex);
}

