N64 programming (libdragon)

Discussion in 'Nintendo Game Development' started by BMBx64, Sep 2, 2017.

  1. BMBx64

    BMBx64 Newly Registered

    Sep 2, 2017
    Likes Received:
    Hi, i did some tests on N64 and some improvements on libdragon on the past months, i was tempted to post here but the forum was down? Anyway i will show my progress, sorry for my english.

    I've focused all my efforts on improving and expanding rdp.c, these are all the features added so far:
    - Sprite flip (vertically, horizontally or both)
    - Sprite zooming (Scale X, Scale Y, both)
    - Virtual center align
    - Alpha blending (32 levels on 16bit mode)
    - Additive blending (somewhat)
    - Intensify / Color Mask and other kind of effects using different color combiners
    - 4 and 8bit texture support
    - Set other modes options: enable copy / 1cycle, enable tlut, enable bilinear filter (useful for zooming), enable atomic prim, etc
    - Bug fixes: RDP textures works now on 32bit mode
    - Some other fixes

    These features are tested on the following examples (used real hardware or CEN64):

    FLIP (Iridion 3D sample)
    Replicates a bit the effect of Iridion 3D (GBA) which indeed uses a small portion of the screen, then the tiles are mirrored.

    GBA uses a small area then scrolls, so i had to set 256x240 with black borders.

    Sprites are sets of 172x8 loaded only once on TMEM to be mirrored, it seems it takes a bit to load, they are 480 files and about 1,30MB for the full animation (16bit textures).

    The example looks like this:


    The function brings a virtual center to X/Y coordinates plus support for multiple sprite joins, mirrored sprites are aligned, the scaled textures will attempt to align equally.

    Textures on libdragon are 0,0 aligned, left pic, on the center the animation uses custom coords for X/Y axis, the right pic shows the number of rectangles, sometimes they can fit TMEM (32x64) or they are split in parts.

    Program example:

    A - Mirror horizontally
    B - Mirror vertically
    Z - Delays animation 1 second
    L - Stops animation for a while
    C up/dowm - Scale Y
    Dpad - Joysticks - Moves the reference pointer


    Small test that shows 32 levels of transparency in 1cycle mode (16bit mode / RDP).

    A - Flip Sprite
    Z - Enable/Disable Additive blending
    L/R - Alpha control
    Joy - Scroll
    C buttons - X / Y Scale (zoom)


    PALETTE EDITOR (4bit texture)
    Uses a 4bit sprite (1cycle, 2x scaled), you can pick a color from the table (get pixel from the framebuffer) and replace any palette color.

    By pressing L starts an automatic palette rotation, you can stop it at any time with R.

    Joystick - Mouse
    A - Pick color
    L/R - Start/Stop palette rotation
    Z - Reverse changes (only 1 slot)
    Start - Default palette


    RGB from 0 (normal) to 255 (white), can do this:

    Shows the sprite silouette in 1 RGB color, can do this kind of effects:

    Besides RDP functions i have added some maths to allow different visual effects (fget_angle, fget_dist, get_distx, get_disty).

    Since i don't have yet raster effects (buffer) i had to use giant horizontally textures (256x4), so i can move the blocks separately.

    - Libdragon won't allow textures beyond 256 wide, they are repeated at this point or mirrored depending on the settings.

    The effect is generated in real time (instead of tables) and can be edited:
    C left / C right = wave
    C up / C down = radius
    A / B = Speed
    R = hide text

    A better gif (graphics sample from Last Blade 2):


    The whole soundtrack converted into ogg 44KHz/Stereo/128kbps using libogg, 34 songs, fits on a 64MB cartridge, plays from start to end, can skip songs with c button.

    It slowdowns 25fps to sync with the audio (audio needs improvements), but since its static background there is no problem at all, colors of the background are specifically selected to minimize audio buzz on bad AV cables.


    RDP rectangles (non textured) of 4x4 with blue color, the random function was replaced by a new one since it was not working properly.

    5600 rectangles at 60fps
    7120 rectangles at 50fps

    *Performance based on libdragon, not the system itfself.


    I made a scroll engine for N64, the performance is very dependant on the size of the texture and how many times is reloaded, besides all the basic functionality have 2 optimizations.

    Discard areas
    This map have 6 scroll layers, but mostly covered by the main layer:

    Performance (same spot area):
    - 90fps (main scroll - 16x16 tiles)
    - 116fps (64x32 tiles)

    Each tile checks a binary list to discard covered tiles..

    - 159fps (main scroll - 32x32 tiles)
    - 178fps (64x32 tiles)

    *These tests are currently old, the performance is higher in all them.

    - Joystick
    - Z disables main layer


    Texture sort
    Drawing scroll in texture order with a display list, uses qsort for ordering.

    - 104fps (16x16 tiles)
    - 169fps (with texture order)


    32BIT TEST
    Textures on this mode had to be set to 1cycle to be displayed with the RDP or system crashes (they worked on software render on libdragon examples, but thats pretty slow).

    32bit mode supports textures of 4,8,16 and 32bits.
    16bit mode supports textures of 4,8,16 and 32bits too (they are converted on the fly)

    This is a screen build with 32bit textures of 16x16 32bit mode in cen64.

    16bit mode with 32bit textures, the colors are lowered as you can see banding on the sky.

    The test uses 320x240 scroll to display that screen.


    I may upload the changes i did on libdragon once i fixed few bugs, to name some:
    - Triple buffer is not working, you get full speed instead of sync video
    - AA disabled causes glitches at 60hz (PAL seems fine)
    - Fix loading speed, load 1200 tiles/files of 512bytes = 47 seconds
    - 4, 8 textures can't use full 2KB of TMEM (this is top priority)
    - Palette colors are sent in a different way, to upload 16 colors you have to send 64 instead (4 times more)
  2. Piratero

    Piratero Peppy Member

    Feb 28, 2009
    Likes Received:
    This is all amazing work.

    Have you thought about forking libdragon on GitHub and pushing all the work onto your fork?
  3. sanni

    sanni Intrepid Member

    May 30, 2008
    Likes Received:
    Great work :)
  4. BMBx64

    BMBx64 Newly Registered

    Sep 2, 2017
    Likes Received:
    Thx :)

    Yeah i been recommended to upload all the work on github, so people can keep track of the progress or send improvements, i could do it soon.

    Libdragon github had an update 4 days ago, im not sure if the owner is still interested on accept requests.

    I forgot to show a list of all the new RDP functions:

    // create RDP commands externally
    void rdp_command( uint32_t data );
    void rdp_send( void );

    // Virtual center sprites
    void rdp_cp_sprite( int x, int y, int flags, int cp_x, int cp_y, int line ); // faster
    void rdp_cp_sprite_scaled( int x, int y, float x_scale, float y_scale, int flags, int cp_x, int cp_y, int line );

    // Set other modes options
    void rdp_enable_filter( int type );
    void rdp_enable_tlut( int type );
    void rdp_enable_1primitive( int type );
    void rdp_texture_1cycle( void );

    // Color combiner
    void rdp_enable_alpha( int type );
    void rdp_additive_blending( void );
    void rdp_intensify( void );
    void rdp_color( void );
    void rdp_rgba_scale(uint8_t _r, uint8_t _g, uint8_t _b, uint8_t _alpha); // prim color

    // Palettes
    void rdp_load_tlut(uint8_t _pal_bp, uint8_t _pal_num, uint16_t *_palette);

    // Triangles (0 = flat, 1 = goraud, 2 = textured, etc)
    void rdp_triangle_setup( int type );

    Color triangles are already supported and textured triangles are on the works (to do sprite rotating for example), it needs to update texture coefficients accordingly.
    takensorryuser likes this.
  5. BMBx64

    BMBx64 Newly Registered

    Sep 2, 2017
    Likes Received:
    I made a github page but its not a fork / clone of the original libdragon, im learning yet how it works github so this is just a test, i did uploaded some files in case someone is interested.


    The interesting ones are rdp.c & rdp.h, there is one TLUT example as well, i will keep adding more examples.

    On tools you can find an update of Sprite 64.
    For 4 and 8 bit use PNG TO TILEMAP of a max of 64x32x4bit or 32x32x8bit textures, they are not fixed yet and PNG TO SPRITE will attempt to reach the maximum size for each sprite.

    I will explain a bit the tool in case anyone is interested:

    This tool can generate N64 textures compatible with libdragon format.

    Input: png folder (drop all the pngs here, will ignore any other file or subfolder)
    Output: sprite folder (N64 sprite textures)

    If enabled the tool will generate arrays of all the data generated.

    Do a PNG replica of the converted textures as well, plus other features.

    The textures compressed will have .zsprite extension instead of .sprite, it needs zlib on N64, not sure if i can find one already ported.

    Group: Everything on the same folder, textures will be named in order, starting from 0 on sprites and 1 on tilemaps (0 is empty).
    Separated: Every png conversion have his own folder (useful when many sprites)

    The tool will use the right TMEM size based on performance preference, an example:

    Libdragon limits:
    - Horizontal size: textures have to be pair, the tool fixes uneven sizes by adding empty space.
    - Vertical size: textures can be any of these sizes: 4,8,16,32,64,128,256
    - Maximum size: 256 width or height

    Based on the optimized textures generated the tool will attemp to find any empty area for the best result.

    Optimize L: Optimize from the left, this can cause alignment problems, but i did a workaround on libdragon.
    Optimize R: Optimize from the right, no issues found.

    Original texture of 68x69: 18,3KB (32bit)
    Texture conversion (68x72, 9 steps * 8 height): 19,1KB
    Optimize R: 14,8KB
    Optimize L+R: 11,2KB
    Zlib: 1,60KB

    * Optimize works diferently on 16bit mode.

    Will make transparent the color input for all the png files, it also supports transparent alpha channel.

    Will convert a png into a tilemap while converts the tiles into N64 textures.

    If include png is enabled will generate:
    - A copy of the full map
    - A copy of all the tiles
    - A tileset of all the tiles generated

    If include code is enabled will generate:
    - Different arrays of the tilemap as .c files (code.c)

    Allows a custom valid size, even if its beyond the 4KB TMEM, in case we want to use software render.

    Will check if the tile is repeated by mirroring and generate flags.c if any found.

    SMB map example

    Tileset of 8x8 (but we want bigger textures on N64 for better performance)

    Tileset of 16x16, less tile match, but better performance.

    Goldenaxe II example

    Tileset of 16x16, deducted mirrored tiles

    - Tiles that are completely transparent will be deducted.
    - If check tile and include code are disabled, all the tiles from the map will be generated. (since we don't know the array)

    The second step of the tool is animator viewer and CP editor.

    The gif is a bit self explanatory.

    Tick is the delay of the animation.
    View provides a ghost reference for faster align.
    Rect shows all the rectangles and the number of textures generated for that concrete png.
    BG changes the background, so we can test if a sprite have "hidden transparent pixels" inside.

    F1 - Normal window size
    F2 - Double size
    Left / Right - Anim left or right
    Up / Down (mouse wheelup/wheeldown) - Zoom
    Num keys - Input
    Mouse for anything else

    This will generate extra files if include code is enabled:
    - animcp_save.dat, the session of the program in case we want to edit later.
    - animcp.cp arrays of all the editable content
    * CP x and CP y are embedded on sprite format by using hslices/vslices, so you don't need to save or remember them.

    VERSION 1.1
    - Added 4bit and 8bit texture support and optimized sizes
    - Added tlut.c generation (and tlut.png table view)
    - Added palette reference function, rename a png into "tlut" on sprite folder to force a concrete palette order

    Tilemap mode:
    - Bug fix on optimize size
    - Improved generation of code.c
    - Added a custom start button for tile generation
    - Added bit.c generation (a binary map to identify tiles of any transparent pixel)
    - if no transparent areas are found bit.c won't be generated

    Tlut.png example (from Goldenaxe map)
    takensorryuser likes this.
  6. Greg2600

    Greg2600 Resolute Member

    Jun 23, 2010
    Likes Received:
    My technical ignorance prevents me surely from appreciated what's accomplished, but it looks/sounds very cool! Particularly for the future. Consider myself an N64 fan, and further homebrew on that system would be very nice.
  7. saturnu

    saturnu Spirited Member

    Dec 8, 2011
    Likes Received:
    i already tested it out and compiled the example. ^^
    thanks for sharing this.

Share This Page