Author Topic: Any DS coders here?  (Read 2886 times)

0 Members and 1 Guest are viewing this topic.

Offline relsoft

  • DBF Aficionado
  • ******
  • Posts: 3303
  • Karma: 47
    • View Profile
Any DS coders here?
« on: April 17, 2010 »
 :updance:

Kind of liking this Homebrew DS coding.  I love the framebuffer mode. It's like TPTC on the DS.
Challenge Trophies Won:

Offline combatking0

  • JavaScript lives!
  • Senior Member
  • DBF Aficionado
  • ********
  • Posts: 4569
  • Karma: 235
  • Retroman!
    • View Profile
    • Combat King's Barcode Battler Home
Re: Any DS coders here?
« Reply #1 on: April 17, 2010 »
I'm not into DS coding, but it's something I'd like to learn about.

Where would be a good place to start?

(edit) Sorry, I've asked this question before, and got a good answer. I'll follow it up.
« Last Edit: April 17, 2010 by combatking0 »
You are our 9001st visitor.
Challenge Trophies Won:

Offline relsoft

  • DBF Aficionado
  • ******
  • Posts: 3303
  • Karma: 47
    • View Profile
Re: Any DS coders here?
« Reply #2 on: April 18, 2010 »
I just read some docs on the net and downloaded the DevkitPro package.  The example files there are easy to follow.

I've uploaded some NDS files along with sources and screenshots....

BTW, to try this on Windows or DOS, you can DL the No$GBA emulator for free here, then load the NDS file.

http://nocash.emubase.de/gba.htm



Code: [Select]
/*
NDS Translucent Plasma
Relminator

http://rel.betterwebber.com

*/

#include <nds.h>
#include <stdio.h>
#include <math.h>


// some sine LUTs
u8 lsin1[2048];
u8 lsin2[2048];
u8 lsin3[2048];

// RGB palette
u16 pal[256];   

int main(void)
{

// constant sine divisor
const u8 K1 = 32;
    const u8 K2 = 12;
    const u8 K3 = 28;

// maximum values our dynamic plasmas can move
u16 KSIN1 = u8(K1 *(360/57.3f));
    u16 KSIN2 = u8(K2 *(360/57.3f));
    u16 KSIN3 = u8(K3 *(360/57.3f));


   
// precalculate our luts
for (int i = 0; i< ((2048) - 1); i++)
{
        lsin1[i] = sin(i/(float)K1) * 32+32;
        lsin2[i] = sin(i/(float)K2) * 16+16;
        lsin3[i] = sin(i/(float)K3) * 20+20;
    }   

// generate our 256 color palette
for (int i=0; i<256; i++)
{
    u8 r = (u8)(abs(int(16 - 15 * sin(i * M_PI / 16.0f))));
u8 g = (u8)(abs(int(16 - 15 * sin(i * M_PI / 12.0f))));
u8 b = (u8)(abs(int(16 - 15 * sin(i * M_PI / 18.0f))));
pal[i] = RGB15(r,g,b);
}

irqInit();
irqEnable(IRQ_VBLANK);


//initialize the DS Dos-like functionality
consoleDemoInit();

iprintf("\x1b[1;1HTranslucent Plasma!");
iprintf("\x1b[2;1HFramebuffer madness!");
iprintf("\x1b[3;1HRelsoft");
iprintf("\x1b[4;1Hhttp://rel.betterwebber.com");
iprintf("\x1b[6;1HAnya Therese B. Lope");
 
//set frame buffer mode 0
videoSetMode(MODE_FB0);
 
//enable VRAM A for writting by the cpu and use
//as a framebuffer by video hardware
vramSetBankA(VRAM_A_LCD);
 
u8 rot; // translucent factor
u16 counter =0; // frame counter
u16 a = 0, b = 0, ct = 0; // movement deltas
u16 c; // palette color index

while(1)
{

// dynamically move our plasmas
a= (a + 1) % (KSIN1 + 1);
b = (b + 1) % (KSIN2 + 1);
ct = (ct + 1) % (KSIN3 + 1);

// offset 2nd plasma by a factor of 64 * 2 or (-64 to 64)
rot = 64 * (((counter & 1) == 1) | 1);

// inc frame
counter++;
   
//write to vram directly
short unsigned int *vram_offset = VRAM_A;

for (int ya = 0; ya<SCREEN_HEIGHT; ya++)
{
for (int xa = 0; xa <SCREEN_WIDTH-1; xa++)
{
rot = -rot; // draw plasmas every other pixel
// calculate colors
c = (lsin1[xa + a + rot] + lsin2[ya + b + rot] +lsin3[1024+xa + ya - ct]);
c = (lsin1[xa + a + rot+c] + lsin2[ya + b + rot+c] +lsin3[1024+xa + ya - ct+c]);
// write to vram
*vram_offset++ = pal[c];
}
vram_offset++; // magic
}
swiWaitForVBlank();
}
 
return 0;
}
 
