Quantcast
Channel: nesdoug
Viewing all articles
Browse latest Browse all 88

Neslib Example Code

$
0
0

I thought this would take me 5 minutes. Boy was I wrong. Here’s some examples on neslib use for NES development. I’ve made some changes, that will probably annoy everyone. Sorry.

I changed the cfg, moving the symbols to crt0.s, adding ONCE segment
I changed PAD_STATE to _PAD_STATE in crt0.s (etc), so I can access it from c code as
extern unsigned char PAD_STATE;
I made slight changes to neslib.s (notably removing _ppu_wait_frame as potentially buggy with split screen effects)

 

 

The first example is a simple “Hello World”. Note, I have arrays of chars called “PALETTE” and “TEXT”. As stated in an earlier blog post, I have created a tile set that positions the letters and numbers exactly in their ASCII position, so I can reference them with actual letters in the code “Hello World!”.

This is how to write to the screen with rendering OFF. Set an address, vram_adr(), then write, vram_write().

void main (void) {

 // rendering is disabled at the startup
 // the init code set the palette brightness to
 // pal_bright(4); // normal

 // load the palette
 pal_bg(PALETTE);

 // load the text
 // vram_adr(NTADR_A(x,y));
 vram_adr(NTADR_A(10,14)); // screen is 32 x 30 tiles
 // this sets a start position on the BG, where to draw the text, left to right

 vram_write((unsigned char*)TEXT,sizeof(TEXT));
 // this draws the array to the screen
 // this function only works with rendering off, and should come after vram_adr()

 // normally, I would reset the scroll position
 // but the next function waits till v-blank and scroll is set automatically in the nmi routine
 // since the RAM was blanked to 0 in init code, scroll variables will be x = 0, y = 0

 // turn on screen
 ppu_on_all();

 // infinite loop
 while (1){

 // game code will go here.

 }
};

Pretty straightforward way to write to the screen with rendering off. Here’s the source code.

http://dl.dropboxusercontent.com/s/5p8o0umed5k10r5/lesson21.zip

lesson1

 

Part 2

This “Hello World” writes 1 letter at a time, then blanks it, and starts over. This is how to write to the screen when rendering is ON.

In this example, I am writing to the screen in 2 different ways, with rendering on. With rendering on, you will write data to a buffer, and set a pointer to that data. The nmi code will automatically push the data to the screen during v-blank.

Both of them are examples of set_vram_update(). The first, non-sequential data. This will write the letter A and the letter B at different screen locations.

// example of non-sequential vram data
const unsigned char TWOLETTERS[]={
MSB(NTADR_A(10,17)),
LSB(NTADR_A(10,17)),
‘A’,
MSB(NTADR_A(18,5)),
LSB(NTADR_A(18,5)),
‘B’,
NT_UPD_EOF}; // data must end in EOF

The second, using the CLEAR array, is a sequential data set. It will write 12 zeros to the screen, covering over the “Hello World!” when the loop ends. NT_UPD_HORZ or NT_UPD_VERT is required to tell the vram update to go sequentially.

// example of sequential vram data
const unsigned char CLEAR[]={
MSB(NTADR_A(10,14))|NT_UPD_HORZ, // where to write, repeat horizontally
LSB(NTADR_A(10,14)),
12, // length of write
0,0,0,0, // what to write there
0,0,0,0, // data needs to be exactly the size of length
0,0,0,0,
NT_UPD_EOF}; // data must end in EOF

And, I’m actually constructing a data set on the fly, when pushing letters of “Hello World!” one at a time to the screen.

v_ram_buffer[0] = high;
v_ram_buffer[1] = low;
data = TEXT[text_Position]; // get 1 letter of the text
v_ram_buffer[2] = data;
v_ram_buffer[3] = NT_UPD_EOF;

This is also an example of delay(), which waits a certain number of frames, before moving to the next line. Here’s the main code (with some comments edited out).

void main (void) {

 // load the palette
 pal_bg(PALETTE);

 // set some initial values
 text_Position = 0;

 // turn on screen
 ppu_on_all();

 // load some non-sequential vram data, during rendering
 memcpy(v_ram_buffer,TWOLETTERS,sizeof(TWOLETTERS)); // copy from the ROM to the RAM
 set_vram_update(v_ram_buffer); // this just sets a pointer to the data, and sets a flag to draw it next v-blank
 // works only when NMI is on

 // infinite loop
 while (1){

    delay(30); // wait 30 frames = 0.5 seconds

    address = NTADR_A(10,14) + text_Position; // 2 bytes wide
    high = (char)(address >> 8); // get just the upper byte
    low = (char)(address & 0xff); // get just the lower byte

    v_ram_buffer[0] = high;
    v_ram_buffer[1] = low;

    data = TEXT[text_Position]; // get 1 letter of the text
    v_ram_buffer[2] = data;

    v_ram_buffer[3] = NT_UPD_EOF;

    ++text_Position;

    if (text_Position >= sizeof(TEXT)){
      text_Position = 0;
      ppu_wait_frame();
      memcpy(v_ram_buffer,CLEAR,sizeof(CLEAR)); // if at end, clear screen
      // by overwriting zeros over the text
    }

    set_vram_update(v_ram_buffer); // set a pointer to the buffer
    // it will auto-update during v-blank

  }
};

So, step 1, fill the v_ram_buffer. Step 2, set_vram_update(v_ram_buffer); will set a pointer to the data and set a flag to push the data to the PPU during the next v-blank.

Note: set_vram_update(NULL); will disable v-ram updates.

And, here it the source code…

http://dl.dropboxusercontent.com/s/cupgyz9bg8ibjny/lesson22.zip

lesson22



Viewing all articles
Browse latest Browse all 88

Trending Articles