Skip to content

L04 — Assets on ROM (DFS)

Goal

Understand that game assets live inside the ROM, convert a PNG to a libdragon sprite, pack it with the Dragon File System (DFS), and draw it with RDPQ.

What you will see

A bobbing star sprite and text explaining the pipeline:

text
PNG → mksprite → DFS → sprite_load("rom:/…")

Why not fopen("star.png") on your PC?

The finished game is a single .z64 image. On real hardware there is no access to your laptop’s files. Assets must be:

  1. Converted to console-friendly formats at build time
  2. Embedded in the ROM
  3. Loaded at runtime via paths like rom:/star.sprite

That embedded filesystem is DFS (Dragon File System).

Build pipeline

text
assets/star.png

       │  mksprite  (host tool)

filesystem/star.sprite

       │  mkdfs + n64tool  (link into .z64)

rom:/star.sprite   ←  sprite_load() at runtime

Course Makefiles do this automatically when assets/*.png exists (common/lesson.mk).

Lesson Makefile note

make
MKSPRITE_FLAGS := -f RGBA16
include ../../common/lesson.mk

RGBA16 is a simple full-color format for teaching. Later you will meet CI4/CI8 palettes and TMEM limits (L05 + graphics modules).

Runtime code

c
dfs_init(DFS_DEFAULT_LOCATION);

sprite_t *star = sprite_load("rom:/star.sprite");

/* in render: */
rdpq_set_mode_standard();
rdpq_mode_alphacompare(1);   /* skip fully transparent texels */
rdpq_sprite_blit(star, x, y, NULL);
CallRole
dfs_initMount the ROM filesystem (once at startup)
sprite_load("rom:/…")Load a packed sprite by ROM path
rdpq_sprite_blitDraw it with the RDP

Path prefix

Always use the rom:/ prefix for DFS assets. A bare star.sprite or a host path will not work on console.

Build & run

bash
source scripts/env.sh
make -C lessons/l04-dfs
# → lessons/l04-dfs/l04_dfs.z64

make clean in the lesson folder also removes generated filesystem/.

Exercises

  1. Replace assets/star.png with your own 32×32 or 64×64 PNG; rebuild.
  2. Draw the sprite in two places (two blits).
  3. (Stretch) Add a second PNG and load both.

Troubleshooting

ProblemFix
Red screen / load failedAsset not packed — check filesystem/star.sprite after build
Invisible spriteWrong path; or fully transparent PNG; enable alphacompare carefully
Build skips spritePut PNG under assets/ with .png extension

Full lesson source

The blocks below are imported from the real repository files at build time (VitePress <<< snippets). They are not hand-copied into this markdown.

lessons/l04-dfs/Makefile · lessons/l04-dfs/src/main.c

lessons/l04-dfs/Makefile
make
# Lesson 04 — Assets on ROM (DFS)
ROMNAME   := l04_dfs
ROM_TITLE := "L04 DFS"

# Prefer a simple RGBA16 sprite for the teaching asset.
MKSPRITE_FLAGS := -f RGBA16

include ../../common/lesson.mk
lessons/l04-dfs/src/main.c
c
/**
 * L04 — Assets on ROM (DFS)
 * ============================================================================
 * Assets live *inside* the .z64, not on your PC at runtime.
 *   PNG → mksprite → filesystem/(name).sprite → packed DFS → rom:/name.sprite
 * Always dfs_init() then sprite_load("rom:/...").
 * DOCS: docs/guide/m0/l04-dfs.md
 */


#include <libdragon.h>
#include <stdio.h>

int main(void)
{
    display_init(RESOLUTION_320x240, DEPTH_16_BPP, 2, GAMMA_NONE,
                 FILTERS_RESAMPLE);
    dfs_init(DFS_DEFAULT_LOCATION);
    rdpq_init();
    rdpq_text_register_font(1, rdpq_font_load_builtin(FONT_BUILTIN_DEBUG_VAR));

    /* Paths are on the *ROM* filesystem — not your PC's disk. */
    sprite_t *star = sprite_load("rom:/star.sprite");
    if (!star) {
        /* Should not happen if Makefile packed filesystem/star.sprite */
        while (1) {
            surface_t *disp = display_get();
            rdpq_attach(disp, NULL);
            rdpq_clear((color_t){ .r = 64, .g = 0, .b = 0, .a = 255 });
            rdpq_text_print(NULL, 1, 40, 100, "Failed to load rom:/star.sprite");
            rdpq_detach_show();
        }
    }

    float t = 0.0f;

    while (1) {
        t += 0.04f;
        /* Gentle bob for juice */
        float bob = fm_sinf(t) * 8.0f;
        float x = 144.0f;
        float y = 100.0f + bob;

        surface_t *disp = display_get();
        rdpq_attach(disp, NULL);
        rdpq_clear((color_t){ .r = 16, .g = 20, .b = 40, .a = 255 });

        rdpq_text_print(NULL, 1, 24, 28, "L04 — DFS assets");
        rdpq_text_print(NULL, 1, 24, 48, "Loaded rom:/star.sprite");

        rdpq_set_mode_standard();
        rdpq_mode_alphacompare(1);
        rdpq_sprite_blit(star, x, y, NULL);

        rdpq_text_print(NULL, 1, 24, 200, "PNG -> mksprite -> DFS -> sprite_load");

        rdpq_detach_show();
    }
}

What you learned

  • Assets are build-time converted and ROM-embedded
  • DFS + rom:/ paths
  • mksprite + sprite_load + rdpq_sprite_blit

Next

L05 — N64 hardware tour names the chips you have been using, then the Module 0 checkpoint proves L01–L04 together.

N64 Educator v1.2.2 — libdragon + Tiny3D · branch master