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 > Fast drawing

#139757 - Blue Frenzy - Sun Sep 09, 2007 10:00 pm

I need a function to make circles on screen, but it seems there is no one in PALib or libnds. So i decided to apply a code to generate my own circle. The problem is that the console is going to slow down a lot since i have to erase screen each frame and draw a lot of circles.

So I would like to know how i can i make it draw in a faster way, like hardware drawing or else.

I am not used to program on this level, so, any help to build code will be welcome.

#139759 - tepples - Sun Sep 09, 2007 10:19 pm

What kind of code did you use to generate your own circle? Did you use the sin/cos() per angle method, the sin/cos() lookup per angle method, the sqrt() per row method, or the Bresenham method?

Are these circles all the same size? Are they filled, or are they hollow?
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#139761 - Blue Frenzy - Sun Sep 09, 2007 11:28 pm

bresenham, diferent sized circles

#139794 - a128 - Mon Sep 10, 2007 7:59 am

This is the fastest circle algo i know....code from the 1980 found somewhere in a book

Code:


void Circle (const Point p, int radius)
{


    int x, y, re;
    int dx=p.X;
    int dy=p.Y;
    x = radius;
    y = 0;
    re = x << 1;         //div 2

    while (x >= y)
    {

        SetPixelClip (dx + y, dy + x); //for a SOLID circle draw a line from, here
        SetPixelClip (dx - y, dy + x); //to here

        SetPixelClip (dx + x, dy + y);
        SetPixelClip (dx - x, dy + y);

        SetPixelClip (dx + x, dy - y);
        SetPixelClip (dx - x, dy - y);

        SetPixelClip (dx + y, dy - x);
        SetPixelClip (dx - y, dy - x);

        re = re - y;
        y++;

        if (re < 0)
        {
            re += x;
            x--;
        }

    }

}

#139804 - Blue Frenzy - Mon Sep 10, 2007 11:21 am

thank you.
And to draw a line with thickness from where should i draw a line, inf it is not too much to ask?

#139814 - a128 - Mon Sep 10, 2007 1:19 pm

Blue Frenzy wrote:
thank you.
And to draw a line with thickness from where should i draw a line,


hmm?? just draw circle with different radius.?

#139815 - nornagon - Mon Sep 10, 2007 1:29 pm

Here is the (rather long) code from World of Sand used for drawing thick lines. Note that it doesn't deal with the endpoints, so you have to cover those yourself with circles. Width is in 16:16 fixed point. You'll probably need to adapt it a bit to fit your code, as it's somewhat WoS-specific.

Code:
// x,y values are all 32:0, width is 16:16
void bresenThick(u8* buf, int x1, int y1, int x2, int y2, u8 val, int width) {
  int dx, dy,  x2_, y2_;
  dx = x2 - x1;
  dy = y2 - y1;

  if (dx == 0 && dy == 0) { buf[y1*256+x1] = val; return; }

  if (abs(dx) > abs(dy)) { // step along X axis
    if (dx < 0) { // swap!
      x1 ^= x2; x2 ^= x1; x1 ^= x2;
      y1 ^= y2; y2 ^= y1; y1 ^= y2;
      dx = -dx; dy = -dy;
    }
    y1 = (y1 << 16) - (width>>1) + 0x8000;
    dy = (dy<<16)/dx;
    y1 += dy>>1;
    if (x1 < 0) { y1 += dy * -x1; x1 = 0; }
    if (x2 > 255) x2 = 255;
    for (dx = x1; dx <= x2; dx++) {
      y2 = (y1 >> 16);
      if (y2 < 0) y2 = 0; // clip
      y2_ = (y1+width) >> 16;
      if (y2_ > 192) y2_ = 192;

      for (; y2 < y2_; y2++)
        buf[y2*256+dx] = val;
      y1 += dy;
    }

  } else { // step along Y axis
    if (dy < 0) { // swap!
      x1 ^= x2; x2 ^= x1; x1 ^= x2;
      y1 ^= y2; y2 ^= y1; y1 ^= y2;
      dx = -dx; dy = -dy;
    }
    x1 = (x1 << 16) - (width>>1) + 0x8000;
    dx = (dx<<16)/dy;
    x1 += dx>>1;
    if (y1 < 0) { x1 += dx * -y1; y1 = 0; }
    if (y2 > 191) y2 = 191;
    for (dy = y1; dy <= y2; dy++) {
      x2 = (x1>>16);
      if (x2 < 0) x2 = 0; // clip
      x2_ = (x1+width) >> 16;
      if (x2_ > 255) x2_ = 255;

      for (; x2 < x2_; x2++)
        buf[dy*256+x2] = val;
      x1 += dx;
    }
  }
}