« Last Edit: April 19, 2010 by relsoft »
Challenge Trophies Won:

Offline Clyde

  • A Little Fuzzy Wuzzy
  • DBF Aficionado
  • ******
  • Posts: 7271
  • Karma: 71
    • View Profile
Re: Any DS coders here?
« Reply #3 on: April 19, 2010 »
I'll download the emu and give these a go!
Nice to see you coding btw dude :)

All the very best,
Clyde.
Still Putting The IT Into Gravy
If Only I Knew Then What I Know Now.

Challenge Trophies Won:

Offline relsoft

  • DBF Aficionado
  • ******
  • Posts: 3303
  • Karma: 47
    • View Profile
Re: Any DS coders here?
« Reply #4 on: April 20, 2010 »
I'll download the emu and give these a go!
Nice to see you coding btw dude :)

All the very best,
Clyde.

Yeah, it's been a while since I last coded something worthwhile.  My daughter was actually the one who motivated me to learn DS coding as she wanted me to make a game on the DS. Nut its more likely that I'll be making a demo first. :)
Challenge Trophies Won:

Offline ninogenio

  • Pentium
  • *****
  • Posts: 1667
  • Karma: 133
    • View Profile
Re: Any DS coders here?
« Reply #5 on: April 22, 2010 »
ahh k+ for bringing some memories back rel!

doesnt look like things have changed much from your code, as too when i was messing about when the ds first come out.

there is a couple of things that can really get the performance of the ds up especially when shifting data around from from SYS_MEM->SYS_MEM SYS_MEM->V_MEM.

and that is the dma blitter and maths co_processor (the latter i only skimmed on but looked like it might have been handy for some perspective correct span lines).

the former is a hardware accelerated memcpy function. the more data shifted in one go the more benifical you will find it. i remeber having some real trouble with a game 25fps then when i discoverd it i hit the vsync.

also the tile modes and oam memory are fun. can be a bit confussing at first but really rewarding when figuared out. i have a tilemap demo that i messed about with plus a few bits and peices that i will dig out.

and if there is any thing i can help with just give a shout.

keep looking threw the includes in the sdk and trying stuff out, you will have some great fun and it really wont be difficult for someone with your skills to crack.
Challenge Trophies Won:

Offline relsoft

  • DBF Aficionado
  • ******
  • Posts: 3303
  • Karma: 47
    • View Profile
Re: Any DS coders here?
« Reply #6 on: April 22, 2010 »
Yeah, I've been playing with the oam. I'm also using DMA whenever I can.  I don't think the DS has a math coprocessor.

http://rel.betterwebber.com/junk.php?id=100

Code: [Select]
/*
 * SHMUP test
 * relminator
 * http://rel.betterwebber.com
 *
 */
 

#include <nds.h>
#include <stdio.h>
#include <math.h>
#include <string.h>

#define  MAX_SPRITES 128

#define  MAX_VIPER_BULLETS 24
#define  MAX_VIPER_SHOT_DELAY 6
#define  VIPER_SHOT_SPEED 8

#define  MAX_OPTIONS 2
#define  MAX_OPTION_BULLETS 8
#define  MAX_OPTION_SHOT_DELAY 10


#define  FP_PI 16384

enum E_shot_ID
{
E_SHOT_NORMAL = 0,
E_SHOT_WAVE
};

class Csprite
{
public:

//static u8 current_oamID;

u8 oamID;

s16 x;
s16 y;


u8 width;
u8 height;

bool active;

u16 *gfx;
SpriteColorFormat format;
SpriteSize size;


};

class Cbullet
{
public:

s32 x;
s32 y;
s32 dx;
s32 dy;
s32 angle; // 0-32767
s32 radius; // FP 1.19.12
E_shot_ID shot_ID;
Csprite sprite;
};

