/*---------------------------------------------------------------------------*
  Project:  NitroSDK - GX - demos - UnitTours/3D_Shadow_Pol
  File:     main.c

  Copyright 2003,2004 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.6  2004/11/02 08:23:30  takano_makoto
  fix comment.

  Revision 1.5  2004/05/27 09:25:01  takano_makoto
  added Autotest code.

  Revision 1.4  2004/04/07 01:23:27  yada
  fixed header comment

  Revision 1.3  2004/04/06 12:48:06  yada
  fixed header comment

  Revision 1.2  2004/03/15 02:01:34  takano_makoto
  modified comments and codes a little.

  Revision 1.1  2004/03/01 09:09:37  takano_makoto
  initial check-in.

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


//---------------------------------------------------------------------------
// A sample that use shadow polygon.
// 
// This sample displays a sphere and ground.
// On the ground, the sphere's shadow is drawn.
//   
//---------------------------------------------------------------------------


#include <nitro.h>
#include "DEMO.h"
#include "data.h"

//---------------------------------------------------------------------------
//  Overview:
//        V-Blank interrupt process
//  Description:
//        Sets up a flag that confirms that a V-Blank interrupt has been performed.
//
//        Initialize common (DEMOInitCommon()) performs the following:
//        * Select IRQ interrupt (OS_SetIrqMask()).
//        * Register this function that performs IRQ interrupt (OS_SetIRQFunction()).
//        * Enable IRQ interrupt (OS_EnableIrq()).
//        This function is called during V-Blank.
//---------------------------------------------------------------------------
void VBlankIntr(void)
{
    OS_SetIrqCheckFlag(OS_IE_V_BLANK);    // Set a flag to confirm V-Blank interrupt
}

//---------------------------------------------------------------------------
// Overview:
//        Use shadow polygons for shadow display
// Description:
//        1. Use cylinders to create the shadow of a sphere on the ground. At this time prepare 2 identical cylinders.
//        2. Prepare a cylinder for masking. The polygons of this cylinder have shadow polygon,
//            polygon attributes (PolygonAttr). Set to draw only the back side.
//        3. Next, in the same coordinates as above, prepare a cylinder for drawing. The polygons of this cylinder have
//           shadow polygon, polygon attributes (PolygonAttr). Set to draw only the back side.
//           At this time give vertex color to the cylinder used for draw.
//        4. When this cylinder intersects the polygons that are the ground, a shadow will be displayed
//           in the area of intersection of the cylinder and the ground surface.
//           At this time the color of the displayed shadow will be the color of the shadow polygons
//           that are used for drawing.
//---------------------------------------------------------------------------
void NitroMain(void)
{
    u16 Rotate = 0;                     // for rotating sphere (0-65535)

    //---------------------
// Initialize (IRQ enable, VRAM initialize, use BG0 in 3D mode)
    //---------------------
    DEMOInitCommon();
    DEMOInitVRAM();
    DEMOInitDisplay3D();

    G3X_AlphaBlend(TRUE);               // Enable alpha blending

    DEMOStartDisplay();

    //---------------------
    // Main loop
    //---------------------
    while (1) {
        G3X_Reset();
        Rotate += 256;

        /* Camera settings */
        {
            VecFx32 Eye = { 0, 15 * FX32_ONE, -15 * FX32_ONE }; // Eye point position
            VecFx32 at  = { 0, 0, 0 };                          // Viewpoint
            VecFx32 vUp = { 0, FX32_ONE, 0 };                   // Up

            G3_LookAt(&Eye, &vUp, &at, NULL);       // Eye point settings
        }

        /* Light setting (set light color and direction) */
        {
            G3_LightVector(GX_LIGHTID_0, 0, -FX32_ONE + 1, 0);
            G3_LightColor(GX_LIGHTID_0, GX_RGB(31, 31, 31));
        }

        G3_MtxMode(GX_MTXMODE_TEXTURE);   // Set the matrix to Texture mode
        G3_Identity();                    // Initialize the current matrix to a unit matrix
                                 // Set the matrix to Position, Vector simultaneous setting mode
        G3_MtxMode(GX_MTXMODE_POSITION_VECTOR);

        /* Ground drawing settings */
        G3_PushMtx();
                                          // Set material's diffuse reflection color and ambient reflection color
        G3_MaterialColorDiffAmb(GX_RGB(31, 31, 31),// Diffuse reflection color
                                GX_RGB(16, 16, 16),// Ambient reflection color
                                FALSE);            // Do not use vertex color

                                          // Set material's specular reflection color and emitted light color
        G3_MaterialColorSpecEmi(GX_RGB(16, 16, 16),// Specular reflection color
                                GX_RGB(0, 0, 0),   // Emitted light color
                                FALSE);            // Specular reflection not used
                                          // Set texture parameters
        G3_TexImageParam(GX_TEXFMT_NONE,       // Do not use texture
                         GX_TEXGEN_NONE,
                         GX_TEXSIZE_S8,
                         GX_TEXSIZE_T8,
                         GX_TEXREPEAT_NONE,
                         GX_TEXFLIP_NONE,
                         GX_TEXPLTTCOLOR0_USE,
                         0);
                                          // Polygon attribute settings
        G3_PolygonAttr(GX_LIGHTMASK_0,            // Light 0 ON
                       GX_POLYGONMODE_MODULATE,   // Modulation mode
                       GX_CULL_NONE,              // No cull back
                       2,                         // Polygon ID 2
                       31,                        // Alpha value
                       GX_POLYGON_ATTR_MISC_NONE);

        G3_Scale(10 * FX32_ONE, 0, 10 * FX32_ONE);

        G3_Begin(GX_BEGIN_QUADS); // Begin vertex list (draw with quadrilateral polygons)
        G3_Normal(0, 1 << 9, 0);
        G3_Vtx( FX16_ONE, 0,  FX16_ONE);
        G3_Vtx( FX16_ONE, 0, -FX16_ONE);
        G3_Vtx(-FX16_ONE, 0, -FX16_ONE);
        G3_Vtx(-FX16_ONE, 0,  FX16_ONE);
        G3_End();                // End of vertex list

        G3_PopMtx(1);


        G3_PushMtx();
        /* Sphere rotation calculation and position setting */
        {
            fx16 s = FX_SinIdx(Rotate);
            fx16 c = FX_CosIdx(Rotate);

            G3_RotY(s, c);
            G3_Translate(0, 5 * FX32_ONE, -5 * FX32_ONE);
            G3_RotX(s, c);
            G3_RotY(s, c);
            G3_RotZ(s, c);
        }

        /* Sphere draw settings */
                                          // Set material's diffuse reflection color and ambient reflection color
        G3_MaterialColorDiffAmb(GX_RGB(31, 31, 31),// Diffuse reflection color
                                GX_RGB(16, 16, 16),// Ambient reflection color
                                FALSE);            // Do not use vertex color

                                          // Set material's specular reflection color and emitted light color
        G3_MaterialColorSpecEmi(GX_RGB(16, 16, 16),// Specular reflection color
                                GX_RGB(0, 0, 0),   // Emitted light color
                                FALSE);            // Specular reflection not used
                                          // Set texture parameters
        G3_TexImageParam(GX_TEXFMT_NONE,       // Do not use texture
                         GX_TEXGEN_NONE,
                         GX_TEXSIZE_S8,
                         GX_TEXSIZE_T8,
                         GX_TEXREPEAT_NONE,
                         GX_TEXFLIP_NONE,
                         GX_TEXPLTTCOLOR0_USE,
                         0);
                                            // Polygon attribute settings
        G3_PolygonAttr(GX_LIGHTMASK_0,              // Light 0 ON
                       GX_POLYGONMODE_MODULATE,     // Modulation mode
                       GX_CULL_BACK,                // Do cull back
                       1,                           // Polygon ID 1
                       31,                          // Alpha value
                       GX_POLYGON_ATTR_MISC_NONE);

        G3_Begin(GX_BEGIN_TRIANGLES); // Begin vertex list (draw with triangular polygons)
        {
            MI_SendGXCommand(3, sphere1, sphere_size);
        }
        G3_End();                       // End of vertex list

        G3_PopMtx(1);

        /* Position setting for masking shadow polygons */
        G3_PushMtx();
        {
            fx16 s = FX_SinIdx(Rotate);
            fx16 c = FX_CosIdx(Rotate);

            G3_RotY(s, c);
            G3_Translate(0, 0, -5 * FX32_ONE);
        }

        /* Draw settings for masking shadow polygons */
                                          // Set material's diffuse reflection color and ambient reflection color
        G3_MaterialColorDiffAmb(GX_RGB(0, 0, 0),// Diffuse reflection color
                                GX_RGB(0, 0, 0),// Ambient reflection color
                                FALSE);         // Do not use vertex color
                                           // Set material's specular reflection color and emitted light color
        G3_MaterialColorSpecEmi(GX_RGB(0, 0, 0),// Specular reflection color
                                GX_RGB(0, 0, 0),// Emitted light color
                                FALSE);         // Specular reflection not used
                                           // Set texture parameters
        G3_TexImageParam(GX_TEXFMT_NONE,       // Do not use texture
                         GX_TEXGEN_NONE,
                         GX_TEXSIZE_S8,
                         GX_TEXSIZE_T8,
                         GX_TEXREPEAT_NONE,
                         GX_TEXFLIP_NONE,
                         GX_TEXPLTTCOLOR0_USE,
                         0);
                                           // Polygon attribute settings
        G3_PolygonAttr(GX_LIGHTMASK_0,            // Do not reflect light
                       GX_POLYGONMODE_SHADOW,     // Shadow polygon mode
                       GX_CULL_FRONT,             // Do cull front
                       0,                         // Polygon ID 0
                       0x08,                      // Alpha value
                       GX_POLYGON_ATTR_MISC_NONE);

                                // Draw mask (cylinder)
        G3_Begin(GX_BEGIN_TRIANGLES); // Begin vertex list (draw with triangular polygons)
        {
            MI_SendGXCommand(3, cylinder1, cylinder_size);
        }
        G3_End();                     // End of vertex list

        /* Draw setting for the Draw shadow polygons */
                                          // Set material's diffuse reflection color and ambient reflection color
        G3_MaterialColorDiffAmb(GX_RGB(0, 0, 0),// Diffuse reflection color
                                GX_RGB(0, 0, 0),// Ambient reflection color
                                TRUE);          // Use vertex color
                                          // Set material's specular reflection color and emitted light color
        G3_MaterialColorSpecEmi(GX_RGB(0, 0, 0),// Specular reflection color
                                GX_RGB(0, 0, 0),// Emitted light color
                                FALSE);         // Specular reflection not used
                                          // Set texture parameters
        G3_TexImageParam(GX_TEXFMT_NONE,       // Do not use texture
                         GX_TEXGEN_NONE,
                         GX_TEXSIZE_S8,
                         GX_TEXSIZE_T8,
                         GX_TEXREPEAT_NONE,
                         GX_TEXFLIP_NONE,
                         GX_TEXPLTTCOLOR0_USE,
                         0);
                                           // Polygon attribute settings
        G3_PolygonAttr(GX_LIGHTMASK_0,            // Do not reflect light
                       GX_POLYGONMODE_SHADOW,     // Shadow polygon mode
                       GX_CULL_BACK,              // Do cull back
                       1,                         // Polygon ID 1
                       0x08,                      // Alpha value
                       GX_POLYGON_ATTR_MISC_NONE);//

                                // Draw shadow (cylinder)
        G3_Begin(GX_BEGIN_TRIANGLES); // Begin vertex list (use triangular polygons)
        {
            MI_SendGXCommand(3, cylinder1, cylinder_size);
        }
        G3_End();                     // End of vertex list

        G3_PopMtx(1);

        // swapping the polygon list RAM, the vertex RAM, etc.
        G3_SwapBuffers(GX_SORTMODE_MANUAL, GX_BUFFERMODE_W);

        /* V-Blank wait */
        SVC_WaitVBlankIntr();

        #ifdef SDK_AUTOTEST // code for auto test
        GX_SetBankForLCDC( GX_VRAM_LCDC_C );
        EXT_TestSetVRAMForScreenShot( GX_VRAM_LCDC_C );
        EXT_TestScreenShot( 100, 0x38FFDE1A );
        EXT_TestTickCounter();
        #endif //SDK_AUTOTEST
    }
}
