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 > SOLVED: Problem displaying BMP loaded from filesystem

#169616 - raomon - Mon Jul 27, 2009 12:50 am

Hi, I'm learning how to develop for the NDS but get stuck in how to load bitmaps in backgrounds. Here is where currently I am. This is the almost (change in order to follow the post code easily) original code that works without problems:

Code:

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

// 14 bytes
typedef struct {
    char signature[2];
    unsigned int fileSize; // 4 bytes, 32 bits
    unsigned int reserved;
    unsigned int offset;
} __attribute__ ((packed)) BmpHeader;

// 40 bytes
typedef struct {
    unsigned int headerSize;
    unsigned int width;
    unsigned int height;
    unsigned short planeCount;
    unsigned short bitDepth;
    unsigned int compression;
    unsigned int compressedImageSize;
    unsigned int horizontalResolution;
    unsigned int verticalResolution;
    unsigned int numColors;
    unsigned int importantColors;
} __attribute__ ((packed)) BmpImageInfo;

// 256 bytes
typedef struct {
    unsigned char blue;
    unsigned char green;
    unsigned char red;
    unsigned char reserved;
} __attribute__ ((packed)) Rgb;

typedef struct {
    BmpHeader header;
    BmpImageInfo info;
    Rgb colors[256];
    unsigned short image[1];
} __attribute__ ((packed)) BmpFile;

int main(int argc, char **argv) {
    u16 *video_buffer_main = (u16*)BG_BMP_RAM(0);
    videoSetMode(MODE_5_2D | DISPLAY_BG3_ACTIVE);
    vramSetBankA(VRAM_A_MAIN_BG_0x06000000);
    BACKGROUND.control[3] = BG_BMP8_256x256 | BG_BMP_BASE(0);
    BACKGROUND.bg3_rotation.xdy = 0;
    BACKGROUND.bg3_rotation.xdx = 1 << 8;
    BACKGROUND.bg3_rotation.ydx = 0;
    BACKGROUND.bg3_rotation.ydy = 1 << 8;
    BmpFile* bmp = (BmpFile*)beerguy_bin;
    consoleDemoInit();
    printf("File Size: %i\n", bmp -> header.fileSize);
    printf("%c%c\n", bmp -> header.signature[0], bmp -> header.signature[1]);
    printf("bit depth: %i\n", bmp -> info.bitDepth);
    printf("width:     %i\n", bmp -> info.width);
    printf("height:    %i\n", bmp -> info.height);
    for (register int i = 0; i < 256; ++i) {
        BG_PALETTE[i] = RGB15(  bmp -> colors[i].red >> 3,
                                               bmp -> colors[i].green >> 3,
                                               bmp -> colors[i].blue >> 3);
    }
    for(register int iy = 0, ix = 0; iy < bmp -> info.height; ++iy) {
        for(ix = 0; ix < bmp -> info.width / 2; ++ix) {
            video_buffer_main[iy * 128 + ix] =
                bmp -> image[   (bmp -> info.height - 1 - iy) *
                                         ((bmp -> info.width + 3) & ~3) / 2 + ix];
        }
    }
    while (1);
    return 0;
}


then, as an exercise (and because a read lots of posts recommending filesystem use instead of use the images directly in code), I try to convert the same code in order to have filesystem support (nitrofs in this case):

Code:

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

// 14 bytes
typedef struct {
    char signature[2];
    unsigned int fileSize; // 4 bytes, 32 bits
    unsigned int reserved;
    unsigned int offset;
} __attribute__ ((packed)) BmpHeader;

// 40 bytes
typedef struct {
    unsigned int headerSize;
    unsigned int width;
    unsigned int height;
    unsigned short planeCount;
    unsigned short bitDepth;
    unsigned int compression;
    unsigned int compressedImageSize;
    unsigned int horizontalResolution;
    unsigned int verticalResolution;
    unsigned int numColors;
    unsigned int importantColors;
} __attribute__ ((packed)) BmpImageInfo;

// 256 bytes
typedef struct {
    unsigned char blue;
    unsigned char green;
    unsigned char red;
    unsigned char reserved;
} __attribute__ ((packed)) Rgb;

typedef struct {
    BmpHeader header;
    BmpImageInfo info;
    Rgb colors[256];
    unsigned short image[1];
} __attribute__ ((packed)) BmpFile;

