Fix errors

This commit is contained in:
2026-04-24 00:25:29 -07:00
parent f68524a6ae
commit 01c1db41db
34 changed files with 361 additions and 210 deletions

View File

@@ -661,11 +661,87 @@ PPIScope : public Scope (abstract) — shared PPI behavior:
- Cursor range/bearing readout under scope (white text)
- Bearing offset for boat mode (k/j)
- Cursor range clamped to max range
- Range rings and labels are beam-painted per sweep sector, NOT a static overlay;
the sweep shader evaluates ring radii for the CURRENT max range at the moment
each beam angle is rendered; the phosphor buffer retains whatever was last
written, so old ring positions fade naturally as the sweep overwrites them with
new geometry — no special transition code required
- Range rings are beam-painted per sweep sector with P7 persistence and decay;
however they are stored in the GAIN-INDEPENDENT G channel of the phosphor FBO
(see PHOSPHOR FBO ARCHITECTURE below) so operator gain does not dim the rings
- renderRingLabels() — virtual method (default no-op); concrete PPI scopes that
have labelled range rings override this to render mile-distance text labels in
P7 fresh-blue colour at a fixed bearing (RING_LABEL_BRG_DEG = 045°)
IMPLEMENTER CHECKLIST — required in every new PPIScope subclass:
1. computeRingRadii(): multiply each normalised ring radius by
GRAT_INNER_RING_FRAC (same as MarinePPIScope). Omitting this
places the outer ring at the scope boundary where it is clipped
and hidden behind the graticule. Target positions are scaled
automatically by PhosphorRenderer::update(); ring radii are not.
2. Override renderRingLabels() using the same pattern as
MarinePPIScope::renderRingLabels() but with the scope's own
ring-mile table. The base-class no-op produces no labels.
The p7Color() fix, two-channel FBO gain-separation, and target
position scaling are all automatic via the shared PhosphorRenderer
and shaders — no per-scope action required for those.
==================================================================
PHOSPHOR FBO ARCHITECTURE
==================================================================
The phosphor FBO is GL_RG32F (two independent float channels):
R channel — signal energy
Written by: target echoes in the sweep shader
Multiplied by: u_gain in the display shader
Effect: operator gain knob dims/brightens received echoes without
affecting the sweep beam or range rings
G channel — timing/geometry energy
Written by: range rings + sweep background glow in the sweep shader
NOT multiplied by gain in the display shader
Effect: rings always appear at a fixed brightness; the rotating
sweep-line glow is always visible even at minimum gain
Both channels decay at the same P7 rate (P7_DECAY_RATE in settings.h).
The display shader combines them: totalEnergy = max(R * gain, G).
This produces the correct visual priority: a strong target echo always
shows above the ring but a dim echo below gain threshold fades away
while the ring stays steady.
RANGE POSITION NORMALISATION
All ring radii and target range values are normalised so that
max-range maps to GRAT_INNER_RING_FRAC (0.915), NOT 1.0.
Normalised 1.0 is the outer edge of the phosphor circle (scope boundary).
The bearing graticule overlay occupies 0.915 to 0.985 of scope radius.
If max-range mapped to 1.0, the outer ring would sit at the scope
boundary — half-clipped by the sweep shader's rng > 1.0 early-exit and
visually hidden behind the graticule outer ring.
Mapping max-range → GRAT_INNER_RING_FRAC keeps all rings and targets
within the clean active display area inside the bearing scale overlay.
Scale is applied in two places:
1. PhosphorRenderer::update() — target range: × GRAT_INNER_RING_FRAC
2. computeRingRadii() in each concrete PPI scope — ring radii: × GRAT_INNER_RING_FRAC
P7 COLOUR FUNCTION
p7Color() in phosphor.frag is a piecewise linear ramp over [0, 1]:
e ≥ T_BLUE (0.82) → pure C_BLUE
[T_GREEN, T_BLUE) → mix(C_GREEN, C_BLUE, normalised within range)
[T_YGREE, T_GREEN) → mix(C_YGREE, C_GREEN, normalised within range)
[T_DARK, T_YGREE) → mix(C_YELLW, C_YGREE, normalised within range)
[0, T_DARK) → mix(C_BLACK, C_YELLW, normalised within range)
Each mix() factor is in [0, 1] and the function is continuous at every
threshold boundary. An earlier version had each branch using the formula
of the branch below it (off-by-one), which caused SWEEP_BACKGROUND_ENERGY
= 0.10 to render as saturated yellow (factor 3.33) instead of dim
yellow-green, producing an unwanted solid-yellow band behind the sweep.
==================================================================
MarinePPIScope : public PPIScope
- Sweep time: 4 seconds

View File

@@ -351,6 +351,8 @@ CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
CMAKE_DLLTOOL-ADVANCED:INTERNAL=1
//Path to cache edit program executable.
CMAKE_EDIT_COMMAND:INTERNAL=/usr/bin/cmake-gui
//Whether to issue deprecation errors for macros and functions.
CMAKE_ERROR_DEPRECATED:INTERNAL=FALSE
//Executable file format
CMAKE_EXECUTABLE_FORMAT:INTERNAL=ELF
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS
@@ -440,12 +442,20 @@ CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_STRIP
CMAKE_STRIP-ADVANCED:INTERNAL=1
//Suppress errors that are meant for the author of the CMakeLists.txt
// files.
CMAKE_SUPPRESS_DEVELOPER_ERRORS:INTERNAL=TRUE
//Suppress Warnings that are meant for the author of the CMakeLists.txt
// files.
CMAKE_SUPPRESS_DEVELOPER_WARNINGS:INTERNAL=TRUE
//ADVANCED property for variable: CMAKE_TAPI
CMAKE_TAPI-ADVANCED:INTERNAL=1
//uname command
CMAKE_UNAME:INTERNAL=/usr/bin/uname
//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE
CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1
//Whether to issue warnings for deprecated functionality.
CMAKE_WARN_DEPRECATED:INTERNAL=FALSE
//Details about finding Freetype
FIND_PACKAGE_MESSAGE_DETAILS_Freetype:INTERNAL=[/usr/lib/x86_64-linux-gnu/libfreetype.so][/usr/include/freetype2][v2.14.2()]
//Details about finding OpenGL

View File