class Coption
{
public:

s32 x;
s32 y;
s32 dx;
s32 dy;
s32 angle; //0-32767
s32 radius_x;
s32 radius_y;
Cbullet shots[MAX_OPTION_BULLETS];
Csprite sprite;
};


class Cviper
{
public:

s32 x;
s32 y;
s32 dx;
s32 dy;
u8 shot_level;
Csprite sprite;
};



void start_shots(Cbullet bullet[], s32 start_x, s32 start_y, u8 max);
void start_sine_shots(Cbullet bullet[], s32 start_x, s32 start_y, u8 max);
void do_shots(Cbullet bullet[], u8 max);
void do_options(Coption option[], s32 cx, s32 cy);
 
Cviper viper;
Cbullet bullets[MAX_VIPER_BULLETS];
Coption options[MAX_OPTIONS];


OamState *oam = &oamMain;



//a sprite constructor
void create_sprite (Csprite &spr,s32 width, s32 height, SpriteSize size, SpriteColorFormat format)
{
static u8 oamID = 0;
spr.oamID = oamID;
spr.active = true;
spr.width = width;
spr.height = height;
spr.size = size;
spr.format = format;
   
//api: allocate a chunk of sprite graphics memory
spr.gfx = oamAllocateGfx(oam, size, format);

oamID++;
}

//sprite deconstructor
void destroy_sprite(Csprite &spr)
{
spr.active = false; 
 
//api: free the graphics
if(spr.gfx)
{
oamFreeGfx(oam, spr.gfx);
}

spr.gfx = 0;
}


//map our sprite to oam entries
void update_sprite(Csprite &s)
{

//oamSet (OamState *oam, int id, int x, int y, int priority,
//   int palette_alpha, SpriteSize size, SpriteColorFormat format,
//   const void *gfxOffset, int affineIndex, bool sizeDouble,
//   bool hide, bool hflip, bool vflip, bool mosaic)
oamSet(oam,
s.oamID, // id
s.x, s.y,    // x,y
0, // priority
0, // palette alpha
s.size, // size
s.format, // color format
s.gfx, // gfx offset
-1, // affine index
false, // double if rotating?
!s.active, // hidden if true
false, // hflip
false, // vflip
false); // apply mosaic?

}