int main(int argc, char **argv) {
    u16 *video_buffer_main = (u16*)BG_BMP_RAM(0);
    BmpFile *bmp = NULL;
    FILE *bitmapFile = NULL;
    videoSetMode(MODE_5_2D | DISPLAY_BG3_ACTIVE);
    vramSetBankA(VRAM_A_MAIN_BG_0x06000000);
    BACKGROUND.control[3] = BG_BMP8_256x256 | BG_BMP_BASE(0);
    BACKGROUND.bg3_rotation.xdy = 0;
    BACKGROUND.bg3_rotation.xdx = 1 << 8;
    BACKGROUND.bg3_rotation.ydx = 0;
    BACKGROUND.bg3_rotation.ydy = 1 << 8;
    consoleDemoInit();
    if (nitroFSInit()) {
        bitmapFile = fopen("beerguy.bmp", "rb");
        fread(&bmp -> header, sizeof(BmpHeader), 1, bitmapFile);
        printf("File Size: %i\n", bmp -> header.fileSize);
        printf("Header size: %ld \n", ftell(bitmapFile));
        printf("%c%c\n", bmp -> header.signature[0], bmp -> header.signature[1]);
        fread(&bmp -> info, sizeof(BmpImageInfo), 1, bitmapFile);
        printf("Info: %ld \n", ftell(bitmapFile));
        printf("Depth: %i\n", bmp -> info.bitDepth);
        printf("Width:     %i\n", bmp -> info.width);
        printf("Height:    %i\n", bmp -> info.height);
// Here is where I'm stuck because fread crash reading BMP palette
        fread(&bmp -> colors, sizeof(Rgb), 256, bitmapFile);
        for (register int i = 0; i < 256; ++i) {
            BG_PALETTE[i] = RGB15(  bmp -> colors[i].red >> 3,
                                                   bmp -> colors[i].green >> 3,
                                                   bmp -> colors[i].blue >> 3);
        }
        printf("Palette: %ld \n", ftell(bitmapFile));
        int sz = bmp -> info.height * bmp -> info.width;
        fread(&bmp -> image, sizeof(unsigned short), sz, bitmapFile);       
        for(register int iy = 0, ix = 0; iy < bmp -> info.height; ++iy) {
            for(ix = 0; ix < bmp -> info.width / 2; ++ix) {
                video_buffer_main[iy * 128 + ix] =
                    bmp -> image[   (bmp -> info.height - 1 - iy) *
                                             ((bmp -> info.width + 3) & ~3) / 2 + ix];
            }
        }
        printf("Image: %ld \n", ftell(bitmapFile));
    } else {
   printf("nitroFSInit failed.\n");
    }
    fclose(bitmapFile);
    while (1);
    return 0;
}


I try the code with the NO$GBA and it crash with a fatal error that say: "Undefined opcode - with no debug vector defined". At first I think the crash was caused by image file size, because at my first try with filesystem support I try an image with a resolution of 320x200, but the file size was 65078 bytes, is not even a half of whole vram bank. Then I try with the original image, beerguy, but it crash too. I look in the forum if someone had the same problem, but this is the only post I found with a, more or less, related problem. Hope that somebody can give guidance of a way to load files correctly in the DS and that Dovoto finish the tutorials in the wiki, they are very helpful indeed! :)

P.D.: The BMP files I'm loading are 8 bit only.


Last edited by raomon on Wed Jul 29, 2009 12:47 am; edited 1 time in total

#169617 - vuurrobin - Mon Jul 27, 2009 1:25 am

I think most people use grit to convert the image files to a format that the ds can handle better.

and Dovoto haven't worked on the tutorials in quite some time. I doubt they are up to date with the latest libnds. not that you can't learn from them, but libnds contains a lot of functions to make things easier for programmers.

#169618 - raomon - Mon Jul 27, 2009 2:38 am

vuurrobin wrote:
I think most people use grit to convert the image files to a format that the ds can handle better.

The main reason to try BMP instead of using tools like grit is because I dont always know, ahead of time, what kind of files I'll be using, so I need to decode "non-native" file formats. For example, if I want to write a comic book viewer homebrew that load RAR,ZIP,etc files with images inside (BMP, GIF, PNG, JPEG, etc), then I can't using the raw "comic book file" without first using grit or other tool for transforming the images inside, making it more a problem for the user point of view. I look at the LibNDS api and found that there is support for loading PCX files from there, very useful but not what I'm looking for (yet). So once I know how to load the BMP images correctly, I can try other image file formats and then continue with the following parts of the tutorial.