Good luck!

#139835 - DragonMinded - Mon Sep 10, 2007 5:24 pm

The way I drew circles with thickness on DSO was I called a pen method instead of a setPixel method in my bressenham. Then, if the pen thickness was supposed to be more than one pixel, I would plot around it. Advantage: it gives the same thickness all around and also allows for textures. Disadvantage: slower than it could be due to re-plotting some pixels.
_________________
Enter the mind of the dragon.

http://dragonminded.blogspot.com

Seriously guys, how hard is it to simply TRY something yourself?

#139878 - Blue Frenzy - Tue Sep 11, 2007 4:00 am

The problem is the high quantity of circles, so, it has to be a fast function. If there is a way to draw them by hardware, much better.

BTW, i am working in the custom ouendan project. I think you know what kind of circles i do need.

#139881 - nornagon - Tue Sep 11, 2007 4:55 am

There is no way to draw circles in hardware. The best you can do is predraw them into sprites. There's not much point precalcing to RAM and then copying out, because Bresenham's circle function will be faster than the memory hit (if using EWRAM) and not much slower than using DTCM.

#139882 - nce - Tue Sep 11, 2007 5:14 am

I've played, and still playing at ouendan.

You said that it display a lot of cicrcle... Even in hard core ( when you play with the girlz ) I don't think I ever seen more that 16 circles on screen at the same time.... what could that means ?

we know you can display 128 sprite on a screen on a time but only 32 that you can scale.

My guess is they have done their circles in sprites and they made one on a 64*64 one on 32*32 , 16*16 , 8*8. ( that don't take soo much place sprite of 4colors like that) , it's even possible that they did a 8 16 24 32 40 48...

you just scale your sprite a the correct size and set the correct gfx on it.

It's maybe possible that they used 2sprites to display one circle.
when you want to display a sprite of size 20 you display the sprite 16 at 50% + the sprite 24 at 50% ( scaled booth at 20 of course ), that can help the eyes to think that the thikness of the circle is always the same.... but the last part I'm not sure ....


OR I'm completly wrong and they did draw circle on the fly using bresenham ( after all, 16 small circles is not to much for the ds )



Edit :
I've launch ouendan...
Forget everything written before LOL
The maximum number of circle at a time is around 3, maybe once ar twice you'll have 4 , but it's too fast to be sure ;)

And YES thickness of circle is decresing, that means they use just 1 scaling sprite ...
_________________
-jerome-

#139922 - Blue Frenzy - Tue Sep 11, 2007 3:51 pm

I did notice it now. It is true, the ouendan's circles are smaller each time. But there are more than 4 circles at time. Look at the last songs. You can have like 20 circles arround.

#139935 - strager - Tue Sep 11, 2007 8:43 pm

Even then, does the DS support sprites with different opacity levels? If not, the game probably uses the 3D engine. Polygons with a circle texture are scaled and blended. Obviously the game uses the 3D engine for the bottom screen (the 3D figures in the background) and not the top screen. I'm sure the DS's 3D engine is powerful enough to display 20 or more alpha-blended textured quads.

This seems to me the simplest method that would produce with the effect you want.

#139936 - mastertop101 - Tue Sep 11, 2007 8:50 pm

maybe you should check the waterdrops demo

