Overview
Una Aventura Inesperada uses the Nintendo DS dual-screen architecture with two distinct rendering modes: framebuffer mode (MODE_FB0) for the main screen displaying menus/HUD, and tiled background mode (MODE_0_2D) for the sub-screen displaying gameplay.Display Modes
The game switches between display modes depending on the current screen:Framebuffer Mode (Main Screen)
Used for menus, HUD, and full-screen images:16-bit framebuffer mode that provides direct pixel access. The main screen uses VRAM_A as the framebuffer.Resolution: 256x192 pixels (49,152 pixels total)Color depth: 16-bit (RGB555 format via RGB15 macro)
GenerarNivel() (main.c:801):
The framebuffer pointer
fb is initialized in main() (main.c:169): fb = VRAM_A;Each pixel is addressed as fb[y*256 + x] where y ∈ [0,192) and x ∈ [0,256).Tiled Background Mode (Sub Screen)
Used for gameplay with tile-based graphics:Tiled background mode supporting up to 4 background layers. The game uses only BG0.
Enables background layer 0 for rendering. Other layers (BG1-BG3) remain disabled.
CrearMenu() (main.c:884):
32x32 tile map (1024 tiles total, each 8x8 pixels)
256-color palette mode (each tile references palette indices)
Map data starts at base 0 of BG map RAM
Tile graphics start at base 1 of BG tile RAM
Dual Screen Setup
The Nintendo DS has two screens, configured independently:Main Screen (Upper Display)
Purpose: Displays menus, HUD, dialog images, and cinematics VRAM Banks: VRAM_A (primary) and VRAM_B (unused but enabled)Configures VRAM bank A for LCD display output.Flags:
VRAM_ENABLE- Enable the bankVRAM_A_LCD- Map to main screen LCD
Sub Screen (Lower Display)
Purpose: Displays tile-based gameplay graphics VRAM Bank: VRAM_C (mapped to sub-screen backgrounds)Configures VRAM bank C for sub-screen background tiles.Flags:
VRAM_ENABLE- Enable the bankVRAM_C_SUB_BG- Map to sub-screen background memory
VRAM Configuration
The game uses three VRAM banks:Memory Layout
| Bank | Size | Purpose | Mapping |
|---|---|---|---|
| VRAM_A | 128KB | Main screen framebuffer | VRAM_A_LCD |
| VRAM_B | 128KB | Unused (enabled but not accessed) | VRAM_B_LCD |
| VRAM_C | 128KB | Sub screen tiles/maps | VRAM_C_SUB_BG |
Tile and Map Memory
Configured inmain() (main.c:171-172):
Points to tile base 1 in sub-screen VRAM. Each tile is 64 bytes (8x8 pixels, 8 bits per pixel).Address calculation: Base address + (tile_index × 64)
Points to map base 0 in sub-screen VRAM. Each entry is a 16-bit tile index.Map size: 32×24 tiles (768 entries, though 32×32 is allocated)
Framebuffer Drawing
Direct pixel manipulation is used for the stamina bar (main.c:809-813):Stamina Bar Updates
TheActualizarBarraMovimientos() function (main.c:853) erases segments:
RGB15 Macro
Colors use the RGB555 format (5 bits per channel):RGB555 precision: Each channel has 32 levels (0-31). To convert 8-bit RGB:
RGB15_value = RGB8_value >> 3For example, RGB(128, 255, 64) becomes RGB15(16, 31, 8).Background Layers
The game uses only BG0 on the sub-screen:Enables background layer 0. Layers 1-3 remain disabled to save processing power.
Map Memory Layout
Tiles are stored in row-major order:- (16, 22):
mapMemory[22*32 + 16] - (17, 22):
mapMemory[22*32 + 17] - (16, 23):
mapMemory[23*32 + 16] - (17, 23):
mapMemory[23*32 + 17]
DMA Transfers
The game uses Direct Memory Access (DMA) for high-speed memory copies:Image Loading
Pointer to source data (typically a bitmap array from an include file)
VRAM destination (
VRAM_A for main screen)Number of bytes to copy. For 256×192 16-bit images:
256 × 192 × 2 = 98,304 bytesTile Loading
TheInicializarTeselas() function (main.c:1065) loads all tile graphics:
Tile memory offset calculation:Each 8×8 tile occupies 64 bytes (8 pixels × 8 pixels × 1 byte per pixel).To load tile N:
tileMemory + (64 * N)DMA Performance
DMA is significantly faster than CPU memcpy:| Operation | CPU Copy | DMA Copy |
|---|---|---|
| 98KB image | ~50,000 cycles | ~1,000 cycles |
| 64-byte tile | ~320 cycles | ~10 cycles |
Palette System
The sub-screen uses a 256-color palette initialized inmain() (main.c:175-201):
Palette Indices in Tile Data
Each pixel in a tile stores an 8-bit palette index (0-255). The tile data format:Performance Optimization
The rendering system is optimized for the DS hardware:- DMA for large transfers - 50× faster than CPU memcpy
- Minimal per-frame updates - Only changed tiles are rewritten
- Single background layer - Reduces hardware workload
- Paused animations during dialogs - Saves CPU cycles
- VBlank synchronization - Prevents tearing without double buffering
Rendering budget per frame (60 FPS):
- VBlank period: approximately 1.6ms (for VRAM writes)
- Active display: approximately 15ms (for game logic)
- Player movement: approximately 8 tile writes (less than 100μs)
- Animation update: approximately 12 tile writes (less than 150μs)
- Stamina bar: approximately 144 pixel writes (less than 500μs)