gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > Circular Windows on NDS

#165565 - MaesterRowen - Sat Dec 27, 2008 11:22 pm

Hello everyone.

I have spent a large portion of the day trying to understand and figure out how to make circular windows on the NDS.

I have done some searching on these forums and other resources and have found the discussion on TONCs page, as well as at this http://forum.gbadev.org/viewtopic.php?t=9023

I was wondering if anyone had any example code for the NDS that created circular windows.

I feel if I can understand how the circular window code works, the concept will be there to create any effect I would like.

I almost had a window with a diagonal edge; but I had a problem with it scrolling from the bottom to the top. It was never stationary.

I appreciate the help.

#165567 - MaesterRowen - Sun Dec 28, 2008 2:14 am

Well,

I figured it out ^_^.

Thanks!

#165579 - silent_code - Sun Dec 28, 2008 8:46 pm

Why not share your solution? :^)
_________________
July 5th 08: "Volumetric Shadow Demo" 1.6.0 (final) source released
June 5th 08: "Zombie NDS" WIP released!
It's all on my page, just click WWW below.

#165583 - Dwedit - Mon Dec 29, 2008 2:32 am

Use HDMA to transfer new window boundaries every scanline.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#165586 - MaesterRowen - Mon Dec 29, 2008 4:01 am

For the record books, here is the code to make the circular window on the DS. It can probably be refined and made better, but atleast it works. It's a slight modification of the TONC guide.

Code:
#include <nds.h>
#include <stdio.h>
#include <stdlib.h>

#include "bg01.h"

#define WIN0_BG0 BIT(0)
#define WIN0_BG1 BIT(1)
#define WIN0_BG2 BIT(2)
#define WIN0_BG3 BIT(3)

#define WIN1_BG0 BIT(8)
#define WIN1_BG1 BIT(9)
#define WIN1_BG2 BIT(10)
#define WIN1_BG3 BIT(11)

u16 g_winh[SCREEN_HEIGHT + 1];

#define DMA_HDMA (DMA_ENABLE | DMA_REPEAT | DMA_START_HBL | DMA_DST_RESET)

#define DMA_TRANSFER(_dst, _src, count, ch, mode)   \
do {                                            \
    DMA_CR(ch)= 0;                         \
   DMA_SRC(ch)= (unsigned int)(_src);       \
    DMA_DEST(ch)= (unsigned int)(_dst);             \
    DMA_CR(ch)= (count) | (mode);          \
} while(0)


int getSize(uint8 *source, uint16 *dest, uint32 arg)
{
   return *(uint32*)source;
}

uint8 readByte(uint8 *source)
{
   return *source;
}

void decompressToVRAM(const void* source, void* dest)
{
   TDecompressionStream decStream = {
      getSize,
      NULL,
      readByte};

   swiDecompressLZSSVram((void*)source, dest, 0, &decStream);
}

void win_circle(int x0, int y0, int rr, u16 winh[])
{
   int x=0, y= rr, d= 1-rr;
   u32 tmp;

   for(int i = 0; i < SCREEN_HEIGHT + 1; i++)
   {
      winh[i] = 0;
   }

   while(y >= x)
   {
      // side octs
      tmp= 255;
      if(x0+y<255)
         tmp= x0+y;
      if(x0>y)
         tmp |= (x0-y)<<8;
       
      if(y0>=x)      // o4, o7
         winh[y0-x]= tmp;
      if(y0+x<192)   // o0, o3
         winh[y0+x]= tmp;

      if(d<0)
      {
         d += 2*x+3;
      }
      else   // change in y: top/bottom octs
      {
         tmp= 255;
         if(x0+x<255)
            tmp= x0+x;
         if(x0>x)
            tmp |= (x0-x)<<8;
         
         if(y0>=y)      // o5, o6
            winh[y0-y]= tmp;
         if(y0+y<192)   // o1, o2
            winh[y0+y]= tmp;

         d += 2*(x- --y)+3;
      }
      x++;
   }
}

int main()
{

   vramSetBankA(VRAM_A_MAIN_BG);
   
   REG_BG3CNT = BG_BMP8_256x256 | BG_BMP_BASE(0) | BG_PRIORITY(3);

   REG_BG3PA = 1 << 8;
   REG_BG3PB = 0;
   REG_BG3PC = 0;
   REG_BG3PD = 1 << 8;

   REG_BG3X = 0 << 8;
   REG_BG3Y = 0 << 8;

   dmaCopy(bg01Pal, BG_PALETTE, bg01PalLen);
   decompressToVRAM(bg01Bitmap, BG_BMP_RAM(0));
   
   consoleDemoInit();
   

   WIN1_X0 = 0;
   WIN1_X1 = 0;

   WIN1_Y0 = 0;
   WIN1_Y1 = 0;

   WIN_IN = WIN1_BG3;

   videoSetMode(MODE_5_2D | DISPLAY_BG3_ACTIVE | DISPLAY_WIN1_ON);

   int tickValue = 1;

   int r =  1;
   int pressed = 0;

   // Infinite loop to keep the program running
   while (1)
   {
      scanKeys();

      consoleClear();
         

      if(keysDown() & KEY_A)
      {
         pressed = 1;
         r = 1;
         tickValue = 1;
         WIN1_Y0 = 0;
         WIN1_Y1 = 192;
      }

      if ( pressed == 1)
      {
         if(--tickValue < 0)
         {
            tickValue = 1;
            r = r + 8;
         }

         if(r > 160)
         {
            tickValue = 60;
            r= 161;
            pressed = 2;
         }

         win_circle(128, 96, r, g_winh);
         DMA_TRANSFER(&WIN1_X1, &g_winh, 1, 3, DMA_HDMA);
      }
      else if (pressed == 2)
      {
         videoSetMode(MODE_5_2D | DISPLAY_BG3_ACTIVE);
         pressed = 3;
      }


      swiWaitForVBlank();
   }
   
   return 0;
}

#165618 - MaesterRowen - Tue Dec 30, 2008 7:15 am

Hmm, I tried out this circular window code on the hardware, and it seems to fall victim to the Vblank Window Glitch.

Guess I need to figure out how to compensate for that.