/*---------------------------------------------------------------------------*
  Project:  NitroSDK - GX - demos - UnitTours/2D_CharBg_Direct
  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.7  2004/11/02 09:59:24  takano_makoto
  fix typo.

  Revision 1.6  2004/07/29 02:18:23  yasu
  Let a picture exchangeable

  Revision 1.5  2004/05/27 09:20:44  takano_makoto
  Add Autotest code.

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

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

  Revision 1.2  2004/03/23 07:08:00  takano_makoto
  Change GX_LoadBGXScr to GX_LoadBGXBmp.

  Revision 1.1  2004/03/01 08:59:52  takano_makoto
  Initial check in.

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

//---------------------------------------------------------------------------
// A sample that use direct color BITMAP BG:
// 
// This sample display picture on the display by direct color BITMAP BG.
// 
// USAGE:
//   UP, DOWN, LEFT, RIGHT      : Slide the BG
//   A, B                       : Scaling the BG
//   L, R                       : Rotate the BG
//   SELECT + [UP, DOWN, LEFT, RIGHT] : Change the center position of rotation
//   SELECT                     : Switch ON/OFF that set BG area over mode, 
//                                loop or transparent.
//   
// HOWTO:
// 1. Transfer the bitmap data by GX_LoadBGxScr().
// 2. Set the direct color BG mode by G2_SetBGxControlDCBmp().
//---------------------------------------------------------------------------


#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);    // Sets flag to confirm V-Blank interrupt
}

//---------------------------------------------------------------------------
//  Overview:
//        Display affine extended direct color bit map BG.
//  Description:
//        Affine converts (rotate, enlarge, reduce) 256 color direct color bitmap BG, and displays it.
//
//
//        1. With BGMODE number 3, use BG surface 3.
//        2. Use G2_SetBG3ControlDCBmp() to set up, and transfer character data to the specified location.
//        3. Transfer screen data to the specified location.
//  Operation:
//       PLUS_KEY         : BG surface offset manipulation.
//       SELECT + PLUS_KEY: Manipulate center position for rotate, enlarge reduce.
//       BUTTON_A,B       : Enlarge, reduce.
//       BUTTON_L,R       : Rotate
//       SELECT           : Area over process switch
//       START            : Initialize settings.
//---------------------------------------------------------------------------
void NitroMain(void)
{
    int trg = 0;
    int offset_H = 0;
    int offset_V = 30;
    fx32 scale = FX32_ONE;
    s16 x_0 = 0, y_0 = 0;
    s16 x_1 = 0, y_1 = 0;
    u16 rotate = 0;

    //---------------------
    // Initialize
    //---------------------
    DEMOInitCommon();
    DEMOInitVRAM();

    /* Set up BG */
    GX_SetBankForBG(GX_VRAM_BG_256_AB);       // Allocate VRAM-A, B banks to BG

    GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS,    // 2D/3D mode
                       GX_BGMODE_3,             // BGMODE 3
                       GX_BG0_AS_2D);           // 2D display to BG0

    GX_SetBGScrOffset(GX_BGSCROFFSET_0x00000);  // Set screen offset value
    GX_SetBGCharOffset(GX_BGCHAROFFSET_0x10000);// Set character offset

    GX_SetVisiblePlane(GX_PLANEMASK_BG3);       // Select BG3 for display
    G2_SetBG3Priority(0);                       // Set BG3 priority to top
    G2_BG3Mosaic(FALSE);                        // Do not apply mosaic to BG3

    /* Transfer bitmap data to BG3. */
    GX_LoadBG3Bmp(bitmapBG_directcolor_Texel, 0, SCREEN_SIZE);

    DEMOStartDisplay();

    //---------------------
    //  Main loop
    //---------------------
    while (1) {
        MtxFx22 mtx;

        /* Reading and manipulating pad information */
        DEMOReadKey();
        
        #ifdef SDK_AUTOTEST    // code for auto test
        {
            const EXTKeys keys[8] = {{PAD_BUTTON_A,10}, {PAD_BUTTON_L,10}, {PAD_KEY_UP | PAD_KEY_RIGHT, 20}};
            EXT_AutoKeys( keys, &gKeyWork.press, &gKeyWork.trigger);
        }
        #endif

        if (DEMO_IS_PRESS(PAD_BUTTON_SELECT)) {
            if (DEMO_IS_PRESS(PAD_KEY_UP))      y_0 -= 2;
            if (DEMO_IS_PRESS(PAD_KEY_DOWN))    y_0 += 2;
            if (DEMO_IS_PRESS(PAD_KEY_RIGHT))   x_0 += 2;
            if (DEMO_IS_PRESS(PAD_KEY_LEFT))    x_0 -= 2;
        } else {
            if (DEMO_IS_PRESS(PAD_KEY_UP))      offset_V += 2;
            if (DEMO_IS_PRESS(PAD_KEY_DOWN))    offset_V -= 2;
            if (DEMO_IS_PRESS(PAD_KEY_RIGHT))   offset_H -= 2;
            if (DEMO_IS_PRESS(PAD_KEY_LEFT))    offset_H += 2;
        }
        if (DEMO_IS_PRESS(PAD_BUTTON_A))        scale += 2 << (FX32_SHIFT - 8);
        if (DEMO_IS_PRESS(PAD_BUTTON_B))        scale -= 2 << (FX32_SHIFT - 8);
        if (DEMO_IS_PRESS(PAD_BUTTON_L))        rotate -= 256;
        if (DEMO_IS_PRESS(PAD_BUTTON_R))        rotate += 256;
        if (DEMO_IS_TRIG(PAD_BUTTON_SELECT)) {
            trg = (trg + 1) & 0x01;
            OS_Printf("area_over=%d\n", trg);
        }

        if (DEMO_IS_TRIG(PAD_BUTTON_START)) {
            offset_H = 0;
            offset_V = 0;
            x_0 = 32;
            y_0 = 32;
            scale = 1 << FX32_SHIFT;
            rotate = 0;
        }

        /* Set screen size 256x256 dots, BG3 to direct color bitmap */
        {
            GXBGAreaOver area_over = (trg ?
                                      GX_BG_AREAOVER_REPEAT
                                      : GX_BG_AREAOVER_XLU);

            // Set BG3 to direct color bitmap BG
            //   Screen size              : Screen size 256 x 256 dots
            //   Area over process      : Determine with area_over
            //   Screen base block: 0x00000
            G2_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256,
                                  area_over,            
                                  GX_BG_BMPSCRBASE_0x00000);
        }

        /* Generate affine conversion matrix */
        {
            fx16 sinVal = FX_SinIdx(rotate);
            fx16 cosVal = FX_CosIdx(rotate);
            fx32 rScale = FX_Inv(scale);
        
            mtx._00 =  (fx32)((cosVal * rScale) >> FX32_SHIFT);
            mtx._01 =  (fx32)((sinVal * rScale) >> FX32_SHIFT);
            mtx._10 = -(fx32)((sinVal * rScale) >> FX32_SHIFT);
            mtx._11 =  (fx32)((cosVal * rScale) >> FX32_SHIFT);
        }
        
        #ifdef SDK_AUTOTEST // code for auto test
        GX_SetBankForLCDC( GX_VRAM_LCDC_C );
        EXT_TestSetVRAMForScreenShot( GX_VRAM_LCDC_C );
        EXT_TestScreenShot( 100, 0x54831E5C );
        EXT_TestTickCounter();
        #endif //SDK_AUTOTEST

        /* VBlank wait */
        SVC_WaitVBlankIntr();

        /* Set affine conversion to apply to BG3 plane */
        G2_SetBG3Affine(&mtx,     // Conversion matrix
                        x_0,      // Rotate center point (X) coordinate
                        y_0,      // Rotate center point (Y) coordinate
                        offset_H, // Coordinate before rotation (X)
                        offset_V);// Coordinate before rotation (Y)
    }
}
