Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

HELLGRID

First-person shooter for the PlayStation 1, written in Rust.

DDA raycasting engine (Wolfenstein/Doom style), fixed-point math, textured walls, enemy sprites, SPU audio — all running on real PS1 hardware via RetroArch.

╔══════════════════════════════════════════════╗
║        H E L L G R I D  —  PS1 FPS         ║
║  Survive the grid. Find the exit. Get out.  ║
╚══════════════════════════════════════════════╝

Requirements

In WSL (Ubuntu/Debian):

  • gcc-mipsel-linux-gnu — MIPS cross-compiler
  • python3 + Pillow — texture conversion
  • ffmpeg — audio conversion
  • rustup nightly with rust-src component

Run the one-time setup:

bash build-wsl.sh setup

Build

# Full build: convert assets → compile Rust → create disc image
bash build-wsl.sh build

# Quick rebuild (skip asset conversion):
bash build-wsl.sh quick

# Just recompile Rust:
bash build-wsl.sh rust

Output: hellgrid.cue + hellgrid.bin


Play

Load hellgrid.cue in RetroArch.

Recommended cores:

Core Notes
Beetle PSX HW Best accuracy, texture filtering
PCSX ReARMed Fast, good for lower-end devices
Mednafen PSX Cycle-accurate

Controls

Button Action
D-pad Up / Down Move forward / backward
D-pad Left / Right Turn
L1 / R1 Strafe left / right
Cross (✕) Shoot
START Pause
START (on Game Over) Restart

Objective: Kill all enemies, find the golden exit tile, survive.


Project Structure

hellgrid/
├── src/
│   ├── main.rs              — entry point, game loop
│   ├── hw.rs                — PS1 MMIO register addresses
│   ├── math.rs              — Q16.16 fixed-point, sin/cos table
│   ├── gpu.rs               — GPU primitives, TIM loader, VRAM upload
│   ├── spu.rs               — SPU audio, VAG upload, voice management
│   ├── input.rs             — SIO0 controller polling
│   ├── level.rs             — 24×24 tile map, collision types
│   ├── game.rs              — player, enemies, game state, AI
│   ├── raycast.rs           — DDA raycaster, wall/sprite/weapon render
│   ├── hud.rs               — HP bar, ammo, score, overlays
│   └── assets_data_stub.rs  — empty asset stubs (used before pipeline runs)
│
├── tools/
│   ├── prepare_assets.py    — master asset pipeline (PNG→TIM, OGG→VAG)
│   ├── png2tim.py           — PS1 TIM 4bpp converter
│   ├── wav2vag.py           — PS1 ADPCM VAG encoder
│   ├── make_psexe.py        — ELF binary → PS-EXE header
│   ├── make_iso.py          — Mode2/2352 ISO 9660 disc builder
│   └── SYSTEM.CNF           — PS1 boot config
│
├── assets/
│   ├── raw/
│   │   ├── textures/tiny-dungeon/Tiles/  — CC0 source tiles (16×16 px)
│   │   ├── sounds/sfx/                   — CC0 sound effects (.ogg)
│   │   └── music/dungeon_ambient.ogg     — CC0 ambient music
│   ├── tim/                 — generated: converted textures
│   └── vag/                 — generated: converted audio
│
├── crt0.s                   — MIPS startup: SP/GP init, BSS clear, jal main
├── psexe.ld                 — linker script: load at 0x80010000, 2MB RAM
├── Cargo.toml               — no_std binary, release: opt-size + LTO
├── .cargo/config.toml       — mipsel-sony-psx target, mipsel-linux-gnu-ld
├── Makefile                 — make all / assets / build / iso / run / clean
└── build-wsl.sh             — full WSL pipeline script

Technical Details

Engine

  • Renderer: DDA raycasting — one ray per screen column (320 rays)
  • Math: Q16.16 fixed-point throughout; no floating point, no FPU
  • Trig: 256-angle lookup table, quarter-wave (65 entries + symmetry)
  • Textures: PS1 TIM 4bpp, 64×64px, loaded into VRAM via CPU→VRAM DMA
  • Sprites: camera-space projection with Z-buffer occlusion
  • Double buffering: draw buffer alternates VRAM Y=0 / Y=240

PS1 Hardware Used

Unit Usage
GPU PolyFT4 (textured quads), Tile, Fill, LineF2
SPU 24-voice ADPCM, DMA upload via FIFO
SIO0 Digital pad polling
VRAM 320×240×2 display buffers + 8 texture slots + CLUTs

VRAM Layout

(0,   0)–(319, 239)  display buffer 0   (15bpp)
(0, 240)–(319, 479)  display buffer 1   (15bpp)
(320,  0)–(383,  63) wall_stone.tim     4bpp  CLUT @ (0,  480)
(384,  0)–(447,  63) wall_metal.tim     4bpp  CLUT @ (16, 480)
(448,  0)–(511,  63) wall_blood.tim     4bpp  CLUT @ (32, 480)
(512,  0)–(575,  63) wall_panel.tim     4bpp  CLUT @ (48, 480)
(576,  0)–(639,  63) floor.tim          4bpp  CLUT @ (64, 480)
(640,  0)–(703,  63) ceiling.tim        4bpp  CLUT @ (80, 480)
(704,  0)–(767,  63) enemy.tim          4bpp  CLUT @ (96, 480)
(768,  0)–(831,  63) weapon.tim         4bpp  CLUT @ (112,480)

Asset Pipeline

PNG (16×16) ──[×4 nearest]──► 64×64 ──[4bpp quantize]──► TIM ──► embedded in EXE
OGG/WAV ──[ffmpeg → PCM]──► 22050 Hz mono ──[ADPCM encode]──► VAG ──► embedded in EXE

All assets are embedded as [u8; N] static arrays in src/assets_data.rs (generated). No file loading at runtime.

Rust Configuration

[profile.release]
opt-level     = "s"   # optimize for size
lto           = true
panic         = "abort"
overflow-checks = false

Target: mipsel-sony-psx (Tier 3, requires -Z build-std=core).


Asset Credits

All assets are CC0 (public domain):

Asset Source
Textures Kenney Tiny Dungeon
Sound effects 100-CC0-SFX pack
Music Loopable Dungeon Ambience (CC0)

Makefile Targets

make all      — full build (assets + compile + ISO)
make assets   — convert PNG/OGG to TIM/VAG
make build    — compile Rust to ELF
make psexe    — ELF → PS-EXE
make iso      — PS-EXE → hellgrid.cue / hellgrid.bin
make run      — launch in mednafen or pcsx-redux
make check    — cargo check (no link)
make clean    — remove build artifacts

About

First-person shooter for the PlayStation 1, written in Rust. DDA raycasting engine (Wolfenstein/Doom style), fixed-point math, textured walls, enemy sprites, SPU audio — all running on real PS1 hardware via RetroArch.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages