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 > Issues with VRAM memory allocations

#52122 - cybereality - Sat Aug 27, 2005 12:05 am

I have just started wih NDS development, but I have read a good amount of what is on the web and the examples given with devkitPro. I started by going through Chris Double's tutorials and while I understand all the logic, I am having trouble with the VRAM allocations. I took Chris' demo to display a JPEG and edited it with my own images. Then I added an extra BG layer on the sub screen so I could display a large image over both screens. I did this by duplicating the image data in both main and sub BG buffers and offseting the Y value in hardware. That works fine, no problem. Now I want to add the console output on one screen (over the image) and it doesn't work. The main screen displays the image fine, the sub screen has a bunch of random ASCII characters on i but colored like the image should be. If I move the image around, I can tell it is writing the the correct VRAM, but the console text garbles it up. I need some help with this from someone who knows what they are talking about.

The lines I have a feeling are wrong are:
Code:

consoleInitDefault((u16*)SCREEN_BASE_BLOCK_SUB(31), (u16*)CHAR_BASE_BLOCK_SUB(0), 16);

Code:

BltImage(images[current_image], BG_GFX_SUB, 256, 256);

Basically, it seems that I am writing the sub image and the console output to the same VRAM bank. I tried a bunch of different things, but I am not all that experienced with low-level memory coding and I can't find any simple demos that do this. I have posted the code below, hopefully someone can make some sense out of it for me. I dont understand what (u16*)SCREEN_BASE_BLOCK_SUB(31) refers to (it sets the map buffer base for the consoleInit I know, but where is this coming from?). Also I couldn't find any info on BG_GFX or BG_GFX_SUB and what other constants could be used for these. If you can, please help me out. Thanks.

Code:
 /*
   mode5_scrolling ARM9 Code
   Chris Double (chris.double@double.co.nz)
   http://www.double.co.nz/nintendo_ds
   
   edits by: cybereality
*/

#include <nds.h>
#include "nds/arm9/console.h"
#include <stdlib.h>
#include <string.h>
#include "gba-jpeg.h"
#include "gba-jpeg-decode.h"
#include "gbfs.h"

// Given the name of a file, look it up in the GBFS archive and use
// the JPEG routines to return the width and height of the image.
void GetImageSize(char* name, int* width, int* height) {
  WAIT_CR &= ~0x80;
  GBFS_FILE const* gbfs_file =
    find_first_gbfs_file((void*)0x08000000);
  const unsigned char* image = (const unsigned char*)gbfs_get_obj(gbfs_file,
                  name,
                  0);
  JPEG_Decoder decoder;
  JPEG_Decoder_ReadHeaders(&decoder, &image);
  *width = decoder.frame.width;
  *height = decoder.frame.height;
  WAIT_CR |= 0x80;
}

// Decode the jpeg file with the given name to the VRAM location
// specified.  The height and width are the height and width of the
// output bitmap.
void BltImage(char* name, u16* vram, int output_width, int output_height)
{
  WAIT_CR &= ~0x80;
  GBFS_FILE const* gbfs_file =
    find_first_gbfs_file((void*)0x08000000);
  uint8* image = (uint8*)gbfs_get_obj(gbfs_file,
                  name,
                  0);
  JPEG_DecompressImage(image, vram, output_width, output_height);

  WAIT_CR |= 0x80;
}

static int scrolly = 0;
static int scrollx = 0;

static int scale_settings[] = {
  1 << 4,
  1 << 5,
  1 << 6,
  1 << 7,
  1 << 8,
  2 << 8,
  3 << 8,
  4 << 8,
  5 << 8,
  6 << 8,
  7 << 8,
  8 << 8,
  9 << 8,
  10 << 8
};
static int scale_count = sizeof(scale_settings) / sizeof(int);
static int scale = 4;

static char* images[] = {
  "shadowrun1.jpg",
  "shadowrun2.jpg",
  "shadowrun3.jpg",
  "shadowrun4.jpg"
};
static int image_count = sizeof(images) / sizeof(char*);
int current_image = 0;

static int height = 0;
static int width = 0;

void on_irq()
{   
  if(IF & IRQ_VBLANK) {
    // Handle vertical blank interrupt
   
   // debug traces
   consoleClear();
   consolePrintf("// cybereality\n\n");
   consolePrintf("Width: %d\n", width);
   consolePrintf("Height: %d\n", height);
   consolePrintf("scrolly: %d\n", scrolly);
   consolePrintf("scrollx: %d\n", scrollx);
   
    // Tell the DS we handled the VBLANK interrupt
    VBLANK_INTR_WAIT_FLAGS |= IRQ_VBLANK;
    IF |= IRQ_VBLANK;
  }
  else {
    // Ignore all other interrupts
    IF = IF;
  }
}

