//////////////////////////////////////////////////////////////////////
// Simple ARM9 demo (touch screen controls the colors)
// -- joat
//////////////////////////////////////////////////////////////////////

#include <NDS/NDS.h>
#include <NDS/memory.h>
#include <NDS/ARM9/rand.h>
#include <NDS/ARM9/video.h>
#include <NDS/ARM9/trig_lut.h>

//////////////////////////////////////////////////////////////////////
void CirclePoints (int x, int y, int value, uint16 *vram);
void MidpointCircle ( int xc, int yc, int radius, int value, uint16 *vram );
void WritePixel(int x, int y , int value, uint16 *vram);
void pltpoint(int x, int y, int c, uint16 *vram);
void circle(int x, int y, int r, int c, uint16 *vram);

volatile unsigned int counter = 0;
void InterruptHandler(void) {

  if (IF & IRQ_VBLANK) {
    counter++;

//    PALETTE[0] = RGB15(IPC->touchX>>7, IPC->touchY>>7, (counter>>4)&0x1F);
//    PALETTE[512] = RGB15(15, IPC->touchZ1>>7, IPC->touchZ2>>7);

    IF = IRQ_VBLANK;
  }
}

//////////////////////////////////////////////////////////////////////

#define KEY_TOUCH (((~IPC->buttons) << 6) & (1<<12))

class drop
{
    public:
        int x;
        int y;
        int c;
        int r;
        int speed;
};

int main(int argc, char ** argv) {
  // Red main screen, blue sub-screen
  PALETTE[0] = RGB15(0, 0, 31);
  PALETTE[512] = RGB15(5, 5, 15);

  // Turn on the screens and 2D cores and switch to mode 0
  POWER_CR = POWER_ALL_2D;
  DISPLAY_CR = MODE_FB0;
  SUB_DISPLAY_CR = MODE_0_2D | DISPLAY_BG0_ACTIVE;
    VRAM_A_CR = VRAM_ENABLE | VRAM_ARM9 | VRAM_CORE_A;
    VRAM_B_CR = VRAM_ENABLE | VRAM_ARM9 | VRAM_CORE_A;

    VRAM_C_CR = VRAM_ENABLE | VRAM_ARM9 | VRAM_CORE_B;
    VRAM_D_CR = VRAM_ENABLE | VRAM_ARM9 | VRAM_CORE_B;

    SUB_BG0_CR = BG_COLOR_256 | (1 << SCREEN_SHIFT);
    SUB_BG1_CR = BG_COLOR_256 | (2 << SCREEN_SHIFT);


    vramSetMainBanks(VRAM_A_LCD,VRAM_B_LCD,VRAM_C_SUB_BG,VRAM_D_SUB_SPRITE);

  // Enable the V-blank interrupt
  IME = 0;
  IRQ_HANDLER = &InterruptHandler;
  IE = IRQ_VBLANK;
  IF = ~0;
  DISP_SR = DISP_VBLANK_IRQ;
  IME = 1;

  int tx=0;
  int ty=0;

  int touched=0;

  drop drops[128];
  for(int i=0; i<128; i++)
  {
      drops[i].r = 0;
  }

  for(int i=0; i<256*192; i++)
  {
      VRAM_C[i] = RGB15(5,5,15);
  }


  // Touchscreen calibration
  int divx = 14;
  int divy = 18;
  int subx = 00;
  int suby = 12;
  uint16* vram = VRAM_A;

  int tx2=0;
  int ty2=0;

  while (1) 
  {
//      swiWaitForVBlank();
//      counter++;
      if(counter > 0)
      {
          counter = 0;
          
          if(KEY_TOUCH)
          {
              if(0 == 0)
              {
                  tx2 = tx;
                  ty2 = ty;
                  touched = 1;
                  tx = IPC->touchX / divx - subx;
                  ty = IPC->touchY / divy - suby;

                  if(tx2 != tx || ty2 != ty)
                  {
                      int n=-1;
                      
                      for(int i=0; i<128; i++)
                      {
                          if(drops[i].r <= 0)
                          {
                              n=i;
                              break;
                          }
                      }
                      if(n != -1)
                      {
                          drops[n].x = tx;
                          drops[n].y = ty;
                          drops[n].r = 10;
                          drops[n].speed = 8 + rand()%5;
                          drops[n].c = rand()%8;
                      }
                  }
                      
              }
          }
          else
              touched = 0;
          
          dmaCopyWords(3, (uint32 *)VRAM_C, (uint32 *)vram, 256*192*2);
/*          for(int i=0; i<256*192; i++)
          {
              vram[i] = 0;
          }*/

          for(int n=0; n<128; n++)
          {
              if(drops[n].r > 0)
              {
                  vram[n*2] = RGB15(0,0,31);
                  vram[n*2 + 1] = RGB15(0,0,31);
//                  vram[512 + n] = RGB15(0,0,31);
                  drops[n].r+=drops[n].speed;

                  int x = drops[n].x;
                  int y = drops[n].y;
                  int r = drops[n].r;
                  int c = drops[n].c;
  
                  circle(x,y,r/16,         RGB15(c+15-(r/64), c+15-r/64, 31-r/64), vram);        
/*
                  for(int i = 0; i<r; i++)
                  {
                      vram[(y-r/2)*256 + x + i - r/2] = RGB15(31-r/4, 31-r/4, 31-r/4);
                      vram[(y+r/2)*256 + x + i - r/2] = RGB15(31-r/4, 31-r/4, 31-r/4);

                      vram[(y-r/2 + i)*256 + x - r/2] = RGB15(31-r/4, 31-r/4, 31-r/4);
                      vram[(y-r/2 + i)*256 + x + r/2] = RGB15(31-r/4, 31-r/4, 31-r/4);
                  }*/


                  if(drops[n].r >= (63*16))
                  {
                      drops[n].r = -1;
                  }
              }
          }
          
          if(vram == VRAM_A)
          {
              videoSetMode(MODE_FB0);
              vram = VRAM_B;
          }
          else
          {
              videoSetMode(MODE_FB1);
              vram = VRAM_A;
          }
          
      }
      
      
      
      
      
  }
  return 0;
}