int main(void)
{


videoSetMode(MODE_0_2D);
videoSetModeSub(MODE_0_2D);
vramSetBankA(VRAM_A_MAIN_SPRITE);
vramSetBankB(VRAM_B_MAIN_SPRITE);
vramSetBankD(VRAM_D_SUB_SPRITE);

consoleDemoInit();

iprintf("\x1b[1;1HSHMUP Test alpha");
iprintf("\x1b[2;1HRelminator");
iprintf("\x1b[3;1Hhttp://rel.betterwebber.com");

iprintf("\x1b[5;1HControls:");
iprintf("\x1b[6;1HArrows->move");
iprintf("\x1b[7;1HKey A->Fire weapons");






//api: initialize OAM to 1D mapping with XX byte offsets and no external palette
oamInit(oam, SpriteMapping_1D_128, false);

// let's make a 32x16 ship
int width = 32;
int height = 16;
SpriteSize size = SpriteSize_32x16;
create_sprite (viper.sprite,width, height, size, SpriteColorFormat_256Color);



// allocate gfx ok fill with garbage  
if(viper.sprite.gfx)
{
//fill the 256 color sprite with index 1 (2 pixels at a time)
dmaFillHalfWords((1<<8)|1, viper.sprite.gfx, width*height);
}


// let's some a 16x8 bullets
width = 16;
height = 8;
size = SpriteSize_16x8;

for (int i=0; i<MAX_VIPER_BULLETS; i++)
{
create_sprite (bullets[i].sprite, width, height, size, SpriteColorFormat_256Color);
// allocate gfx ok fill with garbage  
if(bullets[i].sprite.gfx)
{
//fill the 256 color sprite with random index (2 pixels at a time)
u8 c = rand() % 256;
dmaFillHalfWords((c<<8)|c, bullets[i].sprite.gfx, width*height);
}

bullets[i].sprite.active = false;

}

// let's some a 16x16 options
width = 16;
height = 16;
size = SpriteSize_16x16;

for (int i=0; i<MAX_OPTIONS; i++)
{
create_sprite (options[i].sprite, width, height, size, SpriteColorFormat_256Color);
// allocate gfx ok fill with garbage  
if(options[i].sprite.gfx)
{
//fill the 256 color sprite with random index (2 pixels at a time)
u8 c = rand() % 256;
dmaFillHalfWords((c<<8)|c, options[i].sprite.gfx, width*height);
}

//set radius and angle
options[i].angle = i * FP_PI;
options[i].radius_x = 50;
options[i].radius_y = 40;

// setup option bullets
for (int j=0; j<MAX_OPTION_BULLETS; j++)
{
int s_width = 16;
int s_height = 8;
SpriteSize s_size = SpriteSize_16x8;

create_sprite (options[i].shots[j].sprite, s_width, s_height, s_size, SpriteColorFormat_256Color);
// allocate gfx ok fill with garbage  
if(options[i].shots[j].sprite.gfx)
{
//fill the 256 color sprite with random index (2 pixels at a time)
u8 c = rand() % 256;
dmaFillHalfWords((c<<8)|c, options[i].shots[j].sprite.gfx, s_width*s_height);
}

options[i].shots[j].sprite.active = false;

}
}



//load a randomly colored palette
for(int i = 0; i < 256; i++)
{
      SPRITE_PALETTE[i] = rand();
      SPRITE_PALETTE_SUB[i] = rand();
}


u8 viper_shot_delay = MAX_VIPER_SHOT_DELAY;
u8 option_shot_delay = MAX_OPTION_SHOT_DELAY;
viper.x = 10;
viper.y = 96-16;



while(1)
{


int keys = 0;
scanKeys();

keys = keysHeld();

if (keys & KEY_LEFT)
if (viper.x > 0) viper.x -= 3;
if (keys & KEY_RIGHT)
if (viper.x < SCREEN_WIDTH-viper.sprite.width) viper.x += 3;

if (keys & KEY_UP)
if (viper.y > 0) viper.y -= 2;

if (keys & KEY_DOWN)
if (viper.y < SCREEN_HEIGHT-viper.sprite.height) viper.y += 2;


if (keys & KEY_A)
{

viper_shot_delay--;
if(viper_shot_delay == 0)
{

viper_shot_delay = MAX_VIPER_SHOT_DELAY;
start_shots(bullets,viper.x+32,viper.y+4,MAX_VIPER_BULLETS);
start_sine_shots(bullets,viper.x+32,viper.y+4,MAX_VIPER_BULLETS);

}

// options
option_shot_delay--;
if(option_shot_delay == 0)
{

option_shot_delay = MAX_OPTION_SHOT_DELAY;
for (int i=0; i<MAX_OPTIONS; i++)
start_shots(options[i].shots,options[i].x+16,options[i].y+4,MAX_OPTION_BULLETS);

}



}


// copy bullet pos to oam compatible sprite struct
viper.sprite.x = viper.x;
viper.sprite.y = viper.y;

do_shots(bullets,MAX_VIPER_BULLETS);
do_options(options,viper.x+8,viper.y);


// update to oam
// bullets
for (int i=0; i<MAX_VIPER_BULLETS; i++)
{
update_sprite(bullets[i].sprite);
}

// options and option shots
for (int i=0; i<MAX_OPTIONS; i++)
{
update_sprite(options[i].sprite);
for (int j=0; j<MAX_OPTION_BULLETS; j++)
update_sprite(options[i].shots[j].sprite);
}

// viper
update_sprite(viper.sprite);

// wait retrace
swiWaitForVBlank();

//api: updates real oam memory
oamUpdate(oam);


//consoleClear();
//printf("temp= %i  \n",  Gtemp);


}

return 0;
}


void start_shots(Cbullet bullet[], s32 start_x, s32 start_y,u8 max)
{

for(int i=0; i<max; i++)
{
if (!bullet[i].sprite.active)
{
bullet[i].sprite.active = true;
bullet[i].x = start_x;
bullet[i].y = start_y;
bullet[i].dx = VIPER_SHOT_SPEED;
bullet[i].dy = 0;
bullet[i].shot_ID = E_SHOT_NORMAL;
break;
}
}
}