void InitInterruptHandler()
{
  IME = 0;
  IRQ_HANDLER = on_irq;
  IE = IRQ_VBLANK;
  IF = ~0;
  DISP_SR = DISP_VBLANK_IRQ;
  IME = 1;
}

int main(void)
{
  powerON(POWER_ALL);
 
  //   WAIT_CR=0xe800;
  //   POWER_CR=0x30F;
   
  // Mode5: Backgrounds 0 and 1 are text. Background 2 and 3 are
  // extended rotation backgrounds. Background 0 can be used for 3D.
  videoSetMode(MODE_5_2D | DISPLAY_BG2_ACTIVE);
  vramSetBankA(VRAM_A_MAIN_BG_0x6000000);
 
  BG2_CR = BG_BMP16_256x256;

  // Set translations
  BG2_XDX = scale_settings[scale];
  BG2_XDY = 0;
  BG2_YDX = 0;
  BG2_YDY = scale_settings[scale];
  BG2_CY = 0;
  BG2_CX = 0;

  // top screen
  videoSetModeSub(MODE_5_2D | DISPLAY_BG0_ACTIVE | DISPLAY_BG3_ACTIVE);
  vramSetBankC(VRAM_C_SUB_BG_0x6200000);
  SUB_BG3_CR = BG_BMP16_256x256;
 
  // console text output on bg0
  SUB_BG0_CR = BG_MAP_BASE(31);
  BG_PALETTE_SUB[255] = RGB15(31,31,31);
  consoleInitDefault((u16*)SCREEN_BASE_BLOCK_SUB(31), (u16*)CHAR_BASE_BLOCK_SUB(0), 16);
 
  // allocate memory for main banks
  //vramSetMainBanks(VRAM_A_MAIN_BG_0x6000000,VRAM_B_MAIN_BG_0x6020000,VRAM_C_SUB_BG_0x6200000,VRAM_D_LCD);
 
    // Set translations
  SUB_BG3_XDX = scale_settings[scale];
  SUB_BG3_XDY = 0;
  SUB_BG3_YDX = 0;
  SUB_BG3_YDY = scale_settings[scale];
  SUB_BG3_CY = (-260<<8);
  SUB_BG3_CX = 0;

  // Initialize and enable VBlank interrupt
  InitInterruptHandler();

  // Initialiaze key handler
  keysInit();

  // Wait for the vertical blank interrupt before decoding the image to
  // VRAM. This prevents seeing the image being drawn as its written to
  // memory.
  swiWaitForVBlank();
 
  // draw image to main screen (bottom)
  BltImage(images[current_image], BG_GFX, 256, 256);
  // draw image to sub screen (top)
  // BltImage(images[current_image], BG_GFX_SUB, 256, 256);
 
  GetImageSize(images[current_image], &width, &height);


  while(1) {
    scanKeys();
    swiWaitForVBlank();
    if(keysHeld() & KEY_DOWN) {
      scrolly++;
      BG2_CY = (scrolly<<8);
     SUB_BG3_CY = (scrolly-260<<8);
    }
    if(keysHeld() & KEY_UP) {
      scrolly--;
      BG2_CY = (scrolly<<8);
     SUB_BG3_CY = (scrolly-260<<8);
    }
    if(keysHeld() & KEY_RIGHT) {
      scrollx++;
      BG2_CX = (scrollx<<8);
     SUB_BG3_CX = (scrollx<<8);
    }
    if(keysHeld() & KEY_LEFT) {
      scrollx--;
      BG2_CX = (scrollx<<8);
     SUB_BG3_CX = (scrollx<<8);
    }
    if(keysDown() & KEY_A) {
      scale++;
      if(scale >= scale_count)
   scale = scale_count - 1;
      BG2_XDX = scale_settings[scale];
      BG2_YDY = scale_settings[scale];
     SUB_BG3_XDX = scale_settings[scale];
      SUB_BG3_YDY = scale_settings[scale];
    }
    if(keysDown() & KEY_B) {
      scale--;
      if(scale <1)
   scale = 1;
      BG2_XDX = scale_settings[scale];
      BG2_YDY = scale_settings[scale];
     SUB_BG3_XDX = scale_settings[scale];
      SUB_BG3_YDY = scale_settings[scale];
    }
     
    if(keysDown() & KEY_SELECT) {
      current_image++;
      if(current_image >= image_count)
   current_image = 0;
      memset(BG_GFX, 0, 256*256*2);
     memset(BG_GFX_SUB, 0, 256*256*2);
      BltImage(images[current_image], BG_GFX, 256, 256);
     BltImage(images[current_image], BG_GFX_SUB, 256, 256);
      GetImageSize(images[current_image], &width, &height);
    }
  }

  return 0;
}
[/code]