vuurrobin wrote:
and Dovoto haven't worked on the tutorials in quite some time. I doubt they are up to date with the latest libnds. not that you can't learn from them, but libnds contains a lot of functions to make things easier for programmers.

Is a pity that Dovoto don't work anymore on the tutorials, I like the low level aproach. :/

#169672 - raomon - Wed Jul 29, 2009 12:46 am

Hi, I fix the problem and now it work as should be. Just change the image atribute in BmpFile struct from unsigned short image[1] to unsigned short *image, malloc BmpFile and then image atribute with the resolution size of the image. I hope somebody found it useful. Here is the code:

Code:

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

typedef struct {
    char signature[2];
    unsigned int fileSize;
    unsigned int reserved;
    unsigned int offset;
} __attribute__ ((packed)) BmpHeader;

typedef struct {
    unsigned int headerSize;
    unsigned int width;
    unsigned int height;
    unsigned short planeCount;
    unsigned short bitDepth;
    unsigned int compression;
    unsigned int compressedImageSize;
    unsigned int horizontalResolution;
    unsigned int verticalResolution;
    unsigned int numColors;
    unsigned int importantColors;
} __attribute__ ((packed)) BmpImageInfo;

typedef struct {
    unsigned char blue;
    unsigned char green;
    unsigned char red;
    unsigned char reserved;
} __attribute__ ((packed)) Rgb;

typedef struct {
    BmpHeader header;
    BmpImageInfo info;
    Rgb colors[256];
    unsigned short *image;
} __attribute__ ((packed)) BmpFile;

int main(int argc, char **argv) {
    u16 *video_buffer_main = (u16*)BG_BMP_RAM(0);
    BmpFile *bmp = (BmpFile *) malloc(sizeof(BmpFile));
    FILE *bitmapFile = NULL;
    videoSetMode(MODE_5_2D | DISPLAY_BG3_ACTIVE);
    vramSetBankA(VRAM_A_MAIN_BG_0x06000000);
    BACKGROUND.control[3] = BG_BMP8_256x256 | BG_BMP_BASE(0);
    BACKGROUND.bg3_rotation.xdy = 0;
    BACKGROUND.bg3_rotation.xdx = 1 << 8;
    BACKGROUND.bg3_rotation.ydx = 0;
    BACKGROUND.bg3_rotation.ydy = 1 << 8;
    consoleDemoInit();
    if (nitroFSInit()) {
        bitmapFile = fopen("beerguy.bmp", "rb");
        fread(&bmp -> header, sizeof(BmpHeader), 1, bitmapFile);
        printf("File Size: %i\n", bmp -> header.fileSize);
        printf("Header size: %ld \n", ftell(bitmapFile));
        printf("%c%c\n", bmp -> header.signature[0], bmp -> header.signature[1]);
        fread(&bmp -> info, sizeof(BmpImageInfo), 1, bitmapFile);
        printf("Info: %ld \n", ftell(bitmapFile));
        printf("Depth: %i\n", bmp -> info.bitDepth);
        printf("Width:     %i\n", bmp -> info.width);
        printf("Height:    %i\n", bmp -> info.height);
        fread(bmp -> colors, sizeof(Rgb), 256, bitmapFile);
        for (register int i = 0; i < 256; ++i) {
            BG_PALETTE[i] = RGB15(  bmp -> colors[i].red >> 3,
                                    bmp -> colors[i].green >> 3,
                                    bmp -> colors[i].blue >> 3);
        }
        printf("Palette: %ld \n", ftell(bitmapFile));       
        bmp -> image = (unsigned short *) malloc(sizeof(unsigned short) * (bmp -> info.width * bmp -> info.height));
        fread(bmp -> image, sizeof(unsigned short), (bmp -> info.width * bmp -> info.height), bitmapFile);
        for(register int iy = 0, ix = 0; iy < bmp -> info.height; ++iy) {
            for(ix = 0; ix < bmp -> info.width / 2; ++ix) {
                video_buffer_main[iy * 128 + ix] =
                    bmp -> image[   (bmp -> info.height - 1 - iy) *
                    ((bmp -> info.width + 3) & ~3) / 2 + ix];
            }
        }
        printf("Image: %ld \n", ftell(bitmapFile));
    } else {
        printf("Falla de nitroFSInit: Terminando.\n");
    }
    fclose(bitmapFile);
    free(bmp -> image);
    free(bmp);
    while (1);
    return 0;
}
[/quote]