This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
RBDOOM-3-BFG is a modernization of id Software's DOOM-3-BFG (id Tech 4 BFG) engine: PBR, HDR lighting, soft shadow mapping, TAA/SMAA, glTF2 support, and a DX12/Vulkan renderer through NVRHI. The engine, game code (d3xp), tools, and classic Doom are all compiled into one executable, RBDoom3BFG, plus a standalone map/AAS compiler, rbdmap.
Prerequisites: Vulkan SDK, SDL2, OpenAL, ncurses, ispc, and a dxc binary (DirectXShaderCompiler v1.8.2405) on PATH or passed via -DDXC_CUSTOM_PATH=<dir> (directory only, not the binary path). The NVRHI and ShaderMake submodules must be checked out first:
git submodule update --init --recursiveConfigure with the provided scripts, which must be run from inside neo/ (they wipe and recreate <repo>/build/):
cd neo
./cmake-linux-release.sh # or cmake-linux-debug.sh / cmake-linux-retail.sh
cd ../build
make -j$(nproc)There is no test suite anywhere in the project — verification is manual (build, run, use in-engine cvars/ImGui stats, RenderDoc/Nsight/Optick).
Build gotchas:
FFMPEG=ONandBINKDEC=ONare mutually exclusive (CMake fatal error).- Stale
neo/idlib/precompiled.h.gchorneo/tools/compilers/precompiled.h.gchfiles break GCC/Clang builds; the cmake-linux scripts delete them first. PCH is hand-rolled in CMake (nottarget_precompile_headers). - Shader compilation writes
.binblobs into the source tree atbase/renderprogs2/(orcontent/renderprogs2/whenSTANDALONE=ON), so building dirties the work tree. - Most source dirs are collected with
file(GLOB)inneo/CMakeLists.txt(re-run CMake after adding a file), butd3xp/andsound/use explicitset()lists — new files there must be added toneo/CMakeLists.txtby hand. - Notable CMake options:
STANDALONE(usecontent/instead ofbase/, disables classic Doom),DOOM_CLASSIC(default ON),USE_VULKAN(default ON),USE_DX12(forced OFF on UNIX),OPENAL(forced ON on UNIX),RETAIL,OPTICK,ONATIVE,COMPILE_COMMANDS(emitcompile_commands.json).
Running requires the retail DOOM 3 BFG base/ assets copied into <repo>/base/ and the binary run from the repo root. Mods launch via +set fs_game <modDir>.
Formatting is fully mechanical via Artistic Style (astyle) 2.05.1 exactly — the scripts hard-fail on other versions. Run from inside neo/ before committing:
cd neo && ./astyle-code.sh # uses bundled neo/astyle.x86_64Style summary (from neo/astyle-options.ini): Allman braces, hard tabs (width 4), spaces inside parens id-style — if( isFoo( a, b ) ) — pointer/reference bound to the type (char* foo), braces required on single-statement conditionals. Never reformat neo/libs/, neo/extern/, or the files excluded in the astyle scripts.
Conventions: classes are id-prefixed (idRenderWorld), functions carry /* ===== FunctionName ===== */ banner comments, and fork-specific changes are delimited with author markers (// RB begin / // RB end, // SRS -, // DG:) — preserve this convention when patching near them. Every engine .cpp starts with #include "precompiled.h" + #pragma hdrstop; nearly all subsystem headers are reachable through the PCH (neo/idlib/precompiled.h), so follow that pattern instead of ad-hoc includes.
All C++ sources live under neo/; base/ is version-controlled game data (defs, materials, scripts, TrenchBroom FGDs); doomclassic/doom/ is the embedded classic Doom engine (bridged via doomclassic/doom/doominterface.cpp, switched in idCommonLocal::PerformGameSwitch()).
neo/idlib/— foundation static library: strings, containers, math/SIMD, lexer/parser,MapFile(.map and glTF2), threading/ParallelJobList, and the PCH.neo/framework/— engine core: cvars, commands, console, virtual filesystem (.pk4/.resources), decl system, event loop. The main loop lives inidCommonLocal::Frame()inneo/framework/common_frame.cpp.neo/renderer/— split into a frontend (CPU scene traversal, portal + masked occlusion culling, produces drawSurf lists:tr_frontend_*.cpp, globaltr) and a backend (consumes command buffers, issues draw calls through NVRHI:RenderBackend.cpp,renderer/NVRHI/, globalbackEnd), decoupled by double-buffered frame data (SwapCommandBuffers). Backend code must never modify frontend-owned globals (seeRenderCommon.h). Graphics abstraction is NVRHI (submodule inneo/extern/nvrhi) with DX12 and Vulkan backends — there is no OpenGL path anymore despite legacy file names likeGLState.h. Device/swapchain creation is inneo/sys/DeviceManager_{VK,DX12}.cpp.neo/shaders/— HLSL sources; permutations are declared inneo/shaders/shaders.cfgand compiled by ShaderMake (neo/compileshaders.cmake) to DXIL/SPIR-V blobs loaded at runtime byneo/renderer/NVRHI/RenderProgs_NVRHI.cpp.neo/d3xp/— all game logic: entities, player, weapons, AI, physics, Doomscript VM (script/), SWF-driven menus (menus/). The classicGetGameAPIDLL interface still exists ind3xp/Game.hbut the game is statically linked into the executable.neo/sys/— OS layer (posix/,win32/, SDL2 undersdl/) plus the BFG session/lobby/snapshot netcode. Linux entry point:main()inneo/sys/posix/platform_linux.cpp.neo/sound/— sound frontend with swappable backends:OpenAL/,XAudio2/,stub/.neo/swf/— Flash/SWF player with ActionScript2 VM; drives all BFG shell menus.neo/ui/is the legacy Doom 3.guisystem, still used for in-world surfaces.neo/cm/— collision model manager;neo/aas/— AAS navigation runtime (the AAS builder is inneo/tools/compilers/aas/).neo/tools/compilers/— dmap BSP compiler + AAS builder, built both into the engine and as standalonerbdmap.neo/tools/imgui/— in-engine ImGui editors (light editor, AF editor).neo/extern/— git submodules (nvrhi, ShaderMake).neo/libs/— vendored third-party code (imgui, zlib, rapidjson, stb, libbinkdec, moc, vma, …); never modify formatting or style there.
Engine subsystems are reached through global interface pointers declared at the bottom of their interface headers: common, cvarSystem, cmdSystem, fileSystem, declManager (framework), renderSystem/tr/backEnd/renderProgManager/globalImages (renderer), soundSystem, game/gameEdit (d3xp/Game.h), uiManager, collisionModelManager, session, sys.