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.

Graphics > Circular windows

#76868 - gauauu - Sat Mar 25, 2006 4:58 pm

I was looking at the Simonchu 2 game on the 2004mbit compo cart, and was curious about the circular windowing the author used for transitions.

Looking carefully at the effect in vba, it appears that he only uses the win0 window.

So is he using an hblank interrupt to change it every scanline, or is there some other trick with win0 to get circular windowing?

#76869 - tepples - Sat Mar 25, 2006 5:24 pm

Your first instinct was half right. Super Mario World (Super NES and GBA) during key effect, Yoshi's Island (Super NES and GBA) during boss explosion effect, and Simonchu 2 (GBA) probably use hblank triggered DMA (not an interrupt) to rewrite the left and right extents of the window on each scanline.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#76887 - Miked0801 - Sat Mar 25, 2006 9:33 pm

You can also use a sprite as a window template as well.

#76920 - gauauu - Sun Mar 26, 2006 7:45 am

Cool, thanks.

Quote:
You can also use a sprite as a window template as well.


That's actually the solution I've been using in my game. It works great when small, but doesn't do quite as nicely for when the circle gets really big. Scaled sprites pixellate too much, if you don't scale it, then you need to use bunches and bunches of sprites to get the effect.

#76932 - keldon - Sun Mar 26, 2006 12:50 pm

You can use both a background layer and sprites.

#76937 - Cearn - Sun Mar 26, 2006 2:28 pm

Meh, why not ...

A simple demo for a variable size and position windowed circle, using HDMA. You need a 160 entry array to store the horizontal spans of the window in, to be copied to REG_WIN0H by HDMA. win_circle() sets up the array, with all the required boundary checks, using a modified Breshenham circle routine.
x0, y0, rr are the coordinates and radius of the circle; Move with D-pad, and resize the circle with A and B. The HDMA is set for single u16 repeating copy with a fixed destination (REG_WIN0H). Note that I'm starting the source at winh[1] and not winh[0], because the HBlank follows a scanline. The first scanline's window is set manually.

It might be required to disable the HDMA at VBlank, but it seems to run fine if you don't so I'm not exactly sure.

Code:

u16 g_winh[160];

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

   // clear the whole array first.
   memset16(winh, 0, 160);

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

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

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

void test_circle()
{
   int rr=40, x0=120, y0=80;

   m3_fill(CLR_YELLOW);   // full yellow background

   // register inits
   REG_DISPCNT= DCNT_MODE3 | DCNT_BG2_ON | DCNT_WIN0_ON;
   REG_WININ= 0x3F;   // all layers in win 0
   REG_WIN0H= 240;
   REG_WIN0V= 160;

   while(1)
   {
      vid_vsync();
      key_poll();

      rr += key_tri_fire();   // size with B/A
      x0 += key_tri_horz();   // move left/right
      y0 += key_tri_vert();   // move up/down

      if(rr<0)
         rr= 0;

      // fill circle array
      win_circle(x0, y0, rr, g_winh);
   
      // init win-circle HDMA
      DMA_TRANSFER(&REG_WIN0H, &g_winh[1], 1, 3,
         DMA_ON | DMA_REPEAT | DMA_AT_HBLANK | DMA_DST_FIX);
      // set first scanline manually
      REG_WIN0H= g_winh[0];
   }
}

#76977 - gauauu - Mon Mar 27, 2006 2:11 am

wow, very cool. Thanks, Cearn.