#139956 - Blue Frenzy - Wed Sep 12, 2007 1:10 am

but, if i enable 3D mode, could i draw sprites, or shall i draw the sprites as textures too?

And how to enable 3d mode on bottom screen? I am using PALib so I need some help to use non implemented functions.

#139971 - nce - Wed Sep 12, 2007 4:47 am

normally the ds suport sprite with different opacity, that's way we have the alpha macro for the attribute2 of a sprite ( i think, never try though )

but if you want to draw that in 3d ( I don't recommand it, it's doing a lot of work for something not needed ) you can put your 3d on bottom by swaping screens ( lcdSwap or something similar )

and I played again to ouendan and elite beat. I'm sure there are around 3 maybe maximum 5 circles at a time and yes it was while playing samourai blue on ouendan and survivor on elite ( the last songs you receive in bonus )

If like me you have the impression there is more it just because it is fast, I'm at work so I can't check but I suggest to search on youtube for zz samourai blue and look at the video of guys that finished it on s mode... and when you are sure that there are tones of circles, pause the picture and count.....
_________________
-jerome-

#139973 - dantheman - Wed Sep 12, 2007 5:02 am

You have a point there. The max I could find in an EBA video was 6 at once (last segment of Jumpin Jack Flash in Sweatin' mode), even though there were tons to hit in a short time period.

#139991 - tepples - Wed Sep 12, 2007 12:23 pm

Blue Frenzy wrote:
but, if i enable 3D mode, could i draw sprites, or shall i draw the sprites as textures too?

You can do either.

Quote:
And how to enable 3d mode on bottom screen? I am using PALib so I need some help to use non implemented functions.

Only the main core supports 3D mode, but the main screen signal can be sent to either physical screen. So look for a PALib function that puts the main screen on the bottom.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#139993 - Blue Frenzy - Wed Sep 12, 2007 1:14 pm

the problem is that if the application is customizable, the user could put even more than 10 spheres in the screen. What about if you put lots of psheres and you have a slow "closing" time like in easy mode?

#140002 - jetboy - Wed Sep 12, 2007 3:52 pm

Blue Frenzy wrote:
the problem is that if the application is customizable, the user could put even more than 10 spheres in the screen. What about if you put lots of psheres and you have a slow "closing" time like in easy mode?


If you do fast routine that can display 20, there is posibility user can put 40, if you speed up the thing so it can do 40, there is no reason that user wouldnt put 80... in other words no matter how fast you drawing will be, user can always put more than you can handle. So you have to impose a limit.
You can set it as low as your drawing routines can display.

Anyway. If you would put it in a way that 20 is drawn at the same time, nobody would be able to press them fast enough. So there is no point in putting as many at once.
_________________
Colors! gallery -> http://colors.collectingsmiles.com
Any questions? Try http://colors.collectingsmiles.com/faq.php first, or official forums http://forum.brombra.net

#140029 - Blue Frenzy - Wed Sep 12, 2007 10:20 pm

well, i will try my best. Wish me luck :P

#140050 - nce - Thu Sep 13, 2007 1:06 am

good luck, a ouendan project is awsome, I realy want more song that the one I already know .... :)

My guess that in oendan is not realy the gamedesigner that which sphere will epear when and for how many time... If I had to do this project here the is my idea :

like a subtitle file, you have just to define time when to hit in a file like this :

red:
2000,10,10
2100,50,10
3000,120,30
3100,121,31
blue:
4200,10,140
....

well you guess, you just have to tell when in miliseconde you have to hit exactly and the position.... all the rest the engine will do itself: like numeroting correctly spheres and display only 3 or 4 spheres at a time.... this way it is impossible to the designer to set 1000 spheres on a screen
_________________
-jerome-

#140053 - Blue Frenzy - Thu Sep 13, 2007 1:20 am

i do it that way. The problem is that the appearing time depends on the time closing of the sphere, a global value. So, even if you put 1 second of closing time, user can put as many spheres as he wants with the editor. If user wants can put a closing time of 5 seconds (easy mode)and put one ball each frame.