void circle(int x, int y, int r, int c, uint16 *vram)
{
    for(int a=0; a<512; a+=4)
    {
            pltpoint(x+((COS[a]*r)>>12),y+((SIN[a]*r)>>12),c,vram);
    }
}

inline void pltpoint(int x, int y, int c, uint16 *vram)
{
    int n = y*256+x;
    if(n > 256*192 || n<0)
        return;
//    if(y >= 192 || y < 0 || x >= 256 || x < 0)
  //      return;
    vram[y*256 + x] = c;
}

/*
void MidpointCircle ( int xc, int yc, int radius, int value, uint16 *vram )
{                   
   int     x, y, d, deltaE, deltaSE;

   x       = 0;
   y       = radius;
   d       = 1 - radius;
   deltaE  = 3;
   deltaSE = 5 - radius * 2;

   CirclePoints ( x+xc, y+yc, value,vram );
   
   while ( y > x ) {
      if ( d < 0 ) { // Select E /
         d       += deltaE;
	 deltaE  += 2;
	 deltaSE += 2;
	 x       ++;
      } 
      else {         // Select SE 
         d       += deltaSE;
	 deltaE  += 2;
	 deltaSE += 4;
	 x       ++;
	 y       ++;
      }
      CirclePoints ( x+xc, y+yc, value,vram );
   }
}


void MidpointCircle ( int x1, int y1, int radius, int value, uint16 *vram )
{
   int   x, y;
   int d;

   x = 0;
   y = radius;
   d = 1 - radius;
   CirclePoints ( x+x1, y+y1, value, vram );
   
   while ( y > x ) {
      if ( d < 0 ) {
         d += x * 2 + 3;
	 x ++;
      }
      else {
         d += (x - y) * 2 + 5;
	 x ++;
	 y --;
      }
      CirclePoints ( x+x1, y+y1, value, vram );
   }
}
   
void CirclePoints (int x, int y, int value, uint16 *vram)
{
   WritePixel ( x, y, value ,vram);
   WritePixel ( y, x, value ,vram);
   WritePixel ( y, x, value ,vram);
   WritePixel ( x, y, value ,vram);
   WritePixel ( x, y, value ,vram);
   WritePixel ( y, x, value ,vram);
   WritePixel ( y, x, value ,vram);
   WritePixel ( x, y, value ,vram);
}

void WritePixel(int x, int y , int value, uint16 *vram)
{
    if(y >= 192 || y < 0 || x >= 256 || x < 0)
        return;
    vram[y*256 + y] = value;
}
   */ 


//////////////////////////////////////////////////////////////////////
