diff --git a/CMakeLists.txt b/CMakeLists.txt index e69de29..562a384 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -0,0 +1,59 @@ +cmake_minimum_required(VERSION 3.20) +project(new-radar LANGUAGES C CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +# Output binaries to build/bin +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + +# ── Find system packages ────────────────────────────────────────────────────── +find_package(OpenGL REQUIRED) +find_package(glfw3 REQUIRED) +find_package(Freetype REQUIRED) +find_package(GDAL REQUIRED) + +# PostgreSQL (libpq) +find_package(PostgreSQL REQUIRED) + +# ── GLAD (bundled) ──────────────────────────────────────────────────────────── +add_library(glad STATIC glad/src/glad.c) +target_include_directories(glad PUBLIC ${CMAKE_SOURCE_DIR}/include) + +# ── Collect sources ─────────────────────────────────────────────────────────── +file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS src/*.cpp) + +# ── Main executable ─────────────────────────────────────────────────────────── +add_executable(radar ${SOURCES}) + +target_include_directories(radar PRIVATE + ${CMAKE_SOURCE_DIR}/include + ${FREETYPE_INCLUDE_DIRS} + ${GDAL_INCLUDE_DIRS} + ${PostgreSQL_INCLUDE_DIRS} +) + +target_link_libraries(radar PRIVATE + glad + OpenGL::GL + glfw + Freetype::Freetype + ${GDAL_LIBRARIES} + ${PostgreSQL_LIBRARIES} + pthread +) + +# ── Compiler flags ──────────────────────────────────────────────────────────── +target_compile_options(radar PRIVATE + -Wall + -Wextra + -Wpedantic + $<$:-g -O0> + $<$:-O2> +) + +# AMD Radeon 780M uses Mesa; no vendor-specific extensions +target_compile_definitions(radar PRIVATE + GL_GLEXT_PROTOTYPES +) diff --git a/DESIGN.md b/DESIGN.md index e69de29..a1736c3 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -0,0 +1,145 @@ +# Radar Exhibit — Design Document + +## Hardware target +- Geekom A8 Max: AMD Ryzen 9 8945HS, Radeon 780M (Mesa/RADV), 32 GB RAM +- Ubuntu 25.10, g++ 15.2.0, C++20, OpenGL 4.3 Core + +--- + +## Screen layout + +Three fixed regions rendered with `glViewport` + `glScissor`: + +| Region | Content | +|--------|---------| +| Left panel | Text description, control list (white text; red labels; pink keystrokes) | +| Right panel — upper | Radar scope | +| Right panel — lower | Status bar: range, bearing, scope ID (yellow text) | + +--- + +## Scope sequence (cycled with keys 1 / 2) + +1. Exhibit introduction (text only) +2. Chain Home A-Scope (1940s) +3. Marine A-Scope (1940s) +4. PPI — stationary marine traffic control +5. PPI — on-board boat + +Each scope's control state is **independent** and **resets on re-entry**. + +--- + +## Radar equation + +$$P_r = \frac{P_t G^2 \lambda^2 \sigma}{(4\pi)^3 R^4}$$ + +Signal strength falls off with $1/R^4$. Each radar type has fixed hardware loop gain baked into its shader set as a constant. + +--- + +## Controls (keyboard until physical panel is built) + +| Key | Action | +|-----|--------| +| 1 / 2 | Next / previous scope | +| 3 / 4 | Intensity down / up | +| 5 / 6 | Receiver sensitivity down / up | +| q / w | STC sensitivity down / up | +| e / r | STC range down / up | +| t / y | Radiogoniometer left / right (Chain Home only) | +| u / i | Max range down / up (all except Chain Home) | +| o / p | Range cursor down / up (PPI only) | +| a / s | Bearing cursor CCW / CW (PPI only) | +| d / f | Antenna bearing CCW / CW (Marine A-Scope only) | + +Notes: +- Radiogoniometer, marine antenna bearing, and PPI bearing cursor share one physical knob on the eventual panel; kept separate in software. +- Range cursor ≠ max range: max range is the radar's selected range setting; range cursor is the measurement cursor on the PPI display. + +--- + +## Scope specifications + +### Chain Home A-Scope +- Fixed range: 200 miles +- No graticule; crystal-oscillator range pips every 20 miles (operator cannot change) +- Bearing via radiogoniometer simulation: operator finds null point; bearing shown as text below scope +- Two perpendicular antenna sets (N-S, E-W); radiogoniometer angle determines which target pip goes to null + +### Marine A-Scope +- Ranges: 1.5 / 3.0 / 6.0 / 12.0 miles +- Range pips: every 0.25 / 0.5 / 1.0 / 2.0 miles respectively (fixed oscillator; not affected by range setting) +- No graticule +- Bearing by rotating simulated dish/horn antenna (d/f keys) +- Pip shape: finite rise, fixed-width pulse, finite fall — curved waveform, not a vertical line + +### PPI scopes (both) +- 360° sweep with phosphor persistence via FBO (semi-transparent black quad each frame; no full clear) +- Range cursor and bearing cursor overlay + +#### Stationary (marine traffic control) +- Fixed observer position; targets move relative to scope center + +#### On-boat +- Observer is scope center; heading-up display — world rotates as boat heading changes +- Boat position/heading supplied from GDAL/PostgreSQL data + +--- + +## Architecture + +### Class hierarchy (State pattern) + +``` +BaseScope — intensity, sensitivity, STC vars, virtual render/update +├── AScope — horizontal sweep, curved pip waveform +│ ├── ChainHomeScope — radiogoniometer, fixed 200 mi range, 20 mi pips +│ └── MarineAScope — antenna bearing knob, 4 range settings +└── PPIScope — 360° sweep, FBO persistence, range/bearing cursors + ├── StationaryPPI + └── OnBoatPPI — heading offset passed into shader +``` + +### Threading model + +| Thread | Responsibility | +|--------|---------------| +| Render (main) | OpenGL loop, GLFW input, all `glDraw*` calls — never blocks | +| Simulation | Polls `target_data` (PostgreSQL) and GDAL; updates shared `std::vector` under `std::mutex` | + +### FBO phosphor decay +- Render sweep into FBO each frame +- Blit FBO to screen +- Do **not** clear color buffer between frames; draw full-screen quad at very low alpha (~0.05) to decay old sweeps + +### Shader notes +- GL_DEBUG_OUTPUT + `glDebugMessageCallback` enabled at startup (GPU robustness protocol) +- No NVIDIA-specific extensions; Mesa/RADV only +- $1/R^4$ attenuation computed in fragment shader; hardware loop gain is a per-scope `uniform` constant + +--- + +## File structure + +``` +new-radar/ +├── CMakeLists.txt +├── src/ — .cpp source files +├── include/ — .h/.hpp headers +│ ├── glad/ +│ └── KHR/ +├── glad/src/ — glad.c (bundled) +├── shaders/ — .vert / .frag files +├── data/ — patrol_route.json, etc. +└── map/ + ├── charts_enc/ — ENC .000 and GeoTIFF files + └── lidar_raw/ — LIDAR zips +``` + +--- + +## Database + +- PostgreSQL, database `radar`, user `radar`, password `radar` +- Table `target_data`: polled by simulation thread for live target positions