#140056 - nce - Thu Sep 13, 2007 1:35 am

not if you tell your program to don't display the X circle before the X-5 one has been removed.....

like implementing a FIFO list with a size of 5 and waiting to have a free room in this list to set your circle
_________________
-jerome-

#140057 - Blue Frenzy - Thu Sep 13, 2007 1:43 am

Not that easy, since the object keeps after the hit time.

Actually i think i won't care on limitations since, if people do impossible songs, no one will play. But i want to keep framerates.

#140059 - tepples - Thu Sep 13, 2007 1:59 am

Blue Frenzy wrote:
Actually i think i won't care on limitations since, if people do impossible songs, no one will play.

But the bar for what is considered "impossible" rises every month. Go play some of NVLM_ZK's StepMania files to see what I mean. Sure something like "Right Type of Mood" oni is impossible, but if people are pressing 20 arrow keys per second with nearly exact rhythm...
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#140069 - nce - Thu Sep 13, 2007 4:01 am

Blue Frenzy wrote:
Not that easy, since the object keeps after the hit time.


That's not a problem, the hit sprite, is something else and is realy short, again look at ouendan you never have more than 5 on screen, and if you are afraid for the performance, do the same thing for them allow only 5 on screen at the same time... the only difference here is when you want to display the 6th remove the 1st .... ( at that speed nobody will notice that your 1st one hasen't play all his disapearing animation )
_________________
-jerome-

#140137 - strager - Thu Sep 13, 2007 8:39 pm

Why are you limiting yourself to only four or five sprites anyway? You have 128 to play around with, so it shouldn't be much of a problem of squeezing "all those targets" into the OAM slots. Just toss all the target indicators on the screen when they should appear, and shove them off OAM when their animation completes. That shouldn't be too hard.

#140167 - nce - Fri Sep 14, 2007 12:47 am

I was thinking about a limitation more to force designer to keep a screen that the human eyes can follow.... of course the limit can by set much higger... but well you have to be carrefull here with the 128 sprites...

only 32 scalable so max 32 but :
for 32 circle you will have 32 number associeted ( those one can become the hit after ) and between each of your number ouendan set small dots to show you the direction to follow to the next number ... and those small dots can already take a lot of sprites ;) set an average of 3 dots between your numbers and op you've got 3 * 31 sprites + 32 + 32 and even worse the designer can set all his number in the oposite corner each time... you explode your sprites number....

limiting the number of maximum number at a time can change a lot of stuff in the final ;)
_________________
-jerome-

#140252 - strager - Fri Sep 14, 2007 8:53 pm

nce wrote:
only 32 scalable so max 32 but :
for 32 circle you will have 32 number associeted ( those one can become the hit after ) and between each of your number ouendan set small dots to show you the direction to follow to the next number ... and those small dots can already take a lot of sprites ;) set an average of 3 dots between your numbers and op you've got 3 * 31 sprites + 32 + 32 and even worse the designer can set all his number in the oposite corner each time... you explode your sprites number....

limiting the number of maximum number at a time can change a lot of stuff in the final ;)


I think it'd be reasonable to say that a max of ten targets and indicators each can appear on the screen at one time. That's 20 sprites, leaving 108 for the dots, which is 108 / 9 = 12 dots between each of those shown targets, if you want the dots to persist (stay on the screen even after the target has been hit). You have plenty of room.

I don't think the limitation of targets should be enforced in the code; the code should do the best it can, and if it "doesn't work" right (too many sprites), maybe change the level a little, or go with sprite multiplexing (I think it's called; HBlank tricks).

#140489 - HyperHacker - Sun Sep 16, 2007 9:31 pm

tepples wrote:
look for a PALib function that puts the main screen on the bottom.
PALib "sits on top of" libNDS doesn't it? So you can use lcdMainOnBottom(). BTW, don't just use lcdSwap(), because you can't be sure which screen will be on top when your program starts.
_________________
I'm a PSP hacker now, but I still <3 DS.