==============================================================================
               NAUGHTY TILE-BASED BACKGROUND RENDERING ENGINE
                             Bart Trzynadlowski
==============================================================================

The Naughty Tile-Based Background Rendering Engine is public domain. This is
the documentation for version 0.0.

The author can be reached at trzy@powernet.net -- only useful feedback is
appreciated. Don't email me about anything stupid such as ROMs or software
that you want me to write for you.

This is a simple tile rendering engine which powered the Naughty NES emulator.
It does not facilitate scrolling, but it is just barely good enough to allow
you to quickly add it to see some graphics. It renders the entire background
at once.
        The code is in i386 assembly language. You will need NASM v0.97 or
better to assemble it. For users of DJGPP you would do:

        nasm -f coff nrender.asm

        This code has been designed for use with 32-bit compilers. I have
used it with DJGPP (gcc v2.8.1.) Of course, your mileage may vary. DJGPP can
be obtained at www.delorie.com/djgpp, NASM at www.web-sites.co.uk/nasm. Do
not turn to me if you can't find them, I will not help you with that problem.
Read on to see how to add this background rendering engine to your emulator.

External Dependencies:
        The renderer relies on some external data which must be present in
        your program.

        ** PPU control register 2 **
        You must have a byte-size variable which stores the value of PPU
        control register 2 when an NES program writes to it. Make sure to
        set the %define CTRL_REG_2 to the name of your variable (prefix it
        with an underscore if necessary for your C compiler to access it.)

                Example:

                In your C code:
                unsigned char   ppu_ctrl_reg_2;

                In nrender.asm:
                %define CTRL_REG_2      _ppu_ctrl_reg_2;

        ** Background pattern table **
        You are responsibly for providing a host pointer (unsigned char * in
        C) for the Naughty renderer to use. Remember, it must be a host
        pointer, and not just the address within NES VRAM space.

                Example:

                In your C code:
                unsigned char   *bg_pattern_table;

                In nrender.asm:
                %define BG_PTRN_TABLE   _bg_pattern_table;

        ** Name table **
        The current name table's host pointer.

                Example:

                In your C code:
                unsigned char   *current_name_table;

                In nrender.asm:
                %define NAME_TABLE      _current_name_table

        Be careful here! Naughty's renderer assumes that the attribute table
        for that given name table follows IMMEDIATELY after the name table
        data. Make sure it does, the best way to do this would be to make
        sure the name table and attribute table are in the same array.

        ** Image palette **
        The image palette's host pointer. This is so the renderer gets quick
        access to the NES image palette (note: this is what is found in NES
        VRAM, not a PC palette.)

                Example:

                In your C code:
                unsigned char   *img_pal;

                In nrender.asm:
                %define IMAGE_PALETTE   _img_pal

        ** Attribute lookup table **
        This is not as straightforward as the other stuff, to set it up you
        must declare it as an unsigned char array, like this:

                unsigned char   attrib_lookup[(32 * 30 * 4)+256];

        Then in nrender.asm you would modify the appropriate %define to read
        like this:

                %define ATTRIB_LOOKUP   _attrib_lookup

        Finally, you must initialize the attribute lookup table once. This
        should be done in your PPU initialization code, ppu_init() or whatever
        but it does not matter as long as you do not call the Naughty
        background renderer before you set up the array.
                This very ugly C code demonstrates how to set up the array:

                /* fill up attribute table lookup table */
                for (i = 0; i < 32 * 30 * 4;)
                {
                        for (j = 0; j < 4; j++)
                        {
                                if ((j == 0) || (j == 1))
                                        shr_count = 0;
                                else
                                        shr_count = 4;
                                for (k = 0; k < 32 / 4; k++)
                                {
                                        attrib_lookup[i] = attr_index;
                                        attrib_lookup[i+2] = shr_count;
                                        i += 4;
                                        attrib_lookup[i] = attr_index;
                                        attrib_lookup[i+2] = shr_count;
                                        i += 4;
                                        attrib_lookup[i] = attr_index;
                                        attrib_lookup[i+2] = (shr_count + 2);
                                        i += 4;
                                        attrib_lookup[i] = attr_index;
                                        attrib_lookup[i+2] = (shr_count + 2);
                                        i += 4;
                                        attr_index++;
                                }
                                attr_index -= 32 / 4;
                        }
                        attr_index += 32 / 4;
                }

        This table basically contains data which the renderer relies on
        internally. It describes which attribute table byte to use based on
        which name table entry the renderer is processing and the shift right
        count to use which aids in the isolation of the 2 bits the renderer
        wants from the attribute table. Yes, there is left-over space in each
        4-byte entry, this is from an older variant of the lookup table. I
        suppose you can use the free space if you want, just make sure not to
        alter the used bytes.

Internal Stuff:
        The renderer contains code and data of its own, the following is what
        you need to do to use it.

        ** Naughty tile-based background renderer **
        This is the background rendering code you call. Simply modify the
        %define for RENDER_BACKGROUND to call it whatever you want, make a
        prototype in your C code, and you're set.

                Example:

                In your C code:
                void    naughty_render_background();    /* prototype */

                In nrender.asm:
                %define RENDER_BACKGROUND       _naughty_render_background

        Since the engine renders the entire background at once, you only need
        to call it once during each VBlank. You will want to make sprites use
        a separate buffer. Blit the background first, then overlay the sprites
        on top of it.

        ** Video double buffer **
        The renderer has an internal double buffer of which 256x240 are used
        to render the background in 8-bit linear format. You can call it
        whatever you want by modifying its %define line.

                Example:

                In your C code:
                extern unsigned char    background[256 * 240];

                In nrender.asm:
                %define VIDEO_BUFFER    _background;

        The video buffer itself is located in the renderer's data space. You
        can access it from your C code to blit it. Internally, it is declared
        as a 256x320 byte array. I don't remember what causes it to require
        320 but it will crash if the value is smaller. Only 256x240 of it is
        drawn into, NTSC systems display 256x224 of this IIRC.

        ** Other stuff **
        The renderer has some other internal data, don't mess with it. It also
        has a plot macro, I would advise you not to mess with it either.

Things To Do:
        The Naughty background renderer does not support scrolling. With some
        serious hacking (if you're an assembly guru) you can modify how the
        code uses the internal variables CURRENT_TILE_X, CURRENT_TILE_Y, x,
        and y to make it scroll with tile-granularity. This would be very
        choppy. If you want scrolling, write your own engine, this is just a
        pathetic example.
                More optimization is needed. It would be possible to do away
        with the x and y variables (at least partially) and data from the
        attribute table could be read in once per Y loop instead of during
        each X loop. There is much that can be improved.

Good luck and have fun! If you have tried absolutely everything and it still
won't work for you, I might be able to help you depending on how I feel.


                          



                

                          
                          
                                       