void start_sine_shots(Cbullet bullet[], s32 start_x, s32 start_y, u8 max)
{

static s16 sine_off = 0;
s16 angle;


sine_off += 512;
for (int j=0; j<2; j++)
{
if (j==0)
angle = FP_PI+sine_off;
else
angle = sine_off;
       

for (int i=0; i<max; i++)
{
if (!bullet[i].sprite.active)
{
bullet[i].sprite.active = true;
bullet[i].x = start_x;
bullet[i].y = start_y;
bullet[i].dx = VIPER_SHOT_SPEED-2;
bullet[i].dy = start_y;
bullet[i].angle = angle;
bullet[i].radius = 0;
bullet[i].shot_ID = E_SHOT_WAVE;
break;
}
}
}
}

void do_shots(Cbullet bullet[], u8 max)
{

for(int i=0; i<max; i++)
{

if (bullet[i].shot_ID == E_SHOT_NORMAL)
{
bullet[i].x += bullet[i].dx;
bullet[i].y += bullet[i].dy;
}
else
{
bullet[i].angle += 800;
bullet[i].radius += 3000;
s32 dy = (sinLerp(bullet[i].angle)) * (bullet[i].radius);

bullet[i].x += bullet[i].dx;
bullet[i].y = bullet[i].dy + (dy >> 24);         
}


if (bullet[i].x>SCREEN_WIDTH)
{
bullet[i].sprite.active = false;
}

// copy bullet pos to oam compatible sprite struct
bullet[i].sprite.x = bullet[i].x;
bullet[i].sprite.y = bullet[i].y;
}

}


void do_options(Coption option[], s32 cx, s32 cy)
{

for(int i=0; i<MAX_OPTIONS; i++)
{
option[i].angle += 256;
option[i].x = cx + ( (cosLerp(option[i].angle) *  option[i].radius_x) >> 12);
option[i].y = cy + ( (sinLerp(option[i].angle) *  option[i].radius_y) >> 12);

// copy bullet pos to oam compatible sprite struct
option[i].sprite.x = option[i].x;
option[i].sprite.y = option[i].y;

do_shots(option[i].shots, MAX_OPTION_BULLETS);
}


}


I've read the example files from the devkit package and I'm leaning on using the "man" animation scheme instead of the "woman" animation scheme.

Pros of the man animation scheme:
1. GFX are stored in main mem
2. Animations are easier to manage since the frames if a single sprite would share the same oamID.
3. The createsprite function would automatically set the oamID for each sprite (128 at most)

Con:
1. DMA every frame for every sprite that is active. (would that be a big overhead?) You would at most only use 128 DMAcopies.

Pros of the woman scheme:
1. all GFX are in Vram, so it should be faster

Con:
1. oamID would be really cumbersome to manage(I just tried it.)
ie. Allocate gfx for each sprite and some of them share the same oamID so you need to manually set oamIDs for each sprite.


So what do you think is the better approach?
Thanks in advance!
Challenge Trophies Won:

Offline ninogenio

  • Pentium
  • *****
  • Posts: 1667
  • Karma: 133
    • View Profile
Re: Any DS coders here?
« Reply #7 on: April 22, 2010 »
wow it looks like your really getting to the meat and bones of it quick.

i think its really a case of prefrence and for clarity and managment i would always go with the man scheme i dont think 128 dma copys are asking too much,when i was flat mapping tris i was doing about that for span lines no probs.

its probably when you get too the 000's mark that it starts becoming irrelevent as too using the cpu or dma.

i personally would only look at the woman approch if speed started becoming a problem.

i defo remember finding info about the maths co-processor burried in the sdk includes and jim telling me ways of possibly wringing a little bit of performance from a maths coprocessor. of course it is intirely possible i picked the include file up wrong i was very early on with my coding and just getting a feel for it.

ahh i found it.

http://yabasicprogramming.yuku.com/topic/1058/t/looks-like-the-ds-has-a-maths-CoProssesor.html

it obviously doesnt have any fpu or anything but it looks like it has some paralel sqrt and div capabilites.
« Last Edit: April 22, 2010 by ninogenio »
Challenge Trophies Won:

Offline relsoft

  • DBF Aficionado
  • ******
  • Posts: 3303
  • Karma: 47
    • View Profile
Re: Any DS coders here?
« Reply #8 on: April 24, 2010 »
I've decided to use the "man" scheme.  I also made a fixed point catmull-rom spline routine.

http://rel.betterwebber.com/junk.php?id=101

BTW, it has animated images now.


Challenge Trophies Won: