Developing a Space Flight Simulator in Clojure Date: 05 Sep 2025 By Jan Wedekind, software engineer specializing in software engineering, game development, and simulation. --- Introduction Inspired by the Orbiter 2016 space flight simulator, the author began developing a space flight simulator, starting with prototypes in C and GNU Guile, then moving fully to Clojure due to its advanced features such as multi-methods, efficient data structures, and support for safe parallelism via atoms, agents, and refs. The development has spanned almost five years. The initial focus was on challenging aspects like 3D rendering of planet surfaces, atmosphere, shadows, and volumetric clouds. Source code review of Orbiter reinforced the decision to begin with graphics. --- Software Dependencies The project runs on GNU/Linux and Microsoft Windows and uses several libraries: Clojure: primary programming language. LWJGL: Java wrappers for OpenGL, GLFW (input/windowing), Nuklear (GUI), stb (image/TrueType font I/O), and Assimp (loading 3D models). Jolt Physics: physics simulation for vehicles and mesh collisions. Fastmath: matrix, vector math, spline interpolation. Comb: shader code templating. Instaparse: parsing NASA Planetary Constant Kernel files. Gloss: parsing NASA Double Precision Array Files. Coffi: Clojure's foreign function interface. core.memoize: caching function results. Apache Commons Compress: reading map tiles in tar archives. Malli: function schema validation. Immuconf: load configuration files. Progrock: progress bars. Claypoole: parallel for loops. tools.build: project building. clj-async-profiler: profiling with flame graphs. slf4j-timbre: logging. OS-specific LWJGL bindings are managed via the deps.edn file; Windows support is maintained on a separate Git branch. --- Atmosphere Rendering Utilizes Bruneton’s precomputed atmospheric scattering, which involves iterated numerical integration for: 2D transmittance table 2D surface scattering table 4D Rayleigh and Mie scattering tables Key features: High-order integration functions over spheres, lines, and rays implemented in Clojure using fastmath vectors. Precomputation of atmospheric tables takes hours with parallel map (pmap) usage. Floating point atmospheric data serialized to byte arrays and written to disk using Java's ByteBuffer. During runtime, lookup tables load into OpenGL textures, and atmosphere is superimposed on rendered planets and spacecraft using ray tracing. --- Templating OpenGL Shaders Shader readability and flexibility are enhanced using the Comb templating library. Example: A generalized shader defines multiple octaves of noise via templating. Noise functions are dynamically created by filling in base functions and octave arrays with Comb. This supports procedural texture and effect generation. --- Planet Rendering Data sources: NASA Blue Marble (daytime textures) NASA Black Marble (night textures) NASA Elevation data Workflow: Image data converted into multi-resolution pyramids with tiled map structure. Implemented functions for: Loading and caching map tiles by 2D index and zoom level Pixel extraction from tiles Pixel retrieval by geographic coordinates Generated multiple tile types per map tile: Daytime texture Nighttime texture 3D vector surface meshes Water masks Normal maps Total of 655,350 files generated; to manage the file count, tile rows are bundled in tar files accessed via Apache Commons Compress. Uses LRU cache to maintain open tar files for performance. Tiles managed at runtime via futures that track tiles to load, keep, or drop. Quad tree structure manages tile storage and retrieval. --- Solar System and Orbit Computations Astronomy code