@@ -11,98 +11,21 @@ set(CMAKE_MAKEFILE_DEPENDS
"CMakeFiles/4.2.3/CMakeCCompiler.cmake"
"CMakeFiles/4.2.3/CMakeCXXCompiler.cmake"
"CMakeFiles/4.2.3/CMakeSystem.cmake"
"/usr/share/cmake-4.2/Modules/CMakeCCompiler.cmake.in"
"/usr/share/cmake-4.2/Modules/CMakeCCompilerABI.c"
"/usr/share/cmake-4.2/Modules/CMakeCInformation.cmake"
"/usr/share/cmake-4.2/Modules/CMakeCXXCompiler.cmake.in"
"/usr/share/cmake-4.2/Modules/CMakeCXXCompilerABI.cpp"
"/usr/share/cmake-4.2/Modules/CMakeCXXInformation.cmake"
"/usr/share/cmake-4.2/Modules/CMakeCommonLanguageInclude.cmake"
"/usr/share/cmake-4.2/Modules/CMakeCompilerIdDetection.cmake"
"/usr/share/cmake-4.2/Modules/CMakeDetermineCCompiler.cmake"
"/usr/share/cmake-4.2/Modules/CMakeDetermineCXXCompiler.cmake"
"/usr/share/cmake-4.2/Modules/CMakeDetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/CMakeDetermineCompilerABI.cmake"
"/usr/share/cmake-4.2/Modules/CMakeDetermineCompilerId.cmake"
"/usr/share/cmake-4.2/Modules/CMakeDetermineCompilerSupport.cmake"
"/usr/share/cmake-4.2/Modules/CMakeDetermineSystem.cmake"
"/usr/share/cmake-4.2/Modules/CMakeFindBinUtils.cmake"
"/usr/share/cmake-4.2/Modules/CMakeGenericSystem.cmake"
"/usr/share/cmake-4.2/Modules/CMakeInitializeConfigs.cmake"
"/usr/share/cmake-4.2/Modules/CMakeLanguageInformation.cmake"
"/usr/share/cmake-4.2/Modules/CMakeParseImplicitIncludeInfo.cmake"
"/usr/share/cmake-4.2/Modules/CMakeParseImplicitLinkInfo.cmake"
"/usr/share/cmake-4.2/Modules/CMakeParseLibraryArchitecture.cmake"
"/usr/share/cmake-4.2/Modules/CMakeSystem.cmake.in"
"/usr/share/cmake-4.2/Modules/CMakeSystemSpecificInformation.cmake"
"/usr/share/cmake-4.2/Modules/CMakeSystemSpecificInitialize.cmake"
"/usr/share/cmake-4.2/Modules/CMakeTestCCompiler.cmake"
"/usr/share/cmake-4.2/Modules/CMakeTestCXXCompiler.cmake"
"/usr/share/cmake-4.2/Modules/CMakeTestCompilerCommon.cmake"
"/usr/share/cmake-4.2/Modules/CMakeUnixFindMake.cmake"
"/usr/share/cmake-4.2/Modules/CheckCSourceCompiles.cmake"
"/usr/share/cmake-4.2/Modules/CheckIncludeFile.cmake"
"/usr/share/cmake-4.2/Modules/CheckLibraryExists.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/ADSP-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/ARMCC-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/ARMClang-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/AppleClang-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/Borland-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/Bruce-C-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/CMakeCommonCompilerMacros.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/Clang-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/Clang-DetermineCompilerInternal.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/Compaq-C-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/Compaq-CXX-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/Cray-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/CrayClang-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/Diab-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/Embarcadero-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/Fujitsu-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/FujitsuClang-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/GHS-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/GNU-C-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/GNU-C.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/GNU-CXX-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/GNU-CXX.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/GNU-FindBinUtils.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/GNU.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/HP-C-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/HP-CXX-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/IAR-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/IBMClang-C-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/IBMClang-CXX-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/Intel-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/IntelLLVM-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/LCC-C-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/LCC-CXX-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/MSVC-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/NVHPC-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/NVIDIA-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/OpenWatcom-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/OrangeC-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/PGI-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/PathScale-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/Renesas-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/SCO-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/SDCC-C-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/SunPro-C-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/SunPro-CXX-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/TI-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/TIClang-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/Tasking-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/TinyCC-C-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/VisualAge-C-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/VisualAge-CXX-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/Watcom-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/XL-C-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/XL-CXX-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/XLClang-C-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/XLClang-CXX-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/zOS-C-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/Compiler/zOS-CXX-DetermineCompiler.cmake"
"/usr/share/cmake-4.2/Modules/FindFreetype.cmake"
"/usr/share/cmake-4.2/Modules/FindOpenGL.cmake"
"/usr/share/cmake-4.2/Modules/FindPackageHandleStandardArgs.cmake"
@@ -112,11 +35,7 @@ set(CMAKE_MAKEFILE_DEPENDS
"/usr/share/cmake-4.2/Modules/Internal/CMakeCLinkerInformation.cmake"
"/usr/share/cmake-4.2/Modules/Internal/CMakeCXXLinkerInformation.cmake"
"/usr/share/cmake-4.2/Modules/Internal/CMakeCommonLinkerInformation.cmake"
"/usr/share/cmake-4.2/Modules/Internal/CMakeDetermineLinkerId.cmake"
"/usr/share/cmake-4.2/Modules/Internal/CMakeInspectCLinker.cmake"
"/usr/share/cmake-4.2/Modules/Internal/CMakeInspectCXXLinker.cmake"
"/usr/share/cmake-4.2/Modules/Internal/CheckSourceCompiles.cmake"
"/usr/share/cmake-4.2/Modules/Internal/FeatureTesting.cmake"
"/usr/share/cmake-4.2/Modules/Linker/GNU-C.cmake"
"/usr/share/cmake-4.2/Modules/Linker/GNU-CXX.cmake"
"/usr/share/cmake-4.2/Modules/Linker/GNU.cmake"
@@ -124,7 +43,6 @@ set(CMAKE_MAKEFILE_DEPENDS
"/usr/share/cmake-4.2/Modules/Platform/Linker/Linux-GNU-C.cmake"
"/usr/share/cmake-4.2/Modules/Platform/Linker/Linux-GNU-CXX.cmake"
"/usr/share/cmake-4.2/Modules/Platform/Linker/Linux-GNU.cmake"
"/usr/share/cmake-4.2/Modules/Platform/Linux-Determine-CXX.cmake"
"/usr/share/cmake-4.2/Modules/Platform/Linux-GNU-C.cmake"
"/usr/share/cmake-4.2/Modules/Platform/Linux-GNU-CXX.cmake"
"/usr/share/cmake-4.2/Modules/Platform/Linux-GNU.cmake"
@@ -142,13 +60,6 @@ set(CMAKE_MAKEFILE_OUTPUTS
# Byproducts of CMake generate step:
set(CMAKE_MAKEFILE_PRODUCTS
"CMakeFiles/4.2.3/CMakeSystem.cmake"
"CMakeFiles/4.2.3/CMakeCCompiler.cmake"
"CMakeFiles/4.2.3/CMakeCXXCompiler.cmake"
"CMakeFiles/4.2.3/CMakeCCompiler.cmake"
"CMakeFiles/4.2.3/CMakeCCompiler.cmake"
"CMakeFiles/4.2.3/CMakeCXXCompiler.cmake"
"CMakeFiles/4.2.3/CMakeCXXCompiler.cmake"
"CMakeFiles/CMakeDirectoryInformation.cmake"
)

View File

@@ -2432,6 +2432,7 @@ CMakeFiles/radar.dir/src/scope_marine_ppi.cpp.o
/usr/include/c++/15/bits/ranges_util.h
/usr/include/c++/15/bits/refwrap.h
/usr/include/c++/15/bits/requires_hosted.h
/usr/include/c++/15/bits/specfun.h
/usr/include/c++/15/bits/std_abs.h
/usr/include/c++/15/bits/std_mutex.h
/usr/include/c++/15/bits/stl_algobase.h
@@ -2457,13 +2458,13 @@ CMakeFiles/radar.dir/src/scope_marine_ppi.cpp.o
/usr/include/c++/15/cerrno
/usr/include/c++/15/climits
/usr/include/c++/15/clocale
/usr/include/c++/15/cmath
/usr/include/c++/15/compare
/usr/include/c++/15/concepts
/usr/include/c++/15/cstddef
/usr/include/c++/15/cstdint
/usr/include/c++/15/cstdio
/usr/include/c++/15/cstdlib
/usr/include/c++/15/cstring
/usr/include/c++/15/ctime
/usr/include/c++/15/cwchar
/usr/include/c++/15/debug/assertions.h
@@ -2484,6 +2485,18 @@ CMakeFiles/radar.dir/src/scope_marine_ppi.cpp.o
/usr/include/c++/15/ratio
/usr/include/c++/15/string
/usr/include/c++/15/string_view
/usr/include/c++/15/tr1/bessel_function.tcc
/usr/include/c++/15/tr1/beta_function.tcc
/usr/include/c++/15/tr1/ell_integral.tcc
/usr/include/c++/15/tr1/exp_integral.tcc
/usr/include/c++/15/tr1/gamma.tcc
/usr/include/c++/15/tr1/hypergeometric.tcc
/usr/include/c++/15/tr1/legendre_function.tcc
/usr/include/c++/15/tr1/modified_bessel_func.tcc
/usr/include/c++/15/tr1/poly_hermite.tcc
/usr/include/c++/15/tr1/poly_laguerre.tcc
/usr/include/c++/15/tr1/riemann_zeta.tcc
/usr/include/c++/15/tr1/special_function_util.h
/usr/include/c++/15/tuple
/usr/include/c++/15/type_traits
/usr/include/c++/15/unordered_map
@@ -2502,14 +2515,13 @@ CMakeFiles/radar.dir/src/scope_marine_ppi.cpp.o
/usr/include/linux/stddef.h
/usr/include/linux/types.h
/usr/include/locale.h
/usr/include/math.h
/usr/include/pthread.h
/usr/include/sched.h
/usr/include/stdc-predef.h
/usr/include/stdint.h
/usr/include/stdio.h
/usr/include/stdlib.h
/usr/include/string.h
/usr/include/strings.h
/usr/include/syscall.h
/usr/include/time.h
/usr/include/unistd.h
@@ -2531,12 +2543,22 @@ CMakeFiles/radar.dir/src/scope_marine_ppi.cpp.o
/usr/include/x86_64-linux-gnu/bits/errno.h
/usr/include/x86_64-linux-gnu/bits/floatn-common.h
/usr/include/x86_64-linux-gnu/bits/floatn.h
/usr/include/x86_64-linux-gnu/bits/flt-eval-method.h
/usr/include/x86_64-linux-gnu/bits/fp-fast.h
/usr/include/x86_64-linux-gnu/bits/fp-logb.h
/usr/include/x86_64-linux-gnu/bits/getopt_core.h
/usr/include/x86_64-linux-gnu/bits/getopt_posix.h
/usr/include/x86_64-linux-gnu/bits/iscanonical.h
/usr/include/x86_64-linux-gnu/bits/libc-header-start.h
/usr/include/x86_64-linux-gnu/bits/libm-simd-decl-stubs.h
/usr/include/x86_64-linux-gnu/bits/local_lim.h
/usr/include/x86_64-linux-gnu/bits/locale.h
/usr/include/x86_64-linux-gnu/bits/long-double.h
/usr/include/x86_64-linux-gnu/bits/math-vector.h
/usr/include/x86_64-linux-gnu/bits/mathcalls-helper-functions.h
/usr/include/x86_64-linux-gnu/bits/mathcalls-macros.h
/usr/include/x86_64-linux-gnu/bits/mathcalls-narrow.h
/usr/include/x86_64-linux-gnu/bits/mathcalls.h
/usr/include/x86_64-linux-gnu/bits/posix1_lim.h
/usr/include/x86_64-linux-gnu/bits/posix2_lim.h
/usr/include/x86_64-linux-gnu/bits/posix_opt.h

View File

@@ -2421,6 +2421,7 @@ CMakeFiles/radar.dir/src/scope_marine_ppi.cpp.o: /home/maallyn/new-radar/src/sco
/usr/include/c++/15/bits/ranges_util.h \
/usr/include/c++/15/bits/refwrap.h \
/usr/include/c++/15/bits/requires_hosted.h \
/usr/include/c++/15/bits/specfun.h \
/usr/include/c++/15/bits/std_abs.h \
/usr/include/c++/15/bits/std_mutex.h \
/usr/include/c++/15/bits/stl_algobase.h \
@@ -2446,13 +2447,13 @@ CMakeFiles/radar.dir/src/scope_marine_ppi.cpp.o: /home/maallyn/new-radar/src/sco
/usr/include/c++/15/cerrno \
/usr/include/c++/15/climits \
/usr/include/c++/15/clocale \
/usr/include/c++/15/cmath \
/usr/include/c++/15/compare \
/usr/include/c++/15/concepts \
/usr/include/c++/15/cstddef \
/usr/include/c++/15/cstdint \
/usr/include/c++/15/cstdio \
/usr/include/c++/15/cstdlib \
/usr/include/c++/15/cstring \
/usr/include/c++/15/ctime \
/usr/include/c++/15/cwchar \
/usr/include/c++/15/debug/assertions.h \
@@ -2473,6 +2474,18 @@ CMakeFiles/radar.dir/src/scope_marine_ppi.cpp.o: /home/maallyn/new-radar/src/sco
/usr/include/c++/15/ratio \
/usr/include/c++/15/string \
/usr/include/c++/15/string_view \
/usr/include/c++/15/tr1/bessel_function.tcc \
/usr/include/c++/15/tr1/beta_function.tcc \
/usr/include/c++/15/tr1/ell_integral.tcc \
/usr/include/c++/15/tr1/exp_integral.tcc \
/usr/include/c++/15/tr1/gamma.tcc \
/usr/include/c++/15/tr1/hypergeometric.tcc \
/usr/include/c++/15/tr1/legendre_function.tcc \
/usr/include/c++/15/tr1/modified_bessel_func.tcc \
/usr/include/c++/15/tr1/poly_hermite.tcc \
/usr/include/c++/15/tr1/poly_laguerre.tcc \
/usr/include/c++/15/tr1/riemann_zeta.tcc \
/usr/include/c++/15/tr1/special_function_util.h \
/usr/include/c++/15/tuple \
/usr/include/c++/15/type_traits \
/usr/include/c++/15/unordered_map \
@@ -2491,14 +2504,13 @@ CMakeFiles/radar.dir/src/scope_marine_ppi.cpp.o: /home/maallyn/new-radar/src/sco
/usr/include/linux/stddef.h \
/usr/include/linux/types.h \
/usr/include/locale.h \
/usr/include/math.h \
/usr/include/pthread.h \
/usr/include/sched.h \
/usr/include/stdc-predef.h \
/usr/include/stdint.h \
/usr/include/stdio.h \
/usr/include/stdlib.h \
/usr/include/string.h \
/usr/include/strings.h \
/usr/include/syscall.h \
/usr/include/time.h \
/usr/include/unistd.h \
@@ -2520,12 +2532,22 @@ CMakeFiles/radar.dir/src/scope_marine_ppi.cpp.o: /home/maallyn/new-radar/src/sco
/usr/include/x86_64-linux-gnu/bits/errno.h \
/usr/include/x86_64-linux-gnu/bits/floatn-common.h \
/usr/include/x86_64-linux-gnu/bits/floatn.h \
/usr/include/x86_64-linux-gnu/bits/flt-eval-method.h \
/usr/include/x86_64-linux-gnu/bits/fp-fast.h \
/usr/include/x86_64-linux-gnu/bits/fp-logb.h \
/usr/include/x86_64-linux-gnu/bits/getopt_core.h \
/usr/include/x86_64-linux-gnu/bits/getopt_posix.h \
/usr/include/x86_64-linux-gnu/bits/iscanonical.h \
/usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
/usr/include/x86_64-linux-gnu/bits/libm-simd-decl-stubs.h \
/usr/include/x86_64-linux-gnu/bits/local_lim.h \
/usr/include/x86_64-linux-gnu/bits/locale.h \
/usr/include/x86_64-linux-gnu/bits/long-double.h \
/usr/include/x86_64-linux-gnu/bits/math-vector.h \
/usr/include/x86_64-linux-gnu/bits/mathcalls-helper-functions.h \
/usr/include/x86_64-linux-gnu/bits/mathcalls-macros.h \
/usr/include/x86_64-linux-gnu/bits/mathcalls-narrow.h \
/usr/include/x86_64-linux-gnu/bits/mathcalls.h \
/usr/include/x86_64-linux-gnu/bits/posix1_lim.h \
/usr/include/x86_64-linux-gnu/bits/posix2_lim.h \
/usr/include/x86_64-linux-gnu/bits/posix_opt.h \

View File

@@ -199,4 +199,26 @@ CMakeFiles/radar.dir/src/scope_marine_ppi.cpp.o: \
/home/maallyn/new-radar/include/KHR/khrplatform.h \
/home/maallyn/new-radar/src/phosphor.h \
/home/maallyn/new-radar/src/graticule.h /usr/include/GLFW/glfw3.h \
/usr/include/c++/15/cstring /usr/include/string.h /usr/include/strings.h
/usr/include/c++/15/cmath /usr/include/math.h \
/usr/include/x86_64-linux-gnu/bits/math-vector.h \
/usr/include/x86_64-linux-gnu/bits/libm-simd-decl-stubs.h \
/usr/include/x86_64-linux-gnu/bits/flt-eval-method.h \
/usr/include/x86_64-linux-gnu/bits/fp-logb.h \
/usr/include/x86_64-linux-gnu/bits/fp-fast.h \
/usr/include/x86_64-linux-gnu/bits/mathcalls-macros.h \
/usr/include/x86_64-linux-gnu/bits/mathcalls-helper-functions.h \
/usr/include/x86_64-linux-gnu/bits/mathcalls.h \
/usr/include/x86_64-linux-gnu/bits/mathcalls-narrow.h \
/usr/include/x86_64-linux-gnu/bits/iscanonical.h \
/usr/include/c++/15/bits/specfun.h /usr/include/c++/15/tr1/gamma.tcc \
/usr/include/c++/15/tr1/special_function_util.h \
/usr/include/c++/15/tr1/bessel_function.tcc \
/usr/include/c++/15/tr1/beta_function.tcc \
/usr/include/c++/15/tr1/ell_integral.tcc \
/usr/include/c++/15/tr1/exp_integral.tcc \
/usr/include/c++/15/tr1/hypergeometric.tcc \
/usr/include/c++/15/tr1/legendre_function.tcc \
/usr/include/c++/15/tr1/modified_bessel_func.tcc \
/usr/include/c++/15/tr1/poly_hermite.tcc \
/usr/include/c++/15/tr1/poly_laguerre.tcc \
/usr/include/c++/15/tr1/riemann_zeta.tcc

Binary file not shown.

View File

@@ -2,9 +2,15 @@
* MIT License
* Author: Mark Allyn
*
* phosphor.frag — maps the single-channel phosphor energy texture to
* the P7 colour sequence (blue → green → yellow-green → dark) and
* applies a simple inline bloom (box-filter glow) to bright pixels.
* phosphor.frag — maps the two-channel phosphor energy texture to the
* P7 colour sequence (blue → green → yellow-green → dark) and applies
* a simple inline bloom (box-filter glow) to bright pixels.
*
* The phosphor FBO is GL_RG32F:
* R channel — signal energy (target echoes, sweep background)
* multiplied by u_gain before display
* G channel — range ring energy, gain-independent; mixed with signal
* after gain is applied so rings never dim with gain
*
* Coordinate system: gl_FragCoord.xy in GL viewport pixels (origin
* bottom-left). Scope centre is passed as u_scopeCenter in the same
@@ -14,17 +20,19 @@
out vec4 fragColor;
uniform sampler2D u_phosphor; // GL_R32F phosphor energy FBO
uniform sampler2D u_phosphor; // GL_RG32F phosphor energy FBO
uniform vec2 u_scopeCenter; // scope centre in GL viewport pixels (bottom-left origin)
uniform float u_scopeRadius; // scope radius in pixels
uniform float u_gain; // receiver gain [0,1] — scales brightness
uniform float u_gain; // receiver gain [0,1] — scales signal (R) channel only
uniform float u_bloomStep; // UV step for bloom sample (≈ 2.5 / FBO_SIZE)
uniform float u_bloomStrength; // additive blend weight for bloom
// P7 energy thresholds (match settings.h)
// P7 energy thresholds — MUST match settings.h P7_THRESH_* constants.
// T_YGREE is intentionally low (0.05) to keep most of the decay in the
// GREEN zone; see the comment in settings.h for the full rationale.
const float T_BLUE = 0.82;
const float T_GREEN = 0.55;
const float T_YGREE = 0.22;
const float T_YGREE = 0.05;
const float T_DARK = 0.03;
// P7 colour anchors
@@ -34,16 +42,22 @@ const vec3 C_YGREE = vec3(0.50, 1.00, 0.05);
const vec3 C_YELLW = vec3(0.70, 0.70, 0.00);
const vec3 C_BLACK = vec3(0.00, 0.00, 0.00);
// P7 colour ramp: hue selected by energy level, then scaled by energy so
// brightness decreases monotonically from fresh strike (peak) to dark.
// This prevents intermediate decay colours (yellow-green) from appearing
// brighter than the initial blue flash.
vec3 p7Color(float e) {
if (e < T_DARK) return C_BLACK;
vec3 hue;
if (e >= T_BLUE)
return mix(C_GREEN, C_BLUE, (e - T_GREEN) / (T_BLUE - T_GREEN));
if (e >= T_GREEN)
return mix(C_YGREE, C_GREEN, (e - T_YGREE) / (T_GREEN - T_YGREE));
if (e >= T_YGREE)
return mix(C_YELLW, C_YGREE, (e - T_DARK ) / (T_YGREE - T_DARK ));
if (e >= T_DARK)
return mix(C_BLACK, C_YELLW, e / T_DARK);
return C_BLACK;
hue = C_BLUE;
else if (e >= T_GREEN)
hue = mix(C_GREEN, C_BLUE, (e - T_GREEN) / (T_BLUE - T_GREEN));
else if (e >= T_YGREE)
hue = mix(C_YGREE, C_GREEN, (e - T_YGREE) / (T_GREEN - T_YGREE));
else
hue = mix(C_YELLW, C_YGREE, (e - T_DARK) / (T_YGREE - T_DARK));
return hue * e;
}
void main() {
@@ -57,10 +71,12 @@ void main() {
}
// Map from PPI delta [-1,+1] to phosphor texture UV [0,1]
// delta.x = east, delta.y = north (both y directions already match)
vec2 uv = delta * 0.5 + 0.5;
float energy = texture(u_phosphor, uv).r * u_gain;
vec2 rg = texture(u_phosphor, uv).rg;
// Signal (R): gain-scaled received echoes.
// Ring (G): gain-independent timing reference; always at full brightness.
float energy = max(rg.r * u_gain, rg.g);
// Inline bloom: weighted box-filter over a 5×5 neighbourhood
float bloom = 0.0;
@@ -68,7 +84,8 @@ void main() {
for (int dx = -2; dx <= 2; dx++) {
for (int dy = -2; dy <= 2; dy++) {
float w = exp(-float(dx*dx + dy*dy) * 0.45);
float e = texture(u_phosphor, uv + vec2(dx, dy) * u_bloomStep).r;
vec2 srg = texture(u_phosphor, uv + vec2(dx, dy) * u_bloomStep).rg;
float e = max(srg.r * u_gain, srg.g);
bloom += e * w;
wsum += w;
}

View File

@@ -4,13 +4,16 @@
*
* sweep.frag — phosphor accumulation update shader.
*
* For each texel in the 1024×1024 phosphor FBO:
* 1. Decay the previous frame's energy by u_decayFactor.
* 2. If the texel's PPI bearing falls within the current sweep arc
* [u_beamAnglePrev, u_beamAngle], add contributions from:
* - range rings (beam-painted per the P7 spec)
* - target echoes
* 3. Output the updated single-channel energy value.
* The FBO is GL_RG32F (two independent energy channels):
* R — signal energy: target echoes + sweep-background glow.
* Multiplied by u_gain in the display pass so operators can
* adjust received-signal brightness without touching rings.
* G — range-ring energy: written at u_ringBrightness; NOT scaled
* by gain. Rings are a precision timing reference, not a
* received echo. Both channels decay at the same P7 rate.
*
* The sweep background (u_sweepBg) goes into the G channel so the
* rotating beam is always visible regardless of the gain setting.
*
* PPI convention: north = +y, east = +x; bearing = atan2(x, y)
* in degrees, clockwise from north.
@@ -19,13 +22,13 @@
in vec2 vTexCoord;
layout(location = 0) out vec4 fragOut; // .r = energy; .gba unused
layout(location = 0) out vec4 fragOut; // .r = signal; .g = ring+sweep; .ba unused
uniform sampler2D u_prevPhosphor; // previous frame's energy texture (GL_R32F)
uniform sampler2D u_prevPhosphor; // previous frame's energy texture (GL_RG32F)
uniform float u_decayFactor; // exp(-decay_rate * dt)
uniform float u_beamAngle; // current beam angle, degrees CW from north
uniform float u_beamAnglePrev; // beam angle at previous frame
uniform float u_sweepBg; // ambient sweep-line energy (makes beam visible)
uniform float u_sweepBg; // ambient sweep-line energy (gain-independent)
uniform float u_halfBeamDeg; // half-beamwidth for target blobs (display widening)
// Targets: .x = range_norm (0-1), .y = bearing_deg, .z = brightness, .w = size_norm
@@ -59,8 +62,8 @@ bool inSweep(float b, float prev, float curr) {
// ----------------------------------------------------------------
void main() {
vec2 pos = vTexCoord * 2.0 - 1.0; // PPI coords: (-1,-1) SW … (+1,+1) NE
float rng = length(pos);
vec2 pos = vTexCoord * 2.0 - 1.0; // PPI coords: (-1,-1) SW … (+1,+1) NE
float rng = length(pos);
if (rng > 1.0) {
fragOut = vec4(0.0);
@@ -71,23 +74,25 @@ void main() {
float brg = degrees(atan(pos.x, pos.y));
if (brg < 0.0) brg += 360.0;
// Decay previous value
float energy = texture(u_prevPhosphor, vTexCoord).r * u_decayFactor;
vec2 prev = texture(u_prevPhosphor, vTexCoord).rg;
float signal = prev.r * u_decayFactor;
float ring = prev.g * u_decayFactor;
if (inSweep(brg, u_beamAnglePrev, u_beamAngle)) {
float contrib = u_sweepBg; // beam passage gives a faint ambient glow
// ---- Range rings (painted at every bearing as beam sweeps) ----
// ---- Range rings → G channel (gain-independent) ----
float ringContrib = u_sweepBg; // sweep-background glow also in G channel
for (int i = 0; i < u_ringCount; i++) {
float d = abs(rng - u_ringRadii[i]);
if (d < u_ringWidth) {
float w = 1.0 - d / u_ringWidth;
contrib = max(contrib, u_ringBrightness * w * w);
ringContrib = max(ringContrib, u_ringBrightness * w * w);
}
}
ring = max(ring, ringContrib);
// ---- Target echoes ----
// ---- Target echoes → R channel (gain-scaled in display pass) ----
float sigContrib = 0.0;
for (int i = 0; i < u_targetCount; i++) {
float tRng = u_targets[i].x;
float tBrg = u_targets[i].y;
@@ -96,21 +101,18 @@ void main() {
if (tRng <= 0.0 || tBrt <= 0.0) continue;
// Angular proximity: beam must be sweeping over the target's bearing
float dBrg = angleDiff(brg, tBrg);
if (dBrg >= u_halfBeamDeg) continue;
// Range proximity: pixel must be within the target blob
float dRng = abs(rng - tRng);
if (dRng >= tSize) continue;
float bw = 1.0 - dBrg / u_halfBeamDeg; // angular taper
float rw = 1.0 - dRng / tSize; // range taper
contrib = max(contrib, tBrt * bw * rw);
float bw = 1.0 - dBrg / u_halfBeamDeg;
float rw = 1.0 - dRng / tSize;
sigContrib = max(sigContrib, tBrt * bw * rw);
}
energy = max(energy, contrib);
signal = max(signal, sigContrib);
}
fragOut = vec4(clamp(energy, 0.0, 1.0), 0.0, 0.0, 1.0);
fragOut = vec4(clamp(signal, 0.0, 1.0), clamp(ring, 0.0, 1.0), 0.0, 1.0);
}

8
issues Normal file
View File

@@ -0,0 +1,8 @@
Only one range ring no matter the max range. Range ring has no number indicating ring (I forgot if I mentioned that)
It seems that the empty scan line is excessively strong, along with the range rings. The gain does affect the range rings. I wonder
if this is how things are normal of a period radar. I thought that the gain would be only for targets and noise and land. Not the scan beam
itself and the range rings. Also the cursor seems to be the same color as the p7 fading. It should be more white, like an incandescent light.
At 1/2 on the gain control, the sweeping beams leave a solid yellow for about 1/3 of a sweep. It is solid, not varying due to noise.

View File

@@ -2,9 +2,15 @@
* MIT License
* Author: Mark Allyn
*
* phosphor.frag — maps the single-channel phosphor energy texture to
* the P7 colour sequence (blue → green → yellow-green → dark) and
* applies a simple inline bloom (box-filter glow) to bright pixels.
* phosphor.frag — maps the two-channel phosphor energy texture to the
* P7 colour sequence (blue → green → yellow-green → dark) and applies
* a simple inline bloom (box-filter glow) to bright pixels.
*
* The phosphor FBO is GL_RG32F:
* R channel — signal energy (target echoes, sweep background)
* multiplied by u_gain before display
* G channel — range ring energy, gain-independent; mixed with signal
* after gain is applied so rings never dim with gain
*
* Coordinate system: gl_FragCoord.xy in GL viewport pixels (origin
* bottom-left). Scope centre is passed as u_scopeCenter in the same
@@ -14,17 +20,19 @@
out vec4 fragColor;
uniform sampler2D u_phosphor; // GL_R32F phosphor energy FBO
uniform sampler2D u_phosphor; // GL_RG32F phosphor energy FBO
uniform vec2 u_scopeCenter; // scope centre in GL viewport pixels (bottom-left origin)
uniform float u_scopeRadius; // scope radius in pixels
uniform float u_gain; // receiver gain [0,1] — scales brightness
uniform float u_gain; // receiver gain [0,1] — scales signal (R) channel only
uniform float u_bloomStep; // UV step for bloom sample (≈ 2.5 / FBO_SIZE)
uniform float u_bloomStrength; // additive blend weight for bloom
// P7 energy thresholds (match settings.h)
// P7 energy thresholds — MUST match settings.h P7_THRESH_* constants.
// T_YGREE is intentionally low (0.05) to keep most of the decay in the
// GREEN zone; see the comment in settings.h for the full rationale.
const float T_BLUE = 0.82;
const float T_GREEN = 0.55;
const float T_YGREE = 0.22;
const float T_YGREE = 0.05;
const float T_DARK = 0.03;
// P7 colour anchors
@@ -34,16 +42,22 @@ const vec3 C_YGREE = vec3(0.50, 1.00, 0.05);
const vec3 C_YELLW = vec3(0.70, 0.70, 0.00);
const vec3 C_BLACK = vec3(0.00, 0.00, 0.00);
// P7 colour ramp: hue selected by energy level, then scaled by energy so
// brightness decreases monotonically from fresh strike (peak) to dark.
// This prevents intermediate decay colours (yellow-green) from appearing
// brighter than the initial blue flash.
vec3 p7Color(float e) {
if (e < T_DARK) return C_BLACK;
vec3 hue;
if (e >= T_BLUE)
return mix(C_GREEN, C_BLUE, (e - T_GREEN) / (T_BLUE - T_GREEN));
if (e >= T_GREEN)
return mix(C_YGREE, C_GREEN, (e - T_YGREE) / (T_GREEN - T_YGREE));
if (e >= T_YGREE)
return mix(C_YELLW, C_YGREE, (e - T_DARK ) / (T_YGREE - T_DARK ));
if (e >= T_DARK)
return mix(C_BLACK, C_YELLW, e / T_DARK);
return C_BLACK;
hue = C_BLUE;
else if (e >= T_GREEN)
hue = mix(C_GREEN, C_BLUE, (e - T_GREEN) / (T_BLUE - T_GREEN));
else if (e >= T_YGREE)
hue = mix(C_YGREE, C_GREEN, (e - T_YGREE) / (T_GREEN - T_YGREE));
else
hue = mix(C_YELLW, C_YGREE, (e - T_DARK) / (T_YGREE - T_DARK));
return hue * e;
}
void main() {
@@ -57,10 +71,12 @@ void main() {
}
// Map from PPI delta [-1,+1] to phosphor texture UV [0,1]
// delta.x = east, delta.y = north (both y directions already match)
vec2 uv = delta * 0.5 + 0.5;
float energy = texture(u_phosphor, uv).r * u_gain;
vec2 rg = texture(u_phosphor, uv).rg;
// Signal (R): gain-scaled received echoes.
// Ring (G): gain-independent timing reference; always at full brightness.
float energy = max(rg.r * u_gain, rg.g);
// Inline bloom: weighted box-filter over a 5×5 neighbourhood
float bloom = 0.0;
@@ -68,7 +84,8 @@ void main() {
for (int dx = -2; dx <= 2; dx++) {
for (int dy = -2; dy <= 2; dy++) {
float w = exp(-float(dx*dx + dy*dy) * 0.45);
float e = texture(u_phosphor, uv + vec2(dx, dy) * u_bloomStep).r;
vec2 srg = texture(u_phosphor, uv + vec2(dx, dy) * u_bloomStep).rg;
float e = max(srg.r * u_gain, srg.g);
bloom += e * w;
wsum += w;
}

View File

@@ -4,13 +4,16 @@
*
* sweep.frag — phosphor accumulation update shader.
*
* For each texel in the 1024×1024 phosphor FBO:
* 1. Decay the previous frame's energy by u_decayFactor.
* 2. If the texel's PPI bearing falls within the current sweep arc
* [u_beamAnglePrev, u_beamAngle], add contributions from:
* - range rings (beam-painted per the P7 spec)
* - target echoes
* 3. Output the updated single-channel energy value.
* The FBO is GL_RG32F (two independent energy channels):
* R — signal energy: target echoes + sweep-background glow.
* Multiplied by u_gain in the display pass so operators can
* adjust received-signal brightness without touching rings.
* G — range-ring energy: written at u_ringBrightness; NOT scaled
* by gain. Rings are a precision timing reference, not a
* received echo. Both channels decay at the same P7 rate.
*
* The sweep background (u_sweepBg) goes into the G channel so the
* rotating beam is always visible regardless of the gain setting.
*
* PPI convention: north = +y, east = +x; bearing = atan2(x, y)
* in degrees, clockwise from north.
@@ -19,17 +22,18 @@
in vec2 vTexCoord;
layout(location = 0) out vec4 fragOut; // .r = energy; .gba unused
layout(location = 0) out vec4 fragOut; // .r = signal; .g = ring+sweep; .ba unused
uniform sampler2D u_prevPhosphor; // previous frame's energy texture (GL_R32F)
uniform sampler2D u_prevPhosphor; // previous frame's energy texture (GL_RG32F)
uniform float u_decayFactor; // exp(-decay_rate * dt)
uniform float u_beamAngle; // current beam angle, degrees CW from north
uniform float u_beamAnglePrev; // beam angle at previous frame
uniform float u_sweepBg; // ambient sweep-line energy (makes beam visible)
uniform float u_sweepBg; // ambient sweep-line energy (gain-independent)
uniform float u_halfBeamDeg; // half-beamwidth for target blobs (display widening)
// Targets: .x = range_norm (0-1), .y = bearing_deg, .z = brightness, .w = size_norm
// Targets: .x = range_norm (0-1), .y = bearing_deg, .z = brightness, .w = radial_size_norm
uniform vec4 u_targets[32];
uniform float u_targetAngHalfDeg[32]; // per-target azimuthal half-width (degrees)
uniform int u_targetCount;
// Range rings: up to 4 normalised radii
@@ -59,8 +63,8 @@ bool inSweep(float b, float prev, float curr) {
// ----------------------------------------------------------------
void main() {
vec2 pos = vTexCoord * 2.0 - 1.0; // PPI coords: (-1,-1) SW … (+1,+1) NE
float rng = length(pos);
vec2 pos = vTexCoord * 2.0 - 1.0; // PPI coords: (-1,-1) SW … (+1,+1) NE
float rng = length(pos);
if (rng > 1.0) {
fragOut = vec4(0.0);
@@ -71,23 +75,25 @@ void main() {
float brg = degrees(atan(pos.x, pos.y));
if (brg < 0.0) brg += 360.0;
// Decay previous value
float energy = texture(u_prevPhosphor, vTexCoord).r * u_decayFactor;
vec2 prev = texture(u_prevPhosphor, vTexCoord).rg;
float signal = prev.r * u_decayFactor;
float ring = prev.g * u_decayFactor;
if (inSweep(brg, u_beamAnglePrev, u_beamAngle)) {
float contrib = u_sweepBg; // beam passage gives a faint ambient glow
// ---- Range rings (painted at every bearing as beam sweeps) ----
// ---- Range rings → G channel (gain-independent) ----
float ringContrib = u_sweepBg; // sweep-background glow also in G channel
for (int i = 0; i < u_ringCount; i++) {
float d = abs(rng - u_ringRadii[i]);
if (d < u_ringWidth) {
float w = 1.0 - d / u_ringWidth;
contrib = max(contrib, u_ringBrightness * w * w);
ringContrib = max(ringContrib, u_ringBrightness * w * w);
}
}
ring = max(ring, ringContrib);
// ---- Target echoes ----
// ---- Target echoes → R channel (gain-scaled in display pass) ----
float sigContrib = 0.0;
for (int i = 0; i < u_targetCount; i++) {
float tRng = u_targets[i].x;
float tBrg = u_targets[i].y;
@@ -96,21 +102,19 @@ void main() {
if (tRng <= 0.0 || tBrt <= 0.0) continue;
// Angular proximity: beam must be sweeping over the target's bearing
float tAngHalf = u_targetAngHalfDeg[i];
float dBrg = angleDiff(brg, tBrg);
if (dBrg >= u_halfBeamDeg) continue;
if (dBrg >= tAngHalf) continue;
// Range proximity: pixel must be within the target blob
float dRng = abs(rng - tRng);
if (dRng >= tSize) continue;
float bw = 1.0 - dBrg / u_halfBeamDeg; // angular taper
float rw = 1.0 - dRng / tSize; // range taper
contrib = max(contrib, tBrt * bw * rw);
float bw = 1.0 - dBrg / tAngHalf;
float rw = 1.0 - dRng / tSize;
sigContrib = max(sigContrib, tBrt * bw * rw);
}
energy = max(energy, contrib);
signal = max(signal, sigContrib);
}
fragOut = vec4(clamp(energy, 0.0, 1.0), 0.0, 0.0, 1.0);
fragOut = vec4(clamp(signal, 0.0, 1.0), clamp(ring, 0.0, 1.0), 0.0, 1.0);
}

View File

@@ -102,9 +102,9 @@ bool PhosphorRenderer::init(const std::string& shaderDir) {
glGenTextures(1, &tex_[i]);
glBindTexture(GL_TEXTURE_2D, tex_[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F,
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG32F,
fboSize_, fboSize_, 0,
GL_RED, GL_FLOAT, nullptr);
GL_RG, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -193,16 +193,19 @@ void PhosphorRenderer::update(
// Target array: pack into vec4 array
float tdata[MAX_TARGETS * 4] = {};
float angData[MAX_TARGETS] = {};
int tCount = (targetCount < MAX_TARGETS) ? targetCount : MAX_TARGETS;
float invRange = (maxRangeM > 0.f) ? 1.0f / maxRangeM : 0.f;
for (int i = 0; i < tCount; ++i) {
tdata[i*4+0] = targets[i].range_m * invRange; // normalised 0-1
tdata[i*4+0] = targets[i].range_m * invRange * GRAT_INNER_RING_FRAC;
tdata[i*4+1] = targets[i].bearing_deg;
tdata[i*4+2] = targets[i].brightness;
tdata[i*4+3] = targets[i].size_m * invRange; // normalised blob half-radius
tdata[i*4+3] = targets[i].size_m * invRange * GRAT_INNER_RING_FRAC;
angData[i] = targets[i].ang_half_deg;
}
glUniform4fv(glGetUniformLocation(sweepProg_, "u_targets"), tCount, tdata);
glUniform1i (glGetUniformLocation(sweepProg_, "u_targetCount"), tCount);
glUniform4fv(glGetUniformLocation(sweepProg_, "u_targets"), tCount, tdata);
glUniform1fv(glGetUniformLocation(sweepProg_, "u_targetAngHalfDeg"), tCount, angData);
glUniform1i (glGetUniformLocation(sweepProg_, "u_targetCount"), tCount);
glBindVertexArray(quadVAO_);
glDrawArrays(GL_TRIANGLES, 0, 6);

View File

@@ -7,7 +7,7 @@
#include "scope_marine_ppi.h"
#include <GLFW/glfw3.h>
#include <cstring>
#include <cmath>
// ----------------------------------------------------------------
@@ -18,8 +18,14 @@ float MarinePPIScope::maxRangeM() const {
void MarinePPIScope::computeRingRadii() {
int n = MARINE_RING_COUNT[maxRangeIdx_];
float maxMi = MARINE_RANGE_STEPS[maxRangeIdx_];
for (int i = 0; i < n; ++i)
ringRadiiNorm_[i] = MARINE_RING_MILES[maxRangeIdx_][i] / maxMi;
for (int i = 0; i < n; ++i) {
// Scale by GRAT_INNER_RING_FRAC so max-range maps to the inner
// graticule ring boundary. Targets use the same scale factor
// (applied in PhosphorRenderer::update), so rings and targets
// remain co-registered in the display.
ringRadiiNorm_[i] = (MARINE_RING_MILES[maxRangeIdx_][i] / maxMi)
* GRAT_INNER_RING_FRAC;
}
}
void MarinePPIScope::handleKeyRange(int key, int /*action*/) {

View File

@@ -185,9 +185,16 @@ void PPIScope::render(float dt, float viewportW, float viewportH) {
}
graticule_.render(viewportW, viewportH, gratI, brgOffsetDeg_);
// 3. Yellow cursor overlay
// 3. Yellow cursor overlay — clamp cursor to max range each frame so it
// never escapes the active display area regardless of how it was set.
{
float maxMi = maxM / MILES_TO_METERS;
if (cursorRngMi_ > maxMi) cursorRngMi_ = maxMi;
}
// Map cursor range [0, maxM] → normalised radius [0, GRAT_INNER_RING_FRAC]
// so the cursor at max range sits on the outer ring, not on the bezel.
float cursorNorm = (maxM > 0.f)
? std::min((cursorRngMi_ * MILES_TO_METERS) / maxM, 1.0f)
? (cursorRngMi_ * MILES_TO_METERS / maxM) * GRAT_INNER_RING_FRAC
: 0.f;
// Cursor bearing in display coordinates (subtract offset so it tracks the display)
float dispBrg = std::fmod(cursorBrgDeg_ - brgOffsetDeg_ + 360.f, 360.f);

View File

@@ -31,9 +31,16 @@ constexpr int PHOSPHOR_FBO_SIZE = 1024; // texels per side for phospho
constexpr float P7_DECAY_RATE = 1.1513f; // s^-1; <1% remains after 4 s
// Energy thresholds that define colour transitions in the display shader
// T_YGREE is deliberately low (0.05) so that the ring spends the vast
// majority of the 4-second sweep period in the GREEN zone rather than
// in the yellow-green/yellow zone. With exponential decay (rate 1.15),
// a ring painted at 0.72 stays green for ~2.5 s, dips through a faint
// yellow-green for ~0.45 s (≈ 40° of arc), then goes black. Setting
// T_YGREE = 0.22 (old value) extended the yellow zone to ~1.75 s (44%
// of the scope arc), which is the source of the "solid yellow" report.
constexpr float P7_THRESH_BLUE = 0.82f; // above this: blue strike
constexpr float P7_THRESH_GREEN = 0.55f; // above this: green persistence
constexpr float P7_THRESH_YELLOW_GR = 0.22f; // above this: yellow-green fade
constexpr float P7_THRESH_YELLOW_GR = 0.05f; // above this: yellow-green fade
constexpr float P7_THRESH_DARK = 0.03f; // below this: essentially black
// Colour anchors (RGB)
@@ -42,8 +49,12 @@ constexpr float P7_GREEN_R = 0.05f, P7_GREEN_G = 1.00f, P7_GREEN_B = 0.30f;
constexpr float P7_YGREE_R = 0.50f, P7_YGREE_G = 1.00f, P7_YGREE_B = 0.05f;
constexpr float P7_YELLW_R = 0.70f, P7_YELLW_G = 0.70f, P7_YELLW_B = 0.00f;
// Sweep background energy — gives the rotating beam its visible glow
constexpr float SWEEP_BACKGROUND_ENERGY = 0.10f;
// Sweep background energy written to the G channel each frame the beam
// sweeps over a texel. Kept just above T_DARK so the rotating beam is
// barely visible as a dim trace; it decays to black in ~0.3 s (7% of
// the 4-second sweep arc). 0.10 (old value) left a visible glow for
// ~1.3 s (33% of arc) — major contributor to the "solid yellow" report.
constexpr float SWEEP_BACKGROUND_ENERGY = 0.04f;
// Half-beamwidth used by sweep shader for target blob display (degrees)
constexpr float SWEEP_HALF_BEAM_DEG = 1.0f;
@@ -83,7 +94,13 @@ constexpr int GRAT_SEGMENTS = 360; // circle tessellation segm
// RANGE RINGS (beam-painted; widths in normalised 0-1 scope space)
// ================================================================
constexpr float RING_WIDTH_NORM = 0.005f;
constexpr float RING_BRIGHTNESS = 0.72f;
constexpr float RING_BRIGHTNESS = 1.0f;
// Range-ring distance labels
// Labels appear at a fixed bearing so they don't clutter the display.
// Colour uses the P7 fresh-blue constants (P7_BLUE_R/G/B) already above.
constexpr float RING_LABEL_BRG_DEG = 45.0f; // NE: clear of bearing-mark clusters
constexpr int RING_LABEL_FONT_SIZE = 14; // pixels (matches graticule labels)
// Marine PPI range steps (miles) and ring definitions
// Index: 0 (max 2 mi) 1 (max 4 mi) 2 (max 6 mi)

View File

@@ -67,6 +67,11 @@ Simulator::Simulator() {
// 7. Large barge under tow N — bearing 355°, 4.8 mi
targets_[n++] = { 7, 48.8127f, -122.5739f, 3.08f, 175.0f, 1000.0f, 30.0f };
// 8. DEBUG: large broadside cargo ship NE — bearing 045°, 1.0 mi
// Stationary (speed=0). RCS 500,000 m² (big steel hull broadside).
// sizeM=150 so the blob is clearly visible even in no-persistence mode.
targets_[n++] = { 8, 48.7538f, -122.5492f, 0.0f, 0.0f, 500000.0f, 150.0f };
targetCount_ = n;
}

View File

@@ -27,7 +27,8 @@ struct SimTarget {
float speedMps; // metres per second
float headingDeg; // true heading, CW from north
float sigmaM2; // RCS in m²
float sizeM; // physical blob half-radius in metres
float sizeM; // radial blob half-width in metres (range direction)
float angHalfDeg; // azimuthal half-width in degrees (bearing direction)
};
class Simulator {

View File

@@ -23,7 +23,8 @@ struct TargetState {
float range_m = 0.0f; // metres from radar origin
float bearing_deg = 0.0f; // degrees true, CW from north
float brightness = 0.0f; // 0-1, from radar equation
float size_m = 50.0f; // physical blob half-radius in metres; scope normalises to [0,1]
float size_m = 50.0f; // radial blob half-width in metres (range direction)
float ang_half_deg = SWEEP_HALF_BEAM_DEG; // azimuthal half-width in degrees
bool valid = false;
};