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 > Saving bmp screenshot using fat from hardware

#176308 - SchmendrickSchmuck - Mon Jun 20, 2011 8:09 pm

I'm trying to save a screenshot to fat on hardware. The output however is completely garbled. Any example code I've found is mostly identical.

This is the result: http://temp.dennisvanzwieten.com/DSLieroScreenshot0005.bmp
There is also 0006 and 0007. It doesn't appear to be complete garbage, as it seems to be the visible portion of the 8bit bg, heavily mangled. Text and (3D) sprites can't be seen.

I don't really know how to adjust the code below in order to make it work, since I'm not sure how it accesses the display data in the first place. I assume that using VRAM_A - VRAM_D as LCD / unmapped, you have direct access to the screen's framebuffer, but if that's the case, the result wouldn't be the way it is.

Here is my code:

Code:

void write16(u16* address, u16 value)
{
   u8* first=(u8*)address;
   u8* second=first+1;

   *first=value&0xff;
   *second=value>>8;
}

void write32(u32* address, u32 value)
{

   u8* first=(u8*)address;
   u8* second=first+1;
   u8* third=first+2;
   u8* fourth=first+3;

   *first=value&0xff;
   *second=(value>>8)&0xff;
   *third=(value>>16)&0xff;
   *fourth=(value>>24)&0xff;
}

void CreateScreenshot(const char* filename)
{
   FILE* file=fopen(filename, "wb");

   REG_DISPCAPCNT=DCAP_BANK(3)|DCAP_ENABLE|DCAP_SIZE(3);
   while(REG_DISPCAPCNT & DCAP_ENABLE);

   int ysize = 384;
   int headerSize = sizeof(INFOHEADER) + sizeof(HEADER);
   u8* temp = (u8*)malloc(256 * ysize * 3 + headerSize);

   HEADER* header=(HEADER*)temp;
   INFOHEADER* infoheader=(INFOHEADER*)(temp + sizeof(HEADER));

   write16(&header->type, 0x4D42);
   write32(&header->size, 256 * ysize * 3 + headerSize);
   write32(&header->offset, headerSize);
   write16(&header->reserved1, 0);
   write16(&header->reserved2, 0);

   write16(&infoheader->bits, 24);
   write32(&infoheader->size, sizeof(INFOHEADER));
   write32(&infoheader->compression, 0);
   write32(&infoheader->width, 256);
   write32(&infoheader->height, ysize);
   write16(&infoheader->planes, 1);
   write32(&infoheader->imagesize, 256 * ysize * 3);
   write32(&infoheader->xresolution, 0);
   write32(&infoheader->yresolution, 0);
   write32(&infoheader->importantcolours, 0);
   write32(&infoheader->ncolours, 0);

   u32 vram_temp = vramSetPrimaryBanks(VRAM_A_LCD, VRAM_B_LCD, VRAM_C_LCD, VRAM_D_LCD);

   for(int y = 0; y < ysize; y++)
   {
      for(int x = 0; x < 256;x++)
      {
         u16 color = 0;
         if(y > 192)
            color =  VRAM_C[256 * 192 - (y - 191) * 256 + x];
         else color = VRAM_D[256 * 192 - (y + 1) * 256 + x];

         u8 b =(color & 31) << 3;
         u8 g =((color >> 5) & 31) << 3;
         u8 r =((color >> 10) & 31) << 3;

         temp[((y * 256) + x) * 3 + 0 + headerSize] = r;
         temp[((y * 256) + x) * 3 + 1 + headerSize] = g;
         temp[((y * 256) + x) * 3 + 2 + headerSize] = b;
      }
   }

   vramRestorePrimaryBanks(vram_temp);

   DC_FlushAll();
   fwrite(temp, 1, 256 * ysize * 3 + headerSize, file);
   fclose(file);
   free(temp);
}
[/code]
_________________
http://DSLiero.DennisvanZwieten.com - Liero for NDS!

#176310 - DiscoStew - Tue Jun 21, 2011 2:02 am

A few things...

I see you are wanting to capture both screens. Sorry to be the bearer of bad news, but that isn't possible. This chart will show you what can be done with the capture unit, but for what you are doing, only the main screen can be captured. With this, your 15bit to 24bit conversion can only read the first 192 lines, so that is what 'ysize' will need to be.

When capturing, the bank that is to be used to hold the capture needs to be allocated to LCDC first.



See if that helps.
_________________
DS - It's all about DiscoStew

#176314 - SchmendrickSchmuck - Tue Jun 21, 2011 3:23 pm

Thanks DiscoStew, I've successfully made a screenshot of the main screen. I got some artifacts on the sub screen (I use VRAM_C for sub bg, which gets messed up), but those should be easily worked out.

So the sub screen can't be captured at all? Since it seems to be completely unrelated to all the main screen operations in that diagram.. I had hoped it was at least possible in some way.

Where can I find more libnds documentation for these display capture functions and defines? The http://libnds.devkitpro.org default docs site doesn't have any info on them, and google didn't help much either.

Thanks again!
_________________
http://DSLiero.DennisvanZwieten.com - Liero for NDS!

#176315 - elhobbs - Tue Jun 21, 2011 4:23 pm

the display capture hardware only works on the main screen. you could do something like the dual 3d sample. render the subcreen to the main screen and capture it with the hardware then display it as the subscreen.

gbatek is the best the source that I know of for ds/gba hardware specs.