Skip to content

Add Rumble Racing (PS2)#909

Draft
mattbruv wants to merge 34 commits into
magcius:mainfrom
mattbruv:rumble-racing-ps2
Draft

Add Rumble Racing (PS2)#909
mattbruv wants to merge 34 commits into
magcius:mainfrom
mattbruv:rumble-racing-ps2

Conversation

@mattbruv

@mattbruv mattbruv commented May 20, 2026

Copy link
Copy Markdown

Well, this was a marathon of a coding project... This PR adds Rumble Racing to noclip.

A few noteworthy things about this implementation:

  1. The game calculates the actors' Y level, scale, and rotations at runtime using lots of heuristics based on the map's terrain, actor properties, etc. etc.. To get around having to spend another half year of my prime years in life reverse engineering all of this logic just to move a chicken up 0.1 meter (this is either genius or lazy, you decide) I took a save state using PCSX2 at the exact moment after loading the level, and scraped out the final actor Y levels and transformations. I've saved all of these in a JSON file based on the map and actor ID saved in the DATA folder. All of this data simply places the instanced actor models where they should be, and works for like 98% of the actors.
  2. This is my first experience with rendering 3D geometry (outside of previously writing this data to a gltf file), so I have probably made some horribly naive decisions as far as rendering the scene. Please let me know if I'm doing something dumb.

Known Visual issues:

  1. I was never able to figure out the alternating unwinding face issue when manually unwinding triangle strips, so I don't attempt any back-face culling
  2. I have done no reverse engineering of how the game does lighting, so the scenes have very basic lighting. Luckily the maps are still fun and visually OK to look at despite this issue
  3. I have not looked into how the game creates the panorama / skybox.
  4. I do not handle some alpha/transparent textures/geometry correctly yet. While imperfect, it doesn't take away from things too much.
image

@mattbruv
mattbruv force-pushed the rumble-racing-ps2 branch from 6f1078f to 75b3a01 Compare May 20, 2026 20:56
@mattbruv

Copy link
Copy Markdown
Author

A few more things I'd like to add when thinking more about this PR. Since the AI code in the other PR is getting torn up, I also want to be transparent up front about my AI usage before you review it so you don't go crazy wondering

First of all, please don't be dissuaded by reviewing this PR based on the 43,000 lines added. Almost 90% of that (37,000 lines) is just JSON data for actor transformations. Ignoring that, the actual amount of relevant LOC is like 5,000 LOC. I am definitely open to storing the JSON data in a different format/approach which would be more compressed and/or not inflate file size/LOC.

As far as how AI was used, I used Gemini/Claude to:

  • write decompress.go. The decompression routine was written entirely by AI
  • A fair amount of the Go code have been iterated on to varying degrees during the RE process, between both me and AI. In the Go codebase, I used AI as a tool to write out repetitive code in scenarios where it would have been annoying, (a majority of the VIF command parsing and VIF debug code for example).
  • The noclip specific TS code/structure is almost entirely AI written, and the shader code is 100% AI written). I basically started with the Example scene, and iterated on it with AI to start drawing simple models, then actors, and so on, until we're at the state it is in now.

There are lots of comments in the Go code which are remnants of earlier code, debugging code commented out, and so on. Since I basically copied the relevant code from my CLI tool and pasted it here, a fair amount of the comments and some code could be considered irrelevant.

As we briefly discussed a while ago, you guys said you'd be open to adding Go as a language to noclip. If, after looking at this PR, it seems like it would introduce more annoyances than it's worth, I am fine with re-writing the parsing code in TS / Rust in order to introduce less friction. If you'd rather have me scrap the Go stuff, it won't hurt my feelings.

@magcius

magcius commented May 23, 2026

Copy link
Copy Markdown
Owner

Thanks for the heads up. Sorry I'm so backed up with reviews.

Almost 90% of that (37,000 lines) is just JSON data for actor transformations. Ignoring that, the actual amount of relevant LOC is like 5,000 LOC. I am definitely open to storing the JSON data in a different format/approach which would be more compressed and/or not inflate file size/LOC.

For data like this, rather than have it be part of the initial code bundle, we could instead store it along with the game data, fetched at runtime.

@mattbruv

Copy link
Copy Markdown
Author

@magcius, I was able to have the all of the Go code ported to TS. Now everything is purely in TS. After some reflection I felt like asking noclip to support Go just for one game would unnecessarily introduce complications and bloat. Amazingly, Claude Sonnet 4.6 was able to one-shot the port and keep the code faithful to my original code. I've tested it locally and everything is good, it even feels like it loads faster now than before.

@mattbruv
mattbruv marked this pull request as draft July 11, 2026 19:37

@magcius magcius left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initial review.

Comment thread src/RumbleRacing/helpers/bytes.ts Outdated
Comment thread src/RumbleRacing/asset/o3d/chunk.ts Outdated
Comment thread src/RumbleRacing/asset/o3d/chunk.ts
Comment thread src/RumbleRacing/asset/o3d/vif.ts Outdated
return result;
}

export function swizzleClutPstm4_16<T>(data: T[]): T[] {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the existing gsMemoryMapReadImagePSMT4_PSMCT32 will do what you want?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most likely. I've gone ahead and referenced noclip's existing PS2 GS enums. Figuring out how PS2 texture swizzling was confusing for me at the time when I was writing the original Go code. I was able to figure out how swizzling and CLUTs worked on my own and implemented it in the way that made sense to me, but it is not ideal to have multiple implementations. I'll have to refresh myself on how this all works again and see if I can utilize noclip's implementation

Comment thread src/RumbleRacing/asset/o3d/geometry.ts Outdated
Comment thread src/RumbleRacing/chunk/shoc/decompress.ts Outdated
Comment thread src/RumbleRacing/chunk/shoc/shoc.ts Outdated
mattbruv added 2 commits July 12, 2026 18:52
commit 1306ce1
Author: Matt P <mattp3259@gmail.com>
Date:   Sun Jul 12 18:45:45 2026 -0400

    use existing PS2 GS enums for textures/cluts

commit 0f8ced1
Author: Matt P <mattp3259@gmail.com>
Date:   Sun Jul 12 18:33:39 2026 -0400

    add note

commit 2c31c03
Author: Matt P <mattp3259@gmail.com>
Date:   Sun Jul 12 18:00:32 2026 -0400

    use vec3/2

commit 2af39a8
Author: Matt P <mattp3259@gmail.com>
Date:   Sun Jul 12 17:08:37 2026 -0400

    remove bytes.ts helpers, use DataView and readString()

commit 546bf6a
Author: Matt P <mattp3259@gmail.com>
Date:   Sun Jul 12 15:18:28 2026 -0400

    remove uselss lambda function in decompress routine

commit acd0525
Author: Matt P <mattp3259@gmail.com>
Date:   Sun Jul 12 13:48:35 2026 -0400

    use new common VIF enums

commit 1f05c8b
Merge: 4b57327 12eb0f9
Author: Matt P <mattp3259@gmail.com>
Date:   Sun Jul 12 13:27:55 2026 -0400

    Merge remote-tracking branch 'origin/main' into pr-comments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants